]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/blob - src/patches/dhcp-4.2.2-rfc3442-classless-static-routes.patch
media.cgi: Fix typo 'writen'.
[people/teissler/ipfire-2.x.git] / src / patches / dhcp-4.2.2-rfc3442-classless-static-routes.patch
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 && \