1 /* 2 * dhcpcd - DHCP client daemon 3 * Copyright (c) 2006-2015 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/utsname.h> 29 30 #include <ctype.h> 31 #include <errno.h> 32 #include <fcntl.h> 33 #include <inttypes.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <unistd.h> 37 38 #include "config.h" 39 40 #include "common.h" 41 #include "dhcp-common.h" 42 #include "dhcp.h" 43 #include "if.h" 44 #include "ipv6.h" 45 46 void 47 dhcp_print_option_encoding(const struct dhcp_opt *opt, int cols) 48 { 49 50 while (cols < 40) { 51 putchar(' '); 52 cols++; 53 } 54 putchar('\t'); 55 if (opt->type & EMBED) 56 printf(" embed"); 57 if (opt->type & ENCAP) 58 printf(" encap"); 59 if (opt->type & INDEX) 60 printf(" index"); 61 if (opt->type & ARRAY) 62 printf(" array"); 63 if (opt->type & UINT8) 64 printf(" byte"); 65 else if (opt->type & UINT16) 66 printf(" uint16"); 67 else if (opt->type & SINT16) 68 printf(" sint16"); 69 else if (opt->type & UINT32) 70 printf(" uint32"); 71 else if (opt->type & SINT32) 72 printf(" sint32"); 73 else if (opt->type & ADDRIPV4) 74 printf(" ipaddress"); 75 else if (opt->type & ADDRIPV6) 76 printf(" ip6address"); 77 else if (opt->type & FLAG) 78 printf(" flag"); 79 else if (opt->type & RFC3397) 80 printf(" domain"); 81 else if (opt->type & DOMAIN) 82 printf(" dname"); 83 else if (opt->type & ASCII) 84 printf(" ascii"); 85 else if (opt->type & RAW) 86 printf(" raw"); 87 else if (opt->type & BINHEX) 88 printf(" binhex"); 89 else if (opt->type & STRING) 90 printf(" string"); 91 if (opt->type & RFC3361) 92 printf(" rfc3361"); 93 if (opt->type & RFC3442) 94 printf(" rfc3442"); 95 if (opt->type & RFC5969) 96 printf(" rfc5969"); 97 if (opt->type & REQUEST) 98 printf(" request"); 99 if (opt->type & NOREQ) 100 printf(" norequest"); 101 putchar('\n'); 102 } 103 104 struct dhcp_opt * 105 vivso_find(uint32_t iana_en, const void *arg) 106 { 107 const struct interface *ifp; 108 size_t i; 109 struct dhcp_opt *opt; 110 111 ifp = arg; 112 for (i = 0, opt = ifp->options->vivso_override; 113 i < ifp->options->vivso_override_len; 114 i++, opt++) 115 if (opt->option == iana_en) 116 return opt; 117 for (i = 0, opt = ifp->ctx->vivso; 118 i < ifp->ctx->vivso_len; 119 i++, opt++) 120 if (opt->option == iana_en) 121 return opt; 122 return NULL; 123 } 124 125 ssize_t 126 dhcp_vendor(char *str, size_t len) 127 { 128 struct utsname utn; 129 char *p; 130 int l; 131 132 if (uname(&utn) != 0) 133 return (ssize_t)snprintf(str, len, "%s-%s", 134 PACKAGE, VERSION); 135 p = str; 136 l = snprintf(p, len, 137 "%s-%s:%s-%s:%s", PACKAGE, VERSION, 138 utn.sysname, utn.release, utn.machine); 139 if (l == -1 || (size_t)(l + 1) > len) 140 return -1; 141 p += l; 142 len -= (size_t)l; 143 l = if_machinearch(p, len); 144 if (l == -1 || (size_t)(l + 1) > len) 145 return -1; 146 p += l; 147 return p - str; 148 } 149 150 int 151 make_option_mask(const struct dhcp_opt *dopts, size_t dopts_len, 152 const struct dhcp_opt *odopts, size_t odopts_len, 153 uint8_t *mask, const char *opts, int add) 154 { 155 char *token, *o, *p; 156 const struct dhcp_opt *opt; 157 int match, e; 158 unsigned int n; 159 size_t i; 160 161 if (opts == NULL) 162 return -1; 163 o = p = strdup(opts); 164 while ((token = strsep(&p, ", "))) { 165 if (*token == '\0') 166 continue; 167 match = 0; 168 for (i = 0, opt = odopts; i < odopts_len; i++, opt++) { 169 if (strcmp(opt->var, token) == 0) 170 match = 1; 171 else { 172 n = (unsigned int)strtou(token, NULL, 0, 173 0, UINT_MAX, &e); 174 if (e == 0 && opt->option == n) 175 match = 1; 176 } 177 if (match) 178 break; 179 } 180 if (match == 0) { 181 for (i = 0, opt = dopts; i < dopts_len; i++, opt++) { 182 if (strcmp(opt->var, token) == 0) 183 match = 1; 184 else { 185 n = (unsigned int)strtou(token, NULL, 0, 186 0, UINT_MAX, &e); 187 if (e == 0 && opt->option == n) 188 match = 1; 189 } 190 if (match) 191 break; 192 } 193 } 194 if (!match || !opt->option) { 195 free(o); 196 errno = ENOENT; 197 return -1; 198 } 199 if (add == 2 && !(opt->type & ADDRIPV4)) { 200 free(o); 201 errno = EINVAL; 202 return -1; 203 } 204 if (add == 1 || add == 2) 205 add_option_mask(mask, opt->option); 206 else 207 del_option_mask(mask, opt->option); 208 } 209 free(o); 210 return 0; 211 } 212 213 size_t 214 encode_rfc1035(const char *src, uint8_t *dst) 215 { 216 uint8_t *p; 217 uint8_t *lp; 218 size_t len; 219 uint8_t has_dot; 220 221 if (src == NULL || *src == '\0') 222 return 0; 223 224 if (dst) { 225 p = dst; 226 lp = p++; 227 } 228 /* Silence bogus GCC warnings */ 229 else 230 p = lp = NULL; 231 232 len = 1; 233 has_dot = 0; 234 for (; *src; src++) { 235 if (*src == '\0') 236 break; 237 if (*src == '.') { 238 /* Skip the trailing . */ 239 if (src[1] == '\0') 240 break; 241 has_dot = 1; 242 if (dst) { 243 *lp = (uint8_t)(p - lp - 1); 244 if (*lp == '\0') 245 return len; 246 lp = p++; 247 } 248 } else if (dst) 249 *p++ = (uint8_t)*src; 250 len++; 251 } 252 253 if (dst) { 254 *lp = (uint8_t)(p - lp - 1); 255 if (has_dot) 256 *p++ = '\0'; 257 } 258 259 if (has_dot) 260 len++; 261 262 return len; 263 } 264 265 /* Decode an RFC3397 DNS search order option into a space 266 * separated string. Returns length of string (including 267 * terminating zero) or zero on error. out may be NULL 268 * to just determine output length. */ 269 ssize_t 270 decode_rfc3397(char *out, size_t len, const uint8_t *p, size_t pl) 271 { 272 const char *start; 273 size_t start_len, l, count; 274 const uint8_t *r, *q = p, *e; 275 int hops; 276 uint8_t ltype; 277 278 count = 0; 279 start = out; 280 start_len = len; 281 q = p; 282 e = p + pl; 283 while (q < e) { 284 r = NULL; 285 hops = 0; 286 /* Check we are inside our length again in-case 287 * the name isn't fully qualified (ie, not terminated) */ 288 while (q < e && (l = (size_t)*q++)) { 289 ltype = l & 0xc0; 290 if (ltype == 0x80 || ltype == 0x40) 291 return -1; 292 else if (ltype == 0xc0) { /* pointer */ 293 if (q == e) { 294 errno = ERANGE; 295 return -1; 296 } 297 l = (l & 0x3f) << 8; 298 l |= *q++; 299 /* save source of first jump. */ 300 if (!r) 301 r = q; 302 hops++; 303 if (hops > 255) { 304 errno = ERANGE; 305 return -1; 306 } 307 q = p + l; 308 if (q >= e) { 309 errno = ERANGE; 310 return -1; 311 } 312 } else { 313 /* straightforward name segment, add with '.' */ 314 if (q + l > e) { 315 errno = ERANGE; 316 return -1; 317 } 318 count += l + 1; 319 if (out) { 320 if (l + 1 > len) { 321 errno = ENOBUFS; 322 return -1; 323 } 324 memcpy(out, q, l); 325 out += l; 326 *out++ = '.'; 327 len -= l; 328 len--; 329 } 330 q += l; 331 } 332 } 333 /* change last dot to space */ 334 if (out && out != start) 335 *(out - 1) = ' '; 336 if (r) 337 q = r; 338 } 339 340 /* change last space to zero terminator */ 341 if (out) { 342 if (out != start) 343 *(out - 1) = '\0'; 344 else if (start_len > 0) 345 *out = '\0'; 346 } 347 348 if (count) 349 /* Don't count the trailing NUL */ 350 count--; 351 return (ssize_t)count; 352 } 353 354 /* Check for a valid domain name as per RFC1123 with the exception of 355 * allowing - and _ (but not at start or end) as they seem to be widely used. */ 356 static int 357 valid_domainname(char *lbl, int type) 358 { 359 char *slbl, *lst; 360 unsigned char c; 361 int start, len, errset; 362 363 if (lbl == NULL || *lbl == '\0') { 364 errno = EINVAL; 365 return 0; 366 } 367 368 slbl = lbl; 369 lst = NULL; 370 start = 1; 371 len = errset = 0; 372 for (;;) { 373 c = (unsigned char)*lbl++; 374 if (c == '\0') 375 return 1; 376 if (c == ' ') { 377 if (lbl - 1 == slbl) /* No space at start */ 378 break; 379 if (!(type & ARRAY)) 380 break; 381 /* Skip to the next label */ 382 if (!start) { 383 start = 1; 384 lst = lbl - 1; 385 } 386 if (len) 387 len = 0; 388 continue; 389 } 390 if (c == '.') { 391 if (*lbl == '.') 392 break; 393 len = 0; 394 continue; 395 } 396 if (((c == '-' || c == '_') && 397 !start && *lbl != ' ' && *lbl != '\0') || 398 isalnum(c)) 399 { 400 if (++len > 63) { 401 errno = ERANGE; 402 errset = 1; 403 break; 404 } 405 } else 406 break; 407 if (start) 408 start = 0; 409 } 410 411 if (!errset) 412 errno = EINVAL; 413 if (lst) { 414 /* At least one valid domain, return it */ 415 *lst = '\0'; 416 return 1; 417 } 418 return 0; 419 } 420 421 /* 422 * Prints a chunk of data to a string. 423 * PS_SHELL goes as it is these days, it's upto the target to validate it. 424 * PS_SAFE has all non ascii and non printables changes to escaped octal. 425 */ 426 static const char hexchrs[] = "0123456789abcdef"; 427 ssize_t 428 print_string(char *dst, size_t len, int type, const uint8_t *data, size_t dl) 429 { 430 char *odst; 431 uint8_t c; 432 const uint8_t *e; 433 size_t bytes; 434 435 odst = dst; 436 bytes = 0; 437 e = data + dl; 438 439 while (data < e) { 440 c = *data++; 441 if (type & BINHEX) { 442 if (dst) { 443 if (len == 0 || len == 1) { 444 errno = ENOSPC; 445 return -1; 446 } 447 *dst++ = hexchrs[(c & 0xF0) >> 4]; 448 *dst++ = hexchrs[(c & 0x0F)]; 449 len -= 2; 450 } 451 bytes += 2; 452 continue; 453 } 454 if (type & ASCII && (!isascii(c))) { 455 errno = EINVAL; 456 break; 457 } 458 if (!(type & (ASCII | RAW | ESCSTRING | ESCFILE)) /* plain */ && 459 (!isascii(c) && !isprint(c))) 460 { 461 errno = EINVAL; 462 break; 463 } 464 if ((type & (ESCSTRING | ESCFILE) && 465 (c == '\\' || !isascii(c) || !isprint(c))) || 466 (type & ESCFILE && (c == '/' || c == ' '))) 467 { 468 errno = EINVAL; 469 if (c == '\\') { 470 if (dst) { 471 if (len == 0 || len == 1) { 472 errno = ENOSPC; 473 return -1; 474 } 475 *dst++ = '\\'; *dst++ = '\\'; 476 len -= 2; 477 } 478 bytes += 2; 479 continue; 480 } 481 if (dst) { 482 if (len < 5) { 483 errno = ENOSPC; 484 return -1; 485 } 486 *dst++ = '\\'; 487 *dst++ = (char)(((c >> 6) & 03) + '0'); 488 *dst++ = (char)(((c >> 3) & 07) + '0'); 489 *dst++ = (char)(( c & 07) + '0'); 490 len -= 4; 491 } 492 bytes += 4; 493 } else { 494 if (dst) { 495 if (len == 0) { 496 errno = ENOSPC; 497 return -1; 498 } 499 *dst++ = (char)c; 500 len--; 501 } 502 bytes++; 503 } 504 } 505 506 /* NULL */ 507 if (dst) { 508 if (len == 0) { 509 errno = ENOSPC; 510 return -1; 511 } 512 *dst = '\0'; 513 514 /* Now we've printed it, validate the domain */ 515 if (type & DOMAIN && !valid_domainname(odst, type)) { 516 *odst = '\0'; 517 return 1; 518 } 519 520 } 521 522 return (ssize_t)bytes; 523 } 524 525 #define ADDR6SZ 16 526 static size_t 527 dhcp_optlen(const struct dhcp_opt *opt, size_t dl) 528 { 529 size_t sz; 530 531 if (opt->type & ADDRIPV6) 532 sz = ADDR6SZ; 533 else if (opt->type & (UINT32 | ADDRIPV4)) 534 sz = sizeof(uint32_t); 535 else if (opt->type & UINT16) 536 sz = sizeof(uint16_t); 537 else if (opt->type & (UINT8 | BITFLAG)) 538 sz = sizeof(uint8_t); 539 else if (opt->type & FLAG) 540 return 0; 541 else { 542 /* All other types are variable length */ 543 if (opt->len) { 544 if ((size_t)opt->len > dl) { 545 errno = ENODATA; 546 return -1; 547 } 548 return (ssize_t)opt->len; 549 } 550 return (ssize_t)dl; 551 } 552 if (dl < sz) { 553 errno = ENODATA; 554 return -1; 555 } 556 557 /* Trim any extra data. 558 * Maybe we need a settng to reject DHCP options with extra data? */ 559 if (opt->type & ARRAY) 560 return (ssize_t)(dl - (dl % sz)); 561 return (ssize_t)sz; 562 } 563 564 #ifdef INET6 565 #define PO_IFNAME 566 #else 567 #define PO_IFNAME __unused 568 #endif 569 570 ssize_t 571 print_option(char *s, size_t len, int type, const uint8_t *data, size_t dl, 572 PO_IFNAME const char *ifname) 573 { 574 const uint8_t *e, *t; 575 uint16_t u16; 576 int16_t s16; 577 uint32_t u32; 578 int32_t s32; 579 struct in_addr addr; 580 ssize_t bytes = 0, sl; 581 size_t l; 582 char *tmp; 583 584 if (type & RFC3397) { 585 sl = decode_rfc3397(NULL, 0, data, dl); 586 if (sl == 0 || sl == -1) 587 return sl; 588 l = (size_t)sl + 1; 589 tmp = malloc(l); 590 if (tmp == NULL) 591 return -1; 592 decode_rfc3397(tmp, l, data, dl); 593 sl = print_string(s, len, type, (uint8_t *)tmp, l - 1); 594 free(tmp); 595 return sl; 596 } 597 598 #ifdef INET 599 if (type & RFC3361) { 600 if ((tmp = decode_rfc3361(data, dl)) == NULL) 601 return -1; 602 l = strlen(tmp); 603 sl = print_string(s, len, type, (uint8_t *)tmp, l); 604 free(tmp); 605 return sl; 606 } 607 608 if (type & RFC3442) 609 return decode_rfc3442(s, len, data, dl); 610 611 if (type & RFC5969) 612 return decode_rfc5969(s, len, data, dl); 613 #endif 614 615 if (type & STRING) 616 return print_string(s, len, type, data, dl); 617 618 if (type & FLAG) { 619 if (s) { 620 *s++ = '1'; 621 *s = '\0'; 622 } 623 return 1; 624 } 625 626 if (!s) { 627 if (type & UINT8) 628 l = 3; 629 else if (type & UINT16) { 630 l = 5; 631 dl /= 2; 632 } else if (type & SINT16) { 633 l = 6; 634 dl /= 2; 635 } else if (type & UINT32) { 636 l = 10; 637 dl /= 4; 638 } else if (type & SINT32) { 639 l = 11; 640 dl /= 4; 641 } else if (type & ADDRIPV4) { 642 l = 16; 643 dl /= 4; 644 } 645 #ifdef INET6 646 else if (type & ADDRIPV6) { 647 e = data + dl; 648 l = 0; 649 while (data < e) { 650 if (l) 651 l++; /* space */ 652 sl = ipv6_printaddr(NULL, 0, data, ifname); 653 if (sl != -1) 654 l += (size_t)sl; 655 data += 16; 656 } 657 return (ssize_t)l; 658 } 659 #endif 660 else { 661 errno = EINVAL; 662 return -1; 663 } 664 return (ssize_t)(l * dl); 665 } 666 667 t = data; 668 e = data + dl; 669 while (data < e) { 670 if (data != t) { 671 *s++ = ' '; 672 bytes++; 673 len--; 674 } 675 if (type & UINT8) { 676 sl = snprintf(s, len, "%u", *data); 677 data++; 678 } else if (type & UINT16) { 679 memcpy(&u16, data, sizeof(u16)); 680 u16 = ntohs(u16); 681 sl = snprintf(s, len, "%u", u16); 682 data += sizeof(u16); 683 } else if (type & SINT16) { 684 memcpy(&u16, data, sizeof(u16)); 685 s16 = (int16_t)ntohs(u16); 686 sl = snprintf(s, len, "%d", s16); 687 data += sizeof(u16); 688 } else if (type & UINT32) { 689 memcpy(&u32, data, sizeof(u32)); 690 u32 = ntohl(u32); 691 sl = snprintf(s, len, "%u", u32); 692 data += sizeof(u32); 693 } else if (type & SINT32) { 694 memcpy(&u32, data, sizeof(u32)); 695 s32 = (int32_t)ntohl(u32); 696 sl = snprintf(s, len, "%d", s32); 697 data += sizeof(u32); 698 } else if (type & ADDRIPV4) { 699 memcpy(&addr.s_addr, data, sizeof(addr.s_addr)); 700 sl = snprintf(s, len, "%s", inet_ntoa(addr)); 701 data += sizeof(addr.s_addr); 702 } 703 #ifdef INET6 704 else if (type & ADDRIPV6) { 705 ssize_t r; 706 707 r = ipv6_printaddr(s, len, data, ifname); 708 if (r != -1) 709 sl = r; 710 else 711 sl = 0; 712 data += 16; 713 } 714 #endif 715 else 716 sl = 0; 717 if (len <= sl) { 718 bytes += len; 719 break; 720 } 721 len -= (size_t)sl; 722 bytes += sl; 723 s += sl; 724 } 725 726 return bytes; 727 } 728 729 /* Lease file name is formatted according to the expectation of the ChromiumOS's 730 * connection manager (shill). */ 731 int 732 dhcp_set_leasefile(char *leasefile, size_t len, int family, 733 const struct interface *ifp, const char *extra) 734 { 735 char ssid[len]; 736 737 if (ifp->name[0] == '\0') { 738 strlcpy(leasefile, ifp->ctx->pidfile, len); 739 return 0; 740 } 741 742 if (strlen(ifp->lease_identifier) > 0) { 743 return snprintf(leasefile, len, 744 family == AF_INET ? LEASEFILE : LEASEFILE6, 745 ifp->lease_identifier, "", extra); 746 } 747 return snprintf(leasefile, len, 748 family == AF_INET ? LEASEFILE : LEASEFILE6, 749 ifp->name, "", extra); 750 } 751 752 static size_t 753 dhcp_envoption1(struct dhcpcd_ctx *ctx, char **env, const char *prefix, 754 const struct dhcp_opt *opt, int vname, const uint8_t *od, size_t ol, 755 const char *ifname) 756 { 757 ssize_t len; 758 size_t e; 759 char *v, *val; 760 761 /* Ensure a valid length */ 762 ol = (size_t)dhcp_optlen(opt, ol); 763 if ((ssize_t)ol == -1) 764 return 0; 765 766 len = print_option(NULL, 0, opt->type, od, ol, ifname); 767 if (len < 0) 768 return 0; 769 if (vname) 770 e = strlen(opt->var) + 1; 771 else 772 e = 0; 773 if (prefix) 774 e += strlen(prefix); 775 e += (size_t)len + 2; 776 if (env == NULL) 777 return e; 778 v = val = *env = malloc(e); 779 if (v == NULL) { 780 logger(ctx, LOG_ERR, "%s: %m", __func__); 781 return 0; 782 } 783 if (vname) 784 v += snprintf(val, e, "%s_%s=", prefix, opt->var); 785 else 786 v += snprintf(val, e, "%s=", prefix); 787 if (len != 0) 788 print_option(v, (size_t)len + 1, opt->type, od, ol, ifname); 789 return e; 790 } 791 792 size_t 793 dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix, 794 const char *ifname, struct dhcp_opt *opt, 795 const uint8_t *(*dgetopt)(struct dhcpcd_ctx *, 796 size_t *, unsigned int *, size_t *, 797 const uint8_t *, size_t, struct dhcp_opt **), 798 const uint8_t *od, size_t ol) 799 { 800 size_t e, i, n, eos, eol; 801 unsigned int eoc; 802 const uint8_t *eod; 803 int ov; 804 struct dhcp_opt *eopt, *oopt; 805 char *pfx; 806 807 /* If no embedded or encapsulated options, it's easy */ 808 if (opt->embopts_len == 0 && opt->encopts_len == 0) { 809 if (dhcp_envoption1(ctx, env == NULL ? NULL : &env[0], 810 prefix, opt, 1, od, ol, ifname)) 811 return 1; 812 return 0; 813 } 814 815 /* Create a new prefix based on the option */ 816 if (env) { 817 if (opt->type & INDEX) { 818 if (opt->index > 999) { 819 errno = ENOBUFS; 820 logger(ctx, LOG_ERR, "%s: %m", __func__); 821 return 0; 822 } 823 } 824 e = strlen(prefix) + strlen(opt->var) + 2 + 825 (opt->type & INDEX ? 3 : 0); 826 pfx = malloc(e); 827 if (pfx == NULL) { 828 logger(ctx, LOG_ERR, "%s: %m", __func__); 829 return 0; 830 } 831 if (opt->type & INDEX) 832 snprintf(pfx, e, "%s_%s%d", prefix, 833 opt->var, ++opt->index); 834 else 835 snprintf(pfx, e, "%s_%s", prefix, opt->var); 836 } else 837 pfx = NULL; 838 839 /* Embedded options are always processed first as that 840 * is a fixed layout */ 841 n = 0; 842 for (i = 0, eopt = opt->embopts; i < opt->embopts_len; i++, eopt++) { 843 e = dhcp_optlen(eopt, ol); 844 if (e == 0) { 845 /* An option was expected, but there is not enough 846 * data for it. 847 * This may not be an error as some options like 848 * DHCP FQDN in RFC4702 have a string as the last 849 * option which is optional. 850 * FIXME: Add an flag to the options to indicate 851 * wether this is allowable or not. */ 852 if (ol != 0 || i + 1 < opt->embopts_len) 853 logger(ctx, LOG_WARNING, 854 "%s: %s: malformed option %d", 855 ifname, __func__, opt->option); 856 goto out; 857 } 858 /* Use the option prefix if the embedded option 859 * name is different. 860 * This avoids new_fqdn_fqdn which would be silly. */ 861 ov = strcmp(opt->var, eopt->var); 862 if (dhcp_envoption1(ctx, env == NULL ? NULL : &env[n], 863 pfx, eopt, ov, od, e, ifname)) 864 n++; 865 od += e; 866 ol -= e; 867 } 868 869 /* Enumerate our encapsulated options */ 870 if (opt->encopts_len && ol > 0) { 871 /* Zero any option indexes 872 * We assume that referenced encapsulated options are NEVER 873 * recursive as the index order could break. */ 874 for (i = 0, eopt = opt->encopts; 875 i < opt->encopts_len; 876 i++, eopt++) 877 { 878 eoc = opt->option; 879 if (eopt->type & OPTION) { 880 dgetopt(ctx, NULL, &eoc, NULL, NULL, 0, &oopt); 881 if (oopt) 882 oopt->index = 0; 883 } 884 } 885 886 while ((eod = dgetopt(ctx, &eos, &eoc, &eol, od, ol, &oopt))) { 887 for (i = 0, eopt = opt->encopts; 888 i < opt->encopts_len; 889 i++, eopt++) 890 { 891 if (eopt->option == eoc) { 892 if (eopt->type & OPTION) { 893 if (oopt == NULL) 894 /* Report error? */ 895 continue; 896 } 897 n += dhcp_envoption(ctx, 898 env == NULL ? NULL : &env[n], pfx, 899 ifname, 900 eopt->type & OPTION ? oopt : eopt, 901 dgetopt, eod, eol); 902 break; 903 } 904 } 905 od += eos + eol; 906 ol -= eos + eol; 907 } 908 } 909 910 out: 911 if (env) 912 free(pfx); 913 914 /* Return number of options found */ 915 return n; 916 } 917 918 void 919 dhcp_zero_index(struct dhcp_opt *opt) 920 { 921 size_t i; 922 struct dhcp_opt *o; 923 924 opt->index = 0; 925 for (i = 0, o = opt->embopts; i < opt->embopts_len; i++, o++) 926 dhcp_zero_index(o); 927 for (i = 0, o = opt->encopts; i < opt->encopts_len; i++, o++) 928 dhcp_zero_index(o); 929 } 930