/* * Copyright (c) 2004-2009, 2011, 2014, 2017, 2019 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * Modification History * * August 5, 2004 Allan Nathanson * - initial revision */ #include "scutil.h" #include "net.h" #include "net_protocol.h" #include "prefs.h" #include #include #include #include #include /* -------------------- */ static CFStringRef __copyIPv4Address(const char *arg) { char buf[128]; struct sockaddr_in sin; if (_SC_string_to_sockaddr(arg, AF_INET, (void *)&sin, sizeof(sin)) == NULL) { return NULL; } _SC_sockaddr_to_string((struct sockaddr *)&sin, buf, sizeof(buf)); return CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8); } static CFStringRef __copyIPv6Address(const char *arg) { char buf[128]; struct sockaddr_in6 sin6; if (_SC_string_to_sockaddr(arg, AF_INET6, (void *)&sin6, sizeof(sin6)) == NULL) { return NULL; } _SC_sockaddr_to_string((struct sockaddr *)&sin6, buf, sizeof(buf)); return CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8); } /* -------------------- */ static SCNetworkProtocolRef _find_protocol(char *match) { Boolean allowIndex = TRUE; CFIndex i; CFIndex n; CFStringRef select_name = NULL; SCNetworkProtocolRef selected = NULL; if (protocols == NULL) { if (net_service == NULL) { SCPrint(TRUE, stdout, CFSTR("network service not selected\n")); return NULL; } protocols = SCNetworkServiceCopyProtocols(net_service); if (protocols == NULL) { SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError())); return NULL; } n = CFArrayGetCount(protocols); if (n > 1) { CFMutableArrayRef sorted; sorted = CFArrayCreateMutableCopy(NULL, 0, protocols); CFArraySortValues(sorted, CFRangeMake(0, n), _SCNetworkProtocolCompare, NULL); CFRelease(protocols); protocols = sorted; } allowIndex = FALSE; } // try to select the protocol by its protocol type select_name = CFStringCreateWithCString(NULL, match, kCFStringEncodingUTF8); n = CFArrayGetCount(protocols); for (i = 0; i < n; i++) { SCNetworkProtocolRef protocol; CFStringRef type; protocol = CFArrayGetValueAtIndex(protocols, i); type = SCNetworkProtocolGetProtocolType(protocol); if (CFStringCompare(select_name, type, kCFCompareCaseInsensitive) == kCFCompareEqualTo) { selected = protocol; goto done; } } if (allowIndex) { char *end; char *str = match; long val; // try to select the protocol by its index errno = 0; val = strtol(str, &end, 10); if ((*str != '\0') && (*end == '\0') && (errno == 0)) { if ((val > 0) && (val <= n)) { selected = CFArrayGetValueAtIndex(protocols, val - 1); } } } if (selected != NULL) { goto done; } SCPrint(TRUE, stdout, CFSTR("no match, which protocol?\n")); done : if (select_name != NULL) CFRelease(select_name); return selected; } /* -------------------- */ __private_extern__ void create_protocol(int argc, char **argv) { SCNetworkInterfaceRef interface; CFStringRef protocolType; if ((argc < 1) || (strlen(argv[0]) == 0)) { SCPrint(TRUE, stdout, CFSTR("what protocol type?\n")); return; } if (net_service == NULL) { SCPrint(TRUE, stdout, CFSTR("network service not selected\n")); return; } protocolType = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); interface = SCNetworkServiceGetInterface(net_service); if (interface != NULL) { CFArrayRef supported; CFIndex i; CFIndex n; supported = SCNetworkInterfaceGetSupportedProtocolTypes(interface); n = (supported != NULL) ? CFArrayGetCount(supported) : 0; for (i = 0; i < n; i++) { CFStringRef supportedType; supportedType = CFArrayGetValueAtIndex(supported, i); if (CFStringCompare(protocolType, supportedType, kCFCompareCaseInsensitive) == kCFCompareEqualTo) { CFRelease(protocolType); protocolType = CFRetain(supportedType); break; } } } if (!SCNetworkServiceAddProtocolType(net_service, protocolType)) { SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError())); goto done; } _prefs_changed = TRUE; if (protocols != NULL) { CFRelease(protocols); protocols = NULL; } if (net_protocol != NULL) CFRelease(net_protocol); // net_protocol = NULL; net_protocol = SCNetworkServiceCopyProtocol(net_service, protocolType); if (net_protocol == NULL) { SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError())); goto done; } SCPrint(TRUE, stdout, CFSTR("protocol \"%@\" selected\n"), protocolType); done : CFRelease(protocolType); return; } /* -------------------- */ __private_extern__ void disable_protocol(int argc, char **argv) { SCNetworkProtocolRef protocol = NULL; if (argc > 0) { protocol = _find_protocol(argv[0]); } else { if (net_protocol != NULL) { protocol = net_protocol; } else { SCPrint(TRUE, stdout, CFSTR("protocol not selected\n")); return; } } if (protocol == NULL) { return; } if (!SCNetworkProtocolSetEnabled(protocol, FALSE)) { SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError())); return; } _prefs_changed = TRUE; return; } /* -------------------- */ __private_extern__ void enable_protocol(int argc, char **argv) { SCNetworkProtocolRef protocol = NULL; if (argc > 0) { protocol = _find_protocol(argv[0]); } else { if (net_protocol != NULL) { protocol = net_protocol; } else { SCPrint(TRUE, stdout, CFSTR("protocol not selected\n")); return; } } if (protocol == NULL) { return; } if (!SCNetworkProtocolSetEnabled(protocol, TRUE)) { SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError())); return; } _prefs_changed = TRUE; return; } /* -------------------- */ __private_extern__ void remove_protocol(int argc, char **argv) { SCNetworkProtocolRef protocol = NULL; CFStringRef protocolType; if (argc > 0) { protocol = _find_protocol(argv[0]); } else { if (net_protocol != NULL) { protocol = net_protocol; } else { SCPrint(TRUE, stdout, CFSTR("protocol not selected\n")); return; } } if (protocol == NULL) { return; } CFRetain(protocol); protocolType = SCNetworkProtocolGetProtocolType(protocol); if (!SCNetworkServiceRemoveProtocolType(net_service, protocolType)) { SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError())); goto done; } _prefs_changed = TRUE; SCPrint(TRUE, stdout, CFSTR("protocol \"%@\" removed\n"), protocolType); if ((net_protocol != NULL) && CFEqual(protocol, net_protocol)) { CFRelease(net_protocol); net_protocol = NULL; SCPrint(TRUE, stdout, CFSTR("& no protocol selected\n")); } if (protocols != NULL) { CFRelease(protocols); protocols = NULL; } done : CFRelease(protocol); return; } /* -------------------- */ __private_extern__ void select_protocol(int argc, char **argv) { #pragma unused(argc) SCNetworkProtocolRef protocol; protocol = _find_protocol(argv[0]); if (protocol == NULL) { return; } if (net_protocol != NULL) CFRelease(net_protocol); net_protocol = CFRetain(protocol); SCPrint(TRUE, stdout, CFSTR("protocol \"%@\" selected\n"), SCNetworkProtocolGetProtocolType(protocol)); return; } #pragma mark - #pragma mark DNS static CF_RETURNS_RETAINED CFStringRef __cleanupDomainName(CFStringRef domain) { CFMutableStringRef newDomain; newDomain = CFStringCreateMutableCopy(NULL, 0, domain); CFStringTrimWhitespace(newDomain); CFStringTrim(newDomain, CFSTR(".")); if (CFStringGetLength(newDomain) == 0) { CFRelease(newDomain); newDomain = NULL; } return newDomain; } static int __doDNSDomain(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(description) #pragma unused(info) if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("DNS domain name not specified\n")); return -1; } if (strlen(argv[0]) > 0) { CFStringRef domain; CFStringRef str; str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); domain = __cleanupDomainName(str); CFRelease(str); if (domain != NULL) { CFDictionarySetValue(newConfiguration, key, domain); CFRelease(domain); } else { SCPrint(TRUE, stdout, CFSTR("invalid DNS domain name\n")); return -1; } } else { CFDictionaryRemoveValue(newConfiguration, key); } return 1; } static int __doDNSDomainArray(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(description) #pragma unused(info) CFMutableArrayRef domains; if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("DNS search domain name(s) not specified\n")); return -1; } domains = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); if (strlen(argv[0]) > 0) { CFArrayRef array; CFStringRef str; str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); array = CFStringCreateArrayBySeparatingStrings(NULL, str, CFSTR(",")); CFRelease(str); if (array != NULL) { CFIndex i; CFIndex n = CFArrayGetCount(array); for (i = 0; i < n; i++) { CFStringRef domain; domain = __cleanupDomainName(CFArrayGetValueAtIndex(array, i)); if (domain != NULL) { CFArrayAppendValue(domains, domain); CFRelease(domain); } else { CFRelease(array); CFRelease(domains); SCPrint(TRUE, stdout, CFSTR("invalid DNS search domain name\n")); return -1; } } CFRelease(array); } } if (CFArrayGetCount(domains) > 0) { CFDictionarySetValue(newConfiguration, key, domains); } else { CFDictionaryRemoveValue(newConfiguration, key); } CFRelease(domains); return 1; } static int __doDNSServerAddresses(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(description) #pragma unused(info) CFMutableArrayRef servers; if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("DNS name server address(es) not specified\n")); return -1; } servers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); if (strlen(argv[0]) > 0) { CFArrayRef array; CFIndex i; CFIndex n; CFStringRef str; str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); array = CFStringCreateArrayBySeparatingStrings(NULL, str, CFSTR(",")); CFRelease(str); n = (array != NULL) ? CFArrayGetCount(array) : 0; for (i = 0; i < n; i++) { char str[32]; if (_SC_cfstring_to_cstring(CFArrayGetValueAtIndex(array, i), str, sizeof(str), kCFStringEncodingUTF8) != NULL) { CFStringRef server; server = __copyIPv4Address(str); if (server == NULL) { server = __copyIPv6Address(str); } if (server != NULL) { CFArrayAppendValue(servers, server); CFRelease(server); continue; } } SCPrint(TRUE, stdout, CFSTR("invalid DNS name server address\n")); CFRelease(array); CFRelease(servers); return -1; } if (array != NULL) CFRelease(array); } if (CFArrayGetCount(servers) > 0) { CFDictionarySetValue(newConfiguration, key, servers); } else { CFDictionaryRemoveValue(newConfiguration, key); } CFRelease(servers); return 1; } static options dnsOptions[] = { { "DomainName" , "domain" , isOther, &kSCPropNetDNSDomainName , __doDNSDomain , NULL }, { "domain" , "domain" , isOther, &kSCPropNetDNSDomainName , __doDNSDomain , NULL }, { "SearchDomains" , "search" , isOther, &kSCPropNetDNSSearchDomains , __doDNSDomainArray , NULL }, { "search" , "search" , isOther, &kSCPropNetDNSSearchDomains , __doDNSDomainArray , NULL }, { "ServerAddresses", "address", isOther, &kSCPropNetDNSServerAddresses, __doDNSServerAddresses, NULL }, { "nameserver" , "address", isOther, &kSCPropNetDNSServerAddresses, __doDNSServerAddresses, NULL }, { "nameservers" , "address", isOther, &kSCPropNetDNSServerAddresses, __doDNSServerAddresses, NULL }, { "SupplementalMatchDomains", "domain", isOther, &kSCPropNetDNSSupplementalMatchDomains, __doDNSDomainArray, NULL }, { "?" , NULL , isHelp , NULL , NULL, "\nDNS configuration commands\n\n" " set protocol search domain-name[,domain-name-2]\n" " set protocol nameserver x1.x1.x1.x1[,x2.x2.x2.x2]\n" } }; #define N_DNS_OPTIONS (sizeof(dnsOptions) / sizeof(dnsOptions[0])) static Boolean set_protocol_dns(int argc, char **argv, CFMutableDictionaryRef newConfiguration) { Boolean ok; ok = _process_options(dnsOptions, N_DNS_OPTIONS, argc, argv, newConfiguration); return ok; } #pragma mark - #pragma mark IPv4 #define allowIPv4Address 1<<1 // allow address #define allowIPv4Netmask 1<<2 // allow subnet mask #define allowIPv4Router 1<<3 // allow router #define allowIPv4DHCPClientID 1<<4 // allow DCHP Client ID static selections ipv4ConfigMethods[] = { { CFSTR("BOOTP") , &kSCValNetIPv4ConfigMethodBOOTP , 0 }, { CFSTR("DHCP") , &kSCValNetIPv4ConfigMethodDHCP , allowIPv4DHCPClientID }, { CFSTR("INFORM") , &kSCValNetIPv4ConfigMethodINFORM , allowIPv4Address }, { CFSTR("LinkLocal"), &kSCValNetIPv4ConfigMethodLinkLocal, 0 }, { CFSTR("Manual") , &kSCValNetIPv4ConfigMethodManual , allowIPv4Address|allowIPv4Netmask|allowIPv4Router }, { CFSTR("PPP") , &kSCValNetIPv4ConfigMethodPPP , allowIPv4Address|selectionNotAvailable }, { NULL , NULL , 0 } }; static int __doIPv4ConfigMethod(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(description) #pragma unused(info) #pragma unused(argc) #pragma unused(argv) unsigned int flags; CFStringRef method; CFIndex methodIndex; method = CFDictionaryGetValue(newConfiguration, key); methodIndex = _find_selection(method, (selections *)ipv4ConfigMethods, &flags); if (methodIndex != kCFNotFound) { if (!(flags & allowIPv4Address)) { CFDictionaryRemoveValue(newConfiguration, kSCPropNetIPv4Addresses); } if (!(flags & allowIPv4Netmask)) { CFDictionaryRemoveValue(newConfiguration, kSCPropNetIPv4SubnetMasks); } if (!(flags & allowIPv4Router)) { CFDictionaryRemoveValue(newConfiguration, kSCPropNetIPv4Router); } if (!(flags & allowIPv4DHCPClientID)) { CFDictionaryRemoveValue(newConfiguration, kSCPropNetIPv4DHCPClientID); } } else { SCPrint(TRUE, stdout, CFSTR("unknown configuration method\n")); return -1; } return 0; } static int __doIPv4Addresses(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(description) #pragma unused(argc) Boolean useArray = (info == (void *)FALSE) ? FALSE : TRUE; if (strlen(argv[0]) > 0) { CFStringRef address; address = __copyIPv4Address(argv[0]); if (address != NULL) { if (useArray) { CFArrayRef addresses; addresses = CFArrayCreate(NULL, (const void **)&address, 1, &kCFTypeArrayCallBacks); CFDictionarySetValue(newConfiguration, key, addresses); CFRelease(addresses); } else { CFDictionarySetValue(newConfiguration, key, address); } CFRelease(address); } else { return -1; } } else { CFDictionaryRemoveValue(newConfiguration, key); } return 1; } static options ipv4Options[] = { { "ConfigMethod", "configuration method" , isChooseOne , &kSCPropNetIPv4ConfigMethod, __doIPv4ConfigMethod, (void *)ipv4ConfigMethods }, { "config" , "configuration method" , isChooseOne , &kSCPropNetIPv4ConfigMethod, __doIPv4ConfigMethod, (void *)ipv4ConfigMethods }, { "Addresses" , "address" , isOther , &kSCPropNetIPv4Addresses , __doIPv4Addresses , (void *)TRUE }, { "address" , "address" , isOther , &kSCPropNetIPv4Addresses , __doIPv4Addresses , (void *)TRUE }, { "SubnetMasks" , "netmask" , isOther , &kSCPropNetIPv4SubnetMasks , __doIPv4Addresses , (void *)TRUE }, { "netmask" , "netmask" , isOther , &kSCPropNetIPv4SubnetMasks , __doIPv4Addresses , (void *)TRUE }, { "Router" , "address" , isOther , &kSCPropNetIPv4Router , __doIPv4Addresses , (void *)FALSE }, { "DHCPClientID", "client ID", isString , &kSCPropNetIPv4DHCPClientID, NULL , NULL }, { "?" , NULL , isHelp , NULL , NULL , "\nIPv4 configuration commands\n\n" " set protocol config {BOOTP|DHCP|INFORM|MANUAL}\n" "\n w/config=BOOTP\n" " None\n" "\n w/config=DHCP\n" " set protocol dhcpclientid identifier\n" "\n w/config=INFORM\n" " set protocol address x.x.x.x\n" "\n w/config=MANUAL\n" " set protocol address x.x.x.x\n" " set protocol netmask x.x.x.x\n" " set protocol router x.x.x.x\n" } }; #define N_IPV4_OPTIONS (sizeof(ipv4Options) / sizeof(ipv4Options[0])) static Boolean set_protocol_ipv4(int argc, char **argv, CFMutableDictionaryRef newConfiguration) { Boolean ok; ok = _process_options(ipv4Options, N_IPV4_OPTIONS, argc, argv, newConfiguration); if (ok) { unsigned int flags; CFStringRef method; CFIndex methodIndex; // validate configuration method = CFDictionaryGetValue(newConfiguration, kSCPropNetIPv4ConfigMethod); methodIndex = _find_selection(method, (selections *)ipv4ConfigMethods, &flags); if (methodIndex == kCFNotFound) { SCPrint(TRUE, stdout, CFSTR("unknown configuration method\n")); return FALSE; } if (!(flags & allowIPv4Address) && CFDictionaryContainsKey(newConfiguration, kSCPropNetIPv4Addresses)) { SCPrint(TRUE, stdout, CFSTR("IP address not allowed with %@ configuration\n"), ipv4ConfigMethods[methodIndex].selection); return FALSE; } if (!(flags & allowIPv4Netmask) && CFDictionaryContainsKey(newConfiguration, kSCPropNetIPv4SubnetMasks)) { SCPrint(TRUE, stdout, CFSTR("Subnet mask not allowed with %@ configuration\n"), ipv4ConfigMethods[methodIndex].selection); return FALSE; } if (!(flags & allowIPv4Router) && CFDictionaryContainsKey(newConfiguration, kSCPropNetIPv4Router)) { SCPrint(TRUE, stdout, CFSTR("Default route not allowed with %@ configuration\n"), ipv4ConfigMethods[methodIndex].selection); return FALSE; } if (!(flags & allowIPv4DHCPClientID) && CFDictionaryContainsKey(newConfiguration, kSCPropNetIPv4DHCPClientID)) { SCPrint(TRUE, stdout, CFSTR("DHCP client ID not allowed with %@ configuration\n"), ipv4ConfigMethods[methodIndex].selection); return FALSE; } } return ok; } #pragma mark - #pragma mark IPv6 #define allowIPv6Address 1<<1 // allow address #define allowIPv6PrefixLength 1<<2 // allow prefix length #define allowIPv6Router 1<<3 // allow router static selections ipv6ConfigMethods[] = { { CFSTR("Automatic") , & kSCValNetIPv6ConfigMethodAutomatic , 0 }, { CFSTR("Manual") , & kSCValNetIPv6ConfigMethodManual , allowIPv6Address|allowIPv6PrefixLength|allowIPv6Router }, { CFSTR("RouterAdvertisement"), & kSCValNetIPv6ConfigMethodRouterAdvertisement, allowIPv6Address }, { CFSTR("6to4") , & kSCValNetIPv6ConfigMethod6to4 , 0 }, { NULL , NULL , 0 } }; static int __doIPv6ConfigMethod(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(description) #pragma unused(info) #pragma unused(argc) #pragma unused(argv) unsigned int flags; CFStringRef method; CFIndex methodIndex; method = CFDictionaryGetValue(newConfiguration, key); methodIndex = _find_selection(method, (selections *)ipv6ConfigMethods, &flags); if (methodIndex != kCFNotFound) { if (!(flags & allowIPv6Address)) { CFDictionaryRemoveValue(newConfiguration, kSCPropNetIPv6Addresses); } if (!(flags & allowIPv6PrefixLength)) { CFDictionaryRemoveValue(newConfiguration, kSCPropNetIPv6PrefixLength); } if (!(flags & allowIPv6Router)) { CFDictionaryRemoveValue(newConfiguration, kSCPropNetIPv6Router); } } else { SCPrint(TRUE, stdout, CFSTR("unknown configuration method\n")); return -1; } return 0; } static int __doIPv6Addresses(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(description) #pragma unused(argc) Boolean useArray = (info == (void *)FALSE) ? FALSE : TRUE; if (strlen(argv[0]) > 0) { CFStringRef address; address = __copyIPv6Address(argv[0]); if (address != NULL) { if (useArray) { CFArrayRef addresses; addresses = CFArrayCreate(NULL, (const void **)&address, 1, &kCFTypeArrayCallBacks); CFDictionarySetValue(newConfiguration, key, addresses); CFRelease(addresses); } else { CFDictionarySetValue(newConfiguration, key, address); } CFRelease(address); } else { return -1; } } else { CFDictionaryRemoveValue(newConfiguration, key); } return 1; } static options ipv6Options[] = { { "ConfigMethod", "configuration method" , isChooseOne, &kSCPropNetIPv6ConfigMethod, __doIPv6ConfigMethod, (void *)ipv6ConfigMethods }, { "config" , "configuration method" , isChooseOne, &kSCPropNetIPv6ConfigMethod, __doIPv6ConfigMethod, (void *)ipv6ConfigMethods }, { "Addresses" , "address" , isOther , &kSCPropNetIPv6Addresses , __doIPv6Addresses , (void *)TRUE }, { "address" , "address" , isOther , &kSCPropNetIPv6Addresses , __doIPv6Addresses , (void *)TRUE }, { "EnableCGA" , NULL , isBoolean , &kSCPropNetIPv6EnableCGA , NULL , NULL }, { "PrefixLength", "prefix length", isNumber , &kSCPropNetIPv6PrefixLength, NULL , NULL }, { "Router" , "address" , isOther , &kSCPropNetIPv6Router , __doIPv6Addresses , (void *)FALSE }, { "?" , NULL , isHelp , NULL , NULL , "\nIPv6 configuration commands\n\n" " set protocol config {Automatic|MANUAL}\n" "\n w/config=Automatic\n" " None\n" "\n w/config=MANUAL\n" " set protocol address x:x:x:x:x:x\n" " set protocol router x:x:x:x:x:x\n" " set protocol prefixlength n\n" } }; #define N_IPV6_OPTIONS (sizeof(ipv6Options) / sizeof(ipv6Options[0])) static Boolean set_protocol_ipv6(int argc, char **argv, CFMutableDictionaryRef newConfiguration) { Boolean ok; ok = _process_options(ipv6Options, N_IPV6_OPTIONS, argc, argv, newConfiguration); if (ok) { unsigned int flags; CFStringRef method; CFIndex methodIndex; // validate configuration method = CFDictionaryGetValue(newConfiguration, kSCPropNetIPv6ConfigMethod); methodIndex = _find_selection(method, (selections *)ipv6ConfigMethods, &flags); if (methodIndex == kCFNotFound) { SCPrint(TRUE, stdout, CFSTR("unknown configuration method\n")); return FALSE; } if (!(flags & allowIPv6Address) && CFDictionaryContainsKey(newConfiguration, kSCPropNetIPv6Addresses)) { SCPrint(TRUE, stdout, CFSTR("IP address not allowed with %@ configuration\n"), ipv6ConfigMethods[methodIndex].selection); return FALSE; } if (!(flags & allowIPv6PrefixLength) && CFDictionaryContainsKey(newConfiguration, kSCPropNetIPv6PrefixLength)) { SCPrint(TRUE, stdout, CFSTR("Prefix length not allowed with %@ configuration\n"), ipv6ConfigMethods[methodIndex].selection); return FALSE; } if (!(flags & allowIPv6Router) && CFDictionaryContainsKey(newConfiguration, kSCPropNetIPv6Router)) { SCPrint(TRUE, stdout, CFSTR("Router not allowed with %@ configuration\n"), ipv6ConfigMethods[methodIndex].selection); return FALSE; } } return ok; } #pragma mark - #pragma mark Proxies typedef const struct { const char *proxy; const CFStringRef *keyEnable; const CFStringRef *keyProxy; const CFStringRef *keyPort; const CFStringRef *keyURL; } proxyKeys; static proxyKeys proxyKeys_FTP = { "FTP" , &kSCPropNetProxiesFTPEnable , &kSCPropNetProxiesFTPProxy , &kSCPropNetProxiesFTPPort , NULL }; static proxyKeys proxyKeys_Gopher = { "Gopher", &kSCPropNetProxiesGopherEnable , &kSCPropNetProxiesGopherProxy, &kSCPropNetProxiesGopherPort, NULL }; static proxyKeys proxyKeys_HTTP = { "HTTP" , &kSCPropNetProxiesHTTPEnable , &kSCPropNetProxiesHTTPProxy , &kSCPropNetProxiesHTTPPort , NULL }; static proxyKeys proxyKeys_HTTPS = { "HTTPS" , &kSCPropNetProxiesHTTPSEnable , &kSCPropNetProxiesHTTPSProxy , &kSCPropNetProxiesHTTPSPort , NULL }; static proxyKeys proxyKeys_RTSP = { "RTSP" , &kSCPropNetProxiesRTSPEnable , &kSCPropNetProxiesRTSPProxy , &kSCPropNetProxiesRTSPPort , NULL }; static proxyKeys proxyKeys_SOCKS = { "SOCKS" , &kSCPropNetProxiesSOCKSEnable , &kSCPropNetProxiesSOCKSProxy , &kSCPropNetProxiesSOCKSPort , NULL }; static proxyKeys proxyKeys_PAC = { ".pac" , &kSCPropNetProxiesProxyAutoConfigEnable , NULL , NULL , &kSCPropNetProxiesProxyAutoConfigURLString }; static proxyKeys proxyKeys_WPAD = { "WPAD" , &kSCPropNetProxiesProxyAutoDiscoveryEnable, NULL , NULL , NULL }; static proxyKeys *currentProxy = NULL; static int __doProxySelect (CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration); static int __doProxyEnable (CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration); static int __doProxyHost (CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration); static int __doProxyPort (CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration); static int __doProxyURL (CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration); static int __doProxyFTPPassive(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration); static options proxyOptions[] = { // general options { "ExceptionsList" , "exceptions", isStringArray, &kSCPropNetProxiesExceptionsList , NULL , NULL }, { "ExcludeSimpleHostnames", NULL , isBoolean , &kSCPropNetProxiesExcludeSimpleHostnames, NULL , NULL }, // proxy selection { "FTP" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_FTP }, { "Gopher" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_Gopher }, { "HTTP" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_HTTP }, { "HTTPS" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_HTTPS }, { "RTSP" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_RTSP }, { "SOCKS" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_SOCKS }, { "ProxyAutoConfig" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_PAC }, { ".pac" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_PAC }, { "ProxyAutoDiscovery" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_WPAD }, { "WPAD" , NULL , isOther , NULL , __doProxySelect , (void *)&proxyKeys_WPAD }, // proxy modifiers { "disable" , NULL , isOther , NULL , __doProxyEnable , (void *)FALSE }, { "enable" , NULL , isOther , NULL , __doProxyEnable , (void *)TRUE }, { "proxy" , NULL , isOther , NULL , __doProxyHost , NULL }, { "host" , NULL , isOther , NULL , __doProxyHost , NULL }, { "port" , NULL , isOther , NULL , __doProxyPort , NULL }, { "url" , NULL , isOther , NULL , __doProxyURL , NULL }, // (ftp) proxy modifiers { "FTPPassive" , NULL , isBoolean , &kSCPropNetProxiesFTPPassive , __doProxyFTPPassive, NULL }, { "passive" , NULL , isBoolean , &kSCPropNetProxiesFTPPassive , __doProxyFTPPassive, NULL }, // help { "?" , NULL , isHelp , NULL , NULL , "\nProxy configuration commands\n\n" " set protocol ExceptionsList exception[,exception-2]\n" " set protocol ExcludeSimpleHostnames {enable|disable}\n" "\n" " set protocol ftp {enable|disable}\n" " set protocol ftp host proxy-host\n" " set protocol ftp port proxy-port\n" " set protocol ftp passive {enable|disable}\n" "\n" " set protocol http {enable|disable}\n" " set protocol http host proxy-host\n" " set protocol http port proxy-port\n" "\n" " set protocol https {enable|disable}\n" " set protocol https host proxy-host\n" " set protocol https port proxy-port\n" "\n" " set protocol rtsp {enable|disable}\n" " set protocol rtsp host proxy-host\n" " set protocol rtsp port proxy-port\n" "\n" " set protocol socks {enable|disable}\n" " set protocol socks host proxy-host\n" " set protocol socks port proxy-port\n" "\n" " set protocol .pac {enable|disable}\n" " set protocol .pac url .pac-url\n" "\n" " set protocol wpad {enable|disable}\n" } }; #define N_PROXY_OPTIONS (sizeof(proxyOptions) / sizeof(proxyOptions[0])) static int __doProxySelect(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(key) #pragma unused(description) #pragma unused(newConfiguration) CFIndex nextOption; if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("proxy option[s] not specified\n")); return -1; } currentProxy = (proxyKeys *)info; nextOption = _find_option(argv[0], proxyOptions, N_PROXY_OPTIONS); if ((nextOption == kCFNotFound) || (proxyOptions[nextOption].handler == __doProxySelect)) { SCPrint(TRUE, stdout, CFSTR("%s proxy option[s] not specified\n"), currentProxy->proxy); return -1; } return 0; } static int __doProxyEnable(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(key) #pragma unused(description) #pragma unused(argc) #pragma unused(argv) Boolean enabled = (info == (void *)FALSE) ? FALSE : TRUE; if (currentProxy == NULL) { SCPrint(TRUE, stdout, CFSTR("proxy not specified\n")); return -1; } if (currentProxy->keyEnable == NULL) { SCPrint(TRUE, stdout, CFSTR("%s proxy cannot be %s\n"), currentProxy->proxy, enabled ? "enabled" : "disabled"); return -1; } if (enabled) { CFDictionarySetValue(newConfiguration, *(currentProxy->keyEnable), CFNumberRef_1); } else { CFDictionaryRemoveValue(newConfiguration, *(currentProxy->keyEnable)); if (currentProxy->keyProxy != NULL) { CFDictionaryRemoveValue(newConfiguration, *(currentProxy->keyProxy)); } if (currentProxy->keyPort != NULL) { CFDictionaryRemoveValue(newConfiguration, *(currentProxy->keyPort)); } if (currentProxy->keyURL != NULL) { CFDictionaryRemoveValue(newConfiguration, *(currentProxy->keyURL)); } } return 0; } static Boolean __proxy_enabled(CFDictionaryRef configuration, const CFStringRef *enableKey) { CFNumberRef num; int val; if (enableKey == NULL) { return TRUE; // if proxy does not need to be enabled } num = CFDictionaryGetValue(configuration, *enableKey); if (!isA_CFNumber(num) || !CFNumberGetValue(num, kCFNumberIntType, &val) || (val == 0)) { return FALSE; // if not enabled } return TRUE; } static int __doProxyHost(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(key) #pragma unused(description) #pragma unused(info) if (currentProxy == NULL) { SCPrint(TRUE, stdout, CFSTR("proxy not specified\n")); return -1; } if (currentProxy->keyProxy == NULL) { SCPrint(TRUE, stdout, CFSTR("%s proxy host cannot be specified\n"), currentProxy->proxy); return -1; } if (!__proxy_enabled(newConfiguration, currentProxy->keyEnable)) { SCPrint(TRUE, stdout, CFSTR("%s proxy not enabled\n"), currentProxy->proxy); return -1; } if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("%s proxy host not specified\n"), currentProxy->proxy); return -1; } if (strlen(argv[0]) > 0) { CFStringRef host; host = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); CFDictionarySetValue(newConfiguration, *(currentProxy->keyProxy), host); CFRelease(host); } else { CFDictionaryRemoveValue(newConfiguration, *(currentProxy->keyProxy)); } return 1; } static int __doProxyPort(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(key) #pragma unused(description) #pragma unused(info) if (currentProxy == NULL) { SCPrint(TRUE, stdout, CFSTR("proxy not specified\n")); return -1; } if (currentProxy->keyPort == NULL) { SCPrint(TRUE, stdout, CFSTR("%s proxy port cannot be specified\n"), currentProxy->proxy); return -1; } if (!__proxy_enabled(newConfiguration, currentProxy->keyEnable)) { SCPrint(TRUE, stdout, CFSTR("%s proxy not enabled\n"), currentProxy->proxy); return -1; } if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("%s proxy port not specified\n"), currentProxy->proxy); return -1; } if (strlen(argv[0]) > 0) { CFNumberRef num; int port; num = _copy_number(argv[0]); if (!isA_CFNumber(num) || !CFNumberGetValue(num, kCFNumberIntType, &port) || (port < 0) || (port > 65535)) { SCPrint(TRUE, stdout, CFSTR("invalid %s proxy port number\n"), currentProxy->proxy); if (num != NULL) CFRelease(num); return -1; } CFDictionarySetValue(newConfiguration, *(currentProxy->keyPort), num); CFRelease(num); } else { CFDictionaryRemoveValue(newConfiguration, *(currentProxy->keyPort)); } return 1; } static int __doProxyURL(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(key) #pragma unused(description) #pragma unused(info) if (currentProxy == NULL) { SCPrint(TRUE, stdout, CFSTR("proxy not specified\n")); return -1; } if (currentProxy->keyURL == NULL) { SCPrint(TRUE, stdout, CFSTR("%s proxy URL cannot be specified\n"), currentProxy->proxy); return -1; } if (!__proxy_enabled(newConfiguration, currentProxy->keyEnable)) { SCPrint(TRUE, stdout, CFSTR("%s proxy not enabled\n"), currentProxy->proxy); return -1; } if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("%s proxy URL not specified\n"), currentProxy->proxy); return -1; } if (strlen(argv[0]) > 0) { CFStringRef url; url = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); CFDictionarySetValue(newConfiguration, *(currentProxy->keyURL), url); CFRelease(url); } else { CFDictionaryRemoveValue(newConfiguration, *(currentProxy->keyURL)); } return 1; } static int __doProxyFTPPassive(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(key) #pragma unused(description) #pragma unused(info) #pragma unused(argc) #pragma unused(argv) #pragma unused(newConfiguration) if (currentProxy == NULL) { SCPrint(TRUE, stdout, CFSTR("proxy not specified\n")); return -1; } if (currentProxy != &proxyKeys_FTP) { SCPrint(TRUE, stdout, CFSTR("passive can only be enable for FTP proxy\n")); return -1; } return 0; } static Boolean set_protocol_proxies(int argc, char **argv, CFMutableDictionaryRef newConfiguration) { Boolean ok; ok = _process_options(proxyOptions, N_PROXY_OPTIONS, argc, argv, newConfiguration); return ok; } #pragma mark - #pragma mark SMB #if !TARGET_OS_IPHONE static CF_RETURNS_RETAINED CFStringRef __cleanupName(CFStringRef name) { CFMutableStringRef newName; newName = CFStringCreateMutableCopy(NULL, 0, name); CFStringTrimWhitespace(newName); if (CFStringGetLength(newName) == 0) { CFRelease(newName); newName = NULL; } return newName; } static int __doSMBName(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(description) #pragma unused(info) if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("NetBIOS name not specified\n")); return -1; } if (strlen(argv[0]) > 0) { CFStringRef name; CFStringRef str; str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); name = __cleanupName(str); CFRelease(str); if (name != NULL) { CFDictionarySetValue(newConfiguration, key, name); CFRelease(name); } else { SCPrint(TRUE, stdout, CFSTR("invalid NetBIOS name\n")); return -1; } } else { CFDictionaryRemoveValue(newConfiguration, key); } return 1; } static int __doSMBWorkgroup(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(description) #pragma unused(info) if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("Workgroup not specified\n")); return -1; } if (strlen(argv[0]) > 0) { CFStringRef name; CFStringRef str; str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); name = __cleanupName(str); CFRelease(str); if (name != NULL) { CFDictionarySetValue(newConfiguration, key, name); CFRelease(name); } else { SCPrint(TRUE, stdout, CFSTR("invalid Workgroup\n")); return -1; } } else { CFDictionaryRemoveValue(newConfiguration, key); } return 1; } static int __doSMBWINSAddresses(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) { #pragma unused(description) #pragma unused(info) CFMutableArrayRef servers; if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("WINS address(es) not specified\n")); return -1; } servers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); if (strlen(argv[0]) > 0) { CFArrayRef array; CFIndex i; CFIndex n; CFStringRef str; str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); array = CFStringCreateArrayBySeparatingStrings(NULL, str, CFSTR(",")); CFRelease(str); n = (array != NULL) ? CFArrayGetCount(array) : 0; for (i = 0; i < n; i++) { char str[32]; if (_SC_cfstring_to_cstring(CFArrayGetValueAtIndex(array, i), str, sizeof(str), kCFStringEncodingUTF8) != NULL) { CFStringRef server; server = __copyIPv4Address(str); //if (server == NULL) { // server = __copyIPv6Address(str); //} if (server != NULL) { CFArrayAppendValue(servers, server); CFRelease(server); continue; } } SCPrint(TRUE, stdout, CFSTR("invalid WINS address\n")); CFRelease(array); CFRelease(servers); return -1; } if (array != NULL) CFRelease(array); } if (CFArrayGetCount(servers) > 0) { CFDictionarySetValue(newConfiguration, key, servers); } else { CFDictionaryRemoveValue(newConfiguration, key); } CFRelease(servers); return 1; } static selections smbNodeTypes[] = { { CFSTR("Broadcast"), &kSCValNetSMBNetBIOSNodeTypeBroadcast, 0 }, { CFSTR("Peer") , &kSCValNetSMBNetBIOSNodeTypePeer , 0 }, { CFSTR("Mixed") , &kSCValNetSMBNetBIOSNodeTypeMixed , 0 }, { CFSTR("Hybrid") , &kSCValNetSMBNetBIOSNodeTypeHybrid , 0 }, { NULL , NULL , 0 } }; static options smbOptions[] = { { "NetBIOSName" , "name" , isOther , &kSCPropNetSMBNetBIOSName , __doSMBName , NULL }, { "name" , "name" , isOther , &kSCPropNetSMBNetBIOSName , __doSMBName , NULL }, { "NetBIOSNodeType", "type" , isChooseOne, &kSCPropNetSMBNetBIOSNodeType, NULL , (void *)smbNodeTypes }, { "type", "type" , isChooseOne, &kSCPropNetSMBNetBIOSNodeType, NULL , (void *)smbNodeTypes }, { "Workgroup" , "workgroup", isOther , &kSCPropNetSMBWorkgroup , __doSMBWorkgroup , NULL }, { "WINSAddresses" , "wins" , isOther , &kSCPropNetSMBWINSAddresses , __doSMBWINSAddresses, NULL }, { "wins" , "wins" , isOther , &kSCPropNetSMBWINSAddresses , __doSMBWINSAddresses, NULL }, { "?" , NULL , isHelp , NULL , NULL, "\nSMB configuration commands\n\n" " set protocol name NetBIOS-name\n" " set protocol type (Broadcast|Peer|Mixed|Hybrid)\n" " set protocol workgroup SMB-workgroup\n" " set protocol wins x1.x1.x1.x1[,x2.x2.x2.x2]\n" } }; #define N_SMB_OPTIONS (sizeof(smbOptions) / sizeof(smbOptions[0])) static Boolean set_protocol_smb(int argc, char **argv, CFMutableDictionaryRef newConfiguration) { Boolean ok; ok = _process_options(smbOptions, N_SMB_OPTIONS, argc, argv, newConfiguration); return ok; } #endif // !TARGET_OS_IPHONE #pragma mark - #pragma mark *Protocol* __private_extern__ void set_protocol(int argc, char **argv) { CFDictionaryRef configuration; CFMutableDictionaryRef newConfiguration = NULL; Boolean ok = FALSE; CFStringRef protocolType; if (net_protocol == NULL) { SCPrint(TRUE, stdout, CFSTR("protocol not selected\n")); return; } if (argc < 1) { SCPrint(TRUE, stdout, CFSTR("set what?\n")); return; } configuration = SCNetworkProtocolGetConfiguration(net_protocol); if (configuration == NULL) { newConfiguration = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } else { newConfiguration = CFDictionaryCreateMutableCopy(NULL, 0, configuration); CFDictionaryRemoveValue(newConfiguration, kSCResvInactive); } protocolType = SCNetworkProtocolGetProtocolType(net_protocol); if (CFEqual(protocolType, kSCNetworkProtocolTypeDNS)) { ok = set_protocol_dns(argc, argv, newConfiguration); } else if (CFEqual(protocolType, kSCNetworkProtocolTypeIPv4)) { ok = set_protocol_ipv4(argc, argv, newConfiguration); } else if (CFEqual(protocolType, kSCNetworkProtocolTypeIPv6)) { ok = set_protocol_ipv6(argc, argv, newConfiguration); } else if (CFEqual(protocolType, kSCNetworkProtocolTypeProxies)) { ok = set_protocol_proxies(argc, argv, newConfiguration); #if !TARGET_OS_IPHONE } else if (CFEqual(protocolType, kSCNetworkProtocolTypeSMB)) { ok = set_protocol_smb(argc, argv, newConfiguration); #endif // !TARGET_OS_IPHONE } else { SCPrint(TRUE, stdout, CFSTR("this protocols configuration cannot be changed\n")); } if (!ok) { goto done; } if (((configuration == NULL) && (CFDictionaryGetCount(newConfiguration) > 0)) || ((configuration != NULL) && !CFEqual(configuration, newConfiguration))) { if (!SCNetworkProtocolSetConfiguration(net_protocol, newConfiguration)) { SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError())); goto done; } _prefs_changed = TRUE; } done : if (newConfiguration != NULL) CFRelease(newConfiguration); return; } /* -------------------- */ __private_extern__ void show_protocol(int argc, char **argv) { CFDictionaryRef configuration; SCNetworkProtocolRef protocol = NULL; CFStringRef protocolType; if (argc > 0) { protocol = _find_protocol(argv[0]); } else { if (net_protocol != NULL) { protocol = net_protocol; } else { SCPrint(TRUE, stdout, CFSTR("protocol not selected\n")); return; } } if (protocol == NULL) { return; } protocolType = SCNetworkProtocolGetProtocolType(protocol); SCPrint(TRUE, stdout, CFSTR("protocol type = %@\n"), protocolType); configuration = SCNetworkProtocolGetConfiguration(protocol); if (configuration != NULL) { SCPrint(TRUE, stdout, CFSTR("\n protocol configuration\n")); _show_entity(configuration, CFSTR("")); } if (_sc_debug) { SCPrint(TRUE, stdout, CFSTR("\n%@\n"), protocol); } return; } /* -------------------- */ __private_extern__ void show_protocols(int argc, char **argv) { #pragma unused(argc) #pragma unused(argv) CFIndex i; CFIndex n; if (prefs == NULL) { SCPrint(TRUE, stdout, CFSTR("network configuration not open\n")); return; } if (net_service == NULL) { SCPrint(TRUE, stdout, CFSTR("service not selected\n")); return; } if (protocols != NULL) CFRelease(protocols); protocols = SCNetworkServiceCopyProtocols(net_service); if (protocols == NULL) { SCPrint(TRUE, stdout, CFSTR("%s\n"), SCErrorString(SCError())); return; } n = CFArrayGetCount(protocols); if (n > 1) { CFMutableArrayRef sorted; sorted = CFArrayCreateMutableCopy(NULL, 0, protocols); CFArraySortValues(sorted, CFRangeMake(0, n), _SCNetworkProtocolCompare, NULL); CFRelease(protocols); protocols = sorted; } for (i = 0; i < n; i++) { SCNetworkProtocolRef protocol; CFStringRef protocolType; protocol = CFArrayGetValueAtIndex(protocols, i); protocolType = SCNetworkProtocolGetProtocolType(protocol); SCPrint(TRUE, stdout, CFSTR("%c%2ld: %@%*s :"), ((net_protocol != NULL) && CFEqual(protocol, net_protocol)) ? '>' : ' ', i + 1, protocolType, (int)(sizeof("Proxies") - CFStringGetLength(protocolType) - 1), ""); if (SCNetworkProtocolGetEnabled(protocol)) { CFStringRef description; description = _protocol_description(protocol, FALSE); SCPrint(TRUE, stdout, CFSTR(" %@"), description); CFRelease(description); } else { SCPrint(TRUE, stdout, CFSTR(" *DISABLED*")); } SCPrint(TRUE, stdout, CFSTR("\n")); } return; } /* -------------------- */ __private_extern__ CF_RETURNS_RETAINED CFStringRef _protocol_description(SCNetworkProtocolRef protocol, Boolean skipEmpty) { CFDictionaryRef configuration; CFMutableStringRef description = NULL; CFStringRef protocolType; description = CFStringCreateMutable(NULL, 0); if (!SCNetworkProtocolGetEnabled(protocol)) { goto done; } configuration = SCNetworkProtocolGetConfiguration(protocol); if (configuration == NULL) { goto done; } protocolType = SCNetworkProtocolGetProtocolType(protocol); if (CFEqual(protocolType, kSCNetworkProtocolTypeDNS)) { CFStringRef domain; CFArrayRef search; CFArrayRef servers; domain = CFDictionaryGetValue(configuration, kSCPropNetDNSDomainName); if (isA_CFString(domain)) { CFStringAppendFormat(description, NULL, CFSTR("domain=%@"), domain); } search = CFDictionaryGetValue(configuration, kSCPropNetDNSSearchDomains); if (isA_CFArray(search)) { CFStringRef str; str = CFStringCreateByCombiningStrings(NULL, search, CFSTR(",")); CFStringAppendFormat(description, NULL, CFSTR("%ssearch=%@"), CFStringGetLength(description) > 0 ? ", " : "", str); CFRelease(str); } servers = CFDictionaryGetValue(configuration, kSCPropNetDNSServerAddresses); if (isA_CFArray(servers)) { CFStringRef str; str = CFStringCreateByCombiningStrings(NULL, servers, CFSTR(",")); CFStringAppendFormat(description, NULL, CFSTR("%sservers=%@"), CFStringGetLength(description) > 0 ? ", " : "", str); CFRelease(str); } } else if (CFEqual(protocolType, kSCNetworkProtocolTypeIPv4)) { CFStringRef method; method = CFDictionaryGetValue(configuration, kSCPropNetIPv4ConfigMethod); if (isA_CFString(method)) { CFArrayRef addresses; addresses = CFDictionaryGetValue(configuration, kSCPropNetIPv4Addresses); if (CFEqual(method, kSCValNetIPv4ConfigMethodINFORM) && isA_CFArray(addresses)) { CFStringAppendFormat(description, NULL, CFSTR("%@, address=%@"), method, CFArrayGetValueAtIndex(addresses, 0)); } else if (CFEqual(method, kSCValNetIPv4ConfigMethodManual) && isA_CFArray(addresses)) { CFArrayRef masks; CFStringRef router; CFStringAppendFormat(description, NULL, CFSTR("%@, address=%@"), method, CFArrayGetValueAtIndex(addresses, 0)); if (CFDictionaryGetValueIfPresent(configuration, kSCPropNetIPv4SubnetMasks, (const void **)&masks) && isA_CFArray(masks)) { CFStringAppendFormat(description, NULL, CFSTR(", mask=%@"), CFArrayGetValueAtIndex(masks, 0)); } if (CFDictionaryGetValueIfPresent(configuration, kSCPropNetIPv4Router, (const void **)&router) && isA_CFString(router)) { CFStringAppendFormat(description, NULL, CFSTR(", router=%@"), router); } } else { CFStringAppendFormat(description, NULL, CFSTR("%@"), method); } } } else if (CFEqual(protocolType, kSCNetworkProtocolTypeIPv6)) { CFStringRef method; method = CFDictionaryGetValue(configuration, kSCPropNetIPv6ConfigMethod); if (isA_CFString(method)) { CFStringAppendFormat(description, NULL, CFSTR("%@"), method); } } else if (CFEqual(protocolType, kSCNetworkProtocolTypeProxies)) { static proxyKeys *keys[] = { &proxyKeys_FTP, &proxyKeys_Gopher, &proxyKeys_HTTP, &proxyKeys_HTTPS, &proxyKeys_RTSP, &proxyKeys_SOCKS, &proxyKeys_PAC, &proxyKeys_WPAD }; for (size_t i = 0; i < sizeof(keys)/sizeof(keys[0]); i++) { proxyKeys *currentProxy = keys[i]; if (!__proxy_enabled(configuration, currentProxy->keyEnable)) { continue; } if (((currentProxy->keyProxy != NULL) && !CFDictionaryContainsKey(configuration, *(currentProxy->keyProxy))) || ((currentProxy->keyURL != NULL) && !CFDictionaryContainsKey(configuration, *(currentProxy->keyURL)))) { continue; } CFStringAppendFormat(description, NULL, CFSTR("%s%s"), CFStringGetLength(description) > 0 ? ", " : "", currentProxy->proxy); } #if !TARGET_OS_IPHONE } else if (CFEqual(protocolType, kSCNetworkProtocolTypeSMB)) { CFStringRef name; CFArrayRef servers; CFStringRef workgroup; name = CFDictionaryGetValue(configuration, kSCPropNetSMBNetBIOSName); if (isA_CFString(name)) { CFStringAppendFormat(description, NULL, CFSTR("NetBIOS name=%@"), name); } workgroup = CFDictionaryGetValue(configuration, kSCPropNetSMBWorkgroup); if (isA_CFString(workgroup)) { CFStringAppendFormat(description, NULL, CFSTR("Workgroup=%@"), workgroup); } servers = CFDictionaryGetValue(configuration, kSCPropNetSMBWINSAddresses); if (isA_CFArray(servers)) { CFStringRef str; str = CFStringCreateByCombiningStrings(NULL, servers, CFSTR(",")); CFStringAppendFormat(description, NULL, CFSTR("%sWINS servers=%@"), CFStringGetLength(description) > 0 ? ", " : "", str); CFRelease(str); } #endif // !TARGET_OS_IPHONE } done : if (skipEmpty && CFStringGetLength(description) == 0) { CFRelease(description); description = NULL; } return description; }