]>
Commit | Line | Data |
---|---|---|
78ab9b04 MT |
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 | |
4 | @@ -37,7 +37,7 @@ | |
5 | ||
6 | struct client_config top_level_config; | |
7 | ||
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]; | |
11 | ||
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); | |
15 | ||
16 | /* 4 */ | |
17 | - code = DHO_ROUTERS; | |
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) | |
21 | + */ | |
22 | + code = DHO_CLASSLESS_STATIC_ROUTES; | |
23 | option_code_hash_lookup(&default_requested_options[3], | |
24 | dhcp_universe.code_hash, &code, 0, MDL); | |
25 | ||
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); | |
29 | ||
30 | + /* 15 */ | |
31 | + code = DHO_ROUTERS; | |
32 | + option_code_hash_lookup(&default_requested_options[14], | |
33 | + dhcp_universe.code_hash, &code, 0, MDL); | |
34 | + | |
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 | |
42 | or | |
43 | option dhcp-client-identifier 43:4c:49:45:54:2d:46:4f:4f; | |
44 | .fi | |
45 | +.PP | |
46 | +The | |
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: | |
54 | +.nf | |
55 | +.sp 1 | |
56 | +Subnet number Subnet mask Destination descriptor | |
57 | +0 0 0 | |
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 | |
64 | +.fi | |
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: | |
69 | .RE | |
70 | .PP | |
71 | .nf | |
72 | +.B option \fBclassless-static-routes\fR \fIdestination-descriptor ip-address\fR | |
73 | + [\fB,\fR \fIdestination-descriptor ip-address\fR...]\fB;\fR | |
74 | +.fi | |
75 | +.RS 0.25i | |
76 | +.PP | |
77 | +This option (see RFC3442) specifies a list of classless static routes | |
78 | +that the client should install in its routing cache. | |
79 | +.PP | |
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. | |
83 | +.PP | |
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. | |
89 | +.PP | |
90 | +If the DHCP server returns both a Classless Static Routes option and | |
91 | +a Router option, the DHCP client ignores the Router option. | |
92 | +.RE | |
93 | +.PP | |
94 | +.nf | |
95 | .B option \fBstreettalk-directory-assistance-server\fR \fIip-address\fR | |
96 | [\fB,\fR \fIip-address\fR...]\fB;\fR | |
97 | .fi | |
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; | |
103 | } | |
104 | ||
105 | +static const char * | |
106 | +inet_ntopdd(const unsigned char *src, unsigned srclen, char *dst, size_t size) | |
107 | +{ | |
108 | + char tmp[sizeof("32.255.255.255.255")]; | |
109 | + int len; | |
110 | + | |
111 | + switch (srclen) { | |
112 | + case 2: | |
113 | + len = sprintf (tmp, "%u.%u", src[0], src[1]); | |
114 | + break; | |
115 | + case 3: | |
116 | + len = sprintf (tmp, "%u.%u.%u", src[0], src[1], src[2]); | |
117 | + break; | |
118 | + case 4: | |
119 | + len = sprintf (tmp, "%u.%u.%u.%u", src[0], src[1], src[2], src[3]); | |
120 | + break; | |
121 | + case 5: | |
122 | + len = sprintf (tmp, "%u.%u.%u.%u.%u", src[0], src[1], src[2], src[3], src[4]); | |
123 | + break; | |
124 | + default: | |
125 | + return NULL; | |
126 | + } | |
127 | + if (len < 0) | |
128 | + return NULL; | |
129 | + | |
130 | + if (len > size) { | |
131 | + errno = ENOSPC; | |
132 | + return NULL; | |
133 | + } | |
134 | + | |
135 | + return strcpy (dst, tmp); | |
136 | +} | |
137 | + | |
138 | +/* pdestdesc() turns an iaddr structure into a printable dest. descriptor */ | |
139 | +const char * | |
140 | +pdestdesc(const struct iaddr addr) { | |
141 | + static char pbuf[sizeof("255.255.255.255.255")]; | |
142 | + | |
143 | + if (addr.len == 0) { | |
144 | + return "<null destination descriptor>"; | |
145 | + } | |
146 | + if (addr.len == 1) { | |
147 | + return "0"; | |
148 | + } | |
149 | + if ((addr.len >= 2) && (addr.len <= 5)) { | |
150 | + return inet_ntopdd(addr.iabuf, addr.len, pbuf, sizeof(pbuf)); | |
151 | + } | |
152 | + | |
153 | + log_fatal("pdestdesc():%s:%d: Invalid destination descriptor length %d.", | |
154 | + MDL, addr.len); | |
155 | + /* quell compiler warnings */ | |
156 | + return NULL; | |
157 | +} | |
158 | + | |
159 | /* piaddr() turns an iaddr structure into a printable address. */ | |
160 | /* XXX: should use a const pointer rather than passing the structure */ | |
161 | const char * | |
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 | |
166 | * packet. | |
167 | */ | |
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; | |
173 | + else | |
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; | |
180 | char comma; | |
181 | unsigned long tval; | |
182 | + unsigned int octets = 0; | |
183 | ||
184 | if (emit_commas) | |
185 | comma = ','; | |
186 | @@ -1691,6 +1696,7 @@ const char *pretty_print_option (option, | |
187 | ||
188 | memset (enumbuf, 0, sizeof enumbuf); | |
189 | ||
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, | |
195 | if (numhunk < 0) | |
196 | numhunk = 1; | |
197 | ||
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. | |
207 | + */ | |
208 | + numhunk = 0; | |
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"); | |
214 | + break; | |
215 | + } | |
216 | + numhunk++; | |
217 | + octets = ((data[i]+7) / 8); | |
218 | + } | |
219 | + if (i != len) { | |
220 | + log_error ("classless static routes option has wrong size or " | |
221 | + "there's some garbage in format"); | |
222 | + } | |
223 | + } | |
224 | + | |
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)); | |
230 | dp += 4; | |
231 | break; | |
232 | + | |
233 | + case 'R': | |
234 | + if (dp[0] <= 32) | |
235 | + iaddr.len = (((dp[0]+7)/8)+1); | |
236 | + else { | |
237 | + log_error ("wrong subnet mask width in destination descriptor"); | |
238 | + return "<error>"; | |
239 | + } | |
240 | + | |
241 | + memcpy(iaddr.iabuf, dp, iaddr.len); | |
242 | + strcpy(op, pdestdesc(iaddr)); | |
243 | + dp += iaddr.len; | |
244 | + break; | |
245 | + | |
246 | case '6': | |
247 | iaddr.len = 16; | |
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) | |
253 | } | |
254 | ||
255 | /* | |
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 | |
260 | + */ | |
261 | + | |
262 | +int parse_destination_descriptor (cfile, addr) | |
263 | + struct parse *cfile; | |
264 | + struct iaddr *addr; | |
265 | +{ | |
266 | + unsigned int mask_width, dest_dest_len; | |
267 | + addr -> len = 0; | |
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) { | |
273 | + parse_warn (cfile, | |
274 | + "subnet mask width (%u) greater than 32.", mask_width); | |
275 | + } | |
276 | + else if (dest_dest_len != addr->len) { | |
277 | + parse_warn (cfile, | |
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); | |
281 | + } | |
282 | + | |
283 | + return 1; | |
284 | + } | |
285 | + return 0; | |
286 | +} | |
287 | + | |
288 | +/* | |
289 | * Return true if every character in the string is hexadecimal. | |
290 | */ | |
291 | static int | |
292 | @@ -700,8 +733,10 @@ unsigned char *parse_numeric_aggregate ( | |
293 | if (count) { | |
294 | token = peek_token (&val, (unsigned *)0, cfile); | |
295 | if (token != separator) { | |
296 | - if (!*max) | |
297 | + if (!*max) { | |
298 | + *max = count; | |
299 | break; | |
300 | + } | |
301 | if (token != RBRACE && token != LBRACE) | |
302 | token = next_token (&val, | |
303 | (unsigned *)0, | |
304 | @@ -1624,6 +1659,9 @@ int parse_option_code_definition (cfile, | |
305 | case IP_ADDRESS: | |
306 | type = 'I'; | |
307 | break; | |
308 | + case DESTINATION_DESCRIPTOR: | |
309 | + type = 'R'; | |
310 | + break; | |
311 | case IP6_ADDRESS: | |
312 | type = '6'; | |
313 | break; | |
314 | @@ -5288,6 +5326,15 @@ int parse_option_token (rv, cfile, fmt, | |
315 | } | |
316 | break; | |
317 | ||
318 | + case 'R': /* destination descriptor */ | |
319 | + if (!parse_destination_descriptor (cfile, &addr)) { | |
320 | + return 0; | |
321 | + } | |
322 | + if (!make_const_data (&t, addr.iabuf, addr.len, 0, 1, MDL)) { | |
323 | + return 0; | |
324 | + } | |
325 | + break; | |
326 | + | |
327 | case '6': /* IPv6 address. */ | |
328 | if (!parse_ip6_addr(cfile, &addr)) { | |
329 | return 0; | |
330 | @@ -5548,6 +5595,13 @@ int parse_option_decl (oc, cfile) | |
331 | goto exit; | |
332 | len = ip_addr.len; | |
333 | dp = ip_addr.iabuf; | |
334 | + goto alloc; | |
335 | + | |
336 | + case 'R': /* destination descriptor */ | |
337 | + if (!parse_destination_descriptor (cfile, &ip_addr)) | |
338 | + goto exit; | |
339 | + len = ip_addr.len; | |
340 | + dp = ip_addr.iabuf; | |
341 | ||
342 | alloc: | |
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 | |
348 | Format codes: | |
349 | ||
350 | I - IPv4 address | |
351 | + R - destination descriptor (RFC3442) | |
352 | 6 - IPv6 address | |
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 }, | |
362 | #if 0 | |
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 *); | |
381 | ||
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 | |
392 | ||
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 { | |
397 | REWIND = 663, | |
398 | INITIAL_DELAY = 664, | |
399 | GETHOSTBYNAME = 665, | |
400 | - BOOTP_BROADCAST_ALWAYS = 666 | |
401 | + BOOTP_BROADCAST_ALWAYS = 666, | |
402 | + DESTINATION_DESCRIPTOR = 667 | |
403 | }; | |
404 | ||
405 | #define is_identifier(x) ((x) >= FIRST_TOKEN && \ |