From: Roy Marples Date: Sat, 8 Feb 2020 17:29:03 +0000 (+0000) Subject: BSD: Add support for RO_MISSFILTER route(4) socket option X-Git-Tag: v9.0.0~47 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dd2d73d45140ac1aa9a4b85bdf87751f96766548;p=thirdparty%2Fdhcpcd.git BSD: Add support for RO_MISSFILTER route(4) socket option This allows dhcpcd to only listen for RTM_MISS generated by default routers dhcpcd *could* install so if one becomes unreachable we can pick another. --- diff --git a/src/dhcpcd.h b/src/dhcpcd.h index 6242956a..ac61d926 100644 --- a/src/dhcpcd.h +++ b/src/dhcpcd.h @@ -183,6 +183,13 @@ struct dhcpcd_ctx { char *randomstate; /* original state */ + /* For filtering RTM_MISS messages per router */ +#ifdef BSD + uint8_t *rt_missfilter; + size_t rt_missfilterlen; + size_t rt_missfiltersize; +#endif + #ifdef PRIVSEP struct passwd *ps_user; /* struct passwd for privsep user */ pid_t ps_root_pid; diff --git a/src/if-bsd.c b/src/if-bsd.c index 76ba114e..0e631819 100644 --- a/src/if-bsd.c +++ b/src/if-bsd.c @@ -1509,6 +1509,78 @@ if_dispatch(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm) return 0; } +static int +if_missfilter0(struct dhcpcd_ctx *ctx, struct interface *ifp, + struct sockaddr *sa) +{ + size_t salen = (size_t)RT_ROUNDUP(sa->sa_len); + size_t newlen = ctx->rt_missfilterlen + salen; + size_t diff = salen - (sa->sa_len); + uint8_t *cp; + + if (ctx->rt_missfiltersize < newlen) { + void *n = realloc(ctx->rt_missfilter, newlen); + if (n == NULL) + return -1; + ctx->rt_missfilter = n; + ctx->rt_missfiltersize = newlen; + } + +#ifdef INET6 + if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + + ifa_setscope(sin6, ifp->index); + } +#endif + + cp = ctx->rt_missfilter + ctx->rt_missfilterlen; + memcpy(cp, sa, sa->sa_len); + if (diff != 0) + memset(cp + sa->sa_len, 0, diff); + ctx->rt_missfilterlen += salen; + +#ifdef INET6 + if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + + ifa_setscope(sin6, 0); + } +#endif + + return 0; +} + +int +if_missfilter(struct interface *ifp, struct sockaddr *sa) +{ + + return if_missfilter0(ifp->ctx, ifp, sa); +} + +int +if_missfilter_apply(struct dhcpcd_ctx *ctx) +{ +#ifdef RO_MISSFILTER + if (ctx->rt_missfilterlen == 0) { + struct sockaddr sa = { + .sa_family = AF_UNSPEC, + .sa_len = sizeof(sa), + }; + + if (if_missfilter0(ctx, NULL, &sa) == -1) + return -1; + } + + return setsockopt(ctx->link_fd, PF_ROUTE, RO_MISSFILTER, + ctx->rt_missfilter, (socklen_t)ctx->rt_missfilterlen); +#else +#warning kernel does not support RTM_MISS DST filtering + errno = ENOTSUP; + return -1; +#endif +} + __CTASSERT(offsetof(struct rt_msghdr, rtm_msglen) == 0); int if_handlelink(struct dhcpcd_ctx *ctx) diff --git a/src/if.h b/src/if.h index 0656affe..bac109d6 100644 --- a/src/if.h +++ b/src/if.h @@ -206,6 +206,9 @@ int if_setmac(struct interface *ifp, void *, uint8_t); int if_route(unsigned char, const struct rt *rt); int if_initrt(struct dhcpcd_ctx *, rb_tree_t *, int); +int if_missfilter(struct interface *, struct sockaddr *); +int if_missfilter_apply(struct dhcpcd_ctx *); + #ifdef INET int if_address(unsigned char, const struct ipv4_addr *); int if_addrflags(const struct interface *, const struct in_addr *, diff --git a/src/route.c b/src/route.c index 56e57a31..1b9c26f0 100644 --- a/src/route.c +++ b/src/route.c @@ -690,22 +690,26 @@ rt_build(struct dhcpcd_ctx *ctx, int af) ctx->rt_order = 0; ctx->options |= DHCPCD_RTBUILD; - switch (af) { #ifdef INET - case AF_INET: - if (!inet_getroutes(ctx, &routes)) - goto getfail; - break; + if (!inet_getroutes(ctx, &routes)) + goto getfail; #endif #ifdef INET6 - case AF_INET6: - if (!inet6_getroutes(ctx, &routes)) - goto getfail; - break; + if (!inet6_getroutes(ctx, &routes)) + goto getfail; +#endif + +#ifdef BSD + /* Rewind the miss filter */ + ctx->rt_missfilterlen = 0; #endif - } RB_TREE_FOREACH_SAFE(rt, &routes, rtn) { +#ifdef BSD + if (rt_is_default(rt) && + if_missfilter(rt->rt_ifp, &rt->rt_gateway) == -1) + logerr("if_missfilter"); +#endif if ((rt->rt_dest.sa_family != af && rt->rt_dest.sa_family != AF_UNSPEC) || (rt->rt_gateway.sa_family != af && @@ -724,6 +728,11 @@ rt_build(struct dhcpcd_ctx *ctx, int af) } } +#ifdef BSD + if (if_missfilter_apply(ctx) == -1) + logerr("if_missfilter_apply"); +#endif + /* Remove old routes we used to manage. */ RB_TREE_FOREACH_REVERSE_SAFE(rt, &ctx->routes, rtn) { if ((rt->rt_dest.sa_family != af &&