1/* 2 * Copyright (c) 1999-2013, 2011 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * dhcp_options.c 26 * - routines to parse and access dhcp options 27 * and create new dhcp option areas 28 * - handles overloaded areas as well as vendor-specific options 29 * that are encoded using the RFC 2132 encoding 30 */ 31 32/* 33 * Modification History 34 * 35 * November 23, 1999 Dieter Siegmund (dieter@apple) 36 * - created from objective C version (dhcpOptions.m) 37 * - generalized code so that the file, sname and vendor specific 38 * areas could be parsed using the same routines 39 * - cleanly separated functions that deal with existing option areas 40 * (dhcpol_*) from those that create new option areas (dhpoa_*). 41 */ 42#include "dhcp.h" 43 44#include <unistd.h> 45#include <stdlib.h> 46#include <stdio.h> 47#include <sys/types.h> 48#include <netinet/in.h> 49#include <arpa/inet.h> 50#include <strings.h> 51 52#include "rfc_options.h" 53#include "gen_dhcp_types.h" 54 55#include "dhcp_options.h" 56#include "gen_dhcp_parse_table.h" 57#include "util.h" 58#include "DNSNameList.h" 59#include "nbo.h" 60#include "cfutil.h" 61#include <SystemConfiguration/SCPrivate.h> 62 63/* 64 * Module: dhcpoa (dhcp options area) 65 * 66 * Purpose: 67 * Types and functions to create new dhcp option areas. 68 */ 69 70#define DHCPOA_MAGIC 0x11223344 71 72 73#define MAX_TAG (sizeof(dhcptag_info_table) / sizeof(dhcptag_info_table[0])) 74 75 76__private_extern__ const uint8_t rfc_magic[] = RFC_OPTIONS_MAGIC; 77 78 79/* 80 * Functions: dhcptag_*, dhcptype_* 81 * 82 * Purpose: 83 * Functions to deal with dhcp option tag and type information. 84 */ 85 86/* 87 * Function: dhcptype_info 88 * 89 * Purpose: 90 * Return the type information for the given type. 91 */ 92const dhcptype_info_t * 93dhcptype_info(dhcptype_t type) 94{ 95 if (type > dhcptype_last_e) 96 return (NULL); 97 return dhcptype_info_table + type; 98} 99 100/* 101 * Function: dhcptype_from_str 102 * 103 * Purpose: 104 * Convert from a string to the appropriate internal representation 105 * for the given type. Calls the appropriate strto<type> function. 106 */ 107boolean_t 108dhcptype_from_str(const char * str, int type, void * buf, int * len_p, 109 dhcpo_err_str_t * err) 110{ 111 const dhcptype_info_t * type_info = dhcptype_info(type); 112 113 if (err) 114 err->str[0] = '\0'; 115 116 if (type_info == NULL) { 117 if (err) { 118 snprintf(err->str, sizeof(err->str), "type %d unknown", type); 119 } 120 return (FALSE); 121 } 122 123 if (*len_p < type_info->size) { 124 if (err) { 125 snprintf(err->str, sizeof(err->str), 126 "type %s buffer too small (%d < %d)", 127 type_info->name, *len_p, type_info->size); 128 } 129 return (FALSE); 130 } 131 132 switch (type) { 133 case dhcptype_bool_e: { 134 long l = strtol(str, 0, 0); 135 *len_p = type_info->size; 136 *((uint8_t *)buf) = ((l == 0) ? 0 : 1); 137 break; 138 } 139 case dhcptype_uint8_e: { 140 unsigned long ul = strtoul(str, 0, 0); 141 *len_p = type_info->size; 142 if (ul > 255) { 143 if (err) { 144 snprintf(err->str, sizeof(err->str), 145 "value %ld too large for %s", 146 ul, type_info->name); 147 } 148 return (FALSE); 149 } 150 *((uint8_t *)buf) = ul; 151 break; 152 } 153 case dhcptype_uint16_e: { 154 unsigned long ul = strtoul(str, 0, 0); 155 unsigned short us = ul; 156 157 if (ul > 65535) { 158 if (err) { 159 snprintf(err->str, sizeof(err->str), 160 "value %ld too large for %s", 161 ul, type_info->name); 162 } 163 return (FALSE); 164 } 165 net_uint16_set(buf, us); 166 *len_p = type_info->size; 167 break; 168 } 169 case dhcptype_int32_e: { 170 int32_t l = (int32_t)strtol(str, 0, 0); 171 net_uint32_set(buf, l); 172 *len_p = type_info->size; 173 break; 174 } 175 case dhcptype_uint32_e: { 176 uint32_t l = (uint32_t)strtoul(str, 0, 0); 177 net_uint32_set(buf, l); 178 *len_p = type_info->size; 179 break; 180 } 181 case dhcptype_ip_e: { 182 struct in_addr ip; 183 184 if (inet_aton(str, &ip) == 0) { 185 if (err) { 186 snprintf(err->str, sizeof(err->str), "%s not valid ip", 187 str); 188 } 189 return (FALSE); 190 } 191 bcopy(&ip, buf, sizeof(ip)); 192 *len_p = type_info->size; 193 break; 194 } 195 case dhcptype_string_e: { 196 int len = (int)strlen(str); 197 if (*len_p < len) { 198 if (err) { 199 snprintf(err->str, sizeof(err->str), "string too long"); 200 } 201 return (FALSE); 202 } 203 if (len) 204 bcopy(str, buf, len); 205 *len_p = len; 206 break; 207 } 208 case dhcptype_dns_namelist_e: { 209 (void)DNSNameListBufferCreate(&str, 1, buf, len_p); 210 if (*len_p == 0) { 211 strlcpy(err->str, "no DNS names added", sizeof(err->str)); 212 return (FALSE); 213 } 214 break; 215 } 216 default: 217 if (err) { 218 snprintf(err->str, sizeof(err->str), "type %s not yet supported", 219 type_info->name); 220 } 221 return (FALSE); 222 } 223 return (TRUE); 224} 225 226/* 227 * Function: dhcptype_from_strlist 228 * 229 * Purpose: 230 * Convert from a string list to the appropriate internal representation 231 * for the given type. 232 */ 233boolean_t 234dhcptype_from_strlist(const char * * strlist, int strlist_count, 235 int type, void * buf, int * len_p, 236 dhcpo_err_str_t * err) 237{ 238 if (err != NULL) { 239 err->str[0] = '\0'; 240 } 241 242 switch (type) { 243 case dhcptype_dns_namelist_e: { 244 (void)DNSNameListBufferCreate(strlist, strlist_count, buf, len_p); 245 if (*len_p == 0) { 246 strlcpy(err->str, "no DNS names added", sizeof(err->str)); 247 return (FALSE); 248 } 249 break; 250 } 251 default: 252 if (err != NULL) { 253 snprintf(err->str, sizeof(err->str), "type %d not yet supported", 254 type); 255 } 256 return (FALSE); 257 } 258 return (TRUE); 259} 260 261/* 262 * Function: dhcptype_to_str 263 * 264 * Purpose: 265 * Give a string representation to the given type. 266 */ 267boolean_t 268dhcptype_to_str(char * tmp, size_t maxtmplen, 269 const void * opt, int len, int type, 270 dhcpo_err_str_t * err) 271{ 272 switch (type) { 273 case dhcptype_bool_e: 274 snprintf(tmp, maxtmplen, "%d", *((boolean_t *)opt)); 275 break; 276 case dhcptype_uint8_e: 277 snprintf(tmp, maxtmplen, "%d", *((uint8_t *)opt)); 278 break; 279 case dhcptype_uint16_e: 280 snprintf(tmp, maxtmplen, "%d", net_uint16_get(opt)); 281 break; 282 case dhcptype_int32_e: 283 snprintf(tmp, maxtmplen, "%d", net_uint32_get(opt)); 284 break; 285 case dhcptype_uint32_e: 286 snprintf(tmp, maxtmplen, "%u", net_uint32_get(opt)); 287 break; 288 case dhcptype_ip_e: 289 snprintf(tmp, maxtmplen, IP_FORMAT, IP_LIST(opt)); 290 break; 291 case dhcptype_string_e: 292 if (len < maxtmplen) { 293 strncpy(tmp, opt, len); 294 tmp[len] = '\0'; 295 } 296 else { 297 snprintf(err->str, sizeof(err->str), 298 "type dhcptype_string_e: string too long"); 299 return (FALSE); 300 } 301 break; 302 default: 303 if (err) { 304 snprintf(err->str, sizeof(err->str), 305 "type %d: not supported", type); 306 return (FALSE); 307 } 308 } 309 return (TRUE); 310} 311 312void 313dhcptype_print_cfstr_simple(CFMutableStringRef str, dhcptype_t type, 314 const void * opt, int option_len) 315{ 316 const uint8_t * option = opt; 317 318 switch (type) { 319 case dhcptype_bool_e: 320 STRING_APPEND(str, "%s", *option ? "TRUE" : "FALSE"); 321 break; 322 323 case dhcptype_ip_e: 324 STRING_APPEND(str, IP_FORMAT, IP_LIST(opt)); 325 break; 326 327 case dhcptype_string_e: { 328 STRING_APPEND(str, "%.*s", option_len, (char *)option); 329 break; 330 } 331 332 case dhcptype_opaque_e: 333 STRING_APPEND(str, "\n"); 334 print_data_cfstr(str, option, option_len); 335 break; 336 337 case dhcptype_uint8_e: 338 STRING_APPEND(str, "0x%x", *option); 339 break; 340 341 case dhcptype_uint16_e: 342 STRING_APPEND(str, "0x%x", net_uint16_get(option)); 343 break; 344 345 case dhcptype_int32_e: 346 case dhcptype_uint32_e: 347 STRING_APPEND(str, "0x%x", net_uint32_get(option)); 348 break; 349 350 case dhcptype_dns_namelist_e: { 351 int i; 352 const char * * namelist; 353 int namelist_length = 0; 354 355 namelist = DNSNameListCreate(option, option_len, &namelist_length); 356 STRING_APPEND(str, "{"); 357 if (namelist != NULL) { 358 for (i = 0; i < namelist_length; i++) { 359 STRING_APPEND(str, "%s%s", (i == 0) ? "" : ", ", 360 namelist[i]); 361 } 362 free(namelist); 363 } 364 STRING_APPEND(str, "}"); 365 break; 366 } 367 368 case dhcptype_none_e: 369 default: 370 break; 371 } 372 return; 373} 374 375void 376dhcptype_fprint_simple(FILE * f, dhcptype_t type, 377 const void * opt, int option_len) 378{ 379 CFMutableStringRef str; 380 381 str = CFStringCreateMutable(NULL, 0); 382 dhcptype_print_cfstr_simple(str, type, opt, option_len); 383 SCPrint(TRUE, f, CFSTR("%@"), str); 384 CFRelease(str); 385 return; 386} 387 388/* 389 * Function: dhcptype_print_simple 390 * Purpose: 391 * Display (to stdout) an option with a simple type. 392 */ 393void 394dhcptype_print_simple(dhcptype_t type, const void * opt, int option_len) 395{ 396 dhcptype_fprint_simple(stdout, type, opt, option_len); 397 return; 398} 399 400void 401dhcptype_print_cfstr(CFMutableStringRef str, 402 dhcptype_t type, const void * option, int option_len) 403{ 404 const dhcptype_info_t * type_info = dhcptype_info(type); 405 406 if (type_info && type_info->multiple_of != dhcptype_none_e) { 407 int i; 408 int number; 409 const void * offset; 410 int size; 411 const dhcptype_info_t * subtype_info; 412 413 subtype_info = dhcptype_info(type_info->multiple_of); 414 if (subtype_info == NULL) 415 return; 416 size = subtype_info->size; 417 number = option_len / size; 418 STRING_APPEND(str, "{"); 419 for (i = 0, offset = option; i < number; i++) { 420 if (i != 0) 421 STRING_APPEND(str, ", "); 422 dhcptype_print_cfstr_simple(str, type_info->multiple_of, 423 offset, size); 424 offset += size; 425 } 426 STRING_APPEND(str, "}"); 427 } 428 else { 429 dhcptype_print_cfstr_simple(str, type, option, option_len); 430 } 431 return; 432} 433 434void 435dhcptype_fprint(FILE * f, dhcptype_t type, const void * option, int option_len) 436{ 437 CFMutableStringRef str; 438 439 str = CFStringCreateMutable(NULL, 0); 440 dhcptype_print_cfstr(str, type, option, option_len); 441 SCPrint(TRUE, f, CFSTR("%@"), str); 442 CFRelease(str); 443 return; 444} 445 446/* 447 * Function: dhcptype_print 448 * Purpose: 449 * Display (to stdout) an option with the given type. 450 */ 451void 452dhcptype_print(dhcptype_t type, const void * option, int option_len) 453{ 454 dhcptype_fprint(stdout, type, option, option_len); 455 return; 456} 457 458static boolean_t 459dhcptag_print_cfstr(CFMutableStringRef str, const void * vopt) 460{ 461 const dhcptag_info_t * entry; 462 const uint8_t * opt = vopt; 463 uint8_t tag = opt[TAG_OFFSET]; 464 uint8_t option_len = opt[LEN_OFFSET]; 465 const uint8_t * option = opt + OPTION_OFFSET; 466 467 entry = dhcptag_info(tag); 468 if (entry == NULL) 469 return (FALSE); 470 { 471 const dhcptype_info_t * type = dhcptype_info(entry->type); 472 473 if (type == NULL) { 474 STRING_APPEND(str, "unknown type %d\n", entry->type); 475 return (FALSE); 476 } 477 STRING_APPEND(str, "%s (%s): ", entry->name, type->name); 478 if (tag == dhcptag_dhcp_message_type_e) 479 STRING_APPEND(str, "%s ", dhcp_msgtype_names(*option)); 480 dhcptype_print_cfstr(str, entry->type, option, option_len); 481 STRING_APPEND(str, "\n"); 482 } 483 return (TRUE); 484} 485 486boolean_t 487dhcptag_fprint(FILE * f, const void * vopt) 488{ 489 boolean_t printed; 490 CFMutableStringRef str; 491 492 str = CFStringCreateMutable(NULL, 0); 493 printed = dhcptag_print_cfstr(str, vopt); 494 CFRelease(str); 495 return (printed); 496} 497 498/* 499 * Function: dhcptag_print 500 * Purpose: 501 * Display (to stdout) the given option. 502 * Returns: 503 * TRUE it could be displayed, FALSE otherwise. 504 */ 505boolean_t 506dhcptag_print(const void * vopt) 507{ 508 return (dhcptag_fprint(stdout, vopt)); 509} 510 511/* 512 * Function: dhcptag_info 513 * 514 * Purpose: 515 * Return the tag information for the give tag. 516 */ 517const dhcptag_info_t * 518dhcptag_info(dhcptag_t tag) 519{ 520 if (tag >= MAX_TAG) 521 return (NULL); 522 return dhcptag_info_table + tag; 523} 524 525/* 526 * Function: dhcptag_with_name 527 * 528 * Purpose: 529 * Given a name, return a corresponding tag. This comes from 530 * the table, as well as the default name of the option number itself. 531 */ 532 533dhcptag_t 534dhcptag_with_name(const char * name) 535{ 536 dhcptag_t i; 537 unsigned int v; 538 539 for (i = 0; i < MAX_TAG; i++) { 540 if (dhcptag_info_table[i].name) { 541 if (strcmp(dhcptag_info_table[i].name, name) == 0) 542 return (i); 543 } 544 } 545 if (strncmp(name, "option_", 7) == 0) { 546 v = (unsigned int)strtoul(name + 7, NULL, 10); 547 } 548 else { 549 v = (unsigned int)strtoul(name, NULL, 10); 550 } 551 if (v <= MAX_TAG) { 552 return (v); 553 } 554 return (-1); 555} 556 557/* 558 * Function: dhcptag_name 559 * Purpose: 560 * Return the name of the tag. 561 */ 562const char * 563dhcptag_name(int tag) 564{ 565 const dhcptag_info_t * info; 566 567 info = dhcptag_info(tag); 568 if (info == NULL) 569 return (NULL); 570 return (info->name); 571} 572 573/* 574 * Function: dhcptag_from_strlist 575 * 576 * Purpose: 577 * Convert from a string list using the appropriate 578 * type conversion for the tag's type. 579 */ 580boolean_t 581dhcptag_from_strlist(const char * * slist, int num, 582 int tag, void * buf, int * len_p, 583 dhcpo_err_str_t * err) 584{ 585 int i; 586 int n_per_type; 587 const dhcptag_info_t * tag_info; 588 const dhcptype_info_t * type_info; 589 const dhcptype_info_t * base_type_info; 590 591 if (err) 592 err->str[0] = '\0'; 593 tag_info = dhcptag_info(tag); 594 if (tag_info == NULL) { 595 if (err) 596 snprintf(err->str, sizeof(err->str), "tag %d unknown", tag); 597 return (FALSE); 598 } 599 600 type_info = dhcptype_info(tag_info->type); 601 if (type_info == NULL) { 602 if (err) 603 snprintf(err->str, sizeof(err->str), "tag %d type %d unknown", tag, 604 tag_info->type); 605 return (FALSE); 606 } 607 608 if (type_info->string_list == FALSE) { 609 return (dhcptype_from_str(slist[0], tag_info->type, 610 buf, len_p, err)); 611 } 612 if (type_info->multiple_of == dhcptype_none_e) { 613 return (dhcptype_from_strlist(slist, num, tag_info->type, 614 buf, len_p, err)); 615 } 616 base_type_info = dhcptype_info(type_info->multiple_of); 617 if (base_type_info == NULL) { 618 if (err) 619 snprintf(err->str, sizeof(err->str), "tag %d base type %d unknown", tag, 620 type_info->multiple_of); 621 return (FALSE); 622 } 623 624 n_per_type = type_info->size / base_type_info->size; 625 if (num & (n_per_type - 1)) { 626 if (err) 627 snprintf(err->str, sizeof(err->str), "type %s not a multiple of %d", 628 type_info->name, n_per_type); 629 return (FALSE); 630 } 631 632 if ((num * base_type_info->size) > *len_p) /* truncate if necessary */ 633 num = *len_p / base_type_info->size; 634 635 for (i = 0, *len_p = 0; i < num; i++) { 636 int l; 637 638 l = base_type_info->size; 639 if (dhcptype_from_str(slist[i], type_info->multiple_of, buf, &l, 640 err) == FALSE) 641 return (FALSE); 642 buf += l; 643 *len_p += l; 644 } 645 return (TRUE); 646} 647 648/* 649 * Function: dhcptag_to_str 650 * 651 * Purpose: 652 * Give a string representation to the given tag. 653 * Note: 654 * For tags whose type is a multiple of a type, this routine 655 * only returns the string representation for the first 656 * occurrence. 657 */ 658boolean_t 659dhcptag_to_str(char * tmp, size_t tmplen, int tag, const void * opt, 660 int len, dhcpo_err_str_t * err) 661{ 662 const dhcptag_info_t * tag_info; 663 const dhcptype_info_t * type_info; 664 dhcptype_t type; 665 666 tag_info = dhcptag_info(tag); 667 if (tag_info == NULL) 668 return (FALSE); 669 type_info = dhcptype_info(tag_info->type); 670 if (type_info->multiple_of == dhcptype_none_e) 671 type = tag_info->type; 672 else 673 type = type_info->multiple_of; 674 return (dhcptype_to_str(tmp, tmplen, opt, len, type, err)); 675} 676 677/* 678 * Functions: dhcpol_* 679 * 680 * Purpose: 681 * Routines to parse/access existing options buffers. 682 */ 683boolean_t 684dhcpol_add(dhcpol_t * list, void * element) 685{ 686 return (ptrlist_add((ptrlist_t *)list, element)); 687} 688 689int 690dhcpol_count(dhcpol_t * list) 691{ 692 return (ptrlist_count((ptrlist_t *)list)); 693} 694 695void * 696dhcpol_element(dhcpol_t * list, int i) 697{ 698 return (ptrlist_element((ptrlist_t *)list, i)); 699} 700 701void 702dhcpol_init(dhcpol_t * list) 703{ 704 ptrlist_init((ptrlist_t *)list); 705} 706 707void 708dhcpol_free(dhcpol_t * list) 709{ 710 ptrlist_free((ptrlist_t *)list); 711} 712 713boolean_t 714dhcpol_concat(dhcpol_t * list, dhcpol_t * extra) 715{ 716 return (ptrlist_concat((ptrlist_t *)list, (ptrlist_t *)extra)); 717} 718 719/* 720 * Function: dhcpol_parse_buffer 721 * 722 * Purpose: 723 * Parse the given buffer into DHCP options, returning the 724 * list of option pointers in the given dhcpol_t. 725 * Parsing continues until we hit the end of the buffer or 726 * the end tag. 727 */ 728boolean_t 729dhcpol_parse_buffer(dhcpol_t * list, void * buffer, int length, 730 dhcpo_err_str_t * err) 731{ 732 int len; 733 uint8_t * scan; 734 uint8_t tag; 735 736 if (err) 737 err->str[0] = '\0'; 738 739 dhcpol_init(list); 740 741 len = length; 742 tag = dhcptag_pad_e; 743 for (scan = (uint8_t *)buffer; tag != dhcptag_end_e && len > 0; ) { 744 745 tag = scan[TAG_OFFSET]; 746 747 switch (tag) { 748 case dhcptag_end_e: 749 dhcpol_add(list, scan); /* remember that it was terminated */ 750 scan++; 751 len--; 752 break; 753 case dhcptag_pad_e: /* ignore pad */ 754 scan++; 755 len--; 756 break; 757 default: { 758 uint8_t option_len = scan[LEN_OFFSET]; 759 760 dhcpol_add(list, scan); 761 len -= (option_len + 2); 762 scan += (option_len + 2); 763 break; 764 } 765 } 766 } 767 if (len < 0) { 768 /* ran off the end */ 769 if (err) 770 snprintf(err->str, sizeof(err->str), "parse failed near tag %d", tag); 771 dhcpol_free(list); 772 return (FALSE); 773 } 774 return (TRUE); 775} 776 777/* 778 * Function: dhcpol_find 779 * 780 * Purpose: 781 * Finds the first occurence of the given option, and returns its 782 * length and the option data pointer. 783 * 784 * The optional start parameter allows this function to 785 * return the next start point so that successive 786 * calls will retrieve the next occurence of the option. 787 * Before the first call, *start should be set to 0. 788 */ 789void * 790dhcpol_find(dhcpol_t * list, int tag, int * len_p, int * start) 791{ 792 int i = 0; 793 794 if (tag == dhcptag_end_e || tag == dhcptag_pad_e) 795 return (NULL); 796 797 if (start) 798 i = *start; 799 800 for (; i < dhcpol_count(list); i++) { 801 uint8_t * option = dhcpol_element(list, i); 802 803 if (option[TAG_OFFSET] == tag) { 804 if (len_p) 805 *len_p = option[LEN_OFFSET]; 806 if (start) 807 *start = i + 1; 808 return (option + OPTION_OFFSET); 809 } 810 } 811 return (NULL); 812} 813 814/* 815 * Function: dhcpol_find_with_length 816 * Purpose: 817 * Find a DHCP option with the specified tag that is at least as long 818 * as the passed in min_length value. Return NULL if such an option 819 * does not exist. 820 */ 821void * 822dhcpol_find_with_length(dhcpol_t * options, dhcptag_t tag, int min_length) 823{ 824 int real_length; 825 void * val; 826 827 val = dhcpol_find(options, tag, &real_length, NULL); 828 if (val == NULL) { 829 return (NULL); 830 } 831 if (real_length < min_length) { 832 return (NULL); 833 } 834 return (val); 835} 836 837/* 838 * Function: dhcpol_option_copy 839 * 840 * Purpose: 841 * Accumulate all occurences of the given option into a 842 * malloc'd buffer, and return its length. Used to get 843 * all occurrences of a particular option in a single 844 * data area. 845 * Note: 846 * Use free() to free the returned data area. 847 */ 848void * 849dhcpol_option_copy(dhcpol_t * list, int tag, int * len_p) 850{ 851 int i; 852 void * data = NULL; 853 int data_len = 0; 854 855 if (tag == dhcptag_end_e || tag == dhcptag_pad_e) 856 return (NULL); 857 858 for (i = 0; i < dhcpol_count(list); i++) { 859 uint8_t * option = dhcpol_element(list, i); 860 861 if (option[TAG_OFFSET] == tag) { 862 int len = option[LEN_OFFSET]; 863 864 if (data == NULL) { 865 data = malloc(len); 866 } 867 else { 868 data = reallocf(data, data_len + len); 869 } 870 bcopy(option + OPTION_OFFSET, data + data_len, len); 871 data_len += len; 872 } 873 } 874 *len_p = data_len; 875 return (data); 876} 877 878/* 879 * Function: dhcpol_parse_packet 880 * 881 * Purpose: 882 * Parse the option areas in the DHCP packet. 883 * Verifies that the packet has the right magic number, 884 * then parses and accumulates the option areas. 885 * First the pkt->dp_options is parsed. If that contains 886 * the overload option, it parses pkt->dp_file if specified, 887 * then parses pkt->dp_sname if specified. 888 */ 889boolean_t 890dhcpol_parse_packet(dhcpol_t * options, struct dhcp * pkt, int len, 891 dhcpo_err_str_t * err) 892{ 893 dhcpol_init(options); /* make sure it's empty */ 894 895 if (err) 896 err->str[0] = '\0'; 897 898 if (len < (sizeof(*pkt) + RFC_MAGIC_SIZE)) { 899 if (err) { 900 snprintf(err->str, sizeof(err->str), "packet is too short: %d < %d", 901 len, (int)sizeof(*pkt) + RFC_MAGIC_SIZE); 902 } 903 return (FALSE); 904 } 905 if (bcmp(pkt->dp_options, rfc_magic, RFC_MAGIC_SIZE)) { 906 if (err) 907 snprintf(err->str, sizeof(err->str), "missing magic number"); 908 return (FALSE); 909 } 910 if (dhcpol_parse_buffer(options, pkt->dp_options + RFC_MAGIC_SIZE, 911 len - sizeof(*pkt) - RFC_MAGIC_SIZE, err) == FALSE) 912 return (FALSE); 913 { /* get overloaded options */ 914 uint8_t * overload; 915 int overload_len; 916 917 overload = (uint8_t *)dhcpol_find(options, dhcptag_option_overload_e, 918 &overload_len, NULL); 919 if (overload && overload_len == 1) { /* has overloaded options */ 920 dhcpol_t extra; 921 922 dhcpol_init(&extra); 923 if (*overload == DHCP_OVERLOAD_FILE 924 || *overload == DHCP_OVERLOAD_BOTH) { 925 if (dhcpol_parse_buffer(&extra, pkt->dp_file, 926 sizeof(pkt->dp_file), NULL)) { 927 dhcpol_concat(options, &extra); 928 dhcpol_free(&extra); 929 } 930 } 931 if (*overload == DHCP_OVERLOAD_SNAME 932 || *overload == DHCP_OVERLOAD_BOTH) { 933 if (dhcpol_parse_buffer(&extra, pkt->dp_sname, 934 sizeof(pkt->dp_sname), NULL)) { 935 dhcpol_concat(options, &extra); 936 dhcpol_free(&extra); 937 } 938 } 939 } 940 } 941 return (TRUE); 942} 943 944/* 945 * Function: dhcpol_parse_vendor 946 * 947 * Purpose: 948 * Given a set of options, find the vendor specific option(s) 949 * and parse all of them into a single option list. 950 * 951 * Return value: 952 * TRUE if vendor specific options existed and were parsed succesfully, 953 * FALSE otherwise. 954 */ 955boolean_t 956dhcpol_parse_vendor(dhcpol_t * vendor, dhcpol_t * options, 957 dhcpo_err_str_t * err) 958{ 959 dhcpol_t extra; 960 boolean_t ret = FALSE; 961 int start = 0; 962 963 if (err) 964 err->str[0] = '\0'; 965 966 dhcpol_init(vendor); 967 dhcpol_init(&extra); 968 969 for (;;) { 970 void * data; 971 int len; 972 973 data = dhcpol_find(options, dhcptag_vendor_specific_e, &len, &start); 974 if (data == NULL) { 975 break; /* out of for */ 976 } 977 978 if (dhcpol_parse_buffer(&extra, data, len, err) == FALSE) { 979 goto failed; 980 } 981 982 if (dhcpol_concat(vendor, &extra) == FALSE) { 983 if (err) 984 snprintf(err->str, sizeof(err->str), 985 "dhcpol_concat() failed at %d\n", start); 986 goto failed; 987 } 988 dhcpol_free(&extra); 989 ret = TRUE; 990 } 991 if (ret == FALSE) { 992 if (err) 993 strlcpy(err->str, "missing vendor specific options", 994 sizeof(err->str)); 995 } 996 return (ret); 997 998 failed: 999 dhcpol_free(vendor); 1000 dhcpol_free(&extra); 1001 return (FALSE); 1002} 1003 1004void 1005dhcpol_print_cfstr(CFMutableStringRef str, dhcpol_t * list) 1006{ 1007 int i; 1008 1009 STRING_APPEND(str, "Options count is %d\n", dhcpol_count(list)); 1010 for (i = 0; i < dhcpol_count(list); i++) { 1011 uint8_t * option = dhcpol_element(list, i); 1012 1013 if (dhcptag_print_cfstr(str, option) == FALSE) { 1014 STRING_APPEND(str, "undefined tag %d len %d\n", option[TAG_OFFSET], 1015 option[LEN_OFFSET]); 1016 } 1017 } 1018 return; 1019} 1020 1021void 1022dhcpol_fprint(FILE * f, dhcpol_t * list) 1023{ 1024 CFMutableStringRef str; 1025 1026 str = CFStringCreateMutable(NULL, 0); 1027 dhcpol_print_cfstr(str, list); 1028 SCPrint(TRUE, f, CFSTR("%@"), str); 1029 CFRelease(str); 1030 return; 1031} 1032 1033void 1034dhcpol_print(dhcpol_t * list) 1035{ 1036 dhcpol_fprint(stdout, list); 1037 return; 1038} 1039 1040 1041int 1042dhcpol_count_params(dhcpol_t * options, const uint8_t * tags, int size) 1043{ 1044 int i; 1045 int param_count = 0; 1046 1047 for (i = 0; i < size; i++) { 1048 if (dhcpol_find(options, tags[i], NULL, NULL) != NULL) 1049 param_count++; 1050 } 1051 return (param_count); 1052} 1053 1054 1055/* 1056 * Module: dhcpoa 1057 * 1058 * Purpose: 1059 * Types and functions to create new dhcp option areas. 1060 */ 1061 1062/* 1063 * Function: dhcpoa_{init_common, init_no_end, init} 1064 * 1065 * Purpose: 1066 * Initialize an option area structure so that it can be used 1067 * in calling the dhcpoa_* routines. 1068 */ 1069 1070static void 1071dhcpoa_init_common(dhcpoa_t * oa_p, void * buffer, int size, int reserve) 1072{ 1073 bzero(buffer, size); /* fill option area with pad tags */ 1074 1075 bzero(oa_p, sizeof(*oa_p)); 1076 oa_p->oa_magic = DHCPOA_MAGIC; 1077 oa_p->oa_buffer = buffer; 1078 oa_p->oa_size = size; 1079 oa_p->oa_reserve = reserve; 1080} 1081 1082void 1083dhcpoa_init_no_end(dhcpoa_t * oa_p, void * buffer, int size) 1084{ 1085 dhcpoa_init_common(oa_p, buffer, size, 0); 1086 return; 1087} 1088 1089int 1090dhcpoa_size(dhcpoa_t * oa_p) 1091{ 1092 return (oa_p->oa_size); 1093} 1094 1095void 1096dhcpoa_init(dhcpoa_t * oa_p, void * buffer, int size) 1097{ 1098 /* initialize the area, reserve space for the end tag */ 1099 dhcpoa_init_common(oa_p, buffer, size, 1); 1100 return; 1101} 1102 1103dhcpoa_ret_t 1104dhcpoa_vendor_add(dhcpoa_t * oa_p, dhcpoa_t * vendor_oa_p, 1105 dhcptag_t tag, int len, void * option) 1106{ 1107 int freespace; 1108 dhcpoa_ret_t ret = dhcpoa_success_e; 1109 1110 oa_p->oa_err.str[0] = '\0'; 1111 1112 if (len > (DHCP_OPTION_SIZE_MAX - OPTION_OFFSET)) { 1113 snprintf(vendor_oa_p->oa_err.str, sizeof(vendor_oa_p->oa_err.str), 1114 "tag %d option %d > %d", tag, len, 1115 DHCP_OPTION_SIZE_MAX - OPTION_OFFSET); 1116 return (dhcpoa_failed_e); 1117 } 1118 freespace = dhcpoa_freespace(vendor_oa_p) - OPTION_OFFSET; 1119 if (freespace < len) { 1120 /* add the vendor-specific options to the packet to make room */ 1121 ret = dhcpoa_add(oa_p, dhcptag_vendor_specific_e, 1122 dhcpoa_used(vendor_oa_p), 1123 dhcpoa_buffer(vendor_oa_p)); 1124 if (ret != dhcpoa_success_e) { 1125 snprintf(vendor_oa_p->oa_err.str, sizeof(vendor_oa_p->oa_err.str), 1126 "tag %d option %d > %d", tag, len, freespace); 1127 goto failed; 1128 } 1129 freespace = dhcpoa_freespace(oa_p) - OPTION_OFFSET; 1130 if (freespace > dhcpoa_size(vendor_oa_p)) { 1131 freespace = dhcpoa_size(vendor_oa_p); 1132 } 1133 dhcpoa_init_no_end(vendor_oa_p, dhcpoa_buffer(vendor_oa_p), 1134 freespace); 1135 } 1136 ret = dhcpoa_add(vendor_oa_p, tag, len, option); 1137 1138 failed: 1139 return (ret); 1140} 1141 1142 1143/* 1144 * Function: dhcpoa_add 1145 * 1146 * Purpose: 1147 * Add an option to the option area. 1148 */ 1149dhcpoa_ret_t 1150dhcpoa_add(dhcpoa_t * oa_p, dhcptag_t tag, int len, const void * option) 1151{ 1152 1153 oa_p->oa_err.str[0] = '\0'; 1154 1155 if (len > DHCP_OPTION_SIZE_MAX) { 1156 snprintf(oa_p->oa_err.str, sizeof(oa_p->oa_err.str), 1157 "tag %d option %d > %d", tag, len, DHCP_OPTION_SIZE_MAX); 1158 return (dhcpoa_failed_e); 1159 } 1160 1161 if (oa_p->oa_magic != DHCPOA_MAGIC) { 1162 strlcpy(oa_p->oa_err.str, "dhcpoa_t not initialized - internal error!!!", 1163 sizeof(oa_p->oa_err.str)); 1164 return (dhcpoa_failed_e); 1165 } 1166 1167 if (oa_p->oa_end_tag) { 1168 strlcpy(oa_p->oa_err.str, "attempt to add data after end tag", 1169 sizeof(oa_p->oa_err.str)); 1170 return (dhcpoa_failed_e); 1171 } 1172 1173 switch (tag) { 1174 case dhcptag_end_e: 1175 if ((oa_p->oa_offset + 1) > oa_p->oa_size) { 1176 /* this can't happen since we're careful to leave space */ 1177 snprintf(oa_p->oa_err.str, sizeof(oa_p->oa_err.str), 1178 "can't add end tag %d > %d", 1179 oa_p->oa_offset + oa_p->oa_reserve, oa_p->oa_size); 1180 return (dhcpoa_failed_e); 1181 } 1182 ((uint8_t *)oa_p->oa_buffer)[oa_p->oa_offset + TAG_OFFSET] = tag; 1183 oa_p->oa_offset++; 1184 oa_p->oa_end_tag = TRUE; 1185 break; 1186 1187 case dhcptag_pad_e: 1188 /* 1 for pad tag */ 1189 if ((oa_p->oa_offset + oa_p->oa_reserve + 1) > oa_p->oa_size) { 1190 snprintf(oa_p->oa_err.str, sizeof(oa_p->oa_err.str), 1191 "can't add pad tag %d > %d", 1192 oa_p->oa_offset + oa_p->oa_reserve + 1, oa_p->oa_size); 1193 return (dhcpoa_full_e); 1194 } 1195 ((u_char *)oa_p->oa_buffer)[oa_p->oa_offset + TAG_OFFSET] = tag; 1196 oa_p->oa_offset++; 1197 break; 1198 1199 default: 1200 /* 2 for tag/len */ 1201 if ((oa_p->oa_offset + len + 2 + oa_p->oa_reserve) > oa_p->oa_size) { 1202 snprintf(oa_p->oa_err.str, sizeof(oa_p->oa_err.str), 1203 "can't add tag %d (%d > %d)", tag, 1204 oa_p->oa_offset + len + 2 + oa_p->oa_reserve, 1205 oa_p->oa_size); 1206 return (dhcpoa_full_e); 1207 } 1208 ((uint8_t *)oa_p->oa_buffer)[oa_p->oa_offset + TAG_OFFSET] = tag; 1209 ((uint8_t *)oa_p->oa_buffer)[oa_p->oa_offset + LEN_OFFSET] = len; 1210 if (len) { 1211 bcopy(option, (u_char *)oa_p->oa_buffer 1212 + (OPTION_OFFSET + oa_p->oa_offset), len); 1213 } 1214 oa_p->oa_prev_last = oa_p->oa_last; 1215 oa_p->oa_last = oa_p->oa_offset; 1216 oa_p->oa_offset += len + OPTION_OFFSET; 1217 break; 1218 } 1219 oa_p->oa_option_count++; 1220 return (dhcpoa_success_e); 1221} 1222 1223/* 1224 * Function: dhcpoa_add_from_strlist 1225 * 1226 * Purpose: 1227 * Convert the string list into an option with the specified tag. 1228 * Note: 1229 * This only works for type representations that we know about. 1230 */ 1231dhcpoa_ret_t 1232dhcpoa_add_from_strlist(dhcpoa_t * oa_p, dhcptag_t tag, 1233 const char * * strlist, int strlist_len) 1234{ 1235 int len; 1236 char tmp[DHCP_OPTION_SIZE_MAX]; 1237 1238 len = sizeof(tmp); 1239 1240 if (dhcptag_from_strlist(strlist, strlist_len, tag, tmp, &len, 1241 &oa_p->oa_err) == FALSE) { 1242 return (dhcpoa_failed_e); 1243 } 1244 return (dhcpoa_add(oa_p, tag, len, tmp)); 1245} 1246 1247/* 1248 * Function: dhcpoa_add_from_str 1249 * 1250 * Purpose: 1251 * Convert the string into an option with the specified tag. 1252 */ 1253dhcpoa_ret_t 1254dhcpoa_add_from_str(dhcpoa_t * oa_p, dhcptag_t tag, 1255 const char * str) 1256{ 1257 return (dhcpoa_add_from_strlist(oa_p, tag, &str, 1)); 1258} 1259 1260/* 1261 * Function: dhcpoa_add_dhcpmsg 1262 * 1263 * Purpose: 1264 * Add a dhcp message option to the option area. 1265 */ 1266dhcpoa_ret_t 1267dhcpoa_add_dhcpmsg(dhcpoa_t * oa_p, dhcp_msgtype_t msgtype) 1268{ 1269 char m = (char)msgtype; 1270 return (dhcpoa_add(oa_p, dhcptag_dhcp_message_type_e, 1271 sizeof(m), &m)); 1272} 1273 1274/* 1275 * Function: dhcpoa_err 1276 * 1277 * Purpose: 1278 * Return an error message for the last error that occcurred. 1279 */ 1280char * 1281dhcpoa_err(dhcpoa_t * oa_p) 1282{ 1283 if (oa_p == NULL || oa_p->oa_magic != DHCPOA_MAGIC) 1284 return ("<bad parameter>"); 1285 return (oa_p->oa_err.str); 1286} 1287 1288 1289int 1290dhcpoa_used(dhcpoa_t * oa_p) 1291{ 1292 if (oa_p == NULL || oa_p->oa_magic != DHCPOA_MAGIC) 1293 return 0; 1294 return (oa_p->oa_offset); 1295} 1296 1297int 1298dhcpoa_freespace(dhcpoa_t * oa_p) 1299{ 1300 int freespace; 1301 1302 if (oa_p == NULL || oa_p->oa_magic != DHCPOA_MAGIC) { 1303 return 0; 1304 } 1305 freespace = oa_p->oa_size - oa_p->oa_offset - oa_p->oa_reserve; 1306 if (freespace < 0) { 1307 freespace = 0; 1308 } 1309 return (freespace); 1310} 1311 1312int 1313dhcpoa_count(dhcpoa_t * oa_p) 1314{ 1315 if (oa_p == NULL || oa_p->oa_magic != DHCPOA_MAGIC) 1316 return 0; 1317 return (oa_p->oa_option_count); 1318} 1319 1320void * 1321dhcpoa_buffer(dhcpoa_t * oa_p) 1322{ 1323 if (oa_p == NULL || oa_p->oa_magic != DHCPOA_MAGIC) 1324 return (NULL); 1325 return (oa_p->oa_buffer); 1326} 1327 1328#ifdef TEST_DHCP_OPTIONS 1329char test_empty[] = { 1330 99, 130, 83, 99, 1331 255, 1332}; 1333 1334char test_simple[] = { 1335 99, 130, 83, 99, 1336 1, 4, 255, 255, 252, 0, 1337 3, 4, 17, 202, 40, 1, 1338 255, 1339}; 1340 1341char test_vendor[] = { 1342 99, 130, 83, 99, 1343 1, 4, 255, 255, 252, 0, 1344 3, 4, 17, 202, 40, 1, 1345 43, 6, 1, 4, 1, 2, 3, 4, 1346 43, 6, 1, 4, 1, 2, 3, 4, 1347 255, 1348}; 1349char test_overload_sname[] = { 1350 99, 130, 83, 99, 1351 dhcptag_option_overload_e, 1, DHCP_OVERLOAD_SNAME, 1352 255, 1353}; 1354char test_overload_file[] = { 1355 99, 130, 83, 99, 1356 dhcptag_option_overload_e, 1, DHCP_OVERLOAD_FILE, 1357 255, 1358}; 1359char test_overload_both[] = { 1360 99, 130, 83, 99, 1361 dhcptag_option_overload_e, 1, DHCP_OVERLOAD_BOTH, 1362 255, 1363}; 1364 1365char test_no_end[] = { 1366 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x05, 0x36, 1367 0x04, 0xc0, 0xa8, 0x01, 0x01, 0x33, 0x04, 0x80, 1368 0x00, 0x80, 0x00, 0x01, 0x04, 0xff, 0xff, 0xff, 1369 0x00, 0x03, 0x04, 0xc0, 0xa8, 0x01, 0x01, 0x06, 1370 0x0c, 0x18, 0x1a, 0xa3, 0x21, 0x18, 0x1a, 0xa3, 1371 0x20, 0x18, 0x5e, 0xa3, 0x21, 0x00, 0x00, 0x00, 1372 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1373 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 1374}; 1375 1376char test_too_short[] = { 1377 0x1 1378}; 1379struct test { 1380 char * name; 1381 char * data; 1382 int len; 1383 boolean_t result; 1384}; 1385 1386struct test tests[] = { 1387 { "empty", test_empty, sizeof(test_empty), TRUE }, 1388 { "simple", test_simple, sizeof(test_simple), TRUE }, 1389 { "vendor", test_vendor, sizeof(test_vendor), TRUE }, 1390 { "no_end", test_no_end, sizeof(test_no_end), TRUE }, 1391 { "too_short", test_too_short, sizeof(test_too_short), FALSE }, 1392 { NULL, NULL, 0, FALSE }, 1393}; 1394 1395struct test overload_tests[] = { 1396 { "overload sname", test_overload_sname, sizeof(test_overload_sname),TRUE }, 1397 { "overload file", test_overload_file, sizeof(test_overload_file), TRUE }, 1398 { "overload both", test_overload_both, sizeof(test_overload_both), TRUE }, 1399 { NULL, NULL, 0, FALSE }, 1400}; 1401 1402char test_string_253[253] = "test string 253 characters long (zero padded)"; 1403 1404static char buf[2048]; 1405static char vend_buf[255]; 1406 1407int 1408main() 1409{ 1410 int i; 1411 dhcpo_err_str_t error; 1412 dhcpol_t options; 1413 struct dhcp * pkt = (struct dhcp *)buf; 1414 dhcpol_t vendor_options; 1415 1416 dhcpol_init(&options); 1417 dhcpol_init(&vendor_options); 1418 1419 for (i = 0; tests[i].name; i++) { 1420 printf("\nTest %d: %s: ", i, tests[i].name); 1421 bcopy(tests[i].data, pkt->dp_options, tests[i].len); 1422 if (dhcpol_parse_packet(&options, pkt, 1423 sizeof(*pkt) + tests[i].len, 1424 &error) != tests[i].result) { 1425 printf("FAILED\n"); 1426 if (tests[i].result == TRUE) { 1427 printf("error message returned was %s\n", error.str); 1428 } 1429 } 1430 else { 1431 printf("PASSED\n"); 1432 if (tests[i].result == FALSE) { 1433 printf("error message returned was %s\n", error.str); 1434 } 1435 } 1436 dhcpol_print(&options); 1437 dhcpol_free(&options); 1438 } 1439 bcopy(test_simple + RFC_MAGIC_SIZE, pkt->dp_sname, 1440 sizeof(test_simple) - RFC_MAGIC_SIZE); 1441 bcopy(test_no_end + RFC_MAGIC_SIZE, pkt->dp_file, 1442 sizeof(test_no_end) - RFC_MAGIC_SIZE); 1443 for (i = 0; overload_tests[i].name; i++) { 1444 bcopy(overload_tests[i].data, pkt->dp_options, 1445 overload_tests[i].len); 1446 printf("\nOption overload test %d: %s: ", i, overload_tests[i].name); 1447 if (dhcpol_parse_packet(&options, pkt, 1448 sizeof(*pkt) + overload_tests[i].len, 1449 &error) != tests[i].result) { 1450 printf("FAILED\n"); 1451 if (overload_tests[i].result == TRUE) { 1452 printf("error message returned was %s\n", error.str); 1453 } 1454 } 1455 else { 1456 printf("PASSED\n"); 1457 if (overload_tests[i].result == FALSE) { 1458 printf("error message returned was %s\n", error.str); 1459 } 1460 } 1461 dhcpol_print(&options); 1462 dhcpol_free(&options); 1463 } 1464 1465 printf("\nTesting dhcpoa\n"); 1466 { 1467 struct in_addr iaddr; 1468 dhcpoa_t opts; 1469 dhcpoa_t vend_opts; 1470 dhcpo_err_str_t err; 1471 char * str; 1472 1473 dhcpoa_init(&opts, buf, sizeof(buf)); 1474 dhcpoa_init_no_end(&vend_opts, vend_buf, sizeof(vend_buf)); 1475 1476 iaddr.s_addr = inet_addr("255.255.252.0"); 1477 if (dhcpoa_add(&opts, dhcptag_subnet_mask_e, sizeof(iaddr), 1478 &iaddr) == dhcpoa_failed_e) { 1479 printf("couldn't add subnet mask, %s\n", dhcpoa_err(&opts)); 1480 exit(1); 1481 } 1482 str = "17.202.40.1"; 1483 if (dhcpoa_add_from_str(&opts, dhcptag_router_e, str) 1484 != dhcpoa_success_e) { 1485 printf("couldn't add router, %s\n", dhcpoa_err(&opts)); 1486 exit(1); 1487 } 1488 if (dhcpoa_add_from_str(&opts, dhcptag_host_name_e, "siegdi5") 1489 != dhcpoa_success_e) { 1490 printf("couldn't add hostname tag, %s\n", dhcpoa_err(&opts)); 1491 exit(1); 1492 } 1493 if (dhcpoa_add_from_str(&opts, dhcptag_domain_name_e, "apple.com") 1494 != dhcpoa_success_e) { 1495 printf("couldn't add domain name tag, %s\n", dhcpoa_err(&opts)); 1496 exit(1); 1497 } 1498 { 1499 const char * domain_names[] = { 1500 "euro.apple.com", 1501 "eng.apple.com", 1502 "foo.bar", 1503 "thisisprettylongdontyouthink.foo.bar", 1504 "thisisprettylongdontyouthink.foo.bar.apple.com", 1505 "thisisprettylongdontyouthink.foo.bar.com", 1506 "a.foo.bar" 1507 }; 1508 uint8_t search_buf[DHCP_OPTION_SIZE_MAX]; 1509 int len = sizeof(search_buf); 1510 1511 if (dhcptag_from_strlist(domain_names, 7, 1512 dhcptag_domain_search_e, search_buf, 1513 &len, &err) == FALSE) { 1514 printf("couldn't get domain search option: %s", err.str); 1515 } 1516 else if (dhcpoa_add(&opts, dhcptag_domain_search_e, 1517 len, search_buf) != dhcpoa_success_e) { 1518 printf("couldn't add domain search tag, %s\n", 1519 dhcpoa_err(&opts)); 1520 exit(1); 1521 } 1522 } 1523 for (i = 0; i < 253; i++) { 1524 if (dhcpoa_vendor_add(&opts, &vend_opts, i+1, i, 1525 test_string_253) != dhcpoa_success_e) { 1526 printf("couldn't add vendor option, %s\n", 1527 dhcpoa_err(&vend_opts)); 1528 break; 1529 } 1530 } 1531 if (dhcpoa_used(&vend_opts) > 0) { 1532 if (dhcpoa_add(&opts, dhcptag_vendor_specific_e, 1533 dhcpoa_used(&vend_opts), dhcpoa_buffer(&vend_opts)) 1534 != dhcpoa_success_e) { 1535 printf("couldn't add vendor options, %s\n", dhcpoa_err(&opts)); 1536 exit(1); 1537 } 1538 } 1539 if (dhcpoa_add(&opts, dhcptag_end_e, 0, 0) != dhcpoa_success_e) { 1540 printf("couldn't add end tag, %s\n", dhcpoa_err(&opts)); 1541 exit(1); 1542 } 1543 if (dhcpol_parse_buffer(&options, buf, sizeof(buf), &err) == FALSE) { 1544 printf("parse buffer failed, %s\n", err.str); 1545 exit(1); 1546 } 1547 dhcpol_print(&options); 1548 { 1549 struct in_addr * iaddr; 1550 iaddr = (struct in_addr *) 1551 dhcpol_find(&options, dhcptag_router_e, 0, 0); 1552 if (iaddr == NULL) { 1553 printf("can't find router option\n"); 1554 } 1555 else { 1556 printf("Found router option %s\n", inet_ntoa(*iaddr)); 1557 } 1558 } 1559 if (dhcpol_parse_vendor(&vendor_options, &options, NULL)) { 1560 printf("vendor parsed ok\n"); 1561 } 1562 else { 1563 printf("parse vendor failed\n"); 1564 } 1565 dhcpol_free(&options); 1566 dhcpol_free(&vendor_options); 1567 } 1568 exit(0); 1569} 1570#endif /* TEST_DHCP_OPTIONS */ 1571