Home | History | Annotate | Download | only in dhcpcd
      1 /*
      2  * dhcpcd - DHCP client daemon
      3  * Copyright (c) 2006-2010 Roy Marples <roy (at) marples.name>
      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 
     28 #include <sys/types.h>
     29 #include <sys/utsname.h>
     30 
     31 #include <arpa/inet.h>
     32 
     33 #include <ctype.h>
     34 #include <errno.h>
     35 #include <getopt.h>
     36 #include <paths.h>
     37 #include <stdio.h>
     38 #include <stdlib.h>
     39 #include <string.h>
     40 #include <syslog.h>
     41 #include <unistd.h>
     42 #include <time.h>
     43 
     44 #include "config.h"
     45 #include "common.h"
     46 #include "if-options.h"
     47 #include "net.h"
     48 #include "platform.h"
     49 
     50 /* These options only make sense in the config file, so don't use any
     51    valid short options for them */
     52 #define O_BASE		MAX('z', 'Z') + 1
     53 #define O_ARPING	O_BASE + 1
     54 #define O_FALLBACK	O_BASE + 2
     55 #define O_DESTINATION	O_BASE + 3
     56 
     57 const struct option cf_options[] = {
     58 	{"background",      no_argument,       NULL, 'b'},
     59 	{"script",          required_argument, NULL, 'c'},
     60 	{"debug",           no_argument,       NULL, 'd'},
     61 	{"env",             required_argument, NULL, 'e'},
     62 	{"config",          required_argument, NULL, 'f'},
     63 	{"reconfigure",     no_argument,       NULL, 'g'},
     64 	{"hostname",        optional_argument, NULL, 'h'},
     65 	{"vendorclassid",   optional_argument, NULL, 'i'},
     66 	{"release",         no_argument,       NULL, 'k'},
     67 	{"leasetime",       required_argument, NULL, 'l'},
     68 	{"metric",          required_argument, NULL, 'm'},
     69 	{"rebind",          no_argument,       NULL, 'n'},
     70 	{"option",          required_argument, NULL, 'o'},
     71 	{"persistent",      no_argument,       NULL, 'p'},
     72 	{"quiet",           no_argument,       NULL, 'q'},
     73 	{"request",         optional_argument, NULL, 'r'},
     74 	{"inform",          optional_argument, NULL, 's'},
     75 	{"timeout",         required_argument, NULL, 't'},
     76 	{"userclass",       required_argument, NULL, 'u'},
     77 	{"vendor",          required_argument, NULL, 'v'},
     78 	{"waitip",          no_argument,       NULL, 'w'},
     79 	{"exit",            no_argument,       NULL, 'x'},
     80 	{"allowinterfaces", required_argument, NULL, 'z'},
     81 	{"reboot",          required_argument, NULL, 'y'},
     82 	{"noarp",           no_argument,       NULL, 'A'},
     83 	{"nobackground",    no_argument,       NULL, 'B'},
     84 	{"nohook",          required_argument, NULL, 'C'},
     85 	{"duid",            no_argument,       NULL, 'D'},
     86 	{"lastlease",       no_argument,       NULL, 'E'},
     87 	{"fqdn",            optional_argument, NULL, 'F'},
     88 	{"nogateway",       no_argument,       NULL, 'G'},
     89 	{"xidhwaddr",       no_argument,       NULL, 'H'},
     90 	{"clientid",        optional_argument, NULL, 'I'},
     91 	{"broadcast",       no_argument,       NULL, 'J'},
     92 	{"nolink",          no_argument,       NULL, 'K'},
     93 	{"noipv4ll",        no_argument,       NULL, 'L'},
     94 	{"nooption",        optional_argument, NULL, 'O'},
     95 	{"require",         required_argument, NULL, 'Q'},
     96 	{"static",          required_argument, NULL, 'S'},
     97 	{"test",            no_argument,       NULL, 'T'},
     98 	{"dumplease",       no_argument,       NULL, 'U'},
     99 	{"variables",       no_argument,       NULL, 'V'},
    100 	{"whitelist",       required_argument, NULL, 'W'},
    101 	{"blacklist",       required_argument, NULL, 'X'},
    102 	{"denyinterfaces",  required_argument, NULL, 'Z'},
    103 	{"arping",          required_argument, NULL, O_ARPING},
    104 	{"destination",     required_argument, NULL, O_DESTINATION},
    105 	{"fallback",        required_argument, NULL, O_FALLBACK},
    106 	{NULL,              0,                 NULL, '\0'}
    107 };
    108 
    109 static int
    110 atoint(const char *s)
    111 {
    112 	char *t;
    113 	long n;
    114 
    115 	errno = 0;
    116 	n = strtol(s, &t, 0);
    117 	if ((errno != 0 && n == 0) || s == t ||
    118 	    (errno == ERANGE && (n == LONG_MAX || n == LONG_MIN)))
    119 	{
    120 		syslog(LOG_ERR, "`%s' out of range", s);
    121 		return -1;
    122 	}
    123 
    124 	return (int)n;
    125 }
    126 
    127 static char *
    128 add_environ(struct if_options *ifo, const char *value, int uniq)
    129 {
    130 	char **newlist;
    131 	char **lst = ifo->environ;
    132 	size_t i = 0, l, lv;
    133 	char *match = NULL, *p;
    134 
    135 	match = xstrdup(value);
    136 	p = strchr(match, '=');
    137 	if (p)
    138 		*p++ = '\0';
    139 	l = strlen(match);
    140 
    141 	while (lst && lst[i]) {
    142 		if (match && strncmp(lst[i], match, l) == 0) {
    143 			if (uniq) {
    144 				free(lst[i]);
    145 				lst[i] = xstrdup(value);
    146 			} else {
    147 				/* Append a space and the value to it */
    148 				l = strlen(lst[i]);
    149 				lv = strlen(p);
    150 				lst[i] = xrealloc(lst[i], l + lv + 2);
    151 				lst[i][l] = ' ';
    152 				memcpy(lst[i] + l + 1, p, lv);
    153 				lst[i][l + lv + 1] = '\0';
    154 			}
    155 			free(match);
    156 			return lst[i];
    157 		}
    158 		i++;
    159 	}
    160 
    161 	newlist = xrealloc(lst, sizeof(char *) * (i + 2));
    162 	newlist[i] = xstrdup(value);
    163 	newlist[i + 1] = NULL;
    164 	ifo->environ = newlist;
    165 	free(match);
    166 	return newlist[i];
    167 }
    168 
    169 #define parse_string(buf, len, arg) parse_string_hwaddr(buf, len, arg, 0)
    170 static ssize_t
    171 parse_string_hwaddr(char *sbuf, ssize_t slen, const char *str, int clid)
    172 {
    173 	ssize_t l;
    174 	const char *p;
    175 	int i, punt_last = 0;
    176 	char c[4];
    177 
    178 	/* If surrounded by quotes then it's a string */
    179 	if (*str == '"') {
    180 		str++;
    181 		l = strlen(str);
    182 		p = str + l - 1;
    183 		if (*p == '"')
    184 			punt_last = 1;
    185 	} else {
    186 		l = hwaddr_aton(NULL, str);
    187 		if (l > 1) {
    188 			if (l > slen) {
    189 				errno = ENOBUFS;
    190 				return -1;
    191 			}
    192 			hwaddr_aton((uint8_t *)sbuf, str);
    193 			return l;
    194 		}
    195 	}
    196 
    197 	/* Process escapes */
    198 	l = 0;
    199 	/* If processing a string on the clientid, first byte should be
    200 	 * 0 to indicate a non hardware type */
    201 	if (clid && *str) {
    202 		*sbuf++ = 0;
    203 		l++;
    204 	}
    205 	c[3] = '\0';
    206 	while (*str) {
    207 		if (++l > slen) {
    208 			errno = ENOBUFS;
    209 			return -1;
    210 		}
    211 		if (*str == '\\') {
    212 			str++;
    213 			switch(*str) {
    214 			case '\0':
    215 				break;
    216 			case 'b':
    217 				*sbuf++ = '\b';
    218 				str++;
    219 				break;
    220 			case 'n':
    221 				*sbuf++ = '\n';
    222 				str++;
    223 				break;
    224 			case 'r':
    225 				*sbuf++ = '\r';
    226 				str++;
    227 				break;
    228 			case 't':
    229 				*sbuf++ = '\t';
    230 				str++;
    231 				break;
    232 			case 'x':
    233 				/* Grab a hex code */
    234 				c[1] = '\0';
    235 				for (i = 0; i < 2; i++) {
    236 					if (isxdigit((unsigned char)*str) == 0)
    237 						break;
    238 					c[i] = *str++;
    239 				}
    240 				if (c[1] != '\0') {
    241 					c[2] = '\0';
    242 					*sbuf++ = strtol(c, NULL, 16);
    243 				} else
    244 					l--;
    245 				break;
    246 			case '0':
    247 				/* Grab an octal code */
    248 				c[2] = '\0';
    249 				for (i = 0; i < 3; i++) {
    250 					if (*str < '0' || *str > '7')
    251 						break;
    252 					c[i] = *str++;
    253 				}
    254 				if (c[2] != '\0') {
    255 					i = strtol(c, NULL, 8);
    256 					if (i > 255)
    257 						i = 255;
    258 					*sbuf ++= i;
    259 				} else
    260 					l--;
    261 				break;
    262 			default:
    263 				*sbuf++ = *str++;
    264 			}
    265 		} else
    266 			*sbuf++ = *str++;
    267 	}
    268 	if (punt_last) {
    269 		*--sbuf = '\0';
    270 		l--;
    271 	}
    272 	return l;
    273 }
    274 
    275 static char **
    276 splitv(int *argc, char **argv, const char *arg)
    277 {
    278 	char **v = argv;
    279 	char *o = xstrdup(arg), *p, *t;
    280 
    281 	p = o;
    282 	while ((t = strsep(&p, ", "))) {
    283 		(*argc)++;
    284 		v = xrealloc(v, sizeof(char *) * ((*argc)));
    285 		v[(*argc) - 1] = xstrdup(t);
    286 	}
    287 	free(o);
    288 	return v;
    289 }
    290 
    291 static int
    292 parse_addr(struct in_addr *addr, struct in_addr *net, const char *arg)
    293 {
    294 	char *p;
    295 	int i;
    296 
    297 	if (arg == NULL || *arg == '\0') {
    298 		if (addr != NULL)
    299 			addr->s_addr = 0;
    300 		if (net != NULL)
    301 			net->s_addr = 0;
    302 		return 0;
    303 	}
    304 	if ((p = strchr(arg, '/')) != NULL) {
    305 		*p++ = '\0';
    306 		if (net != NULL &&
    307 		    (sscanf(p, "%d", &i) != 1 ||
    308 			inet_cidrtoaddr(i, net) != 0))
    309 		{
    310 			syslog(LOG_ERR, "`%s' is not a valid CIDR", p);
    311 			return -1;
    312 		}
    313 	}
    314 
    315 	if (addr != NULL && inet_aton(arg, addr) == 0) {
    316 		syslog(LOG_ERR, "`%s' is not a valid IP address", arg);
    317 		return -1;
    318 	}
    319 	if (p != NULL)
    320 		*--p = '/';
    321 	else if (net != NULL)
    322 		net->s_addr = get_netmask(addr->s_addr);
    323 	return 0;
    324 }
    325 
    326 static int
    327 parse_option(struct if_options *ifo, int opt, const char *arg)
    328 {
    329 	int i;
    330 	char *p = NULL, *np;
    331 	ssize_t s;
    332 	struct in_addr addr, addr2;
    333 	struct rt *rt;
    334 
    335 	switch(opt) {
    336 	case 'a': /* FALLTHROUGH */
    337 	case 'f': /* FALLTHROUGH */
    338 	case 'g': /* FALLTHROUGH */
    339 	case 'n': /* FALLTHROUGH */
    340 	case 'x': /* FALLTHROUGH */
    341 	case 'T': /* FALLTHROUGH */
    342 	case 'U': /* We need to handle non interface options */
    343 		break;
    344 	case 'b':
    345 		ifo->options |= DHCPCD_BACKGROUND;
    346 		break;
    347 	case 'c':
    348 		strlcpy(ifo->script, arg, sizeof(ifo->script));
    349 		break;
    350 	case 'd':
    351 		ifo->options |= DHCPCD_DEBUG;
    352 		break;
    353 	case 'e':
    354 		add_environ(ifo, arg, 1);
    355 		break;
    356 	case 'h':
    357 		if (arg) {
    358 			s = parse_string(ifo->hostname,
    359 			    HOSTNAME_MAX_LEN, arg);
    360 			if (s == -1) {
    361 				syslog(LOG_ERR, "hostname: %m");
    362 				return -1;
    363 			}
    364 			if (s != 0 && ifo->hostname[0] == '.') {
    365 				syslog(LOG_ERR,
    366 				    "hostname cannot begin with .");
    367 				return -1;
    368 			}
    369 			ifo->hostname[s] = '\0';
    370 		}
    371 		if (ifo->hostname[0] == '\0')
    372 			ifo->options &= ~DHCPCD_HOSTNAME;
    373 		else
    374 			ifo->options |= DHCPCD_HOSTNAME;
    375 		break;
    376 	case 'i':
    377 		if (arg)
    378 			s = parse_string((char *)ifo->vendorclassid + 1,
    379 			    VENDORCLASSID_MAX_LEN, arg);
    380 		else
    381 			s = 0;
    382 		if (s == -1) {
    383 			syslog(LOG_ERR, "vendorclassid: %m");
    384 			return -1;
    385 		}
    386 		*ifo->vendorclassid = (uint8_t)s;
    387 		break;
    388 	case 'k':
    389 		ifo->options |= DHCPCD_RELEASE;
    390 		break;
    391 	case 'l':
    392 		if (*arg == '-') {
    393 			syslog(LOG_ERR,
    394 			    "leasetime must be a positive value");
    395 			return -1;
    396 		}
    397 		errno = 0;
    398 		ifo->leasetime = (uint32_t)strtol(arg, NULL, 0);
    399 		if (errno == EINVAL || errno == ERANGE) {
    400 			syslog(LOG_ERR, "`%s' out of range", arg);
    401 			return -1;
    402 		}
    403 		break;
    404 	case 'm':
    405 		ifo->metric = atoint(arg);
    406 		if (ifo->metric < 0) {
    407 			syslog(LOG_ERR, "metric must be a positive value");
    408 			return -1;
    409 		}
    410 		break;
    411 	case 'o':
    412 		if (make_option_mask(ifo->requestmask, arg, 1) != 0) {
    413 			syslog(LOG_ERR, "unknown option `%s'", arg);
    414 			return -1;
    415 		}
    416 		break;
    417 	case 'p':
    418 		ifo->options |= DHCPCD_PERSISTENT;
    419 		break;
    420 	case 'q':
    421 		ifo->options |= DHCPCD_QUIET;
    422 		break;
    423 	case 'r':
    424 		if (parse_addr(&ifo->req_addr, NULL, arg) != 0)
    425 			return -1;
    426 		ifo->options |= DHCPCD_REQUEST;
    427 		ifo->req_mask.s_addr = 0;
    428 		break;
    429 	case 's':
    430 		if (arg && *arg != '\0') {
    431 			if (parse_addr(&ifo->req_addr, &ifo->req_mask,
    432 				arg) != 0)
    433 				return -1;
    434 		} else {
    435 			ifo->req_addr.s_addr = 0;
    436 			ifo->req_mask.s_addr = 0;
    437 		}
    438 		ifo->options |= DHCPCD_INFORM | DHCPCD_PERSISTENT;
    439 		ifo->options &= ~(DHCPCD_ARP | DHCPCD_STATIC);
    440 		break;
    441 	case 't':
    442 		ifo->timeout = atoint(arg);
    443 		if (ifo->timeout < 0) {
    444 			syslog(LOG_ERR, "timeout must be a positive value");
    445 			return -1;
    446 		}
    447 		break;
    448 	case 'u':
    449 		s = USERCLASS_MAX_LEN - ifo->userclass[0] - 1;
    450 		s = parse_string((char *)ifo->userclass +
    451 		    ifo->userclass[0] + 2,
    452 		    s, arg);
    453 		if (s == -1) {
    454 			syslog(LOG_ERR, "userclass: %m");
    455 			return -1;
    456 		}
    457 		if (s != 0) {
    458 			ifo->userclass[ifo->userclass[0] + 1] = s;
    459 			ifo->userclass[0] += s + 1;
    460 		}
    461 		break;
    462 	case 'v':
    463 		p = strchr(arg, ',');
    464 		if (!p || !p[1]) {
    465 			syslog(LOG_ERR, "invalid vendor format");
    466 			return -1;
    467 		}
    468 
    469 		/* If vendor starts with , then it is not encapsulated */
    470 		if (p == arg) {
    471 			arg++;
    472 			s = parse_string((char *)ifo->vendor + 1,
    473 			    VENDOR_MAX_LEN, arg);
    474 			if (s == -1) {
    475 				syslog(LOG_ERR, "vendor: %m");
    476 				return -1;
    477 			}
    478 			ifo->vendor[0] = (uint8_t)s;
    479 			ifo->options |= DHCPCD_VENDORRAW;
    480 			break;
    481 		}
    482 
    483 		/* Encapsulated vendor options */
    484 		if (ifo->options & DHCPCD_VENDORRAW) {
    485 			ifo->options &= ~DHCPCD_VENDORRAW;
    486 			ifo->vendor[0] = 0;
    487 		}
    488 
    489 		*p = '\0';
    490 		i = atoint(arg);
    491 		arg = p + 1;
    492 		if (i < 1 || i > 254) {
    493 			syslog(LOG_ERR, "vendor option should be between"
    494 			    " 1 and 254 inclusive");
    495 			return -1;
    496 		}
    497 		s = VENDOR_MAX_LEN - ifo->vendor[0] - 2;
    498 		if (inet_aton(arg, &addr) == 1) {
    499 			if (s < 6) {
    500 				s = -1;
    501 				errno = ENOBUFS;
    502 			} else
    503 				memcpy(ifo->vendor + ifo->vendor[0] + 3,
    504 				    &addr.s_addr, sizeof(addr.s_addr));
    505 		} else {
    506 			s = parse_string((char *)ifo->vendor +
    507 			    ifo->vendor[0] + 3, s, arg);
    508 		}
    509 		if (s == -1) {
    510 			syslog(LOG_ERR, "vendor: %m");
    511 			return -1;
    512 		}
    513 		if (s != 0) {
    514 			ifo->vendor[ifo->vendor[0] + 1] = i;
    515 			ifo->vendor[ifo->vendor[0] + 2] = s;
    516 			ifo->vendor[0] += s + 2;
    517 		}
    518 		break;
    519 	case 'w':
    520 		ifo->options |= DHCPCD_WAITIP;
    521 		break;
    522 	case 'y':
    523 		ifo->reboot = atoint(arg);
    524 		if (ifo->reboot < 0) {
    525 			syslog(LOG_ERR, "reboot must be a positive value");
    526 			return -1;
    527 		}
    528 		break;
    529 	case 'z':
    530 		ifav = splitv(&ifac, ifav, arg);
    531 		break;
    532 	case 'A':
    533 		ifo->options &= ~DHCPCD_ARP;
    534 		/* IPv4LL requires ARP */
    535 		ifo->options &= ~DHCPCD_IPV4LL;
    536 		break;
    537 	case 'B':
    538 		ifo->options &= ~DHCPCD_DAEMONISE;
    539 		break;
    540 	case 'C':
    541 		/* Commas to spaces for shell */
    542 		while ((p = strchr(arg, ',')))
    543 			*p = ' ';
    544 		s = strlen("skip_hooks=") + strlen(arg) + 1;
    545 		p = xmalloc(sizeof(char) * s);
    546 		snprintf(p, s, "skip_hooks=%s", arg);
    547 		add_environ(ifo, p, 0);
    548 		free(p);
    549 		break;
    550 	case 'D':
    551 		ifo->options |= DHCPCD_CLIENTID | DHCPCD_DUID;
    552 		break;
    553 	case 'E':
    554 		ifo->options |= DHCPCD_LASTLEASE;
    555 		break;
    556 	case 'F':
    557 		if (!arg) {
    558 			ifo->fqdn = FQDN_BOTH;
    559 			break;
    560 		}
    561 		if (strcmp(arg, "none") == 0)
    562 			ifo->fqdn = FQDN_NONE;
    563 		else if (strcmp(arg, "ptr") == 0)
    564 			ifo->fqdn = FQDN_PTR;
    565 		else if (strcmp(arg, "both") == 0)
    566 			ifo->fqdn = FQDN_BOTH;
    567 		else if (strcmp(arg, "disable") == 0)
    568 			ifo->fqdn = FQDN_DISABLE;
    569 		else {
    570 			syslog(LOG_ERR, "invalid value `%s' for FQDN", arg);
    571 			return -1;
    572 		}
    573 		break;
    574 	case 'G':
    575 		ifo->options &= ~DHCPCD_GATEWAY;
    576 		break;
    577 	case 'H':
    578 		ifo->options |= DHCPCD_XID_HWADDR;
    579 		break;
    580 	case 'I':
    581 		/* Strings have a type of 0 */;
    582 		ifo->clientid[1] = 0;
    583 		if (arg)
    584 			s = parse_string_hwaddr((char *)ifo->clientid + 1,
    585 			    CLIENTID_MAX_LEN, arg, 1);
    586 		else
    587 			s = 0;
    588 		if (s == -1) {
    589 			syslog(LOG_ERR, "clientid: %m");
    590 			return -1;
    591 		}
    592 		ifo->options |= DHCPCD_CLIENTID;
    593 		ifo->clientid[0] = (uint8_t)s;
    594 		break;
    595 	case 'J':
    596 		ifo->options |= DHCPCD_BROADCAST;
    597 		break;
    598 	case 'K':
    599 		ifo->options &= ~DHCPCD_LINK;
    600 		break;
    601 	case 'L':
    602 		ifo->options &= ~DHCPCD_IPV4LL;
    603 		break;
    604 	case 'O':
    605 		if (make_option_mask(ifo->requestmask, arg, -1) != 0 ||
    606 		    make_option_mask(ifo->requiremask, arg, -1) != 0 ||
    607 		    make_option_mask(ifo->nomask, arg, 1) != 0)
    608 		{
    609 			syslog(LOG_ERR, "unknown option `%s'", arg);
    610 			return -1;
    611 		}
    612 		break;
    613 	case 'Q':
    614 		if (make_option_mask(ifo->requiremask, arg, 1) != 0 ||
    615 		    make_option_mask(ifo->requestmask, arg, 1) != 0)
    616 		{
    617 			syslog(LOG_ERR, "unknown option `%s'", arg);
    618 			return -1;
    619 		}
    620 		break;
    621 	case 'S':
    622 		p = strchr(arg, '=');
    623 		if (p == NULL) {
    624 			syslog(LOG_ERR, "static assignment required");
    625 			return -1;
    626 		}
    627 		p++;
    628 		if (strncmp(arg, "ip_address=", strlen("ip_address=")) == 0) {
    629 			if (parse_addr(&ifo->req_addr, &ifo->req_mask, p) != 0)
    630 				return -1;
    631 
    632 			ifo->options |= DHCPCD_STATIC;
    633 			ifo->options &= ~DHCPCD_INFORM;
    634 		} else if (strncmp(arg, "routes=", strlen("routes=")) == 0 ||
    635 		    strncmp(arg, "static_routes=", strlen("static_routes=")) == 0 ||
    636 		    strncmp(arg, "classless_static_routes=", strlen("classless_static_routes=")) == 0 ||
    637 		    strncmp(arg, "ms_classless_static_routes=", strlen("ms_classless_static_routes=")) == 0)
    638 		{
    639 			np = strchr(p, ' ');
    640 			if (np == NULL) {
    641 				syslog(LOG_ERR, "all routes need a gateway");
    642 				return -1;
    643 			}
    644 			*np++ = '\0';
    645 			while (*np == ' ')
    646 				np++;
    647 			if (ifo->routes == NULL) {
    648 				rt = ifo->routes = xmalloc(sizeof(*rt));
    649 			} else {
    650 				rt = ifo->routes;
    651 				while (rt->next)
    652 					rt = rt->next;
    653 				rt->next = xmalloc(sizeof(*rt));
    654 				rt = rt->next;
    655 			}
    656 			rt->next = NULL;
    657 			if (parse_addr(&rt->dest, &rt->net, p) == -1 ||
    658 			    parse_addr(&rt->gate, NULL, np) == -1)
    659 				return -1;
    660 		} else if (strncmp(arg, "routers=", strlen("routers=")) == 0) {
    661 			if (ifo->routes == NULL) {
    662 				rt = ifo->routes = xzalloc(sizeof(*rt));
    663 			} else {
    664 				rt = ifo->routes;
    665 				while (rt->next)
    666 					rt = rt->next;
    667 				rt->next = xmalloc(sizeof(*rt));
    668 				rt = rt->next;
    669 			}
    670 			rt->dest.s_addr = INADDR_ANY;
    671 			rt->net.s_addr = INADDR_ANY;
    672 			rt->next = NULL;
    673 			if (parse_addr(&rt->gate, NULL, p) == -1)
    674 				return -1;
    675 		} else {
    676 			s = 0;
    677 			if (ifo->config != NULL) {
    678 				while (ifo->config[s] != NULL) {
    679 					if (strncmp(ifo->config[s], arg,
    680 						p - arg) == 0)
    681 					{
    682 						free(ifo->config[s]);
    683 						ifo->config[s] = xstrdup(arg);
    684 						return 1;
    685 					}
    686 					s++;
    687 				}
    688 			}
    689 			ifo->config = xrealloc(ifo->config,
    690 			    sizeof(char *) * (s + 2));
    691 			ifo->config[s] = xstrdup(arg);
    692 			ifo->config[s + 1] = NULL;
    693 		}
    694 		break;
    695 	case 'W':
    696 		if (parse_addr(&addr, &addr2, arg) != 0)
    697 			return -1;
    698 		if (strchr(arg, '/') == NULL)
    699 			addr2.s_addr = INADDR_BROADCAST;
    700 		ifo->whitelist = xrealloc(ifo->whitelist,
    701 		    sizeof(in_addr_t) * (ifo->whitelist_len + 2));
    702 		ifo->whitelist[ifo->whitelist_len++] = addr.s_addr;
    703 		ifo->whitelist[ifo->whitelist_len++] = addr2.s_addr;
    704 		break;
    705 	case 'X':
    706 		if (parse_addr(&addr, &addr2, arg) != 0)
    707 			return -1;
    708 		if (strchr(arg, '/') == NULL)
    709 			addr2.s_addr = INADDR_BROADCAST;
    710 		ifo->blacklist = xrealloc(ifo->blacklist,
    711 		    sizeof(in_addr_t) * (ifo->blacklist_len + 2));
    712 		ifo->blacklist[ifo->blacklist_len++] = addr.s_addr;
    713 		ifo->blacklist[ifo->blacklist_len++] = addr2.s_addr;
    714 		break;
    715 	case 'Z':
    716 		ifdv = splitv(&ifdc, ifdv, arg);
    717 		break;
    718 	case O_ARPING:
    719 		if (parse_addr(&addr, NULL, arg) != 0)
    720 			return -1;
    721 		ifo->arping = xrealloc(ifo->arping,
    722 		    sizeof(in_addr_t) * (ifo->arping_len + 1));
    723 		ifo->arping[ifo->arping_len++] = addr.s_addr;
    724 		break;
    725 	case O_DESTINATION:
    726 		if (make_option_mask(ifo->dstmask, arg, 2) != 0) {
    727 			if (errno == EINVAL)
    728 				syslog(LOG_ERR, "option `%s' does not take"
    729 				    " an IPv4 address", arg);
    730 			else
    731 				syslog(LOG_ERR, "unknown option `%s'", arg);
    732 			return -1;
    733 		}
    734 		break;
    735 	case O_FALLBACK:
    736 		free(ifo->fallback);
    737 		ifo->fallback = xstrdup(arg);
    738 		break;
    739 	default:
    740 		return 0;
    741 	}
    742 
    743 	return 1;
    744 }
    745 
    746 static int
    747 parse_config_line(struct if_options *ifo, const char *opt, char *line)
    748 {
    749 	unsigned int i;
    750 
    751 	for (i = 0; i < sizeof(cf_options) / sizeof(cf_options[0]); i++) {
    752 		if (!cf_options[i].name ||
    753 		    strcmp(cf_options[i].name, opt) != 0)
    754 			continue;
    755 
    756 		if (cf_options[i].has_arg == required_argument && !line) {
    757 			fprintf(stderr,
    758 			    PACKAGE ": option requires an argument -- %s\n",
    759 			    opt);
    760 			return -1;
    761 		}
    762 
    763 		return parse_option(ifo, cf_options[i].val, line);
    764 	}
    765 
    766 	fprintf(stderr, PACKAGE ": unknown option -- %s\n", opt);
    767 	return -1;
    768 }
    769 
    770 struct if_options *
    771 read_config(const char *file,
    772     const char *ifname, const char *ssid, const char *profile)
    773 {
    774 	struct if_options *ifo;
    775 	FILE *f;
    776 	char *line, *option, *p, *platform;
    777 	int skip = 0, have_profile = 0;
    778 	struct utsname utn;
    779 
    780 	/* Seed our default options */
    781 	ifo = xzalloc(sizeof(*ifo));
    782 	ifo->options |= DHCPCD_GATEWAY | DHCPCD_DAEMONISE;
    783 	ifo->options |= DHCPCD_ARP | DHCPCD_IPV4LL | DHCPCD_LINK;
    784 	ifo->timeout = DEFAULT_TIMEOUT;
    785 	ifo->reboot = DEFAULT_REBOOT;
    786 	ifo->metric = -1;
    787 	strlcpy(ifo->script, SCRIPT, sizeof(ifo->script));
    788 	gethostname(ifo->hostname, HOSTNAME_MAX_LEN);
    789 	/* Ensure that the hostname is NULL terminated */
    790 	ifo->hostname[HOSTNAME_MAX_LEN] = '\0';
    791 	if (strcmp(ifo->hostname, "(none)") == 0 ||
    792 	    strcmp(ifo->hostname, "localhost") == 0)
    793 		ifo->hostname[0] = '\0';
    794 
    795 	platform = hardware_platform();
    796 	if (uname(&utn) == 0)
    797 		ifo->vendorclassid[0] = snprintf((char *)ifo->vendorclassid + 1,
    798 		    VENDORCLASSID_MAX_LEN,
    799 	            "%s-%s:%s-%s:%s%s%s", PACKAGE, VERSION,
    800 		    utn.sysname, utn.release, utn.machine,
    801 		    platform ? ":" : "", platform ? platform : "");
    802 	else
    803 		ifo->vendorclassid[0] = snprintf((char *)ifo->vendorclassid + 1,
    804 		    VENDORCLASSID_MAX_LEN, "%s-%s", PACKAGE, VERSION);
    805 
    806 	/* Parse our options file */
    807 	f = fopen(file ? file : CONFIG, "r");
    808 	if (f == NULL) {
    809 		if (file != NULL)
    810 			syslog(LOG_ERR, "fopen `%s': %m", file);
    811 		return ifo;
    812 	}
    813 
    814 	while ((line = get_line(f))) {
    815 		option = strsep(&line, " \t");
    816 		/* Trim trailing whitespace */
    817 		if (line && *line) {
    818 			p = line + strlen(line) - 1;
    819 			while (p != line &&
    820 			    (*p == ' ' || *p == '\t') &&
    821 			    *(p - 1) != '\\')
    822 				*p-- = '\0';
    823 		}
    824 		/* Start of an interface block, skip if not ours */
    825 		if (strcmp(option, "interface") == 0) {
    826 			if (ifname && line && strcmp(line, ifname) == 0)
    827 				skip = 0;
    828 			else
    829 				skip = 1;
    830 			continue;
    831 		}
    832 		/* Start of an ssid block, skip if not ours */
    833 		if (strcmp(option, "ssid") == 0) {
    834 			if (ssid && line && strcmp(line, ssid) == 0)
    835 				skip = 0;
    836 			else
    837 				skip = 1;
    838 			continue;
    839 		}
    840 		/* Start of a profile block, skip if not ours */
    841 		if (strcmp(option, "profile") == 0) {
    842 			if (profile && line && strcmp(line, profile) == 0) {
    843 				skip = 0;
    844 				have_profile = 1;
    845 			} else
    846 				skip = 1;
    847 			continue;
    848 		}
    849 		if (skip)
    850 			continue;
    851 		parse_config_line(ifo, option, line);
    852 	}
    853 	fclose(f);
    854 
    855 	if (profile && !have_profile) {
    856 		free_options(ifo);
    857 		errno = ENOENT;
    858 		ifo = NULL;
    859 	}
    860 
    861 	/* Terminate the encapsulated options */
    862 	if (ifo && ifo->vendor[0] && !(ifo->options & DHCPCD_VENDORRAW)) {
    863 		ifo->vendor[0]++;
    864 		ifo->vendor[ifo->vendor[0]] = DHO_END;
    865 	}
    866 	return ifo;
    867 }
    868 
    869 int
    870 add_options(struct if_options *ifo, int argc, char **argv)
    871 {
    872 	int oi, opt, r = 1;
    873 
    874 	optind = 0;
    875 	while ((opt = getopt_long(argc, argv, IF_OPTS, cf_options, &oi)) != -1)
    876 	{
    877 		r = parse_option(ifo, opt, optarg);
    878 		if (r != 1)
    879 			break;
    880 	}
    881 	/* Terminate the encapsulated options */
    882 	if (r == 1 && ifo->vendor[0] && !(ifo->options & DHCPCD_VENDORRAW)) {
    883 		ifo->vendor[0]++;
    884 		ifo->vendor[ifo->vendor[0]] = DHO_END;
    885 	}
    886 	return r;
    887 }
    888 
    889 void
    890 free_options(struct if_options *ifo)
    891 {
    892 	size_t i;
    893 
    894 	if (ifo) {
    895 		if (ifo->environ) {
    896 			i = 0;
    897 			while (ifo->environ[i])
    898 				free(ifo->environ[i++]);
    899 			free(ifo->environ);
    900 		}
    901 		if (ifo->config) {
    902 			i = 0;
    903 			while (ifo->config[i])
    904 				free(ifo->config[i++]);
    905 			free(ifo->config);
    906 		}
    907 		free_routes(ifo->routes);
    908 		free(ifo->arping);
    909 		free(ifo->blacklist);
    910 		free(ifo->fallback);
    911 		free(ifo);
    912 	}
    913 }
    914