1 diff -up dhcp-4.2.2b1/client/clparse.c.rfc3442 dhcp-4.2.2b1/client/clparse.c
2 --- dhcp-4.2.2b1/client/clparse.c.rfc3442 2011-07-01 14:22:38.031534508 +0200
3 +++ dhcp-4.2.2b1/client/clparse.c 2011-07-01 14:22:38.128532940 +0200
6 struct client_config top_level_config;
8 -#define NUM_DEFAULT_REQUESTED_OPTS 14
9 +#define NUM_DEFAULT_REQUESTED_OPTS 15
10 struct option *default_requested_options[NUM_DEFAULT_REQUESTED_OPTS + 1];
12 static void parse_client_default_duid(struct parse *cfile);
13 @@ -82,7 +82,11 @@ isc_result_t read_client_conf ()
14 dhcp_universe.code_hash, &code, 0, MDL);
18 + /* The Classless Static Routes option code MUST appear in the parameter
19 + * request list prior to both the Router option code and the Static
20 + * Routes option code, if present. (RFC3442)
22 + code = DHO_CLASSLESS_STATIC_ROUTES;
23 option_code_hash_lookup(&default_requested_options[3],
24 dhcp_universe.code_hash, &code, 0, MDL);
26 @@ -136,6 +140,11 @@ isc_result_t read_client_conf ()
27 option_code_hash_lookup(&default_requested_options[13],
28 dhcp_universe.code_hash, &code, 0, MDL);
32 + option_code_hash_lookup(&default_requested_options[14],
33 + dhcp_universe.code_hash, &code, 0, MDL);
35 for (code = 0 ; code < NUM_DEFAULT_REQUESTED_OPTS ; code++) {
36 if (default_requested_options[code] == NULL)
37 log_fatal("Unable to find option definition for "
38 diff -up dhcp-4.2.2b1/common/dhcp-options.5.rfc3442 dhcp-4.2.2b1/common/dhcp-options.5
39 --- dhcp-4.2.2b1/common/dhcp-options.5.rfc3442 2011-07-01 14:22:38.020534686 +0200
40 +++ dhcp-4.2.2b1/common/dhcp-options.5 2011-07-01 14:22:38.129532924 +0200
41 @@ -115,6 +115,26 @@ hexadecimal, separated by colons. For
43 option dhcp-client-identifier 43:4c:49:45:54:2d:46:4f:4f;
47 +.B destination-descriptor
48 +describe the IP subnet number and subnet mask
49 +of a particular destination using a compact encoding. This encoding
50 +consists of one octet describing the width of the subnet mask,
51 +followed by all the significant octets of the subnet number.
52 +The following table contains some examples of how various subnet
53 +number/mask combinations can be encoded:
56 +Subnet number Subnet mask Destination descriptor
58 +10.0.0.0 255.0.0.0 8.10
59 +10.0.0.0 255.255.255.0 24.10.0.0
60 +10.17.0.0 255.255.0.0 16.10.17
61 +10.27.129.0 255.255.255.0 24.10.27.129
62 +10.229.0.128 255.255.255.128 25.10.229.0.128
63 +10.198.122.47 255.255.255.255 32.10.198.122.47
65 .SH SETTING OPTION VALUES USING EXPRESSIONS
66 Sometimes it's helpful to be able to set the value of a DHCP option
67 based on some value that the client has sent. To do this, you can
68 @@ -931,6 +951,29 @@ dhclient-script will create routes:
72 +.B option \fBclassless-static-routes\fR \fIdestination-descriptor ip-address\fR
73 + [\fB,\fR \fIdestination-descriptor ip-address\fR...]\fB;\fR
77 +This option (see RFC3442) specifies a list of classless static routes
78 +that the client should install in its routing cache.
80 +This option can contain one or more static routes, each of which
81 +consists of a destination descriptor and the IP address of the router
82 +that should be used to reach that destination.
84 +Many clients may not implement the Classless Static Routes option.
85 +DHCP server administrators should therefore configure their DHCP
86 +servers to send both a Router option and a Classless Static Routes
87 +option, and should specify the default router(s) both in the Router
88 +option and in the Classless Static Routes option.
90 +If the DHCP server returns both a Classless Static Routes option and
91 +a Router option, the DHCP client ignores the Router option.
95 .B option \fBstreettalk-directory-assistance-server\fR \fIip-address\fR
96 [\fB,\fR \fIip-address\fR...]\fB;\fR
98 diff -up dhcp-4.2.2b1/common/inet.c.rfc3442 dhcp-4.2.2b1/common/inet.c
99 --- dhcp-4.2.2b1/common/inet.c.rfc3442 2011-05-11 02:47:22.000000000 +0200
100 +++ dhcp-4.2.2b1/common/inet.c 2011-07-01 14:22:38.130532908 +0200
101 @@ -528,6 +528,60 @@ free_iaddrcidrnetlist(struct iaddrcidrne
102 return ISC_R_SUCCESS;
106 +inet_ntopdd(const unsigned char *src, unsigned srclen, char *dst, size_t size)
108 + char tmp[sizeof("32.255.255.255.255")];
113 + len = sprintf (tmp, "%u.%u", src[0], src[1]);
116 + len = sprintf (tmp, "%u.%u.%u", src[0], src[1], src[2]);
119 + len = sprintf (tmp, "%u.%u.%u.%u", src[0], src[1], src[2], src[3]);
122 + len = sprintf (tmp, "%u.%u.%u.%u.%u", src[0], src[1], src[2], src[3], src[4]);
135 + return strcpy (dst, tmp);
138 +/* pdestdesc() turns an iaddr structure into a printable dest. descriptor */
140 +pdestdesc(const struct iaddr addr) {
141 + static char pbuf[sizeof("255.255.255.255.255")];
143 + if (addr.len == 0) {
144 + return "<null destination descriptor>";
146 + if (addr.len == 1) {
149 + if ((addr.len >= 2) && (addr.len <= 5)) {
150 + return inet_ntopdd(addr.iabuf, addr.len, pbuf, sizeof(pbuf));
153 + log_fatal("pdestdesc():%s:%d: Invalid destination descriptor length %d.",
155 + /* quell compiler warnings */
159 /* piaddr() turns an iaddr structure into a printable address. */
160 /* XXX: should use a const pointer rather than passing the structure */
162 diff -up dhcp-4.2.2b1/common/options.c.rfc3442 dhcp-4.2.2b1/common/options.c
163 --- dhcp-4.2.2b1/common/options.c.rfc3442 2011-03-24 22:57:13.000000000 +0100
164 +++ dhcp-4.2.2b1/common/options.c 2011-07-01 14:22:38.132532876 +0200
165 @@ -706,7 +706,11 @@ cons_options(struct packet *inpacket, st
168 priority_list[priority_len++] = DHO_SUBNET_MASK;
169 - priority_list[priority_len++] = DHO_ROUTERS;
170 + if (lookup_option(&dhcp_universe, cfg_options,
171 + DHO_CLASSLESS_STATIC_ROUTES))
172 + priority_list[priority_len++] = DHO_CLASSLESS_STATIC_ROUTES;
174 + priority_list[priority_len++] = DHO_ROUTERS;
175 priority_list[priority_len++] = DHO_DOMAIN_NAME_SERVERS;
176 priority_list[priority_len++] = DHO_HOST_NAME;
177 priority_list[priority_len++] = DHO_FQDN;
178 @@ -1683,6 +1687,7 @@ const char *pretty_print_option (option,
179 const unsigned char *dp = data;
182 + unsigned int octets = 0;
186 @@ -1691,6 +1696,7 @@ const char *pretty_print_option (option,
188 memset (enumbuf, 0, sizeof enumbuf);
190 + if (option->format[0] != 'R') { /* see explanation lower */
191 /* Figure out the size of the data. */
192 for (l = i = 0; option -> format [i]; i++, l++) {
193 if (l >= sizeof(fmtbuf) - 1)
194 @@ -1840,6 +1846,33 @@ const char *pretty_print_option (option,
198 + } else { /* option->format[i] == 'R') */
199 + /* R (destination descriptor) has variable length.
200 + * We can find it only in classless static route option,
201 + * so we are for sure parsing classless static route option now.
202 + * We go through whole the option to check whether there are no
203 + * missing/extra bytes.
204 + * I didn't find out how to improve the existing code and that's the
205 + * reason for this separate 'else' where I do my own checkings.
206 + * I know it's little bit unsystematic, but it works.
209 + numelem = 2; /* RI */
210 + fmtbuf[0]='R'; fmtbuf[1]='I'; fmtbuf[2]=0;
211 + for (i =0; i < len; i = i + octets + 5) {
212 + if (data[i] > 32) { /* subnet mask width */
213 + log_error ("wrong subnet mask width in destination descriptor");
217 + octets = ((data[i]+7) / 8);
220 + log_error ("classless static routes option has wrong size or "
221 + "there's some garbage in format");
225 /* Cycle through the array (or hunk) printing the data. */
226 for (i = 0; i < numhunk; i++) {
227 for (j = 0; j < numelem; j++) {
228 @@ -1978,6 +2011,20 @@ const char *pretty_print_option (option,
229 strcpy(op, piaddr(iaddr));
235 + iaddr.len = (((dp[0]+7)/8)+1);
237 + log_error ("wrong subnet mask width in destination descriptor");
241 + memcpy(iaddr.iabuf, dp, iaddr.len);
242 + strcpy(op, pdestdesc(iaddr));
248 memcpy(iaddr.iabuf, dp, 16);
249 diff -up dhcp-4.2.2b1/common/parse.c.rfc3442 dhcp-4.2.2b1/common/parse.c
250 --- dhcp-4.2.2b1/common/parse.c.rfc3442 2011-07-01 14:22:38.097533441 +0200
251 +++ dhcp-4.2.2b1/common/parse.c 2011-07-01 14:22:38.135532828 +0200
252 @@ -341,6 +341,39 @@ int parse_ip_addr (cfile, addr)
256 + * destination-descriptor :== NUMBER DOT NUMBER |
257 + * NUMBER DOT NUMBER DOT NUMBER |
258 + * NUMBER DOT NUMBER DOT NUMBER DOT NUMBER |
259 + * NUMBER DOT NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
262 +int parse_destination_descriptor (cfile, addr)
263 + struct parse *cfile;
264 + struct iaddr *addr;
266 + unsigned int mask_width, dest_dest_len;
268 + if (parse_numeric_aggregate (cfile, addr -> iabuf,
269 + &addr -> len, DOT, 10, 8)) {
270 + mask_width = (unsigned int)addr->iabuf[0];
271 + dest_dest_len = (((mask_width+7)/8)+1);
272 + if (mask_width > 32) {
274 + "subnet mask width (%u) greater than 32.", mask_width);
276 + else if (dest_dest_len != addr->len) {
278 + "destination descriptor with subnet mask width %u "
279 + "should have %u octets, but has %u octets.",
280 + mask_width, dest_dest_len, addr->len);
289 * Return true if every character in the string is hexadecimal.
292 @@ -700,8 +733,10 @@ unsigned char *parse_numeric_aggregate (
294 token = peek_token (&val, (unsigned *)0, cfile);
295 if (token != separator) {
301 if (token != RBRACE && token != LBRACE)
302 token = next_token (&val,
304 @@ -1624,6 +1659,9 @@ int parse_option_code_definition (cfile,
308 + case DESTINATION_DESCRIPTOR:
314 @@ -5288,6 +5326,15 @@ int parse_option_token (rv, cfile, fmt,
318 + case 'R': /* destination descriptor */
319 + if (!parse_destination_descriptor (cfile, &addr)) {
322 + if (!make_const_data (&t, addr.iabuf, addr.len, 0, 1, MDL)) {
327 case '6': /* IPv6 address. */
328 if (!parse_ip6_addr(cfile, &addr)) {
330 @@ -5548,6 +5595,13 @@ int parse_option_decl (oc, cfile)
336 + case 'R': /* destination descriptor */
337 + if (!parse_destination_descriptor (cfile, &ip_addr))
340 + dp = ip_addr.iabuf;
343 if (hunkix + len > sizeof hunkbuf) {
344 diff -up dhcp-4.2.2b1/common/tables.c.rfc3442 dhcp-4.2.2b1/common/tables.c
345 --- dhcp-4.2.2b1/common/tables.c.rfc3442 2011-07-01 14:22:38.087533601 +0200
346 +++ dhcp-4.2.2b1/common/tables.c 2011-07-01 14:22:38.137532796 +0200
347 @@ -51,6 +51,7 @@ HASH_FUNCTIONS (option_code, const unsig
351 + R - destination descriptor (RFC3442)
353 l - 32-bit signed integer
354 L - 32-bit unsigned integer
355 @@ -208,6 +209,7 @@ static struct option dhcp_options[] = {
356 { "default-url", "t", &dhcp_universe, 114, 1 },
357 { "subnet-selection", "I", &dhcp_universe, 118, 1 },
358 { "domain-search", "D", &dhcp_universe, 119, 1 },
359 + { "classless-static-routes", "RIA", &dhcp_universe, 121, 1 },
360 { "vivco", "Evendor-class.", &dhcp_universe, 124, 1 },
361 { "vivso", "Evendor.", &dhcp_universe, 125, 1 },
363 diff -up dhcp-4.2.2b1/includes/dhcpd.h.rfc3442 dhcp-4.2.2b1/includes/dhcpd.h
364 --- dhcp-4.2.2b1/includes/dhcpd.h.rfc3442 2011-07-01 14:22:38.000000000 +0200
365 +++ dhcp-4.2.2b1/includes/dhcpd.h 2011-07-01 14:24:19.999810333 +0200
366 @@ -2662,6 +2662,7 @@ isc_result_t range2cidr(struct iaddrcidr
367 const struct iaddr *lo, const struct iaddr *hi);
368 isc_result_t free_iaddrcidrnetlist(struct iaddrcidrnetlist **result);
369 const char *piaddr (struct iaddr);
370 +const char *pdestdesc (struct iaddr);
371 char *piaddrmask(struct iaddr *, struct iaddr *);
372 char *piaddrcidr(const struct iaddr *, unsigned int);
373 u_int16_t validate_port(char *);
374 @@ -2869,6 +2870,7 @@ void parse_client_lease_declaration (str
375 int parse_option_decl (struct option_cache **, struct parse *);
376 void parse_string_list (struct parse *, struct string_list **, int);
377 int parse_ip_addr (struct parse *, struct iaddr *);
378 +int parse_destination_descriptor (struct parse *, struct iaddr *);
379 int parse_ip_addr_with_subnet(struct parse *, struct iaddrmatch *);
380 void parse_reject_statement (struct parse *, struct client_config *);
382 diff -up dhcp-4.2.2b1/includes/dhcp.h.rfc3442 dhcp-4.2.2b1/includes/dhcp.h
383 --- dhcp-4.2.2b1/includes/dhcp.h.rfc3442 2009-11-20 02:49:01.000000000 +0100
384 +++ dhcp-4.2.2b1/includes/dhcp.h 2011-07-01 14:22:38.145532665 +0200
385 @@ -158,6 +158,7 @@ struct dhcp_packet {
386 #define DHO_ASSOCIATED_IP 92
387 #define DHO_SUBNET_SELECTION 118 /* RFC3011! */
388 #define DHO_DOMAIN_SEARCH 119 /* RFC3397 */
389 +#define DHO_CLASSLESS_STATIC_ROUTES 121 /* RFC3442 */
390 #define DHO_VIVCO_SUBOPTIONS 124
391 #define DHO_VIVSO_SUBOPTIONS 125
393 diff -up dhcp-4.2.2b1/includes/dhctoken.h.rfc3442 dhcp-4.2.2b1/includes/dhctoken.h
394 --- dhcp-4.2.2b1/includes/dhctoken.h.rfc3442 2011-07-01 14:22:37.000000000 +0200
395 +++ dhcp-4.2.2b1/includes/dhctoken.h 2011-07-01 14:25:12.541867623 +0200
396 @@ -362,7 +362,8 @@ enum dhcp_token {
400 - BOOTP_BROADCAST_ALWAYS = 666
401 + BOOTP_BROADCAST_ALWAYS = 666,
402 + DESTINATION_DESCRIPTOR = 667
405 #define is_identifier(x) ((x) >= FIRST_TOKEN && \