mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-15 21:05:08 +00:00
netlink: add an optional post-process hook to the message parsers.
It is primarily used for adding scopeid to the IPv6 link-local sockaddrs. Having proper sockaddrs after parsing minimises the possibility of human mistake when using the parsing. MFC after: 2 weeks
This commit is contained in:
parent
97760572a0
commit
3f6bf6a033
|
@ -110,6 +110,7 @@ struct nlattr_parser {
|
|||
};
|
||||
|
||||
typedef bool strict_parser_f(void *hdr, struct nl_pstate *npt);
|
||||
typedef bool post_parser_f(void *parsed_attrs, struct nl_pstate *npt);
|
||||
|
||||
struct nlhdr_parser {
|
||||
int nl_hdr_off; /* aligned netlink header size */
|
||||
|
@ -118,27 +119,26 @@ struct nlhdr_parser {
|
|||
int np_size;
|
||||
const struct nlfield_parser *fp; /* array of header field parsers */
|
||||
const struct nlattr_parser *np; /* array of attribute parsers */
|
||||
strict_parser_f *sp; /* Parser function */
|
||||
strict_parser_f *sp; /* Pre-parse strict validation function */
|
||||
post_parser_f *post_parse;
|
||||
};
|
||||
|
||||
#define NL_DECLARE_PARSER(_name, _t, _fp, _np) \
|
||||
static const struct nlhdr_parser _name = { \
|
||||
.nl_hdr_off = sizeof(_t), \
|
||||
.fp = &((_fp)[0]), \
|
||||
.np = &((_np)[0]), \
|
||||
.fp_size = NL_ARRAY_LEN(_fp), \
|
||||
.np_size = NL_ARRAY_LEN(_np), \
|
||||
#define NL_DECLARE_PARSER_EXT(_name, _t, _sp, _fp, _np, _pp) \
|
||||
static const struct nlhdr_parser _name = { \
|
||||
.nl_hdr_off = sizeof(_t), \
|
||||
.fp = &((_fp)[0]), \
|
||||
.np = &((_np)[0]), \
|
||||
.fp_size = NL_ARRAY_LEN(_fp), \
|
||||
.np_size = NL_ARRAY_LEN(_np), \
|
||||
.sp = _sp, \
|
||||
.post_parse = _pp, \
|
||||
}
|
||||
|
||||
#define NL_DECLARE_STRICT_PARSER(_name, _t, _sp, _fp, _np)\
|
||||
static const struct nlhdr_parser _name = { \
|
||||
.nl_hdr_off = sizeof(_t), \
|
||||
.fp = &((_fp)[0]), \
|
||||
.np = &((_np)[0]), \
|
||||
.fp_size = NL_ARRAY_LEN(_fp), \
|
||||
.np_size = NL_ARRAY_LEN(_np), \
|
||||
.sp = _sp, \
|
||||
}
|
||||
#define NL_DECLARE_PARSER(_name, _t, _fp, _np) \
|
||||
NL_DECLARE_PARSER_EXT(_name, _t, NULL, _fp, _np, NULL)
|
||||
|
||||
#define NL_DECLARE_STRICT_PARSER(_name, _t, _sp, _fp, _np) \
|
||||
NL_DECLARE_PARSER_EXT(_name, _t, _sp, _fp, _np, NULL)
|
||||
|
||||
#define NL_DECLARE_ARR_PARSER(_name, _t, _o, _fp, _np) \
|
||||
static const struct nlhdr_parser _name = { \
|
||||
|
@ -252,6 +252,11 @@ nl_parse_header(void *hdr, int len, const struct nlhdr_parser *parser,
|
|||
error = nl_parse_attrs_raw(nla_head, len - parser->nl_hdr_off, parser->np,
|
||||
parser->np_size, npt, target);
|
||||
|
||||
if (parser->post_parse != NULL && error == 0) {
|
||||
if (!parser->post_parse(target, npt))
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
|
|
@ -279,14 +279,6 @@ get_lle(struct netlink_walkargs *wa, struct ifnet *ifp, int family, struct socka
|
|||
if (llt == NULL)
|
||||
return (ESRCH);
|
||||
|
||||
#ifdef INET6
|
||||
if (dst->sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)dst;
|
||||
|
||||
if (IN6_IS_SCOPE_LINKLOCAL(&dst6->sin6_addr))
|
||||
in6_set_unicast_scopeid(&dst6->sin6_addr, ifp->if_index);
|
||||
}
|
||||
#endif
|
||||
struct llentry *lle = lla_lookup(llt, LLE_UNLOCKED, dst);
|
||||
if (lle == NULL)
|
||||
return (ESRCH);
|
||||
|
@ -297,6 +289,19 @@ get_lle(struct netlink_walkargs *wa, struct ifnet *ifp, int family, struct socka
|
|||
return (dump_lle(llt, lle, wa));
|
||||
}
|
||||
|
||||
static void
|
||||
set_scope6(struct sockaddr *sa, struct ifnet *ifp)
|
||||
{
|
||||
#ifdef INET6
|
||||
if (sa != NULL && sa->sa_family == AF_INET6 && ifp != NULL) {
|
||||
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
|
||||
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr))
|
||||
in6_set_unicast_scopeid(&sa6->sin6_addr, if_getindex(ifp));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
struct nl_parsed_neigh {
|
||||
struct sockaddr *nda_dst;
|
||||
struct ifnet *nda_ifp;
|
||||
|
@ -330,7 +335,16 @@ static const struct nlattr_parser nla_p_neigh[] = {
|
|||
};
|
||||
#undef _IN
|
||||
#undef _OUT
|
||||
NL_DECLARE_PARSER(ndmsg_parser, struct ndmsg, nlf_p_neigh, nla_p_neigh);
|
||||
|
||||
static bool
|
||||
post_p_neigh(void *_attrs, struct nl_pstate *npt __unused)
|
||||
{
|
||||
struct nl_parsed_neigh *attrs = (struct nl_parsed_neigh *)_attrs;
|
||||
|
||||
set_scope6(attrs->nda_dst, attrs->nda_ifp);
|
||||
return (true);
|
||||
}
|
||||
NL_DECLARE_PARSER_EXT(ndmsg_parser, struct ndmsg, NULL, nlf_p_neigh, nla_p_neigh, post_p_neigh);
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
@ -678,6 +678,19 @@ nlattr_get_nhg(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void
|
|||
return (error);
|
||||
}
|
||||
|
||||
static void
|
||||
set_scope6(struct sockaddr *sa, struct ifnet *ifp)
|
||||
{
|
||||
#ifdef INET6
|
||||
if (sa != NULL && sa->sa_family == AF_INET6 && ifp != NULL) {
|
||||
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
|
||||
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr))
|
||||
in6_set_unicast_scopeid(&sa6->sin6_addr, if_getindex(ifp));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
struct nl_parsed_nhop {
|
||||
uint32_t nha_id;
|
||||
uint8_t nha_blackhole;
|
||||
|
@ -721,7 +734,16 @@ static const struct nlattr_parser nla_p_nh[] = {
|
|||
};
|
||||
#undef _IN
|
||||
#undef _OUT
|
||||
NL_DECLARE_PARSER(nhmsg_parser, struct nhmsg, nlf_p_nh, nla_p_nh);
|
||||
|
||||
static bool
|
||||
post_p_nh(void *_attrs, struct nl_pstate *npt)
|
||||
{
|
||||
struct nl_parsed_nhop *attrs = (struct nl_parsed_nhop *)_attrs;
|
||||
|
||||
set_scope6(attrs->nha_gw, attrs->nha_oif);
|
||||
return (true);
|
||||
}
|
||||
NL_DECLARE_PARSER_EXT(nhmsg_parser, struct nhmsg, NULL, nlf_p_nh, nla_p_nh, post_p_nh);
|
||||
|
||||
static bool
|
||||
eligible_nhg(const struct nhop_object *nh)
|
||||
|
|
|
@ -349,7 +349,6 @@ family_to_group(int family)
|
|||
return (0);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
report_operation(uint32_t fibnum, struct rib_cmd_info *rc,
|
||||
struct nlpcb *nlp, struct nlmsghdr *hdr)
|
||||
|
@ -384,6 +383,19 @@ report_operation(uint32_t fibnum, struct rib_cmd_info *rc,
|
|||
rtsock_callback_p->route_f(fibnum, rc);
|
||||
}
|
||||
|
||||
static void
|
||||
set_scope6(struct sockaddr *sa, struct ifnet *ifp)
|
||||
{
|
||||
#ifdef INET6
|
||||
if (sa != NULL && sa->sa_family == AF_INET6 && ifp != NULL) {
|
||||
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
|
||||
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr))
|
||||
in6_set_unicast_scopeid(&sa6->sin6_addr, if_getindex(ifp));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
struct rta_mpath_nh {
|
||||
struct sockaddr *gw;
|
||||
struct ifnet *ifp;
|
||||
|
@ -404,26 +416,16 @@ const static struct nlfield_parser nlf_p_rtnh[] = {
|
|||
};
|
||||
#undef _IN
|
||||
#undef _OUT
|
||||
NL_DECLARE_PARSER(mpath_parser, struct rtnexthop, nlf_p_rtnh, nla_p_rtnh);
|
||||
|
||||
static void
|
||||
set_scope6(struct sockaddr *sa, struct ifnet *ifp)
|
||||
static bool
|
||||
post_p_rtnh(void *_attrs, struct nl_pstate *npt __unused)
|
||||
{
|
||||
#ifdef INET6
|
||||
if (sa != NULL && sa->sa_family == AF_INET6 && ifp != NULL) {
|
||||
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
|
||||
struct rta_mpath_nh *attrs = (struct rta_mpath_nh *)_attrs;
|
||||
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr))
|
||||
in6_set_unicast_scopeid(&sa6->sin6_addr, ifp->if_index);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
post_p_mpath(struct rta_mpath_nh *mpnh)
|
||||
{
|
||||
set_scope6(mpnh->gw, mpnh->ifp);
|
||||
set_scope6(attrs->gw, attrs->ifp);
|
||||
return (true);
|
||||
}
|
||||
NL_DECLARE_PARSER_EXT(mpath_parser, struct rtnexthop, NULL, nlf_p_rtnh, nla_p_rtnh, post_p_rtnh);
|
||||
|
||||
struct rta_mpath {
|
||||
int num_nhops;
|
||||
|
@ -451,7 +453,6 @@ nlattr_get_multipath(struct nlattr *nla, struct nl_pstate *npt, const void *arg,
|
|||
mp->num_nhops - 1);
|
||||
return (error);
|
||||
}
|
||||
post_p_mpath(mpnh);
|
||||
|
||||
int len = NL_ITEM_ALIGN(rtnh->rtnh_len);
|
||||
data_len -= len;
|
||||
|
@ -513,14 +514,17 @@ static const struct nlfield_parser nlf_p_rtmsg[] = {
|
|||
};
|
||||
#undef _IN
|
||||
#undef _OUT
|
||||
NL_DECLARE_PARSER(rtm_parser, struct rtmsg, nlf_p_rtmsg, nla_p_rtmsg);
|
||||
|
||||
static void
|
||||
post_p_rtmsg(struct nl_parsed_route *r)
|
||||
static bool
|
||||
post_p_rtmsg(void *_attrs, struct nl_pstate *npt __unused)
|
||||
{
|
||||
set_scope6(r->rta_dst, r->rta_oif);
|
||||
set_scope6(r->rta_gw, r->rta_oif);
|
||||
struct nl_parsed_route *attrs = (struct nl_parsed_route *)_attrs;
|
||||
|
||||
set_scope6(attrs->rta_dst, attrs->rta_oif);
|
||||
set_scope6(attrs->rta_gw, attrs->rta_oif);
|
||||
return (true);
|
||||
}
|
||||
NL_DECLARE_PARSER_EXT(rtm_parser, struct rtmsg, NULL, nlf_p_rtmsg, nla_p_rtmsg, post_p_rtmsg);
|
||||
|
||||
struct netlink_walkargs {
|
||||
struct nl_writer *nw;
|
||||
|
@ -926,7 +930,6 @@ rtnl_handle_newroute(struct nlmsghdr *hdr, struct nlpcb *nlp,
|
|||
error = nl_parse_nlmsg(hdr, &rtm_parser, npt, &attrs);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
post_p_rtmsg(&attrs);
|
||||
|
||||
/* Check if we have enough data */
|
||||
if (attrs.rta_dst == NULL) {
|
||||
|
@ -991,7 +994,6 @@ rtnl_handle_delroute(struct nlmsghdr *hdr, struct nlpcb *nlp,
|
|||
error = nl_parse_nlmsg(hdr, &rtm_parser, npt, &attrs);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
post_p_rtmsg(&attrs);
|
||||
|
||||
if (attrs.rta_dst == NULL) {
|
||||
NLMSG_REPORT_ERR_MSG(npt, "RTA_DST is not set");
|
||||
|
@ -1019,7 +1021,6 @@ rtnl_handle_getroute(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *
|
|||
error = nl_parse_nlmsg(hdr, &rtm_parser, npt, &attrs);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
post_p_rtmsg(&attrs);
|
||||
|
||||
if (attrs.rta_table >= V_rt_numfibs) {
|
||||
NLMSG_REPORT_ERR_MSG(npt, "invalid fib");
|
||||
|
|
Loading…
Reference in a new issue