From 5dca88cebaf59bf2beacddbb8d991395e3e08b4e Mon Sep 17 00:00:00 2001 From: florian Date: Wed, 27 Jan 2021 08:30:50 +0000 Subject: [PATCH] Determine available address families (and monitor when this changes) to configure libunbound accordingly. This way it no longer tries to talk to IPv6 nameservers when only IPv4 is available and vice versa. input deraadt OK kn --- sbin/unwind/frontend.c | 76 ++++++++++++++++++++++++++++++++++++++++-- sbin/unwind/frontend.h | 5 ++- sbin/unwind/resolver.c | 51 +++++++++++++++++++++++----- sbin/unwind/unwind.c | 5 +-- sbin/unwind/unwind.h | 3 +- 5 files changed, 126 insertions(+), 14 deletions(-) diff --git a/sbin/unwind/frontend.c b/sbin/unwind/frontend.c index 50dab6c70ca..18d91dfbeb2 100644 --- a/sbin/unwind/frontend.c +++ b/sbin/unwind/frontend.c @@ -1,4 +1,4 @@ -/* $OpenBSD: frontend.c,v 1.65 2021/01/24 18:29:15 florian Exp $ */ +/* $OpenBSD: frontend.c,v 1.66 2021/01/27 08:30:50 florian Exp $ */ /* * Copyright (c) 2018 Florian Obser @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -150,6 +151,7 @@ void parse_blocklist(int); int bl_cmp(struct bl_node *, struct bl_node *); void free_bl(void); int pending_query_cnt(void); +void check_available_af(void); struct uw_conf *frontend_conf; static struct imsgev *iev_main; @@ -212,7 +214,7 @@ frontend(int debug, int verbose) setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) fatal("can't drop privileges"); - if (pledge("stdio unix recvfd", NULL) == -1) + if (pledge("stdio dns unix recvfd", NULL) == -1) fatal("pledge"); event_init(); @@ -660,6 +662,7 @@ frontend_startup(void) event_add(&ev_route, NULL); frontend_imsg_compose_main(IMSG_STARTUP_DONE, 0, NULL, 0); + check_available_af(); } void @@ -1362,6 +1365,11 @@ handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info) frontend_imsg_compose_resolver(IMSG_REPLACE_DNS, 0, &rdns_proposal, sizeof(rdns_proposal)); break; + case RTM_NEWADDR: + case RTM_DELADDR: + case RTM_DESYNC: + check_available_af(); + break; default: break; } @@ -1765,3 +1773,67 @@ tcp_timeout(int fd, short events, void *arg) { free_pending_query(arg); } + +void +check_available_af() +{ + static int available_af = HAVE_IPV4 | HAVE_IPV6; + static int rtable = -1; + struct ifaddrs *ifap, *ifa; + struct if_data *ifa_data; + struct sockaddr_in *sin4; + struct sockaddr_in6 *sin6; + int new_available_af = 0, ifa_rtable = -1; + + if (rtable == -1) + rtable = getrtable(); + + if (getifaddrs(&ifap) != 0) { + log_warn("getifaddrs"); + return; + } + + for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) + continue; + switch(ifa->ifa_addr->sa_family) { + case AF_LINK: + /* AF_LINK comes before inet / inet6 on an interface */ + ifa_data = (struct if_data *)ifa->ifa_data; + ifa_rtable = ifa_data->ifi_rdomain; + break; + case AF_INET: + if (ifa_rtable != rtable) + continue; + + sin4 = (struct sockaddr_in *)ifa->ifa_addr; + if ((ntohl(sin4->sin_addr.s_addr) >> 24) == + IN_LOOPBACKNET) + continue; + new_available_af |= HAVE_IPV4; + break; + case AF_INET6: + if (ifa_rtable != rtable) + continue; + + sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; + if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) || + IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || + IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr) || + IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) + continue; + new_available_af |= HAVE_IPV6; + break; + default: + break; + } + if (new_available_af == (HAVE_IPV4 | HAVE_IPV6)) + break; + } + freeifaddrs(ifap); + if (new_available_af != available_af) { + available_af = new_available_af; + frontend_imsg_compose_resolver(IMSG_CHANGE_AFS, 0, + &available_af, sizeof(available_af)); + } +} diff --git a/sbin/unwind/frontend.h b/sbin/unwind/frontend.h index cd6c21875af..29b64f5a235 100644 --- a/sbin/unwind/frontend.h +++ b/sbin/unwind/frontend.h @@ -1,4 +1,4 @@ -/* $OpenBSD: frontend.h,v 1.8 2021/01/24 18:29:15 florian Exp $ */ +/* $OpenBSD: frontend.h,v 1.9 2021/01/27 08:30:50 florian Exp $ */ /* * Copyright (c) 2018 Florian Obser @@ -17,6 +17,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define HAVE_IPV4 1 +#define HAVE_IPV6 2 + struct trust_anchor { TAILQ_ENTRY(trust_anchor) entry; char *ta; diff --git a/sbin/unwind/resolver.c b/sbin/unwind/resolver.c index c1e399b859a..49f51d8a9ab 100644 --- a/sbin/unwind/resolver.c +++ b/sbin/unwind/resolver.c @@ -1,4 +1,4 @@ -/* $OpenBSD: resolver.c,v 1.136 2021/01/26 12:46:46 florian Exp $ */ +/* $OpenBSD: resolver.c,v 1.137 2021/01/27 08:30:50 florian Exp $ */ /* * Copyright (c) 2018 Florian Obser @@ -230,6 +230,7 @@ struct key_cache *unified_key_cache; struct val_neg_cache *unified_neg_cache; int dns64_present; +int available_afs = HAVE_IPV4 | HAVE_IPV6; static const char * const as112_zones[] = { /* RFC1918 */ @@ -462,13 +463,13 @@ resolver_imsg_compose_frontend(int type, pid_t pid, void *data, void resolver_dispatch_frontend(int fd, short event, void *bula) { - struct imsgev *iev = bula; - struct imsgbuf *ibuf; - struct imsg imsg; - struct query_imsg *query_imsg; - ssize_t n; - int shut = 0, verbose, i; - char *ta; + struct imsgev *iev = bula; + struct imsgbuf *ibuf; + struct imsg imsg; + struct query_imsg *query_imsg; + ssize_t n; + int shut = 0, verbose, i, new_available_afs; + char *ta; ibuf = &iev->ibuf; @@ -567,6 +568,18 @@ resolver_dispatch_frontend(int fd, short event, void *bula) replace_autoconf_forwarders((struct imsg_rdns_proposal *)imsg.data); break; + case IMSG_CHANGE_AFS: + if (IMSG_DATA_SIZE(imsg) != + sizeof(new_available_afs)) + fatalx("%s: IMSG_CHANGE_AFS wrong length: %lu", + __func__, IMSG_DATA_SIZE(imsg)); + memcpy(&new_available_afs, imsg.data, + sizeof(new_available_afs)); + if (new_available_afs != available_afs) { + available_afs = new_available_afs; + restart_ub_resolvers(); + } + break; default: log_debug("%s: unexpected imsg %d", __func__, imsg.hdr.type); @@ -1253,6 +1266,28 @@ create_resolver(enum uw_resolver_type type) } } + if (!(available_afs & HAVE_IPV4)) { + if((err = ub_ctx_set_option(res->ctx, "do-ip4:", + "no")) != 0) { + ub_ctx_delete(res->ctx); + free(res); + log_warnx("error setting do-ip4: no: %s", + ub_strerror(err)); + return (NULL); + } + } + + if (!(available_afs & HAVE_IPV6)) { + if((err = ub_ctx_set_option(res->ctx, "do-ip6:", + "no")) != 0) { + ub_ctx_delete(res->ctx); + free(res); + log_warnx("error setting do-ip6: no: %s", + ub_strerror(err)); + return (NULL); + } + } + if (!log_getdebug()) { if((err = ub_ctx_set_option(res->ctx, "use-syslog:", "no")) != 0) { diff --git a/sbin/unwind/unwind.c b/sbin/unwind/unwind.c index 8cf1ab030ee..00c600560e4 100644 --- a/sbin/unwind/unwind.c +++ b/sbin/unwind/unwind.c @@ -1,4 +1,4 @@ -/* $OpenBSD: unwind.c,v 1.56 2021/01/19 16:52:40 florian Exp $ */ +/* $OpenBSD: unwind.c,v 1.57 2021/01/27 08:30:50 florian Exp $ */ /* * Copyright (c) 2018 Florian Obser @@ -269,7 +269,8 @@ main(int argc, char *argv[]) fatal("route socket"); rtfilter = ROUTE_FILTER(RTM_IFINFO) | ROUTE_FILTER(RTM_PROPOSAL) - | ROUTE_FILTER(RTM_IFANNOUNCE); + | ROUTE_FILTER(RTM_IFANNOUNCE) | ROUTE_FILTER(RTM_NEWADDR) + | ROUTE_FILTER(RTM_DELADDR); if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_MSGFILTER, &rtfilter, sizeof(rtfilter)) == -1) fatal("setsockopt(ROUTE_MSGFILTER)"); diff --git a/sbin/unwind/unwind.h b/sbin/unwind/unwind.h index 1f007cbed0e..e1a2c052987 100644 --- a/sbin/unwind/unwind.h +++ b/sbin/unwind/unwind.h @@ -1,4 +1,4 @@ -/* $OpenBSD: unwind.h,v 1.52 2021/01/24 18:29:15 florian Exp $ */ +/* $OpenBSD: unwind.h,v 1.53 2021/01/27 08:30:50 florian Exp $ */ /* * Copyright (c) 2018 Florian Obser @@ -122,6 +122,7 @@ enum imsg_type { IMSG_NEW_DNS64_PREFIXES_START, IMSG_NEW_DNS64_PREFIX, IMSG_NEW_DNS64_PREFIXES_DONE, + IMSG_CHANGE_AFS, }; struct uw_forwarder { -- 2.20.1