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