bin/99534: [patch] dhclient Classless Static Routes support
Andrey V. Elsukov
bu7cher at yandex.ru
Tue Jun 27 10:00:45 UTC 2006
>Number: 99534
>Category: bin
>Synopsis: [patch] dhclient Classless Static Routes support
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: update
>Submitter-Id: current-users
>Arrival-Date: Tue Jun 27 10:00:32 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator: Andrey V. Elsukov
>Release: FreeBSD
>Organization:
>Environment:
Tested on 6.1-STABLE.
>Description:
I have implemented RFC3442 support for the FreeBSD dhclient.
I have a small bit of testing with isc-dhcpd and dnsmasqd.
It tested and works with:
1) classless routes: 10.0.0.0/21 router, 10.1.0.0/19 router;
2) default route;
3) link routes (different networks on the same interface):
192.168.0.0/24 0.0.0.0, 192.168.1.0/24 0.0.0.0
Brooks Davis has suggested filling a PR.
RFC: http://www.ietf.org/rfc/rfc3442.txt
patch: http://butcher.heavennet.ru/patches/other/dhclient/
FreeBSD Projects ideas: http://www.freebsd.org/projects/ideas/#p-rfc3442
isc-dhcpd configuration: http://www.opennet.ru/tips/info/666.shtml
>How-To-Repeat:
>Fix:
--- dhclient.diff begins here ---
Index: src/sbin/dhclient/clparse.c
===================================================================
RCS file: /ncvs/src/sbin/dhclient/clparse.c,v
retrieving revision 1.2
diff -u -r1.2 clparse.c
--- src/sbin/dhclient/clparse.c 23 Aug 2005 23:59:55 -0000 1.2
+++ src/sbin/dhclient/clparse.c 17 Jun 2006 20:48:13 -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: src/sbin/dhclient/dhclient-script
===================================================================
RCS file: /ncvs/src/sbin/dhclient/dhclient-script,v
retrieving revision 1.14
diff -u -r1.14 dhclient-script
--- src/sbin/dhclient/dhclient-script 26 Jan 2006 21:05:39 -0000 1.14
+++ src/sbin/dhclient/dhclient-script 17 Jun 2006 20:48:13 -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: src/sbin/dhclient/dhclient.c
===================================================================
RCS file: /ncvs/src/sbin/dhclient/dhclient.c,v
retrieving revision 1.15
diff -u -r1.15 dhclient.c
--- src/sbin/dhclient/dhclient.c 23 May 2006 16:57:47 -0000 1.15
+++ src/sbin/dhclient/dhclient.c 17 Jun 2006 20:48:13 -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);
@@ -2379,12 +2380,77 @@
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: src/sbin/dhclient/dhclient.conf
===================================================================
RCS file: /ncvs/src/sbin/dhclient/dhclient.conf,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 dhclient.conf
--- src/sbin/dhclient/dhclient.conf 7 Jun 2005 04:05:07 -0000 1.1.1.1
+++ src/sbin/dhclient/dhclient.conf 17 Jun 2006 20:48:13 -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: src/sbin/dhclient/dhcp.h
===================================================================
RCS file: /ncvs/src/sbin/dhclient/dhcp.h,v
retrieving revision 1.2
diff -u -r1.2 dhcp.h
--- src/sbin/dhclient/dhcp.h 30 Jun 2005 05:50:52 -0000 1.2
+++ src/sbin/dhclient/dhcp.h 17 Jun 2006 20:48:13 -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: src/sbin/dhclient/tables.c
===================================================================
RCS file: /ncvs/src/sbin/dhclient/tables.c,v
retrieving revision 1.3
diff -u -r1.3 tables.c
--- src/sbin/dhclient/tables.c 23 Aug 2005 23:59:55 -0000 1.3
+++ src/sbin/dhclient/tables.c 17 Jun 2006 20:48:13 -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,
--- dhclient.diff ends here ---
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list