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