/*
- * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2014 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,
* 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@
*/
#include <ctype.h>
#include <SystemConfiguration/SCPrivate.h>
#include <notify.h>
+
+#ifdef MAIN
+#define my_log(__level, fmt, ...) SCPrint(TRUE, stdout, CFSTR(fmt "\n"), ## __VA_ARGS__)
+#else // MAIN
#include "ip_plugin.h"
+#endif // MAIN
static SCDynamicStoreRef store = NULL;
static CFRunLoopSourceRef rls = NULL;
-static Boolean dnsActive = FALSE;
-static CFMachPortRef dnsPort = NULL;
-static struct timeval dnsQueryStart;
+static struct timeval ptrQueryStart;
+static SCNetworkReachabilityRef ptrTarget = NULL;
static Boolean _verbose = FALSE;
old_name[sizeof(old_name)-1] = '\0';
new_name[sizeof(new_name)-1] = '\0';
if (strcmp(old_name, new_name) != 0) {
- if (sethostname(new_name, strlen(new_name)) == 0) {
+ if (sethostname(new_name, (int)strlen(new_name)) == 0) {
uint32_t status;
my_log(LOG_NOTICE,
status = notify_post(HOSTNAME_NOTIFY_KEY);
if (status != NOTIFY_STATUS_OK) {
my_log(LOG_ERR,
- "notify_post(" HOSTNAME_NOTIFY_KEY ") failed: error=%lu",
+ "notify_post(" HOSTNAME_NOTIFY_KEY ") failed: error=%u",
status);
}
} else {
my_log(LOG_ERR,
- "sethostname(%s, %d) failed: %s",
+ "sethostname(%s, %ld) failed: %s",
new_name,
strlen(new_name),
strerror(errno));
}
-#define HOSTCONFIG "/etc/hostconfig"
-#define HOSTNAME_KEY "HOSTNAME="
-#define AUTOMATIC "-AUTOMATIC-"
-
-#define HOSTNAME_KEY_LEN (sizeof(HOSTNAME_KEY) - 1)
-
-static CFStringRef
-copy_static_name()
-{
- FILE * f;
- char buf[256];
- CFStringRef name = NULL;
-
- f = fopen(HOSTCONFIG, "r");
- if (f == NULL) {
- return NULL;
- }
-
- while (fgets(buf, sizeof(buf), f) != NULL) {
- char * bp;
- int n;
- char * np;
- Boolean str_escape;
- Boolean str_quote;
-
- n = strlen(buf);
- if (buf[n-1] == '\n') {
- /* the entire line fit in the buffer, remove the newline */
- buf[n-1] = '\0';
- } else {
- /* eat the remainder of the line */
- do {
- n = fgetc(f);
- } while ((n != '\n') && (n != EOF));
- }
-
- // skip leading white space
- bp = &buf[0];
- while (isspace(*bp)) {
- bp++;
- }
-
- // find "HOSTNAME=" key
- if (strncmp(bp, HOSTNAME_KEY, HOSTNAME_KEY_LEN) != 0) {
- continue; // if not
- }
-
- // get the hostname string
- bp += HOSTNAME_KEY_LEN;
- str_escape = FALSE;
- str_quote = FALSE;
-
- np = &buf[0];
- while (*bp != '\0') {
- char ch = *bp;
-
- switch (ch) {
- case '\\' :
- if (!str_escape) {
- str_escape = TRUE;
- bp++;
- continue;
- }
- break;
- case '"' :
- if (!str_escape) {
- str_quote = !str_quote;
- bp++;
- continue;
- }
- break;
- default :
- break;
- }
-
- if (str_escape) {
- str_escape = FALSE;
- } else if (!str_quote && (isspace(ch) || (ch == '#'))) {
- break;
- }
-
- *np++ = ch;
- bp++;
- }
-
- *np = '\0';
-
- if (name != NULL) {
- CFRelease(name);
- name = NULL;
- }
-
- if (str_quote) {
- // the shell won't parse this file so neither will we
- break;
- }
-
- if (strcmp(buf, AUTOMATIC) == 0) {
- // skip "-AUTOMATIC-"
- continue;
- }
-
- name = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8);
- }
-
- (void) fclose(f);
- return name;
-}
-
-
static CFStringRef
copy_prefs_hostname(SCDynamicStoreRef store)
{
return address;
}
+
static void
-reverseDNSComplete(int32_t status, char *host, char *serv, void *context)
+ptr_query_stop()
{
- struct timeval dnsQueryComplete;
- struct timeval dnsQueryElapsed;
- CFStringRef hostname;
- SCDynamicStoreRef store = (SCDynamicStoreRef)context;
+ if (ptrTarget == NULL) {
+ return;
+ }
+
+ SCNetworkReachabilitySetCallback(ptrTarget, NULL, NULL);
+ SCNetworkReachabilityUnscheduleFromRunLoop(ptrTarget, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+ CFRelease(ptrTarget);
+ ptrTarget = NULL;
- (void) gettimeofday(&dnsQueryComplete, NULL);
- timersub(&dnsQueryComplete, &dnsQueryStart, &dnsQueryElapsed);
+ return;
+}
+
+
+static void
+ptr_query_callback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info)
+{
+ CFStringRef hostname = NULL;
+ struct timeval ptrQueryComplete;
+ struct timeval ptrQueryElapsed;
+
+ (void) gettimeofday(&ptrQueryComplete, NULL);
+ timersub(&ptrQueryComplete, &ptrQueryStart, &ptrQueryElapsed);
if (_verbose) {
- my_log(LOG_INFO, "async DNS complete%s (query time = %d.%3.3d)",
- ((status == 0) && (host != NULL)) ? "" : ", host not found",
- dnsQueryElapsed.tv_sec,
- dnsQueryElapsed.tv_usec / 1000);
+ my_log(LOG_DEBUG, "ptr query complete%s (query time = %ld.%3.3d)",
+ (flags & kSCNetworkReachabilityFlagsReachable) ? "" : ", host not found",
+ ptrQueryElapsed.tv_sec,
+ ptrQueryElapsed.tv_usec / 1000);
}
// use reverse DNS name, if available
- switch (status) {
- case 0 :
- /*
- * if [reverse] DNS query was successful
- */
- if (host != NULL) {
- hostname = CFStringCreateWithCString(NULL, host, kCFStringEncodingUTF8);
- if (hostname != NULL) {
- my_log(LOG_INFO, "hostname (reverse DNS query) = %@", hostname);
- set_hostname(hostname);
- CFRelease(hostname);
- goto done;
- }
+ if (flags & kSCNetworkReachabilityFlagsReachable) {
+ int error_num;
+ CFArrayRef hosts;
+
+ /*
+ * if [reverse] DNS query was successful
+ */
+ hosts = SCNetworkReachabilityCopyResolvedAddress(target, &error_num);
+ if (hosts != NULL) {
+ if (CFArrayGetCount(hosts) > 0) {
+
+ hostname = CFArrayGetValueAtIndex(hosts, 0);
+ my_log(LOG_DEBUG, "hostname (reverse DNS query) = %@", hostname);
+ set_hostname(hostname);
+ }
+ CFRelease(hosts);
+
+ if (hostname != NULL) {
+ goto done;
}
- break;
-
- case EAI_NONAME :
-#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
- case EAI_NODATA:
-#endif
- /*
- * if no name available
- */
- break;
-
- default :
- /*
- * Hmmmm...
- */
- my_log(LOG_ERR, "getnameinfo() failed: %s", gai_strerror(status));
+ }
}
// get local (multicast DNS) name, if available
if (hostname != NULL) {
CFMutableStringRef localName;
- my_log(LOG_INFO, "hostname (multicast DNS) = %@", hostname);
+ my_log(LOG_DEBUG, "hostname (multicast DNS) = %@", hostname);
localName = CFStringCreateMutableCopy(NULL, 0, hostname);
assert(localName != NULL);
CFStringAppend(localName, CFSTR(".local"));
done :
- if (host != NULL) free(host);
- if (serv != NULL) free(serv);
- dnsActive = FALSE;
- return;
-}
-
-
-static CFStringRef
-replyMPCopyDescription(const void *info)
-{
- SCDynamicStoreRef store = (SCDynamicStoreRef)info;
-
- return CFStringCreateWithFormat(NULL,
- NULL,
- CFSTR("<getnameinfo_async_start reply MP> {store = %p}"),
- store);
-}
-
-
-static void
-getnameinfo_async_handleCFReply(CFMachPortRef port, void *msg, CFIndex size, void *info)
-{
- mach_port_t mp = MACH_PORT_NULL;
- int32_t status;
-
- if (port != dnsPort) {
- // we've received a callback on the async DNS port but since the
- // associated CFMachPort doesn't match than the request must have
- // already been cancelled.
- my_log(LOG_ERR, "getnameinfo_async_handleCFReply(): port != dnsPort");
- return;
- }
+ ptr_query_stop();
- mp = CFMachPortGetPort(port);
- CFMachPortInvalidate(dnsPort);
- CFRelease(dnsPort);
- dnsPort = NULL;
- __MACH_PORT_DEBUG(mp != MACH_PORT_NULL, "*** set-hostname (after unscheduling)", mp);
-
- status = getnameinfo_async_handle_reply(msg);
- __MACH_PORT_DEBUG(mp != MACH_PORT_NULL, "*** set-hostname (after getnameinfo_async_handle_reply)", mp);
- if ((status == 0) && dnsActive && (mp != MACH_PORT_NULL)) {
- CFMachPortContext context = { 0
- , (void *)store
- , CFRetain
- , CFRelease
- , replyMPCopyDescription
- };
- CFRunLoopSourceRef rls;
-
- // if request has been re-queued
- dnsPort = _SC_CFMachPortCreateWithPort("IPMonitor/set-hostname/re-queue",
- mp,
- getnameinfo_async_handleCFReply,
- &context);
- rls = CFMachPortCreateRunLoopSource(NULL, dnsPort, 0);
- CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
- CFRelease(rls);
- __MACH_PORT_DEBUG(mp != MACH_PORT_NULL, "*** set-hostname (after rescheduling)", mp);
- }
+#ifdef MAIN
+ CFRunLoopStop(CFRunLoopGetCurrent());
+#endif // MAIN
return;
}
-static void
-start_dns_query(SCDynamicStoreRef store, CFStringRef address)
+static Boolean
+ptr_query_start(CFStringRef address)
{
union {
- struct sockaddr sa;
- struct sockaddr_in sin;
- struct sockaddr_in6 sin6;
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
} addr;
char buf[64];
- SCNetworkReachabilityFlags flags;
- Boolean haveDNS;
- Boolean ok;
+ CFDataRef data;
+ CFMutableDictionaryRef options;
if (_SC_cfstring_to_cstring(address, buf, sizeof(buf), kCFStringEncodingASCII) == NULL) {
- my_log(LOG_ERR, "could not convert [primary] address");
- return;
+ my_log(LOG_ERR, "could not convert [primary] address string");
+ return FALSE;
}
if (_SC_string_to_sockaddr(buf, AF_UNSPEC, (void *)&addr, sizeof(addr)) == NULL) {
- /* if not an IP[v6] address */
- my_log(LOG_ERR, "could not parse [primary] address");
- return;
- }
-
- ok = _SC_checkResolverReachabilityByAddress(&store, &flags, &haveDNS, &addr.sa);
- if (ok) {
- if (!(flags & kSCNetworkReachabilityFlagsReachable) ||
- (flags & kSCNetworkReachabilityFlagsConnectionRequired)) {
- // if not reachable *OR* connection required
- ok = FALSE;
- }
+ my_log(LOG_ERR, "could not convert [primary] address");
+ return FALSE;
}
- if (ok) {
- CFMachPortContext context = { 0
- , (void *)store
- , CFRetain
- , CFRelease
- , replyMPCopyDescription
- };
- int32_t error;
- mach_port_t mp;
- CFRunLoopSourceRef rls;
-
- (void) gettimeofday(&dnsQueryStart, NULL);
-
- error = getnameinfo_async_start(&mp,
- &addr.sa,
- addr.sa.sa_len,
- NI_NAMEREQD, // flags
- reverseDNSComplete,
- NULL);
- if (error != 0) {
- goto done;
- }
- __MACH_PORT_DEBUG(TRUE, "*** set-hostname (after getnameinfo_async_start)", mp);
-
- dnsActive = TRUE;
- dnsPort = _SC_CFMachPortCreateWithPort("IPMonitor/set-hostname",
- mp,
- getnameinfo_async_handleCFReply,
- &context);
- rls = CFMachPortCreateRunLoopSource(NULL, dnsPort, 0);
- CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
- CFRelease(rls);
- __MACH_PORT_DEBUG(TRUE, "*** set-hostname (after scheduling)", mp);
+ options = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ data = CFDataCreate(NULL, (const UInt8 *)&addr.sa, addr.sa.sa_len);
+ CFDictionarySetValue(options, kSCNetworkReachabilityOptionPTRAddress, data);
+ CFRelease(data);
+ ptrTarget = SCNetworkReachabilityCreateWithOptions(NULL, options);
+ CFRelease(options);
+ if (ptrTarget == NULL) {
+ my_log(LOG_ERR, "could not resolve [primary] address");
+ return FALSE;
}
- done :
+ (void) SCNetworkReachabilitySetCallback(ptrTarget, ptr_query_callback, NULL);
+ (void) SCNetworkReachabilityScheduleWithRunLoop(ptrTarget, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
- return;
+ return TRUE;
}
// if active, cancel any in-progress attempt to resolve the primary IP address
- if (dnsPort != NULL) {
- mach_port_t mp = CFMachPortGetPort(dnsPort);
-
- /* cancel the outstanding DNS query */
- CFMachPortInvalidate(dnsPort);
- CFRelease(dnsPort);
- dnsPort = NULL;
-
- getnameinfo_async_cancel(mp);
- }
-
- // get static hostname, if available
-
- hostname = copy_static_name();
- if (hostname != NULL) {
- my_log(LOG_INFO, "hostname (static) = %@", hostname);
- set_hostname(hostname);
- goto done;
+ if (ptrTarget != NULL) {
+ ptr_query_stop();
}
// get [prefs] hostname, if available
hostname = copy_prefs_hostname(store);
if (hostname != NULL) {
- my_log(LOG_INFO, "hostname (prefs) = %@", hostname);
+ my_log(LOG_DEBUG, "hostname (prefs) = %@", hostname);
set_hostname(hostname);
goto done;
}
hostname = copy_dhcp_hostname(serviceID);
if (hostname != NULL) {
- my_log(LOG_INFO, "hostname (DHCP) = %@", hostname);
+ my_log(LOG_DEBUG, "hostname (DHCP) = %@", hostname);
set_hostname(hostname);
goto done;
}
address = copy_primary_ip(store, serviceID);
if (address != NULL) {
+ Boolean ok;
+
// start reverse DNS query using primary IP address
- (void) start_dns_query(store, address);
- goto done;
+ ok = ptr_query_start(address);
+ if (ok) {
+ // if query started
+ goto done;
+ }
}
mDNS :
if (hostname != NULL) {
CFMutableStringRef localName;
- my_log(LOG_INFO, "hostname (multicast DNS) = %@", hostname);
+ my_log(LOG_DEBUG, "hostname (multicast DNS) = %@", hostname);
localName = CFStringCreateMutableCopy(NULL, 0, hostname);
assert(localName != NULL);
CFStringAppend(localName, CFSTR(".local"));
_sc_log = FALSE;
if ((argc > 1) && (strcmp(argv[1], "-d") == 0)) {
_sc_verbose = TRUE;
+ _verbose = TRUE;
argv++;
argc--;
}
exit(1);
}
- // get static hostname
- hostname = copy_static_name();
+ // get [prefs] hostname, if available
+ hostname = copy_prefs_hostname(store);
if (hostname != NULL) {
- SCPrint(TRUE, stdout, CFSTR("hostname (static) = %@\n"), hostname);
+ SCPrint(TRUE, stdout, CFSTR("hostname (prefs) = %@\n"), hostname);
CFRelease(hostname);
}
- // get [prefs] hostname, if available
- hostname = copy_prefs_hostname(store);
+ // get local (multicast DNS) name, if available
+
+ hostname = SCDynamicStoreCopyLocalHostName(store);
if (hostname != NULL) {
- SCPrint(TRUE, stdout, CFSTR("hostname (prefs) = %@\n"), hostname);
+ SCPrint(TRUE, stdout, CFSTR("hostname (multicast DNS) = %@\n"), hostname);
CFRelease(hostname);
}
SCPrint(TRUE, stdout, CFSTR("primary service ID = %@\n"), serviceID);
} else {
SCPrint(TRUE, stdout, CFSTR("No primary service\n"));
- goto mDNS;
}
if ((argc == (2+1)) && (argv[1][0] == 's')) {
SCPrint(TRUE, stdout, CFSTR("alternate service ID = %@\n"), serviceID);
}
- // get DHCP provided name
- hostname = copy_dhcp_name(store, serviceID);
- if (hostname != NULL) {
- SCPrint(TRUE, stdout, CFSTR("hostname (DHCP) = %@\n"), hostname);
- CFRelease(hostname);
- }
-
- // get primary IP address
- address = copy_primary_ip(store, serviceID);
- if (address != NULL) {
- SCPrint(TRUE, stdout, CFSTR("primary address = %@\n"), address);
-
- if ((argc == (2+1)) && (argv[1][0] == 'a')) {
- if (address != NULL) CFRelease(address);
- address = CFStringCreateWithCString(NULL, argv[2], kCFStringEncodingUTF8);
- SCPrint(TRUE, stdout, CFSTR("alternate primary address = %@\n"), address);
+ if (serviceID != NULL) {
+ // get DHCP provided name
+ hostname = copy_dhcp_hostname(serviceID);
+ if (hostname != NULL) {
+ SCPrint(TRUE, stdout, CFSTR("hostname (DHCP) = %@\n"), hostname);
+ CFRelease(hostname);
}
- // start reverse DNS query using primary IP address
- start_dns_query(store, address);
- CFRelease(address);
- }
-
- CFRelease(serviceID);
-
- mDNS :
+ // get primary IP address
+ address = copy_primary_ip(store, serviceID);
+ if (address != NULL) {
+ SCPrint(TRUE, stdout, CFSTR("primary address = %@\n"), address);
- // get local (multicast DNS) name, if available
+ if ((argc == (2+1)) && (argv[1][0] == 'a')) {
+ if (address != NULL) CFRelease(address);
+ address = CFStringCreateWithCString(NULL, argv[2], kCFStringEncodingUTF8);
+ SCPrint(TRUE, stdout, CFSTR("alternate primary address = %@\n"), address);
+ }
- hostname = SCDynamicStoreCopyLocalHostName(store);
- if (hostname != NULL) {
- CFMutableStringRef localName;
+ // start reverse DNS query using primary IP address
+ (void) ptr_query_start(address);
+ CFRelease(address);
+ }
- SCPrint(TRUE, stdout, CFSTR("hostname (multicast DNS) = %@\n"), hostname);
- localName = CFStringCreateMutableCopy(NULL, 0, hostname);
- CFStringAppend(localName, CFSTR(".local"));
- CFRelease(localName);
+ CFRelease(serviceID);
}
- if (hostname != NULL) CFRelease(hostname);
-
- update_hostname(store, NULL, NULL);
-
CFRelease(store);
CFRunLoopRun();