I hear there are circuses out there where the dhcp server hands us a /32
and so the default gateway is not reachable.

The comment in sbin/dhclient/kroute.c suggests that the Google Clown
Platform operates in this way. I seem to recall mumblings that Hetzner
does something similar on their VPS.

Currently dhcpleased(8) will not work in such setups, I think this diff
fixes it. Could someone tests this please in the real world?

(This is currently two diffs in one, a bunch of deck chair shuffling and
fixing the actual problem. I'll work on classes static routes option
next to see if the deck chairs have been shuffled sufficiently. Not
asking for OKs just yet.)

diff --git dhcpleased.c dhcpleased.c
index 46685012402..14bd26eb01b 100644
--- dhcpleased.c
+++ dhcpleased.c
@@ -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 *);
@@ -683,9 +685,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);
+                       configure_routes(RTM_ADD, imsg);
        }
        req_sin_addr->sin_port = ntohs(CLIENT_PORT);
        if ((udpsock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
@@ -774,7 +775,7 @@ deconfigure_interface(struct imsg_configure_interface *imsg)
        memset(&ifaliasreq, 0, sizeof(ifaliasreq));
 
        if (imsg->router.s_addr != INADDR_ANY)
-               configure_gateway(imsg, RTM_DELETE);
+               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 +796,66 @@ deconfigure_interface(struct imsg_configure_interface 
*imsg)
        }
 }
 
+/* XXX check weird shit in dhclient/kroute.c set_routes() */
+void
+configure_routes(uint8_t rtm_type, struct imsg_configure_interface *imsg)
+{
+       struct sockaddr_in       dst, gw, mask, ifa;
+       in_addr_t                addrnet, gwnet;
+
+       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);
+
+       addrnet = imsg->addr.s_addr & imsg->mask.s_addr;
+       gwnet =  imsg->router.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.
+               */
+               memset(&dst, 0, sizeof(dst));
+               memcpy(&dst.sin_addr, &imsg->router, sizeof(gw.sin_addr));
+               dst.sin_family = AF_INET;
+               dst.sin_len = sizeof(struct sockaddr_in);
+
+               memset(&mask, 0, sizeof(mask));
+               mask.sin_family = AF_INET;
+               mask.sin_addr.s_addr = 0xffffffff;
+               mask.sin_len = sizeof(struct sockaddr_in);
+
+               configure_route(rtm_type, imsg->if_index, imsg->rdomain, &dst,
+                   &ifa, &mask, &ifa, RTF_CLONING);
+       }
+
+       memset(&dst, 0, sizeof(dst));
+       dst.sin_family = AF_INET;
+       dst.sin_len = sizeof(struct sockaddr_in);
+
+       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);
+
+       memset(&mask, 0, sizeof(mask));
+       mask.sin_family = AF_INET;
+       mask.sin_len = sizeof(struct sockaddr_in);
+
+       configure_route(rtm_type, imsg->if_index, imsg->rdomain, &dst, &gw,
+           &mask, &ifa, 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 *gw, struct sockaddr_in *mask, 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,66 +865,51 @@ 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_flags = RTF_UP | RTF_STATIC | RTF_MPATH | rtm_flags;
 
        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);
+       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;

-- 
I'm not entirely sure you are real.

Reply via email to