1 | /* |
---|
2 | * dhcpcd - DHCP client daemon |
---|
3 | * Copyright (c) 2006-2014 Roy Marples <roy@marples.name> |
---|
4 | * All rights reserved |
---|
5 | |
---|
6 | * Redistribution and use in source and binary forms, with or without |
---|
7 | * modification, are permitted provided that the following conditions |
---|
8 | * are met: |
---|
9 | * 1. Redistributions of source code must retain the above copyright |
---|
10 | * notice, this list of conditions and the following disclaimer. |
---|
11 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
12 | * notice, this list of conditions and the following disclaimer in the |
---|
13 | * documentation and/or other materials provided with the distribution. |
---|
14 | * |
---|
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
---|
16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
---|
19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
25 | * SUCH DAMAGE. |
---|
26 | */ |
---|
27 | |
---|
28 | #include <sys/param.h> |
---|
29 | #include <sys/socket.h> |
---|
30 | #include <sys/stat.h> |
---|
31 | |
---|
32 | #ifdef __linux__ |
---|
33 | # include <asm/types.h> /* for systems with broken headers */ |
---|
34 | # include <linux/rtnetlink.h> |
---|
35 | #endif |
---|
36 | |
---|
37 | #include <arpa/inet.h> |
---|
38 | #include <net/route.h> |
---|
39 | |
---|
40 | #include <netinet/in_systm.h> |
---|
41 | #include <netinet/in.h> |
---|
42 | #include <netinet/ip.h> |
---|
43 | #define __FAVOR_BSD /* Nasty glibc hack so we can use BSD semantics for UDP */ |
---|
44 | #include <netinet/udp.h> |
---|
45 | #undef __FAVOR_BSD |
---|
46 | |
---|
47 | #include <ctype.h> |
---|
48 | #include <errno.h> |
---|
49 | #include <fcntl.h> |
---|
50 | #include <inttypes.h> |
---|
51 | #include <stddef.h> |
---|
52 | #include <stdlib.h> |
---|
53 | #include <string.h> |
---|
54 | #include <syslog.h> |
---|
55 | #include <unistd.h> |
---|
56 | |
---|
57 | #include "config.h" |
---|
58 | #include "arp.h" |
---|
59 | #include "common.h" |
---|
60 | #include "dhcp.h" |
---|
61 | #include "dhcpcd.h" |
---|
62 | #include "dhcp-common.h" |
---|
63 | #include "duid.h" |
---|
64 | #include "eloop.h" |
---|
65 | #include "ipv4.h" |
---|
66 | #include "ipv4ll.h" |
---|
67 | #include "script.h" |
---|
68 | |
---|
69 | #define DAD "Duplicate address detected" |
---|
70 | #define DHCP_MIN_LEASE 20 |
---|
71 | |
---|
72 | static uint8_t *packet; |
---|
73 | |
---|
74 | /* Our aggregate option buffer. |
---|
75 | * We ONLY use this when options are split, which for most purposes is |
---|
76 | * practically never. See RFC3396 for details. */ |
---|
77 | static uint8_t *opt_buffer; |
---|
78 | |
---|
79 | #define IPV4A ADDRIPV4 | ARRAY |
---|
80 | #define IPV4R ADDRIPV4 | REQUEST |
---|
81 | |
---|
82 | /* We should define a maximum for the NAK exponential backoff */ |
---|
83 | #define NAKOFF_MAX 60 |
---|
84 | |
---|
85 | /* Wait N nanoseconds between sending a RELEASE and dropping the address. |
---|
86 | * This gives the kernel enough time to actually send it. */ |
---|
87 | #define RELEASE_DELAY_S 0 |
---|
88 | #define RELEASE_DELAY_NS 10000000 |
---|
89 | |
---|
90 | struct dhcp_op { |
---|
91 | uint8_t value; |
---|
92 | const char *name; |
---|
93 | }; |
---|
94 | |
---|
95 | static const struct dhcp_op dhcp_ops[] = { |
---|
96 | { DHCP_DISCOVER, "DISCOVER" }, |
---|
97 | { DHCP_OFFER, "OFFER" }, |
---|
98 | { DHCP_REQUEST, "REQUEST" }, |
---|
99 | { DHCP_DECLINE, "DECLINE" }, |
---|
100 | { DHCP_ACK, "ACK" }, |
---|
101 | { DHCP_NAK, "NAK" }, |
---|
102 | { DHCP_RELEASE, "RELEASE" }, |
---|
103 | { DHCP_INFORM, "INFORM" }, |
---|
104 | { 0, NULL } |
---|
105 | }; |
---|
106 | |
---|
107 | static const char * const dhcp_params[] = { |
---|
108 | "ip_address", |
---|
109 | "subnet_cidr", |
---|
110 | "network_number", |
---|
111 | "filename", |
---|
112 | "server_name", |
---|
113 | NULL |
---|
114 | }; |
---|
115 | |
---|
116 | struct udp_dhcp_packet |
---|
117 | { |
---|
118 | struct ip ip; |
---|
119 | struct udphdr udp; |
---|
120 | struct dhcp_message dhcp; |
---|
121 | }; |
---|
122 | |
---|
123 | struct dhcp_opt *dhcp_opts = NULL; |
---|
124 | size_t dhcp_opts_len = 0; |
---|
125 | |
---|
126 | static const size_t udp_dhcp_len = sizeof(struct udp_dhcp_packet); |
---|
127 | |
---|
128 | static int dhcp_open(struct interface *); |
---|
129 | |
---|
130 | void |
---|
131 | dhcp_printoptions(void) |
---|
132 | { |
---|
133 | const char * const *p; |
---|
134 | size_t i; |
---|
135 | const struct dhcp_opt *opt; |
---|
136 | |
---|
137 | for (p = dhcp_params; *p; p++) |
---|
138 | printf(" %s\n", *p); |
---|
139 | |
---|
140 | for (i = 0, opt = dhcp_opts; i < dhcp_opts_len; i++, opt++) |
---|
141 | printf("%03d %s\n", opt->option, opt->var); |
---|
142 | } |
---|
143 | |
---|
144 | #ifdef DEBUG_MEMORY |
---|
145 | static void |
---|
146 | dhcp_cleanup(void) |
---|
147 | { |
---|
148 | |
---|
149 | free(packet); |
---|
150 | free(opt_buffer); |
---|
151 | } |
---|
152 | #endif |
---|
153 | |
---|
154 | #define get_option_raw(dhcp, opt) get_option(dhcp, opt, NULL) |
---|
155 | static const uint8_t * |
---|
156 | get_option(const struct dhcp_message *dhcp, uint8_t opt, int *len) |
---|
157 | { |
---|
158 | const uint8_t *p = dhcp->options; |
---|
159 | const uint8_t *e = p + sizeof(dhcp->options); |
---|
160 | uint8_t l, ol = 0; |
---|
161 | uint8_t o = 0; |
---|
162 | uint8_t overl = 0; |
---|
163 | uint8_t *bp = NULL; |
---|
164 | const uint8_t *op = NULL; |
---|
165 | int bl = 0; |
---|
166 | |
---|
167 | while (p < e) { |
---|
168 | o = *p++; |
---|
169 | if (o == opt) { |
---|
170 | if (op) { |
---|
171 | if (!opt_buffer) { |
---|
172 | opt_buffer = malloc(sizeof(*dhcp)); |
---|
173 | if (opt_buffer == NULL) |
---|
174 | return NULL; |
---|
175 | } |
---|
176 | if (!bp) |
---|
177 | bp = opt_buffer; |
---|
178 | memcpy(bp, op, ol); |
---|
179 | bp += ol; |
---|
180 | } |
---|
181 | ol = *p; |
---|
182 | if (p + ol > e) { |
---|
183 | errno = EINVAL; |
---|
184 | return NULL; |
---|
185 | } |
---|
186 | op = p + 1; |
---|
187 | bl += ol; |
---|
188 | } |
---|
189 | switch (o) { |
---|
190 | case DHO_PAD: |
---|
191 | continue; |
---|
192 | case DHO_END: |
---|
193 | if (overl & 1) { |
---|
194 | /* bit 1 set means parse boot file */ |
---|
195 | overl &= ~1; |
---|
196 | p = dhcp->bootfile; |
---|
197 | e = p + sizeof(dhcp->bootfile); |
---|
198 | } else if (overl & 2) { |
---|
199 | /* bit 2 set means parse server name */ |
---|
200 | overl &= ~2; |
---|
201 | p = dhcp->servername; |
---|
202 | e = p + sizeof(dhcp->servername); |
---|
203 | } else |
---|
204 | goto exit; |
---|
205 | break; |
---|
206 | case DHO_OPTIONSOVERLOADED: |
---|
207 | /* Ensure we only get this option once */ |
---|
208 | if (!overl) |
---|
209 | overl = p[1]; |
---|
210 | break; |
---|
211 | } |
---|
212 | l = *p++; |
---|
213 | p += l; |
---|
214 | } |
---|
215 | |
---|
216 | exit: |
---|
217 | if (len) |
---|
218 | *len = bl; |
---|
219 | if (bp) { |
---|
220 | memcpy(bp, op, ol); |
---|
221 | return (const uint8_t *)opt_buffer; |
---|
222 | } |
---|
223 | if (op) |
---|
224 | return op; |
---|
225 | errno = ENOENT; |
---|
226 | return NULL; |
---|
227 | } |
---|
228 | |
---|
229 | int |
---|
230 | get_option_addr(struct in_addr *a, const struct dhcp_message *dhcp, |
---|
231 | uint8_t option) |
---|
232 | { |
---|
233 | const uint8_t *p; |
---|
234 | int len; |
---|
235 | |
---|
236 | p = get_option(dhcp, option, &len); |
---|
237 | if (!p || len < (ssize_t)sizeof(a->s_addr)) |
---|
238 | return -1; |
---|
239 | memcpy(&a->s_addr, p, sizeof(a->s_addr)); |
---|
240 | return 0; |
---|
241 | } |
---|
242 | |
---|
243 | static int |
---|
244 | get_option_uint32(uint32_t *i, const struct dhcp_message *dhcp, uint8_t option) |
---|
245 | { |
---|
246 | const uint8_t *p; |
---|
247 | int len; |
---|
248 | uint32_t d; |
---|
249 | |
---|
250 | p = get_option(dhcp, option, &len); |
---|
251 | if (!p || len < (ssize_t)sizeof(d)) |
---|
252 | return -1; |
---|
253 | memcpy(&d, p, sizeof(d)); |
---|
254 | if (i) |
---|
255 | *i = ntohl(d); |
---|
256 | return 0; |
---|
257 | } |
---|
258 | |
---|
259 | static int |
---|
260 | get_option_uint8(uint8_t *i, const struct dhcp_message *dhcp, uint8_t option) |
---|
261 | { |
---|
262 | const uint8_t *p; |
---|
263 | int len; |
---|
264 | |
---|
265 | p = get_option(dhcp, option, &len); |
---|
266 | if (!p || len < (ssize_t)sizeof(*p)) |
---|
267 | return -1; |
---|
268 | if (i) |
---|
269 | *i = *(p); |
---|
270 | return 0; |
---|
271 | } |
---|
272 | |
---|
273 | ssize_t |
---|
274 | decode_rfc3442(char *out, ssize_t len, int pl, const uint8_t *p) |
---|
275 | { |
---|
276 | const uint8_t *e; |
---|
277 | ssize_t b, bytes = 0, ocets; |
---|
278 | uint8_t cidr; |
---|
279 | struct in_addr addr; |
---|
280 | char *o = out; |
---|
281 | |
---|
282 | /* Minimum is 5 -first is CIDR and a router length of 4 */ |
---|
283 | if (pl < 5) { |
---|
284 | errno = EINVAL; |
---|
285 | return -1; |
---|
286 | } |
---|
287 | |
---|
288 | e = p + pl; |
---|
289 | while (p < e) { |
---|
290 | cidr = *p++; |
---|
291 | if (cidr > 32) { |
---|
292 | errno = EINVAL; |
---|
293 | return -1; |
---|
294 | } |
---|
295 | ocets = (cidr + 7) / 8; |
---|
296 | if (!out) { |
---|
297 | p += 4 + ocets; |
---|
298 | bytes += ((4 * 4) * 2) + 4; |
---|
299 | continue; |
---|
300 | } |
---|
301 | if ((((4 * 4) * 2) + 4) > len) { |
---|
302 | errno = ENOBUFS; |
---|
303 | return -1; |
---|
304 | } |
---|
305 | if (o != out) { |
---|
306 | *o++ = ' '; |
---|
307 | len--; |
---|
308 | } |
---|
309 | /* If we have ocets then we have a destination and netmask */ |
---|
310 | if (ocets > 0) { |
---|
311 | addr.s_addr = 0; |
---|
312 | memcpy(&addr.s_addr, p, ocets); |
---|
313 | b = snprintf(o, len, "%s/%d", inet_ntoa(addr), cidr); |
---|
314 | p += ocets; |
---|
315 | } else |
---|
316 | b = snprintf(o, len, "0.0.0.0/0"); |
---|
317 | o += b; |
---|
318 | len -= b; |
---|
319 | |
---|
320 | /* Finally, snag the router */ |
---|
321 | memcpy(&addr.s_addr, p, 4); |
---|
322 | p += 4; |
---|
323 | b = snprintf(o, len, " %s", inet_ntoa(addr)); |
---|
324 | o += b; |
---|
325 | len -= b; |
---|
326 | } |
---|
327 | |
---|
328 | if (out) |
---|
329 | return o - out; |
---|
330 | return bytes; |
---|
331 | } |
---|
332 | |
---|
333 | static struct rt_head * |
---|
334 | decode_rfc3442_rt(int dl, const uint8_t *data) |
---|
335 | { |
---|
336 | const uint8_t *p = data; |
---|
337 | const uint8_t *e; |
---|
338 | uint8_t cidr; |
---|
339 | size_t ocets; |
---|
340 | struct rt_head *routes; |
---|
341 | struct rt *rt = NULL; |
---|
342 | |
---|
343 | /* Minimum is 5 -first is CIDR and a router length of 4 */ |
---|
344 | if (dl < 5) |
---|
345 | return NULL; |
---|
346 | |
---|
347 | routes = malloc(sizeof(*routes)); |
---|
348 | TAILQ_INIT(routes); |
---|
349 | e = p + dl; |
---|
350 | while (p < e) { |
---|
351 | cidr = *p++; |
---|
352 | if (cidr > 32) { |
---|
353 | ipv4_freeroutes(routes); |
---|
354 | errno = EINVAL; |
---|
355 | return NULL; |
---|
356 | } |
---|
357 | |
---|
358 | rt = calloc(1, sizeof(*rt)); |
---|
359 | if (rt == NULL) { |
---|
360 | syslog(LOG_ERR, "%s: %m", __func__); |
---|
361 | ipv4_freeroutes(routes); |
---|
362 | return NULL; |
---|
363 | } |
---|
364 | TAILQ_INSERT_TAIL(routes, rt, next); |
---|
365 | |
---|
366 | ocets = (cidr + 7) / 8; |
---|
367 | /* If we have ocets then we have a destination and netmask */ |
---|
368 | if (ocets > 0) { |
---|
369 | memcpy(&rt->dest.s_addr, p, ocets); |
---|
370 | p += ocets; |
---|
371 | rt->net.s_addr = htonl(~0U << (32 - cidr)); |
---|
372 | } |
---|
373 | |
---|
374 | /* Finally, snag the router */ |
---|
375 | memcpy(&rt->gate.s_addr, p, 4); |
---|
376 | p += 4; |
---|
377 | } |
---|
378 | return routes; |
---|
379 | } |
---|
380 | |
---|
381 | char * |
---|
382 | decode_rfc3361(int dl, const uint8_t *data) |
---|
383 | { |
---|
384 | uint8_t enc; |
---|
385 | unsigned int l; |
---|
386 | char *sip = NULL; |
---|
387 | struct in_addr addr; |
---|
388 | char *p; |
---|
389 | |
---|
390 | if (dl < 2) { |
---|
391 | errno = EINVAL; |
---|
392 | return 0; |
---|
393 | } |
---|
394 | |
---|
395 | enc = *data++; |
---|
396 | dl--; |
---|
397 | switch (enc) { |
---|
398 | case 0: |
---|
399 | if ((l = decode_rfc3397(NULL, 0, dl, data)) > 0) { |
---|
400 | sip = malloc(l); |
---|
401 | if (sip == NULL) |
---|
402 | return 0; |
---|
403 | decode_rfc3397(sip, l, dl, data); |
---|
404 | } |
---|
405 | break; |
---|
406 | case 1: |
---|
407 | if (dl == 0 || dl % 4 != 0) { |
---|
408 | errno = EINVAL; |
---|
409 | break; |
---|
410 | } |
---|
411 | addr.s_addr = INADDR_BROADCAST; |
---|
412 | l = ((dl / sizeof(addr.s_addr)) * ((4 * 4) + 1)) + 1; |
---|
413 | sip = p = malloc(l); |
---|
414 | if (sip == NULL) |
---|
415 | return 0; |
---|
416 | while (dl != 0) { |
---|
417 | memcpy(&addr.s_addr, data, sizeof(addr.s_addr)); |
---|
418 | data += sizeof(addr.s_addr); |
---|
419 | p += snprintf(p, l - (p - sip), "%s ", inet_ntoa(addr)); |
---|
420 | dl -= sizeof(addr.s_addr); |
---|
421 | } |
---|
422 | *--p = '\0'; |
---|
423 | break; |
---|
424 | default: |
---|
425 | errno = EINVAL; |
---|
426 | return 0; |
---|
427 | } |
---|
428 | |
---|
429 | return sip; |
---|
430 | } |
---|
431 | |
---|
432 | /* Decode an RFC5969 6rd order option into a space |
---|
433 | * separated string. Returns length of string (including |
---|
434 | * terminating zero) or zero on error. */ |
---|
435 | ssize_t |
---|
436 | decode_rfc5969(char *out, ssize_t len, int pl, const uint8_t *p) |
---|
437 | { |
---|
438 | uint8_t ipv4masklen, ipv6prefixlen; |
---|
439 | uint8_t ipv6prefix[16]; |
---|
440 | uint8_t br[4]; |
---|
441 | int i; |
---|
442 | ssize_t b, bytes = 0; |
---|
443 | |
---|
444 | if (pl < 22) { |
---|
445 | errno = EINVAL; |
---|
446 | return 0; |
---|
447 | } |
---|
448 | |
---|
449 | ipv4masklen = *p++; |
---|
450 | pl--; |
---|
451 | ipv6prefixlen = *p++; |
---|
452 | pl--; |
---|
453 | |
---|
454 | for (i = 0; i < 16; i++) { |
---|
455 | ipv6prefix[i] = *p++; |
---|
456 | pl--; |
---|
457 | } |
---|
458 | if (out) { |
---|
459 | b= snprintf(out, len, |
---|
460 | "%d %d " |
---|
461 | "%02x%02x:%02x%02x:" |
---|
462 | "%02x%02x:%02x%02x:" |
---|
463 | "%02x%02x:%02x%02x:" |
---|
464 | "%02x%02x:%02x%02x", |
---|
465 | ipv4masklen, ipv6prefixlen, |
---|
466 | ipv6prefix[0], ipv6prefix[1], ipv6prefix[2], ipv6prefix[3], |
---|
467 | ipv6prefix[4], ipv6prefix[5], ipv6prefix[6], ipv6prefix[7], |
---|
468 | ipv6prefix[8], ipv6prefix[9], ipv6prefix[10],ipv6prefix[11], |
---|
469 | ipv6prefix[12],ipv6prefix[13],ipv6prefix[14], ipv6prefix[15] |
---|
470 | ); |
---|
471 | |
---|
472 | len -= b; |
---|
473 | out += b; |
---|
474 | bytes += b; |
---|
475 | } else { |
---|
476 | bytes += 16 * 2 + 8 + 2 + 1 + 2; |
---|
477 | } |
---|
478 | |
---|
479 | while (pl >= 4) { |
---|
480 | br[0] = *p++; |
---|
481 | br[1] = *p++; |
---|
482 | br[2] = *p++; |
---|
483 | br[3] = *p++; |
---|
484 | pl -= 4; |
---|
485 | |
---|
486 | if (out) { |
---|
487 | b= snprintf(out, len, " %d.%d.%d.%d", |
---|
488 | br[0], br[1], br[2], br[3]); |
---|
489 | len -= b; |
---|
490 | out += b; |
---|
491 | bytes += b; |
---|
492 | } else { |
---|
493 | bytes += (4 * 4); |
---|
494 | } |
---|
495 | } |
---|
496 | |
---|
497 | return bytes; |
---|
498 | } |
---|
499 | |
---|
500 | char * |
---|
501 | get_option_string(const struct dhcp_message *dhcp, uint8_t option) |
---|
502 | { |
---|
503 | int len; |
---|
504 | const uint8_t *p; |
---|
505 | char *s; |
---|
506 | |
---|
507 | p = get_option(dhcp, option, &len); |
---|
508 | if (!p || len == 0 || *p == '\0') |
---|
509 | return NULL; |
---|
510 | |
---|
511 | s = malloc(sizeof(char) * (len + 1)); |
---|
512 | if (s) { |
---|
513 | memcpy(s, p, len); |
---|
514 | s[len] = '\0'; |
---|
515 | } |
---|
516 | return s; |
---|
517 | } |
---|
518 | |
---|
519 | /* This calculates the netmask that we should use for static routes. |
---|
520 | * This IS different from the calculation used to calculate the netmask |
---|
521 | * for an interface address. */ |
---|
522 | static uint32_t |
---|
523 | route_netmask(uint32_t ip_in) |
---|
524 | { |
---|
525 | /* used to be unsigned long - check if error */ |
---|
526 | uint32_t p = ntohl(ip_in); |
---|
527 | uint32_t t; |
---|
528 | |
---|
529 | if (IN_CLASSA(p)) |
---|
530 | t = ~IN_CLASSA_NET; |
---|
531 | else { |
---|
532 | if (IN_CLASSB(p)) |
---|
533 | t = ~IN_CLASSB_NET; |
---|
534 | else { |
---|
535 | if (IN_CLASSC(p)) |
---|
536 | t = ~IN_CLASSC_NET; |
---|
537 | else |
---|
538 | t = 0; |
---|
539 | } |
---|
540 | } |
---|
541 | |
---|
542 | while (t & p) |
---|
543 | t >>= 1; |
---|
544 | |
---|
545 | return (htonl(~t)); |
---|
546 | } |
---|
547 | |
---|
548 | /* We need to obey routing options. |
---|
549 | * If we have a CSR then we only use that. |
---|
550 | * Otherwise we add static routes and then routers. */ |
---|
551 | struct rt_head * |
---|
552 | get_option_routes(struct interface *ifp, const struct dhcp_message *dhcp) |
---|
553 | { |
---|
554 | struct if_options *ifo = ifp->options; |
---|
555 | const uint8_t *p; |
---|
556 | const uint8_t *e; |
---|
557 | struct rt_head *routes = NULL; |
---|
558 | struct rt *route = NULL; |
---|
559 | int len; |
---|
560 | const char *csr = ""; |
---|
561 | |
---|
562 | /* If we have CSR's then we MUST use these only */ |
---|
563 | if (!has_option_mask(ifo->nomask, DHO_CSR)) |
---|
564 | p = get_option(dhcp, DHO_CSR, &len); |
---|
565 | else |
---|
566 | p = NULL; |
---|
567 | /* Check for crappy MS option */ |
---|
568 | if (!p && !has_option_mask(ifo->nomask, DHO_MSCSR)) { |
---|
569 | p = get_option(dhcp, DHO_MSCSR, &len); |
---|
570 | if (p) |
---|
571 | csr = "MS "; |
---|
572 | } |
---|
573 | if (p) { |
---|
574 | routes = decode_rfc3442_rt(len, p); |
---|
575 | if (routes) { |
---|
576 | if (!(ifo->options & DHCPCD_CSR_WARNED)) { |
---|
577 | syslog(LOG_DEBUG, |
---|
578 | "%s: using %sClassless Static Routes", |
---|
579 | ifp->name, csr); |
---|
580 | ifo->options |= DHCPCD_CSR_WARNED; |
---|
581 | } |
---|
582 | return routes; |
---|
583 | } |
---|
584 | } |
---|
585 | |
---|
586 | /* OK, get our static routes first. */ |
---|
587 | routes = malloc(sizeof(*routes)); |
---|
588 | if (routes == NULL) { |
---|
589 | syslog(LOG_ERR, "%s: %m", __func__); |
---|
590 | return NULL; |
---|
591 | } |
---|
592 | TAILQ_INIT(routes); |
---|
593 | if (!has_option_mask(ifo->nomask, DHO_STATICROUTE)) |
---|
594 | p = get_option(dhcp, DHO_STATICROUTE, &len); |
---|
595 | else |
---|
596 | p = NULL; |
---|
597 | if (p) { |
---|
598 | e = p + len; |
---|
599 | while (p < e) { |
---|
600 | route = calloc(1, sizeof(*route)); |
---|
601 | if (route == NULL) { |
---|
602 | syslog(LOG_ERR, "%s: %m", __func__); |
---|
603 | ipv4_freeroutes(routes); |
---|
604 | return NULL; |
---|
605 | } |
---|
606 | memcpy(&route->dest.s_addr, p, 4); |
---|
607 | p += 4; |
---|
608 | memcpy(&route->gate.s_addr, p, 4); |
---|
609 | p += 4; |
---|
610 | route->net.s_addr = route_netmask(route->dest.s_addr); |
---|
611 | TAILQ_INSERT_TAIL(routes, route, next); |
---|
612 | } |
---|
613 | } |
---|
614 | |
---|
615 | /* Now grab our routers */ |
---|
616 | if (!has_option_mask(ifo->nomask, DHO_ROUTER)) |
---|
617 | p = get_option(dhcp, DHO_ROUTER, &len); |
---|
618 | else |
---|
619 | p = NULL; |
---|
620 | if (p) { |
---|
621 | e = p + len; |
---|
622 | while (p < e) { |
---|
623 | route = calloc(1, sizeof(*route)); |
---|
624 | if (route == NULL) { |
---|
625 | syslog(LOG_ERR, "%s: %m", __func__); |
---|
626 | ipv4_freeroutes(routes); |
---|
627 | return NULL; |
---|
628 | } |
---|
629 | memcpy(&route->gate.s_addr, p, 4); |
---|
630 | p += 4; |
---|
631 | TAILQ_INSERT_TAIL(routes, route, next); |
---|
632 | } |
---|
633 | } |
---|
634 | |
---|
635 | return routes; |
---|
636 | } |
---|
637 | |
---|
638 | #define PUTADDR(_type, _val) \ |
---|
639 | { \ |
---|
640 | *p++ = _type; \ |
---|
641 | *p++ = 4; \ |
---|
642 | memcpy(p, &_val.s_addr, 4); \ |
---|
643 | p += 4; \ |
---|
644 | } |
---|
645 | |
---|
646 | int |
---|
647 | dhcp_message_add_addr(struct dhcp_message *dhcp, |
---|
648 | uint8_t type, struct in_addr addr) |
---|
649 | { |
---|
650 | uint8_t *p; |
---|
651 | size_t len; |
---|
652 | |
---|
653 | p = dhcp->options; |
---|
654 | while (*p != DHO_END) { |
---|
655 | p++; |
---|
656 | p += *p + 1; |
---|
657 | } |
---|
658 | |
---|
659 | len = p - (uint8_t *)dhcp; |
---|
660 | if (len + 6 > sizeof(*dhcp)) { |
---|
661 | errno = ENOMEM; |
---|
662 | return -1; |
---|
663 | } |
---|
664 | |
---|
665 | PUTADDR(type, addr); |
---|
666 | *p = DHO_END; |
---|
667 | return 0; |
---|
668 | } |
---|
669 | |
---|
670 | ssize_t |
---|
671 | make_message(struct dhcp_message **message, |
---|
672 | const struct interface *iface, |
---|
673 | uint8_t type) |
---|
674 | { |
---|
675 | struct dhcp_message *dhcp; |
---|
676 | uint8_t *m, *lp, *p, *auth; |
---|
677 | uint8_t *n_params = NULL; |
---|
678 | uint32_t ul; |
---|
679 | uint16_t sz; |
---|
680 | size_t len, i; |
---|
681 | int auth_len; |
---|
682 | const struct dhcp_opt *opt; |
---|
683 | const struct if_options *ifo = iface->options; |
---|
684 | const struct dhcp_state *state = D_CSTATE(iface); |
---|
685 | const struct dhcp_lease *lease = &state->lease; |
---|
686 | time_t up = uptime() - state->start_uptime; |
---|
687 | const char *hostname; |
---|
688 | const struct vivco *vivco; |
---|
689 | |
---|
690 | dhcp = calloc(1, sizeof (*dhcp)); |
---|
691 | if (dhcp == NULL) |
---|
692 | return -1; |
---|
693 | m = (uint8_t *)dhcp; |
---|
694 | p = dhcp->options; |
---|
695 | |
---|
696 | if ((type == DHCP_INFORM || type == DHCP_RELEASE || |
---|
697 | (type == DHCP_REQUEST && |
---|
698 | state->net.s_addr == lease->net.s_addr && |
---|
699 | (state->new == NULL || |
---|
700 | state->new->cookie == htonl(MAGIC_COOKIE))))) |
---|
701 | { |
---|
702 | dhcp->ciaddr = state->addr.s_addr; |
---|
703 | /* In-case we haven't actually configured the address yet */ |
---|
704 | if (type == DHCP_INFORM && state->addr.s_addr == 0) |
---|
705 | dhcp->ciaddr = lease->addr.s_addr; |
---|
706 | } |
---|
707 | |
---|
708 | dhcp->op = DHCP_BOOTREQUEST; |
---|
709 | dhcp->hwtype = iface->family; |
---|
710 | switch (iface->family) { |
---|
711 | case ARPHRD_ETHER: |
---|
712 | case ARPHRD_IEEE802: |
---|
713 | dhcp->hwlen = iface->hwlen; |
---|
714 | memcpy(&dhcp->chaddr, &iface->hwaddr, iface->hwlen); |
---|
715 | break; |
---|
716 | } |
---|
717 | |
---|
718 | if (ifo->options & DHCPCD_BROADCAST && |
---|
719 | dhcp->ciaddr == 0 && |
---|
720 | type != DHCP_DECLINE && |
---|
721 | type != DHCP_RELEASE) |
---|
722 | dhcp->flags = htons(BROADCAST_FLAG); |
---|
723 | |
---|
724 | if (type != DHCP_DECLINE && type != DHCP_RELEASE) { |
---|
725 | if (up < 0 || up > (time_t)UINT16_MAX) |
---|
726 | dhcp->secs = htons((uint16_t)UINT16_MAX); |
---|
727 | else |
---|
728 | dhcp->secs = htons(up); |
---|
729 | } |
---|
730 | dhcp->xid = htonl(state->xid); |
---|
731 | dhcp->cookie = htonl(MAGIC_COOKIE); |
---|
732 | |
---|
733 | *p++ = DHO_MESSAGETYPE; |
---|
734 | *p++ = 1; |
---|
735 | *p++ = type; |
---|
736 | |
---|
737 | if (state->clientid) { |
---|
738 | *p++ = DHO_CLIENTID; |
---|
739 | memcpy(p, state->clientid, state->clientid[0] + 1); |
---|
740 | p += state->clientid[0] + 1; |
---|
741 | } |
---|
742 | |
---|
743 | if (lease->addr.s_addr && lease->cookie == htonl(MAGIC_COOKIE)) { |
---|
744 | if (type == DHCP_DECLINE || |
---|
745 | (type == DHCP_REQUEST && |
---|
746 | lease->addr.s_addr != state->addr.s_addr)) |
---|
747 | { |
---|
748 | PUTADDR(DHO_IPADDRESS, lease->addr); |
---|
749 | if (lease->server.s_addr) |
---|
750 | PUTADDR(DHO_SERVERID, lease->server); |
---|
751 | } |
---|
752 | |
---|
753 | if (type == DHCP_RELEASE) { |
---|
754 | if (lease->server.s_addr) |
---|
755 | PUTADDR(DHO_SERVERID, lease->server); |
---|
756 | } |
---|
757 | } |
---|
758 | |
---|
759 | if (type == DHCP_DECLINE) { |
---|
760 | *p++ = DHO_MESSAGE; |
---|
761 | len = strlen(DAD); |
---|
762 | *p++ = len; |
---|
763 | memcpy(p, DAD, len); |
---|
764 | p += len; |
---|
765 | } |
---|
766 | |
---|
767 | if (type == DHCP_DISCOVER && |
---|
768 | !(options & DHCPCD_TEST) && |
---|
769 | has_option_mask(ifo->requestmask, DHO_RAPIDCOMMIT)) |
---|
770 | { |
---|
771 | /* RFC 4039 Section 3 */ |
---|
772 | *p++ = DHO_RAPIDCOMMIT; |
---|
773 | *p++ = 0; |
---|
774 | } |
---|
775 | |
---|
776 | if (type == DHCP_DISCOVER && ifo->options & DHCPCD_REQUEST) |
---|
777 | PUTADDR(DHO_IPADDRESS, ifo->req_addr); |
---|
778 | |
---|
779 | if (type == DHCP_DISCOVER || |
---|
780 | type == DHCP_INFORM || |
---|
781 | type == DHCP_REQUEST) |
---|
782 | { |
---|
783 | *p++ = DHO_MAXMESSAGESIZE; |
---|
784 | *p++ = 2; |
---|
785 | sz = get_mtu(iface->name); |
---|
786 | if (sz < MTU_MIN) { |
---|
787 | if (set_mtu(iface->name, MTU_MIN) == 0) |
---|
788 | sz = MTU_MIN; |
---|
789 | } else if (sz > MTU_MAX) { |
---|
790 | /* Even though our MTU could be greater than |
---|
791 | * MTU_MAX (1500) dhcpcd does not presently |
---|
792 | * handle DHCP packets any bigger. */ |
---|
793 | sz = MTU_MAX; |
---|
794 | } |
---|
795 | sz = htons(sz); |
---|
796 | memcpy(p, &sz, 2); |
---|
797 | p += 2; |
---|
798 | |
---|
799 | if (ifo->userclass[0]) { |
---|
800 | *p++ = DHO_USERCLASS; |
---|
801 | memcpy(p, ifo->userclass, ifo->userclass[0] + 1); |
---|
802 | p += ifo->userclass[0] + 1; |
---|
803 | } |
---|
804 | |
---|
805 | if (ifo->vendorclassid[0]) { |
---|
806 | *p++ = DHO_VENDORCLASSID; |
---|
807 | memcpy(p, ifo->vendorclassid, |
---|
808 | ifo->vendorclassid[0] + 1); |
---|
809 | p += ifo->vendorclassid[0] + 1; |
---|
810 | } |
---|
811 | |
---|
812 | |
---|
813 | if (type != DHCP_INFORM) { |
---|
814 | if (ifo->leasetime != 0) { |
---|
815 | *p++ = DHO_LEASETIME; |
---|
816 | *p++ = 4; |
---|
817 | ul = htonl(ifo->leasetime); |
---|
818 | memcpy(p, &ul, 4); |
---|
819 | p += 4; |
---|
820 | } |
---|
821 | } |
---|
822 | |
---|
823 | if (ifo->hostname[0] == '\0') |
---|
824 | hostname = get_hostname(ifo->options & |
---|
825 | DHCPCD_HOSTNAME_SHORT ? 1 : 0); |
---|
826 | else |
---|
827 | hostname = ifo->hostname; |
---|
828 | if (ifo->fqdn != FQDN_DISABLE) { |
---|
829 | /* IETF DHC-FQDN option (81), RFC4702 */ |
---|
830 | *p++ = DHO_FQDN; |
---|
831 | lp = p; |
---|
832 | *p++ = 3; |
---|
833 | /* |
---|
834 | * Flags: 0000NEOS |
---|
835 | * S: 1 => Client requests Server to update |
---|
836 | * a RR in DNS as well as PTR |
---|
837 | * O: 1 => Server indicates to client that |
---|
838 | * DNS has been updated |
---|
839 | * E: 1 => Name data is DNS format |
---|
840 | * N: 1 => Client requests Server to not |
---|
841 | * update DNS |
---|
842 | */ |
---|
843 | if (hostname) |
---|
844 | *p++ = (ifo->fqdn & 0x09) | 0x04; |
---|
845 | else |
---|
846 | *p++ = (FQDN_NONE & 0x09) | 0x04; |
---|
847 | *p++ = 0; /* from server for PTR RR */ |
---|
848 | *p++ = 0; /* from server for A RR if S=1 */ |
---|
849 | if (hostname) { |
---|
850 | ul = encode_rfc1035(hostname, p); |
---|
851 | *lp += ul; |
---|
852 | p += ul; |
---|
853 | } |
---|
854 | } else if (ifo->options & DHCPCD_HOSTNAME && hostname) { |
---|
855 | *p++ = DHO_HOSTNAME; |
---|
856 | len = strlen(hostname); |
---|
857 | *p++ = len; |
---|
858 | memcpy(p, hostname, len); |
---|
859 | p += len; |
---|
860 | } |
---|
861 | |
---|
862 | /* vendor is already encoded correctly, so just add it */ |
---|
863 | if (ifo->vendor[0]) { |
---|
864 | *p++ = DHO_VENDOR; |
---|
865 | memcpy(p, ifo->vendor, ifo->vendor[0] + 1); |
---|
866 | p += ifo->vendor[0] + 1; |
---|
867 | } |
---|
868 | |
---|
869 | if (ifo->vivco_len) { |
---|
870 | *p++ = DHO_VIVCO; |
---|
871 | lp = p++; |
---|
872 | *lp = sizeof(ul); |
---|
873 | ul = htonl(ifo->vivco_en); |
---|
874 | memcpy(p, &ul, sizeof(ul)); |
---|
875 | p += sizeof(ul); |
---|
876 | for (i = 0, vivco = ifo->vivco; |
---|
877 | i < ifo->vivco_len; |
---|
878 | i++, vivco++) |
---|
879 | { |
---|
880 | len = (p - m) + vivco->len + 1; |
---|
881 | if (len > sizeof(*dhcp)) |
---|
882 | goto toobig; |
---|
883 | if (vivco->len + 2 + *lp > 255) { |
---|
884 | syslog(LOG_ERR, |
---|
885 | "%s: VIVCO option too big", |
---|
886 | iface->name); |
---|
887 | free(dhcp); |
---|
888 | return -1; |
---|
889 | } |
---|
890 | *p++ = (uint8_t)vivco->len; |
---|
891 | memcpy(p, vivco->data, vivco->len); |
---|
892 | p += vivco->len; |
---|
893 | *lp += (uint8_t)vivco->len + 1; |
---|
894 | } |
---|
895 | } |
---|
896 | |
---|
897 | len = (p - m) + 3; |
---|
898 | if (len > sizeof(*dhcp)) |
---|
899 | goto toobig; |
---|
900 | *p++ = DHO_PARAMETERREQUESTLIST; |
---|
901 | n_params = p; |
---|
902 | *p++ = 0; |
---|
903 | for (i = 0, opt = dhcp_opts; i < dhcp_opts_len; i++, opt++) { |
---|
904 | if (!(opt->type & REQUEST || |
---|
905 | has_option_mask(ifo->requestmask, opt->option))) |
---|
906 | continue; |
---|
907 | if (opt->type & NOREQ) |
---|
908 | continue; |
---|
909 | if (type == DHCP_INFORM && |
---|
910 | (opt->option == DHO_RENEWALTIME || |
---|
911 | opt->option == DHO_REBINDTIME)) |
---|
912 | continue; |
---|
913 | len = (p - m) + 2; |
---|
914 | if (len > sizeof(*dhcp)) |
---|
915 | goto toobig; |
---|
916 | *p++ = opt->option; |
---|
917 | } |
---|
918 | *n_params = p - n_params - 1; |
---|
919 | } |
---|
920 | |
---|
921 | /* silence GCC */ |
---|
922 | auth_len = 0; |
---|
923 | auth = NULL; |
---|
924 | |
---|
925 | if (ifo->auth.options & DHCPCD_AUTH_SEND) { |
---|
926 | auth_len = dhcp_auth_encode(&ifo->auth, state->auth.token, |
---|
927 | NULL, 0, 4, type, NULL, 0); |
---|
928 | if (auth_len > 0) { |
---|
929 | len = (p + auth_len) - m; |
---|
930 | if (auth_len > 255 || len > sizeof(*dhcp)) |
---|
931 | goto toobig; |
---|
932 | *p++ = DHO_AUTHENTICATION; |
---|
933 | *p++ = (uint8_t)auth_len; |
---|
934 | auth = p; |
---|
935 | p += auth_len; |
---|
936 | } else if (auth_len == -1) |
---|
937 | syslog(LOG_ERR, "%s: dhcp_auth_encode: %m", |
---|
938 | iface->name); |
---|
939 | } |
---|
940 | |
---|
941 | *p++ = DHO_END; |
---|
942 | |
---|
943 | #ifdef BOOTP_MESSAGE_LENTH_MIN |
---|
944 | /* Some crappy DHCP servers think they have to obey the BOOTP minimum |
---|
945 | * message length. |
---|
946 | * They are wrong, but we should still cater for them. */ |
---|
947 | while (p - m < BOOTP_MESSAGE_LENTH_MIN) |
---|
948 | *p++ = DHO_PAD; |
---|
949 | #endif |
---|
950 | |
---|
951 | len = p - m; |
---|
952 | if (ifo->auth.options & DHCPCD_AUTH_SEND && auth_len > 0) |
---|
953 | dhcp_auth_encode(&ifo->auth, state->auth.token, |
---|
954 | m, len, 4, type, auth, auth_len); |
---|
955 | |
---|
956 | *message = dhcp; |
---|
957 | return len; |
---|
958 | |
---|
959 | toobig: |
---|
960 | syslog(LOG_ERR, "%s: DHCP messge too big", iface->name); |
---|
961 | free(dhcp); |
---|
962 | return -1; |
---|
963 | } |
---|
964 | |
---|
965 | ssize_t |
---|
966 | write_lease(const struct interface *ifp, const struct dhcp_message *dhcp) |
---|
967 | { |
---|
968 | int fd; |
---|
969 | ssize_t bytes = sizeof(*dhcp); |
---|
970 | const uint8_t *p = dhcp->options; |
---|
971 | const uint8_t *e = p + sizeof(dhcp->options); |
---|
972 | uint8_t l; |
---|
973 | uint8_t o = 0; |
---|
974 | const struct dhcp_state *state = D_CSTATE(ifp); |
---|
975 | |
---|
976 | /* We don't write BOOTP leases */ |
---|
977 | if (is_bootp(dhcp)) { |
---|
978 | unlink(state->leasefile); |
---|
979 | return 0; |
---|
980 | } |
---|
981 | |
---|
982 | syslog(LOG_DEBUG, "%s: writing lease `%s'", |
---|
983 | ifp->name, state->leasefile); |
---|
984 | |
---|
985 | fd = open(state->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0644); |
---|
986 | if (fd == -1) |
---|
987 | return -1; |
---|
988 | |
---|
989 | /* Only write as much as we need */ |
---|
990 | while (p < e) { |
---|
991 | o = *p; |
---|
992 | if (o == DHO_END) { |
---|
993 | bytes = p - (const uint8_t *)dhcp; |
---|
994 | break; |
---|
995 | } |
---|
996 | p++; |
---|
997 | if (o != DHO_PAD) { |
---|
998 | l = *p++; |
---|
999 | p += l; |
---|
1000 | } |
---|
1001 | } |
---|
1002 | bytes = write(fd, dhcp, bytes); |
---|
1003 | close(fd); |
---|
1004 | return bytes; |
---|
1005 | } |
---|
1006 | |
---|
1007 | struct dhcp_message * |
---|
1008 | read_lease(struct interface *ifp) |
---|
1009 | { |
---|
1010 | int fd; |
---|
1011 | struct dhcp_message *dhcp; |
---|
1012 | struct dhcp_state *state = D_STATE(ifp); |
---|
1013 | ssize_t bytes; |
---|
1014 | const uint8_t *auth; |
---|
1015 | uint8_t type; |
---|
1016 | int auth_len; |
---|
1017 | |
---|
1018 | fd = open(state->leasefile, O_RDONLY); |
---|
1019 | if (fd == -1) { |
---|
1020 | if (errno != ENOENT) |
---|
1021 | syslog(LOG_ERR, "%s: open `%s': %m", |
---|
1022 | ifp->name, state->leasefile); |
---|
1023 | return NULL; |
---|
1024 | } |
---|
1025 | syslog(LOG_DEBUG, "%s: reading lease `%s'", |
---|
1026 | ifp->name, state->leasefile); |
---|
1027 | dhcp = calloc(1, sizeof(*dhcp)); |
---|
1028 | if (dhcp == NULL) { |
---|
1029 | close(fd); |
---|
1030 | return NULL; |
---|
1031 | } |
---|
1032 | bytes = read(fd, dhcp, sizeof(*dhcp)); |
---|
1033 | close(fd); |
---|
1034 | if (bytes < 0) { |
---|
1035 | free(dhcp); |
---|
1036 | return NULL; |
---|
1037 | } |
---|
1038 | |
---|
1039 | /* We may have found a BOOTP server */ |
---|
1040 | if (get_option_uint8(&type, dhcp, DHO_MESSAGETYPE) == -1) |
---|
1041 | type = 0; |
---|
1042 | /* Authenticate the message */ |
---|
1043 | auth = get_option(dhcp, DHO_AUTHENTICATION, &auth_len); |
---|
1044 | if (auth) { |
---|
1045 | if (dhcp_auth_validate(&state->auth, &ifp->options->auth, |
---|
1046 | (uint8_t *)dhcp, sizeof(*dhcp), 4, type, |
---|
1047 | auth, auth_len) == NULL) |
---|
1048 | { |
---|
1049 | syslog(LOG_DEBUG, "%s: dhcp_auth_validate: %m", |
---|
1050 | ifp->name); |
---|
1051 | free(dhcp); |
---|
1052 | return NULL; |
---|
1053 | } |
---|
1054 | syslog(LOG_DEBUG, "%s: validated using 0x%08" PRIu32, |
---|
1055 | ifp->name, state->auth.token->secretid); |
---|
1056 | } |
---|
1057 | |
---|
1058 | return dhcp; |
---|
1059 | } |
---|
1060 | |
---|
1061 | static const struct dhcp_opt * |
---|
1062 | dhcp_getoverride(const struct if_options *ifo, uint16_t o) |
---|
1063 | { |
---|
1064 | size_t i; |
---|
1065 | const struct dhcp_opt *opt; |
---|
1066 | |
---|
1067 | for (i = 0, opt = ifo->dhcp_override; |
---|
1068 | i < ifo->dhcp_override_len; |
---|
1069 | i++, opt++) |
---|
1070 | { |
---|
1071 | if (opt->option == o) |
---|
1072 | return opt; |
---|
1073 | } |
---|
1074 | return NULL; |
---|
1075 | } |
---|
1076 | |
---|
1077 | static const uint8_t * |
---|
1078 | dhcp_getoption(unsigned int *os, unsigned int *code, unsigned int *len, |
---|
1079 | const uint8_t *od, unsigned int ol, struct dhcp_opt **oopt) |
---|
1080 | { |
---|
1081 | size_t i; |
---|
1082 | struct dhcp_opt *opt; |
---|
1083 | |
---|
1084 | if (od) { |
---|
1085 | if (ol < 2) { |
---|
1086 | errno = EINVAL; |
---|
1087 | return NULL; |
---|
1088 | } |
---|
1089 | *os = 2; /* code + len */ |
---|
1090 | *code = (int)*od++; |
---|
1091 | *len = (int)*od++; |
---|
1092 | if (*len > ol) { |
---|
1093 | errno = EINVAL; |
---|
1094 | return NULL; |
---|
1095 | } |
---|
1096 | } |
---|
1097 | |
---|
1098 | for (i = 0, opt = dhcp_opts; i < dhcp_opts_len; i++, opt++) { |
---|
1099 | if (opt->option == *code) { |
---|
1100 | *oopt = opt; |
---|
1101 | break; |
---|
1102 | } |
---|
1103 | } |
---|
1104 | |
---|
1105 | return od; |
---|
1106 | } |
---|
1107 | |
---|
1108 | ssize_t |
---|
1109 | dhcp_env(char **env, const char *prefix, const struct dhcp_message *dhcp, |
---|
1110 | const struct interface *ifp) |
---|
1111 | { |
---|
1112 | const struct if_options *ifo; |
---|
1113 | const uint8_t *p; |
---|
1114 | int pl; |
---|
1115 | struct in_addr addr; |
---|
1116 | struct in_addr net; |
---|
1117 | struct in_addr brd; |
---|
1118 | struct dhcp_opt *opt, *vo; |
---|
1119 | ssize_t e = 0; |
---|
1120 | char **ep; |
---|
1121 | char cidr[4]; |
---|
1122 | uint8_t overl = 0; |
---|
1123 | size_t i; |
---|
1124 | uint32_t en; |
---|
1125 | |
---|
1126 | ifo = ifp->options; |
---|
1127 | get_option_uint8(&overl, dhcp, DHO_OPTIONSOVERLOADED); |
---|
1128 | |
---|
1129 | if (!env) { |
---|
1130 | if (dhcp->yiaddr || dhcp->ciaddr) |
---|
1131 | e += 5; |
---|
1132 | if (*dhcp->bootfile && !(overl & 1)) |
---|
1133 | e++; |
---|
1134 | if (*dhcp->servername && !(overl & 2)) |
---|
1135 | e++; |
---|
1136 | for (i = 0, opt = dhcp_opts; |
---|
1137 | i < dhcp_opts_len; |
---|
1138 | i++, opt++) |
---|
1139 | { |
---|
1140 | if (has_option_mask(ifo->nomask, opt->option)) |
---|
1141 | continue; |
---|
1142 | if (dhcp_getoverride(ifo, opt->option)) |
---|
1143 | continue; |
---|
1144 | p = get_option(dhcp, opt->option, &pl); |
---|
1145 | if (!p) |
---|
1146 | continue; |
---|
1147 | e += dhcp_envoption(NULL, NULL, ifp->name, |
---|
1148 | opt, dhcp_getoption, p, pl); |
---|
1149 | } |
---|
1150 | for (i = 0, opt = ifo->dhcp_override; |
---|
1151 | i < ifo->dhcp_override_len; |
---|
1152 | i++, opt++) |
---|
1153 | { |
---|
1154 | if (has_option_mask(ifo->nomask, opt->option)) |
---|
1155 | continue; |
---|
1156 | p = get_option(dhcp, opt->option, &pl); |
---|
1157 | if (!p) |
---|
1158 | continue; |
---|
1159 | e += dhcp_envoption(NULL, NULL, ifp->name, |
---|
1160 | opt, dhcp_getoption, p, pl); |
---|
1161 | } |
---|
1162 | return e; |
---|
1163 | } |
---|
1164 | |
---|
1165 | ep = env; |
---|
1166 | if (dhcp->yiaddr || dhcp->ciaddr) { |
---|
1167 | /* Set some useful variables that we derive from the DHCP |
---|
1168 | * message but are not necessarily in the options */ |
---|
1169 | addr.s_addr = dhcp->yiaddr ? dhcp->yiaddr : dhcp->ciaddr; |
---|
1170 | setvar(&ep, prefix, "ip_address", inet_ntoa(addr)); |
---|
1171 | if (get_option_addr(&net, dhcp, DHO_SUBNETMASK) == -1) { |
---|
1172 | net.s_addr = ipv4_getnetmask(addr.s_addr); |
---|
1173 | setvar(&ep, prefix, "subnet_mask", inet_ntoa(net)); |
---|
1174 | } |
---|
1175 | snprintf(cidr, sizeof(cidr), "%d", inet_ntocidr(net)); |
---|
1176 | setvar(&ep, prefix, "subnet_cidr", cidr); |
---|
1177 | if (get_option_addr(&brd, dhcp, DHO_BROADCAST) == -1) { |
---|
1178 | brd.s_addr = addr.s_addr | ~net.s_addr; |
---|
1179 | setvar(&ep, prefix, "broadcast_address", |
---|
1180 | inet_ntoa(brd)); |
---|
1181 | } |
---|
1182 | addr.s_addr = dhcp->yiaddr & net.s_addr; |
---|
1183 | setvar(&ep, prefix, "network_number", inet_ntoa(addr)); |
---|
1184 | } |
---|
1185 | |
---|
1186 | if (*dhcp->bootfile && !(overl & 1)) |
---|
1187 | setvar(&ep, prefix, "filename", (const char *)dhcp->bootfile); |
---|
1188 | if (*dhcp->servername && !(overl & 2)) |
---|
1189 | setvar(&ep, prefix, "server_name", |
---|
1190 | (const char *)dhcp->servername); |
---|
1191 | |
---|
1192 | /* Zero our indexes */ |
---|
1193 | if (env) { |
---|
1194 | for (i = 0, opt = dhcp_opts; i < dhcp_opts_len; i++, opt++) |
---|
1195 | dhcp_zero_index(opt); |
---|
1196 | for (i = 0, opt = ifp->options->dhcp_override; |
---|
1197 | i < ifp->options->dhcp_override_len; |
---|
1198 | i++, opt++) |
---|
1199 | dhcp_zero_index(opt); |
---|
1200 | for (i = 0, opt = vivso; i < vivso_len; i++, opt++) |
---|
1201 | dhcp_zero_index(opt); |
---|
1202 | } |
---|
1203 | |
---|
1204 | for (i = 0, opt = dhcp_opts; |
---|
1205 | i < dhcp_opts_len; |
---|
1206 | i++, opt++) |
---|
1207 | { |
---|
1208 | if (has_option_mask(ifo->nomask, opt->option)) |
---|
1209 | continue; |
---|
1210 | if (dhcp_getoverride(ifo, opt->option)) |
---|
1211 | continue; |
---|
1212 | if ((p = get_option(dhcp, opt->option, &pl))) { |
---|
1213 | ep += dhcp_envoption(ep, prefix, ifp->name, |
---|
1214 | opt, dhcp_getoption, p, pl); |
---|
1215 | if (opt->option == DHO_VIVSO && |
---|
1216 | pl > (int)sizeof(uint32_t)) |
---|
1217 | { |
---|
1218 | memcpy(&en, p, sizeof(en)); |
---|
1219 | en = ntohl(en); |
---|
1220 | vo = vivso_find(en, ifp); |
---|
1221 | if (vo) { |
---|
1222 | /* Skip over en + total size */ |
---|
1223 | p += sizeof(en) + 1; |
---|
1224 | pl -= sizeof(en) + 1; |
---|
1225 | ep += dhcp_envoption(ep, prefix, |
---|
1226 | ifp->name, |
---|
1227 | vo, dhcp_getoption, p, pl); |
---|
1228 | } |
---|
1229 | } |
---|
1230 | } |
---|
1231 | } |
---|
1232 | |
---|
1233 | for (i = 0, opt = ifo->dhcp_override; |
---|
1234 | i < ifo->dhcp_override_len; |
---|
1235 | i++, opt++) |
---|
1236 | { |
---|
1237 | if (has_option_mask(ifo->nomask, opt->option)) |
---|
1238 | continue; |
---|
1239 | if ((p = get_option(dhcp, opt->option, &pl))) |
---|
1240 | ep += dhcp_envoption(ep, prefix, ifp->name, |
---|
1241 | opt, dhcp_getoption, p, pl); |
---|
1242 | } |
---|
1243 | |
---|
1244 | return ep - env; |
---|
1245 | } |
---|
1246 | |
---|
1247 | void |
---|
1248 | get_lease(struct dhcp_lease *lease, const struct dhcp_message *dhcp) |
---|
1249 | { |
---|
1250 | struct timeval now; |
---|
1251 | |
---|
1252 | lease->cookie = dhcp->cookie; |
---|
1253 | /* BOOTP does not set yiaddr for replies when ciaddr is set. */ |
---|
1254 | if (dhcp->yiaddr) |
---|
1255 | lease->addr.s_addr = dhcp->yiaddr; |
---|
1256 | else |
---|
1257 | lease->addr.s_addr = dhcp->ciaddr; |
---|
1258 | if (get_option_addr(&lease->net, dhcp, DHO_SUBNETMASK) == -1) |
---|
1259 | lease->net.s_addr = ipv4_getnetmask(lease->addr.s_addr); |
---|
1260 | if (get_option_addr(&lease->brd, dhcp, DHO_BROADCAST) == -1) |
---|
1261 | lease->brd.s_addr = lease->addr.s_addr | ~lease->net.s_addr; |
---|
1262 | if (get_option_uint32(&lease->leasetime, dhcp, DHO_LEASETIME) == 0) { |
---|
1263 | /* Ensure that we can use the lease */ |
---|
1264 | get_monotonic(&now); |
---|
1265 | if (now.tv_sec + (time_t)lease->leasetime < now.tv_sec) |
---|
1266 | lease->leasetime = ~0U; /* Infinite lease */ |
---|
1267 | } else |
---|
1268 | lease->leasetime = ~0U; /* Default to infinite lease */ |
---|
1269 | if (get_option_uint32(&lease->renewaltime, dhcp, DHO_RENEWALTIME) != 0) |
---|
1270 | lease->renewaltime = 0; |
---|
1271 | if (get_option_uint32(&lease->rebindtime, dhcp, DHO_REBINDTIME) != 0) |
---|
1272 | lease->rebindtime = 0; |
---|
1273 | if (get_option_addr(&lease->server, dhcp, DHO_SERVERID) != 0) |
---|
1274 | lease->server.s_addr = INADDR_ANY; |
---|
1275 | } |
---|
1276 | |
---|
1277 | static const char * |
---|
1278 | get_dhcp_op(uint8_t type) |
---|
1279 | { |
---|
1280 | const struct dhcp_op *d; |
---|
1281 | |
---|
1282 | for (d = dhcp_ops; d->name; d++) |
---|
1283 | if (d->value == type) |
---|
1284 | return d->name; |
---|
1285 | return NULL; |
---|
1286 | } |
---|
1287 | |
---|
1288 | static void |
---|
1289 | dhcp_fallback(void *arg) |
---|
1290 | { |
---|
1291 | struct interface *iface; |
---|
1292 | |
---|
1293 | iface = (struct interface *)arg; |
---|
1294 | select_profile(iface, iface->options->fallback); |
---|
1295 | start_interface(iface); |
---|
1296 | } |
---|
1297 | |
---|
1298 | uint32_t |
---|
1299 | dhcp_xid(const struct interface *ifp) |
---|
1300 | { |
---|
1301 | uint32_t xid; |
---|
1302 | |
---|
1303 | if (ifp->options->options & DHCPCD_XID_HWADDR && |
---|
1304 | ifp->hwlen >= sizeof(xid)) |
---|
1305 | /* The lower bits are probably more unique on the network */ |
---|
1306 | memcpy(&xid, (ifp->hwaddr + ifp->hwlen) - sizeof(xid), |
---|
1307 | sizeof(xid)); |
---|
1308 | else |
---|
1309 | xid = arc4random(); |
---|
1310 | |
---|
1311 | return xid; |
---|
1312 | } |
---|
1313 | |
---|
1314 | void |
---|
1315 | dhcp_close(struct interface *ifp) |
---|
1316 | { |
---|
1317 | struct dhcp_state *state = D_STATE(ifp); |
---|
1318 | |
---|
1319 | if (state == NULL) |
---|
1320 | return; |
---|
1321 | |
---|
1322 | if (state->arp_fd != -1) { |
---|
1323 | eloop_event_delete(state->arp_fd); |
---|
1324 | close(state->arp_fd); |
---|
1325 | state->arp_fd = -1; |
---|
1326 | } |
---|
1327 | if (state->raw_fd != -1) { |
---|
1328 | eloop_event_delete(state->raw_fd); |
---|
1329 | close(state->raw_fd); |
---|
1330 | state->raw_fd = -1; |
---|
1331 | } |
---|
1332 | if (state->udp_fd != -1) { |
---|
1333 | /* we don't listen to events on the udp */ |
---|
1334 | close(state->udp_fd); |
---|
1335 | state->udp_fd = -1; |
---|
1336 | } |
---|
1337 | |
---|
1338 | state->interval = 0; |
---|
1339 | } |
---|
1340 | |
---|
1341 | static int |
---|
1342 | dhcp_openudp(struct interface *iface) |
---|
1343 | { |
---|
1344 | int s; |
---|
1345 | struct sockaddr_in sin; |
---|
1346 | int n; |
---|
1347 | struct dhcp_state *state; |
---|
1348 | #ifdef SO_BINDTODEVICE |
---|
1349 | struct ifreq ifr; |
---|
1350 | char *p; |
---|
1351 | #endif |
---|
1352 | |
---|
1353 | if ((s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) |
---|
1354 | return -1; |
---|
1355 | |
---|
1356 | n = 1; |
---|
1357 | if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1) |
---|
1358 | goto eexit; |
---|
1359 | #ifdef SO_BINDTODEVICE |
---|
1360 | memset(&ifr, 0, sizeof(ifr)); |
---|
1361 | strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name)); |
---|
1362 | /* We can only bind to the real device */ |
---|
1363 | p = strchr(ifr.ifr_name, ':'); |
---|
1364 | if (p) |
---|
1365 | *p = '\0'; |
---|
1366 | if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, &ifr, |
---|
1367 | sizeof(ifr)) == -1) |
---|
1368 | goto eexit; |
---|
1369 | #endif |
---|
1370 | /* As we don't use this socket for receiving, set the |
---|
1371 | * receive buffer to 1 */ |
---|
1372 | n = 1; |
---|
1373 | if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) == -1) |
---|
1374 | goto eexit; |
---|
1375 | state = D_STATE(iface); |
---|
1376 | memset(&sin, 0, sizeof(sin)); |
---|
1377 | sin.sin_family = AF_INET; |
---|
1378 | sin.sin_port = htons(DHCP_CLIENT_PORT); |
---|
1379 | sin.sin_addr.s_addr = state->addr.s_addr; |
---|
1380 | if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == -1) |
---|
1381 | goto eexit; |
---|
1382 | |
---|
1383 | state->udp_fd = s; |
---|
1384 | set_cloexec(s); |
---|
1385 | return 0; |
---|
1386 | |
---|
1387 | eexit: |
---|
1388 | close(s); |
---|
1389 | return -1; |
---|
1390 | } |
---|
1391 | |
---|
1392 | static ssize_t |
---|
1393 | dhcp_sendpacket(const struct interface *iface, struct in_addr to, |
---|
1394 | const uint8_t *data, ssize_t len) |
---|
1395 | { |
---|
1396 | struct sockaddr_in sin; |
---|
1397 | |
---|
1398 | memset(&sin, 0, sizeof(sin)); |
---|
1399 | sin.sin_family = AF_INET; |
---|
1400 | sin.sin_addr.s_addr = to.s_addr; |
---|
1401 | sin.sin_port = htons(DHCP_SERVER_PORT); |
---|
1402 | return sendto(D_CSTATE(iface)->udp_fd, data, len, 0, |
---|
1403 | (struct sockaddr *)&sin, sizeof(sin)); |
---|
1404 | } |
---|
1405 | |
---|
1406 | static uint16_t |
---|
1407 | checksum(const void *data, uint16_t len) |
---|
1408 | { |
---|
1409 | const uint8_t *addr = data; |
---|
1410 | uint32_t sum = 0; |
---|
1411 | |
---|
1412 | while (len > 1) { |
---|
1413 | sum += addr[0] * 256 + addr[1]; |
---|
1414 | addr += 2; |
---|
1415 | len -= 2; |
---|
1416 | } |
---|
1417 | |
---|
1418 | if (len == 1) |
---|
1419 | sum += *addr * 256; |
---|
1420 | |
---|
1421 | sum = (sum >> 16) + (sum & 0xffff); |
---|
1422 | sum += (sum >> 16); |
---|
1423 | |
---|
1424 | sum = htons(sum); |
---|
1425 | |
---|
1426 | return ~sum; |
---|
1427 | } |
---|
1428 | |
---|
1429 | static ssize_t |
---|
1430 | dhcp_makeudppacket(uint8_t **p, const uint8_t *data, size_t length, |
---|
1431 | struct in_addr source, struct in_addr dest) |
---|
1432 | { |
---|
1433 | struct udp_dhcp_packet *udpp; |
---|
1434 | struct ip *ip; |
---|
1435 | struct udphdr *udp; |
---|
1436 | |
---|
1437 | udpp = calloc(1, sizeof(*udpp)); |
---|
1438 | if (udpp == NULL) |
---|
1439 | return -1; |
---|
1440 | ip = &udpp->ip; |
---|
1441 | udp = &udpp->udp; |
---|
1442 | |
---|
1443 | /* OK, this is important :) |
---|
1444 | * We copy the data to our packet and then create a small part of the |
---|
1445 | * ip structure and an invalid ip_len (basically udp length). |
---|
1446 | * We then fill the udp structure and put the checksum |
---|
1447 | * of the whole packet into the udp checksum. |
---|
1448 | * Finally we complete the ip structure and ip checksum. |
---|
1449 | * If we don't do the ordering like so then the udp checksum will be |
---|
1450 | * broken, so find another way of doing it! */ |
---|
1451 | |
---|
1452 | memcpy(&udpp->dhcp, data, length); |
---|
1453 | |
---|
1454 | ip->ip_p = IPPROTO_UDP; |
---|
1455 | ip->ip_src.s_addr = source.s_addr; |
---|
1456 | if (dest.s_addr == 0) |
---|
1457 | ip->ip_dst.s_addr = INADDR_BROADCAST; |
---|
1458 | else |
---|
1459 | ip->ip_dst.s_addr = dest.s_addr; |
---|
1460 | |
---|
1461 | udp->uh_sport = htons(DHCP_CLIENT_PORT); |
---|
1462 | udp->uh_dport = htons(DHCP_SERVER_PORT); |
---|
1463 | udp->uh_ulen = htons(sizeof(*udp) + length); |
---|
1464 | ip->ip_len = udp->uh_ulen; |
---|
1465 | udp->uh_sum = checksum(udpp, sizeof(*udpp)); |
---|
1466 | |
---|
1467 | ip->ip_v = IPVERSION; |
---|
1468 | ip->ip_hl = sizeof(*ip) >> 2; |
---|
1469 | ip->ip_id = arc4random() & UINT16_MAX; |
---|
1470 | ip->ip_ttl = IPDEFTTL; |
---|
1471 | ip->ip_len = htons(sizeof(*ip) + sizeof(*udp) + length); |
---|
1472 | ip->ip_sum = checksum(ip, sizeof(*ip)); |
---|
1473 | |
---|
1474 | *p = (uint8_t *)udpp; |
---|
1475 | return sizeof(*ip) + sizeof(*udp) + length; |
---|
1476 | } |
---|
1477 | |
---|
1478 | static void |
---|
1479 | send_message(struct interface *iface, int type, |
---|
1480 | void (*callback)(void *)) |
---|
1481 | { |
---|
1482 | struct dhcp_state *state = D_STATE(iface); |
---|
1483 | struct if_options *ifo = iface->options; |
---|
1484 | struct dhcp_message *dhcp; |
---|
1485 | uint8_t *udp; |
---|
1486 | ssize_t len, r; |
---|
1487 | struct in_addr from, to; |
---|
1488 | in_addr_t a = 0; |
---|
1489 | struct timeval tv; |
---|
1490 | |
---|
1491 | if (!callback) |
---|
1492 | syslog(LOG_DEBUG, "%s: sending %s with xid 0x%x", |
---|
1493 | iface->name, get_dhcp_op(type), state->xid); |
---|
1494 | else { |
---|
1495 | if (state->interval == 0) |
---|
1496 | state->interval = 4; |
---|
1497 | else { |
---|
1498 | state->interval *= 2; |
---|
1499 | if (state->interval > 64) |
---|
1500 | state->interval = 64; |
---|
1501 | } |
---|
1502 | tv.tv_sec = state->interval + DHCP_RAND_MIN; |
---|
1503 | tv.tv_usec = arc4random() % (DHCP_RAND_MAX_U - DHCP_RAND_MIN_U); |
---|
1504 | timernorm(&tv); |
---|
1505 | syslog(LOG_DEBUG, |
---|
1506 | "%s: sending %s (xid 0x%x), next in %0.1f seconds", |
---|
1507 | iface->name, get_dhcp_op(type), state->xid, |
---|
1508 | timeval_to_double(&tv)); |
---|
1509 | } |
---|
1510 | |
---|
1511 | /* Ensure sockets are open. */ |
---|
1512 | if (dhcp_open(iface) == -1) { |
---|
1513 | if (!(options & DHCPCD_TEST)) |
---|
1514 | dhcp_drop(iface, "FAIL"); |
---|
1515 | return; |
---|
1516 | } |
---|
1517 | |
---|
1518 | /* If we couldn't open a UDP port for our IP address |
---|
1519 | * then we cannot renew. |
---|
1520 | * This could happen if our IP was pulled out from underneath us. |
---|
1521 | * Also, we should not unicast from a BOOTP lease. */ |
---|
1522 | if (state->udp_fd == -1 || |
---|
1523 | (!(ifo->options & DHCPCD_INFORM) && is_bootp(state->new))) |
---|
1524 | { |
---|
1525 | a = state->addr.s_addr; |
---|
1526 | state->addr.s_addr = 0; |
---|
1527 | } |
---|
1528 | len = make_message(&dhcp, iface, type); |
---|
1529 | if (a) |
---|
1530 | state->addr.s_addr = a; |
---|
1531 | from.s_addr = dhcp->ciaddr; |
---|
1532 | if (from.s_addr) |
---|
1533 | to.s_addr = state->lease.server.s_addr; |
---|
1534 | else |
---|
1535 | to.s_addr = 0; |
---|
1536 | if (to.s_addr && to.s_addr != INADDR_BROADCAST) { |
---|
1537 | r = dhcp_sendpacket(iface, to, (uint8_t *)dhcp, len); |
---|
1538 | if (r == -1) { |
---|
1539 | syslog(LOG_ERR, "%s: dhcp_sendpacket: %m", iface->name); |
---|
1540 | dhcp_close(iface); |
---|
1541 | } |
---|
1542 | } else { |
---|
1543 | len = dhcp_makeudppacket(&udp, (uint8_t *)dhcp, len, from, to); |
---|
1544 | if (len == -1) |
---|
1545 | return; |
---|
1546 | r = ipv4_sendrawpacket(iface, ETHERTYPE_IP, udp, len); |
---|
1547 | free(udp); |
---|
1548 | /* If we failed to send a raw packet this normally means |
---|
1549 | * we don't have the ability to work beneath the IP layer |
---|
1550 | * for this interface. |
---|
1551 | * As such we remove it from consideration without actually |
---|
1552 | * stopping the interface. */ |
---|
1553 | if (r == -1) { |
---|
1554 | syslog(LOG_ERR, "%s: ipv4_sendrawpacket: %m", |
---|
1555 | iface->name); |
---|
1556 | if (!(options & DHCPCD_TEST)) |
---|
1557 | dhcp_drop(iface, "FAIL"); |
---|
1558 | dhcp_close(iface); |
---|
1559 | eloop_timeout_delete(NULL, iface); |
---|
1560 | callback = NULL; |
---|
1561 | } |
---|
1562 | } |
---|
1563 | free(dhcp); |
---|
1564 | |
---|
1565 | /* Even if we fail to send a packet we should continue as we are |
---|
1566 | * as our failure timeouts will change out codepath when needed. */ |
---|
1567 | if (callback) |
---|
1568 | eloop_timeout_add_tv(&tv, callback, iface); |
---|
1569 | } |
---|
1570 | |
---|
1571 | static void |
---|
1572 | send_inform(void *arg) |
---|
1573 | { |
---|
1574 | |
---|
1575 | send_message((struct interface *)arg, DHCP_INFORM, send_inform); |
---|
1576 | } |
---|
1577 | |
---|
1578 | static void |
---|
1579 | send_discover(void *arg) |
---|
1580 | { |
---|
1581 | |
---|
1582 | send_message((struct interface *)arg, DHCP_DISCOVER, send_discover); |
---|
1583 | } |
---|
1584 | |
---|
1585 | static void |
---|
1586 | send_request(void *arg) |
---|
1587 | { |
---|
1588 | |
---|
1589 | send_message((struct interface *)arg, DHCP_REQUEST, send_request); |
---|
1590 | } |
---|
1591 | |
---|
1592 | static void |
---|
1593 | send_renew(void *arg) |
---|
1594 | { |
---|
1595 | |
---|
1596 | send_message((struct interface *)arg, DHCP_REQUEST, send_renew); |
---|
1597 | } |
---|
1598 | |
---|
1599 | static void |
---|
1600 | send_rebind(void *arg) |
---|
1601 | { |
---|
1602 | |
---|
1603 | send_message((struct interface *)arg, DHCP_REQUEST, send_rebind); |
---|
1604 | } |
---|
1605 | |
---|
1606 | void |
---|
1607 | dhcp_discover(void *arg) |
---|
1608 | { |
---|
1609 | struct interface *iface = arg; |
---|
1610 | struct dhcp_state *state = D_STATE(iface); |
---|
1611 | struct if_options *ifo = iface->options; |
---|
1612 | int timeout = ifo->timeout; |
---|
1613 | |
---|
1614 | /* If we're rebooting and we're not daemonised then we need |
---|
1615 | * to shorten the normal timeout to ensure we try correctly |
---|
1616 | * for a fallback or IPv4LL address. */ |
---|
1617 | if (state->state == DHS_REBOOT && !(options & DHCPCD_DAEMONISED)) { |
---|
1618 | timeout -= ifo->reboot; |
---|
1619 | if (timeout <= 0) |
---|
1620 | timeout = 2; |
---|
1621 | } |
---|
1622 | |
---|
1623 | state->state = DHS_DISCOVER; |
---|
1624 | state->xid = dhcp_xid(iface); |
---|
1625 | eloop_timeout_delete(NULL, iface); |
---|
1626 | if (ifo->fallback) |
---|
1627 | eloop_timeout_add_sec(timeout, dhcp_fallback, iface); |
---|
1628 | else if (ifo->options & DHCPCD_IPV4LL && |
---|
1629 | !IN_LINKLOCAL(htonl(state->addr.s_addr))) |
---|
1630 | { |
---|
1631 | if (IN_LINKLOCAL(htonl(state->fail.s_addr))) |
---|
1632 | eloop_timeout_add_sec(RATE_LIMIT_INTERVAL, |
---|
1633 | ipv4ll_start, iface); |
---|
1634 | else |
---|
1635 | eloop_timeout_add_sec(timeout, ipv4ll_start, iface); |
---|
1636 | } |
---|
1637 | if (ifo->options & DHCPCD_REQUEST) |
---|
1638 | syslog(LOG_INFO, "%s: soliciting a DHCP lease (requesting %s)", |
---|
1639 | iface->name, inet_ntoa(ifo->req_addr)); |
---|
1640 | else |
---|
1641 | syslog(LOG_INFO, "%s: soliciting a DHCP lease", iface->name); |
---|
1642 | send_discover(iface); |
---|
1643 | } |
---|
1644 | |
---|
1645 | static void |
---|
1646 | dhcp_request(void *arg) |
---|
1647 | { |
---|
1648 | struct interface *ifp = arg; |
---|
1649 | struct dhcp_state *state = D_STATE(ifp); |
---|
1650 | |
---|
1651 | state->state = DHS_REQUEST; |
---|
1652 | send_request(ifp); |
---|
1653 | } |
---|
1654 | |
---|
1655 | static void |
---|
1656 | dhcp_expire(void *arg) |
---|
1657 | { |
---|
1658 | struct interface *ifp = arg; |
---|
1659 | struct dhcp_state *state = D_STATE(ifp); |
---|
1660 | |
---|
1661 | syslog(LOG_ERR, "%s: DHCP lease expired", ifp->name); |
---|
1662 | eloop_timeout_delete(NULL, ifp); |
---|
1663 | dhcp_drop(ifp, "EXPIRE"); |
---|
1664 | unlink(state->leasefile); |
---|
1665 | |
---|
1666 | state->interval = 0; |
---|
1667 | dhcp_discover(ifp); |
---|
1668 | } |
---|
1669 | |
---|
1670 | void |
---|
1671 | dhcp_decline(struct interface *ifp) |
---|
1672 | { |
---|
1673 | |
---|
1674 | send_message(ifp, DHCP_DECLINE, NULL); |
---|
1675 | } |
---|
1676 | |
---|
1677 | static void |
---|
1678 | dhcp_renew(void *arg) |
---|
1679 | { |
---|
1680 | struct interface *ifp = arg; |
---|
1681 | struct dhcp_state *state = D_STATE(ifp); |
---|
1682 | struct dhcp_lease *lease = &state->lease; |
---|
1683 | |
---|
1684 | syslog(LOG_DEBUG, "%s: renewing lease of %s", |
---|
1685 | ifp->name, inet_ntoa(lease->addr)); |
---|
1686 | syslog(LOG_DEBUG, "%s: rebind in %"PRIu32" seconds," |
---|
1687 | " expire in %"PRIu32" seconds", |
---|
1688 | ifp->name, lease->rebindtime - lease->renewaltime, |
---|
1689 | lease->leasetime - lease->renewaltime); |
---|
1690 | state->state = DHS_RENEW; |
---|
1691 | state->xid = dhcp_xid(ifp); |
---|
1692 | send_renew(ifp); |
---|
1693 | } |
---|
1694 | |
---|
1695 | static void |
---|
1696 | dhcp_rebind(void *arg) |
---|
1697 | { |
---|
1698 | struct interface *ifp = arg; |
---|
1699 | struct dhcp_state *state = D_STATE(ifp); |
---|
1700 | struct dhcp_lease *lease = &state->lease; |
---|
1701 | |
---|
1702 | syslog(LOG_WARNING, "%s: failed to renew DHCP, rebinding", |
---|
1703 | ifp->name); |
---|
1704 | syslog(LOG_DEBUG, "%s: expire in %"PRIu32" seconds", |
---|
1705 | ifp->name, lease->leasetime - lease->rebindtime); |
---|
1706 | state->state = DHS_REBIND; |
---|
1707 | eloop_timeout_delete(send_renew, ifp); |
---|
1708 | state->lease.server.s_addr = 0; |
---|
1709 | ifp->options->options &= ~ DHCPCD_CSR_WARNED; |
---|
1710 | send_rebind(ifp); |
---|
1711 | } |
---|
1712 | |
---|
1713 | void |
---|
1714 | dhcp_bind(void *arg) |
---|
1715 | { |
---|
1716 | struct interface *iface = arg; |
---|
1717 | struct dhcp_state *state = D_STATE(iface); |
---|
1718 | struct if_options *ifo = iface->options; |
---|
1719 | struct dhcp_lease *lease = &state->lease; |
---|
1720 | struct timeval tv; |
---|
1721 | |
---|
1722 | /* We're binding an address now - ensure that sockets are closed */ |
---|
1723 | dhcp_close(iface); |
---|
1724 | state->reason = NULL; |
---|
1725 | if (clock_monotonic) |
---|
1726 | get_monotonic(&lease->boundtime); |
---|
1727 | state->xid = 0; |
---|
1728 | free(state->old); |
---|
1729 | state->old = state->new; |
---|
1730 | state->new = state->offer; |
---|
1731 | state->offer = NULL; |
---|
1732 | get_lease(lease, state->new); |
---|
1733 | if (ifo->options & DHCPCD_STATIC) { |
---|
1734 | syslog(LOG_INFO, "%s: using static address %s/%d", |
---|
1735 | iface->name, inet_ntoa(lease->addr), |
---|
1736 | inet_ntocidr(lease->net)); |
---|
1737 | lease->leasetime = ~0U; |
---|
1738 | state->reason = "STATIC"; |
---|
1739 | } else if (state->new->cookie != htonl(MAGIC_COOKIE)) { |
---|
1740 | syslog(LOG_INFO, "%s: using IPv4LL address %s", |
---|
1741 | iface->name, inet_ntoa(lease->addr)); |
---|
1742 | lease->leasetime = ~0U; |
---|
1743 | state->reason = "IPV4LL"; |
---|
1744 | } else if (ifo->options & DHCPCD_INFORM) { |
---|
1745 | if (ifo->req_addr.s_addr != 0) |
---|
1746 | lease->addr.s_addr = ifo->req_addr.s_addr; |
---|
1747 | else |
---|
1748 | lease->addr.s_addr = state->addr.s_addr; |
---|
1749 | syslog(LOG_INFO, "%s: received approval for %s", iface->name, |
---|
1750 | inet_ntoa(lease->addr)); |
---|
1751 | lease->leasetime = ~0U; |
---|
1752 | state->reason = "INFORM"; |
---|
1753 | } else { |
---|
1754 | if (gettimeofday(&tv, NULL) == 0) |
---|
1755 | lease->leasedfrom = tv.tv_sec; |
---|
1756 | else if (lease->frominfo) |
---|
1757 | state->reason = "TIMEOUT"; |
---|
1758 | if (lease->leasetime == ~0U) { |
---|
1759 | lease->renewaltime = |
---|
1760 | lease->rebindtime = |
---|
1761 | lease->leasetime; |
---|
1762 | syslog(LOG_INFO, "%s: leased %s for infinity", |
---|
1763 | iface->name, inet_ntoa(lease->addr)); |
---|
1764 | } else { |
---|
1765 | if (lease->leasetime < DHCP_MIN_LEASE) { |
---|
1766 | syslog(LOG_WARNING, |
---|
1767 | "%s: minimum lease is %d seconds", |
---|
1768 | iface->name, DHCP_MIN_LEASE); |
---|
1769 | lease->leasetime = DHCP_MIN_LEASE; |
---|
1770 | } |
---|
1771 | if (lease->rebindtime == 0) |
---|
1772 | lease->rebindtime = lease->leasetime * T2; |
---|
1773 | else if (lease->rebindtime >= lease->leasetime) { |
---|
1774 | lease->rebindtime = lease->leasetime * T2; |
---|
1775 | syslog(LOG_WARNING, |
---|
1776 | "%s: rebind time greater than lease " |
---|
1777 | "time, forcing to %"PRIu32" seconds", |
---|
1778 | iface->name, lease->rebindtime); |
---|
1779 | } |
---|
1780 | if (lease->renewaltime == 0) |
---|
1781 | lease->renewaltime = lease->leasetime * T1; |
---|
1782 | else if (lease->renewaltime > lease->rebindtime) { |
---|
1783 | lease->renewaltime = lease->leasetime * T1; |
---|
1784 | syslog(LOG_WARNING, |
---|
1785 | "%s: renewal time greater than rebind " |
---|
1786 | "time, forcing to %"PRIu32" seconds", |
---|
1787 | iface->name, lease->renewaltime); |
---|
1788 | } |
---|
1789 | syslog(lease->addr.s_addr == state->addr.s_addr ? |
---|
1790 | LOG_DEBUG : LOG_INFO, |
---|
1791 | "%s: leased %s for %"PRIu32" seconds", iface->name, |
---|
1792 | inet_ntoa(lease->addr), lease->leasetime); |
---|
1793 | } |
---|
1794 | } |
---|
1795 | if (options & DHCPCD_TEST) { |
---|
1796 | state->reason = "TEST"; |
---|
1797 | script_runreason(iface, state->reason); |
---|
1798 | exit(EXIT_SUCCESS); |
---|
1799 | } |
---|
1800 | if (state->reason == NULL) { |
---|
1801 | if (state->old) { |
---|
1802 | if (state->old->yiaddr == state->new->yiaddr && |
---|
1803 | lease->server.s_addr) |
---|
1804 | state->reason = "RENEW"; |
---|
1805 | else |
---|
1806 | state->reason = "REBIND"; |
---|
1807 | } else if (state->state == DHS_REBOOT) |
---|
1808 | state->reason = "REBOOT"; |
---|
1809 | else |
---|
1810 | state->reason = "BOUND"; |
---|
1811 | } |
---|
1812 | if (lease->leasetime == ~0U) |
---|
1813 | lease->renewaltime = lease->rebindtime = lease->leasetime; |
---|
1814 | else { |
---|
1815 | eloop_timeout_add_sec(lease->renewaltime, dhcp_renew, iface); |
---|
1816 | eloop_timeout_add_sec(lease->rebindtime, dhcp_rebind, iface); |
---|
1817 | eloop_timeout_add_sec(lease->leasetime, dhcp_expire, iface); |
---|
1818 | syslog(LOG_DEBUG, |
---|
1819 | "%s: renew in %"PRIu32" seconds, rebind in %"PRIu32 |
---|
1820 | " seconds", |
---|
1821 | iface->name, lease->renewaltime, lease->rebindtime); |
---|
1822 | } |
---|
1823 | ipv4_applyaddr(iface); |
---|
1824 | daemonise(); |
---|
1825 | state->state = DHS_BOUND; |
---|
1826 | if (ifo->options & DHCPCD_ARP) { |
---|
1827 | state->claims = 0; |
---|
1828 | arp_announce(iface); |
---|
1829 | } |
---|
1830 | } |
---|
1831 | |
---|
1832 | static void |
---|
1833 | dhcp_timeout(void *arg) |
---|
1834 | { |
---|
1835 | struct interface *ifp = arg; |
---|
1836 | struct dhcp_state *state = D_STATE(ifp); |
---|
1837 | |
---|
1838 | dhcp_bind(ifp); |
---|
1839 | state->interval = 0; |
---|
1840 | dhcp_discover(ifp); |
---|
1841 | } |
---|
1842 | |
---|
1843 | struct dhcp_message * |
---|
1844 | dhcp_message_new(const struct in_addr *addr, const struct in_addr *mask) |
---|
1845 | { |
---|
1846 | struct dhcp_message *dhcp; |
---|
1847 | uint8_t *p; |
---|
1848 | |
---|
1849 | dhcp = calloc(1, sizeof(*dhcp)); |
---|
1850 | if (dhcp == NULL) |
---|
1851 | return NULL; |
---|
1852 | dhcp->yiaddr = addr->s_addr; |
---|
1853 | p = dhcp->options; |
---|
1854 | if (mask && mask->s_addr != INADDR_ANY) { |
---|
1855 | *p++ = DHO_SUBNETMASK; |
---|
1856 | *p++ = sizeof(mask->s_addr); |
---|
1857 | memcpy(p, &mask->s_addr, sizeof(mask->s_addr)); |
---|
1858 | p+= sizeof(mask->s_addr); |
---|
1859 | } |
---|
1860 | *p++ = DHO_END; |
---|
1861 | return dhcp; |
---|
1862 | } |
---|
1863 | |
---|
1864 | static void |
---|
1865 | dhcp_static(struct interface *ifp) |
---|
1866 | { |
---|
1867 | struct if_options *ifo; |
---|
1868 | struct dhcp_state *state; |
---|
1869 | |
---|
1870 | state = D_STATE(ifp); |
---|
1871 | ifo = ifp->options; |
---|
1872 | if (ifo->req_addr.s_addr == INADDR_ANY) { |
---|
1873 | syslog(LOG_INFO, |
---|
1874 | "%s: waiting for 3rd party to " |
---|
1875 | "configure IP address", |
---|
1876 | ifp->name); |
---|
1877 | state->reason = "3RDPARTY"; |
---|
1878 | script_runreason(ifp, state->reason); |
---|
1879 | return; |
---|
1880 | } |
---|
1881 | state->offer = dhcp_message_new(&ifo->req_addr, &ifo->req_mask); |
---|
1882 | if (state->offer) { |
---|
1883 | eloop_timeout_delete(NULL, ifp); |
---|
1884 | dhcp_bind(ifp); |
---|
1885 | } |
---|
1886 | } |
---|
1887 | |
---|
1888 | void |
---|
1889 | dhcp_inform(struct interface *ifp) |
---|
1890 | { |
---|
1891 | struct dhcp_state *state; |
---|
1892 | struct if_options *ifo; |
---|
1893 | struct ipv4_addr *ap; |
---|
1894 | |
---|
1895 | state = D_STATE(ifp); |
---|
1896 | ifo = ifp->options; |
---|
1897 | if (options & DHCPCD_TEST) { |
---|
1898 | state->addr.s_addr = ifo->req_addr.s_addr; |
---|
1899 | state->net.s_addr = ifo->req_mask.s_addr; |
---|
1900 | } else { |
---|
1901 | if (ifo->req_addr.s_addr == INADDR_ANY) { |
---|
1902 | state = D_STATE(ifp); |
---|
1903 | ap = ipv4_findaddr(ifp, NULL, NULL); |
---|
1904 | if (ap == NULL) { |
---|
1905 | syslog(LOG_INFO, |
---|
1906 | "%s: waiting for 3rd party to " |
---|
1907 | "configure IP address", |
---|
1908 | ifp->name); |
---|
1909 | state->reason = "3RDPARTY"; |
---|
1910 | script_runreason(ifp, state->reason); |
---|
1911 | return; |
---|
1912 | } |
---|
1913 | state->offer = |
---|
1914 | dhcp_message_new(&ap->addr, &ap->net); |
---|
1915 | } else |
---|
1916 | state->offer = |
---|
1917 | dhcp_message_new(&ifo->req_addr, &ifo->req_mask); |
---|
1918 | if (state->offer) { |
---|
1919 | ifo->options |= DHCPCD_STATIC; |
---|
1920 | dhcp_bind(ifp); |
---|
1921 | ifo->options &= ~DHCPCD_STATIC; |
---|
1922 | } |
---|
1923 | } |
---|
1924 | |
---|
1925 | state->state = DHS_INFORM; |
---|
1926 | state->xid = dhcp_xid(ifp); |
---|
1927 | send_inform(ifp); |
---|
1928 | } |
---|
1929 | |
---|
1930 | void |
---|
1931 | dhcp_reboot_newopts(struct interface *ifp, int oldopts) |
---|
1932 | { |
---|
1933 | struct if_options *ifo; |
---|
1934 | struct dhcp_state *state = D_STATE(ifp); |
---|
1935 | |
---|
1936 | if (state == NULL) |
---|
1937 | return; |
---|
1938 | ifo = ifp->options; |
---|
1939 | if ((ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC) && |
---|
1940 | state->addr.s_addr != ifo->req_addr.s_addr) || |
---|
1941 | (oldopts & (DHCPCD_INFORM | DHCPCD_STATIC) && |
---|
1942 | !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)))) |
---|
1943 | { |
---|
1944 | dhcp_drop(ifp, "EXPIRE"); |
---|
1945 | } |
---|
1946 | } |
---|
1947 | |
---|
1948 | static void |
---|
1949 | dhcp_reboot(struct interface *ifp) |
---|
1950 | { |
---|
1951 | struct if_options *ifo; |
---|
1952 | struct dhcp_state *state = D_STATE(ifp); |
---|
1953 | |
---|
1954 | if (state == NULL) |
---|
1955 | return; |
---|
1956 | ifo = ifp->options; |
---|
1957 | state->interval = 0; |
---|
1958 | |
---|
1959 | if (ifo->options & DHCPCD_LINK && ifp->carrier == LINK_DOWN) { |
---|
1960 | syslog(LOG_INFO, "%s: waiting for carrier", ifp->name); |
---|
1961 | return; |
---|
1962 | } |
---|
1963 | if (ifo->options & DHCPCD_STATIC) { |
---|
1964 | dhcp_static(ifp); |
---|
1965 | return; |
---|
1966 | } |
---|
1967 | if (ifo->reboot == 0 || state->offer == NULL) { |
---|
1968 | dhcp_discover(ifp); |
---|
1969 | return; |
---|
1970 | } |
---|
1971 | if (ifo->options & DHCPCD_INFORM) { |
---|
1972 | syslog(LOG_INFO, "%s: informing address of %s", |
---|
1973 | ifp->name, inet_ntoa(state->lease.addr)); |
---|
1974 | } else if (state->offer->cookie == 0) { |
---|
1975 | if (ifo->options & DHCPCD_IPV4LL) { |
---|
1976 | state->claims = 0; |
---|
1977 | arp_announce(ifp); |
---|
1978 | } else |
---|
1979 | dhcp_discover(ifp); |
---|
1980 | return; |
---|
1981 | } else { |
---|
1982 | syslog(LOG_INFO, "%s: rebinding lease of %s", |
---|
1983 | ifp->name, inet_ntoa(state->lease.addr)); |
---|
1984 | } |
---|
1985 | state->state = DHS_REBOOT; |
---|
1986 | state->xid = dhcp_xid(ifp); |
---|
1987 | state->lease.server.s_addr = 0; |
---|
1988 | eloop_timeout_delete(NULL, ifp); |
---|
1989 | if (ifo->fallback) |
---|
1990 | eloop_timeout_add_sec(ifo->reboot, dhcp_fallback, ifp); |
---|
1991 | else if (ifo->options & DHCPCD_LASTLEASE && state->lease.frominfo) |
---|
1992 | eloop_timeout_add_sec(ifo->reboot, dhcp_timeout, ifp); |
---|
1993 | else if (!(ifo->options & DHCPCD_INFORM && |
---|
1994 | options & (DHCPCD_MASTER | DHCPCD_DAEMONISED))) |
---|
1995 | eloop_timeout_add_sec(ifo->reboot, dhcp_expire, ifp); |
---|
1996 | /* Don't bother ARP checking as the server could NAK us first. */ |
---|
1997 | if (ifo->options & DHCPCD_INFORM) |
---|
1998 | dhcp_inform(ifp); |
---|
1999 | else |
---|
2000 | dhcp_request(ifp); |
---|
2001 | } |
---|
2002 | |
---|
2003 | void |
---|
2004 | dhcp_drop(struct interface *ifp, const char *reason) |
---|
2005 | { |
---|
2006 | struct dhcp_state *state; |
---|
2007 | #ifdef RELEASE_SLOW |
---|
2008 | struct timespec ts; |
---|
2009 | #endif |
---|
2010 | |
---|
2011 | state = D_STATE(ifp); |
---|
2012 | if (state == NULL) |
---|
2013 | return; |
---|
2014 | eloop_timeouts_delete(ifp, dhcp_expire, NULL); |
---|
2015 | if (ifp->options->options & DHCPCD_RELEASE) { |
---|
2016 | unlink(state->leasefile); |
---|
2017 | if (ifp->carrier != LINK_DOWN && |
---|
2018 | state->new != NULL && |
---|
2019 | state->new->cookie == htonl(MAGIC_COOKIE)) |
---|
2020 | { |
---|
2021 | syslog(LOG_INFO, "%s: releasing lease of %s", |
---|
2022 | ifp->name, inet_ntoa(state->lease.addr)); |
---|
2023 | state->xid = dhcp_xid(ifp); |
---|
2024 | send_message(ifp, DHCP_RELEASE, NULL); |
---|
2025 | #ifdef RELEASE_SLOW |
---|
2026 | /* Give the packet a chance to go */ |
---|
2027 | ts.tv_sec = RELEASE_DELAY_S; |
---|
2028 | ts.tv_nsec = RELEASE_DELAY_NS; |
---|
2029 | nanosleep(&ts, NULL); |
---|
2030 | #endif |
---|
2031 | } |
---|
2032 | } |
---|
2033 | free(state->old); |
---|
2034 | state->old = state->new; |
---|
2035 | state->new = NULL; |
---|
2036 | state->reason = reason; |
---|
2037 | ipv4_applyaddr(ifp); |
---|
2038 | free(state->old); |
---|
2039 | state->old = NULL; |
---|
2040 | state->lease.addr.s_addr = 0; |
---|
2041 | ifp->options->options &= ~ DHCPCD_CSR_WARNED; |
---|
2042 | state->auth.token = NULL; |
---|
2043 | state->auth.replay = 0; |
---|
2044 | free(state->auth.reconf); |
---|
2045 | state->auth.reconf = NULL; |
---|
2046 | } |
---|
2047 | |
---|
2048 | static void |
---|
2049 | log_dhcp(int lvl, const char *msg, |
---|
2050 | const struct interface *iface, const struct dhcp_message *dhcp, |
---|
2051 | const struct in_addr *from) |
---|
2052 | { |
---|
2053 | const char *tfrom; |
---|
2054 | char *a; |
---|
2055 | struct in_addr addr; |
---|
2056 | int r; |
---|
2057 | |
---|
2058 | if (strcmp(msg, "NAK:") == 0) |
---|
2059 | a = get_option_string(dhcp, DHO_MESSAGE); |
---|
2060 | else if (dhcp->yiaddr != 0) { |
---|
2061 | addr.s_addr = dhcp->yiaddr; |
---|
2062 | a = strdup(inet_ntoa(addr)); |
---|
2063 | if (a == NULL) { |
---|
2064 | syslog(LOG_ERR, "%s: %m", __func__); |
---|
2065 | return; |
---|
2066 | } |
---|
2067 | } else |
---|
2068 | a = NULL; |
---|
2069 | |
---|
2070 | tfrom = "from"; |
---|
2071 | r = get_option_addr(&addr, dhcp, DHO_SERVERID); |
---|
2072 | if (dhcp->servername[0] && r == 0) |
---|
2073 | syslog(lvl, "%s: %s %s %s %s `%s'", iface->name, msg, a, |
---|
2074 | tfrom, inet_ntoa(addr), dhcp->servername); |
---|
2075 | else { |
---|
2076 | if (r != 0) { |
---|
2077 | tfrom = "via"; |
---|
2078 | addr = *from; |
---|
2079 | } |
---|
2080 | if (a == NULL) |
---|
2081 | syslog(lvl, "%s: %s %s %s", |
---|
2082 | iface->name, msg, tfrom, inet_ntoa(addr)); |
---|
2083 | else |
---|
2084 | syslog(lvl, "%s: %s %s %s %s", |
---|
2085 | iface->name, msg, a, tfrom, inet_ntoa(addr)); |
---|
2086 | } |
---|
2087 | free(a); |
---|
2088 | } |
---|
2089 | |
---|
2090 | static int |
---|
2091 | blacklisted_ip(const struct if_options *ifo, in_addr_t addr) |
---|
2092 | { |
---|
2093 | size_t i; |
---|
2094 | |
---|
2095 | for (i = 0; i < ifo->blacklist_len; i += 2) |
---|
2096 | if (ifo->blacklist[i] == (addr & ifo->blacklist[i + 1])) |
---|
2097 | return 1; |
---|
2098 | return 0; |
---|
2099 | } |
---|
2100 | |
---|
2101 | static int |
---|
2102 | whitelisted_ip(const struct if_options *ifo, in_addr_t addr) |
---|
2103 | { |
---|
2104 | size_t i; |
---|
2105 | |
---|
2106 | if (ifo->whitelist_len == 0) |
---|
2107 | return -1; |
---|
2108 | for (i = 0; i < ifo->whitelist_len; i += 2) |
---|
2109 | if (ifo->whitelist[i] == (addr & ifo->whitelist[i + 1])) |
---|
2110 | return 1; |
---|
2111 | return 0; |
---|
2112 | } |
---|
2113 | |
---|
2114 | static void |
---|
2115 | dhcp_handledhcp(struct interface *iface, struct dhcp_message **dhcpp, |
---|
2116 | const struct in_addr *from) |
---|
2117 | { |
---|
2118 | struct dhcp_state *state = D_STATE(iface); |
---|
2119 | struct if_options *ifo = iface->options; |
---|
2120 | struct dhcp_message *dhcp = *dhcpp; |
---|
2121 | struct dhcp_lease *lease = &state->lease; |
---|
2122 | uint8_t type, tmp; |
---|
2123 | const uint8_t *auth; |
---|
2124 | struct in_addr addr; |
---|
2125 | size_t i; |
---|
2126 | int auth_len; |
---|
2127 | |
---|
2128 | /* We may have found a BOOTP server */ |
---|
2129 | if (get_option_uint8(&type, dhcp, DHO_MESSAGETYPE) == -1) |
---|
2130 | type = 0; |
---|
2131 | |
---|
2132 | /* Authenticate the message */ |
---|
2133 | auth = get_option(dhcp, DHO_AUTHENTICATION, &auth_len); |
---|
2134 | if (auth) { |
---|
2135 | if (dhcp_auth_validate(&state->auth, &ifo->auth, |
---|
2136 | (uint8_t *)*dhcpp, sizeof(**dhcpp), 4, type, |
---|
2137 | auth, auth_len) == NULL) |
---|
2138 | { |
---|
2139 | syslog(LOG_DEBUG, "%s: dhcp_auth_validate: %m", |
---|
2140 | iface->name); |
---|
2141 | log_dhcp(LOG_ERR, "authentication failed", |
---|
2142 | iface, dhcp, from); |
---|
2143 | return; |
---|
2144 | } |
---|
2145 | syslog(LOG_DEBUG, "%s: validated using 0x%08" PRIu32, |
---|
2146 | iface->name, state->auth.token->secretid); |
---|
2147 | } else if (ifo->auth.options & DHCPCD_AUTH_REQUIRE) { |
---|
2148 | log_dhcp(LOG_ERR, "missing authentiation", iface, dhcp, from); |
---|
2149 | return; |
---|
2150 | } |
---|
2151 | |
---|
2152 | /* reset the message counter */ |
---|
2153 | state->interval = 0; |
---|
2154 | |
---|
2155 | if (type == DHCP_NAK) { |
---|
2156 | /* For NAK, only check if we require the ServerID */ |
---|
2157 | if (has_option_mask(ifo->requiremask, DHO_SERVERID) && |
---|
2158 | get_option_addr(&addr, dhcp, DHO_SERVERID) == -1) |
---|
2159 | { |
---|
2160 | log_dhcp(LOG_WARNING, "reject NAK", iface, dhcp, from); |
---|
2161 | return; |
---|
2162 | } |
---|
2163 | /* We should restart on a NAK */ |
---|
2164 | log_dhcp(LOG_WARNING, "NAK:", iface, dhcp, from); |
---|
2165 | if (!(options & DHCPCD_TEST)) { |
---|
2166 | dhcp_drop(iface, "NAK"); |
---|
2167 | unlink(state->leasefile); |
---|
2168 | } |
---|
2169 | dhcp_close(iface); |
---|
2170 | /* If we constantly get NAKS then we should slowly back off */ |
---|
2171 | eloop_timeout_add_sec(state->nakoff, dhcp_discover, iface); |
---|
2172 | if (state->nakoff == 0) |
---|
2173 | state->nakoff = 1; |
---|
2174 | else { |
---|
2175 | state->nakoff *= 2; |
---|
2176 | if (state->nakoff > NAKOFF_MAX) |
---|
2177 | state->nakoff = NAKOFF_MAX; |
---|
2178 | } |
---|
2179 | return; |
---|
2180 | } |
---|
2181 | |
---|
2182 | /* Ensure that all required options are present */ |
---|
2183 | for (i = 1; i < 255; i++) { |
---|
2184 | if (has_option_mask(ifo->requiremask, i) && |
---|
2185 | get_option_uint8(&tmp, dhcp, i) != 0) |
---|
2186 | { |
---|
2187 | /* If we are bootp, then ignore the need for serverid. |
---|
2188 | * To ignore bootp, require dhcp_message_type. */ |
---|
2189 | if (type == 0 && i == DHO_SERVERID) |
---|
2190 | continue; |
---|
2191 | log_dhcp(LOG_WARNING, "reject DHCP", iface, dhcp, from); |
---|
2192 | return; |
---|
2193 | } |
---|
2194 | } |
---|
2195 | |
---|
2196 | /* Ensure that the address offered is valid */ |
---|
2197 | if ((type == 0 || type == DHCP_OFFER || type == DHCP_ACK) && |
---|
2198 | (dhcp->ciaddr == INADDR_ANY || dhcp->ciaddr == INADDR_BROADCAST) && |
---|
2199 | (dhcp->yiaddr == INADDR_ANY || dhcp->yiaddr == INADDR_BROADCAST)) |
---|
2200 | { |
---|
2201 | log_dhcp(LOG_WARNING, "reject invalid address", |
---|
2202 | iface, dhcp, from); |
---|
2203 | return; |
---|
2204 | } |
---|
2205 | |
---|
2206 | if ((type == 0 || type == DHCP_OFFER) && |
---|
2207 | state->state == DHS_DISCOVER) |
---|
2208 | { |
---|
2209 | lease->frominfo = 0; |
---|
2210 | lease->addr.s_addr = dhcp->yiaddr; |
---|
2211 | lease->cookie = dhcp->cookie; |
---|
2212 | if (type == 0 || |
---|
2213 | get_option_addr(&lease->server, dhcp, DHO_SERVERID) != 0) |
---|
2214 | lease->server.s_addr = INADDR_ANY; |
---|
2215 | log_dhcp(LOG_INFO, "offered", iface, dhcp, from); |
---|
2216 | free(state->offer); |
---|
2217 | state->offer = dhcp; |
---|
2218 | *dhcpp = NULL; |
---|
2219 | if (options & DHCPCD_TEST) { |
---|
2220 | free(state->old); |
---|
2221 | state->old = state->new; |
---|
2222 | state->new = state->offer; |
---|
2223 | state->offer = NULL; |
---|
2224 | state->reason = "TEST"; |
---|
2225 | script_runreason(iface, state->reason); |
---|
2226 | exit(EXIT_SUCCESS); |
---|
2227 | } |
---|
2228 | eloop_timeout_delete(send_discover, iface); |
---|
2229 | /* We don't request BOOTP addresses */ |
---|
2230 | if (type) { |
---|
2231 | /* We used to ARP check here, but that seems to be in |
---|
2232 | * violation of RFC2131 where it only describes |
---|
2233 | * DECLINE after REQUEST. |
---|
2234 | * It also seems that some MS DHCP servers actually |
---|
2235 | * ignore DECLINE if no REQUEST, ie we decline a |
---|
2236 | * DISCOVER. */ |
---|
2237 | dhcp_request(iface); |
---|
2238 | return; |
---|
2239 | } |
---|
2240 | } |
---|
2241 | |
---|
2242 | if (type) { |
---|
2243 | if (type == DHCP_OFFER) { |
---|
2244 | log_dhcp(LOG_WARNING, "ignoring offer of", |
---|
2245 | iface, dhcp, from); |
---|
2246 | return; |
---|
2247 | } |
---|
2248 | |
---|
2249 | /* We should only be dealing with acks */ |
---|
2250 | if (type != DHCP_ACK) { |
---|
2251 | log_dhcp(LOG_ERR, "not ACK or OFFER", |
---|
2252 | iface, dhcp, from); |
---|
2253 | return; |
---|
2254 | } |
---|
2255 | |
---|
2256 | if (!(ifo->options & DHCPCD_INFORM)) |
---|
2257 | log_dhcp(LOG_DEBUG, "acknowledged", iface, dhcp, from); |
---|
2258 | else |
---|
2259 | ifo->options &= ~DHCPCD_STATIC; |
---|
2260 | } |
---|
2261 | |
---|
2262 | |
---|
2263 | /* No NAK, so reset the backoff |
---|
2264 | * We don't reset on an OFFER message because the server could |
---|
2265 | * potentially NAK the REQUEST. */ |
---|
2266 | state->nakoff = 0; |
---|
2267 | |
---|
2268 | /* BOOTP could have already assigned this above, so check we still |
---|
2269 | * have a pointer. */ |
---|
2270 | if (*dhcpp) { |
---|
2271 | free(state->offer); |
---|
2272 | state->offer = dhcp; |
---|
2273 | *dhcpp = NULL; |
---|
2274 | } |
---|
2275 | |
---|
2276 | lease->frominfo = 0; |
---|
2277 | eloop_timeout_delete(NULL, iface); |
---|
2278 | |
---|
2279 | /* We now have an offer, so close the DHCP sockets. |
---|
2280 | * This allows us to safely ARP when broken DHCP servers send an ACK |
---|
2281 | * follows by an invalid NAK. */ |
---|
2282 | dhcp_close(iface); |
---|
2283 | |
---|
2284 | if (ifo->options & DHCPCD_ARP && |
---|
2285 | state->addr.s_addr != state->offer->yiaddr) |
---|
2286 | { |
---|
2287 | /* If the interface already has the address configured |
---|
2288 | * then we can't ARP for duplicate detection. */ |
---|
2289 | addr.s_addr = state->offer->yiaddr; |
---|
2290 | if (!ipv4_findaddr(iface, &addr, NULL)) { |
---|
2291 | state->claims = 0; |
---|
2292 | state->probes = 0; |
---|
2293 | state->conflicts = 0; |
---|
2294 | state->state = DHS_PROBE; |
---|
2295 | arp_probe(iface); |
---|
2296 | return; |
---|
2297 | } |
---|
2298 | } |
---|
2299 | |
---|
2300 | dhcp_bind(iface); |
---|
2301 | } |
---|
2302 | |
---|
2303 | static ssize_t |
---|
2304 | get_udp_data(const uint8_t **data, const uint8_t *udp) |
---|
2305 | { |
---|
2306 | struct udp_dhcp_packet p; |
---|
2307 | |
---|
2308 | memcpy(&p, udp, sizeof(p)); |
---|
2309 | *data = udp + offsetof(struct udp_dhcp_packet, dhcp); |
---|
2310 | return ntohs(p.ip.ip_len) - sizeof(p.ip) - sizeof(p.udp); |
---|
2311 | } |
---|
2312 | |
---|
2313 | static int |
---|
2314 | valid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from, |
---|
2315 | int noudpcsum) |
---|
2316 | { |
---|
2317 | struct udp_dhcp_packet p; |
---|
2318 | uint16_t bytes, udpsum; |
---|
2319 | |
---|
2320 | if (data_len < sizeof(p.ip)) { |
---|
2321 | if (from) |
---|
2322 | from->s_addr = INADDR_ANY; |
---|
2323 | errno = EINVAL; |
---|
2324 | return -1; |
---|
2325 | } |
---|
2326 | memcpy(&p, data, MIN(data_len, sizeof(p))); |
---|
2327 | if (from) |
---|
2328 | from->s_addr = p.ip.ip_src.s_addr; |
---|
2329 | if (data_len > sizeof(p)) { |
---|
2330 | errno = EINVAL; |
---|
2331 | return -1; |
---|
2332 | } |
---|
2333 | if (checksum(&p.ip, sizeof(p.ip)) != 0) { |
---|
2334 | errno = EINVAL; |
---|
2335 | return -1; |
---|
2336 | } |
---|
2337 | |
---|
2338 | bytes = ntohs(p.ip.ip_len); |
---|
2339 | if (data_len < bytes) { |
---|
2340 | errno = EINVAL; |
---|
2341 | return -1; |
---|
2342 | } |
---|
2343 | |
---|
2344 | if (noudpcsum == 0) { |
---|
2345 | udpsum = p.udp.uh_sum; |
---|
2346 | p.udp.uh_sum = 0; |
---|
2347 | p.ip.ip_hl = 0; |
---|
2348 | p.ip.ip_v = 0; |
---|
2349 | p.ip.ip_tos = 0; |
---|
2350 | p.ip.ip_len = p.udp.uh_ulen; |
---|
2351 | p.ip.ip_id = 0; |
---|
2352 | p.ip.ip_off = 0; |
---|
2353 | p.ip.ip_ttl = 0; |
---|
2354 | p.ip.ip_sum = 0; |
---|
2355 | if (udpsum && checksum(&p, bytes) != udpsum) { |
---|
2356 | errno = EINVAL; |
---|
2357 | return -1; |
---|
2358 | } |
---|
2359 | } |
---|
2360 | |
---|
2361 | return 0; |
---|
2362 | } |
---|
2363 | |
---|
2364 | static void |
---|
2365 | dhcp_handlepacket(void *arg) |
---|
2366 | { |
---|
2367 | struct interface *iface = arg; |
---|
2368 | struct dhcp_message *dhcp = NULL; |
---|
2369 | const uint8_t *pp; |
---|
2370 | ssize_t bytes; |
---|
2371 | struct in_addr from; |
---|
2372 | int i, partialcsum = 0; |
---|
2373 | const struct dhcp_state *state = D_CSTATE(iface); |
---|
2374 | |
---|
2375 | /* We loop through until our buffer is empty. |
---|
2376 | * The benefit is that if we get >1 DHCP packet in our buffer and |
---|
2377 | * the first one fails for any reason, we can use the next. */ |
---|
2378 | for(;;) { |
---|
2379 | bytes = ipv4_getrawpacket(iface, ETHERTYPE_IP, |
---|
2380 | packet, udp_dhcp_len, &partialcsum); |
---|
2381 | if (bytes == 0 || bytes == -1) |
---|
2382 | break; |
---|
2383 | if (valid_udp_packet(packet, bytes, &from, partialcsum) == -1) { |
---|
2384 | syslog(LOG_ERR, "%s: invalid UDP packet from %s", |
---|
2385 | iface->name, inet_ntoa(from)); |
---|
2386 | continue; |
---|
2387 | } |
---|
2388 | i = whitelisted_ip(iface->options, from.s_addr); |
---|
2389 | if (i == 0) { |
---|
2390 | syslog(LOG_WARNING, |
---|
2391 | "%s: non whitelisted DHCP packet from %s", |
---|
2392 | iface->name, inet_ntoa(from)); |
---|
2393 | continue; |
---|
2394 | } else if (i != 1 && |
---|
2395 | blacklisted_ip(iface->options, from.s_addr) == 1) |
---|
2396 | { |
---|
2397 | syslog(LOG_WARNING, |
---|
2398 | "%s: blacklisted DHCP packet from %s", |
---|
2399 | iface->name, inet_ntoa(from)); |
---|
2400 | continue; |
---|
2401 | } |
---|
2402 | if (iface->flags & IFF_POINTOPOINT && |
---|
2403 | state->dst.s_addr != from.s_addr) |
---|
2404 | { |
---|
2405 | syslog(LOG_WARNING, |
---|
2406 | "%s: server %s is not destination", |
---|
2407 | iface->name, inet_ntoa(from)); |
---|
2408 | } |
---|
2409 | bytes = get_udp_data(&pp, packet); |
---|
2410 | if ((size_t)bytes > sizeof(*dhcp)) { |
---|
2411 | syslog(LOG_ERR, |
---|
2412 | "%s: packet greater than DHCP size from %s", |
---|
2413 | iface->name, inet_ntoa(from)); |
---|
2414 | continue; |
---|
2415 | } |
---|
2416 | if (dhcp == NULL) { |
---|
2417 | dhcp = calloc(1, sizeof(*dhcp)); |
---|
2418 | if (dhcp == NULL) { |
---|
2419 | syslog(LOG_ERR, "%s: calloc: %m", __func__); |
---|
2420 | break; |
---|
2421 | } |
---|
2422 | } |
---|
2423 | memcpy(dhcp, pp, bytes); |
---|
2424 | if (dhcp->cookie != htonl(MAGIC_COOKIE)) { |
---|
2425 | syslog(LOG_DEBUG, "%s: bogus cookie from %s", |
---|
2426 | iface->name, inet_ntoa(from)); |
---|
2427 | continue; |
---|
2428 | } |
---|
2429 | /* Ensure it's the right transaction */ |
---|
2430 | if (state->xid != ntohl(dhcp->xid)) { |
---|
2431 | syslog(LOG_DEBUG, |
---|
2432 | "%s: wrong xid 0x%x (expecting 0x%x) from %s", |
---|
2433 | iface->name, ntohl(dhcp->xid), state->xid, |
---|
2434 | inet_ntoa(from)); |
---|
2435 | continue; |
---|
2436 | } |
---|
2437 | /* Ensure packet is for us */ |
---|
2438 | if (iface->hwlen <= sizeof(dhcp->chaddr) && |
---|
2439 | memcmp(dhcp->chaddr, iface->hwaddr, iface->hwlen)) |
---|
2440 | { |
---|
2441 | syslog(LOG_DEBUG, "%s: xid 0x%x is not for hwaddr %s", |
---|
2442 | iface->name, ntohl(dhcp->xid), |
---|
2443 | hwaddr_ntoa(dhcp->chaddr, sizeof(dhcp->chaddr))); |
---|
2444 | continue; |
---|
2445 | } |
---|
2446 | dhcp_handledhcp(iface, &dhcp, &from); |
---|
2447 | if (state->raw_fd == -1) |
---|
2448 | break; |
---|
2449 | } |
---|
2450 | free(dhcp); |
---|
2451 | } |
---|
2452 | |
---|
2453 | static int |
---|
2454 | dhcp_open(struct interface *ifp) |
---|
2455 | { |
---|
2456 | struct dhcp_state *state; |
---|
2457 | |
---|
2458 | if (packet == NULL) { |
---|
2459 | packet = malloc(udp_dhcp_len); |
---|
2460 | if (packet == NULL) { |
---|
2461 | syslog(LOG_ERR, "%s: %m", __func__); |
---|
2462 | return -1; |
---|
2463 | } |
---|
2464 | #ifdef DEBUG_MEMORY |
---|
2465 | atexit(dhcp_cleanup); |
---|
2466 | #endif |
---|
2467 | } |
---|
2468 | |
---|
2469 | state = D_STATE(ifp); |
---|
2470 | if (state->raw_fd == -1) { |
---|
2471 | state->raw_fd = ipv4_opensocket(ifp, ETHERTYPE_IP); |
---|
2472 | if (state->raw_fd == -1) { |
---|
2473 | syslog(LOG_ERR, "%s: %s: %m", __func__, ifp->name); |
---|
2474 | return -1; |
---|
2475 | } |
---|
2476 | eloop_event_add(state->raw_fd, dhcp_handlepacket, ifp); |
---|
2477 | } |
---|
2478 | if (state->udp_fd == -1 && |
---|
2479 | state->addr.s_addr != 0 && |
---|
2480 | state->new != NULL && |
---|
2481 | (state->new->cookie == htonl(MAGIC_COOKIE) || |
---|
2482 | ifp->options->options & DHCPCD_INFORM)) |
---|
2483 | { |
---|
2484 | if (dhcp_openudp(ifp) == -1 && errno != EADDRINUSE) { |
---|
2485 | syslog(LOG_ERR, "%s: dhcp_openudp: %m", ifp->name); |
---|
2486 | return -1; |
---|
2487 | } |
---|
2488 | } |
---|
2489 | return 0; |
---|
2490 | } |
---|
2491 | |
---|
2492 | int |
---|
2493 | dhcp_dump(const char *ifname) |
---|
2494 | { |
---|
2495 | struct interface *ifp; |
---|
2496 | struct dhcp_state *state; |
---|
2497 | |
---|
2498 | ifaces = malloc(sizeof(*ifaces)); |
---|
2499 | if (ifaces == NULL) |
---|
2500 | goto eexit; |
---|
2501 | TAILQ_INIT(ifaces); |
---|
2502 | ifp = calloc(1, sizeof(*ifp)); |
---|
2503 | if (ifp == NULL) |
---|
2504 | goto eexit; |
---|
2505 | TAILQ_INSERT_HEAD(ifaces, ifp, next); |
---|
2506 | ifp->if_data[IF_DATA_DHCP] = state = calloc(1, sizeof(*state)); |
---|
2507 | if (state == NULL) |
---|
2508 | goto eexit; |
---|
2509 | ifp->options = calloc(1, sizeof(*ifp->options)); |
---|
2510 | if (ifp->options == NULL) |
---|
2511 | goto eexit; |
---|
2512 | strlcpy(ifp->name, ifname, sizeof(ifp->name)); |
---|
2513 | snprintf(state->leasefile, sizeof(state->leasefile), |
---|
2514 | LEASEFILE, ifp->name); |
---|
2515 | strlcpy(ifp->options->script, if_options->script, |
---|
2516 | sizeof(ifp->options->script)); |
---|
2517 | state->new = read_lease(ifp); |
---|
2518 | if (state->new == NULL && errno == ENOENT) { |
---|
2519 | strlcpy(state->leasefile, ifname, sizeof(state->leasefile)); |
---|
2520 | state->new = read_lease(ifp); |
---|
2521 | } |
---|
2522 | if (state->new == NULL) { |
---|
2523 | if (errno == ENOENT) |
---|
2524 | syslog(LOG_ERR, "%s: no lease to dump", ifname); |
---|
2525 | return -1; |
---|
2526 | } |
---|
2527 | state->reason = "DUMP"; |
---|
2528 | return script_runreason(ifp, state->reason); |
---|
2529 | |
---|
2530 | eexit: |
---|
2531 | syslog(LOG_ERR, "%s: %m", __func__); |
---|
2532 | return -1; |
---|
2533 | } |
---|
2534 | |
---|
2535 | void |
---|
2536 | dhcp_free(struct interface *ifp) |
---|
2537 | { |
---|
2538 | struct dhcp_state *state = D_STATE(ifp); |
---|
2539 | |
---|
2540 | if (state) { |
---|
2541 | free(state->old); |
---|
2542 | free(state->new); |
---|
2543 | free(state->offer); |
---|
2544 | free(state->buffer); |
---|
2545 | free(state->clientid); |
---|
2546 | free(state); |
---|
2547 | ifp->if_data[IF_DATA_DHCP] = NULL; |
---|
2548 | } |
---|
2549 | } |
---|
2550 | |
---|
2551 | static int |
---|
2552 | dhcp_init(struct interface *ifp) |
---|
2553 | { |
---|
2554 | struct dhcp_state *state; |
---|
2555 | const struct if_options *ifo; |
---|
2556 | size_t len; |
---|
2557 | |
---|
2558 | state = D_STATE(ifp); |
---|
2559 | if (state == NULL) { |
---|
2560 | ifp->if_data[IF_DATA_DHCP] = calloc(1, sizeof(*state)); |
---|
2561 | state = D_STATE(ifp); |
---|
2562 | if (state == NULL) |
---|
2563 | return -1; |
---|
2564 | /* 0 is a valid fd, so init to -1 */ |
---|
2565 | state->raw_fd = state->udp_fd = state->arp_fd = -1; |
---|
2566 | } |
---|
2567 | |
---|
2568 | state->state = DHS_INIT; |
---|
2569 | state->reason = "PREINIT"; |
---|
2570 | state->nakoff = 0; |
---|
2571 | snprintf(state->leasefile, sizeof(state->leasefile), |
---|
2572 | LEASEFILE, ifp->name); |
---|
2573 | |
---|
2574 | ifo = ifp->options; |
---|
2575 | /* We need to drop the leasefile so that start_interface |
---|
2576 | * doesn't load it. */ |
---|
2577 | if (ifo->options & DHCPCD_REQUEST) |
---|
2578 | unlink(state->leasefile); |
---|
2579 | |
---|
2580 | free(state->clientid); |
---|
2581 | state->clientid = NULL; |
---|
2582 | |
---|
2583 | if (*ifo->clientid) { |
---|
2584 | state->clientid = malloc(ifo->clientid[0] + 1); |
---|
2585 | if (state->clientid == NULL) |
---|
2586 | goto eexit; |
---|
2587 | memcpy(state->clientid, ifo->clientid, ifo->clientid[0] + 1); |
---|
2588 | } else if (ifo->options & DHCPCD_CLIENTID) { |
---|
2589 | if (ifo->options & DHCPCD_DUID) { |
---|
2590 | state->clientid = malloc(duid_len + 6); |
---|
2591 | if (state->clientid == NULL) |
---|
2592 | goto eexit; |
---|
2593 | state->clientid[0] = duid_len + 5; |
---|
2594 | state->clientid[1] = 255; /* RFC 4361 */ |
---|
2595 | memcpy(state->clientid + 2, ifo->iaid, 4); |
---|
2596 | memcpy(state->clientid + 6, duid, duid_len); |
---|
2597 | } else { |
---|
2598 | len = ifp->hwlen + 1; |
---|
2599 | state->clientid = malloc(len + 1); |
---|
2600 | if (state->clientid == NULL) |
---|
2601 | goto eexit; |
---|
2602 | state->clientid[0] = len; |
---|
2603 | state->clientid[1] = ifp->family; |
---|
2604 | memcpy(state->clientid + 2, ifp->hwaddr, |
---|
2605 | ifp->hwlen); |
---|
2606 | } |
---|
2607 | } |
---|
2608 | |
---|
2609 | if (ifo->options & DHCPCD_DUID) |
---|
2610 | /* Don't bother logging as DUID and IAID are reported |
---|
2611 | * at device start. */ |
---|
2612 | return 0; |
---|
2613 | |
---|
2614 | if (ifo->options & DHCPCD_CLIENTID) |
---|
2615 | syslog(LOG_DEBUG, "%s: using ClientID %s", ifp->name, |
---|
2616 | hwaddr_ntoa(state->clientid + 1, state->clientid[0])); |
---|
2617 | else if (ifp->hwlen) |
---|
2618 | syslog(LOG_DEBUG, "%s: using hwaddr %s", ifp->name, |
---|
2619 | hwaddr_ntoa(ifp->hwaddr, ifp->hwlen)); |
---|
2620 | return 0; |
---|
2621 | |
---|
2622 | eexit: |
---|
2623 | syslog(LOG_ERR, "%s: Error making ClientID: %m", __func__); |
---|
2624 | return -1; |
---|
2625 | } |
---|
2626 | |
---|
2627 | void |
---|
2628 | dhcp_start(struct interface *ifp) |
---|
2629 | { |
---|
2630 | struct if_options *ifo = ifp->options; |
---|
2631 | struct dhcp_state *state; |
---|
2632 | struct stat st; |
---|
2633 | struct timeval now; |
---|
2634 | uint32_t l; |
---|
2635 | int nolease; |
---|
2636 | |
---|
2637 | if (!(ifo->options & DHCPCD_IPV4)) |
---|
2638 | return; |
---|
2639 | |
---|
2640 | if (dhcp_init(ifp) == -1) { |
---|
2641 | syslog(LOG_ERR, "%s: dhcp_init: %m", ifp->name); |
---|
2642 | return; |
---|
2643 | } |
---|
2644 | |
---|
2645 | /* Close any pre-existing sockets as we're starting over */ |
---|
2646 | dhcp_close(ifp); |
---|
2647 | |
---|
2648 | state = D_STATE(ifp); |
---|
2649 | state->start_uptime = uptime(); |
---|
2650 | free(state->offer); |
---|
2651 | state->offer = NULL; |
---|
2652 | |
---|
2653 | if (state->arping_index < ifo->arping_len) { |
---|
2654 | arp_start(ifp); |
---|
2655 | return; |
---|
2656 | } |
---|
2657 | |
---|
2658 | if (ifo->options & DHCPCD_STATIC) { |
---|
2659 | dhcp_static(ifp); |
---|
2660 | return; |
---|
2661 | } |
---|
2662 | |
---|
2663 | if (ifo->options & DHCPCD_DHCP && dhcp_open(ifp) == -1) |
---|
2664 | return; |
---|
2665 | |
---|
2666 | if (ifo->options & DHCPCD_INFORM) { |
---|
2667 | dhcp_inform(ifp); |
---|
2668 | return; |
---|
2669 | } |
---|
2670 | if (ifp->hwlen == 0 && ifo->clientid[0] == '\0') { |
---|
2671 | syslog(LOG_WARNING, "%s: needs a clientid to configure", |
---|
2672 | ifp->name); |
---|
2673 | dhcp_drop(ifp, "FAIL"); |
---|
2674 | dhcp_close(ifp); |
---|
2675 | eloop_timeout_delete(NULL, ifp); |
---|
2676 | return; |
---|
2677 | } |
---|
2678 | /* We don't want to read the old lease if we NAK an old test */ |
---|
2679 | nolease = state->offer && options & DHCPCD_TEST; |
---|
2680 | if (!nolease) |
---|
2681 | state->offer = read_lease(ifp); |
---|
2682 | if (state->offer) { |
---|
2683 | get_lease(&state->lease, state->offer); |
---|
2684 | state->lease.frominfo = 1; |
---|
2685 | if (state->offer->cookie == 0) { |
---|
2686 | if (state->offer->yiaddr == state->addr.s_addr) { |
---|
2687 | free(state->offer); |
---|
2688 | state->offer = NULL; |
---|
2689 | } |
---|
2690 | } else if (state->lease.leasetime != ~0U && |
---|
2691 | stat(state->leasefile, &st) == 0) |
---|
2692 | { |
---|
2693 | /* Offset lease times and check expiry */ |
---|
2694 | gettimeofday(&now, NULL); |
---|
2695 | if ((time_t)state->lease.leasetime < |
---|
2696 | now.tv_sec - st.st_mtime) |
---|
2697 | { |
---|
2698 | syslog(LOG_DEBUG, |
---|
2699 | "%s: discarding expired lease", |
---|
2700 | ifp->name); |
---|
2701 | free(state->offer); |
---|
2702 | state->offer = NULL; |
---|
2703 | state->lease.addr.s_addr = 0; |
---|
2704 | } else { |
---|
2705 | l = now.tv_sec - st.st_mtime; |
---|
2706 | state->lease.leasetime -= l; |
---|
2707 | state->lease.renewaltime -= l; |
---|
2708 | state->lease.rebindtime -= l; |
---|
2709 | } |
---|
2710 | } |
---|
2711 | } |
---|
2712 | |
---|
2713 | if (!(ifo->options & DHCPCD_DHCP)) { |
---|
2714 | if (ifo->options & DHCPCD_IPV4LL) { |
---|
2715 | if (state->offer && state->offer->cookie != 0) { |
---|
2716 | free(state->offer); |
---|
2717 | state->offer = NULL; |
---|
2718 | } |
---|
2719 | ipv4ll_start(ifp); |
---|
2720 | } |
---|
2721 | return; |
---|
2722 | } |
---|
2723 | |
---|
2724 | if (state->offer == NULL) |
---|
2725 | dhcp_discover(ifp); |
---|
2726 | else if (state->offer->cookie == 0 && ifo->options & DHCPCD_IPV4LL) |
---|
2727 | ipv4ll_start(ifp); |
---|
2728 | else |
---|
2729 | dhcp_reboot(ifp); |
---|
2730 | } |
---|
2731 | |
---|
2732 | void |
---|
2733 | dhcp_handleifa(int type, struct interface *ifp, |
---|
2734 | const struct in_addr *addr, |
---|
2735 | const struct in_addr *net, |
---|
2736 | const struct in_addr *dst) |
---|
2737 | { |
---|
2738 | struct dhcp_state *state; |
---|
2739 | struct if_options *ifo; |
---|
2740 | int i; |
---|
2741 | |
---|
2742 | state = D_STATE(ifp); |
---|
2743 | if (state == NULL) |
---|
2744 | return; |
---|
2745 | |
---|
2746 | if (type == RTM_DELADDR) { |
---|
2747 | if (state->new && |
---|
2748 | (state->new->yiaddr == addr->s_addr || |
---|
2749 | (state->new->yiaddr == INADDR_ANY && |
---|
2750 | state->new->ciaddr == addr->s_addr))) |
---|
2751 | { |
---|
2752 | syslog(LOG_INFO, "%s: removing IP address %s/%d", |
---|
2753 | ifp->name, inet_ntoa(state->lease.addr), |
---|
2754 | inet_ntocidr(state->lease.net)); |
---|
2755 | dhcp_drop(ifp, "EXPIRE"); |
---|
2756 | } |
---|
2757 | return; |
---|
2758 | } |
---|
2759 | |
---|
2760 | if (type != RTM_NEWADDR) |
---|
2761 | return; |
---|
2762 | |
---|
2763 | ifo = ifp->options; |
---|
2764 | if (ifo->options & DHCPCD_INFORM) { |
---|
2765 | if (state->state != DHS_INFORM) |
---|
2766 | dhcp_inform(ifp); |
---|
2767 | return; |
---|
2768 | } |
---|
2769 | |
---|
2770 | if (!(ifo->options & DHCPCD_STATIC)) |
---|
2771 | return; |
---|
2772 | if (ifo->req_addr.s_addr != INADDR_ANY) |
---|
2773 | return; |
---|
2774 | |
---|
2775 | free(state->old); |
---|
2776 | state->old = state->new; |
---|
2777 | state->new = dhcp_message_new(addr, net); |
---|
2778 | if (state->new == NULL) |
---|
2779 | return; |
---|
2780 | state->dst.s_addr = dst ? dst->s_addr : INADDR_ANY; |
---|
2781 | if (dst) { |
---|
2782 | for (i = 1; i < 255; i++) |
---|
2783 | if (i != DHO_ROUTER && has_option_mask(ifo->dstmask,i)) |
---|
2784 | dhcp_message_add_addr(state->new, i, *dst); |
---|
2785 | } |
---|
2786 | state->reason = "STATIC"; |
---|
2787 | ipv4_buildroutes(); |
---|
2788 | script_runreason(ifp, state->reason); |
---|
2789 | if (ifo->options & DHCPCD_INFORM) { |
---|
2790 | state->state = DHS_INFORM; |
---|
2791 | state->xid = dhcp_xid(ifp); |
---|
2792 | state->lease.server.s_addr = dst ? dst->s_addr : INADDR_ANY; |
---|
2793 | state->addr = *addr; |
---|
2794 | state->net = *net; |
---|
2795 | dhcp_inform(ifp); |
---|
2796 | } |
---|
2797 | } |
---|