Anybody encountering dhcp environments that try to server out
classless static routes, i.e. dhcp option 121? Support for
static routes (option 33) thown in for free.

Apparently Microsoft Network Access Protection may be using them.

If so, tests of the diff below would be highly appreciated.

.... Ken

Index: clparse.c
===================================================================
RCS file: /cvs/src/sbin/dhclient/clparse.c,v
retrieving revision 1.57
diff -u -p -r1.57 clparse.c
--- clparse.c   2 May 2013 16:35:27 -0000       1.57
+++ clparse.c   2 Jun 2013 15:26:57 -0000
@@ -72,6 +72,9 @@ read_client_conf(void)
            [config->requested_option_count++] = DHO_BROADCAST_ADDRESS;
        config->requested_options
            [config->requested_option_count++] = DHO_TIME_OFFSET;
+       /* RFC 3442 says CLASSLESS_STATIC_ROUTES must be before ROUTERS! */
+       config->requested_options
+           [config->requested_option_count++] = DHO_CLASSLESS_STATIC_ROUTES;
        config->requested_options
            [config->requested_option_count++] = DHO_ROUTERS;
        config->requested_options
Index: dhclient.c
===================================================================
RCS file: /cvs/src/sbin/dhclient/dhclient.c,v
retrieving revision 1.248
diff -u -p -r1.248 dhclient.c
--- dhclient.c  1 Jun 2013 16:26:07 -0000       1.248
+++ dhclient.c  2 Jun 2013 22:33:35 -0000
@@ -109,6 +109,8 @@ void                 socket_nonblockmode(int);
 void            apply_ignore_list(char *);
 
 void add_default_route(int, struct in_addr, struct in_addr);
+void add_static_routes(int, struct option_data *);
+void add_classless_static_routes(int, struct option_data *);
 
 #define        ROUNDUP(a) \
            ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
@@ -790,12 +792,21 @@ bind_lease(void)
         * is done by the RTM_NEWADDR message being received.
         */
        add_address(ifi->name, ifi->rdomain, client->new->address, mask);
