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