Implement classless static routes dhcp option.
authorflorian <florian@openbsd.org>
Wed, 16 Jun 2021 14:06:17 +0000 (14:06 +0000)
committerflorian <florian@openbsd.org>
Wed, 16 Jun 2021 14:06:17 +0000 (14:06 +0000)
For this we need to be able to handle multiple routes being sent from
the engine to the main process as well as to the control tool.
The configuration of the various cases (default route, directly
connected routes, non-default route via a gateway) was inspired by
dhclient's set_routes() and should behave the same way.

Tested by Uwe Werler

sbin/dhcpleased/dhcpleased.c
sbin/dhcpleased/dhcpleased.h
sbin/dhcpleased/engine.c
sbin/dhcpleased/engine.h
usr.sbin/dhcpleasectl/dhcpleasectl.c

index 4668501..ad18e13 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: dhcpleased.c,v 1.11 2021/05/01 11:52:36 florian Exp $ */
+/*     $OpenBSD: dhcpleased.c,v 1.12 2021/06/16 14:06:17 florian Exp $ */
 
 /*
  * Copyright (c) 2017, 2021 Florian Obser <florian@openbsd.org>
@@ -77,7 +77,9 @@ void   open_bpfsock(uint32_t);
 void    configure_interface(struct imsg_configure_interface *);
 void    deconfigure_interface(struct imsg_configure_interface *);
 void    propose_rdns(struct imsg_propose_rdns *);
-void    configure_gateway(struct imsg_configure_interface *, uint8_t);
+void    configure_routes(uint8_t, struct imsg_configure_interface *);
+void    configure_route(uint8_t, uint32_t, int, struct sockaddr_in *, struct
+            sockaddr_in *, struct sockaddr_in *, struct sockaddr_in *, int);
 void    read_lease_file(struct imsg_ifinfo *);
 
 static int     main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *);
@@ -486,6 +488,8 @@ main_dispatch_engine(int fd, short event, void *bula)
                                    IMSG_DATA_SIZE(imsg));
                        memcpy(&imsg_interface, imsg.data,
                            sizeof(imsg_interface));
+                       if (imsg_interface.routes_len >= MAX_DHCP_ROUTES)
+                               fatalx("%s: too many routes in imsg", __func__);
                        configure_interface(&imsg_interface);
                        break;
                }
@@ -497,6 +501,8 @@ main_dispatch_engine(int fd, short event, void *bula)
                                    IMSG_DATA_SIZE(imsg));
                        memcpy(&imsg_interface, imsg.data,
                            sizeof(imsg_interface));
+                       if (imsg_interface.routes_len >= MAX_DHCP_ROUTES)
+                               fatalx("%s: too many routes in imsg", __func__);
                        deconfigure_interface(&imsg_interface);
                        main_imsg_compose_frontend(IMSG_CLOSE_UDPSOCK, -1,
                            &imsg_interface.if_index,
@@ -683,9 +689,8 @@ configure_interface(struct imsg_configure_interface *imsg)
                if (ioctl(ioctl_sock, SIOCAIFADDR, &ifaliasreq) == -1)
                        fatal("SIOCAIFADDR");
 
-               /* XXX check weird shit in dhclient/kroute.c set_routes() */
-               if (imsg->router.s_addr != INADDR_ANY)
-                       configure_gateway(imsg, RTM_ADD);
+               if (imsg->routes_len > 0)
+                       configure_routes(RTM_ADD, imsg);
        }
        req_sin_addr->sin_port = ntohs(CLIENT_PORT);
        if ((udpsock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
@@ -773,8 +778,8 @@ deconfigure_interface(struct imsg_configure_interface *imsg)
 
        memset(&ifaliasreq, 0, sizeof(ifaliasreq));
 
-       if (imsg->router.s_addr != INADDR_ANY)
-               configure_gateway(imsg, RTM_DELETE);
+       if (imsg->routes_len > 0)
+               configure_routes(RTM_DELETE, imsg);
 
        if (if_indextoname(imsg->if_index, ifaliasreq.ifra_name) == NULL) {
                log_warnx("%s: cannot find interface %d", __func__,
@@ -795,14 +800,87 @@ deconfigure_interface(struct imsg_configure_interface *imsg)
        }
 }
 
+void
+configure_routes(uint8_t rtm_type, struct imsg_configure_interface *imsg)
+{
+       struct sockaddr_in       dst, mask, gw, ifa;
+       in_addr_t                addrnet, gwnet;
+       int                      i;
+
+       memset(&ifa, 0, sizeof(ifa));
+       ifa.sin_family = AF_INET;
+       ifa.sin_len = sizeof(ifa);
+       ifa.sin_addr.s_addr = imsg->addr.s_addr;
+
+       memset(&dst, 0, sizeof(dst));
+       dst.sin_family = AF_INET;
+       dst.sin_len = sizeof(dst);
+
+       memset(&mask, 0, sizeof(mask));
+       mask.sin_family = AF_INET;
+       mask.sin_len = sizeof(mask);
+
+       memset(&gw, 0, sizeof(gw));
+       gw.sin_family = AF_INET;
+       gw.sin_len = sizeof(gw);
+
+       addrnet = imsg->addr.s_addr & imsg->mask.s_addr;
+
+       for (i = 0; i < imsg->routes_len; i++) {
+               dst.sin_addr.s_addr = imsg->routes[i].dst.s_addr;
+               mask.sin_addr.s_addr = imsg->routes[i].mask.s_addr;
+               gw.sin_addr.s_addr = imsg->routes[i].gw.s_addr;
+
+               if (gw.sin_addr.s_addr == INADDR_ANY) {
+                       /* direct route */
+                       configure_route(rtm_type, imsg->if_index,
+                           imsg->rdomain, &dst, &mask, &ifa, NULL,
+                           RTF_CLONING);
+               } else if (mask.sin_addr.s_addr == INADDR_ANY) {
+                       /* default route */
+                       gwnet =  gw.sin_addr.s_addr & imsg->mask.s_addr;
+                       if (addrnet != gwnet) {
+                               /*
+                                * The gateway for the default route is outside
+                                * the configured prefix. Install a direct
+                                * cloning route for the gateway to make the
+                                * default route reachable.
+                                */
+                               mask.sin_addr.s_addr = 0xffffffff;
+                               configure_route(rtm_type, imsg->if_index,
+                                   imsg->rdomain, &gw, &mask, &ifa, NULL,
+                                   RTF_CLONING);
+                               mask.sin_addr.s_addr =
+                                   imsg->routes[i].mask.s_addr;
+                       }
+
+                       if (gw.sin_addr.s_addr == ifa.sin_addr.s_addr) {
+                               /* directly connected default */
+                               configure_route(rtm_type, imsg->if_index,
+                                   imsg->rdomain, &dst, &mask, &gw, NULL, 0);
+                       } else {
+                               /* default route via gateway */
+                               configure_route(rtm_type, imsg->if_index,
+                                   imsg->rdomain, &dst, &mask, &gw, &ifa,
+                                   RTF_GATEWAY);
+                       }
+               } else {
+                       /* non-default via gateway */
+                       configure_route(rtm_type, imsg->if_index, imsg->rdomain,
+                           &dst, &mask, &gw, NULL, RTF_GATEWAY);
+               }
+       }
+}
+
 #define        ROUNDUP(a)      \
     (((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a))
 void
-configure_gateway(struct imsg_configure_interface *imsg, uint8_t rtm_type)
+configure_route(uint8_t rtm_type, uint32_t if_index, int rdomain, struct
+    sockaddr_in *dst, struct sockaddr_in *mask, struct sockaddr_in *gw,
+    struct sockaddr_in *ifa, int rtm_flags)
 {
        struct rt_msghdr                 rtm;
        struct sockaddr_rtlabel          rl;
-       struct sockaddr_in               dst, gw, mask, ifa;
        struct iovec                     iov[12];
        long                             pad = 0;
        int                              iovcnt = 0, padlen;
@@ -812,70 +890,59 @@ configure_gateway(struct imsg_configure_interface *imsg, uint8_t rtm_type)
        rtm.rtm_version = RTM_VERSION;
        rtm.rtm_type = rtm_type;
        rtm.rtm_msglen = sizeof(rtm);
-       rtm.rtm_tableid = imsg->rdomain;
-       rtm.rtm_index = imsg->if_index;
+       rtm.rtm_index = if_index;
+       rtm.rtm_tableid = rdomain;
        rtm.rtm_seq = ++rtm_seq;
        rtm.rtm_priority = RTP_NONE;
-       rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_IFA |
-           RTA_LABEL;
-       rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC | RTF_MPATH;
+       rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_LABEL;
+       rtm.rtm_flags = RTF_UP | RTF_STATIC | RTF_MPATH | rtm_flags;
+
+       if (ifa)
+               rtm.rtm_addrs |= RTA_IFA;
 
        iov[iovcnt].iov_base = &rtm;
        iov[iovcnt++].iov_len = sizeof(rtm);
 
-       memset(&dst, 0, sizeof(dst));
-       dst.sin_family = AF_INET;
-       dst.sin_len = sizeof(struct sockaddr_in);
-
-       iov[iovcnt].iov_base = &dst;
-       iov[iovcnt++].iov_len = sizeof(dst);
-       rtm.rtm_msglen += sizeof(dst);
-       padlen = ROUNDUP(sizeof(dst)) - sizeof(dst);
+       iov[iovcnt].iov_base = dst;
+       iov[iovcnt++].iov_len = dst->sin_len;
+       rtm.rtm_msglen += dst->sin_len;
+       padlen = ROUNDUP(dst->sin_len) - dst->sin_len;
        if (padlen > 0) {
                iov[iovcnt].iov_base = &pad;
                iov[iovcnt++].iov_len = padlen;
                rtm.rtm_msglen += padlen;
        }
 
-       memset(&gw, 0, sizeof(gw));
-       memcpy(&gw.sin_addr, &imsg->router, sizeof(gw.sin_addr));
-       gw.sin_family = AF_INET;
-       gw.sin_len = sizeof(struct sockaddr_in);
-       iov[iovcnt].iov_base = &gw;
-       iov[iovcnt++].iov_len = sizeof(gw);
-       rtm.rtm_msglen += sizeof(gw);
-       padlen = ROUNDUP(sizeof(gw)) - sizeof(gw);
+       iov[iovcnt].iov_base = gw;
+       iov[iovcnt++].iov_len = gw->sin_len;
+       rtm.rtm_msglen += gw->sin_len;
+       padlen = ROUNDUP(gw->sin_len) - gw->sin_len;
        if (padlen > 0) {
                iov[iovcnt].iov_base = &pad;
                iov[iovcnt++].iov_len = padlen;
                rtm.rtm_msglen += padlen;
        }
 
-       memset(&mask, 0, sizeof(mask));
-       mask.sin_family = AF_INET;
-       mask.sin_len = sizeof(struct sockaddr_in);
-       iov[iovcnt].iov_base = &mask;
-       iov[iovcnt++].iov_len = sizeof(mask);
-       rtm.rtm_msglen += sizeof(mask);
-       padlen = ROUNDUP(sizeof(mask)) - sizeof(mask);
+       iov[iovcnt].iov_base = mask;
+       iov[iovcnt++].iov_len = mask->sin_len;
+       rtm.rtm_msglen += mask->sin_len;
+       padlen = ROUNDUP(mask->sin_len) - mask->sin_len;
        if (padlen > 0) {
                iov[iovcnt].iov_base = &pad;
                iov[iovcnt++].iov_len = padlen;
                rtm.rtm_msglen += padlen;
        }
 
-       memset(&ifa, 0, sizeof(ifa));
-       memcpy(&ifa.sin_addr, &imsg->addr, sizeof(ifa.sin_addr));
-       ifa.sin_family = AF_INET;
-       ifa.sin_len = sizeof(struct sockaddr_in);
-       iov[iovcnt].iov_base = &ifa;
-       iov[iovcnt++].iov_len = sizeof(ifa);
-       rtm.rtm_msglen += sizeof(ifa);
-       padlen = ROUNDUP(sizeof(ifa)) - sizeof(ifa);
-       if (padlen > 0) {
-               iov[iovcnt].iov_base = &pad;
-               iov[iovcnt++].iov_len = padlen;
-               rtm.rtm_msglen += padlen;
+       if (ifa) {
+               iov[iovcnt].iov_base = ifa;
+               iov[iovcnt++].iov_len = ifa->sin_len;
+               rtm.rtm_msglen += ifa->sin_len;
+               padlen = ROUNDUP(ifa->sin_len) - ifa->sin_len;
+               if (padlen > 0) {
+                       iov[iovcnt].iov_base = &pad;
+                       iov[iovcnt++].iov_len = padlen;
+                       rtm.rtm_msglen += padlen;
+               }
        }
 
        memset(&rl, 0, sizeof(rl));
index d4aa71c..bf23ba7 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: dhcpleased.h,v 1.4 2021/04/10 17:22:34 florian Exp $  */
+/*     $OpenBSD: dhcpleased.h,v 1.5 2021/06/16 14:06:17 florian Exp $  */
 
 /*
  * Copyright (c) 2017, 2021 Florian Obser <florian@openbsd.org>
@@ -30,6 +30,9 @@
 #define        DHCPLEASED_MAX_DNSSL    1025
 #define        MAX_RDNS_COUNT          8 /* max nameserver in a RTM_PROPOSAL */
 
+/* A 1500 bytes packet can hold less than 300 classless static routes */
+#define        MAX_DHCP_ROUTES         256
+
 #define        DHCP_COOKIE             {99, 130, 83, 99}
 
 /* Possible values for hardware type (htype) field. */
@@ -168,6 +171,12 @@ struct imsgev {
        short            events;
 };
 
+struct dhcp_route {
+       struct in_addr           dst;
+       struct in_addr           mask;
+       struct in_addr           gw;
+};
+
 enum imsg_type {
        IMSG_NONE,
 #ifndef        SMALL
@@ -207,7 +216,8 @@ struct ctl_engine_info {
        struct in_addr          dhcp_server; /* for unicast */
        struct in_addr          requested_ip;
        struct in_addr          mask;
-       struct in_addr          router;
+       struct dhcp_route       routes[MAX_DHCP_ROUTES];
+       int                     routes_len;
        struct in_addr          nameservers[MAX_RDNS_COUNT];
        uint32_t                lease_time;
        uint32_t                renewal_time;
index badd7c7..be25cf2 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: engine.c,v 1.14 2021/05/01 11:51:59 florian Exp $     */
+/*     $OpenBSD: engine.c,v 1.15 2021/06/16 14:06:17 florian Exp $     */
 
 /*
  * Copyright (c) 2017, 2021 Florian Obser <florian@openbsd.org>
@@ -101,7 +101,8 @@ struct dhcpleased_iface {
        struct in_addr                   dhcp_server; /* for unicast */
        struct in_addr                   requested_ip;
        struct in_addr                   mask;
-       struct in_addr                   router;
+       struct dhcp_route                routes[MAX_DHCP_ROUTES];
+       int                              routes_len;
        struct in_addr                   nameservers[MAX_RDNS_COUNT];
        uint32_t                         lease_time;
        uint32_t                         renewal_time;
@@ -467,7 +468,8 @@ send_interface_info(struct dhcpleased_iface *iface, pid_t pid)
        cei.dhcp_server.s_addr = iface->dhcp_server.s_addr;
        cei.requested_ip.s_addr = iface->requested_ip.s_addr;
        cei.mask.s_addr = iface->mask.s_addr;
-       cei.router.s_addr = iface->router.s_addr;
+       cei.routes_len = iface->routes_len;
+       memcpy(cei.routes, iface->routes, sizeof(cei.routes));
        memcpy(cei.nameservers, iface->nameservers, sizeof(cei.nameservers));
        cei.lease_time = iface->lease_time;
        cei.renewal_time = iface->renewal_time;
@@ -599,13 +601,15 @@ parse_dhcp(struct dhcpleased_iface *iface, struct imsg_dhcp *dhcp)
        struct ip               *ip;
        struct udphdr           *udp;
        struct dhcp_hdr         *dhcp_hdr;
-       struct in_addr           server_identifier, subnet_mask, router;
+       struct in_addr           server_identifier, subnet_mask;
        struct in_addr           nameservers[MAX_RDNS_COUNT];
+       struct dhcp_route        routes[MAX_DHCP_ROUTES];
        size_t                   rem, i;
        uint32_t                 sum, usum, lease_time = 0, renewal_time = 0;
        uint32_t                 rebinding_time = 0;
        uint8_t                 *p, dho = DHO_PAD, dho_len;
        uint8_t                  dhcp_message_type = 0;
+       int                      routes_len = 0;
        char                     from[sizeof("xx:xx:xx:xx:xx:xx")];
        char                     to[sizeof("xx:xx:xx:xx:xx:xx")];
        char                     hbuf_src[INET_ADDRSTRLEN];
@@ -744,7 +748,7 @@ parse_dhcp(struct dhcpleased_iface *iface, struct imsg_dhcp *dhcp)
 
        memset(&server_identifier, 0, sizeof(server_identifier));
        memset(&subnet_mask, 0, sizeof(subnet_mask));
-       memset(&router, 0, sizeof(router));
+       memset(&routes, 0, sizeof(routes));
        memset(&nameservers, 0, sizeof(nameservers));
 
        while (rem > 0 && dho != DHO_END) {
@@ -822,19 +826,30 @@ parse_dhcp(struct dhcpleased_iface *iface, struct imsg_dhcp *dhcp)
                        rem -= dho_len;
                        break;
                case DHO_ROUTERS:
-                       if (dho_len < sizeof(router))
+                       if (dho_len < sizeof(routes[routes_len].gw))
                                goto wrong_length;
-                       if (dho_len % sizeof(router) != 0)
+                       if (dho_len % sizeof(routes[routes_len].gw) != 0)
                                goto wrong_length;
-                       /* we only use one router */
-                       memcpy(&router, p, sizeof(router));
-                       if (log_getverbose() > 1) {
-                               log_debug("DHO_ROUTER: %s (1/%lu)",
-                                   inet_ntop(AF_INET, &router, hbuf,
-                                   sizeof(hbuf)), dho_len / sizeof(router));
+
+                       while (routes_len < MAX_DHCP_ROUTES && dho_len > 0) {
+                               memcpy(&routes[routes_len].gw, p,
+                                   sizeof(routes[routes_len].gw));
+                               if (log_getverbose() > 1) {
+                                       log_debug("DHO_ROUTER: %s",
+                                           inet_ntop(AF_INET,
+                                           &routes[routes_len].gw, hbuf,
+                                           sizeof(hbuf)));
+                               }
+                               p += sizeof(routes[routes_len].gw);
+                               rem -= sizeof(routes[routes_len].gw);
+                               dho_len -= sizeof(routes[routes_len].gw);
+                               routes_len++;
+                       }
+                       if (dho_len != 0) {
+                               /* ignore > MAX_DHCP_ROUTES routes */
+                               p += dho_len;
+                               rem -= dho_len;
                        }
-                       p += dho_len;
-                       rem -= dho_len;
                        break;
                case DHO_DOMAIN_NAME_SERVERS:
                        if (dho_len < sizeof(nameservers[0]))
@@ -908,6 +923,58 @@ parse_dhcp(struct dhcpleased_iface *iface, struct imsg_dhcp *dhcp)
                        p += dho_len;
                        rem -= dho_len;
                        break;
+               case DHO_CLASSLESS_STATIC_ROUTES: {
+                       int     prefixlen, compressed_prefixlen;
+
+                       while (routes_len < MAX_DHCP_ROUTES && dho_len > 0) {
+                               prefixlen = *p;
+                               p += 1;
+                               rem -= 1;
+                               dho_len -= 1;
+
+                               if (prefixlen < 0 || prefixlen > 32) {
+                                       log_warnx("%s: invalid prefixlen: %d",
+                                           __func__, prefixlen);
+                                       return;
+                               }
+
+                               if (prefixlen > 0)
+                                       routes[routes_len].mask.s_addr =
+                                           htonl(0xffffffff << (32 -
+                                               prefixlen));
+                               else
+                                       routes[routes_len].mask.s_addr =
+                                           INADDR_ANY;
+
+                               compressed_prefixlen = (prefixlen + 7) / 8;
+                               if (dho_len < compressed_prefixlen)
+                                       goto wrong_length;
+
+                               memcpy(&routes[routes_len].dst, p,
+                                   compressed_prefixlen);
+                               p += compressed_prefixlen;
+                               rem -= compressed_prefixlen;
+                               dho_len -= compressed_prefixlen;
+
+                               if (dho_len < sizeof(routes[routes_len].gw))
+                                       goto wrong_length;
+
+                               memcpy(&routes[routes_len].gw, p,
+                                   sizeof(routes[routes_len].gw));
+                               p += sizeof(routes[routes_len].gw);
+                               rem -= sizeof(routes[routes_len].gw);
+                               dho_len -= sizeof(routes[routes_len].gw);
+
+                               routes_len++;
+                       }
+
+                       if (dho_len != 0) {
+                               /* ignore > MAX_DHCP_ROUTES routes */
+                               p += dho_len;
+                               rem -= dho_len;
+                       }
+                       break;
+               }
                default:
                        if (log_getverbose() > 1)
                                log_debug("DHO_%u, len: %u", dho, dho_len);
@@ -997,7 +1064,8 @@ parse_dhcp(struct dhcpleased_iface *iface, struct imsg_dhcp *dhcp)
                iface->server_identifier.s_addr = server_identifier.s_addr;
                iface->requested_ip.s_addr = dhcp_hdr->yiaddr.s_addr;
                iface->mask.s_addr = subnet_mask.s_addr;
-               iface->router.s_addr = router.s_addr;
+               iface->routes_len = routes_len;
+               memcpy(iface->routes, routes, sizeof(iface->routes));
                iface->lease_time = lease_time;
                iface->renewal_time = renewal_time;
                iface->rebinding_time = rebinding_time;
@@ -1262,7 +1330,8 @@ send_configure_interface(struct dhcpleased_iface *iface)
        imsg.rdomain = iface->rdomain;
        imsg.addr.s_addr = iface->requested_ip.s_addr;
        imsg.mask.s_addr = iface->mask.s_addr;
-       imsg.router.s_addr = iface->router.s_addr;
+       imsg.routes_len = iface->routes_len;
+       memcpy(imsg.routes, iface->routes, sizeof(imsg.routes));
        engine_imsg_compose_main(IMSG_CONFIGURE_INTERFACE, 0, &imsg,
            sizeof(imsg));
 }
@@ -1281,7 +1350,8 @@ send_deconfigure_interface(struct dhcpleased_iface *iface)
        imsg.rdomain = iface->rdomain;
        imsg.addr.s_addr = iface->requested_ip.s_addr;
        imsg.mask.s_addr = iface->mask.s_addr;
-       imsg.router.s_addr = iface->router.s_addr;
+       imsg.routes_len = iface->routes_len;
+       memcpy(imsg.routes, iface->routes, sizeof(imsg.routes));
        engine_imsg_compose_main(IMSG_DECONFIGURE_INTERFACE, 0, &imsg,
            sizeof(imsg));
 
@@ -1289,7 +1359,8 @@ send_deconfigure_interface(struct dhcpleased_iface *iface)
        iface->dhcp_server.s_addr = INADDR_ANY;
        iface->requested_ip.s_addr = INADDR_ANY;
        iface->mask.s_addr = INADDR_ANY;
-       iface->router.s_addr = INADDR_ANY;
+       iface->routes_len = 0;
+       memset(iface->routes, 0, sizeof(iface->routes));
 }
 
 void
index 317825f..c6aded1 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: engine.h,v 1.1 2021/02/26 16:16:37 florian Exp $      */
+/*     $OpenBSD: engine.h,v 1.2 2021/06/16 14:06:17 florian Exp $      */
 
 /*
  * Copyright (c) 2021 Florian Obser <florian@openbsd.org>
 
 struct imsg_configure_interface {
        uint32_t                 if_index;
+       int                      rdomain;
        struct in_addr           addr;
        struct in_addr           mask;
-       struct in_addr           router;
-       int                      rdomain;
-
+       struct dhcp_route        routes[MAX_DHCP_ROUTES];
+       int                      routes_len;
 };
 
 void            engine(int, int);
index 5e4cc52..6e39719 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: dhcpleasectl.c,v 1.3 2021/03/23 17:46:20 florian Exp $        */
+/*     $OpenBSD: dhcpleasectl.c,v 1.4 2021/06/16 14:06:18 florian Exp $        */
 
 /*
  * Copyright (c) 2021 Florian Obser <florian@openbsd.org>
@@ -181,7 +181,7 @@ show_interface_msg(struct imsg *imsg)
        char                     buf[IF_NAMESIZE], *bufp;
        char                     ipbuf[INET_ADDRSTRLEN];
        char                     maskbuf[INET_ADDRSTRLEN];
-       char                     routerbuf[INET_ADDRSTRLEN];
+       char                     gwbuf[INET_ADDRSTRLEN];
 
        switch (imsg->hdr.type) {
        case IMSG_CTL_SHOW_INTERFACE_INFO:
@@ -210,19 +210,28 @@ show_interface_msg(struct imsg *imsg)
                        timespecsub(&now, &cei->request_time, &diff);
                        memset(ipbuf, 0, sizeof(ipbuf));
                        memset(maskbuf, 0, sizeof(maskbuf));
-                       memset(routerbuf, 0, sizeof(routerbuf));
+                       memset(gwbuf, 0, sizeof(gwbuf));
                        if (inet_ntop(AF_INET, &cei->requested_ip, ipbuf,
                            sizeof(ipbuf)) == NULL)
                                ipbuf[0] = '\0';
                        if (inet_ntop(AF_INET, &cei->mask, maskbuf,
                            sizeof(maskbuf)) == NULL)
                                maskbuf[0] = '\0';
-                       if (inet_ntop(AF_INET, &cei->router, routerbuf,
-                           sizeof(routerbuf)) == NULL)
-                               routerbuf[0] = '\0';
                        printf("\t    IP: %s/%s\n", ipbuf, maskbuf);
-                       if (cei->router.s_addr != INADDR_ANY)
-                               printf("\trouter: %s\n", routerbuf);
+                       for (i = 0; i < cei->routes_len; i++) {
+                               if (inet_ntop(AF_INET, &cei->routes[i].dst,
+                                   ipbuf, sizeof(ipbuf)) == NULL)
+                                       ipbuf[0] = '\0';
+                               if (inet_ntop(AF_INET, &cei->routes[i].mask,
+                                   maskbuf, sizeof(maskbuf)) == NULL)
+                                       maskbuf[0] = '\0';
+                               if (inet_ntop(AF_INET, &cei->routes[i].gw,
+                                   gwbuf, sizeof(gwbuf)) == NULL)
+                                       gwbuf[0] = '\0';
+
+                               printf("\t%s\t%s/%s - %s\n", i == 0 ? "routes:"
+                                   : "", ipbuf, maskbuf, gwbuf);
+                       }
                        if (cei->nameservers[0].s_addr != INADDR_ANY) {
                                printf("\t   DNS:");
                                for (i = 0; i < MAX_RDNS_COUNT &&