1/* 2 * Copyright (c) 1999-2014 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 * client.c 25 * - client side program to talk to ipconfigd 26 */ 27/* 28 * Modification History 29 * 30 * September, 1999 Dieter Siegmund (dieter@apple.com) 31 * - initial revision 32 * July 31, 2000 Dieter Siegmund (dieter@apple.com) 33 * - changed to add set, and new implementation of waitall 34 * - removed waitif 35 * February 24, 2003 Dieter Siegmund (dieter@apple.com) 36 * - added support to retrieve information about the netboot (bsdp) 37 * packet stored in the device tree 38 * September 10, 2009 Dieter Siegmund (dieter@apple.com) 39 * - added IPv6 support 40 */ 41#include <stdio.h> 42#include <unistd.h> 43#include <stdlib.h> 44#include <mach/mach.h> 45#include <mach/mach_error.h> 46#include <servers/bootstrap.h> 47#include <ctype.h> 48#include <string.h> 49#include <sysexits.h> 50 51#include <netinet/in.h> 52#include <netinet/udp.h> 53#include <netinet/in_systm.h> 54#include <netinet/ip.h> 55#include <netinet/bootp.h> 56#include <arpa/inet.h> 57#include <SystemConfiguration/SystemConfiguration.h> 58#include <SystemConfiguration/SCValidation.h> 59 60#include "ipconfig_ext.h" 61#include "ipconfig_types.h" 62#include "dhcp_options.h" 63#include "dhcplib.h" 64#include "bsdp.h" 65#include "bsdplib.h" 66#include "ioregpath.h" 67#include "ipconfig.h" 68#include "cfutil.h" 69#include "DHCPv6.h" 70#include "DHCPv6Options.h" 71#include "IPConfigurationControlPrefs.h" 72 73#define METHOD_LIST_V4 "BOOTP, MANUAL, DHCP, INFORM" 74#define METHOD_LIST_V4_WITH_NONE METHOD_LIST_V4 ", NONE" 75#define METHOD_LIST_V6 "AUTOMATIC-V6, MANUAL-V6, 6TO4" 76#define METHOD_LIST_V6_WITH_NONE METHOD_LIST_V6 ", NONE-V6" 77#define METHOD_LIST METHOD_LIST_V4 ", " METHOD_LIST_V6 78#define METHOD_LIST_WITH_NONE METHOD_LIST_V4_WITH_NONE ", " METHOD_LIST_V6_WITH_NONE 79 80typedef int func_t(mach_port_t server, int argc, char * argv[]); 81typedef func_t * funcptr_t; 82 83static char * progname; 84static char * command_name; 85 86#define STARTUP_KEY CFSTR("Plugin:IPConfiguration") 87 88#define SHADOW_MOUNT_PATH_COMMAND "shadow_mount_path" 89#define SHADOW_FILE_PATH_COMMAND "shadow_file_path" 90#define MACHINE_NAME_COMMAND "machine_name" 91 92static void 93on_alarm(int sigraised) 94{ 95 exit(0); 96} 97 98#define WAIT_ALL_DEFAULT_TIMEOUT 90 99#define WAIT_ALL_MAX_TIMEOUT 120 100 101static void 102key_appeared(SCDynamicStoreRef session, CFArrayRef changes, void * arg) 103{ 104 exit(0); 105} 106 107static int 108S_wait_all(mach_port_t server, int argc, char * argv[]) 109{ 110 CFMutableArrayRef keys; 111 SCDynamicStoreRef session; 112 CFRunLoopSourceRef rls; 113 unsigned long t = WAIT_ALL_DEFAULT_TIMEOUT; 114 CFPropertyListRef value; 115 struct itimerval v; 116 117 if (argc > 0) { 118 t = strtoul(argv[0], 0, 0); 119 if (t > WAIT_ALL_MAX_TIMEOUT) { 120 t = WAIT_ALL_MAX_TIMEOUT; 121 } 122 } 123 124 session = SCDynamicStoreCreate(NULL, CFSTR("ipconfig command"), 125 key_appeared, NULL); 126 if (session == NULL) { 127 fprintf(stderr, "SCDynamicStoreCreate failed: %s\n", 128 SCErrorString(SCError())); 129 return (0); 130 } 131 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 132 CFArrayAppendValue(keys, STARTUP_KEY); 133 SCDynamicStoreSetNotificationKeys(session, keys, NULL); 134 CFRelease(keys); 135 136 rls = SCDynamicStoreCreateRunLoopSource(NULL, session, 0); 137 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); 138 CFRelease(rls); 139 140 signal(SIGALRM, on_alarm); 141 bzero(&v, sizeof(v)); 142 v.it_value.tv_sec = t; 143 if (setitimer(ITIMER_REAL, &v, NULL) < 0) { 144 perror("setitimer"); 145 return (0); 146 } 147 value = SCDynamicStoreCopyValue(session, STARTUP_KEY); 148 if (value == NULL) { 149 CFRunLoopRun(); 150 return (0); 151 } 152 CFRelease(value); 153 CFRelease(session); 154 return (0); 155} 156 157static int 158S_bsdp_get_packet(mach_port_t server, int argc, char * argv[]) 159{ 160 CFDictionaryRef chosen = NULL; 161 struct dhcp * dhcp; 162 int length; 163 CFDataRef response = NULL; 164 int ret = 1; 165 166 if (getuid() != 0) { 167 return (EX_NOPERM); 168 } 169 170 chosen = myIORegistryEntryCopyValue("IODeviceTree:/chosen"); 171 if (chosen == NULL) { 172 goto done; 173 } 174 response = CFDictionaryGetValue(chosen, CFSTR("bsdp-response")); 175 if (isA_CFData(response) == NULL) { 176 response = CFDictionaryGetValue(chosen, CFSTR("bootp-response")); 177 if (isA_CFData(response) == NULL) { 178 goto done; 179 } 180 } 181 /* ALIGN: CFDataGetBytePtr is aligned to at least sizeof(uint64) */ 182 dhcp = (struct dhcp *)(void *)CFDataGetBytePtr(response); 183 length = (int)CFDataGetLength(response); 184 bsdp_print_packet(dhcp, length, 0); 185 ret = 0; 186 done: 187 if (chosen != NULL) { 188 CFRelease(chosen); 189 } 190 return (ret); 191} 192 193static int 194S_bsdp_option(mach_port_t server, int argc, char * argv[]) 195{ 196 CFDictionaryRef chosen = NULL; 197 void * data = NULL; 198 int data_len; 199 struct dhcp * dhcp; 200 int length; 201 dhcpol_t options; 202 CFDataRef response = NULL; 203 int ret = 1; 204 int tag = 0; 205 dhcpol_t vendor_options; 206 int vendor_tag = 0; 207 208 if (getuid() != 0) { 209 return (EX_NOPERM); 210 } 211 212 chosen = myIORegistryEntryCopyValue("IODeviceTree:/chosen"); 213 if (chosen == NULL) { 214 goto done; 215 } 216 response = CFDictionaryGetValue(chosen, CFSTR("bsdp-response")); 217 if (isA_CFData(response) == NULL) { 218 response = CFDictionaryGetValue(chosen, CFSTR("bootp-response")); 219 if (isA_CFData(response) == NULL) { 220 goto done; 221 } 222 } 223 224 /* ALIGN: CFDataGetBytePtr is aligned to at least sizeof(uint64) */ 225 dhcp = (struct dhcp *)(void *)CFDataGetBytePtr(response); 226 length = (int)CFDataGetLength(response); 227 if (dhcpol_parse_packet(&options, dhcp, length, NULL) == FALSE) { 228 goto done; 229 } 230 if (strcmp(argv[0], SHADOW_MOUNT_PATH_COMMAND) == 0) { 231 tag = dhcptag_vendor_specific_e; 232 vendor_tag = bsdptag_shadow_mount_path_e; 233 } 234 else if (strcmp(argv[0], SHADOW_FILE_PATH_COMMAND) == 0) { 235 tag = dhcptag_vendor_specific_e; 236 vendor_tag = bsdptag_shadow_file_path_e; 237 } 238 else if (strcmp(argv[0], MACHINE_NAME_COMMAND) == 0) { 239 tag = dhcptag_vendor_specific_e; 240 vendor_tag = bsdptag_machine_name_e; 241 } 242 else { 243 tag = atoi(argv[0]); 244 if (argc == 2) { 245 vendor_tag = atoi(argv[1]); 246 } 247 } 248 if (tag == dhcptag_vendor_specific_e && vendor_tag != 0) { 249 if (dhcpol_parse_vendor(&vendor_options, &options, NULL) == FALSE) { 250 goto done; 251 } 252 data = dhcpol_option_copy(&vendor_options, vendor_tag, &data_len); 253 if (data != NULL) { 254 dhcptype_print(bsdptag_type(vendor_tag), data, data_len); 255 ret = 0; 256 } 257 dhcpol_free(&vendor_options); 258 } 259 else { 260 const dhcptag_info_t * entry; 261 262 entry = dhcptag_info(tag); 263 if (entry == NULL) { 264 goto done; 265 } 266 data = dhcpol_option_copy(&options, tag, &data_len); 267 if (data != NULL) { 268 dhcptype_print(entry->type, data, data_len); 269 ret = 0; 270 } 271 } 272 done: 273 if (data != NULL) { 274 free(data); 275 } 276 if (chosen != NULL) { 277 CFRelease(chosen); 278 } 279 return (ret); 280} 281 282static int 283S_if_addr(mach_port_t server, int argc, char * argv[]) 284{ 285 struct in_addr ip; 286 kern_return_t kret; 287 if_name_t name; 288 ipconfig_status_t status; 289 290 strlcpy(name, argv[0], sizeof(name)); 291 kret = ipconfig_if_addr(server, name, (ip_address_t *)&ip, &status); 292 if (kret != KERN_SUCCESS) { 293 fprintf(stderr, "get if addr %s failed, %s\n", name, 294 mach_error_string(kret)); 295 } 296 if (status == ipconfig_status_success_e) { 297 printf("%s\n", inet_ntoa(ip)); 298 return (0); 299 } 300 return (1); 301} 302 303static int 304S_if_count(mach_port_t server, int argc, char * argv[]) 305{ 306 int count = 0; 307 kern_return_t status; 308 309 status = ipconfig_if_count(server, &count); 310 if (status == KERN_SUCCESS) { 311 printf("%d\n", count); 312 return (0); 313 } 314 fprintf(stderr, "get if count failed, %s\n", mach_error_string(status)); 315 return (1); 316} 317 318static int 319S_get_option(mach_port_t server, int argc, char * argv[]) 320{ 321 char buf[1024]; 322 inline_data_t data; 323 unsigned int data_len = sizeof(data); 324 dhcpo_err_str_t err; 325 kern_return_t kret; 326 if_name_t name; 327 ipconfig_status_t status; 328 int tag; 329 330 strlcpy(name, argv[0], sizeof(name)); 331 332 tag = dhcptag_with_name(argv[1]); 333 if (tag == -1) { 334 tag = atoi(argv[1]); 335 } 336 kret = ipconfig_get_option(server, name, tag, data, &data_len, 337 &status); 338 if (kret != KERN_SUCCESS) { 339 fprintf(stderr, "ipconfig_get_option failed, %s\n", 340 mach_error_string(kret)); 341 goto done; 342 } 343 if (status != ipconfig_status_success_e) { 344 goto done; 345 } 346 if (dhcptag_to_str(buf, sizeof(buf), tag, data, data_len, &err)) { 347 printf("%s\n", buf); 348 return (0); 349 } 350 fprintf(stderr, "couldn't convert the option, %s\n", 351 err.str); 352 done: 353 return (1); 354} 355 356static int 357S_get_packet(mach_port_t server, int argc, char * argv[]) 358{ 359 uint32_t data[sizeof(inline_data_t)/sizeof(uint32_t)]; 360 unsigned int data_len = sizeof(data); 361 kern_return_t kret; 362 if_name_t name; 363 int ret; 364 ipconfig_status_t status; 365 366 ret = 1; 367 strlcpy(name, argv[0], sizeof(name)); 368 kret = ipconfig_get_packet(server, name, (void *)data, &data_len, &status); 369 if (kret != KERN_SUCCESS) { 370 fprintf(stderr, "ipconfig_get_packet failed, %s\n", 371 mach_error_string(kret)); 372 goto done; 373 } 374 if (status != ipconfig_status_success_e) { 375 goto done; 376 } 377 /* ALIGN: inline_data_t is aligned at least sizeof(uint32_t) bytes */ 378 dhcp_packet_print((struct dhcp *)(void *)data, data_len); 379 ret = 0; 380 381 done: 382 return (ret); 383} 384 385static int 386S_get_v6_packet(mach_port_t server, int argc, char * argv[]) 387{ 388 inline_data_t data; 389 unsigned int data_len = sizeof(data); 390 DHCPv6OptionErrorString err; 391 kern_return_t kret; 392 if_name_t name; 393 DHCPv6OptionListRef options; 394 int ret; 395 ipconfig_status_t status; 396 397 ret = 1; 398 strlcpy(name, argv[0], sizeof(name)); 399 kret = ipconfig_get_v6_packet(server, name, data, &data_len, &status); 400 if (kret != KERN_SUCCESS) { 401 fprintf(stderr, "ipconfig_get_v6_packet failed, %s\n", 402 mach_error_string(kret)); 403 goto done; 404 } 405 if (status != ipconfig_status_success_e) { 406 goto done; 407 } 408 DHCPv6PacketFPrint(stdout, (DHCPv6PacketRef)data, data_len); 409 options = DHCPv6OptionListCreateWithPacket((DHCPv6PacketRef)data, 410 data_len, &err); 411 if (options != NULL) { 412 DHCPv6OptionListFPrint(stdout, options); 413 DHCPv6OptionListRelease(&options); 414 } 415 ret = 0; 416 417 done: 418 return (ret); 419} 420 421#ifndef kSCValNetIPv6ConfigMethodLinkLocal 422static const CFStringRef kIPConfigurationIPv6ConfigMethodLinkLocal = CFSTR("LinkLocal"); 423#define kSCValNetIPv6ConfigMethodLinkLocal kIPConfigurationIPv6ConfigMethodLinkLocal 424#endif /* kSCValNetIPv6ConfigMethodLinkLocal */ 425 426#ifndef kSCValNetIPv4ConfigMethodFailover 427static const CFStringRef kIPConfigurationConfigMethodFailover = CFSTR("Failover"); 428#define kSCValNetIPv4ConfigMethodFailover kIPConfigurationConfigMethodFailover 429#endif /* kSCValNetIPv4ConfigMethodFailover */ 430 431#ifndef kSCPropNetIPv4FailoverAddressTimeout 432static const CFStringRef kIPConfigurationFailoverAddressTimeout = CFSTR("FailoverAddressTimeout"); 433#define kSCPropNetIPv4FailoverAddressTimeout kIPConfigurationFailoverAddressTimeout 434#endif /* kSCPropNetIPv4FailoverAddressTimeout */ 435 436static CFStringRef 437IPv4ConfigMethodGet(const char * m) 438{ 439 if (strcasecmp("bootp", m) == 0) { 440 return (kSCValNetIPv4ConfigMethodBOOTP); 441 } 442 if (strcasecmp("dhcp", m) == 0) { 443 return (kSCValNetIPv4ConfigMethodDHCP); 444 } 445 if (strcasecmp("manual", m) == 0) { 446 return (kSCValNetIPv4ConfigMethodManual); 447 } 448 if (strcasecmp("inform", m) == 0) { 449 return (kSCValNetIPv4ConfigMethodINFORM); 450 } 451 if (strcasecmp("linklocal", m) == 0) { 452 return (kSCValNetIPv4ConfigMethodLinkLocal); 453 } 454 if (strcasecmp("failover", m) == 0) { 455 return (kSCValNetIPv4ConfigMethodFailover); 456 } 457 return (NULL); 458} 459 460static CFDictionaryRef 461IPv4ConfigDictCreate(const char * ifname, 462 int argc, char * argv[], const char * cmd, 463 const char * method_name, 464 CFStringRef config_method) 465{ 466 CFMutableDictionaryRef dict; 467 468 dict = CFDictionaryCreateMutable(NULL, 0, 469 &kCFTypeDictionaryKeyCallBacks, 470 &kCFTypeDictionaryValueCallBacks); 471 CFDictionarySetValue(dict, kSCPropNetIPv4ConfigMethod, 472 config_method); 473 if (config_method == kSCValNetIPv4ConfigMethodFailover 474 || config_method == kSCValNetIPv4ConfigMethodINFORM 475 || config_method == kSCValNetIPv4ConfigMethodManual) { 476 struct in_addr ip_address; 477 478 if (config_method == kSCValNetIPv4ConfigMethodFailover) { 479 if (argc < 1 || argc > 3) { 480 fprintf(stderr, "usage: ipconfig %s %s " 481 "%s <ip-address> [ <subnet-mask> [ <timeout> ] ]\n", 482 cmd, ifname, method_name); 483 goto failed; 484 } 485 } 486 else if (argc < 1 || argc > 2) { 487 fprintf(stderr, "usage: ipconfig %s %s " 488 "%s <ip-address> [ <subnet-mask> ]\n", 489 cmd, ifname, method_name); 490 goto failed; 491 } 492 if (inet_aton(argv[0], &ip_address) == 0) { 493 fprintf(stderr, "Invalid IP address %s\n", argv[0]); 494 goto failed; 495 } 496 my_CFDictionarySetIPAddressAsArrayValue(dict, 497 kSCPropNetIPv4Addresses, 498 ip_address); 499 if (argc >= 2) { 500 if (inet_aton(argv[1], &ip_address) != 1) { 501 fprintf(stderr, "Invalid IP mask %s\n", argv[1]); 502 goto failed; 503 } 504 my_CFDictionarySetIPAddressAsArrayValue(dict, 505 kSCPropNetIPv4SubnetMasks, 506 ip_address); 507 } 508 if (argc >= 3) { 509 int32_t timeout; 510 511 timeout = (int32_t)strtol(argv[2], NULL, 0); 512 if (timeout > 0) { 513 CFNumberRef num; 514 515 num = CFNumberCreate(NULL, kCFNumberSInt32Type, &timeout); 516 CFDictionarySetValue(dict, 517 kSCPropNetIPv4FailoverAddressTimeout, 518 num); 519 CFRelease(num); 520 } 521 } 522 } 523 else if (argc != 0) { 524 fprintf(stderr, "too many arguments for method\n"); 525 goto failed; 526 } 527 return (dict); 528 529 failed: 530 my_CFRelease(&dict); 531 return (NULL); 532} 533 534static CFStringRef 535IPv6ConfigMethodGet(const char * m) 536{ 537 if (strcasecmp(m, "automatic-v6") == 0) { 538 return (kSCValNetIPv6ConfigMethodAutomatic); 539 } 540 else if (strcasecmp(m, "manual-v6") == 0) { 541 return (kSCValNetIPv6ConfigMethodManual); 542 } 543 else if (strcasecmp(m, "6to4") == 0) { 544 return (kSCValNetIPv6ConfigMethod6to4); 545 } 546 if (strcasecmp(m, "linklocal-v6") == 0) { 547 return (kSCValNetIPv6ConfigMethodLinkLocal); 548 } 549 return (NULL); 550} 551 552static void 553my_CFDictionarySetIPv6AddressAsArrayValue(CFMutableDictionaryRef dict, 554 CFStringRef prop, 555 const struct in6_addr * ipaddr_p) 556{ 557 CFStringRef str; 558 559 str = my_CFStringCreateWithIPv6Address(ipaddr_p); 560 my_CFDictionarySetTypeAsArrayValue(dict, prop, str); 561 CFRelease(str); 562 return; 563} 564 565static void 566my_CFDictionarySetIntegerAsArrayValue(CFMutableDictionaryRef dict, 567 CFStringRef prop, int val) 568{ 569 CFNumberRef num; 570 571 num = CFNumberCreate(NULL, kCFNumberIntType, &val); 572 my_CFDictionarySetTypeAsArrayValue(dict, prop, num); 573 CFRelease(num); 574 return; 575} 576 577 578static CFDictionaryRef 579IPv6ConfigDictCreate(const char * ifname, 580 int argc, char * argv[], const char * cmd, 581 const char * method_name, 582 CFStringRef config_method) 583{ 584 CFDictionaryRef dict; 585 CFMutableDictionaryRef ipv6_dict; 586 CFStringRef ipv6_key; 587 588 ipv6_dict = CFDictionaryCreateMutable(NULL, 0, 589 &kCFTypeDictionaryKeyCallBacks, 590 &kCFTypeDictionaryValueCallBacks); 591 CFDictionarySetValue(ipv6_dict, kSCPropNetIPv6ConfigMethod, 592 config_method); 593 if (config_method == kSCValNetIPv6ConfigMethodManual) { 594 struct in6_addr ip_address; 595 int prefix_length; 596 597 if (argc != 2) { 598 fprintf(stderr, "usage: ipconfig %s %s " 599 "%s6 <ipv6-address> <prefix-length>\n", 600 cmd, ifname, method_name); 601 goto failed; 602 } 603 if (inet_pton(AF_INET6, argv[0], &ip_address) != 1) { 604 fprintf(stderr, "Invalid IPv6 address %s\n", argv[0]); 605 goto failed; 606 } 607 my_CFDictionarySetIPv6AddressAsArrayValue(ipv6_dict, 608 kSCPropNetIPv6Addresses, 609 &ip_address); 610 prefix_length = (int)strtol(argv[1], NULL, 0); 611 if (prefix_length < 0 || prefix_length > 128) { 612 fprintf(stderr, "Invalid prefix_length %s\n", argv[1]); 613 goto failed; 614 } 615 my_CFDictionarySetIntegerAsArrayValue(ipv6_dict, 616 kSCPropNetIPv6PrefixLength, 617 prefix_length); 618 } 619 else if (argc != 0) { 620 fprintf(stderr, "too many arguments for method\n"); 621 goto failed; 622 } 623 ipv6_key = kSCEntNetIPv6; 624 dict = CFDictionaryCreate(NULL, 625 (const void * *)&ipv6_key, 626 (const void * *)&ipv6_dict, 1, 627 &kCFTypeDictionaryKeyCallBacks, 628 &kCFTypeDictionaryValueCallBacks); 629 CFRelease(ipv6_dict); 630 return (dict); 631 632 failed: 633 my_CFRelease(&ipv6_dict); 634 return (NULL); 635} 636 637static CFDictionaryRef 638ConfigDictCreate(const char * ifname, int argc, char * argv[], const char * cmd, 639 const char * method_name, boolean_t allow_none) 640{ 641 CFStringRef config_method; 642 643 config_method = IPv4ConfigMethodGet(method_name); 644 if (config_method != NULL) { 645 return (IPv4ConfigDictCreate(ifname, argc, argv, cmd, method_name, 646 config_method)); 647 } 648 config_method = IPv6ConfigMethodGet(method_name); 649 if (config_method == NULL) { 650 fprintf(stderr, 651 "ipconfig %s: invalid method '%s'\n<method> is one of %s\n", 652 cmd, method_name, 653 (allow_none) ? METHOD_LIST_WITH_NONE : METHOD_LIST); 654 return (NULL); 655 } 656 return (IPv6ConfigDictCreate(ifname, argc, argv, cmd, 657 method_name, config_method)); 658} 659 660static int 661S_set(mach_port_t server, int argc, char * argv[]) 662{ 663 CFDataRef data = NULL; 664 CFDictionaryRef dict = NULL; 665 const char * method_name; 666 if_name_t if_name; 667 kern_return_t kret; 668 ipconfig_status_t status = ipconfig_status_success_e; 669 void * xml_data_ptr = NULL; 670 int xml_data_len = 0; 671 672 strlcpy(if_name, argv[0], sizeof(if_name)); 673 method_name = argv[1]; 674 argv += 2; 675 argc -= 2; 676 677 if (strcasecmp(method_name, "NONE") == 0) { 678 /* nothing to do, NONE implies NULL method data */ 679 } 680 else if (strcasecmp(method_name, "NONE-V6") == 0 681 || strcasecmp(method_name, "NONE-V4") == 0) { 682 683 CFDictionaryRef empty_dict; 684 CFStringRef ip_key; 685 686 /* NONE-V{4,6} is represented as an empty IPv{4,6} dictionary */ 687 empty_dict = CFDictionaryCreate(NULL, 688 NULL, NULL, 0, 689 &kCFTypeDictionaryKeyCallBacks, 690 &kCFTypeDictionaryValueCallBacks); 691 if (strcasecmp(method_name, "NONE-V6") == 0) { 692 ip_key = kSCEntNetIPv6; 693 } 694 else { 695 ip_key = kSCEntNetIPv4; 696 } 697 dict = CFDictionaryCreate(NULL, 698 (const void * *)&ip_key, 699 (const void * *)&empty_dict, 1, 700 &kCFTypeDictionaryKeyCallBacks, 701 &kCFTypeDictionaryValueCallBacks); 702 CFRelease(empty_dict); 703 } 704 else { 705 dict = ConfigDictCreate(if_name, argc, argv, command_name, method_name, 706 TRUE); 707 if (dict == NULL) { 708 return (1); 709 } 710 } 711 if (dict != NULL) { 712 data = CFPropertyListCreateData(NULL, 713 dict, 714 kCFPropertyListBinaryFormat_v1_0, 715 0, 716 NULL); 717 if (data == NULL) { 718 CFRelease(dict); 719 fprintf(stderr, "failed to allocate memory\n"); 720 return (1); 721 } 722 xml_data_ptr = (void *)CFDataGetBytePtr(data); 723 xml_data_len = (int)CFDataGetLength(data); 724 } 725 kret = ipconfig_set(server, if_name, xml_data_ptr, xml_data_len, &status); 726 my_CFRelease(&dict); 727 my_CFRelease(&data); 728 if (kret != KERN_SUCCESS) { 729 mach_error("ipconfig_set failed", kret); 730 return (1); 731 } 732 if (status != ipconfig_status_success_e) { 733 fprintf(stderr, "ipconfig_set %s %s failed: %s\n", 734 if_name, method_name, ipconfig_status_string(status)); 735 return (1); 736 } 737 return (0); 738} 739 740static int 741S_set_verbose(mach_port_t server, int argc, char * argv[]) 742{ 743 int verbose; 744 745 verbose = (int)strtol(argv[0], NULL, 0); 746 errno = 0; 747 if (verbose == 0 && errno != 0) { 748 fprintf(stderr, "conversion to integer of %s failed\n", argv[0]); 749 return (1); 750 } 751 if (IPConfigurationControlPrefsSetVerbose(verbose != 0) == FALSE) { 752 fprintf(stderr, "failed to set verbose\n"); 753 return (1); 754 } 755 return (0); 756} 757 758#ifdef IPCONFIG_TEST_NO_ENTRY 759static int 760S_set_something(mach_port_t server, int argc, char * argv[]) 761{ 762 kern_return_t kret; 763 ipconfig_status_t status = ipconfig_status_success_e; 764 int verbose; 765 766 verbose = strtol(argv[0], NULL, 0); 767 errno = 0; 768 if (verbose == 0 && errno != 0) { 769 fprintf(stderr, "conversion to integer of %s failed\n", argv[0]); 770 return (1); 771 } 772 kret = ipconfig_set_something(server, verbose, &status); 773 if (kret != KERN_SUCCESS) { 774 return (1); 775 } 776 if (status != ipconfig_status_success_e) { 777 fprintf(stderr, "setsomething failed: %s\n", 778 ipconfig_status_string(status)); 779 return (1); 780 } 781 return (0); 782} 783#endif /* IPCONFIG_TEST_NO_ENTRY */ 784 785static int 786S_add_or_set_service(mach_port_t server, int argc, char * argv[], bool add) 787{ 788 CFDataRef data = NULL; 789 CFDictionaryRef dict; 790 char * method_name; 791 if_name_t if_name; 792 kern_return_t kret; 793 inline_data_t service_id; 794 unsigned int service_id_len; 795 ipconfig_status_t status = ipconfig_status_success_e; 796 void * xml_data_ptr = NULL; 797 int xml_data_len = 0; 798 799 strlcpy(if_name, argv[0], sizeof(if_name)); 800 method_name = argv[1]; 801 argv += 2; 802 argc -= 2; 803 804 dict = ConfigDictCreate(if_name, argc, argv, command_name, method_name, 805 FALSE); 806 if (dict == NULL) { 807 return (1); 808 } 809 data = CFPropertyListCreateData(NULL, 810 dict, 811 kCFPropertyListBinaryFormat_v1_0, 812 0, 813 NULL); 814 if (data == NULL) { 815 CFRelease(dict); 816 fprintf(stderr, "failed to allocate memory\n"); 817 return (1); 818 } 819 xml_data_ptr = (void *)CFDataGetBytePtr(data); 820 xml_data_len = (int)CFDataGetLength(data); 821 if (add) { 822 kret = ipconfig_add_service(server, if_name, xml_data_ptr, xml_data_len, 823 service_id, &service_id_len, &status); 824 } 825 else { 826 kret = ipconfig_set_service(server, if_name, xml_data_ptr, xml_data_len, 827 service_id, &service_id_len, &status); 828 } 829 CFRelease(dict); 830 CFRelease(data); 831 832 if (kret != KERN_SUCCESS) { 833 fprintf(stderr, "ipconfig_%s_service failed, %s\n", add ? "add" : "set", 834 mach_error_string(kret)); 835 return (1); 836 } 837 if (status != ipconfig_status_success_e) { 838 fprintf(stderr, "ipconfig_%s_service %s %s failed: %s\n", 839 add ? "add" : "set", 840 if_name, method_name, ipconfig_status_string(status)); 841 return (1); 842 } 843 printf("%.*s\n", service_id_len, service_id); 844 return (0); 845} 846 847static int 848S_add_service(mach_port_t server, int argc, char * argv[]) 849{ 850 return (S_add_or_set_service(server, argc, argv, TRUE)); 851} 852 853static int 854S_set_service(mach_port_t server, int argc, char * argv[]) 855{ 856 return (S_add_or_set_service(server, argc, argv, FALSE)); 857} 858 859static int 860S_remove_service_with_id(mach_port_t server, int argc, char * argv[]) 861{ 862 if_name_t if_name; 863 kern_return_t kret; 864 inline_data_t service_id; 865 unsigned int service_id_len; 866 ipconfig_status_t status = ipconfig_status_success_e; 867 868 service_id_len = (int)strlen(argv[0]); 869 if (service_id_len > sizeof(service_id)) { 870 service_id_len = sizeof(service_id); 871 } 872 memcpy(service_id, argv[0], service_id_len); 873 if (argc > 1) { 874 strlcpy(if_name, argv[1], sizeof(if_name)); 875 } 876 else { 877 bzero(if_name, sizeof(if_name)); 878 } 879 kret = ipconfig_remove_service_on_interface(server, 880 if_name, 881 service_id, service_id_len, 882 &status); 883 if (kret != KERN_SUCCESS) { 884 mach_error("ipconfig_remove_service_on_interface failed", kret); 885 return (1); 886 } 887 if (status != ipconfig_status_success_e) { 888 fprintf(stderr, "ipconfig_remove_service_on_interface %s failed: %s\n", 889 argv[0], ipconfig_status_string(status)); 890 return (1); 891 } 892 return (0); 893} 894 895static int 896S_find_service(mach_port_t server, int argc, char * argv[]) 897{ 898 CFDataRef data = NULL; 899 CFDictionaryRef dict; 900 boolean_t exact = FALSE; 901 char * method_name; 902 if_name_t if_name; 903 kern_return_t kret; 904 inline_data_t service_id; 905 unsigned int service_id_len = sizeof(service_id); 906 ipconfig_status_t status = ipconfig_status_success_e; 907 void * xml_data_ptr = NULL; 908 int xml_data_len = 0; 909 910 strlcpy(if_name, argv[0], sizeof(if_name)); 911 argv++; 912 argc--; 913 if (argc > 1 && strcasecmp(argv[0], "exact") == 0) { 914 exact = TRUE; 915 argc--; 916 argv++; 917 } 918 method_name = argv[0]; 919 argc--; 920 argv++; 921 dict = ConfigDictCreate(if_name, argc, argv, command_name, method_name, 922 FALSE); 923 if (dict == NULL) { 924 return (1); 925 } 926 data = CFPropertyListCreateData(NULL, 927 dict, 928 kCFPropertyListBinaryFormat_v1_0, 929 0, 930 NULL); 931 if (data == NULL) { 932 CFRelease(dict); 933 fprintf(stderr, "failed to allocate memory\n"); 934 return (1); 935 } 936 xml_data_ptr = (void *)CFDataGetBytePtr(data); 937 xml_data_len = (int)CFDataGetLength(data); 938 kret = ipconfig_find_service(server, if_name, exact, 939 xml_data_ptr, xml_data_len, 940 service_id, &service_id_len, &status); 941 my_CFRelease(&dict); 942 my_CFRelease(&data); 943 if (kret != KERN_SUCCESS) { 944 mach_error("ipconfig_find_service failed", kret); 945 return (1); 946 } 947 if (status != ipconfig_status_success_e) { 948 fprintf(stderr, "ipconfig_find_service %s %s failed: %s\n", 949 if_name, method_name, ipconfig_status_string(status)); 950 return (1); 951 } 952 printf("%.*s\n", service_id_len, service_id); 953 return (0); 954} 955 956static int 957S_remove_service(mach_port_t server, int argc, char * argv[]) 958{ 959 CFDataRef data = NULL; 960 CFDictionaryRef dict; 961 char * method_name; 962 if_name_t if_name; 963 kern_return_t kret; 964 ipconfig_status_t status = ipconfig_status_success_e; 965 void * xml_data_ptr = NULL; 966 int xml_data_len = 0; 967 968 strlcpy(if_name, argv[0], sizeof(if_name)); 969 method_name = argv[1]; 970 argv += 2; 971 argc -= 2; 972 973 dict = ConfigDictCreate(if_name, argc, argv, command_name, method_name, 974 FALSE); 975 if (dict == NULL) { 976 return (1); 977 } 978 data = CFPropertyListCreateData(NULL, 979 dict, 980 kCFPropertyListBinaryFormat_v1_0, 981 0, 982 NULL); 983 if (data == NULL) { 984 CFRelease(dict); 985 fprintf(stderr, "failed to allocate memory\n"); 986 return (1); 987 } 988 xml_data_ptr = (void *)CFDataGetBytePtr(data); 989 xml_data_len = (int)CFDataGetLength(data); 990 kret = ipconfig_remove_service(server, if_name, xml_data_ptr, xml_data_len, 991 &status); 992 my_CFRelease(&dict); 993 my_CFRelease(&data); 994 if (kret != KERN_SUCCESS) { 995 mach_error("ipconfig_remove_service failed", kret); 996 return (1); 997 } 998 if (status != ipconfig_status_success_e) { 999 fprintf(stderr, "ipconfig_remove_service %s %s failed: %s\n", 1000 if_name, method_name, ipconfig_status_string(status)); 1001 return (1); 1002 } 1003 return (0); 1004} 1005 1006static int 1007S_refresh_service(mach_port_t server, int argc, char * argv[]) 1008{ 1009 if_name_t if_name; 1010 kern_return_t kret; 1011 inline_data_t service_id; 1012 unsigned int service_id_len; 1013 ipconfig_status_t status = ipconfig_status_success_e; 1014 1015 service_id_len = (int)strlen(argv[0]); 1016 if (service_id_len > sizeof(service_id)) { 1017 service_id_len = sizeof(service_id); 1018 } 1019 memcpy(service_id, argv[0], service_id_len); 1020 strlcpy(if_name, argv[1], sizeof(if_name)); 1021 kret = ipconfig_refresh_service(server, 1022 if_name, 1023 service_id, service_id_len, 1024 &status); 1025 if (kret != KERN_SUCCESS) { 1026 mach_error("ipconfig_refresh_service", kret); 1027 return (1); 1028 } 1029 if (status != ipconfig_status_success_e) { 1030 fprintf(stderr, "ipconfig_refresh_service(%s, %s) failed: %s\n", 1031 argv[0], argv[1], ipconfig_status_string(status)); 1032 return (1); 1033 } 1034 return (0); 1035} 1036 1037 1038static const struct command_info { 1039 const char *command; 1040 funcptr_t func; 1041 int argc; 1042 const char *usage; 1043 int display; 1044 int no_server; 1045} commands[] = { 1046 { "waitall", S_wait_all, 0, "[ timeout secs ]", 1, 1 }, 1047 { "getifaddr", S_if_addr, 1, "<interface name>", 1, 0 }, 1048#if 0 1049 { "waitif", S_wait_if, 1, " <interface name>", 1, 0 }, 1050#endif /* 0 */ 1051 { "ifcount", S_if_count, 0, "", 1, 0 }, 1052 { "getoption", S_get_option, 2, 1053 " <interface name | \"\" > <option name> | <option code>", 1, 0 }, 1054 { "getpacket", S_get_packet, 1, " <interface name>", 1, 0 }, 1055 { "getv6packet", S_get_v6_packet, 1, " <interface name>", 1, 0 }, 1056 { "set", S_set, 2, 1057 "<interface name> <method> <method args>\n" 1058 "<method> is one of " METHOD_LIST_WITH_NONE, 1059 1, 0 }, 1060 { "netbootoption", S_bsdp_option, 1, "<option> [<vendor option>] | " 1061 SHADOW_MOUNT_PATH_COMMAND " | " SHADOW_FILE_PATH_COMMAND 1062 " | " MACHINE_NAME_COMMAND, 0, 1 }, 1063 { "netbootpacket", S_bsdp_get_packet, 0, "", 0, 1 }, 1064 { "setverbose", S_set_verbose, 1, "0 | 1", 1, 1 }, 1065#ifdef IPCONFIG_TEST_NO_ENTRY 1066 { "setsomething", S_set_something, 1, "0 | 1", 1, 0 }, 1067#endif /* IPCONFIG_TEST_NO_ENTRY */ 1068 { "addService", S_add_service, 2, 1069 "<interface name> <method> <method args>\n" 1070 "<method> is one of " METHOD_LIST, 1071 0, 0 }, 1072 { "setService", S_set_service, 2, 1073 "<interface name> <method> <method args>\n" 1074 "<method> is one of " METHOD_LIST, 1075 0, 0 }, 1076 { "findService", S_find_service, 2, 1077 "<interface name> [ exact ] <method> <method args>\n" 1078 "<method> is one of " METHOD_LIST, 1079 0, 0 }, 1080 { "removeServiceWithId", S_remove_service_with_id, 1, 1081 "<service ID> [ <interface name> ]", 0, 0 }, 1082 { "removeService", S_remove_service, 2, 1083 "<interface name> <method> <method args>\n" 1084 "<method> is one of " METHOD_LIST, 1085 0, 0 }, 1086 { "refreshService", S_refresh_service, 2, 1087 "<service ID> <interface name>", 0, 0 }, 1088 { NULL, NULL, 0, NULL, 0, 0 }, 1089}; 1090 1091void 1092usage() 1093{ 1094 int i; 1095 fprintf(stderr, "usage: %s <command> <args>\n", progname); 1096 fprintf(stderr, "where <command> is one of "); 1097 for (i = 0; commands[i].command; i++) { 1098 if (commands[i].display) { 1099 fprintf(stderr, "%s%s", i == 0 ? "" : ", ", 1100 commands[i].command); 1101 } 1102 } 1103 fprintf(stderr, "\n"); 1104 exit(1); 1105} 1106 1107static const struct command_info * 1108S_lookup_command(char * cmd, int argc) 1109{ 1110 int i; 1111 1112 for (i = 0; commands[i].command; i++) { 1113 if (strcasecmp(cmd, commands[i].command) == 0) { 1114 if (argc < commands[i].argc) { 1115 fprintf(stderr, "usage: ipconfig %s %s\n", commands[i].command, 1116 commands[i].usage ? commands[i].usage : ""); 1117 exit(1); 1118 } 1119 return commands + i; 1120 } 1121 } 1122 return (NULL); 1123} 1124 1125int 1126main(int argc, char * argv[]) 1127{ 1128 const struct command_info * command; 1129 mach_port_t server = MACH_PORT_NULL; 1130 kern_return_t kret; 1131 1132 progname = argv[0]; 1133 if (argc < 2) 1134 usage(); 1135 1136 argv++; argc--; 1137 command_name = argv[0]; 1138 command = S_lookup_command(command_name, argc - 1); 1139 if (command == NULL) { 1140 usage(); 1141 exit(1); 1142 } 1143 argv++; argc--; 1144 if (command->no_server == 0) { 1145 kret = ipconfig_server_port(&server); 1146 switch (kret) { 1147 case BOOTSTRAP_SUCCESS: 1148 break; 1149 case BOOTSTRAP_UNKNOWN_SERVICE: 1150 fprintf(stderr, "ipconfig server not active\n"); 1151 /* start it maybe??? */ 1152 exit(1); 1153 default: 1154 mach_error("ipconfig_server_port failed", kret); 1155 exit(1); 1156 } 1157 } 1158 exit ((*command->func)(server, argc, argv)); 1159} 1160