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