You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
405 lines
14 KiB
405 lines
14 KiB
diff -up dhcp-4.2.5b1/client/clparse.c.rfc3442 dhcp-4.2.5b1/client/clparse.c |
|
--- dhcp-4.2.5b1/client/clparse.c.rfc3442 2012-12-17 13:23:34.387564654 +0100 |
|
+++ dhcp-4.2.5b1/client/clparse.c 2012-12-17 13:23:34.437563996 +0100 |
|
@@ -37,7 +37,7 @@ |
|
|
|
struct client_config top_level_config; |
|
|
|
-#define NUM_DEFAULT_REQUESTED_OPTS 14 |
|
+#define NUM_DEFAULT_REQUESTED_OPTS 15 |
|
struct option *default_requested_options[NUM_DEFAULT_REQUESTED_OPTS + 1]; |
|
|
|
static void parse_client_default_duid(struct parse *cfile); |
|
@@ -90,7 +90,11 @@ isc_result_t read_client_conf () |
|
dhcp_universe.code_hash, &code, 0, MDL); |
|
|
|
/* 4 */ |
|
- code = DHO_ROUTERS; |
|
+ /* The Classless Static Routes option code MUST appear in the parameter |
|
+ * request list prior to both the Router option code and the Static |
|
+ * Routes option code, if present. (RFC3442) |
|
+ */ |
|
+ code = DHO_CLASSLESS_STATIC_ROUTES; |
|
option_code_hash_lookup(&default_requested_options[3], |
|
dhcp_universe.code_hash, &code, 0, MDL); |
|
|
|
@@ -144,6 +148,11 @@ isc_result_t read_client_conf () |
|
option_code_hash_lookup(&default_requested_options[13], |
|
dhcp_universe.code_hash, &code, 0, MDL); |
|
|
|
+ /* 15 */ |
|
+ code = DHO_ROUTERS; |
|
+ option_code_hash_lookup(&default_requested_options[14], |
|
+ dhcp_universe.code_hash, &code, 0, MDL); |
|
+ |
|
for (code = 0 ; code < NUM_DEFAULT_REQUESTED_OPTS ; code++) { |
|
if (default_requested_options[code] == NULL) |
|
log_fatal("Unable to find option definition for " |
|
diff -up dhcp-4.2.5b1/common/dhcp-options.5.rfc3442 dhcp-4.2.5b1/common/dhcp-options.5 |
|
--- dhcp-4.2.5b1/common/dhcp-options.5.rfc3442 2012-12-17 13:23:34.376564797 +0100 |
|
+++ dhcp-4.2.5b1/common/dhcp-options.5 2012-12-17 13:25:18.435141385 +0100 |
|
@@ -116,6 +116,26 @@ hexadecimal, separated by colons. For e |
|
or |
|
option dhcp-client-identifier 43:4c:49:45:54:2d:46:4f:4f; |
|
.fi |
|
+.PP |
|
+The |
|
+.B destination-descriptor |
|
+describe the IP subnet number and subnet mask |
|
+of a particular destination using a compact encoding. This encoding |
|
+consists of one octet describing the width of the subnet mask, |
|
+followed by all the significant octets of the subnet number. |
|
+The following table contains some examples of how various subnet |
|
+number/mask combinations can be encoded: |
|
+.nf |
|
+.sp 1 |
|
+Subnet number Subnet mask Destination descriptor |
|
+0 0 0 |
|
+10.0.0.0 255.0.0.0 8.10 |
|
+10.0.0.0 255.255.255.0 24.10.0.0 |
|
+10.17.0.0 255.255.0.0 16.10.17 |
|
+10.27.129.0 255.255.255.0 24.10.27.129 |
|
+10.229.0.128 255.255.255.128 25.10.229.0.128 |
|
+10.198.122.47 255.255.255.255 32.10.198.122.47 |
|
+.fi |
|
.SH SETTING OPTION VALUES USING EXPRESSIONS |
|
Sometimes it's helpful to be able to set the value of a DHCP option |
|
based on some value that the client has sent. To do this, you can |
|
@@ -932,6 +952,29 @@ dhclient-script will create routes: |
|
.RE |
|
.PP |
|
.nf |
|
+.B option \fBclassless-static-routes\fR \fIdestination-descriptor ip-address\fR |
|
+ [\fB,\fR \fIdestination-descriptor ip-address\fR...]\fB;\fR |
|
+.fi |
|
+.RS 0.25i |
|
+.PP |
|
+This option (see RFC3442) specifies a list of classless static routes |
|
+that the client should install in its routing cache. |
|
+.PP |
|
+This option can contain one or more static routes, each of which |
|
+consists of a destination descriptor and the IP address of the router |
|
+that should be used to reach that destination. |
|
+.PP |
|
+Many clients may not implement the Classless Static Routes option. |
|
+DHCP server administrators should therefore configure their DHCP |
|
+servers to send both a Router option and a Classless Static Routes |
|
+option, and should specify the default router(s) both in the Router |
|
+option and in the Classless Static Routes option. |
|
+.PP |
|
+If the DHCP server returns both a Classless Static Routes option and |
|
+a Router option, the DHCP client ignores the Router option. |
|
+.RE |
|
+.PP |
|
+.nf |
|
.B option \fBstreettalk-directory-assistance-server\fR \fIip-address\fR |
|
[\fB,\fR \fIip-address\fR...]\fB;\fR |
|
.fi |
|
diff -up dhcp-4.2.5b1/common/inet.c.rfc3442 dhcp-4.2.5b1/common/inet.c |
|
--- dhcp-4.2.5b1/common/inet.c.rfc3442 2012-12-05 02:17:38.000000000 +0100 |
|
+++ dhcp-4.2.5b1/common/inet.c 2012-12-17 13:23:34.440563957 +0100 |
|
@@ -528,6 +528,60 @@ free_iaddrcidrnetlist(struct iaddrcidrne |
|
return ISC_R_SUCCESS; |
|
} |
|
|
|
+static const char * |
|
+inet_ntopdd(const unsigned char *src, unsigned srclen, char *dst, size_t size) |
|
+{ |
|
+ char tmp[sizeof("32.255.255.255.255")]; |
|
+ int len; |
|
+ |
|
+ switch (srclen) { |
|
+ case 2: |
|
+ len = sprintf (tmp, "%u.%u", src[0], src[1]); |
|
+ break; |
|
+ case 3: |
|
+ len = sprintf (tmp, "%u.%u.%u", src[0], src[1], src[2]); |
|
+ break; |
|
+ case 4: |
|
+ len = sprintf (tmp, "%u.%u.%u.%u", src[0], src[1], src[2], src[3]); |
|
+ break; |
|
+ case 5: |
|
+ len = sprintf (tmp, "%u.%u.%u.%u.%u", src[0], src[1], src[2], src[3], src[4]); |
|
+ break; |
|
+ default: |
|
+ return NULL; |
|
+ } |
|
+ if (len < 0) |
|
+ return NULL; |
|
+ |
|
+ if (len > size) { |
|
+ errno = ENOSPC; |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ return strcpy (dst, tmp); |
|
+} |
|
+ |
|
+/* pdestdesc() turns an iaddr structure into a printable dest. descriptor */ |
|
+const char * |
|
+pdestdesc(const struct iaddr addr) { |
|
+ static char pbuf[sizeof("255.255.255.255.255")]; |
|
+ |
|
+ if (addr.len == 0) { |
|
+ return "<null destination descriptor>"; |
|
+ } |
|
+ if (addr.len == 1) { |
|
+ return "0"; |
|
+ } |
|
+ if ((addr.len >= 2) && (addr.len <= 5)) { |
|
+ return inet_ntopdd(addr.iabuf, addr.len, pbuf, sizeof(pbuf)); |
|
+ } |
|
+ |
|
+ log_fatal("pdestdesc():%s:%d: Invalid destination descriptor length %d.", |
|
+ MDL, addr.len); |
|
+ /* quell compiler warnings */ |
|
+ return NULL; |
|
+} |
|
+ |
|
/* piaddr() turns an iaddr structure into a printable address. */ |
|
/* XXX: should use a const pointer rather than passing the structure */ |
|
const char * |
|
diff -up dhcp-4.2.5b1/common/options.c.rfc3442 dhcp-4.2.5b1/common/options.c |
|
--- dhcp-4.2.5b1/common/options.c.rfc3442 2012-12-05 02:17:38.000000000 +0100 |
|
+++ dhcp-4.2.5b1/common/options.c 2012-12-17 13:29:38.961536040 +0100 |
|
@@ -713,7 +713,11 @@ cons_options(struct packet *inpacket, st |
|
* packet. |
|
*/ |
|
priority_list[priority_len++] = DHO_SUBNET_MASK; |
|
- priority_list[priority_len++] = DHO_ROUTERS; |
|
+ if (lookup_option(&dhcp_universe, cfg_options, |
|
+ DHO_CLASSLESS_STATIC_ROUTES)) |
|
+ priority_list[priority_len++] = DHO_CLASSLESS_STATIC_ROUTES; |
|
+ else |
|
+ priority_list[priority_len++] = DHO_ROUTERS; |
|
priority_list[priority_len++] = DHO_DOMAIN_NAME_SERVERS; |
|
priority_list[priority_len++] = DHO_HOST_NAME; |
|
priority_list[priority_len++] = DHO_FQDN; |
|
@@ -1694,6 +1698,7 @@ const char *pretty_print_option (option, |
|
unsigned long tval; |
|
isc_boolean_t a_array = ISC_FALSE; |
|
int len_used; |
|
+ unsigned int octets = 0; |
|
|
|
if (emit_commas) |
|
comma = ','; |
|
@@ -1702,6 +1707,7 @@ const char *pretty_print_option (option, |
|
|
|
memset (enumbuf, 0, sizeof enumbuf); |
|
|
|
+ if (option->format[0] != 'R') { /* see explanation lower */ |
|
/* Figure out the size of the data. */ |
|
for (l = i = 0; option -> format [i]; i++, l++) { |
|
if (l >= sizeof(fmtbuf) - 1) |
|
@@ -1876,6 +1882,33 @@ const char *pretty_print_option (option, |
|
if (numhunk < 0) |
|
numhunk = 1; |
|
|
|
+ } else { /* option->format[i] == 'R') */ |
|
+ /* R (destination descriptor) has variable length. |
|
+ * We can find it only in classless static route option, |
|
+ * so we are for sure parsing classless static route option now. |
|
+ * We go through whole the option to check whether there are no |
|
+ * missing/extra bytes. |
|
+ * I didn't find out how to improve the existing code and that's the |
|
+ * reason for this separate 'else' where I do my own checkings. |
|
+ * I know it's little bit unsystematic, but it works. |
|
+ */ |
|
+ numhunk = 0; |
|
+ numelem = 2; /* RI */ |
|
+ fmtbuf[0]='R'; fmtbuf[1]='I'; fmtbuf[2]=0; |
|
+ for (i =0; i < len; i = i + octets + 5) { |
|
+ if (data[i] > 32) { /* subnet mask width */ |
|
+ log_error ("wrong subnet mask width in destination descriptor"); |
|
+ break; |
|
+ } |
|
+ numhunk++; |
|
+ octets = ((data[i]+7) / 8); |
|
+ } |
|
+ if (i != len) { |
|
+ log_error ("classless static routes option has wrong size or " |
|
+ "there's some garbage in format"); |
|
+ } |
|
+ } |
|
+ |
|
/* Cycle through the array (or hunk) printing the data. */ |
|
for (i = 0; i < numhunk; i++) { |
|
if ((a_array == ISC_TRUE) && (i != 0) && (numelem > 0)) { |
|
@@ -2031,6 +2064,20 @@ const char *pretty_print_option (option, |
|
strcpy(op, piaddr(iaddr)); |
|
dp += 4; |
|
break; |
|
+ |
|
+ case 'R': |
|
+ if (dp[0] <= 32) |
|
+ iaddr.len = (((dp[0]+7)/8)+1); |
|
+ else { |
|
+ log_error ("wrong subnet mask width in destination descriptor"); |
|
+ return "<error>"; |
|
+ } |
|
+ |
|
+ memcpy(iaddr.iabuf, dp, iaddr.len); |
|
+ strcpy(op, pdestdesc(iaddr)); |
|
+ dp += iaddr.len; |
|
+ break; |
|
+ |
|
case '6': |
|
iaddr.len = 16; |
|
memcpy(iaddr.iabuf, dp, 16); |
|
diff -up dhcp-4.2.5b1/common/parse.c.rfc3442 dhcp-4.2.5b1/common/parse.c |
|
--- dhcp-4.2.5b1/common/parse.c.rfc3442 2012-12-17 13:23:34.408564378 +0100 |
|
+++ dhcp-4.2.5b1/common/parse.c 2012-12-17 13:23:34.444563905 +0100 |
|
@@ -341,6 +341,39 @@ int parse_ip_addr (cfile, addr) |
|
} |
|
|
|
/* |
|
+ * destination-descriptor :== NUMBER DOT NUMBER | |
|
+ * NUMBER DOT NUMBER DOT NUMBER | |
|
+ * NUMBER DOT NUMBER DOT NUMBER DOT NUMBER | |
|
+ * NUMBER DOT NUMBER DOT NUMBER DOT NUMBER DOT NUMBER |
|
+ */ |
|
+ |
|
+int parse_destination_descriptor (cfile, addr) |
|
+ struct parse *cfile; |
|
+ struct iaddr *addr; |
|
+{ |
|
+ unsigned int mask_width, dest_dest_len; |
|
+ addr -> len = 0; |
|
+ if (parse_numeric_aggregate (cfile, addr -> iabuf, |
|
+ &addr -> len, DOT, 10, 8)) { |
|
+ mask_width = (unsigned int)addr->iabuf[0]; |
|
+ dest_dest_len = (((mask_width+7)/8)+1); |
|
+ if (mask_width > 32) { |
|
+ parse_warn (cfile, |
|
+ "subnet mask width (%u) greater than 32.", mask_width); |
|
+ } |
|
+ else if (dest_dest_len != addr->len) { |
|
+ parse_warn (cfile, |
|
+ "destination descriptor with subnet mask width %u " |
|
+ "should have %u octets, but has %u octets.", |
|
+ mask_width, dest_dest_len, addr->len); |
|
+ } |
|
+ |
|
+ return 1; |
|
+ } |
|
+ return 0; |
|
+} |
|
+ |
|
+/* |
|
* Return true if every character in the string is hexadecimal. |
|
*/ |
|
static int |
|
@@ -719,8 +752,10 @@ unsigned char *parse_numeric_aggregate ( |
|
if (count) { |
|
token = peek_token (&val, (unsigned *)0, cfile); |
|
if (token != separator) { |
|
- if (!*max) |
|
+ if (!*max) { |
|
+ *max = count; |
|
break; |
|
+ } |
|
if (token != RBRACE && token != LBRACE) |
|
token = next_token (&val, |
|
(unsigned *)0, |
|
@@ -1660,6 +1695,9 @@ int parse_option_code_definition (cfile, |
|
case IP_ADDRESS: |
|
type = 'I'; |
|
break; |
|
+ case DESTINATION_DESCRIPTOR: |
|
+ type = 'R'; |
|
+ break; |
|
case IP6_ADDRESS: |
|
type = '6'; |
|
break; |
|
@@ -5418,6 +5456,15 @@ int parse_option_token (rv, cfile, fmt, |
|
} |
|
break; |
|
|
|
+ case 'R': /* destination descriptor */ |
|
+ if (!parse_destination_descriptor (cfile, &addr)) { |
|
+ return 0; |
|
+ } |
|
+ if (!make_const_data (&t, addr.iabuf, addr.len, 0, 1, MDL)) { |
|
+ return 0; |
|
+ } |
|
+ break; |
|
+ |
|
case '6': /* IPv6 address. */ |
|
if (!parse_ip6_addr(cfile, &addr)) { |
|
return 0; |
|
@@ -5695,6 +5742,13 @@ int parse_option_decl (oc, cfile) |
|
goto exit; |
|
len = ip_addr.len; |
|
dp = ip_addr.iabuf; |
|
+ goto alloc; |
|
+ |
|
+ case 'R': /* destination descriptor */ |
|
+ if (!parse_destination_descriptor (cfile, &ip_addr)) |
|
+ goto exit; |
|
+ len = ip_addr.len; |
|
+ dp = ip_addr.iabuf; |
|
|
|
alloc: |
|
if (hunkix + len > sizeof hunkbuf) { |
|
diff -up dhcp-4.2.5b1/common/tables.c.rfc3442 dhcp-4.2.5b1/common/tables.c |
|
--- dhcp-4.2.5b1/common/tables.c.rfc3442 2012-12-17 13:23:34.398564508 +0100 |
|
+++ dhcp-4.2.5b1/common/tables.c 2012-12-17 13:23:34.445563891 +0100 |
|
@@ -52,6 +52,7 @@ HASH_FUNCTIONS (option_code, const unsig |
|
Format codes: |
|
|
|
I - IPv4 address |
|
+ R - destination descriptor (RFC3442) |
|
6 - IPv6 address |
|
l - 32-bit signed integer |
|
L - 32-bit unsigned integer |
|
@@ -210,6 +211,7 @@ static struct option dhcp_options[] = { |
|
{ "default-url", "t", &dhcp_universe, 114, 1 }, |
|
{ "subnet-selection", "I", &dhcp_universe, 118, 1 }, |
|
{ "domain-search", "D", &dhcp_universe, 119, 1 }, |
|
+ { "classless-static-routes", "RIA", &dhcp_universe, 121, 1 }, |
|
{ "vivco", "Evendor-class.", &dhcp_universe, 124, 1 }, |
|
{ "vivso", "Evendor.", &dhcp_universe, 125, 1 }, |
|
#if 0 |
|
diff -up dhcp-4.2.5b1/includes/dhcpd.h.rfc3442 dhcp-4.2.5b1/includes/dhcpd.h |
|
--- dhcp-4.2.5b1/includes/dhcpd.h.rfc3442 2012-12-17 13:23:34.382564719 +0100 |
|
+++ dhcp-4.2.5b1/includes/dhcpd.h 2012-12-17 13:23:34.446563877 +0100 |
|
@@ -2678,6 +2678,7 @@ isc_result_t range2cidr(struct iaddrcidr |
|
const struct iaddr *lo, const struct iaddr *hi); |
|
isc_result_t free_iaddrcidrnetlist(struct iaddrcidrnetlist **result); |
|
const char *piaddr (struct iaddr); |
|
+const char *pdestdesc (struct iaddr); |
|
char *piaddrmask(struct iaddr *, struct iaddr *); |
|
char *piaddrcidr(const struct iaddr *, unsigned int); |
|
u_int16_t validate_port(char *); |
|
@@ -2887,6 +2888,7 @@ void parse_client_lease_declaration (str |
|
int parse_option_decl (struct option_cache **, struct parse *); |
|
void parse_string_list (struct parse *, struct string_list **, int); |
|
int parse_ip_addr (struct parse *, struct iaddr *); |
|
+int parse_destination_descriptor (struct parse *, struct iaddr *); |
|
int parse_ip_addr_with_subnet(struct parse *, struct iaddrmatch *); |
|
void parse_reject_statement (struct parse *, struct client_config *); |
|
|
|
diff -up dhcp-4.2.5b1/includes/dhcp.h.rfc3442 dhcp-4.2.5b1/includes/dhcp.h |
|
--- dhcp-4.2.5b1/includes/dhcp.h.rfc3442 2012-10-23 21:02:13.000000000 +0200 |
|
+++ dhcp-4.2.5b1/includes/dhcp.h 2012-12-17 13:23:34.446563877 +0100 |
|
@@ -163,6 +163,7 @@ struct dhcp_packet { |
|
#define DHO_ASSOCIATED_IP 92 |
|
#define DHO_SUBNET_SELECTION 118 /* RFC3011! */ |
|
#define DHO_DOMAIN_SEARCH 119 /* RFC3397 */ |
|
+#define DHO_CLASSLESS_STATIC_ROUTES 121 /* RFC3442 */ |
|
#define DHO_VIVCO_SUBOPTIONS 124 |
|
#define DHO_VIVSO_SUBOPTIONS 125 |
|
|
|
diff -up dhcp-4.2.5b1/includes/dhctoken.h.rfc3442 dhcp-4.2.5b1/includes/dhctoken.h |
|
--- dhcp-4.2.5b1/includes/dhctoken.h.rfc3442 2012-12-17 13:23:34.348565167 +0100 |
|
+++ dhcp-4.2.5b1/includes/dhctoken.h 2012-12-17 13:23:34.446563877 +0100 |
|
@@ -365,7 +365,8 @@ enum dhcp_token { |
|
PRIMARY6 = 666, |
|
SECONDARY6 = 667, |
|
TOKEN_INFINIBAND = 668, |
|
- BOOTP_BROADCAST_ALWAYS = 669 |
|
+ BOOTP_BROADCAST_ALWAYS = 669, |
|
+ DESTINATION_DESCRIPTOR = 670 |
|
}; |
|
|
|
#define is_identifier(x) ((x) >= FIRST_TOKEN && \
|
|
|