Index: clparse.c =================================================================== RCS file: /usr/cvs/src/sbin/dhclient/clparse.c,v retrieving revision 1.2 diff -u -r1.2 clparse.c --- clparse.c 23 Aug 2005 23:59:55 -0000 1.2 +++ clparse.c 19 Jun 2006 23:33:57 -0000 @@ -90,6 +90,8 @@ top_level_config.requested_options [top_level_config.requested_option_count++] = DHO_TIME_OFFSET; top_level_config.requested_options + [top_level_config.requested_option_count++] = DHO_CLASSLESS_ROUTES; + top_level_config.requested_options [top_level_config.requested_option_count++] = DHO_ROUTERS; top_level_config.requested_options [top_level_config.requested_option_count++] = DHO_DOMAIN_NAME; Index: dhclient-script =================================================================== RCS file: /usr/cvs/src/sbin/dhclient/dhclient-script,v retrieving revision 1.14 diff -u -r1.14 dhclient-script --- dhclient-script 26 Jan 2006 21:05:39 -0000 1.14 +++ dhclient-script 29 Jun 2006 15:29:11 -0000 @@ -86,8 +86,43 @@ fi } +fill_classless_routes() { + set $1 + while [ $# -gt 5 ]; do + if [ $1 -eq 0 ]; then + route="default" + elif [ $1 -lt 9 ]; then + route="$2.0.0.0/$1" + shift + elif [ $1 -lt 17 ]; then + route="$2.$3.0.0/$1" + shift; shift + elif [ $1 -lt 25 ]; then + route="$2.$3.$4.0/$1" + shift; shift; shift + else + route="$2.$3.$4.$5/$1" + shift; shift; shift; shift + fi + shift + router="$1.$2.$3.$4" + classless_routes="$classless_routes $route $router" + shift; shift; shift; shift + done +} + delete_old_routes() { #route delete "$old_ip_address" $LOCALHOST >/dev/null 2>&1 + if [ -n "$old_classless_routes" ]; then + fill_classless_routes "$old_classless_routes" + set $classless_routes + while [ $# -gt 1 ]; do + route delete "$1" "$2" + shift; shift + done + return 0; + fi + for router in $old_routers; do if [ $if_defaultroute = x -o $if_defaultroute = $interface ]; then route delete default $route >/dev/null 2>&1 @@ -107,6 +142,31 @@ add_new_routes() { #route add $new_ip_address $LOCALHOST >/dev/null 2>&1 + + # RFC 3442: If the DHCP server returns both a Classless Static + # Routes option and a Router option, the DHCP client MUST ignore + # the Router option. + # + # DHCP clients that support this option (Classless Static Routes) + # MUST NOT install the routes specified in the Static Routes + # option (option code 33) if both a Static Routes option and the + # Classless Static Routes option are provided. + + if [ -n "$new_classless_routes" ]; then + fill_classless_routes "$new_classless_routes" + $LOGGER "New Classless Static Routes ($interface): $classless_routes" + set $classless_routes + while [ $# -gt 1 ]; do + if [ "0.0.0.0" = "$2" ]; then + route add "$1" -iface "$interface" + else + route add "$1" "$2" + fi + shift; shift + done + return + fi + for router in $new_routers; do if [ "$new_ip_address" = "$router" ]; then route add default -iface $router >/dev/null 2>&1 Index: dhclient.c =================================================================== RCS file: /usr/cvs/src/sbin/dhclient/dhclient.c,v retrieving revision 1.20 diff -u -r1.20 dhclient.c --- dhclient.c 29 Jan 2007 15:55:13 -0000 1.20 +++ dhclient.c 4 Feb 2007 00:29:51 -0000 @@ -115,6 +115,7 @@ void routehandler(struct protocol *); void usage(void); int check_option(struct client_lease *l, int option); +int check_classless_option(unsigned char *data, int len); int ipv4addrs(char * buf); int res_hnok(const char *dn); int check_search(const char *srch); @@ -2374,12 +2375,79 @@ case DHO_DHCP_USER_CLASS_ID: case DHO_END: return (1); + case DHO_CLASSLESS_ROUTES: + return (check_classless_option(l->options[option].data, + l->options[option].len)); default: warning("unknown dhcp option value 0x%x", option); return (unknown_ok); } } +/* RFC 3442 The Classless Static Routes option checks */ +int +check_classless_option(unsigned char *data, int len) +{ + int i = 0; + unsigned char width; + in_addr_t addr, mask; + + if (len < 5) { + warning("Too small length: %d", len); + return (0); + } + while(i < len) { + width = data[i++]; + if (width == 0) { + i += 4; + continue; + } else if (width < 9) { + addr = (in_addr_t)(data[i] << 24); + i += 1; + } else if (width < 17) { + addr = (in_addr_t)(data[i] << 24) + + (in_addr_t)(data[i + 1] << 16); + i += 2; + } else if (width < 25) { + addr = (in_addr_t)(data[i] << 24) + + (in_addr_t)(data[i + 1] << 16) + + (in_addr_t)(data[i + 2] << 8); + i += 3; + } else if (width < 33) { + addr = (in_addr_t)(data[i] << 24) + + (in_addr_t)(data[i + 1] << 16) + + (in_addr_t)(data[i + 2] << 8) + + data[i + 3]; + i += 4; + } else { + warning("Incorrect subnet width: %d", width); + return (0); + } + mask = (in_addr_t)(~0) << (32 - width); + addr = ntohl(addr); + mask = ntohl(mask); + + /* + * From RFC 3442: + * ... After deriving a subnet number and subnet mask + * from each destination descriptor, the DHCP client + * MUST zero any bits in the subnet number where the + * corresponding bit in the mask is zero... + */ + if ((addr & mask) != addr) { + addr &= mask; + data[i - 1] = (unsigned char)( + (addr >> (((32 - width)/8)*8)) & 0xFF); + } + i += 4; + } + if (i > len) { + warning("Incorrect data length: %d (must be %d)", len, i); + return (0); + } + return (1); +} + int res_hnok(const char *dn) { Index: dhclient.conf =================================================================== RCS file: /usr/cvs/src/sbin/dhclient/dhclient.conf,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 dhclient.conf --- dhclient.conf 7 Jun 2005 04:05:07 -0000 1.1.1.1 +++ dhclient.conf 19 Jun 2006 23:33:57 -0000 @@ -3,8 +3,9 @@ send dhcp-lease-time 3600; supersede domain-name "fugue.com home.vix.com"; prepend domain-name-servers 127.0.0.1; -request subnet-mask, broadcast-address, time-offset, routers, - domain-name, domain-name-servers, host-name; +request subnet-mask, broadcast-address, time-offset, + classless-routes, routers, domain-name, + domain-name-servers, host-name; require subnet-mask, domain-name-servers; timeout 60; retry 60; Index: dhcp.h =================================================================== RCS file: /usr/cvs/src/sbin/dhclient/dhcp.h,v retrieving revision 1.2 diff -u -r1.2 dhcp.h --- dhcp.h 30 Jun 2005 05:50:52 -0000 1.2 +++ dhcp.h 19 Jun 2006 23:33:57 -0000 @@ -162,6 +162,7 @@ #define DHO_FINGER_SERVER 73 #define DHO_IRC_SERVER 74 #define DHO_DHCP_USER_CLASS_ID 77 +#define DHO_CLASSLESS_ROUTES 121 #define DHO_END 255 /* DHCP message types. */ Index: tables.c =================================================================== RCS file: /usr/cvs/src/sbin/dhclient/tables.c,v retrieving revision 1.3 diff -u -r1.3 tables.c --- tables.c 23 Aug 2005 23:59:55 -0000 1.3 +++ tables.c 19 Jun 2006 23:35:58 -0000 @@ -186,7 +186,7 @@ { "option-118", "X", &dhcp_universe, 118 }, { "option-119", "X", &dhcp_universe, 119 }, { "option-120", "X", &dhcp_universe, 120 }, - { "option-121", "X", &dhcp_universe, 121 }, + { "classless-routes", "BA", &dhcp_universe, 121 }, { "option-122", "X", &dhcp_universe, 122 }, { "option-123", "X", &dhcp_universe, 123 }, { "option-124", "X", &dhcp_universe, 124 }, @@ -337,6 +337,7 @@ DHO_DHCP_CLIENT_IDENTIFIER, DHO_SUBNET_MASK, DHO_TIME_OFFSET, + DHO_CLASSLESS_ROUTES, DHO_ROUTERS, DHO_TIME_SERVERS, DHO_NAME_SERVERS, @@ -392,7 +393,7 @@ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, - 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 119, 120, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166,