Implement RFC3442, the Classless Static Route option.
The original DHCP specification includes a route option but it supports only class-based routes. RFC3442 adds support for specifying the netmask width for each static route. A variable length encoding is used to minimize the size of this option. PR: bin/99534 Submitted by: Andrey V. Elsukov <bu7cher@yandex.ru> Reviewed by: brooks
This commit is contained in:
parent
d60226bd43
commit
2fcc737008
@ -89,6 +89,8 @@ read_client_conf(void)
|
||||
[top_level_config.requested_option_count++] = DHO_BROADCAST_ADDRESS;
|
||||
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
|
||||
|
@ -86,8 +86,43 @@ add_new_alias() {
|
||||
fi
|
||||
}
|
||||
|
||||
fill_classless_routes() {
|
||||
set $1
|
||||
while [ $# -gt 5 ]; do
|
||||
if [ $1 -eq 0 ]; then
|
||||
route="default"
|
||||
elif [ $1 -le 8 ]; then
|
||||
route="$2.0.0.0/$1"
|
||||
shift
|
||||
elif [ $1 -le 16 ]; then
|
||||
route="$2.$3.0.0/$1"
|
||||
shift; shift
|
||||
elif [ $1 -le 24 ]; 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 @@ delete_old_routes() {
|
||||
|
||||
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
|
||||
|
@ -115,6 +115,7 @@ struct sockaddr *get_ifa(char *, int);
|
||||
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 @@ check_option(struct client_lease *l, int option)
|
||||
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)
|
||||
{
|
||||
|
@ -5,8 +5,9 @@ send dhcp-client-identifier 1:0:a0:24:ab:fb:9c;
|
||||
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;
|
||||
|
@ -162,6 +162,7 @@ struct dhcp_packet {
|
||||
#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. */
|
||||
|
@ -186,7 +186,7 @@ struct option dhcp_options[256] = {
|
||||
{ "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 @@ unsigned char dhcp_option_default_priority_list[] = {
|
||||
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 @@ unsigned char dhcp_option_default_priority_list[] = {
|
||||
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,
|
||||
|
Loading…
Reference in New Issue
Block a user