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;
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)
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 *,
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 &&
}
}
+#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 &&