Import dhcpcd-10.0.7 with the following changes:
[dragonfly.git] / contrib / dhcpcd / src / if-options.c
blobee8644d20c132c3414a7b089d6166e7234328b1a
1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3 * dhcpcd - DHCP client daemon
4 * Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
5 * All rights reserved
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
29 #include <sys/param.h>
30 #include <sys/types.h>
32 #include <arpa/inet.h>
34 #include <ctype.h>
35 #include <errno.h>
36 #include <getopt.h>
37 #include <grp.h>
38 #include <inttypes.h>
39 #include <limits.h>
40 #include <paths.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <time.h>
47 #include "config.h"
48 #include "common.h"
49 #include "dhcp.h"
50 #include "dhcp6.h"
51 #include "dhcpcd-embedded.h"
52 #include "duid.h"
53 #include "if.h"
54 #include "if-options.h"
55 #include "ipv4.h"
56 #include "logerr.h"
57 #include "sa.h"
59 #define IN_CONFIG_BLOCK(ifo) ((ifo)->options & DHCPCD_FORKED)
60 #define SET_CONFIG_BLOCK(ifo) ((ifo)->options |= DHCPCD_FORKED)
61 #define CLEAR_CONFIG_BLOCK(ifo) ((ifo)->options &= ~DHCPCD_FORKED)
63 static unsigned long long default_options;
65 const struct option cf_options[] = {
66 {"background", no_argument, NULL, 'b'},
67 {"script", required_argument, NULL, 'c'},
68 {"debug", no_argument, NULL, 'd'},
69 {"env", required_argument, NULL, 'e'},
70 {"config", required_argument, NULL, 'f'},
71 {"reconfigure", no_argument, NULL, 'g'},
72 {"hostname", optional_argument, NULL, 'h'},
73 {"vendorclassid", optional_argument, NULL, 'i'},
74 {"logfile", required_argument, NULL, 'j'},
75 {"release", no_argument, NULL, 'k'},
76 {"leasetime", required_argument, NULL, 'l'},
77 {"metric", required_argument, NULL, 'm'},
78 {"rebind", no_argument, NULL, 'n'},
79 {"option", required_argument, NULL, 'o'},
80 {"persistent", no_argument, NULL, 'p'},
81 {"quiet", no_argument, NULL, 'q'},
82 {"request", optional_argument, NULL, 'r'},
83 {"inform", optional_argument, NULL, 's'},
84 {"inform6", optional_argument, NULL, O_INFORM6},
85 {"timeout", required_argument, NULL, 't'},
86 {"userclass", required_argument, NULL, 'u'},
87 #ifndef SMALL
88 {"msuserclass", required_argument, NULL, O_MSUSERCLASS},
89 #endif
90 {"vendor", required_argument, NULL, 'v'},
91 {"waitip", optional_argument, NULL, 'w'},
92 {"exit", no_argument, NULL, 'x'},
93 {"allowinterfaces", required_argument, NULL, 'z'},
94 {"reboot", required_argument, NULL, 'y'},
95 {"noarp", no_argument, NULL, 'A'},
96 {"nobackground", no_argument, NULL, 'B'},
97 {"nohook", required_argument, NULL, 'C'},
98 {"duid", optional_argument, NULL, 'D'},
99 {"lastlease", no_argument, NULL, 'E'},
100 {"fqdn", optional_argument, NULL, 'F'},
101 {"nogateway", no_argument, NULL, 'G'},
102 {"xidhwaddr", no_argument, NULL, 'H'},
103 {"clientid", optional_argument, NULL, 'I'},
104 {"broadcast", no_argument, NULL, 'J'},
105 {"nolink", no_argument, NULL, 'K'},
106 {"noipv4ll", no_argument, NULL, 'L'},
107 {"manager", no_argument, NULL, 'M'},
108 {"renew", no_argument, NULL, 'N'},
109 {"nooption", required_argument, NULL, 'O'},
110 {"printpidfile", no_argument, NULL, 'P'},
111 {"require", required_argument, NULL, 'Q'},
112 {"static", required_argument, NULL, 'S'},
113 {"test", no_argument, NULL, 'T'},
114 {"dumplease", no_argument, NULL, 'U'},
115 {"variables", no_argument, NULL, 'V'},
116 {"whitelist", required_argument, NULL, 'W'},
117 {"blacklist", required_argument, NULL, 'X'},
118 {"denyinterfaces", required_argument, NULL, 'Z'},
119 {"oneshot", no_argument, NULL, '1'},
120 {"ipv4only", no_argument, NULL, '4'},
121 {"ipv6only", no_argument, NULL, '6'},
122 {"anonymous", no_argument, NULL, O_ANONYMOUS},
123 {"randomise_hwaddr",no_argument, NULL, O_RANDOMISE_HWADDR},
124 {"arping", required_argument, NULL, O_ARPING},
125 {"destination", required_argument, NULL, O_DESTINATION},
126 {"fallback", required_argument, NULL, O_FALLBACK},
127 {"ipv6rs", no_argument, NULL, O_IPV6RS},
128 {"noipv6rs", no_argument, NULL, O_NOIPV6RS},
129 {"ipv6ra_autoconf", no_argument, NULL, O_IPV6RA_AUTOCONF},
130 {"ipv6ra_noautoconf", no_argument, NULL, O_IPV6RA_NOAUTOCONF},
131 {"ipv6ra_fork", no_argument, NULL, O_IPV6RA_FORK},
132 {"ipv4", no_argument, NULL, O_IPV4},
133 {"noipv4", no_argument, NULL, O_NOIPV4},
134 {"ipv6", no_argument, NULL, O_IPV6},
135 {"noipv6", no_argument, NULL, O_NOIPV6},
136 {"noalias", no_argument, NULL, O_NOALIAS},
137 {"iaid", required_argument, NULL, O_IAID},
138 {"ia_na", optional_argument, NULL, O_IA_NA},
139 {"ia_ta", optional_argument, NULL, O_IA_TA},
140 {"ia_pd", optional_argument, NULL, O_IA_PD},
141 {"hostname_short", no_argument, NULL, O_HOSTNAME_SHORT},
142 {"dev", required_argument, NULL, O_DEV},
143 {"nodev", no_argument, NULL, O_NODEV},
144 {"define", required_argument, NULL, O_DEFINE},
145 {"definend", required_argument, NULL, O_DEFINEND},
146 {"define6", required_argument, NULL, O_DEFINE6},
147 {"embed", required_argument, NULL, O_EMBED},
148 {"encap", required_argument, NULL, O_ENCAP},
149 {"vendopt", required_argument, NULL, O_VENDOPT},
150 {"vendclass", required_argument, NULL, O_VENDCLASS},
151 {"authprotocol", required_argument, NULL, O_AUTHPROTOCOL},
152 {"authtoken", required_argument, NULL, O_AUTHTOKEN},
153 {"noauthrequired", no_argument, NULL, O_AUTHNOTREQUIRED},
154 {"dhcp", no_argument, NULL, O_DHCP},
155 {"nodhcp", no_argument, NULL, O_NODHCP},
156 {"dhcp6", no_argument, NULL, O_DHCP6},
157 {"nodhcp6", no_argument, NULL, O_NODHCP6},
158 {"controlgroup", required_argument, NULL, O_CONTROLGRP},
159 {"slaac", required_argument, NULL, O_SLAAC},
160 {"gateway", no_argument, NULL, O_GATEWAY},
161 {"reject", required_argument, NULL, O_REJECT},
162 {"bootp", no_argument, NULL, O_BOOTP},
163 {"nodelay", no_argument, NULL, O_NODELAY},
164 {"noup", no_argument, NULL, O_NOUP},
165 {"lastleaseextend", no_argument, NULL, O_LASTLEASE_EXTEND},
166 {"inactive", no_argument, NULL, O_INACTIVE},
167 {"mudurl", required_argument, NULL, O_MUDURL},
168 {"link_rcvbuf", required_argument, NULL, O_LINK_RCVBUF},
169 {"configure", no_argument, NULL, O_CONFIGURE},
170 {"noconfigure", no_argument, NULL, O_NOCONFIGURE},
171 {"arp_persistdefence", no_argument, NULL, O_ARP_PERSISTDEFENCE},
172 {"request_time", required_argument, NULL, O_REQUEST_TIME},
173 {"fallback_time", required_argument, NULL, O_FALLBACK_TIME},
174 {"ipv4ll_time", required_argument, NULL, O_IPV4LL_TIME},
175 {NULL, 0, NULL, '\0'}
178 static char *
179 add_environ(char ***array, const char *value, int uniq)
181 char **newlist, **list = *array;
182 size_t i = 0, l, lv;
183 char *match = NULL, *p, *n;
185 match = strdup(value);
186 if (match == NULL) {
187 logerr(__func__);
188 return NULL;
190 p = strchr(match, '=');
191 if (p == NULL) {
192 logerrx("%s: no assignment: %s", __func__, value);
193 free(match);
194 return NULL;
196 *p++ = '\0';
197 l = strlen(match);
199 while (list && list[i]) {
200 /* We know that it must contain '=' due to the above test */
201 size_t listl = (size_t)(strchr(list[i], '=') - list[i]);
203 if (l == listl && strncmp(list[i], match, l) == 0) {
204 if (uniq) {
205 n = strdup(value);
206 if (n == NULL) {
207 logerr(__func__);
208 free(match);
209 return NULL;
211 free(list[i]);
212 list[i] = n;
213 } else {
214 /* Append a space and the value to it */
215 l = strlen(list[i]);
216 lv = strlen(p);
217 n = realloc(list[i], l + lv + 2);
218 if (n == NULL) {
219 logerr(__func__);
220 free(match);
221 return NULL;
223 list[i] = n;
224 list[i][l] = ' ';
225 memcpy(list[i] + l + 1, p, lv);
226 list[i][l + lv + 1] = '\0';
228 free(match);
229 return list[i];
231 i++;
234 free(match);
235 n = strdup(value);
236 if (n == NULL) {
237 logerr(__func__);
238 return NULL;
240 newlist = reallocarray(list, i + 2, sizeof(char *));
241 if (newlist == NULL) {
242 logerr(__func__);
243 free(n);
244 return NULL;
246 newlist[i] = n;
247 newlist[i + 1] = NULL;
248 *array = newlist;
249 return newlist[i];
252 #define PARSE_STRING 0
253 #define PARSE_STRING_NULL 1
254 #define PARSE_HWADDR 2
255 #define parse_string(a, b, c) parse_str((a), (b), (c), PARSE_STRING)
256 #define parse_nstring(a, b, c) parse_str((a), (b), (c), PARSE_STRING_NULL)
257 #define parse_hwaddr(a, b, c) parse_str((a), (b), (c), PARSE_HWADDR)
258 static ssize_t
259 parse_str(char *sbuf, size_t slen, const char *str, int flags)
261 size_t l;
262 const char *p, *end;
263 int i;
264 char c[4], cmd;
266 end = str + strlen(str);
267 /* If surrounded by quotes then it's a string */
268 if (*str == '"') {
269 p = end - 1;
270 if (*p == '"') {
271 str++;
272 end = p;
274 } else {
275 l = (size_t)hwaddr_aton(NULL, str);
276 if (l > 0) {
277 if ((ssize_t)l == -1) {
278 errno = ENOBUFS;
279 return -1;
281 if (sbuf == NULL)
282 return (ssize_t)l;
283 if (l > slen) {
284 errno = ENOBUFS;
285 return -1;
287 hwaddr_aton((uint8_t *)sbuf, str);
288 return (ssize_t)l;
292 /* Process escapes */
293 l = 0;
294 /* If processing a string on the clientid, first byte should be
295 * 0 to indicate a non hardware type */
296 if (flags == PARSE_HWADDR && *str) {
297 if (sbuf)
298 *sbuf++ = 0;
299 l++;
301 c[3] = '\0';
302 while (str < end) {
303 if (++l > slen && sbuf) {
304 errno = ENOBUFS;
305 return -1;
307 if (*str == '\\') {
308 str++;
309 switch((cmd = *str++)) {
310 case '\0':
311 str--;
312 break;
313 case 'b':
314 if (sbuf)
315 *sbuf++ = '\b';
316 break;
317 case 'n':
318 if (sbuf)
319 *sbuf++ = '\n';
320 break;
321 case 'r':
322 if (sbuf)
323 *sbuf++ = '\r';
324 break;
325 case 't':
326 if (sbuf)
327 *sbuf++ = '\t';
328 break;
329 case 'x':
330 /* Grab a hex code */
331 c[1] = '\0';
332 for (i = 0; i < 2; i++) {
333 if (isxdigit((unsigned char)*str) == 0)
334 break;
335 c[i] = *str++;
337 if (c[1] != '\0') {
338 c[2] = '\0';
339 if (sbuf)
340 *sbuf++ = (char)strtol(c, NULL, 16);
341 } else
342 l--;
343 break;
344 case '0':
345 /* Grab an octal code */
346 c[2] = '\0';
347 for (i = 0; i < 3; i++) {
348 if (*str < '0' || *str > '7')
349 break;
350 c[i] = *str++;
352 if (c[2] != '\0') {
353 i = (int)strtol(c, NULL, 8);
354 if (i > 255)
355 i = 255;
356 if (sbuf)
357 *sbuf++ = (char)i;
358 } else
359 l--;
360 break;
361 default:
362 if (sbuf)
363 *sbuf++ = cmd;
364 break;
366 } else {
367 if (sbuf)
368 *sbuf++ = *str;
369 str++;
372 if (flags == PARSE_STRING_NULL) {
373 l++;
374 if (sbuf != NULL) {
375 if (l > slen) {
376 errno = ENOBUFS;
377 return -1;
379 *sbuf = '\0';
382 return (ssize_t)l;
385 static int
386 parse_iaid1(uint8_t *iaid, const char *arg, size_t len, int n)
388 int e;
389 uint32_t narg;
390 ssize_t s;
392 narg = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
393 if (e == 0) {
394 if (n)
395 narg = htonl(narg);
396 memcpy(iaid, &narg, sizeof(narg));
397 return 0;
400 if ((s = parse_string((char *)iaid, len, arg)) < 1)
401 return -1;
402 if (s < 4)
403 iaid[3] = '\0';
404 if (s < 3)
405 iaid[2] = '\0';
406 if (s < 2)
407 iaid[1] = '\0';
408 return 0;
411 static int
412 parse_iaid(uint8_t *iaid, const char *arg, size_t len)
415 return parse_iaid1(iaid, arg, len, 1);
418 #ifdef AUTH
419 static int
420 parse_uint32(uint32_t *i, const char *arg)
423 return parse_iaid1((uint8_t *)i, arg, sizeof(uint32_t), 0);
425 #endif
427 static char **
428 splitv(int *argc, char **argv, const char *arg)
430 char **n, **v = argv;
431 char *o = strdup(arg), *p, *t, *nt;
433 if (o == NULL) {
434 logerr(__func__);
435 return v;
437 p = o;
438 while ((t = strsep(&p, ", "))) {
439 nt = strdup(t);
440 if (nt == NULL) {
441 logerr(__func__);
442 free(o);
443 return v;
445 n = reallocarray(v, (size_t)(*argc) + 1, sizeof(char *));
446 if (n == NULL) {
447 logerr(__func__);
448 free(o);
449 free(nt);
450 return v;
452 v = n;
453 v[(*argc)++] = nt;
455 free(o);
456 return v;
459 #ifdef INET
460 static int
461 parse_addr(struct in_addr *addr, struct in_addr *net, const char *arg)
463 char *p;
465 if (arg == NULL || *arg == '\0') {
466 if (addr != NULL)
467 addr->s_addr = 0;
468 if (net != NULL)
469 net->s_addr = 0;
470 return 0;
472 if ((p = strchr(arg, '/')) != NULL) {
473 int e;
474 intmax_t i;
476 *p++ = '\0';
477 i = strtoi(p, NULL, 10, 0, 32, &e);
478 if (e != 0 ||
479 (net != NULL && inet_cidrtoaddr((int)i, net) != 0))
481 logerrx("invalid CIDR: %s", p);
482 return -1;
486 if (addr != NULL && inet_aton(arg, addr) == 0) {
487 logerrx("invalid IP address: %s", arg);
488 return -1;
490 if (p != NULL)
491 *--p = '/';
492 else if (net != NULL && addr != NULL)
493 net->s_addr = ipv4_getnetmask(addr->s_addr);
494 return 0;
496 #else
497 static int
498 parse_addr(__unused struct in_addr *addr, __unused struct in_addr *net,
499 __unused const char *arg)
502 logerrx("No IPv4 support");
503 return -1;
505 #endif
507 static void
508 set_option_space(struct dhcpcd_ctx *ctx,
509 const char *arg,
510 const struct dhcp_opt **d, size_t *dl,
511 const struct dhcp_opt **od, size_t *odl,
512 struct if_options *ifo,
513 uint8_t *request[], uint8_t *require[], uint8_t *no[], uint8_t *reject[])
516 #if !defined(INET) && !defined(INET6)
517 UNUSED(ctx);
518 #endif
520 #ifdef INET6
521 if (strncmp(arg, "nd_", strlen("nd_")) == 0) {
522 *d = ctx->nd_opts;
523 *dl = ctx->nd_opts_len;
524 *od = ifo->nd_override;
525 *odl = ifo->nd_override_len;
526 *request = ifo->requestmasknd;
527 *require = ifo->requiremasknd;
528 *no = ifo->nomasknd;
529 *reject = ifo->rejectmasknd;
530 return;
533 #ifdef DHCP6
534 if (strncmp(arg, "dhcp6_", strlen("dhcp6_")) == 0) {
535 *d = ctx->dhcp6_opts;
536 *dl = ctx->dhcp6_opts_len;
537 *od = ifo->dhcp6_override;
538 *odl = ifo->dhcp6_override_len;
539 *request = ifo->requestmask6;
540 *require = ifo->requiremask6;
541 *no = ifo->nomask6;
542 *reject = ifo->rejectmask6;
543 return;
545 #endif
546 #else
547 UNUSED(arg);
548 #endif
550 #ifdef INET
551 *d = ctx->dhcp_opts;
552 *dl = ctx->dhcp_opts_len;
553 *od = ifo->dhcp_override;
554 *odl = ifo->dhcp_override_len;
555 #else
556 *d = NULL;
557 *dl = 0;
558 *od = NULL;
559 *odl = 0;
560 #endif
561 *request = ifo->requestmask;
562 *require = ifo->requiremask;
563 *no = ifo->nomask;
564 *reject = ifo->rejectmask;
567 void
568 free_dhcp_opt_embenc(struct dhcp_opt *opt)
570 size_t i;
571 struct dhcp_opt *o;
573 free(opt->var);
575 for (i = 0, o = opt->embopts; i < opt->embopts_len; i++, o++)
576 free_dhcp_opt_embenc(o);
577 free(opt->embopts);
578 opt->embopts_len = 0;
579 opt->embopts = NULL;
581 for (i = 0, o = opt->encopts; i < opt->encopts_len; i++, o++)
582 free_dhcp_opt_embenc(o);
583 free(opt->encopts);
584 opt->encopts_len = 0;
585 opt->encopts = NULL;
588 static char *
589 strwhite(const char *s)
592 if (s == NULL)
593 return NULL;
594 while (*s != ' ' && *s != '\t') {
595 if (*s == '\0')
596 return NULL;
597 s++;
599 return UNCONST(s);
602 static char *
603 strskipwhite(const char *s)
606 if (s == NULL || *s == '\0')
607 return NULL;
608 while (*s == ' ' || *s == '\t') {
609 s++;
610 if (*s == '\0')
611 return NULL;
613 return UNCONST(s);
616 #ifdef AUTH
617 /* Find the end pointer of a string. */
618 static char *
619 strend(const char *s)
622 s = strskipwhite(s);
623 if (s == NULL)
624 return NULL;
625 if (*s != '"')
626 return strchr(s, ' ');
627 s++;
628 for (; *s != '"' ; s++) {
629 if (*s == '\0')
630 return NULL;
631 if (*s == '\\') {
632 if (*(++s) == '\0')
633 return NULL;
636 return UNCONST(++s);
638 #endif
640 static int
641 parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
642 int opt, const char *arg, struct dhcp_opt **ldop, struct dhcp_opt **edop)
644 int e, i, t;
645 long l;
646 unsigned long u;
647 char *p = NULL, *bp, *fp, *np;
648 ssize_t s;
649 struct in_addr addr, addr2;
650 in_addr_t *naddr;
651 struct rt *rt;
652 const struct dhcp_opt *d, *od;
653 uint8_t *request, *require, *no, *reject;
654 struct dhcp_opt **dop, *ndop;
655 size_t *dop_len, dl, odl;
656 struct vivco *vivco;
657 struct group *grp;
658 #ifdef AUTH
659 struct token *token;
660 #endif
661 #ifdef _REENTRANT
662 struct group grpbuf;
663 #endif
664 #ifdef DHCP6
665 size_t sl;
666 struct if_ia *ia;
667 uint8_t iaid[4];
668 #ifndef SMALL
669 struct if_sla *sla, *slap;
670 #endif
671 #endif
673 dop = NULL;
674 dop_len = NULL;
675 #ifdef INET6
676 i = 0;
677 #endif
679 /* Add a guard for static analysers.
680 * This should not be needed really because of the argument_required option
681 * in the options declaration above. */
682 #define ARG_REQUIRED if (arg == NULL) goto arg_required
684 switch(opt) {
685 case 'f': /* FALLTHROUGH */
686 case 'g': /* FALLTHROUGH */
687 case 'n': /* FALLTHROUGH */
688 case 'q': /* FALLTHROUGH */
689 case 'x': /* FALLTHROUGH */
690 case 'N': /* FALLTHROUGH */
691 case 'P': /* FALLTHROUGH */
692 case 'T': /* FALLTHROUGH */
693 case 'U': /* FALLTHROUGH */
694 case 'V': /* We need to handle non interface options */
695 break;
696 case 'b':
697 ifo->options |= DHCPCD_BACKGROUND;
698 break;
699 case 'c':
700 ARG_REQUIRED;
701 if (IN_CONFIG_BLOCK(ifo)) {
702 logerrx("%s: per interface scripts"
703 " are no longer supported",
704 ifname);
705 return -1;
707 if (ctx->script != dhcpcd_default_script)
708 free(ctx->script);
709 s = parse_nstring(NULL, 0, arg);
710 if (s == 0) {
711 ctx->script = NULL;
712 break;
714 dl = (size_t)s;
715 if (s == -1 || (ctx->script = malloc(dl)) == NULL) {
716 ctx->script = NULL;
717 logerr(__func__);
718 return -1;
720 s = parse_nstring(ctx->script, dl, arg);
721 if (s == -1 ||
722 ctx->script[0] == '\0' ||
723 strcmp(ctx->script, "/dev/null") == 0)
725 free(ctx->script);
726 ctx->script = NULL;
728 break;
729 case 'd':
730 ifo->options |= DHCPCD_DEBUG;
731 break;
732 case 'e':
733 ARG_REQUIRED;
734 add_environ(&ifo->environ, arg, 1);
735 break;
736 case 'h':
737 if (!arg) {
738 ifo->options |= DHCPCD_HOSTNAME;
739 break;
741 s = parse_nstring(ifo->hostname, sizeof(ifo->hostname), arg);
742 if (s == -1) {
743 logerr("%s: hostname", __func__);
744 return -1;
746 if (s != 0 && ifo->hostname[0] == '.') {
747 logerrx("hostname cannot begin with .");
748 return -1;
750 if (ifo->hostname[0] == '\0')
751 ifo->options &= ~DHCPCD_HOSTNAME;
752 else
753 ifo->options |= DHCPCD_HOSTNAME;
754 break;
755 case 'i':
756 if (arg)
757 s = parse_string((char *)ifo->vendorclassid + 1,
758 VENDORCLASSID_MAX_LEN, arg);
759 else
760 s = 0;
761 if (s == -1) {
762 logerr("vendorclassid");
763 return -1;
765 *ifo->vendorclassid = (uint8_t)s;
766 break;
767 case 'j':
768 ARG_REQUIRED;
769 /* per interface logging is not supported
770 * don't want to overide the commandline */
771 if (!IN_CONFIG_BLOCK(ifo) && ctx->logfile == NULL) {
772 logclose();
773 ctx->logfile = strdup(arg);
774 logopen(ctx->logfile);
776 break;
777 case 'k':
778 ifo->options |= DHCPCD_RELEASE;
779 break;
780 case 'l':
781 ARG_REQUIRED;
782 if (strcmp(arg, "-1") == 0) {
783 ifo->leasetime = DHCP_INFINITE_LIFETIME;
784 break;
786 ifo->leasetime = (uint32_t)strtou(arg, NULL,
787 0, 0, UINT32_MAX, &e);
788 if (e) {
789 logerrx("failed to convert leasetime %s", arg);
790 return -1;
792 break;
793 case 'm':
794 ARG_REQUIRED;
795 ifo->metric = (int)strtoi(arg, NULL, 0, 0, INT32_MAX, &e);
796 if (e) {
797 logerrx("failed to convert metric %s", arg);
798 return -1;
800 break;
801 case 'o':
802 ARG_REQUIRED;
803 if (ctx->options & DHCPCD_PRINT_PIDFILE)
804 break;
805 set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
806 &request, &require, &no, &reject);
807 if (make_option_mask(d, dl, od, odl, request, arg, 1) != 0 ||
808 make_option_mask(d, dl, od, odl, no, arg, -1) != 0 ||
809 make_option_mask(d, dl, od, odl, reject, arg, -1) != 0)
811 logerrx("unknown option: %s", arg);
812 return -1;
814 break;
815 case O_REJECT:
816 ARG_REQUIRED;
817 if (ctx->options & DHCPCD_PRINT_PIDFILE)
818 break;
819 set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
820 &request, &require, &no, &reject);
821 if (make_option_mask(d, dl, od, odl, reject, arg, 1) != 0 ||
822 make_option_mask(d, dl, od, odl, request, arg, -1) != 0 ||
823 make_option_mask(d, dl, od, odl, require, arg, -1) != 0)
825 logerrx("unknown option: %s", arg);
826 return -1;
828 break;
829 case 'p':
830 ifo->options |= DHCPCD_PERSISTENT;
831 break;
832 case 'r':
833 if (parse_addr(&ifo->req_addr, NULL, arg) != 0)
834 return -1;
835 ifo->options |= DHCPCD_REQUEST;
836 ifo->req_mask.s_addr = 0;
837 break;
838 case 's':
839 if (arg && *arg != '\0') {
840 /* Strip out a broadcast address */
841 p = strchr(arg, '/');
842 if (p != NULL) {
843 p = strchr(p + 1, '/');
844 if (p != NULL)
845 *p = '\0';
847 i = parse_addr(&ifo->req_addr, &ifo->req_mask, arg);
848 if (p != NULL) {
849 /* Ensure the original string is preserved */
850 *p++ = '/';
851 if (i == 0)
852 i = parse_addr(&ifo->req_brd, NULL, p);
854 if (i != 0)
855 return -1;
856 } else {
857 ifo->req_addr.s_addr = 0;
858 ifo->req_mask.s_addr = 0;
860 ifo->options |= DHCPCD_INFORM | DHCPCD_PERSISTENT;
861 ifo->options &= ~DHCPCD_STATIC;
862 break;
863 case O_INFORM6:
864 ifo->options |= DHCPCD_INFORM6;
865 break;
866 case 't':
867 ARG_REQUIRED;
868 ifo->timeout = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
869 if (e) {
870 logerrx("failed to convert timeout %s", arg);
871 return -1;
873 break;
874 case 'u':
875 dl = sizeof(ifo->userclass) - ifo->userclass[0] - 1;
876 s = parse_string((char *)ifo->userclass +
877 ifo->userclass[0] + 2, dl, arg);
878 if (s == -1) {
879 logerr("userclass");
880 return -1;
882 if (s != 0) {
883 ifo->userclass[ifo->userclass[0] + 1] = (uint8_t)s;
884 ifo->userclass[0] = (uint8_t)(ifo->userclass[0] + s +1);
886 break;
887 #ifndef SMALL
888 case O_MSUSERCLASS:
889 /* Some Microsoft DHCP servers expect userclass to be an
890 * opaque blob. This is not RFC 3004 compliant. */
891 s = parse_string((char *)ifo->userclass + 1,
892 sizeof(ifo->userclass) - 1, arg);
893 if (s == -1) {
894 logerr("msuserclass");
895 return -1;
897 ifo->userclass[0] = (uint8_t)s;
898 break;
899 #endif
900 case 'v':
901 ARG_REQUIRED;
902 p = strchr(arg, ',');
903 if (!p || !p[1]) {
904 logerrx("invalid vendor format: %s", arg);
905 return -1;
908 /* If vendor starts with , then it is not encapsulated */
909 if (p == arg) {
910 arg++;
911 s = parse_string((char *)ifo->vendor + 1,
912 VENDOR_MAX_LEN, arg);
913 if (s == -1) {
914 logerr("vendor");
915 return -1;
917 ifo->vendor[0] = (uint8_t)s;
918 ifo->options |= DHCPCD_VENDORRAW;
919 break;
922 /* Encapsulated vendor options */
923 if (ifo->options & DHCPCD_VENDORRAW) {
924 ifo->options &= ~DHCPCD_VENDORRAW;
925 ifo->vendor[0] = 0;
928 /* Strip and preserve the comma */
929 *p = '\0';
930 i = (int)strtoi(arg, NULL, 0, 1, 254, &e);
931 *p = ',';
932 if (e) {
933 logerrx("vendor option should be between"
934 " 1 and 254 inclusive");
935 return -1;
938 arg = p + 1;
939 s = VENDOR_MAX_LEN - ifo->vendor[0] - 2;
940 if (inet_aton(arg, &addr) == 1) {
941 if (s < 6) {
942 s = -1;
943 errno = ENOBUFS;
944 } else {
945 memcpy(ifo->vendor + ifo->vendor[0] + 3,
946 &addr.s_addr, sizeof(addr.s_addr));
947 s = sizeof(addr.s_addr);
949 } else {
950 s = parse_string((char *)ifo->vendor +
951 ifo->vendor[0] + 3, (size_t)s, arg);
953 if (s == -1) {
954 logerr("vendor");
955 return -1;
957 if (s != 0) {
958 ifo->vendor[ifo->vendor[0] + 1] = (uint8_t)i;
959 ifo->vendor[ifo->vendor[0] + 2] = (uint8_t)s;
960 ifo->vendor[0] = (uint8_t)(ifo->vendor[0] + s + 2);
962 break;
963 case 'w':
964 ifo->options |= DHCPCD_WAITIP;
965 p = UNCONST(arg);
966 // Generally it's --waitip=46, but some expect
967 // --waitip="4 6" to work as well.
968 // It's easier to allow it rather than have confusing docs.
969 while (p != NULL && p[0] != '\0') {
970 if (p[0] == '4' || p[1] == '4')
971 ifo->options |= DHCPCD_WAITIP4;
972 if (p[0] == '6' || p[1] == '6')
973 ifo->options |= DHCPCD_WAITIP6;
974 p = strskipwhite(++p);
976 break;
977 case 'y':
978 ARG_REQUIRED;
979 ifo->reboot = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
980 if (e) {
981 logerr("failed to convert reboot %s", arg);
982 return -1;
984 break;
985 case 'z':
986 ARG_REQUIRED;
987 if (!IN_CONFIG_BLOCK(ifo))
988 ctx->ifav = splitv(&ctx->ifac, ctx->ifav, arg);
989 break;
990 case 'A':
991 ifo->options &= ~DHCPCD_ARP;
992 /* IPv4LL requires ARP */
993 ifo->options &= ~DHCPCD_IPV4LL;
994 break;
995 case 'B':
996 ifo->options &= ~DHCPCD_DAEMONISE;
997 break;
998 case 'C':
999 ARG_REQUIRED;
1000 /* Commas to spaces for shell */
1001 while ((p = strchr(arg, ',')))
1002 *p = ' ';
1003 dl = strlen("skip_hooks=") + strlen(arg) + 1;
1004 p = malloc(sizeof(char) * dl);
1005 if (p == NULL) {
1006 logerr(__func__);
1007 return -1;
1009 snprintf(p, dl, "skip_hooks=%s", arg);
1010 add_environ(&ifo->environ, p, 0);
1011 free(p);
1012 break;
1013 case 'D':
1014 ifo->options |= DHCPCD_CLIENTID | DHCPCD_DUID;
1015 if (ifname != NULL) /* duid type only a global option */
1016 break;
1017 if (arg == NULL)
1018 ctx->duid_type = DUID_DEFAULT;
1019 else if (strcmp(arg, "ll") == 0)
1020 ctx->duid_type = DUID_LL;
1021 else if (strcmp(arg, "llt") == 0)
1022 ctx->duid_type = DUID_LLT;
1023 else if (strcmp(arg, "uuid") == 0)
1024 ctx->duid_type = DUID_UUID;
1025 else {
1026 dl = hwaddr_aton(NULL, arg);
1027 if (dl != 0) {
1028 no = realloc(ctx->duid, dl);
1029 if (no == NULL)
1030 logerrx(__func__);
1031 else {
1032 ctx->duid = no;
1033 ctx->duid_len = hwaddr_aton(no, arg);
1037 break;
1038 case 'E':
1039 ifo->options |= DHCPCD_LASTLEASE;
1040 break;
1041 case 'F':
1042 if (!arg) {
1043 ifo->fqdn = FQDN_BOTH;
1044 break;
1046 if (strcmp(arg, "none") == 0)
1047 ifo->fqdn = FQDN_NONE;
1048 else if (strcmp(arg, "ptr") == 0)
1049 ifo->fqdn = FQDN_PTR;
1050 else if (strcmp(arg, "both") == 0)
1051 ifo->fqdn = FQDN_BOTH;
1052 else if (strcmp(arg, "disable") == 0)
1053 ifo->fqdn = FQDN_DISABLE;
1054 else {
1055 logerrx("invalid FQDN value: %s", arg);
1056 return -1;
1058 break;
1059 case 'G':
1060 ifo->options &= ~DHCPCD_GATEWAY;
1061 break;
1062 case 'H':
1063 ifo->options |= DHCPCD_XID_HWADDR;
1064 break;
1065 case 'I':
1066 /* Strings have a type of 0 */;
1067 ifo->clientid[1] = 0;
1068 if (arg)
1069 s = parse_hwaddr((char *)ifo->clientid + 1,
1070 CLIENTID_MAX_LEN, arg);
1071 else
1072 s = 0;
1073 if (s == -1) {
1074 logerr("clientid");
1075 return -1;
1077 ifo->options |= DHCPCD_CLIENTID;
1078 ifo->clientid[0] = (uint8_t)s;
1079 ifo->options &= ~DHCPCD_DUID;
1080 break;
1081 case 'J':
1082 ifo->options |= DHCPCD_BROADCAST;
1083 break;
1084 case 'K':
1085 ifo->options &= ~DHCPCD_LINK;
1086 break;
1087 case 'L':
1088 ifo->options &= ~DHCPCD_IPV4LL;
1089 break;
1090 case 'M':
1091 ifo->options |= DHCPCD_MANAGER;
1092 break;
1093 case 'O':
1094 ARG_REQUIRED;
1095 if (ctx->options & DHCPCD_PRINT_PIDFILE)
1096 break;
1097 set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
1098 &request, &require, &no, &reject);
1099 if (make_option_mask(d, dl, od, odl, request, arg, -1) != 0 ||
1100 make_option_mask(d, dl, od, odl, require, arg, -1) != 0 ||
1101 make_option_mask(d, dl, od, odl, no, arg, 1) != 0)
1103 logerrx("unknown option: %s", arg);
1104 return -1;
1106 break;
1107 case 'Q':
1108 ARG_REQUIRED;
1109 if (ctx->options & DHCPCD_PRINT_PIDFILE)
1110 break;
1111 set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
1112 &request, &require, &no, &reject);
1113 if (make_option_mask(d, dl, od, odl, require, arg, 1) != 0 ||
1114 make_option_mask(d, dl, od, odl, request, arg, 1) != 0 ||
1115 make_option_mask(d, dl, od, odl, no, arg, -1) != 0 ||
1116 make_option_mask(d, dl, od, odl, reject, arg, -1) != 0)
1118 logerrx("unknown option: %s", arg);
1119 return -1;
1121 break;
1122 case 'S':
1123 ARG_REQUIRED;
1124 p = strchr(arg, '=');
1125 if (p == NULL) {
1126 logerrx("static assignment required");
1127 return -1;
1129 p = strskipwhite(++p);
1130 if (strncmp(arg, "ip_address=", strlen("ip_address=")) == 0) {
1131 if (p == NULL) {
1132 ifo->options &= ~DHCPCD_STATIC;
1133 ifo->req_addr.s_addr = INADDR_ANY;
1134 break;
1136 if (parse_addr(&ifo->req_addr,
1137 ifo->req_mask.s_addr == 0 ? &ifo->req_mask : NULL,
1138 p) != 0)
1139 return -1;
1141 ifo->options |= DHCPCD_STATIC;
1142 ifo->options &= ~DHCPCD_INFORM;
1143 } else if (strncmp(arg, "subnet_mask=",
1144 strlen("subnet_mask=")) == 0)
1146 if (p == NULL) {
1147 ifo->req_mask.s_addr = INADDR_ANY;
1148 break;
1150 if (parse_addr(&ifo->req_mask, NULL, p) != 0)
1151 return -1;
1152 } else if (strncmp(arg, "broadcast_address=",
1153 strlen("broadcast_address=")) == 0)
1155 if (p == NULL) {
1156 ifo->req_brd.s_addr = INADDR_ANY;
1157 break;
1159 if (parse_addr(&ifo->req_brd, NULL, p) != 0)
1160 return -1;
1161 } else if (strncmp(arg, "routes=", strlen("routes=")) == 0 ||
1162 strncmp(arg, "static_routes=",
1163 strlen("static_routes=")) == 0 ||
1164 strncmp(arg, "classless_static_routes=",
1165 strlen("classless_static_routes=")) == 0 ||
1166 strncmp(arg, "ms_classless_static_routes=",
1167 strlen("ms_classless_static_routes=")) == 0)
1169 struct in_addr addr3;
1171 if (p == NULL) {
1172 rt_headclear(&ifo->routes, AF_INET);
1173 add_environ(&ifo->config, arg, 1);
1174 break;
1177 fp = np = strwhite(p);
1178 if (np == NULL) {
1179 logerrx("all routes need a gateway");
1180 return -1;
1182 *np++ = '\0';
1183 np = strskipwhite(np);
1184 if (parse_addr(&addr, &addr2, p) == -1 ||
1185 parse_addr(&addr3, NULL, np) == -1)
1187 *fp = ' ';
1188 return -1;
1190 *fp = ' ';
1191 if ((rt = rt_new0(ctx)) == NULL)
1192 return -1;
1193 sa_in_init(&rt->rt_dest, &addr);
1194 sa_in_init(&rt->rt_netmask, &addr2);
1195 sa_in_init(&rt->rt_gateway, &addr3);
1196 if (rt_proto_add_ctx(&ifo->routes, rt, ctx))
1197 add_environ(&ifo->config, arg, 0);
1198 } else if (strncmp(arg, "routers=", strlen("routers=")) == 0) {
1199 if (p == NULL) {
1200 rt_headclear(&ifo->routes, AF_INET);
1201 add_environ(&ifo->config, arg, 1);
1202 break;
1204 if (parse_addr(&addr, NULL, p) == -1)
1205 return -1;
1206 if ((rt = rt_new0(ctx)) == NULL)
1207 return -1;
1208 addr2.s_addr = INADDR_ANY;
1209 sa_in_init(&rt->rt_dest, &addr2);
1210 sa_in_init(&rt->rt_netmask, &addr2);
1211 sa_in_init(&rt->rt_gateway, &addr);
1212 if (rt_proto_add_ctx(&ifo->routes, rt, ctx))
1213 add_environ(&ifo->config, arg, 0);
1214 } else if (strncmp(arg, "interface_mtu=",
1215 strlen("interface_mtu=")) == 0 ||
1216 strncmp(arg, "mtu=", strlen("mtu=")) == 0)
1218 if (p == NULL)
1219 break;
1220 ifo->mtu = (unsigned int)strtou(p, NULL, 0,
1221 MTU_MIN, MTU_MAX, &e);
1222 if (e) {
1223 logerrx("invalid MTU %s", p);
1224 return -1;
1226 } else if (strncmp(arg, "ip6_address=", strlen("ip6_address=")) == 0) {
1227 if (p == NULL) {
1228 memset(&ifo->req_addr6, 0,
1229 sizeof(ifo->req_addr6));
1230 break;
1233 np = strchr(p, '/');
1234 if (np)
1235 *np++ = '\0';
1236 if ((i = inet_pton(AF_INET6, p, &ifo->req_addr6)) == 1) {
1237 if (np) {
1238 ifo->req_prefix_len = (uint8_t)strtou(np,
1239 NULL, 0, 0, 128, &e);
1240 if (e) {
1241 logerrx("%s: failed to "
1242 "convert prefix len",
1243 ifname);
1244 return -1;
1246 } else
1247 ifo->req_prefix_len = 128;
1249 if (np)
1250 *(--np) = '\0';
1251 if (i != 1) {
1252 logerrx("invalid AF_INET6: %s", p);
1253 memset(&ifo->req_addr6, 0,
1254 sizeof(ifo->req_addr6));
1255 return -1;
1257 } else
1258 add_environ(&ifo->config, arg, p == NULL ? 1 : 0);
1259 break;
1261 case 'W':
1262 if (parse_addr(&addr, &addr2, arg) != 0)
1263 return -1;
1264 if (strchr(arg, '/') == NULL)
1265 addr2.s_addr = INADDR_BROADCAST;
1266 naddr = reallocarray(ifo->whitelist,
1267 ifo->whitelist_len + 2, sizeof(in_addr_t));
1268 if (naddr == NULL) {
1269 logerr(__func__);
1270 return -1;
1272 ifo->whitelist = naddr;
1273 ifo->whitelist[ifo->whitelist_len++] = addr.s_addr;
1274 ifo->whitelist[ifo->whitelist_len++] = addr2.s_addr;
1275 break;
1276 case 'X':
1277 if (parse_addr(&addr, &addr2, arg) != 0)
1278 return -1;
1279 if (strchr(arg, '/') == NULL)
1280 addr2.s_addr = INADDR_BROADCAST;
1281 naddr = reallocarray(ifo->blacklist,
1282 ifo->blacklist_len + 2, sizeof(in_addr_t));
1283 if (naddr == NULL) {
1284 logerr(__func__);
1285 return -1;
1287 ifo->blacklist = naddr;
1288 ifo->blacklist[ifo->blacklist_len++] = addr.s_addr;
1289 ifo->blacklist[ifo->blacklist_len++] = addr2.s_addr;
1290 break;
1291 case 'Z':
1292 ARG_REQUIRED;
1293 if (!IN_CONFIG_BLOCK(ifo))
1294 ctx->ifdv = splitv(&ctx->ifdc, ctx->ifdv, arg);
1295 break;
1296 case '1':
1297 ifo->options |= DHCPCD_ONESHOT;
1298 break;
1299 case '4':
1300 #ifdef INET
1301 ifo->options &= ~DHCPCD_IPV6;
1302 ifo->options |= DHCPCD_IPV4;
1303 break;
1304 #else
1305 logerrx("INET has been compiled out");
1306 return -1;
1307 #endif
1308 case '6':
1309 #ifdef INET6
1310 ifo->options &= ~DHCPCD_IPV4;
1311 ifo->options |= DHCPCD_IPV6;
1312 break;
1313 #else
1314 logerrx("INET6 has been compiled out");
1315 return -1;
1316 #endif
1317 case O_IPV4:
1318 ifo->options |= DHCPCD_IPV4;
1319 break;
1320 case O_NOIPV4:
1321 ifo->options &= ~DHCPCD_IPV4;
1322 break;
1323 case O_IPV6:
1324 ifo->options |= DHCPCD_IPV6;
1325 break;
1326 case O_NOIPV6:
1327 ifo->options &= ~DHCPCD_IPV6;
1328 break;
1329 case O_ANONYMOUS:
1330 ifo->options |= DHCPCD_ANONYMOUS;
1331 ifo->options &= ~DHCPCD_HOSTNAME;
1332 ifo->fqdn = FQDN_DISABLE;
1334 /* Block everything */
1335 memset(ifo->nomask, 0xff, sizeof(ifo->nomask));
1336 memset(ifo->nomask6, 0xff, sizeof(ifo->nomask6));
1338 /* Allow the bare minimum through */
1339 #ifdef INET
1340 del_option_mask(ifo->nomask, DHO_SUBNETMASK);
1341 del_option_mask(ifo->nomask, DHO_CSR);
1342 del_option_mask(ifo->nomask, DHO_ROUTER);
1343 del_option_mask(ifo->nomask, DHO_DNSSERVER);
1344 del_option_mask(ifo->nomask, DHO_DNSDOMAIN);
1345 del_option_mask(ifo->nomask, DHO_BROADCAST);
1346 del_option_mask(ifo->nomask, DHO_STATICROUTE);
1347 del_option_mask(ifo->nomask, DHO_SERVERID);
1348 del_option_mask(ifo->nomask, DHO_RENEWALTIME);
1349 del_option_mask(ifo->nomask, DHO_REBINDTIME);
1350 del_option_mask(ifo->nomask, DHO_DNSSEARCH);
1351 #endif
1353 #ifdef DHCP6
1354 del_option_mask(ifo->nomask6, D6_OPTION_DNS_SERVERS);
1355 del_option_mask(ifo->nomask6, D6_OPTION_DOMAIN_LIST);
1356 del_option_mask(ifo->nomask6, D6_OPTION_SOL_MAX_RT);
1357 del_option_mask(ifo->nomask6, D6_OPTION_INF_MAX_RT);
1358 #endif
1360 break;
1361 case O_RANDOMISE_HWADDR:
1362 ifo->randomise_hwaddr = true;
1363 break;
1364 #ifdef INET
1365 case O_ARPING:
1366 while (arg != NULL) {
1367 fp = strwhite(arg);
1368 if (fp)
1369 *fp++ = '\0';
1370 if (parse_addr(&addr, NULL, arg) != 0)
1371 return -1;
1372 naddr = reallocarray(ifo->arping,
1373 (size_t)ifo->arping_len + 1, sizeof(in_addr_t));
1374 if (naddr == NULL) {
1375 logerr(__func__);
1376 return -1;
1378 ifo->arping = naddr;
1379 ifo->arping[ifo->arping_len++] = addr.s_addr;
1380 arg = strskipwhite(fp);
1382 break;
1383 case O_DESTINATION:
1384 ARG_REQUIRED;
1385 if (ctx->options & DHCPCD_PRINT_PIDFILE)
1386 break;
1387 set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
1388 &request, &require, &no, &reject);
1389 if (make_option_mask(d, dl, od, odl,
1390 ifo->dstmask, arg, 2) != 0)
1392 if (errno == EINVAL)
1393 logerrx("option does not take"
1394 " an IPv4 address: %s", arg);
1395 else
1396 logerrx("unknown option: %s", arg);
1397 return -1;
1399 break;
1400 case O_FALLBACK:
1401 ARG_REQUIRED;
1402 free(ifo->fallback);
1403 ifo->fallback = strdup(arg);
1404 if (ifo->fallback == NULL) {
1405 logerrx(__func__);
1406 return -1;
1408 break;
1409 #endif
1410 case O_IAID:
1411 ARG_REQUIRED;
1412 if (ctx->options & DHCPCD_MANAGER && !IN_CONFIG_BLOCK(ifo)) {
1413 logerrx("IAID must belong in an interface block");
1414 return -1;
1416 if (parse_iaid(ifo->iaid, arg, sizeof(ifo->iaid)) == -1) {
1417 logerrx("invalid IAID %s", arg);
1418 return -1;
1420 ifo->options |= DHCPCD_IAID;
1421 break;
1422 case O_IPV6RS:
1423 ifo->options |= DHCPCD_IPV6RS;
1424 break;
1425 case O_NOIPV6RS:
1426 ifo->options &= ~DHCPCD_IPV6RS;
1427 break;
1428 case O_IPV6RA_FORK:
1429 ifo->options &= ~DHCPCD_IPV6RA_REQRDNSS;
1430 break;
1431 case O_IPV6RA_AUTOCONF:
1432 ifo->options |= DHCPCD_IPV6RA_AUTOCONF;
1433 break;
1434 case O_IPV6RA_NOAUTOCONF:
1435 ifo->options &= ~DHCPCD_IPV6RA_AUTOCONF;
1436 break;
1437 case O_NOALIAS:
1438 ifo->options |= DHCPCD_NOALIAS;
1439 break;
1440 #ifdef DHCP6
1441 case O_IA_NA:
1442 i = D6_OPTION_IA_NA;
1443 /* FALLTHROUGH */
1444 case O_IA_TA:
1445 if (i == 0)
1446 i = D6_OPTION_IA_TA;
1447 /* FALLTHROUGH */
1448 case O_IA_PD:
1449 if (i == 0) {
1450 #ifdef SMALL
1451 logwarnx("%s: IA_PD not compiled in", ifname);
1452 return -1;
1453 #else
1454 if (ctx->options & DHCPCD_MANAGER &&
1455 !IN_CONFIG_BLOCK(ifo))
1457 logerrx("IA PD must belong in an "
1458 "interface block");
1459 return -1;
1461 i = D6_OPTION_IA_PD;
1462 #endif
1464 if (ctx->options & DHCPCD_MANAGER &&
1465 !IN_CONFIG_BLOCK(ifo) && arg)
1467 logerrx("IA with IAID must belong in an "
1468 "interface block");
1469 return -1;
1471 ifo->options |= DHCPCD_IA_FORCED;
1472 fp = strwhite(arg);
1473 if (fp) {
1474 *fp++ = '\0';
1475 fp = strskipwhite(fp);
1477 if (arg) {
1478 p = strchr(arg, '/');
1479 if (p)
1480 *p++ = '\0';
1481 if (parse_iaid(iaid, arg, sizeof(iaid)) == -1) {
1482 logerr("invalid IAID: %s", arg);
1483 return -1;
1486 ia = NULL;
1487 for (sl = 0; sl < ifo->ia_len; sl++) {
1488 if ((arg == NULL && !ifo->ia[sl].iaid_set) ||
1489 (arg != NULL && ifo->ia[sl].iaid_set &&
1490 ifo->ia[sl].ia_type == (uint16_t)i &&
1491 ifo->ia[sl].iaid[0] == iaid[0] &&
1492 ifo->ia[sl].iaid[1] == iaid[1] &&
1493 ifo->ia[sl].iaid[2] == iaid[2] &&
1494 ifo->ia[sl].iaid[3] == iaid[3]))
1496 ia = &ifo->ia[sl];
1497 break;
1500 if (ia == NULL) {
1501 ia = reallocarray(ifo->ia,
1502 ifo->ia_len + 1, sizeof(*ifo->ia));
1503 if (ia == NULL) {
1504 logerr(__func__);
1505 return -1;
1507 ifo->ia = ia;
1508 ia = &ifo->ia[ifo->ia_len++];
1509 ia->ia_type = (uint16_t)i;
1510 if (arg) {
1511 ia->iaid[0] = iaid[0];
1512 ia->iaid[1] = iaid[1];
1513 ia->iaid[2] = iaid[2];
1514 ia->iaid[3] = iaid[3];
1515 ia->iaid_set = 1;
1516 } else
1517 ia->iaid_set = 0;
1518 if (!ia->iaid_set ||
1519 p == NULL ||
1520 ia->ia_type == D6_OPTION_IA_TA)
1522 memset(&ia->addr, 0, sizeof(ia->addr));
1523 ia->prefix_len = 0;
1524 } else {
1525 arg = p;
1526 p = strchr(arg, '/');
1527 if (p)
1528 *p++ = '\0';
1529 if (inet_pton(AF_INET6, arg, &ia->addr) != 1) {
1530 logerrx("invalid AF_INET6: %s", arg);
1531 memset(&ia->addr, 0, sizeof(ia->addr));
1533 if (p && ia->ia_type == D6_OPTION_IA_PD) {
1534 ia->prefix_len = (uint8_t)strtou(p,
1535 NULL, 0, 8, 120, &e);
1536 if (e) {
1537 logerrx("%s: failed to convert"
1538 " prefix len",
1540 ia->prefix_len = 0;
1544 #ifndef SMALL
1545 ia->sla_max = 0;
1546 ia->sla_len = 0;
1547 ia->sla = NULL;
1548 #endif
1551 #ifdef SMALL
1552 break;
1553 #else
1554 if (ia->ia_type != D6_OPTION_IA_PD)
1555 break;
1557 for (p = fp; p; p = fp) {
1558 fp = strwhite(p);
1559 if (fp) {
1560 *fp++ = '\0';
1561 fp = strskipwhite(fp);
1563 sla = reallocarray(ia->sla,
1564 ia->sla_len + 1, sizeof(*ia->sla));
1565 if (sla == NULL) {
1566 logerr(__func__);
1567 return -1;
1569 ia->sla = sla;
1570 sla = &ia->sla[ia->sla_len++];
1571 np = strchr(p, '/');
1572 if (np)
1573 *np++ = '\0';
1574 if (strlcpy(sla->ifname, p,
1575 sizeof(sla->ifname)) >= sizeof(sla->ifname))
1577 logerrx("%s: interface name too long", arg);
1578 goto err_sla;
1580 sla->sla_set = false;
1581 sla->prefix_len = 0;
1582 sla->suffix = 1;
1583 p = np;
1584 if (p) {
1585 np = strchr(p, '/');
1586 if (np)
1587 *np++ = '\0';
1588 if (*p != '\0') {
1589 sla->sla = (uint32_t)strtou(p, NULL,
1590 0, 0, UINT32_MAX, &e);
1591 sla->sla_set = true;
1592 if (e) {
1593 logerrx("%s: failed to convert "
1594 "sla",
1595 ifname);
1596 goto err_sla;
1599 p = np;
1601 if (p) {
1602 np = strchr(p, '/');
1603 if (np)
1604 *np++ = '\0';
1605 if (*p != '\0') {
1606 sla->prefix_len = (uint8_t)strtou(p,
1607 NULL, 0, 0, 120, &e);
1608 if (e) {
1609 logerrx("%s: failed to "
1610 "convert prefix len",
1611 ifname);
1612 goto err_sla;
1615 p = np;
1617 if (p) {
1618 np = strchr(p, '/');
1619 if (np)
1620 *np = '\0';
1621 if (*p != '\0') {
1622 sla->suffix = (uint64_t)strtou(p, NULL,
1623 0, 0, UINT64_MAX, &e);
1624 if (e) {
1625 logerrx("%s: failed to "
1626 "convert suffix",
1627 ifname);
1628 goto err_sla;
1632 /* Sanity check */
1633 for (sl = 0; sl < ia->sla_len - 1; sl++) {
1634 slap = &ia->sla[sl];
1635 if (slap->sla_set != sla->sla_set) {
1636 logerrx("%s: cannot mix automatic "
1637 "and fixed SLA",
1638 sla->ifname);
1639 goto err_sla;
1641 if (ia->prefix_len &&
1642 (sla->prefix_len == ia->prefix_len ||
1643 slap->prefix_len == ia->prefix_len))
1645 logerrx("%s: cannot delegte the same"
1646 "prefix length more than once",
1647 sla->ifname);
1648 goto err_sla;
1650 if (!sla->sla_set &&
1651 strcmp(slap->ifname, sla->ifname) == 0)
1653 logwarnx("%s: cannot specify the "
1654 "same interface twice with "
1655 "an automatic SLA",
1656 sla->ifname);
1657 goto err_sla;
1659 if (slap->sla_set && sla->sla_set &&
1660 slap->sla == sla->sla)
1662 logerrx("%s: cannot"
1663 " assign the same SLA %u"
1664 " more than once",
1665 sla->ifname, sla->sla);
1666 goto err_sla;
1669 if (sla->sla_set && sla->sla > ia->sla_max)
1670 ia->sla_max = sla->sla;
1672 break;
1673 err_sla:
1674 ia->sla_len--;
1675 return -1;
1676 #endif
1677 #endif
1678 case O_HOSTNAME_SHORT:
1679 ifo->options |= DHCPCD_HOSTNAME | DHCPCD_HOSTNAME_SHORT;
1680 break;
1681 case O_DEV:
1682 ARG_REQUIRED;
1683 #ifdef PLUGIN_DEV
1684 if (ctx->dev_load)
1685 free(ctx->dev_load);
1686 ctx->dev_load = strdup(arg);
1687 #endif
1688 break;
1689 case O_NODEV:
1690 ifo->options &= ~DHCPCD_DEV;
1691 break;
1692 case O_DEFINE:
1693 dop = &ifo->dhcp_override;
1694 dop_len = &ifo->dhcp_override_len;
1695 /* FALLTHROUGH */
1696 case O_DEFINEND:
1697 if (dop == NULL) {
1698 dop = &ifo->nd_override;
1699 dop_len = &ifo->nd_override_len;
1701 /* FALLTHROUGH */
1702 case O_DEFINE6:
1703 if (dop == NULL) {
1704 dop = &ifo->dhcp6_override;
1705 dop_len = &ifo->dhcp6_override_len;
1707 /* FALLTHROUGH */
1708 case O_VENDOPT:
1709 if (dop == NULL) {
1710 dop = &ifo->vivso_override;
1711 dop_len = &ifo->vivso_override_len;
1713 *edop = *ldop = NULL;
1714 /* FALLTHROUGH */
1715 case O_EMBED:
1716 if (dop == NULL) {
1717 if (*edop) {
1718 dop = &(*edop)->embopts;
1719 dop_len = &(*edop)->embopts_len;
1720 } else if (ldop) {
1721 dop = &(*ldop)->embopts;
1722 dop_len = &(*ldop)->embopts_len;
1723 } else {
1724 logerrx("embed must be after a define "
1725 "or encap");
1726 return -1;
1729 /* FALLTHROUGH */
1730 case O_ENCAP:
1731 ARG_REQUIRED;
1732 if (dop == NULL) {
1733 if (*ldop == NULL) {
1734 logerrx("encap must be after a define");
1735 return -1;
1737 dop = &(*ldop)->encopts;
1738 dop_len = &(*ldop)->encopts_len;
1741 /* Shared code for define, define6, embed and encap */
1743 /* code */
1744 if (opt == O_EMBED) /* Embedded options don't have codes */
1745 u = 0;
1746 else {
1747 fp = strwhite(arg);
1748 if (fp == NULL) {
1749 logerrx("invalid syntax: %s", arg);
1750 return -1;
1752 *fp++ = '\0';
1753 u = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
1754 if (e) {
1755 logerrx("invalid code: %s", arg);
1756 return -1;
1758 arg = strskipwhite(fp);
1759 if (arg == NULL) {
1760 logerrx("invalid syntax");
1761 return -1;
1764 /* type */
1765 fp = strwhite(arg);
1766 if (fp)
1767 *fp++ = '\0';
1768 np = strchr(arg, ':');
1769 /* length */
1770 if (np) {
1771 *np++ = '\0';
1772 bp = NULL; /* No bitflag */
1773 l = (long)strtou(np, NULL, 0, 0, LONG_MAX, &e);
1774 if (e) {
1775 logerrx("failed to convert length");
1776 return -1;
1778 } else {
1779 l = 0;
1780 bp = strchr(arg, '='); /* bitflag assignment */
1781 if (bp)
1782 *bp++ = '\0';
1784 t = 0;
1785 if (strcasecmp(arg, "request") == 0) {
1786 t |= OT_REQUEST;
1787 arg = strskipwhite(fp);
1788 fp = strwhite(arg);
1789 if (fp == NULL) {
1790 logerrx("incomplete request type");
1791 return -1;
1793 *fp++ = '\0';
1794 } else if (strcasecmp(arg, "norequest") == 0) {
1795 t |= OT_NOREQ;
1796 arg = strskipwhite(fp);
1797 fp = strwhite(arg);
1798 if (fp == NULL) {
1799 logerrx("incomplete request type");
1800 return -1;
1802 *fp++ = '\0';
1804 if (strcasecmp(arg, "optional") == 0) {
1805 t |= OT_OPTIONAL;
1806 arg = strskipwhite(fp);
1807 fp = strwhite(arg);
1808 if (fp == NULL) {
1809 logerrx("incomplete optional type");
1810 return -1;
1812 *fp++ = '\0';
1814 if (strcasecmp(arg, "index") == 0) {
1815 t |= OT_INDEX;
1816 arg = strskipwhite(fp);
1817 fp = strwhite(arg);
1818 if (fp == NULL) {
1819 logerrx("incomplete index type");
1820 return -1;
1822 *fp++ = '\0';
1824 if (strcasecmp(arg, "array") == 0) {
1825 t |= OT_ARRAY;
1826 arg = strskipwhite(fp);
1827 fp = strwhite(arg);
1828 if (fp == NULL) {
1829 logerrx("incomplete array type");
1830 return -1;
1832 *fp++ = '\0';
1834 if (strcasecmp(arg, "ipaddress") == 0)
1835 t |= OT_ADDRIPV4;
1836 else if (strcasecmp(arg, "ip6address") == 0)
1837 t |= OT_ADDRIPV6;
1838 else if (strcasecmp(arg, "string") == 0)
1839 t |= OT_STRING;
1840 else if (strcasecmp(arg, "uri") == 0)
1841 t |= OT_URI;
1842 else if (strcasecmp(arg, "byte") == 0)
1843 t |= OT_UINT8;
1844 else if (strcasecmp(arg, "bitflags") == 0)
1845 t |= OT_BITFLAG;
1846 else if (strcasecmp(arg, "uint8") == 0)
1847 t |= OT_UINT8;
1848 else if (strcasecmp(arg, "int8") == 0)
1849 t |= OT_INT8;
1850 else if (strcasecmp(arg, "uint16") == 0)
1851 t |= OT_UINT16;
1852 else if (strcasecmp(arg, "int16") == 0)
1853 t |= OT_INT16;
1854 else if (strcasecmp(arg, "uint32") == 0)
1855 t |= OT_UINT32;
1856 else if (strcasecmp(arg, "int32") == 0)
1857 t |= OT_INT32;
1858 else if (strcasecmp(arg, "flag") == 0)
1859 t |= OT_FLAG;
1860 else if (strcasecmp(arg, "raw") == 0)
1861 t |= OT_STRING | OT_RAW;
1862 else if (strcasecmp(arg, "ascii") == 0)
1863 t |= OT_STRING | OT_ASCII;
1864 else if (strcasecmp(arg, "domain") == 0)
1865 t |= OT_STRING | OT_DOMAIN | OT_RFC1035;
1866 else if (strcasecmp(arg, "dname") == 0)
1867 t |= OT_STRING | OT_DOMAIN;
1868 else if (strcasecmp(arg, "binhex") == 0)
1869 t |= OT_STRING | OT_BINHEX;
1870 else if (strcasecmp(arg, "embed") == 0)
1871 t |= OT_EMBED;
1872 else if (strcasecmp(arg, "encap") == 0)
1873 t |= OT_ENCAP;
1874 else if (strcasecmp(arg, "rfc3361") ==0)
1875 t |= OT_STRING | OT_RFC3361;
1876 else if (strcasecmp(arg, "rfc3442") ==0)
1877 t |= OT_STRING | OT_RFC3442;
1878 else if (strcasecmp(arg, "option") == 0)
1879 t |= OT_OPTION;
1880 else {
1881 logerrx("unknown type: %s", arg);
1882 return -1;
1884 if (l && !(t & (OT_STRING | OT_BINHEX))) {
1885 logwarnx("ignoring length for type: %s", arg);
1886 l = 0;
1888 if (t & OT_ARRAY && t & (OT_STRING | OT_BINHEX) &&
1889 !(t & (OT_RFC1035 | OT_DOMAIN)))
1891 logwarnx("ignoring array for strings");
1892 t &= ~OT_ARRAY;
1894 if (t & OT_BITFLAG) {
1895 if (bp == NULL)
1896 logwarnx("missing bitflag assignment");
1898 /* variable */
1899 if (!fp) {
1900 if (!(t & OT_OPTION)) {
1901 logerrx("type %s requires a variable name",
1902 arg);
1903 return -1;
1905 np = NULL;
1906 } else {
1907 arg = strskipwhite(fp);
1908 fp = strwhite(arg);
1909 if (fp)
1910 *fp++ = '\0';
1911 if (strcasecmp(arg, "reserved")) {
1912 np = strdup(arg);
1913 if (np == NULL) {
1914 logerr(__func__);
1915 return -1;
1917 } else {
1918 np = NULL;
1919 t |= OT_RESERVED;
1922 if (opt != O_EMBED) {
1923 for (dl = 0, ndop = *dop; dl < *dop_len; dl++, ndop++)
1925 /* type 0 seems freshly malloced struct
1926 * for us to use */
1927 if (ndop->option == u || ndop->type == 0)
1928 break;
1930 if (dl == *dop_len)
1931 ndop = NULL;
1932 } else
1933 ndop = NULL;
1934 if (ndop == NULL) {
1935 ndop = reallocarray(*dop, *dop_len + 1, sizeof(**dop));
1936 if (ndop == NULL) {
1937 logerr(__func__);
1938 free(np);
1939 return -1;
1941 *dop = ndop;
1942 ndop = &(*dop)[(*dop_len)++];
1943 ndop->embopts = NULL;
1944 ndop->embopts_len = 0;
1945 ndop->encopts = NULL;
1946 ndop->encopts_len = 0;
1947 } else
1948 free_dhcp_opt_embenc(ndop);
1949 ndop->option = (uint32_t)u; /* could have been 0 */
1950 ndop->type = t;
1951 ndop->len = (size_t)l;
1952 ndop->var = np;
1953 if (bp) {
1954 dl = strlen(bp);
1955 memcpy(ndop->bitflags, bp, dl);
1956 memset(ndop->bitflags + dl, 0,
1957 sizeof(ndop->bitflags) - dl);
1958 } else
1959 memset(ndop->bitflags, 0, sizeof(ndop->bitflags));
1960 /* Save the define for embed and encap options */
1961 switch (opt) {
1962 case O_DEFINE:
1963 case O_DEFINEND:
1964 case O_DEFINE6:
1965 case O_VENDOPT:
1966 *ldop = ndop;
1967 break;
1968 case O_ENCAP:
1969 *edop = ndop;
1970 break;
1972 break;
1973 case O_VENDCLASS:
1974 ARG_REQUIRED;
1975 fp = strwhite(arg);
1976 if (fp)
1977 *fp++ = '\0';
1978 u = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
1979 if (e) {
1980 logerrx("invalid code: %s", arg);
1981 return -1;
1983 fp = strskipwhite(fp);
1984 if (fp) {
1985 s = parse_string(NULL, 0, fp);
1986 if (s == -1) {
1987 logerr(__func__);
1988 return -1;
1990 dl = (size_t)s;
1991 if (dl + (sizeof(uint16_t) * 2) > UINT16_MAX) {
1992 logerrx("vendor class is too big");
1993 return -1;
1995 np = malloc(dl);
1996 if (np == NULL) {
1997 logerr(__func__);
1998 return -1;
2000 parse_string(np, dl, fp);
2001 } else {
2002 dl = 0;
2003 np = NULL;
2005 vivco = reallocarray(ifo->vivco,
2006 ifo->vivco_len + 1, sizeof(*ifo->vivco));
2007 if (vivco == NULL) {
2008 logerr( __func__);
2009 free(np);
2010 return -1;
2012 ifo->vivco = vivco;
2013 ifo->vivco_en = (uint32_t)u;
2014 vivco = &ifo->vivco[ifo->vivco_len++];
2015 vivco->len = dl;
2016 vivco->data = (uint8_t *)np;
2017 break;
2018 case O_AUTHPROTOCOL:
2019 ARG_REQUIRED;
2020 #ifdef AUTH
2021 fp = strwhite(arg);
2022 if (fp)
2023 *fp++ = '\0';
2024 if (strcasecmp(arg, "token") == 0)
2025 ifo->auth.protocol = AUTH_PROTO_TOKEN;
2026 else if (strcasecmp(arg, "delayed") == 0)
2027 ifo->auth.protocol = AUTH_PROTO_DELAYED;
2028 else if (strcasecmp(arg, "delayedrealm") == 0)
2029 ifo->auth.protocol = AUTH_PROTO_DELAYEDREALM;
2030 else {
2031 logerrx("%s: unsupported protocol", arg);
2032 return -1;
2034 arg = strskipwhite(fp);
2035 fp = strwhite(arg);
2036 if (arg == NULL) {
2037 ifo->auth.options |= DHCPCD_AUTH_SEND;
2038 if (ifo->auth.protocol == AUTH_PROTO_TOKEN)
2039 ifo->auth.protocol = AUTH_ALG_NONE;
2040 else
2041 ifo->auth.algorithm = AUTH_ALG_HMAC_MD5;
2042 ifo->auth.rdm = AUTH_RDM_MONOTONIC;
2043 break;
2045 if (fp)
2046 *fp++ = '\0';
2047 if (ifo->auth.protocol == AUTH_PROTO_TOKEN) {
2048 np = strchr(arg, '/');
2049 if (np) {
2050 if (fp == NULL || np < fp)
2051 *np++ = '\0';
2052 else
2053 np = NULL;
2055 if (parse_uint32(&ifo->auth.token_snd_secretid,
2056 arg) == -1)
2057 logerrx("%s: not a number", arg);
2058 else
2059 ifo->auth.token_rcv_secretid =
2060 ifo->auth.token_snd_secretid;
2061 if (np &&
2062 parse_uint32(&ifo->auth.token_rcv_secretid,
2063 np) == -1)
2064 logerrx("%s: not a number", arg);
2065 } else {
2066 if (strcasecmp(arg, "hmacmd5") == 0 ||
2067 strcasecmp(arg, "hmac-md5") == 0)
2068 ifo->auth.algorithm = AUTH_ALG_HMAC_MD5;
2069 else {
2070 logerrx("%s: unsupported algorithm", arg);
2071 return 1;
2074 arg = fp;
2075 if (arg == NULL) {
2076 ifo->auth.options |= DHCPCD_AUTH_SEND;
2077 ifo->auth.rdm = AUTH_RDM_MONOTONIC;
2078 break;
2080 if (strcasecmp(arg, "monocounter") == 0) {
2081 ifo->auth.rdm = AUTH_RDM_MONOTONIC;
2082 ifo->auth.options |= DHCPCD_AUTH_RDM_COUNTER;
2083 } else if (strcasecmp(arg, "monotonic") ==0 ||
2084 strcasecmp(arg, "monotime") == 0)
2085 ifo->auth.rdm = AUTH_RDM_MONOTONIC;
2086 else {
2087 logerrx("%s: unsupported RDM", arg);
2088 return -1;
2090 ifo->auth.options |= DHCPCD_AUTH_SEND;
2091 break;
2092 #else
2093 logerrx("no authentication support");
2094 return -1;
2095 #endif
2096 case O_AUTHTOKEN:
2097 ARG_REQUIRED;
2098 #ifdef AUTH
2099 fp = strwhite(arg);
2100 if (fp == NULL) {
2101 logerrx("authtoken requires a realm");
2102 return -1;
2104 *fp++ = '\0';
2105 token = calloc(1, sizeof(*token));
2106 if (token == NULL) {
2107 logerr(__func__);
2108 return -1;
2110 if (parse_uint32(&token->secretid, arg) == -1) {
2111 logerrx("%s: not a number", arg);
2112 goto invalid_token;
2114 arg = fp;
2115 fp = strend(arg);
2116 if (fp == NULL) {
2117 logerrx("authtoken requires a realm");
2118 goto invalid_token;
2120 *fp++ = '\0';
2121 s = parse_string(NULL, 0, arg);
2122 if (s == -1) {
2123 logerr("realm_len");
2124 goto invalid_token;
2126 if (s != 0) {
2127 token->realm_len = (size_t)s;
2128 token->realm = malloc(token->realm_len);
2129 if (token->realm == NULL) {
2130 logerr(__func__);
2131 goto invalid_token;
2133 parse_string((char *)token->realm, token->realm_len,
2134 arg);
2136 arg = fp;
2137 fp = strend(arg);
2138 if (fp == NULL) {
2139 logerrx("authtoken requies an expiry date");
2140 goto invalid_token;
2142 *fp++ = '\0';
2143 if (*arg == '"') {
2144 arg++;
2145 np = strchr(arg, '"');
2146 if (np)
2147 *np = '\0';
2149 if (strcmp(arg, "0") == 0 || strcasecmp(arg, "forever") == 0)
2150 token->expire =0;
2151 else {
2152 struct tm tm;
2154 memset(&tm, 0, sizeof(tm));
2155 if (strptime(arg, "%Y-%m-%d %H:%M", &tm) == NULL) {
2156 logerrx("%s: invalid date time", arg);
2157 goto invalid_token;
2159 if ((token->expire = mktime(&tm)) == (time_t)-1) {
2160 logerr("%s: mktime", __func__);
2161 goto invalid_token;
2164 arg = fp;
2165 s = parse_string(NULL, 0, arg);
2166 if (s == -1 || s == 0) {
2167 if (s == -1)
2168 logerr("token_len");
2169 else
2170 logerrx("authtoken requires a key");
2171 goto invalid_token;
2173 token->key_len = (size_t)s;
2174 token->key = malloc(token->key_len);
2175 if (token->key == NULL) {
2176 logerr(__func__);
2177 goto invalid_token;
2179 parse_string((char *)token->key, token->key_len, arg);
2180 TAILQ_INSERT_TAIL(&ifo->auth.tokens, token, next);
2181 break;
2183 invalid_token:
2184 free(token->realm);
2185 free(token);
2186 #else
2187 logerrx("no authentication support");
2188 #endif
2189 return -1;
2190 case O_AUTHNOTREQUIRED:
2191 ifo->auth.options &= ~DHCPCD_AUTH_REQUIRE;
2192 break;
2193 case O_DHCP:
2194 ifo->options |= DHCPCD_DHCP | DHCPCD_WANTDHCP | DHCPCD_IPV4;
2195 break;
2196 case O_NODHCP:
2197 ifo->options &= ~DHCPCD_DHCP;
2198 break;
2199 case O_DHCP6:
2200 ifo->options |= DHCPCD_DHCP6 | DHCPCD_IPV6;
2201 break;
2202 case O_NODHCP6:
2203 ifo->options &= ~DHCPCD_DHCP6;
2204 break;
2205 case O_CONTROLGRP:
2206 ARG_REQUIRED;
2207 #ifdef PRIVSEP
2208 /* Control group is already set by this point.
2209 * We don't need to pledge getpw either with this. */
2210 if (IN_PRIVSEP(ctx))
2211 break;
2212 #endif
2213 #ifdef _REENTRANT
2214 l = sysconf(_SC_GETGR_R_SIZE_MAX);
2215 if (l == -1)
2216 dl = 1024;
2217 else
2218 dl = (size_t)l;
2219 p = malloc(dl);
2220 if (p == NULL) {
2221 logerr(__func__);
2222 return -1;
2224 while ((i = getgrnam_r(arg, &grpbuf, p, dl, &grp)) ==
2225 ERANGE)
2227 size_t nl = dl * 2;
2228 if (nl < dl) {
2229 logerrx("control_group: out of buffer");
2230 free(p);
2231 return -1;
2233 dl = nl;
2234 np = realloc(p, dl);
2235 if (np == NULL) {
2236 logerr(__func__);
2237 free(p);
2238 return -1;
2240 p = np;
2242 if (i != 0) {
2243 errno = i;
2244 logerr("getgrnam_r");
2245 free(p);
2246 return -1;
2248 if (grp == NULL) {
2249 if (!ctx->control_group)
2250 logerrx("controlgroup: %s: not found", arg);
2251 free(p);
2252 return -1;
2254 ctx->control_group = grp->gr_gid;
2255 free(p);
2256 #else
2257 grp = getgrnam(arg);
2258 if (grp == NULL) {
2259 if (!ctx->control_group)
2260 logerrx("controlgroup: %s: not found", arg);
2261 return -1;
2263 ctx->control_group = grp->gr_gid;
2264 #endif
2265 break;
2266 case O_GATEWAY:
2267 ifo->options |= DHCPCD_GATEWAY;
2268 break;
2269 case O_NOUP:
2270 ifo->options &= ~DHCPCD_IF_UP;
2271 break;
2272 case O_SLAAC:
2273 ARG_REQUIRED;
2274 np = strwhite(arg);
2275 if (np != NULL) {
2276 *np++ = '\0';
2277 np = strskipwhite(np);
2279 if (strcmp(arg, "private") == 0 ||
2280 strcmp(arg, "stableprivate") == 0 ||
2281 strcmp(arg, "stable") == 0)
2282 ifo->options |= DHCPCD_SLAACPRIVATE;
2283 else
2284 ifo->options &= ~DHCPCD_SLAACPRIVATE;
2285 #ifdef INET6
2286 if (strcmp(arg, "token") == 0) {
2287 if (np == NULL) {
2288 logerrx("slaac token: no token specified");
2289 return -1;
2291 arg = np;
2292 np = strwhite(np);
2293 if (np != NULL) {
2294 *np++ = '\0';
2295 np = strskipwhite(np);
2297 if (inet_pton(AF_INET6, arg, &ifo->token) != 1) {
2298 logerrx("slaac token: invalid token");
2299 return -1;
2302 #endif
2303 if (np != NULL &&
2304 (strcmp(np, "temp") == 0 || strcmp(np, "temporary") == 0))
2305 ifo->options |= DHCPCD_SLAACTEMP;
2306 break;
2307 case O_BOOTP:
2308 ifo->options |= DHCPCD_BOOTP;
2309 break;
2310 case O_NODELAY:
2311 ifo->options &= ~DHCPCD_INITIAL_DELAY;
2312 break;
2313 case O_LASTLEASE_EXTEND:
2314 ifo->options |= DHCPCD_LASTLEASE | DHCPCD_LASTLEASE_EXTEND;
2315 break;
2316 case O_INACTIVE:
2317 ifo->options |= DHCPCD_INACTIVE;
2318 break;
2319 case O_MUDURL:
2320 ARG_REQUIRED;
2321 s = parse_string((char *)ifo->mudurl + 1, MUDURL_MAX_LEN, arg);
2322 if (s == -1) {
2323 logerr("mudurl");
2324 return -1;
2326 *ifo->mudurl = (uint8_t)s;
2327 break;
2328 case O_LINK_RCVBUF:
2329 #ifndef SMALL
2330 ARG_REQUIRED;
2331 ctx->link_rcvbuf = (int)strtoi(arg, NULL, 0, 0, INT32_MAX, &e);
2332 if (e) {
2333 logerrx("failed to convert link_rcvbuf %s", arg);
2334 return -1;
2336 #endif
2337 break;
2338 case O_CONFIGURE:
2339 ifo->options |= DHCPCD_CONFIGURE;
2340 break;
2341 case O_NOCONFIGURE:
2342 ifo->options &= ~DHCPCD_CONFIGURE;
2343 break;
2344 case O_ARP_PERSISTDEFENCE:
2345 ifo->options |= DHCPCD_ARP_PERSISTDEFENCE;
2346 break;
2347 case O_REQUEST_TIME:
2348 ARG_REQUIRED;
2349 ifo->request_time =
2350 (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
2351 if (e) {
2352 logerrx("invalid request time: %s", arg);
2353 return -1;
2355 break;
2356 #ifdef INET
2357 case O_FALLBACK_TIME:
2358 ARG_REQUIRED;
2359 ifo->request_time =
2360 (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
2361 if (e) {
2362 logerrx("invalid fallback time: %s", arg);
2363 return -1;
2365 break;
2366 case O_IPV4LL_TIME:
2367 ARG_REQUIRED;
2368 ifo->ipv4ll_time =
2369 (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
2370 if (e) {
2371 logerrx("invalid ipv4ll time: %s", arg);
2372 return -1;
2374 break;
2375 #endif
2376 default:
2377 return 0;
2380 return 1;
2382 #ifdef ARG_REQUIRED
2383 arg_required:
2384 logerrx("option %d requires an argument", opt);
2385 return -1;
2386 #undef ARG_REQUIRED
2387 #endif
2390 static int
2391 parse_config_line(struct dhcpcd_ctx *ctx, const char *ifname,
2392 struct if_options *ifo, const char *opt, char *line,
2393 struct dhcp_opt **ldop, struct dhcp_opt **edop)
2395 unsigned int i;
2397 for (i = 0; i < sizeof(cf_options) / sizeof(cf_options[0]); i++) {
2398 if (!cf_options[i].name ||
2399 strcmp(cf_options[i].name, opt) != 0)
2400 continue;
2402 if (cf_options[i].has_arg == required_argument && !line) {
2403 logerrx("option requires an argument -- %s", opt);
2404 return -1;
2407 return parse_option(ctx, ifname, ifo, cf_options[i].val, line,
2408 ldop, edop);
2411 if (!(ctx->options & DHCPCD_PRINT_PIDFILE))
2412 logerrx("unknown option: %s", opt);
2413 return -1;
2416 static void
2417 finish_config(struct if_options *ifo)
2420 /* Terminate the encapsulated options */
2421 if (ifo->vendor[0] && !(ifo->options & DHCPCD_VENDORRAW)) {
2422 ifo->vendor[0]++;
2423 ifo->vendor[ifo->vendor[0]] = DHO_END;
2424 /* We are called twice.
2425 * This should be fixed, but in the meantime, this
2426 * guard should suffice */
2427 ifo->options |= DHCPCD_VENDORRAW;
2430 if (!(ifo->options & DHCPCD_ARP) ||
2431 ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))
2432 ifo->options &= ~DHCPCD_IPV4LL;
2434 if (!(ifo->options & DHCPCD_IPV4))
2435 ifo->options &= ~(DHCPCD_DHCP | DHCPCD_IPV4LL | DHCPCD_WAITIP4);
2437 if (!(ifo->options & DHCPCD_IPV6))
2438 ifo->options &=
2439 ~(DHCPCD_IPV6RS | DHCPCD_DHCP6 | DHCPCD_WAITIP6);
2441 if (!(ifo->options & DHCPCD_IPV6RS))
2442 ifo->options &=
2443 ~(DHCPCD_IPV6RA_AUTOCONF | DHCPCD_IPV6RA_REQRDNSS);
2446 static struct if_options *
2447 default_config(struct dhcpcd_ctx *ctx)
2449 struct if_options *ifo;
2451 /* Seed our default options */
2452 if ((ifo = calloc(1, sizeof(*ifo))) == NULL) {
2453 logerr(__func__);
2454 return NULL;
2456 ifo->options |= DHCPCD_IF_UP | DHCPCD_LINK | DHCPCD_INITIAL_DELAY;
2457 ifo->timeout = DEFAULT_TIMEOUT;
2458 ifo->reboot = DEFAULT_REBOOT;
2459 ifo->request_time = DEFAULT_REQUEST;
2460 #ifdef INET
2461 ifo->fallback_time = DEFAULT_FALLBACK;
2462 ifo->ipv4ll_time = DEFAULT_IPV4LL;
2463 #endif
2464 ifo->metric = -1;
2465 ifo->auth.options |= DHCPCD_AUTH_REQUIRE;
2466 rb_tree_init(&ifo->routes, &rt_compare_list_ops);
2467 #ifdef AUTH
2468 TAILQ_INIT(&ifo->auth.tokens);
2469 #endif
2471 /* Inherit some global defaults */
2472 if (ctx->options & DHCPCD_CONFIGURE)
2473 ifo->options |= DHCPCD_CONFIGURE;
2474 if (ctx->options & DHCPCD_PERSISTENT)
2475 ifo->options |= DHCPCD_PERSISTENT;
2476 if (ctx->options & DHCPCD_SLAACPRIVATE)
2477 ifo->options |= DHCPCD_SLAACPRIVATE;
2479 return ifo;
2482 struct if_options *
2483 read_config(struct dhcpcd_ctx *ctx,
2484 const char *ifname, const char *ssid, const char *profile)
2486 struct if_options *ifo;
2487 char buf[UDPLEN_MAX], *bp; /* 64k max config file size */
2488 char *line, *option, *p;
2489 ssize_t buflen;
2490 size_t vlen;
2491 int skip, have_profile, new_block, had_block;
2492 #if !defined(INET) || !defined(INET6)
2493 size_t i;
2494 struct dhcp_opt *opt;
2495 #endif
2496 struct dhcp_opt *ldop, *edop;
2498 /* Seed our default options */
2499 if ((ifo = default_config(ctx)) == NULL)
2500 return NULL;
2501 if (default_options == 0) {
2502 default_options |= DHCPCD_CONFIGURE | DHCPCD_DAEMONISE |
2503 DHCPCD_GATEWAY;
2504 #ifdef INET
2505 skip = xsocket(PF_INET, SOCK_DGRAM, 0);
2506 if (skip != -1) {
2507 close(skip);
2508 default_options |= DHCPCD_IPV4 | DHCPCD_ARP |
2509 DHCPCD_DHCP | DHCPCD_IPV4LL;
2511 #endif
2512 #ifdef INET6
2513 skip = xsocket(PF_INET6, SOCK_DGRAM, 0);
2514 if (skip != -1) {
2515 close(skip);
2516 default_options |= DHCPCD_IPV6 | DHCPCD_IPV6RS |
2517 DHCPCD_IPV6RA_AUTOCONF | DHCPCD_IPV6RA_REQRDNSS |
2518 DHCPCD_DHCP6;
2520 #endif
2521 #ifdef PLUGIN_DEV
2522 default_options |= DHCPCD_DEV;
2523 #endif
2525 ifo->options |= default_options;
2527 CLEAR_CONFIG_BLOCK(ifo);
2529 vlen = strlcpy((char *)ifo->vendorclassid + 1, ctx->vendor,
2530 sizeof(ifo->vendorclassid) - 1);
2531 ifo->vendorclassid[0] = (uint8_t)(vlen > 255 ? 0 : vlen);
2533 /* Reset route order */
2534 ctx->rt_order = 0;
2536 /* Parse our embedded options file */
2537 if (ifname == NULL && !(ctx->options & DHCPCD_PRINT_PIDFILE)) {
2538 /* Space for initial estimates */
2539 #if defined(INET) && defined(INITDEFINES)
2540 ifo->dhcp_override =
2541 calloc(INITDEFINES, sizeof(*ifo->dhcp_override));
2542 if (ifo->dhcp_override == NULL)
2543 logerr(__func__);
2544 else
2545 ifo->dhcp_override_len = INITDEFINES;
2546 #endif
2548 #if defined(INET6) && defined(INITDEFINENDS)
2549 ifo->nd_override =
2550 calloc(INITDEFINENDS, sizeof(*ifo->nd_override));
2551 if (ifo->nd_override == NULL)
2552 logerr(__func__);
2553 else
2554 ifo->nd_override_len = INITDEFINENDS;
2555 #endif
2556 #if defined(INET6) && defined(INITDEFINE6S)
2557 ifo->dhcp6_override =
2558 calloc(INITDEFINE6S, sizeof(*ifo->dhcp6_override));
2559 if (ifo->dhcp6_override == NULL)
2560 logerr(__func__);
2561 else
2562 ifo->dhcp6_override_len = INITDEFINE6S;
2563 #endif
2565 /* Now load our embedded config */
2566 #ifdef EMBEDDED_CONFIG
2567 buflen = dhcp_readfile(ctx, EMBEDDED_CONFIG, buf, sizeof(buf));
2568 if (buflen == -1) {
2569 logerr("%s: %s", __func__, EMBEDDED_CONFIG);
2570 return ifo;
2572 if (buf[buflen - 1] != '\0') {
2573 if ((size_t)buflen < sizeof(buf) - 1)
2574 buflen++;
2575 buf[buflen - 1] = '\0';
2577 #else
2578 buflen = (ssize_t)strlcpy(buf, dhcpcd_embedded_conf,
2579 sizeof(buf));
2580 if ((size_t)buflen >= sizeof(buf)) {
2581 logerrx("%s: embedded config too big", __func__);
2582 return ifo;
2584 /* Our embedded config is NULL terminated */
2585 #endif
2586 bp = buf;
2587 while ((line = get_line(&bp, &buflen)) != NULL) {
2588 option = strsep(&line, " \t");
2589 if (line)
2590 line = strskipwhite(line);
2591 /* Trim trailing whitespace */
2592 if (line) {
2593 p = line + strlen(line) - 1;
2594 while (p != line &&
2595 (*p == ' ' || *p == '\t') &&
2596 *(p - 1) != '\\')
2597 *p-- = '\0';
2599 parse_config_line(ctx, NULL, ifo, option, line,
2600 &ldop, &edop);
2603 #ifdef INET
2604 ctx->dhcp_opts = ifo->dhcp_override;
2605 ctx->dhcp_opts_len = ifo->dhcp_override_len;
2606 #else
2607 for (i = 0, opt = ifo->dhcp_override;
2608 i < ifo->dhcp_override_len;
2609 i++, opt++)
2610 free_dhcp_opt_embenc(opt);
2611 free(ifo->dhcp_override);
2612 #endif
2613 ifo->dhcp_override = NULL;
2614 ifo->dhcp_override_len = 0;
2616 #ifdef INET6
2617 ctx->nd_opts = ifo->nd_override;
2618 ctx->nd_opts_len = ifo->nd_override_len;
2619 #ifdef DHCP6
2620 ctx->dhcp6_opts = ifo->dhcp6_override;
2621 ctx->dhcp6_opts_len = ifo->dhcp6_override_len;
2622 #endif
2623 #else
2624 for (i = 0, opt = ifo->nd_override;
2625 i < ifo->nd_override_len;
2626 i++, opt++)
2627 free_dhcp_opt_embenc(opt);
2628 free(ifo->nd_override);
2629 for (i = 0, opt = ifo->dhcp6_override;
2630 i < ifo->dhcp6_override_len;
2631 i++, opt++)
2632 free_dhcp_opt_embenc(opt);
2633 free(ifo->dhcp6_override);
2634 #endif
2635 ifo->nd_override = NULL;
2636 ifo->nd_override_len = 0;
2637 ifo->dhcp6_override = NULL;
2638 ifo->dhcp6_override_len = 0;
2640 ctx->vivso = ifo->vivso_override;
2641 ctx->vivso_len = ifo->vivso_override_len;
2642 ifo->vivso_override = NULL;
2643 ifo->vivso_override_len = 0;
2646 /* Parse our options file */
2647 buflen = dhcp_readfile(ctx, ctx->cffile, buf, sizeof(buf));
2648 if (buflen == -1) {
2649 /* dhcpcd can continue without it, but no DNS options
2650 * would be requested ... */
2651 logerr("%s: %s", __func__, ctx->cffile);
2652 return ifo;
2654 if (buf[buflen - 1] != '\0') {
2655 if ((size_t)buflen < sizeof(buf) - 1)
2656 buflen++;
2657 buf[buflen - 1] = '\0';
2659 dhcp_filemtime(ctx, ctx->cffile, &ifo->mtime);
2661 ldop = edop = NULL;
2662 skip = have_profile = new_block = 0;
2663 had_block = ifname == NULL ? 1 : 0;
2664 bp = buf;
2665 while ((line = get_line(&bp, &buflen)) != NULL) {
2666 option = strsep(&line, " \t");
2667 if (line)
2668 line = strskipwhite(line);
2669 /* Trim trailing whitespace */
2670 if (line) {
2671 p = line + strlen(line) - 1;
2672 while (p != line &&
2673 (*p == ' ' || *p == '\t') &&
2674 *(p - 1) != '\\')
2675 *p-- = '\0';
2677 if (skip == 0 && new_block) {
2678 had_block = 1;
2679 new_block = 0;
2680 ifo->options &= ~DHCPCD_WAITOPTS;
2681 SET_CONFIG_BLOCK(ifo);
2684 /* Start of an interface block, skip if not ours */
2685 if (strcmp(option, "interface") == 0) {
2686 char **n;
2688 new_block = 1;
2689 if (line == NULL) {
2690 /* No interface given */
2691 skip = 1;
2692 continue;
2694 if (ifname && strcmp(line, ifname) == 0)
2695 skip = 0;
2696 else
2697 skip = 1;
2698 if (ifname)
2699 continue;
2701 n = reallocarray(ctx->ifcv,
2702 (size_t)ctx->ifcc + 1, sizeof(char *));
2703 if (n == NULL) {
2704 logerr(__func__);
2705 continue;
2707 ctx->ifcv = n;
2708 ctx->ifcv[ctx->ifcc] = strdup(line);
2709 if (ctx->ifcv[ctx->ifcc] == NULL) {
2710 logerr(__func__);
2711 continue;
2713 ctx->ifcc++;
2714 continue;
2716 /* Start of an ssid block, skip if not ours */
2717 if (strcmp(option, "ssid") == 0) {
2718 new_block = 1;
2719 if (ssid && line && strcmp(line, ssid) == 0)
2720 skip = 0;
2721 else
2722 skip = 1;
2723 continue;
2725 /* Start of a profile block, skip if not ours */
2726 if (strcmp(option, "profile") == 0) {
2727 new_block = 1;
2728 if (profile && line && strcmp(line, profile) == 0) {
2729 skip = 0;
2730 have_profile = 1;
2731 } else
2732 skip = 1;
2733 continue;
2735 /* Skip arping if we have selected a profile but not parsing
2736 * one. */
2737 if (profile && !have_profile && strcmp(option, "arping") == 0)
2738 continue;
2739 if (skip)
2740 continue;
2742 parse_config_line(ctx, ifname, ifo, option, line, &ldop, &edop);
2745 if (profile && !have_profile) {
2746 free_options(ctx, ifo);
2747 errno = ENOENT;
2748 return NULL;
2751 if (!had_block)
2752 ifo->options &= ~DHCPCD_WAITOPTS;
2753 CLEAR_CONFIG_BLOCK(ifo);
2754 finish_config(ifo);
2755 return ifo;
2759 add_options(struct dhcpcd_ctx *ctx, const char *ifname,
2760 struct if_options *ifo, int argc, char **argv)
2762 int oi, opt, r;
2763 unsigned long long wait_opts;
2765 if (argc == 0)
2766 return 1;
2768 optind = 0;
2769 r = 1;
2770 /* Don't apply the command line wait options to each interface,
2771 * only use the dhcpcd.conf entry for that. */
2772 if (ifname != NULL)
2773 wait_opts = ifo->options & DHCPCD_WAITOPTS;
2774 while ((opt = getopt_long(argc, argv,
2775 ctx->options & DHCPCD_PRINT_PIDFILE ? NOERR_IF_OPTS : IF_OPTS,
2776 cf_options, &oi)) != -1)
2778 r = parse_option(ctx, ifname, ifo, opt, optarg, NULL, NULL);
2779 if (r != 1)
2780 break;
2782 if (ifname != NULL) {
2783 ifo->options &= ~DHCPCD_WAITOPTS;
2784 ifo->options |= wait_opts;
2787 finish_config(ifo);
2788 return r;
2791 void
2792 free_options(struct dhcpcd_ctx *ctx, struct if_options *ifo)
2794 size_t i;
2795 #ifdef RT_FREE_ROUTE_TABLE
2796 struct interface *ifp;
2797 struct rt *rt;
2798 #endif
2799 struct dhcp_opt *opt;
2800 struct vivco *vo;
2801 #ifdef AUTH
2802 struct token *token;
2803 #endif
2805 if (ifo == NULL)
2806 return;
2808 if (ifo->environ) {
2809 i = 0;
2810 while (ifo->environ[i])
2811 free(ifo->environ[i++]);
2812 free(ifo->environ);
2814 if (ifo->config) {
2815 i = 0;
2816 while (ifo->config[i])
2817 free(ifo->config[i++]);
2818 free(ifo->config);
2821 #ifdef RT_FREE_ROUTE_TABLE
2822 /* Stupidly, we don't know the interface when creating the options.
2823 * As such, make sure each route has one so they can goto the
2824 * free list. */
2825 ifp = ctx->ifaces != NULL ? TAILQ_FIRST(ctx->ifaces) : NULL;
2826 if (ifp != NULL) {
2827 RB_TREE_FOREACH(rt, &ifo->routes) {
2828 if (rt->rt_ifp == NULL)
2829 rt->rt_ifp = ifp;
2832 #endif
2833 rt_headclear0(ctx, &ifo->routes, AF_UNSPEC);
2835 free(ifo->arping);
2836 free(ifo->blacklist);
2837 free(ifo->fallback);
2839 for (opt = ifo->dhcp_override;
2840 ifo->dhcp_override_len > 0;
2841 opt++, ifo->dhcp_override_len--)
2842 free_dhcp_opt_embenc(opt);
2843 free(ifo->dhcp_override);
2844 for (opt = ifo->nd_override;
2845 ifo->nd_override_len > 0;
2846 opt++, ifo->nd_override_len--)
2847 free_dhcp_opt_embenc(opt);
2848 free(ifo->nd_override);
2849 for (opt = ifo->dhcp6_override;
2850 ifo->dhcp6_override_len > 0;
2851 opt++, ifo->dhcp6_override_len--)
2852 free_dhcp_opt_embenc(opt);
2853 free(ifo->dhcp6_override);
2854 for (vo = ifo->vivco;
2855 ifo->vivco_len > 0;
2856 vo++, ifo->vivco_len--)
2857 free(vo->data);
2858 free(ifo->vivco);
2859 for (opt = ifo->vivso_override;
2860 ifo->vivso_override_len > 0;
2861 opt++, ifo->vivso_override_len--)
2862 free_dhcp_opt_embenc(opt);
2863 free(ifo->vivso_override);
2865 #if defined(INET6) && !defined(SMALL)
2866 for (; ifo->ia_len > 0; ifo->ia_len--)
2867 free(ifo->ia[ifo->ia_len - 1].sla);
2868 #endif
2869 free(ifo->ia);
2871 #ifdef AUTH
2872 while ((token = TAILQ_FIRST(&ifo->auth.tokens))) {
2873 TAILQ_REMOVE(&ifo->auth.tokens, token, next);
2874 if (token->realm_len)
2875 free(token->realm);
2876 free(token->key);
2877 free(token);
2879 #endif
2880 free(ifo);