]> git.ipfire.org Git - thirdparty/dhcpcd.git/blame - src/if-options.c
options: allow static routes to be configured on the command line
[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') {
6dc3763d
RM
818 /* Strip out a broadcast address */
819 p = strchr(arg, '/');
820 if (p != NULL) {
821 p = strchr(p + 1, '/');
822 if (p != NULL)
823 *p = '\0';
824 }
825 i = parse_addr(&ifo->req_addr, &ifo->req_mask, arg);
826 if (p != NULL) {
827 /* Ensure the original string is preserved */
828 *p++ = '/';
829 if (i == 0)
830 i = parse_addr(&ifo->req_brd, NULL, p);
831 }
832 if (i != 0)
91a44b91 833 return -1;
2f7cb97c
RM
834 } else {
835 ifo->req_addr.s_addr = 0;
836 ifo->req_mask.s_addr = 0;
fd05b7dc 837 }
5b39d8f5 838 ifo->options |= DHCPCD_INFORM | DHCPCD_PERSISTENT;
10e16029 839 ifo->options &= ~DHCPCD_STATIC;
91a44b91 840 break;
567a2357
RM
841 case O_INFORM6:
842 ifo->options |= DHCPCD_INFORM6;
843 break;
fd05b7dc 844 case 't':
6bcb242d 845 ARG_REQUIRED;
f94b4eab
RM
846 ifo->timeout = (time_t)strtoi(arg, NULL, 0, 0, INT32_MAX, &e);
847 if (e) {
94d1ded9 848 logerrx("failed to convert timeout %s", arg);
fd05b7dc
RM
849 return -1;
850 }
851 break;
852 case 'u':
853 s = USERCLASS_MAX_LEN - ifo->userclass[0] - 1;
eab2229c 854 s = parse_string((char *)ifo->userclass +
34457fe6 855 ifo->userclass[0] + 2, (size_t)s, arg);
fd05b7dc 856 if (s == -1) {
94d1ded9 857 logerr("userclass");
fd05b7dc
RM
858 return -1;
859 }
860 if (s != 0) {
34457fe6 861 ifo->userclass[ifo->userclass[0] + 1] = (uint8_t)s;
d7a4dcf9 862 ifo->userclass[0] = (uint8_t)(ifo->userclass[0] + s +1);
fd05b7dc
RM
863 }
864 break;
865 case 'v':
6bcb242d 866 ARG_REQUIRED;
fd05b7dc
RM
867 p = strchr(arg, ',');
868 if (!p || !p[1]) {
94d1ded9 869 logerrx("invalid vendor format: %s", arg);
fd05b7dc
RM
870 return -1;
871 }
95d6dcfa
RM
872
873 /* If vendor starts with , then it is not encapsulated */
874 if (p == arg) {
875 arg++;
876 s = parse_string((char *)ifo->vendor + 1,
877 VENDOR_MAX_LEN, arg);
878 if (s == -1) {
94d1ded9 879 logerr("vendor");
95d6dcfa
RM
880 return -1;
881 }
882 ifo->vendor[0] = (uint8_t)s;
883 ifo->options |= DHCPCD_VENDORRAW;
884 break;
885 }
886
887 /* Encapsulated vendor options */
888 if (ifo->options & DHCPCD_VENDORRAW) {
889 ifo->options &= ~DHCPCD_VENDORRAW;
890 ifo->vendor[0] = 0;
891 }
892
d7a4dcf9
RM
893 /* Strip and preserve the comma */
894 *p = '\0';
f94b4eab 895 i = (int)strtoi(arg, NULL, 0, 1, 254, &e);
d7a4dcf9 896 *p = ',';
f94b4eab 897 if (e) {
94d1ded9 898 logerrx("vendor option should be between"
eab2229c 899 " 1 and 254 inclusive");
fd05b7dc
RM
900 return -1;
901 }
b357d09f
RM
902
903 arg = p + 1;
fd05b7dc
RM
904 s = VENDOR_MAX_LEN - ifo->vendor[0] - 2;
905 if (inet_aton(arg, &addr) == 1) {
906 if (s < 6) {
907 s = -1;
908 errno = ENOBUFS;
aeddc61a 909 } else {
fd05b7dc 910 memcpy(ifo->vendor + ifo->vendor[0] + 3,
eab2229c 911 &addr.s_addr, sizeof(addr.s_addr));
aeddc61a
RM
912 s = sizeof(addr.s_addr);
913 }
fd05b7dc 914 } else {
eab2229c 915 s = parse_string((char *)ifo->vendor +
34457fe6 916 ifo->vendor[0] + 3, (size_t)s, arg);
fd05b7dc
RM
917 }
918 if (s == -1) {
94d1ded9 919 logerr("vendor");
fd05b7dc
RM
920 return -1;
921 }
922 if (s != 0) {
34457fe6
RM
923 ifo->vendor[ifo->vendor[0] + 1] = (uint8_t)i;
924 ifo->vendor[ifo->vendor[0] + 2] = (uint8_t)s;
d7a4dcf9 925 ifo->vendor[0] = (uint8_t)(ifo->vendor[0] + s + 2);
fd05b7dc
RM
926 }
927 break;
2a07a2af
RM
928 case 'w':
929 ifo->options |= DHCPCD_WAITIP;
7013b073
RM
930 if (arg != NULL && arg[0] != '\0') {
931 if (arg[0] == '4' || arg[1] == '4')
932 ifo->options |= DHCPCD_WAITIP4;
933 if (arg[0] == '6' || arg[1] == '6')
934 ifo->options |= DHCPCD_WAITIP6;
935 }
2a07a2af 936 break;
a2a9a498 937 case 'y':
6bcb242d 938 ARG_REQUIRED;
f94b4eab
RM
939 ifo->reboot = (time_t)strtoi(arg, NULL, 0, 0, UINT32_MAX, &e);
940 if (e) {
94d1ded9 941 logerr("failed to convert reboot %s", arg);
a2a9a498
RM
942 return -1;
943 }
944 break;
d3088c74 945 case 'z':
6bcb242d 946 ARG_REQUIRED;
4eb7b489 947 if (ifname == NULL)
03274c9c 948 ctx->ifav = splitv(&ctx->ifac, ctx->ifav, arg);
d3088c74 949 break;
fd05b7dc
RM
950 case 'A':
951 ifo->options &= ~DHCPCD_ARP;
952 /* IPv4LL requires ARP */
953 ifo->options &= ~DHCPCD_IPV4LL;
954 break;
03c2c879
RM
955 case 'B':
956 ifo->options &= ~DHCPCD_DAEMONISE;
957 break;
fd05b7dc 958 case 'C':
6bcb242d 959 ARG_REQUIRED;
fd05b7dc
RM
960 /* Commas to spaces for shell */
961 while ((p = strchr(arg, ',')))
962 *p = ' ';
34457fe6
RM
963 dl = strlen("skip_hooks=") + strlen(arg) + 1;
964 p = malloc(sizeof(char) * dl);
28382337 965 if (p == NULL) {
94d1ded9 966 logerr(__func__);
28382337
RM
967 return -1;
968 }
34457fe6 969 snprintf(p, dl, "skip_hooks=%s", arg);
03274c9c 970 add_environ(ifo, p, 0);
fd05b7dc
RM
971 free(p);
972 break;
973 case 'D':
c989b023 974 ifo->options |= DHCPCD_CLIENTID | DHCPCD_DUID;
fd05b7dc
RM
975 break;
976 case 'E':
977 ifo->options |= DHCPCD_LASTLEASE;
978 break;
979 case 'F':
980 if (!arg) {
981 ifo->fqdn = FQDN_BOTH;
982 break;
983 }
984 if (strcmp(arg, "none") == 0)
985 ifo->fqdn = FQDN_NONE;
986 else if (strcmp(arg, "ptr") == 0)
987 ifo->fqdn = FQDN_PTR;
988 else if (strcmp(arg, "both") == 0)
989 ifo->fqdn = FQDN_BOTH;
990 else if (strcmp(arg, "disable") == 0)
991 ifo->fqdn = FQDN_DISABLE;
992 else {
94d1ded9 993 logerrx("invalid value `%s' for FQDN", arg);
fd05b7dc
RM
994 return -1;
995 }
996 break;
feb553d0
RM
997 case 'G':
998 ifo->options &= ~DHCPCD_GATEWAY;
999 break;
4242c9b3
RM
1000 case 'H':
1001 ifo->options |= DHCPCD_XID_HWADDR;
1002 break;
fd05b7dc
RM
1003 case 'I':
1004 /* Strings have a type of 0 */;
1005 ifo->clientid[1] = 0;
1006 if (arg)
1007 s = parse_string_hwaddr((char *)ifo->clientid + 1,
eab2229c 1008 CLIENTID_MAX_LEN, arg, 1);
fd05b7dc
RM
1009 else
1010 s = 0;
1011 if (s == -1) {
94d1ded9 1012 logerr("clientid");
fd05b7dc
RM
1013 return -1;
1014 }
c989b023 1015 ifo->options |= DHCPCD_CLIENTID;
fd05b7dc 1016 ifo->clientid[0] = (uint8_t)s;
fd05b7dc 1017 break;
900b3da4
RM
1018 case 'J':
1019 ifo->options |= DHCPCD_BROADCAST;
1020 break;
fd05b7dc
RM
1021 case 'K':
1022 ifo->options &= ~DHCPCD_LINK;
1023 break;
1024 case 'L':
1025 ifo->options &= ~DHCPCD_IPV4LL;
1026 break;
b3174181
RM
1027 case 'M':
1028 ifo->options |= DHCPCD_MASTER;
1029 break;
fd05b7dc 1030 case 'O':
6bcb242d 1031 ARG_REQUIRED;
49b749f0 1032 arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
85bff648 1033 &request, &require, &no, &reject);
49b749f0
RM
1034 if (make_option_mask(d, dl, od, odl, request, arg, -1) != 0 ||
1035 make_option_mask(d, dl, od, odl, require, arg, -1) != 0 ||
1036 make_option_mask(d, dl, od, odl, no, arg, 1) != 0)
fd05b7dc 1037 {
94d1ded9 1038 logerrx("unknown option `%s'", arg);
fd05b7dc
RM
1039 return -1;
1040 }
1041 break;
1042 case 'Q':
6bcb242d 1043 ARG_REQUIRED;
49b749f0 1044 arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
85bff648 1045 &request, &require, &no, &reject);
49b749f0
RM
1046 if (make_option_mask(d, dl, od, odl, require, arg, 1) != 0 ||
1047 make_option_mask(d, dl, od, odl, request, arg, 1) != 0 ||
85bff648
RM
1048 make_option_mask(d, dl, od, odl, no, arg, -1) != 0 ||
1049 make_option_mask(d, dl, od, odl, reject, arg, -1) != 0)
fd05b7dc 1050 {
94d1ded9 1051 logerrx("unknown option `%s'", arg);
fd05b7dc
RM
1052 return -1;
1053 }
1054 break;
91a44b91 1055 case 'S':
6bcb242d 1056 ARG_REQUIRED;
91a44b91
RM
1057 p = strchr(arg, '=');
1058 if (p == NULL) {
94d1ded9 1059 logerrx("static assignment required");
91a44b91
RM
1060 return -1;
1061 }
1062 p++;
1063 if (strncmp(arg, "ip_address=", strlen("ip_address=")) == 0) {
03274c9c 1064 if (parse_addr(&ifo->req_addr,
776961cf
RM
1065 ifo->req_mask.s_addr == 0 ? &ifo->req_mask : NULL,
1066 p) != 0)
91a44b91
RM
1067 return -1;
1068
1069 ifo->options |= DHCPCD_STATIC;
fa8b2a7a 1070 ifo->options &= ~DHCPCD_INFORM;
069e2f28
RM
1071 } else if (strncmp(arg, "subnet_mask=",
1072 strlen("subnet_mask=")) == 0)
1073 {
03274c9c 1074 if (parse_addr(&ifo->req_mask, NULL, p) != 0)
776961cf 1075 return -1;
6dc3763d
RM
1076 } else if (strncmp(arg, "broadcast_address=",
1077 strlen("broadcast_address=")) == 0)
1078 {
1079 if (parse_addr(&ifo->req_brd, NULL, p) != 0)
1080 return -1;
91a44b91 1081 } else if (strncmp(arg, "routes=", strlen("routes=")) == 0 ||
069e2f28
RM
1082 strncmp(arg, "static_routes=",
1083 strlen("static_routes=")) == 0 ||
1084 strncmp(arg, "classless_static_routes=",
1085 strlen("classless_static_routes=")) == 0 ||
1086 strncmp(arg, "ms_classless_static_routes=",
1087 strlen("ms_classless_static_routes=")) == 0)
91a44b91 1088 {
9aa11487
RM
1089 struct in_addr addr3;
1090
1cd05a96 1091 fp = np = strwhite(p);
91a44b91 1092 if (np == NULL) {
94d1ded9 1093 logerrx("all routes need a gateway");
91a44b91
RM
1094 return -1;
1095 }
1096 *np++ = '\0';
1cd05a96 1097 np = strskipwhite(np);
03274c9c
RM
1098 if (parse_addr(&addr, &addr2, p) == -1 ||
1099 parse_addr(&addr3, NULL, np) == -1)
9aa11487 1100 {
4c9c4b3e
RM
1101 *fp = ' ';
1102 return -1;
91a44b91 1103 }
77cdf115 1104 if ((rt = rt_new0(ctx)) == NULL) {
332a5fe6 1105 *fp = ' ';
91a44b91 1106 return -1;
332a5fe6 1107 }
9aa11487
RM
1108 sa_in_init(&rt->rt_dest, &addr);
1109 sa_in_init(&rt->rt_netmask, &addr2);
1110 sa_in_init(&rt->rt_gateway, &addr3);
1111 TAILQ_INSERT_TAIL(&ifo->routes, rt, rt_next);
332a5fe6 1112 *fp = ' ';
91a44b91 1113 } else if (strncmp(arg, "routers=", strlen("routers=")) == 0) {
03274c9c 1114 if (parse_addr(&addr, NULL, p) == -1)
4c9c4b3e 1115 return -1;
77cdf115 1116 if ((rt = rt_new0(ctx)) == NULL)
91a44b91 1117 return -1;
9aa11487
RM
1118 addr2.s_addr = INADDR_ANY;
1119 sa_in_init(&rt->rt_dest, &addr2);
1120 sa_in_init(&rt->rt_netmask, &addr2);
1121 sa_in_init(&rt->rt_gateway, &addr);
1122 TAILQ_INSERT_TAIL(&ifo->routes, rt, rt_next);
afcd7cbd
RM
1123 } else if (strncmp(arg, "interface_mtu=",
1124 strlen("interface_mtu=")) == 0 ||
1125 strncmp(arg, "mtu=", strlen("mtu=")) == 0)
1126 {
1127 ifo->mtu = (unsigned int)strtou(p, NULL, 0,
1128 MTU_MIN, MTU_MAX, &e);
1129 if (e) {
94d1ded9 1130 logerrx("invalid MTU %s", p);
afcd7cbd
RM
1131 return -1;
1132 }
408fe755
RM
1133 } else if (strncmp(arg, "ip6_address=", strlen("ip6_address=")) == 0) {
1134 np = strchr(p, '/');
1135 if (np)
1136 *np++ = '\0';
1137 if (inet_pton(AF_INET6, p, &ifo->req_addr6) == 1) {
1138 if (np) {
1139 ifo->req_prefix_len = (uint8_t)strtou(np,
1140 NULL, 0, 0, 128, &e);
1141 if (e) {
94d1ded9 1142 logerrx("%s: failed to "
408fe755
RM
1143 "convert prefix len",
1144 ifname);
1145 return -1;
1146 }
1147 } else
1148 ifo->req_prefix_len = 128;
1149 }
91a44b91 1150 } else {
34457fe6 1151 dl = 0;
91a44b91 1152 if (ifo->config != NULL) {
34457fe6
RM
1153 while (ifo->config[dl] != NULL) {
1154 if (strncmp(ifo->config[dl], arg,
1155 (size_t)(p - arg)) == 0)
eab2229c 1156 {
78369646
RM
1157 p = strdup(arg);
1158 if (p == NULL) {
94d1ded9 1159 logerr(__func__);
78369646
RM
1160 return -1;
1161 }
34457fe6
RM
1162 free(ifo->config[dl]);
1163 ifo->config[dl] = p;
91a44b91
RM
1164 return 1;
1165 }
34457fe6 1166 dl++;
91a44b91
RM
1167 }
1168 }
78369646 1169 p = strdup(arg);
fa245a4d 1170 if (p == NULL) {
94d1ded9 1171 logerr(__func__);
fa245a4d
RM
1172 return -1;
1173 }
ebdb8730 1174 nconf = reallocarray(ifo->config, dl+2, sizeof(char *));
78369646 1175 if (nconf == NULL) {
94d1ded9 1176 logerr(__func__);
66ca918f 1177 free(p);
78369646
RM
1178 return -1;
1179 }
fa245a4d 1180 ifo->config = nconf;
34457fe6
RM
1181 ifo->config[dl] = p;
1182 ifo->config[dl + 1] = NULL;
91a44b91
RM
1183 }
1184 break;
bf80d526 1185 case 'W':
03274c9c 1186 if (parse_addr(&addr, &addr2, arg) != 0)
bf80d526
RM
1187 return -1;
1188 if (strchr(arg, '/') == NULL)
1189 addr2.s_addr = INADDR_BROADCAST;
62c5b972
RM
1190 naddr = reallocarray(ifo->whitelist,
1191 ifo->whitelist_len + 2, sizeof(in_addr_t));
fa245a4d 1192 if (naddr == NULL) {
94d1ded9 1193 logerr(__func__);
fa245a4d
RM
1194 return -1;
1195 }
1196 ifo->whitelist = naddr;
bf80d526
RM
1197 ifo->whitelist[ifo->whitelist_len++] = addr.s_addr;
1198 ifo->whitelist[ifo->whitelist_len++] = addr2.s_addr;
1199 break;
fd05b7dc 1200 case 'X':
03274c9c 1201 if (parse_addr(&addr, &addr2, arg) != 0)
fd05b7dc 1202 return -1;
ce6b39df
RM
1203 if (strchr(arg, '/') == NULL)
1204 addr2.s_addr = INADDR_BROADCAST;
62c5b972
RM
1205 naddr = reallocarray(ifo->blacklist,
1206 ifo->blacklist_len + 2, sizeof(in_addr_t));
fa245a4d 1207 if (naddr == NULL) {
94d1ded9 1208 logerr(__func__);
fa245a4d
RM
1209 return -1;
1210 }
1211 ifo->blacklist = naddr;
e095a6eb
RM
1212 ifo->blacklist[ifo->blacklist_len++] = addr.s_addr;
1213 ifo->blacklist[ifo->blacklist_len++] = addr2.s_addr;
fd05b7dc 1214 break;
d3088c74 1215 case 'Z':
6bcb242d 1216 ARG_REQUIRED;
4eb7b489 1217 if (ifname == NULL)
03274c9c 1218 ctx->ifdv = splitv(&ctx->ifdc, ctx->ifdv, arg);
d3088c74 1219 break;
df574999
RM
1220 case '1':
1221 ifo->options |= DHCPCD_ONESHOT;
1222 break;
d7555c12 1223 case '4':
2f0addfd 1224 ifo->options &= ~DHCPCD_IPV6;
d7555c12
RM
1225 ifo->options |= DHCPCD_IPV4;
1226 break;
1227 case '6':
1228 ifo->options &= ~DHCPCD_IPV4;
2f0addfd 1229 ifo->options |= DHCPCD_IPV6;
d7555c12 1230 break;
94bec972
RM
1231 case O_IPV4:
1232 ifo->options |= DHCPCD_IPV4;
1233 break;
bb8051bf
RM
1234 case O_NOIPV4:
1235 ifo->options &= ~DHCPCD_IPV4;
1236 break;
94bec972
RM
1237 case O_IPV6:
1238 ifo->options |= DHCPCD_IPV6;
1239 break;
bb8051bf
RM
1240 case O_NOIPV6:
1241 ifo->options &= ~DHCPCD_IPV6;
1242 break;
aae24feb 1243#ifdef INET
4ca7460f 1244 case O_ARPING:
79f1f126 1245 while (arg != NULL) {
48ac077b
RM
1246 fp = strwhite(arg);
1247 if (fp)
1248 *fp++ = '\0';
03274c9c 1249 if (parse_addr(&addr, NULL, arg) != 0)
48ac077b 1250 return -1;
62c5b972
RM
1251 naddr = reallocarray(ifo->arping,
1252 (size_t)ifo->arping_len + 1, sizeof(in_addr_t));
48ac077b 1253 if (naddr == NULL) {
94d1ded9 1254 logerr(__func__);
48ac077b
RM
1255 return -1;
1256 }
1257 ifo->arping = naddr;
1258 ifo->arping[ifo->arping_len++] = addr.s_addr;
4dd50184 1259 arg = strskipwhite(fp);
fa245a4d 1260 }
4ca7460f 1261 break;
41c60e02 1262 case O_DESTINATION:
6bcb242d 1263 ARG_REQUIRED;
49b749f0 1264 arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
85bff648 1265 &request, &require, &no, &reject);
49b749f0
RM
1266 if (make_option_mask(d, dl, od, odl,
1267 ifo->dstmask, arg, 2) != 0)
1268 {
41c60e02 1269 if (errno == EINVAL)
94d1ded9 1270 logerrx("option `%s' does not take"
41c60e02
RM
1271 " an IPv4 address", arg);
1272 else
94d1ded9 1273 logerrx("unknown option `%s'", arg);
41c60e02
RM
1274 return -1;
1275 }
1276 break;
ff021b0b 1277 case O_FALLBACK:
6bcb242d 1278 ARG_REQUIRED;
ff021b0b 1279 free(ifo->fallback);
78369646
RM
1280 ifo->fallback = strdup(arg);
1281 if (ifo->fallback == NULL) {
94d1ded9 1282 logerrx(__func__);
00ababe4 1283 return -1;
78369646 1284 }
ff021b0b 1285 break;
aae24feb 1286#endif
ebc9d360 1287 case O_IAID:
6bcb242d 1288 ARG_REQUIRED;
9ff636a5 1289 if (ifname == NULL) {
94d1ded9 1290 logerrx("IAID must belong in an interface block");
9ff636a5
RM
1291 return -1;
1292 }
069e2f28 1293 if (parse_iaid(ifo->iaid, arg, sizeof(ifo->iaid)) == -1) {
94d1ded9 1294 logerrx("invalid IAID %s", arg);
ebc9d360 1295 return -1;
069e2f28 1296 }
ebc9d360 1297 ifo->options |= DHCPCD_IAID;
563a421c 1298 break;
eebe9a18
RM
1299 case O_IPV6RS:
1300 ifo->options |= DHCPCD_IPV6RS;
1301 break;
91cd7324 1302 case O_NOIPV6RS:
61dd6cf9
RM
1303 ifo->options &= ~DHCPCD_IPV6RS;
1304 break;
eebe9a18 1305 case O_IPV6RA_FORK:
61dd6cf9 1306 ifo->options &= ~DHCPCD_IPV6RA_REQRDNSS;
91cd7324 1307 break;
62f12387
RM
1308 case O_IPV6RA_AUTOCONF:
1309 ifo->options |= DHCPCD_IPV6RA_AUTOCONF;
1310 break;
1311 case O_IPV6RA_NOAUTOCONF:
1312 ifo->options &= ~DHCPCD_IPV6RA_AUTOCONF;
1313 break;
7dab081f
RM
1314 case O_NOALIAS:
1315 ifo->options |= DHCPCD_NOALIAS;
1316 break;
bd762353 1317#ifdef DHCP6
00ababe4
RM
1318 case O_IA_NA:
1319 i = D6_OPTION_IA_NA;
1320 /* FALLTHROUGH */
1321 case O_IA_TA:
1322 if (i == 0)
1323 i = D6_OPTION_IA_TA;
1324 /* FALLTHROUGH */
1325 case O_IA_PD:
9ff636a5 1326 if (i == 0) {
c25b444e
RM
1327#ifdef SMALL
1328 logwarnx("%s: IA_PD not compiled in", ifname);
1329 return -1;
1330#else
9ff636a5 1331 if (ifname == NULL) {
94d1ded9
RM
1332 logerr("IA PD must belong in an "
1333 "interface block");
9ff636a5
RM
1334 return -1;
1335 }
00ababe4 1336 i = D6_OPTION_IA_PD;
c25b444e 1337#endif
9ff636a5 1338 }
b0ca9ae9 1339 if (ifname == NULL && arg) {
94d1ded9
RM
1340 logerrx("IA with IAID must belong in an "
1341 "interface block");
9ff636a5
RM
1342 return -1;
1343 }
00ababe4 1344 ifo->options |= DHCPCD_IA_FORCED;
52bcdc34
RM
1345 fp = strwhite(arg);
1346 if (fp) {
1347 *fp++ = '\0';
1348 fp = strskipwhite(fp);
1349 }
b0ca9ae9 1350 if (arg) {
b0ca9ae9
RM
1351 p = strchr(arg, '/');
1352 if (p)
1353 *p++ = '\0';
069e2f28 1354 if (parse_iaid(iaid, arg, sizeof(iaid)) == -1) {
94d1ded9 1355 logerr("invalid IAID: %s", arg);
b0ca9ae9 1356 return -1;
069e2f28 1357 }
52bcdc34 1358 }
ebc9d360
RM
1359 ia = NULL;
1360 for (sl = 0; sl < ifo->ia_len; sl++) {
52bcdc34 1361 if ((arg == NULL && !ifo->ia[sl].iaid_set) ||
ee184a69 1362 (arg != NULL && ifo->ia[sl].iaid_set &&
8371b540 1363 ifo->ia[sl].iaid[0] == iaid[0] &&
ebc9d360
RM
1364 ifo->ia[sl].iaid[1] == iaid[1] &&
1365 ifo->ia[sl].iaid[2] == iaid[2] &&
b0ca9ae9 1366 ifo->ia[sl].iaid[3] == iaid[3]))
00ababe4 1367 {
ebc9d360 1368 ia = &ifo->ia[sl];
00ababe4
RM
1369 break;
1370 }
1371 }
b0ca9ae9 1372 if (ia && ia->ia_type != (uint16_t)i) {
94d1ded9 1373 logerrx("Cannot mix IA for the same IAID");
b0ca9ae9
RM
1374 break;
1375 }
ebc9d360 1376 if (ia == NULL) {
62c5b972
RM
1377 ia = reallocarray(ifo->ia,
1378 ifo->ia_len + 1, sizeof(*ifo->ia));
ebc9d360 1379 if (ia == NULL) {
94d1ded9 1380 logerr(__func__);
00ababe4
RM
1381 return -1;
1382 }
ebc9d360
RM
1383 ifo->ia = ia;
1384 ia = &ifo->ia[ifo->ia_len++];
b0ca9ae9 1385 ia->ia_type = (uint16_t)i;
52bcdc34 1386 if (arg) {
b0ca9ae9
RM
1387 ia->iaid[0] = iaid[0];
1388 ia->iaid[1] = iaid[1];
1389 ia->iaid[2] = iaid[2];
1390 ia->iaid[3] = iaid[3];
1391 ia->iaid_set = 1;
1392 } else
1393 ia->iaid_set = 0;
1394 if (!ia->iaid_set ||
1395 p == NULL ||
1396 ia->ia_type == D6_OPTION_IA_TA)
1397 {
4f94ed51
RM
1398 memset(&ia->addr, 0, sizeof(ia->addr));
1399 ia->prefix_len = 0;
1400 } else {
1401 arg = p;
1402 p = strchr(arg, '/');
1403 if (p)
1404 *p++ = '\0';
1405 if (inet_pton(AF_INET6, arg, &ia->addr) == -1) {
94d1ded9 1406 logerr("%s", arg);
4f94ed51
RM
1407 memset(&ia->addr, 0, sizeof(ia->addr));
1408 }
b0ca9ae9 1409 if (p && ia->ia_type == D6_OPTION_IA_PD) {
40095c80
RM
1410 ia->prefix_len = (uint8_t)strtou(p,
1411 NULL, 0, 8, 120, &e);
f94b4eab 1412 if (e) {
94d1ded9 1413 logerrx("%s: failed to convert"
f94b4eab
RM
1414 " prefix len",
1415 p);
4f94ed51 1416 ia->prefix_len = 0;
40095c80 1417 }
4f94ed51
RM
1418 }
1419 }
c25b444e 1420#ifndef SMALL
e69793ff 1421 ia->sla_max = 0;
ebc9d360 1422 ia->sla_len = 0;
4f94ed51 1423 ia->sla = NULL;
c25b444e 1424#endif
00ababe4 1425 }
b0ca9ae9 1426 if (ia->ia_type != D6_OPTION_IA_PD)
7cece083 1427 break;
c25b444e 1428#ifndef SMALL
00ababe4 1429 for (p = fp; p; p = fp) {
1cd05a96
RM
1430 fp = strwhite(p);
1431 if (fp) {
00ababe4 1432 *fp++ = '\0';
1cd05a96
RM
1433 fp = strskipwhite(fp);
1434 }
62c5b972
RM
1435 sla = reallocarray(ia->sla,
1436 ia->sla_len + 1, sizeof(*ia->sla));
00ababe4 1437 if (sla == NULL) {
94d1ded9 1438 logerr(__func__);
00ababe4
RM
1439 return -1;
1440 }
ebc9d360
RM
1441 ia->sla = sla;
1442 sla = &ia->sla[ia->sla_len++];
00ababe4
RM
1443 np = strchr(p, '/');
1444 if (np)
1445 *np++ = '\0';
00ababe4
RM
1446 if (strlcpy(sla->ifname, p,
1447 sizeof(sla->ifname)) >= sizeof(sla->ifname))
1448 {
94d1ded9 1449 logerrx("%s: interface name too long", arg);
94a79cea 1450 goto err_sla;
00ababe4 1451 }
fda2c663
RM
1452 sla->sla_set = 0;
1453 sla->prefix_len = 0;
1454 sla->suffix = 1;
00ababe4 1455 p = np;
367f7b11
RM
1456 if (p) {
1457 np = strchr(p, '/');
1458 if (np)
1459 *np++ = '\0';
fda2c663 1460 if (*p != '\0') {
f94b4eab
RM
1461 sla->sla = (uint32_t)strtou(p, NULL,
1462 0, 0, UINT32_MAX, &e);
1463 sla->sla_set = 1;
1464 if (e) {
94d1ded9
RM
1465 logerrx("%s: failed to convert "
1466 "sla",
f94b4eab 1467 ifname);
34457fe6 1468 goto err_sla;
f94b4eab 1469 }
83919266 1470 }
fda2c663
RM
1471 p = np;
1472 }
1473 if (p) {
1474 np = strchr(p, '/');
1475 if (np)
1476 *np++ = '\0';
1477 if (*p != '\0') {
55793e6a 1478 sla->prefix_len = (uint8_t)strtou(p,
fda2c663 1479 NULL, 0, 0, 120, &e);
f94b4eab 1480 if (e) {
94d1ded9 1481 logerrx("%s: failed to "
f94b4eab
RM
1482 "convert prefix len",
1483 ifname);
94a79cea 1484 goto err_sla;
f94b4eab 1485 }
fda2c663
RM
1486 }
1487 p = np;
1488 }
1489 if (p) {
1490 np = strchr(p, '/');
1491 if (np)
1492 *np = '\0';
1493 if (*p != '\0') {
1494 sla->suffix = (uint64_t)strtou(p, NULL,
1495 0, 0, UINT64_MAX, &e);
1496 if (e) {
94d1ded9 1497 logerrx("%s: failed to "
fda2c663
RM
1498 "convert suffix",
1499 ifname);
1500 goto err_sla;
1501 }
1502 }
e69793ff
RM
1503 }
1504 /* Sanity check */
1505 for (sl = 0; sl < ia->sla_len - 1; sl++) {
1506 slap = &ia->sla[sl];
a268d0e4 1507 if (slap->sla_set != sla->sla_set) {
94d1ded9 1508 logerrx("%s: cannot mix automatic "
e69793ff
RM
1509 "and fixed SLA",
1510 sla->ifname);
1511 goto err_sla;
1512 }
857a98fc
RM
1513 if (ia->prefix_len &&
1514 (sla->prefix_len == ia->prefix_len ||
1515 slap->prefix_len == ia->prefix_len))
1516 {
94d1ded9 1517 logerrx("%s: cannot delegte the same"
857a98fc
RM
1518 "prefix length more than once",
1519 sla->ifname);
1520 goto err_sla;
1521 }
e69793ff
RM
1522 if (sla->sla_set == 0 &&
1523 strcmp(slap->ifname, sla->ifname) == 0)
1524 {
94d1ded9 1525 logwarnx("%s: cannot specify the "
e69793ff
RM
1526 "same interface twice with "
1527 "an automatic SLA",
1528 sla->ifname);
1529 goto err_sla;
5985c4e2 1530 }
663d44bf
RM
1531 if (slap->sla_set && sla->sla_set &&
1532 slap->sla == sla->sla)
b1582682 1533 {
94d1ded9 1534 logerrx("%s: cannot"
663d44bf
RM
1535 " assign the same SLA %u"
1536 " more than once",
1537 sla->ifname, sla->sla);
a268d0e4
RM
1538 goto err_sla;
1539 }
367f7b11 1540 }
e69793ff
RM
1541 if (sla->sla_set && sla->sla > ia->sla_max)
1542 ia->sla_max = sla->sla;
00ababe4 1543 }
ebc9d360 1544 break;
94a79cea
RM
1545err_sla:
1546 ia->sla_len--;
1547 return -1;
c25b444e 1548#endif
94a79cea 1549#endif
d6a18654 1550 case O_HOSTNAME_SHORT:
9c54b11b 1551 ifo->options |= DHCPCD_HOSTNAME | DHCPCD_HOSTNAME_SHORT;
d6a18654 1552 break;
413652c1 1553 case O_DEV:
6bcb242d 1554 ARG_REQUIRED;
4eb7b489
RM
1555#ifdef PLUGIN_DEV
1556 if (ctx->dev_load)
1557 free(ctx->dev_load);
1558 ctx->dev_load = strdup(arg);
1559#endif
413652c1
RM
1560 break;
1561 case O_NODEV:
1562 ifo->options &= ~DHCPCD_DEV;
1563 break;
8e7d8c37
RM
1564 case O_DEFINE:
1565 dop = &ifo->dhcp_override;
1566 dop_len = &ifo->dhcp_override_len;
1567 /* FALLTHROUGH */
2be15e88
RM
1568 case O_DEFINEND:
1569 if (dop == NULL) {
1570 dop = &ifo->nd_override;
1571 dop_len = &ifo->nd_override_len;
1572 }
1573 /* FALLTHROUGH */
8e7d8c37
RM
1574 case O_DEFINE6:
1575 if (dop == NULL) {
1576 dop = &ifo->dhcp6_override;
1577 dop_len = &ifo->dhcp6_override_len;
1578 }
7a911e57
RM
1579 /* FALLTHROUGH */
1580 case O_VENDOPT:
1581 if (dop == NULL) {
1582 dop = &ifo->vivso_override;
1583 dop_len = &ifo->vivso_override_len;
1584 }
4eb7b489 1585 *edop = *ldop = NULL;
8e7d8c37
RM
1586 /* FALLTHROUGH */
1587 case O_EMBED:
1588 if (dop == NULL) {
4eb7b489
RM
1589 if (*edop) {
1590 dop = &(*edop)->embopts;
1591 dop_len = &(*edop)->embopts_len;
03476881 1592 } else if (ldop) {
4eb7b489
RM
1593 dop = &(*ldop)->embopts;
1594 dop_len = &(*ldop)->embopts_len;
03476881 1595 } else {
94d1ded9
RM
1596 logerrx("embed must be after a define "
1597 "or encap");
8e7d8c37
RM
1598 return -1;
1599 }
8e7d8c37 1600 }
03476881 1601 /* FALLTHROUGH */
8e7d8c37 1602 case O_ENCAP:
6bcb242d 1603 ARG_REQUIRED;
8e7d8c37 1604 if (dop == NULL) {
4eb7b489 1605 if (*ldop == NULL) {
94d1ded9 1606 logerrx("encap must be after a define");
8e7d8c37
RM
1607 return -1;
1608 }
4eb7b489
RM
1609 dop = &(*ldop)->encopts;
1610 dop_len = &(*ldop)->encopts_len;
8e7d8c37
RM
1611 }
1612
1613 /* Shared code for define, define6, embed and encap */
1614
1615 /* code */
1616 if (opt == O_EMBED) /* Embedded options don't have codes */
7a911e57 1617 u = 0;
8e7d8c37 1618 else {
1cd05a96 1619 fp = strwhite(arg);
4dd50184 1620 if (fp == NULL) {
94d1ded9 1621 logerrx("invalid syntax: %s", arg);
8e7d8c37
RM
1622 return -1;
1623 }
1624 *fp++ = '\0';
6dff2cb3 1625 u = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
f94b4eab 1626 if (e) {
94d1ded9 1627 logerrx("invalid code: %s", arg);
8e7d8c37 1628 return -1;
7a911e57 1629 }
1cd05a96 1630 arg = strskipwhite(fp);
4dd50184 1631 if (arg == NULL) {
94d1ded9 1632 logerrx("invalid syntax");
4dd50184
RM
1633 return -1;
1634 }
8e7d8c37
RM
1635 }
1636 /* type */
1cd05a96 1637 fp = strwhite(arg);
ab371aa6 1638 if (fp)
1cd05a96 1639 *fp++ = '\0';
b21cd906
RM
1640 np = strchr(arg, ':');
1641 /* length */
1642 if (np) {
1643 *np++ = '\0';
cc71162d 1644 bp = NULL; /* No bitflag */
f94b4eab
RM
1645 l = (long)strtou(np, NULL, 0, 0, LONG_MAX, &e);
1646 if (e) {
94d1ded9 1647 logerrx("failed to convert length");
b21cd906 1648 return -1;
f94b4eab 1649 }
cc71162d 1650 } else {
b21cd906 1651 l = 0;
cc71162d
RM
1652 bp = strchr(arg, '='); /* bitflag assignment */
1653 if (bp)
1654 *bp++ = '\0';
1655 }
1cd05a96
RM
1656 t = 0;
1657 if (strcasecmp(arg, "request") == 0) {
41eefe94 1658 t |= OT_REQUEST;
1cd05a96
RM
1659 arg = strskipwhite(fp);
1660 fp = strwhite(arg);
1661 if (fp == NULL) {
94d1ded9 1662 logerrx("incomplete request type");
1cd05a96
RM
1663 return -1;
1664 }
1665 *fp++ = '\0';
1666 } else if (strcasecmp(arg, "norequest") == 0) {
41eefe94 1667 t |= OT_NOREQ;
1cd05a96
RM
1668 arg = strskipwhite(fp);
1669 fp = strwhite(arg);
1670 if (fp == NULL) {
94d1ded9 1671 logerrx("incomplete request type");
1cd05a96
RM
1672 return -1;
1673 }
8e7d8c37 1674 *fp++ = '\0';
1cd05a96 1675 }
ecdbb919 1676 if (strcasecmp(arg, "optional") == 0) {
41eefe94 1677 t |= OT_OPTIONAL;
ecdbb919
RM
1678 arg = strskipwhite(fp);
1679 fp = strwhite(arg);
1680 if (fp == NULL) {
94d1ded9 1681 logerrx("incomplete optional type");
ecdbb919
RM
1682 return -1;
1683 }
1684 *fp++ = '\0';
1685 }
03476881 1686 if (strcasecmp(arg, "index") == 0) {
41eefe94 1687 t |= OT_INDEX;
03476881
RM
1688 arg = strskipwhite(fp);
1689 fp = strwhite(arg);
1690 if (fp == NULL) {
94d1ded9 1691 logerrx("incomplete index type");
03476881
RM
1692 return -1;
1693 }
1694 *fp++ = '\0';
1695 }
1cd05a96 1696 if (strcasecmp(arg, "array") == 0) {
41eefe94 1697 t |= OT_ARRAY;
1cd05a96
RM
1698 arg = strskipwhite(fp);
1699 fp = strwhite(arg);
1700 if (fp == NULL) {
94d1ded9 1701 logerrx("incomplete array type");
1cd05a96
RM
1702 return -1;
1703 }
1704 *fp++ = '\0';
1705 }
8e7d8c37 1706 if (strcasecmp(arg, "ipaddress") == 0)
41eefe94 1707 t |= OT_ADDRIPV4;
8e7d8c37 1708 else if (strcasecmp(arg, "ip6address") == 0)
41eefe94 1709 t |= OT_ADDRIPV6;
8e7d8c37 1710 else if (strcasecmp(arg, "string") == 0)
41eefe94 1711 t |= OT_STRING;
8e7d8c37 1712 else if (strcasecmp(arg, "byte") == 0)
41eefe94 1713 t |= OT_UINT8;
cc71162d 1714 else if (strcasecmp(arg, "bitflags") == 0)
41eefe94 1715 t |= OT_BITFLAG;
c960d1e6 1716 else if (strcasecmp(arg, "uint8") == 0)
41eefe94 1717 t |= OT_UINT8;
c960d1e6 1718 else if (strcasecmp(arg, "int8") == 0)
41eefe94 1719 t |= OT_INT8;
8e7d8c37 1720 else if (strcasecmp(arg, "uint16") == 0)
41eefe94 1721 t |= OT_UINT16;
8e7d8c37 1722 else if (strcasecmp(arg, "int16") == 0)
41eefe94 1723 t |= OT_INT16;
8e7d8c37 1724 else if (strcasecmp(arg, "uint32") == 0)
41eefe94 1725 t |= OT_UINT32;
8e7d8c37 1726 else if (strcasecmp(arg, "int32") == 0)
41eefe94 1727 t |= OT_INT32;
1cd05a96 1728 else if (strcasecmp(arg, "flag") == 0)
41eefe94 1729 t |= OT_FLAG;
8f008ca7 1730 else if (strcasecmp(arg, "raw") == 0)
41eefe94 1731 t |= OT_STRING | OT_RAW;
8f008ca7 1732 else if (strcasecmp(arg, "ascii") == 0)
41eefe94 1733 t |= OT_STRING | OT_ASCII;
8e7d8c37 1734 else if (strcasecmp(arg, "domain") == 0)
41eefe94 1735 t |= OT_STRING | OT_DOMAIN | OT_RFC1035;
8f008ca7 1736 else if (strcasecmp(arg, "dname") == 0)
41eefe94 1737 t |= OT_STRING | OT_DOMAIN;
8e7d8c37 1738 else if (strcasecmp(arg, "binhex") == 0)
41eefe94 1739 t |= OT_STRING | OT_BINHEX;
8e7d8c37 1740 else if (strcasecmp(arg, "embed") == 0)
41eefe94 1741 t |= OT_EMBED;
8e7d8c37 1742 else if (strcasecmp(arg, "encap") == 0)
41eefe94 1743 t |= OT_ENCAP;
1cd05a96 1744 else if (strcasecmp(arg, "rfc3361") ==0)
41eefe94 1745 t |= OT_STRING | OT_RFC3361;
dfee59d2 1746 else if (strcasecmp(arg, "rfc3442") ==0)
41eefe94 1747 t |= OT_STRING | OT_RFC3442;
03476881 1748 else if (strcasecmp(arg, "option") == 0)
41eefe94 1749 t |= OT_OPTION;
8e7d8c37 1750 else {
94d1ded9 1751 logerrx("unknown type: %s", arg);
8e7d8c37
RM
1752 return -1;
1753 }
41eefe94 1754 if (l && !(t & (OT_STRING | OT_BINHEX))) {
94d1ded9 1755 logwarnx("ignoring length for type `%s'", arg);
b21cd906
RM
1756 l = 0;
1757 }
41eefe94
RM
1758 if (t & OT_ARRAY && t & (OT_STRING | OT_BINHEX) &&
1759 !(t & (OT_RFC1035 | OT_DOMAIN)))
8f008ca7 1760 {
94d1ded9 1761 logwarnx("ignoring array for strings");
41eefe94 1762 t &= ~OT_ARRAY;
63bdd2c2 1763 }
41eefe94 1764 if (t & OT_BITFLAG) {
cc71162d 1765 if (bp == NULL)
94d1ded9 1766 logwarnx("missing bitflag assignment");
cc71162d 1767 }
8e7d8c37 1768 /* variable */
d9fbb118 1769 if (!fp) {
41eefe94 1770 if (!(t & OT_OPTION)) {
94d1ded9
RM
1771 logerrx("type %s requires a variable name",
1772 arg);
03476881
RM
1773 return -1;
1774 }
1775 np = NULL;
1776 } else {
1777 arg = strskipwhite(fp);
1778 fp = strwhite(arg);
1779 if (fp)
1780 *fp++ = '\0';
cc71162d
RM
1781 if (strcasecmp(arg, "reserved")) {
1782 np = strdup(arg);
1783 if (np == NULL) {
94d1ded9 1784 logerr(__func__);
cc71162d
RM
1785 return -1;
1786 }
1787 } else {
1788 np = NULL;
41eefe94 1789 t |= OT_RESERVED;
03476881 1790 }
8e7d8c37 1791 }
6714b786 1792 if (opt != O_EMBED) {
f132acc3
RM
1793 for (dl = 0, ndop = *dop; dl < *dop_len; dl++, ndop++)
1794 {
1cd05a96
RM
1795 /* type 0 seems freshly malloced struct
1796 * for us to use */
7a911e57 1797 if (ndop->option == u || ndop->type == 0)
8e7d8c37
RM
1798 break;
1799 }
f132acc3
RM
1800 if (dl == *dop_len)
1801 ndop = NULL;
1802 } else
1803 ndop = NULL;
6714b786 1804 if (ndop == NULL) {
62c5b972
RM
1805 ndop = reallocarray(*dop, *dop_len + 1, sizeof(**dop));
1806 if (ndop == NULL) {
94d1ded9 1807 logerr(__func__);
8fc52ced 1808 free(np);
8e7d8c37
RM
1809 return -1;
1810 }
1811 *dop = ndop;
1812 ndop = &(*dop)[(*dop_len)++];
8e7d8c37
RM
1813 ndop->embopts = NULL;
1814 ndop->embopts_len = 0;
1815 ndop->encopts = NULL;
1816 ndop->encopts_len = 0;
1817 } else
1818 free_dhcp_opt_embenc(ndop);
76bb4d03 1819 ndop->option = (uint32_t)u; /* could have been 0 */
8e7d8c37 1820 ndop->type = t;
34457fe6 1821 ndop->len = (size_t)l;
bc22d277 1822 ndop->var = np;
cc71162d
RM
1823 if (bp) {
1824 dl = strlen(bp);
1825 memcpy(ndop->bitflags, bp, dl);
1826 memset(ndop->bitflags + dl, 0,
1827 sizeof(ndop->bitflags) - dl);
1828 } else
1829 memset(ndop->bitflags, 0, sizeof(ndop->bitflags));
8e7d8c37 1830 /* Save the define for embed and encap options */
2be15e88
RM
1831 switch (opt) {
1832 case O_DEFINE:
1833 case O_DEFINEND:
1834 case O_DEFINE6:
1835 case O_VENDOPT:
4eb7b489 1836 *ldop = ndop;
2be15e88
RM
1837 break;
1838 case O_ENCAP:
4eb7b489 1839 *edop = ndop;
2be15e88
RM
1840 break;
1841 }
8e7d8c37 1842 break;
7a911e57 1843 case O_VENDCLASS:
6bcb242d 1844 ARG_REQUIRED;
7a911e57
RM
1845 fp = strwhite(arg);
1846 if (fp)
1847 *fp++ = '\0';
f94b4eab
RM
1848 u = (uint32_t)strtou(arg, NULL, 0, 0, UINT32_MAX, &e);
1849 if (e) {
94d1ded9 1850 logerrx("invalid code: %s", arg);
7a911e57
RM
1851 return -1;
1852 }
1853 if (fp) {
1854 s = parse_string(NULL, 0, fp);
1855 if (s == -1) {
94d1ded9 1856 logerr(__func__);
7a911e57
RM
1857 return -1;
1858 }
34457fe6
RM
1859 dl = (size_t)s;
1860 if (dl + (sizeof(uint16_t) * 2) > UINT16_MAX) {
94d1ded9 1861 logerrx("vendor class is too big");
7a911e57
RM
1862 return -1;
1863 }
34457fe6 1864 np = malloc(dl);
7a911e57 1865 if (np == NULL) {
94d1ded9 1866 logerr(__func__);
7a911e57
RM
1867 return -1;
1868 }
34457fe6 1869 parse_string(np, dl, fp);
7a911e57 1870 } else {
34457fe6 1871 dl = 0;
7a911e57
RM
1872 np = NULL;
1873 }
62c5b972
RM
1874 vivco = reallocarray(ifo->vivco,
1875 ifo->vivco_len + 1, sizeof(*ifo->vivco));
7a911e57 1876 if (vivco == NULL) {
94d1ded9 1877 logerr( __func__);
7a911e57
RM
1878 return -1;
1879 }
1880 ifo->vivco = vivco;
76bb4d03 1881 ifo->vivco_en = (uint32_t)u;
7a911e57 1882 vivco = &ifo->vivco[ifo->vivco_len++];
34457fe6 1883 vivco->len = dl;
7a911e57
RM
1884 vivco->data = (uint8_t *)np;
1885 break;
c73ed171 1886 case O_AUTHPROTOCOL:
6bcb242d 1887 ARG_REQUIRED;
e5fc8ac4 1888#ifdef AUTH
c73ed171
RM
1889 fp = strwhite(arg);
1890 if (fp)
1891 *fp++ = '\0';
1892 if (strcasecmp(arg, "token") == 0)
1893 ifo->auth.protocol = AUTH_PROTO_TOKEN;
1894 else if (strcasecmp(arg, "delayed") == 0)
1895 ifo->auth.protocol = AUTH_PROTO_DELAYED;
1896 else if (strcasecmp(arg, "delayedrealm") == 0)
1897 ifo->auth.protocol = AUTH_PROTO_DELAYEDREALM;
1898 else {
94d1ded9 1899 logerrx("%s: unsupported protocol", arg);
c73ed171
RM
1900 return -1;
1901 }
1902 arg = strskipwhite(fp);
1903 fp = strwhite(arg);
1904 if (arg == NULL) {
1905 ifo->auth.options |= DHCPCD_AUTH_SEND;
c2603990
RM
1906 if (ifo->auth.protocol == AUTH_PROTO_TOKEN)
1907 ifo->auth.protocol = AUTH_ALG_NONE;
1908 else
1909 ifo->auth.algorithm = AUTH_ALG_HMAC_MD5;
c73ed171
RM
1910 ifo->auth.rdm = AUTH_RDM_MONOTONIC;
1911 break;
1912 }
1913 if (fp)
1914 *fp++ = '\0';
1915 if (strcasecmp(arg, "hmacmd5") == 0 ||
1916 strcasecmp(arg, "hmac-md5") == 0)
1917 ifo->auth.algorithm = AUTH_ALG_HMAC_MD5;
1918 else {
94d1ded9 1919 logerrx("%s: unsupported algorithm", arg);
c73ed171
RM
1920 return 1;
1921 }
1922 arg = fp;
1923 if (arg == NULL) {
1924 ifo->auth.options |= DHCPCD_AUTH_SEND;
1925 ifo->auth.rdm = AUTH_RDM_MONOTONIC;
1926 break;
1927 }
cf0840ef
RM
1928 if (strcasecmp(arg, "monocounter") == 0) {
1929 ifo->auth.rdm = AUTH_RDM_MONOTONIC;
1930 ifo->auth.options |= DHCPCD_AUTH_RDM_COUNTER;
1931 } else if (strcasecmp(arg, "monotonic") ==0 ||
1932 strcasecmp(arg, "monotime") == 0)
c73ed171
RM
1933 ifo->auth.rdm = AUTH_RDM_MONOTONIC;
1934 else {
94d1ded9 1935 logerrx("%s: unsupported RDM", arg);
c73ed171
RM
1936 return -1;
1937 }
35fef8ed 1938 ifo->auth.options |= DHCPCD_AUTH_SEND;
c73ed171 1939 break;
e5fc8ac4 1940#else
94d1ded9 1941 logerrx("no authentication support");
e5fc8ac4
RM
1942 return -1;
1943#endif
c73ed171 1944 case O_AUTHTOKEN:
6bcb242d 1945 ARG_REQUIRED;
e5fc8ac4 1946#ifdef AUTH
c73ed171
RM
1947 fp = strwhite(arg);
1948 if (fp == NULL) {
94d1ded9 1949 logerrx("authtoken requires a realm");
c73ed171
RM
1950 return -1;
1951 }
1952 *fp++ = '\0';
1953 token = malloc(sizeof(*token));
1954 if (token == NULL) {
94d1ded9 1955 logerr(__func__);
a8c8e686 1956 free(token);
c73ed171
RM
1957 return -1;
1958 }
1959 if (parse_uint32(&token->secretid, arg) == -1) {
94d1ded9 1960 logerrx("%s: not a number", arg);
c73ed171
RM
1961 free(token);
1962 return -1;
1963 }
1964 arg = fp;
1965 fp = strend(arg);
1966 if (fp == NULL) {
94d1ded9 1967 logerrx("authtoken requies an a key");
c73ed171
RM
1968 free(token);
1969 return -1;
1970 }
1971 *fp++ = '\0';
34457fe6
RM
1972 s = parse_string(NULL, 0, arg);
1973 if (s == -1) {
94d1ded9 1974 logerr("realm_len");
a8c8e686 1975 free(token);
34457fe6
RM
1976 return -1;
1977 }
1978 if (s) {
1979 token->realm_len = (size_t)s;
c73ed171
RM
1980 token->realm = malloc(token->realm_len);
1981 if (token->realm == NULL) {
94d1ded9 1982 logerr(__func__);
c73ed171 1983 free(token);
c73ed171
RM
1984 return -1;
1985 }
1986 parse_string((char *)token->realm, token->realm_len,
1987 arg);
34457fe6
RM
1988 } else {
1989 token->realm_len = 0;
1990 token->realm = NULL;
c73ed171
RM
1991 }
1992 arg = fp;
1993 fp = strend(arg);
1994 if (fp == NULL) {
94d1ded9 1995 logerrx("authtoken requies an an expiry date");
c73ed171
RM
1996 free(token->realm);
1997 free(token);
1998 return -1;
1999 }
2000 *fp++ = '\0';
2001 if (*arg == '"') {
2002 arg++;
2003 np = strchr(arg, '"');
2004 if (np)
2005 *np = '\0';
2006 }
2007 if (strcmp(arg, "0") == 0 || strcasecmp(arg, "forever") == 0)
2008 token->expire =0;
2009 else {
2010 struct tm tm;
2011
2012 memset(&tm, 0, sizeof(tm));
2013 if (strptime(arg, "%Y-%m-%d %H:%M", &tm) == NULL) {
94d1ded9 2014 logerrx("%s: invalid date time", arg);
c73ed171
RM
2015 free(token->realm);
2016 free(token);
2017 return -1;
2018 }
2019 if ((token->expire = mktime(&tm)) == (time_t)-1) {
94d1ded9 2020 logerr("%s: mktime", __func__);
c73ed171
RM
2021 free(token->realm);
2022 free(token);
2023 return -1;
2024 }
2025 }
2026 arg = fp;
34457fe6
RM
2027 s = parse_string(NULL, 0, arg);
2028 if (s == -1 || s == 0) {
94d1ded9
RM
2029 if (s == -1)
2030 logerr("token_len");
2031 else
2032 logerrx("authtoken needs a key");
c73ed171
RM
2033 free(token->realm);
2034 free(token);
2035 return -1;
2036 }
34457fe6 2037 token->key_len = (size_t)s;
c73ed171
RM
2038 token->key = malloc(token->key_len);
2039 parse_string((char *)token->key, token->key_len, arg);
2040 TAILQ_INSERT_TAIL(&ifo->auth.tokens, token, next);
e5fc8ac4 2041#else
94d1ded9 2042 logerrx("no authentication support");
e5fc8ac4
RM
2043 return -1;
2044#endif
c73ed171
RM
2045 break;
2046 case O_AUTHNOTREQUIRED:
2047 ifo->auth.options &= ~DHCPCD_AUTH_REQUIRE;
2048 break;
94bec972
RM
2049 case O_DHCP:
2050 ifo->options |= DHCPCD_DHCP | DHCPCD_IPV4;
2051 break;
d4154ba7
RM
2052 case O_NODHCP:
2053 ifo->options &= ~DHCPCD_DHCP;
2054 break;
94bec972
RM
2055 case O_DHCP6:
2056 ifo->options |= DHCPCD_DHCP6 | DHCPCD_IPV6;
2057 break;
d4154ba7
RM
2058 case O_NODHCP6:
2059 ifo->options &= ~DHCPCD_DHCP6;
2060 break;
a93e79c6 2061 case O_CONTROLGRP:
6bcb242d 2062 ARG_REQUIRED;
a93e79c6
RM
2063#ifdef _REENTRANT
2064 l = sysconf(_SC_GETGR_R_SIZE_MAX);
2065 if (l == -1)
2066 dl = 1024;
2067 else
2068 dl = (size_t)l;
2069 p = malloc(dl);
2070 if (p == NULL) {
94d1ded9 2071 logerr(__func__);
a93e79c6
RM
2072 return -1;
2073 }
2074 while ((i = getgrnam_r(arg, &grpbuf, p, (size_t)l, &grp)) ==
2075 ERANGE)
2076 {
2077 size_t nl = dl * 2;
2078 if (nl < dl) {
94d1ded9 2079 logerrx("control_group: out of buffer");
a93e79c6
RM
2080 free(p);
2081 return -1;
2082 }
2083 dl = nl;
2084 np = realloc(p, dl);
2085 if (np == NULL) {
94d1ded9 2086 logerr(__func__);
a93e79c6
RM
2087 free(p);
2088 return -1;
2089 }
2090 p = np;
2091 }
2092 if (i != 0) {
2093 errno = i;
94d1ded9 2094 logerr("getgrnam_r");
a93e79c6
RM
2095 free(p);
2096 return -1;
2097 }
2098 if (grp == NULL) {
94d1ded9 2099 logerrx("controlgroup: %s: not found", arg);
a93e79c6
RM
2100 free(p);
2101 return -1;
2102 }
2103 ctx->control_group = grp->gr_gid;
2104 free(p);
2105#else
2106 grp = getgrnam(arg);
2107 if (grp == NULL) {
94d1ded9 2108 logerrx("controlgroup: %s: not found", arg);
a93e79c6
RM
2109 return -1;
2110 }
2111 ctx->control_group = grp->gr_gid;
2112#endif
2113 break;
feb553d0
RM
2114 case O_GATEWAY:
2115 ifo->options |= DHCPCD_GATEWAY;
2116 break;
2862d340
RM
2117 case O_NOUP:
2118 ifo->options &= ~DHCPCD_IF_UP;
2119 break;
1aeaf0e7 2120 case O_SLAAC:
6bcb242d 2121 ARG_REQUIRED;
1aeaf0e7
RM
2122 if (strcmp(arg, "private") == 0 ||
2123 strcmp(arg, "stableprivate") == 0 ||
2124 strcmp(arg, "stable") == 0)
2125 ifo->options |= DHCPCD_SLAACPRIVATE;
2126 else
2127 ifo->options &= ~DHCPCD_SLAACPRIVATE;
3ed12ab8 2128 break;
8f924434
RM
2129 case O_BOOTP:
2130 ifo->options |= DHCPCD_BOOTP;
2131 break;
f572315d
RM
2132 case O_NODELAY:
2133 ifo->options &= ~DHCPCD_INITIAL_DELAY;
2134 break;
b1ad0d39
RM
2135 case O_LASTLEASE_EXTEND:
2136 ifo->options |= DHCPCD_LASTLEASE | DHCPCD_LASTLEASE_EXTEND;
2137 break;
b4a86584
RM
2138 case O_INACTIVE:
2139 ifo->options |= DHCPCD_INACTIVE;
2140 break;
d85ad7d0 2141 case O_MUDURL:
03274c9c 2142 ARG_REQUIRED;
d85ad7d0
RM
2143 s = parse_string((char *)ifo->mudurl + 1, MUDURL_MAX_LEN, arg);
2144 if (s == -1) {
94d1ded9 2145 logerr("mudurl");
d85ad7d0
RM
2146 return -1;
2147 }
2148 *ifo->mudurl = (uint8_t)s;
2149 break;
fd05b7dc
RM
2150 default:
2151 return 0;
2152 }
2153
2154 return 1;
6bcb242d
RM
2155
2156#ifdef ARG_REQUIRED
2157arg_required:
94d1ded9 2158 logerrx("option %d requires an argument", opt);
6bcb242d
RM
2159 return -1;
2160#undef ARG_REQUIRED
2161#endif
fd05b7dc
RM
2162}
2163
2164static int
4eb7b489
RM
2165parse_config_line(struct dhcpcd_ctx *ctx, const char *ifname,
2166 struct if_options *ifo, const char *opt, char *line,
2167 struct dhcp_opt **ldop, struct dhcp_opt **edop)
fd05b7dc
RM
2168{
2169 unsigned int i;
2170
2171 for (i = 0; i < sizeof(cf_options) / sizeof(cf_options[0]); i++) {
2172 if (!cf_options[i].name ||
2173 strcmp(cf_options[i].name, opt) != 0)
2174 continue;
2175
2176 if (cf_options[i].has_arg == required_argument && !line) {
94d1ded9 2177 logerrx("option requires an argument -- %s", opt);
fd05b7dc
RM
2178 return -1;
2179 }
2180
4eb7b489
RM
2181 return parse_option(ctx, ifname, ifo, cf_options[i].val, line,
2182 ldop, edop);
fd05b7dc
RM
2183 }
2184
94d1ded9 2185 logerrx("unknown option: %s", opt);
fd05b7dc
RM
2186 return -1;
2187}
2188
741f46c6 2189static void
b0272a9d 2190finish_config(struct if_options *ifo)
741f46c6
RM
2191{
2192
2193 /* Terminate the encapsulated options */
2194 if (ifo->vendor[0] && !(ifo->options & DHCPCD_VENDORRAW)) {
2195 ifo->vendor[0]++;
2196 ifo->vendor[ifo->vendor[0]] = DHO_END;
aeddc61a
RM
2197 /* We are called twice.
2198 * This should be fixed, but in the meantime, this
2199 * guard should suffice */
2200 ifo->options |= DHCPCD_VENDORRAW;
741f46c6 2201 }
b0272a9d 2202}
741f46c6 2203
c1b54b57
RM
2204/* Handy routine to read very long lines in text files.
2205 * This means we read the whole line and avoid any nasty buffer overflows.
2206 * We strip leading space and avoid comment lines, making the code that calls
2207 * us smaller. */
2208static char *
4eb7b489
RM
2209get_line(char ** __restrict buf, size_t * __restrict buflen,
2210 FILE * __restrict fp)
c1b54b57 2211{
67f84564 2212 char *p, *c;
c1b54b57 2213 ssize_t bytes;
67f84564 2214 int quoted;
c1b54b57
RM
2215
2216 do {
2217 bytes = getline(buf, buflen, fp);
2218 if (bytes == -1)
2219 return NULL;
2220 for (p = *buf; *p == ' ' || *p == '\t'; p++)
2221 ;
2222 } while (*p == '\0' || *p == '\n' || *p == '#' || *p == ';');
2223 if ((*buf)[--bytes] == '\n')
2224 (*buf)[bytes] = '\0';
67f84564
RM
2225
2226 /* Strip embedded comments unless in a quoted string or escaped */
2227 quoted = 0;
2228 for (c = p; *c != '\0'; c++) {
2229 if (*c == '\\') {
2230 c++; /* escaped */
2231 continue;
2232 }
2233 if (*c == '"')
2234 quoted = !quoted;
2235 else if (*c == '#' && !quoted) {
2236 *c = '\0';
2237 break;
2238 }
2239 }
c1b54b57
RM
2240 return p;
2241}
2242
598e6cc7
RM
2243struct if_options *
2244default_config(struct dhcpcd_ctx *ctx)
2245{
2246 struct if_options *ifo;
2247
2248 /* Seed our default options */
2249 if ((ifo = calloc(1, sizeof(*ifo))) == NULL) {
94d1ded9 2250 logerr(__func__);
598e6cc7
RM
2251 return NULL;
2252 }
2253 ifo->options |= DHCPCD_IF_UP | DHCPCD_LINK | DHCPCD_INITIAL_DELAY;
2254 ifo->timeout = DEFAULT_TIMEOUT;
2255 ifo->reboot = DEFAULT_REBOOT;
2256 ifo->metric = -1;
2257 ifo->auth.options |= DHCPCD_AUTH_REQUIRE;
9aa11487 2258 TAILQ_INIT(&ifo->routes);
e5fc8ac4 2259#ifdef AUTH
598e6cc7 2260 TAILQ_INIT(&ifo->auth.tokens);
e5fc8ac4 2261#endif
598e6cc7
RM
2262
2263 /* Inherit some global defaults */
2264 if (ctx->options & DHCPCD_PERSISTENT)
2265 ifo->options |= DHCPCD_PERSISTENT;
2266 if (ctx->options & DHCPCD_SLAACPRIVATE)
2267 ifo->options |= DHCPCD_SLAACPRIVATE;
2268
2269 return ifo;
2270}
2271
fd05b7dc 2272struct if_options *
4eb7b489 2273read_config(struct dhcpcd_ctx *ctx,
6f767217 2274 const char *ifname, const char *ssid, const char *profile)
fd05b7dc
RM
2275{
2276 struct if_options *ifo;
c1b54b57 2277 FILE *fp;
727d8459 2278 struct stat sb;
c1b54b57
RM
2279 char *line, *buf, *option, *p;
2280 size_t buflen;
fec195b5 2281 ssize_t vlen;
417c31a9 2282 int skip, have_profile, new_block, had_block;
1cd05a96 2283#ifndef EMBEDDED_CONFIG
e2e644e9 2284 const char * const *e;
c1b54b57 2285 size_t ol;
1cd05a96 2286#endif
d9fbb118 2287#if !defined(INET) || !defined(INET6)
10cac699 2288 size_t i;
d9fbb118
RM
2289 struct dhcp_opt *opt;
2290#endif
4eb7b489 2291 struct dhcp_opt *ldop, *edop;
fd05b7dc
RM
2292
2293 /* Seed our default options */
598e6cc7 2294 if ((ifo = default_config(ctx)) == NULL)
10e17e3f 2295 return NULL;
feb553d0 2296 ifo->options |= DHCPCD_DAEMONISE | DHCPCD_GATEWAY;
413652c1
RM
2297#ifdef PLUGIN_DEV
2298 ifo->options |= DHCPCD_DEV;
2299#endif
aae24feb 2300#ifdef INET
6456fc27 2301 ifo->options |= DHCPCD_IPV4 | DHCPCD_ARP | DHCPCD_DHCP | DHCPCD_IPV4LL;
aae24feb
RM
2302#endif
2303#ifdef INET6
62f12387
RM
2304 ifo->options |= DHCPCD_IPV6 | DHCPCD_IPV6RS;
2305 ifo->options |= DHCPCD_IPV6RA_AUTOCONF | DHCPCD_IPV6RA_REQRDNSS;
d4154ba7 2306 ifo->options |= DHCPCD_DHCP6;
aae24feb 2307#endif
793c4286 2308
fec195b5
RM
2309 vlen = dhcp_vendor((char *)ifo->vendorclassid + 1,
2310 sizeof(ifo->vendorclassid) - 1);
d7a4dcf9 2311 ifo->vendorclassid[0] = (uint8_t)(vlen == -1 ? 0 : vlen);
fd05b7dc 2312
c1b54b57
RM
2313 buf = NULL;
2314 buflen = 0;
2315
8e7d8c37 2316 /* Parse our embedded options file */
c1642d52 2317 if (ifname == NULL && !(ctx->options & DHCPCD_PRINT_PIDFILE)) {
1cd05a96
RM
2318 /* Space for initial estimates */
2319#if defined(INET) && defined(INITDEFINES)
2320 ifo->dhcp_override =
2321 calloc(INITDEFINES, sizeof(*ifo->dhcp_override));
2322 if (ifo->dhcp_override == NULL)
94d1ded9 2323 logerr(__func__);
1cd05a96
RM
2324 else
2325 ifo->dhcp_override_len = INITDEFINES;
2326#endif
2327
2be15e88
RM
2328#if defined(INET6) && defined(INITDEFINENDS)
2329 ifo->nd_override =
2330 calloc(INITDEFINENDS, sizeof(*ifo->nd_override));
2331 if (ifo->nd_override == NULL)
94d1ded9 2332 logerr(__func__);
2be15e88
RM
2333 else
2334 ifo->nd_override_len = INITDEFINENDS;
2335#endif
1cd05a96
RM
2336#if defined(INET6) && defined(INITDEFINE6S)
2337 ifo->dhcp6_override =
2338 calloc(INITDEFINE6S, sizeof(*ifo->dhcp6_override));
2339 if (ifo->dhcp6_override == NULL)
94d1ded9 2340 logerr(__func__);
1cd05a96 2341 else
d9fbb118 2342 ifo->dhcp6_override_len = INITDEFINE6S;
1cd05a96
RM
2343#endif
2344
2345 /* Now load our embedded config */
2346#ifdef EMBEDDED_CONFIG
c1b54b57
RM
2347 fp = fopen(EMBEDDED_CONFIG, "r");
2348 if (fp == NULL)
94d1ded9 2349 logerr("%s: fopen `%s'", __func__, EMBEDDED_CONFIG);
1cd05a96 2350
c1b54b57 2351 while (fp && (line = get_line(&buf, &buflen, fp))) {
1cd05a96 2352#else
a319fa53
RM
2353 buflen = 80;
2354 buf = malloc(buflen);
2355 if (buf == NULL) {
94d1ded9 2356 logerr(__func__);
e4cba32e 2357 free_options(ifo);
1cd05a96
RM
2358 return NULL;
2359 }
4eb7b489 2360 ldop = edop = NULL;
1cd05a96
RM
2361 for (e = dhcpcd_embedded_conf; *e; e++) {
2362 ol = strlen(*e) + 1;
a319fa53 2363 if (ol > buflen) {
e4cba32e
RM
2364 char *nbuf;
2365
a319fa53 2366 buflen = ol;
e4cba32e
RM
2367 nbuf = realloc(buf, buflen);
2368 if (nbuf == NULL) {
94d1ded9 2369 logerr(__func__);
967db595 2370 free(buf);
e4cba32e 2371 free_options(ifo);
1cd05a96
RM
2372 return NULL;
2373 }
e4cba32e 2374 buf = nbuf;
1cd05a96 2375 }
a319fa53
RM
2376 memcpy(buf, *e, ol);
2377 line = buf;
1cd05a96 2378#endif
8e7d8c37 2379 option = strsep(&line, " \t");
ab371aa6
RM
2380 if (line)
2381 line = strskipwhite(line);
8e7d8c37 2382 /* Trim trailing whitespace */
79f1f126 2383 if (line) {
8e7d8c37
RM
2384 p = line + strlen(line) - 1;
2385 while (p != line &&
2386 (*p == ' ' || *p == '\t') &&
2387 *(p - 1) != '\\')
2388 *p-- = '\0';
2389 }
4eb7b489
RM
2390 parse_config_line(ctx, NULL, ifo, option, line,
2391 &ldop, &edop);
1cd05a96 2392
8e7d8c37 2393 }
1cd05a96
RM
2394
2395#ifdef EMBEDDED_CONFIG
c1b54b57
RM
2396 if (fp)
2397 fclose(fp);
1cd05a96
RM
2398#endif
2399#ifdef INET
4eb7b489
RM
2400 ctx->dhcp_opts = ifo->dhcp_override;
2401 ctx->dhcp_opts_len = ifo->dhcp_override_len;
1cd05a96 2402#else
d9fbb118
RM
2403 for (i = 0, opt = ifo->dhcp_override;
2404 i < ifo->dhcp_override_len;
2405 i++, opt++)
2406 free_dhcp_opt_embenc(opt);
1cd05a96
RM
2407 free(ifo->dhcp_override);
2408#endif
2409 ifo->dhcp_override = NULL;
2410 ifo->dhcp_override_len = 0;
2411
2412#ifdef INET6
2be15e88
RM
2413 ctx->nd_opts = ifo->nd_override;
2414 ctx->nd_opts_len = ifo->nd_override_len;
4eb7b489
RM
2415 ctx->dhcp6_opts = ifo->dhcp6_override;
2416 ctx->dhcp6_opts_len = ifo->dhcp6_override_len;
1cd05a96 2417#else
2be15e88
RM
2418 for (i = 0, opt = ifo->nd_override;
2419 i < ifo->nd_override_len;
2420 i++, opt++)
2421 free_dhcp_opt_embenc(opt);
2422 free(ifo->nd_override);
d9fbb118 2423 for (i = 0, opt = ifo->dhcp6_override;
10cac699 2424 i < ifo->dhcp6_override_len;
d9fbb118
RM
2425 i++, opt++)
2426 free_dhcp_opt_embenc(opt);
1cd05a96
RM
2427 free(ifo->dhcp6_override);
2428#endif
2be15e88
RM
2429 ifo->nd_override = NULL;
2430 ifo->nd_override_len = 0;
1cd05a96
RM
2431 ifo->dhcp6_override = NULL;
2432 ifo->dhcp6_override_len = 0;
7a911e57 2433
4eb7b489
RM
2434 ctx->vivso = ifo->vivso_override;
2435 ctx->vivso_len = ifo->vivso_override_len;
7a911e57
RM
2436 ifo->vivso_override = NULL;
2437 ifo->vivso_override_len = 0;
8e7d8c37
RM
2438 }
2439
fd05b7dc 2440 /* Parse our options file */
4eb7b489 2441 fp = fopen(ctx->cffile, "r");
c1b54b57 2442 if (fp == NULL) {
62cb6de8
RM
2443 /* dhcpcd can continue without it, but no DNS options
2444 * would be requested ... */
94d1ded9 2445 logwarn("%s: fopen `%s'", __func__, ctx->cffile);
c1b54b57 2446 free(buf);
fd05b7dc 2447 return ifo;
5e2062a4 2448 }
727d8459
RM
2449 if (stat(ctx->cffile, &sb) == 0)
2450 ifo->mtime = sb.st_mtime;
fd05b7dc 2451
4eb7b489 2452 ldop = edop = NULL;
417c31a9 2453 skip = have_profile = new_block = 0;
d42067b8 2454 had_block = ifname == NULL ? 1 : 0;
c1b54b57 2455 while ((line = get_line(&buf, &buflen, fp))) {
e1caa8db 2456 option = strsep(&line, " \t");
ab371aa6
RM
2457 if (line)
2458 line = strskipwhite(line);
fd05b7dc 2459 /* Trim trailing whitespace */
79f1f126 2460 if (line) {
fd05b7dc
RM
2461 p = line + strlen(line) - 1;
2462 while (p != line &&
eab2229c
RM
2463 (*p == ' ' || *p == '\t') &&
2464 *(p - 1) != '\\')
fd05b7dc
RM
2465 *p-- = '\0';
2466 }
d42067b8 2467 if (skip == 0 && new_block) {
edb0ed37
RM
2468 had_block = 1;
2469 new_block = 0;
2470 ifo->options &= ~DHCPCD_WAITOPTS;
2471 }
fd05b7dc
RM
2472 /* Start of an interface block, skip if not ours */
2473 if (strcmp(option, "interface") == 0) {
4d91c2e7
RM
2474 char **n;
2475
edb0ed37 2476 new_block = 1;
79f1f126
RM
2477 if (line == NULL) {
2478 /* No interface given */
2479 skip = 1;
2480 continue;
2481 }
2482 if (ifname && strcmp(line, ifname) == 0)
fd05b7dc
RM
2483 skip = 0;
2484 else
2485 skip = 1;
4d91c2e7
RM
2486 if (ifname)
2487 continue;
2488
79f1f126
RM
2489 n = reallocarray(ctx->ifcv,
2490 (size_t)ctx->ifcc + 1, sizeof(char *));
4d91c2e7 2491 if (n == NULL) {
94d1ded9 2492 logerr(__func__);
4d91c2e7
RM
2493 continue;
2494 }
2495 ctx->ifcv = n;
2496 ctx->ifcv[ctx->ifcc] = strdup(line);
2497 if (ctx->ifcv[ctx->ifcc] == NULL) {
94d1ded9 2498 logerr(__func__);
4d91c2e7
RM
2499 continue;
2500 }
2501 ctx->ifcc++;
fd05b7dc 2502 continue;
c53cf4ef
RM
2503 }
2504 /* Start of an ssid block, skip if not ours */
2505 if (strcmp(option, "ssid") == 0) {
edb0ed37 2506 new_block = 1;
c53cf4ef
RM
2507 if (ssid && line && strcmp(line, ssid) == 0)
2508 skip = 0;
2509 else
2510 skip = 1;
2511 continue;
fd05b7dc 2512 }
6f767217
RM
2513 /* Start of a profile block, skip if not ours */
2514 if (strcmp(option, "profile") == 0) {
edb0ed37 2515 new_block = 1;
6f767217
RM
2516 if (profile && line && strcmp(line, profile) == 0) {
2517 skip = 0;
2518 have_profile = 1;
2519 } else
2520 skip = 1;
2521 continue;
2522 }
ba7a34fb
RM
2523 /* Skip arping if we have selected a profile but not parsing
2524 * one. */
2525 if (profile && !have_profile && strcmp(option, "arping") == 0)
2526 continue;
fd05b7dc
RM
2527 if (skip)
2528 continue;
4eb7b489 2529 parse_config_line(ctx, ifname, ifo, option, line, &ldop, &edop);
fd05b7dc 2530 }
c1b54b57
RM
2531 fclose(fp);
2532 free(buf);
fd05b7dc 2533
6f767217
RM
2534 if (profile && !have_profile) {
2535 free_options(ifo);
2536 errno = ENOENT;
658bfd5e 2537 return NULL;
6f767217
RM
2538 }
2539
edb0ed37
RM
2540 if (!had_block)
2541 ifo->options &= ~DHCPCD_WAITOPTS;
b0272a9d 2542 finish_config(ifo);
fd05b7dc
RM
2543 return ifo;
2544}
2545
2546int
4eb7b489
RM
2547add_options(struct dhcpcd_ctx *ctx, const char *ifname,
2548 struct if_options *ifo, int argc, char **argv)
fd05b7dc 2549{
29c0fd6f 2550 int oi, opt, r;
edb0ed37 2551 unsigned long long wait_opts;
29c0fd6f
RM
2552
2553 if (argc == 0)
2554 return 1;
fd05b7dc
RM
2555
2556 optind = 0;
29c0fd6f 2557 r = 1;
edb0ed37
RM
2558 /* Don't apply the command line wait options to each interface,
2559 * only use the dhcpcd.conf entry for that. */
2560 if (ifname != NULL)
2561 wait_opts = ifo->options & DHCPCD_WAITOPTS;
c31b1719
RM
2562 while ((opt = getopt_long(argc, argv,
2563 ctx->options & DHCPCD_PRINT_PIDFILE ? NOERR_IF_OPTS : IF_OPTS,
2564 cf_options, &oi)) != -1)
fd05b7dc 2565 {
4eb7b489 2566 r = parse_option(ctx, ifname, ifo, opt, optarg, NULL, NULL);
fd05b7dc
RM
2567 if (r != 1)
2568 break;
2569 }
edb0ed37
RM
2570 if (ifname != NULL) {
2571 ifo->options &= ~DHCPCD_WAITOPTS;
2572 ifo->options |= wait_opts;
2573 }
741f46c6 2574
b0272a9d 2575 finish_config(ifo);
fd05b7dc
RM
2576 return r;
2577}
2578
2579void
2580free_options(struct if_options *ifo)
2581{
2582 size_t i;
d9fbb118 2583 struct dhcp_opt *opt;
900b6f94 2584 struct vivco *vo;
e5fc8ac4 2585#ifdef AUTH
c73ed171 2586 struct token *token;
e5fc8ac4 2587#endif
fd05b7dc 2588
f43e5853
RM
2589 if (ifo) {
2590 if (ifo->environ) {
2591 i = 0;
2592 while (ifo->environ[i])
2593 free(ifo->environ[i++]);
2594 free(ifo->environ);
2595 }
91a44b91
RM
2596 if (ifo->config) {
2597 i = 0;
2598 while (ifo->config[i])
2599 free(ifo->config[i++]);
2600 free(ifo->config);
2601 }
ded03af2 2602 rt_headclear(&ifo->routes, AF_UNSPEC);
1681b126 2603 free(ifo->script);
ff021b0b 2604 free(ifo->arping);
f43e5853 2605 free(ifo->blacklist);
ff021b0b 2606 free(ifo->fallback);
8e7d8c37 2607
59a555cd
RM
2608 for (opt = ifo->dhcp_override;
2609 ifo->dhcp_override_len > 0;
2610 opt++, ifo->dhcp_override_len--)
d9fbb118 2611 free_dhcp_opt_embenc(opt);
8e7d8c37 2612 free(ifo->dhcp_override);
2be15e88
RM
2613 for (opt = ifo->nd_override;
2614 ifo->nd_override_len > 0;
2615 opt++, ifo->nd_override_len--)
2616 free_dhcp_opt_embenc(opt);
2617 free(ifo->nd_override);
59a555cd
RM
2618 for (opt = ifo->dhcp6_override;
2619 ifo->dhcp6_override_len > 0;
2620 opt++, ifo->dhcp6_override_len--)
7a911e57
RM
2621 free_dhcp_opt_embenc(opt);
2622 free(ifo->dhcp6_override);
59a555cd
RM
2623 for (vo = ifo->vivco;
2624 ifo->vivco_len > 0;
2625 vo++, ifo->vivco_len--)
900b6f94
RM
2626 free(vo->data);
2627 free(ifo->vivco);
59a555cd
RM
2628 for (opt = ifo->vivso_override;
2629 ifo->vivso_override_len > 0;
2630 opt++, ifo->vivso_override_len--)
7a911e57 2631 free_dhcp_opt_embenc(opt);
900b6f94 2632 free(ifo->vivso_override);
8e7d8c37 2633
c25b444e 2634#if defined(INET6) && !defined(SMALL)
59a555cd
RM
2635 for (; ifo->ia_len > 0; ifo->ia_len--)
2636 free(ifo->ia[ifo->ia_len - 1].sla);
00ababe4 2637#endif
ebc9d360
RM
2638 free(ifo->ia);
2639
e5fc8ac4 2640#ifdef AUTH
c73ed171
RM
2641 while ((token = TAILQ_FIRST(&ifo->auth.tokens))) {
2642 TAILQ_REMOVE(&ifo->auth.tokens, token, next);
2643 if (token->realm_len)
2644 free(token->realm);
2645 free(token->key);
2646 free(token);
2647 }
e5fc8ac4 2648#endif
f43e5853 2649 free(ifo);
fd05b7dc 2650 }
fd05b7dc 2651}