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" },