]>
Commit | Line | Data |
---|---|---|
c1e9ba67 MF |
1 | diff -up dhcp-4.3.0rc1/client/clparse.c.rfc3442 dhcp-4.3.0rc1/client/clparse.c |
2 | --- dhcp-4.3.0rc1/client/clparse.c.rfc3442 2014-01-29 10:05:48.474400352 +0100 | |
3 | +++ dhcp-4.3.0rc1/client/clparse.c 2014-01-29 10:05:48.517399955 +0100 | |
4 | @@ -31,7 +31,7 @@ | |
78ab9b04 MT |
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); | |
c1e9ba67 | 13 | @@ -84,7 +84,11 @@ isc_result_t read_client_conf () |
78ab9b04 MT |
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 | ||
c1e9ba67 | 26 | @@ -138,6 +142,11 @@ isc_result_t read_client_conf () |
78ab9b04 MT |
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 " | |
c1e9ba67 MF |
38 | diff -up dhcp-4.3.0rc1/common/dhcp-options.5.rfc3442 dhcp-4.3.0rc1/common/dhcp-options.5 |
39 | --- dhcp-4.3.0rc1/common/dhcp-options.5.rfc3442 2014-01-29 10:05:48.466400426 +0100 | |
40 | +++ dhcp-4.3.0rc1/common/dhcp-options.5 2014-01-29 10:05:48.518399945 +0100 | |
41 | @@ -111,6 +111,26 @@ hexadecimal, separated by colons. For e | |
78ab9b04 MT |
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 | |
c1e9ba67 MF |
67 | based on some value that the client has sent. To do this, you can |
68 | @@ -972,6 +992,29 @@ dhclient-script will create routes: | |
78ab9b04 MT |
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 | |
c1e9ba67 MF |
98 | diff -up dhcp-4.3.0rc1/common/inet.c.rfc3442 dhcp-4.3.0rc1/common/inet.c |
99 | --- dhcp-4.3.0rc1/common/inet.c.rfc3442 2014-01-26 19:40:44.000000000 +0100 | |
100 | +++ dhcp-4.3.0rc1/common/inet.c 2014-01-29 10:05:48.519399936 +0100 | |
101 | @@ -521,6 +521,60 @@ free_iaddrcidrnetlist(struct iaddrcidrne | |
78ab9b04 MT |
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 * | |
c1e9ba67 MF |
162 | diff -up dhcp-4.3.0rc1/common/options.c.rfc3442 dhcp-4.3.0rc1/common/options.c |
163 | --- dhcp-4.3.0rc1/common/options.c.rfc3442 2014-01-26 19:40:44.000000000 +0100 | |
164 | +++ dhcp-4.3.0rc1/common/options.c 2014-01-29 10:05:48.520399927 +0100 | |
165 | @@ -707,7 +707,11 @@ cons_options(struct packet *inpacket, st | |
78ab9b04 MT |
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; | |
c1e9ba67 | 178 | @@ -1688,6 +1692,7 @@ const char *pretty_print_option (option, |
78ab9b04 | 179 | unsigned long tval; |
c1e9ba67 MF |
180 | isc_boolean_t a_array = ISC_FALSE; |
181 | int len_used; | |
182 | + unsigned int octets = 0; | |
78ab9b04 MT |
183 | |
184 | if (emit_commas) | |
185 | comma = ','; | |
c1e9ba67 | 186 | @@ -1696,6 +1701,7 @@ const char *pretty_print_option (option, |
78ab9b04 MT |
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) | |
c1e9ba67 | 194 | @@ -1870,6 +1876,33 @@ const char *pretty_print_option (option, |
78ab9b04 MT |
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++) { | |
c1e9ba67 MF |
227 | if ((a_array == ISC_TRUE) && (i != 0) && (numelem > 0)) { |
228 | @@ -2025,6 +2058,20 @@ const char *pretty_print_option (option, | |
78ab9b04 MT |
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); | |
c1e9ba67 MF |
249 | diff -up dhcp-4.3.0rc1/common/parse.c.rfc3442 dhcp-4.3.0rc1/common/parse.c |
250 | --- dhcp-4.3.0rc1/common/parse.c.rfc3442 2014-01-29 10:05:48.491400195 +0100 | |
251 | +++ dhcp-4.3.0rc1/common/parse.c 2014-01-29 10:05:48.522399908 +0100 | |
252 | @@ -335,6 +335,39 @@ int parse_ip_addr (cfile, addr) | |
78ab9b04 MT |
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 | |
c1e9ba67 | 292 | @@ -713,8 +746,10 @@ unsigned char *parse_numeric_aggregate ( |
78ab9b04 MT |
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, | |
c1e9ba67 | 304 | @@ -1654,6 +1689,9 @@ int parse_option_code_definition (cfile, |
78ab9b04 MT |
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; | |
c1e9ba67 | 314 | @@ -5071,6 +5109,15 @@ int parse_option_token (rv, cfile, fmt, |
78ab9b04 MT |
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; | |
c1e9ba67 | 330 | @@ -5348,6 +5395,13 @@ int parse_option_decl (oc, cfile) |
78ab9b04 MT |
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) { | |
c1e9ba67 MF |
344 | diff -up dhcp-4.3.0rc1/common/tables.c.rfc3442 dhcp-4.3.0rc1/common/tables.c |
345 | --- dhcp-4.3.0rc1/common/tables.c.rfc3442 2014-01-29 10:05:48.485400250 +0100 | |
346 | +++ dhcp-4.3.0rc1/common/tables.c 2014-01-29 10:06:25.724038563 +0100 | |
347 | @@ -46,6 +46,7 @@ HASH_FUNCTIONS (option_code, const unsig | |
78ab9b04 MT |
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 | |
c1e9ba67 MF |
355 | @@ -214,6 +215,7 @@ static struct option dhcp_options[] = { |
356 | #endif | |
78ab9b04 | 357 | { "subnet-selection", "I", &dhcp_universe, 118, 1 }, |
c1e9ba67 | 358 | { "domain-search", "D", &dhcp_universe, 119, 1 }, |
78ab9b04 MT |
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 | |
c1e9ba67 MF |
363 | diff -up dhcp-4.3.0rc1/includes/dhcpd.h.rfc3442 dhcp-4.3.0rc1/includes/dhcpd.h |
364 | --- dhcp-4.3.0rc1/includes/dhcpd.h.rfc3442 2014-01-29 10:05:48.470400389 +0100 | |
365 | +++ dhcp-4.3.0rc1/includes/dhcpd.h 2014-01-29 10:05:48.525399881 +0100 | |
366 | @@ -2725,6 +2725,7 @@ isc_result_t range2cidr(struct iaddrcidr | |
78ab9b04 MT |
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 *); | |
c1e9ba67 | 374 | @@ -2934,6 +2935,7 @@ void parse_client_lease_declaration (str |
78ab9b04 MT |
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 | ||
c1e9ba67 MF |
382 | diff -up dhcp-4.3.0rc1/includes/dhcp.h.rfc3442 dhcp-4.3.0rc1/includes/dhcp.h |
383 | --- dhcp-4.3.0rc1/includes/dhcp.h.rfc3442 2014-01-26 19:40:44.000000000 +0100 | |
384 | +++ dhcp-4.3.0rc1/includes/dhcp.h 2014-01-29 10:05:48.524399890 +0100 | |
385 | @@ -159,6 +159,7 @@ struct dhcp_packet { | |
78ab9b04 MT |
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 | ||
c1e9ba67 MF |
393 | diff -up dhcp-4.3.0rc1/includes/dhctoken.h.rfc3442 dhcp-4.3.0rc1/includes/dhctoken.h |
394 | --- dhcp-4.3.0rc1/includes/dhctoken.h.rfc3442 2014-01-29 10:05:48.435400713 +0100 | |
395 | +++ dhcp-4.3.0rc1/includes/dhctoken.h 2014-01-29 10:05:48.526399871 +0100 | |
396 | @@ -368,7 +368,8 @@ enum dhcp_token { | |
397 | POOL6 = 669, | |
398 | V6RELAY = 670, | |
399 | V6RELOPT = 671, | |
400 | - BOOTP_BROADCAST_ALWAYS = 672 | |
401 | + BOOTP_BROADCAST_ALWAYS = 672, | |
402 | + DESTINATION_DESCRIPTOR = 673 | |
78ab9b04 MT |
403 | }; |
404 | ||
405 | #define is_identifier(x) ((x) >= FIRST_TOKEN && \ |