Determine available address families (and monitor when this changes)
authorflorian <florian@openbsd.org>
Wed, 27 Jan 2021 08:30:50 +0000 (08:30 +0000)
committerflorian <florian@openbsd.org>
Wed, 27 Jan 2021 08:30:50 +0000 (08:30 +0000)
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
sbin/unwind/frontend.h
sbin/unwind/resolver.c
sbin/unwind/unwind.c
sbin/unwind/unwind.h

index 50dab6c..18d91df 100644 (file)
@@ -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 <florian@openbsd.org>
@@ -32,6 +32,7 @@
 
 #include <errno.h>
 #include <event.h>
+#include <ifaddrs.h>
 #include <imsg.h>
 #include <netdb.h>
 #include <pwd.h>
@@ -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));
+       }
+}
index cd6c218..29b64f5 100644 (file)
@@ -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 <florian@openbsd.org>
@@ -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;
index c1e399b..49f51d8 100644 (file)
@@ -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 <florian@openbsd.org>
@@ -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) {
index 8cf1ab0..00c6005 100644 (file)
@@ -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 <florian@openbsd.org>
@@ -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)");
index 1f007cb..e1a2c05 100644 (file)
@@ -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 <florian@openbsd.org>
@@ -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 {