18d36e1dfSRoy Marples /* SPDX-License-Identifier: BSD-2-Clause */
27827cba2SAaron LI /*
37827cba2SAaron LI * dhcpcd - DHCP client daemon
480aa9461SRoy Marples * Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
57827cba2SAaron LI * All rights reserved
67827cba2SAaron LI
77827cba2SAaron LI * Redistribution and use in source and binary forms, with or without
87827cba2SAaron LI * modification, are permitted provided that the following conditions
97827cba2SAaron LI * are met:
107827cba2SAaron LI * 1. Redistributions of source code must retain the above copyright
117827cba2SAaron LI * notice, this list of conditions and the following disclaimer.
127827cba2SAaron LI * 2. Redistributions in binary form must reproduce the above copyright
137827cba2SAaron LI * notice, this list of conditions and the following disclaimer in the
147827cba2SAaron LI * documentation and/or other materials provided with the distribution.
157827cba2SAaron LI *
167827cba2SAaron LI * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
177827cba2SAaron LI * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
187827cba2SAaron LI * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
197827cba2SAaron LI * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
207827cba2SAaron LI * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
217827cba2SAaron LI * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
227827cba2SAaron LI * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
237827cba2SAaron LI * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
247827cba2SAaron LI * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
257827cba2SAaron LI * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
267827cba2SAaron LI * SUCH DAMAGE.
277827cba2SAaron LI */
287827cba2SAaron LI
297827cba2SAaron LI #include <sys/param.h>
307827cba2SAaron LI #include <sys/types.h>
317827cba2SAaron LI
327827cba2SAaron LI #include <arpa/inet.h>
337827cba2SAaron LI
347827cba2SAaron LI #include <ctype.h>
357827cba2SAaron LI #include <errno.h>
367827cba2SAaron LI #include <getopt.h>
377827cba2SAaron LI #include <grp.h>
387827cba2SAaron LI #include <inttypes.h>
397827cba2SAaron LI #include <limits.h>
407827cba2SAaron LI #include <paths.h>
417827cba2SAaron LI #include <stdio.h>
427827cba2SAaron LI #include <stdlib.h>
437827cba2SAaron LI #include <string.h>
447827cba2SAaron LI #include <unistd.h>
457827cba2SAaron LI #include <time.h>
467827cba2SAaron LI
477827cba2SAaron LI #include "config.h"
487827cba2SAaron LI #include "common.h"
497827cba2SAaron LI #include "dhcp.h"
507827cba2SAaron LI #include "dhcp6.h"
517827cba2SAaron LI #include "dhcpcd-embedded.h"
52a0d9933aSRoy Marples #include "duid.h"
537827cba2SAaron LI #include "if.h"
547827cba2SAaron LI #include "if-options.h"
557827cba2SAaron LI #include "ipv4.h"
567827cba2SAaron LI #include "logerr.h"
577827cba2SAaron LI #include "sa.h"
587827cba2SAaron LI
59cc34ba0cSRoy Marples #define IN_CONFIG_BLOCK(ifo) ((ifo)->options & DHCPCD_FORKED)
60cc34ba0cSRoy Marples #define SET_CONFIG_BLOCK(ifo) ((ifo)->options |= DHCPCD_FORKED)
61cc34ba0cSRoy Marples #define CLEAR_CONFIG_BLOCK(ifo) ((ifo)->options &= ~DHCPCD_FORKED)
62cc34ba0cSRoy Marples
63b8b69544SRoy Marples static unsigned long long default_options;
64b8b69544SRoy Marples
657827cba2SAaron LI const struct option cf_options[] = {
667827cba2SAaron LI {"background", no_argument, NULL, 'b'},
677827cba2SAaron LI {"script", required_argument, NULL, 'c'},
687827cba2SAaron LI {"debug", no_argument, NULL, 'd'},
697827cba2SAaron LI {"env", required_argument, NULL, 'e'},
707827cba2SAaron LI {"config", required_argument, NULL, 'f'},
717827cba2SAaron LI {"reconfigure", no_argument, NULL, 'g'},
727827cba2SAaron LI {"hostname", optional_argument, NULL, 'h'},
737827cba2SAaron LI {"vendorclassid", optional_argument, NULL, 'i'},
747827cba2SAaron LI {"logfile", required_argument, NULL, 'j'},
757827cba2SAaron LI {"release", no_argument, NULL, 'k'},
767827cba2SAaron LI {"leasetime", required_argument, NULL, 'l'},
777827cba2SAaron LI {"metric", required_argument, NULL, 'm'},
787827cba2SAaron LI {"rebind", no_argument, NULL, 'n'},
797827cba2SAaron LI {"option", required_argument, NULL, 'o'},
807827cba2SAaron LI {"persistent", no_argument, NULL, 'p'},
817827cba2SAaron LI {"quiet", no_argument, NULL, 'q'},
827827cba2SAaron LI {"request", optional_argument, NULL, 'r'},
837827cba2SAaron LI {"inform", optional_argument, NULL, 's'},
847827cba2SAaron LI {"inform6", optional_argument, NULL, O_INFORM6},
857827cba2SAaron LI {"timeout", required_argument, NULL, 't'},
867827cba2SAaron LI {"userclass", required_argument, NULL, 'u'},
876e63cc1fSRoy Marples #ifndef SMALL
886e63cc1fSRoy Marples {"msuserclass", required_argument, NULL, O_MSUSERCLASS},
896e63cc1fSRoy Marples #endif
907827cba2SAaron LI {"vendor", required_argument, NULL, 'v'},
917827cba2SAaron LI {"waitip", optional_argument, NULL, 'w'},
927827cba2SAaron LI {"exit", no_argument, NULL, 'x'},
937827cba2SAaron LI {"allowinterfaces", required_argument, NULL, 'z'},
947827cba2SAaron LI {"reboot", required_argument, NULL, 'y'},
957827cba2SAaron LI {"noarp", no_argument, NULL, 'A'},
967827cba2SAaron LI {"nobackground", no_argument, NULL, 'B'},
977827cba2SAaron LI {"nohook", required_argument, NULL, 'C'},
98a0d9933aSRoy Marples {"duid", optional_argument, NULL, 'D'},
997827cba2SAaron LI {"lastlease", no_argument, NULL, 'E'},
1007827cba2SAaron LI {"fqdn", optional_argument, NULL, 'F'},
1017827cba2SAaron LI {"nogateway", no_argument, NULL, 'G'},
1027827cba2SAaron LI {"xidhwaddr", no_argument, NULL, 'H'},
1037827cba2SAaron LI {"clientid", optional_argument, NULL, 'I'},
1047827cba2SAaron LI {"broadcast", no_argument, NULL, 'J'},
1057827cba2SAaron LI {"nolink", no_argument, NULL, 'K'},
1067827cba2SAaron LI {"noipv4ll", no_argument, NULL, 'L'},
1070a68f8d2SRoy Marples {"manager", no_argument, NULL, 'M'},
1087827cba2SAaron LI {"renew", no_argument, NULL, 'N'},
1097827cba2SAaron LI {"nooption", required_argument, NULL, 'O'},
1107827cba2SAaron LI {"printpidfile", no_argument, NULL, 'P'},
1117827cba2SAaron LI {"require", required_argument, NULL, 'Q'},
1127827cba2SAaron LI {"static", required_argument, NULL, 'S'},
1137827cba2SAaron LI {"test", no_argument, NULL, 'T'},
1147827cba2SAaron LI {"dumplease", no_argument, NULL, 'U'},
1157827cba2SAaron LI {"variables", no_argument, NULL, 'V'},
1167827cba2SAaron LI {"whitelist", required_argument, NULL, 'W'},
1177827cba2SAaron LI {"blacklist", required_argument, NULL, 'X'},
1187827cba2SAaron LI {"denyinterfaces", required_argument, NULL, 'Z'},
1197827cba2SAaron LI {"oneshot", no_argument, NULL, '1'},
1207827cba2SAaron LI {"ipv4only", no_argument, NULL, '4'},
1217827cba2SAaron LI {"ipv6only", no_argument, NULL, '6'},
1226e63cc1fSRoy Marples {"anonymous", no_argument, NULL, O_ANONYMOUS},
1230aaf6155SRoy Marples {"randomise_hwaddr",no_argument, NULL, O_RANDOMISE_HWADDR},
1247827cba2SAaron LI {"arping", required_argument, NULL, O_ARPING},
1257827cba2SAaron LI {"destination", required_argument, NULL, O_DESTINATION},
1267827cba2SAaron LI {"fallback", required_argument, NULL, O_FALLBACK},
1277827cba2SAaron LI {"ipv6rs", no_argument, NULL, O_IPV6RS},
1287827cba2SAaron LI {"noipv6rs", no_argument, NULL, O_NOIPV6RS},
1297827cba2SAaron LI {"ipv6ra_autoconf", no_argument, NULL, O_IPV6RA_AUTOCONF},
1307827cba2SAaron LI {"ipv6ra_noautoconf", no_argument, NULL, O_IPV6RA_NOAUTOCONF},
1317827cba2SAaron LI {"ipv6ra_fork", no_argument, NULL, O_IPV6RA_FORK},
1327827cba2SAaron LI {"ipv4", no_argument, NULL, O_IPV4},
1337827cba2SAaron LI {"noipv4", no_argument, NULL, O_NOIPV4},
1347827cba2SAaron LI {"ipv6", no_argument, NULL, O_IPV6},
1357827cba2SAaron LI {"noipv6", no_argument, NULL, O_NOIPV6},
1367827cba2SAaron LI {"noalias", no_argument, NULL, O_NOALIAS},
1377827cba2SAaron LI {"iaid", required_argument, NULL, O_IAID},
13820329f2aSRoy Marples {"ia_na", optional_argument, NULL, O_IA_NA},
13920329f2aSRoy Marples {"ia_ta", optional_argument, NULL, O_IA_TA},
14020329f2aSRoy Marples {"ia_pd", optional_argument, NULL, O_IA_PD},
1417827cba2SAaron LI {"hostname_short", no_argument, NULL, O_HOSTNAME_SHORT},
1427827cba2SAaron LI {"dev", required_argument, NULL, O_DEV},
1437827cba2SAaron LI {"nodev", no_argument, NULL, O_NODEV},
1447827cba2SAaron LI {"define", required_argument, NULL, O_DEFINE},
1457827cba2SAaron LI {"definend", required_argument, NULL, O_DEFINEND},
1467827cba2SAaron LI {"define6", required_argument, NULL, O_DEFINE6},
1477827cba2SAaron LI {"embed", required_argument, NULL, O_EMBED},
1487827cba2SAaron LI {"encap", required_argument, NULL, O_ENCAP},
1497827cba2SAaron LI {"vendopt", required_argument, NULL, O_VENDOPT},
1507827cba2SAaron LI {"vendclass", required_argument, NULL, O_VENDCLASS},
1517827cba2SAaron LI {"authprotocol", required_argument, NULL, O_AUTHPROTOCOL},
1527827cba2SAaron LI {"authtoken", required_argument, NULL, O_AUTHTOKEN},
1537827cba2SAaron LI {"noauthrequired", no_argument, NULL, O_AUTHNOTREQUIRED},
1547827cba2SAaron LI {"dhcp", no_argument, NULL, O_DHCP},
1557827cba2SAaron LI {"nodhcp", no_argument, NULL, O_NODHCP},
1567827cba2SAaron LI {"dhcp6", no_argument, NULL, O_DHCP6},
1577827cba2SAaron LI {"nodhcp6", no_argument, NULL, O_NODHCP6},
1587827cba2SAaron LI {"controlgroup", required_argument, NULL, O_CONTROLGRP},
1597827cba2SAaron LI {"slaac", required_argument, NULL, O_SLAAC},
1607827cba2SAaron LI {"gateway", no_argument, NULL, O_GATEWAY},
1617827cba2SAaron LI {"reject", required_argument, NULL, O_REJECT},
1627827cba2SAaron LI {"bootp", no_argument, NULL, O_BOOTP},
1637827cba2SAaron LI {"nodelay", no_argument, NULL, O_NODELAY},
1647827cba2SAaron LI {"noup", no_argument, NULL, O_NOUP},
1657827cba2SAaron LI {"lastleaseextend", no_argument, NULL, O_LASTLEASE_EXTEND},
1667827cba2SAaron LI {"inactive", no_argument, NULL, O_INACTIVE},
1677827cba2SAaron LI {"mudurl", required_argument, NULL, O_MUDURL},
1688d36e1dfSRoy Marples {"link_rcvbuf", required_argument, NULL, O_LINK_RCVBUF},
169b2927f2bSRoy Marples {"configure", no_argument, NULL, O_CONFIGURE},
170b2927f2bSRoy Marples {"noconfigure", no_argument, NULL, O_NOCONFIGURE},
171*54175cefSRoy Marples {"arp_persistdefence", no_argument, NULL, O_ARP_PERSISTDEFENCE},
172*54175cefSRoy Marples {"request_time", required_argument, NULL, O_REQUEST_TIME},
173*54175cefSRoy Marples {"fallback_time", required_argument, NULL, O_FALLBACK_TIME},
174*54175cefSRoy Marples {"ipv4ll_time", required_argument, NULL, O_IPV4LL_TIME},
1757827cba2SAaron LI {NULL, 0, NULL, '\0'}
1767827cba2SAaron LI };
1777827cba2SAaron LI
1787827cba2SAaron LI static char *
add_environ(char *** array,const char * value,int uniq)1798d36e1dfSRoy Marples add_environ(char ***array, const char *value, int uniq)
1807827cba2SAaron LI {
1818d36e1dfSRoy Marples char **newlist, **list = *array;
1827827cba2SAaron LI size_t i = 0, l, lv;
1837827cba2SAaron LI char *match = NULL, *p, *n;
1847827cba2SAaron LI
1857827cba2SAaron LI match = strdup(value);
1867827cba2SAaron LI if (match == NULL) {
1877827cba2SAaron LI logerr(__func__);
1887827cba2SAaron LI return NULL;
1897827cba2SAaron LI }
1907827cba2SAaron LI p = strchr(match, '=');
1917827cba2SAaron LI if (p == NULL) {
1927827cba2SAaron LI logerrx("%s: no assignment: %s", __func__, value);
1937827cba2SAaron LI free(match);
1947827cba2SAaron LI return NULL;
1957827cba2SAaron LI }
1967827cba2SAaron LI *p++ = '\0';
1977827cba2SAaron LI l = strlen(match);
1987827cba2SAaron LI
1998d36e1dfSRoy Marples while (list && list[i]) {
20080aa9461SRoy Marples /* We know that it must contain '=' due to the above test */
20180aa9461SRoy Marples size_t listl = (size_t)(strchr(list[i], '=') - list[i]);
20280aa9461SRoy Marples
20380aa9461SRoy Marples if (l == listl && strncmp(list[i], match, l) == 0) {
2047827cba2SAaron LI if (uniq) {
2057827cba2SAaron LI n = strdup(value);
2067827cba2SAaron LI if (n == NULL) {
2077827cba2SAaron LI logerr(__func__);
2087827cba2SAaron LI free(match);
2097827cba2SAaron LI return NULL;
2107827cba2SAaron LI }
2118d36e1dfSRoy Marples free(list[i]);
2128d36e1dfSRoy Marples list[i] = n;
2137827cba2SAaron LI } else {
2147827cba2SAaron LI /* Append a space and the value to it */
2158d36e1dfSRoy Marples l = strlen(list[i]);
2167827cba2SAaron LI lv = strlen(p);
2178d36e1dfSRoy Marples n = realloc(list[i], l + lv + 2);
2187827cba2SAaron LI if (n == NULL) {
2197827cba2SAaron LI logerr(__func__);
2207827cba2SAaron LI free(match);
2217827cba2SAaron LI return NULL;
2227827cba2SAaron LI }
2238d36e1dfSRoy Marples list[i] = n;
2248d36e1dfSRoy Marples list[i][l] = ' ';
2258d36e1dfSRoy Marples memcpy(list[i] + l + 1, p, lv);
2268d36e1dfSRoy Marples list[i][l + lv + 1] = '\0';
2277827cba2SAaron LI }
2287827cba2SAaron LI free(match);
2298d36e1dfSRoy Marples return list[i];
2307827cba2SAaron LI }
2317827cba2SAaron LI i++;
2327827cba2SAaron LI }
2337827cba2SAaron LI
2347827cba2SAaron LI free(match);
2357827cba2SAaron LI n = strdup(value);
2367827cba2SAaron LI if (n == NULL) {
2377827cba2SAaron LI logerr(__func__);
2387827cba2SAaron LI return NULL;
2397827cba2SAaron LI }
2408d36e1dfSRoy Marples newlist = reallocarray(list, i + 2, sizeof(char *));
2417827cba2SAaron LI if (newlist == NULL) {
2427827cba2SAaron LI logerr(__func__);
2437827cba2SAaron LI free(n);
2447827cba2SAaron LI return NULL;
2457827cba2SAaron LI }
2467827cba2SAaron LI newlist[i] = n;
2477827cba2SAaron LI newlist[i + 1] = NULL;
2488d36e1dfSRoy Marples *array = newlist;
2497827cba2SAaron LI return newlist[i];
2507827cba2SAaron LI }
2517827cba2SAaron LI
2528d36e1dfSRoy Marples #define PARSE_STRING 0
2538d36e1dfSRoy Marples #define PARSE_STRING_NULL 1
2548d36e1dfSRoy Marples #define PARSE_HWADDR 2
2558d36e1dfSRoy Marples #define parse_string(a, b, c) parse_str((a), (b), (c), PARSE_STRING)
2566e63cc1fSRoy Marples #define parse_nstring(a, b, c) parse_str((a), (b), (c), PARSE_STRING_NULL)
2578d36e1dfSRoy Marples #define parse_hwaddr(a, b, c) parse_str((a), (b), (c), PARSE_HWADDR)
2587827cba2SAaron LI static ssize_t
parse_str(char * sbuf,size_t slen,const char * str,int flags)2598d36e1dfSRoy Marples parse_str(char *sbuf, size_t slen, const char *str, int flags)
2607827cba2SAaron LI {
2617827cba2SAaron LI size_t l;
2628d36e1dfSRoy Marples const char *p, *end;
2638d36e1dfSRoy Marples int i;
2647827cba2SAaron LI char c[4], cmd;
2657827cba2SAaron LI
2668d36e1dfSRoy Marples end = str + strlen(str);
2677827cba2SAaron LI /* If surrounded by quotes then it's a string */
2687827cba2SAaron LI if (*str == '"') {
2698d36e1dfSRoy Marples p = end - 1;
2708d36e1dfSRoy Marples if (*p == '"') {
2717827cba2SAaron LI str++;
2728d36e1dfSRoy Marples end = p;
2738d36e1dfSRoy Marples }
2747827cba2SAaron LI } else {
2757827cba2SAaron LI l = (size_t)hwaddr_aton(NULL, str);
27680aa9461SRoy Marples if (l > 0) {
27780aa9461SRoy Marples if ((ssize_t)l == -1) {
27880aa9461SRoy Marples errno = ENOBUFS;
27980aa9461SRoy Marples return -1;
28080aa9461SRoy Marples }
28180aa9461SRoy Marples if (sbuf == NULL)
28280aa9461SRoy Marples return (ssize_t)l;
2837827cba2SAaron LI if (l > slen) {
2847827cba2SAaron LI errno = ENOBUFS;
2857827cba2SAaron LI return -1;
2867827cba2SAaron LI }
2877827cba2SAaron LI hwaddr_aton((uint8_t *)sbuf, str);
2887827cba2SAaron LI return (ssize_t)l;
2897827cba2SAaron LI }
2907827cba2SAaron LI }
2917827cba2SAaron LI
2927827cba2SAaron LI /* Process escapes */
2937827cba2SAaron LI l = 0;
2947827cba2SAaron LI /* If processing a string on the clientid, first byte should be
2957827cba2SAaron LI * 0 to indicate a non hardware type */
2968d36e1dfSRoy Marples if (flags == PARSE_HWADDR && *str) {
2977827cba2SAaron LI if (sbuf)
2987827cba2SAaron LI *sbuf++ = 0;
2997827cba2SAaron LI l++;
3007827cba2SAaron LI }
3017827cba2SAaron LI c[3] = '\0';
3028d36e1dfSRoy Marples while (str < end) {
3037827cba2SAaron LI if (++l > slen && sbuf) {
3047827cba2SAaron LI errno = ENOBUFS;
3057827cba2SAaron LI return -1;
3067827cba2SAaron LI }
3077827cba2SAaron LI if (*str == '\\') {
3087827cba2SAaron LI str++;
3097827cba2SAaron LI switch((cmd = *str++)) {
3107827cba2SAaron LI case '\0':
3117827cba2SAaron LI str--;
3127827cba2SAaron LI break;
3137827cba2SAaron LI case 'b':
3147827cba2SAaron LI if (sbuf)
3157827cba2SAaron LI *sbuf++ = '\b';
3167827cba2SAaron LI break;
3177827cba2SAaron LI case 'n':
3187827cba2SAaron LI if (sbuf)
3197827cba2SAaron LI *sbuf++ = '\n';
3207827cba2SAaron LI break;
3217827cba2SAaron LI case 'r':
3227827cba2SAaron LI if (sbuf)
3237827cba2SAaron LI *sbuf++ = '\r';
3247827cba2SAaron LI break;
3257827cba2SAaron LI case 't':
3267827cba2SAaron LI if (sbuf)
3277827cba2SAaron LI *sbuf++ = '\t';
3287827cba2SAaron LI break;
3297827cba2SAaron LI case 'x':
3307827cba2SAaron LI /* Grab a hex code */
3317827cba2SAaron LI c[1] = '\0';
3327827cba2SAaron LI for (i = 0; i < 2; i++) {
3337827cba2SAaron LI if (isxdigit((unsigned char)*str) == 0)
3347827cba2SAaron LI break;
3357827cba2SAaron LI c[i] = *str++;
3367827cba2SAaron LI }
3370a68f8d2SRoy Marples if (c[1] != '\0') {
3387827cba2SAaron LI c[2] = '\0';
3390a68f8d2SRoy Marples if (sbuf)
3407827cba2SAaron LI *sbuf++ = (char)strtol(c, NULL, 16);
3417827cba2SAaron LI } else
3427827cba2SAaron LI l--;
3437827cba2SAaron LI break;
3447827cba2SAaron LI case '0':
3457827cba2SAaron LI /* Grab an octal code */
3467827cba2SAaron LI c[2] = '\0';
3477827cba2SAaron LI for (i = 0; i < 3; i++) {
3487827cba2SAaron LI if (*str < '0' || *str > '7')
3497827cba2SAaron LI break;
3507827cba2SAaron LI c[i] = *str++;
3517827cba2SAaron LI }
3520a68f8d2SRoy Marples if (c[2] != '\0') {
3537827cba2SAaron LI i = (int)strtol(c, NULL, 8);
3547827cba2SAaron LI if (i > 255)
3557827cba2SAaron LI i = 255;
3560a68f8d2SRoy Marples if (sbuf)
3577827cba2SAaron LI *sbuf++ = (char)i;
3587827cba2SAaron LI } else
3597827cba2SAaron LI l--;
3607827cba2SAaron LI break;
3617827cba2SAaron LI default:
3627827cba2SAaron LI if (sbuf)
3637827cba2SAaron LI *sbuf++ = cmd;
3647827cba2SAaron LI break;
3657827cba2SAaron LI }
3667827cba2SAaron LI } else {
3677827cba2SAaron LI if (sbuf)
3687827cba2SAaron LI *sbuf++ = *str;
3697827cba2SAaron LI str++;
3707827cba2SAaron LI }
3717827cba2SAaron LI }
372e0bc1ec6SRoy Marples if (flags == PARSE_STRING_NULL) {
373e0bc1ec6SRoy Marples l++;
374e0bc1ec6SRoy Marples if (sbuf != NULL) {
375e0bc1ec6SRoy Marples if (l > slen) {
376e0bc1ec6SRoy Marples errno = ENOBUFS;
377e0bc1ec6SRoy Marples return -1;
378e0bc1ec6SRoy Marples }
3798d36e1dfSRoy Marples *sbuf = '\0';
380e0bc1ec6SRoy Marples }
381e0bc1ec6SRoy Marples }
3827827cba2SAaron LI return (ssize_t)l;
3837827cba2SAaron LI }
3847827cba2SAaron LI
3857827cba2SAaron LI static int
parse_iaid1(uint8_t * iaid,const char * arg,size_t len,int n)3867827cba2SAaron LI parse_iaid1(uint8_t *iaid, const char *arg, size_t len, int n)
3877827cba2SAaron LI {
3887827cba2SAaron LI int e;
3897827cba2SAaron LI uint32_t narg;
3907827cba2SAaron LI ssize_t s;
3917827cba2SAaron LI
3927827cba2SAaron LI narg = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
3937827cba2SAaron LI if (e == 0) {
3947827cba2SAaron LI if (n)
3957827cba2SAaron LI narg = htonl(narg);
3967827cba2SAaron LI memcpy(iaid, &narg, sizeof(narg));
3977827cba2SAaron LI return 0;
3987827cba2SAaron LI }
3997827cba2SAaron LI
4007827cba2SAaron LI if ((s = parse_string((char *)iaid, len, arg)) < 1)
4017827cba2SAaron LI return -1;
4027827cba2SAaron LI if (s < 4)
4037827cba2SAaron LI iaid[3] = '\0';
4047827cba2SAaron LI if (s < 3)
4057827cba2SAaron LI iaid[2] = '\0';
4067827cba2SAaron LI if (s < 2)
4077827cba2SAaron LI iaid[1] = '\0';
4087827cba2SAaron LI return 0;
4097827cba2SAaron LI }
4107827cba2SAaron LI
4117827cba2SAaron LI static int
parse_iaid(uint8_t * iaid,const char * arg,size_t len)4127827cba2SAaron LI parse_iaid(uint8_t *iaid, const char *arg, size_t len)
4137827cba2SAaron LI {
4147827cba2SAaron LI
4157827cba2SAaron LI return parse_iaid1(iaid, arg, len, 1);
4167827cba2SAaron LI }
4177827cba2SAaron LI
4187827cba2SAaron LI #ifdef AUTH
4197827cba2SAaron LI static int
parse_uint32(uint32_t * i,const char * arg)4207827cba2SAaron LI parse_uint32(uint32_t *i, const char *arg)
4217827cba2SAaron LI {
4227827cba2SAaron LI
4237827cba2SAaron LI return parse_iaid1((uint8_t *)i, arg, sizeof(uint32_t), 0);
4247827cba2SAaron LI }
4257827cba2SAaron LI #endif
4267827cba2SAaron LI
4277827cba2SAaron LI static char **
splitv(int * argc,char ** argv,const char * arg)4287827cba2SAaron LI splitv(int *argc, char **argv, const char *arg)
4297827cba2SAaron LI {
4307827cba2SAaron LI char **n, **v = argv;
4317827cba2SAaron LI char *o = strdup(arg), *p, *t, *nt;
4327827cba2SAaron LI
4337827cba2SAaron LI if (o == NULL) {
4347827cba2SAaron LI logerr(__func__);
4357827cba2SAaron LI return v;
4367827cba2SAaron LI }
4377827cba2SAaron LI p = o;
4387827cba2SAaron LI while ((t = strsep(&p, ", "))) {
4397827cba2SAaron LI nt = strdup(t);
4407827cba2SAaron LI if (nt == NULL) {
4417827cba2SAaron LI logerr(__func__);
4427827cba2SAaron LI free(o);
4437827cba2SAaron LI return v;
4447827cba2SAaron LI }
4457827cba2SAaron LI n = reallocarray(v, (size_t)(*argc) + 1, sizeof(char *));
4467827cba2SAaron LI if (n == NULL) {
4477827cba2SAaron LI logerr(__func__);
4487827cba2SAaron LI free(o);
4497827cba2SAaron LI free(nt);
4507827cba2SAaron LI return v;
4517827cba2SAaron LI }
4527827cba2SAaron LI v = n;
4537827cba2SAaron LI v[(*argc)++] = nt;
4547827cba2SAaron LI }
4557827cba2SAaron LI free(o);
4567827cba2SAaron LI return v;
4577827cba2SAaron LI }
4587827cba2SAaron LI
4597827cba2SAaron LI #ifdef INET
4607827cba2SAaron LI static int
parse_addr(struct in_addr * addr,struct in_addr * net,const char * arg)4617827cba2SAaron LI parse_addr(struct in_addr *addr, struct in_addr *net, const char *arg)
4627827cba2SAaron LI {
4637827cba2SAaron LI char *p;
4647827cba2SAaron LI
4657827cba2SAaron LI if (arg == NULL || *arg == '\0') {
4667827cba2SAaron LI if (addr != NULL)
4677827cba2SAaron LI addr->s_addr = 0;
4687827cba2SAaron LI if (net != NULL)
4697827cba2SAaron LI net->s_addr = 0;
4707827cba2SAaron LI return 0;
4717827cba2SAaron LI }
4727827cba2SAaron LI if ((p = strchr(arg, '/')) != NULL) {
4737827cba2SAaron LI int e;
4747827cba2SAaron LI intmax_t i;
4757827cba2SAaron LI
4767827cba2SAaron LI *p++ = '\0';
4777827cba2SAaron LI i = strtoi(p, NULL, 10, 0, 32, &e);
4787827cba2SAaron LI if (e != 0 ||
4797827cba2SAaron LI (net != NULL && inet_cidrtoaddr((int)i, net) != 0))
4807827cba2SAaron LI {
481a0d9933aSRoy Marples logerrx("invalid CIDR: %s", p);
4827827cba2SAaron LI return -1;
4837827cba2SAaron LI }
4847827cba2SAaron LI }
4857827cba2SAaron LI
4867827cba2SAaron LI if (addr != NULL && inet_aton(arg, addr) == 0) {
487a0d9933aSRoy Marples logerrx("invalid IP address: %s", arg);
4887827cba2SAaron LI return -1;
4897827cba2SAaron LI }
4907827cba2SAaron LI if (p != NULL)
4917827cba2SAaron LI *--p = '/';
4927827cba2SAaron LI else if (net != NULL && addr != NULL)
4937827cba2SAaron LI net->s_addr = ipv4_getnetmask(addr->s_addr);
4947827cba2SAaron LI return 0;
4957827cba2SAaron LI }
4967827cba2SAaron LI #else
4977827cba2SAaron LI static int
parse_addr(__unused struct in_addr * addr,__unused struct in_addr * net,__unused const char * arg)4987827cba2SAaron LI parse_addr(__unused struct in_addr *addr, __unused struct in_addr *net,
4997827cba2SAaron LI __unused const char *arg)
5007827cba2SAaron LI {
5017827cba2SAaron LI
5027827cba2SAaron LI logerrx("No IPv4 support");
5037827cba2SAaron LI return -1;
5047827cba2SAaron LI }
5057827cba2SAaron LI #endif
5067827cba2SAaron LI
5071b3b16a2SRoy Marples static void
set_option_space(struct dhcpcd_ctx * ctx,const char * arg,const struct dhcp_opt ** d,size_t * dl,const struct dhcp_opt ** od,size_t * odl,struct if_options * ifo,uint8_t * request[],uint8_t * require[],uint8_t * no[],uint8_t * reject[])5087827cba2SAaron LI set_option_space(struct dhcpcd_ctx *ctx,
5097827cba2SAaron LI const char *arg,
5107827cba2SAaron LI const struct dhcp_opt **d, size_t *dl,
5117827cba2SAaron LI const struct dhcp_opt **od, size_t *odl,
5127827cba2SAaron LI struct if_options *ifo,
5137827cba2SAaron LI uint8_t *request[], uint8_t *require[], uint8_t *no[], uint8_t *reject[])
5147827cba2SAaron LI {
5157827cba2SAaron LI
5167827cba2SAaron LI #if !defined(INET) && !defined(INET6)
5177827cba2SAaron LI UNUSED(ctx);
5187827cba2SAaron LI #endif
5197827cba2SAaron LI
5207827cba2SAaron LI #ifdef INET6
5217827cba2SAaron LI if (strncmp(arg, "nd_", strlen("nd_")) == 0) {
5227827cba2SAaron LI *d = ctx->nd_opts;
5237827cba2SAaron LI *dl = ctx->nd_opts_len;
5247827cba2SAaron LI *od = ifo->nd_override;
5257827cba2SAaron LI *odl = ifo->nd_override_len;
5267827cba2SAaron LI *request = ifo->requestmasknd;
5277827cba2SAaron LI *require = ifo->requiremasknd;
5287827cba2SAaron LI *no = ifo->nomasknd;
5297827cba2SAaron LI *reject = ifo->rejectmasknd;
5301b3b16a2SRoy Marples return;
5317827cba2SAaron LI }
5327827cba2SAaron LI
5338d36e1dfSRoy Marples #ifdef DHCP6
5347827cba2SAaron LI if (strncmp(arg, "dhcp6_", strlen("dhcp6_")) == 0) {
5357827cba2SAaron LI *d = ctx->dhcp6_opts;
5367827cba2SAaron LI *dl = ctx->dhcp6_opts_len;
5377827cba2SAaron LI *od = ifo->dhcp6_override;
5387827cba2SAaron LI *odl = ifo->dhcp6_override_len;
5397827cba2SAaron LI *request = ifo->requestmask6;
5407827cba2SAaron LI *require = ifo->requiremask6;
5417827cba2SAaron LI *no = ifo->nomask6;
5427827cba2SAaron LI *reject = ifo->rejectmask6;
5431b3b16a2SRoy Marples return;
5447827cba2SAaron LI }
5457827cba2SAaron LI #endif
546280986e4SRoy Marples #else
547280986e4SRoy Marples UNUSED(arg);
5488d36e1dfSRoy Marples #endif
5497827cba2SAaron LI
5507827cba2SAaron LI #ifdef INET
5517827cba2SAaron LI *d = ctx->dhcp_opts;
5527827cba2SAaron LI *dl = ctx->dhcp_opts_len;
5537827cba2SAaron LI *od = ifo->dhcp_override;
5547827cba2SAaron LI *odl = ifo->dhcp_override_len;
5557827cba2SAaron LI #else
5567827cba2SAaron LI *d = NULL;
5577827cba2SAaron LI *dl = 0;
5587827cba2SAaron LI *od = NULL;
5597827cba2SAaron LI *odl = 0;
5607827cba2SAaron LI #endif
5617827cba2SAaron LI *request = ifo->requestmask;
5627827cba2SAaron LI *require = ifo->requiremask;
5637827cba2SAaron LI *no = ifo->nomask;
5647827cba2SAaron LI *reject = ifo->rejectmask;
5657827cba2SAaron LI }
5667827cba2SAaron LI
5677827cba2SAaron LI void
free_dhcp_opt_embenc(struct dhcp_opt * opt)5687827cba2SAaron LI free_dhcp_opt_embenc(struct dhcp_opt *opt)
5697827cba2SAaron LI {
5707827cba2SAaron LI size_t i;
5717827cba2SAaron LI struct dhcp_opt *o;
5727827cba2SAaron LI
5737827cba2SAaron LI free(opt->var);
5747827cba2SAaron LI
5757827cba2SAaron LI for (i = 0, o = opt->embopts; i < opt->embopts_len; i++, o++)
5767827cba2SAaron LI free_dhcp_opt_embenc(o);
5777827cba2SAaron LI free(opt->embopts);
5787827cba2SAaron LI opt->embopts_len = 0;
5797827cba2SAaron LI opt->embopts = NULL;
5807827cba2SAaron LI
5817827cba2SAaron LI for (i = 0, o = opt->encopts; i < opt->encopts_len; i++, o++)
5827827cba2SAaron LI free_dhcp_opt_embenc(o);
5837827cba2SAaron LI free(opt->encopts);
5847827cba2SAaron LI opt->encopts_len = 0;
5857827cba2SAaron LI opt->encopts = NULL;
5867827cba2SAaron LI }
5877827cba2SAaron LI
5887827cba2SAaron LI static char *
strwhite(const char * s)5897827cba2SAaron LI strwhite(const char *s)
5907827cba2SAaron LI {
5917827cba2SAaron LI
5927827cba2SAaron LI if (s == NULL)
5937827cba2SAaron LI return NULL;
5947827cba2SAaron LI while (*s != ' ' && *s != '\t') {
5957827cba2SAaron LI if (*s == '\0')
5967827cba2SAaron LI return NULL;
5977827cba2SAaron LI s++;
5987827cba2SAaron LI }
5997827cba2SAaron LI return UNCONST(s);
6007827cba2SAaron LI }
6017827cba2SAaron LI
6027827cba2SAaron LI static char *
strskipwhite(const char * s)6037827cba2SAaron LI strskipwhite(const char *s)
6047827cba2SAaron LI {
6057827cba2SAaron LI
6067827cba2SAaron LI if (s == NULL || *s == '\0')
6077827cba2SAaron LI return NULL;
6087827cba2SAaron LI while (*s == ' ' || *s == '\t') {
6097827cba2SAaron LI s++;
6107827cba2SAaron LI if (*s == '\0')
6117827cba2SAaron LI return NULL;
6127827cba2SAaron LI }
6137827cba2SAaron LI return UNCONST(s);
6147827cba2SAaron LI }
6157827cba2SAaron LI
6167827cba2SAaron LI #ifdef AUTH
6177827cba2SAaron LI /* Find the end pointer of a string. */
6187827cba2SAaron LI static char *
strend(const char * s)6197827cba2SAaron LI strend(const char *s)
6207827cba2SAaron LI {
6217827cba2SAaron LI
6227827cba2SAaron LI s = strskipwhite(s);
6237827cba2SAaron LI if (s == NULL)
6247827cba2SAaron LI return NULL;
6257827cba2SAaron LI if (*s != '"')
6267827cba2SAaron LI return strchr(s, ' ');
6277827cba2SAaron LI s++;
6287827cba2SAaron LI for (; *s != '"' ; s++) {
6297827cba2SAaron LI if (*s == '\0')
6307827cba2SAaron LI return NULL;
6317827cba2SAaron LI if (*s == '\\') {
6327827cba2SAaron LI if (*(++s) == '\0')
6337827cba2SAaron LI return NULL;
6347827cba2SAaron LI }
6357827cba2SAaron LI }
6367827cba2SAaron LI return UNCONST(++s);
6377827cba2SAaron LI }
6387827cba2SAaron LI #endif
6397827cba2SAaron LI
6407827cba2SAaron LI static int
parse_option(struct dhcpcd_ctx * ctx,const char * ifname,struct if_options * ifo,int opt,const char * arg,struct dhcp_opt ** ldop,struct dhcp_opt ** edop)6417827cba2SAaron LI parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
6427827cba2SAaron LI int opt, const char *arg, struct dhcp_opt **ldop, struct dhcp_opt **edop)
6437827cba2SAaron LI {
6447827cba2SAaron LI int e, i, t;
6457827cba2SAaron LI long l;
6467827cba2SAaron LI unsigned long u;
6478d36e1dfSRoy Marples char *p = NULL, *bp, *fp, *np;
6487827cba2SAaron LI ssize_t s;
6497827cba2SAaron LI struct in_addr addr, addr2;
6507827cba2SAaron LI in_addr_t *naddr;
6517827cba2SAaron LI struct rt *rt;
6527827cba2SAaron LI const struct dhcp_opt *d, *od;
6537827cba2SAaron LI uint8_t *request, *require, *no, *reject;
6547827cba2SAaron LI struct dhcp_opt **dop, *ndop;
6557827cba2SAaron LI size_t *dop_len, dl, odl;
6567827cba2SAaron LI struct vivco *vivco;
6577827cba2SAaron LI struct group *grp;
6587827cba2SAaron LI #ifdef AUTH
6597827cba2SAaron LI struct token *token;
6607827cba2SAaron LI #endif
6617827cba2SAaron LI #ifdef _REENTRANT
6627827cba2SAaron LI struct group grpbuf;
6637827cba2SAaron LI #endif
6647827cba2SAaron LI #ifdef DHCP6
6657827cba2SAaron LI size_t sl;
6667827cba2SAaron LI struct if_ia *ia;
6677827cba2SAaron LI uint8_t iaid[4];
6687827cba2SAaron LI #ifndef SMALL
6697827cba2SAaron LI struct if_sla *sla, *slap;
6707827cba2SAaron LI #endif
6717827cba2SAaron LI #endif
6727827cba2SAaron LI
6737827cba2SAaron LI dop = NULL;
6747827cba2SAaron LI dop_len = NULL;
6757827cba2SAaron LI #ifdef INET6
6767827cba2SAaron LI i = 0;
6777827cba2SAaron LI #endif
6787827cba2SAaron LI
6797827cba2SAaron LI /* Add a guard for static analysers.
6807827cba2SAaron LI * This should not be needed really because of the argument_required option
6817827cba2SAaron LI * in the options declaration above. */
6827827cba2SAaron LI #define ARG_REQUIRED if (arg == NULL) goto arg_required
6837827cba2SAaron LI
6847827cba2SAaron LI switch(opt) {
6857827cba2SAaron LI case 'f': /* FALLTHROUGH */
6867827cba2SAaron LI case 'g': /* FALLTHROUGH */
6877827cba2SAaron LI case 'n': /* FALLTHROUGH */
6887827cba2SAaron LI case 'q': /* FALLTHROUGH */
6897827cba2SAaron LI case 'x': /* FALLTHROUGH */
6907827cba2SAaron LI case 'N': /* FALLTHROUGH */
6917827cba2SAaron LI case 'P': /* FALLTHROUGH */
6927827cba2SAaron LI case 'T': /* FALLTHROUGH */
6937827cba2SAaron LI case 'U': /* FALLTHROUGH */
6947827cba2SAaron LI case 'V': /* We need to handle non interface options */
6957827cba2SAaron LI break;
6967827cba2SAaron LI case 'b':
6977827cba2SAaron LI ifo->options |= DHCPCD_BACKGROUND;
6987827cba2SAaron LI break;
6997827cba2SAaron LI case 'c':
7007827cba2SAaron LI ARG_REQUIRED;
701cc34ba0cSRoy Marples if (IN_CONFIG_BLOCK(ifo)) {
702d4fb1e02SRoy Marples logerrx("%s: per interface scripts"
703d4fb1e02SRoy Marples " are no longer supported",
704d4fb1e02SRoy Marples ifname);
705d4fb1e02SRoy Marples return -1;
706d4fb1e02SRoy Marples }
707d4fb1e02SRoy Marples if (ctx->script != dhcpcd_default_script)
708d4fb1e02SRoy Marples free(ctx->script);
7096e63cc1fSRoy Marples s = parse_nstring(NULL, 0, arg);
7108d36e1dfSRoy Marples if (s == 0) {
711d4fb1e02SRoy Marples ctx->script = NULL;
7128d36e1dfSRoy Marples break;
7138d36e1dfSRoy Marples }
7148d36e1dfSRoy Marples dl = (size_t)s;
715d4fb1e02SRoy Marples if (s == -1 || (ctx->script = malloc(dl)) == NULL) {
716d4fb1e02SRoy Marples ctx->script = NULL;
7177827cba2SAaron LI logerr(__func__);
7188d36e1dfSRoy Marples return -1;
7198d36e1dfSRoy Marples }
720d4fb1e02SRoy Marples s = parse_nstring(ctx->script, dl, arg);
7218d36e1dfSRoy Marples if (s == -1 ||
722d4fb1e02SRoy Marples ctx->script[0] == '\0' ||
723d4fb1e02SRoy Marples strcmp(ctx->script, "/dev/null") == 0)
7248d36e1dfSRoy Marples {
725d4fb1e02SRoy Marples free(ctx->script);
726d4fb1e02SRoy Marples ctx->script = NULL;
7278d36e1dfSRoy Marples }
7287827cba2SAaron LI break;
7297827cba2SAaron LI case 'd':
7307827cba2SAaron LI ifo->options |= DHCPCD_DEBUG;
7317827cba2SAaron LI break;
7327827cba2SAaron LI case 'e':
7337827cba2SAaron LI ARG_REQUIRED;
7348d36e1dfSRoy Marples add_environ(&ifo->environ, arg, 1);
7357827cba2SAaron LI break;
7367827cba2SAaron LI case 'h':
7377827cba2SAaron LI if (!arg) {
7387827cba2SAaron LI ifo->options |= DHCPCD_HOSTNAME;
7397827cba2SAaron LI break;
7407827cba2SAaron LI }
7416e63cc1fSRoy Marples s = parse_nstring(ifo->hostname, sizeof(ifo->hostname), arg);
7427827cba2SAaron LI if (s == -1) {
7437827cba2SAaron LI logerr("%s: hostname", __func__);
7447827cba2SAaron LI return -1;
7457827cba2SAaron LI }
7467827cba2SAaron LI if (s != 0 && ifo->hostname[0] == '.') {
7477827cba2SAaron LI logerrx("hostname cannot begin with .");
7487827cba2SAaron LI return -1;
7497827cba2SAaron LI }
7507827cba2SAaron LI if (ifo->hostname[0] == '\0')
7517827cba2SAaron LI ifo->options &= ~DHCPCD_HOSTNAME;
7527827cba2SAaron LI else
7537827cba2SAaron LI ifo->options |= DHCPCD_HOSTNAME;
7547827cba2SAaron LI break;
7557827cba2SAaron LI case 'i':
7567827cba2SAaron LI if (arg)
7577827cba2SAaron LI s = parse_string((char *)ifo->vendorclassid + 1,
7587827cba2SAaron LI VENDORCLASSID_MAX_LEN, arg);
7597827cba2SAaron LI else
7607827cba2SAaron LI s = 0;
7617827cba2SAaron LI if (s == -1) {
7627827cba2SAaron LI logerr("vendorclassid");
7637827cba2SAaron LI return -1;
7647827cba2SAaron LI }
7657827cba2SAaron LI *ifo->vendorclassid = (uint8_t)s;
7667827cba2SAaron LI break;
7677827cba2SAaron LI case 'j':
7687827cba2SAaron LI ARG_REQUIRED;
7697827cba2SAaron LI /* per interface logging is not supported
7707827cba2SAaron LI * don't want to overide the commandline */
771cc34ba0cSRoy Marples if (!IN_CONFIG_BLOCK(ifo) && ctx->logfile == NULL) {
7727827cba2SAaron LI logclose();
7737827cba2SAaron LI ctx->logfile = strdup(arg);
7747827cba2SAaron LI logopen(ctx->logfile);
7757827cba2SAaron LI }
7767827cba2SAaron LI break;
7777827cba2SAaron LI case 'k':
7787827cba2SAaron LI ifo->options |= DHCPCD_RELEASE;
7797827cba2SAaron LI break;
7807827cba2SAaron LI case 'l':
7817827cba2SAaron LI ARG_REQUIRED;
782b8b69544SRoy Marples if (strcmp(arg, "-1") == 0) {
783b8b69544SRoy Marples ifo->leasetime = DHCP_INFINITE_LIFETIME;
784b8b69544SRoy Marples break;
785b8b69544SRoy Marples }
7867827cba2SAaron LI ifo->leasetime = (uint32_t)strtou(arg, NULL,
7877827cba2SAaron LI 0, 0, UINT32_MAX, &e);
7887827cba2SAaron LI if (e) {
7897827cba2SAaron LI logerrx("failed to convert leasetime %s", arg);
7907827cba2SAaron LI return -1;
7917827cba2SAaron LI }
7927827cba2SAaron LI break;
7937827cba2SAaron LI case 'm':
7947827cba2SAaron LI ARG_REQUIRED;
7957827cba2SAaron LI ifo->metric = (int)strtoi(arg, NULL, 0, 0, INT32_MAX, &e);
7967827cba2SAaron LI if (e) {
7977827cba2SAaron LI logerrx("failed to convert metric %s", arg);
7987827cba2SAaron LI return -1;
7997827cba2SAaron LI }
8007827cba2SAaron LI break;
8017827cba2SAaron LI case 'o':
8027827cba2SAaron LI ARG_REQUIRED;
803b2927f2bSRoy Marples if (ctx->options & DHCPCD_PRINT_PIDFILE)
804b2927f2bSRoy Marples break;
8051b3b16a2SRoy Marples set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
8067827cba2SAaron LI &request, &require, &no, &reject);
8077827cba2SAaron LI if (make_option_mask(d, dl, od, odl, request, arg, 1) != 0 ||
8087827cba2SAaron LI make_option_mask(d, dl, od, odl, no, arg, -1) != 0 ||
8097827cba2SAaron LI make_option_mask(d, dl, od, odl, reject, arg, -1) != 0)
8107827cba2SAaron LI {
811a0d9933aSRoy Marples logerrx("unknown option: %s", arg);
8127827cba2SAaron LI return -1;
8137827cba2SAaron LI }
8147827cba2SAaron LI break;
8157827cba2SAaron LI case O_REJECT:
8167827cba2SAaron LI ARG_REQUIRED;
817b2927f2bSRoy Marples if (ctx->options & DHCPCD_PRINT_PIDFILE)
818b2927f2bSRoy Marples break;
8191b3b16a2SRoy Marples set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
8207827cba2SAaron LI &request, &require, &no, &reject);
8217827cba2SAaron LI if (make_option_mask(d, dl, od, odl, reject, arg, 1) != 0 ||
8227827cba2SAaron LI make_option_mask(d, dl, od, odl, request, arg, -1) != 0 ||
8237827cba2SAaron LI make_option_mask(d, dl, od, odl, require, arg, -1) != 0)
8247827cba2SAaron LI {
825a0d9933aSRoy Marples logerrx("unknown option: %s", arg);
8267827cba2SAaron LI return -1;
8277827cba2SAaron LI }
8287827cba2SAaron LI break;
8297827cba2SAaron LI case 'p':
8307827cba2SAaron LI ifo->options |= DHCPCD_PERSISTENT;
8317827cba2SAaron LI break;
8327827cba2SAaron LI case 'r':
8337827cba2SAaron LI if (parse_addr(&ifo->req_addr, NULL, arg) != 0)
8347827cba2SAaron LI return -1;
8357827cba2SAaron LI ifo->options |= DHCPCD_REQUEST;
8367827cba2SAaron LI ifo->req_mask.s_addr = 0;
8377827cba2SAaron LI break;
8387827cba2SAaron LI case 's':
8397827cba2SAaron LI if (arg && *arg != '\0') {
8407827cba2SAaron LI /* Strip out a broadcast address */
8417827cba2SAaron LI p = strchr(arg, '/');
8427827cba2SAaron LI if (p != NULL) {
8437827cba2SAaron LI p = strchr(p + 1, '/');
8447827cba2SAaron LI if (p != NULL)
8457827cba2SAaron LI *p = '\0';
8467827cba2SAaron LI }
8477827cba2SAaron LI i = parse_addr(&ifo->req_addr, &ifo->req_mask, arg);
8487827cba2SAaron LI if (p != NULL) {
8497827cba2SAaron LI /* Ensure the original string is preserved */
8507827cba2SAaron LI *p++ = '/';
8517827cba2SAaron LI if (i == 0)
8527827cba2SAaron LI i = parse_addr(&ifo->req_brd, NULL, p);
8537827cba2SAaron LI }
8547827cba2SAaron LI if (i != 0)
8557827cba2SAaron LI return -1;
8567827cba2SAaron LI } else {
8577827cba2SAaron LI ifo->req_addr.s_addr = 0;
8587827cba2SAaron LI ifo->req_mask.s_addr = 0;
8597827cba2SAaron LI }
8607827cba2SAaron LI ifo->options |= DHCPCD_INFORM | DHCPCD_PERSISTENT;
8617827cba2SAaron LI ifo->options &= ~DHCPCD_STATIC;
8627827cba2SAaron LI break;
8637827cba2SAaron LI case O_INFORM6:
8647827cba2SAaron LI ifo->options |= DHCPCD_INFORM6;
8657827cba2SAaron LI break;
8667827cba2SAaron LI case 't':
8677827cba2SAaron LI ARG_REQUIRED;
8686e63cc1fSRoy Marples ifo->timeout = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
8697827cba2SAaron LI if (e) {
8707827cba2SAaron LI logerrx("failed to convert timeout %s", arg);
8717827cba2SAaron LI return -1;
8727827cba2SAaron LI }
8737827cba2SAaron LI break;
8747827cba2SAaron LI case 'u':
8756e63cc1fSRoy Marples dl = sizeof(ifo->userclass) - ifo->userclass[0] - 1;
8767827cba2SAaron LI s = parse_string((char *)ifo->userclass +
8776e63cc1fSRoy Marples ifo->userclass[0] + 2, dl, arg);
8787827cba2SAaron LI if (s == -1) {
8797827cba2SAaron LI logerr("userclass");
8807827cba2SAaron LI return -1;
8817827cba2SAaron LI }
8827827cba2SAaron LI if (s != 0) {
8837827cba2SAaron LI ifo->userclass[ifo->userclass[0] + 1] = (uint8_t)s;
8847827cba2SAaron LI ifo->userclass[0] = (uint8_t)(ifo->userclass[0] + s +1);
8857827cba2SAaron LI }
8867827cba2SAaron LI break;
8876e63cc1fSRoy Marples #ifndef SMALL
8886e63cc1fSRoy Marples case O_MSUSERCLASS:
8896e63cc1fSRoy Marples /* Some Microsoft DHCP servers expect userclass to be an
8906e63cc1fSRoy Marples * opaque blob. This is not RFC 3004 compliant. */
8916e63cc1fSRoy Marples s = parse_string((char *)ifo->userclass + 1,
8926e63cc1fSRoy Marples sizeof(ifo->userclass) - 1, arg);
8936e63cc1fSRoy Marples if (s == -1) {
8946e63cc1fSRoy Marples logerr("msuserclass");
8956e63cc1fSRoy Marples return -1;
8966e63cc1fSRoy Marples }
8976e63cc1fSRoy Marples ifo->userclass[0] = (uint8_t)s;
8986e63cc1fSRoy Marples break;
8996e63cc1fSRoy Marples #endif
9007827cba2SAaron LI case 'v':
9017827cba2SAaron LI ARG_REQUIRED;
9027827cba2SAaron LI p = strchr(arg, ',');
9037827cba2SAaron LI if (!p || !p[1]) {
9047827cba2SAaron LI logerrx("invalid vendor format: %s", arg);
9057827cba2SAaron LI return -1;
9067827cba2SAaron LI }
9077827cba2SAaron LI
9087827cba2SAaron LI /* If vendor starts with , then it is not encapsulated */
9097827cba2SAaron LI if (p == arg) {
9107827cba2SAaron LI arg++;
9117827cba2SAaron LI s = parse_string((char *)ifo->vendor + 1,
9127827cba2SAaron LI VENDOR_MAX_LEN, arg);
9137827cba2SAaron LI if (s == -1) {
9147827cba2SAaron LI logerr("vendor");
9157827cba2SAaron LI return -1;
9167827cba2SAaron LI }
9177827cba2SAaron LI ifo->vendor[0] = (uint8_t)s;
9187827cba2SAaron LI ifo->options |= DHCPCD_VENDORRAW;
9197827cba2SAaron LI break;
9207827cba2SAaron LI }
9217827cba2SAaron LI
9227827cba2SAaron LI /* Encapsulated vendor options */
9237827cba2SAaron LI if (ifo->options & DHCPCD_VENDORRAW) {
9247827cba2SAaron LI ifo->options &= ~DHCPCD_VENDORRAW;
9257827cba2SAaron LI ifo->vendor[0] = 0;
9267827cba2SAaron LI }
9277827cba2SAaron LI
9287827cba2SAaron LI /* Strip and preserve the comma */
9297827cba2SAaron LI *p = '\0';
9307827cba2SAaron LI i = (int)strtoi(arg, NULL, 0, 1, 254, &e);
9317827cba2SAaron LI *p = ',';
9327827cba2SAaron LI if (e) {
9337827cba2SAaron LI logerrx("vendor option should be between"
9347827cba2SAaron LI " 1 and 254 inclusive");
9357827cba2SAaron LI return -1;
9367827cba2SAaron LI }
9377827cba2SAaron LI
9387827cba2SAaron LI arg = p + 1;
9397827cba2SAaron LI s = VENDOR_MAX_LEN - ifo->vendor[0] - 2;
9407827cba2SAaron LI if (inet_aton(arg, &addr) == 1) {
9417827cba2SAaron LI if (s < 6) {
9427827cba2SAaron LI s = -1;
9437827cba2SAaron LI errno = ENOBUFS;
9447827cba2SAaron LI } else {
9457827cba2SAaron LI memcpy(ifo->vendor + ifo->vendor[0] + 3,
9467827cba2SAaron LI &addr.s_addr, sizeof(addr.s_addr));
9477827cba2SAaron LI s = sizeof(addr.s_addr);
9487827cba2SAaron LI }
9497827cba2SAaron LI } else {
9507827cba2SAaron LI s = parse_string((char *)ifo->vendor +
9517827cba2SAaron LI ifo->vendor[0] + 3, (size_t)s, arg);
9527827cba2SAaron LI }
9537827cba2SAaron LI if (s == -1) {
9547827cba2SAaron LI logerr("vendor");
9557827cba2SAaron LI return -1;
9567827cba2SAaron LI }
9577827cba2SAaron LI if (s != 0) {
9587827cba2SAaron LI ifo->vendor[ifo->vendor[0] + 1] = (uint8_t)i;
9597827cba2SAaron LI ifo->vendor[ifo->vendor[0] + 2] = (uint8_t)s;
9607827cba2SAaron LI ifo->vendor[0] = (uint8_t)(ifo->vendor[0] + s + 2);
9617827cba2SAaron LI }
9627827cba2SAaron LI break;
9637827cba2SAaron LI case 'w':
9647827cba2SAaron LI ifo->options |= DHCPCD_WAITIP;
965f3744ac9SRoy Marples p = UNCONST(arg);
966f3744ac9SRoy Marples // Generally it's --waitip=46, but some expect
967f3744ac9SRoy Marples // --waitip="4 6" to work as well.
968f3744ac9SRoy Marples // It's easier to allow it rather than have confusing docs.
969f3744ac9SRoy Marples while (p != NULL && p[0] != '\0') {
970f3744ac9SRoy Marples if (p[0] == '4' || p[1] == '4')
9717827cba2SAaron LI ifo->options |= DHCPCD_WAITIP4;
972f3744ac9SRoy Marples if (p[0] == '6' || p[1] == '6')
9737827cba2SAaron LI ifo->options |= DHCPCD_WAITIP6;
974f3744ac9SRoy Marples p = strskipwhite(++p);
9757827cba2SAaron LI }
9767827cba2SAaron LI break;
9777827cba2SAaron LI case 'y':
9787827cba2SAaron LI ARG_REQUIRED;
9796e63cc1fSRoy Marples ifo->reboot = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
9807827cba2SAaron LI if (e) {
9817827cba2SAaron LI logerr("failed to convert reboot %s", arg);
9827827cba2SAaron LI return -1;
9837827cba2SAaron LI }
9847827cba2SAaron LI break;
9857827cba2SAaron LI case 'z':
9867827cba2SAaron LI ARG_REQUIRED;
987cc34ba0cSRoy Marples if (!IN_CONFIG_BLOCK(ifo))
9887827cba2SAaron LI ctx->ifav = splitv(&ctx->ifac, ctx->ifav, arg);
9897827cba2SAaron LI break;
9907827cba2SAaron LI case 'A':
9917827cba2SAaron LI ifo->options &= ~DHCPCD_ARP;
9927827cba2SAaron LI /* IPv4LL requires ARP */
9937827cba2SAaron LI ifo->options &= ~DHCPCD_IPV4LL;
9947827cba2SAaron LI break;
9957827cba2SAaron LI case 'B':
9967827cba2SAaron LI ifo->options &= ~DHCPCD_DAEMONISE;
9977827cba2SAaron LI break;
9987827cba2SAaron LI case 'C':
9997827cba2SAaron LI ARG_REQUIRED;
10007827cba2SAaron LI /* Commas to spaces for shell */
10017827cba2SAaron LI while ((p = strchr(arg, ',')))
10027827cba2SAaron LI *p = ' ';
10037827cba2SAaron LI dl = strlen("skip_hooks=") + strlen(arg) + 1;
10047827cba2SAaron LI p = malloc(sizeof(char) * dl);
10057827cba2SAaron LI if (p == NULL) {
10067827cba2SAaron LI logerr(__func__);
10077827cba2SAaron LI return -1;
10087827cba2SAaron LI }
10097827cba2SAaron LI snprintf(p, dl, "skip_hooks=%s", arg);
10108d36e1dfSRoy Marples add_environ(&ifo->environ, p, 0);
10117827cba2SAaron LI free(p);
10127827cba2SAaron LI break;
10137827cba2SAaron LI case 'D':
10147827cba2SAaron LI ifo->options |= DHCPCD_CLIENTID | DHCPCD_DUID;
1015a0d9933aSRoy Marples if (ifname != NULL) /* duid type only a global option */
1016a0d9933aSRoy Marples break;
1017a0d9933aSRoy Marples if (arg == NULL)
1018a0d9933aSRoy Marples ctx->duid_type = DUID_DEFAULT;
1019a0d9933aSRoy Marples else if (strcmp(arg, "ll") == 0)
1020a0d9933aSRoy Marples ctx->duid_type = DUID_LL;
1021a0d9933aSRoy Marples else if (strcmp(arg, "llt") == 0)
1022a0d9933aSRoy Marples ctx->duid_type = DUID_LLT;
1023a0d9933aSRoy Marples else if (strcmp(arg, "uuid") == 0)
1024a0d9933aSRoy Marples ctx->duid_type = DUID_UUID;
1025a0d9933aSRoy Marples else {
102620329f2aSRoy Marples dl = hwaddr_aton(NULL, arg);
102720329f2aSRoy Marples if (dl != 0) {
102820329f2aSRoy Marples no = realloc(ctx->duid, dl);
102920329f2aSRoy Marples if (no == NULL)
103020329f2aSRoy Marples logerrx(__func__);
103120329f2aSRoy Marples else {
103220329f2aSRoy Marples ctx->duid = no;
103320329f2aSRoy Marples ctx->duid_len = hwaddr_aton(no, arg);
103420329f2aSRoy Marples }
103520329f2aSRoy Marples }
1036a0d9933aSRoy Marples }
10377827cba2SAaron LI break;
10387827cba2SAaron LI case 'E':
10397827cba2SAaron LI ifo->options |= DHCPCD_LASTLEASE;
10407827cba2SAaron LI break;
10417827cba2SAaron LI case 'F':
10427827cba2SAaron LI if (!arg) {
10437827cba2SAaron LI ifo->fqdn = FQDN_BOTH;
10447827cba2SAaron LI break;
10457827cba2SAaron LI }
10467827cba2SAaron LI if (strcmp(arg, "none") == 0)
10477827cba2SAaron LI ifo->fqdn = FQDN_NONE;
10487827cba2SAaron LI else if (strcmp(arg, "ptr") == 0)
10497827cba2SAaron LI ifo->fqdn = FQDN_PTR;
10507827cba2SAaron LI else if (strcmp(arg, "both") == 0)
10517827cba2SAaron LI ifo->fqdn = FQDN_BOTH;
10527827cba2SAaron LI else if (strcmp(arg, "disable") == 0)
10537827cba2SAaron LI ifo->fqdn = FQDN_DISABLE;
10547827cba2SAaron LI else {
1055a0d9933aSRoy Marples logerrx("invalid FQDN value: %s", arg);
10567827cba2SAaron LI return -1;
10577827cba2SAaron LI }
10587827cba2SAaron LI break;
10597827cba2SAaron LI case 'G':
10607827cba2SAaron LI ifo->options &= ~DHCPCD_GATEWAY;
10617827cba2SAaron LI break;
10627827cba2SAaron LI case 'H':
10637827cba2SAaron LI ifo->options |= DHCPCD_XID_HWADDR;
10647827cba2SAaron LI break;
10657827cba2SAaron LI case 'I':
10667827cba2SAaron LI /* Strings have a type of 0 */;
10677827cba2SAaron LI ifo->clientid[1] = 0;
10687827cba2SAaron LI if (arg)
10698d36e1dfSRoy Marples s = parse_hwaddr((char *)ifo->clientid + 1,
10708d36e1dfSRoy Marples CLIENTID_MAX_LEN, arg);
10717827cba2SAaron LI else
10727827cba2SAaron LI s = 0;
10737827cba2SAaron LI if (s == -1) {
10747827cba2SAaron LI logerr("clientid");
10757827cba2SAaron LI return -1;
10767827cba2SAaron LI }
10777827cba2SAaron LI ifo->options |= DHCPCD_CLIENTID;
10787827cba2SAaron LI ifo->clientid[0] = (uint8_t)s;
1079b8b69544SRoy Marples ifo->options &= ~DHCPCD_DUID;
10807827cba2SAaron LI break;
10817827cba2SAaron LI case 'J':
10827827cba2SAaron LI ifo->options |= DHCPCD_BROADCAST;
10837827cba2SAaron LI break;
10847827cba2SAaron LI case 'K':
10857827cba2SAaron LI ifo->options &= ~DHCPCD_LINK;
10867827cba2SAaron LI break;
10877827cba2SAaron LI case 'L':
10887827cba2SAaron LI ifo->options &= ~DHCPCD_IPV4LL;
10897827cba2SAaron LI break;
10907827cba2SAaron LI case 'M':
10910a68f8d2SRoy Marples ifo->options |= DHCPCD_MANAGER;
10927827cba2SAaron LI break;
10937827cba2SAaron LI case 'O':
10947827cba2SAaron LI ARG_REQUIRED;
1095b2927f2bSRoy Marples if (ctx->options & DHCPCD_PRINT_PIDFILE)
1096b2927f2bSRoy Marples break;
10971b3b16a2SRoy Marples set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
10987827cba2SAaron LI &request, &require, &no, &reject);
10997827cba2SAaron LI if (make_option_mask(d, dl, od, odl, request, arg, -1) != 0 ||
11007827cba2SAaron LI make_option_mask(d, dl, od, odl, require, arg, -1) != 0 ||
11017827cba2SAaron LI make_option_mask(d, dl, od, odl, no, arg, 1) != 0)
11027827cba2SAaron LI {
1103a0d9933aSRoy Marples logerrx("unknown option: %s", arg);
11047827cba2SAaron LI return -1;
11057827cba2SAaron LI }
11067827cba2SAaron LI break;
11077827cba2SAaron LI case 'Q':
11087827cba2SAaron LI ARG_REQUIRED;
1109b2927f2bSRoy Marples if (ctx->options & DHCPCD_PRINT_PIDFILE)
1110b2927f2bSRoy Marples break;
11111b3b16a2SRoy Marples set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
11127827cba2SAaron LI &request, &require, &no, &reject);
11137827cba2SAaron LI if (make_option_mask(d, dl, od, odl, require, arg, 1) != 0 ||
11147827cba2SAaron LI make_option_mask(d, dl, od, odl, request, arg, 1) != 0 ||
11157827cba2SAaron LI make_option_mask(d, dl, od, odl, no, arg, -1) != 0 ||
11167827cba2SAaron LI make_option_mask(d, dl, od, odl, reject, arg, -1) != 0)
11177827cba2SAaron LI {
1118a0d9933aSRoy Marples logerrx("unknown option: %s", arg);
11197827cba2SAaron LI return -1;
11207827cba2SAaron LI }
11217827cba2SAaron LI break;
11227827cba2SAaron LI case 'S':
11237827cba2SAaron LI ARG_REQUIRED;
11247827cba2SAaron LI p = strchr(arg, '=');
11257827cba2SAaron LI if (p == NULL) {
11267827cba2SAaron LI logerrx("static assignment required");
11277827cba2SAaron LI return -1;
11287827cba2SAaron LI }
112980aa9461SRoy Marples p = strskipwhite(++p);
11307827cba2SAaron LI if (strncmp(arg, "ip_address=", strlen("ip_address=")) == 0) {
113180aa9461SRoy Marples if (p == NULL) {
113280aa9461SRoy Marples ifo->options &= ~DHCPCD_STATIC;
113380aa9461SRoy Marples ifo->req_addr.s_addr = INADDR_ANY;
113480aa9461SRoy Marples break;
113580aa9461SRoy Marples }
11367827cba2SAaron LI if (parse_addr(&ifo->req_addr,
11377827cba2SAaron LI ifo->req_mask.s_addr == 0 ? &ifo->req_mask : NULL,
11387827cba2SAaron LI p) != 0)
11397827cba2SAaron LI return -1;
11407827cba2SAaron LI
11417827cba2SAaron LI ifo->options |= DHCPCD_STATIC;
11427827cba2SAaron LI ifo->options &= ~DHCPCD_INFORM;
11437827cba2SAaron LI } else if (strncmp(arg, "subnet_mask=",
11447827cba2SAaron LI strlen("subnet_mask=")) == 0)
11457827cba2SAaron LI {
114680aa9461SRoy Marples if (p == NULL) {
114780aa9461SRoy Marples ifo->req_mask.s_addr = INADDR_ANY;
114880aa9461SRoy Marples break;
114980aa9461SRoy Marples }
11507827cba2SAaron LI if (parse_addr(&ifo->req_mask, NULL, p) != 0)
11517827cba2SAaron LI return -1;
11527827cba2SAaron LI } else if (strncmp(arg, "broadcast_address=",
11537827cba2SAaron LI strlen("broadcast_address=")) == 0)
11547827cba2SAaron LI {
115580aa9461SRoy Marples if (p == NULL) {
115680aa9461SRoy Marples ifo->req_brd.s_addr = INADDR_ANY;
115780aa9461SRoy Marples break;
115880aa9461SRoy Marples }
11597827cba2SAaron LI if (parse_addr(&ifo->req_brd, NULL, p) != 0)
11607827cba2SAaron LI return -1;
11617827cba2SAaron LI } else if (strncmp(arg, "routes=", strlen("routes=")) == 0 ||
11627827cba2SAaron LI strncmp(arg, "static_routes=",
11637827cba2SAaron LI strlen("static_routes=")) == 0 ||
11647827cba2SAaron LI strncmp(arg, "classless_static_routes=",
11657827cba2SAaron LI strlen("classless_static_routes=")) == 0 ||
11667827cba2SAaron LI strncmp(arg, "ms_classless_static_routes=",
11677827cba2SAaron LI strlen("ms_classless_static_routes=")) == 0)
11687827cba2SAaron LI {
11697827cba2SAaron LI struct in_addr addr3;
11707827cba2SAaron LI
117180aa9461SRoy Marples if (p == NULL) {
117280aa9461SRoy Marples rt_headclear(&ifo->routes, AF_INET);
117380aa9461SRoy Marples add_environ(&ifo->config, arg, 1);
117480aa9461SRoy Marples break;
117580aa9461SRoy Marples }
117680aa9461SRoy Marples
11777827cba2SAaron LI fp = np = strwhite(p);
11787827cba2SAaron LI if (np == NULL) {
11797827cba2SAaron LI logerrx("all routes need a gateway");
11807827cba2SAaron LI return -1;
11817827cba2SAaron LI }
11827827cba2SAaron LI *np++ = '\0';
11837827cba2SAaron LI np = strskipwhite(np);
11847827cba2SAaron LI if (parse_addr(&addr, &addr2, p) == -1 ||
11857827cba2SAaron LI parse_addr(&addr3, NULL, np) == -1)
11867827cba2SAaron LI {
11877827cba2SAaron LI *fp = ' ';
11887827cba2SAaron LI return -1;
11897827cba2SAaron LI }
11907827cba2SAaron LI *fp = ' ';
11918d36e1dfSRoy Marples if ((rt = rt_new0(ctx)) == NULL)
11927827cba2SAaron LI return -1;
11937827cba2SAaron LI sa_in_init(&rt->rt_dest, &addr);
11947827cba2SAaron LI sa_in_init(&rt->rt_netmask, &addr2);
11957827cba2SAaron LI sa_in_init(&rt->rt_gateway, &addr3);
11968d36e1dfSRoy Marples if (rt_proto_add_ctx(&ifo->routes, rt, ctx))
11978d36e1dfSRoy Marples add_environ(&ifo->config, arg, 0);
11987827cba2SAaron LI } else if (strncmp(arg, "routers=", strlen("routers=")) == 0) {
119980aa9461SRoy Marples if (p == NULL) {
120080aa9461SRoy Marples rt_headclear(&ifo->routes, AF_INET);
120180aa9461SRoy Marples add_environ(&ifo->config, arg, 1);
120280aa9461SRoy Marples break;
120380aa9461SRoy Marples }
12047827cba2SAaron LI if (parse_addr(&addr, NULL, p) == -1)
12057827cba2SAaron LI return -1;
12067827cba2SAaron LI if ((rt = rt_new0(ctx)) == NULL)
12077827cba2SAaron LI return -1;
12087827cba2SAaron LI addr2.s_addr = INADDR_ANY;
12097827cba2SAaron LI sa_in_init(&rt->rt_dest, &addr2);
12107827cba2SAaron LI sa_in_init(&rt->rt_netmask, &addr2);
12117827cba2SAaron LI sa_in_init(&rt->rt_gateway, &addr);
12128d36e1dfSRoy Marples if (rt_proto_add_ctx(&ifo->routes, rt, ctx))
12138d36e1dfSRoy Marples add_environ(&ifo->config, arg, 0);
12147827cba2SAaron LI } else if (strncmp(arg, "interface_mtu=",
12157827cba2SAaron LI strlen("interface_mtu=")) == 0 ||
12167827cba2SAaron LI strncmp(arg, "mtu=", strlen("mtu=")) == 0)
12177827cba2SAaron LI {
121880aa9461SRoy Marples if (p == NULL)
121980aa9461SRoy Marples break;
12207827cba2SAaron LI ifo->mtu = (unsigned int)strtou(p, NULL, 0,
12217827cba2SAaron LI MTU_MIN, MTU_MAX, &e);
12227827cba2SAaron LI if (e) {
12237827cba2SAaron LI logerrx("invalid MTU %s", p);
12247827cba2SAaron LI return -1;
12257827cba2SAaron LI }
12267827cba2SAaron LI } else if (strncmp(arg, "ip6_address=", strlen("ip6_address=")) == 0) {
122780aa9461SRoy Marples if (p == NULL) {
122880aa9461SRoy Marples memset(&ifo->req_addr6, 0,
122980aa9461SRoy Marples sizeof(ifo->req_addr6));
123080aa9461SRoy Marples break;
123180aa9461SRoy Marples }
123280aa9461SRoy Marples
12337827cba2SAaron LI np = strchr(p, '/');
12347827cba2SAaron LI if (np)
12357827cba2SAaron LI *np++ = '\0';
12366e63cc1fSRoy Marples if ((i = inet_pton(AF_INET6, p, &ifo->req_addr6)) == 1) {
12377827cba2SAaron LI if (np) {
12387827cba2SAaron LI ifo->req_prefix_len = (uint8_t)strtou(np,
12397827cba2SAaron LI NULL, 0, 0, 128, &e);
12407827cba2SAaron LI if (e) {
12417827cba2SAaron LI logerrx("%s: failed to "
12427827cba2SAaron LI "convert prefix len",
12437827cba2SAaron LI ifname);
12447827cba2SAaron LI return -1;
12457827cba2SAaron LI }
12467827cba2SAaron LI } else
12477827cba2SAaron LI ifo->req_prefix_len = 128;
12487827cba2SAaron LI }
12496e63cc1fSRoy Marples if (np)
12506e63cc1fSRoy Marples *(--np) = '\0';
12516e63cc1fSRoy Marples if (i != 1) {
12526e63cc1fSRoy Marples logerrx("invalid AF_INET6: %s", p);
12536e63cc1fSRoy Marples memset(&ifo->req_addr6, 0,
12546e63cc1fSRoy Marples sizeof(ifo->req_addr6));
12556e63cc1fSRoy Marples return -1;
12566e63cc1fSRoy Marples }
12578d36e1dfSRoy Marples } else
125880aa9461SRoy Marples add_environ(&ifo->config, arg, p == NULL ? 1 : 0);
12597827cba2SAaron LI break;
126080aa9461SRoy Marples
12617827cba2SAaron LI case 'W':
12627827cba2SAaron LI if (parse_addr(&addr, &addr2, arg) != 0)
12637827cba2SAaron LI return -1;
12647827cba2SAaron LI if (strchr(arg, '/') == NULL)
12657827cba2SAaron LI addr2.s_addr = INADDR_BROADCAST;
12667827cba2SAaron LI naddr = reallocarray(ifo->whitelist,
12677827cba2SAaron LI ifo->whitelist_len + 2, sizeof(in_addr_t));
12687827cba2SAaron LI if (naddr == NULL) {
12697827cba2SAaron LI logerr(__func__);
12707827cba2SAaron LI return -1;
12717827cba2SAaron LI }
12727827cba2SAaron LI ifo->whitelist = naddr;
12737827cba2SAaron LI ifo->whitelist[ifo->whitelist_len++] = addr.s_addr;
12747827cba2SAaron LI ifo->whitelist[ifo->whitelist_len++] = addr2.s_addr;
12757827cba2SAaron LI break;
12767827cba2SAaron LI case 'X':
12777827cba2SAaron LI if (parse_addr(&addr, &addr2, arg) != 0)
12787827cba2SAaron LI return -1;
12797827cba2SAaron LI if (strchr(arg, '/') == NULL)
12807827cba2SAaron LI addr2.s_addr = INADDR_BROADCAST;
12817827cba2SAaron LI naddr = reallocarray(ifo->blacklist,
12827827cba2SAaron LI ifo->blacklist_len + 2, sizeof(in_addr_t));
12837827cba2SAaron LI if (naddr == NULL) {
12847827cba2SAaron LI logerr(__func__);
12857827cba2SAaron LI return -1;
12867827cba2SAaron LI }
12877827cba2SAaron LI ifo->blacklist = naddr;
12887827cba2SAaron LI ifo->blacklist[ifo->blacklist_len++] = addr.s_addr;
12897827cba2SAaron LI ifo->blacklist[ifo->blacklist_len++] = addr2.s_addr;
12907827cba2SAaron LI break;
12917827cba2SAaron LI case 'Z':
12927827cba2SAaron LI ARG_REQUIRED;
1293cc34ba0cSRoy Marples if (!IN_CONFIG_BLOCK(ifo))
12947827cba2SAaron LI ctx->ifdv = splitv(&ctx->ifdc, ctx->ifdv, arg);
12957827cba2SAaron LI break;
12967827cba2SAaron LI case '1':
12977827cba2SAaron LI ifo->options |= DHCPCD_ONESHOT;
12987827cba2SAaron LI break;
12997827cba2SAaron LI case '4':
1300b8b69544SRoy Marples #ifdef INET
13017827cba2SAaron LI ifo->options &= ~DHCPCD_IPV6;
13027827cba2SAaron LI ifo->options |= DHCPCD_IPV4;
13037827cba2SAaron LI break;
1304b8b69544SRoy Marples #else
1305b8b69544SRoy Marples logerrx("INET has been compiled out");
1306b8b69544SRoy Marples return -1;
1307b8b69544SRoy Marples #endif
13087827cba2SAaron LI case '6':
1309b8b69544SRoy Marples #ifdef INET6
13107827cba2SAaron LI ifo->options &= ~DHCPCD_IPV4;
13117827cba2SAaron LI ifo->options |= DHCPCD_IPV6;
13127827cba2SAaron LI break;
1313b8b69544SRoy Marples #else
1314b8b69544SRoy Marples logerrx("INET6 has been compiled out");
1315b8b69544SRoy Marples return -1;
1316b8b69544SRoy Marples #endif
13177827cba2SAaron LI case O_IPV4:
13187827cba2SAaron LI ifo->options |= DHCPCD_IPV4;
13197827cba2SAaron LI break;
13207827cba2SAaron LI case O_NOIPV4:
13217827cba2SAaron LI ifo->options &= ~DHCPCD_IPV4;
13227827cba2SAaron LI break;
13237827cba2SAaron LI case O_IPV6:
13247827cba2SAaron LI ifo->options |= DHCPCD_IPV6;
13257827cba2SAaron LI break;
13267827cba2SAaron LI case O_NOIPV6:
13277827cba2SAaron LI ifo->options &= ~DHCPCD_IPV6;
13287827cba2SAaron LI break;
13296e63cc1fSRoy Marples case O_ANONYMOUS:
13306e63cc1fSRoy Marples ifo->options |= DHCPCD_ANONYMOUS;
13316e63cc1fSRoy Marples ifo->options &= ~DHCPCD_HOSTNAME;
13326e63cc1fSRoy Marples ifo->fqdn = FQDN_DISABLE;
13336e63cc1fSRoy Marples
13346e63cc1fSRoy Marples /* Block everything */
13356e63cc1fSRoy Marples memset(ifo->nomask, 0xff, sizeof(ifo->nomask));
13366e63cc1fSRoy Marples memset(ifo->nomask6, 0xff, sizeof(ifo->nomask6));
13376e63cc1fSRoy Marples
13386e63cc1fSRoy Marples /* Allow the bare minimum through */
1339280986e4SRoy Marples #ifdef INET
13406e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_SUBNETMASK);
13416e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_CSR);
13426e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_ROUTER);
13436e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_DNSSERVER);
13446e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_DNSDOMAIN);
13456e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_BROADCAST);
13466e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_STATICROUTE);
13476e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_SERVERID);
13486e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_RENEWALTIME);
13496e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_REBINDTIME);
13506e63cc1fSRoy Marples del_option_mask(ifo->nomask, DHO_DNSSEARCH);
1351280986e4SRoy Marples #endif
13526e63cc1fSRoy Marples
1353d4fb1e02SRoy Marples #ifdef DHCP6
13546e63cc1fSRoy Marples del_option_mask(ifo->nomask6, D6_OPTION_DNS_SERVERS);
13556e63cc1fSRoy Marples del_option_mask(ifo->nomask6, D6_OPTION_DOMAIN_LIST);
13566e63cc1fSRoy Marples del_option_mask(ifo->nomask6, D6_OPTION_SOL_MAX_RT);
13576e63cc1fSRoy Marples del_option_mask(ifo->nomask6, D6_OPTION_INF_MAX_RT);
1358280986e4SRoy Marples #endif
13596e63cc1fSRoy Marples
13606e63cc1fSRoy Marples break;
13610aaf6155SRoy Marples case O_RANDOMISE_HWADDR:
13620aaf6155SRoy Marples ifo->randomise_hwaddr = true;
13630aaf6155SRoy Marples break;
13647827cba2SAaron LI #ifdef INET
13657827cba2SAaron LI case O_ARPING:
13667827cba2SAaron LI while (arg != NULL) {
13677827cba2SAaron LI fp = strwhite(arg);
13687827cba2SAaron LI if (fp)
13697827cba2SAaron LI *fp++ = '\0';
13707827cba2SAaron LI if (parse_addr(&addr, NULL, arg) != 0)
13717827cba2SAaron LI return -1;
13727827cba2SAaron LI naddr = reallocarray(ifo->arping,
13737827cba2SAaron LI (size_t)ifo->arping_len + 1, sizeof(in_addr_t));
13747827cba2SAaron LI if (naddr == NULL) {
13757827cba2SAaron LI logerr(__func__);
13767827cba2SAaron LI return -1;
13777827cba2SAaron LI }
13787827cba2SAaron LI ifo->arping = naddr;
13797827cba2SAaron LI ifo->arping[ifo->arping_len++] = addr.s_addr;
13807827cba2SAaron LI arg = strskipwhite(fp);
13817827cba2SAaron LI }
13827827cba2SAaron LI break;
13837827cba2SAaron LI case O_DESTINATION:
13847827cba2SAaron LI ARG_REQUIRED;
1385b2927f2bSRoy Marples if (ctx->options & DHCPCD_PRINT_PIDFILE)
1386b2927f2bSRoy Marples break;
13871b3b16a2SRoy Marples set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
13887827cba2SAaron LI &request, &require, &no, &reject);
13897827cba2SAaron LI if (make_option_mask(d, dl, od, odl,
13907827cba2SAaron LI ifo->dstmask, arg, 2) != 0)
13917827cba2SAaron LI {
13927827cba2SAaron LI if (errno == EINVAL)
1393a0d9933aSRoy Marples logerrx("option does not take"
1394a0d9933aSRoy Marples " an IPv4 address: %s", arg);
13957827cba2SAaron LI else
1396a0d9933aSRoy Marples logerrx("unknown option: %s", arg);
13977827cba2SAaron LI return -1;
13987827cba2SAaron LI }
13997827cba2SAaron LI break;
14007827cba2SAaron LI case O_FALLBACK:
14017827cba2SAaron LI ARG_REQUIRED;
14027827cba2SAaron LI free(ifo->fallback);
14037827cba2SAaron LI ifo->fallback = strdup(arg);
14047827cba2SAaron LI if (ifo->fallback == NULL) {
14057827cba2SAaron LI logerrx(__func__);
14067827cba2SAaron LI return -1;
14077827cba2SAaron LI }
14087827cba2SAaron LI break;
14097827cba2SAaron LI #endif
14107827cba2SAaron LI case O_IAID:
14117827cba2SAaron LI ARG_REQUIRED;
14120a68f8d2SRoy Marples if (ctx->options & DHCPCD_MANAGER && !IN_CONFIG_BLOCK(ifo)) {
14137827cba2SAaron LI logerrx("IAID must belong in an interface block");
14147827cba2SAaron LI return -1;
14157827cba2SAaron LI }
14167827cba2SAaron LI if (parse_iaid(ifo->iaid, arg, sizeof(ifo->iaid)) == -1) {
14177827cba2SAaron LI logerrx("invalid IAID %s", arg);
14187827cba2SAaron LI return -1;
14197827cba2SAaron LI }
14207827cba2SAaron LI ifo->options |= DHCPCD_IAID;
14217827cba2SAaron LI break;
14227827cba2SAaron LI case O_IPV6RS:
14237827cba2SAaron LI ifo->options |= DHCPCD_IPV6RS;
14247827cba2SAaron LI break;
14257827cba2SAaron LI case O_NOIPV6RS:
14267827cba2SAaron LI ifo->options &= ~DHCPCD_IPV6RS;
14277827cba2SAaron LI break;
14287827cba2SAaron LI case O_IPV6RA_FORK:
14297827cba2SAaron LI ifo->options &= ~DHCPCD_IPV6RA_REQRDNSS;
14307827cba2SAaron LI break;
14317827cba2SAaron LI case O_IPV6RA_AUTOCONF:
14327827cba2SAaron LI ifo->options |= DHCPCD_IPV6RA_AUTOCONF;
14337827cba2SAaron LI break;
14347827cba2SAaron LI case O_IPV6RA_NOAUTOCONF:
14357827cba2SAaron LI ifo->options &= ~DHCPCD_IPV6RA_AUTOCONF;
14367827cba2SAaron LI break;
14377827cba2SAaron LI case O_NOALIAS:
14387827cba2SAaron LI ifo->options |= DHCPCD_NOALIAS;
14397827cba2SAaron LI break;
14407827cba2SAaron LI #ifdef DHCP6
14417827cba2SAaron LI case O_IA_NA:
14427827cba2SAaron LI i = D6_OPTION_IA_NA;
14437827cba2SAaron LI /* FALLTHROUGH */
14447827cba2SAaron LI case O_IA_TA:
14457827cba2SAaron LI if (i == 0)
14467827cba2SAaron LI i = D6_OPTION_IA_TA;
14477827cba2SAaron LI /* FALLTHROUGH */
14487827cba2SAaron LI case O_IA_PD:
14497827cba2SAaron LI if (i == 0) {
14507827cba2SAaron LI #ifdef SMALL
14517827cba2SAaron LI logwarnx("%s: IA_PD not compiled in", ifname);
14527827cba2SAaron LI return -1;
14537827cba2SAaron LI #else
14540a68f8d2SRoy Marples if (ctx->options & DHCPCD_MANAGER &&
145520329f2aSRoy Marples !IN_CONFIG_BLOCK(ifo))
145620329f2aSRoy Marples {
14578d36e1dfSRoy Marples logerrx("IA PD must belong in an "
14587827cba2SAaron LI "interface block");
14597827cba2SAaron LI return -1;
14607827cba2SAaron LI }
14617827cba2SAaron LI i = D6_OPTION_IA_PD;
14627827cba2SAaron LI #endif
14637827cba2SAaron LI }
14640a68f8d2SRoy Marples if (ctx->options & DHCPCD_MANAGER &&
146520329f2aSRoy Marples !IN_CONFIG_BLOCK(ifo) && arg)
146620329f2aSRoy Marples {
14677827cba2SAaron LI logerrx("IA with IAID must belong in an "
14687827cba2SAaron LI "interface block");
14697827cba2SAaron LI return -1;
14707827cba2SAaron LI }
14717827cba2SAaron LI ifo->options |= DHCPCD_IA_FORCED;
14727827cba2SAaron LI fp = strwhite(arg);
14737827cba2SAaron LI if (fp) {
14747827cba2SAaron LI *fp++ = '\0';
14757827cba2SAaron LI fp = strskipwhite(fp);
14767827cba2SAaron LI }
14777827cba2SAaron LI if (arg) {
14787827cba2SAaron LI p = strchr(arg, '/');
14797827cba2SAaron LI if (p)
14807827cba2SAaron LI *p++ = '\0';
14817827cba2SAaron LI if (parse_iaid(iaid, arg, sizeof(iaid)) == -1) {
14827827cba2SAaron LI logerr("invalid IAID: %s", arg);
14837827cba2SAaron LI return -1;
14847827cba2SAaron LI }
14857827cba2SAaron LI }
14867827cba2SAaron LI ia = NULL;
14877827cba2SAaron LI for (sl = 0; sl < ifo->ia_len; sl++) {
14887827cba2SAaron LI if ((arg == NULL && !ifo->ia[sl].iaid_set) ||
14897827cba2SAaron LI (arg != NULL && ifo->ia[sl].iaid_set &&
14907827cba2SAaron LI ifo->ia[sl].ia_type == (uint16_t)i &&
14917827cba2SAaron LI ifo->ia[sl].iaid[0] == iaid[0] &&
14927827cba2SAaron LI ifo->ia[sl].iaid[1] == iaid[1] &&
14937827cba2SAaron LI ifo->ia[sl].iaid[2] == iaid[2] &&
14947827cba2SAaron LI ifo->ia[sl].iaid[3] == iaid[3]))
14957827cba2SAaron LI {
14967827cba2SAaron LI ia = &ifo->ia[sl];
14977827cba2SAaron LI break;
14987827cba2SAaron LI }
14997827cba2SAaron LI }
15007827cba2SAaron LI if (ia == NULL) {
15017827cba2SAaron LI ia = reallocarray(ifo->ia,
15027827cba2SAaron LI ifo->ia_len + 1, sizeof(*ifo->ia));
15037827cba2SAaron LI if (ia == NULL) {
15047827cba2SAaron LI logerr(__func__);
15057827cba2SAaron LI return -1;
15067827cba2SAaron LI }
15077827cba2SAaron LI ifo->ia = ia;
15087827cba2SAaron LI ia = &ifo->ia[ifo->ia_len++];
15097827cba2SAaron LI ia->ia_type = (uint16_t)i;
15107827cba2SAaron LI if (arg) {
15117827cba2SAaron LI ia->iaid[0] = iaid[0];
15127827cba2SAaron LI ia->iaid[1] = iaid[1];
15137827cba2SAaron LI ia->iaid[2] = iaid[2];
15147827cba2SAaron LI ia->iaid[3] = iaid[3];
15157827cba2SAaron LI ia->iaid_set = 1;
15167827cba2SAaron LI } else
15177827cba2SAaron LI ia->iaid_set = 0;
15187827cba2SAaron LI if (!ia->iaid_set ||
15197827cba2SAaron LI p == NULL ||
15207827cba2SAaron LI ia->ia_type == D6_OPTION_IA_TA)
15217827cba2SAaron LI {
15227827cba2SAaron LI memset(&ia->addr, 0, sizeof(ia->addr));
15237827cba2SAaron LI ia->prefix_len = 0;
15247827cba2SAaron LI } else {
15257827cba2SAaron LI arg = p;
15267827cba2SAaron LI p = strchr(arg, '/');
15277827cba2SAaron LI if (p)
15287827cba2SAaron LI *p++ = '\0';
15296e63cc1fSRoy Marples if (inet_pton(AF_INET6, arg, &ia->addr) != 1) {
15306e63cc1fSRoy Marples logerrx("invalid AF_INET6: %s", arg);
15317827cba2SAaron LI memset(&ia->addr, 0, sizeof(ia->addr));
15327827cba2SAaron LI }
15337827cba2SAaron LI if (p && ia->ia_type == D6_OPTION_IA_PD) {
15347827cba2SAaron LI ia->prefix_len = (uint8_t)strtou(p,
15357827cba2SAaron LI NULL, 0, 8, 120, &e);
15367827cba2SAaron LI if (e) {
15377827cba2SAaron LI logerrx("%s: failed to convert"
15387827cba2SAaron LI " prefix len",
15397827cba2SAaron LI p);
15407827cba2SAaron LI ia->prefix_len = 0;
15417827cba2SAaron LI }
15427827cba2SAaron LI }
15437827cba2SAaron LI }
15447827cba2SAaron LI #ifndef SMALL
15457827cba2SAaron LI ia->sla_max = 0;
15467827cba2SAaron LI ia->sla_len = 0;
15477827cba2SAaron LI ia->sla = NULL;
15487827cba2SAaron LI #endif
15497827cba2SAaron LI }
15508d36e1dfSRoy Marples
15518d36e1dfSRoy Marples #ifdef SMALL
15528d36e1dfSRoy Marples break;
15538d36e1dfSRoy Marples #else
15547827cba2SAaron LI if (ia->ia_type != D6_OPTION_IA_PD)
15557827cba2SAaron LI break;
15568d36e1dfSRoy Marples
15577827cba2SAaron LI for (p = fp; p; p = fp) {
15587827cba2SAaron LI fp = strwhite(p);
15597827cba2SAaron LI if (fp) {
15607827cba2SAaron LI *fp++ = '\0';
15617827cba2SAaron LI fp = strskipwhite(fp);
15627827cba2SAaron LI }
15637827cba2SAaron LI sla = reallocarray(ia->sla,
15647827cba2SAaron LI ia->sla_len + 1, sizeof(*ia->sla));
15657827cba2SAaron LI if (sla == NULL) {
15667827cba2SAaron LI logerr(__func__);
15677827cba2SAaron LI return -1;
15687827cba2SAaron LI }
15697827cba2SAaron LI ia->sla = sla;
15707827cba2SAaron LI sla = &ia->sla[ia->sla_len++];
15717827cba2SAaron LI np = strchr(p, '/');
15727827cba2SAaron LI if (np)
15737827cba2SAaron LI *np++ = '\0';
15747827cba2SAaron LI if (strlcpy(sla->ifname, p,
15757827cba2SAaron LI sizeof(sla->ifname)) >= sizeof(sla->ifname))
15767827cba2SAaron LI {
15777827cba2SAaron LI logerrx("%s: interface name too long", arg);
15787827cba2SAaron LI goto err_sla;
15797827cba2SAaron LI }
15807f8103cdSRoy Marples sla->sla_set = false;
15817827cba2SAaron LI sla->prefix_len = 0;
15827827cba2SAaron LI sla->suffix = 1;
15837827cba2SAaron LI p = np;
15847827cba2SAaron LI if (p) {
15857827cba2SAaron LI np = strchr(p, '/');
15867827cba2SAaron LI if (np)
15877827cba2SAaron LI *np++ = '\0';
15887827cba2SAaron LI if (*p != '\0') {
15897827cba2SAaron LI sla->sla = (uint32_t)strtou(p, NULL,
15907827cba2SAaron LI 0, 0, UINT32_MAX, &e);
15917f8103cdSRoy Marples sla->sla_set = true;
15927827cba2SAaron LI if (e) {
15937827cba2SAaron LI logerrx("%s: failed to convert "
15947827cba2SAaron LI "sla",
15957827cba2SAaron LI ifname);
15967827cba2SAaron LI goto err_sla;
15977827cba2SAaron LI }
15987827cba2SAaron LI }
15997827cba2SAaron LI p = np;
16007827cba2SAaron LI }
16017827cba2SAaron LI if (p) {
16027827cba2SAaron LI np = strchr(p, '/');
16037827cba2SAaron LI if (np)
16047827cba2SAaron LI *np++ = '\0';
16057827cba2SAaron LI if (*p != '\0') {
16067827cba2SAaron LI sla->prefix_len = (uint8_t)strtou(p,
16077827cba2SAaron LI NULL, 0, 0, 120, &e);
16087827cba2SAaron LI if (e) {
16097827cba2SAaron LI logerrx("%s: failed to "
16107827cba2SAaron LI "convert prefix len",
16117827cba2SAaron LI ifname);
16127827cba2SAaron LI goto err_sla;
16137827cba2SAaron LI }
16147827cba2SAaron LI }
16157827cba2SAaron LI p = np;
16167827cba2SAaron LI }
16177827cba2SAaron LI if (p) {
16187827cba2SAaron LI np = strchr(p, '/');
16197827cba2SAaron LI if (np)
16207827cba2SAaron LI *np = '\0';
16217827cba2SAaron LI if (*p != '\0') {
16227827cba2SAaron LI sla->suffix = (uint64_t)strtou(p, NULL,
16237827cba2SAaron LI 0, 0, UINT64_MAX, &e);
16247827cba2SAaron LI if (e) {
16257827cba2SAaron LI logerrx("%s: failed to "
16267827cba2SAaron LI "convert suffix",
16277827cba2SAaron LI ifname);
16287827cba2SAaron LI goto err_sla;
16297827cba2SAaron LI }
16307827cba2SAaron LI }
16317827cba2SAaron LI }
16327827cba2SAaron LI /* Sanity check */
16337827cba2SAaron LI for (sl = 0; sl < ia->sla_len - 1; sl++) {
16347827cba2SAaron LI slap = &ia->sla[sl];
16357827cba2SAaron LI if (slap->sla_set != sla->sla_set) {
16367827cba2SAaron LI logerrx("%s: cannot mix automatic "
16377827cba2SAaron LI "and fixed SLA",
16387827cba2SAaron LI sla->ifname);
16397827cba2SAaron LI goto err_sla;
16407827cba2SAaron LI }
16417827cba2SAaron LI if (ia->prefix_len &&
16427827cba2SAaron LI (sla->prefix_len == ia->prefix_len ||
16437827cba2SAaron LI slap->prefix_len == ia->prefix_len))
16447827cba2SAaron LI {
16457827cba2SAaron LI logerrx("%s: cannot delegte the same"
16467827cba2SAaron LI "prefix length more than once",
16477827cba2SAaron LI sla->ifname);
16487827cba2SAaron LI goto err_sla;
16497827cba2SAaron LI }
16507f8103cdSRoy Marples if (!sla->sla_set &&
16517827cba2SAaron LI strcmp(slap->ifname, sla->ifname) == 0)
16527827cba2SAaron LI {
16537827cba2SAaron LI logwarnx("%s: cannot specify the "
16547827cba2SAaron LI "same interface twice with "
16557827cba2SAaron LI "an automatic SLA",
16567827cba2SAaron LI sla->ifname);
16577827cba2SAaron LI goto err_sla;
16587827cba2SAaron LI }
16597827cba2SAaron LI if (slap->sla_set && sla->sla_set &&
16607827cba2SAaron LI slap->sla == sla->sla)
16617827cba2SAaron LI {
16627827cba2SAaron LI logerrx("%s: cannot"
16637827cba2SAaron LI " assign the same SLA %u"
16647827cba2SAaron LI " more than once",
16657827cba2SAaron LI sla->ifname, sla->sla);
16667827cba2SAaron LI goto err_sla;
16677827cba2SAaron LI }
16687827cba2SAaron LI }
16697827cba2SAaron LI if (sla->sla_set && sla->sla > ia->sla_max)
16707827cba2SAaron LI ia->sla_max = sla->sla;
16717827cba2SAaron LI }
16727827cba2SAaron LI break;
16737827cba2SAaron LI err_sla:
16747827cba2SAaron LI ia->sla_len--;
16757827cba2SAaron LI return -1;
16767827cba2SAaron LI #endif
16777827cba2SAaron LI #endif
16787827cba2SAaron LI case O_HOSTNAME_SHORT:
16797827cba2SAaron LI ifo->options |= DHCPCD_HOSTNAME | DHCPCD_HOSTNAME_SHORT;
16807827cba2SAaron LI break;
16817827cba2SAaron LI case O_DEV:
16827827cba2SAaron LI ARG_REQUIRED;
16837827cba2SAaron LI #ifdef PLUGIN_DEV
16847827cba2SAaron LI if (ctx->dev_load)
16857827cba2SAaron LI free(ctx->dev_load);
16867827cba2SAaron LI ctx->dev_load = strdup(arg);
16877827cba2SAaron LI #endif
16887827cba2SAaron LI break;
16897827cba2SAaron LI case O_NODEV:
16907827cba2SAaron LI ifo->options &= ~DHCPCD_DEV;
16917827cba2SAaron LI break;
16927827cba2SAaron LI case O_DEFINE:
16937827cba2SAaron LI dop = &ifo->dhcp_override;
16947827cba2SAaron LI dop_len = &ifo->dhcp_override_len;
16957827cba2SAaron LI /* FALLTHROUGH */
16967827cba2SAaron LI case O_DEFINEND:
16977827cba2SAaron LI if (dop == NULL) {
16987827cba2SAaron LI dop = &ifo->nd_override;
16997827cba2SAaron LI dop_len = &ifo->nd_override_len;
17007827cba2SAaron LI }
17017827cba2SAaron LI /* FALLTHROUGH */
17027827cba2SAaron LI case O_DEFINE6:
17037827cba2SAaron LI if (dop == NULL) {
17047827cba2SAaron LI dop = &ifo->dhcp6_override;
17057827cba2SAaron LI dop_len = &ifo->dhcp6_override_len;
17067827cba2SAaron LI }
17077827cba2SAaron LI /* FALLTHROUGH */
17087827cba2SAaron LI case O_VENDOPT:
17097827cba2SAaron LI if (dop == NULL) {
17107827cba2SAaron LI dop = &ifo->vivso_override;
17117827cba2SAaron LI dop_len = &ifo->vivso_override_len;
17127827cba2SAaron LI }
17137827cba2SAaron LI *edop = *ldop = NULL;
17147827cba2SAaron LI /* FALLTHROUGH */
17157827cba2SAaron LI case O_EMBED:
17167827cba2SAaron LI if (dop == NULL) {
17177827cba2SAaron LI if (*edop) {
17187827cba2SAaron LI dop = &(*edop)->embopts;
17197827cba2SAaron LI dop_len = &(*edop)->embopts_len;
17207827cba2SAaron LI } else if (ldop) {
17217827cba2SAaron LI dop = &(*ldop)->embopts;
17227827cba2SAaron LI dop_len = &(*ldop)->embopts_len;
17237827cba2SAaron LI } else {
17247827cba2SAaron LI logerrx("embed must be after a define "
17257827cba2SAaron LI "or encap");
17267827cba2SAaron LI return -1;
17277827cba2SAaron LI }
17287827cba2SAaron LI }
17297827cba2SAaron LI /* FALLTHROUGH */
17307827cba2SAaron LI case O_ENCAP:
17317827cba2SAaron LI ARG_REQUIRED;
17327827cba2SAaron LI if (dop == NULL) {
17337827cba2SAaron LI if (*ldop == NULL) {
17347827cba2SAaron LI logerrx("encap must be after a define");
17357827cba2SAaron LI return -1;
17367827cba2SAaron LI }
17377827cba2SAaron LI dop = &(*ldop)->encopts;
17387827cba2SAaron LI dop_len = &(*ldop)->encopts_len;
17397827cba2SAaron LI }
17407827cba2SAaron LI
17417827cba2SAaron LI /* Shared code for define, define6, embed and encap */
17427827cba2SAaron LI
17437827cba2SAaron LI /* code */
17447827cba2SAaron LI if (opt == O_EMBED) /* Embedded options don't have codes */
17457827cba2SAaron LI u = 0;
17467827cba2SAaron LI else {
17477827cba2SAaron LI fp = strwhite(arg);
17487827cba2SAaron LI if (fp == NULL) {
17497827cba2SAaron LI logerrx("invalid syntax: %s", arg);
17507827cba2SAaron LI return -1;
17517827cba2SAaron LI }
17527827cba2SAaron LI *fp++ = '\0';
17537827cba2SAaron LI u = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
17547827cba2SAaron LI if (e) {
17557827cba2SAaron LI logerrx("invalid code: %s", arg);
17567827cba2SAaron LI return -1;
17577827cba2SAaron LI }
17587827cba2SAaron LI arg = strskipwhite(fp);
17597827cba2SAaron LI if (arg == NULL) {
17607827cba2SAaron LI logerrx("invalid syntax");
17617827cba2SAaron LI return -1;
17627827cba2SAaron LI }
17637827cba2SAaron LI }
17647827cba2SAaron LI /* type */
17657827cba2SAaron LI fp = strwhite(arg);
17667827cba2SAaron LI if (fp)
17677827cba2SAaron LI *fp++ = '\0';
17687827cba2SAaron LI np = strchr(arg, ':');
17697827cba2SAaron LI /* length */
17707827cba2SAaron LI if (np) {
17717827cba2SAaron LI *np++ = '\0';
17727827cba2SAaron LI bp = NULL; /* No bitflag */
17737827cba2SAaron LI l = (long)strtou(np, NULL, 0, 0, LONG_MAX, &e);
17747827cba2SAaron LI if (e) {
17757827cba2SAaron LI logerrx("failed to convert length");
17767827cba2SAaron LI return -1;
17777827cba2SAaron LI }
17787827cba2SAaron LI } else {
17797827cba2SAaron LI l = 0;
17807827cba2SAaron LI bp = strchr(arg, '='); /* bitflag assignment */
17817827cba2SAaron LI if (bp)
17827827cba2SAaron LI *bp++ = '\0';
17837827cba2SAaron LI }
17847827cba2SAaron LI t = 0;
17857827cba2SAaron LI if (strcasecmp(arg, "request") == 0) {
17867827cba2SAaron LI t |= OT_REQUEST;
17877827cba2SAaron LI arg = strskipwhite(fp);
17887827cba2SAaron LI fp = strwhite(arg);
17897827cba2SAaron LI if (fp == NULL) {
17907827cba2SAaron LI logerrx("incomplete request type");
17917827cba2SAaron LI return -1;
17927827cba2SAaron LI }
17937827cba2SAaron LI *fp++ = '\0';
17947827cba2SAaron LI } else if (strcasecmp(arg, "norequest") == 0) {
17957827cba2SAaron LI t |= OT_NOREQ;
17967827cba2SAaron LI arg = strskipwhite(fp);
17977827cba2SAaron LI fp = strwhite(arg);
17987827cba2SAaron LI if (fp == NULL) {
17997827cba2SAaron LI logerrx("incomplete request type");
18007827cba2SAaron LI return -1;
18017827cba2SAaron LI }
18027827cba2SAaron LI *fp++ = '\0';
18037827cba2SAaron LI }
18047827cba2SAaron LI if (strcasecmp(arg, "optional") == 0) {
18057827cba2SAaron LI t |= OT_OPTIONAL;
18067827cba2SAaron LI arg = strskipwhite(fp);
18077827cba2SAaron LI fp = strwhite(arg);
18087827cba2SAaron LI if (fp == NULL) {
18097827cba2SAaron LI logerrx("incomplete optional type");
18107827cba2SAaron LI return -1;
18117827cba2SAaron LI }
18127827cba2SAaron LI *fp++ = '\0';
18137827cba2SAaron LI }
18147827cba2SAaron LI if (strcasecmp(arg, "index") == 0) {
18157827cba2SAaron LI t |= OT_INDEX;
18167827cba2SAaron LI arg = strskipwhite(fp);
18177827cba2SAaron LI fp = strwhite(arg);
18187827cba2SAaron LI if (fp == NULL) {
18197827cba2SAaron LI logerrx("incomplete index type");
18207827cba2SAaron LI return -1;
18217827cba2SAaron LI }
18227827cba2SAaron LI *fp++ = '\0';
18237827cba2SAaron LI }
18247827cba2SAaron LI if (strcasecmp(arg, "array") == 0) {
18257827cba2SAaron LI t |= OT_ARRAY;
18267827cba2SAaron LI arg = strskipwhite(fp);
18277827cba2SAaron LI fp = strwhite(arg);
18287827cba2SAaron LI if (fp == NULL) {
18297827cba2SAaron LI logerrx("incomplete array type");
18307827cba2SAaron LI return -1;
18317827cba2SAaron LI }
18327827cba2SAaron LI *fp++ = '\0';
18337827cba2SAaron LI }
18347827cba2SAaron LI if (strcasecmp(arg, "ipaddress") == 0)
18357827cba2SAaron LI t |= OT_ADDRIPV4;
18367827cba2SAaron LI else if (strcasecmp(arg, "ip6address") == 0)
18377827cba2SAaron LI t |= OT_ADDRIPV6;
18387827cba2SAaron LI else if (strcasecmp(arg, "string") == 0)
18397827cba2SAaron LI t |= OT_STRING;
18404f235d86SRoy Marples else if (strcasecmp(arg, "uri") == 0)
18414f235d86SRoy Marples t |= OT_URI;
18427827cba2SAaron LI else if (strcasecmp(arg, "byte") == 0)
18437827cba2SAaron LI t |= OT_UINT8;
18447827cba2SAaron LI else if (strcasecmp(arg, "bitflags") == 0)
18457827cba2SAaron LI t |= OT_BITFLAG;
18467827cba2SAaron LI else if (strcasecmp(arg, "uint8") == 0)
18477827cba2SAaron LI t |= OT_UINT8;
18487827cba2SAaron LI else if (strcasecmp(arg, "int8") == 0)
18497827cba2SAaron LI t |= OT_INT8;
18507827cba2SAaron LI else if (strcasecmp(arg, "uint16") == 0)
18517827cba2SAaron LI t |= OT_UINT16;
18527827cba2SAaron LI else if (strcasecmp(arg, "int16") == 0)
18537827cba2SAaron LI t |= OT_INT16;
18547827cba2SAaron LI else if (strcasecmp(arg, "uint32") == 0)
18557827cba2SAaron LI t |= OT_UINT32;
18567827cba2SAaron LI else if (strcasecmp(arg, "int32") == 0)
18577827cba2SAaron LI t |= OT_INT32;
18587827cba2SAaron LI else if (strcasecmp(arg, "flag") == 0)
18597827cba2SAaron LI t |= OT_FLAG;
18607827cba2SAaron LI else if (strcasecmp(arg, "raw") == 0)
18617827cba2SAaron LI t |= OT_STRING | OT_RAW;
18627827cba2SAaron LI else if (strcasecmp(arg, "ascii") == 0)
18637827cba2SAaron LI t |= OT_STRING | OT_ASCII;
18647827cba2SAaron LI else if (strcasecmp(arg, "domain") == 0)
18657827cba2SAaron LI t |= OT_STRING | OT_DOMAIN | OT_RFC1035;
18667827cba2SAaron LI else if (strcasecmp(arg, "dname") == 0)
18677827cba2SAaron LI t |= OT_STRING | OT_DOMAIN;
18687827cba2SAaron LI else if (strcasecmp(arg, "binhex") == 0)
18697827cba2SAaron LI t |= OT_STRING | OT_BINHEX;
18707827cba2SAaron LI else if (strcasecmp(arg, "embed") == 0)
18717827cba2SAaron LI t |= OT_EMBED;
18727827cba2SAaron LI else if (strcasecmp(arg, "encap") == 0)
18737827cba2SAaron LI t |= OT_ENCAP;
18747827cba2SAaron LI else if (strcasecmp(arg, "rfc3361") ==0)
18757827cba2SAaron LI t |= OT_STRING | OT_RFC3361;
18767827cba2SAaron LI else if (strcasecmp(arg, "rfc3442") ==0)
18777827cba2SAaron LI t |= OT_STRING | OT_RFC3442;
18787827cba2SAaron LI else if (strcasecmp(arg, "option") == 0)
18797827cba2SAaron LI t |= OT_OPTION;
18807827cba2SAaron LI else {
18817827cba2SAaron LI logerrx("unknown type: %s", arg);
18827827cba2SAaron LI return -1;
18837827cba2SAaron LI }
18847827cba2SAaron LI if (l && !(t & (OT_STRING | OT_BINHEX))) {
1885a0d9933aSRoy Marples logwarnx("ignoring length for type: %s", arg);
18867827cba2SAaron LI l = 0;
18877827cba2SAaron LI }
18887827cba2SAaron LI if (t & OT_ARRAY && t & (OT_STRING | OT_BINHEX) &&
18897827cba2SAaron LI !(t & (OT_RFC1035 | OT_DOMAIN)))
18907827cba2SAaron LI {
18917827cba2SAaron LI logwarnx("ignoring array for strings");
18927827cba2SAaron LI t &= ~OT_ARRAY;
18937827cba2SAaron LI }
18947827cba2SAaron LI if (t & OT_BITFLAG) {
18957827cba2SAaron LI if (bp == NULL)
18967827cba2SAaron LI logwarnx("missing bitflag assignment");
18977827cba2SAaron LI }
18987827cba2SAaron LI /* variable */
18997827cba2SAaron LI if (!fp) {
19007827cba2SAaron LI if (!(t & OT_OPTION)) {
19017827cba2SAaron LI logerrx("type %s requires a variable name",
19027827cba2SAaron LI arg);
19037827cba2SAaron LI return -1;
19047827cba2SAaron LI }
19057827cba2SAaron LI np = NULL;
19067827cba2SAaron LI } else {
19077827cba2SAaron LI arg = strskipwhite(fp);
19087827cba2SAaron LI fp = strwhite(arg);
19097827cba2SAaron LI if (fp)
19107827cba2SAaron LI *fp++ = '\0';
19117827cba2SAaron LI if (strcasecmp(arg, "reserved")) {
19127827cba2SAaron LI np = strdup(arg);
19137827cba2SAaron LI if (np == NULL) {
19147827cba2SAaron LI logerr(__func__);
19157827cba2SAaron LI return -1;
19167827cba2SAaron LI }
19177827cba2SAaron LI } else {
19187827cba2SAaron LI np = NULL;
19197827cba2SAaron LI t |= OT_RESERVED;
19207827cba2SAaron LI }
19217827cba2SAaron LI }
19227827cba2SAaron LI if (opt != O_EMBED) {
19237827cba2SAaron LI for (dl = 0, ndop = *dop; dl < *dop_len; dl++, ndop++)
19247827cba2SAaron LI {
19257827cba2SAaron LI /* type 0 seems freshly malloced struct
19267827cba2SAaron LI * for us to use */
19277827cba2SAaron LI if (ndop->option == u || ndop->type == 0)
19287827cba2SAaron LI break;
19297827cba2SAaron LI }
19307827cba2SAaron LI if (dl == *dop_len)
19317827cba2SAaron LI ndop = NULL;
19327827cba2SAaron LI } else
19337827cba2SAaron LI ndop = NULL;
19347827cba2SAaron LI if (ndop == NULL) {
19357827cba2SAaron LI ndop = reallocarray(*dop, *dop_len + 1, sizeof(**dop));
19367827cba2SAaron LI if (ndop == NULL) {
19377827cba2SAaron LI logerr(__func__);
19387827cba2SAaron LI free(np);
19397827cba2SAaron LI return -1;
19407827cba2SAaron LI }
19417827cba2SAaron LI *dop = ndop;
19427827cba2SAaron LI ndop = &(*dop)[(*dop_len)++];
19437827cba2SAaron LI ndop->embopts = NULL;
19447827cba2SAaron LI ndop->embopts_len = 0;
19457827cba2SAaron LI ndop->encopts = NULL;
19467827cba2SAaron LI ndop->encopts_len = 0;
19477827cba2SAaron LI } else
19487827cba2SAaron LI free_dhcp_opt_embenc(ndop);
19497827cba2SAaron LI ndop->option = (uint32_t)u; /* could have been 0 */
19507827cba2SAaron LI ndop->type = t;
19517827cba2SAaron LI ndop->len = (size_t)l;
19527827cba2SAaron LI ndop->var = np;
19537827cba2SAaron LI if (bp) {
19547827cba2SAaron LI dl = strlen(bp);
19557827cba2SAaron LI memcpy(ndop->bitflags, bp, dl);
19567827cba2SAaron LI memset(ndop->bitflags + dl, 0,
19577827cba2SAaron LI sizeof(ndop->bitflags) - dl);
19587827cba2SAaron LI } else
19597827cba2SAaron LI memset(ndop->bitflags, 0, sizeof(ndop->bitflags));
19607827cba2SAaron LI /* Save the define for embed and encap options */
19617827cba2SAaron LI switch (opt) {
19627827cba2SAaron LI case O_DEFINE:
19637827cba2SAaron LI case O_DEFINEND:
19647827cba2SAaron LI case O_DEFINE6:
19657827cba2SAaron LI case O_VENDOPT:
19667827cba2SAaron LI *ldop = ndop;
19677827cba2SAaron LI break;
19687827cba2SAaron LI case O_ENCAP:
19697827cba2SAaron LI *edop = ndop;
19707827cba2SAaron LI break;
19717827cba2SAaron LI }
19727827cba2SAaron LI break;
19737827cba2SAaron LI case O_VENDCLASS:
19747827cba2SAaron LI ARG_REQUIRED;
19757827cba2SAaron LI fp = strwhite(arg);
19767827cba2SAaron LI if (fp)
19777827cba2SAaron LI *fp++ = '\0';
19787827cba2SAaron LI u = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
19797827cba2SAaron LI if (e) {
19807827cba2SAaron LI logerrx("invalid code: %s", arg);
19817827cba2SAaron LI return -1;
19827827cba2SAaron LI }
19837827cba2SAaron LI fp = strskipwhite(fp);
19847827cba2SAaron LI if (fp) {
19857827cba2SAaron LI s = parse_string(NULL, 0, fp);
19867827cba2SAaron LI if (s == -1) {
19877827cba2SAaron LI logerr(__func__);
19887827cba2SAaron LI return -1;
19897827cba2SAaron LI }
19907827cba2SAaron LI dl = (size_t)s;
19917827cba2SAaron LI if (dl + (sizeof(uint16_t) * 2) > UINT16_MAX) {
19927827cba2SAaron LI logerrx("vendor class is too big");
19937827cba2SAaron LI return -1;
19947827cba2SAaron LI }
19957827cba2SAaron LI np = malloc(dl);
19967827cba2SAaron LI if (np == NULL) {
19977827cba2SAaron LI logerr(__func__);
19987827cba2SAaron LI return -1;
19997827cba2SAaron LI }
20007827cba2SAaron LI parse_string(np, dl, fp);
20017827cba2SAaron LI } else {
20027827cba2SAaron LI dl = 0;
20037827cba2SAaron LI np = NULL;
20047827cba2SAaron LI }
20057827cba2SAaron LI vivco = reallocarray(ifo->vivco,
20067827cba2SAaron LI ifo->vivco_len + 1, sizeof(*ifo->vivco));
20077827cba2SAaron LI if (vivco == NULL) {
20087827cba2SAaron LI logerr( __func__);
20098d36e1dfSRoy Marples free(np);
20107827cba2SAaron LI return -1;
20117827cba2SAaron LI }
20127827cba2SAaron LI ifo->vivco = vivco;
20137827cba2SAaron LI ifo->vivco_en = (uint32_t)u;
20147827cba2SAaron LI vivco = &ifo->vivco[ifo->vivco_len++];
20157827cba2SAaron LI vivco->len = dl;
20167827cba2SAaron LI vivco->data = (uint8_t *)np;
20177827cba2SAaron LI break;
20187827cba2SAaron LI case O_AUTHPROTOCOL:
20197827cba2SAaron LI ARG_REQUIRED;
20207827cba2SAaron LI #ifdef AUTH
20217827cba2SAaron LI fp = strwhite(arg);
20227827cba2SAaron LI if (fp)
20237827cba2SAaron LI *fp++ = '\0';
20247827cba2SAaron LI if (strcasecmp(arg, "token") == 0)
20257827cba2SAaron LI ifo->auth.protocol = AUTH_PROTO_TOKEN;
20267827cba2SAaron LI else if (strcasecmp(arg, "delayed") == 0)
20277827cba2SAaron LI ifo->auth.protocol = AUTH_PROTO_DELAYED;
20287827cba2SAaron LI else if (strcasecmp(arg, "delayedrealm") == 0)
20297827cba2SAaron LI ifo->auth.protocol = AUTH_PROTO_DELAYEDREALM;
20307827cba2SAaron LI else {
20317827cba2SAaron LI logerrx("%s: unsupported protocol", arg);
20327827cba2SAaron LI return -1;
20337827cba2SAaron LI }
20347827cba2SAaron LI arg = strskipwhite(fp);
20357827cba2SAaron LI fp = strwhite(arg);
20367827cba2SAaron LI if (arg == NULL) {
20377827cba2SAaron LI ifo->auth.options |= DHCPCD_AUTH_SEND;
20387827cba2SAaron LI if (ifo->auth.protocol == AUTH_PROTO_TOKEN)
20397827cba2SAaron LI ifo->auth.protocol = AUTH_ALG_NONE;
20407827cba2SAaron LI else
20417827cba2SAaron LI ifo->auth.algorithm = AUTH_ALG_HMAC_MD5;
20427827cba2SAaron LI ifo->auth.rdm = AUTH_RDM_MONOTONIC;
20437827cba2SAaron LI break;
20447827cba2SAaron LI }
20457827cba2SAaron LI if (fp)
20467827cba2SAaron LI *fp++ = '\0';
20477827cba2SAaron LI if (ifo->auth.protocol == AUTH_PROTO_TOKEN) {
20487827cba2SAaron LI np = strchr(arg, '/');
20497827cba2SAaron LI if (np) {
20507827cba2SAaron LI if (fp == NULL || np < fp)
20517827cba2SAaron LI *np++ = '\0';
20527827cba2SAaron LI else
20537827cba2SAaron LI np = NULL;
20547827cba2SAaron LI }
20557827cba2SAaron LI if (parse_uint32(&ifo->auth.token_snd_secretid,
20567827cba2SAaron LI arg) == -1)
20577827cba2SAaron LI logerrx("%s: not a number", arg);
20587827cba2SAaron LI else
20597827cba2SAaron LI ifo->auth.token_rcv_secretid =
20607827cba2SAaron LI ifo->auth.token_snd_secretid;
20617827cba2SAaron LI if (np &&
20627827cba2SAaron LI parse_uint32(&ifo->auth.token_rcv_secretid,
20637827cba2SAaron LI np) == -1)
20647827cba2SAaron LI logerrx("%s: not a number", arg);
20657827cba2SAaron LI } else {
20667827cba2SAaron LI if (strcasecmp(arg, "hmacmd5") == 0 ||
20677827cba2SAaron LI strcasecmp(arg, "hmac-md5") == 0)
20687827cba2SAaron LI ifo->auth.algorithm = AUTH_ALG_HMAC_MD5;
20697827cba2SAaron LI else {
20707827cba2SAaron LI logerrx("%s: unsupported algorithm", arg);
20717827cba2SAaron LI return 1;
20727827cba2SAaron LI }
20737827cba2SAaron LI }
20747827cba2SAaron LI arg = fp;
20757827cba2SAaron LI if (arg == NULL) {
20767827cba2SAaron LI ifo->auth.options |= DHCPCD_AUTH_SEND;
20777827cba2SAaron LI ifo->auth.rdm = AUTH_RDM_MONOTONIC;
20787827cba2SAaron LI break;
20797827cba2SAaron LI }
20807827cba2SAaron LI if (strcasecmp(arg, "monocounter") == 0) {
20817827cba2SAaron LI ifo->auth.rdm = AUTH_RDM_MONOTONIC;
20827827cba2SAaron LI ifo->auth.options |= DHCPCD_AUTH_RDM_COUNTER;
20837827cba2SAaron LI } else if (strcasecmp(arg, "monotonic") ==0 ||
20847827cba2SAaron LI strcasecmp(arg, "monotime") == 0)
20857827cba2SAaron LI ifo->auth.rdm = AUTH_RDM_MONOTONIC;
20867827cba2SAaron LI else {
20877827cba2SAaron LI logerrx("%s: unsupported RDM", arg);
20887827cba2SAaron LI return -1;
20897827cba2SAaron LI }
20907827cba2SAaron LI ifo->auth.options |= DHCPCD_AUTH_SEND;
20917827cba2SAaron LI break;
20927827cba2SAaron LI #else
20937827cba2SAaron LI logerrx("no authentication support");
20947827cba2SAaron LI return -1;
20957827cba2SAaron LI #endif
20967827cba2SAaron LI case O_AUTHTOKEN:
20977827cba2SAaron LI ARG_REQUIRED;
20987827cba2SAaron LI #ifdef AUTH
20997827cba2SAaron LI fp = strwhite(arg);
21007827cba2SAaron LI if (fp == NULL) {
21017827cba2SAaron LI logerrx("authtoken requires a realm");
21027827cba2SAaron LI return -1;
21037827cba2SAaron LI }
21047827cba2SAaron LI *fp++ = '\0';
21056e63cc1fSRoy Marples token = calloc(1, sizeof(*token));
21067827cba2SAaron LI if (token == NULL) {
21077827cba2SAaron LI logerr(__func__);
21087827cba2SAaron LI return -1;
21097827cba2SAaron LI }
21107827cba2SAaron LI if (parse_uint32(&token->secretid, arg) == -1) {
21117827cba2SAaron LI logerrx("%s: not a number", arg);
21126e63cc1fSRoy Marples goto invalid_token;
21137827cba2SAaron LI }
21147827cba2SAaron LI arg = fp;
21157827cba2SAaron LI fp = strend(arg);
21167827cba2SAaron LI if (fp == NULL) {
211780aa9461SRoy Marples logerrx("authtoken requires a realm");
21186e63cc1fSRoy Marples goto invalid_token;
21197827cba2SAaron LI }
21207827cba2SAaron LI *fp++ = '\0';
21217827cba2SAaron LI s = parse_string(NULL, 0, arg);
21227827cba2SAaron LI if (s == -1) {
21237827cba2SAaron LI logerr("realm_len");
21246e63cc1fSRoy Marples goto invalid_token;
21257827cba2SAaron LI }
21266e63cc1fSRoy Marples if (s != 0) {
21277827cba2SAaron LI token->realm_len = (size_t)s;
21287827cba2SAaron LI token->realm = malloc(token->realm_len);
21297827cba2SAaron LI if (token->realm == NULL) {
21307827cba2SAaron LI logerr(__func__);
21316e63cc1fSRoy Marples goto invalid_token;
21327827cba2SAaron LI }
21337827cba2SAaron LI parse_string((char *)token->realm, token->realm_len,
21347827cba2SAaron LI arg);
21357827cba2SAaron LI }
21367827cba2SAaron LI arg = fp;
21377827cba2SAaron LI fp = strend(arg);
21387827cba2SAaron LI if (fp == NULL) {
21398d36e1dfSRoy Marples logerrx("authtoken requies an expiry date");
21406e63cc1fSRoy Marples goto invalid_token;
21417827cba2SAaron LI }
21427827cba2SAaron LI *fp++ = '\0';
21437827cba2SAaron LI if (*arg == '"') {
21447827cba2SAaron LI arg++;
21457827cba2SAaron LI np = strchr(arg, '"');
21467827cba2SAaron LI if (np)
21477827cba2SAaron LI *np = '\0';
21487827cba2SAaron LI }
21497827cba2SAaron LI if (strcmp(arg, "0") == 0 || strcasecmp(arg, "forever") == 0)
21507827cba2SAaron LI token->expire =0;
21517827cba2SAaron LI else {
21527827cba2SAaron LI struct tm tm;
21537827cba2SAaron LI
21547827cba2SAaron LI memset(&tm, 0, sizeof(tm));
21557827cba2SAaron LI if (strptime(arg, "%Y-%m-%d %H:%M", &tm) == NULL) {
21567827cba2SAaron LI logerrx("%s: invalid date time", arg);
21576e63cc1fSRoy Marples goto invalid_token;
21587827cba2SAaron LI }
21597827cba2SAaron LI if ((token->expire = mktime(&tm)) == (time_t)-1) {
21607827cba2SAaron LI logerr("%s: mktime", __func__);
21616e63cc1fSRoy Marples goto invalid_token;
21627827cba2SAaron LI }
21637827cba2SAaron LI }
21647827cba2SAaron LI arg = fp;
21657827cba2SAaron LI s = parse_string(NULL, 0, arg);
21667827cba2SAaron LI if (s == -1 || s == 0) {
21677827cba2SAaron LI if (s == -1)
21687827cba2SAaron LI logerr("token_len");
21697827cba2SAaron LI else
217080aa9461SRoy Marples logerrx("authtoken requires a key");
21716e63cc1fSRoy Marples goto invalid_token;
21727827cba2SAaron LI }
21737827cba2SAaron LI token->key_len = (size_t)s;
21747827cba2SAaron LI token->key = malloc(token->key_len);
21756e63cc1fSRoy Marples if (token->key == NULL) {
21766e63cc1fSRoy Marples logerr(__func__);
21776e63cc1fSRoy Marples goto invalid_token;
21786e63cc1fSRoy Marples }
21797827cba2SAaron LI parse_string((char *)token->key, token->key_len, arg);
21807827cba2SAaron LI TAILQ_INSERT_TAIL(&ifo->auth.tokens, token, next);
21816e63cc1fSRoy Marples break;
21826e63cc1fSRoy Marples
21836e63cc1fSRoy Marples invalid_token:
21846e63cc1fSRoy Marples free(token->realm);
21856e63cc1fSRoy Marples free(token);
21867827cba2SAaron LI #else
21877827cba2SAaron LI logerrx("no authentication support");
21887827cba2SAaron LI #endif
21896e63cc1fSRoy Marples return -1;
21907827cba2SAaron LI case O_AUTHNOTREQUIRED:
21917827cba2SAaron LI ifo->auth.options &= ~DHCPCD_AUTH_REQUIRE;
21927827cba2SAaron LI break;
21937827cba2SAaron LI case O_DHCP:
21948d36e1dfSRoy Marples ifo->options |= DHCPCD_DHCP | DHCPCD_WANTDHCP | DHCPCD_IPV4;
21957827cba2SAaron LI break;
21967827cba2SAaron LI case O_NODHCP:
21977827cba2SAaron LI ifo->options &= ~DHCPCD_DHCP;
21987827cba2SAaron LI break;
21997827cba2SAaron LI case O_DHCP6:
22007827cba2SAaron LI ifo->options |= DHCPCD_DHCP6 | DHCPCD_IPV6;
22017827cba2SAaron LI break;
22027827cba2SAaron LI case O_NODHCP6:
22037827cba2SAaron LI ifo->options &= ~DHCPCD_DHCP6;
22047827cba2SAaron LI break;
22057827cba2SAaron LI case O_CONTROLGRP:
22067827cba2SAaron LI ARG_REQUIRED;
2207b8b69544SRoy Marples #ifdef PRIVSEP
2208b8b69544SRoy Marples /* Control group is already set by this point.
2209b8b69544SRoy Marples * We don't need to pledge getpw either with this. */
2210b8b69544SRoy Marples if (IN_PRIVSEP(ctx))
2211b8b69544SRoy Marples break;
2212b8b69544SRoy Marples #endif
22137827cba2SAaron LI #ifdef _REENTRANT
22147827cba2SAaron LI l = sysconf(_SC_GETGR_R_SIZE_MAX);
22157827cba2SAaron LI if (l == -1)
22167827cba2SAaron LI dl = 1024;
22177827cba2SAaron LI else
22187827cba2SAaron LI dl = (size_t)l;
22197827cba2SAaron LI p = malloc(dl);
22207827cba2SAaron LI if (p == NULL) {
22217827cba2SAaron LI logerr(__func__);
22227827cba2SAaron LI return -1;
22237827cba2SAaron LI }
2224d4fb1e02SRoy Marples while ((i = getgrnam_r(arg, &grpbuf, p, dl, &grp)) ==
22257827cba2SAaron LI ERANGE)
22267827cba2SAaron LI {
22277827cba2SAaron LI size_t nl = dl * 2;
22287827cba2SAaron LI if (nl < dl) {
22297827cba2SAaron LI logerrx("control_group: out of buffer");
22307827cba2SAaron LI free(p);
22317827cba2SAaron LI return -1;
22327827cba2SAaron LI }
22337827cba2SAaron LI dl = nl;
22347827cba2SAaron LI np = realloc(p, dl);
22357827cba2SAaron LI if (np == NULL) {
22367827cba2SAaron LI logerr(__func__);
22377827cba2SAaron LI free(p);
22387827cba2SAaron LI return -1;
22397827cba2SAaron LI }
22407827cba2SAaron LI p = np;
22417827cba2SAaron LI }
22427827cba2SAaron LI if (i != 0) {
22437827cba2SAaron LI errno = i;
22447827cba2SAaron LI logerr("getgrnam_r");
22457827cba2SAaron LI free(p);
22467827cba2SAaron LI return -1;
22477827cba2SAaron LI }
22487827cba2SAaron LI if (grp == NULL) {
2249d4fb1e02SRoy Marples if (!ctx->control_group)
22507827cba2SAaron LI logerrx("controlgroup: %s: not found", arg);
22517827cba2SAaron LI free(p);
22527827cba2SAaron LI return -1;
22537827cba2SAaron LI }
22547827cba2SAaron LI ctx->control_group = grp->gr_gid;
22557827cba2SAaron LI free(p);
22567827cba2SAaron LI #else
22577827cba2SAaron LI grp = getgrnam(arg);
22587827cba2SAaron LI if (grp == NULL) {
2259d4fb1e02SRoy Marples if (!ctx->control_group)
22607827cba2SAaron LI logerrx("controlgroup: %s: not found", arg);
22617827cba2SAaron LI return -1;
22627827cba2SAaron LI }
22637827cba2SAaron LI ctx->control_group = grp->gr_gid;
22647827cba2SAaron LI #endif
22657827cba2SAaron LI break;
22667827cba2SAaron LI case O_GATEWAY:
22677827cba2SAaron LI ifo->options |= DHCPCD_GATEWAY;
22687827cba2SAaron LI break;
22697827cba2SAaron LI case O_NOUP:
22707827cba2SAaron LI ifo->options &= ~DHCPCD_IF_UP;
22717827cba2SAaron LI break;
22727827cba2SAaron LI case O_SLAAC:
22737827cba2SAaron LI ARG_REQUIRED;
22747a0236bfSRoy Marples np = strwhite(arg);
22757a0236bfSRoy Marples if (np != NULL) {
22767a0236bfSRoy Marples *np++ = '\0';
22777a0236bfSRoy Marples np = strskipwhite(np);
22787a0236bfSRoy Marples }
22797827cba2SAaron LI if (strcmp(arg, "private") == 0 ||
22807827cba2SAaron LI strcmp(arg, "stableprivate") == 0 ||
22817827cba2SAaron LI strcmp(arg, "stable") == 0)
22827827cba2SAaron LI ifo->options |= DHCPCD_SLAACPRIVATE;
22837827cba2SAaron LI else
22847827cba2SAaron LI ifo->options &= ~DHCPCD_SLAACPRIVATE;
228580aa9461SRoy Marples #ifdef INET6
228680aa9461SRoy Marples if (strcmp(arg, "token") == 0) {
228780aa9461SRoy Marples if (np == NULL) {
228880aa9461SRoy Marples logerrx("slaac token: no token specified");
228980aa9461SRoy Marples return -1;
229080aa9461SRoy Marples }
229180aa9461SRoy Marples arg = np;
229280aa9461SRoy Marples np = strwhite(np);
229380aa9461SRoy Marples if (np != NULL) {
229480aa9461SRoy Marples *np++ = '\0';
229580aa9461SRoy Marples np = strskipwhite(np);
229680aa9461SRoy Marples }
229780aa9461SRoy Marples if (inet_pton(AF_INET6, arg, &ifo->token) != 1) {
229880aa9461SRoy Marples logerrx("slaac token: invalid token");
229980aa9461SRoy Marples return -1;
230080aa9461SRoy Marples }
230180aa9461SRoy Marples }
230280aa9461SRoy Marples #endif
23037a0236bfSRoy Marples if (np != NULL &&
23047a0236bfSRoy Marples (strcmp(np, "temp") == 0 || strcmp(np, "temporary") == 0))
23057a0236bfSRoy Marples ifo->options |= DHCPCD_SLAACTEMP;
23067827cba2SAaron LI break;
23077827cba2SAaron LI case O_BOOTP:
23087827cba2SAaron LI ifo->options |= DHCPCD_BOOTP;
23097827cba2SAaron LI break;
23107827cba2SAaron LI case O_NODELAY:
23117827cba2SAaron LI ifo->options &= ~DHCPCD_INITIAL_DELAY;
23127827cba2SAaron LI break;
23137827cba2SAaron LI case O_LASTLEASE_EXTEND:
23147827cba2SAaron LI ifo->options |= DHCPCD_LASTLEASE | DHCPCD_LASTLEASE_EXTEND;
23157827cba2SAaron LI break;
23167827cba2SAaron LI case O_INACTIVE:
23177827cba2SAaron LI ifo->options |= DHCPCD_INACTIVE;
23187827cba2SAaron LI break;
23197827cba2SAaron LI case O_MUDURL:
23207827cba2SAaron LI ARG_REQUIRED;
23217827cba2SAaron LI s = parse_string((char *)ifo->mudurl + 1, MUDURL_MAX_LEN, arg);
23227827cba2SAaron LI if (s == -1) {
23237827cba2SAaron LI logerr("mudurl");
23247827cba2SAaron LI return -1;
23257827cba2SAaron LI }
23267827cba2SAaron LI *ifo->mudurl = (uint8_t)s;
23277827cba2SAaron LI break;
23288d36e1dfSRoy Marples case O_LINK_RCVBUF:
23298d36e1dfSRoy Marples #ifndef SMALL
23308d36e1dfSRoy Marples ARG_REQUIRED;
23318d36e1dfSRoy Marples ctx->link_rcvbuf = (int)strtoi(arg, NULL, 0, 0, INT32_MAX, &e);
23328d36e1dfSRoy Marples if (e) {
23338d36e1dfSRoy Marples logerrx("failed to convert link_rcvbuf %s", arg);
23348d36e1dfSRoy Marples return -1;
23358d36e1dfSRoy Marples }
23368d36e1dfSRoy Marples #endif
23378d36e1dfSRoy Marples break;
2338b2927f2bSRoy Marples case O_CONFIGURE:
2339b2927f2bSRoy Marples ifo->options |= DHCPCD_CONFIGURE;
2340b2927f2bSRoy Marples break;
2341b2927f2bSRoy Marples case O_NOCONFIGURE:
2342b2927f2bSRoy Marples ifo->options &= ~DHCPCD_CONFIGURE;
2343b2927f2bSRoy Marples break;
2344*54175cefSRoy Marples case O_ARP_PERSISTDEFENCE:
2345*54175cefSRoy Marples ifo->options |= DHCPCD_ARP_PERSISTDEFENCE;
2346*54175cefSRoy Marples break;
2347*54175cefSRoy Marples case O_REQUEST_TIME:
2348*54175cefSRoy Marples ARG_REQUIRED;
2349*54175cefSRoy Marples ifo->request_time =
2350*54175cefSRoy Marples (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
2351*54175cefSRoy Marples if (e) {
2352*54175cefSRoy Marples logerrx("invalid request time: %s", arg);
2353*54175cefSRoy Marples return -1;
2354*54175cefSRoy Marples }
2355*54175cefSRoy Marples break;
2356*54175cefSRoy Marples #ifdef INET
2357*54175cefSRoy Marples case O_FALLBACK_TIME:
2358*54175cefSRoy Marples ARG_REQUIRED;
2359*54175cefSRoy Marples ifo->request_time =
2360*54175cefSRoy Marples (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
2361*54175cefSRoy Marples if (e) {
2362*54175cefSRoy Marples logerrx("invalid fallback time: %s", arg);
2363*54175cefSRoy Marples return -1;
2364*54175cefSRoy Marples }
2365*54175cefSRoy Marples break;
2366*54175cefSRoy Marples case O_IPV4LL_TIME:
2367*54175cefSRoy Marples ARG_REQUIRED;
2368*54175cefSRoy Marples ifo->ipv4ll_time =
2369*54175cefSRoy Marples (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
2370*54175cefSRoy Marples if (e) {
2371*54175cefSRoy Marples logerrx("invalid ipv4ll time: %s", arg);
2372*54175cefSRoy Marples return -1;
2373*54175cefSRoy Marples }
2374*54175cefSRoy Marples break;
2375*54175cefSRoy Marples #endif
23767827cba2SAaron LI default:
23777827cba2SAaron LI return 0;
23787827cba2SAaron LI }
23797827cba2SAaron LI
23807827cba2SAaron LI return 1;
23817827cba2SAaron LI
23827827cba2SAaron LI #ifdef ARG_REQUIRED
23837827cba2SAaron LI arg_required:
23847827cba2SAaron LI logerrx("option %d requires an argument", opt);
23857827cba2SAaron LI return -1;
23867827cba2SAaron LI #undef ARG_REQUIRED
23877827cba2SAaron LI #endif
23887827cba2SAaron LI }
23897827cba2SAaron LI
23907827cba2SAaron LI static int
parse_config_line(struct dhcpcd_ctx * ctx,const char * ifname,struct if_options * ifo,const char * opt,char * line,struct dhcp_opt ** ldop,struct dhcp_opt ** edop)23917827cba2SAaron LI parse_config_line(struct dhcpcd_ctx *ctx, const char *ifname,
23927827cba2SAaron LI struct if_options *ifo, const char *opt, char *line,
23937827cba2SAaron LI struct dhcp_opt **ldop, struct dhcp_opt **edop)
23947827cba2SAaron LI {
23957827cba2SAaron LI unsigned int i;
23967827cba2SAaron LI
23977827cba2SAaron LI for (i = 0; i < sizeof(cf_options) / sizeof(cf_options[0]); i++) {
23987827cba2SAaron LI if (!cf_options[i].name ||
23997827cba2SAaron LI strcmp(cf_options[i].name, opt) != 0)
24007827cba2SAaron LI continue;
24017827cba2SAaron LI
24027827cba2SAaron LI if (cf_options[i].has_arg == required_argument && !line) {
24037827cba2SAaron LI logerrx("option requires an argument -- %s", opt);
24047827cba2SAaron LI return -1;
24057827cba2SAaron LI }
24067827cba2SAaron LI
24077827cba2SAaron LI return parse_option(ctx, ifname, ifo, cf_options[i].val, line,
24087827cba2SAaron LI ldop, edop);
24097827cba2SAaron LI }
24107827cba2SAaron LI
2411b2927f2bSRoy Marples if (!(ctx->options & DHCPCD_PRINT_PIDFILE))
24127827cba2SAaron LI logerrx("unknown option: %s", opt);
24137827cba2SAaron LI return -1;
24147827cba2SAaron LI }
24157827cba2SAaron LI
24167827cba2SAaron LI static void
finish_config(struct if_options * ifo)24177827cba2SAaron LI finish_config(struct if_options *ifo)
24187827cba2SAaron LI {
24197827cba2SAaron LI
24207827cba2SAaron LI /* Terminate the encapsulated options */
24217827cba2SAaron LI if (ifo->vendor[0] && !(ifo->options & DHCPCD_VENDORRAW)) {
24227827cba2SAaron LI ifo->vendor[0]++;
24237827cba2SAaron LI ifo->vendor[ifo->vendor[0]] = DHO_END;
24247827cba2SAaron LI /* We are called twice.
24257827cba2SAaron LI * This should be fixed, but in the meantime, this
24267827cba2SAaron LI * guard should suffice */
24277827cba2SAaron LI ifo->options |= DHCPCD_VENDORRAW;
24287827cba2SAaron LI }
24296e63cc1fSRoy Marples
24306e63cc1fSRoy Marples if (!(ifo->options & DHCPCD_ARP) ||
24316e63cc1fSRoy Marples ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))
24326e63cc1fSRoy Marples ifo->options &= ~DHCPCD_IPV4LL;
24336e63cc1fSRoy Marples
24346e63cc1fSRoy Marples if (!(ifo->options & DHCPCD_IPV4))
24356e63cc1fSRoy Marples ifo->options &= ~(DHCPCD_DHCP | DHCPCD_IPV4LL | DHCPCD_WAITIP4);
24366e63cc1fSRoy Marples
24376e63cc1fSRoy Marples if (!(ifo->options & DHCPCD_IPV6))
24386e63cc1fSRoy Marples ifo->options &=
24396e63cc1fSRoy Marples ~(DHCPCD_IPV6RS | DHCPCD_DHCP6 | DHCPCD_WAITIP6);
24406e63cc1fSRoy Marples
24416e63cc1fSRoy Marples if (!(ifo->options & DHCPCD_IPV6RS))
24426e63cc1fSRoy Marples ifo->options &=
24436e63cc1fSRoy Marples ~(DHCPCD_IPV6RA_AUTOCONF | DHCPCD_IPV6RA_REQRDNSS);
24447827cba2SAaron LI }
24457827cba2SAaron LI
24460b4c9755SRoy Marples static struct if_options *
default_config(struct dhcpcd_ctx * ctx)24477827cba2SAaron LI default_config(struct dhcpcd_ctx *ctx)
24487827cba2SAaron LI {
24497827cba2SAaron LI struct if_options *ifo;
24507827cba2SAaron LI
24517827cba2SAaron LI /* Seed our default options */
24527827cba2SAaron LI if ((ifo = calloc(1, sizeof(*ifo))) == NULL) {
24537827cba2SAaron LI logerr(__func__);
24547827cba2SAaron LI return NULL;
24557827cba2SAaron LI }
24567827cba2SAaron LI ifo->options |= DHCPCD_IF_UP | DHCPCD_LINK | DHCPCD_INITIAL_DELAY;
24577827cba2SAaron LI ifo->timeout = DEFAULT_TIMEOUT;
24587827cba2SAaron LI ifo->reboot = DEFAULT_REBOOT;
2459*54175cefSRoy Marples ifo->request_time = DEFAULT_REQUEST;
2460*54175cefSRoy Marples #ifdef INET
2461*54175cefSRoy Marples ifo->fallback_time = DEFAULT_FALLBACK;
2462*54175cefSRoy Marples ifo->ipv4ll_time = DEFAULT_IPV4LL;
2463*54175cefSRoy Marples #endif
24647827cba2SAaron LI ifo->metric = -1;
24657827cba2SAaron LI ifo->auth.options |= DHCPCD_AUTH_REQUIRE;
24668d36e1dfSRoy Marples rb_tree_init(&ifo->routes, &rt_compare_list_ops);
24677827cba2SAaron LI #ifdef AUTH
24687827cba2SAaron LI TAILQ_INIT(&ifo->auth.tokens);
24697827cba2SAaron LI #endif
24707827cba2SAaron LI
24717827cba2SAaron LI /* Inherit some global defaults */
247220329f2aSRoy Marples if (ctx->options & DHCPCD_CONFIGURE)
247320329f2aSRoy Marples ifo->options |= DHCPCD_CONFIGURE;
24747827cba2SAaron LI if (ctx->options & DHCPCD_PERSISTENT)
24757827cba2SAaron LI ifo->options |= DHCPCD_PERSISTENT;
24767827cba2SAaron LI if (ctx->options & DHCPCD_SLAACPRIVATE)
24777827cba2SAaron LI ifo->options |= DHCPCD_SLAACPRIVATE;
24787827cba2SAaron LI
24797827cba2SAaron LI return ifo;
24807827cba2SAaron LI }
24817827cba2SAaron LI
24827827cba2SAaron LI struct if_options *
read_config(struct dhcpcd_ctx * ctx,const char * ifname,const char * ssid,const char * profile)24837827cba2SAaron LI read_config(struct dhcpcd_ctx *ctx,
24847827cba2SAaron LI const char *ifname, const char *ssid, const char *profile)
24857827cba2SAaron LI {
24867827cba2SAaron LI struct if_options *ifo;
2487d4fb1e02SRoy Marples char buf[UDPLEN_MAX], *bp; /* 64k max config file size */
2488d4fb1e02SRoy Marples char *line, *option, *p;
2489d4fb1e02SRoy Marples ssize_t buflen;
2490d4fb1e02SRoy Marples size_t vlen;
24917827cba2SAaron LI int skip, have_profile, new_block, had_block;
24927827cba2SAaron LI #if !defined(INET) || !defined(INET6)
24937827cba2SAaron LI size_t i;
24947827cba2SAaron LI struct dhcp_opt *opt;
24957827cba2SAaron LI #endif
24967827cba2SAaron LI struct dhcp_opt *ldop, *edop;
24977827cba2SAaron LI
24987827cba2SAaron LI /* Seed our default options */
24997827cba2SAaron LI if ((ifo = default_config(ctx)) == NULL)
25007827cba2SAaron LI return NULL;
2501b8b69544SRoy Marples if (default_options == 0) {
250220329f2aSRoy Marples default_options |= DHCPCD_CONFIGURE | DHCPCD_DAEMONISE |
250320329f2aSRoy Marples DHCPCD_GATEWAY;
25047827cba2SAaron LI #ifdef INET
2505*54175cefSRoy Marples skip = xsocket(PF_INET, SOCK_DGRAM, 0);
2506b8b69544SRoy Marples if (skip != -1) {
2507b8b69544SRoy Marples close(skip);
2508b8b69544SRoy Marples default_options |= DHCPCD_IPV4 | DHCPCD_ARP |
2509b8b69544SRoy Marples DHCPCD_DHCP | DHCPCD_IPV4LL;
2510b8b69544SRoy Marples }
25117827cba2SAaron LI #endif
25127827cba2SAaron LI #ifdef INET6
2513*54175cefSRoy Marples skip = xsocket(PF_INET6, SOCK_DGRAM, 0);
2514b8b69544SRoy Marples if (skip != -1) {
2515b8b69544SRoy Marples close(skip);
2516b8b69544SRoy Marples default_options |= DHCPCD_IPV6 | DHCPCD_IPV6RS |
2517b8b69544SRoy Marples DHCPCD_IPV6RA_AUTOCONF | DHCPCD_IPV6RA_REQRDNSS |
2518b8b69544SRoy Marples DHCPCD_DHCP6;
2519b8b69544SRoy Marples }
25207827cba2SAaron LI #endif
2521b8b69544SRoy Marples #ifdef PLUGIN_DEV
2522b8b69544SRoy Marples default_options |= DHCPCD_DEV;
2523b8b69544SRoy Marples #endif
2524b8b69544SRoy Marples }
2525b8b69544SRoy Marples ifo->options |= default_options;
25267827cba2SAaron LI
2527cc34ba0cSRoy Marples CLEAR_CONFIG_BLOCK(ifo);
2528cc34ba0cSRoy Marples
2529d4fb1e02SRoy Marples vlen = strlcpy((char *)ifo->vendorclassid + 1, ctx->vendor,
25307827cba2SAaron LI sizeof(ifo->vendorclassid) - 1);
2531d4fb1e02SRoy Marples ifo->vendorclassid[0] = (uint8_t)(vlen > 255 ? 0 : vlen);
25327827cba2SAaron LI
25338d36e1dfSRoy Marples /* Reset route order */
25348d36e1dfSRoy Marples ctx->rt_order = 0;
25358d36e1dfSRoy Marples
25367827cba2SAaron LI /* Parse our embedded options file */
25377827cba2SAaron LI if (ifname == NULL && !(ctx->options & DHCPCD_PRINT_PIDFILE)) {
25387827cba2SAaron LI /* Space for initial estimates */
25397827cba2SAaron LI #if defined(INET) && defined(INITDEFINES)
25407827cba2SAaron LI ifo->dhcp_override =
25417827cba2SAaron LI calloc(INITDEFINES, sizeof(*ifo->dhcp_override));
25427827cba2SAaron LI if (ifo->dhcp_override == NULL)
25437827cba2SAaron LI logerr(__func__);
25447827cba2SAaron LI else
25457827cba2SAaron LI ifo->dhcp_override_len = INITDEFINES;
25467827cba2SAaron LI #endif
25477827cba2SAaron LI
25487827cba2SAaron LI #if defined(INET6) && defined(INITDEFINENDS)
25497827cba2SAaron LI ifo->nd_override =
25507827cba2SAaron LI calloc(INITDEFINENDS, sizeof(*ifo->nd_override));
25517827cba2SAaron LI if (ifo->nd_override == NULL)
25527827cba2SAaron LI logerr(__func__);
25537827cba2SAaron LI else
25547827cba2SAaron LI ifo->nd_override_len = INITDEFINENDS;
25557827cba2SAaron LI #endif
25567827cba2SAaron LI #if defined(INET6) && defined(INITDEFINE6S)
25577827cba2SAaron LI ifo->dhcp6_override =
25587827cba2SAaron LI calloc(INITDEFINE6S, sizeof(*ifo->dhcp6_override));
25597827cba2SAaron LI if (ifo->dhcp6_override == NULL)
25607827cba2SAaron LI logerr(__func__);
25617827cba2SAaron LI else
25627827cba2SAaron LI ifo->dhcp6_override_len = INITDEFINE6S;
25637827cba2SAaron LI #endif
25647827cba2SAaron LI
25657827cba2SAaron LI /* Now load our embedded config */
25667827cba2SAaron LI #ifdef EMBEDDED_CONFIG
2567d4fb1e02SRoy Marples buflen = dhcp_readfile(ctx, EMBEDDED_CONFIG, buf, sizeof(buf));
2568d4fb1e02SRoy Marples if (buflen == -1) {
2569d4fb1e02SRoy Marples logerr("%s: %s", __func__, EMBEDDED_CONFIG);
2570d4fb1e02SRoy Marples return ifo;
2571d4fb1e02SRoy Marples }
2572d4fb1e02SRoy Marples if (buf[buflen - 1] != '\0') {
25737f8103cdSRoy Marples if ((size_t)buflen < sizeof(buf) - 1)
25747f8103cdSRoy Marples buflen++;
2575d4fb1e02SRoy Marples buf[buflen - 1] = '\0';
2576d4fb1e02SRoy Marples }
25777827cba2SAaron LI #else
2578d4fb1e02SRoy Marples buflen = (ssize_t)strlcpy(buf, dhcpcd_embedded_conf,
2579d4fb1e02SRoy Marples sizeof(buf));
2580d4fb1e02SRoy Marples if ((size_t)buflen >= sizeof(buf)) {
2581d4fb1e02SRoy Marples logerrx("%s: embedded config too big", __func__);
2582d4fb1e02SRoy Marples return ifo;
25837827cba2SAaron LI }
2584d4fb1e02SRoy Marples /* Our embedded config is NULL terminated */
25857827cba2SAaron LI #endif
2586d4fb1e02SRoy Marples bp = buf;
2587d4fb1e02SRoy Marples while ((line = get_line(&bp, &buflen)) != NULL) {
25887827cba2SAaron LI option = strsep(&line, " \t");
25897827cba2SAaron LI if (line)
25907827cba2SAaron LI line = strskipwhite(line);
25917827cba2SAaron LI /* Trim trailing whitespace */
25927827cba2SAaron LI if (line) {
25937827cba2SAaron LI p = line + strlen(line) - 1;
25947827cba2SAaron LI while (p != line &&
25957827cba2SAaron LI (*p == ' ' || *p == '\t') &&
25967827cba2SAaron LI *(p - 1) != '\\')
25977827cba2SAaron LI *p-- = '\0';
25987827cba2SAaron LI }
25997827cba2SAaron LI parse_config_line(ctx, NULL, ifo, option, line,
26007827cba2SAaron LI &ldop, &edop);
26017827cba2SAaron LI }
26027827cba2SAaron LI
26037827cba2SAaron LI #ifdef INET
26047827cba2SAaron LI ctx->dhcp_opts = ifo->dhcp_override;
26057827cba2SAaron LI ctx->dhcp_opts_len = ifo->dhcp_override_len;
26067827cba2SAaron LI #else
26077827cba2SAaron LI for (i = 0, opt = ifo->dhcp_override;
26087827cba2SAaron LI i < ifo->dhcp_override_len;
26097827cba2SAaron LI i++, opt++)
26107827cba2SAaron LI free_dhcp_opt_embenc(opt);
26117827cba2SAaron LI free(ifo->dhcp_override);
26127827cba2SAaron LI #endif
26137827cba2SAaron LI ifo->dhcp_override = NULL;
26147827cba2SAaron LI ifo->dhcp_override_len = 0;
26157827cba2SAaron LI
26167827cba2SAaron LI #ifdef INET6
26177827cba2SAaron LI ctx->nd_opts = ifo->nd_override;
26187827cba2SAaron LI ctx->nd_opts_len = ifo->nd_override_len;
26198d36e1dfSRoy Marples #ifdef DHCP6
26207827cba2SAaron LI ctx->dhcp6_opts = ifo->dhcp6_override;
26217827cba2SAaron LI ctx->dhcp6_opts_len = ifo->dhcp6_override_len;
26228d36e1dfSRoy Marples #endif
26237827cba2SAaron LI #else
26247827cba2SAaron LI for (i = 0, opt = ifo->nd_override;
26257827cba2SAaron LI i < ifo->nd_override_len;
26267827cba2SAaron LI i++, opt++)
26277827cba2SAaron LI free_dhcp_opt_embenc(opt);
26287827cba2SAaron LI free(ifo->nd_override);
26297827cba2SAaron LI for (i = 0, opt = ifo->dhcp6_override;
26307827cba2SAaron LI i < ifo->dhcp6_override_len;
26317827cba2SAaron LI i++, opt++)
26327827cba2SAaron LI free_dhcp_opt_embenc(opt);
26337827cba2SAaron LI free(ifo->dhcp6_override);
26347827cba2SAaron LI #endif
26357827cba2SAaron LI ifo->nd_override = NULL;
26367827cba2SAaron LI ifo->nd_override_len = 0;
26377827cba2SAaron LI ifo->dhcp6_override = NULL;
26387827cba2SAaron LI ifo->dhcp6_override_len = 0;
26397827cba2SAaron LI
26407827cba2SAaron LI ctx->vivso = ifo->vivso_override;
26417827cba2SAaron LI ctx->vivso_len = ifo->vivso_override_len;
26427827cba2SAaron LI ifo->vivso_override = NULL;
26437827cba2SAaron LI ifo->vivso_override_len = 0;
26447827cba2SAaron LI }
26457827cba2SAaron LI
26467827cba2SAaron LI /* Parse our options file */
2647d4fb1e02SRoy Marples buflen = dhcp_readfile(ctx, ctx->cffile, buf, sizeof(buf));
2648d4fb1e02SRoy Marples if (buflen == -1) {
26497827cba2SAaron LI /* dhcpcd can continue without it, but no DNS options
26507827cba2SAaron LI * would be requested ... */
2651d4fb1e02SRoy Marples logerr("%s: %s", __func__, ctx->cffile);
26527827cba2SAaron LI return ifo;
26537827cba2SAaron LI }
2654d4fb1e02SRoy Marples if (buf[buflen - 1] != '\0') {
2655d4fb1e02SRoy Marples if ((size_t)buflen < sizeof(buf) - 1)
2656d4fb1e02SRoy Marples buflen++;
2657d4fb1e02SRoy Marples buf[buflen - 1] = '\0';
2658d4fb1e02SRoy Marples }
2659d4fb1e02SRoy Marples dhcp_filemtime(ctx, ctx->cffile, &ifo->mtime);
26607827cba2SAaron LI
26617827cba2SAaron LI ldop = edop = NULL;
26627827cba2SAaron LI skip = have_profile = new_block = 0;
26637827cba2SAaron LI had_block = ifname == NULL ? 1 : 0;
2664d4fb1e02SRoy Marples bp = buf;
2665d4fb1e02SRoy Marples while ((line = get_line(&bp, &buflen)) != NULL) {
26667827cba2SAaron LI option = strsep(&line, " \t");
26677827cba2SAaron LI if (line)
26687827cba2SAaron LI line = strskipwhite(line);
26697827cba2SAaron LI /* Trim trailing whitespace */
26707827cba2SAaron LI if (line) {
26717827cba2SAaron LI p = line + strlen(line) - 1;
26727827cba2SAaron LI while (p != line &&
26737827cba2SAaron LI (*p == ' ' || *p == '\t') &&
26747827cba2SAaron LI *(p - 1) != '\\')
26757827cba2SAaron LI *p-- = '\0';
26767827cba2SAaron LI }
26777827cba2SAaron LI if (skip == 0 && new_block) {
26787827cba2SAaron LI had_block = 1;
26797827cba2SAaron LI new_block = 0;
26807827cba2SAaron LI ifo->options &= ~DHCPCD_WAITOPTS;
2681cc34ba0cSRoy Marples SET_CONFIG_BLOCK(ifo);
26827827cba2SAaron LI }
2683cc34ba0cSRoy Marples
26847827cba2SAaron LI /* Start of an interface block, skip if not ours */
26857827cba2SAaron LI if (strcmp(option, "interface") == 0) {
26867827cba2SAaron LI char **n;
26877827cba2SAaron LI
26887827cba2SAaron LI new_block = 1;
26897827cba2SAaron LI if (line == NULL) {
26907827cba2SAaron LI /* No interface given */
26917827cba2SAaron LI skip = 1;
26927827cba2SAaron LI continue;
26937827cba2SAaron LI }
26947827cba2SAaron LI if (ifname && strcmp(line, ifname) == 0)
26957827cba2SAaron LI skip = 0;
26967827cba2SAaron LI else
26977827cba2SAaron LI skip = 1;
26987827cba2SAaron LI if (ifname)
26997827cba2SAaron LI continue;
27007827cba2SAaron LI
27017827cba2SAaron LI n = reallocarray(ctx->ifcv,
27027827cba2SAaron LI (size_t)ctx->ifcc + 1, sizeof(char *));
27037827cba2SAaron LI if (n == NULL) {
27047827cba2SAaron LI logerr(__func__);
27057827cba2SAaron LI continue;
27067827cba2SAaron LI }
27077827cba2SAaron LI ctx->ifcv = n;
27087827cba2SAaron LI ctx->ifcv[ctx->ifcc] = strdup(line);
27097827cba2SAaron LI if (ctx->ifcv[ctx->ifcc] == NULL) {
27107827cba2SAaron LI logerr(__func__);
27117827cba2SAaron LI continue;
27127827cba2SAaron LI }
27137827cba2SAaron LI ctx->ifcc++;
27147827cba2SAaron LI continue;
27157827cba2SAaron LI }
27167827cba2SAaron LI /* Start of an ssid block, skip if not ours */
27177827cba2SAaron LI if (strcmp(option, "ssid") == 0) {
27187827cba2SAaron LI new_block = 1;
27197827cba2SAaron LI if (ssid && line && strcmp(line, ssid) == 0)
27207827cba2SAaron LI skip = 0;
27217827cba2SAaron LI else
27227827cba2SAaron LI skip = 1;
27237827cba2SAaron LI continue;
27247827cba2SAaron LI }
27257827cba2SAaron LI /* Start of a profile block, skip if not ours */
27267827cba2SAaron LI if (strcmp(option, "profile") == 0) {
27277827cba2SAaron LI new_block = 1;
27287827cba2SAaron LI if (profile && line && strcmp(line, profile) == 0) {
27297827cba2SAaron LI skip = 0;
27307827cba2SAaron LI have_profile = 1;
27317827cba2SAaron LI } else
27327827cba2SAaron LI skip = 1;
27337827cba2SAaron LI continue;
27347827cba2SAaron LI }
27357827cba2SAaron LI /* Skip arping if we have selected a profile but not parsing
27367827cba2SAaron LI * one. */
27377827cba2SAaron LI if (profile && !have_profile && strcmp(option, "arping") == 0)
27387827cba2SAaron LI continue;
27397827cba2SAaron LI if (skip)
27407827cba2SAaron LI continue;
2741d4fb1e02SRoy Marples
27427827cba2SAaron LI parse_config_line(ctx, ifname, ifo, option, line, &ldop, &edop);
27437827cba2SAaron LI }
27447827cba2SAaron LI
27457827cba2SAaron LI if (profile && !have_profile) {
27467827cba2SAaron LI free_options(ctx, ifo);
27477827cba2SAaron LI errno = ENOENT;
27487827cba2SAaron LI return NULL;
27497827cba2SAaron LI }
27507827cba2SAaron LI
27517827cba2SAaron LI if (!had_block)
27527827cba2SAaron LI ifo->options &= ~DHCPCD_WAITOPTS;
2753cc34ba0cSRoy Marples CLEAR_CONFIG_BLOCK(ifo);
27547827cba2SAaron LI finish_config(ifo);
27557827cba2SAaron LI return ifo;
27567827cba2SAaron LI }
27577827cba2SAaron LI
27587827cba2SAaron LI int
add_options(struct dhcpcd_ctx * ctx,const char * ifname,struct if_options * ifo,int argc,char ** argv)27597827cba2SAaron LI add_options(struct dhcpcd_ctx *ctx, const char *ifname,
27607827cba2SAaron LI struct if_options *ifo, int argc, char **argv)
27617827cba2SAaron LI {
27627827cba2SAaron LI int oi, opt, r;
27637827cba2SAaron LI unsigned long long wait_opts;
27647827cba2SAaron LI
27657827cba2SAaron LI if (argc == 0)
27667827cba2SAaron LI return 1;
27677827cba2SAaron LI
27687827cba2SAaron LI optind = 0;
27697827cba2SAaron LI r = 1;
27707827cba2SAaron LI /* Don't apply the command line wait options to each interface,
27717827cba2SAaron LI * only use the dhcpcd.conf entry for that. */
27727827cba2SAaron LI if (ifname != NULL)
27737827cba2SAaron LI wait_opts = ifo->options & DHCPCD_WAITOPTS;
27747827cba2SAaron LI while ((opt = getopt_long(argc, argv,
27757827cba2SAaron LI ctx->options & DHCPCD_PRINT_PIDFILE ? NOERR_IF_OPTS : IF_OPTS,
27767827cba2SAaron LI cf_options, &oi)) != -1)
27777827cba2SAaron LI {
27787827cba2SAaron LI r = parse_option(ctx, ifname, ifo, opt, optarg, NULL, NULL);
27797827cba2SAaron LI if (r != 1)
27807827cba2SAaron LI break;
27817827cba2SAaron LI }
27827827cba2SAaron LI if (ifname != NULL) {
27837827cba2SAaron LI ifo->options &= ~DHCPCD_WAITOPTS;
27847827cba2SAaron LI ifo->options |= wait_opts;
27857827cba2SAaron LI }
27867827cba2SAaron LI
27877827cba2SAaron LI finish_config(ifo);
27887827cba2SAaron LI return r;
27897827cba2SAaron LI }
27907827cba2SAaron LI
27917827cba2SAaron LI void
free_options(struct dhcpcd_ctx * ctx,struct if_options * ifo)27927827cba2SAaron LI free_options(struct dhcpcd_ctx *ctx, struct if_options *ifo)
27937827cba2SAaron LI {
27947827cba2SAaron LI size_t i;
27958d36e1dfSRoy Marples #ifdef RT_FREE_ROUTE_TABLE
27968d36e1dfSRoy Marples struct interface *ifp;
27978d36e1dfSRoy Marples struct rt *rt;
27988d36e1dfSRoy Marples #endif
27997827cba2SAaron LI struct dhcp_opt *opt;
28007827cba2SAaron LI struct vivco *vo;
28017827cba2SAaron LI #ifdef AUTH
28027827cba2SAaron LI struct token *token;
28037827cba2SAaron LI #endif
28047827cba2SAaron LI
28058d36e1dfSRoy Marples if (ifo == NULL)
28068d36e1dfSRoy Marples return;
28078d36e1dfSRoy Marples
28087827cba2SAaron LI if (ifo->environ) {
28097827cba2SAaron LI i = 0;
28107827cba2SAaron LI while (ifo->environ[i])
28117827cba2SAaron LI free(ifo->environ[i++]);
28127827cba2SAaron LI free(ifo->environ);
28137827cba2SAaron LI }
28147827cba2SAaron LI if (ifo->config) {
28157827cba2SAaron LI i = 0;
28167827cba2SAaron LI while (ifo->config[i])
28177827cba2SAaron LI free(ifo->config[i++]);
28187827cba2SAaron LI free(ifo->config);
28197827cba2SAaron LI }
28208d36e1dfSRoy Marples
28218d36e1dfSRoy Marples #ifdef RT_FREE_ROUTE_TABLE
28228d36e1dfSRoy Marples /* Stupidly, we don't know the interface when creating the options.
28238d36e1dfSRoy Marples * As such, make sure each route has one so they can goto the
28248d36e1dfSRoy Marples * free list. */
28258d36e1dfSRoy Marples ifp = ctx->ifaces != NULL ? TAILQ_FIRST(ctx->ifaces) : NULL;
28268d36e1dfSRoy Marples if (ifp != NULL) {
28278d36e1dfSRoy Marples RB_TREE_FOREACH(rt, &ifo->routes) {
28288d36e1dfSRoy Marples if (rt->rt_ifp == NULL)
28298d36e1dfSRoy Marples rt->rt_ifp = ifp;
28308d36e1dfSRoy Marples }
28318d36e1dfSRoy Marples }
28328d36e1dfSRoy Marples #endif
28337827cba2SAaron LI rt_headclear0(ctx, &ifo->routes, AF_UNSPEC);
28348d36e1dfSRoy Marples
28357827cba2SAaron LI free(ifo->arping);
28367827cba2SAaron LI free(ifo->blacklist);
28377827cba2SAaron LI free(ifo->fallback);
28387827cba2SAaron LI
28397827cba2SAaron LI for (opt = ifo->dhcp_override;
28407827cba2SAaron LI ifo->dhcp_override_len > 0;
28417827cba2SAaron LI opt++, ifo->dhcp_override_len--)
28427827cba2SAaron LI free_dhcp_opt_embenc(opt);
28437827cba2SAaron LI free(ifo->dhcp_override);
28447827cba2SAaron LI for (opt = ifo->nd_override;
28457827cba2SAaron LI ifo->nd_override_len > 0;
28467827cba2SAaron LI opt++, ifo->nd_override_len--)
28477827cba2SAaron LI free_dhcp_opt_embenc(opt);
28487827cba2SAaron LI free(ifo->nd_override);
28497827cba2SAaron LI for (opt = ifo->dhcp6_override;
28507827cba2SAaron LI ifo->dhcp6_override_len > 0;
28517827cba2SAaron LI opt++, ifo->dhcp6_override_len--)
28527827cba2SAaron LI free_dhcp_opt_embenc(opt);
28537827cba2SAaron LI free(ifo->dhcp6_override);
28547827cba2SAaron LI for (vo = ifo->vivco;
28557827cba2SAaron LI ifo->vivco_len > 0;
28567827cba2SAaron LI vo++, ifo->vivco_len--)
28577827cba2SAaron LI free(vo->data);
28587827cba2SAaron LI free(ifo->vivco);
28597827cba2SAaron LI for (opt = ifo->vivso_override;
28607827cba2SAaron LI ifo->vivso_override_len > 0;
28617827cba2SAaron LI opt++, ifo->vivso_override_len--)
28627827cba2SAaron LI free_dhcp_opt_embenc(opt);
28637827cba2SAaron LI free(ifo->vivso_override);
28647827cba2SAaron LI
28657827cba2SAaron LI #if defined(INET6) && !defined(SMALL)
28667827cba2SAaron LI for (; ifo->ia_len > 0; ifo->ia_len--)
28677827cba2SAaron LI free(ifo->ia[ifo->ia_len - 1].sla);
28687827cba2SAaron LI #endif
28697827cba2SAaron LI free(ifo->ia);
28707827cba2SAaron LI
28717827cba2SAaron LI #ifdef AUTH
28727827cba2SAaron LI while ((token = TAILQ_FIRST(&ifo->auth.tokens))) {
28737827cba2SAaron LI TAILQ_REMOVE(&ifo->auth.tokens, token, next);
28747827cba2SAaron LI if (token->realm_len)
28757827cba2SAaron LI free(token->realm);
28767827cba2SAaron LI free(token->key);
28777827cba2SAaron LI free(token);
28787827cba2SAaron LI }
28797827cba2SAaron LI #endif
28807827cba2SAaron LI free(ifo);
28817827cba2SAaron LI }
2882