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