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