-       if (options[DHO_ROUTERS].len) {
-               memset(&gateway, 0, sizeof(gateway));
-               /* XXX Only use FIRST router address for now. */
-               memcpy(&gateway.s_addr, options[DHO_ROUTERS].data,
-                   options[DHO_ROUTERS].len);
-               add_default_route(ifi->rdomain, client->new->address, gateway);
+       if (options[DHO_CLASSLESS_STATIC_ROUTES].len) {
+               add_classless_static_routes(ifi->rdomain,
+                   &options[DHO_CLASSLESS_STATIC_ROUTES]);
+       } else {
+               if (options[DHO_ROUTERS].len) {
+                       memset(&gateway, 0, sizeof(gateway));
+                       /* XXX Only use FIRST router address for now. */
+                       memcpy(&gateway.s_addr, options[DHO_ROUTERS].data,
+                           options[DHO_ROUTERS].len);
+                       add_default_route(ifi->rdomain, client->new->address,
+                           gateway);
+               }
+               if (options[DHO_STATIC_ROUTES].len)
+                       add_static_routes(ifi->rdomain,
+                           &options[DHO_STATIC_ROUTES]);
        }
 
        client->new->resolv_conf = resolv_conf_contents(
@@ -2280,27 +2291,76 @@ priv_write_file(struct imsg_write_file *
 void
 add_default_route(int rdomain, struct in_addr addr, struct in_addr gateway)
 {
-       struct imsg_add_route    imsg;
-       int                      rslt;
-
-       memset(&imsg, 0, sizeof(imsg));
+       struct in_addr netmask;
+       int addrs;
 
-       imsg.rdomain = rdomain;
-       imsg.dest = addr;
-       imsg.addrs = RTA_DST | RTA_NETMASK;
+       memset(&netmask, 0, sizeof(netmask));
+       addrs = RTA_DST | RTA_NETMASK;
 
        /*
         * Set gateway address if and only if non-zero addr supplied. A
         * gateway address of 0 implies '-iface'.
         */
-       if (bcmp(&gateway, &addr, sizeof(addr)) != 0) {
-               imsg.gateway = gateway;
-               imsg.addrs |= RTA_GATEWAY;
+       if (bcmp(&gateway, &addr, sizeof(addr)) != 0)
+               addrs |= RTA_GATEWAY;
+
+       add_route(rdomain, addr, netmask, gateway, addrs); 
+}
+
+void
+add_static_routes(int rdomain, struct option_data *static_routes)
+{
+       struct in_addr           dest, netmask, gateway;
+       u_int8_t                 *addr;
+       int                      i;
+
+       memset(&netmask, 0, sizeof(netmask));   /* Always 0 for class addrs. */
+
+       for (i = 0; (i + 7) < static_routes->len; i += 8) {
+               addr = &static_routes->data[i];
+               memset(&dest, 0, sizeof(dest));
+               memset(&gateway, 0, sizeof(gateway));
+
+               memcpy(&dest.s_addr, addr, 4);
+               if (dest.s_addr == INADDR_ANY)
+                       continue; /* RFC 2132 says 0.0.0.0 is not allowed. */
+               memcpy(&gateway.s_addr, addr+4, 4);
+
+               /* XXX Order implies priority but we're ignoring that. */
+               add_route(rdomain, dest, netmask, gateway,
+                   RTA_DST | RTA_GATEWAY);
        }
+}
+
+void add_classless_static_routes(int rdomain,
+    struct option_data *classless_static_routes)
+{
+       struct in_addr   dest, netmask, gateway;
+       int              bits, bytes, i;
 
-       rslt = imsg_compose(unpriv_ibuf, IMSG_ADD_ROUTE, 0, 0, -1, &imsg,
-          sizeof(imsg));
+       i = 0;
+       while (i < classless_static_routes->len) {
+               bits = classless_static_routes->data[i];
+               bytes = (bits + 7) / 8;
+               i++;
 
-       if (rslt == -1)
-               warning("add_route: imsg_compose: %s", strerror(errno));
+               memset(&netmask, 0, sizeof(netmask));
+               if (bits)
+                       netmask.s_addr = htonl(0xffffffff << (32 - bits)); 
+
+               memset(&dest, 0, sizeof(dest));
+               memcpy(&dest, &classless_static_routes->data[i], bytes);
+               dest.s_addr = dest.s_addr & netmask.s_addr;
+               i += bytes;
+
+               memset(&gateway, 0, sizeof(gateway));
+               memcpy(&gateway, &classless_static_routes->data[i], 4);
+               i += 4;
+
+               if (gateway.s_addr == INADDR_ANY)
+                       continue; /* OBSD TCP/IP doesn't support this. */
+
+               add_route(rdomain, dest, netmask, gateway,
+                   RTA_DST | RTA_GATEWAY | RTA_NETMASK);
+       }
 }
Index: dhcp.h
===================================================================
RCS file: /cvs/src/sbin/dhclient/dhcp.h,v
retrieving revision 1.12
diff -u -p -r1.12 dhcp.h
--- dhcp.h      2 May 2013 16:35:27 -0000       1.12
+++ dhcp.h      1 Jun 2013 18:47:21 -0000
@@ -173,6 +173,7 @@ struct dhcp_packet {
 #define DHO_NDS_SERVERS                        85
 #define DHO_NDS_TREE_NAME              86
 #define DHO_NDS_CONTEXT                        87
+#define DHO_CLASSLESS_STATIC_ROUTES    121
 #define DHO_TFTP_CONFIG_FILE           144
 #define DHO_VOIP_CONFIGURATION_SERVER  150
 #define DHO_AUTOPROXY_SCRIPT           252
Index: kroute.c
===================================================================
RCS file: /cvs/src/sbin/dhclient/kroute.c,v
retrieving revision 1.48
diff -u -p -r1.48 kroute.c
--- kroute.c    1 Jun 2013 16:26:07 -0000       1.48
+++ kroute.c    1 Jun 2013 20:10:30 -0000
@@ -229,18 +229,21 @@ priv_add_route(struct imsg_add_route *im
        iov[iovcnt].iov_base = &rtm;
        iov[iovcnt++].iov_len = sizeof(rtm);
        
-       /* Set destination address of all zeros. */
+       /* Set destination address. */
 
        memset(&dest, 0, sizeof(dest));
 
-       dest.sin_len = sizeof(dest);
-       dest.sin_family = AF_INET;
+       if (imsg->addrs & RTA_DST) {
+               dest.sin_len = sizeof(dest);
+               dest.sin_family = AF_INET;
+               dest.sin_addr.s_addr = imsg->dest.s_addr;
 
-       rtm.rtm_addrs |= RTA_DST;
-       rtm.rtm_msglen += sizeof(dest);
+               rtm.rtm_addrs |= RTA_DST;
+               rtm.rtm_msglen += sizeof(dest);
 
-       iov[iovcnt].iov_base = &dest;
-       iov[iovcnt++].iov_len = sizeof(dest);
+               iov[iovcnt].iov_base = &dest;
+               iov[iovcnt++].iov_len = sizeof(dest);
+       }
        
        /*
         * Set gateway address if and only if non-zero addr supplied. A
@@ -248,7 +251,7 @@ priv_add_route(struct imsg_add_route *im
         */
 
        memset(&gateway, 0, sizeof(gateway));
-       if ((imsg->addrs & RTA_GATEWAY) != 0) {
+       if (imsg->addrs & RTA_GATEWAY) {
                gateway.sin_len = sizeof(gateway);
                gateway.sin_family = AF_INET;
                gateway.sin_addr.s_addr = imsg->gateway.s_addr;
@@ -261,18 +264,20 @@ priv_add_route(struct imsg_add_route *im
                iov[iovcnt++].iov_len = sizeof(gateway);
        }
 
-       /* Add netmask of 0. */
+       /* Add netmask. */
        memset(&mask, 0, sizeof(mask));
 
-       mask.sin_len = sizeof(mask);
-       mask.sin_family = AF_INET;
-       mask.sin_addr.s_addr = imsg->netmask.s_addr;
+       if (imsg->addrs & RTA_NETMASK) {
+               mask.sin_len = sizeof(mask);
+               mask.sin_family = AF_INET;
+               mask.sin_addr.s_addr = imsg->netmask.s_addr;
 
-       rtm.rtm_addrs |= RTA_NETMASK;
-       rtm.rtm_msglen += sizeof(mask);
+               rtm.rtm_addrs |= RTA_NETMASK;
+               rtm.rtm_msglen += sizeof(mask);
 
-       iov[iovcnt].iov_base = &mask;
-       iov[iovcnt++].iov_len = sizeof(mask);
+               iov[iovcnt].iov_base = &mask;
+               iov[iovcnt++].iov_len = sizeof(mask);
+       }
 
        /* Add our label so we can identify the route as our creation. */
        if (create_route_label(&label) == 0) {
Index: tables.c
===================================================================
RCS file: /cvs/src/sbin/dhclient/tables.c,v
retrieving revision 1.13
diff -u -p -r1.13 tables.c
--- tables.c    2 May 2013 16:35:27 -0000       1.13
+++ tables.c    2 Jun 2013 00:37:37 -0000
@@ -182,7 +182,7 @@ const struct option dhcp_options[256] = 
        /* 118 */ { "option-118", "X" },
        /* 119 */ { "option-119", "X" },
        /* 120 */ { "option-120", "X" },
-       /* 121 */ { "option-121", "X" },
+       /* 121 */ { "classless-static-routes", "X" },
        /* 122 */ { "option-122", "X" },
        /* 123 */ { "option-123", "X" },
        /* 124 */ { "option-124", "X" },

Reply via email to