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