summaryrefslogtreecommitdiffstats
path: root/src/if-bsd.c
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2020-02-08 17:29:03 +0000
committerRoy Marples <roy@marples.name>2020-02-08 17:30:35 +0000
commitdd2d73d45140ac1aa9a4b85bdf87751f96766548 (patch)
tree1dcca0db4bf0d062627349aba3b4004500b1a539 /src/if-bsd.c
parent91b11be6dc29b3e3ff4ea50dd54e589d30b443c1 (diff)
downloaddhcpcd-dd2d73d45140ac1aa9a4b85bdf87751f96766548.tar.xz
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.
Diffstat (limited to 'src/if-bsd.c')
-rw-r--r--src/if-bsd.c72
1 files changed, 72 insertions, 0 deletions
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)