Expand PMF_FN_* macros.
[netbsd-mini2440.git] / external / bsd / dhcpcd / dist / dhcp.c
blob7ccda877c4ab53fbbc912ab4ce9cee312f171c2d
1 /*
2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2009 Roy Marples <roy@marples.name>
4 * All rights reserved
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.
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.
28 #include <ctype.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <syslog.h>
34 #include <unistd.h>
36 #include "config.h"
37 #include "common.h"
38 #include "dhcp.h"
40 #define REQUEST (1 << 0)
41 #define UINT8 (1 << 1)
42 #define UINT16 (1 << 2)
43 #define SINT16 (1 << 3)
44 #define UINT32 (1 << 4)
45 #define SINT32 (1 << 5)
46 #define IPV4 (1 << 6)
47 #define STRING (1 << 7)
48 #define PAIR (1 << 8)
49 #define ARRAY (1 << 9)
50 #define RFC3361 (1 << 10)
51 #define RFC3397 (1 << 11)
52 #define RFC3442 (1 << 12)
54 #define IPV4R IPV4 | REQUEST
56 #define DAD "Duplicate address detected"
58 /* Our aggregate option buffer.
59 * We ONLY use this when options are split, which for most purposes is
60 * practically never. See RFC3396 for details. */
61 static uint8_t *opt_buffer;
63 struct dhcp_opt {
64 uint8_t option;
65 int type;
66 const char *var;
69 static const struct dhcp_opt const dhcp_opts[] = {
70 { 1, IPV4 | REQUEST, "subnet_mask" },
71 /* RFC 3442 states that the CSR has to come before all other
72 * routes. For completeness, we also specify static routes,
73 * then routers. */
74 { 121, RFC3442, "classless_static_routes" },
75 { 249, RFC3442, "ms_classless_static_routes" },
76 { 33, IPV4 | ARRAY | REQUEST, "static_routes" },
77 { 3, IPV4 | ARRAY | REQUEST, "routers" },
78 { 2, UINT32, "time_offset" },
79 { 4, IPV4 | ARRAY, "time_servers" },
80 { 5, IPV4 | ARRAY, "ien116_name_servers" },
81 { 6, IPV4 | ARRAY, "domain_name_servers" },
82 { 7, IPV4 | ARRAY, "log_servers" },
83 { 8, IPV4 | ARRAY, "cookie_servers" },
84 { 9, IPV4 | ARRAY, "lpr_servers" },
85 { 10, IPV4 | ARRAY, "impress_servers" },
86 { 11, IPV4 | ARRAY, "resource_location_servers" },
87 { 12, STRING, "host_name" },
88 { 13, UINT16, "boot_size" },
89 { 14, STRING, "merit_dump" },
90 { 15, STRING, "domain_name" },
91 { 16, IPV4, "swap_server" },
92 { 17, STRING, "root_path" },
93 { 18, STRING, "extensions_path" },
94 { 19, UINT8, "ip_forwarding" },
95 { 20, UINT8, "non_local_source_routing" },
96 { 21, IPV4 | ARRAY, "policy_filter" },
97 { 22, SINT16, "max_dgram_reassembly" },
98 { 23, UINT16, "default_ip_ttl" },
99 { 24, UINT32, "path_mtu_aging_timeout" },
100 { 25, UINT16 | ARRAY, "path_mtu_plateau_table" },
101 { 26, UINT16, "interface_mtu" },
102 { 27, UINT8, "all_subnets_local" },
103 { 28, IPV4 | REQUEST, "broadcast_address" },
104 { 29, UINT8, "perform_mask_discovery" },
105 { 30, UINT8, "mask_supplier" },
106 { 31, UINT8, "router_discovery" },
107 { 32, IPV4, "router_solicitation_address" },
108 { 34, UINT8, "trailer_encapsulation" },
109 { 35, UINT32, "arp_cache_timeout" },
110 { 36, UINT16, "ieee802_3_encapsulation" },
111 { 37, UINT8, "default_tcp_ttl" },
112 { 38, UINT32, "tcp_keepalive_interval" },
113 { 39, UINT8, "tcp_keepalive_garbage" },
114 { 40, STRING, "nis_domain" },
115 { 41, IPV4 | ARRAY, "nis_servers" },
116 { 42, IPV4 | ARRAY, "ntp_servers" },
117 { 43, STRING, "vendor_encapsulated_options" },
118 { 44, IPV4 | ARRAY, "netbios_name_servers" },
119 { 45, IPV4, "netbios_dd_server" },
120 { 46, UINT8, "netbios_node_type" },
121 { 47, STRING, "netbios_scope" },
122 { 48, IPV4 | ARRAY, "font_servers" },
123 { 49, IPV4 | ARRAY, "x_display_manager" },
124 { 50, IPV4, "dhcp_requested_address" },
125 { 51, UINT32 | REQUEST, "dhcp_lease_time" },
126 { 52, UINT8, "dhcp_option_overload" },
127 { 53, UINT8, "dhcp_message_type" },
128 { 54, IPV4, "dhcp_server_identifier" },
129 { 55, UINT8 | ARRAY, "dhcp_parameter_request_list" },
130 { 56, STRING, "dhcp_message" },
131 { 57, UINT16, "dhcp_max_message_size" },
132 { 58, UINT32 | REQUEST, "dhcp_renewal_time" },
133 { 59, UINT32 | REQUEST, "dhcp_rebinding_time" },
134 { 64, STRING, "nisplus_domain" },
135 { 65, IPV4 | ARRAY, "nisplus_servers" },
136 { 66, STRING, "tftp_server_name" },
137 { 67, STRING, "bootfile_name" },
138 { 68, IPV4 | ARRAY, "mobile_ip_home_agent" },
139 { 69, IPV4 | ARRAY, "smtp_server" },
140 { 70, IPV4 | ARRAY, "pop_server" },
141 { 71, IPV4 | ARRAY, "nntp_server" },
142 { 72, IPV4 | ARRAY, "www_server" },
143 { 73, IPV4 | ARRAY, "finger_server" },
144 { 74, IPV4 | ARRAY, "irc_server" },
145 { 75, IPV4 | ARRAY, "streettalk_server" },
146 { 76, IPV4 | ARRAY, "streettalk_directory_assistance_server" },
147 { 77, STRING, "user_class" },
148 { 81, STRING | RFC3397, "fqdn_name" },
149 { 85, IPV4 | ARRAY, "nds_servers" },
150 { 86, STRING, "nds_tree_name" },
151 { 87, STRING, "nds_context" },
152 { 88, STRING | RFC3397, "bcms_controller_names" },
153 { 89, IPV4 | ARRAY, "bcms_controller_address" },
154 { 91, UINT32, "client_last_transaction_time" },
155 { 92, IPV4 | ARRAY, "associated_ip" },
156 { 98, STRING, "uap_servers" },
157 { 112, IPV4 | ARRAY, "netinfo_server_address" },
158 { 113, STRING, "netinfo_server_tag" },
159 { 114, STRING, "default_url" },
160 { 118, IPV4, "subnet_selection" },
161 { 119, STRING | RFC3397, "domain_search" },
162 { 0, 0, NULL }
165 static const char *if_params[] = {
166 "interface",
167 "reason",
168 "pid",
169 "ifmetric",
170 "ifwireless",
171 "ifflags",
172 "profile",
173 "interface_order",
174 NULL
177 static const char *dhcp_params[] = {
178 "ip_address",
179 "subnet_cidr",
180 "network_number",
181 "ssid",
182 "filename",
183 "server_name",
184 NULL
187 void
188 print_options(void)
190 const struct dhcp_opt *opt;
191 const char **p;
193 for (p = if_params; *p; p++)
194 printf(" - %s\n", *p);
196 for (p = dhcp_params; *p; p++)
197 printf(" %s\n", *p);
199 for (opt = dhcp_opts; opt->option; opt++)
200 if (opt->var)
201 printf("%03d %s\n", opt->option, opt->var);
204 int make_option_mask(uint8_t *mask, const char *opts, int add)
206 char *token, *o, *p, *t;
207 const struct dhcp_opt *opt;
208 int match, n;
210 o = p = xstrdup(opts);
211 while ((token = strsep(&p, ", "))) {
212 if (*token == '\0')
213 continue;
214 for (opt = dhcp_opts; opt->option; opt++) {
215 if (!opt->var)
216 continue;
217 match = 0;
218 if (strcmp(opt->var, token) == 0)
219 match = 1;
220 else {
221 errno = 0;
222 n = strtol(token, &t, 0);
223 if (errno == 0 && !*t)
224 if (opt->option == n)
225 match = 1;
227 if (match) {
228 if (add == 2 && !(opt->type & IPV4)) {
229 free(o);
230 errno = EINVAL;
231 return -1;
233 if (add == 1 || add == 2)
234 add_option_mask(mask,
235 opt->option);
236 else
237 del_option_mask(mask,
238 opt->option);
239 break;
242 if (!opt->option) {
243 free(o);
244 errno = ENOENT;
245 return -1;
248 free(o);
249 return 0;
252 static int
253 valid_length(uint8_t option, int dl, int *type)
255 const struct dhcp_opt *opt;
256 ssize_t sz;
258 if (dl == 0)
259 return -1;
261 for (opt = dhcp_opts; opt->option; opt++) {
262 if (opt->option != option)
263 continue;
265 if (type)
266 *type = opt->type;
268 if (opt->type == 0 ||
269 opt->type & STRING ||
270 opt->type & RFC3442)
271 return 0;
273 sz = 0;
274 if (opt->type & UINT32 || opt->type & IPV4)
275 sz = sizeof(uint32_t);
276 if (opt->type & UINT16)
277 sz = sizeof(uint16_t);
278 if (opt->type & UINT8)
279 sz = sizeof(uint8_t);
280 if (opt->type & IPV4 || opt->type & ARRAY)
281 return dl % sz;
282 return (dl == sz ? 0 : -1);
285 /* unknown option, so let it pass */
286 return 0;
289 #ifdef DEBUG_MEMORY
290 static void
291 free_option_buffer(void)
293 free(opt_buffer);
295 #endif
297 #define get_option_raw(dhcp, opt) get_option(dhcp, opt, NULL, NULL)
298 static const uint8_t *
299 get_option(const struct dhcp_message *dhcp, uint8_t opt, int *len, int *type)
301 const uint8_t *p = dhcp->options;
302 const uint8_t *e = p + sizeof(dhcp->options);
303 uint8_t l, ol = 0;
304 uint8_t o = 0;
305 uint8_t overl = 0;
306 uint8_t *bp = NULL;
307 const uint8_t *op = NULL;
308 int bl = 0;
310 while (p < e) {
311 o = *p++;
312 if (o == opt) {
313 if (op) {
314 if (!opt_buffer) {
315 opt_buffer = xmalloc(sizeof(*dhcp));
316 #ifdef DEBUG_MEMORY
317 atexit(free_option_buffer);
318 #endif
320 if (!bp)
321 bp = opt_buffer;
322 memcpy(bp, op, ol);
323 bp += ol;
325 ol = *p;
326 op = p + 1;
327 bl += ol;
329 switch (o) {
330 case DHO_PAD:
331 continue;
332 case DHO_END:
333 if (overl & 1) {
334 /* bit 1 set means parse boot file */
335 overl &= ~1;
336 p = dhcp->bootfile;
337 e = p + sizeof(dhcp->bootfile);
338 } else if (overl & 2) {
339 /* bit 2 set means parse server name */
340 overl &= ~2;
341 p = dhcp->servername;
342 e = p + sizeof(dhcp->servername);
343 } else
344 goto exit;
345 break;
346 case DHO_OPTIONSOVERLOADED:
347 /* Ensure we only get this option once */
348 if (!overl)
349 overl = p[1];
350 break;
352 l = *p++;
353 p += l;
356 exit:
357 if (valid_length(opt, bl, type) == -1) {
358 errno = EINVAL;
359 return NULL;
361 if (len)
362 *len = bl;
363 if (bp) {
364 memcpy(bp, op, ol);
365 return (const uint8_t *)&opt_buffer;
367 if (op)
368 return op;
369 errno = ENOENT;
370 return NULL;
374 get_option_addr(struct in_addr *a, const struct dhcp_message *dhcp,
375 uint8_t option)
377 const uint8_t *p = get_option_raw(dhcp, option);
379 if (!p)
380 return -1;
381 memcpy(&a->s_addr, p, sizeof(a->s_addr));
382 return 0;
386 get_option_uint32(uint32_t *i, const struct dhcp_message *dhcp, uint8_t option)
388 const uint8_t *p = get_option_raw(dhcp, option);
389 uint32_t d;
391 if (!p)
392 return -1;
393 memcpy(&d, p, sizeof(d));
394 *i = ntohl(d);
395 return 0;
399 get_option_uint16(uint16_t *i, const struct dhcp_message *dhcp, uint8_t option)
401 const uint8_t *p = get_option_raw(dhcp, option);
402 uint16_t d;
404 if (!p)
405 return -1;
406 memcpy(&d, p, sizeof(d));
407 *i = ntohs(d);
408 return 0;
412 get_option_uint8(uint8_t *i, const struct dhcp_message *dhcp, uint8_t option)
414 const uint8_t *p = get_option_raw(dhcp, option);
416 if (!p)
417 return -1;
418 if (i)
419 *i = *(p);
420 return 0;
423 /* Decode an RFC3397 DNS search order option into a space
424 * seperated string. Returns length of string (including
425 * terminating zero) or zero on error. out may be NULL
426 * to just determine output length. */
427 static ssize_t
428 decode_rfc3397(char *out, ssize_t len, int pl, const uint8_t *p)
430 const uint8_t *r, *q = p;
431 int count = 0, l, hops;
432 uint8_t ltype;
434 while (q - p < pl) {
435 r = NULL;
436 hops = 0;
437 /* We check we are inside our length again incase
438 * the data is NOT terminated correctly. */
439 while ((l = *q++) && q - p < pl) {
440 ltype = l & 0xc0;
441 if (ltype == 0x80 || ltype == 0x40)
442 return 0;
443 else if (ltype == 0xc0) { /* pointer */
444 l = (l & 0x3f) << 8;
445 l |= *q++;
446 /* save source of first jump. */
447 if (!r)
448 r = q;
449 hops++;
450 if (hops > 255)
451 return 0;
452 q = p + l;
453 if (q - p >= pl)
454 return 0;
455 } else {
456 /* straightforward name segment, add with '.' */
457 count += l + 1;
458 if (out) {
459 if ((ssize_t)l + 1 > len) {
460 errno = ENOBUFS;
461 return -1;
463 memcpy(out, q, l);
464 out += l;
465 *out++ = '.';
466 len -= l;
467 len--;
469 q += l;
472 /* change last dot to space */
473 if (out)
474 *(out - 1) = ' ';
475 if (r)
476 q = r;
479 /* change last space to zero terminator */
480 if (out)
481 *(out - 1) = 0;
483 return count;
486 static ssize_t
487 decode_rfc3442(char *out, ssize_t len, int pl, const uint8_t *p)
489 const uint8_t *e;
490 ssize_t b, bytes = 0, ocets;
491 uint8_t cidr;
492 struct in_addr addr;
493 char *o = out;
495 /* Minimum is 5 -first is CIDR and a router length of 4 */
496 if (pl < 5) {
497 errno = EINVAL;
498 return -1;
501 e = p + pl;
502 while (p < e) {
503 cidr = *p++;
504 if (cidr > 32) {
505 errno = EINVAL;
506 return -1;
508 ocets = (cidr + 7) / 8;
509 if (!out) {
510 p += 4 + ocets;
511 bytes += ((4 * 4) * 2) + 4;
512 continue;
514 if ((((4 * 4) * 2) + 4) > len) {
515 errno = ENOBUFS;
516 return -1;
518 if (o != out) {
519 *o++ = ' ';
520 len--;
522 /* If we have ocets then we have a destination and netmask */
523 if (ocets > 0) {
524 addr.s_addr = 0;
525 memcpy(&addr.s_addr, p, ocets);
526 b = snprintf(o, len, "%s/%d", inet_ntoa(addr), cidr);
527 p += ocets;
528 } else
529 b = snprintf(o, len, "0.0.0.0/0");
530 o += b;
531 len -= b;
533 /* Finally, snag the router */
534 memcpy(&addr.s_addr, p, 4);
535 p += 4;
536 b = snprintf(o, len, " %s", inet_ntoa(addr));
537 o += b;
538 len -= b;
541 if (out)
542 return o - out;
543 return bytes;
546 static struct rt *
547 decode_rfc3442_rt(int dl, const uint8_t *data)
549 const uint8_t *p = data;
550 const uint8_t *e;
551 uint8_t cidr;
552 size_t ocets;
553 struct rt *routes = NULL;
554 struct rt *rt = NULL;
556 /* Minimum is 5 -first is CIDR and a router length of 4 */
557 if (dl < 5)
558 return NULL;
560 e = p + dl;
561 while (p < e) {
562 cidr = *p++;
563 if (cidr > 32) {
564 free_routes(routes);
565 errno = EINVAL;
566 return NULL;
569 if (rt) {
570 rt->next = xzalloc(sizeof(*rt));
571 rt = rt->next;
572 } else {
573 routes = rt = xzalloc(sizeof(*routes));
575 rt->next = NULL;
577 ocets = (cidr + 7) / 8;
578 /* If we have ocets then we have a destination and netmask */
579 if (ocets > 0) {
580 memcpy(&rt->dest.s_addr, p, ocets);
581 p += ocets;
582 rt->net.s_addr = htonl(~0U << (32 - cidr));
585 /* Finally, snag the router */
586 memcpy(&rt->gate.s_addr, p, 4);
587 p += 4;
589 return routes;
592 static char *
593 decode_rfc3361(int dl, const uint8_t *data)
595 uint8_t enc;
596 unsigned int l;
597 char *sip = NULL;
598 struct in_addr addr;
599 char *p;
601 if (dl < 2) {
602 errno = EINVAL;
603 return 0;
606 enc = *data++;
607 dl--;
608 switch (enc) {
609 case 0:
610 if ((l = decode_rfc3397(NULL, 0, dl, data)) > 0) {
611 sip = xmalloc(l);
612 decode_rfc3397(sip, l, dl, data);
614 break;
615 case 1:
616 if (dl == 0 || dl % 4 != 0) {
617 errno = EINVAL;
618 break;
620 addr.s_addr = INADDR_BROADCAST;
621 l = ((dl / sizeof(addr.s_addr)) * ((4 * 4) + 1)) + 1;
622 sip = p = xmalloc(l);
623 while (l != 0) {
624 memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
625 data += sizeof(addr.s_addr);
626 p += snprintf(p, l - (p - sip), "%s ", inet_ntoa(addr));
627 l -= sizeof(addr.s_addr);
629 *--p = '\0';
630 break;
631 default:
632 errno = EINVAL;
633 return 0;
636 return sip;
639 char *
640 get_option_string(const struct dhcp_message *dhcp, uint8_t option)
642 int type = 0;
643 int len;
644 const uint8_t *p;
645 char *s;
647 p = get_option(dhcp, option, &len, &type);
648 if (!p || *p == '\0')
649 return NULL;
651 if (type & RFC3397) {
652 type = decode_rfc3397(NULL, 0, len, p);
653 if (!type) {
654 errno = EINVAL;
655 return NULL;
657 s = xmalloc(sizeof(char) * type);
658 decode_rfc3397(s, type, len, p);
659 return s;
662 if (type & RFC3361)
663 return decode_rfc3361(len, p);
665 s = xmalloc(sizeof(char) * (len + 1));
666 memcpy(s, p, len);
667 s[len] = '\0';
668 return s;
671 /* This calculates the netmask that we should use for static routes.
672 * This IS different from the calculation used to calculate the netmask
673 * for an interface address. */
674 static uint32_t
675 route_netmask(uint32_t ip_in)
677 /* used to be unsigned long - check if error */
678 uint32_t p = ntohl(ip_in);
679 uint32_t t;
681 if (IN_CLASSA(p))
682 t = ~IN_CLASSA_NET;
683 else {
684 if (IN_CLASSB(p))
685 t = ~IN_CLASSB_NET;
686 else {
687 if (IN_CLASSC(p))
688 t = ~IN_CLASSC_NET;
689 else
690 t = 0;
694 while (t & p)
695 t >>= 1;
697 return (htonl(~t));
700 /* We need to obey routing options.
701 * If we have a CSR then we only use that.
702 * Otherwise we add static routes and then routers. */
703 struct rt *
704 get_option_routes(const struct dhcp_message *dhcp,
705 const char *ifname, int *opts)
707 const uint8_t *p;
708 const uint8_t *e;
709 struct rt *routes = NULL;
710 struct rt *route = NULL;
711 int len;
713 /* If we have CSR's then we MUST use these only */
714 p = get_option(dhcp, DHO_CSR, &len, NULL);
715 /* Check for crappy MS option */
716 if (!p)
717 p = get_option(dhcp, DHO_MSCSR, &len, NULL);
718 if (p) {
719 routes = decode_rfc3442_rt(len, p);
720 if (routes && !(*opts & DHCPCD_CSR_WARNED)) {
721 syslog(LOG_DEBUG,
722 "%s: using Classless Static Routes (RFC3442)",
723 ifname);
724 *opts |= DHCPCD_CSR_WARNED;
725 return routes;
729 /* OK, get our static routes first. */
730 p = get_option(dhcp, DHO_STATICROUTE, &len, NULL);
731 if (p) {
732 e = p + len;
733 while (p < e) {
734 if (route) {
735 route->next = xmalloc(sizeof(*route));
736 route = route->next;
737 } else
738 routes = route = xmalloc(sizeof(*routes));
739 route->next = NULL;
740 memcpy(&route->dest.s_addr, p, 4);
741 p += 4;
742 memcpy(&route->gate.s_addr, p, 4);
743 p += 4;
744 route->net.s_addr = route_netmask(route->dest.s_addr);
748 /* Now grab our routers */
749 p = get_option(dhcp, DHO_ROUTER, &len, NULL);
750 if (p) {
751 e = p + len;
752 while (p < e) {
753 if (route) {
754 route->next = xzalloc(sizeof(*route));
755 route = route->next;
756 } else
757 routes = route = xzalloc(sizeof(*route));
758 memcpy(&route->gate.s_addr, p, 4);
759 p += 4;
763 return routes;
766 static size_t
767 encode_rfc1035(const char *src, uint8_t *dst)
769 uint8_t *p = dst;
770 uint8_t *lp = p++;
772 if (*src == '\0')
773 return 0;
774 for (; *src; src++) {
775 if (*src == '\0')
776 break;
777 if (*src == '.') {
778 /* Skip the trailing . */
779 if (src[1] == '\0')
780 break;
781 *lp = p - lp - 1;
782 if (*lp == '\0')
783 return p - dst;
784 lp = p++;
785 } else
786 *p++ = (uint8_t)*src;
788 *lp = p - lp - 1;
789 *p++ = '\0';
790 return p - dst;
793 #define PUTADDR(_type, _val) \
795 *p++ = _type; \
796 *p++ = 4; \
797 memcpy(p, &_val.s_addr, 4); \
798 p += 4; \
802 dhcp_message_add_addr(struct dhcp_message *dhcp,
803 uint8_t type, struct in_addr addr)
805 uint8_t *p;
806 size_t len;
808 p = dhcp->options;
809 while (*p != DHO_END) {
810 p++;
811 p += *p + 1;
814 len = p - (uint8_t *)dhcp;
815 if (len + 6 > sizeof(*dhcp)) {
816 errno = ENOMEM;
817 return -1;
820 PUTADDR(type, addr);
821 *p = DHO_END;
822 return 0;
825 ssize_t
826 make_message(struct dhcp_message **message,
827 const struct interface *iface,
828 uint8_t type)
830 struct dhcp_message *dhcp;
831 uint8_t *m, *lp, *p;
832 uint8_t *n_params = NULL;
833 time_t up = uptime() - iface->start_uptime;
834 uint32_t ul;
835 uint16_t sz;
836 size_t len;
837 const char *hp;
838 const struct dhcp_opt *opt;
839 const struct if_options *ifo = iface->state->options;
840 const struct dhcp_lease *lease = &iface->state->lease;
842 dhcp = xzalloc(sizeof (*dhcp));
843 m = (uint8_t *)dhcp;
844 p = dhcp->options;
846 if ((type == DHCP_INFORM ||
847 type == DHCP_RELEASE ||
848 type == DHCP_REQUEST) &&
849 !IN_LINKLOCAL(ntohl(iface->addr.s_addr)))
851 dhcp->ciaddr = iface->addr.s_addr;
852 /* In-case we haven't actually configured the address yet */
853 if (type == DHCP_INFORM && iface->addr.s_addr == 0)
854 dhcp->ciaddr = lease->addr.s_addr;
855 /* Zero the address if we're currently on a different subnet */
856 if (type == DHCP_REQUEST &&
857 iface->net.s_addr != lease->net.s_addr)
858 dhcp->ciaddr = 0;
861 dhcp->op = DHCP_BOOTREQUEST;
862 dhcp->hwtype = iface->family;
863 switch (iface->family) {
864 case ARPHRD_ETHER:
865 case ARPHRD_IEEE802:
866 dhcp->hwlen = ETHER_ADDR_LEN;
867 memcpy(&dhcp->chaddr, &iface->hwaddr, ETHER_ADDR_LEN);
868 break;
869 case ARPHRD_IEEE1394:
870 case ARPHRD_INFINIBAND:
871 dhcp->hwlen = 0;
872 if (dhcp->ciaddr == 0 &&
873 type != DHCP_DECLINE && type != DHCP_RELEASE)
874 dhcp->flags = htons(BROADCAST_FLAG);
875 break;
878 if (type != DHCP_DECLINE && type != DHCP_RELEASE) {
879 if (up < 0 || up > (time_t)UINT16_MAX)
880 dhcp->secs = htons((uint16_t)UINT16_MAX);
881 else
882 dhcp->secs = htons(up);
884 dhcp->xid = iface->state->xid;
885 dhcp->cookie = htonl(MAGIC_COOKIE);
887 *p++ = DHO_MESSAGETYPE;
888 *p++ = 1;
889 *p++ = type;
891 if (iface->clientid) {
892 *p++ = DHO_CLIENTID;
893 memcpy(p, iface->clientid, iface->clientid[0] + 1);
894 p += iface->clientid[0] + 1;
897 if (lease->addr.s_addr && !IN_LINKLOCAL(htonl(lease->addr.s_addr))) {
898 if (type == DHCP_DECLINE ||
899 type == DHCP_DISCOVER ||
900 (type == DHCP_REQUEST &&
901 lease->addr.s_addr != iface->addr.s_addr))
903 PUTADDR(DHO_IPADDRESS, lease->addr);
904 if (lease->server.s_addr)
905 PUTADDR(DHO_SERVERID, lease->server);
908 if (type == DHCP_RELEASE) {
909 if (lease->server.s_addr)
910 PUTADDR(DHO_SERVERID, lease->server);
914 if (type == DHCP_DECLINE) {
915 *p++ = DHO_MESSAGE;
916 len = strlen(DAD);
917 *p++ = len;
918 memcpy(p, DAD, len);
919 p += len;
922 if (type == DHCP_DISCOVER ||
923 type == DHCP_INFORM ||
924 type == DHCP_REQUEST)
926 *p++ = DHO_MAXMESSAGESIZE;
927 *p++ = 2;
928 sz = get_mtu(iface->name);
929 if (sz < MTU_MIN) {
930 if (set_mtu(iface->name, MTU_MIN) == 0)
931 sz = MTU_MIN;
933 sz = htons(sz);
934 memcpy(p, &sz, 2);
935 p += 2;
937 if (ifo->userclass[0]) {
938 *p++ = DHO_USERCLASS;
939 memcpy(p, ifo->userclass, ifo->userclass[0] + 1);
940 p += ifo->userclass[0] + 1;
943 if (ifo->vendorclassid[0]) {
944 *p++ = DHO_VENDORCLASSID;
945 memcpy(p, ifo->vendorclassid,
946 ifo->vendorclassid[0] + 1);
947 p += ifo->vendorclassid[0] + 1;
951 if (type != DHCP_INFORM) {
952 if (ifo->leasetime != 0) {
953 *p++ = DHO_LEASETIME;
954 *p++ = 4;
955 ul = htonl(ifo->leasetime);
956 memcpy(p, &ul, 4);
957 p += 4;
961 /* Regardless of RFC2132, we should always send a hostname
962 * upto the first dot (the short hostname) as otherwise
963 * confuses some DHCP servers when updating DNS.
964 * The FQDN option should be used if a FQDN is required. */
965 if (ifo->options & DHCPCD_HOSTNAME && ifo->hostname[0]) {
966 *p++ = DHO_HOSTNAME;
967 hp = strchr(ifo->hostname, '.');
968 if (hp)
969 len = hp - ifo->hostname;
970 else
971 len = strlen(ifo->hostname);
972 *p++ = len;
973 memcpy(p, ifo->hostname, len);
974 p += len;
976 if (ifo->fqdn != FQDN_DISABLE && ifo->hostname[0]) {
977 /* IETF DHC-FQDN option (81), RFC4702 */
978 *p++ = DHO_FQDN;
979 lp = p;
980 *p++ = 3;
982 * Flags: 0000NEOS
983 * S: 1 => Client requests Server to update
984 * a RR in DNS as well as PTR
985 * O: 1 => Server indicates to client that
986 * DNS has been updated
987 * E: 1 => Name data is DNS format
988 * N: 1 => Client requests Server to not
989 * update DNS
991 *p++ = (ifo->fqdn & 0x09) | 0x04;
992 *p++ = 0; /* from server for PTR RR */
993 *p++ = 0; /* from server for A RR if S=1 */
994 ul = encode_rfc1035(ifo->hostname, p);
995 *lp += ul;
996 p += ul;
999 /* vendor is already encoded correctly, so just add it */
1000 if (ifo->vendor[0]) {
1001 *p++ = DHO_VENDOR;
1002 memcpy(p, ifo->vendor, ifo->vendor[0] + 1);
1003 p += ifo->vendor[0] + 1;
1006 *p++ = DHO_PARAMETERREQUESTLIST;
1007 n_params = p;
1008 *p++ = 0;
1009 for (opt = dhcp_opts; opt->option; opt++) {
1010 if (!(opt->type & REQUEST ||
1011 has_option_mask(ifo->requestmask, opt->option)))
1012 continue;
1013 if (type == DHCP_INFORM &&
1014 (opt->option == DHO_RENEWALTIME ||
1015 opt->option == DHO_REBINDTIME))
1016 continue;
1017 *p++ = opt->option;
1019 *n_params = p - n_params - 1;
1021 *p++ = DHO_END;
1023 #ifdef BOOTP_MESSAGE_LENTH_MIN
1024 /* Some crappy DHCP servers think they have to obey the BOOTP minimum
1025 * message length.
1026 * They are wrong, but we should still cater for them. */
1027 while (p - m < BOOTP_MESSAGE_LENTH_MIN)
1028 *p++ = DHO_PAD;
1029 #endif
1031 *message = dhcp;
1032 return p - m;
1035 ssize_t
1036 write_lease(const struct interface *iface, const struct dhcp_message *dhcp)
1038 int fd;
1039 ssize_t bytes = sizeof(*dhcp);
1040 const uint8_t *p = dhcp->options;
1041 const uint8_t *e = p + sizeof(dhcp->options);
1042 uint8_t l;
1043 uint8_t o = 0;
1045 /* We don't write BOOTP leases */
1046 if (is_bootp(dhcp)) {
1047 unlink(iface->leasefile);
1048 return 0;
1051 syslog(LOG_DEBUG, "%s: writing lease `%s'",
1052 iface->name, iface->leasefile);
1054 fd = open(iface->leasefile, O_WRONLY | O_CREAT | O_TRUNC, 0400);
1055 if (fd == -1) {
1056 syslog(LOG_ERR, "%s: open: %m", iface->name);
1057 return -1;
1060 /* Only write as much as we need */
1061 while (p < e) {
1062 o = *p;
1063 if (o == DHO_END) {
1064 bytes = p - (const uint8_t *)dhcp;
1065 break;
1067 p++;
1068 if (o != DHO_PAD) {
1069 l = *p++;
1070 p += l;
1073 bytes = write(fd, dhcp, bytes);
1074 close(fd);
1075 return bytes;
1078 struct dhcp_message *
1079 read_lease(const struct interface *iface)
1081 int fd;
1082 struct dhcp_message *dhcp;
1083 ssize_t bytes;
1085 fd = open(iface->leasefile, O_RDONLY);
1086 if (fd == -1) {
1087 if (errno != ENOENT)
1088 syslog(LOG_ERR, "%s: open `%s': %m",
1089 iface->name, iface->leasefile);
1090 return NULL;
1092 syslog(LOG_DEBUG, "%s: reading lease `%s'",
1093 iface->name, iface->leasefile);
1094 dhcp = xmalloc(sizeof(*dhcp));
1095 memset(dhcp, 0, sizeof(*dhcp));
1096 bytes = read(fd, dhcp, sizeof(*dhcp));
1097 close(fd);
1098 if (bytes < 0) {
1099 free(dhcp);
1100 dhcp = NULL;
1102 return dhcp;
1105 static ssize_t
1106 print_string(char *s, ssize_t len, int dl, const uint8_t *data)
1108 uint8_t c;
1109 const uint8_t *e, *p;
1110 ssize_t bytes = 0;
1111 ssize_t r;
1113 e = data + dl;
1114 while (data < e) {
1115 c = *data++;
1116 if (c == '\0') {
1117 /* If rest is all NULL, skip it. */
1118 for (p = data; p < e; p++)
1119 if (*p != '\0')
1120 break;
1121 if (p == e)
1122 break;
1124 if (!isascii(c) || !isprint(c)) {
1125 if (s) {
1126 if (len < 5) {
1127 errno = ENOBUFS;
1128 return -1;
1130 r = snprintf(s, len, "\\%03o", c);
1131 len -= r;
1132 bytes += r;
1133 s += r;
1134 } else
1135 bytes += 4;
1136 continue;
1138 switch (c) {
1139 case '"': /* FALLTHROUGH */
1140 case '\'': /* FALLTHROUGH */
1141 case '$': /* FALLTHROUGH */
1142 case '`': /* FALLTHROUGH */
1143 case '\\':
1144 if (s) {
1145 if (len < 3) {
1146 errno = ENOBUFS;
1147 return -1;
1149 *s++ = '\\';
1150 len--;
1152 bytes++;
1153 break;
1155 if (s) {
1156 *s++ = c;
1157 len--;
1159 bytes++;
1162 /* NULL */
1163 if (s)
1164 *s = '\0';
1165 bytes++;
1166 return bytes;
1169 static ssize_t
1170 print_option(char *s, ssize_t len, int type, int dl, const uint8_t *data)
1172 const uint8_t *e, *t;
1173 uint16_t u16;
1174 int16_t s16;
1175 uint32_t u32;
1176 int32_t s32;
1177 struct in_addr addr;
1178 ssize_t bytes = 0;
1179 ssize_t l;
1180 char *tmp;
1182 if (type & RFC3397) {
1183 l = decode_rfc3397(NULL, 0, dl, data);
1184 if (l < 1)
1185 return l;
1186 tmp = xmalloc(l);
1187 decode_rfc3397(tmp, l, dl, data);
1188 l = print_string(s, len, l - 1, (uint8_t *)tmp);
1189 free(tmp);
1190 return l;
1193 if (type & RFC3442)
1194 return decode_rfc3442(s, len, dl, data);
1196 if (type & STRING) {
1197 /* Some DHCP servers return NULL strings */
1198 if (*data == '\0')
1199 return 0;
1200 return print_string(s, len, dl, data);
1203 if (!s) {
1204 if (type & UINT8)
1205 l = 3;
1206 else if (type & UINT16) {
1207 l = 5;
1208 dl /= 2;
1209 } else if (type & SINT16) {
1210 l = 6;
1211 dl /= 2;
1212 } else if (type & UINT32) {
1213 l = 10;
1214 dl /= 4;
1215 } else if (type & SINT32) {
1216 l = 11;
1217 dl /= 4;
1218 } else if (type & IPV4) {
1219 l = 16;
1220 dl /= 4;
1221 } else {
1222 errno = EINVAL;
1223 return -1;
1225 return (l + 1) * dl;
1228 t = data;
1229 e = data + dl;
1230 while (data < e) {
1231 if (data != t) {
1232 *s++ = ' ';
1233 bytes++;
1234 len--;
1236 if (type & UINT8) {
1237 l = snprintf(s, len, "%d", *data);
1238 data++;
1239 } else if (type & UINT16) {
1240 memcpy(&u16, data, sizeof(u16));
1241 u16 = ntohs(u16);
1242 l = snprintf(s, len, "%d", u16);
1243 data += sizeof(u16);
1244 } else if (type & SINT16) {
1245 memcpy(&s16, data, sizeof(s16));
1246 s16 = ntohs(s16);
1247 l = snprintf(s, len, "%d", s16);
1248 data += sizeof(s16);
1249 } else if (type & UINT32) {
1250 memcpy(&u32, data, sizeof(u32));
1251 u32 = ntohl(u32);
1252 l = snprintf(s, len, "%d", u32);
1253 data += sizeof(u32);
1254 } else if (type & SINT32) {
1255 memcpy(&s32, data, sizeof(s32));
1256 s32 = ntohl(s32);
1257 l = snprintf(s, len, "%d", s32);
1258 data += sizeof(s32);
1259 } else if (type & IPV4) {
1260 memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
1261 l = snprintf(s, len, "%s", inet_ntoa(addr));
1262 data += sizeof(addr.s_addr);
1263 } else
1264 l = 0;
1265 len -= l;
1266 bytes += l;
1267 s += l;
1270 return bytes;
1273 static void
1274 setvar(char ***e, const char *prefix, const char *var, const char *value)
1276 size_t len = strlen(prefix) + strlen(var) + strlen(value) + 4;
1278 **e = xmalloc(len);
1279 snprintf(**e, len, "%s_%s=%s", prefix, var, value);
1280 (*e)++;
1283 ssize_t
1284 configure_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
1285 const struct if_options *ifo)
1287 unsigned int i;
1288 const uint8_t *p;
1289 int pl;
1290 struct in_addr addr;
1291 struct in_addr net;
1292 struct in_addr brd;
1293 char *val, *v;
1294 const struct dhcp_opt *opt;
1295 ssize_t len, e = 0;
1296 char **ep;
1297 char cidr[4];
1298 uint8_t overl = 0;
1300 get_option_uint8(&overl, dhcp, DHO_OPTIONSOVERLOADED);
1302 if (!env) {
1303 for (opt = dhcp_opts; opt->option; opt++) {
1304 if (!opt->var)
1305 continue;
1306 if (has_option_mask(ifo->nomask, opt->option))
1307 continue;
1308 if (get_option_raw(dhcp, opt->option))
1309 e++;
1311 if (dhcp->yiaddr || dhcp->ciaddr)
1312 e += 5;
1313 if (*dhcp->bootfile && !(overl & 1))
1314 e++;
1315 if (*dhcp->servername && !(overl & 2))
1316 e++;
1317 return e;
1320 ep = env;
1321 if (dhcp->yiaddr || dhcp->ciaddr) {
1322 /* Set some useful variables that we derive from the DHCP
1323 * message but are not necessarily in the options */
1324 addr.s_addr = dhcp->yiaddr ? dhcp->yiaddr : dhcp->ciaddr;
1325 setvar(&ep, prefix, "ip_address", inet_ntoa(addr));
1326 if (get_option_addr(&net, dhcp, DHO_SUBNETMASK) == -1) {
1327 net.s_addr = get_netmask(addr.s_addr);
1328 setvar(&ep, prefix, "subnet_mask", inet_ntoa(net));
1330 i = inet_ntocidr(net);
1331 snprintf(cidr, sizeof(cidr), "%d", inet_ntocidr(net));
1332 setvar(&ep, prefix, "subnet_cidr", cidr);
1333 if (get_option_addr(&brd, dhcp, DHO_BROADCAST) == -1) {
1334 brd.s_addr = addr.s_addr | ~net.s_addr;
1335 setvar(&ep, prefix, "broadcast_address", inet_ntoa(brd));
1337 addr.s_addr = dhcp->yiaddr & net.s_addr;
1338 setvar(&ep, prefix, "network_number", inet_ntoa(addr));
1341 if (*dhcp->bootfile && !(overl & 1))
1342 setvar(&ep, prefix, "filename", (const char *)dhcp->bootfile);
1343 if (*dhcp->servername && !(overl & 2))
1344 setvar(&ep, prefix, "server_name", (const char *)dhcp->servername);
1346 for (opt = dhcp_opts; opt->option; opt++) {
1347 if (!opt->var)
1348 continue;
1349 if (has_option_mask(ifo->nomask, opt->option))
1350 continue;
1351 val = NULL;
1352 p = get_option(dhcp, opt->option, &pl, NULL);
1353 if (!p)
1354 continue;
1355 /* We only want the FQDN name */
1356 if (opt->option == DHO_FQDN) {
1357 p += 3;
1358 pl -= 3;
1360 len = print_option(NULL, 0, opt->type, pl, p);
1361 if (len < 0)
1362 return -1;
1363 e = strlen(prefix) + strlen(opt->var) + len + 4;
1364 v = val = *ep++ = xmalloc(e);
1365 v += snprintf(val, e, "%s_%s=", prefix, opt->var);
1366 if (len != 0)
1367 print_option(v, len, opt->type, pl, p);
1370 return ep - env;
1373 void
1374 get_lease(struct dhcp_lease *lease, const struct dhcp_message *dhcp)
1376 struct timeval now;
1378 /* BOOTP does not set yiaddr for replies when ciaddr is set. */
1379 if (dhcp->yiaddr)
1380 lease->addr.s_addr = dhcp->yiaddr;
1381 else
1382 lease->addr.s_addr = dhcp->ciaddr;
1383 if (get_option_addr(&lease->net, dhcp, DHO_SUBNETMASK) == -1)
1384 lease->net.s_addr = get_netmask(lease->addr.s_addr);
1385 if (get_option_addr(&lease->brd, dhcp, DHO_BROADCAST) == -1)
1386 lease->brd.s_addr = lease->addr.s_addr | ~lease->net.s_addr;
1387 if (get_option_uint32(&lease->leasetime, dhcp, DHO_LEASETIME) == 0) {
1388 /* Ensure that we can use the lease */
1389 get_monotonic(&now);
1390 if (now.tv_sec + (time_t)lease->leasetime < now.tv_sec)
1391 lease->leasetime = ~0U; /* Infinite lease */
1392 } else
1393 lease->leasetime = ~0U; /* Default to infinite lease */
1394 if (get_option_uint32(&lease->renewaltime, dhcp, DHO_RENEWALTIME) != 0)
1395 lease->renewaltime = 0;
1396 if (get_option_uint32(&lease->rebindtime, dhcp, DHO_REBINDTIME) != 0)
1397 lease->rebindtime = 0;
1398 if (get_option_addr(&lease->server, dhcp, DHO_SERVERID) != 0)
1399 lease->server.s_addr = INADDR_ANY;