[Midnightbsd-cvs] src [6985] vendor/apple/mDNSResponder/561.1.1: mDNSResponder 561.1.1
laffer1 at midnightbsd.org
laffer1 at midnightbsd.org
Thu Mar 19 21:14:53 EDT 2015
Revision: 6985
http://svnweb.midnightbsd.org/src/?rev=6985
Author: laffer1
Date: 2015-03-19 21:14:52 -0400 (Thu, 19 Mar 2015)
Log Message:
-----------
mDNSResponder 561.1.1
Added Paths:
-----------
vendor/apple/mDNSResponder/561.1.1/
vendor/apple/mDNSResponder/561.1.1/Clients/dnsctl.c
vendor/apple/mDNSResponder/561.1.1/Makefile
vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/BonjourEvents.c
vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/LaunchDaemonInfo.plist
vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/Private/dns_services.c
vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/Private/dns_services_mdns.h
vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/base.xcconfig
vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/helper.c
vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/mDNSMacOSX.c
vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
vendor/apple/mDNSResponder/561.1.1/mDNSPosix/mDNSPosix.c
vendor/apple/mDNSResponder/561.1.1/mDNSShared/dns_sd.h
vendor/apple/mDNSResponder/561.1.1/mDNSShared/dnssd_clientstub.c
vendor/apple/mDNSResponder/561.1.1/mDNSShared/dnssd_ipc.h
vendor/apple/mDNSResponder/561.1.1/mDNSWindows/mDNSWin32.c
Removed Paths:
-------------
vendor/apple/mDNSResponder/561.1.1/Clients/dnsctl.c
vendor/apple/mDNSResponder/561.1.1/Makefile
vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/BonjourEvents.c
vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/LaunchDaemonInfo.plist
vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/Private/dns_services.c
vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/helper.c
vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/mDNSMacOSX.c
vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
vendor/apple/mDNSResponder/561.1.1/mDNSPosix/mDNSPosix.c
vendor/apple/mDNSResponder/561.1.1/mDNSShared/dns_sd.h
vendor/apple/mDNSResponder/561.1.1/mDNSShared/dnssd_clientstub.c
vendor/apple/mDNSResponder/561.1.1/mDNSShared/dnssd_ipc.h
vendor/apple/mDNSResponder/561.1.1/mDNSWindows/mDNSWin32.c
Deleted: vendor/apple/mDNSResponder/561.1.1/Clients/dnsctl.c
===================================================================
--- vendor/apple/mDNSResponder/dist/Clients/dnsctl.c 2014-06-30 23:58:12 UTC (rev 6706)
+++ vendor/apple/mDNSResponder/561.1.1/Clients/dnsctl.c 2015-03-20 01:14:52 UTC (rev 6985)
@@ -1,177 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2012 Apple Inc. All rights reserved.
- *
- * dnsctl.c
- * Command-line tool using libdns_services.dylib
- *
- * To build only this tool, copy and paste the following on the command line:
- * On Apple 64bit Platforms ONLY OSX/iOS:
- * clang -Wall dnsctl.c /usr/lib/libdns_services.dylib -o dnsctl
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-#include <net/if.h> // if_nametoindex()
-
-#include <dispatch/dispatch.h>
-#include "dns_services.h"
-
-//*************************************************************************************************************
-// Globals:
-//*************************************************************************************************************
-
-static const char kFilePathSep = '/';
-static DNSXConnRef ClientRef = NULL;
-
-//*************************************************************************************************************
-// Utility Funcs:
-//*************************************************************************************************************
-
-static void printtimestamp(void)
-{
- struct tm tm;
- int ms;
- static char date[16];
- static char new_date[16];
- struct timeval tv;
- gettimeofday(&tv, NULL);
- localtime_r((time_t*)&tv.tv_sec, &tm);
- ms = tv.tv_usec/1000;
- strftime(new_date, sizeof(new_date), "%a %d %b %Y", &tm);
- //display date only if it has changed
- if (strncmp(date, new_date, sizeof(new_date)))
- {
- printf("DATE: ---%s---\n", new_date);
- strncpy(date, new_date, sizeof(date));
- }
- printf("%2d:%02d:%02d.%03d ", tm.tm_hour, tm.tm_min, tm.tm_sec, ms);
-}
-
-static void print_usage(const char *arg0)
-{
- fprintf(stderr, "%s USAGE: \n", arg0);
- fprintf(stderr, "%s -DP Enable DNS Proxy with Default Parameters \n", arg0);
- fprintf(stderr, "%s -DP [-o <output interface>] [-i <input interface(s)>] Enable DNS Proxy \n", arg0);
-}
-
-//*************************************************************************************************************
-// CallBack Funcs:
-//*************************************************************************************************************
-
-// DNSXEnableProxy Callback from the Daemon
-static void dnsproxy_reply(DNSXConnRef connRef, DNSXErrorType errCode)
-{
- (void) connRef;
- printtimestamp();
- switch (errCode)
- {
- case kDNSX_NoError : printf(" SUCCESS \n"); break;
- case kDNSX_DictError : printf(" DICT ERROR \n"); break;
- case kDNSX_DaemonNotRunning : printf(" NO DAEMON \n");
- DNSXRefDeAlloc(ClientRef); break;
- case kDNSX_Engaged : printf(" ENGAGED \n");
- DNSXRefDeAlloc(ClientRef); break;
- case kDNSX_UnknownErr :
- default : printf("UNKNOWN ERR \n");
- DNSXRefDeAlloc(ClientRef); break;
- }
-
-}
-
-//*************************************************************************************************************
-
-int main(int argc, char **argv)
-{
- DNSXErrorType err;
-
- // Default i/p intf is lo0 and o/p intf is primary interface
- IfIndex Ipintfs[MaxInputIf] = {1, 0, 0, 0, 0};
- IfIndex Opintf = kDNSIfindexAny;
-
- // Extract program name from argv[0], which by convention contains the path to this executable
- const char *a0 = strrchr(argv[0], kFilePathSep) + 1;
- if (a0 == (const char *)1)
- a0 = argv[0];
-
- // Must run as root
- if (0 != geteuid())
- {
- fprintf(stderr, "%s MUST run as root!!\n", a0);
- exit(-1);
- }
- if ((sizeof(argv) == 8))
- printf("dnsctl running in 64-bit mode\n");
- else if ((sizeof(argv) == 4))
- printf("dnsctl running in 32-bit mode\n");
-
- // expects atleast one argument
- if (argc < 2)
- goto Usage;
-
- if ( !strcmp(argv[1], "-DP") || !strcmp(argv[1], "-dp") )
- {
- if (argc == 2)
- {
- printtimestamp();
- printf("Proceeding to Enable DNSProxy on mDNSResponder with Default Parameters\n");
- dispatch_queue_t my_Q = dispatch_queue_create("com.apple.dnsctl.callback_queue", NULL);
- err = DNSXEnableProxy(&ClientRef, kDNSProxyEnable, Ipintfs, Opintf, my_Q, dnsproxy_reply);
- }
- else if (argc > 2)
- {
- argc--;
- argv++;
- if (!strcmp(argv[1], "-o"))
- {
- Opintf = if_nametoindex(argv[2]);
- if (!Opintf)
- Opintf = atoi(argv[2]);
- if (!Opintf)
- {
- fprintf(stderr, "Could not parse o/p interface [%s]: Passing default primary \n", argv[2]);
- Opintf = kDNSIfindexAny;
- }
- argc -= 2;
- argv += 2;
- }
- if (argc > 2 && !strcmp(argv[1], "-i"))
- {
- int i;
- argc--;
- argv++;
- for (i = 0; i < MaxInputIf && argc > 1; i++)
- {
- Ipintfs[i] = if_nametoindex(argv[1]);
- if (!Ipintfs[i])
- Ipintfs[i] = atoi(argv[1]);
- if (!Ipintfs[i])
- {
- fprintf(stderr, "Could not parse i/p interface [%s]: Passing default lo0 \n", argv[2]);
- Ipintfs[i] = 1;
- }
- argc--;
- argv++;
- }
- }
- printtimestamp();
- printf("Proceeding to Enable DNSProxy on mDNSResponder \n");
- dispatch_queue_t my_Q = dispatch_queue_create("com.apple.dnsctl.callback_queue", NULL);
- err = DNSXEnableProxy(&ClientRef, kDNSProxyEnable, Ipintfs, Opintf, my_Q, dnsproxy_reply);
- }
- }
- else
- {
- goto Usage;
- }
-
- dispatch_main();
-
-Usage:
- print_usage(a0);
- return 0;
-}
-
Copied: vendor/apple/mDNSResponder/561.1.1/Clients/dnsctl.c (from rev 6984, vendor/apple/mDNSResponder/dist/Clients/dnsctl.c)
===================================================================
--- vendor/apple/mDNSResponder/561.1.1/Clients/dnsctl.c (rev 0)
+++ vendor/apple/mDNSResponder/561.1.1/Clients/dnsctl.c 2015-03-20 01:14:52 UTC (rev 6985)
@@ -0,0 +1,178 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * dnsctl.c
+ * Command-line tool using libdns_services.dylib
+ *
+ * To build only this tool, copy and paste the following on the command line:
+ * On Apple 64bit Platforms ONLY OSX/iOS:
+ * clang -Wall dnsctl.c /usr/lib/libdns_services.dylib -o dnsctl
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <net/if.h> // if_nametoindex()
+
+#include <dispatch/dispatch.h>
+#include "dns_services_mdns.h"
+
+//*************************************************************************************************************
+// Globals:
+//*************************************************************************************************************
+
+static const char kFilePathSep = '/';
+static DNSXConnRef ClientRef = NULL;
+
+//*************************************************************************************************************
+// Utility Funcs:
+//*************************************************************************************************************
+
+static void printtimestamp(void)
+{
+ struct tm tm;
+ int ms;
+ static char date[16];
+ static char new_date[16];
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ localtime_r((time_t*)&tv.tv_sec, &tm);
+ ms = tv.tv_usec/1000;
+ strftime(new_date, sizeof(new_date), "%a %d %b %Y", &tm);
+ //display date only if it has changed
+ if (strncmp(date, new_date, sizeof(new_date)))
+ {
+ printf("DATE: ---%s---\n", new_date);
+ strncpy(date, new_date, sizeof(date));
+ }
+ printf("%2d:%02d:%02d.%03d ", tm.tm_hour, tm.tm_min, tm.tm_sec, ms);
+}
+
+static void print_usage(const char *arg0)
+{
+ fprintf(stderr, "%s USAGE: \n", arg0);
+ fprintf(stderr, "%s -DP Enable DNS Proxy with Default Parameters \n", arg0);
+ fprintf(stderr, "%s -DP [-o <output interface>] [-i <input interface(s)>] Enable DNS Proxy \n", arg0);
+}
+
+//*************************************************************************************************************
+// CallBack Funcs:
+//*************************************************************************************************************
+
+// DNSXEnableProxy Callback from the Daemon
+static void dnsproxy_reply(DNSXConnRef connRef, DNSXErrorType errCode)
+{
+ (void) connRef;
+ printtimestamp();
+ switch (errCode)
+ {
+ case kDNSX_NoError : printf(" SUCCESS \n"); break;
+ case kDNSX_DictError : printf(" DICT ERROR \n"); break;
+ case kDNSX_DaemonNotRunning : printf(" NO DAEMON \n");
+ DNSXRefDeAlloc(ClientRef); break;
+ case kDNSX_Engaged : printf(" ENGAGED \n");
+ DNSXRefDeAlloc(ClientRef); break;
+ case kDNSX_UnknownErr :
+ default : printf("UNKNOWN ERR \n");
+ DNSXRefDeAlloc(ClientRef); break;
+ }
+ fflush(NULL);
+
+}
+
+//*************************************************************************************************************
+
+int main(int argc, char **argv)
+{
+ DNSXErrorType err;
+
+ // Default i/p intf is lo0 and o/p intf is primary interface
+ IfIndex Ipintfs[MaxInputIf] = {1, 0, 0, 0, 0};
+ IfIndex Opintf = kDNSIfindexAny;
+
+ // Extract program name from argv[0], which by convention contains the path to this executable
+ const char *a0 = strrchr(argv[0], kFilePathSep) + 1;
+ if (a0 == (const char *)1)
+ a0 = argv[0];
+
+ // Must run as root
+ if (0 != geteuid())
+ {
+ fprintf(stderr, "%s MUST run as root!!\n", a0);
+ exit(-1);
+ }
+ if ((sizeof(argv) == 8))
+ printf("dnsctl running in 64-bit mode\n");
+ else if ((sizeof(argv) == 4))
+ printf("dnsctl running in 32-bit mode\n");
+
+ // expects atleast one argument
+ if (argc < 2)
+ goto Usage;
+
+ if ( !strcmp(argv[1], "-DP") || !strcmp(argv[1], "-dp") )
+ {
+ if (argc == 2)
+ {
+ printtimestamp();
+ printf("Proceeding to Enable DNSProxy on mDNSResponder with Default Parameters\n");
+ dispatch_queue_t my_Q = dispatch_queue_create("com.apple.dnsctl.callback_queue", NULL);
+ err = DNSXEnableProxy(&ClientRef, kDNSProxyEnable, Ipintfs, Opintf, my_Q, dnsproxy_reply);
+ }
+ else if (argc > 2)
+ {
+ argc--;
+ argv++;
+ if (!strcmp(argv[1], "-o"))
+ {
+ Opintf = if_nametoindex(argv[2]);
+ if (!Opintf)
+ Opintf = atoi(argv[2]);
+ if (!Opintf)
+ {
+ fprintf(stderr, "Could not parse o/p interface [%s]: Passing default primary \n", argv[2]);
+ Opintf = kDNSIfindexAny;
+ }
+ argc -= 2;
+ argv += 2;
+ }
+ if (argc > 2 && !strcmp(argv[1], "-i"))
+ {
+ int i;
+ argc--;
+ argv++;
+ for (i = 0; i < MaxInputIf && argc > 1; i++)
+ {
+ Ipintfs[i] = if_nametoindex(argv[1]);
+ if (!Ipintfs[i])
+ Ipintfs[i] = atoi(argv[1]);
+ if (!Ipintfs[i])
+ {
+ fprintf(stderr, "Could not parse i/p interface [%s]: Passing default lo0 \n", argv[2]);
+ Ipintfs[i] = 1;
+ }
+ argc--;
+ argv++;
+ }
+ }
+ printtimestamp();
+ printf("Proceeding to Enable DNSProxy on mDNSResponder \n");
+ dispatch_queue_t my_Q = dispatch_queue_create("com.apple.dnsctl.callback_queue", NULL);
+ err = DNSXEnableProxy(&ClientRef, kDNSProxyEnable, Ipintfs, Opintf, my_Q, dnsproxy_reply);
+ }
+ }
+ else
+ {
+ goto Usage;
+ }
+
+ dispatch_main();
+
+Usage:
+ print_usage(a0);
+ return 0;
+}
+
Deleted: vendor/apple/mDNSResponder/561.1.1/Makefile
===================================================================
--- vendor/apple/mDNSResponder/dist/Makefile 2014-06-30 23:58:12 UTC (rev 6706)
+++ vendor/apple/mDNSResponder/561.1.1/Makefile 2015-03-20 01:14:52 UTC (rev 6985)
@@ -1,49 +0,0 @@
-#
-# Top level makefile for Build & Integration.
-#
-# This file is used to facilitate checking the mDNSResponder project
-# directly out of CVS and submitting to B&I at Apple.
-#
-# The various platform directories contain makefiles or projects
-# specific to that platform.
-#
-# B&I builds must respect the following target:
-# install:
-# installsrc:
-# installhdrs:
-# clean:
-#
-
-include $(MAKEFILEPATH)/pb_makefiles/platform.make
-
-MVERS = "mDNSResponder-541"
-
-DDNSWRITECONFIG = "$(DSTROOT)/Library/Application Support/Bonjour/ddnswriteconfig"
-VER =
-ifneq ($(strip $(GCC_VERSION)),)
- VER = -- GCC_VERSION=$(GCC_VERSION)
-endif
-echo "VER = $(VER)"
-
-installSome:
- cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target Build\ Some $(VER)
-
-SystemLibraries:
- cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target SystemLibraries $(VER)
-
-install:
- cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) $(VER)
- # Make sure ddnswriteconfig is owned by root:wheel, then make it setuid root executable
- if test -e $(DDNSWRITECONFIG) ; then chown 0:80 $(DDNSWRITECONFIG) ; chmod 4555 $(DDNSWRITECONFIG) ; fi
-
-installsrc:
- ditto . "$(SRCROOT)"
-
-installhdrs::
- cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild installhdrs OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target SystemLibraries $(VER)
-
-java:
- cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target libjdns_sd.jnilib $(VER)
-
-clean::
- echo clean
Copied: vendor/apple/mDNSResponder/561.1.1/Makefile (from rev 6984, vendor/apple/mDNSResponder/dist/Makefile)
===================================================================
--- vendor/apple/mDNSResponder/561.1.1/Makefile (rev 0)
+++ vendor/apple/mDNSResponder/561.1.1/Makefile 2015-03-20 01:14:52 UTC (rev 6985)
@@ -0,0 +1,49 @@
+#
+# Top level makefile for Build & Integration.
+#
+# This file is used to facilitate checking the mDNSResponder project
+# directly out of CVS and submitting to B&I at Apple.
+#
+# The various platform directories contain makefiles or projects
+# specific to that platform.
+#
+# B&I builds must respect the following target:
+# install:
+# installsrc:
+# installhdrs:
+# clean:
+#
+
+include $(MAKEFILEPATH)/pb_makefiles/platform.make
+
+MVERS = "mDNSResponder-561.1.1"
+
+DDNSWRITECONFIG = "$(DSTROOT)/Library/Application Support/Bonjour/ddnswriteconfig"
+VER =
+ifneq ($(strip $(GCC_VERSION)),)
+ VER = -- GCC_VERSION=$(GCC_VERSION)
+endif
+echo "VER = $(VER)"
+
+installSome:
+ cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target Build\ Some $(VER)
+
+SystemLibraries:
+ cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target SystemLibraries $(VER)
+
+install:
+ cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) $(VER)
+ # Make sure ddnswriteconfig is owned by root:wheel, then make it setuid root executable
+ if test -e $(DDNSWRITECONFIG) ; then chown 0:80 $(DDNSWRITECONFIG) ; chmod 4555 $(DDNSWRITECONFIG) ; fi
+
+installsrc:
+ ditto . "$(SRCROOT)"
+
+installhdrs::
+ cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild installhdrs OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target SystemLibraries $(VER)
+
+java:
+ cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target libjdns_sd.jnilib $(VER)
+
+clean::
+ echo clean
Deleted: vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/BonjourEvents.c
===================================================================
--- vendor/apple/mDNSResponder/dist/mDNSMacOSX/BonjourEvents.c 2014-06-30 23:58:12 UTC (rev 6706)
+++ vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/BonjourEvents.c 2015-03-20 01:14:52 UTC (rev 6985)
@@ -1,991 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2010 Apple Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <CoreFoundation/CoreFoundation.h>
-#include <CoreFoundation/CFXPCBridge.h>
-#include "dns_sd.h"
-#include <UserEventAgentInterface.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <asl.h>
-#include <xpc/xpc.h>
-
-
-#pragma mark -
-#pragma mark Types
-#pragma mark -
-static const char* sPluginIdentifier = "com.apple.bonjour.events";
-
-// PLIST Keys
-static const CFStringRef sServiceNameKey = CFSTR("ServiceName");
-static const CFStringRef sServiceTypeKey = CFSTR("ServiceType");
-static const CFStringRef sServiceDomainKey = CFSTR("ServiceDomain");
-
-static const CFStringRef sOnServiceAddKey = CFSTR("OnServiceAdd");
-static const CFStringRef sOnServiceRemoveKey = CFSTR("OnServiceRemove");
-
-static const CFStringRef sLaunchdTokenKey = CFSTR("LaunchdToken");
-static const CFStringRef sLaunchdDictKey = CFSTR("LaunchdDict");
-
-
-/************************************************
-* Launch Event Dictionary (input from launchd)
-* Passed To: ManageEventsCallback
-*-----------------------------------------------
-* Typing in this dictionary is not enforced
-* above us. So this may not be true. Type check
-* all input before using it.
-*-----------------------------------------------
-* sServiceNameKey - CFString (Optional)
-* sServiceTypeKey - CFString
-* sServiceDomainKey - CFString
-*
-* One or more of the following.
-*-----------------------------------
-* sOnServiceAddKey - CFBoolean
-* sOnServiceRemoveKey - CFBoolean
-* sWhileServiceExistsKey - CFBoolean
-************************************************/
-
-/************************************************
-* Browser Dictionary
-*-----------------------------------------------
-* sServiceDomainKey - CFString
-* sServiceTypeKey - CFString
-************************************************/
-
-/************************************************
-* Event Dictionary
-*-----------------------------------------------
-* sServiceNameKey - CFString (Optional)
-* sLaunchdTokenKey - CFNumber
-************************************************/
-
-typedef struct {
- UserEventAgentInterfaceStruct* _UserEventAgentInterface;
- CFUUIDRef _factoryID;
- UInt32 _refCount;
-
- void* _pluginContext;
-
- CFMutableDictionaryRef _tokenToBrowserMap; // Maps a token to a browser that can be used to scan the remaining dictionaries.
- CFMutableDictionaryRef _browsers; // A Dictionary of Browser Dictionaries where the resposible browser is the key.
- CFMutableDictionaryRef _onAddEvents; // A Dictionary of Event Dictionaries that describe events to trigger on a service appearing.
- CFMutableDictionaryRef _onRemoveEvents; // A Dictionary of Event Dictionaries that describe events to trigger on a service disappearing.
-} BonjourUserEventsPlugin;
-
-typedef struct {
- CFIndex refCount;
- DNSServiceRef browserRef;
-} NetBrowserInfo;
-
-#pragma mark -
-#pragma mark Prototypes
-#pragma mark -
-// COM Stuff
-static HRESULT QueryInterface(void *myInstance, REFIID iid, LPVOID *ppv);
-static ULONG AddRef(void* instance);
-static ULONG Release(void* instance);
-
-static BonjourUserEventsPlugin* Alloc(CFUUIDRef factoryID);
-static void Dealloc(BonjourUserEventsPlugin* plugin);
-
-void * UserEventAgentFactory(CFAllocatorRef allocator, CFUUIDRef typeID);
-
-// Plugin Management
-static void Install(void* instance);
-static void ManageEventsCallback(
- UserEventAgentLaunchdAction action,
- CFNumberRef token,
- CFTypeRef eventMatchDict,
- void * vContext);
-
-
-// Plugin Guts
-void AddEventToPlugin(BonjourUserEventsPlugin* plugin, CFNumberRef launchdToken, CFDictionaryRef eventParameters);
-void RemoveEventFromPlugin(BonjourUserEventsPlugin* plugin, CFNumberRef launchToken);
-
-NetBrowserInfo* CreateBrowser(BonjourUserEventsPlugin* plugin, CFStringRef type, CFStringRef domain);
-NetBrowserInfo* BrowserForSDRef(BonjourUserEventsPlugin* plugin, DNSServiceRef sdRef);
-void AddEventDictionary(CFDictionaryRef eventDict, CFMutableDictionaryRef allEventsDictionary, NetBrowserInfo* key);
-void RemoveEventFromArray(CFMutableArrayRef array, CFNumberRef launchdToken);
-
-// Net Service Browser Stuff
-void ServiceBrowserCallback (DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char* serviceName, const char* regtype, const char* replyDomain, void* context);
-void HandleTemporaryEventsForService(BonjourUserEventsPlugin* plugin, NetBrowserInfo* browser, CFStringRef serviceName, CFMutableDictionaryRef eventsDictionary);
-
-// Convence Stuff
-const char* CStringFromCFString(CFStringRef string);
-
-// NetBrowserInfo "Object"
-NetBrowserInfo* NetBrowserInfoCreate(CFStringRef serviceType, CFStringRef domain, void* context);
-const void* NetBrowserInfoRetain(CFAllocatorRef allocator, const void* info);
-void NetBrowserInfoRelease(CFAllocatorRef allocator, const void* info);
-Boolean NetBrowserInfoEqual(const void *value1, const void *value2);
-CFHashCode NetBrowserInfoHash(const void *value);
-CFStringRef NetBrowserInfoCopyDescription(const void *value);
-
-static const CFDictionaryKeyCallBacks kNetBrowserInfoDictionaryKeyCallbacks = {
- 0,
- NetBrowserInfoRetain,
- NetBrowserInfoRelease,
- NetBrowserInfoCopyDescription,
- NetBrowserInfoEqual,
- NetBrowserInfoHash
-};
-
-static const CFDictionaryValueCallBacks kNetBrowserInfoDictionaryValueCallbacks = {
- 0,
- NetBrowserInfoRetain,
- NetBrowserInfoRelease,
- NetBrowserInfoCopyDescription,
- NetBrowserInfoEqual
-};
-
-// COM type definition goop.
-static UserEventAgentInterfaceStruct UserEventAgentInterfaceFtbl = {
- NULL, // Required padding for COM
- QueryInterface, // Query Interface
- AddRef, // AddRef()
- Release, // Release()
- Install // Install
-};
-
-#pragma mark -
-#pragma mark COM Management
-#pragma mark -
-
-/*****************************************************************************
-*****************************************************************************/
-static HRESULT QueryInterface(void *myInstance, REFIID iid, LPVOID *ppv)
-{
- CFUUIDRef interfaceID = CFUUIDCreateFromUUIDBytes(NULL, iid);
-
- // Test the requested ID against the valid interfaces.
- if(CFEqual(interfaceID, kUserEventAgentInterfaceID))
- {
- ((BonjourUserEventsPlugin *) myInstance)->_UserEventAgentInterface->AddRef(myInstance);
- *ppv = myInstance;
- CFRelease(interfaceID);
- return S_OK;
- }
- else if(CFEqual(interfaceID, IUnknownUUID))
- {
- ((BonjourUserEventsPlugin *) myInstance)->_UserEventAgentInterface->AddRef(myInstance);
- *ppv = myInstance;
- CFRelease(interfaceID);
- return S_OK;
- }
- else // Requested interface unknown, bail with error.
- {
- *ppv = NULL;
- CFRelease(interfaceID);
- return E_NOINTERFACE;
- }
-}
-
-/*****************************************************************************
-*****************************************************************************/
-static ULONG AddRef(void* instance)
-{
- BonjourUserEventsPlugin* plugin = (BonjourUserEventsPlugin*)instance;
- return ++plugin->_refCount;
-}
-
-/*****************************************************************************
-*****************************************************************************/
-static ULONG Release(void* instance)
-{
- BonjourUserEventsPlugin* plugin = (BonjourUserEventsPlugin*)instance;
-
- if (plugin->_refCount != 0)
- --plugin->_refCount;
-
- if (plugin->_refCount == 0)
- {
- Dealloc(instance);
- return 0;
- }
-
- return plugin->_refCount;
-}
-
-/*****************************************************************************
-* Alloc
-* -
-* Functionas as both +[alloc] and -[init] for the plugin. Add any
-* initalization of member variables here.
-*****************************************************************************/
-static BonjourUserEventsPlugin* Alloc(CFUUIDRef factoryID)
-{
- BonjourUserEventsPlugin* plugin = malloc(sizeof(BonjourUserEventsPlugin));
-
- plugin->_UserEventAgentInterface = &UserEventAgentInterfaceFtbl;
- plugin->_pluginContext = NULL;
-
- if (factoryID)
- {
- plugin->_factoryID = (CFUUIDRef)CFRetain(factoryID);
- CFPlugInAddInstanceForFactory(factoryID);
- }
-
- plugin->_refCount = 1;
- plugin->_tokenToBrowserMap = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kNetBrowserInfoDictionaryValueCallbacks);
- plugin->_browsers = CFDictionaryCreateMutable(NULL, 0, &kNetBrowserInfoDictionaryKeyCallbacks, &kCFTypeDictionaryValueCallBacks);
- plugin->_onAddEvents = CFDictionaryCreateMutable(NULL, 0, &kNetBrowserInfoDictionaryKeyCallbacks, &kCFTypeDictionaryValueCallBacks);
- plugin->_onRemoveEvents = CFDictionaryCreateMutable(NULL, 0, &kNetBrowserInfoDictionaryKeyCallbacks, &kCFTypeDictionaryValueCallBacks);
-
- return plugin;
-}
-
-/*****************************************************************************
-* Dealloc
-* -
-* Much like Obj-C dealloc this method is responsible for releasing any object
-* this plugin is holding. Unlike ObjC, you call directly free() instead of
-* [super dalloc].
-*****************************************************************************/
-static void Dealloc(BonjourUserEventsPlugin* plugin)
-{
- CFUUIDRef factoryID = plugin->_factoryID;
-
- if (factoryID)
- {
- CFPlugInRemoveInstanceForFactory(factoryID);
- CFRelease(factoryID);
- }
-
- if (plugin->_tokenToBrowserMap)
- CFRelease(plugin->_tokenToBrowserMap);
-
- if (plugin->_browsers)
- CFRelease(plugin->_browsers);
-
- if (plugin->_onAddEvents)
- CFRelease(plugin->_onAddEvents);
-
- if (plugin->_onRemoveEvents)
- CFRelease(plugin->_onRemoveEvents);
-
- free(plugin);
-}
-
-/*******************************************************************************
-*******************************************************************************/
-void * UserEventAgentFactory(CFAllocatorRef allocator, CFUUIDRef typeID)
-{
- (void)allocator;
- BonjourUserEventsPlugin * result = NULL;
-
- if (typeID && CFEqual(typeID, kUserEventAgentTypeID)) {
- result = Alloc(kUserEventAgentFactoryID);
- }
-
- return (void *)result;
-}
-
-#pragma mark -
-#pragma mark Plugin Management
-#pragma mark -
-/*****************************************************************************
-* Install
-* -
-* This is invoked once when the plugin is loaded to do initial setup and
-* allow us to register with launchd. If UserEventAgent crashes, the plugin
-* will need to be reloaded, and hence this will get invoked again.
-*****************************************************************************/
-static void Install(void *instance)
-{
- BonjourUserEventsPlugin* plugin = (BonjourUserEventsPlugin*)instance;
-
- plugin->_pluginContext = UserEventAgentRegisterForLaunchEvents(sPluginIdentifier, &ManageEventsCallback, plugin);
-
- if (!plugin->_pluginContext)
- {
- fprintf(stderr, "%s:%s failed to register for launch events.\n", sPluginIdentifier, __FUNCTION__);
- return;
- }
-
-}
-
-/*****************************************************************************
-* ManageEventsCallback
-* -
-* This is invoked when launchd loads a event dictionary and needs to inform
-* us what a daemon / agent is looking for.
-*****************************************************************************/
-static void ManageEventsCallback(UserEventAgentLaunchdAction action, CFNumberRef token, CFTypeRef eventMatchDict, void* vContext)
-{
- if (action == kUserEventAgentLaunchdAdd)
- {
- if (!eventMatchDict)
- {
- fprintf(stderr, "%s:%s empty dictionary\n", sPluginIdentifier, __FUNCTION__);
- return;
- }
- if (CFGetTypeID(eventMatchDict) != CFDictionaryGetTypeID())
- {
- fprintf(stderr, "%s:%s given non-dict for event dictionary, action %d\n", sPluginIdentifier, __FUNCTION__, action);
- return;
- }
- // Launchd wants us to add a launch event for this token and matching dictionary.
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s calling AddEventToPlugin", sPluginIdentifier, __FUNCTION__);
- AddEventToPlugin((BonjourUserEventsPlugin*)vContext, token, (CFDictionaryRef)eventMatchDict);
- }
- else if (action == kUserEventAgentLaunchdRemove)
- {
- // Launchd wants us to remove the event hook we setup for this token / matching dictionary.
- // Note: eventMatchDict can be NULL for Remove.
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s calling RemoveEventToPlugin", sPluginIdentifier, __FUNCTION__);
- RemoveEventFromPlugin((BonjourUserEventsPlugin*)vContext, token);
- }
- else
- {
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s unknown callback event\n", sPluginIdentifier, __FUNCTION__);
- }
-}
-
-
-#pragma mark -
-#pragma mark Plugin Guts
-#pragma mark -
-
-/*****************************************************************************
-* AddEventToPlugin
-* -
-* This method is invoked when launchd wishes the plugin to setup a launch
-* event matching the parameters in the dictionary.
-*****************************************************************************/
-void AddEventToPlugin(BonjourUserEventsPlugin* plugin, CFNumberRef launchdToken, CFDictionaryRef eventParameters)
-{
- CFStringRef domain = CFDictionaryGetValue(eventParameters, sServiceDomainKey);
- CFStringRef type = CFDictionaryGetValue(eventParameters, sServiceTypeKey);
- CFStringRef name = CFDictionaryGetValue(eventParameters, sServiceNameKey);
- CFBooleanRef cfOnAdd = CFDictionaryGetValue(eventParameters, sOnServiceAddKey);
- CFBooleanRef cfOnRemove = CFDictionaryGetValue(eventParameters, sOnServiceRemoveKey);
-
- Boolean onAdd = false;
- Boolean onRemove = false;
-
- if (cfOnAdd && CFGetTypeID(cfOnAdd) == CFBooleanGetTypeID() && CFBooleanGetValue(cfOnAdd))
- onAdd = true;
-
- if (cfOnRemove && CFGetTypeID(cfOnRemove) == CFBooleanGetTypeID() && CFBooleanGetValue(cfOnRemove))
- onRemove = true;
-
- // A type is required. If none is specified, BAIL
- if (!type || CFGetTypeID(type) != CFStringGetTypeID())
- {
- fprintf(stderr, "%s:%s: a LaunchEvent is missing a service type.\n", sPluginIdentifier, __FUNCTION__);
- return;
- }
-
- // If we aren't suppose to launch on services appearing or disappearing, this service does nothing. Ignore.
- if (!onAdd && !onRemove)
- {
- fprintf(stderr, "%s:%s a LaunchEvent is missing both onAdd and onRemove events\n", sPluginIdentifier, __FUNCTION__);
- return;
- }
-
- // If no domain is specified, assume local.
- if (!domain)
- {
- domain = CFSTR("local");
- }
- else if (CFGetTypeID(domain) != CFStringGetTypeID() ) // If the domain is not a string, fail
- {
- fprintf(stderr, "%s:%s a LaunchEvent has a domain that is not a string.\n", sPluginIdentifier, __FUNCTION__);
- return;
- }
-
- // If we have a name filter, but it's not a string. This event is broken, bail.
- if (name && CFGetTypeID(name) != CFStringGetTypeID())
- {
- fprintf(stderr, "%s:%s a LaunchEvent has a domain that is not a string.\n", sPluginIdentifier, __FUNCTION__);
- return;
- }
-
- // Get us a browser
- NetBrowserInfo* browser = CreateBrowser(plugin, type, domain);
-
- if (!browser)
- {
- fprintf(stderr, "%s:%s cannot create browser\n", sPluginIdentifier, __FUNCTION__);
- return;
- }
-
- // Create Event Dictionary
- CFMutableDictionaryRef eventDictionary = CFDictionaryCreateMutable(NULL, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-
- // We store both the Token and the Dictionary. UserEventAgentSetLaunchEventState needs
- // the token and UserEventAgentSetFireEvent needs both the token and the dictionary
- CFDictionarySetValue(eventDictionary, sLaunchdTokenKey, launchdToken);
- CFDictionarySetValue(eventDictionary, sLaunchdDictKey, eventParameters);
-
- if (name)
- CFDictionarySetValue(eventDictionary, sServiceNameKey, name);
-
- // Add to the correct dictionary.
- if (onAdd)
- {
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Adding browser to AddEvents", sPluginIdentifier, __FUNCTION__);
- AddEventDictionary(eventDictionary, plugin->_onAddEvents, browser);
- }
-
- if (onRemove)
- {
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Adding browser to RemoveEvents", sPluginIdentifier, __FUNCTION__);
- AddEventDictionary(eventDictionary, plugin->_onRemoveEvents, browser);
- }
-
- // Add Token Mapping
- CFDictionarySetValue(plugin->_tokenToBrowserMap, launchdToken, browser);
-
- // Release Memory
- CFRelease(eventDictionary);
-}
-
-/*****************************************************************************
-* RemoveEventFromPlugin
-* -
-* This method is invoked when launchd wishes the plugin to setup a launch
-* event matching the parameters in the dictionary.
-*****************************************************************************/
-void RemoveEventFromPlugin(BonjourUserEventsPlugin* plugin, CFNumberRef launchdToken)
-{
- NetBrowserInfo* browser = (NetBrowserInfo*)CFDictionaryGetValue(plugin->_tokenToBrowserMap, launchdToken);
- Boolean othersUsingBrowser = false;
-
- if (!browser)
- {
- long long value = 0;
- CFNumberGetValue(launchdToken, kCFNumberLongLongType, &value);
- fprintf(stderr, "%s:%s Launchd asked us to remove a token we did not register! ==Token:%lld== \n", sPluginIdentifier, __FUNCTION__, value);
- return;
- }
-
- CFMutableArrayRef onAddEvents = (CFMutableArrayRef)CFDictionaryGetValue(plugin->_onAddEvents, browser);
- CFMutableArrayRef onRemoveEvents = (CFMutableArrayRef)CFDictionaryGetValue(plugin->_onRemoveEvents, browser);
-
- if (onAddEvents)
- {
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Calling RemoveEventFromArray for OnAddEvents", sPluginIdentifier, __FUNCTION__);
- RemoveEventFromArray(onAddEvents, launchdToken);
-
- // Is the array now empty, clean up
- if (CFArrayGetCount(onAddEvents) == 0)
- {
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Removing the browser from AddEvents", sPluginIdentifier, __FUNCTION__);
- CFDictionaryRemoveValue(plugin->_onAddEvents, browser);
- }
- }
-
- if (onRemoveEvents)
- {
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Calling RemoveEventFromArray for OnRemoveEvents", sPluginIdentifier, __FUNCTION__);
- RemoveEventFromArray(onRemoveEvents, launchdToken);
-
- // Is the array now empty, clean up
- if (CFArrayGetCount(onRemoveEvents) == 0)
- {
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Removing the browser from RemoveEvents", sPluginIdentifier, __FUNCTION__);
- CFDictionaryRemoveValue(plugin->_onRemoveEvents, browser);
- }
- }
-
- // Remove ourselves from the token dictionary.
- CFDictionaryRemoveValue(plugin->_tokenToBrowserMap, launchdToken);
-
- // Check to see if anyone else is using this browser.
- CFIndex i;
- CFIndex count = CFDictionaryGetCount(plugin->_tokenToBrowserMap);
- NetBrowserInfo** browsers = malloc(count * sizeof(NetBrowserInfo*));
-
- // Fetch the values of the token dictionary
- CFDictionaryGetKeysAndValues(plugin->_tokenToBrowserMap, NULL, (const void**)browsers);
-
- for (i = 0; i < count; ++i)
- {
- if (NetBrowserInfoEqual(browsers[i], browser))
- {
- othersUsingBrowser = true;
- break;
- }
- }
-
- // If no one else is useing our browser, clean up!
- if (!othersUsingBrowser)
- {
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Removing browser %p from _browsers", sPluginIdentifier, __FUNCTION__, browser);
- CFDictionaryRemoveValue(plugin->_browsers, browser); // This triggers release and dealloc of the browser
- }
- else
- {
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Decrementing browsers %p count", sPluginIdentifier, __FUNCTION__, browser);
- // Decrement my reference count (it was incremented when it was added to _browsers in CreateBrowser)
- NetBrowserInfoRelease(NULL, browser);
- }
-
- free(browsers);
-}
-
-
-/*****************************************************************************
-* CreateBrowser
-* -
-* This method returns a NetBrowserInfo that is looking for a type of
-* service in a domain. If no browser exists, it will create one and return it.
-*****************************************************************************/
-NetBrowserInfo* CreateBrowser(BonjourUserEventsPlugin* plugin, CFStringRef type, CFStringRef domain)
-{
- CFIndex i;
- CFIndex count = CFDictionaryGetCount(plugin->_browsers);
- NetBrowserInfo* browser = NULL;
- CFDictionaryRef* dicts = malloc(count * sizeof(CFDictionaryRef));
- NetBrowserInfo** browsers = malloc(count * sizeof(NetBrowserInfo*));
-
- // Fetch the values of the browser dictionary
- CFDictionaryGetKeysAndValues(plugin->_browsers, (const void**)browsers, (const void**)dicts);
-
-
- // Loop thru the browsers list and see if we can find a matching one.
- for (i = 0; i < count; ++i)
- {
- CFDictionaryRef browserDict = dicts[i];
-
- CFStringRef browserType = CFDictionaryGetValue(browserDict, sServiceTypeKey);
- CFStringRef browserDomain = CFDictionaryGetValue(browserDict, sServiceDomainKey);
-
- // If we have a matching browser, break
- if ((CFStringCompare(browserType, type, kCFCompareCaseInsensitive) == kCFCompareEqualTo) &&
- (CFStringCompare(browserDomain, domain, kCFCompareCaseInsensitive) == kCFCompareEqualTo))
- {
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: found a duplicate browser\n", sPluginIdentifier, __FUNCTION__);
- browser = browsers[i];
- NetBrowserInfoRetain(NULL, browser);
- break;
- }
- }
-
- // No match found, lets create one!
- if (!browser)
- {
-
- browser = NetBrowserInfoCreate(type, domain, plugin);
-
- if (!browser)
- {
- fprintf(stderr, "%s:%s failed to search for %s.%s", sPluginIdentifier, __FUNCTION__, CStringFromCFString(type), CStringFromCFString(domain));
- free(dicts);
- free(browsers);
- return NULL;
- }
-
- // Service browser created, lets add this to ourselves to the dictionary.
- CFMutableDictionaryRef browserDict = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-
- CFDictionarySetValue(browserDict, sServiceTypeKey, type);
- CFDictionarySetValue(browserDict, sServiceDomainKey, domain);
-
- // Add the dictionary to the browsers dictionary.
- CFDictionarySetValue(plugin->_browsers, browser, browserDict);
-
- NetBrowserInfoRelease(NULL, browser);
-
- // Release Memory
- CFRelease(browserDict);
- }
-
- free(dicts);
- free(browsers);
-
- return browser;
-}
-
-/*****************************************************************************
-* BrowserForSDRef
-* -
-* This method returns a NetBrowserInfo that matches the calling SDRef passed
-* in via the callback.
-*****************************************************************************/
-NetBrowserInfo* BrowserForSDRef(BonjourUserEventsPlugin* plugin, DNSServiceRef sdRef)
-{
- CFIndex i;
- CFIndex count = CFDictionaryGetCount(plugin->_browsers);
- NetBrowserInfo* browser = NULL;
- NetBrowserInfo** browsers = malloc(count * sizeof(NetBrowserInfo*));
-
- // Fetch the values of the browser dictionary
- CFDictionaryGetKeysAndValues(plugin->_browsers, (const void**)browsers, NULL);
-
- // Loop thru the browsers list and see if we can find a matching one.
- for (i = 0; i < count; ++i)
- {
- NetBrowserInfo* currentBrowser = browsers[i];
-
- if (currentBrowser->browserRef == sdRef)
- {
- browser = currentBrowser;
- break;
- }
- }
-
-
- free(browsers);
-
- return browser;
-}
-
-/*****************************************************************************
-* AddEventDictionary
-* -
-* Adds a event to a browser's event dictionary
-*****************************************************************************/
-
-void AddEventDictionary(CFDictionaryRef eventDict, CFMutableDictionaryRef allEventsDictionary, NetBrowserInfo* key)
-{
- CFMutableArrayRef eventsForBrowser = (CFMutableArrayRef)CFDictionaryGetValue(allEventsDictionary, key);
-
- if (!eventsForBrowser) // We have no events for this browser yet, lets add him.
- {
- eventsForBrowser = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- CFDictionarySetValue(allEventsDictionary, key, eventsForBrowser);
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s creating a new array", sPluginIdentifier, __FUNCTION__);
- }
- else
- {
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s Incrementing refcount", sPluginIdentifier, __FUNCTION__);
- CFRetain(eventsForBrowser);
- }
-
- CFArrayAppendValue(eventsForBrowser, eventDict);
- CFRelease(eventsForBrowser);
-}
-
-/*****************************************************************************
-* RemoveEventFromArray
-* -
-* Searches a Array of Event Dictionaries to find one with a matching launchd
-* token and remove it.
-*****************************************************************************/
-
-void RemoveEventFromArray(CFMutableArrayRef array, CFNumberRef launchdToken)
-{
- CFIndex i;
- CFIndex count = CFArrayGetCount(array);
-
- // Loop thru looking for us.
- for (i = 0; i < count; )
- {
- CFDictionaryRef eventDict = CFArrayGetValueAtIndex(array, i);
- CFNumberRef token = CFDictionaryGetValue(eventDict, sLaunchdTokenKey);
-
- if (CFEqual(token, launchdToken)) // This is the same event?
- {
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s found token", sPluginIdentifier, __FUNCTION__);
- CFArrayRemoveValueAtIndex(array, i); // Remove the event,
- break; // The token should only exist once, so it makes no sense to continue.
- }
- else
- {
- ++i; // If it's not us, advance.
- }
- }
- if (i == count) asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s did not find token", sPluginIdentifier, __FUNCTION__);
-}
-
-#pragma mark -
-#pragma mark Net Service Browser Stuff
-#pragma mark -
-
-/*****************************************************************************
-* ServiceBrowserCallback
-* -
-* This method is the heart of the plugin. It's the runloop callback annoucing
-* the appearence and disappearance of network services.
-*****************************************************************************/
-
-void ServiceBrowserCallback (DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char* serviceName,
- const char* regtype,
- const char* replyDomain,
- void* context )
-{
- (void)interfaceIndex;
- (void)regtype;
- (void)replyDomain;
- BonjourUserEventsPlugin* plugin = (BonjourUserEventsPlugin*)context;
- NetBrowserInfo* browser = BrowserForSDRef(plugin, sdRef);
-
- if (!browser) // Missing browser?
- {
- fprintf(stderr, "%s:%s ServiceBrowserCallback: missing browser\n", sPluginIdentifier, __FUNCTION__);
- return;
- }
-
- if (errorCode != kDNSServiceErr_NoError)
- {
- fprintf(stderr, "%s:%s ServiceBrowserCallback: errcode set %d\n", sPluginIdentifier, __FUNCTION__, errorCode);
- return;
- }
-
- CFStringRef cfServiceName = CFStringCreateWithCString(NULL, serviceName, kCFStringEncodingUTF8);
-
- if (flags & kDNSServiceFlagsAdd)
- {
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s calling HandleTemporaryEventsForService Add\n", sPluginIdentifier, __FUNCTION__);
- HandleTemporaryEventsForService(plugin, browser, cfServiceName, plugin->_onAddEvents);
- }
- else
- {
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s calling HandleTemporaryEventsForService Remove\n", sPluginIdentifier, __FUNCTION__);
- HandleTemporaryEventsForService(plugin, browser, cfServiceName, plugin->_onRemoveEvents);
- }
-
- CFRelease(cfServiceName);
-}
-
-/*****************************************************************************
-* HandleTemporaryEventsForService
-* -
-* This method handles the firing of one shot events. Aka. Events that are
-* signaled when a service appears / disappears. They have a temporarly
-* signaled state.
-*****************************************************************************/
-void HandleTemporaryEventsForService(BonjourUserEventsPlugin* plugin, NetBrowserInfo* browser, CFStringRef serviceName, CFMutableDictionaryRef eventsDictionary)
-{
- CFArrayRef events = (CFArrayRef)CFDictionaryGetValue(eventsDictionary, browser); // Get events for the browser we passed in.
- CFIndex i;
- CFIndex count;
-
- if (!events) // Somehow we have a orphan browser...
- return;
-
- count = CFArrayGetCount(events);
-
- // Go thru the events and run filters, notifity if they pass.
- for (i = 0; i < count; ++i)
- {
- CFDictionaryRef eventDict = (CFDictionaryRef)CFArrayGetValueAtIndex(events, i);
- CFStringRef eventServiceName = (CFStringRef)CFDictionaryGetValue(eventDict, sServiceNameKey);
- CFNumberRef token = (CFNumberRef) CFDictionaryGetValue(eventDict, sLaunchdTokenKey);
- CFDictionaryRef dict = (CFDictionaryRef) CFDictionaryGetValue(eventDict, sLaunchdDictKey);
-
- // Currently we only filter on service name, that makes this as simple as...
- if (!eventServiceName || CFEqual(serviceName, eventServiceName))
- {
- uint64_t tokenUint64;
- // Signal Event: This is edge trigger. When the action has been taken, it will not
- // be remembered anymore.
-
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s HandleTemporaryEventsForService signal\n", sPluginIdentifier, __FUNCTION__);
- CFNumberGetValue(token, kCFNumberLongLongType, &tokenUint64);
-
- xpc_object_t jobRequest = _CFXPCCreateXPCObjectFromCFObject(dict);
-
- UserEventAgentFireEvent(plugin->_pluginContext, tokenUint64, jobRequest);
- xpc_release(jobRequest);
- }
- }
-}
-
-#pragma mark -
-#pragma mark Convenience
-#pragma mark -
-
-/*****************************************************************************
-* CStringFromCFString
-* -
-* Silly convenence function for dealing with non-critical CFSTR -> cStr
-* conversions.
-*****************************************************************************/
-
-const char* CStringFromCFString(CFStringRef string)
-{
- const char* defaultString = "??????";
- const char* cstring;
-
- if (!string)
- return defaultString;
-
- cstring = CFStringGetCStringPtr(string, kCFStringEncodingUTF8);
-
- return (cstring) ? cstring : defaultString;
-
-}
-
-#pragma mark -
-#pragma mark NetBrowserInfo "Object"
-#pragma mark -
-/*****************************************************************************
-* NetBrowserInfoCreate
-* -
-* The method creates a NetBrowserInfo Object and initalizes it.
-*****************************************************************************/
-NetBrowserInfo* NetBrowserInfoCreate(CFStringRef serviceType, CFStringRef domain, void* context)
-{
- NetBrowserInfo* outObj = NULL;
- DNSServiceRef browserRef = NULL;
- char* cServiceType = NULL;
- char* cDomain = NULL;
- Boolean success = true;
-
- CFIndex serviceSize = CFStringGetMaximumSizeForEncoding(CFStringGetLength(serviceType), kCFStringEncodingUTF8);
- cServiceType = calloc(serviceSize, 1);
- success = CFStringGetCString(serviceType, cServiceType, serviceSize, kCFStringEncodingUTF8);
-
-
- if (domain)
- {
- CFIndex domainSize = CFStringGetMaximumSizeForEncoding(CFStringGetLength(domain), kCFStringEncodingUTF8);
- if (domainSize)
- {
- cDomain = calloc(domainSize, 1);
- success = success && CFStringGetCString(domain, cDomain, domainSize, kCFStringEncodingUTF8);
- }
- }
-
- if (!success)
- {
- fprintf(stderr, "%s:%s LaunchEvent has badly encoded service type or domain.\n", sPluginIdentifier, __FUNCTION__);
- free(cServiceType);
-
- if (cDomain)
- free(cDomain);
-
- return NULL;
- }
-
- DNSServiceErrorType err = DNSServiceBrowse(&browserRef, 0, 0, cServiceType, cDomain, ServiceBrowserCallback, context);
-
- if (err != kDNSServiceErr_NoError)
- {
- fprintf(stderr, "%s:%s Failed to create browser for %s, %s\n", sPluginIdentifier, __FUNCTION__, cServiceType, cDomain);
- free(cServiceType);
-
- if (cDomain)
- free(cDomain);
-
- return NULL;
- }
-
- DNSServiceSetDispatchQueue(browserRef, dispatch_get_main_queue());
-
-
- outObj = malloc(sizeof(NetBrowserInfo));
-
- outObj->refCount = 1;
- outObj->browserRef = browserRef;
-
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: created new object %p", sPluginIdentifier, __FUNCTION__, outObj);
-
- free(cServiceType);
-
- if (cDomain)
- free(cDomain);
-
- return outObj;
-}
-
-/*****************************************************************************
-* NetBrowserInfoRetain
-* -
-* The method retains a NetBrowserInfo object.
-*****************************************************************************/
-const void* NetBrowserInfoRetain(CFAllocatorRef allocator, const void* info)
-{
- (void)allocator;
- NetBrowserInfo* obj = (NetBrowserInfo*)info;
-
- if (!obj)
- return NULL;
-
- ++obj->refCount;
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Incremented ref count on %p, count %d", sPluginIdentifier, __FUNCTION__, obj->browserRef, (int)obj->refCount);
-
- return obj;
-}
-
-/*****************************************************************************
-* NetBrowserInfoRelease
-* -
-* The method releases a NetBrowserInfo object.
-*****************************************************************************/
-void NetBrowserInfoRelease(CFAllocatorRef allocator, const void* info)
-{
- (void)allocator;
- NetBrowserInfo* obj = (NetBrowserInfo*)info;
-
- if (!obj)
- return;
-
- if (obj->refCount == 1)
- {
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: DNSServiceRefDeallocate %p", sPluginIdentifier, __FUNCTION__, obj->browserRef);
- DNSServiceRefDeallocate(obj->browserRef);
- free(obj);
- }
- else
- {
- --obj->refCount;
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Decremented ref count on %p, count %d", sPluginIdentifier, __FUNCTION__, obj->browserRef, (int)obj->refCount);
- }
-
-}
-
-/*****************************************************************************
-* NetBrowserInfoEqual
-* -
-* The method is used to compare two NetBrowserInfo objects for equality.
-*****************************************************************************/
-Boolean NetBrowserInfoEqual(const void *value1, const void *value2)
-{
- NetBrowserInfo* obj1 = (NetBrowserInfo*)value1;
- NetBrowserInfo* obj2 = (NetBrowserInfo*)value2;
-
- if (obj1->browserRef == obj2->browserRef)
- return true;
-
- return false;
-}
-
-/*****************************************************************************
-* NetBrowserInfoHash
-* -
-* The method is used to make a hash for the object. We can cheat and use the
-* browser pointer.
-*****************************************************************************/
-CFHashCode NetBrowserInfoHash(const void *value)
-{
- return (CFHashCode)((NetBrowserInfo*)value)->browserRef;
-}
-
-
-/*****************************************************************************
-* NetBrowserInfoCopyDescription
-* -
-* Make CF happy.
-*****************************************************************************/
-CFStringRef NetBrowserInfoCopyDescription(const void *value)
-{
- (void)value;
- return CFStringCreateWithCString(NULL, "NetBrowserInfo: No useful description", kCFStringEncodingUTF8);
-}
-
Copied: vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/BonjourEvents.c (from rev 6984, vendor/apple/mDNSResponder/dist/mDNSMacOSX/BonjourEvents.c)
===================================================================
--- vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/BonjourEvents.c (rev 0)
+++ vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/BonjourEvents.c 2015-03-20 01:14:52 UTC (rev 6985)
@@ -0,0 +1,1001 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreFoundation/CFXPCBridge.h>
+#include "dns_sd.h"
+#include <UserEventAgentInterface.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <asl.h>
+#include <xpc/xpc.h>
+
+
+#pragma mark -
+#pragma mark Types
+#pragma mark -
+static const char* sPluginIdentifier = "com.apple.bonjour.events";
+
+// PLIST Keys
+static const CFStringRef sServiceNameKey = CFSTR("ServiceName");
+static const CFStringRef sServiceTypeKey = CFSTR("ServiceType");
+static const CFStringRef sServiceDomainKey = CFSTR("ServiceDomain");
+
+static const CFStringRef sOnServiceAddKey = CFSTR("OnServiceAdd");
+static const CFStringRef sOnServiceRemoveKey = CFSTR("OnServiceRemove");
+
+static const CFStringRef sLaunchdTokenKey = CFSTR("LaunchdToken");
+static const CFStringRef sLaunchdDictKey = CFSTR("LaunchdDict");
+
+
+/************************************************
+* Launch Event Dictionary (input from launchd)
+* Passed To: ManageEventsCallback
+*-----------------------------------------------
+* Typing in this dictionary is not enforced
+* above us. So this may not be true. Type check
+* all input before using it.
+*-----------------------------------------------
+* sServiceNameKey - CFString (Optional)
+* sServiceTypeKey - CFString
+* sServiceDomainKey - CFString
+*
+* One or more of the following.
+*-----------------------------------
+* sOnServiceAddKey - CFBoolean
+* sOnServiceRemoveKey - CFBoolean
+* sWhileServiceExistsKey - CFBoolean
+************************************************/
+
+/************************************************
+* Browser Dictionary
+*-----------------------------------------------
+* sServiceDomainKey - CFString
+* sServiceTypeKey - CFString
+************************************************/
+
+/************************************************
+* Event Dictionary
+*-----------------------------------------------
+* sServiceNameKey - CFString (Optional)
+* sLaunchdTokenKey - CFNumber
+************************************************/
+
+typedef struct {
+ UserEventAgentInterfaceStruct* _UserEventAgentInterface;
+ CFUUIDRef _factoryID;
+ UInt32 _refCount;
+
+ void* _pluginContext;
+
+ CFMutableDictionaryRef _tokenToBrowserMap; // Maps a token to a browser that can be used to scan the remaining dictionaries.
+ CFMutableDictionaryRef _browsers; // A Dictionary of Browser Dictionaries where the resposible browser is the key.
+ CFMutableDictionaryRef _onAddEvents; // A Dictionary of Event Dictionaries that describe events to trigger on a service appearing.
+ CFMutableDictionaryRef _onRemoveEvents; // A Dictionary of Event Dictionaries that describe events to trigger on a service disappearing.
+} BonjourUserEventsPlugin;
+
+typedef struct {
+ CFIndex refCount;
+ DNSServiceRef browserRef;
+} NetBrowserInfo;
+
+#pragma mark -
+#pragma mark Prototypes
+#pragma mark -
+// COM Stuff
+static HRESULT QueryInterface(void *myInstance, REFIID iid, LPVOID *ppv);
+static ULONG AddRef(void* instance);
+static ULONG Release(void* instance);
+
+static BonjourUserEventsPlugin* Alloc(CFUUIDRef factoryID);
+static void Dealloc(BonjourUserEventsPlugin* plugin);
+
+void * UserEventAgentFactory(CFAllocatorRef allocator, CFUUIDRef typeID);
+
+// Plugin Management
+static void Install(void* instance);
+static void ManageEventsCallback(
+ UserEventAgentLaunchdAction action,
+ CFNumberRef token,
+ CFTypeRef eventMatchDict,
+ void * vContext);
+
+
+// Plugin Guts
+void AddEventToPlugin(BonjourUserEventsPlugin* plugin, CFNumberRef launchdToken, CFDictionaryRef eventParameters);
+void RemoveEventFromPlugin(BonjourUserEventsPlugin* plugin, CFNumberRef launchToken);
+
+NetBrowserInfo* CreateBrowser(BonjourUserEventsPlugin* plugin, CFStringRef type, CFStringRef domain);
+NetBrowserInfo* BrowserForSDRef(BonjourUserEventsPlugin* plugin, DNSServiceRef sdRef);
+void AddEventDictionary(CFDictionaryRef eventDict, CFMutableDictionaryRef allEventsDictionary, NetBrowserInfo* key);
+void RemoveEventFromArray(CFMutableArrayRef array, CFNumberRef launchdToken);
+
+// Net Service Browser Stuff
+void ServiceBrowserCallback (DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char* serviceName, const char* regtype, const char* replyDomain, void* context);
+void HandleTemporaryEventsForService(BonjourUserEventsPlugin* plugin, NetBrowserInfo* browser, CFStringRef serviceName, CFMutableDictionaryRef eventsDictionary);
+
+// Convence Stuff
+const char* CStringFromCFString(CFStringRef string);
+
+// NetBrowserInfo "Object"
+NetBrowserInfo* NetBrowserInfoCreate(CFStringRef serviceType, CFStringRef domain, void* context);
+const void* NetBrowserInfoRetain(CFAllocatorRef allocator, const void* info);
+void NetBrowserInfoRelease(CFAllocatorRef allocator, const void* info);
+Boolean NetBrowserInfoEqual(const void *value1, const void *value2);
+CFHashCode NetBrowserInfoHash(const void *value);
+CFStringRef NetBrowserInfoCopyDescription(const void *value);
+
+static const CFDictionaryKeyCallBacks kNetBrowserInfoDictionaryKeyCallbacks = {
+ 0,
+ NetBrowserInfoRetain,
+ NetBrowserInfoRelease,
+ NetBrowserInfoCopyDescription,
+ NetBrowserInfoEqual,
+ NetBrowserInfoHash
+};
+
+static const CFDictionaryValueCallBacks kNetBrowserInfoDictionaryValueCallbacks = {
+ 0,
+ NetBrowserInfoRetain,
+ NetBrowserInfoRelease,
+ NetBrowserInfoCopyDescription,
+ NetBrowserInfoEqual
+};
+
+// COM type definition goop.
+static UserEventAgentInterfaceStruct UserEventAgentInterfaceFtbl = {
+ NULL, // Required padding for COM
+ QueryInterface, // Query Interface
+ AddRef, // AddRef()
+ Release, // Release()
+ Install // Install
+};
+
+#pragma mark -
+#pragma mark COM Management
+#pragma mark -
+
+/*****************************************************************************
+*****************************************************************************/
+static HRESULT QueryInterface(void *myInstance, REFIID iid, LPVOID *ppv)
+{
+ CFUUIDRef interfaceID = CFUUIDCreateFromUUIDBytes(NULL, iid);
+
+ // Test the requested ID against the valid interfaces.
+ if(CFEqual(interfaceID, kUserEventAgentInterfaceID))
+ {
+ ((BonjourUserEventsPlugin *) myInstance)->_UserEventAgentInterface->AddRef(myInstance);
+ *ppv = myInstance;
+ CFRelease(interfaceID);
+ return S_OK;
+ }
+ else if(CFEqual(interfaceID, IUnknownUUID))
+ {
+ ((BonjourUserEventsPlugin *) myInstance)->_UserEventAgentInterface->AddRef(myInstance);
+ *ppv = myInstance;
+ CFRelease(interfaceID);
+ return S_OK;
+ }
+ else // Requested interface unknown, bail with error.
+ {
+ *ppv = NULL;
+ CFRelease(interfaceID);
+ return E_NOINTERFACE;
+ }
+}
+
+/*****************************************************************************
+*****************************************************************************/
+static ULONG AddRef(void* instance)
+{
+ BonjourUserEventsPlugin* plugin = (BonjourUserEventsPlugin*)instance;
+ return ++plugin->_refCount;
+}
+
+/*****************************************************************************
+*****************************************************************************/
+static ULONG Release(void* instance)
+{
+ BonjourUserEventsPlugin* plugin = (BonjourUserEventsPlugin*)instance;
+
+ if (plugin->_refCount != 0)
+ --plugin->_refCount;
+
+ if (plugin->_refCount == 0)
+ {
+ Dealloc(instance);
+ return 0;
+ }
+
+ return plugin->_refCount;
+}
+
+/*****************************************************************************
+* Alloc
+* -
+* Functionas as both +[alloc] and -[init] for the plugin. Add any
+* initalization of member variables here.
+*****************************************************************************/
+static BonjourUserEventsPlugin* Alloc(CFUUIDRef factoryID)
+{
+ BonjourUserEventsPlugin* plugin = malloc(sizeof(BonjourUserEventsPlugin));
+
+ plugin->_UserEventAgentInterface = &UserEventAgentInterfaceFtbl;
+ plugin->_pluginContext = NULL;
+
+ if (factoryID)
+ {
+ plugin->_factoryID = (CFUUIDRef)CFRetain(factoryID);
+ CFPlugInAddInstanceForFactory(factoryID);
+ }
+
+ plugin->_refCount = 1;
+ plugin->_tokenToBrowserMap = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kNetBrowserInfoDictionaryValueCallbacks);
+ plugin->_browsers = CFDictionaryCreateMutable(NULL, 0, &kNetBrowserInfoDictionaryKeyCallbacks, &kCFTypeDictionaryValueCallBacks);
+ plugin->_onAddEvents = CFDictionaryCreateMutable(NULL, 0, &kNetBrowserInfoDictionaryKeyCallbacks, &kCFTypeDictionaryValueCallBacks);
+ plugin->_onRemoveEvents = CFDictionaryCreateMutable(NULL, 0, &kNetBrowserInfoDictionaryKeyCallbacks, &kCFTypeDictionaryValueCallBacks);
+
+ return plugin;
+}
+
+/*****************************************************************************
+* Dealloc
+* -
+* Much like Obj-C dealloc this method is responsible for releasing any object
+* this plugin is holding. Unlike ObjC, you call directly free() instead of
+* [super dalloc].
+*****************************************************************************/
+static void Dealloc(BonjourUserEventsPlugin* plugin)
+{
+ CFUUIDRef factoryID = plugin->_factoryID;
+
+ if (factoryID)
+ {
+ CFPlugInRemoveInstanceForFactory(factoryID);
+ CFRelease(factoryID);
+ }
+
+ if (plugin->_tokenToBrowserMap)
+ CFRelease(plugin->_tokenToBrowserMap);
+
+ if (plugin->_browsers)
+ CFRelease(plugin->_browsers);
+
+ if (plugin->_onAddEvents)
+ CFRelease(plugin->_onAddEvents);
+
+ if (plugin->_onRemoveEvents)
+ CFRelease(plugin->_onRemoveEvents);
+
+ free(plugin);
+}
+
+/*******************************************************************************
+*******************************************************************************/
+void * UserEventAgentFactory(CFAllocatorRef allocator, CFUUIDRef typeID)
+{
+ (void)allocator;
+ BonjourUserEventsPlugin * result = NULL;
+
+ if (typeID && CFEqual(typeID, kUserEventAgentTypeID)) {
+ result = Alloc(kUserEventAgentFactoryID);
+ }
+
+ return (void *)result;
+}
+
+#pragma mark -
+#pragma mark Plugin Management
+#pragma mark -
+/*****************************************************************************
+* Install
+* -
+* This is invoked once when the plugin is loaded to do initial setup and
+* allow us to register with launchd. If UserEventAgent crashes, the plugin
+* will need to be reloaded, and hence this will get invoked again.
+*****************************************************************************/
+static void Install(void *instance)
+{
+ BonjourUserEventsPlugin* plugin = (BonjourUserEventsPlugin*)instance;
+
+ plugin->_pluginContext = UserEventAgentRegisterForLaunchEvents(sPluginIdentifier, &ManageEventsCallback, plugin);
+
+ if (!plugin->_pluginContext)
+ {
+ fprintf(stderr, "%s:%s failed to register for launch events.\n", sPluginIdentifier, __FUNCTION__);
+ return;
+ }
+
+}
+
+/*****************************************************************************
+* ManageEventsCallback
+* -
+* This is invoked when launchd loads a event dictionary and needs to inform
+* us what a daemon / agent is looking for.
+*****************************************************************************/
+static void ManageEventsCallback(UserEventAgentLaunchdAction action, CFNumberRef token, CFTypeRef eventMatchDict, void* vContext)
+{
+ if (action == kUserEventAgentLaunchdAdd)
+ {
+ if (!eventMatchDict)
+ {
+ fprintf(stderr, "%s:%s empty dictionary\n", sPluginIdentifier, __FUNCTION__);
+ return;
+ }
+ if (CFGetTypeID(eventMatchDict) != CFDictionaryGetTypeID())
+ {
+ fprintf(stderr, "%s:%s given non-dict for event dictionary, action %d\n", sPluginIdentifier, __FUNCTION__, action);
+ return;
+ }
+ // Launchd wants us to add a launch event for this token and matching dictionary.
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s calling AddEventToPlugin", sPluginIdentifier, __FUNCTION__);
+ AddEventToPlugin((BonjourUserEventsPlugin*)vContext, token, (CFDictionaryRef)eventMatchDict);
+ }
+ else if (action == kUserEventAgentLaunchdRemove)
+ {
+ // Launchd wants us to remove the event hook we setup for this token / matching dictionary.
+ // Note: eventMatchDict can be NULL for Remove.
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s calling RemoveEventToPlugin", sPluginIdentifier, __FUNCTION__);
+ RemoveEventFromPlugin((BonjourUserEventsPlugin*)vContext, token);
+ }
+ else
+ {
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s unknown callback event\n", sPluginIdentifier, __FUNCTION__);
+ }
+}
+
+
+#pragma mark -
+#pragma mark Plugin Guts
+#pragma mark -
+
+/*****************************************************************************
+* AddEventToPlugin
+* -
+* This method is invoked when launchd wishes the plugin to setup a launch
+* event matching the parameters in the dictionary.
+*****************************************************************************/
+void AddEventToPlugin(BonjourUserEventsPlugin* plugin, CFNumberRef launchdToken, CFDictionaryRef eventParameters)
+{
+ CFStringRef domain = CFDictionaryGetValue(eventParameters, sServiceDomainKey);
+ CFStringRef type = CFDictionaryGetValue(eventParameters, sServiceTypeKey);
+ CFStringRef name = CFDictionaryGetValue(eventParameters, sServiceNameKey);
+ CFBooleanRef cfOnAdd = CFDictionaryGetValue(eventParameters, sOnServiceAddKey);
+ CFBooleanRef cfOnRemove = CFDictionaryGetValue(eventParameters, sOnServiceRemoveKey);
+
+ Boolean onAdd = false;
+ Boolean onRemove = false;
+
+ if (cfOnAdd && CFGetTypeID(cfOnAdd) == CFBooleanGetTypeID() && CFBooleanGetValue(cfOnAdd))
+ onAdd = true;
+
+ if (cfOnRemove && CFGetTypeID(cfOnRemove) == CFBooleanGetTypeID() && CFBooleanGetValue(cfOnRemove))
+ onRemove = true;
+
+ // A type is required. If none is specified, BAIL
+ if (!type || CFGetTypeID(type) != CFStringGetTypeID())
+ {
+ fprintf(stderr, "%s:%s: a LaunchEvent is missing a service type.\n", sPluginIdentifier, __FUNCTION__);
+ return;
+ }
+
+ // If we aren't suppose to launch on services appearing or disappearing, this service does nothing. Ignore.
+ if (!onAdd && !onRemove)
+ {
+ fprintf(stderr, "%s:%s a LaunchEvent is missing both onAdd and onRemove events\n", sPluginIdentifier, __FUNCTION__);
+ return;
+ }
+
+ // If no domain is specified, assume local.
+ if (!domain)
+ {
+ domain = CFSTR("local");
+ }
+ else if (CFGetTypeID(domain) != CFStringGetTypeID() ) // If the domain is not a string, fail
+ {
+ fprintf(stderr, "%s:%s a LaunchEvent has a domain that is not a string.\n", sPluginIdentifier, __FUNCTION__);
+ return;
+ }
+
+ // If we have a name filter, but it's not a string. This event is broken, bail.
+ if (name && CFGetTypeID(name) != CFStringGetTypeID())
+ {
+ fprintf(stderr, "%s:%s a LaunchEvent has a domain that is not a string.\n", sPluginIdentifier, __FUNCTION__);
+ return;
+ }
+
+ // Get us a browser
+ NetBrowserInfo* browser = CreateBrowser(plugin, type, domain);
+
+ if (!browser)
+ {
+ fprintf(stderr, "%s:%s cannot create browser\n", sPluginIdentifier, __FUNCTION__);
+ return;
+ }
+
+ // Create Event Dictionary
+ CFMutableDictionaryRef eventDictionary = CFDictionaryCreateMutable(NULL, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+
+ // We store both the Token and the Dictionary. UserEventAgentSetLaunchEventState needs
+ // the token and UserEventAgentSetFireEvent needs both the token and the dictionary
+ CFDictionarySetValue(eventDictionary, sLaunchdTokenKey, launchdToken);
+ CFDictionarySetValue(eventDictionary, sLaunchdDictKey, eventParameters);
+
+ if (name)
+ CFDictionarySetValue(eventDictionary, sServiceNameKey, name);
+
+ // Add to the correct dictionary.
+ if (onAdd)
+ {
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Adding browser to AddEvents", sPluginIdentifier, __FUNCTION__);
+ AddEventDictionary(eventDictionary, plugin->_onAddEvents, browser);
+ }
+
+ if (onRemove)
+ {
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Adding browser to RemoveEvents", sPluginIdentifier, __FUNCTION__);
+ AddEventDictionary(eventDictionary, plugin->_onRemoveEvents, browser);
+ }
+
+ // Add Token Mapping
+ CFDictionarySetValue(plugin->_tokenToBrowserMap, launchdToken, browser);
+
+ // Release Memory
+ CFRelease(eventDictionary);
+}
+
+/*****************************************************************************
+* RemoveEventFromPlugin
+* -
+* This method is invoked when launchd wishes the plugin to setup a launch
+* event matching the parameters in the dictionary.
+*****************************************************************************/
+void RemoveEventFromPlugin(BonjourUserEventsPlugin* plugin, CFNumberRef launchdToken)
+{
+ NetBrowserInfo* browser = (NetBrowserInfo*)CFDictionaryGetValue(plugin->_tokenToBrowserMap, launchdToken);
+ Boolean othersUsingBrowser = false;
+
+ if (!browser)
+ {
+ long long value = 0;
+ CFNumberGetValue(launchdToken, kCFNumberLongLongType, &value);
+ fprintf(stderr, "%s:%s Launchd asked us to remove a token we did not register! ==Token:%lld== \n", sPluginIdentifier, __FUNCTION__, value);
+ return;
+ }
+
+ CFMutableArrayRef onAddEvents = (CFMutableArrayRef)CFDictionaryGetValue(plugin->_onAddEvents, browser);
+ CFMutableArrayRef onRemoveEvents = (CFMutableArrayRef)CFDictionaryGetValue(plugin->_onRemoveEvents, browser);
+
+ if (onAddEvents)
+ {
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Calling RemoveEventFromArray for OnAddEvents", sPluginIdentifier, __FUNCTION__);
+ RemoveEventFromArray(onAddEvents, launchdToken);
+
+ // Is the array now empty, clean up
+ if (CFArrayGetCount(onAddEvents) == 0)
+ {
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Removing the browser from AddEvents", sPluginIdentifier, __FUNCTION__);
+ CFDictionaryRemoveValue(plugin->_onAddEvents, browser);
+ }
+ }
+
+ if (onRemoveEvents)
+ {
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Calling RemoveEventFromArray for OnRemoveEvents", sPluginIdentifier, __FUNCTION__);
+ RemoveEventFromArray(onRemoveEvents, launchdToken);
+
+ // Is the array now empty, clean up
+ if (CFArrayGetCount(onRemoveEvents) == 0)
+ {
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Removing the browser from RemoveEvents", sPluginIdentifier, __FUNCTION__);
+ CFDictionaryRemoveValue(plugin->_onRemoveEvents, browser);
+ }
+ }
+
+ // Remove ourselves from the token dictionary.
+ CFDictionaryRemoveValue(plugin->_tokenToBrowserMap, launchdToken);
+
+ // Check to see if anyone else is using this browser.
+ CFIndex i;
+ CFIndex count = CFDictionaryGetCount(plugin->_tokenToBrowserMap);
+ NetBrowserInfo** browsers = malloc(count * sizeof(NetBrowserInfo*));
+
+ // Fetch the values of the token dictionary
+ CFDictionaryGetKeysAndValues(plugin->_tokenToBrowserMap, NULL, (const void**)browsers);
+
+ for (i = 0; i < count; ++i)
+ {
+ if (NetBrowserInfoEqual(browsers[i], browser))
+ {
+ othersUsingBrowser = true;
+ break;
+ }
+ }
+
+ // If no one else is useing our browser, clean up!
+ if (!othersUsingBrowser)
+ {
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Removing browser %p from _browsers", sPluginIdentifier, __FUNCTION__, browser);
+ CFDictionaryRemoveValue(plugin->_browsers, browser); // This triggers release and dealloc of the browser
+ }
+ else
+ {
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Decrementing browsers %p count", sPluginIdentifier, __FUNCTION__, browser);
+ // Decrement my reference count (it was incremented when it was added to _browsers in CreateBrowser)
+ NetBrowserInfoRelease(NULL, browser);
+ }
+
+ free(browsers);
+}
+
+
+/*****************************************************************************
+* CreateBrowser
+* -
+* This method returns a NetBrowserInfo that is looking for a type of
+* service in a domain. If no browser exists, it will create one and return it.
+*****************************************************************************/
+NetBrowserInfo* CreateBrowser(BonjourUserEventsPlugin* plugin, CFStringRef type, CFStringRef domain)
+{
+ CFIndex i;
+ CFIndex count = CFDictionaryGetCount(plugin->_browsers);
+ NetBrowserInfo* browser = NULL;
+ CFDictionaryRef* dicts = malloc(count * sizeof(CFDictionaryRef));
+ NetBrowserInfo** browsers = malloc(count * sizeof(NetBrowserInfo*));
+
+ // Fetch the values of the browser dictionary
+ CFDictionaryGetKeysAndValues(plugin->_browsers, (const void**)browsers, (const void**)dicts);
+
+
+ // Loop thru the browsers list and see if we can find a matching one.
+ for (i = 0; i < count; ++i)
+ {
+ CFDictionaryRef browserDict = dicts[i];
+
+ CFStringRef browserType = CFDictionaryGetValue(browserDict, sServiceTypeKey);
+ CFStringRef browserDomain = CFDictionaryGetValue(browserDict, sServiceDomainKey);
+
+ // If we have a matching browser, break
+ if ((CFStringCompare(browserType, type, kCFCompareCaseInsensitive) == kCFCompareEqualTo) &&
+ (CFStringCompare(browserDomain, domain, kCFCompareCaseInsensitive) == kCFCompareEqualTo))
+ {
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: found a duplicate browser\n", sPluginIdentifier, __FUNCTION__);
+ browser = browsers[i];
+ NetBrowserInfoRetain(NULL, browser);
+ break;
+ }
+ }
+
+ // No match found, lets create one!
+ if (!browser)
+ {
+
+ browser = NetBrowserInfoCreate(type, domain, plugin);
+
+ if (!browser)
+ {
+ fprintf(stderr, "%s:%s failed to search for %s.%s", sPluginIdentifier, __FUNCTION__, CStringFromCFString(type), CStringFromCFString(domain));
+ free(dicts);
+ free(browsers);
+ return NULL;
+ }
+
+ // Service browser created, lets add this to ourselves to the dictionary.
+ CFMutableDictionaryRef browserDict = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+
+ CFDictionarySetValue(browserDict, sServiceTypeKey, type);
+ CFDictionarySetValue(browserDict, sServiceDomainKey, domain);
+
+ // Add the dictionary to the browsers dictionary.
+ CFDictionarySetValue(plugin->_browsers, browser, browserDict);
+
+ NetBrowserInfoRelease(NULL, browser);
+
+ // Release Memory
+ CFRelease(browserDict);
+ }
+
+ free(dicts);
+ free(browsers);
+
+ return browser;
+}
+
+/*****************************************************************************
+* BrowserForSDRef
+* -
+* This method returns a NetBrowserInfo that matches the calling SDRef passed
+* in via the callback.
+*****************************************************************************/
+NetBrowserInfo* BrowserForSDRef(BonjourUserEventsPlugin* plugin, DNSServiceRef sdRef)
+{
+ CFIndex i;
+ CFIndex count = CFDictionaryGetCount(plugin->_browsers);
+ NetBrowserInfo* browser = NULL;
+ NetBrowserInfo** browsers = malloc(count * sizeof(NetBrowserInfo*));
+
+ // Fetch the values of the browser dictionary
+ CFDictionaryGetKeysAndValues(plugin->_browsers, (const void**)browsers, NULL);
+
+ // Loop thru the browsers list and see if we can find a matching one.
+ for (i = 0; i < count; ++i)
+ {
+ NetBrowserInfo* currentBrowser = browsers[i];
+
+ if (currentBrowser->browserRef == sdRef)
+ {
+ browser = currentBrowser;
+ break;
+ }
+ }
+
+
+ free(browsers);
+
+ return browser;
+}
+
+/*****************************************************************************
+* AddEventDictionary
+* -
+* Adds a event to a browser's event dictionary
+*****************************************************************************/
+
+void AddEventDictionary(CFDictionaryRef eventDict, CFMutableDictionaryRef allEventsDictionary, NetBrowserInfo* key)
+{
+ CFMutableArrayRef eventsForBrowser = (CFMutableArrayRef)CFDictionaryGetValue(allEventsDictionary, key);
+
+ if (!eventsForBrowser) // We have no events for this browser yet, lets add him.
+ {
+ eventsForBrowser = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ CFDictionarySetValue(allEventsDictionary, key, eventsForBrowser);
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s creating a new array", sPluginIdentifier, __FUNCTION__);
+ }
+ else
+ {
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s Incrementing refcount", sPluginIdentifier, __FUNCTION__);
+ CFRetain(eventsForBrowser);
+ }
+
+ CFArrayAppendValue(eventsForBrowser, eventDict);
+ CFRelease(eventsForBrowser);
+}
+
+/*****************************************************************************
+* RemoveEventFromArray
+* -
+* Searches a Array of Event Dictionaries to find one with a matching launchd
+* token and remove it.
+*****************************************************************************/
+
+void RemoveEventFromArray(CFMutableArrayRef array, CFNumberRef launchdToken)
+{
+ CFIndex i;
+ CFIndex count = CFArrayGetCount(array);
+
+ // Loop thru looking for us.
+ for (i = 0; i < count; )
+ {
+ CFDictionaryRef eventDict = CFArrayGetValueAtIndex(array, i);
+ CFNumberRef token = CFDictionaryGetValue(eventDict, sLaunchdTokenKey);
+
+ if (CFEqual(token, launchdToken)) // This is the same event?
+ {
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s found token", sPluginIdentifier, __FUNCTION__);
+ CFArrayRemoveValueAtIndex(array, i); // Remove the event,
+ break; // The token should only exist once, so it makes no sense to continue.
+ }
+ else
+ {
+ ++i; // If it's not us, advance.
+ }
+ }
+ if (i == count) asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s did not find token", sPluginIdentifier, __FUNCTION__);
+}
+
+#pragma mark -
+#pragma mark Net Service Browser Stuff
+#pragma mark -
+
+/*****************************************************************************
+* ServiceBrowserCallback
+* -
+* This method is the heart of the plugin. It's the runloop callback annoucing
+* the appearence and disappearance of network services.
+*****************************************************************************/
+
+void ServiceBrowserCallback (DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char* serviceName,
+ const char* regtype,
+ const char* replyDomain,
+ void* context )
+{
+ (void)interfaceIndex;
+ (void)regtype;
+ (void)replyDomain;
+ BonjourUserEventsPlugin* plugin = (BonjourUserEventsPlugin*)context;
+ NetBrowserInfo* browser = BrowserForSDRef(plugin, sdRef);
+
+ if (!browser) // Missing browser?
+ {
+ fprintf(stderr, "%s:%s ServiceBrowserCallback: missing browser\n", sPluginIdentifier, __FUNCTION__);
+ return;
+ }
+
+ if (errorCode != kDNSServiceErr_NoError)
+ {
+ fprintf(stderr, "%s:%s ServiceBrowserCallback: errcode set %d\n", sPluginIdentifier, __FUNCTION__, errorCode);
+ return;
+ }
+
+ CFStringRef cfServiceName = CFStringCreateWithCString(NULL, serviceName, kCFStringEncodingUTF8);
+ if (cfServiceName == NULL)
+ {
+ static int msgCount = 0;
+ if (msgCount < 1000)
+ {
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s Can not create CFString for serviceName %s", sPluginIdentifier, __FUNCTION__, serviceName);
+ msgCount++;
+ }
+ return;
+ }
+
+ if (flags & kDNSServiceFlagsAdd)
+ {
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s calling HandleTemporaryEventsForService Add\n", sPluginIdentifier, __FUNCTION__);
+ HandleTemporaryEventsForService(plugin, browser, cfServiceName, plugin->_onAddEvents);
+ }
+ else
+ {
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s calling HandleTemporaryEventsForService Remove\n", sPluginIdentifier, __FUNCTION__);
+ HandleTemporaryEventsForService(plugin, browser, cfServiceName, plugin->_onRemoveEvents);
+ }
+
+ CFRelease(cfServiceName);
+}
+
+/*****************************************************************************
+* HandleTemporaryEventsForService
+* -
+* This method handles the firing of one shot events. Aka. Events that are
+* signaled when a service appears / disappears. They have a temporarly
+* signaled state.
+*****************************************************************************/
+void HandleTemporaryEventsForService(BonjourUserEventsPlugin* plugin, NetBrowserInfo* browser, CFStringRef serviceName, CFMutableDictionaryRef eventsDictionary)
+{
+ CFArrayRef events = (CFArrayRef)CFDictionaryGetValue(eventsDictionary, browser); // Get events for the browser we passed in.
+ CFIndex i;
+ CFIndex count;
+
+ if (!events) // Somehow we have a orphan browser...
+ return;
+
+ count = CFArrayGetCount(events);
+
+ // Go thru the events and run filters, notifity if they pass.
+ for (i = 0; i < count; ++i)
+ {
+ CFDictionaryRef eventDict = (CFDictionaryRef)CFArrayGetValueAtIndex(events, i);
+ CFStringRef eventServiceName = (CFStringRef)CFDictionaryGetValue(eventDict, sServiceNameKey);
+ CFNumberRef token = (CFNumberRef) CFDictionaryGetValue(eventDict, sLaunchdTokenKey);
+ CFDictionaryRef dict = (CFDictionaryRef) CFDictionaryGetValue(eventDict, sLaunchdDictKey);
+
+ // Currently we only filter on service name, that makes this as simple as...
+ if (!eventServiceName || CFEqual(serviceName, eventServiceName))
+ {
+ uint64_t tokenUint64;
+ // Signal Event: This is edge trigger. When the action has been taken, it will not
+ // be remembered anymore.
+
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s HandleTemporaryEventsForService signal\n", sPluginIdentifier, __FUNCTION__);
+ CFNumberGetValue(token, kCFNumberLongLongType, &tokenUint64);
+
+ xpc_object_t jobRequest = _CFXPCCreateXPCObjectFromCFObject(dict);
+
+ UserEventAgentFireEvent(plugin->_pluginContext, tokenUint64, jobRequest);
+ xpc_release(jobRequest);
+ }
+ }
+}
+
+#pragma mark -
+#pragma mark Convenience
+#pragma mark -
+
+/*****************************************************************************
+* CStringFromCFString
+* -
+* Silly convenence function for dealing with non-critical CFSTR -> cStr
+* conversions.
+*****************************************************************************/
+
+const char* CStringFromCFString(CFStringRef string)
+{
+ const char* defaultString = "??????";
+ const char* cstring;
+
+ if (!string)
+ return defaultString;
+
+ cstring = CFStringGetCStringPtr(string, kCFStringEncodingUTF8);
+
+ return (cstring) ? cstring : defaultString;
+
+}
+
+#pragma mark -
+#pragma mark NetBrowserInfo "Object"
+#pragma mark -
+/*****************************************************************************
+* NetBrowserInfoCreate
+* -
+* The method creates a NetBrowserInfo Object and initalizes it.
+*****************************************************************************/
+NetBrowserInfo* NetBrowserInfoCreate(CFStringRef serviceType, CFStringRef domain, void* context)
+{
+ NetBrowserInfo* outObj = NULL;
+ DNSServiceRef browserRef = NULL;
+ char* cServiceType = NULL;
+ char* cDomain = NULL;
+ Boolean success = true;
+
+ CFIndex serviceSize = CFStringGetMaximumSizeForEncoding(CFStringGetLength(serviceType), kCFStringEncodingUTF8);
+ cServiceType = calloc(serviceSize, 1);
+ success = CFStringGetCString(serviceType, cServiceType, serviceSize, kCFStringEncodingUTF8);
+
+
+ if (domain)
+ {
+ CFIndex domainSize = CFStringGetMaximumSizeForEncoding(CFStringGetLength(domain), kCFStringEncodingUTF8);
+ if (domainSize)
+ {
+ cDomain = calloc(domainSize, 1);
+ success = success && CFStringGetCString(domain, cDomain, domainSize, kCFStringEncodingUTF8);
+ }
+ }
+
+ if (!success)
+ {
+ fprintf(stderr, "%s:%s LaunchEvent has badly encoded service type or domain.\n", sPluginIdentifier, __FUNCTION__);
+ free(cServiceType);
+
+ if (cDomain)
+ free(cDomain);
+
+ return NULL;
+ }
+
+ DNSServiceErrorType err = DNSServiceBrowse(&browserRef, 0, 0, cServiceType, cDomain, ServiceBrowserCallback, context);
+
+ if (err != kDNSServiceErr_NoError)
+ {
+ fprintf(stderr, "%s:%s Failed to create browser for %s, %s\n", sPluginIdentifier, __FUNCTION__, cServiceType, cDomain);
+ free(cServiceType);
+
+ if (cDomain)
+ free(cDomain);
+
+ return NULL;
+ }
+
+ DNSServiceSetDispatchQueue(browserRef, dispatch_get_main_queue());
+
+
+ outObj = malloc(sizeof(NetBrowserInfo));
+
+ outObj->refCount = 1;
+ outObj->browserRef = browserRef;
+
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: created new object %p", sPluginIdentifier, __FUNCTION__, outObj);
+
+ free(cServiceType);
+
+ if (cDomain)
+ free(cDomain);
+
+ return outObj;
+}
+
+/*****************************************************************************
+* NetBrowserInfoRetain
+* -
+* The method retains a NetBrowserInfo object.
+*****************************************************************************/
+const void* NetBrowserInfoRetain(CFAllocatorRef allocator, const void* info)
+{
+ (void)allocator;
+ NetBrowserInfo* obj = (NetBrowserInfo*)info;
+
+ if (!obj)
+ return NULL;
+
+ ++obj->refCount;
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Incremented ref count on %p, count %d", sPluginIdentifier, __FUNCTION__, obj->browserRef, (int)obj->refCount);
+
+ return obj;
+}
+
+/*****************************************************************************
+* NetBrowserInfoRelease
+* -
+* The method releases a NetBrowserInfo object.
+*****************************************************************************/
+void NetBrowserInfoRelease(CFAllocatorRef allocator, const void* info)
+{
+ (void)allocator;
+ NetBrowserInfo* obj = (NetBrowserInfo*)info;
+
+ if (!obj)
+ return;
+
+ if (obj->refCount == 1)
+ {
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: DNSServiceRefDeallocate %p", sPluginIdentifier, __FUNCTION__, obj->browserRef);
+ DNSServiceRefDeallocate(obj->browserRef);
+ free(obj);
+ }
+ else
+ {
+ --obj->refCount;
+ asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Decremented ref count on %p, count %d", sPluginIdentifier, __FUNCTION__, obj->browserRef, (int)obj->refCount);
+ }
+
+}
+
+/*****************************************************************************
+* NetBrowserInfoEqual
+* -
+* The method is used to compare two NetBrowserInfo objects for equality.
+*****************************************************************************/
+Boolean NetBrowserInfoEqual(const void *value1, const void *value2)
+{
+ NetBrowserInfo* obj1 = (NetBrowserInfo*)value1;
+ NetBrowserInfo* obj2 = (NetBrowserInfo*)value2;
+
+ if (obj1->browserRef == obj2->browserRef)
+ return true;
+
+ return false;
+}
+
+/*****************************************************************************
+* NetBrowserInfoHash
+* -
+* The method is used to make a hash for the object. We can cheat and use the
+* browser pointer.
+*****************************************************************************/
+CFHashCode NetBrowserInfoHash(const void *value)
+{
+ return (CFHashCode)((NetBrowserInfo*)value)->browserRef;
+}
+
+
+/*****************************************************************************
+* NetBrowserInfoCopyDescription
+* -
+* Make CF happy.
+*****************************************************************************/
+CFStringRef NetBrowserInfoCopyDescription(const void *value)
+{
+ (void)value;
+ return CFStringCreateWithCString(NULL, "NetBrowserInfo: No useful description", kCFStringEncodingUTF8);
+}
+
Deleted: vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/LaunchDaemonInfo.plist
===================================================================
(Binary files differ)
Copied: vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/LaunchDaemonInfo.plist (from rev 6984, vendor/apple/mDNSResponder/dist/mDNSMacOSX/LaunchDaemonInfo.plist)
===================================================================
(Binary files differ)
Deleted: vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/Private/dns_services.c
===================================================================
--- vendor/apple/mDNSResponder/dist/mDNSMacOSX/Private/dns_services.c 2014-06-30 23:58:12 UTC (rev 6706)
+++ vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/Private/dns_services.c 2015-03-20 01:14:52 UTC (rev 6985)
@@ -1,212 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2012 Apple Inc. All rights reserved.
- *
- * PRIVATE DNSX CLIENT LIBRARY --FOR Apple Platforms ONLY OSX/iOS--
- * Resides in /usr/lib/libdns_services.dylib
- */
-
-#include "dns_services.h"
-#include "dns_xpc.h"
-#include <xpc/xpc.h>
-#include <Block.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <syslog.h>
-
-//*************************************************************************************************************
-// Globals
-
-#define connection_t xpc_connection_t
-
-struct _DNSXConnRef_t
-{
- connection_t conn_ref; // xpc_connection between client and daemon
- dispatch_queue_t lib_q; // internal queue created in library itself
- void *AppCallBack; // Callback function ptr for Client
- dispatch_queue_t client_q; // Queue specified by client for scheduling its Callback
-};
-
-//*************************************************************************************************************
-// Utility Functions
-
-static bool LogDebugEnabled()
-{
- return false;
-}
-
-static void LogDebug(const char *prefix, xpc_object_t o)
-{
- if (!LogDebugEnabled())
- return;
-
- char *desc = xpc_copy_description(o);
- syslog(LOG_INFO, "%s: %s", prefix, desc);
- free(desc);
-}
-
-//**************************************************************************************************************
-
-void DNSXRefDeAlloc(DNSXConnRef connRef)
-{
- if (!connRef)
- {
- syslog(LOG_WARNING, "dns_services: DNSXRefDeAlloc called with NULL DNSXConnRef");
- return;
- }
-
- // Schedule this work on the internal library queue
- dispatch_sync(connRef->lib_q, ^{
-
- xpc_release(connRef->conn_ref);
- connRef->AppCallBack = NULL;
- dispatch_release(connRef->client_q);
-
- });
-
- dispatch_release(connRef->lib_q);
- free(connRef);
-
- syslog(LOG_INFO, "dns_services: DNSXRefDeAlloc successfully DeAllocated connRef");
-
-}
-
-// Sends the Msg(Dictionary) to the Server
-static DNSXErrorType SendMsgToServer(DNSXConnRef *connRef, xpc_object_t msg, bool old_conn)
-{
- DNSXErrorType errx = kDNSX_NoError;
-
- LogDebug("dns_services: SendMsgToServer", msg);
-
- xpc_connection_set_event_handler((*connRef)->conn_ref, ^(xpc_object_t recv_msg)
- {
- xpc_type_t type = xpc_get_type(recv_msg);
-
- if (type == XPC_TYPE_DICTIONARY)
- {
- LogDebug("dns_services: SendMsgToServer SUCCESS CALLBACK FROM SERVER", recv_msg);
- syslog(LOG_INFO, "dns_services: Successfully Sent Msg to the Daemon");
- uint64_t daemon_status = xpc_dictionary_get_uint64(recv_msg, kDNSDaemonReply);
-
- // Schedule the AppCallBacks on the Client Specified Queue
- switch (daemon_status)
- {
- case kDNSDaemonEngaged:
- dispatch_async((*connRef)->client_q, ^{
- ((DNSXEnableProxyReply)(*connRef)->AppCallBack)((*connRef), kDNSX_Engaged);
- });
- break;
- case kDNSMsgReceived:
- dispatch_async((*connRef)->client_q, ^{
- ((DNSXEnableProxyReply)(*connRef)->AppCallBack)((*connRef), kDNSX_NoError);
- });
- break;
- default:
- dispatch_async((*connRef)->client_q, ^{
- ((DNSXEnableProxyReply)(*connRef)->AppCallBack)((*connRef), kDNSX_UnknownErr);
- });
- break;
- }
-
- }
- else
- {
- LogDebug("dns_services: SendMsgToServer UNEXPECTED CALLBACK FROM SERVER", recv_msg);
- syslog(LOG_WARNING, "dns_services: Connection failed since NO privileges to access service OR Daemon NOT Running");
- dispatch_async((*connRef)->client_q, ^{
- ((DNSXEnableProxyReply)(*connRef)->AppCallBack)((*connRef), kDNSX_DaemonNotRunning);
- });
- }
- });
-
- // To prevent Over-Resume of a connection
- if (!old_conn)
- xpc_connection_resume((*connRef)->conn_ref);
- xpc_connection_send_message((*connRef)->conn_ref, msg);
- if (!errx)
- syslog(LOG_INFO, "dns_services: SendMSgToServer sent Msg Dict successfully to Daemon");
- return errx;
-}
-
-// Creates a new DNSX Connection Reference(DNSXConnRef).
-// If DNSXConnRef exists, you may want to use that depending on the use case
-static DNSXErrorType InitConnection(DNSXConnRef *connRef, const char *servname, dispatch_queue_t clientq, void *AppCallBack)
-{
- if (!connRef)
- {
- syslog(LOG_WARNING, "dns_services: InitConnection() called with NULL DNSXConnRef");
- return kDNSX_BadParam;
- }
-
- *connRef = malloc(sizeof(struct _DNSXConnRef_t));
- if (!(*connRef))
- {
- syslog(LOG_WARNING, "dns_services: InitConnection() No memory to allocate");
- return kDNSX_NoMem;
- }
-
- // Initialize the DNSXConnRef
- dispatch_retain(clientq);
- (*connRef)->client_q = clientq;
- (*connRef)->AppCallBack = AppCallBack;
- (*connRef)->lib_q = dispatch_queue_create("com.apple.mDNSResponder.libdns_services.q", NULL);
- (*connRef)->conn_ref = xpc_connection_create_mach_service(servname, (*connRef)->lib_q, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
-
- syslog(LOG_INFO, "dns_services: InitConnection() successfully create a new DNSXConnRef");
- return kDNSX_NoError;
-}
-
-DNSXErrorType DNSXEnableProxy(DNSXConnRef *connRef, DNSProxyParameters proxyparam, IfIndex inIfindexArr[MaxInputIf],
- IfIndex outIfindex, dispatch_queue_t clientq, DNSXEnableProxyReply callBack)
-{
-
- DNSXErrorType errx = kDNSX_NoError;
- bool old_conn = false;
-
- // Sanity Checks
- if (!connRef || !callBack || !clientq)
- {
- syslog(LOG_WARNING, "dns_services: DNSXEnableProxy called with NULL DNSXConnRef OR Callback OR ClientQ parameter");
- return kDNSX_BadParam;
- }
-
- // If no connRef, get it from InitConnection()
- if (!*connRef)
- {
- errx = InitConnection(connRef, kDNSProxyService, clientq, callBack);
- if (errx) // On error InitConnection() leaves *connRef set to NULL
- {
- syslog(LOG_WARNING, "dns_services: Since InitConnection() returned %d error returning w/o sending msg", errx);
- return errx;
- }
- }
- else // Client already has a valid connRef
- {
- old_conn = true;
- }
-
- // Create Dictionary To Send
- xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
- if (!dict)
- {
- syslog(LOG_WARNING, "dns_services: DNSXEnableProxy could not create the Msg Dict To Send!");
- DNSXRefDeAlloc(*connRef);
- return kDNSX_DictError;
- }
-
- xpc_dictionary_set_uint64(dict, kDNSProxyParameters, proxyparam);
-
- xpc_dictionary_set_uint64(dict, kDNSInIfindex0, inIfindexArr[0]);
- xpc_dictionary_set_uint64(dict, kDNSInIfindex1, inIfindexArr[1]);
- xpc_dictionary_set_uint64(dict, kDNSInIfindex2, inIfindexArr[2]);
- xpc_dictionary_set_uint64(dict, kDNSInIfindex3, inIfindexArr[3]);
- xpc_dictionary_set_uint64(dict, kDNSInIfindex4, inIfindexArr[4]);
-
- xpc_dictionary_set_uint64(dict, kDNSOutIfindex, outIfindex);
-
- errx = SendMsgToServer(connRef, dict, old_conn);
- xpc_release(dict);
-
- return errx;
-}
-
Copied: vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/Private/dns_services.c (from rev 6984, vendor/apple/mDNSResponder/dist/mDNSMacOSX/Private/dns_services.c)
===================================================================
--- vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/Private/dns_services.c (rev 0)
+++ vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/Private/dns_services.c 2015-03-20 01:14:52 UTC (rev 6985)
@@ -0,0 +1,212 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * PRIVATE DNSX CLIENT LIBRARY --FOR Apple Platforms ONLY OSX/iOS--
+ * Resides in /usr/lib/libdns_services.dylib
+ */
+
+#include "dns_services_mdns.h"
+#include "dns_xpc.h"
+#include <xpc/xpc.h>
+#include <Block.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+
+//*************************************************************************************************************
+// Globals
+
+#define connection_t xpc_connection_t
+
+struct _DNSXConnRef_t
+{
+ connection_t conn_ref; // xpc_connection between client and daemon
+ dispatch_queue_t lib_q; // internal queue created in library itself
+ void *AppCallBack; // Callback function ptr for Client
+ dispatch_queue_t client_q; // Queue specified by client for scheduling its Callback
+};
+
+//*************************************************************************************************************
+// Utility Functions
+
+static bool LogDebugEnabled()
+{
+ return true;
+}
+
+static void LogDebug(const char *prefix, xpc_object_t o)
+{
+ if (!LogDebugEnabled())
+ return;
+
+ char *desc = xpc_copy_description(o);
+ syslog(LOG_INFO, "%s: %s", prefix, desc);
+ free(desc);
+}
+
+//**************************************************************************************************************
+
+void DNSXRefDeAlloc(DNSXConnRef connRef)
+{
+ if (!connRef)
+ {
+ syslog(LOG_WARNING, "dns_services: DNSXRefDeAlloc called with NULL DNSXConnRef");
+ return;
+ }
+
+ // Schedule this work on the internal library queue
+ dispatch_sync(connRef->lib_q, ^{
+
+ xpc_release(connRef->conn_ref);
+ connRef->AppCallBack = NULL;
+ dispatch_release(connRef->client_q);
+
+ });
+
+ dispatch_release(connRef->lib_q);
+ free(connRef);
+
+ syslog(LOG_INFO, "dns_services: DNSXRefDeAlloc successfully DeAllocated connRef");
+
+}
+
+// Sends the Msg(Dictionary) to the Server
+static DNSXErrorType SendMsgToServer(DNSXConnRef *connRef, xpc_object_t msg, bool old_conn)
+{
+ DNSXErrorType errx = kDNSX_NoError;
+
+ LogDebug("dns_services: SendMsgToServer", msg);
+
+ xpc_connection_set_event_handler((*connRef)->conn_ref, ^(xpc_object_t recv_msg)
+ {
+ xpc_type_t type = xpc_get_type(recv_msg);
+
+ if (type == XPC_TYPE_DICTIONARY)
+ {
+ LogDebug("dns_services: SendMsgToServer SUCCESS CALLBACK FROM SERVER", recv_msg);
+ syslog(LOG_INFO, "dns_services: Successfully Sent Msg to the Daemon");
+ uint64_t daemon_status = xpc_dictionary_get_uint64(recv_msg, kDNSDaemonReply);
+
+ // Schedule the AppCallBacks on the Client Specified Queue
+ switch (daemon_status)
+ {
+ case kDNSDaemonEngaged:
+ dispatch_async((*connRef)->client_q, ^{
+ ((DNSXEnableProxyReply)(*connRef)->AppCallBack)((*connRef), kDNSX_Engaged);
+ });
+ break;
+ case kDNSMsgReceived:
+ dispatch_async((*connRef)->client_q, ^{
+ ((DNSXEnableProxyReply)(*connRef)->AppCallBack)((*connRef), kDNSX_NoError);
+ });
+ break;
+ default:
+ dispatch_async((*connRef)->client_q, ^{
+ ((DNSXEnableProxyReply)(*connRef)->AppCallBack)((*connRef), kDNSX_UnknownErr);
+ });
+ break;
+ }
+
+ }
+ else
+ {
+ LogDebug("dns_services: SendMsgToServer UNEXPECTED CALLBACK FROM SERVER", recv_msg);
+ syslog(LOG_WARNING, "dns_services: Connection failed since NO privileges to access service OR Daemon NOT Running");
+ dispatch_async((*connRef)->client_q, ^{
+ ((DNSXEnableProxyReply)(*connRef)->AppCallBack)((*connRef), kDNSX_DaemonNotRunning);
+ });
+ }
+ });
+
+ // To prevent Over-Resume of a connection
+ if (!old_conn)
+ xpc_connection_resume((*connRef)->conn_ref);
+ xpc_connection_send_message((*connRef)->conn_ref, msg);
+ if (!errx)
+ syslog(LOG_INFO, "dns_services: SendMSgToServer sent Msg Dict successfully to Daemon");
+ return errx;
+}
+
+// Creates a new DNSX Connection Reference(DNSXConnRef).
+// If DNSXConnRef exists, you may want to use that depending on the use case
+static DNSXErrorType InitConnection(DNSXConnRef *connRef, const char *servname, dispatch_queue_t clientq, void *AppCallBack)
+{
+ if (!connRef)
+ {
+ syslog(LOG_WARNING, "dns_services: InitConnection() called with NULL DNSXConnRef");
+ return kDNSX_BadParam;
+ }
+
+ *connRef = malloc(sizeof(struct _DNSXConnRef_t));
+ if (!(*connRef))
+ {
+ syslog(LOG_WARNING, "dns_services: InitConnection() No memory to allocate");
+ return kDNSX_NoMem;
+ }
+
+ // Initialize the DNSXConnRef
+ dispatch_retain(clientq);
+ (*connRef)->client_q = clientq;
+ (*connRef)->AppCallBack = AppCallBack;
+ (*connRef)->lib_q = dispatch_queue_create("com.apple.mDNSResponder.libdns_services.q", NULL);
+ (*connRef)->conn_ref = xpc_connection_create_mach_service(servname, (*connRef)->lib_q, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
+
+ syslog(LOG_INFO, "dns_services: InitConnection() successfully create a new DNSXConnRef");
+ return kDNSX_NoError;
+}
+
+DNSXErrorType DNSXEnableProxy(DNSXConnRef *connRef, DNSProxyParameters proxyparam, IfIndex inIfindexArr[MaxInputIf],
+ IfIndex outIfindex, dispatch_queue_t clientq, DNSXEnableProxyReply callBack)
+{
+
+ DNSXErrorType errx = kDNSX_NoError;
+ bool old_conn = false;
+
+ // Sanity Checks
+ if (!connRef || !callBack || !clientq)
+ {
+ syslog(LOG_WARNING, "dns_services: DNSXEnableProxy called with NULL DNSXConnRef OR Callback OR ClientQ parameter");
+ return kDNSX_BadParam;
+ }
+
+ // If no connRef, get it from InitConnection()
+ if (!*connRef)
+ {
+ errx = InitConnection(connRef, kDNSProxyService, clientq, callBack);
+ if (errx) // On error InitConnection() leaves *connRef set to NULL
+ {
+ syslog(LOG_WARNING, "dns_services: Since InitConnection() returned %d error returning w/o sending msg", errx);
+ return errx;
+ }
+ }
+ else // Client already has a valid connRef
+ {
+ old_conn = true;
+ }
+
+ // Create Dictionary To Send
+ xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
+ if (!dict)
+ {
+ syslog(LOG_WARNING, "dns_services: DNSXEnableProxy could not create the Msg Dict To Send!");
+ DNSXRefDeAlloc(*connRef);
+ return kDNSX_DictError;
+ }
+
+ xpc_dictionary_set_uint64(dict, kDNSProxyParameters, proxyparam);
+
+ xpc_dictionary_set_uint64(dict, kDNSInIfindex0, inIfindexArr[0]);
+ xpc_dictionary_set_uint64(dict, kDNSInIfindex1, inIfindexArr[1]);
+ xpc_dictionary_set_uint64(dict, kDNSInIfindex2, inIfindexArr[2]);
+ xpc_dictionary_set_uint64(dict, kDNSInIfindex3, inIfindexArr[3]);
+ xpc_dictionary_set_uint64(dict, kDNSInIfindex4, inIfindexArr[4]);
+
+ xpc_dictionary_set_uint64(dict, kDNSOutIfindex, outIfindex);
+
+ errx = SendMsgToServer(connRef, dict, old_conn);
+ xpc_release(dict);
+
+ return errx;
+}
+
Copied: vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/Private/dns_services_mdns.h (from rev 6984, vendor/apple/mDNSResponder/dist/mDNSMacOSX/Private/dns_services_mdns.h)
===================================================================
--- vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/Private/dns_services_mdns.h (rev 0)
+++ vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/Private/dns_services_mdns.h 2015-03-20 01:14:52 UTC (rev 6985)
@@ -0,0 +1,124 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ *
+ * @header Interface to DNSX SPI
+ *
+ * @discussion Describes the functions and data structures
+ * that make up the DNSX SPI
+ */
+
+#ifndef _DNS_SERVICES_H
+#define _DNS_SERVICES_H
+
+#include <dispatch/dispatch.h>
+
+// DNSXConnRef: Opaque internal data type
+typedef struct _DNSXConnRef_t *DNSXConnRef;
+
+typedef enum
+{
+ kDNSX_NoError = 0,
+ kDNSX_UnknownErr = -65537, /* 0xFFFE FFFF */
+ kDNSX_NoMem = -65539,
+ kDNSX_BadParam = -65540,
+ kDNSX_DaemonNotRunning = -65563, /* Background daemon not running */
+ kDNSX_DictError = -65565, /* Dictionary Error */
+ kDNSX_Engaged = -65566, /* DNS Proxy is in use by another client */
+ kDNSX_Timeout = -65568
+} DNSXErrorType;
+
+// A max of 5 input interfaces can be processed at one time
+#define MaxInputIf 5
+#define IfIndex uint64_t
+#define kDNSIfindexAny 0
+
+// Enable DNS Proxy with an appropriate parameter defined below
+typedef enum
+{
+ kDNSProxyEnable = 1
+ // Other values reserved for future use
+} DNSProxyParameters;
+
+/*********************************************************************************************
+*
+* Enable DNS Proxy Functionality
+*
+*********************************************************************************************/
+
+/* DNSXEnableProxy : Turns ON the DNS Proxy (Details below)
+ *
+ * DNSXEnableProxyReply() parameters:
+ *
+ * connRef: The DNSXConnRef initialized by DNSXEnableProxy().
+ *
+ * errCode: Will be kDNSX_NoError on success, otherwise will indicate the
+ * failure that occurred. Other parameters are undefined if
+ * errCode is nonzero.
+ *
+ */
+
+typedef void (*DNSXEnableProxyReply)
+(
+ DNSXConnRef connRef,
+ DNSXErrorType errCode
+);
+
+/* DNSXEnableProxy
+ *
+ * Enables the DNS Proxy functionality which will remain ON until the client terminates explictly (or exits/crashes).
+ * Client can turn it OFF by passing the returned DNSXConnRef to DNSXRefDeAlloc()
+ *
+ * DNSXEnableProxy() Parameters:
+ *
+ * connRef: A pointer to DNSXConnRef that is initialized to NULL when called for the first
+ * time. If the call succeeds it will be initialized to a non-NULL value.
+ * Client terminates the DNS Proxy by passing this DNSXConnRef to DNSXRefDeAlloc().
+ *
+ * proxyparam: Enable DNS Proxy functionality with parameters that are described in
+ * DNSProxyParameters above.
+ *
+ * inIfindexArr[MaxInputIf]: List of input interfaces from which the DNS queries will be accepted and
+ * forwarded to the output interface specified below. The daemon processes
+ * MaxInputIf entries in the list. For eg. if one has less than MaxInputIfs
+ * values, just initialize the other values to be 0. Note: This field needs to
+ * be initialized by the client.
+ *
+ * outIfindex: Output interface on which the query will be forwarded.
+ * Passing kDNSIfindexAny causes DNS Queries to be sent on the primary interface.
+ *
+ * clientq: Queue the client wants to schedule the callBack on (Note: Must not be NULL)
+ *
+ * callBack: CallBack function for the client that indicates success or failure.
+ * Note: callback may be invoked more than once, For eg. if enabling DNS Proxy
+ * first succeeds and the daemon possibly crashes sometime later.
+ *
+ * return value: Returns kDNSX_NoError when no error otherwise returns an error code indicating
+ * the error that occurred. Note: A return value of kDNSX_NoError does not mean
+ * that DNS Proxy was successfully enabled. The callBack may asynchronously
+ * return an error (such as kDNSX_DaemonNotRunning/ kDNSX_Engaged)
+ *
+ */
+
+DNSXErrorType DNSXEnableProxy
+(
+ DNSXConnRef *connRef,
+ DNSProxyParameters proxyparam,
+ IfIndex inIfindexArr[MaxInputIf],
+ IfIndex outIfindex,
+ dispatch_queue_t clientq,
+ DNSXEnableProxyReply callBack
+);
+
+/* DNSXRefDeAlloc()
+ *
+ * Terminate a connection with the daemon and free memory associated with the DNSXConnRef.
+ * Used to Disable DNS Proxy on that connection.
+ *
+ * connRef: A DNSXConnRef initialized by any of the DNSX*() calls.
+ *
+ */
+void DNSXRefDeAlloc(DNSXConnRef connRef);
+
+#endif /* _DNS_SERVICES_H */
Copied: vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/base.xcconfig (from rev 6984, vendor/apple/mDNSResponder/dist/mDNSMacOSX/base.xcconfig)
===================================================================
--- vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/base.xcconfig (rev 0)
+++ vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/base.xcconfig 2015-03-20 01:14:52 UTC (rev 6985)
@@ -0,0 +1,8 @@
+#include "<DEVELOPER_DIR>/AppleInternal/XcodeConfig/SimulatorSupport.xcconfig"
+
+// Set INSTALL_PATH[sdk=macosx*] when SimulatorSupport.xcconfig is unavailable
+INSTALL_PATH[sdk=macosx*] = $(INSTALL_PATH_ACTUAL)
+
+// Use $(INSTALL_PATH_PREFIX) instead of $(SDKROOT) as an unconditional prefix
+PUBLIC_HEADERS_FOLDER_PATH = $(INSTALL_PATH_PREFIX)/usr/include
+PRIVATE_HEADERS_FOLDER_PATH = $(INSTALL_PATH_PREFIX)/usr/local/include
Deleted: vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/helper.c
===================================================================
--- vendor/apple/mDNSResponder/dist/mDNSMacOSX/helper.c 2014-06-30 23:58:12 UTC (rev 6706)
+++ vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/helper.c 2015-03-20 01:14:52 UTC (rev 6985)
@@ -1,2867 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2007-2012 Apple Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <sys/cdefs.h>
-#include <arpa/inet.h>
-#include <bsm/libbsm.h>
-#include <net/if.h>
-#include <net/route.h>
-#include <net/if_dl.h>
-#include <net/if_types.h>
-#include <netinet/in.h>
-#include <netinet/if_ether.h>
-#include <netinet6/in6_var.h>
-#include <netinet6/nd6.h>
-#include <netinet6/ipsec.h>
-#include <sys/ioctl.h>
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <asl.h>
-#include <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <string.h>
-#include <unistd.h>
-#include <Security/Security.h>
-#include <SystemConfiguration/SystemConfiguration.h>
-#include <SystemConfiguration/SCPreferencesSetSpecific.h>
-#include <TargetConditionals.h>
-#include <IOKit/pwr_mgt/IOPMLib.h>
-#include <net/bpf.h>
-#include <sys/sysctl.h>
-
-#include "mDNSEmbeddedAPI.h"
-#include "dns_sd.h"
-#include "dnssd_ipc.h"
-#include "libpfkey.h"
-#include "helper.h"
-#include "helpermsgServer.h"
-#include "helper-server.h"
-#include "ipsec_options.h"
-#include "P2PPacketFilter.h"
-
-#include <netinet/ip.h>
-#include <netinet/tcp.h>
-
-#ifndef RTF_IFSCOPE
-#define RTF_IFSCOPE 0x1000000
-#endif
-
-#if TARGET_OS_EMBEDDED
-#ifndef MDNS_NO_IPSEC
-#define MDNS_NO_IPSEC 1
-#endif
-#define NO_CFUSERNOTIFICATION 1
-#define NO_SECURITYFRAMEWORK 1
-#endif
-
-// Embed the client stub code here, so we can access private functions like ConnectToServer, create_hdr, deliver_request
-#include "../mDNSShared/dnssd_ipc.c"
-#include "../mDNSShared/dnssd_clientstub.c"
-
-typedef struct sadb_x_policy *ipsec_policy_t;
-
-unsigned short InetChecksum(unsigned short *ptr,int nbytes);
-unsigned long in_cksum(unsigned short *ptr,int nbytes);
-void TCPCheckSum(int af, struct tcphdr *t, int tcplen, v6addr_t sadd6, v6addr_t dadd6);
-
-uid_t mDNSResponderUID;
-gid_t mDNSResponderGID;
-static const char kTunnelAddressInterface[] = "lo0";
-
-void
-debug_(const char *func, const char *fmt, ...)
-{
- char buf[2048];
- va_list ap;
-
- va_start(ap, fmt);
- vsnprintf(buf, sizeof(buf), fmt, ap);
- va_end(ap);
- helplog(ASL_LEVEL_DEBUG, "%s: %s", func, buf);
-}
-
-static int
-authorized(audit_token_t *token)
-{
- int ok = 0;
- pid_t pid = (pid_t)-1;
- uid_t euid = (uid_t)-1;
-
- audit_token_to_au32(*token, NULL, &euid, NULL, NULL, NULL, &pid, NULL,
- NULL);
- ok = (euid == mDNSResponderUID || euid == 0);
- if (!ok)
- helplog(ASL_LEVEL_NOTICE,
- "Unauthorized access by euid=%lu pid=%lu",
- (unsigned long)euid, (unsigned long)pid);
- return ok;
-}
-
-kern_return_t
-do_mDNSExit(__unused mach_port_t port, audit_token_t token)
-{
- debug("entry");
- if (!authorized(&token))
- goto fin;
- helplog(ASL_LEVEL_INFO, "exit");
- exit(0);
-
-fin:
- debug("fin");
- return KERN_SUCCESS;
-}
-
-kern_return_t do_mDNSRequestBPF(__unused mach_port_t port, audit_token_t token)
-{
- if (!authorized(&token)) return KERN_SUCCESS;
- DNSServiceRef ref;
- DNSServiceErrorType err = ConnectToServer(&ref, 0, send_bpf, NULL, NULL, NULL);
- if (err) { helplog(ASL_LEVEL_ERR, "do_mDNSRequestBPF: ConnectToServer %d", err); return err; }
-
- char *ptr;
- size_t len = sizeof(DNSServiceFlags);
- ipc_msg_hdr *hdr = create_hdr(send_bpf, &len, &ptr, 0, ref);
- if (!hdr) { DNSServiceRefDeallocate(ref); return kDNSServiceErr_NoMemory; }
- put_flags(0, &ptr);
- deliver_request(hdr, ref); // Will free hdr for us
- DNSServiceRefDeallocate(ref);
- update_idle_timer();
- return KERN_SUCCESS;
-}
-
-kern_return_t do_mDNSPowerRequest(__unused mach_port_t port, int key, int interval, int *err, audit_token_t token)
-{
- *err = -1;
- if (!authorized(&token)) { *err = kmDNSHelperNotAuthorized; goto fin; }
-
- CFArrayRef events = IOPMCopyScheduledPowerEvents();
- if (events)
- {
- int i;
- CFIndex count = CFArrayGetCount(events);
- for (i=0; i<count; i++)
- {
- CFDictionaryRef dict = CFArrayGetValueAtIndex(events, i);
- CFStringRef id = CFDictionaryGetValue(dict, CFSTR(kIOPMPowerEventAppNameKey));
- if (CFEqual(id, CFSTR("mDNSResponderHelper")))
- {
- CFDateRef EventTime = CFDictionaryGetValue(dict, CFSTR(kIOPMPowerEventTimeKey));
- CFStringRef EventType = CFDictionaryGetValue(dict, CFSTR(kIOPMPowerEventTypeKey));
- IOReturn result = IOPMCancelScheduledPowerEvent(EventTime, id, EventType);
- //helplog(ASL_LEVEL_ERR, "Deleting old event %s");
- if (result) helplog(ASL_LEVEL_ERR, "IOPMCancelScheduledPowerEvent %d failed %d", i, result);
- }
- }
- CFRelease(events);
- }
-
- if (key < 0) // mDNSPowerRequest(-1,-1) means "clear any stale schedules" (see above)
- *err = 0;
- else if (key == 0) // mDNSPowerRequest(0, 0) means "sleep now"
- {
- IOReturn r = IOPMSleepSystem(IOPMFindPowerManagement(MACH_PORT_NULL));
- if (r) { usleep(100000); helplog(ASL_LEVEL_ERR, "IOPMSleepSystem %d", r); }
- *err = r;
- }
- else if (key > 0)
- {
- CFDateRef w = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent() + interval);
- if (w)
- {
- IOReturn r = IOPMSchedulePowerEvent(w, CFSTR("mDNSResponderHelper"), key ? CFSTR(kIOPMAutoWake) : CFSTR(kIOPMAutoSleep));
- if (r) { usleep(100000); helplog(ASL_LEVEL_ERR, "IOPMSchedulePowerEvent(%d) %d %x", interval, r, r); }
- *err = r;
- CFRelease(w);
- }
- }
-fin:
- update_idle_timer();
- return KERN_SUCCESS;
-}
-
-kern_return_t do_mDNSSetLocalAddressCacheEntry(__unused mach_port_t port, int ifindex, int family, v6addr_t ip, ethaddr_t eth, int *err, audit_token_t token)
-{
- #define IPv6FMTSTRING "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X"
- #define IPv6FMTARGS ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7], ip[8], ip[9], ip[10], ip[11], ip[12], ip[13], ip[14], ip[15]
- #if 0
- if (family == 4)
- helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry %d IPv%d %d.%d.%d.%d %02X:%02X:%02X:%02X:%02X:%02X",
- ifindex, family, ip[0], ip[1], ip[2], ip[3], eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
- else
- helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry %d IPv%d " IPv6FMTSTRING " %02X:%02X:%02X:%02X:%02X:%02X",
- ifindex, family, IPv6FMTARGS, eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
- #endif
-
- *err = -1;
- if (!authorized(&token)) { *err = kmDNSHelperNotAuthorized; goto fin; }
-
- static int s = -1, seq = 0;
- if (s < 0)
- {
- s = socket(PF_ROUTE, SOCK_RAW, 0);
- if (s < 0) helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: socket(PF_ROUTE, SOCK_RAW, 0) failed %d (%s)", errno, strerror(errno));
- }
-
- if (s >= 0)
- {
- struct timeval tv;
- gettimeofday(&tv, 0);
- if (family == 4)
- {
- struct { struct rt_msghdr hdr; struct sockaddr_inarp dst; struct sockaddr_dl sdl; } rtmsg;
- memset(&rtmsg, 0, sizeof(rtmsg));
-
- rtmsg.hdr.rtm_msglen = sizeof(rtmsg);
- rtmsg.hdr.rtm_version = RTM_VERSION;
- rtmsg.hdr.rtm_type = RTM_ADD;
- rtmsg.hdr.rtm_index = ifindex;
- rtmsg.hdr.rtm_flags = RTF_HOST | RTF_STATIC | RTF_IFSCOPE;
- rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
- rtmsg.hdr.rtm_pid = 0;
- rtmsg.hdr.rtm_seq = seq++;
- rtmsg.hdr.rtm_errno = 0;
- rtmsg.hdr.rtm_use = 0;
- rtmsg.hdr.rtm_inits = RTV_EXPIRE;
- rtmsg.hdr.rtm_rmx.rmx_expire = tv.tv_sec + 30;
-
- rtmsg.dst.sin_len = sizeof(rtmsg.dst);
- rtmsg.dst.sin_family = AF_INET;
- rtmsg.dst.sin_port = 0;
- rtmsg.dst.sin_addr.s_addr = *(in_addr_t*)ip;
- rtmsg.dst.sin_srcaddr.s_addr = 0;
- rtmsg.dst.sin_tos = 0;
- rtmsg.dst.sin_other = 0;
-
- rtmsg.sdl.sdl_len = sizeof(rtmsg.sdl);
- rtmsg.sdl.sdl_family = AF_LINK;
- rtmsg.sdl.sdl_index = ifindex;
- rtmsg.sdl.sdl_type = IFT_ETHER;
- rtmsg.sdl.sdl_nlen = 0;
- rtmsg.sdl.sdl_alen = ETHER_ADDR_LEN;
- rtmsg.sdl.sdl_slen = 0;
-
- // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
- memcpy(rtmsg.sdl.sdl_data, eth, sizeof(ethaddr_t));
-
- int len = write(s, (char *)&rtmsg, sizeof(rtmsg));
- if (len < 0)
- helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: write(%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s)",
- sizeof(rtmsg), ifindex, ip[0], ip[1], ip[2], ip[3], rtmsg.hdr.rtm_seq, len, errno, strerror(errno));
- len = read(s, (char *)&rtmsg, sizeof(rtmsg));
- if (len < 0 || rtmsg.hdr.rtm_errno)
- helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: read (%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s) %d",
- sizeof(rtmsg), ifindex, ip[0], ip[1], ip[2], ip[3], rtmsg.hdr.rtm_seq, len, errno, strerror(errno), rtmsg.hdr.rtm_errno);
-
- *err = 0;
- }
- else
- {
- struct { struct rt_msghdr hdr; struct sockaddr_in6 dst; struct sockaddr_dl sdl; } rtmsg;
- memset(&rtmsg, 0, sizeof(rtmsg));
-
- rtmsg.hdr.rtm_msglen = sizeof(rtmsg);
- rtmsg.hdr.rtm_version = RTM_VERSION;
- rtmsg.hdr.rtm_type = RTM_ADD;
- rtmsg.hdr.rtm_index = ifindex;
- rtmsg.hdr.rtm_flags = RTF_HOST | RTF_STATIC | RTF_IFSCOPE;
- rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
- rtmsg.hdr.rtm_pid = 0;
- rtmsg.hdr.rtm_seq = seq++;
- rtmsg.hdr.rtm_errno = 0;
- rtmsg.hdr.rtm_use = 0;
- rtmsg.hdr.rtm_inits = RTV_EXPIRE;
- rtmsg.hdr.rtm_rmx.rmx_expire = tv.tv_sec + 30;
-
- rtmsg.dst.sin6_len = sizeof(rtmsg.dst);
- rtmsg.dst.sin6_family = AF_INET6;
- rtmsg.dst.sin6_port = 0;
- rtmsg.dst.sin6_flowinfo = 0;
- rtmsg.dst.sin6_addr = *(struct in6_addr*)ip;
- rtmsg.dst.sin6_scope_id = ifindex;
-
- rtmsg.sdl.sdl_len = sizeof(rtmsg.sdl);
- rtmsg.sdl.sdl_family = AF_LINK;
- rtmsg.sdl.sdl_index = ifindex;
- rtmsg.sdl.sdl_type = IFT_ETHER;
- rtmsg.sdl.sdl_nlen = 0;
- rtmsg.sdl.sdl_alen = ETHER_ADDR_LEN;
- rtmsg.sdl.sdl_slen = 0;
-
- // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
- memcpy(rtmsg.sdl.sdl_data, eth, sizeof(ethaddr_t));
-
- int len = write(s, (char *)&rtmsg, sizeof(rtmsg));
- if (len < 0)
- helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: write(%d) interface %d address " IPv6FMTSTRING " seq %d result %d errno %d (%s)",
- sizeof(rtmsg), ifindex, IPv6FMTARGS, rtmsg.hdr.rtm_seq, len, errno, strerror(errno));
- len = read(s, (char *)&rtmsg, sizeof(rtmsg));
- if (len < 0 || rtmsg.hdr.rtm_errno)
- helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: read (%d) interface %d address " IPv6FMTSTRING " seq %d result %d errno %d (%s) %d",
- sizeof(rtmsg), ifindex, IPv6FMTARGS, rtmsg.hdr.rtm_seq, len, errno, strerror(errno), rtmsg.hdr.rtm_errno);
-
- *err = 0;
- }
-
- }
-
-fin:
- update_idle_timer();
- return KERN_SUCCESS;
-}
-
-kern_return_t do_mDNSNotify(__unused mach_port_t port, const char *title, const char *msg, audit_token_t token)
-{
- if (!authorized(&token)) return KERN_SUCCESS;
-
-#ifndef NO_CFUSERNOTIFICATION
- static const char footer[] = "(Note: This message only appears on machines with 17.x.x.x IP addresses — i.e. at Apple — not on customer machines.)";
- CFStringRef alertHeader = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
- CFStringRef alertBody = CFStringCreateWithCString(NULL, msg, kCFStringEncodingUTF8);
- CFStringRef alertFooter = CFStringCreateWithCString(NULL, footer, kCFStringEncodingUTF8);
- CFStringRef alertMessage = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@\r\r%@"), alertBody, alertFooter);
- CFRelease(alertBody);
- CFRelease(alertFooter);
- int err = CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, alertHeader, alertMessage, NULL);
- if (err) helplog(ASL_LEVEL_ERR, "CFUserNotificationDisplayNotice returned %d", err);
- CFRelease(alertHeader);
- CFRelease(alertMessage);
-#else
- (void)title;
- (void)msg;
-#endif /* NO_CFUSERNOTIFICATION */
-
- update_idle_timer();
- return KERN_SUCCESS;
-}
-
-char usercompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name the user saw
-char userhostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name the user saw
-char lastcompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name saved to preferences
-char lasthostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name saved to preferences
-
-#ifndef NO_CFUSERNOTIFICATION
-static CFStringRef CFS_OQ = NULL;
-static CFStringRef CFS_CQ = NULL;
-static CFStringRef CFS_Format = NULL;
-static CFStringRef CFS_ComputerName = NULL;
-static CFStringRef CFS_ComputerNameMsg = NULL;
-static CFStringRef CFS_LocalHostName = NULL;
-static CFStringRef CFS_LocalHostNameMsg = NULL;
-static CFStringRef CFS_Problem = NULL;
-
-static CFUserNotificationRef gNotification = NULL;
-static CFRunLoopSourceRef gNotificationRLS = NULL;
-
-static void NotificationCallBackDismissed(CFUserNotificationRef userNotification, CFOptionFlags responseFlags)
-{
- debug("entry");
- (void)responseFlags; // Unused
- if (userNotification != gNotification) helplog(ASL_LEVEL_ERR, "NotificationCallBackDismissed: Wrong CFUserNotificationRef");
- if (gNotificationRLS)
- {
- // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
- // We need to explicitly specify the desired CFRunLoop from which we want to remove this event source.
- CFRunLoopRemoveSource(gRunLoop, gNotificationRLS, kCFRunLoopDefaultMode);
- CFRelease(gNotificationRLS);
- gNotificationRLS = NULL;
- CFRelease(gNotification);
- gNotification = NULL;
- }
- // By dismissing the alert, the user has conceptually acknowleged the rename.
- // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".)
- // If we get *another* conflict, the new alert should refer to the 'old' name
- // as now being "computer-2.local", not "computer.local"
- usercompname[0] = 0;
- userhostname[0] = 0;
- lastcompname[0] = 0;
- lasthostname[0] = 0;
- update_idle_timer();
- unpause_idle_timer();
-}
-
-static void ShowNameConflictNotification(CFMutableArrayRef header, CFStringRef subtext)
-{
- CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- if (!dictionary) return;
-
- debug("entry");
-
- CFDictionarySetValue(dictionary, kCFUserNotificationAlertHeaderKey, header);
- CFDictionarySetValue(dictionary, kCFUserNotificationAlertMessageKey, subtext);
-
- CFURLRef urlRef = CFURLCreateWithFileSystemPath(NULL, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle, true);
- if (urlRef) { CFDictionarySetValue(dictionary, kCFUserNotificationLocalizationURLKey, urlRef); CFRelease(urlRef); }
-
- if (gNotification) // If notification already on-screen, update it in place
- CFUserNotificationUpdate(gNotification, 0, kCFUserNotificationCautionAlertLevel, dictionary);
- else // else, we need to create it
- {
- SInt32 error;
- gNotification = CFUserNotificationCreate(NULL, 0, kCFUserNotificationCautionAlertLevel, &error, dictionary);
- if (!gNotification || error) { helplog(ASL_LEVEL_ERR, "ShowNameConflictNotification: CFUserNotificationRef: Error %d", error); return; }
- gNotificationRLS = CFUserNotificationCreateRunLoopSource(NULL, gNotification, NotificationCallBackDismissed, 0);
- if (!gNotificationRLS) { helplog(ASL_LEVEL_ERR,"ShowNameConflictNotification: RLS"); CFRelease(gNotification); gNotification = NULL; return; }
- // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
- // We need to explicitly specify the desired CFRunLoop to which we want to add this event source.
- CFRunLoopAddSource(gRunLoop, gNotificationRLS, kCFRunLoopDefaultMode);
- debug("gRunLoop=%p gNotification=%p gNotificationRLS=%p", gRunLoop, gNotification, gNotificationRLS);
- pause_idle_timer();
- }
-
- CFRelease(dictionary);
-}
-
-static CFMutableArrayRef GetHeader(const char* oldname, const char* newname, const CFStringRef msg, const char* suffix)
-{
- CFMutableArrayRef alertHeader = NULL;
-
- const CFStringRef cfoldname = CFStringCreateWithCString(NULL, oldname, kCFStringEncodingUTF8);
- // NULL newname means we've given up trying to construct a name that doesn't conflict
- const CFStringRef cfnewname = newname ? CFStringCreateWithCString(NULL, newname, kCFStringEncodingUTF8) : NULL;
- // We tag a zero-width non-breaking space at the end of the literal text to guarantee that, no matter what
- // arbitrary computer name the user may choose, this exact text (with zero-width non-breaking space added)
- // can never be one that occurs in the Localizable.strings translation file.
- if (!cfoldname)
- helplog(ASL_LEVEL_ERR,"Could not construct CFStrings for old=%s", newname);
- else if (newname && !cfnewname)
- helplog(ASL_LEVEL_ERR,"Could not construct CFStrings for new=%s", newname);
- else
- {
- const CFStringRef s1 = CFStringCreateWithFormat(NULL, NULL, CFS_Format, cfoldname, suffix);
- const CFStringRef s2 = cfnewname ? CFStringCreateWithFormat(NULL, NULL, CFS_Format, cfnewname, suffix) : NULL;
-
- alertHeader = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-
- if (!s1)
- helplog(ASL_LEVEL_ERR, "Could not construct secondary CFString for old=%s", oldname);
- else if (cfnewname && !s2)
- helplog(ASL_LEVEL_ERR, "Could not construct secondary CFString for new=%s", newname);
- else if (!alertHeader)
- helplog(ASL_LEVEL_ERR, "Could not construct CFArray for notification");
- else
- {
- // Make sure someone is logged in. We don't want this popping up over the login window
- uid_t uid;
- gid_t gid;
- CFStringRef userName = SCDynamicStoreCopyConsoleUser(NULL, &uid, &gid);
- if (userName)
- {
- CFRelease(userName);
- CFArrayAppendValue(alertHeader, msg); // Opening phrase of message, provided by caller
- CFArrayAppendValue(alertHeader, CFS_OQ); CFArrayAppendValue(alertHeader, s1); CFArrayAppendValue(alertHeader, CFS_CQ);
- CFArrayAppendValue(alertHeader, CFSTR(" is already in use on this network. "));
- if (s2)
- {
- CFArrayAppendValue(alertHeader, CFSTR("The name has been changed to "));
- CFArrayAppendValue(alertHeader, CFS_OQ); CFArrayAppendValue(alertHeader, s2); CFArrayAppendValue(alertHeader, CFS_CQ);
- CFArrayAppendValue(alertHeader, CFSTR("."));
- }
- else
- CFArrayAppendValue(alertHeader, CFSTR("All attempts to find an available name by adding a number to the name were also unsuccessful."));
- }
- }
- if (s1) CFRelease(s1);
- if (s2) CFRelease(s2);
- }
- if (cfoldname) CFRelease(cfoldname);
- if (cfnewname) CFRelease(cfnewname);
-
- return alertHeader;
-}
-#endif /* ndef NO_CFUSERNOTIFICATION */
-
-static void update_notification(void)
-{
-#ifndef NO_CFUSERNOTIFICATION
- debug("entry ucn=%s, uhn=%s, lcn=%s, lhn=%s", usercompname, userhostname, lastcompname, lasthostname);
- if (!CFS_OQ)
- {
- // Note: the "\xEF\xBB\xBF" byte sequence in the CFS_Format string is the UTF-8 encoding of the zero-width non-breaking space character.
- // By appending this invisible character on the end of literal names, we ensure the these strings cannot inadvertently match any string
- // in the localization file -- since we know for sure that none of our strings in the localization file contain the ZWNBS character.
- //
- // For languages that are written right to left, when we mix English (host names could be in english with brackets etc. and the
- // rest in Arabic) we need unicode markups for proper formatting. The Unicode sequence 202C (UTF8 E2 80 AC), 200E (UTF8 E2 80 8E) and
- // 202B (UTF8 E2 80 AB) helps with the formatting. See <rdar://problem/8629082> for more details.
- CFS_OQ = CFStringCreateWithCString(NULL, "“\xE2\x80\xAB", kCFStringEncodingUTF8);
- CFS_CQ = CFStringCreateWithCString(NULL, "\xE2\x80\xAC”", kCFStringEncodingUTF8);
- CFS_Format = CFStringCreateWithCString(NULL, "%@%s\xEF\xBB\xBF\xE2\x80\x8E", kCFStringEncodingUTF8);
- CFS_ComputerName = CFStringCreateWithCString(NULL, "The name of your computer ", kCFStringEncodingUTF8);
- CFS_ComputerNameMsg = CFStringCreateWithCString(NULL, "To change the name of your computer, "
- "open System Preferences and click Sharing, then type the name in the Computer Name field.", kCFStringEncodingUTF8);
- CFS_LocalHostName = CFStringCreateWithCString(NULL, "This computer’s local hostname ", kCFStringEncodingUTF8);
- CFS_LocalHostNameMsg = CFStringCreateWithCString(NULL, "To change the local hostname, "
- "open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field.", kCFStringEncodingUTF8);
- CFS_Problem = CFStringCreateWithCString(NULL, "This may indicate a problem with the local network. "
- "Please inform your network administrator.", kCFStringEncodingUTF8);
- }
-
- if (!usercompname[0] && !userhostname[0])
- {
- if (gNotificationRLS)
- {
- debug("canceling notification %p", gNotification);
- CFUserNotificationCancel(gNotification);
- unpause_idle_timer();
- }
- }
- else
- {
- CFMutableArrayRef header = NULL;
- CFStringRef* subtext = NULL;
- if (userhostname[0] && !lasthostname[0]) // we've given up trying to construct a name that doesn't conflict
- {
- header = GetHeader(userhostname, NULL, CFS_LocalHostName, ".local");
- subtext = &CFS_Problem;
- }
- else if (usercompname[0])
- {
- header = GetHeader(usercompname, lastcompname, CFS_ComputerName, "");
- subtext = &CFS_ComputerNameMsg;
- }
- else
- {
- header = GetHeader(userhostname, lasthostname, CFS_LocalHostName, ".local");
- subtext = &CFS_LocalHostNameMsg;
- }
- ShowNameConflictNotification(header, *subtext);
- CFRelease(header);
- }
-#endif
-}
-
-kern_return_t
-do_mDNSPreferencesSetName(__unused mach_port_t port, int key, const char* old, const char* new, audit_token_t token)
-{
- SCPreferencesRef session = NULL;
- Boolean ok = FALSE;
- Boolean locked = FALSE;
- CFStringRef cfstr = NULL;
- char* user = NULL;
- char* last = NULL;
- Boolean needUpdate = FALSE;
-
- debug("entry %s old=%s new=%s", key==kmDNSComputerName ? "ComputerName" : (key==kmDNSLocalHostName ? "LocalHostName" : "UNKNOWN"), old, new);
- if (!authorized(&token)) goto fin;
-
- switch ((enum mDNSPreferencesSetNameKey)key)
- {
- case kmDNSComputerName:
- user = usercompname;
- last = lastcompname;
- break;
- case kmDNSLocalHostName:
- user = userhostname;
- last = lasthostname;
- break;
- default:
- debug("unrecognized key: %d", key);
- goto fin;
- }
-
- if (!last)
- {
- helplog(ASL_LEVEL_ERR, "%s: no last ptr", __func__);
- goto fin;
- }
-
- if (!user)
- {
- helplog(ASL_LEVEL_ERR, "%s: no user ptr", __func__);
- goto fin;
- }
-
- if (0 == strncmp(old, new, MAX_DOMAIN_LABEL+1))
- {
- // old and new are same means the config changed i.e, the user has set something in the preferences pane.
- // This means the conflict has been resolved. We need to dismiss the dialogue.
- if (last[0] && 0 != strncmp(last, new, MAX_DOMAIN_LABEL+1))
- {
- last[0] = 0;
- user[0] = 0;
- needUpdate = TRUE;
- }
- goto fin;
- }
- else
- {
- // old and new are not same, this means there is a conflict. For the first conflict, we show
- // the old value and the new value. For all subsequent conflicts, while the dialogue is still
- // up, we do a real time update of the "new" value in the dialogue. That's why we update just
- // "last" here and not "user".
- if (strncmp(last, new, MAX_DOMAIN_LABEL+1))
- {
- strncpy(last, new, MAX_DOMAIN_LABEL);
- needUpdate = TRUE;
- }
- }
-
- // If we are not showing the dialogue, we need to remember the first "old" value so that
- // we maintain the same through the lifetime of the dialogue. Subsequence conflicts don't
- // update the "old" value.
- if (!user[0])
- {
- strncpy(user, old, MAX_DOMAIN_LABEL);
- needUpdate = TRUE;
- }
-
- if (!new[0]) // we've given up trying to construct a name that doesn't conflict
- goto fin;
-
- cfstr = CFStringCreateWithCString(NULL, new, kCFStringEncodingUTF8);
-
- session = SCPreferencesCreate(NULL, CFSTR(kmDNSHelperServiceName), NULL);
-
- if (cfstr == NULL || session == NULL)
- {
- debug("SCPreferencesCreate failed");
- goto fin;
- }
- if (!SCPreferencesLock(session, 0))
- {
- debug("lock failed");
- goto fin;
- }
- locked = TRUE;
-
- switch ((enum mDNSPreferencesSetNameKey)key)
- {
- case kmDNSComputerName:
- {
- // We want to write the new Computer Name to System Preferences, without disturbing the user-selected
- // system-wide default character set used for things like AppleTalk NBP and NETBIOS service advertising.
- // Note that this encoding is not used for the computer name, but since both are set by the same call,
- // we need to take care to set the name without changing the character set.
- CFStringEncoding encoding = kCFStringEncodingUTF8;
- CFStringRef unused = SCDynamicStoreCopyComputerName(NULL, &encoding);
- if (unused) { CFRelease(unused); unused = NULL; }
- else encoding = kCFStringEncodingUTF8;
-
- ok = SCPreferencesSetComputerName(session, cfstr, encoding);
- }
- break;
- case kmDNSLocalHostName:
- ok = SCPreferencesSetLocalHostName(session, cfstr);
- break;
- default:
- break;
- }
-
- if (!ok || !SCPreferencesCommitChanges(session) ||
- !SCPreferencesApplyChanges(session))
- {
- debug("SCPreferences update failed");
- goto fin;
- }
- debug("succeeded");
-
-fin:
- if (NULL != cfstr)
- CFRelease(cfstr);
- if (NULL != session)
- {
- if (locked)
- SCPreferencesUnlock(session);
- CFRelease(session);
- }
- update_idle_timer();
- if (needUpdate) update_notification();
- return KERN_SUCCESS;
-}
-
-enum DNSKeyFormat
-{
- formatNotDNSKey, formatDdnsTypeItem, formatDnsPrefixedServiceItem, formatBtmmPrefixedServiceItem
-};
-
-// On Mac OS X on Intel, the four-character string seems to be stored backwards, at least sometimes.
-// I suspect some overenthusiastic inexperienced engineer said, "On Intel everything's backwards,
-// therefore I need to add some byte swapping in this API to make this four-character string backwards too."
-// To cope with this we allow *both* "ddns" and "sndd" as valid item types.
-
-static const char dnsprefix[] = "dns:";
-static const char ddns[] = "ddns";
-static const char ddnsrev[] = "sndd";
-static const char btmmprefix[] = "btmmdns:";
-
-#ifndef NO_SECURITYFRAMEWORK
-static enum DNSKeyFormat
-getDNSKeyFormat(SecKeychainItemRef item, SecKeychainAttributeList **attributesp)
-{
- static UInt32 tags[4] =
- {
- kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr, kSecLabelItemAttr
- };
- static SecKeychainAttributeInfo attributeInfo =
- {
- sizeof(tags)/sizeof(tags[0]), tags, NULL
- };
- SecKeychainAttributeList *attributes = NULL;
- enum DNSKeyFormat format;
- Boolean malformed = FALSE;
- OSStatus status = noErr;
- int i = 0;
-
- *attributesp = NULL;
- if (noErr != (status = SecKeychainItemCopyAttributesAndData(item,
- &attributeInfo, NULL, &attributes, NULL, NULL)))
- {
- debug("SecKeychainItemCopyAttributesAndData %d - skipping",
- status);
- goto skip;
- }
- if (attributeInfo.count != attributes->count)
- malformed = TRUE;
- for (i = 0; !malformed && i < (int)attributeInfo.count; ++i)
- if (attributeInfo.tag[i] != attributes->attr[i].tag)
- malformed = TRUE;
- if (malformed)
- {
- debug(
- "malformed result from SecKeychainItemCopyAttributesAndData - skipping");
- goto skip;
- }
-
- debug("entry (\"%.*s\", \"%.*s\", \"%.*s\")",
- (int)attributes->attr[0].length, attributes->attr[0].data,
- (int)attributes->attr[1].length, attributes->attr[1].data,
- (int)attributes->attr[2].length, attributes->attr[2].data);
- if (attributes->attr[1].length >= MAX_ESCAPED_DOMAIN_NAME +
- sizeof(dnsprefix)-1)
- {
- debug("kSecServiceItemAttr too long (%u) - skipping",
- (unsigned int)attributes->attr[1].length);
- goto skip;
- }
- if (attributes->attr[2].length >= MAX_ESCAPED_DOMAIN_NAME)
- {
- debug("kSecAccountItemAttr too long (%u) - skipping",
- (unsigned int)attributes->attr[2].length);
- goto skip;
- }
- if (attributes->attr[1].length >= sizeof(dnsprefix)-1 &&
- 0 == strncasecmp(attributes->attr[1].data, dnsprefix,
- sizeof(dnsprefix)-1))
- format = formatDnsPrefixedServiceItem;
- else if (attributes->attr[1].length >= sizeof(btmmprefix)-1 &&
- 0 == strncasecmp(attributes->attr[1].data, btmmprefix, sizeof(btmmprefix)-1))
- format = formatBtmmPrefixedServiceItem;
- else if (attributes->attr[0].length == sizeof(ddns)-1 &&
- 0 == strncasecmp(attributes->attr[0].data, ddns, sizeof(ddns)-1))
- format = formatDdnsTypeItem;
- else if (attributes->attr[0].length == sizeof(ddnsrev)-1 &&
- 0 == strncasecmp(attributes->attr[0].data, ddnsrev, sizeof(ddnsrev)-1))
- format = formatDdnsTypeItem;
- else
- {
- debug("uninterested in this entry");
- goto skip;
- }
- *attributesp = attributes;
- debug("accepting this entry");
- return format;
-
-skip:
- SecKeychainItemFreeAttributesAndData(attributes, NULL);
- return formatNotDNSKey;
-}
-
-// Insert the attributes as defined by mDNSKeyChainAttributes
-static CFPropertyListRef
-getKeychainItemInfo(SecKeychainItemRef item,
- SecKeychainAttributeList *attributes, enum DNSKeyFormat format)
-{
- CFMutableArrayRef entry = NULL;
- CFDataRef data = NULL;
- OSStatus status = noErr;
- UInt32 keylen = 0;
- void *keyp = 0;
-
- if (NULL == (entry = CFArrayCreateMutable(NULL, 0,
- &kCFTypeArrayCallBacks)))
- {
- debug("CFArrayCreateMutable failed");
- goto error;
- }
-
- // Insert the Account attribute (kmDNSKcWhere)
- switch ((enum DNSKeyFormat)format)
- {
- case formatDdnsTypeItem:
- data = CFDataCreate(kCFAllocatorDefault,
- attributes->attr[1].data, attributes->attr[1].length);
- break;
- case formatDnsPrefixedServiceItem:
- case formatBtmmPrefixedServiceItem:
- data = CFDataCreate(kCFAllocatorDefault,
- attributes->attr[1].data, attributes->attr[1].length);
- break;
- default:
- assert("unknown DNSKeyFormat value");
- break;
- }
- if (NULL == data)
- {
- debug("CFDataCreate for attr[1] failed");
- goto error;
- }
- CFArrayAppendValue(entry, data);
- CFRelease(data);
-
- // Insert the Where attribute (kmDNSKcAccount)
- if (NULL == (data = CFDataCreate(kCFAllocatorDefault,
- attributes->attr[2].data, attributes->attr[2].length)))
- {
- debug("CFDataCreate for attr[2] failed");
- goto error;
- }
- CFArrayAppendValue(entry, data);
- CFRelease(data);
-
- // Insert the Key attribute (kmDNSKcKey)
- if (noErr != (status = SecKeychainItemCopyAttributesAndData(item, NULL,
- NULL, NULL, &keylen, &keyp)))
- {
- debug("could not retrieve key for \"%.*s\": %d",
- (int)attributes->attr[1].length, attributes->attr[1].data,
- status);
- goto error;
- }
- data = CFDataCreate(kCFAllocatorDefault, keyp, keylen);
- SecKeychainItemFreeAttributesAndData(NULL, keyp);
- if (NULL == data)
- {
- debug("CFDataCreate for keyp failed");
- goto error;
- }
- CFArrayAppendValue(entry, data);
- CFRelease(data);
-
- // Insert the Name attribute (kmDNSKcName)
- if (NULL == (data = CFDataCreate(kCFAllocatorDefault,
- attributes->attr[3].data, attributes->attr[3].length)))
- {
- debug("CFDataCreate for attr[3] failed");
- goto error;
- }
- CFArrayAppendValue(entry, data);
- CFRelease(data);
- return entry;
-
-error:
- if (NULL != entry)
- CFRelease(entry);
- return NULL;
-}
-#endif
-
-kern_return_t
-do_mDNSKeychainGetSecrets(__unused mach_port_t port, __unused unsigned int *numsecrets,
- __unused vm_offset_t *secrets, __unused mach_msg_type_number_t *secretsCnt, __unused int *err,
- __unused audit_token_t token)
-{
-#ifndef NO_SECURITYFRAMEWORK
- CFWriteStreamRef stream = NULL;
- CFDataRef result = NULL;
- CFPropertyListRef entry = NULL;
- CFMutableArrayRef keys = NULL;
- SecKeychainRef skc = NULL;
- SecKeychainItemRef item = NULL;
- SecKeychainSearchRef search = NULL;
- SecKeychainAttributeList *attributes = NULL;
- enum DNSKeyFormat format;
- OSStatus status = 0;
-
- debug("entry");
- *err = 0;
- *numsecrets = 0;
- *secrets = (vm_offset_t)NULL;
- if (!authorized(&token))
- {
- *err = kmDNSHelperNotAuthorized;
- goto fin;
- }
- if (NULL == (keys = CFArrayCreateMutable(NULL, 0,
- &kCFTypeArrayCallBacks)))
- {
- debug("CFArrayCreateMutable failed");
- *err = kmDNSHelperCreationFailed;
- goto fin;
- }
- if (noErr != (status = SecKeychainCopyDefault(&skc)))
- {
- *err = kmDNSHelperKeychainCopyDefaultFailed;
- goto fin;
- }
- if (noErr != (status = SecKeychainSearchCreateFromAttributes(skc, kSecGenericPasswordItemClass, NULL, &search)))
- {
- *err = kmDNSHelperKeychainSearchCreationFailed;
- goto fin;
- }
- for (status = SecKeychainSearchCopyNext(search, &item);
- noErr == status;
- status = SecKeychainSearchCopyNext(search, &item))
- {
- if (formatNotDNSKey != (format = getDNSKeyFormat(item,
- &attributes)) &&
- NULL != (entry = getKeychainItemInfo(item, attributes,
- format)))
- {
- CFArrayAppendValue(keys, entry);
- CFRelease(entry);
- }
- SecKeychainItemFreeAttributesAndData(attributes, NULL);
- CFRelease(item);
- }
- if (errSecItemNotFound != status)
- helplog(ASL_LEVEL_ERR, "%s: SecKeychainSearchCopyNext failed: %d",
- __func__, status);
- if (NULL == (stream =
- CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault,
- kCFAllocatorDefault)))
- {
- *err = kmDNSHelperCreationFailed;
- debug("CFWriteStreamCreateWithAllocatedBuffers failed");
- goto fin;
- }
- CFWriteStreamOpen(stream);
- if (0 == CFPropertyListWriteToStream(keys, stream,
- kCFPropertyListBinaryFormat_v1_0, NULL))
- {
- *err = kmDNSHelperPListWriteFailed;
- debug("CFPropertyListWriteToStream failed");
- goto fin;
- }
- result = CFWriteStreamCopyProperty(stream,
- kCFStreamPropertyDataWritten);
- if (KERN_SUCCESS != vm_allocate(mach_task_self(), secrets,
- CFDataGetLength(result), VM_FLAGS_ANYWHERE))
- {
- *err = kmDNSHelperCreationFailed;
- debug("vm_allocate failed");
- goto fin;
- }
- CFDataGetBytes(result, CFRangeMake(0, CFDataGetLength(result)),
- (void *)*secrets);
- *secretsCnt = CFDataGetLength(result);
- *numsecrets = CFArrayGetCount(keys);
- debug("succeeded");
-
-fin:
- debug("returning %u secrets", *numsecrets);
- if (NULL != stream)
- {
- CFWriteStreamClose(stream);
- CFRelease(stream);
- }
- if (NULL != result)
- CFRelease(result);
- if (NULL != keys)
- CFRelease(keys);
- if (NULL != search)
- CFRelease(search);
- if (NULL != skc)
- CFRelease(skc);
- update_idle_timer();
- return KERN_SUCCESS;
-#else
- return KERN_FAILURE;
-#endif
-}
-
-#ifndef MDNS_NO_IPSEC
-typedef enum _mDNSTunnelPolicyWhich
-{
- kmDNSTunnelPolicySetup,
- kmDNSTunnelPolicyTeardown,
- kmDNSTunnelPolicyGenerate
-} mDNSTunnelPolicyWhich;
-
-// For kmDNSTunnelPolicySetup, you can setup IPv6-in-IPv6 tunnel or IPv6-in-IPv4 tunnel
-// kmDNSNoTunnel is used for other Policy types
-typedef enum _mDNSTunnelType
-{
- kmDNSNoTunnel,
- kmDNSIPv6IPv4Tunnel,
- kmDNSIPv6IPv6Tunnel
-} mDNSTunnelType;
-
-static const uint8_t kWholeV6Mask = 128;
-
-#endif /* ifndef MDNS_NO_IPSEC */
-
-#ifndef MDNS_NO_IPSEC
-
-static const char g_racoon_config_dir[] = "/var/run/racoon/";
-static const char g_racoon_config_dir_old[] = "/etc/racoon/remote/";
-
-CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
-CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
-
-// Major version 6 is 10.2.x (Jaguar)
-// Major version 7 is 10.3.x (Panther)
-// Major version 8 is 10.4.x (Tiger)
-// Major version 9 is 10.5.x (Leopard)
-// Major version 10 is 10.6.x (SnowLeopard)
-static int MacOSXSystemBuildNumber(char* letter_out, int* minor_out)
-{
- int major = 0, minor = 0;
- char letter = 0, buildver[256]="<Unknown>";
- CFDictionaryRef vers = _CFCopySystemVersionDictionary();
- if (vers)
- {
- CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
- if (cfbuildver) CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8);
- sscanf(buildver, "%d%c%d", &major, &letter, &minor);
- CFRelease(vers);
- }
- else
- helplog(ASL_LEVEL_NOTICE, "_CFCopySystemVersionDictionary failed");
-
- if (!major) { major=10; letter = 'A'; minor = 190; helplog(ASL_LEVEL_NOTICE, "Note: No Major Build Version number found; assuming 10A190"); }
- if (letter_out) *letter_out = letter;
- if (minor_out) *minor_out = minor;
- return(major);
-}
-
-static int UseOldRacoon()
-{
- static int g_oldRacoon = -1;
-
- if (g_oldRacoon == -1)
- {
- char letter = 0;
- int minor = 0;
- g_oldRacoon = (MacOSXSystemBuildNumber(&letter, &minor) < 10);
- debug("%s", g_oldRacoon ? "old" : "new");
- }
-
- return g_oldRacoon;
-}
-
-static int RacoonSignal()
-{
- return UseOldRacoon() ? SIGHUP : SIGUSR1;
-}
-
-static const char* GetRacoonConfigDir()
-{
- return UseOldRacoon() ? g_racoon_config_dir_old : g_racoon_config_dir;
-}
-
-static const char* GetOldRacoonConfigDir()
-{
- return UseOldRacoon() ? NULL : g_racoon_config_dir_old;
-}
-
-static const char racoon_config_file[] = "anonymous.conf";
-static const char racoon_config_file_orig[] = "anonymous.conf.orig";
-
-static const char configHeader[] = "# BackToMyMac\n";
-
-static int IsFamiliarRacoonConfiguration(const char* racoon_config_path)
-{
- int fd = open(racoon_config_path, O_RDONLY);
- debug("entry %s", racoon_config_path);
- if (0 > fd)
- {
- helplog(ASL_LEVEL_NOTICE, "open \"%s\" failed: %s", racoon_config_path, strerror(errno));
- return 0;
- }
- else
- {
- char header[sizeof(configHeader)] = {0};
- ssize_t bytesRead = read(fd, header, sizeof(header)-1);
- close(fd);
- if (bytesRead != sizeof(header)-1) return 0;
- return (0 == memcmp(header, configHeader, sizeof(header)-1));
- }
-}
-
-static void
-revertAnonymousRacoonConfiguration(const char* dir)
-{
- if (!dir) return;
-
- debug("entry %s", dir);
-
- char racoon_config_path[64];
- strlcpy(racoon_config_path, dir, sizeof(racoon_config_path));
- strlcat(racoon_config_path, racoon_config_file, sizeof(racoon_config_path));
-
- struct stat s;
- int ret = stat(racoon_config_path, &s);
- debug("stat(%s): %d errno=%d", racoon_config_path, ret, errno);
- if (ret == 0)
- {
- if (IsFamiliarRacoonConfiguration(racoon_config_path))
- {
- helplog(ASL_LEVEL_INFO, "\"%s\" looks familiar, unlinking", racoon_config_path);
- unlink(racoon_config_path);
- }
- else
- {
- helplog(ASL_LEVEL_NOTICE, "\"%s\" does not look familiar, leaving in place", racoon_config_path);
- return;
- }
- }
- else if (errno != ENOENT)
- {
- helplog(ASL_LEVEL_NOTICE, "stat failed for \"%s\", leaving in place: %s", racoon_config_path, strerror(errno));
- return;
- }
-
- char racoon_config_path_orig[64];
- strlcpy(racoon_config_path_orig, dir, sizeof(racoon_config_path_orig));
- strlcat(racoon_config_path_orig, racoon_config_file_orig, sizeof(racoon_config_path_orig));
-
- ret = stat(racoon_config_path_orig, &s);
- debug("stat(%s): %d errno=%d", racoon_config_path_orig, ret, errno);
- if (ret == 0)
- {
- if (0 > rename(racoon_config_path_orig, racoon_config_path))
- helplog(ASL_LEVEL_NOTICE, "rename \"%s\" \"%s\" failed: %s", racoon_config_path_orig, racoon_config_path, strerror(errno));
- else
- debug("reverted \"%s\" to \"%s\"", racoon_config_path_orig, racoon_config_path);
- }
- else if (errno != ENOENT)
- {
- helplog(ASL_LEVEL_NOTICE, "stat failed for \"%s\", leaving in place: %s", racoon_config_path_orig, strerror(errno));
- return;
- }
-}
-
-static void
-moveAsideAnonymousRacoonConfiguration(const char* dir)
-{
- if (!dir) return;
-
- debug("entry %s", dir);
-
- char racoon_config_path[64];
- strlcpy(racoon_config_path, dir, sizeof(racoon_config_path));
- strlcat(racoon_config_path, racoon_config_file, sizeof(racoon_config_path));
-
- struct stat s;
- int ret = stat(racoon_config_path, &s);
- if (ret == 0)
- {
- if (IsFamiliarRacoonConfiguration(racoon_config_path))
- {
- helplog(ASL_LEVEL_INFO, "\"%s\" looks familiar, unlinking", racoon_config_path);
- unlink(racoon_config_path);
- }
- else
- {
- char racoon_config_path_orig[64];
- strlcpy(racoon_config_path_orig, dir, sizeof(racoon_config_path_orig));
- strlcat(racoon_config_path_orig, racoon_config_file_orig, sizeof(racoon_config_path_orig));
- if (0 > rename(racoon_config_path, racoon_config_path_orig)) // If we didn't write it, move it to the side so it can be reverted later
- helplog(ASL_LEVEL_NOTICE, "rename \"%s\" to \"%s\" failed: %s", racoon_config_path, racoon_config_path_orig, strerror(errno));
- else
- debug("successfully renamed \"%s\" to \"%s\"", racoon_config_path, racoon_config_path_orig);
- }
- }
- else if (errno != ENOENT)
- {
- helplog(ASL_LEVEL_NOTICE, "stat failed for \"%s\", leaving in place: %s", racoon_config_path, strerror(errno));
- return;
- }
-}
-
-static int
-ensureExistenceOfRacoonConfigDir(const char* const racoon_config_dir)
-{
- struct stat s;
- int ret = stat(racoon_config_dir, &s);
- if (ret != 0)
- {
- if (errno != ENOENT)
- {
- helplog(ASL_LEVEL_ERR, "stat of \"%s\" failed (%d): %s",
- racoon_config_dir, ret, strerror(errno));
- return -1;
- }
- else
- {
- ret = mkdir(racoon_config_dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
- if (ret != 0)
- {
- helplog(ASL_LEVEL_ERR, "mkdir \"%s\" failed: %s",
- racoon_config_dir, strerror(errno));
- return -1;
- }
- else
- helplog(ASL_LEVEL_INFO, "created directory \"%s\"", racoon_config_dir);
- }
- }
- else if (!(s.st_mode & S_IFDIR))
- {
- helplog(ASL_LEVEL_ERR, "\"%s\" is not a directory!",
- racoon_config_dir);
- return -1;
- }
-
- return 0;
-}
-
-static int
-createAnonymousRacoonConfiguration(const char *fqdn)
-{
- static const char config1[] =
- "remote anonymous {\n"
- " exchange_mode aggressive;\n"
- " doi ipsec_doi;\n"
- " situation identity_only;\n"
- " verify_identifier off;\n"
- " generate_policy on;\n"
- " shared_secret keychain_by_id \"";
- static const char config2[] =
- "\";\n"
- " nonce_size 16;\n"
- " lifetime time 15 min;\n"
- " initial_contact on;\n"
- " support_proxy on;\n"
- " nat_traversal force;\n"
- " proposal_check claim;\n"
- " proposal {\n"
- " encryption_algorithm aes;\n"
- " hash_algorithm sha256;\n"
- " authentication_method pre_shared_key;\n"
- " dh_group 2;\n"
- " lifetime time 15 min;\n"
- " }\n"
- " proposal {\n"
- " encryption_algorithm aes;\n"
- " hash_algorithm sha1;\n"
- " authentication_method pre_shared_key;\n"
- " dh_group 2;\n"
- " lifetime time 15 min;\n"
- " }\n"
- "}\n\n"
- "sainfo anonymous { \n"
- " pfs_group 2;\n"
- " lifetime time 10 min;\n"
- " encryption_algorithm aes;\n"
- " authentication_algorithm hmac_sha256,hmac_sha1;\n"
- " compression_algorithm deflate;\n"
- "}\n";
- char tmp_config_path[64];
- char racoon_config_path[64];
- const char* const racoon_config_dir = GetRacoonConfigDir();
- const char* const racoon_config_dir_old = GetOldRacoonConfigDir();
- int fd = -1;
-
- debug("entry");
-
- if (0 > ensureExistenceOfRacoonConfigDir(racoon_config_dir))
- return -1;
-
- strlcpy(tmp_config_path, racoon_config_dir, sizeof(tmp_config_path));
- strlcat(tmp_config_path, "tmp.XXXXXX", sizeof(tmp_config_path));
-
- fd = mkstemp(tmp_config_path);
-
- if (0 > fd)
- {
- helplog(ASL_LEVEL_ERR, "mkstemp \"%s\" failed: %s",
- tmp_config_path, strerror(errno));
- return -1;
- }
- write(fd, configHeader, sizeof(configHeader)-1);
- write(fd, config1, sizeof(config1)-1);
- write(fd, fqdn, strlen(fqdn));
- write(fd, config2, sizeof(config2)-1);
- close(fd);
-
- strlcpy(racoon_config_path, racoon_config_dir, sizeof(racoon_config_path));
- strlcat(racoon_config_path, racoon_config_file, sizeof(racoon_config_path));
-
- moveAsideAnonymousRacoonConfiguration(racoon_config_dir_old);
- moveAsideAnonymousRacoonConfiguration(racoon_config_dir);
-
- if (0 > rename(tmp_config_path, racoon_config_path))
- {
- unlink(tmp_config_path);
- helplog(ASL_LEVEL_ERR, "rename \"%s\" \"%s\" failed: %s",
- tmp_config_path, racoon_config_path, strerror(errno));
- revertAnonymousRacoonConfiguration(racoon_config_dir_old);
- revertAnonymousRacoonConfiguration(racoon_config_dir);
- return -1;
- }
-
- debug("successfully renamed \"%s\" \"%s\"", tmp_config_path, racoon_config_path);
- return 0;
-}
-
-static int
-notifyRacoon(void)
-{
- debug("entry");
- static const char racoon_pid_path[] = "/var/run/racoon.pid";
- char buf[] = "18446744073709551615"; /* largest 64-bit integer */
- char *p = NULL;
- ssize_t n = 0;
- unsigned long m = 0;
- int fd = open(racoon_pid_path, O_RDONLY);
-
- if (0 > fd)
- {
- debug("open \"%s\" failed, and that's OK: %s", racoon_pid_path,
- strerror(errno));
- return kmDNSHelperRacoonNotificationFailed;
- }
- n = read(fd, buf, sizeof(buf)-1);
- close(fd);
- if (1 > n)
- {
- debug("read of \"%s\" failed: %s", racoon_pid_path,
- n == 0 ? "empty file" : strerror(errno));
- return kmDNSHelperRacoonNotificationFailed;
- }
- buf[n] = '\0';
- m = strtoul(buf, &p, 10);
- if (*p != '\0' && !isspace(*p))
- {
- debug("invalid PID \"%s\" (around '%c')", buf, *p);
- return kmDNSHelperRacoonNotificationFailed;
- }
- if (2 > m)
- {
- debug("refusing to kill PID %lu", m);
- return kmDNSHelperRacoonNotificationFailed;
- }
- if (0 != kill(m, RacoonSignal()))
- {
- debug("Could not signal racoon (%lu): %s", m, strerror(errno));
- return kmDNSHelperRacoonNotificationFailed;
- }
- debug("Sent racoon (%lu) signal %d", m, RacoonSignal());
- return 0;
-}
-
-static void
-closefds(int from)
-{
- int fd = 0;
- struct dirent entry, *entryp = NULL;
- DIR *dirp = opendir("/dev/fd");
-
- if (dirp == NULL)
- {
- /* fall back to the erroneous getdtablesize method */
- for (fd = from; fd < getdtablesize(); ++fd)
- close(fd);
- return;
- }
- while (0 == readdir_r(dirp, &entry, &entryp) && NULL != entryp)
- {
- fd = atoi(entryp->d_name);
- if (fd >= from && fd != dirfd(dirp))
- close(fd);
- }
- closedir(dirp);
-}
-
-static int
-startRacoonOld(void)
-{
- debug("entry");
- char * const racoon_args[] = { "/usr/sbin/racoon", "-e", NULL };
- ssize_t n = 0;
- pid_t pid = 0;
- int status = 0;
-
- if (0 == (pid = fork()))
- {
- closefds(0);
- execve(racoon_args[0], racoon_args, NULL);
- helplog(ASL_LEVEL_ERR, "execve of \"%s\" failed: %s",
- racoon_args[0], strerror(errno));
- exit(2);
- }
- helplog(ASL_LEVEL_NOTICE, "racoon (pid=%lu) started",
- (unsigned long)pid);
- n = waitpid(pid, &status, 0);
- if (-1 == n)
- {
- helplog(ASL_LEVEL_ERR, "Unexpected waitpid failure: %s",
- strerror(errno));
- return kmDNSHelperRacoonStartFailed;
- }
- else if (pid != n)
- {
- helplog(ASL_LEVEL_ERR, "Unexpected waitpid return value %d",
- (int)n);
- return kmDNSHelperRacoonStartFailed;
- }
- else if (WIFSIGNALED(status))
- {
- helplog(ASL_LEVEL_ERR,
- "racoon (pid=%lu) terminated due to signal %d",
- (unsigned long)pid, WTERMSIG(status));
- return kmDNSHelperRacoonStartFailed;
- }
- else if (WIFSTOPPED(status))
- {
- helplog(ASL_LEVEL_ERR,
- "racoon (pid=%lu) has stopped due to signal %d",
- (unsigned long)pid, WSTOPSIG(status));
- return kmDNSHelperRacoonStartFailed;
- }
- else if (0 != WEXITSTATUS(status))
- {
- helplog(ASL_LEVEL_ERR,
- "racoon (pid=%lu) exited with status %d",
- (unsigned long)pid, WEXITSTATUS(status));
- return kmDNSHelperRacoonStartFailed;
- }
- debug("racoon (pid=%lu) daemonized normally", (unsigned long)pid);
- return 0;
-}
-
-// constant and structure for the racoon control socket
-#define VPNCTL_CMD_PING 0x0004
-typedef struct vpnctl_hdr_struct
-{
- u_int16_t msg_type;
- u_int16_t flags;
- u_int32_t cookie;
- u_int32_t reserved;
- u_int16_t result;
- u_int16_t len;
-} vpnctl_hdr;
-
-static int
-startRacoon(void)
-{
- debug("entry");
- int fd = socket(PF_UNIX, SOCK_STREAM, 0);
- if (0 > fd)
- {
- helplog(ASL_LEVEL_ERR, "Could not create endpoint for racoon control socket: %d %s",
- errno, strerror(errno));
- return kmDNSHelperRacoonStartFailed;
- }
-
- struct sockaddr_un saddr;
- memset(&saddr, 0, sizeof(saddr));
- saddr.sun_family = AF_UNIX;
- saddr.sun_len = sizeof(saddr);
- static const char racoon_control_sock_path[] = "/var/run/vpncontrol.sock";
- strcpy(saddr.sun_path, racoon_control_sock_path);
- int result = connect(fd, (struct sockaddr*) &saddr, saddr.sun_len);
- if (0 > result)
- {
- helplog(ASL_LEVEL_ERR, "Could not connect racoon control socket %s: %d %s",
- racoon_control_sock_path, errno, strerror(errno));
- return kmDNSHelperRacoonStartFailed;
- }
-
- u_int32_t btmm_cookie = 0x4d4d5442;
- vpnctl_hdr h = { htons(VPNCTL_CMD_PING), 0, btmm_cookie, 0, 0, 0 };
- size_t bytes = 0;
- ssize_t ret = 0;
-
- while (bytes < sizeof(vpnctl_hdr))
- {
- ret = write(fd, ((unsigned char*)&h)+bytes, sizeof(vpnctl_hdr) - bytes);
- if (ret == -1)
- {
- helplog(ASL_LEVEL_ERR, "Could not write to racoon control socket: %d %s",
- errno, strerror(errno));
- return kmDNSHelperRacoonStartFailed;
- }
- bytes += ret;
- }
-
- int nfds = fd + 1;
- fd_set fds;
- int counter = 0;
- struct timeval tv;
- bytes = 0;
- h.cookie = 0;
-
- for (counter = 0; counter < 100; counter++)
- {
- FD_ZERO(&fds);
- FD_SET(fd, &fds);
- tv = (struct timeval){ 0, 10000 }; // 10 milliseconds * 100 iterations = 1 second max wait time
-
- result = select(nfds, &fds, (fd_set*)NULL, (fd_set*)NULL, &tv);
- if (result > 0)
- {
- if (FD_ISSET(fd, &fds))
- {
- ret = read(fd, ((unsigned char*)&h)+bytes, sizeof(vpnctl_hdr) - bytes);
-
- if (ret == -1)
- {
- helplog(ASL_LEVEL_ERR, "Could not read from racoon control socket: %d %s",
- strerror(errno));
- break;
- }
- bytes += ret;
- if (bytes >= sizeof(vpnctl_hdr)) break;
- }
- else
- {
- debug("select returned but fd_isset not on expected fd\n");
- }
- }
- else if (result < 0)
- {
- debug("select returned %d errno %d %s\n", result, errno, strerror(errno));
- if (errno != EINTR) break;
- }
- }
-
- close(fd);
-
- if (bytes < sizeof(vpnctl_hdr) || h.cookie != btmm_cookie) return kmDNSHelperRacoonStartFailed;
-
- debug("racoon started");
- return 0;
-}
-
-static int
-kickRacoon(void)
-{
- if ( 0 == notifyRacoon() )
- return 0;
- return UseOldRacoon() ? startRacoonOld() : startRacoon();
-}
-
-#endif /* ndef MDNS_NO_IPSEC */
-
-int
-do_mDNSConfigureServer(__unused mach_port_t port, int updown, const char *fqdn, audit_token_t token)
-{
-#ifndef MDNS_NO_IPSEC
- debug("entry");
- if (!authorized(&token)) goto fin;
-
- switch ((enum mDNSUpDown)updown)
- {
- case kmDNSUp:
- if (0 != createAnonymousRacoonConfiguration(fqdn)) goto fin;
- break;
- case kmDNSDown:
- revertAnonymousRacoonConfiguration(GetOldRacoonConfigDir());
- revertAnonymousRacoonConfiguration(GetRacoonConfigDir());
- break;
- default:
- goto fin;
- }
-
- if (0 != kickRacoon())
- goto fin;
- debug("succeeded");
-
-fin:
-#else
- (void)port; (void)updown; (void)fqdn; (void)token;
-#endif
- update_idle_timer();
- return KERN_SUCCESS;
-}
-
-#ifndef MDNS_NO_IPSEC
-
-static unsigned int routeSeq = 1;
-
-static int
-setupTunnelRoute(v6addr_t local, v6addr_t remote)
-{
- struct
- {
- struct rt_msghdr hdr;
- struct sockaddr_in6 dst;
- struct sockaddr_in6 gtwy;
- } msg;
- int err = 0;
- int s = -1;
-
- if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET)))
- {
- helplog(ASL_LEVEL_ERR, "socket(PF_ROUTE, ...) failed: %s",
- strerror(errno));
- err = kmDNSHelperRoutingSocketCreationFailed;
- goto fin;
- }
- memset(&msg, 0, sizeof(msg));
- msg.hdr.rtm_msglen = sizeof(msg);
- msg.hdr.rtm_type = RTM_ADD;
- /* The following flags are set by `route add -inet6 -host ...` */
- msg.hdr.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_HOST | RTF_STATIC;
- msg.hdr.rtm_version = RTM_VERSION;
- msg.hdr.rtm_seq = routeSeq++;
- msg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
- msg.hdr.rtm_inits = RTV_MTU;
- msg.hdr.rtm_rmx.rmx_mtu = 1280;
-
- msg.dst.sin6_len = sizeof(msg.dst);
- msg.dst.sin6_family = AF_INET6;
- memcpy(&msg.dst.sin6_addr, remote, sizeof(msg.dst.sin6_addr));
-
- msg.gtwy.sin6_len = sizeof(msg.gtwy);
- msg.gtwy.sin6_family = AF_INET6;
- memcpy(&msg.gtwy.sin6_addr, local, sizeof(msg.gtwy.sin6_addr));
-
- /* send message, ignore error when route already exists */
- if (0 > write(s, &msg, msg.hdr.rtm_msglen))
- {
- int errno_ = errno;
-
- debug("write to routing socket failed: %s", strerror(errno_));
- if (EEXIST != errno_)
- {
- err = kmDNSHelperRouteAdditionFailed;
- goto fin;
- }
- }
-
-fin:
- if (0 <= s)
- close(s);
- return err;
-}
-
-static int
-teardownTunnelRoute(v6addr_t remote)
-{
- struct
- {
- struct rt_msghdr hdr;
- struct sockaddr_in6 dst;
- } msg;
- int err = 0;
- int s = -1;
-
- if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET)))
- {
- helplog(ASL_LEVEL_ERR, "socket(PF_ROUTE, ...) failed: %s",
- strerror(errno));
- err = kmDNSHelperRoutingSocketCreationFailed;
- goto fin;
- }
- memset(&msg, 0, sizeof(msg));
-
- msg.hdr.rtm_msglen = sizeof(msg);
- msg.hdr.rtm_type = RTM_DELETE;
- msg.hdr.rtm_version = RTM_VERSION;
- msg.hdr.rtm_seq = routeSeq++;
- msg.hdr.rtm_addrs = RTA_DST;
-
- msg.dst.sin6_len = sizeof(msg.dst);
- msg.dst.sin6_family = AF_INET6;
- memcpy(&msg.dst.sin6_addr, remote, sizeof(msg.dst.sin6_addr));
- if (0 > write(s, &msg, msg.hdr.rtm_msglen))
- {
- int errno_ = errno;
-
- debug("write to routing socket failed: %s", strerror(errno_));
- if (ESRCH != errno_)
- {
- err = kmDNSHelperRouteDeletionFailed;
- goto fin;
- }
- }
-
-fin:
- if (0 <= s)
- close(s);
- return err;
-}
-
-static int
-v4addr_to_string(v4addr_t addr, char *buf, size_t buflen)
-{
- if (NULL == inet_ntop(AF_INET, addr, buf, buflen))
- {
- helplog(ASL_LEVEL_ERR, "inet_ntop failed: %s",
- strerror(errno));
- return kmDNSHelperInvalidNetworkAddress;
- }
- else
- return 0;
-}
-
-static int
-v6addr_to_string(v6addr_t addr, char *buf, size_t buflen)
-{
- if (NULL == inet_ntop(AF_INET6, addr, buf, buflen))
- {
- helplog(ASL_LEVEL_ERR, "inet_ntop failed: %s",
- strerror(errno));
- return kmDNSHelperInvalidNetworkAddress;
- }
- else
- return 0;
-}
-
-/* Caller owns object returned in `policy' */
-static int
-generateTunnelPolicy(mDNSTunnelPolicyWhich which, mDNSTunnelType type, int in,
- v4addr_t src, uint16_t src_port,
- v4addr_t dst, uint16_t dst_port,
- v6addr_t src6, v6addr_t dst6,
- ipsec_policy_t *policy, size_t *len)
-{
- char srcs[INET_ADDRSTRLEN], dsts[INET_ADDRSTRLEN];
- char srcs6[INET6_ADDRSTRLEN], dsts6[INET6_ADDRSTRLEN];
- char buf[512];
- char *inOut = in ? "in" : "out";
- ssize_t n = 0;
- int err = 0;
-
- *policy = NULL;
- *len = 0;
-
- switch (which)
- {
- case kmDNSTunnelPolicySetup:
- if (type == kmDNSIPv6IPv4Tunnel)
- {
- if (0 != (err = v4addr_to_string(src, srcs, sizeof(srcs))))
- goto fin;
- if (0 != (err = v4addr_to_string(dst, dsts, sizeof(dsts))))
- goto fin;
- n = snprintf(buf, sizeof(buf),
- "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require",
- inOut, srcs, src_port, dsts, dst_port);
- }
- else if (type == kmDNSIPv6IPv6Tunnel)
- {
- if (0 != (err = v6addr_to_string(src6, srcs6, sizeof(srcs6))))
- goto fin;
- if (0 != (err = v6addr_to_string(dst6, dsts6, sizeof(dsts6))))
- goto fin;
- n = snprintf(buf, sizeof(buf),
- "%s ipsec esp/tunnel/%s-%s/require",
- inOut, srcs6, dsts6);
- }
- break;
- case kmDNSTunnelPolicyTeardown:
- n = strlcpy(buf, inOut, sizeof(buf));
- break;
- case kmDNSTunnelPolicyGenerate:
- n = snprintf(buf, sizeof(buf), "%s generate", inOut);
- break;
- default:
- err = kmDNSHelperIPsecPolicyCreationFailed;
- goto fin;
- }
-
- if (n >= (int)sizeof(buf))
- {
- err = kmDNSHelperResultTooLarge;
- goto fin;
- }
-
- debug("policy=\"%s\"", buf);
- if (NULL == (*policy = (ipsec_policy_t)ipsec_set_policy(buf, n)))
- {
- helplog(ASL_LEVEL_ERR,
- "Could not create IPsec policy from \"%s\"", buf);
- err = kmDNSHelperIPsecPolicyCreationFailed;
- goto fin;
- }
- *len = ((ipsec_policy_t)(*policy))->sadb_x_policy_len * 8;
-
-fin:
- return err;
-}
-
-static int
-sendPolicy(int s, int setup,
- struct sockaddr *src, uint8_t src_bits,
- struct sockaddr *dst, uint8_t dst_bits,
- ipsec_policy_t policy, size_t len)
-{
- static unsigned int policySeq = 0;
- int err = 0;
-
- debug("entry, setup=%d", setup);
- if (setup)
- err = pfkey_send_spdadd(s, src, src_bits, dst, dst_bits, -1,
- (char *)policy, len, policySeq++);
- else
- err = pfkey_send_spddelete(s, src, src_bits, dst, dst_bits, -1,
- (char *)policy, len, policySeq++);
- if (0 > err)
- {
- helplog(ASL_LEVEL_ERR, "Could not set IPsec policy: %s",
- ipsec_strerror());
- err = kmDNSHelperIPsecPolicySetFailed;
- goto fin;
- }
- else
- err = 0;
- debug("succeeded");
-
-fin:
- return err;
-}
-
-static int
-removeSA(int s, struct sockaddr *src, struct sockaddr *dst)
-{
- int err = 0;
-
- debug("entry");
- err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, src, dst);
- if (0 > err)
- {
- helplog(ASL_LEVEL_ERR, "Could not remove IPsec SA: %s", ipsec_strerror());
- err = kmDNSHelperIPsecRemoveSAFailed;
- goto fin;
- }
- err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, dst, src);
- if (0 > err)
- {
- helplog(ASL_LEVEL_ERR, "Could not remove IPsec SA: %s", ipsec_strerror());
- err = kmDNSHelperIPsecRemoveSAFailed;
- goto fin;
- }
- else
- err = 0;
-
- debug("succeeded");
-
-fin:
- return err;
-}
-
-static int
-doTunnelPolicy(mDNSTunnelPolicyWhich which, mDNSTunnelType type,
- v6addr_t loc_inner, uint8_t loc_bits,
- v4addr_t loc_outer, uint16_t loc_port,
- v6addr_t rmt_inner, uint8_t rmt_bits,
- v4addr_t rmt_outer, uint16_t rmt_port,
- v6addr_t loc_outer6, v6addr_t rmt_outer6)
-{
- struct sockaddr_in6 sin6_loc;
- struct sockaddr_in6 sin6_rmt;
- ipsec_policy_t policy = NULL;
- size_t len = 0;
- int s = -1;
- int err = 0;
-
- debug("entry");
- if (0 > (s = pfkey_open()))
- {
- helplog(ASL_LEVEL_ERR,
- "Could not create IPsec policy socket: %s",
- ipsec_strerror());
- err = kmDNSHelperIPsecPolicySocketCreationFailed;
- goto fin;
- }
-
- memset(&sin6_loc, 0, sizeof(sin6_loc));
- sin6_loc.sin6_len = sizeof(sin6_loc);
- sin6_loc.sin6_family = AF_INET6;
- sin6_loc.sin6_port = htons(0);
- memcpy(&sin6_loc.sin6_addr, loc_inner, sizeof(sin6_loc.sin6_addr));
-
- memset(&sin6_rmt, 0, sizeof(sin6_rmt));
- sin6_rmt.sin6_len = sizeof(sin6_rmt);
- sin6_rmt.sin6_family = AF_INET6;
- sin6_rmt.sin6_port = htons(0);
- memcpy(&sin6_rmt.sin6_addr, rmt_inner, sizeof(sin6_rmt.sin6_addr));
-
- int setup = which != kmDNSTunnelPolicyTeardown;
-
- if (0 != (err = generateTunnelPolicy(which, type, 1,
- rmt_outer, rmt_port,
- loc_outer, loc_port,
- rmt_outer6, loc_outer6,
- &policy, &len)))
- goto fin;
- if (0 != (err = sendPolicy(s, setup,
- (struct sockaddr *)&sin6_rmt, rmt_bits,
- (struct sockaddr *)&sin6_loc, loc_bits,
- policy, len)))
- goto fin;
- if (NULL != policy)
- {
- free(policy);
- policy = NULL;
- }
- if (0 != (err = generateTunnelPolicy(which, type, 0,
- loc_outer, loc_port,
- rmt_outer, rmt_port,
- loc_outer6, rmt_outer6,
- &policy, &len)))
- goto fin;
- if (0 != (err = sendPolicy(s, setup,
- (struct sockaddr *)&sin6_loc, loc_bits,
- (struct sockaddr *)&sin6_rmt, rmt_bits,
- policy, len)))
- goto fin;
-
- if (which == kmDNSTunnelPolicyTeardown)
- {
- if (rmt_port) // Outer tunnel is IPv4
- {
- if (loc_outer && rmt_outer)
- {
- struct sockaddr_in sin_loc;
- struct sockaddr_in sin_rmt;
- memset(&sin_loc, 0, sizeof(sin_loc));
- sin_loc.sin_len = sizeof(sin_loc);
- sin_loc.sin_family = AF_INET;
- memcpy(&sin_loc.sin_addr, loc_outer, sizeof(sin_loc.sin_addr));
-
- memset(&sin_rmt, 0, sizeof(sin_rmt));
- sin_rmt.sin_len = sizeof(sin_rmt);
- sin_rmt.sin_family = AF_INET;
- memcpy(&sin_rmt.sin_addr, rmt_outer, sizeof(sin_rmt.sin_addr));
- if (0 != (err = removeSA(s, (struct sockaddr *)&sin_loc, (struct sockaddr *)&sin_rmt)))
- goto fin;
- }
- }
- else
- {
- if (loc_outer6 && rmt_outer6)
- {
- struct sockaddr_in6 sin6_lo;
- struct sockaddr_in6 sin6_rm;
-
- memset(&sin6_lo, 0, sizeof(sin6_lo));
- sin6_lo.sin6_len = sizeof(sin6_lo);
- sin6_lo.sin6_family = AF_INET6;
- memcpy(&sin6_lo.sin6_addr, loc_outer6, sizeof(sin6_lo.sin6_addr));
-
- memset(&sin6_rm, 0, sizeof(sin6_rm));
- sin6_rm.sin6_len = sizeof(sin6_rm);
- sin6_rm.sin6_family = AF_INET6;
- memcpy(&sin6_rm.sin6_addr, rmt_outer6, sizeof(sin6_rm.sin6_addr));
- if (0 != (err = removeSA(s, (struct sockaddr *)&sin6_lo, (struct sockaddr *)&sin6_rm)))
- goto fin;
- }
- }
- }
-
-
- debug("succeeded");
-
-fin:
- if (s >= 0)
- pfkey_close(s);
- if (NULL != policy)
- free(policy);
- return err;
-}
-
-#endif /* ndef MDNS_NO_IPSEC */
-
-int
-do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete,
- v6addr_t loc_inner, v6addr_t loc_outer6, uint16_t loc_port,
- v6addr_t rmt_inner, v6addr_t rmt_outer6, uint16_t rmt_port,
- const char *id, int *err, audit_token_t token)
-{
-#ifndef MDNS_NO_IPSEC
- static const char config[] =
- "%s"
- "remote %s [%u] {\n"
- " disconnect_on_idle idle_timeout 600 idle_direction idle_outbound;\n"
- " exchange_mode aggressive;\n"
- " doi ipsec_doi;\n"
- " situation identity_only;\n"
- " verify_identifier off;\n"
- " generate_policy on;\n"
- " my_identifier user_fqdn \"%s\";\n"
- " shared_secret keychain \"%s\";\n"
- " nonce_size 16;\n"
- " lifetime time 15 min;\n"
- " initial_contact on;\n"
- " support_proxy on;\n"
- " nat_traversal force;\n"
- " proposal_check claim;\n"
- " proposal {\n"
- " encryption_algorithm aes;\n"
- " hash_algorithm sha256;\n"
- " authentication_method pre_shared_key;\n"
- " dh_group 2;\n"
- " lifetime time 15 min;\n"
- " }\n"
- " proposal {\n"
- " encryption_algorithm aes;\n"
- " hash_algorithm sha1;\n"
- " authentication_method pre_shared_key;\n"
- " dh_group 2;\n"
- " lifetime time 15 min;\n"
- " }\n"
- "}\n\n"
- "sainfo address %s any address %s any {\n"
- " pfs_group 2;\n"
- " lifetime time 10 min;\n"
- " encryption_algorithm aes;\n"
- " authentication_algorithm hmac_sha256,hmac_sha1;\n"
- " compression_algorithm deflate;\n"
- "}\n\n"
- "sainfo address %s any address %s any {\n"
- " pfs_group 2;\n"
- " lifetime time 10 min;\n"
- " encryption_algorithm aes;\n"
- " authentication_algorithm hmac_sha256,hmac_sha1;\n"
- " compression_algorithm deflate;\n"
- "}\n";
- char path[PATH_MAX] = "";
- char li[INET6_ADDRSTRLEN], lo[INET_ADDRSTRLEN], lo6[INET6_ADDRSTRLEN],
- ri[INET6_ADDRSTRLEN], ro[INET_ADDRSTRLEN], ro6[INET6_ADDRSTRLEN];
- FILE *fp = NULL;
- int fd = -1;
- char tmp_path[PATH_MAX] = "";
- v4addr_t loc_outer, rmt_outer;
-
- debug("entry");
- *err = 0;
- if (!authorized(&token))
- {
- *err = kmDNSHelperNotAuthorized;
- goto fin;
- }
- switch ((enum mDNSAutoTunnelSetKeysReplaceDelete)replacedelete)
- {
- case kmDNSAutoTunnelSetKeysReplace:
- case kmDNSAutoTunnelSetKeysDelete:
- break;
- default:
- *err = kmDNSHelperInvalidTunnelSetKeysOperation;
- goto fin;
- }
-
- if (0 != (*err = v6addr_to_string(loc_inner, li, sizeof(li))))
- goto fin;
- if (0 != (*err = v6addr_to_string(rmt_inner, ri, sizeof(ri))))
- goto fin;
-
- debug("loc_inner=%s rmt_inner=%s", li, ri);
- if (!rmt_port)
- {
- loc_outer[0] = loc_outer[1] = loc_outer[2] = loc_outer[3] = 0;
- rmt_outer[0] = rmt_outer[1] = rmt_outer[2] = rmt_outer[3] = 0;
-
- if (0 != (*err = v6addr_to_string(loc_outer6, lo6, sizeof(lo6))))
- goto fin;
- if (0 != (*err = v6addr_to_string(rmt_outer6, ro6, sizeof(ro6))))
- goto fin;
- debug("IPv6 outer tunnel: loc_outer6=%s rmt_outer6=%s", lo6, ro6);
- if ((int)sizeof(path) <= snprintf(path, sizeof(path),
- "%s%s.conf", GetRacoonConfigDir(), ro6))
- {
- *err = kmDNSHelperResultTooLarge;
- goto fin;
- }
- }
- else
- {
- loc_outer[0] = loc_outer6[0];
- loc_outer[1] = loc_outer6[1];
- loc_outer[2] = loc_outer6[2];
- loc_outer[3] = loc_outer6[3];
-
- rmt_outer[0] = rmt_outer6[0];
- rmt_outer[1] = rmt_outer6[1];
- rmt_outer[2] = rmt_outer6[2];
- rmt_outer[3] = rmt_outer6[3];
-
- if (0 != (*err = v4addr_to_string(loc_outer, lo, sizeof(lo))))
- goto fin;
- if (0 != (*err = v4addr_to_string(rmt_outer, ro, sizeof(ro))))
- goto fin;
- debug("IPv4 outer tunnel: loc_outer=%s loc_port=%u rmt_outer=%s rmt_port=%u",
- lo, loc_port, ro, rmt_port);
-
- if ((int)sizeof(path) <= snprintf(path, sizeof(path),
- "%s%s.%u.conf", GetRacoonConfigDir(), ro,
- rmt_port))
- {
- *err = kmDNSHelperResultTooLarge;
- goto fin;
- }
- }
-
-
-
- if (kmDNSAutoTunnelSetKeysReplace == replacedelete)
- {
- if (0 > ensureExistenceOfRacoonConfigDir(GetRacoonConfigDir()))
- {
- *err = kmDNSHelperRacoonConfigCreationFailed;
- goto fin;
- }
- if ((int)sizeof(tmp_path) <=
- snprintf(tmp_path, sizeof(tmp_path), "%s.XXXXXX", path))
- {
- *err = kmDNSHelperResultTooLarge;
- goto fin;
- }
- if (0 > (fd = mkstemp(tmp_path)))
- {
- helplog(ASL_LEVEL_ERR, "mkstemp \"%s\" failed: %s",
- tmp_path, strerror(errno));
- *err = kmDNSHelperRacoonConfigCreationFailed;
- goto fin;
- }
- if (NULL == (fp = fdopen(fd, "w")))
- {
- helplog(ASL_LEVEL_ERR, "fdopen: %s",
- strerror(errno));
- *err = kmDNSHelperRacoonConfigCreationFailed;
- goto fin;
- }
- fd = -1;
- fprintf(fp, config, configHeader, (!rmt_port ? ro6 : ro), rmt_port, id, id, ri, li, li, ri);
- fclose(fp);
- fp = NULL;
- if (0 > rename(tmp_path, path))
- {
- helplog(ASL_LEVEL_ERR,
- "rename \"%s\" \"%s\" failed: %s",
- tmp_path, path, strerror(errno));
- *err = kmDNSHelperRacoonConfigCreationFailed;
- goto fin;
- }
- }
- else
- {
- if (0 != unlink(path))
- debug("unlink \"%s\" failed: %s", path,
- strerror(errno));
- }
-
- if (0 != (*err = doTunnelPolicy(kmDNSTunnelPolicyTeardown, kmDNSNoTunnel,
- loc_inner, kWholeV6Mask, loc_outer, loc_port,
- rmt_inner, kWholeV6Mask, rmt_outer, rmt_port, loc_outer6, rmt_outer6)))
- goto fin;
- if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
- 0 != (*err = doTunnelPolicy(kmDNSTunnelPolicySetup, (!rmt_port ? kmDNSIPv6IPv6Tunnel : kmDNSIPv6IPv4Tunnel),
- loc_inner, kWholeV6Mask, loc_outer, loc_port,
- rmt_inner, kWholeV6Mask, rmt_outer, rmt_port, loc_outer6, rmt_outer6)))
- goto fin;
-
- if (0 != (*err = teardownTunnelRoute(rmt_inner)))
- goto fin;
- if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
- 0 != (*err = setupTunnelRoute(loc_inner, rmt_inner)))
- goto fin;
-
- if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
- 0 != (*err = kickRacoon()))
- goto fin;
-
- debug("succeeded");
-
-fin:
- if (NULL != fp)
- fclose(fp);
- if (0 <= fd)
- close(fd);
- unlink(tmp_path);
-#else
- (void)replacedelete; (void)loc_inner; (void)loc_outer6; (void)loc_port; (void)rmt_inner;
- (void)rmt_outer6; (void)rmt_port; (void)id; (void)token;
-
- *err = kmDNSHelperIPsecDisabled;
-#endif /* MDNS_NO_IPSEC */
- update_idle_timer();
- return KERN_SUCCESS;
-}
-
-kern_return_t
-do_mDNSSendWakeupPacket(__unused mach_port_t port, unsigned ifid, const char *eth_addr, const char *ip_addr, int iteration, audit_token_t token)
-{
- int bpf_fd, i, j;
- struct ifreq ifr;
- char ifname[IFNAMSIZ];
- char packet[512];
- char *ptr = packet;
- char bpf_device[12];
- struct ether_addr *ea;
- (void) ip_addr; // unused
- (void) iteration; // unused
- (void) token; // unused
-
- if (if_indextoname(ifid, ifname) == NULL)
- {
- helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket invalid interface index %u", ifid);
- return errno;
- }
-
- ea = ether_aton(eth_addr);
- if (ea == NULL)
- {
- helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket invalid ethernet address %s", eth_addr);
- return errno;
- }
-
- for (i = 0; i < 100; i++)
- {
- snprintf(bpf_device, sizeof(bpf_device), "/dev/bpf%d", i);
- bpf_fd = open(bpf_device, O_RDWR, 0);
- if (bpf_fd == -1)
- continue;
- else break;
- }
-
- if (bpf_fd == -1)
- {
- helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket cannot find a bpf device");
- return ENXIO;
- }
-
- memset(&ifr, 0, sizeof(ifr));
- strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
-
- if (ioctl(bpf_fd, BIOCSETIF, (char *)&ifr) < 0)
- {
- helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket BIOCSETIF failed %s", strerror(errno));
- return errno;
- }
-
- // 0x00 Destination address
- for (i=0; i<6; i++) *ptr++ = ea->octet[i];
-
- // 0x06 Source address (Note: Since we don't currently set the BIOCSHDRCMPLT option, BPF will fill in the real interface address for us)
- for (i=0; i<6; i++) *ptr++ = 0;
-
- // 0x0C Ethertype (0x0842)
- *ptr++ = 0x08;
- *ptr++ = 0x42;
-
- // 0x0E Wakeup sync sequence
- for (i=0; i<6; i++) *ptr++ = 0xFF;
-
- // 0x14 Wakeup data
- for (j=0; j<16; j++) for (i=0; i<6; i++) *ptr++ = ea->octet[i];
-
- // 0x74 Password
- for (i=0; i<6; i++) *ptr++ = 0;
-
- if (write(bpf_fd, packet, ptr - packet) < 0)
- {
- helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket write failed %s", strerror(errno));
- return errno;
- }
- helplog(ASL_LEVEL_INFO, "do_mDNSSendWakeupPacket sent unicast eth_addr %s, ip_addr %s", eth_addr, ip_addr);
- // Send a broadcast one to handle ethernet switches that don't flood forward packets with
- // unknown mac addresses.
- for (i=0; i<6; i++) packet[i] = 0xFF;
- if (write(bpf_fd, packet, ptr - packet) < 0)
- {
- helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket write failed %s", strerror(errno));
- return errno;
- }
- helplog(ASL_LEVEL_INFO, "do_mDNSSendWakeupPacket sent broadcast eth_addr %s, ip_addr %s", eth_addr, ip_addr);
- close(bpf_fd);
- return KERN_SUCCESS;
-}
-
-// Open the specified port for protocol in the P2P firewall.
-kern_return_t
-do_mDNSPacketFilterControl(__unused mach_port_t port, uint32_t command, const char * ifname, uint32_t count, pfArray_t portArray, pfArray_t protocolArray, audit_token_t token)
-{
- (void) token; // unused
- int error;
- kern_return_t result = KERN_SUCCESS;
-
- helplog(ASL_LEVEL_INFO, "do_mDNSPacketFilterControl: command %d ifname %s, count %d",
- command, ifname, count);
-
- switch (command)
- {
- case PF_SET_RULES:
- error = P2PPacketFilterAddBonjourRuleSet(ifname, count, portArray, protocolArray);
- if (error)
- {
- helplog(ASL_LEVEL_ERR, "P2PPacketFilterAddBonjourRuleSet failed %s", strerror(error));
- result = KERN_FAILURE;
- }
- break;
-
- case PF_CLEAR_RULES:
- error = P2PPacketFilterClearBonjourRules();
- if (error)
- {
- helplog(ASL_LEVEL_ERR, "P2PPacketFilterClearBonjourRules failed %s", strerror(error));
- result = KERN_FAILURE;
- }
- break;
-
- default:
- helplog(ASL_LEVEL_ERR, "do_mDNSPacketFilterControl: invalid command %d", command);
- result = KERN_INVALID_ARGUMENT;
- break;
- }
-
- return result;
-}
-
-unsigned long
-in_cksum(unsigned short *ptr,int nbytes)
-{
- unsigned long sum;
- u_short oddbyte;
-
- /*
- * Our algorithm is simple, using a 32-bit accumulator (sum),
- * we add sequential 16-bit words to it, and at the end, fold back
- * all the carry bits from the top 16 bits into the lower 16 bits.
- */
- sum = 0;
- while (nbytes > 1) {
- sum += *ptr++;
- nbytes -= 2;
- }
-
- /* mop up an odd byte, if necessary */
- if (nbytes == 1) {
- /* make sure top half is zero */
- oddbyte = 0;
-
- /* one byte only */
- *((u_char *)&oddbyte) = *(u_char *)ptr;
- sum += oddbyte;
- }
- /* Add back carry outs from top 16 bits to low 16 bits. */
- sum = (sum >> 16) + (sum & 0xffff);
-
- /* add carry */
- sum += (sum >> 16);
-
- return sum;
-}
-
-unsigned short
-InetChecksum(unsigned short *ptr,int nbytes)
-{
- unsigned long sum;
-
- sum = in_cksum(ptr, nbytes);
- return (unsigned short)~sum;
-}
-
-void TCPCheckSum(int af, struct tcphdr *t, int tcplen, v6addr_t sadd6, v6addr_t dadd6)
-{
- unsigned long sum = 0;
- unsigned short *ptr;
-
- /* TCP header checksum */
- sum = in_cksum((unsigned short *)t, tcplen);
-
- if (af == AF_INET)
- {
- /* Pseudo header */
- ptr = (unsigned short *)sadd6;
- sum += *ptr++;
- sum += *ptr++;
- ptr = (unsigned short *)dadd6;
- sum += *ptr++;
- sum += *ptr++;
- }
- else if (af == AF_INET6)
- {
- /* Pseudo header */
- ptr = (unsigned short *)sadd6;
- sum += *ptr++;
- sum += *ptr++;
- sum += *ptr++;
- sum += *ptr++;
- sum += *ptr++;
- sum += *ptr++;
- sum += *ptr++;
- sum += *ptr++;
- ptr = (unsigned short *)dadd6;
- sum += *ptr++;
- sum += *ptr++;
- sum += *ptr++;
- sum += *ptr++;
- sum += *ptr++;
- sum += *ptr++;
- sum += *ptr++;
- sum += *ptr++;
- }
-
- sum += htons(tcplen);
- sum += htons(IPPROTO_TCP);
-
- while (sum >> 16)
- sum = (sum >> 16) + (sum & 0xFFFF);
-
- t->th_sum = ~sum;
-
-}
-
-kern_return_t do_mDNSSendKeepalive(__unused mach_port_t port, v6addr_t sadd6, v6addr_t dadd6, uint16_t lport, uint16_t rport, unsigned seq, unsigned ack, uint16_t win, audit_token_t token)
-{
- struct packet4 {
- struct ip ip;
- struct tcphdr tcp;
- } packet4;
- struct packet6 {
- struct tcphdr tcp;
- } packet6;
- int sock, on;
- struct tcphdr *t;
- int af;
- struct sockaddr_storage ss_to;
- struct sockaddr_in *sin_to = (struct sockaddr_in *)&ss_to;
- struct sockaddr_in6 *sin6_to = (struct sockaddr_in6 *)&ss_to;
- void *packet;
- ssize_t packetlen;
- char ctlbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
- struct msghdr msghdr;
- struct iovec iov;
- ssize_t len;
-
- if (!authorized(&token))
- {
- helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: Not authorized");
- return kmDNSHelperNotAuthorized;
- }
-
- helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: called");
-
- // all the incoming arguments are in network order
- if ((*(unsigned *)(sadd6 +4) == 0) && (*(unsigned *)(sadd6 + 8) == 0) && (*(unsigned *)(sadd6 + 12) == 0))
- {
- af = AF_INET;
- memset(&packet4, 0, sizeof (packet4));
-
- /* Fill in all the IP header information - should be in host order*/
- packet4.ip.ip_v = 4; /* 4-bit Version */
- packet4.ip.ip_hl = 5; /* 4-bit Header Length */
- packet4.ip.ip_tos = 0; /* 8-bit Type of service */
- packet4.ip.ip_len = 40; /* 16-bit Total length */
- packet4.ip.ip_id = 9864; /* 16-bit ID field */
- packet4.ip.ip_off = 0; /* 13-bit Fragment offset */
- packet4.ip.ip_ttl = 63; /* 8-bit Time To Live */
- packet4.ip.ip_p = IPPROTO_TCP; /* 8-bit Protocol */
- packet4.ip.ip_sum = 0; /* 16-bit Header checksum (below) */
- memcpy(&packet4.ip.ip_src.s_addr, sadd6, 4);
- memcpy(&packet4.ip.ip_dst.s_addr, dadd6, 4);
-
- /* IP header checksum */
- packet4.ip.ip_sum = InetChecksum((unsigned short *)&packet4.ip, 20);
- t = &packet4.tcp;
- packet = &packet4;
- packetlen = 40; // sum of IPv4 header len(20) and TCP header len(20)
- }
- else
- {
- af = AF_INET6;
- memset(&packet6, 0, sizeof (packet6));
- t = &packet6.tcp;
- packet = &packet6;
- // We don't send IPv6 header, hence just the TCP header len (20)
- packetlen = 20;
- }
-
- /* Fill in all the TCP header information */
- t->th_sport = lport; /* 16-bit Source port number */
- t->th_dport = rport; /* 16-bit Destination port */
- t->th_seq = seq; /* 32-bit Sequence Number */
- t->th_ack = ack; /* 32-bit Acknowledgement Number */
- t->th_off = 5; /* Data offset */
- t->th_flags = TH_ACK;
- t->th_win = win;
- t->th_sum = 0; /* 16-bit checksum (below) */
- t->th_urp = 0; /* 16-bit urgent offset */
-
- TCPCheckSum(af, t, 20, sadd6, dadd6);
-
- /* Open up a RAW socket */
- if ((sock = socket(af, SOCK_RAW, IPPROTO_TCP)) < 0)
- {
- helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: socket %s", strerror(errno));
- return errno;
- }
-
-
- if (af == AF_INET)
- {
- on = 1;
- if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &on, sizeof (on)))
- {
- close(sock);
- helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: setsockopt %s", strerror(errno));
- return errno;
- }
-
- memset(sin_to, 0, sizeof(struct sockaddr_in));
- sin_to->sin_len = sizeof(struct sockaddr_in);
- sin_to->sin_family = AF_INET;
- memcpy(&sin_to->sin_addr, sadd6, sizeof(struct in_addr));
- sin_to->sin_port = rport;
-
- msghdr.msg_control = NULL;
- msghdr.msg_controllen = 0;
-
- }
- else
- {
- struct cmsghdr *ctl;
-
- memset(sin6_to, 0, sizeof(struct sockaddr_in6));
- sin6_to->sin6_len = sizeof(struct sockaddr_in6);
- sin6_to->sin6_family = AF_INET6;
- memcpy(&sin6_to->sin6_addr, dadd6, sizeof(struct in6_addr));
-
- sin6_to->sin6_port = rport;
- sin6_to->sin6_flowinfo = 0;
-
-
- msghdr.msg_control = ctlbuf;
- msghdr.msg_controllen = sizeof(ctlbuf);
- ctl = CMSG_FIRSTHDR(&msghdr);
- ctl->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
- ctl->cmsg_level = IPPROTO_IPV6;
- ctl->cmsg_type = IPV6_PKTINFO;
- struct in6_pktinfo *pktinfo = (struct in6_pktinfo *) CMSG_DATA(ctl);
- memcpy(&pktinfo->ipi6_addr, sadd6, sizeof(struct in6_addr));
- pktinfo->ipi6_ifindex = 0;
- }
-
- msghdr.msg_name = (struct sockaddr *)&ss_to;
- msghdr.msg_namelen = ss_to.ss_len;
- iov.iov_base = packet;
- iov.iov_len = packetlen;
- msghdr.msg_iov = &iov;
- msghdr.msg_iovlen = 1;
- msghdr.msg_flags = 0;
-again:
- len = sendmsg(sock, &msghdr, 0);
- if (len == -1)
- {
- if (errno == EINTR)
- goto again;
- }
-
- if (len != packetlen)
- {
- helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: sendmsg failed %s", strerror(errno));
- }
- else
- {
- char source[INET6_ADDRSTRLEN], dest[INET6_ADDRSTRLEN];
-
- inet_ntop(af, (void *)sadd6, source, sizeof(source));
- inet_ntop(af, (void *)dadd6, dest, sizeof(dest));
-
- helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: Success Source %s:%d, Dest %s:%d, %u, %u, %u", source, ntohs(lport), dest, ntohs(rport), ntohl(seq), ntohl(ack), ntohs(win));
-
- }
- close(sock);
- return KERN_SUCCESS;
-}
-
-
-kern_return_t do_mDNSRetrieveTCPInfo(__unused mach_port_t port, int family, v6addr_t laddr, uint16_t lport, v6addr_t raddr, uint16_t rport,
- uint32_t *seq, uint32_t *ack, uint16_t *win, int32_t *intfid, audit_token_t token)
-{
- struct tcp_info ti;
- struct info_tuple itpl;
- int mib[4];
- unsigned int miblen;
- size_t len;
- size_t sz;
-
- memset(&itpl, 0, sizeof(struct info_tuple));
- memset(&ti, 0, sizeof(struct tcp_info));
-
- if (!authorized(&token))
- {
- helplog(ASL_LEVEL_ERR, "mDNSRetrieveTCPInfo: Not authorized");
- return kmDNSHelperNotAuthorized;
- }
-
- if (family == AF_INET)
- {
- memcpy(&itpl.itpl_local_sin.sin_addr, laddr, sizeof(struct in_addr));
- memcpy(&itpl.itpl_remote_sin.sin_addr, raddr, sizeof(struct in_addr));
- itpl.itpl_local_sin.sin_port = lport;
- itpl.itpl_remote_sin.sin_port = rport;
- itpl.itpl_local_sin.sin_family = AF_INET;
- itpl.itpl_remote_sin.sin_family = AF_INET;
- }
- else
- {
- memcpy(&itpl.itpl_local_sin6.sin6_addr, laddr, sizeof(struct in6_addr));
- memcpy(&itpl.itpl_remote_sin6.sin6_addr, raddr, sizeof(struct in6_addr));
- itpl.itpl_local_sin6.sin6_port = lport;
- itpl.itpl_remote_sin6.sin6_port = rport;
- itpl.itpl_local_sin6.sin6_family = AF_INET6;
- itpl.itpl_remote_sin6.sin6_family = AF_INET6;
- }
- itpl.itpl_proto = IPPROTO_TCP;
- sz = sizeof(mib)/sizeof(mib[0]);
- if (sysctlnametomib("net.inet.tcp.info", mib, &sz) == -1)
- {
- helplog(ASL_LEVEL_ERR, "do_RetrieveTCPInfo: sysctlnametomib failed %d, %s", errno, strerror(errno));
- return errno;
- }
- miblen = (unsigned int)sz;
- len = sizeof(struct tcp_info);
- if (sysctl(mib, miblen, &ti, &len, &itpl, sizeof(struct info_tuple)) == -1)
- {
- helplog(ASL_LEVEL_ERR, "do_RetrieveTCPInfo: sysctl failed %d, %s", errno, strerror(errno));
- return errno;
- }
-
- *seq = ti.tcpi_snd_nxt - 1;
- *ack = ti.tcpi_rcv_nxt;
- *win = ti.tcpi_rcv_space >> ti.tcpi_rcv_wscale;
- *intfid = ti.tcpi_last_outif;
- return KERN_SUCCESS;
-}
-
-static int getMACAddress(int family, v6addr_t raddr, v6addr_t gaddr, int *gfamily, ethaddr_t eth)
-{
- struct
- {
- struct rt_msghdr m_rtm;
- char m_space[512];
- } m_rtmsg;
-
- struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
- char *cp = m_rtmsg.m_space;
- int seq = 6367, sock, rlen, i;
- struct sockaddr_in *sin = NULL;
- struct sockaddr_in6 *sin6 = NULL;
- struct sockaddr_dl *sdl = NULL;
- struct sockaddr_storage sins;
- struct sockaddr_dl sdl_m;
-
-#define NEXTADDR(w, s, len) \
- if (rtm->rtm_addrs & (w)) \
- { \
- bcopy((char *)s, cp, len); \
- cp += len; \
- }
-
- bzero(&sins, sizeof(struct sockaddr_storage));
- bzero(&sdl_m, sizeof(struct sockaddr_dl));
- bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
-
- sock = socket(PF_ROUTE, SOCK_RAW, 0);
- if (sock < 0)
- {
- helplog(ASL_LEVEL_ERR, "mDNSGetRemoteMAC: Can not open the socket - %s", strerror(errno));
- return errno;
- }
-
- rtm->rtm_addrs |= RTA_DST | RTA_GATEWAY;
- rtm->rtm_type = RTM_GET;
- rtm->rtm_flags = 0;
- rtm->rtm_version = RTM_VERSION;
- rtm->rtm_seq = ++seq;
-
- sdl_m.sdl_len = sizeof(sdl_m);
- sdl_m.sdl_family = AF_LINK;
- if (family == AF_INET)
- {
- sin = (struct sockaddr_in*)&sins;
- sin->sin_family = AF_INET;
- sin->sin_len = sizeof(struct sockaddr_in);
- memcpy(&sin->sin_addr, raddr, sizeof(struct in_addr));
- NEXTADDR(RTA_DST, sin, sin->sin_len);
- }
- else if (family == AF_INET6)
- {
- sin6 = (struct sockaddr_in6 *)&sins;
- sin6->sin6_len = sizeof(struct sockaddr_in6);
- sin6->sin6_family = AF_INET6;
- memcpy(&sin6->sin6_addr, raddr, sizeof(struct in6_addr));
- NEXTADDR(RTA_DST, sin6, sin6->sin6_len);
- }
- NEXTADDR(RTA_GATEWAY, &sdl_m, sdl_m.sdl_len);
- rtm->rtm_msglen = rlen = cp - (char *)&m_rtmsg;
-
- if (write(sock, (char *)&m_rtmsg, rlen) < 0)
- {
- helplog(ASL_LEVEL_INFO, "do_mDNSGetRemoteMAC: writing to routing socket: %s", strerror(errno));
- close(sock);
- return errno;
- }
-
- do
- {
- rlen = read(sock, (char *)&m_rtmsg, sizeof(m_rtmsg));
- }
- while (rlen > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != getpid()));
-
- if (rlen < 0)
- helplog(ASL_LEVEL_ERR, "do_mDNSGetRemoteMAC: Read from routing socket failed");
-
- if (family == AF_INET)
- {
- sin = (struct sockaddr_in *) (rtm + 1);
- sdl = (struct sockaddr_dl *) (sin->sin_len + (char *) sin);
- }
- else if (family == AF_INET6)
- {
- sin6 = (struct sockaddr_in6 *) (rtm +1);
- sdl = (struct sockaddr_dl *) (sin6->sin6_len + (char *) sin6);
- }
- // If the address is not on the local net, we get the IP address of the gateway.
- // We would have to repeat the process to get the MAC address of the gateway
- *gfamily = sdl->sdl_family;
- if (sdl->sdl_family == AF_INET)
- {
- struct sockaddr_in *new_sin = (struct sockaddr_in *)(sin->sin_len +(char*) sin);
- memcpy(gaddr, &new_sin->sin_addr, sizeof(struct in_addr));
- close(sock);
- return -1;
- }
- else if (sdl->sdl_family == AF_INET6)
- {
- struct sockaddr_in6 *new_sin6 = (struct sockaddr_in6 *)(sin6->sin6_len +(char*) sin6);
- memcpy(gaddr, &new_sin6->sin6_addr, sizeof(struct in6_addr));
- close(sock);
- return -1;
- }
-
- unsigned char *ptr = (unsigned char *)LLADDR(sdl);
- for (i = 0; i < ETHER_ADDR_LEN; i++)
- (eth)[i] = *(ptr +i);
-
- close(sock);
- return KERN_SUCCESS;
-}
-
-kern_return_t do_mDNSGetRemoteMAC(__unused mach_port_t port, int family, v6addr_t raddr, ethaddr_t eth, audit_token_t token)
-{
- int ret = 0;
- v6addr_t gateway;
- int gfamily;
- int count = 0;
-
- if (!authorized(&token))
- {
- helplog(ASL_LEVEL_ERR, "mDNSGetRemoteMAC: Not authorized");
- return kmDNSHelperNotAuthorized;
- }
-
- do
- {
- ret = getMACAddress(family, raddr, gateway, &gfamily, eth);
- if (ret == -1)
- {
- memcpy(raddr, gateway, sizeof(family));
- family = gfamily;
- count++;
- }
- }
- while ((ret == -1) && (count < 5));
- return ret;
-}
-
-
-kern_return_t do_mDNSStoreSPSMACAddress(__unused mach_port_t port, int family, v6addr_t spsaddr, const char *ifname, audit_token_t token)
-{
- ethaddr_t eth;
- char spsip[INET6_ADDRSTRLEN];
- int ret = 0;
- CFStringRef sckey = NULL;
- SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:StoreSPSMACAddress"), NULL, NULL);
- SCDynamicStoreRef ipstore = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetIPv6Addresses"), NULL, NULL);
- CFMutableDictionaryRef dict = NULL;
- CFStringRef entityname = NULL;
- CFDictionaryRef ipdict = NULL;
- CFArrayRef addrs = NULL;
-
- if (!authorized(&token))
- {
- helplog(ASL_LEVEL_ERR, "mDNSStoreSPSMAC: Not authorized");
- return kmDNSHelperNotAuthorized;
- }
-
- if ((store == NULL) || (ipstore == NULL))
- {
- helplog(ASL_LEVEL_ERR, "Unable to access SC Dynamic Store");
- return KERN_FAILURE;
- }
-
- // Get the MAC address of the Sleep Proxy Server
- memset(eth, 0, sizeof(eth));
- ret = do_mDNSGetRemoteMAC(port, family, spsaddr, eth, token);
- if (ret != KERN_SUCCESS)
- {
- helplog(ASL_LEVEL_ERR, "mDNSStoreSPSMAC: Failed to determine the MAC address");
- goto fin;
- }
-
- // Create/Update the dynamic store entry for the specified interface
- sckey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname, "/BonjourSleepProxyAddress");
- dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- if (!dict)
- {
- helplog(ASL_LEVEL_ERR, "SPSCreateDict: Could not create CFDictionary dict");
- ret = KERN_FAILURE;
- goto fin;
- }
-
- CFStringRef macaddr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%02x:%02x:%02x:%02x:%02x:%02x"), eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
- CFDictionarySetValue(dict, CFSTR("MACAddress"), macaddr);
- if (NULL != macaddr) CFRelease(macaddr);
-
- if( NULL == inet_ntop(family, (void *)spsaddr, spsip, sizeof(spsip)))
- {
- helplog(ASL_LEVEL_ERR, "inet_ntop failed: %s", strerror(errno));
- ret = kmDNSHelperInvalidNetworkAddress;
- goto fin;
- }
-
- CFStringRef ipaddr = CFStringCreateWithCString(NULL, spsip, kCFStringEncodingUTF8);
- CFDictionarySetValue(dict, CFSTR("IPAddress"), ipaddr);
- if (NULL != ipaddr) CFRelease(ipaddr);
-
- // Get the current IPv6 addresses on this interface and store them so NAs can be sent on wakeup
- if ((entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/IPv6"), ifname)) != NULL)
- {
- if ((ipdict = SCDynamicStoreCopyValue(ipstore, entityname)) != NULL)
- {
- if((addrs = CFDictionaryGetValue(ipdict, CFSTR("Addresses"))) != NULL)
- {
- addrs = CFRetain(addrs);
- CFDictionarySetValue(dict, CFSTR("RegisteredAddresses"), addrs);
- }
- }
- }
- SCDynamicStoreSetValue(store, sckey, dict);
-
-fin:
- if (store) CFRelease(store);
- if (ipstore) CFRelease(ipstore);
- if (sckey) CFRelease(sckey);
- if (dict) CFRelease(dict);
- if (ipdict) CFRelease(ipdict);
- if (entityname) CFRelease(entityname);
- if (addrs) CFRelease(addrs);
-
- update_idle_timer();
- return ret;
-}
Copied: vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/helper.c (from rev 6984, vendor/apple/mDNSResponder/dist/mDNSMacOSX/helper.c)
===================================================================
--- vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/helper.c (rev 0)
+++ vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/helper.c 2015-03-20 01:14:52 UTC (rev 6985)
@@ -0,0 +1,2867 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007-2012 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/cdefs.h>
+#include <arpa/inet.h>
+#include <bsm/libbsm.h>
+#include <net/if.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
+#include <netinet6/ipsec.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <asl.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <Security/Security.h>
+#include <SystemConfiguration/SystemConfiguration.h>
+#include <SystemConfiguration/SCPreferencesSetSpecific.h>
+#include <TargetConditionals.h>
+#include <IOKit/pwr_mgt/IOPMLib.h>
+#include <net/bpf.h>
+#include <sys/sysctl.h>
+
+#include "mDNSEmbeddedAPI.h"
+#include "dns_sd.h"
+#include "dnssd_ipc.h"
+#include "libpfkey.h"
+#include "helper.h"
+#include "helpermsgServer.h"
+#include "helper-server.h"
+#include "ipsec_options.h"
+#include "P2PPacketFilter.h"
+
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+
+#ifndef RTF_IFSCOPE
+#define RTF_IFSCOPE 0x1000000
+#endif
+
+#if TARGET_OS_EMBEDDED
+#ifndef MDNS_NO_IPSEC
+#define MDNS_NO_IPSEC 1
+#endif
+#define NO_CFUSERNOTIFICATION 1
+#define NO_SECURITYFRAMEWORK 1
+#endif
+
+// Embed the client stub code here, so we can access private functions like ConnectToServer, create_hdr, deliver_request
+#include "../mDNSShared/dnssd_ipc.c"
+#include "../mDNSShared/dnssd_clientstub.c"
+
+typedef struct sadb_x_policy *ipsec_policy_t;
+
+unsigned short InetChecksum(unsigned short *ptr,int nbytes);
+unsigned long in_cksum(unsigned short *ptr,int nbytes);
+void TCPCheckSum(int af, struct tcphdr *t, int tcplen, v6addr_t sadd6, v6addr_t dadd6);
+
+uid_t mDNSResponderUID;
+gid_t mDNSResponderGID;
+
+void
+debug_(const char *func, const char *fmt, ...)
+{
+ char buf[2048];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ helplog(ASL_LEVEL_DEBUG, "%s: %s", func, buf);
+}
+
+static int
+authorized(audit_token_t *token)
+{
+ int ok = 0;
+ pid_t pid = (pid_t)-1;
+ uid_t euid = (uid_t)-1;
+
+ audit_token_to_au32(*token, NULL, &euid, NULL, NULL, NULL, &pid, NULL,
+ NULL);
+ ok = (euid == mDNSResponderUID || euid == 0);
+ if (!ok)
+ helplog(ASL_LEVEL_NOTICE,
+ "Unauthorized access by euid=%lu pid=%lu",
+ (unsigned long)euid, (unsigned long)pid);
+ return ok;
+}
+
+kern_return_t
+do_mDNSExit(__unused mach_port_t port, audit_token_t token)
+{
+ debug("entry");
+ if (!authorized(&token))
+ goto fin;
+ helplog(ASL_LEVEL_INFO, "exit");
+ exit(0);
+
+fin:
+ debug("fin");
+ return KERN_SUCCESS;
+}
+
+kern_return_t do_mDNSRequestBPF(__unused mach_port_t port, audit_token_t token)
+{
+ if (!authorized(&token)) return KERN_SUCCESS;
+ DNSServiceRef ref;
+ DNSServiceErrorType err = ConnectToServer(&ref, 0, send_bpf, NULL, NULL, NULL);
+ if (err) { helplog(ASL_LEVEL_ERR, "do_mDNSRequestBPF: ConnectToServer %d", err); return err; }
+
+ char *ptr;
+ size_t len = sizeof(DNSServiceFlags);
+ ipc_msg_hdr *hdr = create_hdr(send_bpf, &len, &ptr, 0, ref);
+ if (!hdr) { DNSServiceRefDeallocate(ref); return kDNSServiceErr_NoMemory; }
+ put_flags(0, &ptr);
+ deliver_request(hdr, ref); // Will free hdr for us
+ DNSServiceRefDeallocate(ref);
+ update_idle_timer();
+ return KERN_SUCCESS;
+}
+
+kern_return_t do_mDNSPowerRequest(__unused mach_port_t port, int key, int interval, int *err, audit_token_t token)
+{
+ *err = -1;
+ if (!authorized(&token)) { *err = kmDNSHelperNotAuthorized; goto fin; }
+
+ CFArrayRef events = IOPMCopyScheduledPowerEvents();
+ if (events)
+ {
+ int i;
+ CFIndex count = CFArrayGetCount(events);
+ for (i=0; i<count; i++)
+ {
+ CFDictionaryRef dict = CFArrayGetValueAtIndex(events, i);
+ CFStringRef id = CFDictionaryGetValue(dict, CFSTR(kIOPMPowerEventAppNameKey));
+ if (CFEqual(id, CFSTR("mDNSResponderHelper")))
+ {
+ CFDateRef EventTime = CFDictionaryGetValue(dict, CFSTR(kIOPMPowerEventTimeKey));
+ CFStringRef EventType = CFDictionaryGetValue(dict, CFSTR(kIOPMPowerEventTypeKey));
+ IOReturn result = IOPMCancelScheduledPowerEvent(EventTime, id, EventType);
+ //helplog(ASL_LEVEL_ERR, "Deleting old event %s");
+ if (result) helplog(ASL_LEVEL_ERR, "IOPMCancelScheduledPowerEvent %d failed %d", i, result);
+ }
+ }
+ CFRelease(events);
+ }
+
+ if (key < 0) // mDNSPowerRequest(-1,-1) means "clear any stale schedules" (see above)
+ *err = 0;
+ else if (key == 0) // mDNSPowerRequest(0, 0) means "sleep now"
+ {
+ IOReturn r = IOPMSleepSystem(IOPMFindPowerManagement(MACH_PORT_NULL));
+ if (r) { usleep(100000); helplog(ASL_LEVEL_ERR, "IOPMSleepSystem %d", r); }
+ *err = r;
+ }
+ else if (key > 0)
+ {
+ CFDateRef w = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent() + interval);
+ if (w)
+ {
+ IOReturn r = IOPMSchedulePowerEvent(w, CFSTR("mDNSResponderHelper"), key ? CFSTR(kIOPMAutoWake) : CFSTR(kIOPMAutoSleep));
+ if (r) { usleep(100000); helplog(ASL_LEVEL_ERR, "IOPMSchedulePowerEvent(%d) %d %x", interval, r, r); }
+ *err = r;
+ CFRelease(w);
+ }
+ }
+fin:
+ update_idle_timer();
+ return KERN_SUCCESS;
+}
+
+kern_return_t do_mDNSSetLocalAddressCacheEntry(__unused mach_port_t port, int ifindex, int family, v6addr_t ip, ethaddr_t eth, int *err, audit_token_t token)
+{
+ #define IPv6FMTSTRING "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X"
+ #define IPv6FMTARGS ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7], ip[8], ip[9], ip[10], ip[11], ip[12], ip[13], ip[14], ip[15]
+ #if 0
+ if (family == 4)
+ helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry %d IPv%d %d.%d.%d.%d %02X:%02X:%02X:%02X:%02X:%02X",
+ ifindex, family, ip[0], ip[1], ip[2], ip[3], eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
+ else
+ helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry %d IPv%d " IPv6FMTSTRING " %02X:%02X:%02X:%02X:%02X:%02X",
+ ifindex, family, IPv6FMTARGS, eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
+ #endif
+
+ *err = -1;
+ if (!authorized(&token)) { *err = kmDNSHelperNotAuthorized; goto fin; }
+
+ static int s = -1, seq = 0;
+ if (s < 0)
+ {
+ s = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (s < 0) helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: socket(PF_ROUTE, SOCK_RAW, 0) failed %d (%s)", errno, strerror(errno));
+ }
+
+ if (s >= 0)
+ {
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ if (family == 4)
+ {
+ struct { struct rt_msghdr hdr; struct sockaddr_inarp dst; struct sockaddr_dl sdl; } rtmsg;
+ memset(&rtmsg, 0, sizeof(rtmsg));
+
+ rtmsg.hdr.rtm_msglen = sizeof(rtmsg);
+ rtmsg.hdr.rtm_version = RTM_VERSION;
+ rtmsg.hdr.rtm_type = RTM_ADD;
+ rtmsg.hdr.rtm_index = ifindex;
+ rtmsg.hdr.rtm_flags = RTF_HOST | RTF_STATIC | RTF_IFSCOPE;
+ rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
+ rtmsg.hdr.rtm_pid = 0;
+ rtmsg.hdr.rtm_seq = seq++;
+ rtmsg.hdr.rtm_errno = 0;
+ rtmsg.hdr.rtm_use = 0;
+ rtmsg.hdr.rtm_inits = RTV_EXPIRE;
+ rtmsg.hdr.rtm_rmx.rmx_expire = tv.tv_sec + 30;
+
+ rtmsg.dst.sin_len = sizeof(rtmsg.dst);
+ rtmsg.dst.sin_family = AF_INET;
+ rtmsg.dst.sin_port = 0;
+ rtmsg.dst.sin_addr.s_addr = *(in_addr_t*)ip;
+ rtmsg.dst.sin_srcaddr.s_addr = 0;
+ rtmsg.dst.sin_tos = 0;
+ rtmsg.dst.sin_other = 0;
+
+ rtmsg.sdl.sdl_len = sizeof(rtmsg.sdl);
+ rtmsg.sdl.sdl_family = AF_LINK;
+ rtmsg.sdl.sdl_index = ifindex;
+ rtmsg.sdl.sdl_type = IFT_ETHER;
+ rtmsg.sdl.sdl_nlen = 0;
+ rtmsg.sdl.sdl_alen = ETHER_ADDR_LEN;
+ rtmsg.sdl.sdl_slen = 0;
+
+ // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
+ memcpy(rtmsg.sdl.sdl_data, eth, sizeof(ethaddr_t));
+
+ int len = write(s, (char *)&rtmsg, sizeof(rtmsg));
+ if (len < 0)
+ helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: write(%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s)",
+ sizeof(rtmsg), ifindex, ip[0], ip[1], ip[2], ip[3], rtmsg.hdr.rtm_seq, len, errno, strerror(errno));
+ len = read(s, (char *)&rtmsg, sizeof(rtmsg));
+ if (len < 0 || rtmsg.hdr.rtm_errno)
+ helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: read (%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s) %d",
+ sizeof(rtmsg), ifindex, ip[0], ip[1], ip[2], ip[3], rtmsg.hdr.rtm_seq, len, errno, strerror(errno), rtmsg.hdr.rtm_errno);
+
+ *err = 0;
+ }
+ else
+ {
+ struct { struct rt_msghdr hdr; struct sockaddr_in6 dst; struct sockaddr_dl sdl; } rtmsg;
+ memset(&rtmsg, 0, sizeof(rtmsg));
+
+ rtmsg.hdr.rtm_msglen = sizeof(rtmsg);
+ rtmsg.hdr.rtm_version = RTM_VERSION;
+ rtmsg.hdr.rtm_type = RTM_ADD;
+ rtmsg.hdr.rtm_index = ifindex;
+ rtmsg.hdr.rtm_flags = RTF_HOST | RTF_STATIC | RTF_IFSCOPE;
+ rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
+ rtmsg.hdr.rtm_pid = 0;
+ rtmsg.hdr.rtm_seq = seq++;
+ rtmsg.hdr.rtm_errno = 0;
+ rtmsg.hdr.rtm_use = 0;
+ rtmsg.hdr.rtm_inits = RTV_EXPIRE;
+ rtmsg.hdr.rtm_rmx.rmx_expire = tv.tv_sec + 30;
+
+ rtmsg.dst.sin6_len = sizeof(rtmsg.dst);
+ rtmsg.dst.sin6_family = AF_INET6;
+ rtmsg.dst.sin6_port = 0;
+ rtmsg.dst.sin6_flowinfo = 0;
+ rtmsg.dst.sin6_addr = *(struct in6_addr*)ip;
+ rtmsg.dst.sin6_scope_id = ifindex;
+
+ rtmsg.sdl.sdl_len = sizeof(rtmsg.sdl);
+ rtmsg.sdl.sdl_family = AF_LINK;
+ rtmsg.sdl.sdl_index = ifindex;
+ rtmsg.sdl.sdl_type = IFT_ETHER;
+ rtmsg.sdl.sdl_nlen = 0;
+ rtmsg.sdl.sdl_alen = ETHER_ADDR_LEN;
+ rtmsg.sdl.sdl_slen = 0;
+
+ // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
+ memcpy(rtmsg.sdl.sdl_data, eth, sizeof(ethaddr_t));
+
+ int len = write(s, (char *)&rtmsg, sizeof(rtmsg));
+ if (len < 0)
+ helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: write(%d) interface %d address " IPv6FMTSTRING " seq %d result %d errno %d (%s)",
+ sizeof(rtmsg), ifindex, IPv6FMTARGS, rtmsg.hdr.rtm_seq, len, errno, strerror(errno));
+ len = read(s, (char *)&rtmsg, sizeof(rtmsg));
+ if (len < 0 || rtmsg.hdr.rtm_errno)
+ helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: read (%d) interface %d address " IPv6FMTSTRING " seq %d result %d errno %d (%s) %d",
+ sizeof(rtmsg), ifindex, IPv6FMTARGS, rtmsg.hdr.rtm_seq, len, errno, strerror(errno), rtmsg.hdr.rtm_errno);
+
+ *err = 0;
+ }
+
+ }
+
+fin:
+ update_idle_timer();
+ return KERN_SUCCESS;
+}
+
+kern_return_t do_mDNSNotify(__unused mach_port_t port, const char *title, const char *msg, audit_token_t token)
+{
+ if (!authorized(&token)) return KERN_SUCCESS;
+
+#ifndef NO_CFUSERNOTIFICATION
+ static const char footer[] = "(Note: This message only appears on machines with 17.x.x.x IP addresses — i.e. at Apple — not on customer machines.)";
+ CFStringRef alertHeader = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
+ CFStringRef alertBody = CFStringCreateWithCString(NULL, msg, kCFStringEncodingUTF8);
+ CFStringRef alertFooter = CFStringCreateWithCString(NULL, footer, kCFStringEncodingUTF8);
+ CFStringRef alertMessage = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@\r\r%@"), alertBody, alertFooter);
+ CFRelease(alertBody);
+ CFRelease(alertFooter);
+ int err = CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, alertHeader, alertMessage, NULL);
+ if (err) helplog(ASL_LEVEL_ERR, "CFUserNotificationDisplayNotice returned %d", err);
+ CFRelease(alertHeader);
+ CFRelease(alertMessage);
+#else
+ (void)title;
+ (void)msg;
+#endif /* NO_CFUSERNOTIFICATION */
+
+ update_idle_timer();
+ return KERN_SUCCESS;
+}
+
+char usercompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name the user saw
+char userhostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name the user saw
+char lastcompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name saved to preferences
+char lasthostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name saved to preferences
+
+#ifndef NO_CFUSERNOTIFICATION
+static CFStringRef CFS_OQ = NULL;
+static CFStringRef CFS_CQ = NULL;
+static CFStringRef CFS_Format = NULL;
+static CFStringRef CFS_ComputerName = NULL;
+static CFStringRef CFS_ComputerNameMsg = NULL;
+static CFStringRef CFS_LocalHostName = NULL;
+static CFStringRef CFS_LocalHostNameMsg = NULL;
+static CFStringRef CFS_Problem = NULL;
+
+static CFUserNotificationRef gNotification = NULL;
+static CFRunLoopSourceRef gNotificationRLS = NULL;
+
+static void NotificationCallBackDismissed(CFUserNotificationRef userNotification, CFOptionFlags responseFlags)
+{
+ debug("entry");
+ (void)responseFlags; // Unused
+ if (userNotification != gNotification) helplog(ASL_LEVEL_ERR, "NotificationCallBackDismissed: Wrong CFUserNotificationRef");
+ if (gNotificationRLS)
+ {
+ // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
+ // We need to explicitly specify the desired CFRunLoop from which we want to remove this event source.
+ CFRunLoopRemoveSource(gRunLoop, gNotificationRLS, kCFRunLoopDefaultMode);
+ CFRelease(gNotificationRLS);
+ gNotificationRLS = NULL;
+ CFRelease(gNotification);
+ gNotification = NULL;
+ }
+ // By dismissing the alert, the user has conceptually acknowleged the rename.
+ // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".)
+ // If we get *another* conflict, the new alert should refer to the 'old' name
+ // as now being "computer-2.local", not "computer.local"
+ usercompname[0] = 0;
+ userhostname[0] = 0;
+ lastcompname[0] = 0;
+ lasthostname[0] = 0;
+ update_idle_timer();
+ unpause_idle_timer();
+}
+
+static void ShowNameConflictNotification(CFMutableArrayRef header, CFStringRef subtext)
+{
+ CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ if (!dictionary) return;
+
+ debug("entry");
+
+ CFDictionarySetValue(dictionary, kCFUserNotificationAlertHeaderKey, header);
+ CFDictionarySetValue(dictionary, kCFUserNotificationAlertMessageKey, subtext);
+
+ CFURLRef urlRef = CFURLCreateWithFileSystemPath(NULL, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle, true);
+ if (urlRef) { CFDictionarySetValue(dictionary, kCFUserNotificationLocalizationURLKey, urlRef); CFRelease(urlRef); }
+
+ if (gNotification) // If notification already on-screen, update it in place
+ CFUserNotificationUpdate(gNotification, 0, kCFUserNotificationCautionAlertLevel, dictionary);
+ else // else, we need to create it
+ {
+ SInt32 error;
+ gNotification = CFUserNotificationCreate(NULL, 0, kCFUserNotificationCautionAlertLevel, &error, dictionary);
+ if (!gNotification || error) { helplog(ASL_LEVEL_ERR, "ShowNameConflictNotification: CFUserNotificationRef: Error %d", error); return; }
+ gNotificationRLS = CFUserNotificationCreateRunLoopSource(NULL, gNotification, NotificationCallBackDismissed, 0);
+ if (!gNotificationRLS) { helplog(ASL_LEVEL_ERR,"ShowNameConflictNotification: RLS"); CFRelease(gNotification); gNotification = NULL; return; }
+ // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread.
+ // We need to explicitly specify the desired CFRunLoop to which we want to add this event source.
+ CFRunLoopAddSource(gRunLoop, gNotificationRLS, kCFRunLoopDefaultMode);
+ debug("gRunLoop=%p gNotification=%p gNotificationRLS=%p", gRunLoop, gNotification, gNotificationRLS);
+ pause_idle_timer();
+ }
+
+ CFRelease(dictionary);
+}
+
+static CFMutableArrayRef GetHeader(const char* oldname, const char* newname, const CFStringRef msg, const char* suffix)
+{
+ CFMutableArrayRef alertHeader = NULL;
+
+ const CFStringRef cfoldname = CFStringCreateWithCString(NULL, oldname, kCFStringEncodingUTF8);
+ // NULL newname means we've given up trying to construct a name that doesn't conflict
+ const CFStringRef cfnewname = newname ? CFStringCreateWithCString(NULL, newname, kCFStringEncodingUTF8) : NULL;
+ // We tag a zero-width non-breaking space at the end of the literal text to guarantee that, no matter what
+ // arbitrary computer name the user may choose, this exact text (with zero-width non-breaking space added)
+ // can never be one that occurs in the Localizable.strings translation file.
+ if (!cfoldname)
+ helplog(ASL_LEVEL_ERR,"Could not construct CFStrings for old=%s", newname);
+ else if (newname && !cfnewname)
+ helplog(ASL_LEVEL_ERR,"Could not construct CFStrings for new=%s", newname);
+ else
+ {
+ const CFStringRef s1 = CFStringCreateWithFormat(NULL, NULL, CFS_Format, cfoldname, suffix);
+ const CFStringRef s2 = cfnewname ? CFStringCreateWithFormat(NULL, NULL, CFS_Format, cfnewname, suffix) : NULL;
+
+ alertHeader = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+
+ if (!s1)
+ helplog(ASL_LEVEL_ERR, "Could not construct secondary CFString for old=%s", oldname);
+ else if (cfnewname && !s2)
+ helplog(ASL_LEVEL_ERR, "Could not construct secondary CFString for new=%s", newname);
+ else if (!alertHeader)
+ helplog(ASL_LEVEL_ERR, "Could not construct CFArray for notification");
+ else
+ {
+ // Make sure someone is logged in. We don't want this popping up over the login window
+ uid_t uid;
+ gid_t gid;
+ CFStringRef userName = SCDynamicStoreCopyConsoleUser(NULL, &uid, &gid);
+ if (userName)
+ {
+ CFRelease(userName);
+ CFArrayAppendValue(alertHeader, msg); // Opening phrase of message, provided by caller
+ CFArrayAppendValue(alertHeader, CFS_OQ); CFArrayAppendValue(alertHeader, s1); CFArrayAppendValue(alertHeader, CFS_CQ);
+ CFArrayAppendValue(alertHeader, CFSTR(" is already in use on this network. "));
+ if (s2)
+ {
+ CFArrayAppendValue(alertHeader, CFSTR("The name has been changed to "));
+ CFArrayAppendValue(alertHeader, CFS_OQ); CFArrayAppendValue(alertHeader, s2); CFArrayAppendValue(alertHeader, CFS_CQ);
+ CFArrayAppendValue(alertHeader, CFSTR("."));
+ }
+ else
+ CFArrayAppendValue(alertHeader, CFSTR("All attempts to find an available name by adding a number to the name were also unsuccessful."));
+ }
+ }
+ if (s1) CFRelease(s1);
+ if (s2) CFRelease(s2);
+ }
+ if (cfoldname) CFRelease(cfoldname);
+ if (cfnewname) CFRelease(cfnewname);
+
+ return alertHeader;
+}
+#endif /* ndef NO_CFUSERNOTIFICATION */
+
+static void update_notification(void)
+{
+#ifndef NO_CFUSERNOTIFICATION
+ debug("entry ucn=%s, uhn=%s, lcn=%s, lhn=%s", usercompname, userhostname, lastcompname, lasthostname);
+ if (!CFS_OQ)
+ {
+ // Note: the "\xEF\xBB\xBF" byte sequence in the CFS_Format string is the UTF-8 encoding of the zero-width non-breaking space character.
+ // By appending this invisible character on the end of literal names, we ensure the these strings cannot inadvertently match any string
+ // in the localization file -- since we know for sure that none of our strings in the localization file contain the ZWNBS character.
+ //
+ // For languages that are written right to left, when we mix English (host names could be in english with brackets etc. and the
+ // rest in Arabic) we need unicode markups for proper formatting. The Unicode sequence 202C (UTF8 E2 80 AC), 200E (UTF8 E2 80 8E) and
+ // 202B (UTF8 E2 80 AB) helps with the formatting. See <rdar://problem/8629082> for more details.
+ CFS_OQ = CFStringCreateWithCString(NULL, "“\xE2\x80\xAB", kCFStringEncodingUTF8);
+ CFS_CQ = CFStringCreateWithCString(NULL, "\xE2\x80\xAC”", kCFStringEncodingUTF8);
+ CFS_Format = CFStringCreateWithCString(NULL, "%@%s\xEF\xBB\xBF\xE2\x80\x8E", kCFStringEncodingUTF8);
+ CFS_ComputerName = CFStringCreateWithCString(NULL, "The name of your computer ", kCFStringEncodingUTF8);
+ CFS_ComputerNameMsg = CFStringCreateWithCString(NULL, "To change the name of your computer, "
+ "open System Preferences and click Sharing, then type the name in the Computer Name field.", kCFStringEncodingUTF8);
+ CFS_LocalHostName = CFStringCreateWithCString(NULL, "This computer’s local hostname ", kCFStringEncodingUTF8);
+ CFS_LocalHostNameMsg = CFStringCreateWithCString(NULL, "To change the local hostname, "
+ "open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field.", kCFStringEncodingUTF8);
+ CFS_Problem = CFStringCreateWithCString(NULL, "This may indicate a problem with the local network. "
+ "Please inform your network administrator.", kCFStringEncodingUTF8);
+ }
+
+ if (!usercompname[0] && !userhostname[0])
+ {
+ if (gNotificationRLS)
+ {
+ debug("canceling notification %p", gNotification);
+ CFUserNotificationCancel(gNotification);
+ unpause_idle_timer();
+ }
+ }
+ else
+ {
+ CFMutableArrayRef header = NULL;
+ CFStringRef* subtext = NULL;
+ if (userhostname[0] && !lasthostname[0]) // we've given up trying to construct a name that doesn't conflict
+ {
+ header = GetHeader(userhostname, NULL, CFS_LocalHostName, ".local");
+ subtext = &CFS_Problem;
+ }
+ else if (usercompname[0])
+ {
+ header = GetHeader(usercompname, lastcompname, CFS_ComputerName, "");
+ subtext = &CFS_ComputerNameMsg;
+ }
+ else
+ {
+ header = GetHeader(userhostname, lasthostname, CFS_LocalHostName, ".local");
+ subtext = &CFS_LocalHostNameMsg;
+ }
+ ShowNameConflictNotification(header, *subtext);
+ CFRelease(header);
+ }
+#endif
+}
+
+kern_return_t
+do_mDNSPreferencesSetName(__unused mach_port_t port, int key, const char* old, const char* new, audit_token_t token)
+{
+ SCPreferencesRef session = NULL;
+ Boolean ok = FALSE;
+ Boolean locked = FALSE;
+ CFStringRef cfstr = NULL;
+ char* user = NULL;
+ char* last = NULL;
+ Boolean needUpdate = FALSE;
+
+ debug("entry %s old=%s new=%s", key==kmDNSComputerName ? "ComputerName" : (key==kmDNSLocalHostName ? "LocalHostName" : "UNKNOWN"), old, new);
+ if (!authorized(&token)) goto fin;
+
+ switch ((enum mDNSPreferencesSetNameKey)key)
+ {
+ case kmDNSComputerName:
+ user = usercompname;
+ last = lastcompname;
+ break;
+ case kmDNSLocalHostName:
+ user = userhostname;
+ last = lasthostname;
+ break;
+ default:
+ debug("unrecognized key: %d", key);
+ goto fin;
+ }
+
+ if (!last)
+ {
+ helplog(ASL_LEVEL_ERR, "%s: no last ptr", __func__);
+ goto fin;
+ }
+
+ if (!user)
+ {
+ helplog(ASL_LEVEL_ERR, "%s: no user ptr", __func__);
+ goto fin;
+ }
+
+ if (0 == strncmp(old, new, MAX_DOMAIN_LABEL+1))
+ {
+ // old and new are same means the config changed i.e, the user has set something in the preferences pane.
+ // This means the conflict has been resolved. We need to dismiss the dialogue.
+ if (last[0] && 0 != strncmp(last, new, MAX_DOMAIN_LABEL+1))
+ {
+ last[0] = 0;
+ user[0] = 0;
+ needUpdate = TRUE;
+ }
+ goto fin;
+ }
+ else
+ {
+ // old and new are not same, this means there is a conflict. For the first conflict, we show
+ // the old value and the new value. For all subsequent conflicts, while the dialogue is still
+ // up, we do a real time update of the "new" value in the dialogue. That's why we update just
+ // "last" here and not "user".
+ if (strncmp(last, new, MAX_DOMAIN_LABEL+1))
+ {
+ strncpy(last, new, MAX_DOMAIN_LABEL);
+ needUpdate = TRUE;
+ }
+ }
+
+ // If we are not showing the dialogue, we need to remember the first "old" value so that
+ // we maintain the same through the lifetime of the dialogue. Subsequence conflicts don't
+ // update the "old" value.
+ if (!user[0])
+ {
+ strncpy(user, old, MAX_DOMAIN_LABEL);
+ needUpdate = TRUE;
+ }
+
+ if (!new[0]) // we've given up trying to construct a name that doesn't conflict
+ goto fin;
+
+ cfstr = CFStringCreateWithCString(NULL, new, kCFStringEncodingUTF8);
+
+ session = SCPreferencesCreate(NULL, CFSTR(kmDNSHelperServiceName), NULL);
+
+ if (cfstr == NULL || session == NULL)
+ {
+ debug("SCPreferencesCreate failed");
+ goto fin;
+ }
+ if (!SCPreferencesLock(session, 0))
+ {
+ debug("lock failed");
+ goto fin;
+ }
+ locked = TRUE;
+
+ switch ((enum mDNSPreferencesSetNameKey)key)
+ {
+ case kmDNSComputerName:
+ {
+ // We want to write the new Computer Name to System Preferences, without disturbing the user-selected
+ // system-wide default character set used for things like AppleTalk NBP and NETBIOS service advertising.
+ // Note that this encoding is not used for the computer name, but since both are set by the same call,
+ // we need to take care to set the name without changing the character set.
+ CFStringEncoding encoding = kCFStringEncodingUTF8;
+ CFStringRef unused = SCDynamicStoreCopyComputerName(NULL, &encoding);
+ if (unused) { CFRelease(unused); unused = NULL; }
+ else encoding = kCFStringEncodingUTF8;
+
+ ok = SCPreferencesSetComputerName(session, cfstr, encoding);
+ }
+ break;
+ case kmDNSLocalHostName:
+ ok = SCPreferencesSetLocalHostName(session, cfstr);
+ break;
+ default:
+ break;
+ }
+
+ if (!ok || !SCPreferencesCommitChanges(session) ||
+ !SCPreferencesApplyChanges(session))
+ {
+ debug("SCPreferences update failed");
+ goto fin;
+ }
+ debug("succeeded");
+
+fin:
+ if (NULL != cfstr)
+ CFRelease(cfstr);
+ if (NULL != session)
+ {
+ if (locked)
+ SCPreferencesUnlock(session);
+ CFRelease(session);
+ }
+ update_idle_timer();
+ if (needUpdate) update_notification();
+ return KERN_SUCCESS;
+}
+
+enum DNSKeyFormat
+{
+ formatNotDNSKey, formatDdnsTypeItem, formatDnsPrefixedServiceItem, formatBtmmPrefixedServiceItem
+};
+
+// On Mac OS X on Intel, the four-character string seems to be stored backwards, at least sometimes.
+// I suspect some overenthusiastic inexperienced engineer said, "On Intel everything's backwards,
+// therefore I need to add some byte swapping in this API to make this four-character string backwards too."
+// To cope with this we allow *both* "ddns" and "sndd" as valid item types.
+
+
+#ifndef NO_SECURITYFRAMEWORK
+static const char btmmprefix[] = "btmmdns:";
+static const char dnsprefix[] = "dns:";
+static const char ddns[] = "ddns";
+static const char ddnsrev[] = "sndd";
+
+static enum DNSKeyFormat
+getDNSKeyFormat(SecKeychainItemRef item, SecKeychainAttributeList **attributesp)
+{
+ static UInt32 tags[4] =
+ {
+ kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr, kSecLabelItemAttr
+ };
+ static SecKeychainAttributeInfo attributeInfo =
+ {
+ sizeof(tags)/sizeof(tags[0]), tags, NULL
+ };
+ SecKeychainAttributeList *attributes = NULL;
+ enum DNSKeyFormat format;
+ Boolean malformed = FALSE;
+ OSStatus status = noErr;
+ int i = 0;
+
+ *attributesp = NULL;
+ if (noErr != (status = SecKeychainItemCopyAttributesAndData(item,
+ &attributeInfo, NULL, &attributes, NULL, NULL)))
+ {
+ debug("SecKeychainItemCopyAttributesAndData %d - skipping",
+ status);
+ goto skip;
+ }
+ if (attributeInfo.count != attributes->count)
+ malformed = TRUE;
+ for (i = 0; !malformed && i < (int)attributeInfo.count; ++i)
+ if (attributeInfo.tag[i] != attributes->attr[i].tag)
+ malformed = TRUE;
+ if (malformed)
+ {
+ debug(
+ "malformed result from SecKeychainItemCopyAttributesAndData - skipping");
+ goto skip;
+ }
+
+ debug("entry (\"%.*s\", \"%.*s\", \"%.*s\")",
+ (int)attributes->attr[0].length, attributes->attr[0].data,
+ (int)attributes->attr[1].length, attributes->attr[1].data,
+ (int)attributes->attr[2].length, attributes->attr[2].data);
+ if (attributes->attr[1].length >= MAX_ESCAPED_DOMAIN_NAME +
+ sizeof(dnsprefix)-1)
+ {
+ debug("kSecServiceItemAttr too long (%u) - skipping",
+ (unsigned int)attributes->attr[1].length);
+ goto skip;
+ }
+ if (attributes->attr[2].length >= MAX_ESCAPED_DOMAIN_NAME)
+ {
+ debug("kSecAccountItemAttr too long (%u) - skipping",
+ (unsigned int)attributes->attr[2].length);
+ goto skip;
+ }
+ if (attributes->attr[1].length >= sizeof(dnsprefix)-1 &&
+ 0 == strncasecmp(attributes->attr[1].data, dnsprefix,
+ sizeof(dnsprefix)-1))
+ format = formatDnsPrefixedServiceItem;
+ else if (attributes->attr[1].length >= sizeof(btmmprefix)-1 &&
+ 0 == strncasecmp(attributes->attr[1].data, btmmprefix, sizeof(btmmprefix)-1))
+ format = formatBtmmPrefixedServiceItem;
+ else if (attributes->attr[0].length == sizeof(ddns)-1 &&
+ 0 == strncasecmp(attributes->attr[0].data, ddns, sizeof(ddns)-1))
+ format = formatDdnsTypeItem;
+ else if (attributes->attr[0].length == sizeof(ddnsrev)-1 &&
+ 0 == strncasecmp(attributes->attr[0].data, ddnsrev, sizeof(ddnsrev)-1))
+ format = formatDdnsTypeItem;
+ else
+ {
+ debug("uninterested in this entry");
+ goto skip;
+ }
+ *attributesp = attributes;
+ debug("accepting this entry");
+ return format;
+
+skip:
+ SecKeychainItemFreeAttributesAndData(attributes, NULL);
+ return formatNotDNSKey;
+}
+
+// Insert the attributes as defined by mDNSKeyChainAttributes
+static CFPropertyListRef
+getKeychainItemInfo(SecKeychainItemRef item,
+ SecKeychainAttributeList *attributes, enum DNSKeyFormat format)
+{
+ CFMutableArrayRef entry = NULL;
+ CFDataRef data = NULL;
+ OSStatus status = noErr;
+ UInt32 keylen = 0;
+ void *keyp = 0;
+
+ if (NULL == (entry = CFArrayCreateMutable(NULL, 0,
+ &kCFTypeArrayCallBacks)))
+ {
+ debug("CFArrayCreateMutable failed");
+ goto error;
+ }
+
+ // Insert the Account attribute (kmDNSKcWhere)
+ switch ((enum DNSKeyFormat)format)
+ {
+ case formatDdnsTypeItem:
+ data = CFDataCreate(kCFAllocatorDefault,
+ attributes->attr[1].data, attributes->attr[1].length);
+ break;
+ case formatDnsPrefixedServiceItem:
+ case formatBtmmPrefixedServiceItem:
+ data = CFDataCreate(kCFAllocatorDefault,
+ attributes->attr[1].data, attributes->attr[1].length);
+ break;
+ default:
+ assert("unknown DNSKeyFormat value");
+ break;
+ }
+ if (NULL == data)
+ {
+ debug("CFDataCreate for attr[1] failed");
+ goto error;
+ }
+ CFArrayAppendValue(entry, data);
+ CFRelease(data);
+
+ // Insert the Where attribute (kmDNSKcAccount)
+ if (NULL == (data = CFDataCreate(kCFAllocatorDefault,
+ attributes->attr[2].data, attributes->attr[2].length)))
+ {
+ debug("CFDataCreate for attr[2] failed");
+ goto error;
+ }
+ CFArrayAppendValue(entry, data);
+ CFRelease(data);
+
+ // Insert the Key attribute (kmDNSKcKey)
+ if (noErr != (status = SecKeychainItemCopyAttributesAndData(item, NULL,
+ NULL, NULL, &keylen, &keyp)))
+ {
+ debug("could not retrieve key for \"%.*s\": %d",
+ (int)attributes->attr[1].length, attributes->attr[1].data,
+ status);
+ goto error;
+ }
+ data = CFDataCreate(kCFAllocatorDefault, keyp, keylen);
+ SecKeychainItemFreeAttributesAndData(NULL, keyp);
+ if (NULL == data)
+ {
+ debug("CFDataCreate for keyp failed");
+ goto error;
+ }
+ CFArrayAppendValue(entry, data);
+ CFRelease(data);
+
+ // Insert the Name attribute (kmDNSKcName)
+ if (NULL == (data = CFDataCreate(kCFAllocatorDefault,
+ attributes->attr[3].data, attributes->attr[3].length)))
+ {
+ debug("CFDataCreate for attr[3] failed");
+ goto error;
+ }
+ CFArrayAppendValue(entry, data);
+ CFRelease(data);
+ return entry;
+
+error:
+ if (NULL != entry)
+ CFRelease(entry);
+ return NULL;
+}
+#endif
+
+kern_return_t
+do_mDNSKeychainGetSecrets(__unused mach_port_t port, __unused unsigned int *numsecrets,
+ __unused vm_offset_t *secrets, __unused mach_msg_type_number_t *secretsCnt, __unused int *err,
+ __unused audit_token_t token)
+{
+#ifndef NO_SECURITYFRAMEWORK
+ CFWriteStreamRef stream = NULL;
+ CFDataRef result = NULL;
+ CFPropertyListRef entry = NULL;
+ CFMutableArrayRef keys = NULL;
+ SecKeychainRef skc = NULL;
+ SecKeychainItemRef item = NULL;
+ SecKeychainSearchRef search = NULL;
+ SecKeychainAttributeList *attributes = NULL;
+ enum DNSKeyFormat format;
+ OSStatus status = 0;
+
+ debug("entry");
+ *err = 0;
+ *numsecrets = 0;
+ *secrets = (vm_offset_t)NULL;
+ if (!authorized(&token))
+ {
+ *err = kmDNSHelperNotAuthorized;
+ goto fin;
+ }
+ if (NULL == (keys = CFArrayCreateMutable(NULL, 0,
+ &kCFTypeArrayCallBacks)))
+ {
+ debug("CFArrayCreateMutable failed");
+ *err = kmDNSHelperCreationFailed;
+ goto fin;
+ }
+ if (noErr != (status = SecKeychainCopyDefault(&skc)))
+ {
+ *err = kmDNSHelperKeychainCopyDefaultFailed;
+ goto fin;
+ }
+ if (noErr != (status = SecKeychainSearchCreateFromAttributes(skc, kSecGenericPasswordItemClass, NULL, &search)))
+ {
+ *err = kmDNSHelperKeychainSearchCreationFailed;
+ goto fin;
+ }
+ for (status = SecKeychainSearchCopyNext(search, &item);
+ noErr == status;
+ status = SecKeychainSearchCopyNext(search, &item))
+ {
+ if (formatNotDNSKey != (format = getDNSKeyFormat(item,
+ &attributes)) &&
+ NULL != (entry = getKeychainItemInfo(item, attributes,
+ format)))
+ {
+ CFArrayAppendValue(keys, entry);
+ CFRelease(entry);
+ }
+ SecKeychainItemFreeAttributesAndData(attributes, NULL);
+ CFRelease(item);
+ }
+ if (errSecItemNotFound != status)
+ helplog(ASL_LEVEL_ERR, "%s: SecKeychainSearchCopyNext failed: %d",
+ __func__, status);
+ if (NULL == (stream =
+ CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault,
+ kCFAllocatorDefault)))
+ {
+ *err = kmDNSHelperCreationFailed;
+ debug("CFWriteStreamCreateWithAllocatedBuffers failed");
+ goto fin;
+ }
+ CFWriteStreamOpen(stream);
+ if (0 == CFPropertyListWriteToStream(keys, stream,
+ kCFPropertyListBinaryFormat_v1_0, NULL))
+ {
+ *err = kmDNSHelperPListWriteFailed;
+ debug("CFPropertyListWriteToStream failed");
+ goto fin;
+ }
+ result = CFWriteStreamCopyProperty(stream,
+ kCFStreamPropertyDataWritten);
+ if (KERN_SUCCESS != vm_allocate(mach_task_self(), secrets,
+ CFDataGetLength(result), VM_FLAGS_ANYWHERE))
+ {
+ *err = kmDNSHelperCreationFailed;
+ debug("vm_allocate failed");
+ goto fin;
+ }
+ CFDataGetBytes(result, CFRangeMake(0, CFDataGetLength(result)),
+ (void *)*secrets);
+ *secretsCnt = CFDataGetLength(result);
+ *numsecrets = CFArrayGetCount(keys);
+ debug("succeeded");
+
+fin:
+ debug("returning %u secrets", *numsecrets);
+ if (NULL != stream)
+ {
+ CFWriteStreamClose(stream);
+ CFRelease(stream);
+ }
+ if (NULL != result)
+ CFRelease(result);
+ if (NULL != keys)
+ CFRelease(keys);
+ if (NULL != search)
+ CFRelease(search);
+ if (NULL != skc)
+ CFRelease(skc);
+ update_idle_timer();
+ return KERN_SUCCESS;
+#else
+ return KERN_FAILURE;
+#endif
+}
+
+#ifndef MDNS_NO_IPSEC
+typedef enum _mDNSTunnelPolicyWhich
+{
+ kmDNSTunnelPolicySetup,
+ kmDNSTunnelPolicyTeardown,
+ kmDNSTunnelPolicyGenerate
+} mDNSTunnelPolicyWhich;
+
+// For kmDNSTunnelPolicySetup, you can setup IPv6-in-IPv6 tunnel or IPv6-in-IPv4 tunnel
+// kmDNSNoTunnel is used for other Policy types
+typedef enum _mDNSTunnelType
+{
+ kmDNSNoTunnel,
+ kmDNSIPv6IPv4Tunnel,
+ kmDNSIPv6IPv6Tunnel
+} mDNSTunnelType;
+
+static const uint8_t kWholeV6Mask = 128;
+
+#endif /* ifndef MDNS_NO_IPSEC */
+
+#ifndef MDNS_NO_IPSEC
+
+static const char g_racoon_config_dir[] = "/var/run/racoon/";
+static const char g_racoon_config_dir_old[] = "/etc/racoon/remote/";
+
+CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
+CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
+
+// Major version 6 is 10.2.x (Jaguar)
+// Major version 7 is 10.3.x (Panther)
+// Major version 8 is 10.4.x (Tiger)
+// Major version 9 is 10.5.x (Leopard)
+// Major version 10 is 10.6.x (SnowLeopard)
+static int MacOSXSystemBuildNumber(char* letter_out, int* minor_out)
+{
+ int major = 0, minor = 0;
+ char letter = 0, buildver[256]="<Unknown>";
+ CFDictionaryRef vers = _CFCopySystemVersionDictionary();
+ if (vers)
+ {
+ CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
+ if (cfbuildver) CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8);
+ sscanf(buildver, "%d%c%d", &major, &letter, &minor);
+ CFRelease(vers);
+ }
+ else
+ helplog(ASL_LEVEL_NOTICE, "_CFCopySystemVersionDictionary failed");
+
+ if (!major) { major=10; letter = 'A'; minor = 190; helplog(ASL_LEVEL_NOTICE, "Note: No Major Build Version number found; assuming 10A190"); }
+ if (letter_out) *letter_out = letter;
+ if (minor_out) *minor_out = minor;
+ return(major);
+}
+
+static int UseOldRacoon()
+{
+ static int g_oldRacoon = -1;
+
+ if (g_oldRacoon == -1)
+ {
+ char letter = 0;
+ int minor = 0;
+ g_oldRacoon = (MacOSXSystemBuildNumber(&letter, &minor) < 10);
+ debug("%s", g_oldRacoon ? "old" : "new");
+ }
+
+ return g_oldRacoon;
+}
+
+static int RacoonSignal()
+{
+ return UseOldRacoon() ? SIGHUP : SIGUSR1;
+}
+
+static const char* GetRacoonConfigDir()
+{
+ return UseOldRacoon() ? g_racoon_config_dir_old : g_racoon_config_dir;
+}
+
+static const char* GetOldRacoonConfigDir()
+{
+ return UseOldRacoon() ? NULL : g_racoon_config_dir_old;
+}
+
+static const char racoon_config_file[] = "anonymous.conf";
+static const char racoon_config_file_orig[] = "anonymous.conf.orig";
+
+static const char configHeader[] = "# BackToMyMac\n";
+
+static int IsFamiliarRacoonConfiguration(const char* racoon_config_path)
+{
+ int fd = open(racoon_config_path, O_RDONLY);
+ debug("entry %s", racoon_config_path);
+ if (0 > fd)
+ {
+ helplog(ASL_LEVEL_NOTICE, "open \"%s\" failed: %s", racoon_config_path, strerror(errno));
+ return 0;
+ }
+ else
+ {
+ char header[sizeof(configHeader)] = {0};
+ ssize_t bytesRead = read(fd, header, sizeof(header)-1);
+ close(fd);
+ if (bytesRead != sizeof(header)-1) return 0;
+ return (0 == memcmp(header, configHeader, sizeof(header)-1));
+ }
+}
+
+static void
+revertAnonymousRacoonConfiguration(const char* dir)
+{
+ if (!dir) return;
+
+ debug("entry %s", dir);
+
+ char racoon_config_path[64];
+ strlcpy(racoon_config_path, dir, sizeof(racoon_config_path));
+ strlcat(racoon_config_path, racoon_config_file, sizeof(racoon_config_path));
+
+ struct stat s;
+ int ret = stat(racoon_config_path, &s);
+ debug("stat(%s): %d errno=%d", racoon_config_path, ret, errno);
+ if (ret == 0)
+ {
+ if (IsFamiliarRacoonConfiguration(racoon_config_path))
+ {
+ helplog(ASL_LEVEL_INFO, "\"%s\" looks familiar, unlinking", racoon_config_path);
+ unlink(racoon_config_path);
+ }
+ else
+ {
+ helplog(ASL_LEVEL_NOTICE, "\"%s\" does not look familiar, leaving in place", racoon_config_path);
+ return;
+ }
+ }
+ else if (errno != ENOENT)
+ {
+ helplog(ASL_LEVEL_NOTICE, "stat failed for \"%s\", leaving in place: %s", racoon_config_path, strerror(errno));
+ return;
+ }
+
+ char racoon_config_path_orig[64];
+ strlcpy(racoon_config_path_orig, dir, sizeof(racoon_config_path_orig));
+ strlcat(racoon_config_path_orig, racoon_config_file_orig, sizeof(racoon_config_path_orig));
+
+ ret = stat(racoon_config_path_orig, &s);
+ debug("stat(%s): %d errno=%d", racoon_config_path_orig, ret, errno);
+ if (ret == 0)
+ {
+ if (0 > rename(racoon_config_path_orig, racoon_config_path))
+ helplog(ASL_LEVEL_NOTICE, "rename \"%s\" \"%s\" failed: %s", racoon_config_path_orig, racoon_config_path, strerror(errno));
+ else
+ debug("reverted \"%s\" to \"%s\"", racoon_config_path_orig, racoon_config_path);
+ }
+ else if (errno != ENOENT)
+ {
+ helplog(ASL_LEVEL_NOTICE, "stat failed for \"%s\", leaving in place: %s", racoon_config_path_orig, strerror(errno));
+ return;
+ }
+}
+
+static void
+moveAsideAnonymousRacoonConfiguration(const char* dir)
+{
+ if (!dir) return;
+
+ debug("entry %s", dir);
+
+ char racoon_config_path[64];
+ strlcpy(racoon_config_path, dir, sizeof(racoon_config_path));
+ strlcat(racoon_config_path, racoon_config_file, sizeof(racoon_config_path));
+
+ struct stat s;
+ int ret = stat(racoon_config_path, &s);
+ if (ret == 0)
+ {
+ if (IsFamiliarRacoonConfiguration(racoon_config_path))
+ {
+ helplog(ASL_LEVEL_INFO, "\"%s\" looks familiar, unlinking", racoon_config_path);
+ unlink(racoon_config_path);
+ }
+ else
+ {
+ char racoon_config_path_orig[64];
+ strlcpy(racoon_config_path_orig, dir, sizeof(racoon_config_path_orig));
+ strlcat(racoon_config_path_orig, racoon_config_file_orig, sizeof(racoon_config_path_orig));
+ if (0 > rename(racoon_config_path, racoon_config_path_orig)) // If we didn't write it, move it to the side so it can be reverted later
+ helplog(ASL_LEVEL_NOTICE, "rename \"%s\" to \"%s\" failed: %s", racoon_config_path, racoon_config_path_orig, strerror(errno));
+ else
+ debug("successfully renamed \"%s\" to \"%s\"", racoon_config_path, racoon_config_path_orig);
+ }
+ }
+ else if (errno != ENOENT)
+ {
+ helplog(ASL_LEVEL_NOTICE, "stat failed for \"%s\", leaving in place: %s", racoon_config_path, strerror(errno));
+ return;
+ }
+}
+
+static int
+ensureExistenceOfRacoonConfigDir(const char* const racoon_config_dir)
+{
+ struct stat s;
+ int ret = stat(racoon_config_dir, &s);
+ if (ret != 0)
+ {
+ if (errno != ENOENT)
+ {
+ helplog(ASL_LEVEL_ERR, "stat of \"%s\" failed (%d): %s",
+ racoon_config_dir, ret, strerror(errno));
+ return -1;
+ }
+ else
+ {
+ ret = mkdir(racoon_config_dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+ if (ret != 0)
+ {
+ helplog(ASL_LEVEL_ERR, "mkdir \"%s\" failed: %s",
+ racoon_config_dir, strerror(errno));
+ return -1;
+ }
+ else
+ helplog(ASL_LEVEL_INFO, "created directory \"%s\"", racoon_config_dir);
+ }
+ }
+ else if (!(s.st_mode & S_IFDIR))
+ {
+ helplog(ASL_LEVEL_ERR, "\"%s\" is not a directory!",
+ racoon_config_dir);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+createAnonymousRacoonConfiguration(const char *fqdn)
+{
+ static const char config1[] =
+ "remote anonymous {\n"
+ " exchange_mode aggressive;\n"
+ " doi ipsec_doi;\n"
+ " situation identity_only;\n"
+ " verify_identifier off;\n"
+ " generate_policy on;\n"
+ " shared_secret keychain_by_id \"";
+ static const char config2[] =
+ "\";\n"
+ " nonce_size 16;\n"
+ " lifetime time 15 min;\n"
+ " initial_contact on;\n"
+ " support_proxy on;\n"
+ " nat_traversal force;\n"
+ " proposal_check claim;\n"
+ " proposal {\n"
+ " encryption_algorithm aes;\n"
+ " hash_algorithm sha256;\n"
+ " authentication_method pre_shared_key;\n"
+ " dh_group 2;\n"
+ " lifetime time 15 min;\n"
+ " }\n"
+ " proposal {\n"
+ " encryption_algorithm aes;\n"
+ " hash_algorithm sha1;\n"
+ " authentication_method pre_shared_key;\n"
+ " dh_group 2;\n"
+ " lifetime time 15 min;\n"
+ " }\n"
+ "}\n\n"
+ "sainfo anonymous { \n"
+ " pfs_group 2;\n"
+ " lifetime time 10 min;\n"
+ " encryption_algorithm aes;\n"
+ " authentication_algorithm hmac_sha256,hmac_sha1;\n"
+ " compression_algorithm deflate;\n"
+ "}\n";
+ char tmp_config_path[64];
+ char racoon_config_path[64];
+ const char* const racoon_config_dir = GetRacoonConfigDir();
+ const char* const racoon_config_dir_old = GetOldRacoonConfigDir();
+ int fd = -1;
+
+ debug("entry");
+
+ if (0 > ensureExistenceOfRacoonConfigDir(racoon_config_dir))
+ return -1;
+
+ strlcpy(tmp_config_path, racoon_config_dir, sizeof(tmp_config_path));
+ strlcat(tmp_config_path, "tmp.XXXXXX", sizeof(tmp_config_path));
+
+ fd = mkstemp(tmp_config_path);
+
+ if (0 > fd)
+ {
+ helplog(ASL_LEVEL_ERR, "mkstemp \"%s\" failed: %s",
+ tmp_config_path, strerror(errno));
+ return -1;
+ }
+ write(fd, configHeader, sizeof(configHeader)-1);
+ write(fd, config1, sizeof(config1)-1);
+ write(fd, fqdn, strlen(fqdn));
+ write(fd, config2, sizeof(config2)-1);
+ close(fd);
+
+ strlcpy(racoon_config_path, racoon_config_dir, sizeof(racoon_config_path));
+ strlcat(racoon_config_path, racoon_config_file, sizeof(racoon_config_path));
+
+ moveAsideAnonymousRacoonConfiguration(racoon_config_dir_old);
+ moveAsideAnonymousRacoonConfiguration(racoon_config_dir);
+
+ if (0 > rename(tmp_config_path, racoon_config_path))
+ {
+ unlink(tmp_config_path);
+ helplog(ASL_LEVEL_ERR, "rename \"%s\" \"%s\" failed: %s",
+ tmp_config_path, racoon_config_path, strerror(errno));
+ revertAnonymousRacoonConfiguration(racoon_config_dir_old);
+ revertAnonymousRacoonConfiguration(racoon_config_dir);
+ return -1;
+ }
+
+ debug("successfully renamed \"%s\" \"%s\"", tmp_config_path, racoon_config_path);
+ return 0;
+}
+
+static int
+notifyRacoon(void)
+{
+ debug("entry");
+ static const char racoon_pid_path[] = "/var/run/racoon.pid";
+ char buf[] = "18446744073709551615"; /* largest 64-bit integer */
+ char *p = NULL;
+ ssize_t n = 0;
+ unsigned long m = 0;
+ int fd = open(racoon_pid_path, O_RDONLY);
+
+ if (0 > fd)
+ {
+ debug("open \"%s\" failed, and that's OK: %s", racoon_pid_path,
+ strerror(errno));
+ return kmDNSHelperRacoonNotificationFailed;
+ }
+ n = read(fd, buf, sizeof(buf)-1);
+ close(fd);
+ if (1 > n)
+ {
+ debug("read of \"%s\" failed: %s", racoon_pid_path,
+ n == 0 ? "empty file" : strerror(errno));
+ return kmDNSHelperRacoonNotificationFailed;
+ }
+ buf[n] = '\0';
+ m = strtoul(buf, &p, 10);
+ if (*p != '\0' && !isspace(*p))
+ {
+ debug("invalid PID \"%s\" (around '%c')", buf, *p);
+ return kmDNSHelperRacoonNotificationFailed;
+ }
+ if (2 > m)
+ {
+ debug("refusing to kill PID %lu", m);
+ return kmDNSHelperRacoonNotificationFailed;
+ }
+ if (0 != kill(m, RacoonSignal()))
+ {
+ debug("Could not signal racoon (%lu): %s", m, strerror(errno));
+ return kmDNSHelperRacoonNotificationFailed;
+ }
+ debug("Sent racoon (%lu) signal %d", m, RacoonSignal());
+ return 0;
+}
+
+static void
+closefds(int from)
+{
+ int fd = 0;
+ struct dirent entry, *entryp = NULL;
+ DIR *dirp = opendir("/dev/fd");
+
+ if (dirp == NULL)
+ {
+ /* fall back to the erroneous getdtablesize method */
+ for (fd = from; fd < getdtablesize(); ++fd)
+ close(fd);
+ return;
+ }
+ while (0 == readdir_r(dirp, &entry, &entryp) && NULL != entryp)
+ {
+ fd = atoi(entryp->d_name);
+ if (fd >= from && fd != dirfd(dirp))
+ close(fd);
+ }
+ closedir(dirp);
+}
+
+static int
+startRacoonOld(void)
+{
+ debug("entry");
+ char * const racoon_args[] = { "/usr/sbin/racoon", "-e", NULL };
+ ssize_t n = 0;
+ pid_t pid = 0;
+ int status = 0;
+
+ if (0 == (pid = fork()))
+ {
+ closefds(0);
+ execve(racoon_args[0], racoon_args, NULL);
+ helplog(ASL_LEVEL_ERR, "execve of \"%s\" failed: %s",
+ racoon_args[0], strerror(errno));
+ exit(2);
+ }
+ helplog(ASL_LEVEL_NOTICE, "racoon (pid=%lu) started",
+ (unsigned long)pid);
+ n = waitpid(pid, &status, 0);
+ if (-1 == n)
+ {
+ helplog(ASL_LEVEL_ERR, "Unexpected waitpid failure: %s",
+ strerror(errno));
+ return kmDNSHelperRacoonStartFailed;
+ }
+ else if (pid != n)
+ {
+ helplog(ASL_LEVEL_ERR, "Unexpected waitpid return value %d",
+ (int)n);
+ return kmDNSHelperRacoonStartFailed;
+ }
+ else if (WIFSIGNALED(status))
+ {
+ helplog(ASL_LEVEL_ERR,
+ "racoon (pid=%lu) terminated due to signal %d",
+ (unsigned long)pid, WTERMSIG(status));
+ return kmDNSHelperRacoonStartFailed;
+ }
+ else if (WIFSTOPPED(status))
+ {
+ helplog(ASL_LEVEL_ERR,
+ "racoon (pid=%lu) has stopped due to signal %d",
+ (unsigned long)pid, WSTOPSIG(status));
+ return kmDNSHelperRacoonStartFailed;
+ }
+ else if (0 != WEXITSTATUS(status))
+ {
+ helplog(ASL_LEVEL_ERR,
+ "racoon (pid=%lu) exited with status %d",
+ (unsigned long)pid, WEXITSTATUS(status));
+ return kmDNSHelperRacoonStartFailed;
+ }
+ debug("racoon (pid=%lu) daemonized normally", (unsigned long)pid);
+ return 0;
+}
+
+// constant and structure for the racoon control socket
+#define VPNCTL_CMD_PING 0x0004
+typedef struct vpnctl_hdr_struct
+{
+ u_int16_t msg_type;
+ u_int16_t flags;
+ u_int32_t cookie;
+ u_int32_t reserved;
+ u_int16_t result;
+ u_int16_t len;
+} vpnctl_hdr;
+
+static int
+startRacoon(void)
+{
+ debug("entry");
+ int fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (0 > fd)
+ {
+ helplog(ASL_LEVEL_ERR, "Could not create endpoint for racoon control socket: %d %s",
+ errno, strerror(errno));
+ return kmDNSHelperRacoonStartFailed;
+ }
+
+ struct sockaddr_un saddr;
+ memset(&saddr, 0, sizeof(saddr));
+ saddr.sun_family = AF_UNIX;
+ saddr.sun_len = sizeof(saddr);
+ static const char racoon_control_sock_path[] = "/var/run/vpncontrol.sock";
+ strcpy(saddr.sun_path, racoon_control_sock_path);
+ int result = connect(fd, (struct sockaddr*) &saddr, saddr.sun_len);
+ if (0 > result)
+ {
+ helplog(ASL_LEVEL_ERR, "Could not connect racoon control socket %s: %d %s",
+ racoon_control_sock_path, errno, strerror(errno));
+ return kmDNSHelperRacoonStartFailed;
+ }
+
+ u_int32_t btmm_cookie = 0x4d4d5442;
+ vpnctl_hdr h = { htons(VPNCTL_CMD_PING), 0, btmm_cookie, 0, 0, 0 };
+ size_t bytes = 0;
+ ssize_t ret = 0;
+
+ while (bytes < sizeof(vpnctl_hdr))
+ {
+ ret = write(fd, ((unsigned char*)&h)+bytes, sizeof(vpnctl_hdr) - bytes);
+ if (ret == -1)
+ {
+ helplog(ASL_LEVEL_ERR, "Could not write to racoon control socket: %d %s",
+ errno, strerror(errno));
+ return kmDNSHelperRacoonStartFailed;
+ }
+ bytes += ret;
+ }
+
+ int nfds = fd + 1;
+ fd_set fds;
+ int counter = 0;
+ struct timeval tv;
+ bytes = 0;
+ h.cookie = 0;
+
+ for (counter = 0; counter < 100; counter++)
+ {
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ tv = (struct timeval){ 0, 10000 }; // 10 milliseconds * 100 iterations = 1 second max wait time
+
+ result = select(nfds, &fds, (fd_set*)NULL, (fd_set*)NULL, &tv);
+ if (result > 0)
+ {
+ if (FD_ISSET(fd, &fds))
+ {
+ ret = read(fd, ((unsigned char*)&h)+bytes, sizeof(vpnctl_hdr) - bytes);
+
+ if (ret == -1)
+ {
+ helplog(ASL_LEVEL_ERR, "Could not read from racoon control socket: %d %s",
+ strerror(errno));
+ break;
+ }
+ bytes += ret;
+ if (bytes >= sizeof(vpnctl_hdr)) break;
+ }
+ else
+ {
+ debug("select returned but fd_isset not on expected fd\n");
+ }
+ }
+ else if (result < 0)
+ {
+ debug("select returned %d errno %d %s\n", result, errno, strerror(errno));
+ if (errno != EINTR) break;
+ }
+ }
+
+ close(fd);
+
+ if (bytes < sizeof(vpnctl_hdr) || h.cookie != btmm_cookie) return kmDNSHelperRacoonStartFailed;
+
+ debug("racoon started");
+ return 0;
+}
+
+static int
+kickRacoon(void)
+{
+ if ( 0 == notifyRacoon() )
+ return 0;
+ return UseOldRacoon() ? startRacoonOld() : startRacoon();
+}
+
+#endif /* ndef MDNS_NO_IPSEC */
+
+int
+do_mDNSConfigureServer(__unused mach_port_t port, int updown, const char *fqdn, audit_token_t token)
+{
+#ifndef MDNS_NO_IPSEC
+ debug("entry");
+ if (!authorized(&token)) goto fin;
+
+ switch ((enum mDNSUpDown)updown)
+ {
+ case kmDNSUp:
+ if (0 != createAnonymousRacoonConfiguration(fqdn)) goto fin;
+ break;
+ case kmDNSDown:
+ revertAnonymousRacoonConfiguration(GetOldRacoonConfigDir());
+ revertAnonymousRacoonConfiguration(GetRacoonConfigDir());
+ break;
+ default:
+ goto fin;
+ }
+
+ if (0 != kickRacoon())
+ goto fin;
+ debug("succeeded");
+
+fin:
+#else
+ (void)port; (void)updown; (void)fqdn; (void)token;
+#endif
+ update_idle_timer();
+ return KERN_SUCCESS;
+}
+
+#ifndef MDNS_NO_IPSEC
+
+static unsigned int routeSeq = 1;
+
+static int
+setupTunnelRoute(v6addr_t local, v6addr_t remote)
+{
+ struct
+ {
+ struct rt_msghdr hdr;
+ struct sockaddr_in6 dst;
+ struct sockaddr_in6 gtwy;
+ } msg;
+ int err = 0;
+ int s = -1;
+
+ if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET)))
+ {
+ helplog(ASL_LEVEL_ERR, "socket(PF_ROUTE, ...) failed: %s",
+ strerror(errno));
+ err = kmDNSHelperRoutingSocketCreationFailed;
+ goto fin;
+ }
+ memset(&msg, 0, sizeof(msg));
+ msg.hdr.rtm_msglen = sizeof(msg);
+ msg.hdr.rtm_type = RTM_ADD;
+ /* The following flags are set by `route add -inet6 -host ...` */
+ msg.hdr.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_HOST | RTF_STATIC;
+ msg.hdr.rtm_version = RTM_VERSION;
+ msg.hdr.rtm_seq = routeSeq++;
+ msg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
+ msg.hdr.rtm_inits = RTV_MTU;
+ msg.hdr.rtm_rmx.rmx_mtu = 1280;
+
+ msg.dst.sin6_len = sizeof(msg.dst);
+ msg.dst.sin6_family = AF_INET6;
+ memcpy(&msg.dst.sin6_addr, remote, sizeof(msg.dst.sin6_addr));
+
+ msg.gtwy.sin6_len = sizeof(msg.gtwy);
+ msg.gtwy.sin6_family = AF_INET6;
+ memcpy(&msg.gtwy.sin6_addr, local, sizeof(msg.gtwy.sin6_addr));
+
+ /* send message, ignore error when route already exists */
+ if (0 > write(s, &msg, msg.hdr.rtm_msglen))
+ {
+ int errno_ = errno;
+
+ debug("write to routing socket failed: %s", strerror(errno_));
+ if (EEXIST != errno_)
+ {
+ err = kmDNSHelperRouteAdditionFailed;
+ goto fin;
+ }
+ }
+
+fin:
+ if (0 <= s)
+ close(s);
+ return err;
+}
+
+static int
+teardownTunnelRoute(v6addr_t remote)
+{
+ struct
+ {
+ struct rt_msghdr hdr;
+ struct sockaddr_in6 dst;
+ } msg;
+ int err = 0;
+ int s = -1;
+
+ if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET)))
+ {
+ helplog(ASL_LEVEL_ERR, "socket(PF_ROUTE, ...) failed: %s",
+ strerror(errno));
+ err = kmDNSHelperRoutingSocketCreationFailed;
+ goto fin;
+ }
+ memset(&msg, 0, sizeof(msg));
+
+ msg.hdr.rtm_msglen = sizeof(msg);
+ msg.hdr.rtm_type = RTM_DELETE;
+ msg.hdr.rtm_version = RTM_VERSION;
+ msg.hdr.rtm_seq = routeSeq++;
+ msg.hdr.rtm_addrs = RTA_DST;
+
+ msg.dst.sin6_len = sizeof(msg.dst);
+ msg.dst.sin6_family = AF_INET6;
+ memcpy(&msg.dst.sin6_addr, remote, sizeof(msg.dst.sin6_addr));
+ if (0 > write(s, &msg, msg.hdr.rtm_msglen))
+ {
+ int errno_ = errno;
+
+ debug("write to routing socket failed: %s", strerror(errno_));
+ if (ESRCH != errno_)
+ {
+ err = kmDNSHelperRouteDeletionFailed;
+ goto fin;
+ }
+ }
+
+fin:
+ if (0 <= s)
+ close(s);
+ return err;
+}
+
+static int
+v4addr_to_string(v4addr_t addr, char *buf, size_t buflen)
+{
+ if (NULL == inet_ntop(AF_INET, addr, buf, buflen))
+ {
+ helplog(ASL_LEVEL_ERR, "inet_ntop failed: %s",
+ strerror(errno));
+ return kmDNSHelperInvalidNetworkAddress;
+ }
+ else
+ return 0;
+}
+
+static int
+v6addr_to_string(v6addr_t addr, char *buf, size_t buflen)
+{
+ if (NULL == inet_ntop(AF_INET6, addr, buf, buflen))
+ {
+ helplog(ASL_LEVEL_ERR, "inet_ntop failed: %s",
+ strerror(errno));
+ return kmDNSHelperInvalidNetworkAddress;
+ }
+ else
+ return 0;
+}
+
+/* Caller owns object returned in `policy' */
+static int
+generateTunnelPolicy(mDNSTunnelPolicyWhich which, mDNSTunnelType type, int in,
+ v4addr_t src, uint16_t src_port,
+ v4addr_t dst, uint16_t dst_port,
+ v6addr_t src6, v6addr_t dst6,
+ ipsec_policy_t *policy, size_t *len)
+{
+ char srcs[INET_ADDRSTRLEN], dsts[INET_ADDRSTRLEN];
+ char srcs6[INET6_ADDRSTRLEN], dsts6[INET6_ADDRSTRLEN];
+ char buf[512];
+ char *inOut = in ? "in" : "out";
+ ssize_t n = 0;
+ int err = 0;
+
+ *policy = NULL;
+ *len = 0;
+
+ switch (which)
+ {
+ case kmDNSTunnelPolicySetup:
+ if (type == kmDNSIPv6IPv4Tunnel)
+ {
+ if (0 != (err = v4addr_to_string(src, srcs, sizeof(srcs))))
+ goto fin;
+ if (0 != (err = v4addr_to_string(dst, dsts, sizeof(dsts))))
+ goto fin;
+ n = snprintf(buf, sizeof(buf),
+ "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require",
+ inOut, srcs, src_port, dsts, dst_port);
+ }
+ else if (type == kmDNSIPv6IPv6Tunnel)
+ {
+ if (0 != (err = v6addr_to_string(src6, srcs6, sizeof(srcs6))))
+ goto fin;
+ if (0 != (err = v6addr_to_string(dst6, dsts6, sizeof(dsts6))))
+ goto fin;
+ n = snprintf(buf, sizeof(buf),
+ "%s ipsec esp/tunnel/%s-%s/require",
+ inOut, srcs6, dsts6);
+ }
+ break;
+ case kmDNSTunnelPolicyTeardown:
+ n = strlcpy(buf, inOut, sizeof(buf));
+ break;
+ case kmDNSTunnelPolicyGenerate:
+ n = snprintf(buf, sizeof(buf), "%s generate", inOut);
+ break;
+ default:
+ err = kmDNSHelperIPsecPolicyCreationFailed;
+ goto fin;
+ }
+
+ if (n >= (int)sizeof(buf))
+ {
+ err = kmDNSHelperResultTooLarge;
+ goto fin;
+ }
+
+ debug("policy=\"%s\"", buf);
+ if (NULL == (*policy = (ipsec_policy_t)ipsec_set_policy(buf, n)))
+ {
+ helplog(ASL_LEVEL_ERR,
+ "Could not create IPsec policy from \"%s\"", buf);
+ err = kmDNSHelperIPsecPolicyCreationFailed;
+ goto fin;
+ }
+ *len = ((ipsec_policy_t)(*policy))->sadb_x_policy_len * 8;
+
+fin:
+ return err;
+}
+
+static int
+sendPolicy(int s, int setup,
+ struct sockaddr *src, uint8_t src_bits,
+ struct sockaddr *dst, uint8_t dst_bits,
+ ipsec_policy_t policy, size_t len)
+{
+ static unsigned int policySeq = 0;
+ int err = 0;
+
+ debug("entry, setup=%d", setup);
+ if (setup)
+ err = pfkey_send_spdadd(s, src, src_bits, dst, dst_bits, -1,
+ (char *)policy, len, policySeq++);
+ else
+ err = pfkey_send_spddelete(s, src, src_bits, dst, dst_bits, -1,
+ (char *)policy, len, policySeq++);
+ if (0 > err)
+ {
+ helplog(ASL_LEVEL_ERR, "Could not set IPsec policy: %s",
+ ipsec_strerror());
+ err = kmDNSHelperIPsecPolicySetFailed;
+ goto fin;
+ }
+ else
+ err = 0;
+ debug("succeeded");
+
+fin:
+ return err;
+}
+
+static int
+removeSA(int s, struct sockaddr *src, struct sockaddr *dst)
+{
+ int err = 0;
+
+ debug("entry");
+ err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, src, dst);
+ if (0 > err)
+ {
+ helplog(ASL_LEVEL_ERR, "Could not remove IPsec SA: %s", ipsec_strerror());
+ err = kmDNSHelperIPsecRemoveSAFailed;
+ goto fin;
+ }
+ err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, dst, src);
+ if (0 > err)
+ {
+ helplog(ASL_LEVEL_ERR, "Could not remove IPsec SA: %s", ipsec_strerror());
+ err = kmDNSHelperIPsecRemoveSAFailed;
+ goto fin;
+ }
+ else
+ err = 0;
+
+ debug("succeeded");
+
+fin:
+ return err;
+}
+
+static int
+doTunnelPolicy(mDNSTunnelPolicyWhich which, mDNSTunnelType type,
+ v6addr_t loc_inner, uint8_t loc_bits,
+ v4addr_t loc_outer, uint16_t loc_port,
+ v6addr_t rmt_inner, uint8_t rmt_bits,
+ v4addr_t rmt_outer, uint16_t rmt_port,
+ v6addr_t loc_outer6, v6addr_t rmt_outer6)
+{
+ struct sockaddr_in6 sin6_loc;
+ struct sockaddr_in6 sin6_rmt;
+ ipsec_policy_t policy = NULL;
+ size_t len = 0;
+ int s = -1;
+ int err = 0;
+
+ debug("entry");
+ if (0 > (s = pfkey_open()))
+ {
+ helplog(ASL_LEVEL_ERR,
+ "Could not create IPsec policy socket: %s",
+ ipsec_strerror());
+ err = kmDNSHelperIPsecPolicySocketCreationFailed;
+ goto fin;
+ }
+
+ memset(&sin6_loc, 0, sizeof(sin6_loc));
+ sin6_loc.sin6_len = sizeof(sin6_loc);
+ sin6_loc.sin6_family = AF_INET6;
+ sin6_loc.sin6_port = htons(0);
+ memcpy(&sin6_loc.sin6_addr, loc_inner, sizeof(sin6_loc.sin6_addr));
+
+ memset(&sin6_rmt, 0, sizeof(sin6_rmt));
+ sin6_rmt.sin6_len = sizeof(sin6_rmt);
+ sin6_rmt.sin6_family = AF_INET6;
+ sin6_rmt.sin6_port = htons(0);
+ memcpy(&sin6_rmt.sin6_addr, rmt_inner, sizeof(sin6_rmt.sin6_addr));
+
+ int setup = which != kmDNSTunnelPolicyTeardown;
+
+ if (0 != (err = generateTunnelPolicy(which, type, 1,
+ rmt_outer, rmt_port,
+ loc_outer, loc_port,
+ rmt_outer6, loc_outer6,
+ &policy, &len)))
+ goto fin;
+ if (0 != (err = sendPolicy(s, setup,
+ (struct sockaddr *)&sin6_rmt, rmt_bits,
+ (struct sockaddr *)&sin6_loc, loc_bits,
+ policy, len)))
+ goto fin;
+ if (NULL != policy)
+ {
+ free(policy);
+ policy = NULL;
+ }
+ if (0 != (err = generateTunnelPolicy(which, type, 0,
+ loc_outer, loc_port,
+ rmt_outer, rmt_port,
+ loc_outer6, rmt_outer6,
+ &policy, &len)))
+ goto fin;
+ if (0 != (err = sendPolicy(s, setup,
+ (struct sockaddr *)&sin6_loc, loc_bits,
+ (struct sockaddr *)&sin6_rmt, rmt_bits,
+ policy, len)))
+ goto fin;
+
+ if (which == kmDNSTunnelPolicyTeardown)
+ {
+ if (rmt_port) // Outer tunnel is IPv4
+ {
+ if (loc_outer && rmt_outer)
+ {
+ struct sockaddr_in sin_loc;
+ struct sockaddr_in sin_rmt;
+ memset(&sin_loc, 0, sizeof(sin_loc));
+ sin_loc.sin_len = sizeof(sin_loc);
+ sin_loc.sin_family = AF_INET;
+ memcpy(&sin_loc.sin_addr, loc_outer, sizeof(sin_loc.sin_addr));
+
+ memset(&sin_rmt, 0, sizeof(sin_rmt));
+ sin_rmt.sin_len = sizeof(sin_rmt);
+ sin_rmt.sin_family = AF_INET;
+ memcpy(&sin_rmt.sin_addr, rmt_outer, sizeof(sin_rmt.sin_addr));
+ if (0 != (err = removeSA(s, (struct sockaddr *)&sin_loc, (struct sockaddr *)&sin_rmt)))
+ goto fin;
+ }
+ }
+ else
+ {
+ if (loc_outer6 && rmt_outer6)
+ {
+ struct sockaddr_in6 sin6_lo;
+ struct sockaddr_in6 sin6_rm;
+
+ memset(&sin6_lo, 0, sizeof(sin6_lo));
+ sin6_lo.sin6_len = sizeof(sin6_lo);
+ sin6_lo.sin6_family = AF_INET6;
+ memcpy(&sin6_lo.sin6_addr, loc_outer6, sizeof(sin6_lo.sin6_addr));
+
+ memset(&sin6_rm, 0, sizeof(sin6_rm));
+ sin6_rm.sin6_len = sizeof(sin6_rm);
+ sin6_rm.sin6_family = AF_INET6;
+ memcpy(&sin6_rm.sin6_addr, rmt_outer6, sizeof(sin6_rm.sin6_addr));
+ if (0 != (err = removeSA(s, (struct sockaddr *)&sin6_lo, (struct sockaddr *)&sin6_rm)))
+ goto fin;
+ }
+ }
+ }
+
+
+ debug("succeeded");
+
+fin:
+ if (s >= 0)
+ pfkey_close(s);
+ if (NULL != policy)
+ free(policy);
+ return err;
+}
+
+#endif /* ndef MDNS_NO_IPSEC */
+
+int
+do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete,
+ v6addr_t loc_inner, v6addr_t loc_outer6, uint16_t loc_port,
+ v6addr_t rmt_inner, v6addr_t rmt_outer6, uint16_t rmt_port,
+ const char *id, int *err, audit_token_t token)
+{
+#ifndef MDNS_NO_IPSEC
+ static const char config[] =
+ "%s"
+ "remote %s [%u] {\n"
+ " disconnect_on_idle idle_timeout 600 idle_direction idle_outbound;\n"
+ " exchange_mode aggressive;\n"
+ " doi ipsec_doi;\n"
+ " situation identity_only;\n"
+ " verify_identifier off;\n"
+ " generate_policy on;\n"
+ " my_identifier user_fqdn \"%s\";\n"
+ " shared_secret keychain \"%s\";\n"
+ " nonce_size 16;\n"
+ " lifetime time 15 min;\n"
+ " initial_contact on;\n"
+ " support_proxy on;\n"
+ " nat_traversal force;\n"
+ " proposal_check claim;\n"
+ " proposal {\n"
+ " encryption_algorithm aes;\n"
+ " hash_algorithm sha256;\n"
+ " authentication_method pre_shared_key;\n"
+ " dh_group 2;\n"
+ " lifetime time 15 min;\n"
+ " }\n"
+ " proposal {\n"
+ " encryption_algorithm aes;\n"
+ " hash_algorithm sha1;\n"
+ " authentication_method pre_shared_key;\n"
+ " dh_group 2;\n"
+ " lifetime time 15 min;\n"
+ " }\n"
+ "}\n\n"
+ "sainfo address %s any address %s any {\n"
+ " pfs_group 2;\n"
+ " lifetime time 10 min;\n"
+ " encryption_algorithm aes;\n"
+ " authentication_algorithm hmac_sha256,hmac_sha1;\n"
+ " compression_algorithm deflate;\n"
+ "}\n\n"
+ "sainfo address %s any address %s any {\n"
+ " pfs_group 2;\n"
+ " lifetime time 10 min;\n"
+ " encryption_algorithm aes;\n"
+ " authentication_algorithm hmac_sha256,hmac_sha1;\n"
+ " compression_algorithm deflate;\n"
+ "}\n";
+ char path[PATH_MAX] = "";
+ char li[INET6_ADDRSTRLEN], lo[INET_ADDRSTRLEN], lo6[INET6_ADDRSTRLEN],
+ ri[INET6_ADDRSTRLEN], ro[INET_ADDRSTRLEN], ro6[INET6_ADDRSTRLEN];
+ FILE *fp = NULL;
+ int fd = -1;
+ char tmp_path[PATH_MAX] = "";
+ v4addr_t loc_outer, rmt_outer;
+
+ debug("entry");
+ *err = 0;
+ if (!authorized(&token))
+ {
+ *err = kmDNSHelperNotAuthorized;
+ goto fin;
+ }
+ switch ((enum mDNSAutoTunnelSetKeysReplaceDelete)replacedelete)
+ {
+ case kmDNSAutoTunnelSetKeysReplace:
+ case kmDNSAutoTunnelSetKeysDelete:
+ break;
+ default:
+ *err = kmDNSHelperInvalidTunnelSetKeysOperation;
+ goto fin;
+ }
+
+ if (0 != (*err = v6addr_to_string(loc_inner, li, sizeof(li))))
+ goto fin;
+ if (0 != (*err = v6addr_to_string(rmt_inner, ri, sizeof(ri))))
+ goto fin;
+
+ debug("loc_inner=%s rmt_inner=%s", li, ri);
+ if (!rmt_port)
+ {
+ loc_outer[0] = loc_outer[1] = loc_outer[2] = loc_outer[3] = 0;
+ rmt_outer[0] = rmt_outer[1] = rmt_outer[2] = rmt_outer[3] = 0;
+
+ if (0 != (*err = v6addr_to_string(loc_outer6, lo6, sizeof(lo6))))
+ goto fin;
+ if (0 != (*err = v6addr_to_string(rmt_outer6, ro6, sizeof(ro6))))
+ goto fin;
+ debug("IPv6 outer tunnel: loc_outer6=%s rmt_outer6=%s", lo6, ro6);
+ if ((int)sizeof(path) <= snprintf(path, sizeof(path),
+ "%s%s.conf", GetRacoonConfigDir(), ro6))
+ {
+ *err = kmDNSHelperResultTooLarge;
+ goto fin;
+ }
+ }
+ else
+ {
+ loc_outer[0] = loc_outer6[0];
+ loc_outer[1] = loc_outer6[1];
+ loc_outer[2] = loc_outer6[2];
+ loc_outer[3] = loc_outer6[3];
+
+ rmt_outer[0] = rmt_outer6[0];
+ rmt_outer[1] = rmt_outer6[1];
+ rmt_outer[2] = rmt_outer6[2];
+ rmt_outer[3] = rmt_outer6[3];
+
+ if (0 != (*err = v4addr_to_string(loc_outer, lo, sizeof(lo))))
+ goto fin;
+ if (0 != (*err = v4addr_to_string(rmt_outer, ro, sizeof(ro))))
+ goto fin;
+ debug("IPv4 outer tunnel: loc_outer=%s loc_port=%u rmt_outer=%s rmt_port=%u",
+ lo, loc_port, ro, rmt_port);
+
+ if ((int)sizeof(path) <= snprintf(path, sizeof(path),
+ "%s%s.%u.conf", GetRacoonConfigDir(), ro,
+ rmt_port))
+ {
+ *err = kmDNSHelperResultTooLarge;
+ goto fin;
+ }
+ }
+
+
+
+ if (kmDNSAutoTunnelSetKeysReplace == replacedelete)
+ {
+ if (0 > ensureExistenceOfRacoonConfigDir(GetRacoonConfigDir()))
+ {
+ *err = kmDNSHelperRacoonConfigCreationFailed;
+ goto fin;
+ }
+ if ((int)sizeof(tmp_path) <=
+ snprintf(tmp_path, sizeof(tmp_path), "%s.XXXXXX", path))
+ {
+ *err = kmDNSHelperResultTooLarge;
+ goto fin;
+ }
+ if (0 > (fd = mkstemp(tmp_path)))
+ {
+ helplog(ASL_LEVEL_ERR, "mkstemp \"%s\" failed: %s",
+ tmp_path, strerror(errno));
+ *err = kmDNSHelperRacoonConfigCreationFailed;
+ goto fin;
+ }
+ if (NULL == (fp = fdopen(fd, "w")))
+ {
+ helplog(ASL_LEVEL_ERR, "fdopen: %s",
+ strerror(errno));
+ *err = kmDNSHelperRacoonConfigCreationFailed;
+ goto fin;
+ }
+ fd = -1;
+ fprintf(fp, config, configHeader, (!rmt_port ? ro6 : ro), rmt_port, id, id, ri, li, li, ri);
+ fclose(fp);
+ fp = NULL;
+ if (0 > rename(tmp_path, path))
+ {
+ helplog(ASL_LEVEL_ERR,
+ "rename \"%s\" \"%s\" failed: %s",
+ tmp_path, path, strerror(errno));
+ *err = kmDNSHelperRacoonConfigCreationFailed;
+ goto fin;
+ }
+ }
+ else
+ {
+ if (0 != unlink(path))
+ debug("unlink \"%s\" failed: %s", path,
+ strerror(errno));
+ }
+
+ if (0 != (*err = doTunnelPolicy(kmDNSTunnelPolicyTeardown, kmDNSNoTunnel,
+ loc_inner, kWholeV6Mask, loc_outer, loc_port,
+ rmt_inner, kWholeV6Mask, rmt_outer, rmt_port, loc_outer6, rmt_outer6)))
+ goto fin;
+ if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
+ 0 != (*err = doTunnelPolicy(kmDNSTunnelPolicySetup, (!rmt_port ? kmDNSIPv6IPv6Tunnel : kmDNSIPv6IPv4Tunnel),
+ loc_inner, kWholeV6Mask, loc_outer, loc_port,
+ rmt_inner, kWholeV6Mask, rmt_outer, rmt_port, loc_outer6, rmt_outer6)))
+ goto fin;
+
+ if (0 != (*err = teardownTunnelRoute(rmt_inner)))
+ goto fin;
+ if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
+ 0 != (*err = setupTunnelRoute(loc_inner, rmt_inner)))
+ goto fin;
+
+ if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
+ 0 != (*err = kickRacoon()))
+ goto fin;
+
+ debug("succeeded");
+
+fin:
+ if (NULL != fp)
+ fclose(fp);
+ if (0 <= fd)
+ close(fd);
+ unlink(tmp_path);
+#else
+ (void)replacedelete; (void)loc_inner; (void)loc_outer6; (void)loc_port; (void)rmt_inner;
+ (void)rmt_outer6; (void)rmt_port; (void)id; (void)token;
+
+ *err = kmDNSHelperIPsecDisabled;
+#endif /* MDNS_NO_IPSEC */
+ update_idle_timer();
+ return KERN_SUCCESS;
+}
+
+kern_return_t
+do_mDNSSendWakeupPacket(__unused mach_port_t port, unsigned ifid, const char *eth_addr, const char *ip_addr, int iteration, audit_token_t token)
+{
+ int bpf_fd, i, j;
+ struct ifreq ifr;
+ char ifname[IFNAMSIZ];
+ char packet[512];
+ char *ptr = packet;
+ char bpf_device[12];
+ struct ether_addr *ea;
+ (void) ip_addr; // unused
+ (void) iteration; // unused
+ (void) token; // unused
+
+ if (if_indextoname(ifid, ifname) == NULL)
+ {
+ helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket invalid interface index %u", ifid);
+ return errno;
+ }
+
+ ea = ether_aton(eth_addr);
+ if (ea == NULL)
+ {
+ helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket invalid ethernet address %s", eth_addr);
+ return errno;
+ }
+
+ for (i = 0; i < 100; i++)
+ {
+ snprintf(bpf_device, sizeof(bpf_device), "/dev/bpf%d", i);
+ bpf_fd = open(bpf_device, O_RDWR, 0);
+ if (bpf_fd == -1)
+ continue;
+ else break;
+ }
+
+ if (bpf_fd == -1)
+ {
+ helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket cannot find a bpf device");
+ return ENXIO;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+
+ if (ioctl(bpf_fd, BIOCSETIF, (char *)&ifr) < 0)
+ {
+ helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket BIOCSETIF failed %s", strerror(errno));
+ return errno;
+ }
+
+ // 0x00 Destination address
+ for (i=0; i<6; i++) *ptr++ = ea->octet[i];
+
+ // 0x06 Source address (Note: Since we don't currently set the BIOCSHDRCMPLT option, BPF will fill in the real interface address for us)
+ for (i=0; i<6; i++) *ptr++ = 0;
+
+ // 0x0C Ethertype (0x0842)
+ *ptr++ = 0x08;
+ *ptr++ = 0x42;
+
+ // 0x0E Wakeup sync sequence
+ for (i=0; i<6; i++) *ptr++ = 0xFF;
+
+ // 0x14 Wakeup data
+ for (j=0; j<16; j++) for (i=0; i<6; i++) *ptr++ = ea->octet[i];
+
+ // 0x74 Password
+ for (i=0; i<6; i++) *ptr++ = 0;
+
+ if (write(bpf_fd, packet, ptr - packet) < 0)
+ {
+ helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket write failed %s", strerror(errno));
+ return errno;
+ }
+ helplog(ASL_LEVEL_INFO, "do_mDNSSendWakeupPacket sent unicast eth_addr %s, ip_addr %s", eth_addr, ip_addr);
+ // Send a broadcast one to handle ethernet switches that don't flood forward packets with
+ // unknown mac addresses.
+ for (i=0; i<6; i++) packet[i] = 0xFF;
+ if (write(bpf_fd, packet, ptr - packet) < 0)
+ {
+ helplog(ASL_LEVEL_ERR, "do_mDNSSendWakeupPacket write failed %s", strerror(errno));
+ return errno;
+ }
+ helplog(ASL_LEVEL_INFO, "do_mDNSSendWakeupPacket sent broadcast eth_addr %s, ip_addr %s", eth_addr, ip_addr);
+ close(bpf_fd);
+ return KERN_SUCCESS;
+}
+
+// Open the specified port for protocol in the P2P firewall.
+kern_return_t
+do_mDNSPacketFilterControl(__unused mach_port_t port, uint32_t command, const char * ifname, uint32_t count, pfArray_t portArray, pfArray_t protocolArray, audit_token_t token)
+{
+ (void) token; // unused
+ int error;
+ kern_return_t result = KERN_SUCCESS;
+
+ helplog(ASL_LEVEL_INFO, "do_mDNSPacketFilterControl: command %d ifname %s, count %d",
+ command, ifname, count);
+
+ switch (command)
+ {
+ case PF_SET_RULES:
+ error = P2PPacketFilterAddBonjourRuleSet(ifname, count, portArray, protocolArray);
+ if (error)
+ {
+ helplog(ASL_LEVEL_ERR, "P2PPacketFilterAddBonjourRuleSet failed %s", strerror(error));
+ result = KERN_FAILURE;
+ }
+ break;
+
+ case PF_CLEAR_RULES:
+ error = P2PPacketFilterClearBonjourRules();
+ if (error)
+ {
+ helplog(ASL_LEVEL_ERR, "P2PPacketFilterClearBonjourRules failed %s", strerror(error));
+ result = KERN_FAILURE;
+ }
+ break;
+
+ default:
+ helplog(ASL_LEVEL_ERR, "do_mDNSPacketFilterControl: invalid command %d", command);
+ result = KERN_INVALID_ARGUMENT;
+ break;
+ }
+
+ return result;
+}
+
+unsigned long
+in_cksum(unsigned short *ptr,int nbytes)
+{
+ unsigned long sum;
+ u_short oddbyte;
+
+ /*
+ * Our algorithm is simple, using a 32-bit accumulator (sum),
+ * we add sequential 16-bit words to it, and at the end, fold back
+ * all the carry bits from the top 16 bits into the lower 16 bits.
+ */
+ sum = 0;
+ while (nbytes > 1) {
+ sum += *ptr++;
+ nbytes -= 2;
+ }
+
+ /* mop up an odd byte, if necessary */
+ if (nbytes == 1) {
+ /* make sure top half is zero */
+ oddbyte = 0;
+
+ /* one byte only */
+ *((u_char *)&oddbyte) = *(u_char *)ptr;
+ sum += oddbyte;
+ }
+ /* Add back carry outs from top 16 bits to low 16 bits. */
+ sum = (sum >> 16) + (sum & 0xffff);
+
+ /* add carry */
+ sum += (sum >> 16);
+
+ return sum;
+}
+
+unsigned short
+InetChecksum(unsigned short *ptr,int nbytes)
+{
+ unsigned long sum;
+
+ sum = in_cksum(ptr, nbytes);
+ return (unsigned short)~sum;
+}
+
+void TCPCheckSum(int af, struct tcphdr *t, int tcplen, v6addr_t sadd6, v6addr_t dadd6)
+{
+ unsigned long sum = 0;
+ unsigned short *ptr;
+
+ /* TCP header checksum */
+ sum = in_cksum((unsigned short *)t, tcplen);
+
+ if (af == AF_INET)
+ {
+ /* Pseudo header */
+ ptr = (unsigned short *)sadd6;
+ sum += *ptr++;
+ sum += *ptr++;
+ ptr = (unsigned short *)dadd6;
+ sum += *ptr++;
+ sum += *ptr++;
+ }
+ else if (af == AF_INET6)
+ {
+ /* Pseudo header */
+ ptr = (unsigned short *)sadd6;
+ sum += *ptr++;
+ sum += *ptr++;
+ sum += *ptr++;
+ sum += *ptr++;
+ sum += *ptr++;
+ sum += *ptr++;
+ sum += *ptr++;
+ sum += *ptr++;
+ ptr = (unsigned short *)dadd6;
+ sum += *ptr++;
+ sum += *ptr++;
+ sum += *ptr++;
+ sum += *ptr++;
+ sum += *ptr++;
+ sum += *ptr++;
+ sum += *ptr++;
+ sum += *ptr++;
+ }
+
+ sum += htons(tcplen);
+ sum += htons(IPPROTO_TCP);
+
+ while (sum >> 16)
+ sum = (sum >> 16) + (sum & 0xFFFF);
+
+ t->th_sum = ~sum;
+
+}
+
+kern_return_t do_mDNSSendKeepalive(__unused mach_port_t port, v6addr_t sadd6, v6addr_t dadd6, uint16_t lport, uint16_t rport, unsigned seq, unsigned ack, uint16_t win, audit_token_t token)
+{
+ struct packet4 {
+ struct ip ip;
+ struct tcphdr tcp;
+ } packet4;
+ struct packet6 {
+ struct tcphdr tcp;
+ } packet6;
+ int sock, on;
+ struct tcphdr *t;
+ int af;
+ struct sockaddr_storage ss_to;
+ struct sockaddr_in *sin_to = (struct sockaddr_in *)&ss_to;
+ struct sockaddr_in6 *sin6_to = (struct sockaddr_in6 *)&ss_to;
+ void *packet;
+ ssize_t packetlen;
+ char ctlbuf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+ struct msghdr msghdr;
+ struct iovec iov;
+ ssize_t len;
+
+ if (!authorized(&token))
+ {
+ helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: Not authorized");
+ return kmDNSHelperNotAuthorized;
+ }
+
+ helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: called");
+
+ // all the incoming arguments are in network order
+ if ((*(unsigned *)(sadd6 +4) == 0) && (*(unsigned *)(sadd6 + 8) == 0) && (*(unsigned *)(sadd6 + 12) == 0))
+ {
+ af = AF_INET;
+ memset(&packet4, 0, sizeof (packet4));
+
+ /* Fill in all the IP header information - should be in host order*/
+ packet4.ip.ip_v = 4; /* 4-bit Version */
+ packet4.ip.ip_hl = 5; /* 4-bit Header Length */
+ packet4.ip.ip_tos = 0; /* 8-bit Type of service */
+ packet4.ip.ip_len = 40; /* 16-bit Total length */
+ packet4.ip.ip_id = 9864; /* 16-bit ID field */
+ packet4.ip.ip_off = 0; /* 13-bit Fragment offset */
+ packet4.ip.ip_ttl = 63; /* 8-bit Time To Live */
+ packet4.ip.ip_p = IPPROTO_TCP; /* 8-bit Protocol */
+ packet4.ip.ip_sum = 0; /* 16-bit Header checksum (below) */
+ memcpy(&packet4.ip.ip_src.s_addr, sadd6, 4);
+ memcpy(&packet4.ip.ip_dst.s_addr, dadd6, 4);
+
+ /* IP header checksum */
+ packet4.ip.ip_sum = InetChecksum((unsigned short *)&packet4.ip, 20);
+ t = &packet4.tcp;
+ packet = &packet4;
+ packetlen = 40; // sum of IPv4 header len(20) and TCP header len(20)
+ }
+ else
+ {
+ af = AF_INET6;
+ memset(&packet6, 0, sizeof (packet6));
+ t = &packet6.tcp;
+ packet = &packet6;
+ // We don't send IPv6 header, hence just the TCP header len (20)
+ packetlen = 20;
+ }
+
+ /* Fill in all the TCP header information */
+ t->th_sport = lport; /* 16-bit Source port number */
+ t->th_dport = rport; /* 16-bit Destination port */
+ t->th_seq = seq; /* 32-bit Sequence Number */
+ t->th_ack = ack; /* 32-bit Acknowledgement Number */
+ t->th_off = 5; /* Data offset */
+ t->th_flags = TH_ACK;
+ t->th_win = win;
+ t->th_sum = 0; /* 16-bit checksum (below) */
+ t->th_urp = 0; /* 16-bit urgent offset */
+
+ TCPCheckSum(af, t, 20, sadd6, dadd6);
+
+ /* Open up a RAW socket */
+ if ((sock = socket(af, SOCK_RAW, IPPROTO_TCP)) < 0)
+ {
+ helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: socket %s", strerror(errno));
+ return errno;
+ }
+
+
+ if (af == AF_INET)
+ {
+ on = 1;
+ if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &on, sizeof (on)))
+ {
+ close(sock);
+ helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: setsockopt %s", strerror(errno));
+ return errno;
+ }
+
+ memset(sin_to, 0, sizeof(struct sockaddr_in));
+ sin_to->sin_len = sizeof(struct sockaddr_in);
+ sin_to->sin_family = AF_INET;
+ memcpy(&sin_to->sin_addr, sadd6, sizeof(struct in_addr));
+ sin_to->sin_port = rport;
+
+ msghdr.msg_control = NULL;
+ msghdr.msg_controllen = 0;
+
+ }
+ else
+ {
+ struct cmsghdr *ctl;
+
+ memset(sin6_to, 0, sizeof(struct sockaddr_in6));
+ sin6_to->sin6_len = sizeof(struct sockaddr_in6);
+ sin6_to->sin6_family = AF_INET6;
+ memcpy(&sin6_to->sin6_addr, dadd6, sizeof(struct in6_addr));
+
+ sin6_to->sin6_port = rport;
+ sin6_to->sin6_flowinfo = 0;
+
+
+ msghdr.msg_control = ctlbuf;
+ msghdr.msg_controllen = sizeof(ctlbuf);
+ ctl = CMSG_FIRSTHDR(&msghdr);
+ ctl->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+ ctl->cmsg_level = IPPROTO_IPV6;
+ ctl->cmsg_type = IPV6_PKTINFO;
+ struct in6_pktinfo *pktinfo = (struct in6_pktinfo *) CMSG_DATA(ctl);
+ memcpy(&pktinfo->ipi6_addr, sadd6, sizeof(struct in6_addr));
+ pktinfo->ipi6_ifindex = 0;
+ }
+
+ msghdr.msg_name = (struct sockaddr *)&ss_to;
+ msghdr.msg_namelen = ss_to.ss_len;
+ iov.iov_base = packet;
+ iov.iov_len = packetlen;
+ msghdr.msg_iov = &iov;
+ msghdr.msg_iovlen = 1;
+ msghdr.msg_flags = 0;
+again:
+ len = sendmsg(sock, &msghdr, 0);
+ if (len == -1)
+ {
+ if (errno == EINTR)
+ goto again;
+ }
+
+ if (len != packetlen)
+ {
+ helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: sendmsg failed %s", strerror(errno));
+ }
+ else
+ {
+ char source[INET6_ADDRSTRLEN], dest[INET6_ADDRSTRLEN];
+
+ inet_ntop(af, (void *)sadd6, source, sizeof(source));
+ inet_ntop(af, (void *)dadd6, dest, sizeof(dest));
+
+ helplog(ASL_LEVEL_ERR, "mDNSSendKeepalive: Success Source %s:%d, Dest %s:%d, %u, %u, %u", source, ntohs(lport), dest, ntohs(rport), ntohl(seq), ntohl(ack), ntohs(win));
+
+ }
+ close(sock);
+ return KERN_SUCCESS;
+}
+
+
+kern_return_t do_mDNSRetrieveTCPInfo(__unused mach_port_t port, int family, v6addr_t laddr, uint16_t lport, v6addr_t raddr, uint16_t rport,
+ uint32_t *seq, uint32_t *ack, uint16_t *win, int32_t *intfid, audit_token_t token)
+{
+ struct tcp_info ti;
+ struct info_tuple itpl;
+ int mib[4];
+ unsigned int miblen;
+ size_t len;
+ size_t sz;
+
+ memset(&itpl, 0, sizeof(struct info_tuple));
+ memset(&ti, 0, sizeof(struct tcp_info));
+
+ if (!authorized(&token))
+ {
+ helplog(ASL_LEVEL_ERR, "mDNSRetrieveTCPInfo: Not authorized");
+ return kmDNSHelperNotAuthorized;
+ }
+
+ if (family == AF_INET)
+ {
+ memcpy(&itpl.itpl_local_sin.sin_addr, laddr, sizeof(struct in_addr));
+ memcpy(&itpl.itpl_remote_sin.sin_addr, raddr, sizeof(struct in_addr));
+ itpl.itpl_local_sin.sin_port = lport;
+ itpl.itpl_remote_sin.sin_port = rport;
+ itpl.itpl_local_sin.sin_family = AF_INET;
+ itpl.itpl_remote_sin.sin_family = AF_INET;
+ }
+ else
+ {
+ memcpy(&itpl.itpl_local_sin6.sin6_addr, laddr, sizeof(struct in6_addr));
+ memcpy(&itpl.itpl_remote_sin6.sin6_addr, raddr, sizeof(struct in6_addr));
+ itpl.itpl_local_sin6.sin6_port = lport;
+ itpl.itpl_remote_sin6.sin6_port = rport;
+ itpl.itpl_local_sin6.sin6_family = AF_INET6;
+ itpl.itpl_remote_sin6.sin6_family = AF_INET6;
+ }
+ itpl.itpl_proto = IPPROTO_TCP;
+ sz = sizeof(mib)/sizeof(mib[0]);
+ if (sysctlnametomib("net.inet.tcp.info", mib, &sz) == -1)
+ {
+ helplog(ASL_LEVEL_ERR, "do_RetrieveTCPInfo: sysctlnametomib failed %d, %s", errno, strerror(errno));
+ return errno;
+ }
+ miblen = (unsigned int)sz;
+ len = sizeof(struct tcp_info);
+ if (sysctl(mib, miblen, &ti, &len, &itpl, sizeof(struct info_tuple)) == -1)
+ {
+ helplog(ASL_LEVEL_ERR, "do_RetrieveTCPInfo: sysctl failed %d, %s", errno, strerror(errno));
+ return errno;
+ }
+
+ *seq = ti.tcpi_snd_nxt - 1;
+ *ack = ti.tcpi_rcv_nxt;
+ *win = ti.tcpi_rcv_space >> ti.tcpi_rcv_wscale;
+ *intfid = ti.tcpi_last_outif;
+ return KERN_SUCCESS;
+}
+
+static int getMACAddress(int family, v6addr_t raddr, v6addr_t gaddr, int *gfamily, ethaddr_t eth)
+{
+ struct
+ {
+ struct rt_msghdr m_rtm;
+ char m_space[512];
+ } m_rtmsg;
+
+ struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
+ char *cp = m_rtmsg.m_space;
+ int seq = 6367, sock, rlen, i;
+ struct sockaddr_in *sin = NULL;
+ struct sockaddr_in6 *sin6 = NULL;
+ struct sockaddr_dl *sdl = NULL;
+ struct sockaddr_storage sins;
+ struct sockaddr_dl sdl_m;
+
+#define NEXTADDR(w, s, len) \
+ if (rtm->rtm_addrs & (w)) \
+ { \
+ bcopy((char *)s, cp, len); \
+ cp += len; \
+ }
+
+ bzero(&sins, sizeof(struct sockaddr_storage));
+ bzero(&sdl_m, sizeof(struct sockaddr_dl));
+ bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
+
+ sock = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (sock < 0)
+ {
+ helplog(ASL_LEVEL_ERR, "mDNSGetRemoteMAC: Can not open the socket - %s", strerror(errno));
+ return errno;
+ }
+
+ rtm->rtm_addrs |= RTA_DST | RTA_GATEWAY;
+ rtm->rtm_type = RTM_GET;
+ rtm->rtm_flags = 0;
+ rtm->rtm_version = RTM_VERSION;
+ rtm->rtm_seq = ++seq;
+
+ sdl_m.sdl_len = sizeof(sdl_m);
+ sdl_m.sdl_family = AF_LINK;
+ if (family == AF_INET)
+ {
+ sin = (struct sockaddr_in*)&sins;
+ sin->sin_family = AF_INET;
+ sin->sin_len = sizeof(struct sockaddr_in);
+ memcpy(&sin->sin_addr, raddr, sizeof(struct in_addr));
+ NEXTADDR(RTA_DST, sin, sin->sin_len);
+ }
+ else if (family == AF_INET6)
+ {
+ sin6 = (struct sockaddr_in6 *)&sins;
+ sin6->sin6_len = sizeof(struct sockaddr_in6);
+ sin6->sin6_family = AF_INET6;
+ memcpy(&sin6->sin6_addr, raddr, sizeof(struct in6_addr));
+ NEXTADDR(RTA_DST, sin6, sin6->sin6_len);
+ }
+ NEXTADDR(RTA_GATEWAY, &sdl_m, sdl_m.sdl_len);
+ rtm->rtm_msglen = rlen = cp - (char *)&m_rtmsg;
+
+ if (write(sock, (char *)&m_rtmsg, rlen) < 0)
+ {
+ helplog(ASL_LEVEL_INFO, "do_mDNSGetRemoteMAC: writing to routing socket: %s", strerror(errno));
+ close(sock);
+ return errno;
+ }
+
+ do
+ {
+ rlen = read(sock, (char *)&m_rtmsg, sizeof(m_rtmsg));
+ }
+ while (rlen > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != getpid()));
+
+ if (rlen < 0)
+ helplog(ASL_LEVEL_ERR, "do_mDNSGetRemoteMAC: Read from routing socket failed");
+
+ if (family == AF_INET)
+ {
+ sin = (struct sockaddr_in *) (rtm + 1);
+ sdl = (struct sockaddr_dl *) (sin->sin_len + (char *) sin);
+ }
+ else if (family == AF_INET6)
+ {
+ sin6 = (struct sockaddr_in6 *) (rtm +1);
+ sdl = (struct sockaddr_dl *) (sin6->sin6_len + (char *) sin6);
+ }
+ // If the address is not on the local net, we get the IP address of the gateway.
+ // We would have to repeat the process to get the MAC address of the gateway
+ *gfamily = sdl->sdl_family;
+ if (sdl->sdl_family == AF_INET)
+ {
+ struct sockaddr_in *new_sin = (struct sockaddr_in *)(sin->sin_len +(char*) sin);
+ memcpy(gaddr, &new_sin->sin_addr, sizeof(struct in_addr));
+ close(sock);
+ return -1;
+ }
+ else if (sdl->sdl_family == AF_INET6)
+ {
+ struct sockaddr_in6 *new_sin6 = (struct sockaddr_in6 *)(sin6->sin6_len +(char*) sin6);
+ memcpy(gaddr, &new_sin6->sin6_addr, sizeof(struct in6_addr));
+ close(sock);
+ return -1;
+ }
+
+ unsigned char *ptr = (unsigned char *)LLADDR(sdl);
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
+ (eth)[i] = *(ptr +i);
+
+ close(sock);
+ return KERN_SUCCESS;
+}
+
+kern_return_t do_mDNSGetRemoteMAC(__unused mach_port_t port, int family, v6addr_t raddr, ethaddr_t eth, audit_token_t token)
+{
+ int ret = 0;
+ v6addr_t gateway;
+ int gfamily;
+ int count = 0;
+
+ if (!authorized(&token))
+ {
+ helplog(ASL_LEVEL_ERR, "mDNSGetRemoteMAC: Not authorized");
+ return kmDNSHelperNotAuthorized;
+ }
+
+ do
+ {
+ ret = getMACAddress(family, raddr, gateway, &gfamily, eth);
+ if (ret == -1)
+ {
+ memcpy(raddr, gateway, sizeof(family));
+ family = gfamily;
+ count++;
+ }
+ }
+ while ((ret == -1) && (count < 5));
+ return ret;
+}
+
+
+kern_return_t do_mDNSStoreSPSMACAddress(__unused mach_port_t port, int family, v6addr_t spsaddr, const char *ifname, audit_token_t token)
+{
+ ethaddr_t eth;
+ char spsip[INET6_ADDRSTRLEN];
+ int ret = 0;
+ CFStringRef sckey = NULL;
+ SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:StoreSPSMACAddress"), NULL, NULL);
+ SCDynamicStoreRef ipstore = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetIPv6Addresses"), NULL, NULL);
+ CFMutableDictionaryRef dict = NULL;
+ CFStringRef entityname = NULL;
+ CFDictionaryRef ipdict = NULL;
+ CFArrayRef addrs = NULL;
+
+ if (!authorized(&token))
+ {
+ helplog(ASL_LEVEL_ERR, "mDNSStoreSPSMAC: Not authorized");
+ return kmDNSHelperNotAuthorized;
+ }
+
+ if ((store == NULL) || (ipstore == NULL))
+ {
+ helplog(ASL_LEVEL_ERR, "Unable to access SC Dynamic Store");
+ return KERN_FAILURE;
+ }
+
+ // Get the MAC address of the Sleep Proxy Server
+ memset(eth, 0, sizeof(eth));
+ ret = do_mDNSGetRemoteMAC(port, family, spsaddr, eth, token);
+ if (ret != KERN_SUCCESS)
+ {
+ helplog(ASL_LEVEL_ERR, "mDNSStoreSPSMAC: Failed to determine the MAC address");
+ goto fin;
+ }
+
+ // Create/Update the dynamic store entry for the specified interface
+ sckey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", ifname, "/BonjourSleepProxyAddress");
+ dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ if (!dict)
+ {
+ helplog(ASL_LEVEL_ERR, "SPSCreateDict: Could not create CFDictionary dict");
+ ret = KERN_FAILURE;
+ goto fin;
+ }
+
+ CFStringRef macaddr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%02x:%02x:%02x:%02x:%02x:%02x"), eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
+ CFDictionarySetValue(dict, CFSTR("MACAddress"), macaddr);
+ if (NULL != macaddr) CFRelease(macaddr);
+
+ if( NULL == inet_ntop(family, (void *)spsaddr, spsip, sizeof(spsip)))
+ {
+ helplog(ASL_LEVEL_ERR, "inet_ntop failed: %s", strerror(errno));
+ ret = kmDNSHelperInvalidNetworkAddress;
+ goto fin;
+ }
+
+ CFStringRef ipaddr = CFStringCreateWithCString(NULL, spsip, kCFStringEncodingUTF8);
+ CFDictionarySetValue(dict, CFSTR("IPAddress"), ipaddr);
+ if (NULL != ipaddr) CFRelease(ipaddr);
+
+ // Get the current IPv6 addresses on this interface and store them so NAs can be sent on wakeup
+ if ((entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/IPv6"), ifname)) != NULL)
+ {
+ if ((ipdict = SCDynamicStoreCopyValue(ipstore, entityname)) != NULL)
+ {
+ if((addrs = CFDictionaryGetValue(ipdict, CFSTR("Addresses"))) != NULL)
+ {
+ addrs = CFRetain(addrs);
+ CFDictionarySetValue(dict, CFSTR("RegisteredAddresses"), addrs);
+ }
+ }
+ }
+ SCDynamicStoreSetValue(store, sckey, dict);
+
+fin:
+ if (store) CFRelease(store);
+ if (ipstore) CFRelease(ipstore);
+ if (sckey) CFRelease(sckey);
+ if (dict) CFRelease(dict);
+ if (ipdict) CFRelease(ipdict);
+ if (entityname) CFRelease(entityname);
+ if (addrs) CFRelease(addrs);
+
+ update_idle_timer();
+ return ret;
+}
Deleted: vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/mDNSMacOSX.c
===================================================================
--- vendor/apple/mDNSResponder/dist/mDNSMacOSX/mDNSMacOSX.c 2014-06-30 23:58:12 UTC (rev 6706)
+++ vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/mDNSMacOSX.c 2015-03-20 01:14:52 UTC (rev 6985)
@@ -1,10441 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2013 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// ***************************************************************************
-// mDNSMacOSX.c:
-// Supporting routines to run mDNS on a CFRunLoop platform
-// ***************************************************************************
-
-// For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
-// including ones that mDNSResponder chooses not to use.
-#define LIST_ALL_INTERFACES 0
-
-#include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
-#include "DNSCommon.h"
-#include "uDNS.h"
-#include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
-#include "dns_sd.h" // For mDNSInterface_LocalOnly etc.
-#include "PlatformCommon.h"
-#include "uds_daemon.h"
-#include "CryptoSupport.h"
-
-#include <stdio.h>
-#include <stdarg.h> // For va_list support
-#include <stdlib.h> // For arc4random
-#include <net/if.h>
-#include <net/if_types.h> // For IFT_ETHER
-#include <net/if_dl.h>
-#include <net/bpf.h> // For BIOCSETIF etc.
-#include <sys/uio.h>
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <sys/sysctl.h>
-#include <sys/event.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <time.h> // platform support for UTC time
-#include <arpa/inet.h> // for inet_aton
-#include <pthread.h>
-#include <netdb.h> // for getaddrinfo
-#include <sys/sockio.h> // for SIOCGIFEFLAGS
-#include <notify.h>
-#include <netinet/in.h> // For IP_RECVTTL
-#ifndef IP_RECVTTL
-#define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
-#endif
-
-#include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
-#include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
-#include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
-#include <netinet6/nd6.h> // For ND6_INFINITE_LIFETIME etc.
-
-#include <netinet/tcp.h>
-
-#include <DebugServices.h>
-#include "dnsinfo.h"
-
-#include <ifaddrs.h>
-
-#include <IOKit/IOKitLib.h>
-#include <IOKit/IOMessage.h>
-
-#include <IOKit/ps/IOPowerSources.h>
-#include <IOKit/ps/IOPowerSourcesPrivate.h>
-#include <IOKit/ps/IOPSKeys.h>
-
-#include <mach/mach_error.h>
-#include <mach/mach_port.h>
-#include <mach/mach_time.h>
-#include "helper.h"
-#include "P2PPacketFilter.h"
-
-#include <asl.h>
-#include <SystemConfiguration/SCPrivate.h>
-
-// Include definition of opaque_presence_indication for KEV_DL_NODE_PRESENCE handling logic.
-#include <Kernel/IOKit/apple80211/apple80211_var.h>
-
-#if APPLE_OSX_mDNSResponder
-#include <DeviceToDeviceManager/DeviceToDeviceManager.h>
-#include <AWACS.h>
-#if !NO_D2D
-D2DStatus D2DInitialize(CFRunLoopRef runLoop, D2DServiceCallback serviceCallback, void* userData) __attribute__((weak_import));
-D2DStatus D2DRetain(D2DServiceInstance instanceHandle, D2DTransportType transportType) __attribute__((weak_import));
-D2DStatus D2DStopAdvertisingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
-D2DStatus D2DRelease(D2DServiceInstance instanceHandle, D2DTransportType transportType) __attribute__((weak_import));
-D2DStatus D2DStartAdvertisingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
-D2DStatus D2DStartBrowsingForKeyOnTransport(const Byte *key, const size_t keySize, D2DTransportType transport) __attribute__((weak_import));
-D2DStatus D2DStopBrowsingForKeyOnTransport(const Byte *key, const size_t keySize, D2DTransportType transport) __attribute__((weak_import));
-void D2DStartResolvingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
-void D2DStopResolvingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
-D2DStatus D2DTerminate() __attribute__((weak_import));
-
-#endif // ! NO_D2D
-
-#else
-#define NO_D2D 1
-#define NO_AWACS 1
-#endif // APPLE_OSX_mDNSResponder
-
-#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
-#include <IOKit/platform/IOPlatformSupportPrivate.h>
-#endif // APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
-
-
-#define kInterfaceSpecificOption "interface="
-
-#define mDNS_IOREG_KEY "mDNS_KEY"
-#define mDNS_IOREG_VALUE "2009-07-30"
-#define mDNS_IOREG_KA_KEY "mDNS_Keepalive"
-#define mDNS_USER_CLIENT_CREATE_TYPE 'mDNS'
-
-// cache the InterfaceID of the AWDL interface
-static mDNSInterfaceID AWDLInterfaceID;
-
-// ***************************************************************************
-// Globals
-
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark - Globals
-#endif
-
-// By default we don't offer sleep proxy service
-// If OfferSleepProxyService is set non-zero (typically via command-line switch),
-// then we'll offer sleep proxy service on desktop Macs that are set to never sleep.
-// We currently do not offer sleep proxy service on laptops, or on machines that are set to go to sleep.
-mDNSexport int OfferSleepProxyService = 0;
-mDNSexport int DisableSleepProxyClient = 0;
-mDNSexport int UseInternalSleepProxy = 1; // Set to non-zero to use internal (in-NIC) Sleep Proxy
-
-mDNSexport int OSXVers, iOSVers;
-mDNSexport int KQueueFD;
-
-#ifndef NO_SECURITYFRAMEWORK
-static CFArrayRef ServerCerts;
-OSStatus SSLSetAllowAnonymousCiphers(SSLContextRef context, Boolean enable);
-#endif /* NO_SECURITYFRAMEWORK */
-
-static CFStringRef NetworkChangedKey_IPv4;
-static CFStringRef NetworkChangedKey_IPv6;
-static CFStringRef NetworkChangedKey_Hostnames;
-static CFStringRef NetworkChangedKey_Computername;
-static CFStringRef NetworkChangedKey_DNS;
-static CFStringRef NetworkChangedKey_StateInterfacePrefix;
-static CFStringRef NetworkChangedKey_DynamicDNS = CFSTR("Setup:/Network/DynamicDNS");
-static CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac");
-static CFStringRef NetworkChangedKey_BTMMConnectivity = CFSTR("State:/Network/Connectivity");
-static CFStringRef NetworkChangedKey_PowerSettings = CFSTR("State:/IOKit/PowerManagement/CurrentSettings");
-
-static char HINFO_HWstring_buffer[32];
-static char *HINFO_HWstring = "Device";
-static int HINFO_HWstring_prefixlen = 6;
-
-mDNSexport int WatchDogReportingThreshold = 250;
-
-dispatch_queue_t SSLqueue;
-
-//To prevent blocking the main queue, all writes to DynamicStore happen on the DynamicStoreQueue
-static dispatch_queue_t DynamicStoreQueue;
-
-#if TARGET_OS_EMBEDDED
-#define kmDNSResponderManagedPrefsID CFSTR("/Library/Managed Preferences/mobile/com.apple.mDNSResponder.plist")
-#endif
-
-#if APPLE_OSX_mDNSResponder
-static mDNSu8 SPMetricPortability = 99;
-static mDNSu8 SPMetricMarginalPower = 99;
-static mDNSu8 SPMetricTotalPower = 99;
-static mDNSu8 SPMetricFeatures = 1; /* The current version supports TCP Keep Alive Feature */
-mDNSexport domainname ActiveDirectoryPrimaryDomain;
-mDNSexport int ActiveDirectoryPrimaryDomainLabelCount;
-mDNSexport mDNSAddr ActiveDirectoryPrimaryDomainServer;
-#endif // APPLE_OSX_mDNSResponder
-
-// Don't send triggers too often. We arbitrarily limit it to three minutes.
-#define DNS_TRIGGER_INTERVAL (180 * mDNSPlatformOneSecond)
-
-// Used by AutoTunnel
-const char btmmprefix[] = "btmmdns:";
-const char dnsprefix[] = "dns:";
-
-// String Array used to write list of private domains to Dynamic Store
-static CFArrayRef privateDnsArray = NULL;
-
-// ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - D2D Support
-#endif
-
-#if !NO_D2D
-
-mDNSexport void D2D_start_advertising_interface(NetworkInterfaceInfo *interface)
-{
- // AWDL wants the address and reverse address PTR record communicated
- // via the D2D interface layer.
- if (interface->InterfaceID == AWDLInterfaceID)
- {
- // only log if we have a valid record to start advertising
- if (interface->RR_A.resrec.RecordType || interface->RR_PTR.resrec.RecordType)
- LogInfo("D2D_start_advertising_interface: %s", interface->ifname);
-
- if (interface->RR_A.resrec.RecordType)
- external_start_advertising_service(&interface->RR_A.resrec, NULL);
- if (interface->RR_PTR.resrec.RecordType)
- external_start_advertising_service(&interface->RR_PTR.resrec, NULL);
- }
-}
-
-mDNSexport void D2D_stop_advertising_interface(NetworkInterfaceInfo *interface)
-{
- if (interface->InterfaceID == AWDLInterfaceID)
- {
- // only log if we have a valid record to stop advertising
- if (interface->RR_A.resrec.RecordType || interface->RR_PTR.resrec.RecordType)
- LogInfo("D2D_stop_advertising_interface: %s", interface->ifname);
-
- if (interface->RR_A.resrec.RecordType)
- external_stop_advertising_service(&interface->RR_A.resrec, NULL);
- if (interface->RR_PTR.resrec.RecordType)
- external_stop_advertising_service(&interface->RR_PTR.resrec, NULL);
- }
-}
-
-// Name compression items for fake packet version number 1
-static const mDNSu8 compression_packet_v1 = 0x01;
-
-static DNSMessage compression_base_msg = { { {{0}}, {{0}}, 2, 0, 0, 0 }, "\x04_tcp\x05local\x00\x00\x0C\x00\x01\x04_udp\xC0\x11\x00\x0C\x00\x01" };
-static mDNSu8 *const compression_limit = (mDNSu8 *) &compression_base_msg + sizeof(DNSMessage);
-static mDNSu8 *const compression_lhs = (mDNSu8 *const) compression_base_msg.data + 27;
-
-mDNSlocal void FreeD2DARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
-mDNSlocal void PrintHex(mDNSu8 *data, mDNSu16 len);
-
-typedef struct D2DRecordListElem
-{
- struct D2DRecordListElem *next;
- AuthRecord ar;
- D2DServiceInstance instanceHandle;
- D2DTransportType transportType;
-} D2DRecordListElem;
-
-static D2DRecordListElem *D2DRecords = NULL; // List of records returned with D2DServiceFound events
-
-typedef struct D2DBrowseListElem
-{
- struct D2DBrowseListElem *next;
- domainname name;
- mDNSu16 type;
- unsigned int refCount;
-} D2DBrowseListElem;
-
-D2DBrowseListElem* D2DBrowseList = NULL;
-
-mDNSlocal mDNSu8 *putVal16(mDNSu8 *ptr, mDNSu16 val)
-{
- ptr[0] = (mDNSu8)((val >> 8 ) & 0xFF);
- ptr[1] = (mDNSu8)((val ) & 0xFF);
- return ptr + sizeof(mDNSu16);
-}
-
-mDNSlocal mDNSu8 *putVal32(mDNSu8 *ptr, mDNSu32 val)
-{
- ptr[0] = (mDNSu8)((val >> 24) & 0xFF);
- ptr[1] = (mDNSu8)((val >> 16) & 0xFF);
- ptr[2] = (mDNSu8)((val >> 8) & 0xFF);
- ptr[3] = (mDNSu8)((val ) & 0xFF);
- return ptr + sizeof(mDNSu32);
-}
-
-mDNSlocal void DomainnameToLower(const domainname * const in, domainname * const out)
-{
- const mDNSu8 * const start = (const mDNSu8 * const)in;
- mDNSu8 *ptr = (mDNSu8*)start;
- while(*ptr)
- {
- mDNSu8 c = *ptr;
- out->c[ptr-start] = *ptr;
- ptr++;
- for (; c; c--,ptr++) out->c[ptr-start] = mDNSIsUpperCase(*ptr) ? (*ptr - 'A' + 'a') : *ptr;
- }
- out->c[ptr-start] = *ptr;
-}
-
-mDNSlocal mStatus DNSNameCompressionParseBytes(mDNS *const m, const mDNSu8 *const lhs, const mDNSu16 lhs_len, const mDNSu8 *const rhs, const mDNSu16 rhs_len, AuthRecord *rr)
-{
- if (mDNS_LoggingEnabled)
- {
- LogInfo("%s", __func__);
- LogInfo(" Static Bytes: (%d bytes)", compression_lhs - (mDNSu8*)&compression_base_msg);
- PrintHex((mDNSu8*)&compression_base_msg, compression_lhs - (mDNSu8*)&compression_base_msg);
- }
-
- mDNSu8 *ptr = compression_lhs; // pointer to the end of our fake packet
-
- // Check to make sure we're not going to go past the end of the DNSMessage data
- // 7 = 2 for CLASS (-1 for our version) + 4 for TTL + 2 for RDLENGTH
- if (ptr + lhs_len - 7 + rhs_len >= compression_limit) return mStatus_NoMemoryErr;
-
- // Copy the LHS onto our fake wire packet
- mDNSPlatformMemCopy(ptr, lhs, lhs_len);
- ptr += lhs_len - 1;
-
- // Check the 'fake packet' version number, to ensure that we know how to decompress this data
- if (*ptr != compression_packet_v1) return mStatus_Incompatible;
-
- // two bytes of CLASS
- ptr = putVal16(ptr, kDNSClass_IN | kDNSClass_UniqueRRSet);
-
- // four bytes of TTL
- ptr = putVal32(ptr, 120);
-
- // Copy the RHS length into the RDLENGTH of our fake wire packet
- ptr = putVal16(ptr, rhs_len);
-
- // Copy the RHS onto our fake wire packet
- mDNSPlatformMemCopy(ptr, rhs, rhs_len);
- ptr += rhs_len;
-
- if (mDNS_LoggingEnabled)
- {
- LogInfo(" Our Bytes (%d bytes): ", ptr - compression_lhs);
- PrintHex(compression_lhs, ptr - compression_lhs);
- }
-
- ptr = (mDNSu8 *) GetLargeResourceRecord(m, &compression_base_msg, compression_lhs, ptr, mDNSInterface_Any, kDNSRecordTypePacketAns, &m->rec);
- if (!ptr || m->rec.r.resrec.RecordType == kDNSRecordTypePacketNegative)
- { LogMsg("DNSNameCompressionParseBytes: failed to get large RR"); m->rec.r.resrec.RecordType = 0; return mStatus_UnknownErr; }
- else LogInfo("DNSNameCompressionParseBytes: got rr: %s", CRDisplayString(m, &m->rec.r));
-
- mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_P2P, m->rec.r.resrec.rrtype, 7200, kDNSRecordTypeShared, AuthRecordP2P, FreeD2DARElemCallback, NULL);
- AssignDomainName(&rr->namestorage, &m->rec.namestorage);
- rr->resrec.rdlength = m->rec.r.resrec.rdlength;
- rr->resrec.rdata->MaxRDLength = m->rec.r.resrec.rdlength;
- mDNSPlatformMemCopy(rr->resrec.rdata->u.data, m->rec.r.resrec.rdata->u.data, m->rec.r.resrec.rdlength);
- rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
- SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
-
- m->rec.r.resrec.RecordType = 0; // Mark m->rec as no longer in use
-
- return mStatus_NoError;
-}
-
-mDNSlocal mDNSu8 * DNSNameCompressionBuildLHS(const domainname* typeDomain, DNS_TypeValues qtype)
-{
- mDNSu8 *ptr = putDomainNameAsLabels(&compression_base_msg, compression_lhs, compression_limit, typeDomain);
- if (!ptr) return ptr;
- *ptr = (qtype >> 8) & 0xff;
- ptr += 1;
- *ptr = qtype & 0xff;
- ptr += 1;
- *ptr = compression_packet_v1;
- return ptr + 1;
-}
-
-mDNSlocal mDNSu8 * DNSNameCompressionBuildRHS(mDNSu8 *start, const ResourceRecord *const resourceRecord)
-{
- return putRData(&compression_base_msg, start, compression_limit, resourceRecord);
-}
-
-#define PRINT_DEBUG_BYTES_LIMIT 64 // set limit on number of record bytes printed for debugging
-
-mDNSlocal void PrintHex(mDNSu8 *data, mDNSu16 len)
-{
- mDNSu8 *end;
- char buffer[49] = {0};
- char *bufend = buffer + sizeof(buffer);
-
- if (len > PRINT_DEBUG_BYTES_LIMIT)
- {
- LogInfo(" (limiting debug output to %d bytes)", PRINT_DEBUG_BYTES_LIMIT);
- len = PRINT_DEBUG_BYTES_LIMIT;
- }
- end = data + len;
-
- while(data < end)
- {
- char *ptr = buffer;
- for(; data < end && ptr < bufend-1; ptr+=3,data++)
- mDNS_snprintf(ptr, bufend - ptr, "%02X ", *data);
- LogInfo(" %s", buffer);
- }
-}
-
-mDNSlocal void PrintHelper(const char *const tag, mDNSu8 *lhs, mDNSu16 lhs_len, mDNSu8 *rhs, mDNSu16 rhs_len)
-{
- if (!mDNS_LoggingEnabled) return;
-
- LogInfo("%s:", tag);
- LogInfo(" LHS: (%d bytes)", lhs_len);
- PrintHex(lhs, lhs_len);
-
- if (!rhs) return;
-
- LogInfo(" RHS: (%d bytes)", rhs_len);
- PrintHex(rhs, rhs_len);
-}
-
-mDNSlocal void FreeD2DARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
-{
- (void)m; // unused
- if (result == mStatus_MemFree)
- {
- D2DRecordListElem **ptr = &D2DRecords;
- D2DRecordListElem *tmp;
- while (*ptr && &(*ptr)->ar != rr) ptr = &(*ptr)->next;
- if (!*ptr) { LogMsg("FreeD2DARElemCallback: Could not find in D2DRecords: %s", ARDisplayString(m, rr)); return; }
- LogInfo("FreeD2DARElemCallback: Found in D2DRecords: %s", ARDisplayString(m, rr));
- tmp = *ptr;
- *ptr = (*ptr)->next;
- // Just because we stoppped browsing, doesn't mean we should tear down the PAN connection.
- mDNSPlatformMemFree(tmp);
- }
-}
-
-mDNSexport void external_connection_release(const domainname *instance)
-{
- (void) instance;
- D2DRecordListElem *ptr = D2DRecords;
-
- for ( ; ptr ; ptr = ptr->next)
- {
- if ((ptr->ar.resrec.rrtype == kDNSServiceType_PTR) &&
- SameDomainName(&ptr->ar.rdatastorage.u.name, instance))
- {
- LogInfo("external_connection_release: Calling D2DRelease(instanceHandle = %p, transportType = %d",
- ptr->instanceHandle, ptr->transportType);
- if (D2DRelease) D2DRelease(ptr->instanceHandle, ptr->transportType);
- }
- }
-}
-
-mDNSlocal void xD2DClearCache(const domainname *regType, DNS_TypeValues qtype)
-{
- D2DRecordListElem *ptr = D2DRecords;
- for ( ; ptr ; ptr = ptr->next)
- {
- if ((ptr->ar.resrec.rrtype == qtype) && SameDomainName(&ptr->ar.namestorage, regType))
- {
- mDNS_Deregister(&mDNSStorage, &ptr->ar);
- LogInfo("xD2DClearCache: Clearing cache record and deregistering %s", ARDisplayString(&mDNSStorage, &ptr->ar));
- }
- }
-}
-
-mDNSlocal D2DBrowseListElem ** D2DFindInBrowseList(const domainname *const name, mDNSu16 type)
-{
- D2DBrowseListElem **ptr = &D2DBrowseList;
-
- for ( ; *ptr; ptr = &(*ptr)->next)
- if ((*ptr)->type == type && SameDomainName(&(*ptr)->name, name))
- break;
-
- return ptr;
-}
-
-mDNSlocal unsigned int D2DBrowseListRefCount(const domainname *const name, mDNSu16 type)
-{
- D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
- return *ptr ? (*ptr)->refCount : 0;
-}
-
-mDNSlocal void D2DBrowseListRetain(const domainname *const name, mDNSu16 type)
-{
- D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
-
- if (!*ptr)
- {
- *ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
- mDNSPlatformMemZero(*ptr, sizeof(**ptr));
- (*ptr)->type = type;
- AssignDomainName(&(*ptr)->name, name);
- }
- (*ptr)->refCount += 1;
-
- LogInfo("D2DBrowseListRetain: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount);
-}
-
-mDNSlocal void D2DBrowseListRelease(const domainname *const name, mDNSu16 type)
-{
- D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
-
- if (!*ptr) { LogMsg("D2DBrowseListRelease: Didn't find %##s %s in list", name->c, DNSTypeName(type)); return; }
-
- (*ptr)->refCount -= 1;
-
- LogInfo("D2DBrowseListRelease: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount);
-
- if (!(*ptr)->refCount)
- {
- D2DBrowseListElem *tmp = *ptr;
- *ptr = (*ptr)->next;
- mDNSPlatformMemFree(tmp);
- }
-}
-
-mDNSlocal mStatus xD2DParse(mDNS *const m, const mDNSu8 * const lhs, const mDNSu16 lhs_len, const mDNSu8 * const rhs, const mDNSu16 rhs_len, AuthRecord *rr)
-{
- if (*(lhs + (lhs_len - 1)) == compression_packet_v1)
- return DNSNameCompressionParseBytes(m, lhs, lhs_len, rhs, rhs_len, rr);
- else
- return mStatus_Incompatible;
-}
-
-mDNSlocal void xD2DAddToCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
-{
- if (result == kD2DSuccess)
- {
- if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DAddToCache: NULL Byte * passed in or length == 0"); return; }
-
- mStatus err;
- D2DRecordListElem *ptr = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData)));
-
- if (ptr == NULL) { LogMsg("xD2DAddToCache: memory allocation failure"); return; }
-
- err = xD2DParse(m, (const mDNSu8 * const)key, (const mDNSu16)keySize, (const mDNSu8 * const)value, (const mDNSu16)valueSize, &ptr->ar);
- if (err)
- {
- LogMsg("xD2DAddToCache: xD2DParse returned error: %d", err);
- PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
- mDNSPlatformMemFree(ptr);
- return;
- }
- err = mDNS_Register(m, &ptr->ar);
- if (err)
- {
- LogMsg("xD2DAddToCache: mDNS_Register returned error %d for %s", err, ARDisplayString(m, &ptr->ar));
- mDNSPlatformMemFree(ptr);
- return;
- }
-
- LogInfo("xD2DAddToCache: mDNS_Register succeeded for %s", ARDisplayString(m, &ptr->ar));
- ptr->instanceHandle = instanceHandle;
- ptr->transportType = transportType;
- ptr->next = D2DRecords;
- D2DRecords = ptr;
- }
- else
- LogMsg("xD2DAddToCache: Unexpected result %d", result);
-}
-
-mDNSlocal D2DRecordListElem * xD2DFindInList(mDNS *const m, const Byte *const key, const size_t keySize, const Byte *const value, const size_t valueSize)
-{
- D2DRecordListElem *ptr = D2DRecords;
- D2DRecordListElem *arptr;
-
- if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DFindInList: NULL Byte * passed in or length == 0"); return NULL; }
-
- arptr = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData)));
- if (arptr == NULL) { LogMsg("xD2DFindInList: memory allocation failure"); return NULL; }
-
- if (xD2DParse(m, (const mDNSu8 *const)key, (const mDNSu16)keySize, (const mDNSu8 *const)value, (const mDNSu16)valueSize, &arptr->ar) != mStatus_NoError)
- {
- LogMsg("xD2DFindInList: xD2DParse failed for key: %p (%u) value: %p (%u)", key, keySize, value, valueSize);
- mDNSPlatformMemFree(arptr);
- return NULL;
- }
-
- while (ptr)
- {
- if (IdenticalResourceRecord(&arptr->ar.resrec, &ptr->ar.resrec)) break;
- ptr = ptr->next;
- }
-
- if (!ptr) LogMsg("xD2DFindInList: Could not find in D2DRecords: %s", ARDisplayString(m, &arptr->ar));
- mDNSPlatformMemFree(arptr);
- return ptr;
-}
-
-mDNSlocal void xD2DRemoveFromCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
-{
- (void)transportType; // We don't care about this, yet.
- (void)instanceHandle; // We don't care about this, yet.
-
- if (result == kD2DSuccess)
- {
- D2DRecordListElem *ptr = xD2DFindInList(m, key, keySize, value, valueSize);
- if (ptr)
- {
- LogInfo("xD2DRemoveFromCache: Remove from cache: %s", ARDisplayString(m, &ptr->ar));
- mDNS_Deregister(m, &ptr->ar);
- }
- }
- else
- LogMsg("xD2DRemoveFromCache: Unexpected result %d", result);
-}
-
-mDNSlocal void xD2DServiceResolved(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
-{
- (void)m;
- (void)key;
- (void)keySize;
- (void)value;
- (void)valueSize;
-
- if (result == kD2DSuccess)
- {
- LogInfo("xD2DServiceResolved: Starting up PAN connection for %p", instanceHandle);
- if (D2DRetain) D2DRetain(instanceHandle, transportType);
- }
- else LogMsg("xD2DServiceResolved: Unexpected result %d", result);
-}
-
-mDNSlocal void xD2DRetainHappened(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
-{
- (void)m;
- (void)instanceHandle;
- (void)transportType;
- (void)key;
- (void)keySize;
- (void)value;
- (void)valueSize;
-
- if (result == kD2DSuccess) LogInfo("xD2DRetainHappened: Opening up PAN connection for %p", instanceHandle);
- else LogMsg("xD2DRetainHappened: Unexpected result %d", result);
-}
-
-mDNSlocal void xD2DReleaseHappened(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
-{
- (void)m;
- (void)instanceHandle;
- (void)transportType;
- (void)key;
- (void)keySize;
- (void)value;
- (void)valueSize;
-
- if (result == kD2DSuccess) LogInfo("xD2DReleaseHappened: Closing PAN connection for %p", instanceHandle);
- else LogMsg("xD2DReleaseHappened: Unexpected result %d", result);
-}
-
-mDNSlocal void xD2DServiceCallback(D2DServiceEvent event, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize, void *userData)
-{
- mDNS *m = (mDNS *) userData;
- const char *eventString = "unknown";
-
- KQueueLock(m);
-
- if (keySize > 0xFFFF) LogMsg("xD2DServiceCallback: keySize too large: %u", keySize);
- if (valueSize > 0xFFFF) LogMsg("xD2DServiceCallback: valueSize too large: %u", valueSize);
-
- switch (event)
- {
- case D2DServiceFound:
- eventString = "D2DServiceFound";
- break;
- case D2DServiceLost:
- eventString = "D2DServiceLost";
- break;
- case D2DServiceResolved:
- eventString = "D2DServiceResolved";
- break;
- case D2DServiceRetained:
- eventString = "D2DServiceRetained";
- break;
- case D2DServiceReleased:
- eventString = "D2DServiceReleased";
- break;
- default:
- break;
- }
-
- LogInfo("xD2DServiceCallback: event=%s result=%d instanceHandle=%p transportType=%d LHS=%p (%u) RHS=%p (%u) userData=%p", eventString, result, instanceHandle, transportType, key, keySize, value, valueSize, userData);
- PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
-
- switch (event)
- {
- case D2DServiceFound:
- xD2DAddToCache(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
- break;
- case D2DServiceLost:
- xD2DRemoveFromCache(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
- break;
- case D2DServiceResolved:
- xD2DServiceResolved(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
- break;
- case D2DServiceRetained:
- xD2DRetainHappened(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
- break;
- case D2DServiceReleased:
- xD2DReleaseHappened(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
- break;
- default:
- break;
- }
-
- // Need to tickle the main kqueue loop to potentially handle records we removed or added.
- KQueueUnlock(m, "xD2DServiceCallback");
-}
-
-// Map interface index and flags to a specific D2D transport type or D2DTransportMax if all plugins
-// should be called.
-// When D2DTransportMax is returned, if a specific transport should not be called, *excludedTransportType
-// will be set to the excluded transport value, otherwise, it will be set to D2DTransportMax.
-// If the return value is not D2DTransportMax, excludedTransportType is undefined.
-
-mDNSlocal D2DTransportType xD2DInterfaceToTransportType(mDNSInterfaceID InterfaceID, DNSServiceFlags flags, D2DTransportType * excludedTransportType)
-{
- NetworkInterfaceInfoOSX *info;
-
- // Default exludes the D2DAWDLTransport when D2DTransportMax is returned.
- *excludedTransportType = D2DAWDLTransport;
-
- // Call all D2D plugins when both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set.
- if ((flags & kDNSServiceFlagsIncludeP2P) && (flags & kDNSServiceFlagsIncludeAWDL))
- {
- LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (including AWDL) since both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set");
- *excludedTransportType = D2DTransportMax;
- return D2DTransportMax;
- }
- // Call all D2D plugins (exlcluding AWDL) when only kDNSServiceFlagsIncludeP2P is set.
- else if (flags & kDNSServiceFlagsIncludeP2P)
- {
- LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) since only kDNSServiceFlagsIncludeP2P is set");
- return D2DTransportMax;
- }
- // Call AWDL D2D plugin when only kDNSServiceFlagsIncludeAWDL is set.
- else if (flags & kDNSServiceFlagsIncludeAWDL)
- {
- LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport since only kDNSServiceFlagsIncludeAWDL is set");
- return D2DAWDLTransport;
- }
-
- if (InterfaceID == mDNSInterface_P2P)
- {
- LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) for interface index mDNSInterface_P2P");
- return D2DTransportMax;
- }
-
- // Compare to cached AWDL interface ID.
- if (AWDLInterfaceID && (InterfaceID == AWDLInterfaceID))
- {
- LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport for interface index %d", InterfaceID);
- return D2DAWDLTransport;
- }
-
- info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
- if (info == NULL)
- {
- LogInfo("xD2DInterfaceToTransportType: Invalid interface index %d", InterfaceID);
- return D2DTransportMax;
- }
-
- // Recognize AirDrop specific p2p* interface based on interface name.
- if (strncmp(info->ifinfo.ifname, "p2p", 3) == 0)
- {
- LogInfo("xD2DInterfaceToTransportType: returning D2DWifiPeerToPeerTransport for interface index %d", InterfaceID);
- return D2DWifiPeerToPeerTransport;
- }
-
- // Currently there is no way to identify Bluetooth interface by name,
- // since they use "en*" based name strings.
-
- LogInfo("xD2DInterfaceToTransportType: returning default D2DTransportMax for interface index %d", InterfaceID);
- return D2DTransportMax;
-}
-
-mDNSexport void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags)
-{
- domainname lower;
-
- if (qtype == kDNSServiceType_A || qtype == kDNSServiceType_AAAA)
- {
- LogInfo("external_start_browsing_for_service: ignoring address record");
- return;
- }
-
- DomainnameToLower(typeDomain, &lower);
-
- if (!D2DBrowseListRefCount(&lower, qtype))
- {
- D2DTransportType transportType, excludedTransport;
-
- LogInfo("external_start_browsing_for_service: Starting browse for: %##s %s", lower.c, DNSTypeName(qtype));
- mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype);
- PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0);
-
- transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
- if (transportType == D2DTransportMax)
- {
- D2DTransportType i;
- for (i = 0; i < D2DTransportMax; i++)
- {
- if (i == excludedTransport) continue;
- if (D2DStartBrowsingForKeyOnTransport) D2DStartBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, i);
- }
- }
- else
- {
- if (D2DStartBrowsingForKeyOnTransport) D2DStartBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, transportType);
- }
- }
- D2DBrowseListRetain(&lower, qtype);
-}
-
-mDNSexport void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags)
-{
- domainname lower;
-
- if (qtype == kDNSServiceType_A || qtype == kDNSServiceType_AAAA)
- {
- LogInfo("external_stop_browsing_for_service: ignoring address record");
- return;
- }
-
- DomainnameToLower(typeDomain, &lower);
-
- D2DBrowseListRelease(&lower, qtype);
- if (!D2DBrowseListRefCount(&lower, qtype))
- {
- D2DTransportType transportType, excludedTransport;
-
- LogInfo("external_stop_browsing_for_service: Stopping browse for: %##s %s", lower.c, DNSTypeName(qtype));
- mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype);
- PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0);
-
- transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
- if (transportType == D2DTransportMax)
- {
- D2DTransportType i;
- for (i = 0; i < D2DTransportMax; i++)
- {
- if (i == excludedTransport) continue;
- if (D2DStopBrowsingForKeyOnTransport) D2DStopBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, i);
- }
- }
- else
- {
- if (D2DStopBrowsingForKeyOnTransport) D2DStopBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, transportType);
- }
-
- // The D2D driver may not generate the D2DServiceLost event for this key after
- // the D2DStopBrowsingForKey*() call above. So, we flush the key from the D2D
- // record cache now.
- xD2DClearCache(&lower, qtype);
- }
-}
-
-mDNSexport void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags)
-{
- domainname lower;
- mDNSu8 *rhs = NULL;
- mDNSu8 *end = NULL;
- D2DTransportType transportType, excludedTransport;
- DomainnameToLower(resourceRecord->name, &lower);
-
- LogInfo("external_start_advertising_service: %s", RRDisplayString(&mDNSStorage, resourceRecord));
- // For SRV records, update packet filter if p2p interface already exists, otherwise,
- // if will be updated when we get the KEV_DL_IF_ATTACHED event for the interface.
- if (resourceRecord->rrtype == kDNSType_SRV)
- mDNSUpdatePacketFilter(NULL);
-
- rhs = DNSNameCompressionBuildLHS(&lower, resourceRecord->rrtype);
- end = DNSNameCompressionBuildRHS(rhs, resourceRecord);
- PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
-
- transportType = xD2DInterfaceToTransportType(resourceRecord->InterfaceID, flags, & excludedTransport);
- if (transportType == D2DTransportMax)
- {
- D2DTransportType i;
- for (i = 0; i < D2DTransportMax; i++)
- {
- if (i == excludedTransport) continue;
- if (D2DStartAdvertisingPairOnTransport) D2DStartAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
- }
- }
- else
- {
- if (D2DStartAdvertisingPairOnTransport) D2DStartAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
- }
-}
-
-mDNSexport void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags)
-{
- domainname lower;
- mDNSu8 *rhs = NULL;
- mDNSu8 *end = NULL;
- D2DTransportType transportType, excludedTransport;
- DomainnameToLower(resourceRecord->name, &lower);
-
- LogInfo("external_stop_advertising_service: %s", RRDisplayString(&mDNSStorage, resourceRecord));
-
- // For SRV records, update packet filter to to remove this port from list
- if (resourceRecord->rrtype == kDNSType_SRV)
- mDNSUpdatePacketFilter(resourceRecord);
-
- rhs = DNSNameCompressionBuildLHS(&lower, resourceRecord->rrtype);
- end = DNSNameCompressionBuildRHS(rhs, resourceRecord);
- PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
-
- transportType = xD2DInterfaceToTransportType(resourceRecord->InterfaceID, flags, & excludedTransport);
- if (transportType == D2DTransportMax)
- {
- D2DTransportType i;
- for (i = 0; i < D2DTransportMax; i++)
- {
- if (i == excludedTransport) continue;
- if (D2DStopAdvertisingPairOnTransport) D2DStopAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
- }
- }
- else
- {
- if (D2DStopAdvertisingPairOnTransport) D2DStopAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
- }
-}
-
-mDNSexport void external_start_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags)
-{
- domainname lower;
- mDNSu8 *rhs = NULL;
- mDNSu8 *end = NULL;
- mDNSBool AWDL_used = false; // whether AWDL was used for this resolve
- D2DTransportType transportType, excludedTransport;
- DomainnameToLower(SkipLeadingLabels(fqdn, 1), &lower);
-
- LogInfo("external_start_resolving_service: %##s", fqdn->c);
- rhs = DNSNameCompressionBuildLHS(&lower, kDNSType_PTR);
- end = putDomainNameAsLabels(&compression_base_msg, rhs, compression_limit, fqdn);
- PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
-
- transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
- if (transportType == D2DTransportMax)
- {
- // Resolving over all the transports, except for excludedTransport if set.
- D2DTransportType i;
- for (i = 0; i < D2DTransportMax; i++)
- {
- if (i == excludedTransport) continue;
- if (D2DStartResolvingPairOnTransport) D2DStartResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
-
- if (i == D2DAWDLTransport)
- AWDL_used = true;
- }
- }
- else
- {
- // Resolving over one specific transport.
- if (D2DStartResolvingPairOnTransport) D2DStartResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
-
- if (transportType == D2DAWDLTransport)
- AWDL_used = true;
- }
-
- // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
- // We only want these records going to AWDL, so use AWDLInterfaceID as the
- // interface and don't set any other flags.
- if (AWDL_used && AWDLInterfaceID)
- {
- LogInfo("external_start_resolving_service: browse for TXT and SRV over AWDL");
- external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_TXT, NULL);
- external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, NULL);
- }
-}
-
-mDNSexport void external_stop_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags)
-{
- domainname lower;
- mDNSu8 *rhs = NULL;
- mDNSu8 *end = NULL;
- mDNSBool AWDL_used = false; // whether AWDL was used for this resolve
- D2DTransportType transportType, excludedTransport;
- DomainnameToLower(SkipLeadingLabels(fqdn, 1), &lower);
-
- LogInfo("external_stop_resolving_service: %##s", fqdn->c);
- rhs = DNSNameCompressionBuildLHS(&lower, kDNSType_PTR);
- end = putDomainNameAsLabels(&compression_base_msg, rhs, compression_limit, fqdn);
- PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
-
- transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
- if (transportType == D2DTransportMax)
- {
- D2DTransportType i;
- for (i = 0; i < D2DTransportMax; i++)
- {
- if (i == excludedTransport) continue;
- if (D2DStopResolvingPairOnTransport) D2DStopResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
-
- if (i == D2DAWDLTransport)
- AWDL_used = true;
- }
- }
- else
- {
- if (D2DStopResolvingPairOnTransport) D2DStopResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
-
- if (transportType == D2DAWDLTransport)
- AWDL_used = true;
- }
-
- // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
- // We only want these records going to AWDL, so use AWDLInterfaceID as the
- // interface and don't set any other flags.
- if (AWDL_used && AWDLInterfaceID)
- {
- LogInfo("external_stop_resolving_service: stop browse for TXT and SRV on AWDL");
- external_stop_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_TXT, NULL);
- external_stop_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, NULL);
- }
-}
-
-#elif APPLE_OSX_mDNSResponder
-
-mDNSexport void external_start_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags) { (void)m; (void)type; (void)qtype; (void)flags;}
-mDNSexport void external_stop_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags) { (void)m; (void)type; (void)qtype; (void)flags;}
-mDNSexport void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;}
-mDNSexport void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;}
-mDNSexport void external_start_resolving_service(const domainname *const fqdn, DNSServiceFlags flags) { (void)fqdn; (void)flags;}
-mDNSexport void external_stop_resolving_service(const domainname *const fqdn, DNSServiceFlags flags) { (void)fqdn; (void)flags;}
-
-#endif // ! NO_D2D
-
-// ***************************************************************************
-// Functions
-
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - Utility Functions
-#endif
-
-// We only attempt to send and receive multicast packets on interfaces that are
-// (a) flagged as multicast-capable
-// (b) *not* flagged as point-to-point (e.g. modem)
-// Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
-// to run up the user's bill sending multicast traffic over a link where there's only a single device at the
-// other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
-#define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
-
-mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both strings are UTF-8 text
-{
- static int notifyCount = 0;
- if (notifyCount) return;
-
- // If we display our alert early in the boot process, then it vanishes once the desktop appears.
- // To avoid this, we don't try to display alerts in the first three minutes after boot.
- if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return;
-
- // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
- #if !ForceAlerts
- {
- // Determine if we're at Apple (17.*.*.*)
- NetworkInterfaceInfoOSX *i;
- for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
- if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && i->ifinfo.ip.ip.v4.b[0] == 17)
- break;
- if (!i) return; // If not at Apple, don't show the alert
- }
- #endif
-
- LogMsg("%s", title);
- LogMsg("%s", msg);
- // Display a notification to the user
- notifyCount++;
-
-#ifndef NO_CFUSERNOTIFICATION
- mDNSNotify(title, msg);
-#endif /* NO_CFUSERNOTIFICATION */
-}
-
-// Returns true if it is an AppleTV based hardware running iOS, false otherwise
-mDNSlocal mDNSBool IsAppleTV(void)
-{
-#if TARGET_OS_EMBEDDED
- static mDNSBool sInitialized = mDNSfalse;
- static mDNSBool sIsAppleTV = mDNSfalse;
- CFStringRef deviceClass = NULL;
-
- if(!sInitialized)
- {
- deviceClass = (CFStringRef) MGCopyAnswer(kMGQDeviceClass, NULL);
- if(deviceClass)
- {
- if(CFEqual(deviceClass, kMGDeviceClassAppleTV))
- sIsAppleTV = mDNStrue;
- CFRelease(deviceClass);
- }
- sInitialized = mDNStrue;
- }
- return(sIsAppleTV);
-#else
- return mDNSfalse;
-#endif // TARGET_OS_EMBEDDED
-}
-
-mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh)
-{
- static struct ifaddrs *ifa = NULL;
-
- if (refresh && ifa)
- {
- freeifaddrs(ifa);
- ifa = NULL;
- }
-
- if (ifa == NULL)
- getifaddrs(&ifa);
- return ifa;
-}
-
-mDNSlocal void DynamicStoreWrite(int key, const char* subkey, uintptr_t value, signed long valueCnt)
-{
- CFStringRef sckey = NULL;
- Boolean release_sckey = FALSE;
- CFDataRef bytes = NULL;
- CFPropertyListRef plist = NULL;
- SCDynamicStoreRef store = NULL;
-
- switch ((enum mDNSDynamicStoreSetConfigKey)key)
- {
- case kmDNSMulticastConfig:
- sckey = CFSTR("State:/Network/" kDNSServiceCompMulticastDNS);
- break;
- case kmDNSDynamicConfig:
- sckey = CFSTR("State:/Network/DynamicDNS");
- break;
- case kmDNSPrivateConfig:
- sckey = CFSTR("State:/Network/" kDNSServiceCompPrivateDNS);
- break;
- case kmDNSBackToMyMacConfig:
- sckey = CFSTR("State:/Network/BackToMyMac");
- break;
- case kmDNSSleepProxyServersState:
- {
- CFMutableStringRef tmp = CFStringCreateMutable(kCFAllocatorDefault, 0);
- CFStringAppend(tmp, CFSTR("State:/Network/Interface/"));
- CFStringAppendCString(tmp, subkey, kCFStringEncodingUTF8);
- CFStringAppend(tmp, CFSTR("/SleepProxyServers"));
- sckey = CFStringCreateCopy(kCFAllocatorDefault, tmp);
- release_sckey = TRUE;
- CFRelease(tmp);
- break;
- }
- case kmDNSDebugState:
- sckey = CFSTR("State:/Network/mDNSResponder/DebugState");
- break;
- default:
- LogMsg("unrecognized key %d", key);
- goto fin;
- }
- if (NULL == (bytes = CFDataCreateWithBytesNoCopy(NULL, (void *)value,
- valueCnt, kCFAllocatorNull)))
- {
- LogMsg("CFDataCreateWithBytesNoCopy of value failed");
- goto fin;
- }
- if (NULL == (plist = CFPropertyListCreateFromXMLData(NULL, bytes,
- kCFPropertyListImmutable, NULL)))
- {
- LogMsg("CFPropertyListCreateFromXMLData of bytes failed");
- goto fin;
- }
- CFRelease(bytes);
- bytes = NULL;
- if (NULL == (store = SCDynamicStoreCreate(NULL,
- CFSTR(kmDNSResponderServName), NULL, NULL)))
- {
- LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
- goto fin;
- }
- SCDynamicStoreSetValue(store, sckey, plist);
-
-fin:
- if (NULL != bytes)
- CFRelease(bytes);
- if (NULL != plist)
- CFRelease(plist);
- if (NULL != store)
- CFRelease(store);
- if (release_sckey && sckey)
- CFRelease(sckey);
-}
-
-mDNSexport void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropertyListRef value)
-{
- CFPropertyListRef valueCopy;
- char *subkeyCopy = NULL;
- if (!value)
- return;
-
- // We need to copy the key and value before we dispatch off the block below as the
- // caller will free the memory once we return from this function.
- valueCopy = CFPropertyListCreateDeepCopy(NULL, value, kCFPropertyListImmutable);
- if (!valueCopy)
- {
- LogMsg("mDNSDynamicStoreSetConfig: ERROR valueCopy NULL");
- return;
- }
- if (subkey)
- {
- int len = strlen(subkey);
- subkeyCopy = mDNSPlatformMemAllocate(len + 1);
- if (!subkeyCopy)
- {
- LogMsg("mDNSDynamicStoreSetConfig: ERROR subkeyCopy NULL");
- return;
- }
- mDNSPlatformMemCopy(subkeyCopy, subkey, len);
- subkeyCopy[len] = 0;
- }
-
- dispatch_async(DynamicStoreQueue, ^{
- CFWriteStreamRef stream = NULL;
- CFDataRef bytes = NULL;
- CFStringRef error;
- CFIndex ret;
-
- if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(NULL, NULL)))
- {
- LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCreateWithAllocatedBuffers failed (Object creation failed)");
- goto END;
- }
- CFWriteStreamOpen(stream);
- ret = CFPropertyListWriteToStream(valueCopy, stream, kCFPropertyListBinaryFormat_v1_0, &error);
- if (ret == 0)
- {
- LogMsg("mDNSDynamicStoreSetConfig : CFPropertyListWriteToStream failed (Could not write property list to stream)");
- goto END;
- }
- if (NULL == (bytes = CFWriteStreamCopyProperty(stream, kCFStreamPropertyDataWritten)))
- {
- LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCopyProperty failed (Object creation failed) ");
- goto END;
- }
- CFWriteStreamClose(stream);
- CFRelease(stream);
- stream = NULL;
- LogInfo("mDNSDynamicStoreSetConfig: key %d subkey %s", key, subkeyCopy);
- DynamicStoreWrite(key, subkeyCopy ? subkeyCopy : "", (uintptr_t)CFDataGetBytePtr(bytes), CFDataGetLength(bytes));
-
- END:
- CFRelease(valueCopy);
- if (NULL != stream)
- {
- CFWriteStreamClose(stream);
- CFRelease(stream);
- }
- if (NULL != bytes)
- CFRelease(bytes);
- if (subkeyCopy)
- mDNSPlatformMemFree(subkeyCopy);
- });
-}
-
-// To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type
-mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, const char *ifname, int type)
-{
- NetworkInterfaceInfoOSX *i;
- for (i = m->p->InterfaceList; i; i = i->next)
- if (i->Exists && !strcmp(i->ifinfo.ifname, ifname) &&
- ((type == AF_UNSPEC ) ||
- (type == AF_INET && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
- (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i);
- return(NULL);
-}
-
-#if TARGET_OS_EMBEDDED
-mDNSlocal SCPreferencesRef mDNSManagedPrefsGet(void)
-{
- SCPreferencesRef smDNSManagedPrefs = NULL;
- smDNSManagedPrefs = SCPreferencesCreate(kCFAllocatorDefault, CFSTR("mDNSManagedPrefs"), kmDNSResponderManagedPrefsID);
-
- return (smDNSManagedPrefs);
-}
-
-mDNSlocal mDNSBool GetmDNSManagedPrefKeyVal(SCPreferencesRef prefs, CFStringRef key)
-{
- mDNSBool val = mDNSfalse;
- CFBooleanRef val_cf = NULL;
-
- if (prefs != NULL)
- {
- val_cf = SCPreferencesGetValue(prefs, key);
- if (isA_CFBoolean(val_cf) != NULL)
- val = CFBooleanGetValue(val_cf); //When mDNSResponder-Debug-profile is Installed
- else
- val = mDNSfalse; //When mDNSResponder-Debug-profile is Uninstalled
- }
- else
- {
- LogMsg("GetmDNSManagedPrefKeyVal: mDNSManagedPrefs are NULL!");
- val = mDNSfalse;
- }
- if (val_cf)
- CFRelease(val_cf);
- return (val);
-}
-
-mDNSexport mDNSBool GetmDNSManagedPref(CFStringRef key)
-{
- SCPreferencesRef managed = NULL;
- mDNSBool ret_value;
-
- managed = mDNSManagedPrefsGet();
- ret_value = GetmDNSManagedPrefKeyVal(managed, key);
-
- if (managed)
- CFRelease(managed);
- return (ret_value);
-}
-#endif //TARGET_OS_EMBEDDED
-
-mDNSlocal int myIfIndexToName(u_short ifindex, char *name)
-{
- struct ifaddrs *ifa;
- for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
- if (ifa->ifa_addr->sa_family == AF_LINK)
- if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == ifindex)
- { strlcpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
- return -1;
-}
-
-mDNSexport NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(const mDNS *const m, mDNSInterfaceID ifindex)
-{
- mDNSu32 scope_id = (mDNSu32)(uintptr_t)ifindex;
- NetworkInterfaceInfoOSX *i;
-
- // Don't get tricked by inactive interfaces
- for (i = m->p->InterfaceList; i; i = i->next)
- if (i->Registered && i->scope_id == scope_id) return(i);
-
- return mDNSNULL;
-}
-
-mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex)
-{
- if (ifindex == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
- if (ifindex == kDNSServiceInterfaceIndexP2P ) return(mDNSInterface_P2P);
- if (ifindex == kDNSServiceInterfaceIndexAny ) return(mDNSNULL);
-
- NetworkInterfaceInfoOSX* ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
- if (!ifi)
- {
- // Not found. Make sure our interface list is up to date, then try again.
- LogInfo("mDNSPlatformInterfaceIDfromInterfaceIndex: InterfaceID for interface index %d not found; Updating interface list", ifindex);
- mDNSMacOSXNetworkChanged(m);
- ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
- }
-
- if (!ifi) return(mDNSNULL);
-
- return(ifi->ifinfo.InterfaceID);
-}
-
-
-mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange)
-{
- NetworkInterfaceInfoOSX *i;
- if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
- if (id == mDNSInterface_P2P ) return(kDNSServiceInterfaceIndexP2P);
- if (id == mDNSInterface_Any ) return(0);
-
- mDNSu32 scope_id = (mDNSu32)(uintptr_t)id;
-
- // Don't use i->Registered here, because we DO want to find inactive interfaces, which have no Registered set
- for (i = m->p->InterfaceList; i; i = i->next)
- if (i->scope_id == scope_id) return(i->scope_id);
-
- // If we are supposed to suppress network change, return "id" back
- if (suppressNetworkChange) return scope_id;
-
- // Not found. Make sure our interface list is up to date, then try again.
- LogInfo("Interface index for InterfaceID %p not found; Updating interface list", id);
- mDNSMacOSXNetworkChanged(m);
- for (i = m->p->InterfaceList; i; i = i->next)
- if (i->scope_id == scope_id) return(i->scope_id);
-
- return(0);
-}
-
-#if APPLE_OSX_mDNSResponder
-mDNSexport void mDNSASLLog(uuid_t *uuid, const char *subdomain, const char *result, const char *signature, const char *fmt, ...)
-{
- if (iOSVers)
- return; // No ASL on iOS
-
- static char buffer[512];
- aslmsg asl_msg = asl_new(ASL_TYPE_MSG);
-
- if (!asl_msg) { LogMsg("mDNSASLLog: asl_new failed"); return; }
- if (uuid)
- {
- char uuidStr[37];
- uuid_unparse(*uuid, uuidStr);
- asl_set (asl_msg, "com.apple.message.uuid", uuidStr);
- }
-
- static char domainBase[] = "com.apple.mDNSResponder.%s";
- mDNS_snprintf (buffer, sizeof(buffer), domainBase, subdomain);
- asl_set (asl_msg, "com.apple.message.domain", buffer);
-
- if (result) asl_set(asl_msg, "com.apple.message.result", result);
- if (signature) asl_set(asl_msg, "com.apple.message.signature", signature);
-
- va_list ptr;
- va_start(ptr,fmt);
- mDNS_vsnprintf(buffer, sizeof(buffer), fmt, ptr);
- va_end(ptr);
-
- int old_filter = asl_set_filter(NULL,ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
- asl_log(NULL, asl_msg, ASL_LEVEL_DEBUG, "%s", buffer);
- asl_set_filter(NULL, old_filter);
- asl_free(asl_msg);
-}
-
-
-mDNSlocal void mDNSLogDNSSECStatistics(mDNS *const m)
-{
- char buffer[16];
-
- aslmsg aslmsg = asl_new(ASL_TYPE_MSG);
-
- // If we failed to allocate an aslmsg structure, keep accumulating
- // the statistics and try again at the next log interval.
- if (!aslmsg)
- {
- LogMsg("mDNSLogDNSSECStatistics: asl_new() failed!");
- return;
- }
-
- asl_set(aslmsg,"com.apple.message.domain", "com.apple.mDNSResponder.DNSSECstatistics");
-
- if (m->rrcache_totalused_unicast)
- {
- mDNS_snprintf(buffer, sizeof(buffer), "%u", (mDNSu32) ((unsigned long)(m->DNSSECStats.TotalMemUsed * 100))/m->rrcache_totalused_unicast);
- }
- else
- {
- LogMsg("mDNSLogDNSSECStatistics: unicast is zero");
- buffer[0] = 0;
- }
- asl_set(aslmsg,"com.apple.message.MemUsage", buffer);
-
- mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency0);
- asl_set(aslmsg,"com.apple.message.Latency0", buffer);
- mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency10);
- asl_set(aslmsg,"com.apple.message.Latency10", buffer);
- mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency20);
- asl_set(aslmsg,"com.apple.message.Latency20", buffer);
- mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency50);
- asl_set(aslmsg,"com.apple.message.Latency50", buffer);
- mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency100);
- asl_set(aslmsg,"com.apple.message.Latency100", buffer);
-
- mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets0);
- asl_set(aslmsg,"com.apple.message.ExtraPackets0", buffer);
- mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets3);
- asl_set(aslmsg,"com.apple.message.ExtraPackets3", buffer);
- mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets7);
- asl_set(aslmsg,"com.apple.message.ExtraPackets7", buffer);
- mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets10);
- asl_set(aslmsg,"com.apple.message.ExtraPackets10", buffer);
-
- // Ignore IndeterminateStatus as we don't log them
- mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.SecureStatus);
- asl_set(aslmsg,"com.apple.message.SecureStatus", buffer);
- mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.InsecureStatus);
- asl_set(aslmsg,"com.apple.message.InsecureStatus", buffer);
- mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.BogusStatus);
- asl_set(aslmsg,"com.apple.message.BogusStatus", buffer);
- mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.NoResponseStatus);
- asl_set(aslmsg,"com.apple.message.NoResponseStatus", buffer);
-
- mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.NumProbesSent);
- asl_set(aslmsg,"com.apple.message.NumProbesSent", buffer);
- mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.MsgSize0);
- asl_set(aslmsg,"com.apple.message.MsgSize0", buffer);
- mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.MsgSize1);
- asl_set(aslmsg,"com.apple.message.MsgSize1", buffer);
- mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.MsgSize2);
- asl_set(aslmsg,"com.apple.message.MsgSize2", buffer);
-
- asl_log(NULL, aslmsg, ASL_LEVEL_NOTICE, "");
- asl_free(aslmsg);
-}
-
-// Calculate packets per hour given total packet count and interval in seconds.
-// Cast one term of multiplication to (long) to use 64-bit arithmetic
-// and avoid a potential 32-bit overflow prior to the division.
-#define ONE_HOUR 3600
-#define PACKET_RATE(PACKETS, INTERVAL) (int)(((long) (PACKETS) * ONE_HOUR)/(INTERVAL))
-
-// Put packet rate data in discrete buckets.
-mDNSlocal int mDNSBucketData(int inputData, int interval)
-{
- if (!interval)
- {
- LogMsg("mDNSBucketData: interval is zero!");
- return 0;
- }
-
- int ratePerHour = PACKET_RATE(inputData, interval);
- int bucket;
-
- if (ratePerHour == 0)
- bucket = 0;
- else if (ratePerHour <= 10)
- bucket = 10;
- else if (ratePerHour <= 100)
- bucket = 100;
- else if (ratePerHour <= 1000)
- bucket = 1000;
- else if (ratePerHour <= 5000)
- bucket = 5000;
- else if (ratePerHour <= 10000)
- bucket = 10000;
- else if (ratePerHour <= 50000)
- bucket = 50000;
- else if (ratePerHour <= 100000)
- bucket = 100000;
- else if (ratePerHour <= 250000)
- bucket = 250000;
- else if (ratePerHour <= 500000)
- bucket = 500000;
- else
- bucket = 1000000;
-
- return bucket;
-}
-
-mDNSlocal void mDNSLogBonjourStatistics(mDNS *const m)
-{
- static mDNSs32 last_PktNum, last_MPktNum;
- static mDNSs32 last_UnicastPacketsSent, last_MulticastPacketsSent;
- static mDNSs32 last_RemoteSubnet;
-
- mDNSs32 interval;
- char buffer[16];
- mDNSs32 inMulticast = m->MPktNum - last_MPktNum;
- mDNSs32 inUnicast = m->PktNum - last_PktNum - inMulticast;
- mDNSs32 outUnicast = m->UnicastPacketsSent - last_UnicastPacketsSent;
- mDNSs32 outMulticast = m->MulticastPacketsSent - last_MulticastPacketsSent;
- mDNSs32 remoteSubnet = m->RemoteSubnet - last_RemoteSubnet;
-
-
- // save starting values for new interval
- last_PktNum = m->PktNum;
- last_MPktNum = m->MPktNum;
- last_UnicastPacketsSent = m->UnicastPacketsSent;
- last_MulticastPacketsSent = m->MulticastPacketsSent;
- last_RemoteSubnet = m->RemoteSubnet;
-
- // Need a non-zero active time interval.
- if (!m->ActiveStatTime)
- return;
-
- // Round interval time to nearest hour boundary. Less then 30 minutes rounds to zero.
- interval = (m->ActiveStatTime + ONE_HOUR/2)/ONE_HOUR;
-
- // Use a minimum of 30 minutes of awake time to calculate average packet rates.
- // The rounded awake interval should not be greater than the rounded reporting
- // interval.
- if ((interval == 0) || (interval > (kDefaultNextStatsticsLogTime + ONE_HOUR/2)/ONE_HOUR))
- return;
-
- aslmsg aslmsg = asl_new(ASL_TYPE_MSG);
-
- if (!aslmsg)
- {
- LogMsg("mDNSLogBonjourStatistics: asl_new() failed!");
- return;
- }
- // log in MessageTracer format
- asl_set(aslmsg,"com.apple.message.domain", "com.apple.mDNSResponder.statistics");
-
- snprintf(buffer, sizeof(buffer), "%d", interval);
- asl_set(aslmsg,"com.apple.message.interval", buffer);
-
- // log the packet rates as packets per hour
- snprintf(buffer, sizeof(buffer), "%d",
- mDNSBucketData(inUnicast, m->ActiveStatTime));
- asl_set(aslmsg,"com.apple.message.UnicastIn", buffer);
-
- snprintf(buffer, sizeof(buffer), "%d",
- mDNSBucketData(inMulticast, m->ActiveStatTime));
- asl_set(aslmsg,"com.apple.message.MulticastIn", buffer);
-
- snprintf(buffer, sizeof(buffer), "%d",
- mDNSBucketData(outUnicast, m->ActiveStatTime));
- asl_set(aslmsg,"com.apple.message.UnicastOut", buffer);
-
- snprintf(buffer, sizeof(buffer), "%d",
- mDNSBucketData(outMulticast, m->ActiveStatTime));
- asl_set(aslmsg,"com.apple.message.MulticastOut", buffer);
-
- snprintf(buffer, sizeof(buffer), "%d",
- mDNSBucketData(remoteSubnet, m->ActiveStatTime));
- asl_set(aslmsg,"com.apple.message.RemoteSubnet", buffer);
-
- asl_log(NULL, aslmsg, ASL_LEVEL_NOTICE, "");
-
- asl_free(aslmsg);
-}
-
-// Log multicast and unicast traffic statistics to MessageTracer on OSX
-mDNSexport void mDNSLogStatistics(mDNS *const m)
-{
- // MessageTracer only available on OSX
- if (iOSVers)
- return;
-
- mDNSs32 currentUTC = mDNSPlatformUTC();
-
- // log runtime statistics
- if ((currentUTC - m->NextStatLogTime) >= 0)
- {
- m->NextStatLogTime = currentUTC + kDefaultNextStatsticsLogTime;
- // If StatStartTime is zero, it hasn't been reinitialized yet
- // in the wakeup code path.
- if (m->StatStartTime)
- {
- m->ActiveStatTime += currentUTC - m->StatStartTime;
- }
-
- // Only log statistics if we have recorded some active time during
- // this statistics interval.
- if (m->ActiveStatTime)
- {
- mDNSLogBonjourStatistics(m);
- mDNSLogDNSSECStatistics(m);
- }
-
- // Start a new statistics gathering interval.
- m->StatStartTime = currentUTC;
- m->ActiveStatTime = 0;
- }
-}
-
-#endif // APPLE_OSX_mDNSResponder
-
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - UDP & TCP send & receive
-#endif
-
-mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
-{
- mDNSBool result = mDNSfalse;
- SCNetworkConnectionFlags flags;
- CFDataRef remote_addr;
- CFMutableDictionaryRef options;
- SCNetworkReachabilityRef ReachRef = NULL;
-
- options = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- remote_addr = CFDataCreate(NULL, (const UInt8 *)addr, addr->sa_len);
- CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, remote_addr);
- CFDictionarySetValue(options, kSCNetworkReachabilityOptionServerBypass, kCFBooleanTrue);
- ReachRef = SCNetworkReachabilityCreateWithOptions(kCFAllocatorDefault, options);
- CFRelease(options);
- CFRelease(remote_addr);
-
- if (!ReachRef)
- {
- LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithOptions");
- goto end;
- }
- if (!SCNetworkReachabilityGetFlags(ReachRef, &flags))
- {
- LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags");
- goto end;
- }
- result = flags & kSCNetworkFlagsConnectionRequired;
-
-end:
- if (ReachRef)
- CFRelease(ReachRef);
- return result;
-}
-
-// Set traffic class for socket
-mDNSlocal void setTrafficClass(int socketfd, mDNSBool useBackgroundTrafficClass)
-{
- int traffic_class;
-
- if (useBackgroundTrafficClass)
- traffic_class = SO_TC_BK_SYS;
- else
- traffic_class = SO_TC_CTL;
-
- (void) setsockopt(socketfd, SOL_SOCKET, SO_TRAFFIC_CLASS, (void *)&traffic_class, sizeof(traffic_class));
-}
-
-mDNSexport void mDNSPlatformSetDelegatePID(UDPSocket *src, const mDNSAddr *dst, DNSQuestion *q)
-{
- if (src)
- {
- int s;
-
- if (dst->type == mDNSAddrType_IPv4)
- {
- s = src->ss.sktv4;
- }
- else
- {
- s = src->ss.sktv6;
- }
-
- if (q->pid)
- {
- if (setsockopt(s, SOL_SOCKET, SO_DELEGATED, &q->pid, sizeof(q->pid)) == -1)
- {
- LogInfo("mDNSPlatformSetDelegatePID: Delegate PID failed %s for PID %d", strerror(errno), q->pid);
- }
- }
- else
- {
- if (setsockopt(s, SOL_SOCKET, SO_DELEGATED_UUID, &q->uuid, sizeof(q->uuid)) == -1)
- {
- LogInfo("mDNSPlatformSetDelegatePID: Delegate UUID failed %s", strerror(errno));
- }
- }
- }
-}
-
-// Note: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
-// Note: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
-// OR send via our primary v4 unicast socket
-// UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket
-mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
- mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
- mDNSIPPort dstPort, mDNSBool useBackgroundTrafficClass)
-{
- NetworkInterfaceInfoOSX *info = mDNSNULL;
- struct sockaddr_storage to;
- int s = -1, err;
- mStatus result = mStatus_NoError;
-
- if (InterfaceID)
- {
- info = IfindexToInterfaceInfoOSX(m, InterfaceID);
- if (info == NULL)
- {
- // We may not have registered interfaces with the "core" as we may not have
- // seen any interface notifications yet. This typically happens during wakeup
- // where we might try to send DNS requests (non-SuppressUnusable questions internal
- // to mDNSResponder) before we receive network notifications.
- LogInfo("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
- return mStatus_BadParamErr;
- }
- }
-
- char *ifa_name = InterfaceID ? info->ifinfo.ifname : "unicast";
-
- if (dst->type == mDNSAddrType_IPv4)
- {
- struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
- sin_to->sin_len = sizeof(*sin_to);
- sin_to->sin_family = AF_INET;
- sin_to->sin_port = dstPort.NotAnInteger;
- sin_to->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
- s = (src ? src->ss : m->p->permanentsockets).sktv4;
-
- if (info) // Specify outgoing interface
- {
- if (!mDNSAddrIsDNSMulticast(dst))
- {
- #ifdef IP_BOUND_IF
- if (info->scope_id == 0)
- LogInfo("IP_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info, ifa_name);
- else
- setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
- #else
- {
- static int displayed = 0;
- if (displayed < 1000)
- {
- displayed++;
- LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets");
- }
- }
- #endif
- }
- else
- #ifdef IP_MULTICAST_IFINDEX
- {
- err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IFINDEX, &info->scope_id, sizeof(info->scope_id));
- // We get an error when we compile on a machine that supports this option and run the binary on
- // a different machine that does not support it
- if (err < 0)
- {
- if (errno != ENOPROTOOPT) LogInfo("mDNSPlatformSendUDP: setsockopt: IP_MUTLTICAST_IFINDEX returned %d", errno);
- err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
- if (err < 0 && !m->p->NetworkChanged)
- LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
- }
- }
- #else
- {
- err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
- if (err < 0 && !m->p->NetworkChanged)
- LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
-
- }
- #endif
- }
- }
-
- else if (dst->type == mDNSAddrType_IPv6)
- {
- struct sockaddr_in6 *sin6_to = (struct sockaddr_in6*)&to;
- sin6_to->sin6_len = sizeof(*sin6_to);
- sin6_to->sin6_family = AF_INET6;
- sin6_to->sin6_port = dstPort.NotAnInteger;
- sin6_to->sin6_flowinfo = 0;
- sin6_to->sin6_addr = *(struct in6_addr*)&dst->ip.v6;
- sin6_to->sin6_scope_id = info ? info->scope_id : 0;
- s = (src ? src->ss : m->p->permanentsockets).sktv6;
- if (info && mDNSAddrIsDNSMulticast(dst)) // Specify outgoing interface
- {
- err = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &info->scope_id, sizeof(info->scope_id));
- if (err < 0)
- {
- char name[IFNAMSIZ];
- if (if_indextoname(info->scope_id, name) != NULL)
- LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err, errno, strerror(errno));
- else
- LogInfo("setsockopt - IPV6_MUTLICAST_IF scopeid %d, not a valid interface", info->scope_id);
- }
- }
- }
-
- else
- {
- LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
-#if ForceAlerts
- *(long*)0 = 0;
-#endif
- return mStatus_BadParamErr;
- }
-
- if (s >= 0)
- verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
- InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
- else
- verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
- InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort));
-
- // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
- // If we don't have the corresponding type of socket available, then return mStatus_Invalid
- if (s < 0) return(mStatus_Invalid);
-
- // switch to background traffic class for this message if requested
- if (useBackgroundTrafficClass)
- setTrafficClass(s, useBackgroundTrafficClass);
-
- err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
-
- // set traffic class back to default value
- if (useBackgroundTrafficClass)
- setTrafficClass(s, mDNSfalse);
-
- if (err < 0)
- {
- static int MessageCount = 0;
- // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
- if (!mDNSAddressIsAllDNSLinkGroup(dst))
- if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
- // Don't report EHOSTUNREACH in the first three minutes after boot
- // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
- // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
- if (errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(mStatus_TransientErr);
- // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
- if (errno == EADDRNOTAVAIL && m->p->NetworkChanged) return(mStatus_TransientErr);
- if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
- LogInfo("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
- s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
- else
- {
- MessageCount++;
- if (MessageCount < 50) // Cap and ensure NO spamming of LogMsgs
- LogMsg("mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu MessageCount is %d",
- s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow), MessageCount);
- else // If logging is enabled, remove the cap and log aggressively
- LogInfo("mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu MessageCount is %d",
- s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow), MessageCount);
- }
-
- result = mStatus_UnknownErr;
- }
-
-#ifdef IP_BOUND_IF
- if (dst->type == mDNSAddrType_IPv4 && info && !mDNSAddrIsDNSMulticast(dst))
- {
- static const mDNSu32 ifindex = 0;
- setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex));
- }
-#endif
-
- return(result);
-}
-
-mDNSexport ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
- struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char ifname[IF_NAMESIZE], mDNSu8 *ttl)
-{
- static unsigned int numLogMessages = 0;
- struct iovec databuffers = { (char *)buffer, max };
- struct msghdr msg;
- ssize_t n;
- struct cmsghdr *cmPtr;
- char ancillary[1024];
-
- *ttl = 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
-
- // Set up the message
- msg.msg_name = (caddr_t)from;
- msg.msg_namelen = *fromlen;
- msg.msg_iov = &databuffers;
- msg.msg_iovlen = 1;
- msg.msg_control = (caddr_t)&ancillary;
- msg.msg_controllen = sizeof(ancillary);
- msg.msg_flags = 0;
-
- // Receive the data
- n = recvmsg(s, &msg, 0);
- if (n<0)
- {
- if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
- return(-1);
- }
- if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
- {
- if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu, errno %d",
- s, n, msg.msg_controllen, sizeof(struct cmsghdr), errno);
- return(-1);
- }
- if (msg.msg_flags & MSG_CTRUNC)
- {
- if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
- return(-1);
- }
-
- *fromlen = msg.msg_namelen;
-
- // Parse each option out of the ancillary data.
- for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
- {
- // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
- if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
- {
- dstaddr->type = mDNSAddrType_IPv4;
- dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr);
- //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
- }
- if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
- {
- struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
- if (sdl->sdl_nlen < IF_NAMESIZE)
- {
- mDNSPlatformMemCopy(ifname, sdl->sdl_data, sdl->sdl_nlen);
- ifname[sdl->sdl_nlen] = 0;
- // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
- }
- }
- if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL)
- *ttl = *(u_char*)CMSG_DATA(cmPtr);
- if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
- {
- struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr);
- dstaddr->type = mDNSAddrType_IPv6;
- dstaddr->ip.v6 = *(mDNSv6Addr*)&ip6_info->ipi6_addr;
- myIfIndexToName(ip6_info->ipi6_ifindex, ifname);
- }
- if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
- *ttl = *(int*)CMSG_DATA(cmPtr);
- }
-
- return(n);
-}
-
-mDNSlocal mDNSInterfaceID FindMyInterface(mDNS *const m, const mDNSAddr *addr)
-{
- NetworkInterfaceInfo *intf;
-
- if (addr->type == mDNSAddrType_IPv4)
- {
- for (intf = m->HostInterfaces; intf; intf = intf->next)
- {
- if (intf->ip.type == addr->type && intf->McastTxRx)
- {
- if ((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) == 0)
- {
- return(intf->InterfaceID);
- }
- }
- }
- }
-
- if (addr->type == mDNSAddrType_IPv6)
- {
- for (intf = m->HostInterfaces; intf; intf = intf->next)
- {
- if (intf->ip.type == addr->type && intf->McastTxRx)
- {
- if (((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) == 0) &&
- ((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) == 0) &&
- ((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) == 0) &&
- (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) == 0)))
- {
- return(intf->InterfaceID);
- }
- }
- }
- }
- return(mDNSInterface_Any);
-}
-
-mDNSexport mDNSBool mDNSPlatformPeekUDP(mDNS *const m, UDPSocket *src)
-{
- // We should have a DNSMessage header followed by the question and an answer
- // which also includes a CNAME (that's when this function is called). To keep it
- // simple, we expect at least the size of DNSMessage header(12) and size of "A"
- // record (14 bytes).
- char buffer[26];
- int ret;
-
- (void) m;
-
- if (!src)
- return mDNSfalse;
-
- ret = recv(src->ss.sktv4, buffer, sizeof(buffer), MSG_PEEK);
- if (ret > 0)
- return mDNStrue;
- else
- return mDNSfalse;
-}
-
-mDNSexport void myKQSocketCallBack(int s1, short filter, void *context)
-{
- KQSocketSet *const ss = (KQSocketSet *)context;
- mDNS *const m = ss->m;
- int err = 0, count = 0, closed = 0;
-
- if (filter != EVFILT_READ)
- LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
-
- if (s1 != ss->sktv4 && s1 != ss->sktv6)
- {
- LogMsg("myKQSocketCallBack: native socket %d", s1);
- LogMsg("myKQSocketCallBack: sktv4 %d sktv6 %d", ss->sktv4, ss->sktv6);
- }
-
- while (!closed)
- {
- mDNSAddr senderAddr, destAddr;
- mDNSIPPort senderPort;
- struct sockaddr_storage from;
- size_t fromlen = sizeof(from);
- char packetifname[IF_NAMESIZE] = "";
- mDNSu8 ttl;
- err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl);
- if (err < 0) break;
-
- count++;
- if (from.ss_family == AF_INET)
- {
- struct sockaddr_in *s = (struct sockaddr_in*)&from;
- senderAddr.type = mDNSAddrType_IPv4;
- senderAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr;
- senderPort.NotAnInteger = s->sin_port;
- //LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
- }
- else if (from.ss_family == AF_INET6)
- {
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&from;
- senderAddr.type = mDNSAddrType_IPv6;
- senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
- senderPort.NotAnInteger = sin6->sin6_port;
- //LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
- }
- else
- {
- LogMsg("myKQSocketCallBack from is unknown address family %d", from.ss_family);
- return;
- }
-
- // Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
- mDNSInterfaceID InterfaceID = mDNSNULL;
- NetworkInterfaceInfoOSX *intf = m->p->InterfaceList;
- while (intf)
- {
- if (intf->Exists && !strcmp(intf->ifinfo.ifname, packetifname))
- break;
- intf = intf->next;
- }
-
- // When going to sleep we deregister all our interfaces, but if the machine
- // takes a few seconds to sleep we may continue to receive multicasts
- // during that time, which would confuse mDNSCoreReceive, because as far
- // as it's concerned, we should have no active interfaces any more.
- // Hence we ignore multicasts for which we can find no matching InterfaceID.
- if (intf)
- InterfaceID = intf->ifinfo.InterfaceID;
- else if (mDNSAddrIsDNSMulticast(&destAddr))
- continue;
-
- if (!InterfaceID)
- {
- InterfaceID = FindMyInterface(m, &destAddr);
- }
-
-// LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
-// &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
-
- // mDNSCoreReceive may close the socket we're reading from. We must break out of our
- // loop when that happens, or we may try to read from an invalid FD. We do this by
- // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us
- // if it closes the socketset.
- ss->closeFlag = &closed;
-
- if (ss->proxy)
- {
- m->p->UDPProxyCallback(m, &m->p->UDPProxy, (unsigned char *)&m->imsg, (unsigned char*)&m->imsg + err, &senderAddr,
- senderPort, &destAddr, ss->port, InterfaceID, NULL);
- }
- else
- {
- mDNSCoreReceive(m, &m->imsg, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, ss->port, InterfaceID);
- }
-
- // if we didn't close, we can safely dereference the socketset, and should to
- // reset the closeFlag, since it points to something on the stack
- if (!closed) ss->closeFlag = mDNSNULL;
- }
-
- if (err < 0 && (errno != EWOULDBLOCK || count == 0))
- {
- // Something is busted here.
- // kqueue says there is a packet, but myrecvfrom says there is not.
- // Try calling select() to get another opinion.
- // Find out about other socket parameter that can help understand why select() says the socket is ready for read
- // All of this is racy, as data may have arrived after the call to select()
- static unsigned int numLogMessages = 0;
- int save_errno = errno;
- int so_error = -1;
- int so_nread = -1;
- int fionread = -1;
- socklen_t solen = sizeof(int);
- fd_set readfds;
- struct timeval timeout;
- int selectresult;
- FD_ZERO(&readfds);
- FD_SET(s1, &readfds);
- timeout.tv_sec = 0;
- timeout.tv_usec = 0;
- selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
- if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
- LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno);
- if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
- LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno);
- if (ioctl(s1, FIONREAD, &fionread) == -1)
- LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno);
- if (numLogMessages++ < 100)
- LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
- s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
- if (numLogMessages > 5)
- NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
- "Congratulations, you've reproduced an elusive bug.\r"
- "Please contact the current assignee of <rdar://problem/3375328>.\r"
- "Alternatively, you can send email to radar-3387020 at group.apple.com. (Note number is different.)\r"
- "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
-
- sleep(1); // After logging this error, rate limit so we don't flood syslog
- }
-}
-
-mDNSlocal void doTcpSocketCallback(TCPSocket *sock)
-{
- mDNSBool c = !sock->connected;
- sock->connected = mDNStrue;
- sock->callback(sock, sock->context, c, sock->err);
- // Note: the callback may call CloseConnection here, which frees the context structure!
-}
-
-#ifndef NO_SECURITYFRAMEWORK
-
-mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength)
-{
- int ret = send(((TCPSocket *)connection)->fd, data, *dataLength, 0);
- if (ret >= 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
- if (ret >= 0) { *dataLength = ret; return(noErr); }
- *dataLength = 0;
- if (errno == EAGAIN ) return(errSSLWouldBlock);
- if (errno == ENOENT ) return(errSSLClosedGraceful);
- if (errno == EPIPE || errno == ECONNRESET) return(errSSLClosedAbort);
- LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket *)connection)->fd, errno, strerror(errno));
- return(errSSLClosedAbort);
-}
-
-mDNSlocal OSStatus tlsReadSock(SSLConnectionRef connection, void *data, size_t *dataLength)
-{
- int ret = recv(((TCPSocket *)connection)->fd, data, *dataLength, 0);
- if (ret > 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
- if (ret > 0) { *dataLength = ret; return(noErr); }
- *dataLength = 0;
- if (ret == 0 || errno == ENOENT ) return(errSSLClosedGraceful);
- if ( errno == EAGAIN ) return(errSSLWouldBlock);
- if ( errno == ECONNRESET) return(errSSLClosedAbort);
- LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno, strerror(errno));
- return(errSSLClosedAbort);
-}
-
-mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, SSLProtocolSide pside, SSLConnectionType ctype)
-{
- char domname_cstr[MAX_ESCAPED_DOMAIN_NAME];
-
- sock->tlsContext = SSLCreateContext(kCFAllocatorDefault, pside, ctype);
- if (!sock->tlsContext)
- {
- LogMsg("ERROR: tlsSetupSock: SSLCreateContext failed");
- return(mStatus_UnknownErr);
- }
-
- mStatus err = SSLSetIOFuncs(sock->tlsContext, tlsReadSock, tlsWriteSock);
- if (err)
- {
- LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err);
- goto fail;
- }
-
- err = SSLSetConnection(sock->tlsContext, (SSLConnectionRef) sock);
- if (err)
- {
- LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err);
- goto fail;
- }
-
- // Instead of listing all the acceptable ciphers, we just disable the bad ciphers. It does not disable
- // all the bad ciphers like RC4_MD5, but it assumes that the servers don't offer them.
- err = SSLSetAllowAnonymousCiphers(sock->tlsContext, 0);
- if (err)
- {
- LogMsg("ERROR: tlsSetupSock: SSLSetAllowAnonymousCiphers failed with error code: %d", err);
- goto fail;
- }
-
- // We already checked for NULL in hostname and this should never happen. Hence, returning -1
- // (error not in OSStatus space) is okay.
- if (!sock->hostname.c[0])
- {
- LogMsg("ERROR: tlsSetupSock: hostname NULL");
- err = -1;
- goto fail;
- }
-
- ConvertDomainNameToCString(&sock->hostname, domname_cstr);
- err = SSLSetPeerDomainName(sock->tlsContext, domname_cstr, strlen(domname_cstr));
- if (err)
- {
- LogMsg("ERROR: tlsSetupSock: SSLSetPeerDomainname: %s failed with error code: %d", domname_cstr, err);
- goto fail;
- }
-
- return(err);
-
-fail:
- if (sock->tlsContext)
- CFRelease(sock->tlsContext);
- return(err);
-}
-
-#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
-mDNSlocal void doSSLHandshake(TCPSocket *sock)
-{
- mStatus err = SSLHandshake(sock->tlsContext);
-
- //Can't have multiple threads in mDNS core. When MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM is
- //defined, KQueueLock is a noop. Hence we need to serialize here
- //
- //NOTE: We just can't serialize doTcpSocketCallback alone on the main queue.
- //We need the rest of the logic also. Otherwise, we can enable the READ
- //events below, dispatch a doTcpSocketCallback on the main queue. Assume it is
- //ConnFailed which means we are going to free the tcpInfo. While it
- //is waiting to be dispatched, another read event can come into tcpKQSocketCallback
- //and potentially call doTCPCallback with error which can close the fd and free the
- //tcpInfo. Later when the thread gets dispatched it will crash because the tcpInfo
- //is already freed.
-
- dispatch_async(dispatch_get_main_queue(), ^{
-
- LogInfo("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
-
- if (sock->handshake == handshake_to_be_closed)
- {
- LogInfo("SSLHandshake completed after close");
- mDNSPlatformTCPCloseConnection(sock);
- }
- else
- {
- if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
- else LogMsg("doSSLHandshake: sock->fd is -1");
-
- if (err == errSSLWouldBlock)
- sock->handshake = handshake_required;
- else
- {
- if (err)
- {
- LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
- CFRelease(sock->tlsContext);
- sock->tlsContext = NULL;
- }
-
- sock->err = err ? mStatus_ConnFailed : 0;
- sock->handshake = handshake_completed;
-
- LogInfo("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
- doTcpSocketCallback(sock);
- }
- }
-
- LogInfo("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
- return;
- });
-}
-#else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
-mDNSlocal void *doSSLHandshake(TCPSocket *sock)
-{
- // Warning: Touching sock without the kqueue lock!
- // We're protected because sock->handshake == handshake_in_progress
- mDNS * const m = sock->m; // Get m now, as we may free sock if marked to be closed while we're waiting on SSLHandshake
- mStatus err = SSLHandshake(sock->tlsContext);
-
- KQueueLock(m);
- debugf("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
-
- if (sock->handshake == handshake_to_be_closed)
- {
- LogInfo("SSLHandshake completed after close");
- mDNSPlatformTCPCloseConnection(sock);
- }
- else
- {
- if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
- else LogMsg("doSSLHandshake: sock->fd is -1");
-
- if (err == errSSLWouldBlock)
- sock->handshake = handshake_required;
- else
- {
- if (err)
- {
- LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
- CFRelease(sock->tlsContext);
- sock->tlsContext = NULL;
- }
-
- sock->err = err ? mStatus_ConnFailed : 0;
- sock->handshake = handshake_completed;
-
- debugf("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
- doTcpSocketCallback(sock);
- }
- }
-
- debugf("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
- KQueueUnlock(m, "doSSLHandshake");
- return NULL;
-}
-#endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
-
-mDNSlocal void spawnSSLHandshake(TCPSocket* sock)
-{
- debugf("spawnSSLHandshake %p: entry", sock);
-
- if (sock->handshake != handshake_required) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock->handshake);
- sock->handshake = handshake_in_progress;
- KQueueSet(sock->fd, EV_DELETE, EVFILT_READ, sock->kqEntry);
-
- // Dispatch it on a separate queue to help avoid blocking other threads/queues, and
- // to limit the number of threads used for SSLHandshake
- dispatch_async(SSLqueue, ^{doSSLHandshake(sock);});
-
- debugf("spawnSSLHandshake %p: done for %d", sock, sock->fd);
-}
-
-#endif /* NO_SECURITYFRAMEWORK */
-
-mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context)
-{
- TCPSocket *sock = context;
- sock->err = mStatus_NoError;
-
- //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
- //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
- // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
- if (filter == EVFILT_WRITE)
- KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, sock->kqEntry);
-
- if (sock->flags & kTCPSocketFlags_UseTLS)
- {
-#ifndef NO_SECURITYFRAMEWORK
- if (!sock->setup)
- {
- sock->setup = mDNStrue;
- sock->err = tlsSetupSock(sock, kSSLClientSide, kSSLStreamType);
- if (sock->err)
- {
- LogMsg("ERROR: tcpKQSocketCallback: tlsSetupSock failed with error code: %d", sock->err);
- return;
- }
- }
- if (sock->handshake == handshake_required)
- {
- spawnSSLHandshake(sock);
- return;
- }
- else if (sock->handshake == handshake_in_progress || sock->handshake == handshake_to_be_closed)
- {
- return;
- }
- else if (sock->handshake != handshake_completed)
- {
- if (!sock->err)
- sock->err = mStatus_UnknownErr;
- LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock->handshake);
- }
-#else /* NO_SECURITYFRAMEWORK */
- sock->err = mStatus_UnsupportedErr;
-#endif /* NO_SECURITYFRAMEWORK */
- }
-
- doTcpSocketCallback(sock);
-}
-
-#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
-mDNSexport int KQueueSet(int fd, u_short flags, short filter, KQueueEntry *const entryRef)
-{
- dispatch_queue_t queue = dispatch_get_main_queue();
- dispatch_source_t source;
- if (flags == EV_DELETE)
- {
- if (filter == EVFILT_READ)
- {
- dispatch_source_cancel(entryRef->readSource);
- dispatch_release(entryRef->readSource);
- entryRef->readSource = mDNSNULL;
- debugf("KQueueSet: source cancel for read %p, %p", entryRef->readSource, entryRef->writeSource);
- }
- else if (filter == EVFILT_WRITE)
- {
- dispatch_source_cancel(entryRef->writeSource);
- dispatch_release(entryRef->writeSource);
- entryRef->writeSource = mDNSNULL;
- debugf("KQueueSet: source cancel for write %p, %p", entryRef->readSource, entryRef->writeSource);
- }
- else
- LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_DELETE", filter);
- return 0;
- }
- if (flags != EV_ADD) LogMsg("KQueueSet: Invalid flags %d", flags);
-
- if (filter == EVFILT_READ)
- {
- source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, queue);
- }
- else if (filter == EVFILT_WRITE)
- {
- source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, queue);
- }
- else
- {
- LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_ADD", filter);
- return -1;
- }
- if (!source) return -1;
- dispatch_source_set_event_handler(source, ^{
-
- mDNSs32 stime = mDNSPlatformRawTime();
- entryRef->KQcallback(fd, filter, entryRef->KQcontext);
- mDNSs32 etime = mDNSPlatformRawTime();
- if (etime - stime >= WatchDogReportingThreshold)
- LogInfo("KQEntryCallback Block: WARNING: took %dms to complete", etime - stime);
-
- // Trigger the event delivery to the application. Even though we trigger the
- // event completion after handling every event source, these all will hopefully
- // get merged
- TriggerEventCompletion();
-
- });
- dispatch_source_set_cancel_handler(source, ^{
- if (entryRef->fdClosed)
- {
- //LogMsg("CancelHandler: closing fd %d", fd);
- close(fd);
- }
- });
- dispatch_resume(source);
- if (filter == EVFILT_READ)
- entryRef->readSource = source;
- else
- entryRef->writeSource = source;
-
- return 0;
-}
-
-mDNSexport void KQueueLock(mDNS *const m)
-{
- (void)m; //unused
-}
-mDNSexport void KQueueUnlock(mDNS *const m, const char const *task)
-{
- (void)m; //unused
- (void)task; //unused
-}
-#else
-mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef)
-{
- struct kevent new_event;
- EV_SET(&new_event, fd, filter, flags, 0, 0, (void*)entryRef);
- return (kevent(KQueueFD, &new_event, 1, NULL, 0, NULL) < 0) ? errno : 0;
-}
-
-mDNSexport void KQueueLock(mDNS *const m)
-{
- pthread_mutex_lock(&m->p->BigMutex);
- m->p->BigMutexStartTime = mDNSPlatformRawTime();
-}
-
-mDNSexport void KQueueUnlock(mDNS *const m, const char* task)
-{
- mDNSs32 end = mDNSPlatformRawTime();
- (void)task;
- if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
- LogInfo("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime);
-
- pthread_mutex_unlock(&m->p->BigMutex);
-
- char wake = 1;
- if (send(m->p->WakeKQueueLoopFD, &wake, sizeof(wake), 0) == -1)
- LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno, strerror(errno));
-}
-#endif
-
-mDNSexport void mDNSPlatformCloseFD(KQueueEntry *kq, int fd)
-{
-#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
- (void) fd; //unused
- if (kq->readSource)
- {
- dispatch_source_cancel(kq->readSource);
- kq->readSource = mDNSNULL;
- }
- if (kq->writeSource)
- {
- dispatch_source_cancel(kq->writeSource);
- kq->writeSource = mDNSNULL;
- }
- // Close happens in the cancellation handler
- debugf("mDNSPlatformCloseFD: resetting sources for %d", fd);
- kq->fdClosed = mDNStrue;
-#else
- (void)kq; //unused
- close(fd);
-#endif
-}
-
-mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, u_short sa_family, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
-{
- KQSocketSet *cp = &sock->ss;
- int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
- KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
- const int on = 1; // "on" for setsockopt
- mStatus err;
-
- int skt = socket(sa_family, SOCK_STREAM, IPPROTO_TCP);
- if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupTCPSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); }
-
- // for TCP sockets, the traffic class is set once and not changed
- setTrafficClass(skt, useBackgroundTrafficClass);
-
- if (sa_family == AF_INET)
- {
- // Bind it
- struct sockaddr_in addr;
- mDNSPlatformMemZero(&addr, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = port->NotAnInteger;
- err = bind(skt, (struct sockaddr*) &addr, sizeof(addr));
- if (err < 0) { LogMsg("ERROR: bind %s", strerror(errno)); return err; }
-
- // Receive interface identifiers
- err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
- if (err < 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); return err; }
-
- mDNSPlatformMemZero(&addr, sizeof(addr));
- socklen_t len = sizeof(addr);
- err = getsockname(skt, (struct sockaddr*) &addr, &len);
- if (err < 0) { LogMsg("getsockname - %s", strerror(errno)); return err; }
-
- port->NotAnInteger = addr.sin_port;
- }
- else
- {
- // Bind it
- struct sockaddr_in6 addr6;
- mDNSPlatformMemZero(&addr6, sizeof(addr6));
- addr6.sin6_family = AF_INET6;
- addr6.sin6_port = port->NotAnInteger;
- err = bind(skt, (struct sockaddr*) &addr6, sizeof(addr6));
- if (err < 0) { LogMsg("ERROR: bind6 %s", strerror(errno)); return err; }
-
- // We want to receive destination addresses and receive interface identifiers
- err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
- if (err < 0) { LogMsg("ERROR: setsockopt IPV6_RECVPKTINFO %s", strerror(errno)); return err; }
-
- mDNSPlatformMemZero(&addr6, sizeof(addr6));
- socklen_t len = sizeof(addr6);
- err = getsockname(skt, (struct sockaddr *) &addr6, &len);
- if (err < 0) { LogMsg("getsockname6 - %s", strerror(errno)); return err; }
-
- port->NotAnInteger = addr6.sin6_port;
-
- }
- *s = skt;
- k->KQcallback = tcpKQSocketCallback;
- k->KQcontext = sock;
- k->KQtask = "mDNSPlatformTCPSocket";
-#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
- k->readSource = mDNSNULL;
- k->writeSource = mDNSNULL;
- k->fdClosed = mDNSfalse;
-#endif
- return mStatus_NoError;
-}
-
-mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
-{
- mStatus err;
- (void) m;
-
- TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket));
- if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); }
-
- mDNSPlatformMemZero(sock, sizeof(TCPSocket));
-
- sock->ss.m = m;
- sock->ss.sktv4 = -1;
- sock->ss.sktv6 = -1;
- err = SetupTCPSocket(sock, AF_INET, port, useBackgroundTrafficClass);
-
- if (!err)
- {
- err = SetupTCPSocket(sock, AF_INET6, port, useBackgroundTrafficClass);
- if (err) { mDNSPlatformCloseFD(&sock->ss.kqsv4, sock->ss.sktv4); sock->ss.sktv4 = -1; }
- }
- if (err)
- {
- LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno));
- freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
- return(mDNSNULL);
- }
- // sock->fd is used as the default fd if the caller does not call mDNSPlatformTCPConnect
- sock->fd = sock->ss.sktv4;
- sock->callback = mDNSNULL;
- sock->flags = flags;
- sock->context = mDNSNULL;
- sock->setup = mDNSfalse;
- sock->connected = mDNSfalse;
- sock->handshake = handshake_required;
- sock->m = m;
- sock->err = mStatus_NoError;
-
- return sock;
-}
-
-mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
-{
- KQSocketSet *cp = &sock->ss;
- int *s = (dst->type == mDNSAddrType_IPv4) ? &cp->sktv4 : &cp->sktv6;
- KQueueEntry *k = (dst->type == mDNSAddrType_IPv4) ? &cp->kqsv4 : &cp->kqsv6;
- mStatus err = mStatus_NoError;
- struct sockaddr_storage ss;
-
- sock->callback = callback;
- sock->context = context;
- sock->setup = mDNSfalse;
- sock->connected = mDNSfalse;
- sock->handshake = handshake_required;
- sock->err = mStatus_NoError;
-
- if (hostname) { debugf("mDNSPlatformTCPConnect: hostname %##s", hostname->c); AssignDomainName(&sock->hostname, hostname); }
-
- if (dst->type == mDNSAddrType_IPv4)
- {
- struct sockaddr_in *saddr = (struct sockaddr_in *)&ss;
- mDNSPlatformMemZero(saddr, sizeof(*saddr));
- saddr->sin_family = AF_INET;
- saddr->sin_port = dstport.NotAnInteger;
- saddr->sin_len = sizeof(*saddr);
- saddr->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
- }
- else
- {
- struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&ss;
- mDNSPlatformMemZero(saddr6, sizeof(*saddr6));
- saddr6->sin6_family = AF_INET6;
- saddr6->sin6_port = dstport.NotAnInteger;
- saddr6->sin6_len = sizeof(*saddr6);
- saddr6->sin6_addr = *(struct in6_addr *)&dst->ip.v6;
- }
-
- // Watch for connect complete (write is ready)
- // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
- if (KQueueSet(*s, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, k))
- {
- LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
- return errno;
- }
-
- // Watch for incoming data
- if (KQueueSet(*s, EV_ADD, EVFILT_READ, k))
- {
- LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
- return errno;
- }
-
- if (fcntl(*s, F_SETFL, fcntl(*s, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
- {
- LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
- return mStatus_UnknownErr;
- }
-
- // We bind to the interface and all subsequent packets including the SYN will be sent out
- // on this interface
- //
- // Note: If we are in Active Directory domain, we may try TCP (if the response can't fit in
- // UDP). mDNSInterface_Unicast indicates this case and not a valid interface.
- if (InterfaceID && InterfaceID != mDNSInterface_Unicast)
- {
- NetworkInterfaceInfoOSX *info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
- if (dst->type == mDNSAddrType_IPv4)
- {
- #ifdef IP_BOUND_IF
- if (info) setsockopt(*s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
- else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
- #else
- (void)InterfaceID; // Unused
- (void)info; // Unused
- #endif
- }
- else
- {
- #ifdef IPV6_BOUND_IF
- if (info) setsockopt(*s, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
- else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
- #else
- (void)InterfaceID; // Unused
- (void)info; // Unused
- #endif
- }
- }
-
- // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
- // from which we can infer the destination address family. Hence we need to remember that here.
- // Instead of remembering the address family, we remember the right fd.
- sock->fd = *s;
- sock->kqEntry = k;
- // initiate connection wth peer
- if (connect(*s, (struct sockaddr *)&ss, ss.ss_len) < 0)
- {
- if (errno == EINPROGRESS) return mStatus_ConnPending;
- if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
- LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock->fd, errno, strerror(errno));
- else
- LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d", sock->fd, errno, strerror(errno), ss.ss_len);
- return mStatus_ConnFailed;
- }
-
- LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
- // kQueue should notify us, but this LogMsg is to help track down if it doesn't
- return err;
-}
-
-// Why doesn't mDNSPlatformTCPAccept actually call accept() ?
-mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
-{
- mStatus err = mStatus_NoError;
-
- TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket));
- if (!sock) return(mDNSNULL);
-
- mDNSPlatformMemZero(sock, sizeof(*sock));
- sock->fd = fd;
- sock->flags = flags;
-
- if (flags & kTCPSocketFlags_UseTLS)
- {
-#ifndef NO_SECURITYFRAMEWORK
- if (!ServerCerts) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err = mStatus_UnknownErr; goto exit; }
-
- err = tlsSetupSock(sock, kSSLServerSide, kSSLStreamType);
- if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err); goto exit; }
-
- err = SSLSetCertificate(sock->tlsContext, ServerCerts);
- if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err); goto exit; }
-#else
- err = mStatus_UnsupportedErr;
-#endif /* NO_SECURITYFRAMEWORK */
- }
-#ifndef NO_SECURITYFRAMEWORK
-exit:
-#endif
-
- if (err) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock); return(mDNSNULL); }
- return(sock);
-}
-
-mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
-{
- mDNSu16 port;
-
- port = -1;
- if (sock)
- {
- port = sock->ss.port.NotAnInteger;
- }
- return port;
-}
-
-mDNSlocal void CloseSocketSet(KQSocketSet *ss)
-{
- if (ss->sktv4 != -1)
- {
- mDNSPlatformCloseFD(&ss->kqsv4, ss->sktv4);
- ss->sktv4 = -1;
- }
- if (ss->sktv6 != -1)
- {
- mDNSPlatformCloseFD(&ss->kqsv6, ss->sktv6);
- ss->sktv6 = -1;
- }
- if (ss->closeFlag) *ss->closeFlag = 1;
-}
-
-mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
-{
- if (sock)
- {
-#ifndef NO_SECURITYFRAMEWORK
- if (sock->tlsContext)
- {
- if (sock->handshake == handshake_in_progress) // SSLHandshake thread using this sock (esp. tlsContext)
- {
- LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress");
- // When we come back from SSLHandshake, we will notice that a close was here and
- // call this function again which will do the cleanup then.
- sock->handshake = handshake_to_be_closed;
- return;
- }
-
- SSLClose(sock->tlsContext);
- CFRelease(sock->tlsContext);
- sock->tlsContext = NULL;
- }
-#endif /* NO_SECURITYFRAMEWORK */
- if (sock->ss.sktv4 != -1)
- shutdown(sock->ss.sktv4, 2);
- if (sock->ss.sktv6 != -1)
- shutdown(sock->ss.sktv6, 2);
- CloseSocketSet(&sock->ss);
- sock->fd = -1;
-
- freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock);
- }
-}
-
-mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
-{
- ssize_t nread = 0;
- *closed = mDNSfalse;
-
- if (sock->flags & kTCPSocketFlags_UseTLS)
- {
-#ifndef NO_SECURITYFRAMEWORK
- if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; }
- else if (sock->handshake == handshake_in_progress) return 0;
- else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock->handshake);
-
- //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
- mStatus err = SSLRead(sock->tlsContext, buf, buflen, (size_t *)&nread);
- //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
- if (err == errSSLClosedGraceful) { nread = 0; *closed = mDNStrue; }
- else if (err && err != errSSLWouldBlock)
- { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err); nread = -1; *closed = mDNStrue; }
-#else
- nread = -1;
- *closed = mDNStrue;
-#endif /* NO_SECURITYFRAMEWORK */
- }
- else
- {
- static int CLOSEDcount = 0;
- static int EAGAINcount = 0;
- nread = recv(sock->fd, buf, buflen, 0);
-
- if (nread > 0)
- {
- CLOSEDcount = 0;
- EAGAINcount = 0;
- } // On success, clear our error counters
- else if (nread == 0)
- {
- *closed = mDNStrue;
- if ((++CLOSEDcount % 1000) == 0)
- {
- LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock->fd, CLOSEDcount);
- assert(CLOSEDcount < 1000);
- // Recovery Mechanism to bail mDNSResponder out of trouble: Instead of logging the same error msg multiple times,
- // crash mDNSResponder using assert() and restart fresh. See advantages below:
- // 1.Better User Experience
- // 2.CrashLogs frequency can be monitored
- // 3.StackTrace can be used for more info
- }
- }
- // else nread is negative -- see what kind of error we got
- else if (errno == ECONNRESET) { nread = 0; *closed = mDNStrue; }
- else if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno, strerror(errno)); nread = -1; }
- else // errno is EAGAIN (EWOULDBLOCK) -- no data available
- {
- nread = 0;
- if ((++EAGAINcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock->fd, EAGAINcount); sleep(1); }
- }
- }
-
- return nread;
-}
-
-mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
-{
- int nsent;
-
- if (sock->flags & kTCPSocketFlags_UseTLS)
- {
-#ifndef NO_SECURITYFRAMEWORK
- size_t processed;
- if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; }
- if (sock->handshake == handshake_in_progress) return 0;
- else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock->handshake);
-
- mStatus err = SSLWrite(sock->tlsContext, msg, len, &processed);
-
- if (!err) nsent = (int) processed;
- else if (err == errSSLWouldBlock) nsent = 0;
- else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err); nsent = -1; }
-#else
- nsent = -1;
-#endif /* NO_SECURITYFRAMEWORK */
- }
- else
- {
- nsent = send(sock->fd, msg, len, 0);
- if (nsent < 0)
- {
- if (errno == EAGAIN) nsent = 0;
- else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno)); nsent = -1; }
- }
- }
-
- return nsent;
-}
-
-mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
-{
- return sock->fd;
-}
-
-// If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
-// If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
-mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport)
-{
- int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
- KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
- const int on = 1;
- const int twofivefive = 255;
- mStatus err = mStatus_NoError;
- char *errstr = mDNSNULL;
- const int mtu = 0;
-
- cp->closeFlag = mDNSNULL;
-
- int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
- if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); }
-
- // set default traffic class
- setTrafficClass(skt, mDNSfalse);
-
-#ifdef SO_RECV_ANYIF
- // Enable inbound packets on IFEF_AWDL interface.
- // Only done for multicast sockets, since we don't expect unicast socket operations
- // on the IFEF_AWDL interface. Operation is a no-op for other interface types.
- if (mDNSSameIPPort(port, MulticastDNSPort))
- {
- err = setsockopt(skt, SOL_SOCKET, SO_RECV_ANYIF, &on, sizeof(on));
- if (err < 0) { errstr = "setsockopt - SO_RECV_ANYIF"; goto fail; }
- }
-#endif // SO_RECV_ANYIF
-
- // ... with a shared UDP port, if it's for multicast receiving
- if (mDNSSameIPPort(port, MulticastDNSPort) || mDNSSameIPPort(port, NATPMPAnnouncementPort)) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
- if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
-
- if (sa_family == AF_INET)
- {
- // We want to receive destination addresses
- err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
- if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; }
-
- // We want to receive interface identifiers
- err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
- if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; }
-
- // We want to receive packet TTL value so we can check it
- err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
- // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
-
- // Send unicast packets with TTL 255
- err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
- if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; }
-
- // And multicast packets with TTL 255 too
- err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
- if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; }
-
- // And start listening for packets
- struct sockaddr_in listening_sockaddr;
- listening_sockaddr.sin_family = AF_INET;
- listening_sockaddr.sin_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
- listening_sockaddr.sin_addr.s_addr = mDNSSameIPPort(port, NATPMPAnnouncementPort) ? AllHosts_v4.NotAnInteger : 0;
- err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
- if (err) { errstr = "bind"; goto fail; }
- if (outport) outport->NotAnInteger = listening_sockaddr.sin_port;
- }
- else if (sa_family == AF_INET6)
- {
- // NAT-PMP Announcements make no sense on IPv6, and we don't support IPv6 for PCP, so bail early w/o error
- if (mDNSSameIPPort(port, NATPMPAnnouncementPort)) { if (outport) *outport = zeroIPPort;return mStatus_NoError; }
-
- // We want to receive destination addresses and receive interface identifiers
- err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
- if (err < 0) { errstr = "setsockopt - IPV6_RECVPKTINFO"; goto fail; }
-
- // We want to receive packet hop count value so we can check it
- err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on));
- if (err < 0) { errstr = "setsockopt - IPV6_RECVHOPLIMIT"; goto fail; }
-
- // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
- // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
- err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
- if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; }
-
- // Send unicast packets with TTL 255
- err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
- if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; }
-
- // And multicast packets with TTL 255 too
- err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
- if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; }
-
- // Want to receive our own packets
- err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
- if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; }
-
- // Disable default option to send mDNSv6 packets at min IPv6 MTU: RFC 3542, Sec 11
- err = setsockopt(skt, IPPROTO_IPV6, IPV6_USE_MIN_MTU, &mtu, sizeof(mtu));
- if (err < 0) // Since it is an optimization if we fail just log the err, no need to close the skt
- LogMsg("SetupSocket: setsockopt - IPV6_USE_MIN_MTU: IP6PO_MINMTU_DISABLE socket %d err %d errno %d (%s)",
- skt, err, errno, strerror(errno));
-
- // And start listening for packets
- struct sockaddr_in6 listening_sockaddr6;
- mDNSPlatformMemZero(&listening_sockaddr6, sizeof(listening_sockaddr6));
- listening_sockaddr6.sin6_len = sizeof(listening_sockaddr6);
- listening_sockaddr6.sin6_family = AF_INET6;
- listening_sockaddr6.sin6_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
- listening_sockaddr6.sin6_flowinfo = 0;
- listening_sockaddr6.sin6_addr = in6addr_any; // Want to receive multicasts AND unicasts on this socket
- listening_sockaddr6.sin6_scope_id = 0;
- err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
- if (err) { errstr = "bind"; goto fail; }
- if (outport) outport->NotAnInteger = listening_sockaddr6.sin6_port;
- }
-
- fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
- fcntl(skt, F_SETFD, 1); // set close-on-exec
- *s = skt;
- k->KQcallback = myKQSocketCallBack;
- k->KQcontext = cp;
- k->KQtask = "UDP packet reception";
-#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
- k->readSource = mDNSNULL;
- k->writeSource = mDNSNULL;
- k->fdClosed = mDNSfalse;
-#endif
- KQueueSet(*s, EV_ADD, EVFILT_READ, k);
-
- return(err);
-
-fail:
- // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
- if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port))
- LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr, skt, mDNSVal16(port), err, errno, strerror(errno));
-
- // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port
- if (!strcmp(errstr, "bind") && errno == EADDRINUSE)
- {
- err = EADDRINUSE;
- if (mDNSSameIPPort(port, MulticastDNSPort))
- NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
- "Congratulations, you've reproduced an elusive bug.\r"
- "Please contact the current assignee of <rdar://problem/3814904>.\r"
- "Alternatively, you can send email to radar-3387020 at group.apple.com. (Note number is different.)\r"
- "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
- }
-
- mDNSPlatformCloseFD(k, skt);
- return(err);
-}
-
-mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport)
-{
- mStatus err;
- mDNSIPPort port = requestedport;
- mDNSBool randomizePort = mDNSIPPortIsZero(requestedport);
- int i = 10000; // Try at most 10000 times to get a unique random port
- UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket));
- if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
- mDNSPlatformMemZero(p, sizeof(UDPSocket));
- p->ss.port = zeroIPPort;
- p->ss.m = m;
- p->ss.sktv4 = -1;
- p->ss.sktv6 = -1;
- p->ss.proxy = mDNSfalse;
-
- do
- {
- // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
- if (randomizePort) port = mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
- err = SetupSocket(&p->ss, port, AF_INET, &p->ss.port);
- if (!err)
- {
- err = SetupSocket(&p->ss, port, AF_INET6, &p->ss.port);
- if (err) { mDNSPlatformCloseFD(&p->ss.kqsv4, p->ss.sktv4); p->ss.sktv4 = -1; }
- }
- i--;
- } while (err == EADDRINUSE && randomizePort && i);
-
- if (err)
- {
- // In customer builds we don't want to log failures with port 5351, because this is a known issue
- // of failing to bind to this port when Internet Sharing has already bound to it
- // We also don't want to log about port 5350, due to a known bug when some other
- // process is bound to it.
- if (mDNSSameIPPort(requestedport, NATPMPPort) || mDNSSameIPPort(requestedport, NATPMPAnnouncementPort))
- LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
- else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
- freeL("UDPSocket", p);
- return(mDNSNULL);
- }
- return(p);
-}
-
-mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
-{
- CloseSocketSet(&sock->ss);
- freeL("UDPSocket", sock);
-}
-
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - BPF Raw packet sending/receiving
-#endif
-
-#if APPLE_OSX_mDNSResponder
-
-mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
-{
- if (!InterfaceID) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
- NetworkInterfaceInfoOSX *info;
-
- info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
- if (info == NULL)
- {
- LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
- return;
- }
- if (info->BPF_fd < 0)
- LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info->ifinfo.ifname, info->BPF_fd);
- else
- {
- //LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname);
- if (write(info->BPF_fd, msg, end - (mDNSu8 *)msg) < 0)
- LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info->BPF_fd, errno, strerror(errno));
- }
-}
-
-mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
-{
- if (!InterfaceID) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: No InterfaceID specified"); return; }
- NetworkInterfaceInfoOSX *info;
- info = IfindexToInterfaceInfoOSX(m, InterfaceID);
- if (info == NULL) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: Invalid interface index %p", InterfaceID); return; }
- // Manually inject an entry into our local ARP cache.
- // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.)
- if (!mDNS_AddressIsLocalSubnet(m, InterfaceID, tpa, mDNSNULL))
- LogSPS("Don't need address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha);
- else
- {
- int result = mDNSSetLocalAddressCacheEntry(info->scope_id, tpa->type, tpa->ip.v6.b, tha->b);
- if (result) LogMsg("Set local address cache entry for %s %#a %.6a failed: %d", info->ifinfo.ifname, tpa, tha, result);
- else LogSPS("Set local address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha);
- }
-}
-
-mDNSlocal void CloseBPF(NetworkInterfaceInfoOSX *const i)
-{
- LogSPS("%s closing BPF fd %d", i->ifinfo.ifname, i->BPF_fd);
-#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
- // close will happen in the cancel handler
- dispatch_source_cancel(i->BPF_source);
-#else
-
- // Note: MUST NOT close() the underlying native BSD sockets.
- // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because
- // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them.
- CFRunLoopRemoveSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode);
- CFRelease(i->BPF_rls);
- CFSocketInvalidate(i->BPF_cfs);
- CFRelease(i->BPF_cfs);
-#endif
- i->BPF_fd = -1;
- if (i->BPF_mcfd >= 0) { close(i->BPF_mcfd); i->BPF_mcfd = -1; }
-}
-
-mDNSlocal void bpf_callback_common(NetworkInterfaceInfoOSX *info)
-{
- KQueueLock(info->m);
-
- // Now we've got the lock, make sure the kqueue thread didn't close the fd out from under us (will not be a problem once the OS X
- // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition).
- if (info->BPF_fd < 0) goto exit;
-
- ssize_t n = read(info->BPF_fd, &info->m->imsg, info->BPF_len);
- const mDNSu8 *ptr = (const mDNSu8 *)&info->m->imsg;
- const mDNSu8 *end = (const mDNSu8 *)&info->m->imsg + n;
- debugf("%3d: bpf_callback got %d bytes on %s", info->BPF_fd, n, info->ifinfo.ifname);
-
- if (n<0)
- {
- /* <rdar://problem/10287386>
- * sometimes there can be a race condition btw when the bpf socket
- * gets data and the callback get scheduled and when we call BIOCSETF (which
- * clears the socket). this can cause the read to hang for a really long time
- * and effectively prevent us from responding to requests for long periods of time.
- * to prevent this make the socket non blocking and just bail if we dont get anything
- */
- if (errno == EAGAIN)
- {
- LogMsg("bpf_callback got EAGAIN bailing");
- goto exit;
- }
- LogMsg("Closing %s BPF fd %d due to error %d (%s)", info->ifinfo.ifname, info->BPF_fd, errno, strerror(errno));
- CloseBPF(info);
- goto exit;
- }
-
- while (ptr < end)
- {
- const struct bpf_hdr *const bh = (const struct bpf_hdr *)ptr;
- debugf("%3d: bpf_callback ptr %p bh_hdrlen %d data %p bh_caplen %4d bh_datalen %4d next %p remaining %4d",
- info->BPF_fd, ptr, bh->bh_hdrlen, ptr + bh->bh_hdrlen, bh->bh_caplen, bh->bh_datalen,
- ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen), end - (ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen)));
- // Note that BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header.
- // Given that An Ethernet header is 14 bytes, this means that if the network layer header (e.g. IP header,
- // ARP message, etc.) is 4-byte aligned, then necessarily the Ethernet header will be NOT be 4-byte aligned.
- mDNSCoreReceiveRawPacket(info->m, ptr + bh->bh_hdrlen, ptr + bh->bh_hdrlen + bh->bh_caplen, info->ifinfo.InterfaceID);
- ptr += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
- }
-exit:
- KQueueUnlock(info->m, "bpf_callback");
-}
-#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
-mDNSlocal void bpf_callback_dispatch(NetworkInterfaceInfoOSX *const info)
-{
- bpf_callback_common(info);
-}
-#else
-mDNSlocal void bpf_callback(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context)
-{
- (void)cfs;
- (void)CallBackType;
- (void)address;
- (void)data;
- bpf_callback_common((NetworkInterfaceInfoOSX *)context);
-}
-#endif
-
-mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win)
-{
- LogMsg("mDNSPlatformSendKeepalive called\n");
- mDNSSendKeepalive(sadd->ip.v6.b, dadd->ip.v6.b, lport->NotAnInteger, rport->NotAnInteger, seq, ack, win);
-}
-
-mDNSexport mStatus mDNSPlatformClearSPSMACAddr(void)
-{
- SCDynamicStoreRef store = NULL;
- CFStringRef entityname = NULL;
-
- if ((store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:ClearSPSMACAddress"), NULL, NULL)))
- {
- if ((entityname = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", "[^/]", "/BonjourSleepProxyAddress")))
- {
- if (SCDynamicStoreRemoveValue(store, entityname) == false)
- LogMsg("mDNSPlatformClearSPSMACAddr: Unable to remove key");
- }
- }
-
- if (entityname) CFRelease(entityname);
- if (store) CFRelease(store);
- return KERN_SUCCESS;
-}
-
-mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname)
-{
- int family = (spsaddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
- LogSPS("mDNSPlatformStoreSPSMACAddr : Storing %#a on interface %s", spsaddr, ifname);
- mDNSStoreSPSMACAddress(family, spsaddr->ip.v6.b, ifname);
- return KERN_SUCCESS;
-}
-
-mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNS *const m, mDNSAddr *raddr)
-{
- int family = (raddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
-
- mDNSGetRemoteMAC(m, family, raddr->ip.v6.b);
- return KERN_SUCCESS;
-}
-
-mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNS *const m, mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
-{
- mDNSs32 intfid;
- mDNSs32 error = 0;
- int family = (laddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
-
- error = mDNSRetrieveTCPInfo(family, laddr->ip.v6.b, lport->NotAnInteger, raddr->ip.v6.b, rport->NotAnInteger, (uint32_t *)&(mti->seq), (uint32_t *)&(mti->ack), (uint16_t *)&(mti->window), (int32_t*)&intfid);
- if (error != KERN_SUCCESS)
- {
- LogMsg("%s: mDNSRetrieveTCPInfo returned : %d", __func__, error);
- return error;
- }
- mti->IntfId = mDNSPlatformInterfaceIDfromInterfaceIndex(m, intfid);
- return error;
-}
-
-#define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
-
-mDNSlocal int CountProxyTargets(mDNS *const m, NetworkInterfaceInfoOSX *x, int *p4, int *p6)
-{
- int numv4 = 0, numv6 = 0;
- AuthRecord *rr;
-
- for (rr = m->ResourceRecords; rr; rr=rr->next)
- if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
- {
- if (p4) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x->BPF_fd, x->ifinfo.ifname, numv4, &rr->AddressProxy.ip.v4);
- numv4++;
- }
-
- for (rr = m->ResourceRecords; rr; rr=rr->next)
- if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
- {
- if (p6) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x->BPF_fd, x->ifinfo.ifname, numv6, &rr->AddressProxy.ip.v6);
- numv6++;
- }
-
- if (p4) *p4 = numv4;
- if (p6) *p6 = numv6;
- return(numv4 + numv6);
-}
-
-mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
-{
- NetworkInterfaceInfoOSX *x;
-
- // Note: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also.
- for (x = m->p->InterfaceList; x; x = x->next) if (x->ifinfo.InterfaceID == InterfaceID) break;
-
- if (!x) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID); return; }
-
- #define MAX_BPF_ADDRS 250
- int numv4 = 0, numv6 = 0;
-
- if (CountProxyTargets(m, x, &numv4, &numv6) > MAX_BPF_ADDRS)
- {
- LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4, numv6);
- if (numv4 > MAX_BPF_ADDRS) numv4 = MAX_BPF_ADDRS;
- numv6 = MAX_BPF_ADDRS - numv4;
- }
-
- LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC %.6a %d v4 %d v6", x->BPF_fd, x->ifinfo.ifname, &x->ifinfo.MAC, numv4, numv6);
-
- // Caution: This is a static structure, so we need to be careful that any modifications we make to it
- // are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times
- static struct bpf_insn filter[17 + MAX_BPF_ADDRS] =
- {
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), // 0 Read Ethertype (bytes 12,13)
-
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0806, 0, 1), // 1 If Ethertype == ARP goto next, else 3
- BPF_STMT(BPF_RET + BPF_K, 42), // 2 Return 42-byte ARP
-
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0800, 4, 0), // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
-
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x86DD, 0, 9), // 4 If Ethertype == IPv6 goto next, else exit
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), // 5 Read Protocol and Hop Limit (bytes 20,21)
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x3AFF, 0, 9), // 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check
- BPF_STMT(BPF_RET + BPF_K, 86), // 7 Return 86-byte ND
-
- // Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for
- BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 30), // 8 Read IPv4 Dst (bytes 30,31,32,33)
- };
-
- struct bpf_insn *pc = &filter[9];
- struct bpf_insn *chk6 = pc + numv4 + 1; // numv4 address checks, plus a "return 0"
- struct bpf_insn *fail = chk6 + 1 + numv6; // Get v6 Dst LSW, plus numv6 address checks
- struct bpf_insn *ret4 = fail + 1;
- struct bpf_insn *ret6 = ret4 + 4;
-
- static const struct bpf_insn rf = BPF_STMT(BPF_RET + BPF_K, 0); // No match: Return nothing
-
- static const struct bpf_insn g6 = BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 50); // Read IPv6 Dst LSW (bytes 50,51,52,53)
-
- static const struct bpf_insn r4a = BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14); // Get IP Header length (normally 20)
- static const struct bpf_insn r4b = BPF_STMT(BPF_LD + BPF_IMM, 54); // A = 54 (14-byte Ethernet plus 20-byte TCP + 20 bytes spare)
- static const struct bpf_insn r4c = BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0); // A += IP Header length
- static const struct bpf_insn r4d = BPF_STMT(BPF_RET + BPF_A, 0); // Success: Return Ethernet + IP + TCP + 20 bytes spare (normally 74)
-
- static const struct bpf_insn r6a = BPF_STMT(BPF_RET + BPF_K, 94); // Success: Return Eth + IPv6 + TCP + 20 bytes spare
-
- BPF_SetOffset(&filter[4], jf, fail); // If Ethertype not ARP, IPv4, or IPv6, fail
- BPF_SetOffset(&filter[6], jf, chk6); // If IPv6 but not ICMPv6, go to IPv6 address list check
-
- // BPF Byte-Order Note
- // The BPF API designers apparently thought that programmers would not be smart enough to use htons
- // and htonl correctly to convert numeric values to network byte order on little-endian machines,
- // so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings
- // that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc.
- // As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API
- // will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange
- // that on little-endian machines we deliberately put addresses in memory with the bytes backwards,
- // so that when the BPF API goes through and swaps them all, they end up back as they should be.
- // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't*
- // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly.
-
- // IPSEC capture size notes:
- // 8 bytes UDP header
- // 4 bytes Non-ESP Marker
- // 28 bytes IKE Header
- // --
- // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet.
-
- AuthRecord *rr;
- for (rr = m->ResourceRecords; rr; rr=rr->next)
- if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
- {
- mDNSv4Addr a = rr->AddressProxy.ip.v4;
- pc->code = BPF_JMP + BPF_JEQ + BPF_K;
- BPF_SetOffset(pc, jt, ret4);
- pc->jf = 0;
- pc->k = (bpf_u_int32)a.b[0] << 24 | (bpf_u_int32)a.b[1] << 16 | (bpf_u_int32)a.b[2] << 8 | (bpf_u_int32)a.b[3];
- pc++;
- }
- *pc++ = rf;
-
- if (pc != chk6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc, chk6);
- *pc++ = g6; // chk6 points here
-
- // First cancel any previous ND group memberships we had, then create a fresh socket
- if (x->BPF_mcfd >= 0) close(x->BPF_mcfd);
- x->BPF_mcfd = socket(AF_INET6, SOCK_DGRAM, 0);
-
- for (rr = m->ResourceRecords; rr; rr=rr->next)
- if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
- {
- const mDNSv6Addr *const a = &rr->AddressProxy.ip.v6;
- pc->code = BPF_JMP + BPF_JEQ + BPF_K;
- BPF_SetOffset(pc, jt, ret6);
- pc->jf = 0;
- pc->k = (bpf_u_int32)a->b[0x0C] << 24 | (bpf_u_int32)a->b[0x0D] << 16 | (bpf_u_int32)a->b[0x0E] << 8 | (bpf_u_int32)a->b[0x0F];
- pc++;
-
- struct ipv6_mreq i6mr;
- i6mr.ipv6mr_interface = x->scope_id;
- i6mr.ipv6mr_multiaddr = *(const struct in6_addr*)&NDP_prefix;
- i6mr.ipv6mr_multiaddr.s6_addr[0xD] = a->b[0xD];
- i6mr.ipv6mr_multiaddr.s6_addr[0xE] = a->b[0xE];
- i6mr.ipv6mr_multiaddr.s6_addr[0xF] = a->b[0xF];
-
- // Do precautionary IPV6_LEAVE_GROUP first, necessary to clear stale kernel state
- mStatus err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
- if (err < 0 && (errno != EADDRNOTAVAIL))
- LogMsg("mDNSPlatformUpdateProxyList: IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
-
- err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
- if (err < 0 && (errno != EADDRINUSE)) // Joining same group twice can give "Address already in use" error -- no need to report that
- LogMsg("mDNSPlatformUpdateProxyList: IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
-
- LogSPS("Joined IPv6 ND multicast group %.16a for %.16a", &i6mr.ipv6mr_multiaddr, a);
- }
-
- if (pc != fail) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc, fail);
- *pc++ = rf; // fail points here
-
- if (pc != ret4) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc, ret4);
- *pc++ = r4a; // ret4 points here
- *pc++ = r4b;
- *pc++ = r4c;
- *pc++ = r4d;
-
- if (pc != ret6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc, ret6);
- *pc++ = r6a; // ret6 points here
-
- struct bpf_program prog = { pc - filter, filter };
-
-#if 0
- // For debugging BPF filter program
- unsigned int q;
- for (q=0; q<prog.bf_len; q++)
- LogSPS("mDNSPlatformUpdateProxyList: %2d { 0x%02x, %d, %d, 0x%08x },", q, prog.bf_insns[q].code, prog.bf_insns[q].jt, prog.bf_insns[q].jf, prog.bf_insns[q].k);
-#endif
-
- if (!numv4 && !numv6)
- {
- LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
- if (m->timenow == 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
- // Schedule check to see if we can close this BPF_fd now
- if (!m->p->NetworkChanged) m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
- // prog.bf_len = 0; This seems to panic the kernel
- if (x->BPF_fd < 0) return; // If we've already closed our BPF_fd, no need to generate an error message below
- }
-
- if (ioctl(x->BPF_fd, BIOCSETFNR, &prog) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) failed %d (%s)", prog.bf_len, errno, strerror(errno));
- else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) successful", prog.bf_len);
-}
-
-mDNSexport void mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd)
-{
- mDNS_Lock(m);
-
- NetworkInterfaceInfoOSX *i;
- for (i = m->p->InterfaceList; i; i = i->next) if (i->BPF_fd == -2) break;
- if (!i) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd); close(fd); }
- else
- {
- LogSPS("%s using BPF fd %d", i->ifinfo.ifname, fd);
-
- struct bpf_version v;
- if (ioctl(fd, BIOCVERSION, &v) < 0)
- LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
- else if (BPF_MAJOR_VERSION != v.bv_major || BPF_MINOR_VERSION != v.bv_minor)
- LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d",
- fd, i->ifinfo.ifname, BPF_MAJOR_VERSION, BPF_MINOR_VERSION, v.bv_major, v.bv_minor);
-
- if (ioctl(fd, BIOCGBLEN, &i->BPF_len) < 0)
- LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
-
- if (i->BPF_len > sizeof(m->imsg))
- {
- i->BPF_len = sizeof(m->imsg);
- if (ioctl(fd, BIOCSBLEN, &i->BPF_len) < 0)
- LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
- else
- LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", fd, i->ifinfo.ifname, i->BPF_len);
- }
-
- static const u_int opt_one = 1;
- if (ioctl(fd, BIOCIMMEDIATE, &opt_one) < 0)
- LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
-
- //if (ioctl(fd, BIOCPROMISC, &opt_one) < 0)
- // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
-
- //if (ioctl(fd, BIOCSHDRCMPLT, &opt_one) < 0)
- // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
-
- /* <rdar://problem/10287386>
- * make socket non blocking see comments in bpf_callback_common for more info
- */
- if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
- {
- LogMsg("mDNSPlatformReceiveBPF_fd: %d %s O_NONBLOCK failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
- }
-
- struct ifreq ifr;
- mDNSPlatformMemZero(&ifr, sizeof(ifr));
- strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
- if (ioctl(fd, BIOCSETIF, &ifr) < 0)
- { LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); i->BPF_fd = -3; }
- else
- {
-#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
- i->BPF_fd = fd;
- i->BPF_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, dispatch_get_main_queue());
- if (!i->BPF_source) {LogMsg("mDNSPlatformReceiveBPF_fd: dispatch source create failed"); return;}
- dispatch_source_set_event_handler(i->BPF_source, ^{bpf_callback_dispatch(i);});
- dispatch_source_set_cancel_handler(i->BPF_source, ^{close(fd);});
- dispatch_resume(i->BPF_source);
-#else
- CFSocketContext myCFSocketContext = { 0, i, NULL, NULL, NULL };
- i->BPF_fd = fd;
- i->BPF_cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, bpf_callback, &myCFSocketContext);
- i->BPF_rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, i->BPF_cfs, 0);
- CFRunLoopAddSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode);
-#endif
- mDNSPlatformUpdateProxyList(m, i->ifinfo.InterfaceID);
- }
- }
-
- mDNS_Unlock(m);
-}
-
-#endif // APPLE_OSX_mDNSResponder
-
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - Key Management
-#endif
-
-#ifndef NO_SECURITYFRAMEWORK
-mDNSlocal CFArrayRef GetCertChain(SecIdentityRef identity)
-{
- CFMutableArrayRef certChain = NULL;
- if (!identity) { LogMsg("getCertChain: identity is NULL"); return(NULL); }
- SecCertificateRef cert;
- OSStatus err = SecIdentityCopyCertificate(identity, &cert);
- if (err || !cert) LogMsg("getCertChain: SecIdentityCopyCertificate() returned %d", (int) err);
- else
- {
- SecPolicySearchRef searchRef;
- err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
- if (err || !searchRef) LogMsg("getCertChain: SecPolicySearchCreate() returned %d", (int) err);
- else
- {
- SecPolicyRef policy;
- err = SecPolicySearchCopyNext(searchRef, &policy);
- if (err || !policy) LogMsg("getCertChain: SecPolicySearchCopyNext() returned %d", (int) err);
- else
- {
- CFArrayRef wrappedCert = CFArrayCreate(NULL, (const void**) &cert, 1, &kCFTypeArrayCallBacks);
- if (!wrappedCert) LogMsg("getCertChain: wrappedCert is NULL");
- else
- {
- SecTrustRef trust;
- err = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
- if (err || !trust) LogMsg("getCertChain: SecTrustCreateWithCertificates() returned %d", (int) err);
- else
- {
- err = SecTrustEvaluate(trust, NULL);
- if (err) LogMsg("getCertChain: SecTrustEvaluate() returned %d", (int) err);
- else
- {
- CFArrayRef rawCertChain;
- CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
- err = SecTrustGetResult(trust, NULL, &rawCertChain, &statusChain);
- if (err || !rawCertChain || !statusChain) LogMsg("getCertChain: SecTrustGetResult() returned %d", (int) err);
- else
- {
- certChain = CFArrayCreateMutableCopy(NULL, 0, rawCertChain);
- if (!certChain) LogMsg("getCertChain: certChain is NULL");
- else
- {
- // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
- // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
- CFArraySetValueAtIndex(certChain, 0, identity);
- // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
- if (CFArrayGetCount(certChain) > 1) CFArrayRemoveValueAtIndex(certChain, CFArrayGetCount(certChain) - 1);
- }
- CFRelease(rawCertChain);
- // Do not free statusChain:
- // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
- // certChain: Call the CFRelease function to release this object when you are finished with it.
- // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
- }
- }
- CFRelease(trust);
- }
- CFRelease(wrappedCert);
- }
- CFRelease(policy);
- }
- CFRelease(searchRef);
- }
- CFRelease(cert);
- }
- return certChain;
-}
-#endif /* NO_SECURITYFRAMEWORK */
-
-mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
-{
-#ifdef NO_SECURITYFRAMEWORK
- return mStatus_UnsupportedErr;
-#else
- SecIdentityRef identity = nil;
- SecIdentitySearchRef srchRef = nil;
- OSStatus err;
-
- // search for "any" identity matching specified key use
- // In this app, we expect there to be exactly one
- err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_DECRYPT, &srchRef);
- if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err); return err; }
-
- err = SecIdentitySearchCopyNext(srchRef, &identity);
- if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err); return err; }
-
- if (CFGetTypeID(identity) != SecIdentityGetTypeID())
- { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr; }
-
- // Found one. Call getCertChain to create the correct certificate chain.
- ServerCerts = GetCertChain(identity);
- if (ServerCerts == nil) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: getCertChain error"); return mStatus_UnknownErr; }
-
- return mStatus_NoError;
-#endif /* NO_SECURITYFRAMEWORK */
-}
-
-mDNSexport void mDNSPlatformTLSTearDownCerts(void)
-{
-#ifndef NO_SECURITYFRAMEWORK
- if (ServerCerts) { CFRelease(ServerCerts); ServerCerts = NULL; }
-#endif /* NO_SECURITYFRAMEWORK */
-}
-
-// This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
-mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
-{
- CFStringEncoding encoding = kCFStringEncodingUTF8;
- CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
- if (cfs)
- {
- CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
- CFRelease(cfs);
- }
-}
-
-// This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
-mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
-{
- CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
- if (cfs)
- {
- CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
- CFRelease(cfs);
- }
-}
-
-mDNSexport mDNSBool DictionaryIsEnabled(CFDictionaryRef dict)
-{
- mDNSs32 val;
- CFNumberRef state = (CFNumberRef)CFDictionaryGetValue(dict, CFSTR("Enabled"));
- if (!state) return mDNSfalse;
- if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val))
- { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse; }
- return val ? mDNStrue : mDNSfalse;
-}
-
-mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
-{
- if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
-
- if (sa->sa_family == AF_INET)
- {
- struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
- ip->type = mDNSAddrType_IPv4;
- ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
- return(mStatus_NoError);
- }
-
- if (sa->sa_family == AF_INET6)
- {
- struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
- // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
- // value into the second word of the IPv6 link-local address, so they can just
- // pass around IPv6 address structures instead of full sockaddr_in6 structures.
- // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
- // To work around this we always whack the second word of any IPv6 link-local address back to zero.
- if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
- ip->type = mDNSAddrType_IPv6;
- ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
- return(mStatus_NoError);
- }
-
- LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
- return(mStatus_Invalid);
-}
-
-mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name)
-{
- mDNSEthAddr eth = zeroEthAddr;
- SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetBSSID"), NULL, NULL);
- if (!store)
- LogMsg("GetBSSID: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
- else
- {
- CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name);
- if (entityname)
- {
- CFDictionaryRef dict = SCDynamicStoreCopyValue(store, entityname);
- if (dict)
- {
- CFRange range = { 0, 6 }; // Offset, length
- CFDataRef data = CFDictionaryGetValue(dict, CFSTR("BSSID"));
- if (data && CFDataGetLength(data) == 6) CFDataGetBytes(data, range, eth.b);
- CFRelease(dict);
- }
- CFRelease(entityname);
- }
- CFRelease(store);
- }
- return(eth);
-}
-
-mDNSlocal int GetMAC(mDNSEthAddr *eth, u_short ifindex)
-{
- struct ifaddrs *ifa;
- for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
- if (ifa->ifa_addr->sa_family == AF_LINK)
- {
- const struct sockaddr_dl *const sdl = (const struct sockaddr_dl *)ifa->ifa_addr;
- if (sdl->sdl_index == ifindex)
- { mDNSPlatformMemCopy(eth->b, sdl->sdl_data + sdl->sdl_nlen, 6); return 0; }
- }
- *eth = zeroEthAddr;
- return -1;
-}
-
-#ifndef SIOCGIFWAKEFLAGS
-#define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
-#endif
-
-#ifndef IF_WAKE_ON_MAGIC_PACKET
-#define IF_WAKE_ON_MAGIC_PACKET 0x01
-#endif
-
-#ifndef ifr_wake_flags
-#define ifr_wake_flags ifr_ifru.ifru_intval
-#endif
-
-mDNSlocal mDNSBool CheckInterfaceSupport(NetworkInterfaceInfo *const intf, const char *key)
-{
- io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
- if (!service)
- {
- LogSPS("CheckInterfaceSupport: No service for interface %s", intf->ifname);
- return mDNSfalse;
- }
-
- io_name_t n1, n2;
- IOObjectGetClass(service, n1);
- io_object_t parent;
- mDNSBool ret = mDNSfalse;
- kern_return_t kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
- if (kr == KERN_SUCCESS)
- {
- CFStringRef keystr = CFStringCreateWithCString(NULL, key, kCFStringEncodingUTF8);
- IOObjectGetClass(parent, n2);
- LogSPS("CheckInterfaceSupport: Interface %s service %s parent %s", intf->ifname, n1, n2);
- const CFTypeRef ref = IORegistryEntryCreateCFProperty(parent, keystr, kCFAllocatorDefault, mDNSNULL);
- if (!ref)
- {
- LogSPS("CheckInterfaceSupport: No mDNS_IOREG_KEY for interface %s/%s/%s", intf->ifname, n1, n2);
- ret = mDNSfalse;
- }
- else
- {
- ret = mDNStrue;
- CFRelease(ref);
- }
- IOObjectRelease(parent);
- CFRelease(keystr);
- }
- else
- {
- LogSPS("CheckInterfaceSupport: IORegistryEntryGetParentEntry for %s/%s failed %d", intf->ifname, n1, kr);
- ret = mDNSfalse;
- }
- IOObjectRelease(service);
- return ret;
-}
-
-
-mDNSlocal mDNSBool InterfaceSupportsKeepAlive(NetworkInterfaceInfo *const intf)
-{
- return CheckInterfaceSupport(intf, mDNS_IOREG_KA_KEY);
-}
-
-mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i)
-{
- if (!MulticastInterface(i) ) return(mDNSfalse); // We only use Sleep Proxy Service on multicast-capable interfaces
- if (i->ifa_flags & IFF_LOOPBACK) return(mDNSfalse); // except loopback
-
- // If the interface supports TCPKeepalive, it is capable of waking up for a magic packet
- // This check is needed since the SIOCGIFWAKEFLAGS ioctl returns wrong values for WOMP capability
- // when the power source is not AC Power.
- if (InterfaceSupportsKeepAlive(&i->ifinfo))
- {
- LogSPS("NetWakeInterface: %s supports TCP Keepalive returning true", i->ifinfo.ifname);
- return mDNStrue;
- }
-
- int s = socket(AF_INET, SOCK_DGRAM, 0);
- if (s < 0) { LogMsg("NetWakeInterface socket failed %s error %d errno %d (%s)", i->ifinfo.ifname, s, errno, strerror(errno)); return(mDNSfalse); }
-
- struct ifreq ifr;
- strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
- if (ioctl(s, SIOCGIFWAKEFLAGS, &ifr) < 0)
- {
- // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be
- // 102 when compiling kernel code, and 45 when compiling user-level code. Since this
- // error code is being returned from the kernel, we need to use the kernel version.
- #define KERNEL_EOPNOTSUPP 102
- if (errno != KERNEL_EOPNOTSUPP) // "Operation not supported on socket", the expected result on Leopard and earlier
- LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i->ifinfo.ifname, errno, strerror(errno));
- // If on Leopard or earlier, we get EOPNOTSUPP, so in that case
- // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on.
- ifr.ifr_wake_flags = (errno == KERNEL_EOPNOTSUPP && !(i)->BSSID.l[0] && i->m->SystemWakeOnLANEnabled) ? IF_WAKE_ON_MAGIC_PACKET : 0;
- }
-
- close(s);
-
- // ifr.ifr_wake_flags = IF_WAKE_ON_MAGIC_PACKET; // For testing with MacBook Air, using a USB dongle that doesn't actually support Wake-On-LAN
-
- LogSPS("%-6s %#-14a %s WOMP", i->ifinfo.ifname, &i->ifinfo.ip, (ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) ? "supports" : "no");
-
- return((ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) != 0);
-}
-
-mDNSlocal u_int64_t getExtendedFlags(char * ifa_name)
-{
- int sockFD;
- struct ifreq ifr;
-
- sockFD = socket(AF_INET, SOCK_DGRAM, 0);
- if (sockFD < 0)
- {
- LogMsg("getExtendedFlags: socket() call failed, errno = %d (%s)", errno, strerror(errno));
- return 0;
- }
-
- ifr.ifr_addr.sa_family = AF_INET;
- strlcpy(ifr.ifr_name, ifa_name, sizeof(ifr.ifr_name));
-
- if (ioctl(sockFD, SIOCGIFEFLAGS, (caddr_t)&ifr) == -1)
- {
- LogMsg("getExtendedFlags: SIOCGIFEFLAGS failed, errno = %d (%s)", errno, strerror(errno));
- ifr.ifr_eflags = 0;
- }
- LogInfo("getExtendedFlags: %s ifr_eflags = 0x%x", ifa_name, ifr.ifr_eflags);
-
- close(sockFD);
- return ifr.ifr_eflags;
-}
-
-// Returns pointer to newly created NetworkInterfaceInfoOSX object, or
-// pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
-// may return NULL if out of memory (unlikely) or parameters are invalid for some reason
-// (e.g. sa_family not AF_INET or AF_INET6)
-mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa, mDNSs32 utc)
-{
- mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
- mDNSEthAddr bssid = GetBSSID(ifa->ifa_name);
- u_int64_t eflags = getExtendedFlags(ifa->ifa_name);
-
- mDNSAddr ip, mask;
- if (SetupAddr(&ip, ifa->ifa_addr ) != mStatus_NoError) return(NULL);
- if (SetupAddr(&mask, ifa->ifa_netmask) != mStatus_NoError) return(NULL);
-
- NetworkInterfaceInfoOSX **p;
- for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
- if (scope_id == (*p)->scope_id &&
- mDNSSameAddress(&ip, &(*p)->ifinfo.ip) &&
- mDNSSameEthAddress(&bssid, &(*p)->BSSID))
- {
- debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p, ifname before %s, after %s", scope_id, &bssid, &ip, *p, (*p)->ifinfo.ifname, ifa->ifa_name);
- // The name should be updated to the new name so that we don't report a wrong name in our SIGINFO output.
- // When interfaces are created with same MAC address, kernel resurrects the old interface.
- // Even though the interface index is the same (which should be sufficient), when we receive a UDP packet
- // we get the corresponding name for the interface index on which the packet was received and check against
- // the InterfaceList for a matching name. So, keep the name in sync
- strlcpy((*p)->ifinfo.ifname, ifa->ifa_name, sizeof((*p)->ifinfo.ifname));
- (*p)->Exists = mDNStrue;
- // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
- if ((*p)->LastSeen != utc) (*p)->AppearanceTime = utc;
-
- // If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected)
- // we may need to start or stop or sleep proxy browse operation
- const mDNSBool NetWake = NetWakeInterface(*p);
- if ((*p)->ifinfo.NetWake != NetWake)
- {
- (*p)->ifinfo.NetWake = NetWake;
- // If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly.
- // If this interface is not already registered (i.e. it's a dormant interface we had in our list
- // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet.
- // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary.
- if ((*p)->Registered)
- {
- mDNS_Lock(m);
- if (NetWake) mDNS_ActivateNetWake_internal (m, &(*p)->ifinfo);
- else mDNS_DeactivateNetWake_internal(m, &(*p)->ifinfo);
- mDNS_Unlock(m);
- }
- }
- // Reset the flag if it has changed this time.
- (*p)->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue;
-
- return(*p);
- }
-
- NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
- debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
- if (!i) return(mDNSNULL);
- mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX));
- i->ifinfo.InterfaceID = (mDNSInterfaceID)(uintptr_t)scope_id;
- i->ifinfo.ip = ip;
- i->ifinfo.mask = mask;
- strlcpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
- i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0;
- // We can be configured to disable multicast advertisement, but we want to to support
- // local-only services, which need a loopback address record.
- i->ifinfo.Advertise = m->DivertMulticastAdvertisements ? ((ifa->ifa_flags & IFF_LOOPBACK) ? mDNStrue : mDNSfalse) : m->AdvertiseLocalAddresses;
- i->ifinfo.McastTxRx = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList
- i->ifinfo.Loopback = ((ifa->ifa_flags & IFF_LOOPBACK) != 0) ? mDNStrue : mDNSfalse;
- i->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue;
- i->ifinfo.DirectLink = (eflags & IFEF_DIRECTLINK) ? mDNStrue: mDNSfalse;
-
- i->next = mDNSNULL;
- i->m = m;
- i->Exists = mDNStrue;
- i->Flashing = mDNSfalse;
- i->Occulting = mDNSfalse;
- i->D2DInterface = (eflags & IFEF_LOCALNET_PRIVATE) ? mDNStrue: mDNSfalse;
- if (eflags & IFEF_AWDL)
- {
- AWDLInterfaceID = i->ifinfo.InterfaceID;
- LogInfo("AddInterfaceToList: AWDLInterfaceID = %d", (int) AWDLInterfaceID);
- }
- i->AppearanceTime = utc; // Brand new interface; AppearanceTime is now
- i->LastSeen = utc;
- i->ifa_flags = ifa->ifa_flags;
- i->scope_id = scope_id;
- i->BSSID = bssid;
- i->sa_family = ifa->ifa_addr->sa_family;
- i->BPF_fd = -1;
- i->BPF_mcfd = -1;
- i->BPF_len = 0;
- i->Registered = mDNSNULL;
-
- // Do this AFTER i->BSSID has been set up
- i->ifinfo.NetWake = NetWakeInterface(i);
- GetMAC(&i->ifinfo.MAC, scope_id);
- if (i->ifinfo.NetWake && !i->ifinfo.MAC.l[0])
- LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i->ifinfo.MAC, scope_id, i->ifinfo.ifname, &ip);
-
- *p = i;
- return(i);
-}
-
-#if APPLE_OSX_mDNSResponder
-
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - AutoTunnel
-#endif
-
-#define kRacoonPort 4500
-
-static DomainAuthInfo* AnonymousRacoonConfig = mDNSNULL;
-
-#ifndef NO_SECURITYFRAMEWORK
-
-static CFMutableDictionaryRef domainStatusDict = NULL;
-
-mDNSlocal mStatus CheckQuestionForStatus(const DNSQuestion *const q)
-{
- if (q->LongLived)
- {
- if (q->servAddr.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsOnes(q->servAddr.ip.v4))
- return mStatus_NoSuchRecord;
- else if (q->state == LLQ_Poll)
- return mStatus_PollingMode;
- else if (q->state != LLQ_Established && !q->DuplicateOf)
- return mStatus_TransientErr;
- }
-
- return mStatus_NoError;
-}
-
-mDNSlocal mStatus UpdateLLQStatus(const mDNS *const m, char *buffer, int bufsz, const DomainAuthInfo *const info)
-{
- mStatus status = mStatus_NoError;
- DNSQuestion* q, *worst_q = mDNSNULL;
- for (q = m->Questions; q; q=q->next)
- if (q->AuthInfo == info)
- {
- mStatus newStatus = CheckQuestionForStatus(q);
- if (newStatus == mStatus_NoSuchRecord) { status = newStatus; worst_q = q; break; }
- else if (newStatus == mStatus_PollingMode) { status = newStatus; worst_q = q; }
- else if (newStatus == mStatus_TransientErr && status == mStatus_NoError) { status = newStatus; worst_q = q; }
- }
-
- if (status == mStatus_NoError) mDNS_snprintf(buffer, bufsz, "Success");
- else if (status == mStatus_NoSuchRecord) mDNS_snprintf(buffer, bufsz, "GetZoneData %s: %##s", worst_q->nta ? "not yet complete" : "failed", worst_q->qname.c);
- else if (status == mStatus_PollingMode) mDNS_snprintf(buffer, bufsz, "Query polling %##s", worst_q->qname.c);
- else if (status == mStatus_TransientErr) mDNS_snprintf(buffer, bufsz, "Query not yet established %##s", worst_q->qname.c);
- return status;
-}
-
-mDNSlocal mStatus UpdateRRStatus(const mDNS *const m, char *buffer, int bufsz, const DomainAuthInfo *const info)
-{
- AuthRecord *r;
-
- if (info->deltime) return mStatus_NoError;
- for (r = m->ResourceRecords; r; r = r->next)
- {
- // This function is called from UpdateAutoTunnelDomainStatus which in turn may be called from
- // a callback e.g., CheckNATMappings. GetAuthInfoFor_internal does not like that (reentrancy being 1),
- // hence we inline the code here. We just need the lock to walk the list of AuthInfos which the caller
- // has already checked
- const domainname *n = r->resrec.name;
- while (n->c[0])
- {
- DomainAuthInfo *ptr;
- for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
- if (SameDomainName(&ptr->domain, n))
- {
- if (ptr == info && (r->updateError == mStatus_BadSig || r->updateError == mStatus_BadKey || r->updateError == mStatus_BadTime))
- {
- mDNS_snprintf(buffer, bufsz, "Resource record update failed for %##s", r->resrec.name);
- return r->updateError;
- }
- }
- n = (const domainname *)(n->c + 1 + n->c[0]);
- }
- }
- return mStatus_NoError;
-}
-
-#endif // ndef NO_SECURITYFRAMEWORK
-
-// MUST be called with lock held
-mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAuthInfo *const info)
-{
-#ifdef NO_SECURITYFRAMEWORK
- (void) m;
- (void)info;
-#else
- // Note that in the LLQNAT, the clientCallback being non-zero means it's in use,
- // whereas in the AutoTunnelNAT, the clientContext being non-zero means it's in use
- const NATTraversalInfo *const llq = m->LLQNAT.clientCallback ? &m->LLQNAT : mDNSNULL;
- const NATTraversalInfo *const tun = m->AutoTunnelNAT.clientContext ? &m->AutoTunnelNAT : mDNSNULL;
- char buffer[1024];
- mDNSu32 buflen = 0;
- CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- CFStringRef domain = NULL;
- CFStringRef tmp = NULL;
- CFNumberRef num = NULL;
- mStatus status = mStatus_NoError;
- mStatus llqStatus = mStatus_NoError;
- char llqBuffer[1024];
-
- mDNS_CheckLock(m);
-
- if (!domainStatusDict)
- {
- domainStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- if (!domainStatusDict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; }
- }
-
- if (!dict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; }
-
- buflen = mDNS_snprintf(buffer, sizeof(buffer), "%##s", info->domain.c);
- domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
- if (!domain) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString domain"); return; }
-
- if (info->deltime)
- {
- if (CFDictionaryContainsKey(domainStatusDict, domain))
- {
- CFDictionaryRemoveValue(domainStatusDict, domain);
- if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
- }
- CFRelease(domain);
- CFRelease(dict);
-
- return;
- }
-
- mDNS_snprintf(buffer, sizeof(buffer), "%#a", &m->Router);
- tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
- if (!tmp)
- LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress");
- else
- {
- CFDictionarySetValue(dict, CFSTR("RouterAddress"), tmp);
- CFRelease(tmp);
- }
-
- if (llq)
- {
- mDNSu32 port = mDNSVal16(llq->ExternalPort);
-
- num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
- if (!num)
- LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort");
- else
- {
- CFDictionarySetValue(dict, CFSTR("LLQExternalPort"), num);
- CFRelease(num);
- }
-
- if (llq->Result)
- {
- num = CFNumberCreate(NULL, kCFNumberSInt32Type, &llq->Result);
- if (!num)
- LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus");
- else
- {
- CFDictionarySetValue(dict, CFSTR("LLQNPMStatus"), num);
- CFRelease(num);
- }
- }
- }
-
- if (tun)
- {
- mDNSu32 port = mDNSVal16(tun->ExternalPort);
-
- num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
- if (!num)
- LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort");
- else
- {
- CFDictionarySetValue(dict, CFSTR("AutoTunnelExternalPort"), num);
- CFRelease(num);
- }
-
- mDNS_snprintf(buffer, sizeof(buffer), "%.4a", &tun->ExternalAddress);
- tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
- if (!tmp)
- LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress");
- else
- {
- CFDictionarySetValue(dict, CFSTR("ExternalAddress"), tmp);
- CFRelease(tmp);
- }
-
- if (tun->Result)
- {
- num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tun->Result);
- if (!num)
- LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus");
- else
- {
- CFDictionarySetValue(dict, CFSTR("AutoTunnelNPMStatus"), num);
- CFRelease(num);
- }
- }
- }
- if (tun || llq)
- {
- mDNSu32 code = m->LastNATMapResultCode;
-
- num = CFNumberCreate(NULL, kCFNumberSInt32Type, &code);
- if (!num)
- LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode");
- else
- {
- CFDictionarySetValue(dict, CFSTR("LastNATMapResultCode"), num);
- CFRelease(num);
- }
- }
-
- mDNS_snprintf(buffer, sizeof(buffer), "Success");
- llqStatus = UpdateLLQStatus(m, llqBuffer, sizeof(llqBuffer), info);
- status = UpdateRRStatus(m, buffer, sizeof(buffer), info);
-
- // If we have a bad signature error updating a RR, it overrides any error as it needs to be
- // reported so that it can be fixed automatically (or the user needs to be notified)
- if (status != mStatus_NoError)
- {
- LogInfo("UpdateAutoTunnelDomainStatus: RR Status %d, %s", status, buffer);
- }
- else if (m->Router.type == mDNSAddrType_None)
- {
- status = mStatus_NoRouter;
- mDNS_snprintf(buffer, sizeof(buffer), "No network connection - none");
- }
- else if (m->Router.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero(m->Router.ip.v4))
- {
- status = mStatus_NoRouter;
- mDNS_snprintf(buffer, sizeof(buffer), "No network connection - v4 zero");
- }
- else if (mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress))
- {
- status = mStatus_ServiceNotRunning;
- mDNS_snprintf(buffer, sizeof(buffer), "No inner address");
- }
- else if (!llq && !tun)
- {
- status = mStatus_NotInitializedErr;
- mDNS_snprintf(buffer, sizeof(buffer), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
- }
- else if (llqStatus == mStatus_NoSuchRecord)
- {
- status = llqStatus;
- mDNS_snprintf(buffer, sizeof(buffer), llqBuffer);
- }
- else if ((llq && llq->Result == mStatus_DoubleNAT) || (tun && tun->Result == mStatus_DoubleNAT))
- {
- status = mStatus_DoubleNAT;
- mDNS_snprintf(buffer, sizeof(buffer), "Double NAT: Router is reporting a private address");
- }
- else if ((llq && llq->Result == mStatus_NATPortMappingDisabled) ||
- (tun && tun->Result == mStatus_NATPortMappingDisabled) ||
- (m->LastNATMapResultCode == NATErr_Refused && ((llq && !llq->Result && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && !tun->Result && mDNSIPPortIsZero(tun->ExternalPort)))))
- {
- status = mStatus_NATPortMappingDisabled;
- mDNS_snprintf(buffer, sizeof(buffer), "PCP/NAT-PMP is disabled on the router");
- }
- else if ((llq && llq->Result) || (tun && tun->Result))
- {
- status = mStatus_NATTraversal;
- mDNS_snprintf(buffer, sizeof(buffer), "Error obtaining NAT port mapping from router");
- }
- else if ((llq && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && mDNSIPPortIsZero(tun->ExternalPort)))
- {
- status = mStatus_NATTraversal;
- mDNS_snprintf(buffer, sizeof(buffer), "Unable to obtain NAT port mapping from router");
- }
- else
- {
- status = llqStatus;
- mDNS_snprintf(buffer, sizeof(buffer), llqBuffer);
- LogInfo("UpdateAutoTunnelDomainStatus: LLQ Status %d, %s", status, buffer);
- }
-
- num = CFNumberCreate(NULL, kCFNumberSInt32Type, &status);
- if (!num)
- LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode");
- else
- {
- CFDictionarySetValue(dict, CFSTR("StatusCode"), num);
- CFRelease(num);
- }
-
- tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
- if (!tmp)
- LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage");
- else
- {
- CFDictionarySetValue(dict, CFSTR("StatusMessage"), tmp);
- CFRelease(tmp);
- }
-
- if (!CFDictionaryContainsKey(domainStatusDict, domain) ||
- !CFEqual(dict, (CFMutableDictionaryRef)CFDictionaryGetValue(domainStatusDict, domain)))
- {
- CFDictionarySetValue(domainStatusDict, domain, dict);
- if (!m->ShutdownTime)
- {
- static char statusBuf[16];
- mDNS_snprintf(statusBuf, sizeof(statusBuf), "%d", (int)status);
- mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.domainstatus", status ? "failure" : "success", statusBuf, "");
- mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
- }
- }
-
- CFRelease(domain);
- CFRelease(dict);
-
- debugf("UpdateAutoTunnelDomainStatus: %s", buffer);
-#endif // def NO_SECURITYFRAMEWORK
-}
-
-// MUST be called with lock held
-mDNSexport void UpdateAutoTunnelDomainStatuses(const mDNS *const m)
-{
-#ifdef NO_SECURITYFRAMEWORK
- (void) m;
-#else
- mDNS_CheckLock(m);
- DomainAuthInfo* info;
- for (info = m->AuthInfoList; info; info = info->next)
- if (info->AutoTunnel && !info->deltime)
- UpdateAutoTunnelDomainStatus(m, info);
-#endif // def NO_SECURITYFRAMEWORK
-}
-
-mDNSlocal void UpdateAnonymousRacoonConfig(mDNS *m) // Determine whether we need racoon to accept incoming connections
-{
- DomainAuthInfo *info;
-
- for (info = m->AuthInfoList; info; info = info->next)
- if (info->AutoTunnel && !info->deltime && (!mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || !mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr)))
- break;
-
- if (info != AnonymousRacoonConfig)
- {
- AnonymousRacoonConfig = info;
- // Create or revert configuration file, and start (or SIGHUP) Racoon
- (void)mDNSConfigureServer(AnonymousRacoonConfig ? kmDNSUp : kmDNSDown, AnonymousRacoonConfig ? btmmprefix : mDNSNULL, AnonymousRacoonConfig ? &AnonymousRacoonConfig->domain : mDNSNULL);
- }
-}
-
-mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
-
-// Caller must hold the lock
-mDNSlocal mDNSBool DeregisterAutoTunnelRecord(mDNS *m, DomainAuthInfo *info, AuthRecord* record)
-{
- mDNS_CheckLock(m);
-
- LogInfo("DeregisterAutoTunnelRecord %##s %##s", &info->domain.c, record->namestorage.c);
-
- if (record->resrec.RecordType > kDNSRecordTypeDeregistering)
- {
- mStatus err = mDNS_Deregister_internal(m, record, mDNS_Dereg_normal);
- if (err)
- {
- record->resrec.RecordType = kDNSRecordTypeUnregistered;
- LogMsg("DeregisterAutoTunnelRecord error %d deregistering %##s %##s", err, info->domain.c, record->namestorage.c);
- return mDNSfalse;
- }
- else LogInfo("DeregisterAutoTunnelRecord: Deregistered");
- }
- else LogInfo("DeregisterAutoTunnelRecord: Not deregistering, state:%d", record->resrec.RecordType);
-
- return mDNStrue;
-}
-
-// Caller must hold the lock
-mDNSlocal void DeregisterAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
-{
- if (!DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelHostRecord))
- {
- info->AutoTunnelHostRecord.namestorage.c[0] = 0;
- m->NextSRVUpdate = NonZeroTime(m->timenow);
- }
-}
-
-// Caller must hold the lock
-mDNSlocal void UpdateAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
-{
- mStatus err;
- mDNSBool NATProblem = mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result;
-
- mDNS_CheckLock(m);
-
- if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress) || (m->SleepState != SleepState_Awake && NATProblem))
- {
- LogInfo("UpdateAutoTunnelHostRecord: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) address(%.16a) sleepstate(%d)",
- info->domain.c, info->AutoTunnelServiceStarted, info->deltime, &info->AutoTunnelInnerAddress, m->SleepState);
- DeregisterAutoTunnelHostRecord(m, info);
- }
- else if (info->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered)
- {
- mDNS_SetupResourceRecord(&info->AutoTunnelHostRecord, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
- kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
- info->AutoTunnelHostRecord.namestorage.c[0] = 0;
- AppendDomainLabel(&info->AutoTunnelHostRecord.namestorage, &m->hostlabel);
- AppendDomainName (&info->AutoTunnelHostRecord.namestorage, &info->domain);
- info->AutoTunnelHostRecord.resrec.rdata->u.ipv6 = info->AutoTunnelInnerAddress;
- info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeKnownUnique;
-
- err = mDNS_Register_internal(m, &info->AutoTunnelHostRecord);
- if (err) LogMsg("UpdateAutoTunnelHostRecord error %d registering %##s", err, info->AutoTunnelHostRecord.namestorage.c);
- else
- {
- // Make sure we trigger the registration of all SRV records in regState_NoTarget again
- m->NextSRVUpdate = NonZeroTime(m->timenow);
- LogInfo("UpdateAutoTunnelHostRecord registering %##s", info->AutoTunnelHostRecord.namestorage.c);
- }
- }
- else LogInfo("UpdateAutoTunnelHostRecord: Type %d", info->AutoTunnelHostRecord.resrec.RecordType);
-}
-
-// Caller must hold the lock
-mDNSlocal void DeregisterAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
-{
- LogInfo("DeregisterAutoTunnelServiceRecords %##s", info->domain.c);
-
- DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelTarget);
- DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelService);
- UpdateAutoTunnelHostRecord(m, info);
-}
-
-// Caller must hold the lock
-mDNSlocal void UpdateAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
-{
- mDNS_CheckLock(m);
-
- if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result)
- {
- LogInfo("UpdateAutoTunnelServiceRecords: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) ExtPort(%d) NATResult(%d)", info->domain.c, info->AutoTunnelServiceStarted, info->deltime, mDNSVal16(m->AutoTunnelNAT.ExternalPort), m->AutoTunnelNAT.Result);
- DeregisterAutoTunnelServiceRecords(m, info);
- }
- else
- {
- if (info->AutoTunnelTarget.resrec.RecordType == kDNSRecordTypeUnregistered)
- {
- // 1. Set up our address record for the external tunnel address
- // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
- mDNS_SetupResourceRecord(&info->AutoTunnelTarget, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL,
- kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
- AssignDomainName (&info->AutoTunnelTarget.namestorage, (const domainname*) "\x0B" "_autotunnel");
- AppendDomainLabel(&info->AutoTunnelTarget.namestorage, &m->hostlabel);
- AppendDomainName (&info->AutoTunnelTarget.namestorage, &info->domain);
- info->AutoTunnelTarget.resrec.rdata->u.ipv4 = m->AutoTunnelNAT.ExternalAddress;
- info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeKnownUnique;
-
- mStatus err = mDNS_Register_internal(m, &info->AutoTunnelTarget);
- if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelTarget.namestorage.c);
- else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelTarget.namestorage.c);
- }
- else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Target state(%d)", info->AutoTunnelTarget.resrec.RecordType);
-
- if (info->AutoTunnelService.resrec.RecordType == kDNSRecordTypeUnregistered)
- {
- // 2. Set up IKE tunnel's SRV record: _autotunnel._udp.AutoTunnelHost SRV 0 0 port AutoTunnelTarget
- mDNS_SetupResourceRecord(&info->AutoTunnelService, mDNSNULL, mDNSInterface_Any, kDNSType_SRV, kHostNameTTL,
- kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
- AssignDomainName (&info->AutoTunnelService.namestorage, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
- AppendDomainLabel(&info->AutoTunnelService.namestorage, &m->hostlabel);
- AppendDomainName (&info->AutoTunnelService.namestorage, &info->domain);
- info->AutoTunnelService.resrec.rdata->u.srv.priority = 0;
- info->AutoTunnelService.resrec.rdata->u.srv.weight = 0;
- info->AutoTunnelService.resrec.rdata->u.srv.port = m->AutoTunnelNAT.ExternalPort;
- AssignDomainName(&info->AutoTunnelService.resrec.rdata->u.srv.target, &info->AutoTunnelTarget.namestorage);
- info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeKnownUnique;
-
- mStatus err = mDNS_Register_internal(m, &info->AutoTunnelService);
- if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelService.namestorage.c);
- else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelService.namestorage.c);
- }
- else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Service state(%d)", info->AutoTunnelService.resrec.RecordType);
-
- UpdateAutoTunnelHostRecord(m, info);
-
- LogInfo("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
- info->AutoTunnelTarget.namestorage.c, &m->AdvertisedV4.ip.v4, mDNSVal16(m->AutoTunnelNAT.IntPort),
- info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
-
- }
-}
-
-// Caller must hold the lock
-mDNSlocal void DeregisterAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
-{
- DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelDeviceInfo);
-}
-
-// Caller must hold the lock
-mDNSlocal void UpdateAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
-{
- mDNS_CheckLock(m);
-
- if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime)
- DeregisterAutoTunnelDeviceInfoRecord(m, info);
- else if (info->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered)
- {
- mDNS_SetupResourceRecord(&info->AutoTunnelDeviceInfo, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
- ConstructServiceName(&info->AutoTunnelDeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &info->domain);
-
- info->AutoTunnelDeviceInfo.resrec.rdlength = initializeDeviceInfoTXT(m, info->AutoTunnelDeviceInfo.resrec.rdata->u.data);
- info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeKnownUnique;
-
- mStatus err = mDNS_Register_internal(m, &info->AutoTunnelDeviceInfo);
- if (err) LogMsg("UpdateAutoTunnelDeviceInfoRecord error %d registering %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
- else LogInfo("UpdateAutoTunnelDeviceInfoRecord registering %##s", info->AutoTunnelDeviceInfo.namestorage.c);
- }
- else
- LogInfo("UpdateAutoTunnelDeviceInfoRecord: not in Unregistered state: %d",info->AutoTunnelDeviceInfo.resrec.RecordType);
-}
-
-// Caller must hold the lock
-mDNSlocal void DeregisterAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
-{
- LogInfo("DeregisterAutoTunnel6Record %##s", info->domain.c);
-
- DeregisterAutoTunnelRecord(m, info, &info->AutoTunnel6Record);
- UpdateAutoTunnelHostRecord(m, info);
- UpdateAutoTunnelDomainStatus(m, info);
-}
-
-// Caller must hold the lock
-mDNSlocal void UpdateAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
-{
- mDNS_CheckLock(m);
-
- if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr) || m->SleepState != SleepState_Awake)
- DeregisterAutoTunnel6Record(m, info);
- else if (info->AutoTunnel6Record.resrec.RecordType == kDNSRecordTypeUnregistered)
- {
- mDNS_SetupResourceRecord(&info->AutoTunnel6Record, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
- kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
- AssignDomainName (&info->AutoTunnel6Record.namestorage, (const domainname*) "\x0C" "_autotunnel6");
- AppendDomainLabel(&info->AutoTunnel6Record.namestorage, &m->hostlabel);
- AppendDomainName (&info->AutoTunnel6Record.namestorage, &info->domain);
- info->AutoTunnel6Record.resrec.rdata->u.ipv6 = m->AutoTunnelRelayAddr;
- info->AutoTunnel6Record.resrec.RecordType = kDNSRecordTypeKnownUnique;
-
- mStatus err = mDNS_Register_internal(m, &info->AutoTunnel6Record);
- if (err) LogMsg("UpdateAutoTunnel6Record error %d registering %##s", err, info->AutoTunnel6Record.namestorage.c);
- else LogInfo("UpdateAutoTunnel6Record registering %##s", info->AutoTunnel6Record.namestorage.c);
-
- UpdateAutoTunnelHostRecord(m, info);
-
- LogInfo("AutoTunnel6 server listening for connections on %##s[%.16a] :%##s[%.16a]",
- info->AutoTunnel6Record.namestorage.c, &m->AutoTunnelRelayAddr,
- info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
-
- }
- else LogInfo("UpdateAutoTunnel6Record NOOP state(%d)",info->AutoTunnel6Record.resrec.RecordType);
-}
-
-mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
-{
- DomainAuthInfo *info = (DomainAuthInfo *)rr->RecordContext;
- if (result == mStatus_MemFree)
- {
- LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr));
-
- mDNS_Lock(m);
-
- // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister
- if (rr == &info->AutoTunnelHostRecord)
- {
- rr->namestorage.c[0] = 0;
- m->NextSRVUpdate = NonZeroTime(m->timenow);
- LogInfo("AutoTunnelRecordCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
- }
- if (m->ShutdownTime)
- {
- LogInfo("AutoTunnelRecordCallback: Shutdown, returning");
- mDNS_Unlock(m);
- return;
- }
- if (rr == &info->AutoTunnelHostRecord)
- {
- LogInfo("AutoTunnelRecordCallback: calling UpdateAutoTunnelHostRecord");
- UpdateAutoTunnelHostRecord(m,info);
- }
- else if (rr == &info->AutoTunnelDeviceInfo)
- {
- LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelDeviceInfoRecord");
- UpdateAutoTunnelDeviceInfoRecord(m,info);
- }
- else if (rr == &info->AutoTunnelService || rr == &info->AutoTunnelTarget)
- {
- LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelServiceRecords");
- UpdateAutoTunnelServiceRecords(m,info);
- }
- else if (rr == &info->AutoTunnel6Record)
- {
- LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnel6Record");
- UpdateAutoTunnel6Record(m,info);
- }
-
- mDNS_Unlock(m);
- }
-}
-
-mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n)
-{
- DomainAuthInfo *info;
-
- LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d",
- n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort));
-
- mDNS_Lock(m);
-
- m->NextSRVUpdate = NonZeroTime(m->timenow);
- LogInfo("AutoTunnelNATCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
-
- for (info = m->AuthInfoList; info; info = info->next)
- if (info->AutoTunnel)
- UpdateAutoTunnelServiceRecords(m, info);
-
- UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
-
- UpdateAutoTunnelDomainStatuses(m);
-
- mDNS_Unlock(m);
-}
-
-mDNSlocal void AutoTunnelHostNameChanged(mDNS *m, DomainAuthInfo *info)
-{
- LogInfo("AutoTunnelHostNameChanged %#s.%##s", m->hostlabel.c, info->domain.c);
-
- mDNS_Lock(m);
- // We forcibly deregister the records that are based on the hostname.
- // When deregistration of each completes, the MemFree callback will make the
- // appropriate Update* call to use the new name to reregister.
- DeregisterAutoTunnelHostRecord(m, info);
- DeregisterAutoTunnelDeviceInfoRecord(m, info);
- DeregisterAutoTunnelServiceRecords(m, info);
- DeregisterAutoTunnel6Record(m, info);
- m->NextSRVUpdate = NonZeroTime(m->timenow);
- mDNS_Unlock(m);
-}
-
-// Must be called with the lock held
-mDNSexport void StartServerTunnel(mDNS *const m, DomainAuthInfo *const info)
-{
- if (info->deltime) return;
-
- if (info->AutoTunnelServiceStarted)
- {
- // On wake from sleep, this function will be called when determining SRV targets,
- // and needs to re-register the host record for the target to be set correctly
- UpdateAutoTunnelHostRecord(m, info);
- return;
- }
-
- info->AutoTunnelServiceStarted = mDNStrue;
-
- // Now that we have a service in this domain, we need to try to register the
- // AutoTunnel records, because the relay connection & NAT-T may have already been
- // started for another domain. If the relay connection is not up or the NAT-T has not
- // yet succeeded, the Update* functions are smart enough to not register the records.
- // Note: This should be done after we set AutoTunnelServiceStarted, as that variable is used to
- // decide whether to register the AutoTunnel records in the calls below.
- UpdateAutoTunnelServiceRecords(m, info);
- UpdateAutoTunnel6Record(m, info);
- UpdateAutoTunnelDeviceInfoRecord(m, info);
- UpdateAutoTunnelHostRecord(m, info);
-
- // If the global AutoTunnel NAT-T is not yet started, start it.
- if (!m->AutoTunnelNAT.clientContext)
- {
- m->AutoTunnelNAT.clientCallback = AutoTunnelNATCallback;
- m->AutoTunnelNAT.clientContext = (void*)1; // Means AutoTunnelNAT Traversal is active;
- m->AutoTunnelNAT.Protocol = NATOp_MapUDP;
- m->AutoTunnelNAT.IntPort = IPSECPort;
- m->AutoTunnelNAT.RequestedPort = IPSECPort;
- m->AutoTunnelNAT.NATLease = 0;
- mStatus err = mDNS_StartNATOperation_internal(m, &m->AutoTunnelNAT);
- if (err) LogMsg("StartServerTunnel: error %d starting NAT mapping", err);
- }
-}
-
-mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew)
-{
- mDNSv6Addr loc_outer6;
- mDNSv6Addr rmt_outer6;
-
- // When we are tunneling over IPv6 Relay address, the port number is zero
- if (mDNSIPPortIsZero(tun->rmt_outer_port))
- {
- loc_outer6 = tun->loc_outer6;
- rmt_outer6 = tun->rmt_outer6;
- }
- else
- {
- loc_outer6 = zerov6Addr;
- loc_outer6.b[0] = tun->loc_outer.b[0];
- loc_outer6.b[1] = tun->loc_outer.b[1];
- loc_outer6.b[2] = tun->loc_outer.b[2];
- loc_outer6.b[3] = tun->loc_outer.b[3];
-
- rmt_outer6 = zerov6Addr;
- rmt_outer6.b[0] = tun->rmt_outer.b[0];
- rmt_outer6.b[1] = tun->rmt_outer.b[1];
- rmt_outer6.b[2] = tun->rmt_outer.b[2];
- rmt_outer6.b[3] = tun->rmt_outer.b[3];
- }
-
- return(mDNSAutoTunnelSetKeys(AddNew ? kmDNSAutoTunnelSetKeysReplace : kmDNSAutoTunnelSetKeysDelete, tun->loc_inner.b, loc_outer6.b, kRacoonPort, tun->rmt_inner.b, rmt_outer6.b, mDNSVal16(tun->rmt_outer_port), btmmprefix, SkipLeadingLabels(&tun->dstname, 1)));
-}
-
-// If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
-#define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
-
-mDNSlocal void ReissueBlockedQuestionWithType(mDNS *const m, domainname *d, mDNSBool success, mDNSu16 qtype)
-{
- DNSQuestion *q = m->Questions;
- while (q)
- {
- if (q->NoAnswer == NoAnswer_Suspended && q->qtype == qtype && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
- {
- LogInfo("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- mDNSQuestionCallback *tmp = q->QuestionCallback;
- q->QuestionCallback = AutoTunnelCallback; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
- mDNS_StopQuery(m, q);
- mDNS_StartQuery(m, q);
- q->QuestionCallback = tmp; // Restore QuestionCallback back to the real value
- if (!success) q->NoAnswer = NoAnswer_Fail;
- // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too.
- // In general we have to assume that the question list might have changed in arbitrary ways.
- // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
- // already in use. The safest solution is just to go back to the start of the list and start again.
- // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
- // just one suspended question, so it's really a 2n algorithm.
- q = m->Questions;
- }
- else
- q = q->next;
- }
-}
-
-mDNSlocal void ReissueBlockedQuestions(mDNS *const m, domainname *d, mDNSBool success)
-{
- // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
- // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
- // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
- // even if the name does have a valid AAAA record, we don't want clients trying to connect to it without a properly encrypted tunnel.
- // 3. For A queries we never fabricate failures -- if a BTTM service is really using raw IPv4, then it doesn't need the IPv6 tunnel.
- ReissueBlockedQuestionWithType(m, d, success, kDNSType_AAAA);
- ReissueBlockedQuestionWithType(m, d, mDNStrue, kDNSType_A);
-}
-
-mDNSlocal void UnlinkAndReissueBlockedQuestions(mDNS *const m, ClientTunnel *tun, mDNSBool success)
-{
- ClientTunnel **p = &m->TunnelClients;
- while (*p != tun && *p) p = &(*p)->next;
- if (*p) *p = tun->next;
- ReissueBlockedQuestions(m, &tun->dstname, success);
- LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun);
- freeL("ClientTunnel", tun);
-}
-
-mDNSlocal mDNSBool TunnelClientDeleteMatching(mDNS *const m, ClientTunnel *tun, mDNSBool v6Tunnel)
-{
- ClientTunnel **p;
- mDNSBool needSetKeys = mDNStrue;
-
- p = &tun->next;
- while (*p)
- {
- // Is this a tunnel to the same host that we are trying to setup now?
- if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
- else
- {
- ClientTunnel *old = *p;
- if (v6Tunnel)
- {
- if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
- LogInfo("TunnelClientDeleteMatching: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
- if (old->q.ThisQInterval >= 0)
- {
- LogInfo("TunnelClientDeleteMatching: Stopping query on IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
- mDNS_StopQuery(m, &old->q);
- }
- else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
- !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
- !mDNSSameIPv6Address(old->loc_outer6, tun->loc_outer6) ||
- !mDNSSameIPv6Address(old->rmt_outer6, tun->rmt_outer6))
- {
- // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
- // the other parameters of the tunnel are different
- LogInfo("TunnelClientDeleteMatching: Deleting existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
- AutoTunnelSetKeys(old, mDNSfalse);
- }
- else
- {
- // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
- // as "tun" and "old" are identical
- LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c,
- &old->rmt_inner);
- needSetKeys = mDNSfalse;
- }
- }
- else
- {
- if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
- LogInfo("TunnelClientDeleteMatching: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
- if (old->q.ThisQInterval >= 0)
- {
- LogInfo("TunnelClientDeleteMatching: Stopping query on IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
- mDNS_StopQuery(m, &old->q);
- }
- else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
- !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
- !mDNSSameIPv4Address(old->loc_outer, tun->loc_outer) ||
- !mDNSSameIPv4Address(old->rmt_outer, tun->rmt_outer) ||
- !mDNSSameIPPort(old->rmt_outer_port, tun->rmt_outer_port))
- {
- // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
- // the other parameters of the tunnel are different
- LogInfo("TunnelClientDeleteMatching: Deleting existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
- AutoTunnelSetKeys(old, mDNSfalse);
- }
- else
- {
- // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
- // as "tun" and "old" are identical
- LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c,
- &old->rmt_inner);
- needSetKeys = mDNSfalse;
- }
- }
-
- *p = old->next;
- LogInfo("TunnelClientDeleteMatching: Disposing ClientTunnel %p", old);
- freeL("ClientTunnel", old);
- }
- }
- return needSetKeys;
-}
-
-// v6Tunnel indicates whether to delete a tunnel whose outer header is IPv6. If false, outer IPv4
-// tunnel will be deleted
-mDNSlocal void TunnelClientDeleteAny(mDNS *const m, ClientTunnel *tun, mDNSBool v6Tunnel)
-{
- ClientTunnel **p;
-
- p = &tun->next;
- while (*p)
- {
- // If there is more than one client tunnel to the same host, delete all of them.
- // We do this by just checking against the EUI64 rather than the full address
- if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
- else
- {
- ClientTunnel *old = *p;
- if (v6Tunnel)
- {
- if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
- LogInfo("TunnelClientDeleteAny: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
- }
- else
- {
- if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
- LogInfo("TunnelClientDeleteAny: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
- }
- if (old->q.ThisQInterval >= 0)
- {
- LogInfo("TunnelClientDeleteAny: Stopping query on AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
- mDNS_StopQuery(m, &old->q);
- }
- else
- {
- LogInfo("TunnelClientDeleteAny: Deleting existing AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
- AutoTunnelSetKeys(old, mDNSfalse);
- }
- *p = old->next;
- LogInfo("TunnelClientDeleteAny: Disposing ClientTunnel %p", old);
- freeL("ClientTunnel", old);
- }
- }
-}
-
-mDNSlocal void TunnelClientFinish(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer)
-{
- mDNSBool needSetKeys = mDNStrue;
- ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
- mDNSBool v6Tunnel = mDNSfalse;
- DomainAuthInfo *info;
-
- // If the port is zero, then we have a relay address of the peer
- if (mDNSIPPortIsZero(tun->rmt_outer_port))
- v6Tunnel = mDNStrue;
-
- if (v6Tunnel)
- {
- LogInfo("TunnelClientFinish: Relay address %.16a", &answer->rdata->u.ipv6);
- tun->rmt_outer6 = answer->rdata->u.ipv6;
- tun->loc_outer6 = m->AutoTunnelRelayAddr;
- }
- else
- {
- LogInfo("TunnelClientFinish: SRV target address %.4a", &answer->rdata->u.ipv4);
- tun->rmt_outer = answer->rdata->u.ipv4;
- mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
- tmpDst.ip.v4 = tun->rmt_outer;
- mDNSAddr tmpSrc = zeroAddr;
- mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
- if (tmpSrc.type == mDNSAddrType_IPv4) tun->loc_outer = tmpSrc.ip.v4;
- else tun->loc_outer = m->AdvertisedV4.ip.v4;
- }
-
- question->ThisQInterval = -1; // So we know this tunnel setup has completed
-
- info = GetAuthInfoForName(m, &tun->dstname);
- if (!info)
- {
- LogMsg("TunnelClientFinish: Could not get AuthInfo for %##s", tun->dstname.c);
- ReissueBlockedQuestions(m, &tun->dstname, mDNSfalse);
- return;
- }
-
- tun->loc_inner = info->AutoTunnelInnerAddress;
-
- // If we found a v6Relay address for our peer, delete all the v4Tunnels for our peer and
- // look for existing tunnels to see whether they have the same information for our peer.
- // If not, delete them and need to create a new tunnel. If they are same, just use the
- // same tunnel. Do the similar thing if we found a v4Tunnel end point for our peer.
- TunnelClientDeleteAny(m, tun, !v6Tunnel);
- needSetKeys = TunnelClientDeleteMatching(m, tun, v6Tunnel);
-
- if (needSetKeys) LogInfo("TunnelClientFinish: New %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
- else LogInfo("TunnelClientFinish: Reusing exiting %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
-
- mStatus result = needSetKeys ? AutoTunnelSetKeys(tun, mDNStrue) : mStatus_NoError;
- static char msgbuf[32];
- mDNS_snprintf(msgbuf, sizeof(msgbuf), "Tunnel setup - %d", result);
- mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.config", result ? "failure" : "success", msgbuf, "");
- // Kick off any questions that were held pending this tunnel setup
- ReissueBlockedQuestions(m, &tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse);
-}
-
-mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
-{
- ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
- DomainAuthInfo *info;
-
- LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype);
-
- if (!AddRecord) return;
- mDNS_StopQuery(m, question);
-
- // If we are looking up the AAAA record for _autotunnel6, don't consider it as failure.
- // The code below will look for _autotunnel._udp SRV record followed by A record
- if (tun->tc_state != TC_STATE_AAAA_PEER_RELAY && !answer->rdlength)
- {
- LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
- static char msgbuf[16];
- mDNS_snprintf(msgbuf, sizeof(msgbuf), "%s lookup", DNSTypeName(question->qtype));
- mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.config", "failure", msgbuf, "");
- UnlinkAndReissueBlockedQuestions(m, tun, mDNSfalse);
- return;
- }
-
- switch (tun->tc_state)
- {
- case TC_STATE_AAAA_PEER:
- if (question->qtype != kDNSType_AAAA)
- {
- LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER", question->qtype);
- }
- info = GetAuthInfoForName(m, &tun->dstname);
- if (!info)
- {
- LogMsg("AutoTunnelCallback: Could not get AuthInfo for %##s", tun->dstname.c);
- UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
- return;
- }
- if (mDNSSameIPv6Address(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
- {
- LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6);
- UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
- return;
- }
- if (info && mDNSSameIPv6NetworkPart(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
- {
- LogInfo("AutoTunnelCallback: suppressing tunnel to peer %.16a", &answer->rdata->u.ipv6);
- UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
- return;
- }
- tun->rmt_inner = answer->rdata->u.ipv6;
- LogInfo("AutoTunnelCallback:TC_STATE_AAAA_PEER: dst host %.16a", &tun->rmt_inner);
- if (!mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr))
- {
- LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA");
- tun->tc_state = TC_STATE_AAAA_PEER_RELAY;
- question->qtype = kDNSType_AAAA;
- AssignDomainName(&question->qname, (const domainname*) "\x0C" "_autotunnel6");
- }
- else
- {
- LogInfo("AutoTunnelCallback: Looking up _autotunnel._udp SRV");
- tun->tc_state = TC_STATE_SRV_PEER;
- question->qtype = kDNSType_SRV;
- AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
- }
- AppendDomainName(&question->qname, &tun->dstname);
- mDNS_StartQuery(m, &tun->q);
- return;
- case TC_STATE_AAAA_PEER_RELAY:
- if (question->qtype != kDNSType_AAAA)
- {
- LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER_RELAY", question->qtype);
- }
- // If it failed, look for the SRV record.
- if (!answer->rdlength)
- {
- LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA failed, trying SRV");
- tun->tc_state = TC_STATE_SRV_PEER;
- AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
- AppendDomainName(&question->qname, &tun->dstname);
- question->qtype = kDNSType_SRV;
- mDNS_StartQuery(m, &tun->q);
- return;
- }
- TunnelClientFinish(m, question, answer);
- return;
- case TC_STATE_SRV_PEER:
- if (question->qtype != kDNSType_SRV)
- {
- LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_SRV_PEER", question->qtype);
- }
- LogInfo("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c);
- tun->tc_state = TC_STATE_ADDR_PEER;
- AssignDomainName(&tun->q.qname, &answer->rdata->u.srv.target);
- tun->rmt_outer_port = answer->rdata->u.srv.port;
- question->qtype = kDNSType_A;
- mDNS_StartQuery(m, &tun->q);
- return;
- case TC_STATE_ADDR_PEER:
- if (question->qtype != kDNSType_A)
- {
- LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_ADDR_PEER", question->qtype);
- }
- TunnelClientFinish(m, question, answer);
- return;
- default:
- LogMsg("AutoTunnelCallback: Unknown question %p", question);
- }
-}
-
-// Must be called with the lock held
-mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q)
-{
- ClientTunnel *p = mallocL("ClientTunnel", sizeof(ClientTunnel));
- if (!p) return;
- AssignDomainName(&p->dstname, &q->qname);
- p->MarkedForDeletion = mDNSfalse;
- p->loc_inner = zerov6Addr;
- p->loc_outer = zerov4Addr;
- p->loc_outer6 = zerov6Addr;
- p->rmt_inner = zerov6Addr;
- p->rmt_outer = zerov4Addr;
- p->rmt_outer6 = zerov6Addr;
- p->rmt_outer_port = zeroIPPort;
- p->tc_state = TC_STATE_AAAA_PEER;
- p->next = m->TunnelClients;
- m->TunnelClients = p; // We intentionally build list in reverse order
-
- p->q.InterfaceID = mDNSInterface_Any;
- p->q.flags = 0;
- p->q.Target = zeroAddr;
- AssignDomainName(&p->q.qname, &q->qname);
- p->q.qtype = kDNSType_AAAA;
- p->q.qclass = kDNSClass_IN;
- p->q.LongLived = mDNSfalse;
- p->q.ExpectUnique = mDNStrue;
- p->q.ForceMCast = mDNSfalse;
- p->q.ReturnIntermed = mDNStrue;
- p->q.SuppressUnusable = mDNSfalse;
- p->q.SearchListIndex = 0;
- p->q.AppendSearchDomains = 0;
- p->q.RetryWithSearchDomains = mDNSfalse;
- p->q.TimeoutQuestion = 0;
- p->q.WakeOnResolve = 0;
- p->q.UseBackgroundTrafficClass = mDNSfalse;
- p->q.ValidationRequired = 0;
- p->q.ValidatingResponse = 0;
- p->q.ProxyQuestion = 0;
- p->q.qnameOrig = mDNSNULL;
- p->q.AnonInfo = mDNSNULL;
- p->q.pid = mDNSPlatformGetPID();
- p->q.QuestionCallback = AutoTunnelCallback;
- p->q.QuestionContext = p;
-
- LogInfo("AddNewClientTunnel start tun %p %##s (%s)%s", p, &q->qname.c, DNSTypeName(q->qtype), q->LongLived ? " LongLived" : "");
- mDNS_StartQuery_internal(m, &p->q);
-}
-
-#endif // APPLE_OSX_mDNSResponder
-
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - Power State & Configuration Change Management
-#endif
-
-mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
-{
- mDNSBool foundav4 = mDNSfalse;
- mDNSBool foundav6 = mDNSfalse;
- struct ifaddrs *ifa = myGetIfAddrs(1);
- struct ifaddrs *v4Loopback = NULL;
- struct ifaddrs *v6Loopback = NULL;
- char defaultname[64];
- int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
- if (InfoSocket < 3 && errno != EAFNOSUPPORT)
- LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
-
- while (ifa)
- {
-#if LIST_ALL_INTERFACES
- if (ifa->ifa_addr->sa_family == AF_APPLETALK)
- LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
- ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
- else if (ifa->ifa_addr->sa_family == AF_LINK)
- LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
- ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
- else if (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)
- LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
- ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
- if (!(ifa->ifa_flags & IFF_UP))
- LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
- ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
- if (!(ifa->ifa_flags & IFF_MULTICAST))
- LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
- ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
- if (ifa->ifa_flags & IFF_POINTOPOINT)
- LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
- ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
- if (ifa->ifa_flags & IFF_LOOPBACK)
- LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
- ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
-#endif
-
- if (ifa->ifa_addr->sa_family == AF_LINK)
- {
- struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
- if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(m->PrimaryMAC) && mDNSSameEthAddress(&m->PrimaryMAC, &zeroEthAddr))
- mDNSPlatformMemCopy(m->PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6);
- }
-
- if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr)
- if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)
- {
- if (!ifa->ifa_netmask)
- {
- mDNSAddr ip;
- SetupAddr(&ip, ifa->ifa_addr);
- LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
- ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip);
- }
- // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be zero, so we don't complain about that
- // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
- else if (ifa->ifa_netmask->sa_family != ifa->ifa_addr->sa_family && ifa->ifa_netmask->sa_family != 0)
- {
- mDNSAddr ip;
- SetupAddr(&ip, ifa->ifa_addr);
- LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
- ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip, ifa->ifa_netmask->sa_family);
- }
- // Currently we use a few internal ones like mDNSInterfaceID_LocalOnly etc. that are negative values (0, -1, -2).
- else if ((int)if_nametoindex(ifa->ifa_name) <= 0)
- {
- LogMsg("UpdateInterfaceList: if_nametoindex returned zero/negative value for %5s(%d)", ifa->ifa_name, if_nametoindex(ifa->ifa_name));
- }
- else
- {
- // Make sure ifa_netmask->sa_family is set correctly
- // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
- ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family;
- int ifru_flags6 = 0;
-
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
- if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
- {
- struct in6_ifreq ifr6;
- mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
- strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
- ifr6.ifr_addr = *sin6;
- if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
- ifru_flags6 = ifr6.ifr_ifru.ifru_flags6;
- verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6);
- }
-
- if (!(ifru_flags6 & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
- {
- if (ifa->ifa_flags & IFF_LOOPBACK)
- {
- if (ifa->ifa_addr->sa_family == AF_INET)
- v4Loopback = ifa;
- else if (sin6->sin6_addr.s6_addr[0] != 0xFD)
- v6Loopback = ifa;
- }
- else
- {
- NetworkInterfaceInfoOSX *i = AddInterfaceToList(m, ifa, utc);
- if (i && MulticastInterface(i) && i->ifinfo.Advertise)
- {
- if (ifa->ifa_addr->sa_family == AF_INET)
- foundav4 = mDNStrue;
- else
- foundav6 = mDNStrue;
- }
- }
- }
- }
- }
- ifa = ifa->ifa_next;
- }
-
- // For efficiency, we don't register a loopback interface when other interfaces of that family are available and advertising
- if (!foundav4 && v4Loopback) AddInterfaceToList(m, v4Loopback, utc);
- if (!foundav6 && v6Loopback) AddInterfaceToList(m, v6Loopback, utc);
-
- // Now the list is complete, set the McastTxRx setting for each interface.
- NetworkInterfaceInfoOSX *i;
- for (i = m->p->InterfaceList; i; i = i->next)
- if (i->Exists)
- {
- mDNSBool txrx = MulticastInterface(i);
- if (i->ifinfo.McastTxRx != txrx)
- {
- i->ifinfo.McastTxRx = txrx;
- i->Exists = 2; // State change; need to deregister and reregister this interface
- }
- }
-
- if (InfoSocket >= 0)
- close(InfoSocket);
-
- mDNS_snprintf(defaultname, sizeof(defaultname), "%.*s-%02X%02X%02X%02X%02X%02X", HINFO_HWstring_prefixlen, HINFO_HWstring,
- m->PrimaryMAC.b[0], m->PrimaryMAC.b[1], m->PrimaryMAC.b[2], m->PrimaryMAC.b[3], m->PrimaryMAC.b[4], m->PrimaryMAC.b[5]);
-
- // Set up the nice label
- domainlabel nicelabel;
- nicelabel.c[0] = 0;
- GetUserSpecifiedFriendlyComputerName(&nicelabel);
- if (nicelabel.c[0] == 0)
- {
- debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname);
- MakeDomainLabelFromLiteralString(&nicelabel, defaultname);
- }
-
- // Set up the RFC 1034-compliant label
- domainlabel hostlabel;
- hostlabel.c[0] = 0;
- GetUserSpecifiedLocalHostName(&hostlabel);
- if (hostlabel.c[0] == 0)
- {
- debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname);
- MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
- }
-
- mDNSBool namechange = mDNSfalse;
-
- // We use a case-sensitive comparison here because even though changing the capitalization
- // of the name alone is not significant to DNS, it's still a change from the user's point of view
- if (SameDomainLabelCS(m->p->usernicelabel.c, nicelabel.c))
- debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m->p->usernicelabel.c, m->nicelabel.c);
- else
- {
- if (m->p->usernicelabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
- LogMsg("User updated Computer Name from “%#s” to “%#s”", m->p->usernicelabel.c, nicelabel.c);
- m->p->usernicelabel = m->nicelabel = nicelabel;
- namechange = mDNStrue;
- }
-
- if (SameDomainLabelCS(m->p->userhostlabel.c, hostlabel.c))
- debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m->p->userhostlabel.c, m->hostlabel.c);
- else
- {
- if (m->p->userhostlabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
- LogMsg("User updated Local Hostname from “%#s” to “%#s”", m->p->userhostlabel.c, hostlabel.c);
- m->p->userhostlabel = m->hostlabel = hostlabel;
- mDNS_SetFQDN(m);
- namechange = mDNStrue;
- }
-
-#if APPLE_OSX_mDNSResponder
- if (namechange) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
- {
- DomainAuthInfo *info;
- for (info = m->AuthInfoList; info; info = info->next)
- if (info->AutoTunnel) AutoTunnelHostNameChanged(m, info);
- }
-#endif // APPLE_OSX_mDNSResponder
-
- return(mStatus_NoError);
-}
-
-// Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
-// Returns -1 if all the one-bits are not contiguous
-mDNSlocal int CountMaskBits(mDNSAddr *mask)
-{
- int i = 0, bits = 0;
- int bytes = mask->type == mDNSAddrType_IPv4 ? 4 : mask->type == mDNSAddrType_IPv6 ? 16 : 0;
- while (i < bytes)
- {
- mDNSu8 b = mask->ip.v6.b[i++];
- while (b & 0x80) { bits++; b <<= 1; }
- if (b) return(-1);
- }
- while (i < bytes) if (mask->ip.v6.b[i++]) return(-1);
- return(bits);
-}
-
-// returns count of non-link local V4 addresses registered
-mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
-{
- NetworkInterfaceInfoOSX *i;
- int count = 0;
- for (i = m->p->InterfaceList; i; i = i->next)
- if (i->Exists)
- {
- NetworkInterfaceInfo *const n = &i->ifinfo;
- NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AF_UNSPEC);
- if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifinfo.ifname);
-
- if (i->Registered && i->Registered != primary) // Sanity check
- {
- LogMsg("SetupActiveInterfaces ERROR! n->Registered %p != primary %p", i->Registered, primary);
- i->Registered = mDNSNULL;
- }
-
- if (!i->Registered)
- {
- // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
- // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
- // If i->Registered is NOT set, then we haven't registered it and we should not try to deregister it
- //
-
- i->Registered = primary;
-
- // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
- // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
- // If the interface is an old one that went away and came back in less than a minute, then we're in a flapping scenario.
- i->Occulting = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
-
- // Temporary fix to handle P2P flapping. P2P reuses the scope-id, mac address and the IP address
- // everytime it creates a new interface. We think it is a duplicate and hence consider it
- // as flashing and occulting, that is, flapping. If an interface is marked as flapping,
- // mDNS_RegisterInterface() changes the probe delay from 1/2 second to 5 seconds and
- // logs a warning message to system.log noting frequent interface transitions.
- // Same logic applies when IFEF_DIRECTLINK flag is set on the interface.
- if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->ifinfo.DirectLink)
- {
- LogInfo("SetupActiveInterfaces: %s interface registering %s %s", i->ifinfo.ifname,
- i->Flashing ? " (Flashing)" : "",
- i->Occulting ? " (Occulting)" : "");
- mDNS_RegisterInterface(m, n, 0);
- }
- else
- {
- mDNS_RegisterInterface(m, n, i->Flashing && i->Occulting);
- }
-
- if (!mDNSAddressIsLinkLocal(&n->ip)) count++;
- LogInfo("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
- i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, primary, &n->ip, CountMaskBits(&n->mask),
- i->Flashing ? " (Flashing)" : "",
- i->Occulting ? " (Occulting)" : "",
- n->InterfaceActive ? " (Primary)" : "");
-
- if (!n->McastTxRx)
- debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, &n->ip);
- else
- {
- if (i->sa_family == AF_INET)
- {
- struct ip_mreq imr;
- primary->ifa_v4addr.s_addr = n->ip.ip.v4.NotAnInteger;
- imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
- imr.imr_interface = primary->ifa_v4addr;
-
- // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first,
- // before trying to join the group, to clear out stale kernel state which may be lingering.
- // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state
- // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group
- // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't
- // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state.
- // Also, trying to make the code leave the group when the adapter is removed doesn't work either,
- // because by the time we get the configuration change notification, the interface is already gone,
- // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
- // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
- if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET) == i)
- {
- LogInfo("SetupActiveInterfaces: %5s(%lu) Doing precautionary IP_DROP_MEMBERSHIP for %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
- mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(imr));
- if (err < 0 && (errno != EADDRNOTAVAIL))
- LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err, errno, strerror(errno));
- }
-
- LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
- mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
- // Joining same group twice can give "Address already in use" error -- no need to report that
- if (err < 0 && (errno != EADDRINUSE))
- LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %d errno %d (%s) group %.4a on %.4a", err, errno, strerror(errno), &imr.imr_multiaddr, &imr.imr_interface);
- }
- if (i->sa_family == AF_INET6)
- {
- struct ipv6_mreq i6mr;
- i6mr.ipv6mr_interface = primary->scope_id;
- i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
-
- if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET6) == i)
- {
- LogInfo("SetupActiveInterfaces: %5s(%lu) Doing precautionary IPV6_LEAVE_GROUP for %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
- mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
- if (err < 0 && (errno != EADDRNOTAVAIL))
- LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
- }
-
- LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
- mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
- // Joining same group twice can give "Address already in use" error -- no need to report that
- if (err < 0 && (errno != EADDRINUSE))
- LogMsg("setsockopt - IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
- }
- }
- }
- }
-
- return count;
-}
-
-mDNSlocal void MarkAllInterfacesInactive(mDNS *const m, mDNSs32 utc)
-{
- NetworkInterfaceInfoOSX *i;
- for (i = m->p->InterfaceList; i; i = i->next)
- {
- if (i->Exists) i->LastSeen = utc;
- i->Exists = mDNSfalse;
- }
-}
-
-// returns count of non-link local V4 addresses deregistered
-mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
-{
- // First pass:
- // If an interface is going away, then deregister this from the mDNSCore.
- // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
- // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
- // it refers to has gone away we'll crash.
- NetworkInterfaceInfoOSX *i;
- int count = 0;
- for (i = m->p->InterfaceList; i; i = i->next)
- {
- // If this interface is no longer active, or its InterfaceID is changing, deregister it
- NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AF_UNSPEC);
- if (i->Registered)
- if (i->Exists == 0 || i->Exists == 2 || i->Registered != primary)
- {
- i->Flashing = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->AppearanceTime < 60);
- LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
- i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, primary,
- &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask),
- i->Flashing ? " (Flashing)" : "",
- i->Occulting ? " (Occulting)" : "",
- i->ifinfo.InterfaceActive ? " (Primary)" : "");
-
- // Temporary fix to handle P2P flapping. P2P reuses the scope-id, mac address and the IP address
- // everytime it creates a new interface. We think it is a duplicate and hence consider it
- // as flashing and occulting. The "core" does not flush the cache for this case. This leads to
- // stale data returned to the application even after the interface is removed. The application
- // then starts to send data but the new interface is not yet created.
- // Same logic applies when IFEF_DIRECTLINK flag is set on the interface.
- if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->ifinfo.DirectLink)
- {
- LogInfo("ClearInactiveInterfaces: %s interface deregistering %s %s", i->ifinfo.ifname,
- i->Flashing ? " (Flashing)" : "",
- i->Occulting ? " (Occulting)" : "");
- mDNS_DeregisterInterface(m, &i->ifinfo, 0);
- }
- else
- {
- mDNS_DeregisterInterface(m, &i->ifinfo, i->Flashing && i->Occulting);
- }
- if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
- i->Registered = mDNSNULL;
- // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
- // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
- // If i->Registered is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
-
- // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
- // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
- }
- }
-
- // Second pass:
- // Now that everything that's going to deregister has done so, we can clean up and free the memory
- NetworkInterfaceInfoOSX **p = &m->p->InterfaceList;
- while (*p)
- {
- i = *p;
- // If no longer active, delete interface from list and free memory
- if (!i->Exists)
- {
- if (i->LastSeen == utc) i->LastSeen = utc - 1;
- mDNSBool delete = (NumCacheRecordsForInterfaceID(m, i->ifinfo.InterfaceID) == 0) && (utc - i->LastSeen >= 60);
- LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p(%p) %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
- i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i,
- &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen,
- i->ifinfo.InterfaceActive ? " (Primary)" : "");
-#if APPLE_OSX_mDNSResponder
- if (i->BPF_fd >= 0) CloseBPF(i);
-#endif // APPLE_OSX_mDNSResponder
- if (delete)
- {
- *p = i->next;
- freeL("NetworkInterfaceInfoOSX", i);
- continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
- }
- }
- p = &i->next;
- }
- return count;
-}
-
-mDNSlocal void AppendDNameListElem(DNameListElem ***List, mDNSu32 uid, domainname *name)
-{
- DNameListElem *dnle = (DNameListElem*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem));
- if (!dnle) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
- else
- {
- dnle->next = mDNSNULL;
- dnle->uid = uid;
- AssignDomainName(&dnle->name, name);
- **List = dnle;
- *List = &dnle->next;
- }
-}
-
-mDNSlocal int compare_dns_configs(const void *aa, const void *bb)
-{
- dns_resolver_t *a = *(dns_resolver_t**)aa;
- dns_resolver_t *b = *(dns_resolver_t**)bb;
-
- return (a->search_order < b->search_order) ? -1 : (a->search_order == b->search_order) ? 0 : 1;
-}
-
-mDNSlocal void UpdateSearchDomainHash(mDNS *const m, MD5_CTX *sdc, char *domain, mDNSInterfaceID InterfaceID)
-{
- char *buf = ".";
- mDNSu32 scopeid = 0;
- char ifid_buf[16];
-
- if (domain)
- buf = domain;
- //
- // Hash the search domain name followed by the InterfaceID.
- // As we have scoped search domains, we also included InterfaceID. If either of them change,
- // we will detect it. Even if the order of them change, we will detect it.
- //
- // Note: We have to handle a few of these tricky cases.
- //
- // 1) Current: com, apple.com Changing to: comapple.com
- // 2) Current: a.com,b.com Changing to a.comb.com
- // 3) Current: a.com,b.com (ifid 8), Changing to a.com8b.com (ifid 8)
- // 4) Current: a.com (ifid 12), Changing to a.com1 (ifid: 2)
- //
- // There are more variants of the above. The key thing is if we include the null in each case
- // at the end of name and the InterfaceID, it will prevent a new name (which can't include
- // NULL as part of the name) to be mistakenly thought of as a old name.
-
- scopeid = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID, mDNStrue);
- // mDNS_snprintf always null terminates
- if (mDNS_snprintf(ifid_buf, sizeof(ifid_buf), "%u", scopeid) >= sizeof(ifid_buf))
- LogMsg("UpdateSearchDomainHash: mDNS_snprintf failed for scopeid %u", scopeid);
-
- LogInfo("UpdateSearchDomainHash: buf %s, ifid_buf %s", buf, ifid_buf);
- MD5_Update(sdc, buf, strlen(buf) + 1);
- MD5_Update(sdc, ifid_buf, strlen(ifid_buf) + 1);
-}
-
-mDNSlocal void FinalizeSearchDomainHash(mDNS *const m, MD5_CTX *sdc)
-{
- mDNSu8 md5_hash[MD5_LEN];
-
- MD5_Final(md5_hash, sdc);
-
- if (memcmp(md5_hash, m->SearchDomainsHash, MD5_LEN))
- {
- // If the hash is different, either the search domains have changed or
- // the ordering between them has changed. Restart the questions that
- // would be affected by this.
- LogInfo("FinalizeSearchDomains: The hash is different");
- memcpy(m->SearchDomainsHash, md5_hash, MD5_LEN);
- RetrySearchDomainQuestions(m);
- }
- else { LogInfo("FinalizeSearchDomains: The hash is same"); }
-}
-
-mDNSexport const char *DNSScopeToString(mDNSu32 scope)
-{
- switch (scope)
- {
- case kScopeNone:
- return "Unscoped";
- case kScopeInterfaceID:
- return "InterfaceScoped";
- case kScopeServiceID:
- return "ServiceScoped";
- default:
- return "Unknown";
- }
-}
-
-mDNSlocal void ConfigSearchDomains(mDNS *const m, dns_resolver_t *resolver, mDNSInterfaceID interface, mDNSu32 scope, MD5_CTX *sdc)
-{
- const char *scopeString = DNSScopeToString(scope);
- int j;
-
- if (scope != kScopeNone)
- {
- LogInfo("ConfigSearchDomains: (%s) Ignoring search domain for Interface %p", scopeString, interface);
- return;
- }
- for (j = 0; j < resolver->n_search; j++)
- {
- LogInfo("ConfigSearchDomains: (%s) configuring search list %s", scopeString, resolver->search[j]);
- UpdateSearchDomainHash(m, sdc, resolver->search[j], NULL);
- mDNS_AddSearchDomain_CString(resolver->search[j], NULL);
- }
-}
-
-mDNSlocal mDNSInterfaceID ConfigParseInterfaceID(mDNS *const m, mDNSu32 ifindex)
-{
- NetworkInterfaceInfoOSX *ni;
- mDNSInterfaceID interface;
-
- for (ni = m->p->InterfaceList; ni; ni = ni->next)
- {
- if (ni->ifinfo.InterfaceID && ni->scope_id == ifindex)
- break;
- }
- if (ni != NULL)
- {
- interface = ni->ifinfo.InterfaceID;
- }
- else
- {
- // In rare circumstances, we could potentially hit this case where we cannot parse the InterfaceID
- // (see <rdar://problem/13214785>). At this point, we still accept the DNS Config from configd
- // Note: We currently ack the whole dns configuration and not individual resolvers or DNS servers.
- // As the caller is going to ack the configuration always, we have to add all the DNS servers
- // in the configuration. Otherwise, we won't have any DNS servers up until the network change.
-
- LogMsg("ConfigParseInterfaceID: interface specific index %d not found (interface may not be UP)",ifindex);
-
- // Set the correct interface from configd before passing this to mDNS_AddDNSServer() below
- interface = (mDNSInterfaceID)(unsigned long)ifindex;
- }
- return interface;
-}
-
-mDNSlocal void ConfigNonUnicastResolver(mDNS *const m, dns_resolver_t *r)
-{
- char *opt = r->options;
- domainname d;
-
- if (opt && !strncmp(opt, "mdns", strlen(opt)))
- {
- if (!MakeDomainNameFromDNSNameString(&d, r->domain))
- {
- LogMsg("ConfigNonUnicastResolver: config->resolver bad domain %s", r->domain);
- return;
- }
- mDNS_AddMcastResolver(m, &d, mDNSInterface_Any, r->timeout);
- }
-}
-
-mDNSlocal void ConfigDNSServers(mDNS *const m, dns_resolver_t *r, mDNSInterfaceID interface, mDNSu32 scope, mDNSu16 resGroupID)
-{
- int n;
- domainname d;
- int serviceID = 0;
- mDNSBool cellIntf = mDNSfalse;
- mDNSBool scopedDNS = mDNSfalse;
- mDNSBool reqA, reqAAAA;
-
- if (!r->domain || !*r->domain)
- {
- d.c[0] = 0;
- }
- else if (!MakeDomainNameFromDNSNameString(&d, r->domain))
- {
- LogMsg("ConfigDNSServers: bad domain %s", r->domain);
- return;
- }
- // Parse the resolver specific attributes that affects all the DNS servers.
- if (scope == kScopeInterfaceID)
- {
- scopedDNS = mDNStrue;
- }
- else if (scope == kScopeServiceID)
- {
- serviceID = r->service_identifier;
- }
-
-#if TARGET_OS_IPHONE
- cellIntf = (r->reach_flags & kSCNetworkReachabilityFlagsIsWWAN) ? mDNStrue : mDNSfalse;
-#endif
- reqA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS ? mDNStrue : mDNSfalse);
- reqAAAA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS ? mDNStrue : mDNSfalse);
-
- for (n = 0; n < r->n_nameserver; n++)
- {
- mDNSAddr saddr;
- DNSServer *s;
-
- if (r->nameserver[n]->sa_family != AF_INET && r->nameserver[n]->sa_family != AF_INET6)
- continue;
-
- if (SetupAddr(&saddr, r->nameserver[n]))
- {
- LogMsg("ConfigDNSServers: Bad address");
- continue;
- }
-
- // The timeout value is for all the DNS servers in a given resolver, hence we pass
- // the timeout value only for the first DNSServer. If we don't have a value in the
- // resolver, then use the core's default value
- //
- // Note: this assumes that when the core picks a list of DNSServers for a question,
- // it takes the sum of all the timeout values for all DNS servers. By doing this, it
- // tries all the DNS servers in a specified timeout
- s = mDNS_AddDNSServer(m, &d, interface, serviceID, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort, scope,
- (n == 0 ? (r->timeout ? r->timeout : DEFAULT_UDNS_TIMEOUT) : 0), cellIntf, resGroupID, reqA, reqAAAA, mDNStrue);
- if (s)
- {
- LogInfo("ConfigDNSServers(%s): DNS server %#a:%d for domain %##s", DNSScopeToString(scope), &s->addr, mDNSVal16(s->port), d.c);
- }
- }
-}
-
-// ConfigResolvers is called for different types of resolvers: Unscoped resolver, Interface scope resolver and
-// Service scope resolvers. This is indicated by the scope argument.
-//
-// "resolver" has entries that should only be used for unscoped questions.
-//
-// "scoped_resolver" has entries that should only be used for Interface scoped question i.e., questions that specify an
-// interface index (q->InterfaceID)
-//
-// "service_specific_resolver" has entries that should be used for Service scoped question i.e., questions that specify
-// a service identifier (q->ServiceID)
-//
-mDNSlocal void ConfigResolvers(mDNS *const m, dns_config_t *config, mDNSu32 scope, mDNSBool setsearch, mDNSBool setservers, MD5_CTX *sdc, mDNSu16 resGroupID)
-{
- int i;
- dns_resolver_t **resolver;
- int nresolvers;
- const char *scopeString = DNSScopeToString(scope);
- mDNSInterfaceID interface;
-
- switch (scope)
- {
- case kScopeNone:
- resolver = config->resolver;
- nresolvers = config->n_resolver;
- break;
- case kScopeInterfaceID:
- resolver = config->scoped_resolver;
- nresolvers = config->n_scoped_resolver;
- break;
- case kScopeServiceID:
- resolver = config->service_specific_resolver;
- nresolvers = config->n_service_specific_resolver;
- break;
- default:
- return;
- }
- qsort(resolver, nresolvers, sizeof(dns_resolver_t*), compare_dns_configs);
-
- for (i = 0; i < nresolvers; i++)
- {
- dns_resolver_t *r = resolver[i];
-
- LogInfo("ConfigResolvers: %s resolver[%d] domain %s n_nameserver %d", scopeString, i, r->domain, r->n_nameserver);
-
- interface = mDNSInterface_Any;
-
- // Parse the interface index
- if (r->if_index != 0)
- {
- interface = ConfigParseInterfaceID(m, r->if_index);
- }
-
- if (setsearch)
- {
- ConfigSearchDomains(m, resolver[i], interface, scope, sdc);
- // Parse other scoped resolvers for search lists
- if (!setservers)
- continue;
- }
-
- if (r->port == 5353 || r->n_nameserver == 0)
- {
- ConfigNonUnicastResolver(m, r);
- }
- else
- {
- // Each scoped resolver gets its own ID (i.e., they are in their own group) so that responses from the
- // scoped resolver are not used by other non-scoped or scoped resolvers.
- if (scope != kScopeNone)
- resGroupID++;
-
- ConfigDNSServers(m, r, interface, scope, resGroupID);
- }
- }
-}
-
-#if APPLE_OSX_mDNSResponder
-mDNSlocal mDNSBool QuestionValidForDNSTrigger(DNSQuestion *q)
-{
- if (QuerySuppressed(q))
- {
- debugf("QuestionValidForDNSTrigger: Suppressed: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- return mDNSfalse;
- }
- if (mDNSOpaque16IsZero(q->TargetQID))
- {
- debugf("QuestionValidForDNSTrigger: Multicast: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- return mDNSfalse;
- }
- // If we answered using LocalOnly records e.g., /etc/hosts, don't consider that a valid response
- // for trigger.
- if (q->LOAddressAnswers)
- {
- debugf("QuestionValidForDNSTrigger: LocalOnly answers: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- return mDNSfalse;
- }
- return mDNStrue;
-}
-#endif
-
-// This function is called if we are not delivering unicast answers to "A" or "AAAA" questions.
-// We set our state appropriately so that if we start receiving answers, trigger the
-// upper layer to retry DNS questions.
-#if APPLE_OSX_mDNSResponder
-mDNSexport void mDNSPlatformUpdateDNSStatus(mDNS *const m, DNSQuestion *q)
-{
- if (!QuestionValidForDNSTrigger(q))
- return;
-
- // Ignore applications that start and stop queries for no reason before we ever talk
- // to any DNS server.
- if (!q->triedAllServersOnce)
- {
- LogInfo("QuestionValidForDNSTrigger: question %##s (%s) stopped too soon", q->qname.c, DNSTypeName(q->qtype));
- return;
- }
- if (q->qtype == kDNSType_A)
- m->p->v4answers = 0;
- if (q->qtype == kDNSType_AAAA)
- m->p->v6answers = 0;
- if (!m->p->v4answers || !m->p->v6answers)
- {
- LogInfo("mDNSPlatformUpdateDNSStatus: Trigger needed v4 %d, v6 %d, quesiton %##s (%s)", m->p->v4answers, m->p->v6answers, q->qname.c,
- DNSTypeName(q->qtype));
- }
-}
-#endif
-
-mDNSlocal void AckConfigd(mDNS *const m, dns_config_t *config)
-{
- mDNS_CheckLock(m);
-
- // Acking the configuration triggers configd to reissue the reachability queries
- m->p->DNSTrigger = NonZeroTime(m->timenow);
- _dns_configuration_ack(config, "com.apple.mDNSResponder");
-}
-
-// If v4q is non-NULL, it means we have received some answers for "A" type questions
-// If v6q is non-NULL, it means we have received some answers for "AAAA" type questions
-#if APPLE_OSX_mDNSResponder
-mDNSexport void mDNSPlatformTriggerDNSRetry(mDNS *const m, DNSQuestion *v4q, DNSQuestion *v6q)
-{
- mDNSBool trigger = mDNSfalse;
- mDNSs32 timenow;
-
- // Don't send triggers too often.
- // If we have started delivering answers to questions, we should send a trigger
- // if the time permits. If we are delivering answers, we should set the state
- // of v4answers/v6answers to 1 and avoid sending a trigger. But, we don't know
- // whether the answers that are being delivered currently is for configd or some
- // other application. If we set the v4answers/v6answers to 1 and not deliver a trigger,
- // then we won't deliver the trigger later when it is okay to send one as the
- // "answers" are already set to 1. Hence, don't affect the state of v4answers and
- // v6answers if we are not delivering triggers.
- mDNS_Lock(m);
- timenow = m->timenow;
- if (m->p->DNSTrigger && (timenow - m->p->DNSTrigger) < DNS_TRIGGER_INTERVAL)
- {
- if (!m->p->v4answers || !m->p->v6answers)
- {
- debugf("mDNSPlatformTriggerDNSRetry: not triggering, time since last trigger %d ms, v4ans %d, v6ans %d",
- (timenow - m->p->DNSTrigger), m->p->v4answers, m->p->v6answers);
- }
- mDNS_Unlock(m);
- return;
- }
- mDNS_Unlock(m);
- if (v4q != NULL && QuestionValidForDNSTrigger(v4q))
- {
- int old = m->p->v4answers;
-
- m->p->v4answers = 1;
-
- // If there are IPv4 answers now and previously we did not have
- // any answers, trigger a DNS change so that reachability
- // can retry the queries again.
- if (!old)
- {
- LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv4, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
- v4q->qname.c, DNSTypeName(v4q->qtype));
- trigger = mDNStrue;
- }
- }
- if (v6q != NULL && QuestionValidForDNSTrigger(v6q))
- {
- int old = m->p->v6answers;
-
- m->p->v6answers = 1;
- // If there are IPv6 answers now and previously we did not have
- // any answers, trigger a DNS change so that reachability
- // can retry the queries again.
- if (!old)
- {
- LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv6, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
- v6q->qname.c, DNSTypeName(v6q->qtype));
- trigger = mDNStrue;
- }
- }
- if (trigger)
- {
- dns_config_t *config = dns_configuration_copy();
- if (config)
- {
- mDNS_Lock(m);
- AckConfigd(m, config);
- mDNS_Unlock(m);
- dns_configuration_free(config);
- }
- else
- {
- LogMsg("mDNSPlatformTriggerDNSRetry: ERROR!! configd did not return config");
- }
- }
-}
-
-mDNSlocal void SetupActiveDirectoryDomain(dns_config_t *config)
-{
- // Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up
- // by someone using Microsoft Active Directory using "local" as a private internal top-level domain
- if (config->n_resolver && config->resolver[0]->domain && config->resolver[0]->n_nameserver &&
- config->resolver[0]->nameserver[0])
- {
- MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, config->resolver[0]->domain);
- }
- else
- {
- ActiveDirectoryPrimaryDomain.c[0] = 0;
- }
-
- //MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, "test.local");
- ActiveDirectoryPrimaryDomainLabelCount = CountLabels(&ActiveDirectoryPrimaryDomain);
- if (config->n_resolver && config->resolver[0]->n_nameserver &&
- SameDomainName(SkipLeadingLabels(&ActiveDirectoryPrimaryDomain, ActiveDirectoryPrimaryDomainLabelCount - 1), &localdomain))
- {
- SetupAddr(&ActiveDirectoryPrimaryDomainServer, config->resolver[0]->nameserver[0]);
- }
- else
- {
- AssignDomainName(&ActiveDirectoryPrimaryDomain, (const domainname *)"");
- ActiveDirectoryPrimaryDomainLabelCount = 0;
- ActiveDirectoryPrimaryDomainServer = zeroAddr;
- }
-}
-#endif
-
-mDNSlocal void SetupDDNSDomains(domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains)
-{
- int i;
- char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
- domainname d;
-
- SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformSetDNSConfig"), NULL, NULL);
- if (!store)
- {
- LogMsg("SetupDDNSDomains: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
- }
- else
- {
- CFDictionaryRef ddnsdict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DynamicDNS);
- if (ddnsdict)
- {
- if (fqdn)
- {
- CFArrayRef fqdnArray = CFDictionaryGetValue(ddnsdict, CFSTR("HostNames"));
- if (fqdnArray && CFArrayGetCount(fqdnArray) > 0)
- {
- // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
- CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0);
- if (fqdnDict && DictionaryIsEnabled(fqdnDict))
- {
- CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
- if (name)
- {
- if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
- !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
- LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
- else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
- }
- }
- }
- }
-
- if (RegDomains)
- {
- CFArrayRef regArray = CFDictionaryGetValue(ddnsdict, CFSTR("RegistrationDomains"));
- if (regArray && CFArrayGetCount(regArray) > 0)
- {
- CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
- if (regDict && DictionaryIsEnabled(regDict))
- {
- CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
- if (name)
- {
- if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
- !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
- LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
- else
- {
- debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf);
- AppendDNameListElem(&RegDomains, 0, &d);
- }
- }
- }
- }
- }
-
- if (BrowseDomains)
- {
- CFArrayRef browseArray = CFDictionaryGetValue(ddnsdict, CFSTR("BrowseDomains"));
- if (browseArray)
- {
- for (i = 0; i < CFArrayGetCount(browseArray); i++)
- {
- CFDictionaryRef browseDict = CFArrayGetValueAtIndex(browseArray, i);
- if (browseDict && DictionaryIsEnabled(browseDict))
- {
- CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
- if (name)
- {
- if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
- !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
- LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf[0] ? buf : "(unknown)");
- else
- {
- debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf);
- AppendDNameListElem(&BrowseDomains, 0, &d);
- }
- }
- }
- }
- }
- }
- CFRelease(ddnsdict);
- }
-
- if (RegDomains)
- {
- CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
- if (btmm)
- {
- CFIndex size = CFDictionaryGetCount(btmm);
- const void *key[size];
- const void *val[size];
- CFDictionaryGetKeysAndValues(btmm, key, val);
- for (i = 0; i < size; i++)
- {
- LogInfo("BackToMyMac %d", i);
- if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
- LogMsg("Can't read BackToMyMac %d key %s", i, buf);
- else
- {
- mDNSu32 uid = atoi(buf);
- if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
- LogMsg("Can't read BackToMyMac %d val %s", i, buf);
- else if (MakeDomainNameFromDNSNameString(&d, buf) && d.c[0])
- {
- LogInfo("BackToMyMac %d %d %##s", i, uid, d.c);
- AppendDNameListElem(&RegDomains, uid, &d);
- }
- }
- }
- CFRelease(btmm);
- }
- }
- CFRelease(store);
- }
-}
-
-// Returns mDNSfalse, if it does not set the configuration i.e., if the DNS configuration did not change
-mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn,
- DNameListElem **RegDomains, DNameListElem **BrowseDomains, mDNSBool ackConfig)
-{
- MD5_CTX sdc; // search domain context
- static mDNSu16 resolverGroupID = 0;
-
- // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
- if (fqdn) fqdn->c[0] = 0;
- if (RegDomains ) *RegDomains = NULL;
- if (BrowseDomains) *BrowseDomains = NULL;
-
- LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s",
- setservers ? " setservers" : "",
- setsearch ? " setsearch" : "",
- fqdn ? " fqdn" : "",
- RegDomains ? " RegDomains" : "",
- BrowseDomains ? " BrowseDomains" : "");
-
- if (setsearch) MD5_Init(&sdc);
-
- // Add the inferred address-based configuration discovery domains
- // (should really be in core code I think, not platform-specific)
- if (setsearch)
- {
- struct ifaddrs *ifa = mDNSNULL;
- struct sockaddr_in saddr;
- mDNSPlatformMemZero(&saddr, sizeof(saddr));
- saddr.sin_len = sizeof(saddr);
- saddr.sin_family = AF_INET;
- saddr.sin_port = 0;
- saddr.sin_addr.s_addr = *(in_addr_t *)&m->Router.ip.v4;
-
- // Don't add any reverse-IP search domains if doing the WAB bootstrap queries would cause dial-on-demand connection initiation
- if (!AddrRequiresPPPConnection((struct sockaddr *)&saddr)) ifa = myGetIfAddrs(1);
-
- while (ifa)
- {
- mDNSAddr a, n;
- char buf[64];
-
- if (ifa->ifa_addr->sa_family == AF_INET &&
- ifa->ifa_netmask &&
- !(ifa->ifa_flags & IFF_LOOPBACK) &&
- !SetupAddr(&a, ifa->ifa_addr) &&
- !mDNSv4AddressIsLinkLocal(&a.ip.v4) )
- {
- // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be incorrect, so we explicitly fix it here before calling SetupAddr
- // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
- ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family; // Make sure ifa_netmask->sa_family is set correctly
- SetupAddr(&n, ifa->ifa_netmask);
- // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
- mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", a.ip.v4.b[3] & n.ip.v4.b[3],
- a.ip.v4.b[2] & n.ip.v4.b[2],
- a.ip.v4.b[1] & n.ip.v4.b[1],
- a.ip.v4.b[0] & n.ip.v4.b[0]);
- UpdateSearchDomainHash(m, &sdc, buf, NULL);
- mDNS_AddSearchDomain_CString(buf, mDNSNULL);
- }
- ifa = ifa->ifa_next;
- }
- }
-
-#ifndef MDNS_NO_DNSINFO
- if (setservers || setsearch)
- {
- dns_config_t *config = dns_configuration_copy();
- if (!config)
- {
- // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
- // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
- // Apparently this is expected behaviour -- "not a bug".
- // Accordingly, we suppress syslog messages for the first three minutes after boot.
- // If we are still getting failures after three minutes, then we log them.
- if ((mDNSu32)mDNSPlatformRawTime() > (mDNSu32)(mDNSPlatformOneSecond * 180))
- LogMsg("mDNSPlatformSetDNSConfig: Error: dns_configuration_copy returned NULL");
- }
- else
- {
- LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d, generation %llu", config->n_resolver, config->generation);
- if (m->p->LastConfigGeneration == config->generation)
- {
- LogInfo("mDNSPlatformSetDNSConfig: generation number %llu same, not processing", config->generation);
- dns_configuration_free(config);
- SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
- return mDNSfalse;
- }
-#if APPLE_OSX_mDNSResponder
- SetupActiveDirectoryDomain(config);
-#endif
-
- // With scoped DNS, we don't want to answer a non-scoped question using a scoped cache entry
- // and vice-versa. As we compare resolverGroupID for matching cache entry with question, we need
- // to make sure that they don't match. We ensure this by always bumping up resolverGroupID between
- // the two calls to ConfigResolvers DNSServers for scoped and non-scoped can never have the
- // same resolverGroupID.
- //
- // All non-scoped resolvers use the same resolverGroupID i.e, we treat them all equally.
- ConfigResolvers(m, config, kScopeNone, setsearch, setservers, &sdc, ++resolverGroupID);
- resolverGroupID += config->n_resolver;
-
- ConfigResolvers(m, config, kScopeInterfaceID, setsearch, setservers, &sdc, resolverGroupID);
- resolverGroupID += config->n_scoped_resolver;
-
- ConfigResolvers(m, config, kScopeServiceID, setsearch, setservers, &sdc, resolverGroupID);
-
- // Acking provides a hint that we processed this current configuration and
- // we will use that from now on, assuming we don't get another one immediately
- // after we return from here.
- if (ackConfig)
- {
- // Note: We have to set the generation number here when we are acking.
- // For every DNS configuration change, we do the following:
- //
- // 1) Copy dns configuration, handle search domains change
- // 2) Copy dns configuration, handle dns server change
- //
- // If we update the generation number at step (1), we won't process the
- // DNS servers the second time because generation number would be the same.
- // As we ack only when we process dns servers, we set the generation number
- // during acking.
- m->p->LastConfigGeneration = config->generation;
- LogInfo("mDNSPlatformSetDNSConfig: Acking configuration setservers %d, setsearch %d", setservers, setsearch);
- AckConfigd(m, config);
- }
- dns_configuration_free(config);
- if (setsearch) FinalizeSearchDomainHash(m, &sdc);
- setservers = mDNSfalse; // Done these now -- no need to fetch the same data from SCDynamicStore
- setsearch = mDNSfalse;
- }
- }
-#endif // MDNS_NO_DNSINFO
- SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
- return mDNStrue;
-}
-
-
-mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r)
-{
- char buf[256];
- (void)m; // Unused
-
- SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL, NULL);
- if (!store)
- LogMsg("mDNSPlatformGetPrimaryInterface: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
- else
- {
- CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_IPv4);
- if (dict)
- {
- r->type = mDNSAddrType_IPv4;
- r->ip.v4 = zerov4Addr;
- CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
- if (string)
- {
- if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
- LogMsg("Could not convert router to CString");
- else
- {
- struct sockaddr_in saddr;
- saddr.sin_len = sizeof(saddr);
- saddr.sin_family = AF_INET;
- saddr.sin_port = 0;
- inet_aton(buf, &saddr.sin_addr);
-
- *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr;
- }
- }
-
- string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
- if (string)
- {
- mDNSBool HavePrimaryGlobalv6 = mDNSfalse; // does the primary interface have a global v6 address?
- struct ifaddrs *ifa = myGetIfAddrs(1);
-
- *v4 = *v6 = zeroAddr;
-
- if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8)) { LogMsg("Could not convert router to CString"); goto exit; }
-
- // find primary interface in list
- while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6))
- {
- mDNSAddr tmp6 = zeroAddr;
- if (!strcmp(buf, ifa->ifa_name))
- {
- if (ifa->ifa_addr->sa_family == AF_INET)
- {
- if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4)) SetupAddr(v4, ifa->ifa_addr);
- }
- else if (ifa->ifa_addr->sa_family == AF_INET6)
- {
- SetupAddr(&tmp6, ifa->ifa_addr);
- if (tmp6.ip.v6.b[0] >> 5 == 1) // global prefix: 001
- { HavePrimaryGlobalv6 = mDNStrue; *v6 = tmp6; }
- }
- }
- else
- {
- // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
- if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6->ip.v6.b[0])
- {
- SetupAddr(&tmp6, ifa->ifa_addr);
- if (tmp6.ip.v6.b[0] >> 5 == 1) *v6 = tmp6;
- }
- }
- ifa = ifa->ifa_next;
- }
-
- // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
- // V4 to communicate w/ our DNS server
- }
-
-exit:
- CFRelease(dict);
- }
- CFRelease(store);
- }
- return mStatus_NoError;
-}
-
-mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
-{
- LogInfo("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status, dname->c);
- char uname[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
- ConvertDomainNameToCString(dname, uname);
-
- char *p = uname;
- while (*p)
- {
- *p = tolower(*p);
- if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
- p++;
- }
-
- // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
- // That single entity is a CFDictionary with name "HostNames".
- // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
- // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
- // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
- // The CFDictionary for each FQDN holds (at present) a single name/value pair,
- // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
-
- const CFStringRef StateKeys [1] = { CFSTR("HostNames") };
- const CFStringRef HostKeys [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) };
- const CFStringRef StatusKeys[1] = { CFSTR("Status") };
- if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname);
- else
- {
- const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
- if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status);
- else
- {
- const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
- if (HostVals[0])
- {
- const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
- if (StateVals[0])
- {
- CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- if (StateDict)
- {
- mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, mDNSNULL, StateDict);
- CFRelease(StateDict);
- }
- CFRelease(StateVals[0]);
- }
- CFRelease(HostVals[0]);
- }
- CFRelease(StatusVals[0]);
- }
- CFRelease(HostKeys[0]);
- }
-}
-
-#if APPLE_OSX_mDNSResponder
-#if !NO_AWACS
-
-// checks whether a domain is present in Setup:/Network/BackToMyMac. Just because there is a key in the
-// keychain for a domain, it does not become a valid BTMM domain. If things get inconsistent, this will
-// help catch it
-mDNSlocal mDNSBool IsBTMMDomain(domainname *d)
-{
- SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:IsBTMMDomain"), NULL, NULL);
- if (!store)
- {
- LogMsg("IsBTMMDomain: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
- return mDNSfalse;
- }
- CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
- if (btmm)
- {
- CFIndex size = CFDictionaryGetCount(btmm);
- char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
- const void *key[size];
- const void *val[size];
- domainname dom;
- int i;
- CFDictionaryGetKeysAndValues(btmm, key, val);
- for (i = 0; i < size; i++)
- {
- LogInfo("BackToMyMac %d", i);
- if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
- LogMsg("IsBTMMDomain: ERROR!! Can't read BackToMyMac %d key %s", i, buf);
- else
- {
- mDNSu32 uid = atoi(buf);
- if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
- LogMsg("IsBTMMDomain: Can't read BackToMyMac %d val %s", i, buf);
- else if (MakeDomainNameFromDNSNameString(&dom, buf) && dom.c[0])
- {
- if (SameDomainName(&dom, d))
- {
- LogInfo("IsBTMMDomain: Domain %##s is a btmm domain, uid %u", d->c, uid);
- CFRelease(btmm);
- CFRelease(store);
- return mDNStrue;
- }
- }
- }
- }
- CFRelease(btmm);
- }
- CFRelease(store);
- LogInfo("IsBTMMDomain: Domain %##s not a btmm domain", d->c);
- return mDNSfalse;
-}
-
-// Appends data to the buffer
-mDNSlocal int AddOneItem(char *buf, int bufsz, char *data, int *currlen)
-{
- int len;
-
- len = strlcpy(buf + *currlen, data, bufsz - *currlen);
- if (len >= (bufsz - *currlen))
- {
- // if we have exceeded the space in buf, it has already been NULL terminated
- // and we have nothing more to do. Set currlen to the last byte so that the caller
- // knows to do the right thing
- LogMsg("AddOneItem: Exceeded the max buffer size currlen %d, len %d", *currlen, len);
- *currlen = bufsz - 1;
- return -1;
- }
- else { (*currlen) += len; }
-
- buf[*currlen] = ',';
- if (*currlen >= bufsz)
- {
- LogMsg("AddOneItem: ERROR!! How can currlen be %d", *currlen);
- *currlen = bufsz - 1;
- buf[*currlen] = 0;
- return -1;
- }
- // if we have filled up the buffer exactly, then there is no more work to do
- if (*currlen == bufsz - 1) { buf[*currlen] = 0; return -1; }
- (*currlen)++;
- return *currlen;
-}
-
-// If we have at least one BTMM domain, then trigger the connection to the relay. If we have no
-// BTMM domains, then bring down the connection to the relay.
-mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
-{
- DomainAuthInfo *BTMMDomain = mDNSNULL;
- DomainAuthInfo *FoundInList;
- static mDNSBool AWACSDConnected = mDNSfalse;
- char AllUsers[1024]; // maximum size of mach message
- char AllPass[1024]; // maximum size of mach message
- char username[MAX_DOMAIN_LABEL + 1];
- int currulen = 0;
- int currplen = 0;
-
- // if a domain is being deleted, we want to send a disconnect. If we send a disconnect now,
- // we may not be able to send the dns queries over the relay connection which may be needed
- // for sending the deregistrations. Hence, we need to delay sending the disconnect. But we
- // need to make sure that we send the disconnect before attempting the next connect as the
- // awacs connections are redirected based on usernames.
- //
- // For now we send a disconnect immediately. When we start sending dns queries over the relay
- // connection, we will need to fix this.
-
- for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
- if (!FoundInList->deltime && FoundInList->AutoTunnel && IsBTMMDomain(&FoundInList->domain))
- {
- // We need the passwd from the first domain.
- BTMMDomain = FoundInList;
- ConvertDomainLabelToCString_unescaped((domainlabel *)BTMMDomain->domain.c, username);
- LogInfo("UpdateBTMMRelayConnection: user %s for domain %##s", username, BTMMDomain->domain.c);
- if (AddOneItem(AllUsers, sizeof(AllUsers), username, &currulen) == -1) break;
- if (AddOneItem(AllPass, sizeof(AllPass), BTMMDomain->b64keydata, &currplen) == -1) break;
- }
-
- if (BTMMDomain)
- {
- // In the normal case (where we neither exceed the buffer size nor write bytes that
- // fit exactly into the buffer), currulen/currplen should be a different size than
- // (AllUsers - 1) / (AllPass - 1). In that case, we need to override the "," with a NULL byte.
-
- if (currulen != (int)(sizeof(AllUsers) - 1)) AllUsers[currulen - 1] = 0;
- if (currplen != (int)(sizeof(AllPass) - 1)) AllPass[currplen - 1] = 0;
-
- LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers);
- AWACS_Connect(AllUsers, AllPass, "hello.connectivity.me.com");
- AWACSDConnected = mDNStrue;
- }
- else
- {
- // Disconnect only if we connected previously
- if (AWACSDConnected)
- {
- LogInfo("UpdateBTMMRelayConnection: AWS_Disconnect");
- AWACS_Disconnect();
- AWACSDConnected = mDNSfalse;
- }
- else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect");
- }
-}
-#else
-mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
-{
- (void) m; // Unused
- LogInfo("UpdateBTMMRelayConnection: AWACS connection not started, no AWACS library");
-}
-#endif // ! NO_AWACS
-
-mDNSlocal void ProcessConndConfigChanges(mDNS *const m);
-
-#endif // APPLE_OSX_mDNSResponder
-
-// MUST be called holding the lock
-mDNSexport void SetDomainSecrets(mDNS *m)
-{
-#ifdef NO_SECURITYFRAMEWORK
- (void) m;
- LogMsg("Note: SetDomainSecrets: no keychain support");
-#else
- mDNSBool haveAutoTunnels = mDNSfalse;
-
- LogInfo("SetDomainSecrets");
-
- // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
- // In the case where the user simultaneously removes their DDNS host name and the key
- // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
- // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
- // address records behind that we no longer have permission to delete.
- DomainAuthInfo *ptr;
- for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
- ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
-
-#if APPLE_OSX_mDNSResponder
- {
- // Mark all TunnelClients for deletion
- ClientTunnel *client;
- for (client = m->TunnelClients; client; client = client->next)
- {
- LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c);
- client->MarkedForDeletion = mDNStrue;
- }
- }
-#endif // APPLE_OSX_mDNSResponder
-
- // String Array used to write list of private domains to Dynamic Store
- CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- if (!sa) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
- CFIndex i;
- CFDataRef data = NULL;
- const int itemsPerEntry = 4; // domain name, key name, key value, Name value
- CFArrayRef secrets = NULL;
- int err = mDNSKeychainGetSecrets(&secrets);
- if (err || !secrets)
- LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err, secrets);
- else
- {
- CFIndex ArrayCount = CFArrayGetCount(secrets);
- // Iterate through the secrets
- for (i = 0; i < ArrayCount; ++i)
- {
- mDNSBool AutoTunnel;
- int j, offset;
- CFArrayRef entry = CFArrayGetValueAtIndex(secrets, i);
- if (CFArrayGetTypeID() != CFGetTypeID(entry) || itemsPerEntry != CFArrayGetCount(entry))
- { LogMsg("SetDomainSecrets: malformed entry %d, itemsPerEntry %d", i, itemsPerEntry); continue; }
- for (j = 0; j < CFArrayGetCount(entry); ++j)
- if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry, j)))
- { LogMsg("SetDomainSecrets: malformed entry item %d", j); continue; }
-
- // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
-
- // Max legal domainname as C-string, including space for btmmprefix and terminating NUL
- // Get DNS domain this key is for (kmDNSKcWhere)
- char stringbuf[MAX_ESCAPED_DOMAIN_NAME + sizeof(btmmprefix)];
- data = CFArrayGetValueAtIndex(entry, kmDNSKcWhere);
- if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
- { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data)); continue; }
- CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
- stringbuf[CFDataGetLength(data)] = '\0';
-
- AutoTunnel = mDNSfalse;
- offset = 0;
- if (!strncmp(stringbuf, dnsprefix, strlen(dnsprefix)))
- offset = strlen(dnsprefix);
- else if (!strncmp(stringbuf, btmmprefix, strlen(btmmprefix)))
- {
- AutoTunnel = mDNStrue;
- offset = strlen(btmmprefix);
- }
- domainname domain;
- if (!MakeDomainNameFromDNSNameString(&domain, stringbuf + offset)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf); continue; }
-
- // Get key name (kmDNSKcAccount)
- data = CFArrayGetValueAtIndex(entry, kmDNSKcAccount);
- if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
- { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data)); continue; }
- CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)stringbuf);
- stringbuf[CFDataGetLength(data)] = '\0';
-
- domainname keyname;
- if (!MakeDomainNameFromDNSNameString(&keyname, stringbuf)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf); continue; }
-
- // Get key data (kmDNSKcKey)
- data = CFArrayGetValueAtIndex(entry, kmDNSKcKey);
- if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
- {
- LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data));
- continue;
- }
- CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
- stringbuf[CFDataGetLength(data)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
-
- // Get the Name of the keychain entry (kmDNSKcName) host or host:port
- // The hostname also has the port number and ":". It should take a maximum of 6 bytes.
- char hostbuf[MAX_ESCAPED_DOMAIN_NAME + 6]; // Max legal domainname as C-string, including terminating NUL
- data = CFArrayGetValueAtIndex(entry, kmDNSKcName);
- if (CFDataGetLength(data) >= (int)sizeof(hostbuf))
- {
- LogMsg("SetDomainSecrets: host:port data too long: %d", CFDataGetLength(data));
- continue;
- }
- CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)hostbuf);
- hostbuf[CFDataGetLength(data)] = '\0';
-
- domainname hostname;
- mDNSIPPort port;
- char *hptr;
- hptr = strchr(hostbuf, ':');
-
- port.NotAnInteger = 0;
- if (hptr)
- {
- mDNSu8 *p;
- mDNSu16 val = 0;
-
- *hptr++ = '\0';
- while(hptr && *hptr != 0)
- {
- if (*hptr < '0' || *hptr > '9')
- { LogMsg("SetDomainSecrets: Malformed Port number %d, val %d", *hptr, val); val = 0; break;}
- val = val * 10 + *hptr - '0';
- hptr++;
- }
- if (!val) continue;
- p = (mDNSu8 *)&val;
- port.NotAnInteger = p[0] << 8 | p[1];
- }
- // The hostbuf is of the format dsid at hostname:port. We don't care about the dsid.
- hptr = strchr(hostbuf, '@');
- if (hptr)
- hptr++;
- else
- hptr = hostbuf;
- if (!MakeDomainNameFromDNSNameString(&hostname, hptr)) { LogMsg("SetDomainSecrets: bad host name %s", hptr); continue; }
-
- DomainAuthInfo *FoundInList;
- for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
- if (SameDomainName(&FoundInList->domain, &domain)) break;
-
-#if APPLE_OSX_mDNSResponder
- if (FoundInList)
- {
- // If any client tunnel destination is in this domain, set deletion flag to false
- ClientTunnel *client;
- for (client = m->TunnelClients; client; client = client->next)
- if (FoundInList == GetAuthInfoForName_internal(m, &client->dstname))
- {
- LogInfo("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c);
- client->MarkedForDeletion = mDNSfalse;
- }
- }
-
-#endif // APPLE_OSX_mDNSResponder
-
- // Uncomment the line below to view the keys as they're read out of the system keychain
- // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
- //LogInfo("SetDomainSecrets: domain %##s keyname %##s key %s hostname %##s port %d", &domain.c, &keyname.c, stringbuf, hostname.c, (port.b[0] << 8 | port.b[1]));
- LogInfo("SetDomainSecrets: domain %##s keyname %##s hostname %##s port %d", &domain.c, &keyname.c, hostname.c, (port.b[0] << 8 | port.b[1]));
-
- // If didn't find desired domain in the list, make a new entry
- ptr = FoundInList;
- if (FoundInList && FoundInList->AutoTunnel && haveAutoTunnels == mDNSfalse) haveAutoTunnels = mDNStrue;
- if (!FoundInList)
- {
- ptr = (DomainAuthInfo*)mallocL("DomainAuthInfo", sizeof(*ptr));
- if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; }
- }
-
- //LogInfo("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
-
- // It is an AutoTunnel if the keychains tells us so (with btmm prefix) or if it is a TunnelModeDomain
- if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, stringbuf, &hostname, &port, AutoTunnel) == mStatus_BadParamErr)
- {
- if (!FoundInList) mDNSPlatformMemFree(ptr); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
- continue;
- }
-
- ConvertDomainNameToCString(&domain, stringbuf);
- CFStringRef cfs = CFStringCreateWithCString(NULL, stringbuf, kCFStringEncodingUTF8);
- if (cfs) { CFArrayAppendValue(sa, cfs); CFRelease(cfs); }
- }
- CFRelease(secrets);
- }
-
- if (!privateDnsArray || !CFEqual(privateDnsArray, sa))
- {
- if (privateDnsArray)
- CFRelease(privateDnsArray);
-
- privateDnsArray = sa;
- CFRetain(privateDnsArray);
- mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
- }
- CFRelease(sa);
-
-#if APPLE_OSX_mDNSResponder
- {
- // clean up ClientTunnels
- ClientTunnel **pp = &m->TunnelClients;
- while (*pp)
- {
- if ((*pp)->MarkedForDeletion)
- {
- ClientTunnel *cur = *pp;
- LogInfo("SetDomainSecrets: removing client %p %##s from list", cur, cur->dstname.c);
- if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
- AutoTunnelSetKeys(cur, mDNSfalse);
- *pp = cur->next;
- freeL("ClientTunnel", cur);
- }
- else
- pp = &(*pp)->next;
- }
-
- mDNSBool needAutoTunnelNAT = mDNSfalse;
- DomainAuthInfo *info;
- for (info = m->AuthInfoList; info; info = info->next)
- {
- if (info->AutoTunnel)
- {
- UpdateAutoTunnelDeviceInfoRecord(m, info);
- UpdateAutoTunnelHostRecord(m, info);
- UpdateAutoTunnelServiceRecords(m, info);
- UpdateAutoTunnel6Record(m, info);
- if (info->deltime)
- {
- if (info->AutoTunnelServiceStarted) info->AutoTunnelServiceStarted = mDNSfalse;
- }
- else if (info->AutoTunnelServiceStarted)
- needAutoTunnelNAT = true;
-
- UpdateAutoTunnelDomainStatus(m, info);
- }
- }
-
- // If the AutoTunnel NAT-T is no longer needed (& is currently running), stop it
- if (!needAutoTunnelNAT && m->AutoTunnelNAT.clientContext)
- {
- // stop the NAT operation, reset port, cleanup state
- mDNS_StopNATOperation_internal(m, &m->AutoTunnelNAT);
- m->AutoTunnelNAT.ExternalAddress = zerov4Addr;
- m->AutoTunnelNAT.NewAddress = zerov4Addr;
- m->AutoTunnelNAT.ExternalPort = zeroIPPort;
- m->AutoTunnelNAT.RequestedPort = zeroIPPort;
- m->AutoTunnelNAT.Lifetime = 0;
- m->AutoTunnelNAT.Result = mStatus_NoError;
- m->AutoTunnelNAT.clientContext = mDNSNULL;
- }
-
- UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
- ProcessConndConfigChanges(m); // Update AutoTunnelInnerAddress values and default ipsec policies as necessary
- }
-#endif // APPLE_OSX_mDNSResponder
-
- CheckSuppressUnusableQuestions(m);
-
-#endif /* NO_SECURITYFRAMEWORK */
-}
-
-mDNSlocal void SetLocalDomains(void)
-{
- CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- if (!sa) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
-
- CFArrayAppendValue(sa, CFSTR("local"));
- CFArrayAppendValue(sa, CFSTR("254.169.in-addr.arpa"));
- CFArrayAppendValue(sa, CFSTR("8.e.f.ip6.arpa"));
- CFArrayAppendValue(sa, CFSTR("9.e.f.ip6.arpa"));
- CFArrayAppendValue(sa, CFSTR("a.e.f.ip6.arpa"));
- CFArrayAppendValue(sa, CFSTR("b.e.f.ip6.arpa"));
-
- mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, mDNSNULL, sa);
- CFRelease(sa);
-}
-
-mDNSlocal void GetCurrentPMSetting(const CFStringRef name, mDNSs32 *val)
-{
-#if USE_IOPMCOPYACTIVEPMPREFERENCES
- CFTypeRef blob = NULL;
- CFStringRef str = NULL;
- CFDictionaryRef odict = NULL;
- CFDictionaryRef idict = NULL;
- CFNumberRef number = NULL;
-
- blob = IOPSCopyPowerSourcesInfo();
- if (!blob) { LogMsg("GetCurrentPMSetting: IOPSCopyPowerSourcesInfo failed!"); goto end; }
-
- odict = IOPMCopyActivePMPreferences();
- if (!odict) { LogMsg("GetCurrentPMSetting: IOPMCopyActivePMPreferences failed!"); goto end; }
-
- str = IOPSGetProvidingPowerSourceType(blob);
- if (!str) { LogMsg("GetCurrentPMSetting: IOPSGetProvidingPowerSourceType failed!"); goto end; }
-
- idict = CFDictionaryGetValue(odict, str);
- if (!idict)
- {
- char buf[256];
- if (!CFStringGetCString(str, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
- LogMsg("GetCurrentPMSetting: CFDictionaryGetValue (%s) failed!", buf);
- goto end;
- }
-
- number = CFDictionaryGetValue(idict, name);
- if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
- *val = 0;
-end:
- if (blob) CFRelease(blob);
- if (odict) CFRelease(odict);
-
-#else
-
- SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetCurrentPMSetting"), NULL, NULL);
- if (!store) LogMsg("GetCurrentPMSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
- else
- {
- CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_PowerSettings);
- if (!dict) LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict");
- else
- {
- CFNumberRef number = CFDictionaryGetValue(dict, name);
- if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
- *val = 0;
- CFRelease(dict);
- }
- CFRelease(store);
- }
-
-#endif
-}
-
-#if APPLE_OSX_mDNSResponder
-
-static CFMutableDictionaryRef spsStatusDict = NULL;
-static const CFStringRef kMetricRef = CFSTR("Metric");
-
-mDNSlocal void SPSStatusPutNumber(CFMutableDictionaryRef dict, const mDNSu8* const ptr, CFStringRef key)
-{
- mDNSu8 tmp = (ptr[0] - '0') * 10 + ptr[1] - '0';
- CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt8Type, &tmp);
- if (!num)
- LogMsg("SPSStatusPutNumber: Could not create CFNumber");
- else
- {
- CFDictionarySetValue(dict, key, num);
- CFRelease(num);
- }
-}
-
-mDNSlocal CFMutableDictionaryRef SPSCreateDict(const mDNSu8* const ptr)
-{
- CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- if (!dict) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict; }
-
- char buffer[1024];
- buffer[mDNS_snprintf(buffer, sizeof(buffer), "%##s", ptr) - 1] = 0;
- CFStringRef spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
- if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname full"); CFRelease(dict); return NULL; }
- CFDictionarySetValue(dict, CFSTR("FullName"), spsname);
- CFRelease(spsname);
-
- if (ptr[0] >= 2) SPSStatusPutNumber(dict, ptr + 1, CFSTR("Type"));
- if (ptr[0] >= 5) SPSStatusPutNumber(dict, ptr + 4, CFSTR("Portability"));
- if (ptr[0] >= 8) SPSStatusPutNumber(dict, ptr + 7, CFSTR("MarginalPower"));
- if (ptr[0] >= 11) SPSStatusPutNumber(dict, ptr +10, CFSTR("TotalPower"));
-
- mDNSu32 tmp = SPSMetric(ptr);
- CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tmp);
- if (!num)
- LogMsg("SPSCreateDict: Could not create CFNumber");
- else
- {
- CFDictionarySetValue(dict, kMetricRef, num);
- CFRelease(num);
- }
-
- if (ptr[0] >= 12)
- {
- memcpy(buffer, ptr + 13, ptr[0] - 12);
- buffer[ptr[0] - 12] = 0;
- spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
- if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname"); CFRelease(dict); return NULL; }
- else
- {
- CFDictionarySetValue(dict, CFSTR("PrettyName"), spsname);
- CFRelease(spsname);
- }
- }
-
- return dict;
-}
-
-mDNSlocal CFComparisonResult CompareSPSEntries(const void *val1, const void *val2, void *context)
-{
- (void)context;
- return CFNumberCompare((CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val1, kMetricRef),
- (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val2, kMetricRef),
- NULL);
-}
-
-mDNSlocal void UpdateSPSStatus(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
-{
- NetworkInterfaceInfo* info = (NetworkInterfaceInfo*)question->QuestionContext;
- debugf("UpdateSPSStatus: %s %##s %s %s", info->ifname, question->qname.c, AddRecord ? "Add" : "Rmv", answer ? RRDisplayString(m, answer) : "<null>");
-
- mDNS_Lock(m);
- mDNS_UpdateAllowSleep(m);
- mDNS_Unlock(m);
-
- if (answer && SPSMetric(answer->rdata->u.name.c) > 999999) return; // Ignore instances with invalid names
-
- if (!spsStatusDict)
- {
- spsStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- if (!spsStatusDict) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; }
- }
-
- CFStringRef ifname = CFStringCreateWithCString(NULL, info->ifname, kCFStringEncodingUTF8);
- if (!ifname) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; }
-
- CFMutableArrayRef array = NULL;
-
- if (!CFDictionaryGetValueIfPresent(spsStatusDict, ifname, (const void**) &array))
- {
- array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- if (!array) { LogMsg("UpdateSPSStatus: Could not create CFMutableArray"); CFRelease(ifname); return; }
- CFDictionarySetValue(spsStatusDict, ifname, array);
- CFRelease(array); // let go of our reference, now that the dict has one
- }
- else
- if (!array) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info->ifname); CFRelease(ifname); return; }
-
- if (!answer) // special call that means the question has been stopped (because the interface is going away)
- CFArrayRemoveAllValues(array);
- else
- {
- CFMutableDictionaryRef dict = SPSCreateDict(answer->rdata->u.name.c);
- if (!dict) { CFRelease(ifname); return; }
-
- if (AddRecord)
- {
- if (!CFArrayContainsValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict))
- {
- int i=0;
- for (i=0; i<CFArrayGetCount(array); i++)
- if (CompareSPSEntries(CFArrayGetValueAtIndex(array, i), dict, NULL) != kCFCompareLessThan)
- break;
- CFArrayInsertValueAtIndex(array, i, dict);
- }
- else LogMsg("UpdateSPSStatus: %s array already contains %##s", info->ifname, answer->rdata->u.name.c);
- }
- else
- {
- CFIndex i = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict);
- if (i != -1) CFArrayRemoveValueAtIndex(array, i);
- else LogMsg("UpdateSPSStatus: %s array does not contain %##s", info->ifname, answer->rdata->u.name.c);
- }
-
- CFRelease(dict);
- }
-
- if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, info->ifname, array);
-
- CFRelease(ifname);
-}
-
-mDNSlocal mDNSs32 GetSystemSleepTimerSetting(void)
-{
- mDNSs32 val = -1;
- SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL, NULL);
- if (!store)
- LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
- else
- {
- CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_PowerSettings);
- if (dict)
- {
- CFNumberRef number = CFDictionaryGetValue(dict, CFSTR("System Sleep Timer"));
- if (number) CFNumberGetValue(number, kCFNumberSInt32Type, &val);
- CFRelease(dict);
- }
- CFRelease(store);
- }
- return val;
-}
-
-mDNSlocal void SetSPS(mDNS *const m)
-{
-
- // If we ever want to know InternetSharing status in the future, use DNSXEnableProxy()
- mDNSu8 sps = (OfferSleepProxyService && GetSystemSleepTimerSetting() == 0) ? mDNSSleepProxyMetric_IncidentalSoftware : 0;
-
- // For devices that are not running NAT, but are set to never sleep, we may choose to act
- // as a Sleep Proxy, but only for non-portable Macs (Portability > 35 means nominal weight < 3kg)
- //if (sps > mDNSSleepProxyMetric_PrimarySoftware && SPMetricPortability > 35) sps = 0;
-
- // If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery
-
- // For devices that are unable to sleep at all to save power, or save 1W or less by sleeping,
- // it makes sense for them to offer low-priority Sleep Proxy service on the network.
- // We rate such a device as metric 70 ("Incidentally Available Hardware")
- if (SPMetricMarginalPower <= 60 && !sps) sps = mDNSSleepProxyMetric_IncidentalHardware;
-
- // If the launchd plist specifies an explicit value for the Intent Metric, then use that instead of the
- // computed value (currently 40 "Primary Network Infrastructure Software" or 80 "Incidentally Available Software")
- if (sps && OfferSleepProxyService && OfferSleepProxyService < 100) sps = OfferSleepProxyService;
-
-#ifdef NO_APPLETV_SLEEP_PROXY_ON_WIFI
- // AppleTVs are not reliable sleep proxy servers on WiFi. Do not offer to be a BSP if the WiFi interface is active.
- if (IsAppleTV())
- {
- NetworkInterfaceInfo *intf = mDNSNULL;
- mDNSEthAddr bssid = zeroEthAddr;
- for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
- {
- bssid = GetBSSID(intf->ifname);
- if (!mDNSSameEthAddress(&bssid, &zeroEthAddr))
- {
- LogMsg("SetSPS: AppleTV on WiFi - not advertising BSP services");
- sps = 0;
- break;
- }
- }
- }
-#endif // NO_APPLETV_SLEEP_PROXY_ON_WIFI
-
- mDNSCoreBeSleepProxyServer(m, sps, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures);
-}
-
-// The definitions below should eventually come from some externally-supplied header file.
-// However, since these definitions can't really be changed without breaking binary compatibility,
-// they should never change, so in practice it should not be a big problem to have them defined here.
-
-enum
-{ // commands from the daemon to the driver
- cmd_mDNSOffloadRR = 21, // give the mdns update buffer to the driver
-};
-
-typedef union { void *ptr; mDNSOpaque64 sixtyfourbits; } FatPtr;
-
-typedef struct
-{ // cmd_mDNSOffloadRR structure
- uint32_t command; // set to OffloadRR
- uint32_t rrBufferSize; // number of bytes of RR records
- uint32_t numUDPPorts; // number of SRV UDP ports
- uint32_t numTCPPorts; // number of SRV TCP ports
- uint32_t numRRRecords; // number of RR records
- uint32_t compression; // rrRecords - compression is base for compressed strings
- FatPtr rrRecords; // address of array of pointers to the rr records
- FatPtr udpPorts; // address of udp port list (SRV)
- FatPtr tcpPorts; // address of tcp port list (SRV)
-} mDNSOffloadCmd;
-
-#include <IOKit/IOKitLib.h>
-#include <dns_util.h>
-
-mDNSlocal mDNSu16 GetPortArray(mDNS *const m, int trans, mDNSIPPort *portarray)
-{
- const domainlabel *const tp = (trans == mDNSTransport_UDP) ? (const domainlabel *)"\x4_udp" : (const domainlabel *)"\x4_tcp";
- int count = 0;
- AuthRecord *rr;
- for (rr = m->ResourceRecords; rr; rr=rr->next)
- if (rr->resrec.rrtype == kDNSType_SRV && SameDomainLabel(ThirdLabel(rr->resrec.name)->c, tp->c))
- {
- if (portarray) portarray[count] = rr->resrec.rdata->u.srv.port;
- count++;
- }
-
- // If Back to My Mac is on, also wake for packets to the IPSEC UDP port (4500)
- if (trans == mDNSTransport_UDP && m->AutoTunnelNAT.clientContext)
- {
- LogSPS("GetPortArray Back to My Mac at %d", count);
- if (portarray) portarray[count] = IPSECPort;
- count++;
- }
- return(count);
-}
-
-#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
-mDNSlocal mDNSBool SupportsTCPKeepAlive()
-{
- IOReturn ret = kIOReturnSuccess;
- CFTypeRef obj = NULL;
- mDNSBool supports = mDNSfalse;
-
- ret = IOPlatformCopyFeatureActive(CFSTR("TCPKeepAliveDuringSleep"), &obj);
- if ((kIOReturnSuccess == ret) && (obj != NULL))
- {
- supports = (obj == kCFBooleanTrue)? mDNStrue : mDNSfalse;
- CFRelease(obj);
- }
- LogSPS("%s: The hardware %s TCP Keep Alive", __func__, (supports ? "supports" : "does not support"));
- return supports;
-}
-
-mDNSlocal mDNSBool OnBattery(void)
-{
- CFTypeRef powerInfo = IOPSCopyPowerSourcesInfo();
- CFTypeRef powerSrc = IOPSGetProvidingPowerSourceType(powerInfo);
- mDNSBool result = mDNSfalse;
-
- if (powerInfo != NULL)
- {
- result = CFEqual(CFSTR(kIOPSBatteryPowerValue), powerSrc);
- CFRelease(powerInfo);
- }
- LogSPS("%s: The system is on %s", __func__, (result)? "Battery" : "AC Power");
- return result;
-}
-
-#endif // !TARGET_OS_EMBEDDED
-
-#define TfrRecordToNIC(RR) \
- ((!(RR)->resrec.InterfaceID && ((RR)->ForceMCast || IsLocalDomain((RR)->resrec.name))))
-
-mDNSlocal mDNSu32 CountProxyRecords(mDNS *const m, uint32_t *const numbytes, NetworkInterfaceInfo *const intf, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
-{
- *numbytes = 0;
- int count = 0;
-
- AuthRecord *rr;
-
- for (rr = m->ResourceRecords; rr; rr=rr->next)
- {
- if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
- {
-#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
- mDNSBool isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
- // Skip over all other records if we are registering TCP KeepAlive records only
- // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive.
- if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
- continue;
-
- // Update the record before calculating the number of bytes required
- // We offload the TCP Keepalive record even if the update fails. When the driver gets the record, it will
- // attempt to update the record again.
- if (isKeepAliveRecord && (UpdateKeepaliveRData(m, rr, intf, mDNSfalse, mDNSNULL) != mStatus_NoError))
- LogSPS("CountProxyRecords: Failed to update keepalive record - %s", ARDisplayString(m, rr));
-#else
- (void) TCPKAOnly; // unused
- (void) supportsTCPKA; // unused
- (void) intf; // unused
-#endif // APPLE_OSX_mDNSResponder
- if (TfrRecordToNIC(rr))
- {
- *numbytes += DomainNameLength(rr->resrec.name) + 10 + rr->resrec.rdestimate;
- LogSPS("CountProxyRecords: %3d size %5d total %5d %s",
- count, DomainNameLength(rr->resrec.name) + 10 + rr->resrec.rdestimate, *numbytes, ARDisplayString(m,rr));
- count++;
- }
- }
- }
- return(count);
-}
-
-mDNSlocal void GetProxyRecords(mDNS *const m, DNSMessage *const msg, uint32_t *const numbytes, FatPtr *const records, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
-{
- mDNSu8 *p = msg->data;
- const mDNSu8 *const limit = p + *numbytes;
- InitializeDNSMessage(&msg->h, zeroID, zeroID);
-
- int count = 0;
- AuthRecord *rr;
-
- for (rr = m->ResourceRecords; rr; rr=rr->next)
- {
- if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
- {
-#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
- mDNSBool isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
-
- // Skip over all other records if we are registering TCP KeepAlive records only
- // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive
- if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
- continue;
-#else
- (void) TCPKAOnly; // unused
- (void) supportsTCPKA; // unused
-#endif // APPLE_OSX_mDNSResponder
-
- if (TfrRecordToNIC(rr))
- {
- records[count].sixtyfourbits = zeroOpaque64;
- records[count].ptr = p;
- if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
- rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the 'unique' bit so PutResourceRecord will set it
- p = PutResourceRecordTTLWithLimit(msg, p, &msg->h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit);
- rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear 'unique' bit back to normal state
- LogSPS("GetProxyRecords: %3d start %p end %p size %5d total %5d %s",
- count, records[count].ptr, p, p - (mDNSu8 *)records[count].ptr, p - msg->data, ARDisplayString(m,rr));
- count++;
- }
- }
- }
- *numbytes = p - msg->data;
-}
-
-// If compiling with old headers and libraries (pre 10.5) that don't include IOConnectCallStructMethod
-// then we declare a dummy version here so that the code at least compiles
-#ifndef AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
-static kern_return_t
-IOConnectCallStructMethod(
- mach_port_t connection, // In
- uint32_t selector, // In
- const void *inputStruct, // In
- size_t inputStructCnt, // In
- void *outputStruct, // Out
- size_t *outputStructCnt) // In/Out
-{
- (void)connection;
- (void)selector;
- (void)inputStruct;
- (void)inputStructCnt;
- (void)outputStruct;
- (void)outputStructCnt;
- LogMsg("Compiled without IOConnectCallStructMethod");
- return(KERN_FAILURE);
-}
-#endif
-
-mDNSexport mDNSBool SupportsInNICProxy(NetworkInterfaceInfo *const intf)
-{
- if(!UseInternalSleepProxy)
- {
- LogSPS("SupportsInNICProxy: Internal Sleep Proxy is disabled");
- return mDNSfalse;
- }
- return CheckInterfaceSupport(intf, mDNS_IOREG_KEY);
-}
-
-mDNSexport mStatus ActivateLocalProxy(mDNS *const m, NetworkInterfaceInfo *const intf) // Called with the lock held
-{
- mStatus result = mStatus_UnknownErr;
- mDNSBool TCPKAOnly = mDNSfalse;
- mDNSBool supportsTCPKA = mDNSfalse;
- mDNSBool onbattery = mDNSfalse;
- io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
-
-#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
- onbattery = OnBattery();
- // Check if the interface supports TCP Keepalives and the system policy says it is ok to offload TCP Keepalive records
- supportsTCPKA = (InterfaceSupportsKeepAlive(intf) && SupportsTCPKeepAlive());
-
- // Only TCP Keepalive records are to be offloaded if
- // - The system is on battery
- // - OR wake for network access is not set but powernap is enabled
- TCPKAOnly = supportsTCPKA && ((m->SystemWakeOnLANEnabled == mDNS_WakeOnBattery) || onbattery);
-#else
- (void) onbattery; // unused;
-#endif
- if (!service) { LogMsg("ActivateLocalProxy: No service for interface %s", intf->ifname); return(mStatus_UnknownErr); }
-
- io_name_t n1, n2;
- IOObjectGetClass(service, n1);
- io_object_t parent;
- kern_return_t kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
- if (kr != KERN_SUCCESS) LogMsg("ActivateLocalProxy: IORegistryEntryGetParentEntry for %s/%s failed %d", intf->ifname, n1, kr);
- else
- {
- IOObjectGetClass(parent, n2);
- LogSPS("ActivateLocalProxy: Interface %s service %s parent %s", intf->ifname, n1, n2);
- const CFTypeRef ref = IORegistryEntryCreateCFProperty(parent, CFSTR(mDNS_IOREG_KEY), kCFAllocatorDefault, mDNSNULL);
- if (!ref) LogSPS("ActivateLocalProxy: No mDNS_IOREG_KEY for interface %s/%s/%s", intf->ifname, n1, n2);
- else
- {
- if (CFGetTypeID(ref) != CFStringGetTypeID() || !CFEqual(ref, CFSTR(mDNS_IOREG_VALUE)))
- LogMsg("ActivateLocalProxy: mDNS_IOREG_KEY for interface %s/%s/%s value %s != %s",
- intf->ifname, n1, n2, CFStringGetCStringPtr(ref, mDNSNULL), mDNS_IOREG_VALUE);
- else if (!UseInternalSleepProxy)
- LogSPS("ActivateLocalProxy: Not using internal (NIC) sleep proxy for interface %s", intf->ifname);
- else
- {
- io_connect_t conObj;
- kr = IOServiceOpen(parent, mach_task_self(), mDNS_USER_CLIENT_CREATE_TYPE, &conObj);
- if (kr != KERN_SUCCESS) LogMsg("ActivateLocalProxy: IOServiceOpen for %s/%s/%s failed %d", intf->ifname, n1, n2, kr);
- else
- {
- mDNSOffloadCmd cmd;
- mDNSPlatformMemZero(&cmd, sizeof(cmd)); // When compiling 32-bit, make sure top 32 bits of 64-bit pointers get initialized to zero
- cmd.command = cmd_mDNSOffloadRR;
- cmd.numUDPPorts = GetPortArray(m, mDNSTransport_UDP, mDNSNULL);
- cmd.numTCPPorts = GetPortArray(m, mDNSTransport_TCP, mDNSNULL);
- cmd.numRRRecords = CountProxyRecords(m, &cmd.rrBufferSize, intf, TCPKAOnly, supportsTCPKA);
- cmd.compression = sizeof(DNSMessageHeader);
-
- DNSMessage *msg = (DNSMessage *)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader) + cmd.rrBufferSize);
- cmd.rrRecords.ptr = mallocL("mDNSOffloadCmd rrRecords", cmd.numRRRecords * sizeof(FatPtr));
- cmd.udpPorts.ptr = mallocL("mDNSOffloadCmd udpPorts", cmd.numUDPPorts * sizeof(mDNSIPPort));
- cmd.tcpPorts.ptr = mallocL("mDNSOffloadCmd tcpPorts", cmd.numTCPPorts * sizeof(mDNSIPPort));
-
- LogSPS("ActivateLocalProxy: msg %p %d RR %p %d, UDP %p %d, TCP %p %d",
- msg, cmd.rrBufferSize,
- cmd.rrRecords.ptr, cmd.numRRRecords,
- cmd.udpPorts.ptr, cmd.numUDPPorts,
- cmd.tcpPorts.ptr, cmd.numTCPPorts);
-
- if (!msg || !cmd.rrRecords.ptr || !cmd.udpPorts.ptr || !cmd.tcpPorts.ptr)
- LogMsg("ActivateLocalProxy: Failed to allocate memory: msg %p %d RR %p %d, UDP %p %d, TCP %p %d",
- msg, cmd.rrBufferSize,
- cmd.rrRecords.ptr, cmd.numRRRecords,
- cmd.udpPorts.ptr, cmd.numUDPPorts,
- cmd.tcpPorts.ptr, cmd.numTCPPorts);
- else
- {
- GetProxyRecords(m, msg, &cmd.rrBufferSize, cmd.rrRecords.ptr, TCPKAOnly, supportsTCPKA);
- GetPortArray(m, mDNSTransport_UDP, cmd.udpPorts.ptr);
- GetPortArray(m, mDNSTransport_TCP, cmd.tcpPorts.ptr);
- char outputData[2];
- size_t outputDataSize = sizeof(outputData);
- kr = IOConnectCallStructMethod(conObj, 0, &cmd, sizeof(cmd), outputData, &outputDataSize);
- LogSPS("ActivateLocalProxy: IOConnectCallStructMethod for %s/%s/%s %d", intf->ifname, n1, n2, kr);
- if (kr == KERN_SUCCESS) result = mStatus_NoError;
- }
-
- if (cmd.tcpPorts.ptr) freeL("mDNSOffloadCmd udpPorts", cmd.tcpPorts.ptr);
- if (cmd.udpPorts.ptr) freeL("mDNSOffloadCmd tcpPorts", cmd.udpPorts.ptr);
- if (cmd.rrRecords.ptr) freeL("mDNSOffloadCmd rrRecords", cmd.rrRecords.ptr);
- if (msg) freeL("mDNSOffloadCmd msg", msg);
- IOServiceClose(conObj);
- }
- }
- CFRelease(ref);
- }
- IOObjectRelease(parent);
- }
- IOObjectRelease(service);
- return result;
-}
-
-#endif // APPLE_OSX_mDNSResponder
-
-mDNSlocal mDNSu8 SystemWakeForNetworkAccess(void)
-{
- mDNSs32 val = 0;
- mDNSu8 ret = (mDNSu8)mDNS_NoWake;
-
- if (DisableSleepProxyClient)
- {
- LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
- return mDNSfalse;
- }
-
- GetCurrentPMSetting(CFSTR("Wake On LAN"), &val);
-
- ret = (mDNSu8)(val != 0) ? mDNS_WakeOnAC : mDNS_NoWake;
-
-#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
- // If we have TCP Keepalive support, system is capable of registering for TCP Keepalives.
- // Further policy decisions on whether to offload the records is handled during sleep processing.
- if ((ret == mDNS_NoWake) && SupportsTCPKeepAlive())
- ret = (mDNSu8)mDNS_WakeOnBattery;
-#endif // APPLE_OSX_mDNSResponder
-
- LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", ret);
- return ret;
-}
-
-mDNSlocal mDNSBool SystemSleepOnlyIfWakeOnLAN(void)
-{
- mDNSs32 val = 0;
- GetCurrentPMSetting(CFSTR("PrioritizeNetworkReachabilityOverSleep"), &val);
- return val != 0 ? mDNStrue : mDNSfalse;
-}
-
-#if APPLE_OSX_mDNSResponder
-// When sleeping, we always ensure that the _autotunnel6 record (if connected to RR relay)
-// gets deregistered, so that older peers are forced to connect over direct UDP instead of
-// the RR relay.
-//
-// When sleeping w/o a successful AutoTunnel NAT Mapping, we ensure that all our BTMM
-// service records are deregistered, so they do not appear in peers' Finder sidebars.
-// We do this by checking for the (non-autotunnel) SRV records, as the PTR and TXT records
-// depend on their associated SRV record and therefore will be deregistered together in a
-// single update with the SRV record.
-//
-// Also, the per-zone _kerberos TXT record is always there, including while sleeping, so
-// its presence shouldn't delay sleep.
-//
-// Note that the order of record deregistration is: first _autotunnel6 (if connected to RR
-// relay) and host records get deregistered, then SRV (UpdateAllSrvRecords), PTR and TXT.
-//
-// Also note that returning false here will not delay sleep past the maximum of 10 seconds.
-mDNSexport mDNSBool RecordReadyForSleep(mDNS *const m, AuthRecord *rr)
-{
- if (!AuthRecord_uDNS(rr)) return mDNStrue;
-
- if ((rr->resrec.rrtype == kDNSType_AAAA) && SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0c_autotunnel6"))
- {
- LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
- return mDNSfalse;
- }
-
- if ((mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result))
- {
- if (rr->resrec.rrtype == kDNSType_SRV && rr->state != regState_NoTarget && rr->zone
- && !SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0b_autotunnel"))
- {
- DomainAuthInfo *info = GetAuthInfoForName_internal(m, rr->zone);
- if (info && info->AutoTunnel)
- {
- LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
- return mDNSfalse;
- }
- }
- }
-
- return mDNStrue;
-}
-
-// Caller must hold the lock
-mDNSexport void RemoveAutoTunnel6Record(mDNS *const m)
-{
- DomainAuthInfo *info;
- // Set the address to zero before calling UpdateAutoTunnel6Record, so that it will
- // deregister the record, and the MemFree callback won't re-register.
- m->AutoTunnelRelayAddr = zerov6Addr;
- for (info = m->AuthInfoList; info; info = info->next)
- if (info->AutoTunnel)
- UpdateAutoTunnel6Record(m, info);
-}
-
-mDNSlocal mDNSBool IPv6AddressIsOnInterface(mDNSv6Addr ipv6Addr, char *ifname)
-{
- struct ifaddrs *ifa;
- struct ifaddrs *ifaddrs;
- mDNSAddr addr;
-
- if (if_nametoindex(ifname) == 0) {LogInfo("IPv6AddressIsOnInterface: Invalid name %s", ifname); return mDNSfalse;}
-
- if (getifaddrs(&ifaddrs) < 0) {LogInfo("IPv6AddressIsOnInterface: getifaddrs failed"); return mDNSfalse;}
-
- for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next)
- {
- if (strncmp(ifa->ifa_name, ifname, IFNAMSIZ) != 0)
- continue;
- if ((ifa->ifa_flags & IFF_UP) == 0 || !ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET6)
- continue;
- if (SetupAddr(&addr, ifa->ifa_addr) != mStatus_NoError)
- {
- LogInfo("IPv6AddressIsOnInterface: SetupAddr error, continuing to the next address");
- continue;
- }
- if (mDNSSameIPv6Address(ipv6Addr, *(mDNSv6Addr*)&addr.ip.v6))
- {
- LogInfo("IPv6AddressIsOnInterface: found %.16a", &ipv6Addr);
- break;
- }
- }
- freeifaddrs(ifaddrs);
- return ifa != NULL;
-}
-
-mDNSlocal mDNSv6Addr IPv6AddressFromString(char* buf)
-{
- mDNSv6Addr retVal;
- struct addrinfo hints;
- struct addrinfo *res0;
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_INET6;
- hints.ai_flags = AI_NUMERICHOST;
-
- int err = getaddrinfo(buf, NULL, &hints, &res0);
- if (err)
- return zerov6Addr;
-
- retVal = *(mDNSv6Addr*)&((struct sockaddr_in6*)res0->ai_addr)->sin6_addr;
-
- freeaddrinfo(res0);
-
- return retVal;
-}
-
-mDNSlocal CFDictionaryRef CopyConnectivityBackToMyMacDict()
-{
- SCDynamicStoreRef store = NULL;
- CFDictionaryRef connd = NULL;
- CFDictionaryRef BTMMDict = NULL;
-
- store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:CopyConnectivityBackToMyMacDict"), NULL, NULL);
- if (!store)
- {
- LogMsg("CopyConnectivityBackToMyMacDict: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
- goto end;
- }
-
- connd = SCDynamicStoreCopyValue(store, NetworkChangedKey_BTMMConnectivity);
- if (!connd)
- {
- LogInfo("CopyConnectivityBackToMyMacDict: SCDynamicStoreCopyValue failed: %s", SCErrorString(SCError()));
- goto end;
- }
-
- BTMMDict = CFDictionaryGetValue(connd, CFSTR("BackToMyMac"));
- if (!BTMMDict)
- {
- LogInfo("CopyConnectivityBackToMyMacDict: CFDictionaryGetValue: No value for BackToMyMac");
- goto end;
- }
-
- // Non-dictionary is treated as non-existent dictionary
- if (CFGetTypeID(BTMMDict) != CFDictionaryGetTypeID())
- {
- BTMMDict = NULL;
- LogMsg("CopyConnectivityBackToMyMacDict: BackToMyMac not a dictionary");
- goto end;
- }
-
- CFRetain(BTMMDict);
-
-end:
- if (connd) CFRelease(connd);
- if (store) CFRelease(store);
-
- return BTMMDict;
-}
-
-#define MAX_IPV6_TEXTUAL 40
-
-mDNSlocal mDNSv6Addr ParseBackToMyMacAddr(CFDictionaryRef BTMMDict, CFStringRef ifKey, CFStringRef addrKey)
-{
- mDNSv6Addr retVal = zerov6Addr;
- CFTypeRef string = NULL;
- char ifname[IFNAMSIZ];
- char address[MAX_IPV6_TEXTUAL];
-
- if (!BTMMDict)
- return zerov6Addr;
-
- if (!CFDictionaryGetValueIfPresent(BTMMDict, ifKey, &string))
- {
- LogInfo("ParseBackToMyMacAddr: interface key does not exist");
- return zerov6Addr;
- }
-
- if (!CFStringGetCString(string, ifname, IFNAMSIZ, kCFStringEncodingUTF8))
- {
- LogMsg("ParseBackToMyMacAddr: Could not convert interface to CString");
- return zerov6Addr;
- }
-
- if (!CFDictionaryGetValueIfPresent(BTMMDict, addrKey, &string))
- {
- LogMsg("ParseBackToMyMacAddr: address key does not exist, but interface key does");
- return zerov6Addr;
- }
-
- if (!CFStringGetCString(string, address, sizeof(address), kCFStringEncodingUTF8))
- {
- LogMsg("ParseBackToMyMacAddr: Could not convert address to CString");
- return zerov6Addr;
- }
-
- retVal = IPv6AddressFromString(address);
- LogInfo("ParseBackToMyMacAddr: %s (%s) %.16a", ifname, address, &retVal);
-
- if (mDNSIPv6AddressIsZero(retVal))
- return zerov6Addr;
-
- if (!IPv6AddressIsOnInterface(retVal, ifname))
- {
- LogMsg("ParseBackToMyMacAddr: %.16a is not on %s", &retVal, ifname);
- return zerov6Addr;
- }
-
- return retVal;
-}
-
-mDNSlocal CFDictionaryRef GetBackToMyMacZones(CFDictionaryRef BTMMDict)
-{
- CFTypeRef zones = NULL;
-
- if (!BTMMDict)
- return NULL;
-
- if (!CFDictionaryGetValueIfPresent(BTMMDict, CFSTR("Zones"), &zones))
- {
- LogInfo("CopyBTMMZones: Zones key does not exist");
- return NULL;
- }
-
- return zones;
-}
-
-mDNSlocal mDNSv6Addr ParseBackToMyMacZone(CFDictionaryRef zones, DomainAuthInfo* info)
-{
- mDNSv6Addr addr = zerov6Addr;
- char buffer[MAX_ESCAPED_DOMAIN_NAME];
- CFStringRef domain = NULL;
- CFTypeRef theZone = NULL;
-
- if (!zones)
- return addr;
-
- ConvertDomainNameToCString(&info->domain, buffer);
- domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
- if (!domain)
- return addr;
-
- if (CFDictionaryGetValueIfPresent(zones, domain, &theZone))
- addr = ParseBackToMyMacAddr(theZone, CFSTR("Interface"), CFSTR("Address"));
-
- CFRelease(domain);
-
- return addr;
-}
-
-mDNSlocal void SetupBackToMyMacInnerAddresses(mDNS *const m, CFDictionaryRef BTMMDict)
-{
- DomainAuthInfo* info;
- CFDictionaryRef zones = GetBackToMyMacZones(BTMMDict);
- mDNSv6Addr newAddr;
-
- for (info = m->AuthInfoList; info; info = info->next)
- {
- if (!info->AutoTunnel)
- continue;
-
- newAddr = ParseBackToMyMacZone(zones, info);
-
- if (mDNSSameIPv6Address(newAddr, info->AutoTunnelInnerAddress))
- continue;
-
- info->AutoTunnelInnerAddress = newAddr;
- DeregisterAutoTunnelHostRecord(m, info);
- UpdateAutoTunnelHostRecord(m, info);
- UpdateAutoTunnelDomainStatus(m, info);
- }
-}
-
-// MUST be called holding the lock
-mDNSlocal void ProcessConndConfigChanges(mDNS *const m)
-{
- CFDictionaryRef dict = CopyConnectivityBackToMyMacDict();
- if (!dict)
- LogInfo("ProcessConndConfigChanges: No BTMM dictionary");
- mDNSv6Addr relayAddr = ParseBackToMyMacAddr(dict, CFSTR("RelayInterface"), CFSTR("RelayAddress"));
-
- LogInfo("ProcessConndConfigChanges: relay %.16a", &relayAddr);
-
- SetupBackToMyMacInnerAddresses(m, dict);
-
- if (dict) CFRelease(dict);
-
- if (!mDNSSameIPv6Address(relayAddr, m->AutoTunnelRelayAddr))
- {
- m->AutoTunnelRelayAddr = relayAddr;
-
- DomainAuthInfo* info;
- for (info = m->AuthInfoList; info; info = info->next)
- if (info->AutoTunnel)
- {
- DeregisterAutoTunnel6Record(m, info);
- UpdateAutoTunnel6Record(m, info);
- UpdateAutoTunnelDomainStatus(m, info);
- }
-
- // Determine whether we need racoon to accept incoming connections
- UpdateAnonymousRacoonConfig(m);
- }
-
- // If awacsd crashes or exits for some reason, restart it
- UpdateBTMMRelayConnection(m);
-}
-#endif /* APPLE_OSX_mDNSResponder */
-
-mDNSlocal mDNSBool IsAppleNetwork(mDNS *const m)
-{
- DNSServer *s;
- // Determine if we're on AppleNW based on DNSServer having 17.x.y.z IPv4 addr
- for (s = m->DNSServers; s; s = s->next)
- {
- if (s->addr.ip.v4.b[0] == 17)
- {
- LogInfo("IsAppleNetwork: Found 17.x.y.z DNSServer concluding that we are on AppleNW: %##s %#a", s->domain.c, &s->addr);
- return mDNStrue;
- }
- }
- return mDNSfalse;
-}
-
-mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
-{
- LogInfo("*** Network Configuration Change *** (%d)%s",
- m->p->NetworkChanged ? mDNS_TimeNow(m) - m->p->NetworkChanged : 0,
- m->p->NetworkChanged ? "" : " (no scheduled configuration change)");
- m->p->NetworkChanged = 0; // If we received a network change event and deferred processing, we're now dealing with it
- mDNSs32 utc = mDNSPlatformUTC();
- m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
- m->SystemSleepOnlyIfWakeOnLAN = SystemSleepOnlyIfWakeOnLAN();
- MarkAllInterfacesInactive(m, utc);
- UpdateInterfaceList(m, utc);
- ClearInactiveInterfaces(m, utc);
- SetupActiveInterfaces(m, utc);
-
-#if APPLE_OSX_mDNSResponder
-
- mDNS_Lock(m);
- ProcessConndConfigChanges(m);
- mDNS_Unlock(m);
-
- // Scan to find client tunnels whose questions have completed,
- // but whose local inner/outer addresses have changed since the tunnel was set up
- ClientTunnel *p;
- for (p = m->TunnelClients; p; p = p->next)
- if (p->q.ThisQInterval < 0)
- {
- DomainAuthInfo* info = GetAuthInfoForName(m, &p->dstname);
- if (!info)
- {
- LogMsg("mDNSMacOSXNetworkChanged: Could not get AuthInfo for %##s, removing tunnel keys", p->dstname.c);
- AutoTunnelSetKeys(p, mDNSfalse);
- }
- else
- {
- mDNSv6Addr inner = info->AutoTunnelInnerAddress;
-
- if (!mDNSIPPortIsZero(p->rmt_outer_port))
- {
- mDNSAddr tmpSrc = zeroAddr;
- mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
- tmpDst.ip.v4 = p->rmt_outer;
- mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
- if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
- !mDNSSameIPv4Address(p->loc_outer, tmpSrc.ip.v4))
- {
- AutoTunnelSetKeys(p, mDNSfalse);
- p->loc_inner = inner;
- p->loc_outer = tmpSrc.ip.v4;
- AutoTunnelSetKeys(p, mDNStrue);
- }
- }
- else
- {
- if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
- !mDNSSameIPv6Address(p->loc_outer6, m->AutoTunnelRelayAddr))
- {
- AutoTunnelSetKeys(p, mDNSfalse);
- p->loc_inner = inner;
- p->loc_outer6 = m->AutoTunnelRelayAddr;
- AutoTunnelSetKeys(p, mDNStrue);
- }
- }
- }
- }
-
- SetSPS(m);
-
- NetworkInterfaceInfoOSX *i;
- for (i = m->p->InterfaceList; i; i = i->next)
- {
- if (!m->SPSSocket) // Not being Sleep Proxy Server; close any open BPF fds
- {
- if (i->BPF_fd >= 0 && CountProxyTargets(m, i, mDNSNULL, mDNSNULL) == 0) CloseBPF(i);
- }
- else // else, we're Sleep Proxy Server; open BPF fds
- {
- if (i->Exists && i->Registered == i && i->ifinfo.McastTxRx && !(i->ifa_flags & IFF_LOOPBACK) && i->BPF_fd == -1)
- { LogSPS("%s requesting BPF", i->ifinfo.ifname); i->BPF_fd = -2; mDNSRequestBPF(); }
- }
- }
-
-#endif // APPLE_OSX_mDNSResponder
-
- uDNS_SetupDNSConfig(m);
- mDNS_ConfigChanged(m);
-
- if (IsAppleNetwork(m) != mDNS_McastTracingEnabled)
- {
- mDNS_McastTracingEnabled = mDNS_McastTracingEnabled ? mDNSfalse : mDNStrue;
- LogMsg("mDNSMacOSXNetworkChanged: Multicast Tracing %s", mDNS_McastTracingEnabled ? "Enabled" : "Disabled");
- UpdateDebugState();
- }
-
-}
-
-// Called with KQueueLock & mDNS lock
-mDNSlocal void SetNetworkChanged(mDNS *const m, mDNSs32 delay)
-{
- if (!m->p->NetworkChanged || m->p->NetworkChanged - NonZeroTime(m->timenow + delay) < 0)
- {
- m->p->NetworkChanged = NonZeroTime(m->timenow + delay);
- LogInfo("SetNetworkChanged: scheduling in %d msec", delay);
- }
-}
-
-// Called with KQueueLock & mDNS lock
-mDNSlocal void SetKeyChainTimer(mDNS *const m, mDNSs32 delay)
-{
- // If it's not set or it needs to happen sooner than when it's currently set
- if (!m->p->KeyChainTimer || m->p->KeyChainTimer - NonZeroTime(m->timenow + delay) > 0)
- {
- m->p->KeyChainTimer = NonZeroTime(m->timenow + delay);
- LogInfo("SetKeyChainTimer: %d", delay);
- }
-}
-
-// Copy the fourth slash-delimited element from either:
-// State:/Network/Interface/<bsdname>/IPv4
-// or
-// Setup:/Network/Service/<servicename>/Interface
-mDNSlocal CFStringRef CopyNameFromKey(CFStringRef key)
-{
- CFArrayRef a;
- CFStringRef name = NULL;
-
- a = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
- if (a && CFArrayGetCount(a) == 5) name = CFRetain(CFArrayGetValueAtIndex(a, 3));
- if (a != NULL) CFRelease(a);
-
- return name;
-}
-
-// Whether a key from a network change notification corresponds to
-// an IP service that is explicitly configured for IPv4 Link Local
-mDNSlocal mDNSBool ChangedKeysHaveIPv4LL(CFArrayRef inkeys)
-{
- SCDynamicStoreRef store = NULL;
- CFDictionaryRef dict = NULL;
- CFMutableArrayRef a;
- const void **keys = NULL, **vals = NULL;
- CFStringRef pattern = NULL;
- int i, ic, j, jc;
- mDNSBool found = mDNSfalse;
-
- jc = CFArrayGetCount(inkeys);
- if (!jc) goto done;
-
- store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:ChangedKeysHaveIPv4LL"), NULL, NULL);
- if (store == NULL) goto done;
-
- a = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- if (a == NULL) goto done;
-
- // Setup:/Network/Service/[^/]+/Interface
- pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetInterface);
- if (pattern == NULL) goto done;
- CFArrayAppendValue(a, pattern);
- CFRelease(pattern);
-
- // Setup:/Network/Service/[^/]+/IPv4
- pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetIPv4);
- if (pattern == NULL) goto done;
- CFArrayAppendValue(a, pattern);
- CFRelease(pattern);
-
- dict = SCDynamicStoreCopyMultiple(store, NULL, a);
- CFRelease(a);
-
- if (!dict)
- {
- LogMsg("ChangedKeysHaveIPv4LL: Empty dictionary");
- goto done;
- }
-
- ic = CFDictionaryGetCount(dict);
- vals = mDNSPlatformMemAllocate(sizeof (void *) * ic);
- keys = mDNSPlatformMemAllocate(sizeof (void *) * ic);
- CFDictionaryGetKeysAndValues(dict, keys, vals);
-
- for (j = 0; j < jc && !found; j++)
- {
- CFStringRef key = CFArrayGetValueAtIndex(inkeys, j);
- CFStringRef ifname = NULL;
-
- char buf[256];
-
- // It would be nice to use a regex here
- if (!CFStringHasPrefix(key, CFSTR("State:/Network/Interface/")) || !CFStringHasSuffix(key, kSCEntNetIPv4)) continue;
-
- if ((ifname = CopyNameFromKey(key)) == NULL) continue;
- if (mDNS_LoggingEnabled)
- {
- if (!CFStringGetCString(ifname, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
- LogInfo("ChangedKeysHaveIPv4LL: potential ifname %s", buf);
- }
-
- for (i = 0; i < ic; i++)
- {
- CFDictionaryRef ipv4dict;
- CFStringRef name;
- CFStringRef serviceid;
- CFStringRef configmethod;
-
- if (!CFStringHasSuffix(keys[i], kSCEntNetInterface)) continue;
-
- if (CFDictionaryGetTypeID() != CFGetTypeID(vals[i])) continue;
-
- if ((name = CFDictionaryGetValue(vals[i], kSCPropNetInterfaceDeviceName)) == NULL) continue;
-
- if (!CFEqual(ifname, name)) continue;
-
- if ((serviceid = CopyNameFromKey(keys[i])) == NULL) continue;
- if (mDNS_LoggingEnabled)
- {
- if (!CFStringGetCString(serviceid, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
- LogInfo("ChangedKeysHaveIPv4LL: found serviceid %s", buf);
- }
-
- pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceid, kSCEntNetIPv4);
- CFRelease(serviceid);
- if (pattern == NULL) continue;
-
- ipv4dict = CFDictionaryGetValue(dict, pattern);
- CFRelease(pattern);
- if (!ipv4dict || CFDictionaryGetTypeID() != CFGetTypeID(ipv4dict)) continue;
-
- configmethod = CFDictionaryGetValue(ipv4dict, kSCPropNetIPv4ConfigMethod);
- if (!configmethod) continue;
-
- if (mDNS_LoggingEnabled)
- {
- if (!CFStringGetCString(configmethod, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
- LogInfo("ChangedKeysHaveIPv4LL: configmethod %s", buf);
- }
-
- if (CFEqual(configmethod, kSCValNetIPv4ConfigMethodLinkLocal)) { found = mDNStrue; break; }
- }
-
- CFRelease(ifname);
- }
-
-done:
- if (vals != NULL) mDNSPlatformMemFree(vals);
- if (keys != NULL) mDNSPlatformMemFree(keys);
- if (dict != NULL) CFRelease(dict);
- if (store != NULL) CFRelease(store);
-
- return found;
-}
-
-mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
-{
- (void)store; // Parameter not used
- mDNSBool changeNow = mDNSfalse;
- mDNS *const m = (mDNS *const)context;
- KQueueLock(m);
- mDNS_Lock(m);
-
- mDNSs32 delay = mDNSPlatformOneSecond * 2; // Start off assuming a two-second delay
-
- int c = CFArrayGetCount(changedKeys); // Count changes
- CFRange range = { 0, c };
- int c1 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Hostnames ) != 0);
- int c2 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0);
- int c3 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS ) != 0);
- int c4 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DNS ) != 0);
- if (c && c - c1 - c2 - c3 - c4 == 0)
- delay = mDNSPlatformOneSecond/10; // If these were the only changes, shorten delay
-
- // Do immediate network changed processing for "p2p*" interfaces and
- // for interfaces with the IFEF_DIRECTLINK flag set.
- {
- CFArrayRef labels;
- CFIndex n;
- for (int i = 0; i < c; i++)
- {
- CFStringRef key = CFArrayGetValueAtIndex(changedKeys, i);
-
- // Only look at keys with prefix "State:/Network/Interface/"
- if (!CFStringHasPrefix(key, NetworkChangedKey_StateInterfacePrefix))
- continue;
-
- // And suffix "IPv6" or "IPv4".
- if (!CFStringHasSuffix(key, kSCEntNetIPv6) && !CFStringHasSuffix(key, kSCEntNetIPv4))
- continue;
-
- labels = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
- if (labels == NULL)
- break;
- n = CFArrayGetCount(labels);
-
- // Interface changes will have keys of the form:
- // State:/Network/Interface/<interfaceName>/IPv6
- // Thus five '/' seperated fields, the 4th one being the <interfaceName> string.
- if (n == 5)
- {
- char buf[256];
-
- // The 4th label (index = 3) should be the interface name.
- if (CFStringGetCString(CFArrayGetValueAtIndex(labels, 3), buf, sizeof(buf), kCFStringEncodingUTF8)
- && (strstr(buf, "p2p") || (getExtendedFlags(buf) & IFEF_DIRECTLINK)))
- {
- LogInfo("NetworkChanged: interface %s, not delaying network change", buf);
- changeNow = mDNStrue;
- CFRelease(labels);
- break;
- }
- }
- CFRelease(labels);
- }
- }
-
- mDNSBool btmmChanged = CFArrayContainsValue(changedKeys, range, NetworkChangedKey_BackToMyMac);
- if (btmmChanged) delay = 0;
-
- if (mDNS_LoggingEnabled)
- {
- int i;
- for (i=0; i<c; i++)
- {
- char buf[256];
- if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys, i), buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
- LogInfo("*** NetworkChanged SC key: %s", buf);
- }
- LogInfo("*** NetworkChanged *** %d change%s %s%s%s%sdelay %d",
- c, c>1 ? "s" : "",
- c1 ? "(Local Hostname) " : "",
- c2 ? "(Computer Name) " : "",
- c3 ? "(DynamicDNS) " : "",
- c4 ? "(DNS) " : "",
- changeNow ? 0 : delay);
- }
-
- if (!changeNow)
- SetNetworkChanged(m, delay);
-
- // Other software might pick up these changes to register or browse in WAB or BTMM domains,
- // so in order for secure updates to be made to the server, make sure to read the keychain and
- // setup the DomainAuthInfo before handing the network change.
- // If we don't, then we will first try to register services in the clear, then later setup the
- // DomainAuthInfo, which is incorrect.
- if (c3 || btmmChanged)
- SetKeyChainTimer(m, delay);
-
- mDNS_Unlock(m);
-
- // If DNS settings changed, immediately force a reconfig (esp. cache flush)
- // Similarly, if an interface changed that is explicitly IPv4 link local, immediately force a reconfig
- if (c4 || ChangedKeysHaveIPv4LL(changedKeys) || changeNow) mDNSMacOSXNetworkChanged(m);
-
- KQueueUnlock(m, "NetworkChanged");
-}
-
-#if APPLE_OSX_mDNSResponder
-mDNSlocal void RefreshSPSStatus(const void *key, const void *value, void *context)
-{
- (void)context;
- char buf[IFNAMSIZ];
-
- CFStringRef ifnameStr = (CFStringRef)key;
- CFArrayRef array = (CFArrayRef)value;
- if (!CFStringGetCString(ifnameStr, buf, sizeof(buf), kCFStringEncodingUTF8))
- buf[0] = 0;
-
- LogInfo("RefreshSPSStatus: Updating SPS state for key %s, array count %d", buf, CFArrayGetCount(array));
- mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, buf, value);
-}
-#endif
-
-mDNSlocal void DynamicStoreReconnected(SCDynamicStoreRef store, void *info)
-{
- mDNS *const m = (mDNS *const)info;
- (void)store;
-
- LogInfo("DynamicStoreReconnected: Reconnected");
-
- // State:/Network/MulticastDNS
- SetLocalDomains();
-
- // State:/Network/DynamicDNS
- if (m->FQDN.c[0])
- mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1);
-
- // Note: PrivateDNS and BackToMyMac are automatically populated when configd is restarted
- // as we receive network change notifications and thus not necessary. But we leave it here
- // so that if things are done differently in the future, this code still works.
-
- // State:/Network/PrivateDNS
- if (privateDnsArray)
- mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
-
-#if APPLE_OSX_mDNSResponder
- mDNS_Lock(m);
- // State:/Network/BackToMyMac
- UpdateAutoTunnelDomainStatuses(m);
- mDNS_Unlock(m);
-
- // State:/Network/Interface/en0/SleepProxyServers
- if (spsStatusDict)
- CFDictionaryApplyFunction(spsStatusDict, RefreshSPSStatus, NULL);
-#endif
-}
-
-mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
-{
- mStatus err = -1;
- SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
- SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged, &context);
- CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- CFStringRef pattern1 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
- CFStringRef pattern2 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
- CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-
- if (!store) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error; }
- if (!keys || !pattern1 || !pattern2 || !patterns) goto error;
-
- CFArrayAppendValue(keys, NetworkChangedKey_IPv4);
- CFArrayAppendValue(keys, NetworkChangedKey_IPv6);
- CFArrayAppendValue(keys, NetworkChangedKey_Hostnames);
- CFArrayAppendValue(keys, NetworkChangedKey_Computername);
- CFArrayAppendValue(keys, NetworkChangedKey_DNS);
- CFArrayAppendValue(keys, NetworkChangedKey_DynamicDNS);
- CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac);
- CFArrayAppendValue(keys, NetworkChangedKey_PowerSettings); // should remove as part of <rdar://problem/6751656>
- CFArrayAppendValue(keys, NetworkChangedKey_BTMMConnectivity);
- CFArrayAppendValue(patterns, pattern1);
- CFArrayAppendValue(patterns, pattern2);
- CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
- if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns))
- { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error; }
-
-#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
- if (!SCDynamicStoreSetDispatchQueue(store, dispatch_get_main_queue()))
- { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
-#else
- m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
- if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
- CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
-#endif
- SCDynamicStoreSetDisconnectCallBack(store, DynamicStoreReconnected);
- m->p->Store = store;
- err = 0;
- goto exit;
-
-error:
- if (store) CFRelease(store);
-
-exit:
- if (patterns) CFRelease(patterns);
- if (pattern2) CFRelease(pattern2);
- if (pattern1) CFRelease(pattern1);
- if (keys) CFRelease(keys);
-
- return(err);
-}
-
-#if 0 // <rdar://problem/6751656>
-mDNSlocal void PMChanged(void *context)
-{
- mDNS *const m = (mDNS *const)context;
-
- KQueueLock(m);
- mDNS_Lock(m);
-
- LogSPS("PMChanged");
-
- SetNetworkChanged(m, mDNSPlatformOneSecond * 2);
-
- mDNS_Unlock(m);
- KQueueUnlock(m, "PMChanged");
-}
-
-mDNSlocal mStatus WatchForPMChanges(mDNS *const m)
-{
- m->p->PMRLS = IOPMPrefsNotificationCreateRunLoopSource(PMChanged, m);
- if (!m->p->PMRLS) { LogMsg("IOPMPrefsNotificationCreateRunLoopSource failed!"); return mStatus_UnknownErr; }
-
- CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->PMRLS, kCFRunLoopDefaultMode);
-
- return mStatus_NoError;
-}
-#endif
-
-#if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
-
-mDNSlocal void mDNSSetPacketFilterRules(mDNS *const m, char * ifname, const ResourceRecord *const excludeRecord)
-{
- AuthRecord *rr;
- pfArray_t portArray;
- pfArray_t protocolArray;
- uint32_t count = 0;
-
- for (rr = m->ResourceRecords; rr; rr=rr->next)
- {
- if ((rr->resrec.rrtype == kDNSServiceType_SRV)
- && ((rr->ARType == AuthRecordAnyIncludeP2P) || (rr->ARType == AuthRecordAnyIncludeAWDLandP2P)))
- {
- const mDNSu8 *p;
-
- if (count >= PFPortArraySize)
- {
- LogMsg("mDNSSetPacketFilterRules: %d service limit, skipping %s", PFPortArraySize, ARDisplayString(m, rr));
- continue;
- }
-
- if (excludeRecord && IdenticalResourceRecord(&rr->resrec, excludeRecord))
- {
- LogInfo("mDNSSetPacketFilterRules: record being removed, skipping %s", ARDisplayString(m, rr));
- continue;
- }
-
- LogInfo("mDNSSetPacketFilterRules: found %s", ARDisplayString(m, rr));
-
- portArray[count] = rr->resrec.rdata->u.srv.port.NotAnInteger;
-
- // Assume <Service Instance>.<App Protocol>.<Transport Protocol>.<Name>
- p = rr->resrec.name->c;
-
- // Skip to App Protocol
- if (p[0]) p += 1 + p[0];
-
- // Skip to Transport Protocol
- if (p[0]) p += 1 + p[0];
-
- if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp")) protocolArray[count] = IPPROTO_TCP;
- else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp")) protocolArray[count] = IPPROTO_UDP;
- else
- {
- LogMsg("mDNSSetPacketFilterRules: could not determine transport protocol of service");
- LogMsg("mDNSSetPacketFilterRules: %s", ARDisplayString(m, rr));
- return;
- }
- count++;
- }
- }
- mDNSPacketFilterControl(PF_SET_RULES, ifname, count, portArray, protocolArray);
-}
-
-// If the p2p interface already exists, update the Bonjour packet filter rules for it.
-mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
-{
- mDNS *const m = &mDNSStorage;
-
- NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
- while (intf)
- {
- if (strncmp(intf->ifname, "p2p", 3) == 0)
- {
- LogInfo("mDNSInitPacketFilter: Setting rules for ifname %s", intf->ifname);
- mDNSSetPacketFilterRules(m, intf->ifname, excludeRecord);
- break;
- }
- intf = GetFirstActiveInterface(intf->next);
- }
-}
-
-#else // !TARGET_OS_EMBEDDED
-
-// Currently no packet filter setup required on embedded platforms.
-mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
-{
- (void) excludeRecord; // unused
-}
-
-#endif // !TARGET_OS_EMBEDDED
-
-// Handle AWDL KEV_DL_MASTER_ELECTED event by restarting queries and advertisements
-// marked to include the AWDL interface.
-mDNSlocal void newMasterElected(mDNS *const m, struct net_event_data * ptr)
-{
- char ifname[IFNAMSIZ];
- mDNSu32 interfaceIndex;
- DNSQuestion *q;
- AuthRecord *rr;
- NetworkInterfaceInfoOSX *infoOSX;
- mDNSInterfaceID InterfaceID;
-
- snprintf(ifname, IFNAMSIZ, "%s%d", ptr->if_name, ptr->if_unit);
- interfaceIndex = if_nametoindex(ifname);
-
- if (!interfaceIndex)
- {
- LogMsg("newMasterElected: if_nametoindex(%s) failed", ifname);
- return;
- }
-
- LogInfo("newMasterElected: ifname = %s, interfaceIndex = %d", ifname, interfaceIndex);
- infoOSX = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)interfaceIndex);
-
- // Can get an KEV_DL_MASTER_ELECTED event prior to the interface existing
- // when it is first brought up.
- if (!infoOSX)
- {
- LogInfo("newMasterElected: interface not yet active");
- return;
- }
- InterfaceID = infoOSX->ifinfo.InterfaceID;
-
- for (q = m->Questions; q; q=q->next)
- {
- if ((!q->InterfaceID && (q->flags & kDNSServiceFlagsIncludeAWDL))
- || q->InterfaceID == InterfaceID)
- {
- LogInfo("newMasterElected: restarting %s query for %##s", DNSTypeName(q->qtype), q->qname.c);
- mDNSCoreRestartQuestion(m, q);
- }
- }
-
- for (rr = m->ResourceRecords; rr; rr=rr->next)
- {
- if ((!rr->resrec.InterfaceID
- && ((rr->ARType == AuthRecordAnyIncludeAWDL) || ((rr->ARType == AuthRecordAnyIncludeAWDLandP2P))))
- || rr->resrec.InterfaceID == InterfaceID)
- {
- LogInfo("newMasterElected: restarting %s announcements for %##s", DNSTypeName(rr->resrec.rrtype), rr->namestorage.c);
- mDNSCoreRestartRegistration(m, rr, -1);
- }
- }
-}
-
-// An ssth array of all zeroes indicates the peer has no services registered.
-mDNSlocal mDNSBool allZeroSSTH(struct opaque_presence_indication *op)
-{
- int i;
- int *intp = (int *) op->ssth;
-
- // MAX_SSTH_SIZE should always be a multiple of sizeof(int), if
- // it's not, print an error message and return false so that
- // corresponding peer records are not flushed when KEV_DL_NODE_PRESENCE event
- // is received.
- if (MAX_SSTH_SIZE % sizeof(int))
- {
- LogInfo("allZeroSSTH: MAX_SSTH_SIZE = %d not a multiple of sizeof(int)", MAX_SSTH_SIZE);
- return mDNSfalse;
- }
-
- for (i = 0; i < (int)(MAX_SSTH_SIZE / sizeof(int)); i++, intp++)
- {
- if (*intp)
- return mDNSfalse;
- }
- return mDNStrue;
-}
-
-// mDNS_Reconfirm_internal() adds 33% to this interval, so the records should
-// be removed in 4 seconds.
-#define kAWDLReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 3)
-
-// Mark records from this peer for deletion from the cache.
-mDNSlocal void removeCachedPeerRecords(mDNS *const m, mDNSu32 ifindex, mDNSAddr *ap)
-{
- mDNSu32 slot;
- CacheGroup *cg;
- CacheRecord *cr;
- mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(m, ifindex);
-
- if (!InterfaceID)
- {
- LogInfo("removeCachedPeerRecords: Invalid ifindex: %d", ifindex);
- return;
- }
-
- FORALL_CACHERECORDS(slot, cg, cr)
- {
- if ((InterfaceID == cr->resrec.InterfaceID) && mDNSSameAddress(ap, & cr->sourceAddress))
- {
- LogInfo("removeCachedPeerRecords: %s %##s marking for deletion",
- DNSTypeName(cr->resrec.rrtype), cr->resrec.name->c);
- mDNS_Reconfirm_internal(m, cr, kAWDLReconfirmTime);
- }
- }
-}
-
-// Handle KEV_DL_NODE_PRESENCE event.
-mDNSlocal void nodePresence(mDNS *const m, struct kev_dl_node_presence * p)
-{
- char buf[INET6_ADDRSTRLEN];
- struct opaque_presence_indication *op = (struct opaque_presence_indication *) p->node_service_info;
-
- if (inet_ntop(AF_INET6, & p->sin6_node_address.sin6_addr, buf, sizeof(buf)))
- LogInfo("nodePresence: IPv6 address: %s, SUI %d", buf, op->SUI);
- else
- LogInfo("nodePresence: inet_ntop() error");
-
- // AWDL will generate a KEV_DL_NODE_PRESENCE event with SSTH field of
- // all zeroes when a node is present and has no services registered.
- if (allZeroSSTH(op))
- {
- mDNSAddr peerAddr;
-
- peerAddr.type = mDNSAddrType_IPv6;
- peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
-
- LogInfo("nodePresence: ssth is all zeroes, delete cached records from this peer");
- removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr);
- }
-}
-
-// Handle KEV_DL_NODE_ABSENCE event.
-mDNSlocal void nodeAbsence(mDNS *const m, struct kev_dl_node_absence * p)
-{
- mDNSAddr peerAddr;
- char buf[INET6_ADDRSTRLEN];
-
- if (inet_ntop(AF_INET6, & p->sin6_node_address.sin6_addr, buf, sizeof(buf)))
- LogInfo("nodeAbsence: IPv6 address: %s", buf);
- else
- LogInfo("nodeAbsence: inet_ntop() error");
-
- peerAddr.type = mDNSAddrType_IPv6;
- peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
-
- LogInfo("nodeAbsence: delete cached records from this peer");
- removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr);
-}
-
-mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context)
-{
- mDNS *const m = (mDNS *const)context;
-
- mDNS_Lock(m);
-
- struct { struct kern_event_msg k; char extra[256]; } msg;
- int bytes = recv(s1, &msg, sizeof(msg), 0);
- if (bytes < 0)
- LogMsg("SysEventCallBack: recv error %d errno %d (%s)", bytes, errno, strerror(errno));
- else
- {
- LogInfo("SysEventCallBack got %d bytes size %d %X %s %X %s %X %s id %d code %d %s",
- bytes, msg.k.total_size,
- msg.k.vendor_code, msg.k.vendor_code == KEV_VENDOR_APPLE ? "KEV_VENDOR_APPLE" : "?",
- msg.k.kev_class, msg.k.kev_class == KEV_NETWORK_CLASS ? "KEV_NETWORK_CLASS" : "?",
- msg.k.kev_subclass, msg.k.kev_subclass == KEV_DL_SUBCLASS ? "KEV_DL_SUBCLASS" : "?",
- msg.k.id, msg.k.event_code,
- msg.k.event_code == KEV_DL_SIFFLAGS ? "KEV_DL_SIFFLAGS" :
- msg.k.event_code == KEV_DL_SIFMETRICS ? "KEV_DL_SIFMETRICS" :
- msg.k.event_code == KEV_DL_SIFMTU ? "KEV_DL_SIFMTU" :
- msg.k.event_code == KEV_DL_SIFPHYS ? "KEV_DL_SIFPHYS" :
- msg.k.event_code == KEV_DL_SIFMEDIA ? "KEV_DL_SIFMEDIA" :
- msg.k.event_code == KEV_DL_SIFGENERIC ? "KEV_DL_SIFGENERIC" :
- msg.k.event_code == KEV_DL_ADDMULTI ? "KEV_DL_ADDMULTI" :
- msg.k.event_code == KEV_DL_DELMULTI ? "KEV_DL_DELMULTI" :
- msg.k.event_code == KEV_DL_IF_ATTACHED ? "KEV_DL_IF_ATTACHED" :
- msg.k.event_code == KEV_DL_IF_DETACHING ? "KEV_DL_IF_DETACHING" :
- msg.k.event_code == KEV_DL_IF_DETACHED ? "KEV_DL_IF_DETACHED" :
- msg.k.event_code == KEV_DL_LINK_OFF ? "KEV_DL_LINK_OFF" :
- msg.k.event_code == KEV_DL_LINK_ON ? "KEV_DL_LINK_ON" :
- msg.k.event_code == KEV_DL_PROTO_ATTACHED ? "KEV_DL_PROTO_ATTACHED" :
- msg.k.event_code == KEV_DL_PROTO_DETACHED ? "KEV_DL_PROTO_DETACHED" :
- msg.k.event_code == KEV_DL_LINK_ADDRESS_CHANGED ? "KEV_DL_LINK_ADDRESS_CHANGED" :
- msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED ? "KEV_DL_WAKEFLAGS_CHANGED" :
- msg.k.event_code == KEV_DL_IF_IDLE_ROUTE_REFCNT ? "KEV_DL_IF_IDLE_ROUTE_REFCNT" :
- msg.k.event_code == KEV_DL_IFCAP_CHANGED ? "KEV_DL_IFCAP_CHANGED" :
- msg.k.event_code == KEV_DL_LINK_QUALITY_METRIC_CHANGED ? "KEV_DL_LINK_QUALITY_METRIC_CHANGED" :
- msg.k.event_code == KEV_DL_NODE_PRESENCE ? "KEV_DL_NODE_PRESENCE" :
- msg.k.event_code == KEV_DL_NODE_ABSENCE ? "KEV_DL_NODE_ABSENCE" :
- msg.k.event_code == KEV_DL_MASTER_ELECTED ? "KEV_DL_MASTER_ELECTED" :
- "?");
-
- if (msg.k.event_code == KEV_DL_NODE_PRESENCE)
- nodePresence(m, (struct kev_dl_node_presence *) &msg.k.event_data);
-
- if (msg.k.event_code == KEV_DL_NODE_ABSENCE)
- nodeAbsence(m, (struct kev_dl_node_absence *) &msg.k.event_data);
-
- if (msg.k.event_code == KEV_DL_MASTER_ELECTED)
- newMasterElected(m, (struct net_event_data *) &msg.k.event_data);
-
- // We receive network change notifications both through configd and through SYSPROTO_EVENT socket.
- // Configd may not generate network change events for manually configured interfaces (i.e., non-DHCP)
- // always during sleep/wakeup due to some race conditions (See radar:8666757). At the same time, if
- // "Wake on Network Access" is not turned on, the notification will not have KEV_DL_WAKEFLAGS_CHANGED.
- // Hence, during wake up, if we see a KEV_DL_LINK_ON (i.e., link is UP), we trigger a network change.
-
- if (msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED || msg.k.event_code == KEV_DL_LINK_ON)
- SetNetworkChanged(m, mDNSPlatformOneSecond * 2);
-
-#if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
-
- // For p2p interfaces, need to open the advertised service port in the firewall.
- if (msg.k.event_code == KEV_DL_IF_ATTACHED)
- {
- struct net_event_data * p;
- p = (struct net_event_data *) &msg.k.event_data;
-
- if (strncmp(p->if_name, "p2p", 3) == 0)
- {
- char ifname[IFNAMSIZ];
- snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit);
-
- LogInfo("SysEventCallBack: KEV_DL_IF_ATTACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name);
-
- mDNSSetPacketFilterRules(m, ifname, NULL);
- }
- }
-
- // For p2p interfaces, need to clear the firewall rules on interface detach
- if (msg.k.event_code == KEV_DL_IF_DETACHED)
- {
- struct net_event_data * p;
- p = (struct net_event_data *) &msg.k.event_data;
-
- if (strncmp(p->if_name, "p2p", 3) == 0)
- {
- pfArray_t portArray, protocolArray; // not initialized since count is 0 for PF_CLEAR_RULES
- char ifname[IFNAMSIZ];
- snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit);
-
- LogInfo("SysEventCallBack: KEV_DL_IF_DETACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name);
-
- mDNSPacketFilterControl(PF_CLEAR_RULES, ifname, 0, portArray, protocolArray);
- }
- }
-#endif // !TARGET_OS_EMBEDDED
-
- }
-
- mDNS_Unlock(m);
-}
-
-mDNSlocal mStatus WatchForSysEvents(mDNS *const m)
-{
- m->p->SysEventNotifier = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
- if (m->p->SysEventNotifier < 0)
- { LogMsg("WatchForSysEvents: socket failed error %d errno %d (%s)", m->p->SysEventNotifier, errno, strerror(errno)); return(mStatus_NoMemoryErr); }
-
- struct kev_request kev_req = { KEV_VENDOR_APPLE, KEV_NETWORK_CLASS, KEV_DL_SUBCLASS };
- int err = ioctl(m->p->SysEventNotifier, SIOCSKEVFILT, &kev_req);
- if (err < 0)
- {
- LogMsg("WatchForSysEvents: SIOCSKEVFILT failed error %d errno %d (%s)", err, errno, strerror(errno));
- close(m->p->SysEventNotifier);
- m->p->SysEventNotifier = -1;
- return(mStatus_UnknownErr);
- }
-
- m->p->SysEventKQueue.KQcallback = SysEventCallBack;
- m->p->SysEventKQueue.KQcontext = m;
- m->p->SysEventKQueue.KQtask = "System Event Notifier";
- KQueueSet(m->p->SysEventNotifier, EV_ADD, EVFILT_READ, &m->p->SysEventKQueue);
-
- return(mStatus_NoError);
-}
-
-#ifndef NO_SECURITYFRAMEWORK
-mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void *context)
-{
- LogInfo("*** Keychain Changed ***");
- mDNS *const m = (mDNS *const)context;
- SecKeychainRef skc;
- OSStatus err = SecKeychainCopyDefault(&skc);
- if (!err)
- {
- if (info->keychain == skc)
- {
- // For delete events, attempt to verify what item was deleted fail because the item is already gone, so we just assume they may be relevant
- mDNSBool relevant = (keychainEvent == kSecDeleteEvent);
- if (!relevant)
- {
- UInt32 tags[3] = { kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr };
- SecKeychainAttributeInfo attrInfo = { 3, tags, NULL }; // Count, array of tags, array of formats
- SecKeychainAttributeList *a = NULL;
- err = SecKeychainItemCopyAttributesAndData(info->item, &attrInfo, NULL, &a, NULL, NULL);
- if (!err)
- {
- relevant = ((a->attr[0].length == 4 && (!strncasecmp(a->attr[0].data, "ddns", 4) || !strncasecmp(a->attr[0].data, "sndd", 4))) ||
- (a->attr[1].length >= mDNSPlatformStrLen(dnsprefix) && (!strncasecmp(a->attr[1].data, dnsprefix, mDNSPlatformStrLen(dnsprefix)))) ||
- (a->attr[1].length >= mDNSPlatformStrLen(btmmprefix) && (!strncasecmp(a->attr[1].data, btmmprefix, mDNSPlatformStrLen(btmmprefix)))));
- SecKeychainItemFreeAttributesAndData(a, NULL);
- }
- }
- if (relevant)
- {
- LogInfo("*** Keychain Changed *** KeychainEvent=%d %s",
- keychainEvent,
- keychainEvent == kSecAddEvent ? "kSecAddEvent" :
- keychainEvent == kSecDeleteEvent ? "kSecDeleteEvent" :
- keychainEvent == kSecUpdateEvent ? "kSecUpdateEvent" : "<Unknown>");
- // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
- KQueueLock(m);
- mDNS_Lock(m);
-
- // To not read the keychain twice: when BTMM is enabled, changes happen to the keychain
- // then the BTMM DynStore dictionary, so delay reading the keychain for a second.
- // NetworkChanged() will reset the keychain timer to fire immediately when the DynStore changes.
- //
- // In the "fixup" case where the BTMM DNS servers aren't accepting the key mDNSResponder has,
- // the DynStore dictionary won't change (because the BTMM zone won't change). In that case,
- // a one second delay is ok, as we'll still converge to correctness, and there's no race
- // condition between the RegistrationDomain and the DomainAuthInfo.
- //
- // Lastly, non-BTMM WAB cases can use the keychain but not the DynStore, so we need to set
- // the timer here, as it will not get set by NetworkChanged().
- SetKeyChainTimer(m, mDNSPlatformOneSecond);
-
- mDNS_Unlock(m);
- KQueueUnlock(m, "KeychainChanged");
- }
- }
- CFRelease(skc);
- }
-
- return 0;
-}
-#endif
-
-mDNSlocal void PowerOn(mDNS *const m)
-{
- mDNSCoreMachineSleep(m, false); // Will set m->SleepState = SleepState_Awake;
- if (m->p->WakeAtUTC)
- {
- long utc = mDNSPlatformUTC();
- mDNSPowerRequest(-1,-1); // Need to explicitly clear any previous power requests -- they're not cleared automatically on wake
- if (m->p->WakeAtUTC - utc > 30)
- {
- LogSPS("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m->p->WakeAtUTC - utc);
- }
- else if (utc - m->p->WakeAtUTC > 30)
- {
- LogSPS("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc - m->p->WakeAtUTC);
- }
- else if (IsAppleTV())
- {
- LogSPS("PowerChanged PowerOn %d seconds late, device is an AppleTV running iOS so not re-sleeping", utc - m->p->WakeAtUTC);
- }
- else
- {
- LogSPS("PowerChanged: Waking for network maintenance operations %d seconds early; re-sleeping in 20 seconds", m->p->WakeAtUTC - utc);
- m->p->RequestReSleep = mDNS_TimeNow(m) + 20 * mDNSPlatformOneSecond;
- }
- }
-}
-
-mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
-{
- mDNS *const m = (mDNS *const)refcon;
- KQueueLock(m);
- (void)service; // Parameter not used
- debugf("PowerChanged %X %lX", messageType, messageArgument);
-
- // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
- m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
-
- switch(messageType)
- {
- case kIOMessageCanSystemPowerOff: LogSPS("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
- case kIOMessageSystemWillPowerOff: LogSPS("PowerChanged kIOMessageSystemWillPowerOff"); // E0000250
- mDNSCoreMachineSleep(m, true);
- if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
- break;
- case kIOMessageSystemWillNotPowerOff: LogSPS("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
- case kIOMessageCanSystemSleep: LogSPS("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
- case kIOMessageSystemWillSleep: LogSPS("PowerChanged kIOMessageSystemWillSleep"); // E0000280
- mDNSCoreMachineSleep(m, true);
- break;
- case kIOMessageSystemWillNotSleep: LogSPS("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
- case kIOMessageSystemHasPoweredOn: LogSPS("PowerChanged kIOMessageSystemHasPoweredOn"); // E0000300
- // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
- if (m->SleepState)
- {
- LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m->SleepState);
- PowerOn(m);
- }
- // Just to be safe, schedule a mDNSMacOSXNetworkChanged(), in case we never received
- // the System Configuration Framework "network changed" event that we expect
- // to receive some time shortly after the kIOMessageSystemWillPowerOn message
- mDNS_Lock(m);
- if (!m->p->NetworkChanged ||
- m->p->NetworkChanged - NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2) < 0)
- m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
- mDNS_Unlock(m);
-
- break;
- case kIOMessageSystemWillRestart: LogSPS("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
- case kIOMessageSystemWillPowerOn: LogSPS("PowerChanged kIOMessageSystemWillPowerOn"); // E0000320
-
- // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
- if (m->SleepState != SleepState_Sleeping)
- {
- LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m->SleepState);
- m->SleepState = SleepState_Sleeping;
- mDNSMacOSXNetworkChanged(m);
- }
- PowerOn(m);
- break;
- default: LogSPS("PowerChanged unknown message %X", messageType); break;
- }
-
- if (messageType == kIOMessageSystemWillSleep) m->p->SleepCookie = (long)messageArgument;
- else IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
-
- KQueueUnlock(m, "PowerChanged Sleep/Wake");
-}
-
-// iPhone OS doesn't currently have SnowLeopard's IO Power Management
-// but it does define kIOPMAcknowledgmentOptionSystemCapabilityRequirements
-#if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && !TARGET_OS_EMBEDDED
-mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection, IOPMConnectionMessageToken token, IOPMSystemPowerStateCapabilities eventDescriptor)
-{
- mDNS *const m = (mDNS *const)refcon;
- KQueueLock(m);
- LogSPS("SnowLeopardPowerChanged %X %X %X%s%s%s%s%s",
- connection, token, eventDescriptor,
- eventDescriptor & kIOPMSystemPowerStateCapabilityCPU ? " CPU" : "",
- eventDescriptor & kIOPMSystemPowerStateCapabilityVideo ? " Video" : "",
- eventDescriptor & kIOPMSystemPowerStateCapabilityAudio ? " Audio" : "",
- eventDescriptor & kIOPMSystemPowerStateCapabilityNetwork ? " Network" : "",
- eventDescriptor & kIOPMSystemPowerStateCapabilityDisk ? " Disk" : "");
-
- // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
- m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
-
- if (eventDescriptor & kIOPMSystemPowerStateCapabilityCPU)
- {
- // We might be in Sleeping or Transferring state. When we go from "wakeup" to "sleep" state, we don't
- // go directly to sleep state, but transfer in to the sleep state during which SleepState is set to
- // SleepState_Transferring. During that time, we might get another wakeup before we transition to Sleeping
- // state. In that case, we need to acknowledge the previous "sleep" before we acknowledge the wakeup.
- if (m->SleepLimit)
- {
- LogSPS("SnowLeopardPowerChanged: Waking up, Acking old Sleep, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
- IOPMConnectionAcknowledgeEvent(connection, m->p->SleepCookie);
- m->SleepLimit = 0;
- }
- LogSPS("SnowLeopardPowerChanged: Waking up, Acking Wakeup, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
- // If the network notifications have already come before we got the wakeup, we ignored them and
- // in case we get no more, we need to trigger one.
- mDNS_Lock(m);
- SetNetworkChanged(m, 2 * mDNSPlatformOneSecond);
- mDNS_Unlock(m);
- // CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down.
- if (m->SleepState != SleepState_Awake) PowerOn(m);
- IOPMConnectionAcknowledgeEvent(connection, token);
- }
- else
- {
- // CPU sleeping. Should not get this repeatedly -- once we're told that the CPU is halting
- // we should hear nothing more until we're told that the CPU has started executing again.
- if (m->SleepState) LogMsg("SnowLeopardPowerChanged: Sleep Error %X m->SleepState %d", eventDescriptor, m->SleepState);
- //sleep(5);
- //mDNSMacOSXNetworkChanged(m);
- mDNSCoreMachineSleep(m, true);
- //if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
- m->p->SleepCookie = token;
- }
-
- KQueueUnlock(m, "SnowLeopardPowerChanged Sleep/Wake");
-}
-#endif
-
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - /etc/hosts support
-#endif
-
-// Implementation Notes
-//
-// As /etc/hosts file can be huge (1000s of entries - when this comment was written, the test file had about
-// 23000 entries with about 4000 duplicates), we can't use a linked list to store these entries. So, we parse
-// them into a hash table. The implementation need to be able to do the following things efficiently
-//
-// 1. Detect duplicates e.g., two entries with "1.2.3.4 foo"
-// 2. Detect whether /etc/hosts has changed and what has changed since the last read from the disk
-// 3. Ability to support multiple addresses per name e.g., "1.2.3.4 foo, 2.3.4.5 foo". To support this, we
-// need to be able set the RRSet of a resource record to the first one in the list and also update when
-// one of them go away. This is needed so that the core thinks that they are all part of the same RRSet and
-// not a duplicate
-// 4. Don't maintain any local state about any records registered with the core to detect changes to /etc/hosts
-//
-// CFDictionary is not a suitable candidate because it does not support duplicates and even if we use a custom
-// "hash" function to solve this, the others are hard to solve. Hence, we share the hash (AuthHash) implementation
-// of the core layer which does all of the above very efficiently
-
-#define ETCHOSTS_BUFSIZE 1024 // Buffer size to parse a single line in /etc/hosts
-
-mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
-{
- (void)m; // unused
- (void)rr;
- (void)result;
- if (result == mStatus_MemFree)
- {
- LogInfo("FreeEtcHosts: %s", ARDisplayString(m, rr));
- freeL("etchosts", rr);
- }
-}
-
-// Returns true on success and false on failure
-mDNSlocal mDNSBool mDNSMacOSXCreateEtcHostsEntry(mDNS *const m, const domainname *domain, const struct sockaddr *sa, const domainname *cname, char *ifname, AuthHash *auth)
-{
- AuthRecord *rr;
- mDNSu32 slot;
- mDNSu32 namehash;
- AuthGroup *ag;
- mDNSInterfaceID InterfaceID = mDNSInterface_LocalOnly;
- mDNSu16 rrtype;
-
- if (!domain)
- {
- LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! name NULL");
- return mDNSfalse;
- }
- if (!sa && !cname)
- {
- LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa and cname both NULL");
- return mDNSfalse;
- }
-
- if (sa && sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
- {
- LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa with bad family %d", sa->sa_family);
- return mDNSfalse;
- }
-
-
- if (ifname)
- {
- mDNSu32 ifindex = if_nametoindex(ifname);
- if (!ifindex)
- {
- LogMsg("mDNSMacOSXCreateEtcHostsEntry: hosts entry %##s with invalid ifname %s", domain->c, ifname);
- return mDNSfalse;
- }
- InterfaceID = (mDNSInterfaceID)(uintptr_t)ifindex;
- }
-
- if (sa)
- rrtype = (sa->sa_family == AF_INET ? kDNSType_A : kDNSType_AAAA);
- else
- rrtype = kDNSType_CNAME;
-
- // Check for duplicates. See whether we parsed an entry before like this ?
- slot = AuthHashSlot(domain);
- namehash = DomainNameHashValue(domain);
- ag = AuthGroupForName(auth, slot, namehash, domain);
- if (ag)
- {
- rr = ag->members;
- while (rr)
- {
- if (rr->resrec.rrtype == rrtype)
- {
- if (rrtype == kDNSType_A)
- {
- mDNSv4Addr ip;
- ip.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
- if (mDNSSameIPv4Address(rr->resrec.rdata->u.ipv4, ip))
- {
- LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv4 address for name %##s", domain->c);
- return mDNSfalse;
- }
- }
- else if (rrtype == kDNSType_AAAA)
- {
- mDNSv6Addr ip6;
- ip6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0];
- ip6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
- ip6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
- ip6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
- if (mDNSSameIPv6Address(rr->resrec.rdata->u.ipv6, ip6))
- {
- LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv6 address for name %##s", domain->c);
- return mDNSfalse;
- }
- }
- else if (rrtype == kDNSType_CNAME)
- {
- if (SameDomainName(&rr->resrec.rdata->u.name, cname))
- {
- LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same cname %##s for name %##s", cname->c, domain->c);
- return mDNSfalse;
- }
- }
- }
- rr = rr->next;
- }
- }
- rr= mallocL("etchosts", sizeof(*rr));
- if (rr == NULL) return mDNSfalse;
- mDNSPlatformMemZero(rr, sizeof(*rr));
- mDNS_SetupResourceRecord(rr, NULL, InterfaceID, rrtype, 1, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, FreeEtcHosts, NULL);
- AssignDomainName(&rr->namestorage, domain);
-
- if (sa)
- {
- rr->resrec.rdlength = sa->sa_family == AF_INET ? sizeof(mDNSv4Addr) : sizeof(mDNSv6Addr);
- if (sa->sa_family == AF_INET)
- rr->resrec.rdata->u.ipv4.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
- else
- {
- rr->resrec.rdata->u.ipv6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0];
- rr->resrec.rdata->u.ipv6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
- rr->resrec.rdata->u.ipv6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
- rr->resrec.rdata->u.ipv6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
- }
- }
- else
- {
- rr->resrec.rdlength = DomainNameLength(cname);
- rr->resrec.rdata->u.name.c[0] = 0;
- AssignDomainName(&rr->resrec.rdata->u.name, cname);
- }
- rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
- SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
- LogInfo("mDNSMacOSXCreateEtcHostsEntry: Adding resource record %s", ARDisplayString(m, rr));
- InsertAuthRecord(m, auth, rr);
- return mDNStrue;
-}
-
-mDNSlocal int EtcHostsParseOneName(int start, int length, char *buffer, char **name)
-{
- int i;
-
- *name = NULL;
- for (i = start; i < length; i++)
- {
- if (buffer[i] == '#')
- return -1;
- if (buffer[i] != ' ' && buffer[i] != ',' && buffer[i] != '\t')
- {
- *name = &buffer[i];
-
- // Found the start of a name, find the end and null terminate
- for (i++; i < length; i++)
- {
- if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
- {
- buffer[i] = 0;
- break;
- }
- }
- return i;
- }
- }
- return -1;
-}
-
-mDNSlocal void mDNSMacOSXParseEtcHostsLine(mDNS *const m, char *buffer, ssize_t length, AuthHash *auth)
-{
- int i;
- int ifStart = 0;
- char *ifname = NULL;
- domainname name1d;
- domainname name2d;
- char *name1;
- char *name2;
- int aliasIndex;
-
- //Ignore leading whitespaces and tabs
- while (*buffer == ' ' || *buffer == '\t')
- {
- buffer++;
- length--;
- }
-
- // Find the end of the address string
- for (i = 0; i < length; i++)
- {
- if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t' || buffer[i] == '%')
- {
- if (buffer[i] == '%')
- ifStart = i + 1;
- buffer[i] = 0;
- break;
- }
- }
-
- // Convert the address string to an address
- struct addrinfo hints;
- bzero(&hints, sizeof(hints));
- hints.ai_flags = AI_NUMERICHOST;
- struct addrinfo *gairesults = NULL;
- if (getaddrinfo(buffer, NULL, &hints, &gairesults) != 0)
- {
- LogInfo("mDNSMacOSXParseEtcHostsLine: getaddrinfo returning null");
- return;
- }
-
- if (ifStart)
- {
- // Parse the interface
- ifname = &buffer[ifStart];
- for (i = ifStart + 1; i < length; i++)
- {
- if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
- {
- buffer[i] = 0;
- break;
- }
- }
- }
-
- i = EtcHostsParseOneName(i + 1, length, buffer, &name1);
- if (i == length)
- {
- // Common case (no aliases) : The entry is of the form "1.2.3.4 somehost" with no trailing white spaces/tabs etc.
- if (!MakeDomainNameFromDNSNameString(&name1d, name1))
- {
- LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
- freeaddrinfo(gairesults);
- return;
- }
- mDNSMacOSXCreateEtcHostsEntry(m, &name1d, gairesults->ai_addr, mDNSNULL, ifname, auth);
- }
- else if (i != -1)
- {
- domainname first;
- // We might have some extra white spaces at the end for the common case of "1.2.3.4 somehost".
- // When we parse again below, EtchHostsParseOneName would return -1 and we will end up
- // doing the right thing.
- if (!MakeDomainNameFromDNSNameString(&first, name1))
- {
- LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
- freeaddrinfo(gairesults);
- return;
- }
- // If the /etc/hosts has an entry like this
- //
- // 1.2.3.4 sun star bright
- //
- // star and bright are aliases (gethostbyname h_alias should point to these) and sun is the canonical
- // name (getaddrinfo ai_cannonname and gethostbyname h_name points to "sun")
- //
- // To achieve this, we need to add the entry like this:
- //
- // star CNAME bright
- // bright CNAME sun
- // sun A 1.2.3.4
- //
- // We store the first name we parsed in "first". Then we parse additional names adding CNAME records
- // till we reach the end. When we reach the end, we wrap around and add one final CNAME with the last
- // entry and the first entry. Finally, we add the Address (A/AAAA) record.
- aliasIndex = 0;
- while (i <= length)
- {
- // Parse a name. If there are no names, we need to know whether we
- // parsed CNAMEs before or not. If we parsed CNAMEs before, then we
- // add a CNAME with the last name and the first name. Otherwise, this
- // is same as the common case above where the line has just one name
- // but with trailing white spaces.
- i = EtcHostsParseOneName(i + 1, length, buffer, &name2);
- if (name2)
- {
- if (!MakeDomainNameFromDNSNameString(&name2d, name2))
- {
- LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name2);
- freeaddrinfo(gairesults);
- return;
- }
- aliasIndex++;
- }
- else if (!aliasIndex)
- {
- // We have never parsed any aliases. This case happens if there
- // is just one name and some extra white spaces at the end.
- LogInfo("mDNSMacOSXParseEtcHostsLine: White space at the end of %##s", first.c);
- break;
- }
- else
- {
- // We have parsed at least one alias before and we reached the end of the line.
- // Setup a CNAME for the last name with "first" name as its RDATA
- name2d.c[0] = 0;
- AssignDomainName(&name2d, &first);
- }
-
- // Don't add a CNAME for the first alias we parse (see the example above).
- // As we parse more, we might discover that there are no more aliases, in
- // which case we would have set "name2d" to "first" above. We need to add
- // the CNAME in that case.
-
- if (aliasIndex > 1 || SameDomainName(&name2d, &first))
- {
- // Ignore if it points to itself
- if (!SameDomainName(&name1d, &name2d))
- {
- if (!mDNSMacOSXCreateEtcHostsEntry(m, &name1d, mDNSNULL, &name2d, ifname, auth))
- {
- freeaddrinfo(gairesults);
- return;
- }
- }
- else
- LogMsg("mDNSMacOSXParseEtcHostsLine: Ignoring entry with same names name1 %##s, name2 %##s", name1d.c, name2d.c);
- }
-
- // If we have already wrapped around, we just need to add the A/AAAA record alone
- // which is done below
- if (SameDomainName(&name2d, &first)) break;
-
- // Remember the current name so that we can set the CNAME record if we parse one
- // more name
- name1d.c[0] = 0;
- AssignDomainName(&name1d, &name2d);
- }
- // Added all the CNAMEs if any, add the "A/AAAA" record
- mDNSMacOSXCreateEtcHostsEntry(m, &first, gairesults->ai_addr, mDNSNULL, ifname, auth);
- }
- freeaddrinfo(gairesults);
-}
-
-mDNSlocal void mDNSMacOSXParseEtcHosts(mDNS *const m, int fd, AuthHash *auth)
-{
- mDNSBool good;
- char buf[ETCHOSTS_BUFSIZE];
- ssize_t len;
- FILE *fp;
-
- if (fd == -1) { LogInfo("mDNSMacOSXParseEtcHosts: fd is -1"); return; }
-
- fp = fopen("/etc/hosts", "r");
- if (!fp) { LogInfo("mDNSMacOSXParseEtcHosts: fp is NULL"); return; }
-
- while (1)
- {
- good = (fgets(buf, ETCHOSTS_BUFSIZE, fp) != NULL);
- if (!good) break;
-
- // skip comment and empty lines
- if (buf[0] == '#' || buf[0] == '\r' || buf[0] == '\n')
- continue;
-
- len = strlen(buf);
- if (!len) break; // sanity check
- //Check for end of line code(mostly only \n but pre-OS X Macs could have only \r)
- if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
- {
- buf[len - 1] = '\0';
- len = len - 1;
- }
- // fgets always null terminates and hence even if we have no
- // newline at the end, it is null terminated. The callee
- // (mDNSMacOSXParseEtcHostsLine) expects the length to be such that
- // buf[length] is zero and hence we decrement len to reflect that.
- if (len)
- {
- //Additional check when end of line code is 2 chars ie\r\n(DOS, other old OSes)
- //here we need to check for just \r but taking extra caution.
- if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
- {
- buf[len - 1] = '\0';
- len = len - 1;
- }
- }
- if (!len) //Sanity Check: len should never be zero
- {
- LogMsg("mDNSMacOSXParseEtcHosts: Length is zero!");
- continue;
- }
- mDNSMacOSXParseEtcHostsLine(m, buf, len, auth);
- }
- fclose(fp);
-}
-
-mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m);
-
-mDNSlocal int mDNSMacOSXGetEtcHostsFD(mDNS *const m)
-{
-#ifdef __DISPATCH_GROUP__
- // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
- static dispatch_queue_t etcq = 0;
- static dispatch_source_t etcsrc = 0;
- static dispatch_source_t hostssrc = 0;
-
- // First time through? just schedule ourselves on the main queue and we'll do the work later
- if (!etcq)
- {
- etcq = dispatch_get_main_queue();
- if (etcq)
- {
- // Do this work on the queue, not here - solves potential synchronization issues
- dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
- }
- return -1;
- }
-
- if (hostssrc) return dispatch_source_get_handle(hostssrc);
-#endif
-
- int fd = open("/etc/hosts", O_RDONLY);
-
-#ifdef __DISPATCH_GROUP__
- // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
- if (fd == -1)
- {
- // If the open failed and we're already watching /etc, we're done
- if (etcsrc) { LogInfo("mDNSMacOSXGetEtcHostsFD: Returning etcfd because no etchosts"); return fd; }
-
- // we aren't watching /etc, we should be
- fd = open("/etc", O_RDONLY);
- if (fd == -1) { LogInfo("mDNSMacOSXGetEtcHostsFD: etc does not exist"); return -1; }
- etcsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME, etcq);
- if (etcsrc == NULL)
- {
- close(fd);
- return -1;
- }
- dispatch_source_set_event_handler(etcsrc,
- ^{
- u_int32_t flags = dispatch_source_get_data(etcsrc);
- LogMsg("mDNSMacOSXGetEtcHostsFD: /etc changed 0x%x", flags);
- if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0)
- {
- dispatch_source_cancel(etcsrc);
- dispatch_release(etcsrc);
- etcsrc = NULL;
- dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
- return;
- }
- if ((flags & DISPATCH_VNODE_WRITE) != 0 && hostssrc == NULL)
- {
- mDNSMacOSXUpdateEtcHosts(m);
- }
- });
- dispatch_source_set_cancel_handler(etcsrc, ^{close(fd);});
- dispatch_resume(etcsrc);
-
- // Try and open /etc/hosts once more now that we're watching /etc, in case we missed the creation
- fd = open("/etc/hosts", O_RDONLY | O_EVTONLY);
- if (fd == -1) { LogMsg("mDNSMacOSXGetEtcHostsFD etc hosts does not exist, watching etc"); return -1; }
- }
-
- // create a dispatch source to watch for changes to hosts file
- hostssrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd,
- (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME |
- DISPATCH_VNODE_ATTRIB | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_LINK | DISPATCH_VNODE_REVOKE), etcq);
- if (hostssrc == NULL)
- {
- close(fd);
- return -1;
- }
- dispatch_source_set_event_handler(hostssrc,
- ^{
- u_int32_t flags = dispatch_source_get_data(hostssrc);
- LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts changed 0x%x", flags);
- if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0)
- {
- dispatch_source_cancel(hostssrc);
- dispatch_release(hostssrc);
- hostssrc = NULL;
- // Bug in LibDispatch: wait a second before scheduling the block. If we schedule
- // the block immediately, we try to open the file and the file may not exist and may
- // fail to get a notification in the future. When the file does not exist and
- // we start to monitor the directory, on "dispatch_resume" of that source, there
- // is no guarantee that the file creation will be notified always because when
- // the dispatch_resume returns, the kevent manager may not have registered the
- // kevent yet but the file may have been created
- usleep(1000000);
- dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
- return;
- }
- if ((flags & DISPATCH_VNODE_WRITE) != 0)
- {
- mDNSMacOSXUpdateEtcHosts(m);
- }
- });
- dispatch_source_set_cancel_handler(hostssrc, ^{LogInfo("mDNSMacOSXGetEtcHostsFD: Closing etchosts fd %d", fd); close(fd);});
- dispatch_resume(hostssrc);
-
- // Cleanup /etc source, no need to watch it if we already have /etc/hosts
- if (etcsrc)
- {
- dispatch_source_cancel(etcsrc);
- dispatch_release(etcsrc);
- etcsrc = NULL;
- }
-
- LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts being monitored, and not etc");
- return hostssrc ? (int)dispatch_source_get_handle(hostssrc) : -1;
-#else
- (void)m;
- return fd;
-#endif
-}
-
-// When /etc/hosts is modified, flush all the cache records as there may be local
-// authoritative answers now
-mDNSlocal void FlushAllCacheRecords(mDNS *const m)
-{
- CacheRecord *cr;
- mDNSu32 slot;
- CacheGroup *cg;
-
- FORALL_CACHERECORDS(slot, cg, cr)
- {
- // Skip multicast.
- if (cr->resrec.InterfaceID) continue;
-
- // If a resource record can answer A or AAAA, they need to be flushed so that we will
- // never used to deliver an ADD or RMV
- if (RRTypeAnswersQuestionType(&cr->resrec, kDNSType_A) ||
- RRTypeAnswersQuestionType(&cr->resrec, kDNSType_AAAA))
- {
- LogInfo("FlushAllCacheRecords: Purging Resourcerecord %s", CRDisplayString(m, cr));
- mDNS_PurgeCacheResourceRecord(m, cr);
- }
- }
-}
-
-// Add new entries to the core. If justCheck is set, this function does not add, just returns true
-mDNSlocal mDNSBool EtcHostsAddNewEntries(mDNS *const m, AuthHash *newhosts, mDNSBool justCheck)
-{
- AuthGroup *ag;
- mDNSu32 slot;
- AuthRecord *rr, *primary, *rrnext;
- for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
- for (ag = newhosts->rrauth_hash[slot]; ag; ag = ag->next)
- {
- primary = NULL;
- for (rr = ag->members; rr; rr = rrnext)
- {
- rrnext = rr->next;
- AuthGroup *ag1;
- AuthRecord *rr1;
- mDNSBool found = mDNSfalse;
- ag1 = AuthGroupForRecord(&m->rrauth, slot, &rr->resrec);
- if (ag1 && ag1->members)
- {
- if (!primary) primary = ag1->members;
- rr1 = ag1->members;
- while (rr1)
- {
- // We are not using InterfaceID in checking for duplicates. This means,
- // if there are two addresses for a given name e.g., fe80::1%en0 and
- // fe80::1%en1, we only add the first one. It is not clear whether
- // this is a common case. To fix this, we also need to modify
- // mDNS_Register_internal in how it handles duplicates. If it becomes a
- // common case, we will fix it then.
- if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
- {
- LogInfo("EtcHostsAddNewEntries: Skipping, not adding %s", ARDisplayString(m, rr1));
- found = mDNStrue;
- break;
- }
- rr1 = rr1->next;
- }
- }
- if (!found)
- {
- if (justCheck)
- {
- LogInfo("EtcHostsAddNewEntries: Entry %s not registered with core yet", ARDisplayString(m, rr));
- return mDNStrue;
- }
- RemoveAuthRecord(m, newhosts, rr);
- // if there is no primary, point to self
- rr->RRSet = (primary ? primary : rr);
- rr->next = NULL;
- LogInfo("EtcHostsAddNewEntries: Adding %s", ARDisplayString(m, rr));
- if (mDNS_Register_internal(m, rr) != mStatus_NoError)
- LogMsg("EtcHostsAddNewEntries: mDNS_Register failed for %s", ARDisplayString(m, rr));
- }
- }
- }
- return mDNSfalse;
-}
-
-// Delete entries from the core that are no longer needed. If justCheck is set, this function
-// does not delete, just returns true
-mDNSlocal mDNSBool EtcHostsDeleteOldEntries(mDNS *const m, AuthHash *newhosts, mDNSBool justCheck)
-{
- AuthGroup *ag;
- mDNSu32 slot;
- AuthRecord *rr, *primary, *rrnext;
- for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
- for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next)
- for (rr = ag->members; rr; rr = rrnext)
- {
- mDNSBool found = mDNSfalse;
- AuthGroup *ag1;
- AuthRecord *rr1;
- rrnext = rr->next;
- if (rr->RecordCallback != FreeEtcHosts) continue;
- ag1 = AuthGroupForRecord(newhosts, slot, &rr->resrec);
- if (ag1)
- {
- primary = rr1 = ag1->members;
- while (rr1)
- {
- if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
- {
- LogInfo("EtcHostsDeleteOldEntries: Old record %s found in new, skipping", ARDisplayString(m, rr));
- found = mDNStrue;
- break;
- }
- rr1 = rr1->next;
- }
- }
- // there is no corresponding record in newhosts for the same name. This means
- // we should delete this from the core.
- if (!found)
- {
- if (justCheck)
- {
- LogInfo("EtcHostsDeleteOldEntries: Record %s not found in new, deleting", ARDisplayString(m, rr));
- return mDNStrue;
- }
- // if primary is going away, make sure that the rest of the records
- // point to the new primary
- if (rr == ag->members)
- {
- AuthRecord *new_primary = rr->next;
- AuthRecord *r = new_primary;
- while (r)
- {
- if (r->RRSet == rr)
- {
- LogInfo("EtcHostsDeleteOldEntries: Updating Resource Record %s to primary", ARDisplayString(m, r));
- r->RRSet = new_primary;
- }
- else LogMsg("EtcHostsDeleteOldEntries: ERROR!! Resource Record %s not pointing to primary %##s", ARDisplayString(m, r), r->resrec.name);
- r = r->next;
- }
- }
- LogInfo("EtcHostsDeleteOldEntries: Deleting %s", ARDisplayString(m, rr));
- mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
- }
- }
- return mDNSfalse;
-}
-
-mDNSlocal void UpdateEtcHosts(mDNS *const m, void *context)
-{
- AuthHash *newhosts = (AuthHash *)context;
-
- mDNS_CheckLock(m);
-
- //Delete old entries from the core if they are not present in the newhosts
- EtcHostsDeleteOldEntries(m, newhosts, mDNSfalse);
- // Add the new entries to the core if not already present in the core
- EtcHostsAddNewEntries(m, newhosts, mDNSfalse);
-}
-
-mDNSlocal void FreeNewHosts(AuthHash *newhosts)
-{
- mDNSu32 slot;
- AuthGroup *ag, *agnext;
- AuthRecord *rr, *rrnext;
-
- for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
- for (ag = newhosts->rrauth_hash[slot]; ag; ag = agnext)
- {
- agnext = ag->next;
- for (rr = ag->members; rr; rr = rrnext)
- {
- rrnext = rr->next;
- freeL("etchosts", rr);
- }
- freeL("AuthGroups", ag);
- }
-}
-
-mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m)
-{
- AuthHash newhosts;
-
- // As we will be modifying the core, we can only have one thread running at
- // any point in time.
- KQueueLock(m);
-
- mDNSPlatformMemZero(&newhosts, sizeof(AuthHash));
-
- // Get the file desecriptor (will trigger us to start watching for changes)
- int fd = mDNSMacOSXGetEtcHostsFD(m);
- if (fd != -1)
- {
- LogInfo("mDNSMacOSXUpdateEtcHosts: Parsing /etc/hosts fd %d", fd);
- mDNSMacOSXParseEtcHosts(m, fd, &newhosts);
- }
- else LogInfo("mDNSMacOSXUpdateEtcHosts: /etc/hosts is not present");
-
- // Optimization: Detect whether /etc/hosts changed or not.
- //
- // 1. Check to see if there are any new entries. We do this by seeing whether any entries in
- // newhosts is already registered with core. If we find at least one entry that is not
- // registered with core, then it means we have work to do.
- //
- // 2. Next, we check to see if any of the entries that are registered with core is not present
- // in newhosts. If we find at least one entry that is not present, it means we have work to
- // do.
- //
- // Note: We may not have to hold the lock right here as KQueueLock is held which prevents any
- // other thread from running. But mDNS_Lock is needed here as we will be traversing the core
- // data structure in EtcHostsDeleteOldEntries/NewEntries which might expect the lock to be held
- // in the future and this code does not have to change.
- mDNS_Lock(m);
- // Add the new entries to the core if not already present in the core
- if (!EtcHostsAddNewEntries(m, &newhosts, mDNStrue))
- {
- // No new entries to add, check to see if we need to delete any old entries from the
- // core if they are not present in the newhosts
- if (!EtcHostsDeleteOldEntries(m, &newhosts, mDNStrue))
- {
- LogInfo("mDNSMacOSXUpdateEtcHosts: No work");
- mDNS_Unlock(m);
- KQueueUnlock(m, "/etc/hosts changed");
- FreeNewHosts(&newhosts);
- return;
- }
- }
-
- // This will flush the cache, stop and start the query so that the queries
- // can look at the /etc/hosts again
- //
- // Notes:
- //
- // We can't delete and free the records here. We wait for the mDNSCoreRestartAddressQueries to
- // deliver RMV events. It has to be done in a deferred way because we can't deliver RMV
- // events for local records *before* the RMV events for cache records. mDNSCoreRestartAddressQueries
- // delivers these events in the right order and then calls us back to delete them.
- //
- // Similarly, we do a deferred Registration of the record because mDNSCoreRestartAddressQueries
- // is a common function that looks at all local auth records and delivers a RMV including
- // the records that we might add here. If we deliver a ADD here, it will get a RMV and then when
- // the query is restarted, it will get another ADD. To avoid this (ADD-RMV-ADD), we defer registering
- // the record until the RMVs are delivered in mDNSCoreRestartAddressQueries after which UpdateEtcHosts
- // is called back where we do the Registration of the record. This results in RMV followed by ADD which
- // looks normal.
- mDNSCoreRestartAddressQueries(m, mDNSfalse, FlushAllCacheRecords, UpdateEtcHosts, &newhosts);
- mDNS_Unlock(m);
-
- KQueueUnlock(m, "/etc/hosts changed");
- FreeNewHosts(&newhosts);
-}
-
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - Initialization & Teardown
-#endif
-
-CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
-CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
-CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
-CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
-
-// Major version 13 is 10.9.x
-mDNSexport void mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
-{
- int major = 0, minor = 0;
- char letter = 0, prodname[256]="<Unknown>", prodvers[256]="<Unknown>", buildver[256]="<Unknown>";
- CFDictionaryRef vers = _CFCopySystemVersionDictionary();
- if (vers)
- {
- CFStringRef cfprodname = CFDictionaryGetValue(vers, _kCFSystemVersionProductNameKey);
- CFStringRef cfprodvers = CFDictionaryGetValue(vers, _kCFSystemVersionProductVersionKey);
- CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
- if (cfprodname)
- CFStringGetCString(cfprodname, prodname, sizeof(prodname), kCFStringEncodingUTF8);
- if (cfprodvers)
- CFStringGetCString(cfprodvers, prodvers, sizeof(prodvers), kCFStringEncodingUTF8);
- if (cfbuildver && CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8))
- sscanf(buildver, "%d%c%d", &major, &letter, &minor);
- CFRelease(vers);
- }
- if (!major)
- {
- major = 13;
- LogMsg("Note: No Major Build Version number found; assuming 13");
- }
- if (HINFO_SWstring)
- mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, STRINGIFY(mDNSResponderVersion));
- //LogMsg("%s %s (%s), %d %c %d", prodname, prodvers, buildver, major, letter, minor);
-
- // If product name is "Mac OS X" (or similar) we set OSXVers, else we set iOSVers;
- if ((prodname[0] & 0xDF) == 'M')
- OSXVers = major;
- else
- iOSVers = major;
-}
-
-// Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
-// If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
-// we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
-mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
-{
- int err = -1;
- int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (s < 3)
- LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s, errno, strerror(errno));
- else
- {
- struct sockaddr_in s5353;
- s5353.sin_family = AF_INET;
- s5353.sin_port = MulticastDNSPort.NotAnInteger;
- s5353.sin_addr.s_addr = 0;
- err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
- close(s);
- }
-
- if (err) LogMsg("No unicast UDP responses");
- else debugf("Unicast UDP responses okay");
- return(err == 0);
-}
-
-mDNSlocal void CreatePTRRecord(mDNS *const m, const domainname *domain)
-{
- AuthRecord *rr;
- const domainname *pname = (domainname *)"\x9" "localhost";
-
- rr= mallocL("localhosts", sizeof(*rr));
- if (rr == NULL) return;
- mDNSPlatformMemZero(rr, sizeof(*rr));
-
- mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, mDNSNULL, mDNSNULL);
- AssignDomainName(&rr->namestorage, domain);
-
- rr->resrec.rdlength = DomainNameLength(pname);
- rr->resrec.rdata->u.name.c[0] = 0;
- AssignDomainName(&rr->resrec.rdata->u.name, pname);
-
- rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
- SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
- mDNS_Register(m, rr);
-}
-
-// Setup PTR records for 127.0.0.1 and ::1. This helps answering them locally rather than relying
-// on the external DNS server to answer this. Sometimes, the DNS servers don't respond in a timely
-// fashion and applications depending on this e.g., telnetd, times out after 30 seconds creating
-// a bad user experience. For now, we specifically create only localhosts to handle radar://9354225
-//
-// Note: We could have set this up while parsing the entries in /etc/hosts. But this is kept separate
-// intentionally to avoid adding to the complexity of code handling /etc/hosts.
-mDNSlocal void SetupLocalHostRecords(mDNS *const m)
-{
- char buffer[MAX_REVERSE_MAPPING_NAME];
- domainname name;
- int i;
- struct in6_addr addr;
- mDNSu8 *ptr = addr.__u6_addr.__u6_addr8;
-
- if (inet_pton(AF_INET, "127.0.0.1", &addr) == 1)
- {
- mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.",
- ptr[3], ptr[2], ptr[1], ptr[0]);
- MakeDomainNameFromDNSNameString(&name, buffer);
- CreatePTRRecord(m, &name);
- }
- else LogMsg("SetupLocalHostRecords: ERROR!! inet_pton AF_INET failed");
-
- if (inet_pton(AF_INET6, "::1", &addr) == 1)
- {
- for (i = 0; i < 16; i++)
- {
- static const char hexValues[] = "0123456789ABCDEF";
- buffer[i * 4 ] = hexValues[ptr[15 - i] & 0x0F];
- buffer[i * 4 + 1] = '.';
- buffer[i * 4 + 2] = hexValues[ptr[15 - i] >> 4];
- buffer[i * 4 + 3] = '.';
- }
- mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
- MakeDomainNameFromDNSNameString(&name, buffer);
- CreatePTRRecord(m, &name);
- }
- else LogMsg("SetupLocalHostRecords: ERROR!! inet_pton AF_INET6 failed");
-}
-
-// Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
-// 1) query for b._dns-sd._udp.local on LocalOnly interface
-// (.local manually generated via explicit callback)
-// 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
-// 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
-// 4) result above should generate a callback from question in (1). result added to global list
-// 5) global list delivered to client via GetSearchDomainList()
-// 6) client calls to enumerate domains now go over LocalOnly interface
-// (!!!KRS may add outgoing interface in addition)
-
-mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
-{
- mStatus err;
- m->p->CFRunLoop = CFRunLoopGetCurrent();
-
- char HINFO_SWstring[256] = "";
- mDNSMacOSXSystemBuildNumber(HINFO_SWstring);
-
- err = mDNSHelperInit();
- if (err)
- return err;
-
- DynamicStoreQueue = dispatch_queue_create("com.apple.mDNSResponder.DynamicStoreQueue", NULL);
- if (DynamicStoreQueue == NULL)
- {
- LogMsg("dispatch_queue_create: DynamicStoreQueue NULL!");
- return mStatus_NoMemoryErr;
- }
-
- // Store mDNSResponder Platform
- if (OSXVers)
- {
- m->mDNS_plat = platform_OSX;
- }
- else if (iOSVers)
- {
- if (IsAppleTV())
- m->mDNS_plat = platform_Atv;
- else
- m->mDNS_plat = platform_iOS;
- }
- else
- {
- m->mDNS_plat = platform_NonApple;
- }
-
- // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
- // If we can't read the user's preferences, then we sleep a bit and try again, for up to five seconds before we give up.
- int i;
- for (i=0; i<100; i++)
- {
- domainlabel testlabel;
- testlabel.c[0] = 0;
- GetUserSpecifiedLocalHostName(&testlabel);
- if (testlabel.c[0]) break;
- usleep(50000);
- }
-
- m->hostlabel.c[0] = 0;
-
- int get_model[2] = { CTL_HW, HW_MODEL };
- size_t len_model = sizeof(HINFO_HWstring_buffer);
-
- // Normal Apple model names are of the form "iPhone2,1", and
- // internal code names are strings containing no commas, e.g. "N88AP".
- // We used to ignore internal code names, but Apple now uses these internal code names
- // even in released shipping products, so we no longer ignore strings containing no commas.
-// if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
- if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0)
- HINFO_HWstring = HINFO_HWstring_buffer;
-
- // For names of the form "iPhone2,1" we use "iPhone" as the prefix for automatic name generation.
- // For names of the form "N88AP" containg no comma, we use the entire string.
- HINFO_HWstring_prefixlen = strchr(HINFO_HWstring_buffer, ',') ? strcspn(HINFO_HWstring, "0123456789") : strlen(HINFO_HWstring);
-
- if (mDNSPlatformInit_CanReceiveUnicast())
- m->CanReceiveUnicastOn5353 = mDNStrue;
-
- mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
- mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
- if (hlen + slen < 254)
- {
- m->HIHardware.c[0] = hlen;
- m->HISoftware.c[0] = slen;
- mDNSPlatformMemCopy(&m->HIHardware.c[1], HINFO_HWstring, hlen);
- mDNSPlatformMemCopy(&m->HISoftware.c[1], HINFO_SWstring, slen);
- }
-
- m->p->permanentsockets.port = MulticastDNSPort;
- m->p->permanentsockets.m = m;
- m->p->permanentsockets.sktv4 = -1;
- m->p->permanentsockets.kqsv4.KQcallback = myKQSocketCallBack;
- m->p->permanentsockets.kqsv4.KQcontext = &m->p->permanentsockets;
- m->p->permanentsockets.kqsv4.KQtask = "UDP packet reception";
- m->p->permanentsockets.sktv6 = -1;
- m->p->permanentsockets.kqsv6.KQcallback = myKQSocketCallBack;
- m->p->permanentsockets.kqsv6.KQcontext = &m->p->permanentsockets;
- m->p->permanentsockets.kqsv6.KQtask = "UDP packet reception";
-
- err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET, mDNSNULL);
- err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET6, mDNSNULL);
-
- struct sockaddr_in s4;
- socklen_t n4 = sizeof(s4);
- if (getsockname(m->p->permanentsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0)
- LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno));
- else
- m->UnicastPort4.NotAnInteger = s4.sin_port;
-
- if (m->p->permanentsockets.sktv6 >= 0)
- {
- struct sockaddr_in6 s6;
- socklen_t n6 = sizeof(s6);
- if (getsockname(m->p->permanentsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno));
- else m->UnicastPort6.NotAnInteger = s6.sin6_port;
- }
-
- m->p->InterfaceList = mDNSNULL;
- m->p->userhostlabel.c[0] = 0;
- m->p->usernicelabel.c[0] = 0;
- m->p->prevoldnicelabel.c[0] = 0;
- m->p->prevnewnicelabel.c[0] = 0;
- m->p->prevoldhostlabel.c[0] = 0;
- m->p->prevnewhostlabel.c[0] = 0;
- m->p->NotifyUser = 0;
- m->p->KeyChainTimer = 0;
- m->p->WakeAtUTC = 0;
- m->p->RequestReSleep = 0;
- // Assume that everything is good to begin with. If something is not working,
- // we will detect that when we start sending questions.
- m->p->v4answers = 1;
- m->p->v6answers = 1;
- m->p->DNSTrigger = 0;
- m->p->LastConfigGeneration = 0;
-
-#if APPLE_OSX_mDNSResponder
- uuid_generate(m->asl_uuid);
-#endif
-
- m->AutoTunnelRelayAddr = zerov6Addr;
-
- NetworkChangedKey_IPv4 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
- NetworkChangedKey_IPv6 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
- NetworkChangedKey_Hostnames = SCDynamicStoreKeyCreateHostNames(NULL);
- NetworkChangedKey_Computername = SCDynamicStoreKeyCreateComputerName(NULL);
- NetworkChangedKey_DNS = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
- NetworkChangedKey_StateInterfacePrefix = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, CFSTR(""), NULL);
- if (!NetworkChangedKey_IPv4 || !NetworkChangedKey_IPv6 || !NetworkChangedKey_Hostnames || !NetworkChangedKey_Computername || !NetworkChangedKey_DNS || !NetworkChangedKey_StateInterfacePrefix)
- { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr); }
-
- err = WatchForNetworkChanges(m);
- if (err) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err); return(err); }
-
-#if 0 // <rdar://problem/6751656>
- err = WatchForPMChanges(m);
- if (err) { LogMsg("mDNSPlatformInit_setup: WatchForPMChanges failed %d", err); return(err); }
-#endif
-
- err = WatchForSysEvents(m);
- if (err) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err); return(err); }
-
- mDNSs32 utc = mDNSPlatformUTC();
- m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
- UpdateInterfaceList(m, utc);
- SetupActiveInterfaces(m, utc);
-
- // Explicitly ensure that our Keychain operations utilize the system domain.
-#ifndef NO_SECURITYFRAMEWORK
- SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
-#endif
-
- mDNS_Lock(m);
- SetDomainSecrets(m);
- SetLocalDomains();
- mDNS_Unlock(m);
-
-#ifndef NO_SECURITYFRAMEWORK
- err = SecKeychainAddCallback(KeychainChanged, kSecAddEventMask|kSecDeleteEventMask|kSecUpdateEventMask, m);
- if (err) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err); return(err); }
-#endif
-
-#if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_EMBEDDED
- LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
-#else
- IOPMConnection c;
- IOReturn iopmerr = IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU, &c);
- if (iopmerr) LogMsg("IOPMConnectionCreate failed %d", iopmerr);
- else
- {
- iopmerr = IOPMConnectionSetNotification(c, m, SnowLeopardPowerChanged);
- if (iopmerr) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr);
- else
- {
-#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
- IOPMConnectionSetDispatchQueue(c, dispatch_get_main_queue());
- LogInfo("IOPMConnectionSetDispatchQueue is now running");
-#else
- iopmerr = IOPMConnectionScheduleWithRunLoop(c, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
- if (iopmerr) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr);
- LogInfo("IOPMConnectionScheduleWithRunLoop is now running");
-#endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
- }
- }
- m->p->IOPMConnection = iopmerr ? mDNSNULL : c;
- if (iopmerr) // If IOPMConnectionCreate unavailable or failed, proceed with old-style power notification code below
-#endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements
- {
- m->p->PowerConnection = IORegisterForSystemPower(m, &m->p->PowerPortRef, PowerChanged, &m->p->PowerNotifier);
- if (!m->p->PowerConnection) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
- else
- {
-#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
- IONotificationPortSetDispatchQueue(m->p->PowerPortRef, dispatch_get_main_queue());
-#else
- CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
-#endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
- }
- }
-
-#if APPLE_OSX_mDNSResponder
- // Note: We use SPMetricPortability > 35 to indicate a laptop of some kind
- // SPMetricPortability <= 35 means nominally a non-portable machine (i.e. Mac mini or better)
- // Apple TVs, AirPort base stations, and Time Capsules do not actually weigh 3kg, but we assign them
- // higher 'nominal' masses to indicate they should be treated as being relatively less portable than a laptop
- if (!strncasecmp(HINFO_HWstring, "Xserve", 6)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
- else if (!strncasecmp(HINFO_HWstring, "RackMac", 7)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
- else if (!strncasecmp(HINFO_HWstring, "MacPro", 6)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
- else if (!strncasecmp(HINFO_HWstring, "PowerMac", 8)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 82 /* 160W */; SPMetricTotalPower = 83 /* 200W */; }
- else if (!strncasecmp(HINFO_HWstring, "iMac", 4)) { SPMetricPortability = 30 /* 10kg */; SPMetricMarginalPower = 77 /* 50W */; SPMetricTotalPower = 78 /* 60W */; }
- else if (!strncasecmp(HINFO_HWstring, "Macmini", 7)) { SPMetricPortability = 33 /* 5kg */; SPMetricMarginalPower = 73 /* 20W */; SPMetricTotalPower = 74 /* 25W */; }
- else if (!strncasecmp(HINFO_HWstring, "TimeCapsule", 11)) { SPMetricPortability = 34 /* 4kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 13W */; }
- else if (!strncasecmp(HINFO_HWstring, "AirPort", 7)) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 12W */; }
- else if ( IsAppleTV() ) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 60 /* 1W */; SPMetricTotalPower = 63 /* 2W */; }
- else if (!strncasecmp(HINFO_HWstring, "MacBook", 7)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
- else if (!strncasecmp(HINFO_HWstring, "PowerBook", 9)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
- LogSPS("HW_MODEL: %.*s (%s) Portability %d Marginal Power %d Total Power %d Features %d",
- HINFO_HWstring_prefixlen, HINFO_HWstring, HINFO_HWstring, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures);
-#endif // APPLE_OSX_mDNSResponder
-
- // Currently this is not defined. SSL code will eventually fix this. If it becomes
- // critical, we will define this to workaround the bug in SSL.
-#ifdef __SSL_NEEDS_SERIALIZATION__
- SSLqueue = dispatch_queue_create("com.apple.mDNSResponder.SSLQueue", NULL);
-#else
- SSLqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
-#endif
- if (SSLqueue == mDNSNULL) LogMsg("dispatch_queue_create: SSL queue NULL");
-
- mDNSMacOSXUpdateEtcHosts(m);
- SetupLocalHostRecords(m);
- CUPInit(m);
-
- return(mStatus_NoError);
-}
-
-mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
-{
-#if MDNS_NO_DNSINFO
- LogMsg("Note: Compiled without Apple-specific Split-DNS support");
-#endif
-
- // Adding interfaces will use this flag, so set it now.
- m->DivertMulticastAdvertisements = !m->AdvertiseLocalAddresses;
-
-#if APPLE_OSX_mDNSResponder
- m->SPSBrowseCallback = UpdateSPSStatus;
-#endif // APPLE_OSX_mDNSResponder
-
- mStatus result = mDNSPlatformInit_setup(m);
-
- // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
- // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
- if (result == mStatus_NoError)
- {
- mDNSCoreInitComplete(m, mStatus_NoError);
-
-#if !NO_D2D
- // We only initialize if mDNSCore successfully initialized.
- if (D2DInitialize)
- {
- D2DStatus ds = D2DInitialize(m->p->CFRunLoop, xD2DServiceCallback, m) ;
- if (ds != kD2DSuccess)
- LogMsg("D2DInitialiize failed: %d", ds);
- else
- LogMsg("D2DInitialize succeeded");
- }
-#endif // ! NO_D2D
-
- }
- result = DNSSECCryptoInit(m);
- return(result);
-}
-
-mDNSexport void mDNSPlatformClose(mDNS *const m)
-{
- if (m->p->PowerConnection)
- {
-#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
- IONotificationPortSetDispatchQueue(m->p->PowerPortRef, NULL);
-#else
- CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
-#endif
- // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
- // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
- IODeregisterForSystemPower(&m->p->PowerNotifier);
- IOServiceClose ( m->p->PowerConnection);
- IONotificationPortDestroy ( m->p->PowerPortRef);
- m->p->PowerConnection = 0;
- }
-
- if (m->p->Store)
- {
-#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
- if (!SCDynamicStoreSetDispatchQueue(m->p->Store, NULL))
- LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed");
-#else
- CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
- CFRunLoopSourceInvalidate(m->p->StoreRLS);
- CFRelease(m->p->StoreRLS);
- m->p->StoreRLS = NULL;
-#endif
- CFRelease(m->p->Store);
- m->p->Store = NULL;
- }
-
- if (m->p->PMRLS)
- {
- CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->PMRLS, kCFRunLoopDefaultMode);
- CFRunLoopSourceInvalidate(m->p->PMRLS);
- CFRelease(m->p->PMRLS);
- m->p->PMRLS = NULL;
- }
-
- if (m->p->SysEventNotifier >= 0) { close(m->p->SysEventNotifier); m->p->SysEventNotifier = -1; }
-
-#if !NO_D2D
- if (D2DTerminate)
- {
- D2DStatus ds = D2DTerminate();
- if (ds != kD2DSuccess)
- LogMsg("D2DTerminate failed: %d", ds);
- else
- LogMsg("D2DTerminate succeeded");
- }
-#endif // ! NO_D2D
-
- mDNSs32 utc = mDNSPlatformUTC();
- MarkAllInterfacesInactive(m, utc);
- ClearInactiveInterfaces(m, utc);
- CloseSocketSet(&m->p->permanentsockets);
-
-#if APPLE_OSX_mDNSResponder
- // clean up tunnels
- while (m->TunnelClients)
- {
- ClientTunnel *cur = m->TunnelClients;
- LogInfo("mDNSPlatformClose: removing client tunnel %p %##s from list", cur, cur->dstname.c);
- if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
- AutoTunnelSetKeys(cur, mDNSfalse);
- m->TunnelClients = cur->next;
- freeL("ClientTunnel", cur);
- }
-
- if (AnonymousRacoonConfig)
- {
- AnonymousRacoonConfig = mDNSNULL;
- LogInfo("mDNSPlatformClose: Deconfiguring autotunnel");
- (void)mDNSConfigureServer(kmDNSDown, mDNSNULL, mDNSNULL);
- }
-#endif // APPLE_OSX_mDNSResponder
-}
-
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - General Platform Support Layer functions
-#endif
-
-mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
-{
- return(arc4random());
-}
-
-mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000;
-mDNSexport mDNSu32 mDNSPlatformClockDivisor = 0;
-
-mDNSexport mStatus mDNSPlatformTimeInit(void)
-{
- // Notes: Typical values for mach_timebase_info:
- // tbi.numer = 1000 million
- // tbi.denom = 33 million
- // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
- // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
- // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
- // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
- // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
- //
- // Arithmetic notes:
- // tbi.denom is at least 1, and not more than 2^32-1.
- // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
- // tbi.denom is at least 1, and not more than 2^32-1.
- // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
- // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
- // which is unlikely on any current or future Macintosh.
- // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
- // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
- struct mach_timebase_info tbi;
- kern_return_t result = mach_timebase_info(&tbi);
- if (result == KERN_SUCCESS) mDNSPlatformClockDivisor = ((uint64_t)tbi.denom * 1000000) / tbi.numer;
- return(result);
-}
-
-mDNSexport mDNSs32 mDNSPlatformRawTime(void)
-{
- if (mDNSPlatformClockDivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
-
- static uint64_t last_mach_absolute_time = 0;
- //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
- uint64_t this_mach_absolute_time = mach_absolute_time();
- if ((int64_t)this_mach_absolute_time - (int64_t)last_mach_absolute_time < 0)
- {
- LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time);
- LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time);
- // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
- last_mach_absolute_time = this_mach_absolute_time;
- // Note: This bug happens all the time on 10.3
- NotifyOfElusiveBug("mach_absolute_time went backwards!",
- "This error occurs from time to time, often on newly released hardware, "
- "and usually the exact cause is different in each instance.\r\r"
- "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
- "and assign it to Radar Component “Kernel” Version “X”.");
- }
- last_mach_absolute_time = this_mach_absolute_time;
-
- return((mDNSs32)(this_mach_absolute_time / mDNSPlatformClockDivisor));
-}
-
-mDNSexport mDNSs32 mDNSPlatformUTC(void)
-{
- return time(NULL);
-}
-
-// Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
-mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; }
-mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; }
-mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { strcpy((char *)dst, (char *)src); }
-mDNSexport mDNSu32 mDNSPlatformStrLen ( const void *src) { return(strlen((char*)src)); }
-mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, mDNSu32 len) { memcpy(dst, src, len); }
-mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len) == 0); }
-mDNSexport int mDNSPlatformMemCmp(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len)); }
-mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) { memset(dst, 0, len); }
-mDNSexport void mDNSPlatformQsort ( void *base, int nel, int width, int (*compar)(const void *, const void *))
-{
- return (qsort(base, nel, width, compar));
-}
-#if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
-mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
-#endif
-mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }
-
-mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason)
-{
- if (allowSleep && m->p->IOPMAssertion)
- {
- LogInfo("%s Destroying NoIdleSleep power assertion", __FUNCTION__);
- IOPMAssertionRelease(m->p->IOPMAssertion);
- m->p->IOPMAssertion = 0;
- }
- else if (!allowSleep)
- {
-#ifdef kIOPMAssertionTypeNoIdleSleep
- if (m->p->IOPMAssertion)
- {
- IOPMAssertionRelease(m->p->IOPMAssertion);
- m->p->IOPMAssertion = 0;
- }
-
- CFStringRef assertionName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%d %s"), getprogname(), getpid(), reason ? reason : "");
- IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, assertionName ? assertionName : CFSTR("mDNSResponder"), &m->p->IOPMAssertion);
- if (assertionName) CFRelease(assertionName);
- LogInfo("%s Creating NoIdleSleep power assertion", __FUNCTION__);
-#endif
- }
-}
-
-mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
-{
- mDNSu32 ifindex;
-
- // Sanity check
- ifindex = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID, mDNStrue);
- if (ifindex <= 0)
- {
- LogMsg("mDNSPlatformSendWakeupPacket: ERROR!! Invalid InterfaceID %u", ifindex);
- return;
- }
- mDNSSendWakeupPacket(ifindex, EthAddr, IPAddr, iteration);
-}
-
-mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
-{
- NetworkInterfaceInfoOSX *info;
-
- if (InterfaceID == mDNSInterface_P2P)
- return mDNStrue;
-
- if ( (InterfaceID == mDNSInterface_Any)
- || (InterfaceID == mDNSInterfaceMark)
- || (InterfaceID == mDNSInterface_LocalOnly)
- || (InterfaceID == mDNSInterface_Unicast))
- return mDNSfalse;
-
- info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
- if (info == NULL)
- {
- // this log message can print when operations are stopped on an interface that has gone away
- LogInfo("mDNSPlatformInterfaceIsD2D: Invalid interface index %d", InterfaceID);
- return mDNSfalse;
- }
-
- return (mDNSBool) info->D2DInterface;
-}
-
-// Filter records send over P2P (D2D) type interfaces
-// Note that the terms P2P and D2D are used synonymously in the current code and comments.
-mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const NetworkInterfaceInfo *intf)
-{
- // For an explicit match to a valid interface ID, return true.
- if (rr->resrec.InterfaceID == intf->InterfaceID)
- return mDNStrue;
-
- // Only filtering records for D2D type interfaces, return true for all other interface types.
- if (!mDNSPlatformInterfaceIsD2D(intf->InterfaceID))
- return mDNStrue;
-
- // If it's an AWDL interface the record must be explicitly marked to include AWDL.
- if (intf->InterfaceID == AWDLInterfaceID)
- {
- if (rr->ARType == AuthRecordAnyIncludeAWDL || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
- return mDNStrue;
- else
- return mDNSfalse;
- }
-
- // Send record if it is explicitly marked to include all other P2P type interfaces.
- if (rr->ARType == AuthRecordAnyIncludeP2P || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
- return mDNStrue;
-
- // Don't send the record over this interface.
- return mDNSfalse;
-}
-
-// Filter questions send over P2P (D2D) type interfaces.
-mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf)
-{
- // For an explicit match to a valid interface ID, return true.
- if (q->InterfaceID == intf->InterfaceID)
- return mDNStrue;
-
- // Only filtering questions for D2D type interfaces
- if (!mDNSPlatformInterfaceIsD2D(intf->InterfaceID))
- return mDNStrue;
-
- // If it's an AWDL interface the question must be explicitly marked to include AWDL.
- if (intf->InterfaceID == AWDLInterfaceID)
- {
- if (q->flags & kDNSServiceFlagsIncludeAWDL)
- return mDNStrue;
- else
- return mDNSfalse;
- }
-
- // Sent question if it is explicitly marked to include all other P2P type interfaces.
- if (q->flags & kDNSServiceFlagsIncludeP2P)
- return mDNStrue;
-
- // Don't send the question over this interface.
- return mDNSfalse;
-}
-
-// Returns true unless record was received over the AWDL interface and
-// the question was not specific to the AWDL interface or did not specify kDNSServiceInterfaceIndexAny
-// with the kDNSServiceFlagsIncludeAWDL flag set.
-mDNSexport mDNSBool mDNSPlatformValidRecordForQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
-{
- if (!rr->InterfaceID || (rr->InterfaceID == q->InterfaceID))
- return mDNStrue;
-
- if ((rr->InterfaceID == AWDLInterfaceID) && !(q->flags & kDNSServiceFlagsIncludeAWDL))
- {
- LogInfo("mDNSPlatformValidRecordForQuestion: Record recieved over AWDL not returned for %s %##s query",
- DNSTypeName(q->qtype), q->qname.c);
- return mDNSfalse;
- }
-
- return mDNStrue;
-}
-
-// formating time to RFC 4034 format
-mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize)
-{
- struct tm tmTime;
- time_t t = (time_t)te;
- // Time since epoch : strftime takes "tm". Convert seconds to "tm" using
- // gmtime_r first and then use strftime
- gmtime_r(&t, &tmTime);
- strftime((char *)buf, bufsize, "%Y%m%d%H%M%S", &tmTime);
-}
-
-mDNSexport mDNSs32 mDNSPlatformGetPID()
-{
- return getpid();
-}
-
-// Schedule a function asynchronously on the main queue
-mDNSexport void mDNSPlatformDispatchAsync(mDNS *const m, void *context, AsyncDispatchFunc func)
-{
- // KQueueLock/Unlock is used for two purposes
- //
- // 1. We can't be running along with the KQueue thread and hence acquiring the lock
- // serializes the access to the "core"
- //
- // 2. KQueueUnlock also sends a message wake up the KQueue thread which in turn wakes
- // up and calls udsserver_idle which schedules the messages across the uds socket.
- // If "func" delivers something to the uds socket from the dispatch thread, it will
- // not be delivered immediately if not for the Unlock.
- dispatch_async(dispatch_get_main_queue(), ^{
- KQueueLock(m);
- func(m, context);
- KQueueUnlock(m, "mDNSPlatformDispatchAsync");
-#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
- // KQueueUnlock is a noop. Hence, we need to run kick off the idle loop
- // to handle any message that "func" might deliver.
- TriggerEventCompletion();
-#endif
- });
-}
-
-// definitions for device-info record construction
-#define DEVINFO_MODEL "model="
-#define DEVINFO_MODEL_LEN strlen(DEVINFO_MODEL)
-
-#define OSX_VER "osxvers="
-#define OSX_VER_LEN strlen(OSX_VER)
-#define VER_NUM_LEN 2 // 2 digits of version number added to base string
-
-// Bytes available in TXT record for model name after subtracting space for other
-// fixed size strings and their length bytes.
-#define MAX_MODEL_NAME_LEN (256 - (DEVINFO_MODEL_LEN + 1) - (OSX_VER_LEN + VER_NUM_LEN + 1))
-
-// Initialize device-info TXT record contents and return total length of record data.
-mDNSexport mDNSu32 initializeDeviceInfoTXT(mDNS *m, mDNSu8 *ptr)
-{
- mDNSu8 *bufferStart = ptr;
- mDNSu8 len = m->HIHardware.c[0] < MAX_MODEL_NAME_LEN ? m->HIHardware.c[0] : MAX_MODEL_NAME_LEN;
-
- *ptr = DEVINFO_MODEL_LEN + len; // total length of DEVINFO_MODEL string plus the hardware name string
- ptr++;
- mDNSPlatformMemCopy(ptr, DEVINFO_MODEL, DEVINFO_MODEL_LEN);
- ptr += DEVINFO_MODEL_LEN;
- mDNSPlatformMemCopy(ptr, m->HIHardware.c + 1, len);
- ptr += len;
-
- // only include this string for OSX
- if (OSXVers)
- {
- char ver_num[VER_NUM_LEN + 1]; // version digits + null written by snprintf
- *ptr = OSX_VER_LEN + VER_NUM_LEN; // length byte
- ptr++;
- mDNSPlatformMemCopy(ptr, OSX_VER, OSX_VER_LEN);
- ptr += OSX_VER_LEN;
- // convert version number to ASCII, add 1 for terminating null byte written by snprintf()
- snprintf(ver_num, VER_NUM_LEN + 1, "%d", OSXVers);
- mDNSPlatformMemCopy(ptr, ver_num, VER_NUM_LEN);
- ptr += VER_NUM_LEN;
- }
-
- return (ptr - bufferStart);
-}
Copied: vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/mDNSMacOSX.c (from rev 6984, vendor/apple/mDNSResponder/dist/mDNSMacOSX/mDNSMacOSX.c)
===================================================================
--- vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/mDNSMacOSX.c (rev 0)
+++ vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/mDNSMacOSX.c 2015-03-20 01:14:52 UTC (rev 6985)
@@ -0,0 +1,10443 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002-2013 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// ***************************************************************************
+// mDNSMacOSX.c:
+// Supporting routines to run mDNS on a CFRunLoop platform
+// ***************************************************************************
+
+// For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
+// including ones that mDNSResponder chooses not to use.
+#define LIST_ALL_INTERFACES 0
+
+#include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
+#include "DNSCommon.h"
+#include "uDNS.h"
+#include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
+#include "dns_sd.h" // For mDNSInterface_LocalOnly etc.
+#include "PlatformCommon.h"
+#include "uds_daemon.h"
+#include "CryptoSupport.h"
+
+#include <stdio.h>
+#include <stdarg.h> // For va_list support
+#include <stdlib.h> // For arc4random
+#include <net/if.h>
+#include <net/if_types.h> // For IFT_ETHER
+#include <net/if_dl.h>
+#include <net/bpf.h> // For BIOCSETIF etc.
+#include <sys/uio.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/event.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <time.h> // platform support for UTC time
+#include <arpa/inet.h> // for inet_aton
+#include <pthread.h>
+#include <netdb.h> // for getaddrinfo
+#include <sys/sockio.h> // for SIOCGIFEFLAGS
+#include <notify.h>
+#include <netinet/in.h> // For IP_RECVTTL
+#ifndef IP_RECVTTL
+#define IP_RECVTTL 24 // bool; receive reception TTL w/dgram
+#endif
+
+#include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
+#include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
+#include <netinet6/in6_var.h> // For IN6_IFF_NOTREADY etc.
+#include <netinet6/nd6.h> // For ND6_INFINITE_LIFETIME etc.
+
+#include <netinet/tcp.h>
+
+#include <DebugServices.h>
+#include "dnsinfo.h"
+
+#include <ifaddrs.h>
+
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOMessage.h>
+
+#include <IOKit/ps/IOPowerSources.h>
+#include <IOKit/ps/IOPowerSourcesPrivate.h>
+#include <IOKit/ps/IOPSKeys.h>
+
+#include <mach/mach_error.h>
+#include <mach/mach_port.h>
+#include <mach/mach_time.h>
+#include "helper.h"
+#include "P2PPacketFilter.h"
+
+#include <asl.h>
+#include <SystemConfiguration/SCPrivate.h>
+
+// Include definition of opaque_presence_indication for KEV_DL_NODE_PRESENCE handling logic.
+#include <Kernel/IOKit/apple80211/apple80211_var.h>
+
+#if APPLE_OSX_mDNSResponder
+#include <DeviceToDeviceManager/DeviceToDeviceManager.h>
+#include <AWACS.h>
+#if !NO_D2D
+D2DStatus D2DInitialize(CFRunLoopRef runLoop, D2DServiceCallback serviceCallback, void* userData) __attribute__((weak_import));
+D2DStatus D2DRetain(D2DServiceInstance instanceHandle, D2DTransportType transportType) __attribute__((weak_import));
+D2DStatus D2DStopAdvertisingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
+D2DStatus D2DRelease(D2DServiceInstance instanceHandle, D2DTransportType transportType) __attribute__((weak_import));
+D2DStatus D2DStartAdvertisingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
+D2DStatus D2DStartBrowsingForKeyOnTransport(const Byte *key, const size_t keySize, D2DTransportType transport) __attribute__((weak_import));
+D2DStatus D2DStopBrowsingForKeyOnTransport(const Byte *key, const size_t keySize, D2DTransportType transport) __attribute__((weak_import));
+void D2DStartResolvingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
+void D2DStopResolvingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
+D2DStatus D2DTerminate() __attribute__((weak_import));
+
+#endif // ! NO_D2D
+
+#else
+#define NO_D2D 1
+#define NO_AWACS 1
+#endif // APPLE_OSX_mDNSResponder
+
+#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
+#include <IOKit/platform/IOPlatformSupportPrivate.h>
+#endif // APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
+
+
+#define kInterfaceSpecificOption "interface="
+
+#define mDNS_IOREG_KEY "mDNS_KEY"
+#define mDNS_IOREG_VALUE "2009-07-30"
+#define mDNS_IOREG_KA_KEY "mDNS_Keepalive"
+#define mDNS_USER_CLIENT_CREATE_TYPE 'mDNS'
+
+// cache the InterfaceID of the AWDL interface
+static mDNSInterfaceID AWDLInterfaceID;
+
+// ***************************************************************************
+// Globals
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - Globals
+#endif
+
+// By default we don't offer sleep proxy service
+// If OfferSleepProxyService is set non-zero (typically via command-line switch),
+// then we'll offer sleep proxy service on desktop Macs that are set to never sleep.
+// We currently do not offer sleep proxy service on laptops, or on machines that are set to go to sleep.
+mDNSexport int OfferSleepProxyService = 0;
+mDNSexport int DisableSleepProxyClient = 0;
+mDNSexport int UseInternalSleepProxy = 1; // Set to non-zero to use internal (in-NIC) Sleep Proxy
+
+mDNSexport int OSXVers, iOSVers;
+mDNSexport int KQueueFD;
+
+#ifndef NO_SECURITYFRAMEWORK
+static CFArrayRef ServerCerts;
+OSStatus SSLSetAllowAnonymousCiphers(SSLContextRef context, Boolean enable);
+#endif /* NO_SECURITYFRAMEWORK */
+
+static CFStringRef NetworkChangedKey_IPv4;
+static CFStringRef NetworkChangedKey_IPv6;
+static CFStringRef NetworkChangedKey_Hostnames;
+static CFStringRef NetworkChangedKey_Computername;
+static CFStringRef NetworkChangedKey_DNS;
+static CFStringRef NetworkChangedKey_StateInterfacePrefix;
+static CFStringRef NetworkChangedKey_DynamicDNS = CFSTR("Setup:/Network/DynamicDNS");
+static CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac");
+static CFStringRef NetworkChangedKey_BTMMConnectivity = CFSTR("State:/Network/Connectivity");
+static CFStringRef NetworkChangedKey_PowerSettings = CFSTR("State:/IOKit/PowerManagement/CurrentSettings");
+
+static char HINFO_HWstring_buffer[32];
+static char *HINFO_HWstring = "Device";
+static int HINFO_HWstring_prefixlen = 6;
+
+mDNSexport int WatchDogReportingThreshold = 250;
+
+dispatch_queue_t SSLqueue;
+
+//To prevent blocking the main queue, all writes to DynamicStore happen on the DynamicStoreQueue
+static dispatch_queue_t DynamicStoreQueue;
+
+#if TARGET_OS_EMBEDDED
+#define kmDNSResponderManagedPrefsID CFSTR("/Library/Managed Preferences/mobile/com.apple.mDNSResponder.plist")
+#endif
+
+#if APPLE_OSX_mDNSResponder
+static mDNSu8 SPMetricPortability = 99;
+static mDNSu8 SPMetricMarginalPower = 99;
+static mDNSu8 SPMetricTotalPower = 99;
+static mDNSu8 SPMetricFeatures = 1; /* The current version supports TCP Keep Alive Feature */
+mDNSexport domainname ActiveDirectoryPrimaryDomain;
+mDNSexport int ActiveDirectoryPrimaryDomainLabelCount;
+mDNSexport mDNSAddr ActiveDirectoryPrimaryDomainServer;
+#endif // APPLE_OSX_mDNSResponder
+
+// Don't send triggers too often. We arbitrarily limit it to three minutes.
+#define DNS_TRIGGER_INTERVAL (180 * mDNSPlatformOneSecond)
+
+// Used by AutoTunnel
+const char btmmprefix[] = "btmmdns:";
+const char dnsprefix[] = "dns:";
+
+// String Array used to write list of private domains to Dynamic Store
+static CFArrayRef privateDnsArray = NULL;
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - D2D Support
+#endif
+
+#if !NO_D2D
+
+mDNSexport void D2D_start_advertising_interface(NetworkInterfaceInfo *interface)
+{
+ // AWDL wants the address and reverse address PTR record communicated
+ // via the D2D interface layer.
+ if (interface->InterfaceID == AWDLInterfaceID)
+ {
+ // only log if we have a valid record to start advertising
+ if (interface->RR_A.resrec.RecordType || interface->RR_PTR.resrec.RecordType)
+ LogInfo("D2D_start_advertising_interface: %s", interface->ifname);
+
+ if (interface->RR_A.resrec.RecordType)
+ external_start_advertising_service(&interface->RR_A.resrec, NULL);
+ if (interface->RR_PTR.resrec.RecordType)
+ external_start_advertising_service(&interface->RR_PTR.resrec, NULL);
+ }
+}
+
+mDNSexport void D2D_stop_advertising_interface(NetworkInterfaceInfo *interface)
+{
+ if (interface->InterfaceID == AWDLInterfaceID)
+ {
+ // only log if we have a valid record to stop advertising
+ if (interface->RR_A.resrec.RecordType || interface->RR_PTR.resrec.RecordType)
+ LogInfo("D2D_stop_advertising_interface: %s", interface->ifname);
+
+ if (interface->RR_A.resrec.RecordType)
+ external_stop_advertising_service(&interface->RR_A.resrec, NULL);
+ if (interface->RR_PTR.resrec.RecordType)
+ external_stop_advertising_service(&interface->RR_PTR.resrec, NULL);
+ }
+}
+
+// Name compression items for fake packet version number 1
+static const mDNSu8 compression_packet_v1 = 0x01;
+
+static DNSMessage compression_base_msg = { { {{0}}, {{0}}, 2, 0, 0, 0 }, "\x04_tcp\x05local\x00\x00\x0C\x00\x01\x04_udp\xC0\x11\x00\x0C\x00\x01" };
+static mDNSu8 *const compression_limit = (mDNSu8 *) &compression_base_msg + sizeof(DNSMessage);
+static mDNSu8 *const compression_lhs = (mDNSu8 *const) compression_base_msg.data + 27;
+
+mDNSlocal void FreeD2DARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
+mDNSlocal void PrintHex(mDNSu8 *data, mDNSu16 len);
+
+typedef struct D2DRecordListElem
+{
+ struct D2DRecordListElem *next;
+ D2DServiceInstance instanceHandle;
+ D2DTransportType transportType;
+ AuthRecord ar; // must be last in the structure to accomodate extra space
+ // allocated for large records.
+} D2DRecordListElem;
+
+static D2DRecordListElem *D2DRecords = NULL; // List of records returned with D2DServiceFound events
+
+typedef struct D2DBrowseListElem
+{
+ struct D2DBrowseListElem *next;
+ domainname name;
+ mDNSu16 type;
+ unsigned int refCount;
+} D2DBrowseListElem;
+
+D2DBrowseListElem* D2DBrowseList = NULL;
+
+mDNSlocal mDNSu8 *putVal16(mDNSu8 *ptr, mDNSu16 val)
+{
+ ptr[0] = (mDNSu8)((val >> 8 ) & 0xFF);
+ ptr[1] = (mDNSu8)((val ) & 0xFF);
+ return ptr + sizeof(mDNSu16);
+}
+
+mDNSlocal mDNSu8 *putVal32(mDNSu8 *ptr, mDNSu32 val)
+{
+ ptr[0] = (mDNSu8)((val >> 24) & 0xFF);
+ ptr[1] = (mDNSu8)((val >> 16) & 0xFF);
+ ptr[2] = (mDNSu8)((val >> 8) & 0xFF);
+ ptr[3] = (mDNSu8)((val ) & 0xFF);
+ return ptr + sizeof(mDNSu32);
+}
+
+mDNSlocal void DomainnameToLower(const domainname * const in, domainname * const out)
+{
+ const mDNSu8 * const start = (const mDNSu8 * const)in;
+ mDNSu8 *ptr = (mDNSu8*)start;
+ while(*ptr)
+ {
+ mDNSu8 c = *ptr;
+ out->c[ptr-start] = *ptr;
+ ptr++;
+ for (; c; c--,ptr++) out->c[ptr-start] = mDNSIsUpperCase(*ptr) ? (*ptr - 'A' + 'a') : *ptr;
+ }
+ out->c[ptr-start] = *ptr;
+}
+
+mDNSlocal mStatus DNSNameCompressionParseBytes(mDNS *const m, const mDNSu8 *const lhs, const mDNSu16 lhs_len, const mDNSu8 *const rhs, const mDNSu16 rhs_len, AuthRecord *rr)
+{
+ if (mDNS_LoggingEnabled)
+ {
+ LogInfo("%s", __func__);
+ LogInfo(" Static Bytes: (%d bytes)", compression_lhs - (mDNSu8*)&compression_base_msg);
+ PrintHex((mDNSu8*)&compression_base_msg, compression_lhs - (mDNSu8*)&compression_base_msg);
+ }
+
+ mDNSu8 *ptr = compression_lhs; // pointer to the end of our fake packet
+
+ // Check to make sure we're not going to go past the end of the DNSMessage data
+ // 7 = 2 for CLASS (-1 for our version) + 4 for TTL + 2 for RDLENGTH
+ if (ptr + lhs_len - 7 + rhs_len >= compression_limit) return mStatus_NoMemoryErr;
+
+ // Copy the LHS onto our fake wire packet
+ mDNSPlatformMemCopy(ptr, lhs, lhs_len);
+ ptr += lhs_len - 1;
+
+ // Check the 'fake packet' version number, to ensure that we know how to decompress this data
+ if (*ptr != compression_packet_v1) return mStatus_Incompatible;
+
+ // two bytes of CLASS
+ ptr = putVal16(ptr, kDNSClass_IN | kDNSClass_UniqueRRSet);
+
+ // four bytes of TTL
+ ptr = putVal32(ptr, 120);
+
+ // Copy the RHS length into the RDLENGTH of our fake wire packet
+ ptr = putVal16(ptr, rhs_len);
+
+ // Copy the RHS onto our fake wire packet
+ mDNSPlatformMemCopy(ptr, rhs, rhs_len);
+ ptr += rhs_len;
+
+ if (mDNS_LoggingEnabled)
+ {
+ LogInfo(" Our Bytes (%d bytes): ", ptr - compression_lhs);
+ PrintHex(compression_lhs, ptr - compression_lhs);
+ }
+
+ ptr = (mDNSu8 *) GetLargeResourceRecord(m, &compression_base_msg, compression_lhs, ptr, mDNSInterface_Any, kDNSRecordTypePacketAns, &m->rec);
+ if (!ptr || m->rec.r.resrec.RecordType == kDNSRecordTypePacketNegative)
+ { LogMsg("DNSNameCompressionParseBytes: failed to get large RR"); m->rec.r.resrec.RecordType = 0; return mStatus_UnknownErr; }
+ else LogInfo("DNSNameCompressionParseBytes: got rr: %s", CRDisplayString(m, &m->rec.r));
+
+ mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_P2P, m->rec.r.resrec.rrtype, 7200, kDNSRecordTypeShared, AuthRecordP2P, FreeD2DARElemCallback, NULL);
+ AssignDomainName(&rr->namestorage, &m->rec.namestorage);
+ rr->resrec.rdlength = m->rec.r.resrec.rdlength;
+ rr->resrec.rdata->MaxRDLength = m->rec.r.resrec.rdlength;
+ mDNSPlatformMemCopy(rr->resrec.rdata->u.data, m->rec.r.resrec.rdata->u.data, m->rec.r.resrec.rdlength);
+ rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
+ SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
+
+ m->rec.r.resrec.RecordType = 0; // Mark m->rec as no longer in use
+
+ return mStatus_NoError;
+}
+
+mDNSlocal mDNSu8 * DNSNameCompressionBuildLHS(const domainname* typeDomain, DNS_TypeValues qtype)
+{
+ mDNSu8 *ptr = putDomainNameAsLabels(&compression_base_msg, compression_lhs, compression_limit, typeDomain);
+ if (!ptr) return ptr;
+ *ptr = (qtype >> 8) & 0xff;
+ ptr += 1;
+ *ptr = qtype & 0xff;
+ ptr += 1;
+ *ptr = compression_packet_v1;
+ return ptr + 1;
+}
+
+mDNSlocal mDNSu8 * DNSNameCompressionBuildRHS(mDNSu8 *start, const ResourceRecord *const resourceRecord)
+{
+ return putRData(&compression_base_msg, start, compression_limit, resourceRecord);
+}
+
+#define PRINT_DEBUG_BYTES_LIMIT 64 // set limit on number of record bytes printed for debugging
+
+mDNSlocal void PrintHex(mDNSu8 *data, mDNSu16 len)
+{
+ mDNSu8 *end;
+ char buffer[49] = {0};
+ char *bufend = buffer + sizeof(buffer);
+
+ if (len > PRINT_DEBUG_BYTES_LIMIT)
+ {
+ LogInfo(" (limiting debug output to %d bytes)", PRINT_DEBUG_BYTES_LIMIT);
+ len = PRINT_DEBUG_BYTES_LIMIT;
+ }
+ end = data + len;
+
+ while(data < end)
+ {
+ char *ptr = buffer;
+ for(; data < end && ptr < bufend-1; ptr+=3,data++)
+ mDNS_snprintf(ptr, bufend - ptr, "%02X ", *data);
+ LogInfo(" %s", buffer);
+ }
+}
+
+mDNSlocal void PrintHelper(const char *const tag, mDNSu8 *lhs, mDNSu16 lhs_len, mDNSu8 *rhs, mDNSu16 rhs_len)
+{
+ if (!mDNS_LoggingEnabled) return;
+
+ LogInfo("%s:", tag);
+ LogInfo(" LHS: (%d bytes)", lhs_len);
+ PrintHex(lhs, lhs_len);
+
+ if (!rhs) return;
+
+ LogInfo(" RHS: (%d bytes)", rhs_len);
+ PrintHex(rhs, rhs_len);
+}
+
+mDNSlocal void FreeD2DARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+{
+ (void)m; // unused
+ if (result == mStatus_MemFree)
+ {
+ D2DRecordListElem **ptr = &D2DRecords;
+ D2DRecordListElem *tmp;
+ while (*ptr && &(*ptr)->ar != rr) ptr = &(*ptr)->next;
+ if (!*ptr) { LogMsg("FreeD2DARElemCallback: Could not find in D2DRecords: %s", ARDisplayString(m, rr)); return; }
+ LogInfo("FreeD2DARElemCallback: Found in D2DRecords: %s", ARDisplayString(m, rr));
+ tmp = *ptr;
+ *ptr = (*ptr)->next;
+ // Just because we stoppped browsing, doesn't mean we should tear down the PAN connection.
+ mDNSPlatformMemFree(tmp);
+ }
+}
+
+mDNSexport void external_connection_release(const domainname *instance)
+{
+ (void) instance;
+ D2DRecordListElem *ptr = D2DRecords;
+
+ for ( ; ptr ; ptr = ptr->next)
+ {
+ if ((ptr->ar.resrec.rrtype == kDNSServiceType_PTR) &&
+ SameDomainName(&ptr->ar.rdatastorage.u.name, instance))
+ {
+ LogInfo("external_connection_release: Calling D2DRelease(instanceHandle = %p, transportType = %d",
+ ptr->instanceHandle, ptr->transportType);
+ if (D2DRelease) D2DRelease(ptr->instanceHandle, ptr->transportType);
+ }
+ }
+}
+
+mDNSlocal void xD2DClearCache(const domainname *regType, DNS_TypeValues qtype)
+{
+ D2DRecordListElem *ptr = D2DRecords;
+ for ( ; ptr ; ptr = ptr->next)
+ {
+ if ((ptr->ar.resrec.rrtype == qtype) && SameDomainName(&ptr->ar.namestorage, regType))
+ {
+ mDNS_Deregister(&mDNSStorage, &ptr->ar);
+ LogInfo("xD2DClearCache: Clearing cache record and deregistering %s", ARDisplayString(&mDNSStorage, &ptr->ar));
+ }
+ }
+}
+
+mDNSlocal D2DBrowseListElem ** D2DFindInBrowseList(const domainname *const name, mDNSu16 type)
+{
+ D2DBrowseListElem **ptr = &D2DBrowseList;
+
+ for ( ; *ptr; ptr = &(*ptr)->next)
+ if ((*ptr)->type == type && SameDomainName(&(*ptr)->name, name))
+ break;
+
+ return ptr;
+}
+
+mDNSlocal unsigned int D2DBrowseListRefCount(const domainname *const name, mDNSu16 type)
+{
+ D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
+ return *ptr ? (*ptr)->refCount : 0;
+}
+
+mDNSlocal void D2DBrowseListRetain(const domainname *const name, mDNSu16 type)
+{
+ D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
+
+ if (!*ptr)
+ {
+ *ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
+ mDNSPlatformMemZero(*ptr, sizeof(**ptr));
+ (*ptr)->type = type;
+ AssignDomainName(&(*ptr)->name, name);
+ }
+ (*ptr)->refCount += 1;
+
+ LogInfo("D2DBrowseListRetain: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount);
+}
+
+mDNSlocal void D2DBrowseListRelease(const domainname *const name, mDNSu16 type)
+{
+ D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
+
+ if (!*ptr) { LogMsg("D2DBrowseListRelease: Didn't find %##s %s in list", name->c, DNSTypeName(type)); return; }
+
+ (*ptr)->refCount -= 1;
+
+ LogInfo("D2DBrowseListRelease: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount);
+
+ if (!(*ptr)->refCount)
+ {
+ D2DBrowseListElem *tmp = *ptr;
+ *ptr = (*ptr)->next;
+ mDNSPlatformMemFree(tmp);
+ }
+}
+
+mDNSlocal mStatus xD2DParse(mDNS *const m, const mDNSu8 * const lhs, const mDNSu16 lhs_len, const mDNSu8 * const rhs, const mDNSu16 rhs_len, AuthRecord *rr)
+{
+ if (*(lhs + (lhs_len - 1)) == compression_packet_v1)
+ return DNSNameCompressionParseBytes(m, lhs, lhs_len, rhs, rhs_len, rr);
+ else
+ return mStatus_Incompatible;
+}
+
+mDNSlocal void xD2DAddToCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
+{
+ if (result == kD2DSuccess)
+ {
+ if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DAddToCache: NULL Byte * passed in or length == 0"); return; }
+
+ mStatus err;
+ D2DRecordListElem *ptr = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData)));
+
+ if (ptr == NULL) { LogMsg("xD2DAddToCache: memory allocation failure"); return; }
+
+ err = xD2DParse(m, (const mDNSu8 * const)key, (const mDNSu16)keySize, (const mDNSu8 * const)value, (const mDNSu16)valueSize, &ptr->ar);
+ if (err)
+ {
+ LogMsg("xD2DAddToCache: xD2DParse returned error: %d", err);
+ PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
+ mDNSPlatformMemFree(ptr);
+ return;
+ }
+ err = mDNS_Register(m, &ptr->ar);
+ if (err)
+ {
+ LogMsg("xD2DAddToCache: mDNS_Register returned error %d for %s", err, ARDisplayString(m, &ptr->ar));
+ mDNSPlatformMemFree(ptr);
+ return;
+ }
+
+ LogInfo("xD2DAddToCache: mDNS_Register succeeded for %s", ARDisplayString(m, &ptr->ar));
+ ptr->instanceHandle = instanceHandle;
+ ptr->transportType = transportType;
+ ptr->next = D2DRecords;
+ D2DRecords = ptr;
+ }
+ else
+ LogMsg("xD2DAddToCache: Unexpected result %d", result);
+}
+
+mDNSlocal D2DRecordListElem * xD2DFindInList(mDNS *const m, const Byte *const key, const size_t keySize, const Byte *const value, const size_t valueSize)
+{
+ D2DRecordListElem *ptr = D2DRecords;
+ D2DRecordListElem *arptr;
+
+ if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DFindInList: NULL Byte * passed in or length == 0"); return NULL; }
+
+ arptr = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData)));
+ if (arptr == NULL) { LogMsg("xD2DFindInList: memory allocation failure"); return NULL; }
+
+ if (xD2DParse(m, (const mDNSu8 *const)key, (const mDNSu16)keySize, (const mDNSu8 *const)value, (const mDNSu16)valueSize, &arptr->ar) != mStatus_NoError)
+ {
+ LogMsg("xD2DFindInList: xD2DParse failed for key: %p (%u) value: %p (%u)", key, keySize, value, valueSize);
+ mDNSPlatformMemFree(arptr);
+ return NULL;
+ }
+
+ while (ptr)
+ {
+ if (IdenticalResourceRecord(&arptr->ar.resrec, &ptr->ar.resrec)) break;
+ ptr = ptr->next;
+ }
+
+ if (!ptr) LogMsg("xD2DFindInList: Could not find in D2DRecords: %s", ARDisplayString(m, &arptr->ar));
+ mDNSPlatformMemFree(arptr);
+ return ptr;
+}
+
+mDNSlocal void xD2DRemoveFromCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
+{
+ (void)transportType; // We don't care about this, yet.
+ (void)instanceHandle; // We don't care about this, yet.
+
+ if (result == kD2DSuccess)
+ {
+ D2DRecordListElem *ptr = xD2DFindInList(m, key, keySize, value, valueSize);
+ if (ptr)
+ {
+ LogInfo("xD2DRemoveFromCache: Remove from cache: %s", ARDisplayString(m, &ptr->ar));
+ mDNS_Deregister(m, &ptr->ar);
+ }
+ }
+ else
+ LogMsg("xD2DRemoveFromCache: Unexpected result %d", result);
+}
+
+mDNSlocal void xD2DServiceResolved(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
+{
+ (void)m;
+ (void)key;
+ (void)keySize;
+ (void)value;
+ (void)valueSize;
+
+ if (result == kD2DSuccess)
+ {
+ LogInfo("xD2DServiceResolved: Starting up PAN connection for %p", instanceHandle);
+ if (D2DRetain) D2DRetain(instanceHandle, transportType);
+ }
+ else LogMsg("xD2DServiceResolved: Unexpected result %d", result);
+}
+
+mDNSlocal void xD2DRetainHappened(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
+{
+ (void)m;
+ (void)instanceHandle;
+ (void)transportType;
+ (void)key;
+ (void)keySize;
+ (void)value;
+ (void)valueSize;
+
+ if (result == kD2DSuccess) LogInfo("xD2DRetainHappened: Opening up PAN connection for %p", instanceHandle);
+ else LogMsg("xD2DRetainHappened: Unexpected result %d", result);
+}
+
+mDNSlocal void xD2DReleaseHappened(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
+{
+ (void)m;
+ (void)instanceHandle;
+ (void)transportType;
+ (void)key;
+ (void)keySize;
+ (void)value;
+ (void)valueSize;
+
+ if (result == kD2DSuccess) LogInfo("xD2DReleaseHappened: Closing PAN connection for %p", instanceHandle);
+ else LogMsg("xD2DReleaseHappened: Unexpected result %d", result);
+}
+
+mDNSlocal void xD2DServiceCallback(D2DServiceEvent event, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize, void *userData)
+{
+ mDNS *m = (mDNS *) userData;
+ const char *eventString = "unknown";
+
+ KQueueLock(m);
+
+ if (keySize > 0xFFFF) LogMsg("xD2DServiceCallback: keySize too large: %u", keySize);
+ if (valueSize > 0xFFFF) LogMsg("xD2DServiceCallback: valueSize too large: %u", valueSize);
+
+ switch (event)
+ {
+ case D2DServiceFound:
+ eventString = "D2DServiceFound";
+ break;
+ case D2DServiceLost:
+ eventString = "D2DServiceLost";
+ break;
+ case D2DServiceResolved:
+ eventString = "D2DServiceResolved";
+ break;
+ case D2DServiceRetained:
+ eventString = "D2DServiceRetained";
+ break;
+ case D2DServiceReleased:
+ eventString = "D2DServiceReleased";
+ break;
+ default:
+ break;
+ }
+
+ LogInfo("xD2DServiceCallback: event=%s result=%d instanceHandle=%p transportType=%d LHS=%p (%u) RHS=%p (%u) userData=%p", eventString, result, instanceHandle, transportType, key, keySize, value, valueSize, userData);
+ PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
+
+ switch (event)
+ {
+ case D2DServiceFound:
+ xD2DAddToCache(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
+ break;
+ case D2DServiceLost:
+ xD2DRemoveFromCache(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
+ break;
+ case D2DServiceResolved:
+ xD2DServiceResolved(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
+ break;
+ case D2DServiceRetained:
+ xD2DRetainHappened(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
+ break;
+ case D2DServiceReleased:
+ xD2DReleaseHappened(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
+ break;
+ default:
+ break;
+ }
+
+ // Need to tickle the main kqueue loop to potentially handle records we removed or added.
+ KQueueUnlock(m, "xD2DServiceCallback");
+}
+
+// Map interface index and flags to a specific D2D transport type or D2DTransportMax if all plugins
+// should be called.
+// When D2DTransportMax is returned, if a specific transport should not be called, *excludedTransportType
+// will be set to the excluded transport value, otherwise, it will be set to D2DTransportMax.
+// If the return value is not D2DTransportMax, excludedTransportType is undefined.
+
+mDNSlocal D2DTransportType xD2DInterfaceToTransportType(mDNSInterfaceID InterfaceID, DNSServiceFlags flags, D2DTransportType * excludedTransportType)
+{
+ NetworkInterfaceInfoOSX *info;
+
+ // Default exludes the D2DAWDLTransport when D2DTransportMax is returned.
+ *excludedTransportType = D2DAWDLTransport;
+
+ // Call all D2D plugins when both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set.
+ if ((flags & kDNSServiceFlagsIncludeP2P) && (flags & kDNSServiceFlagsIncludeAWDL))
+ {
+ LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (including AWDL) since both kDNSServiceFlagsIncludeP2P and kDNSServiceFlagsIncludeAWDL are set");
+ *excludedTransportType = D2DTransportMax;
+ return D2DTransportMax;
+ }
+ // Call all D2D plugins (exlcluding AWDL) when only kDNSServiceFlagsIncludeP2P is set.
+ else if (flags & kDNSServiceFlagsIncludeP2P)
+ {
+ LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) since only kDNSServiceFlagsIncludeP2P is set");
+ return D2DTransportMax;
+ }
+ // Call AWDL D2D plugin when only kDNSServiceFlagsIncludeAWDL is set.
+ else if (flags & kDNSServiceFlagsIncludeAWDL)
+ {
+ LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport since only kDNSServiceFlagsIncludeAWDL is set");
+ return D2DAWDLTransport;
+ }
+
+ if (InterfaceID == mDNSInterface_P2P)
+ {
+ LogInfo("xD2DInterfaceToTransportType: returning D2DTransportMax (excluding AWDL) for interface index mDNSInterface_P2P");
+ return D2DTransportMax;
+ }
+
+ // Compare to cached AWDL interface ID.
+ if (AWDLInterfaceID && (InterfaceID == AWDLInterfaceID))
+ {
+ LogInfo("xD2DInterfaceToTransportType: returning D2DAWDLTransport for interface index %d", InterfaceID);
+ return D2DAWDLTransport;
+ }
+
+ info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
+ if (info == NULL)
+ {
+ LogInfo("xD2DInterfaceToTransportType: Invalid interface index %d", InterfaceID);
+ return D2DTransportMax;
+ }
+
+ // Recognize AirDrop specific p2p* interface based on interface name.
+ if (strncmp(info->ifinfo.ifname, "p2p", 3) == 0)
+ {
+ LogInfo("xD2DInterfaceToTransportType: returning D2DWifiPeerToPeerTransport for interface index %d", InterfaceID);
+ return D2DWifiPeerToPeerTransport;
+ }
+
+ // Currently there is no way to identify Bluetooth interface by name,
+ // since they use "en*" based name strings.
+
+ LogInfo("xD2DInterfaceToTransportType: returning default D2DTransportMax for interface index %d", InterfaceID);
+ return D2DTransportMax;
+}
+
+mDNSexport void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags)
+{
+ domainname lower;
+
+ if (qtype == kDNSServiceType_A || qtype == kDNSServiceType_AAAA)
+ {
+ LogInfo("external_start_browsing_for_service: ignoring address record");
+ return;
+ }
+
+ DomainnameToLower(typeDomain, &lower);
+
+ if (!D2DBrowseListRefCount(&lower, qtype))
+ {
+ D2DTransportType transportType, excludedTransport;
+
+ LogInfo("external_start_browsing_for_service: Starting browse for: %##s %s", lower.c, DNSTypeName(qtype));
+ mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype);
+ PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0);
+
+ transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
+ if (transportType == D2DTransportMax)
+ {
+ D2DTransportType i;
+ for (i = 0; i < D2DTransportMax; i++)
+ {
+ if (i == excludedTransport) continue;
+ if (D2DStartBrowsingForKeyOnTransport) D2DStartBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, i);
+ }
+ }
+ else
+ {
+ if (D2DStartBrowsingForKeyOnTransport) D2DStartBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, transportType);
+ }
+ }
+ D2DBrowseListRetain(&lower, qtype);
+}
+
+mDNSexport void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags)
+{
+ domainname lower;
+
+ if (qtype == kDNSServiceType_A || qtype == kDNSServiceType_AAAA)
+ {
+ LogInfo("external_stop_browsing_for_service: ignoring address record");
+ return;
+ }
+
+ DomainnameToLower(typeDomain, &lower);
+
+ D2DBrowseListRelease(&lower, qtype);
+ if (!D2DBrowseListRefCount(&lower, qtype))
+ {
+ D2DTransportType transportType, excludedTransport;
+
+ LogInfo("external_stop_browsing_for_service: Stopping browse for: %##s %s", lower.c, DNSTypeName(qtype));
+ mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype);
+ PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0);
+
+ transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
+ if (transportType == D2DTransportMax)
+ {
+ D2DTransportType i;
+ for (i = 0; i < D2DTransportMax; i++)
+ {
+ if (i == excludedTransport) continue;
+ if (D2DStopBrowsingForKeyOnTransport) D2DStopBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, i);
+ }
+ }
+ else
+ {
+ if (D2DStopBrowsingForKeyOnTransport) D2DStopBrowsingForKeyOnTransport(compression_lhs, end - compression_lhs, transportType);
+ }
+
+ // The D2D driver may not generate the D2DServiceLost event for this key after
+ // the D2DStopBrowsingForKey*() call above. So, we flush the key from the D2D
+ // record cache now.
+ xD2DClearCache(&lower, qtype);
+ }
+}
+
+mDNSexport void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags)
+{
+ domainname lower;
+ mDNSu8 *rhs = NULL;
+ mDNSu8 *end = NULL;
+ D2DTransportType transportType, excludedTransport;
+ DomainnameToLower(resourceRecord->name, &lower);
+
+ LogInfo("external_start_advertising_service: %s", RRDisplayString(&mDNSStorage, resourceRecord));
+ // For SRV records, update packet filter if p2p interface already exists, otherwise,
+ // if will be updated when we get the KEV_DL_IF_ATTACHED event for the interface.
+ if (resourceRecord->rrtype == kDNSType_SRV)
+ mDNSUpdatePacketFilter(NULL);
+
+ rhs = DNSNameCompressionBuildLHS(&lower, resourceRecord->rrtype);
+ end = DNSNameCompressionBuildRHS(rhs, resourceRecord);
+ PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
+
+ transportType = xD2DInterfaceToTransportType(resourceRecord->InterfaceID, flags, & excludedTransport);
+ if (transportType == D2DTransportMax)
+ {
+ D2DTransportType i;
+ for (i = 0; i < D2DTransportMax; i++)
+ {
+ if (i == excludedTransport) continue;
+ if (D2DStartAdvertisingPairOnTransport) D2DStartAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
+ }
+ }
+ else
+ {
+ if (D2DStartAdvertisingPairOnTransport) D2DStartAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
+ }
+}
+
+mDNSexport void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags)
+{
+ domainname lower;
+ mDNSu8 *rhs = NULL;
+ mDNSu8 *end = NULL;
+ D2DTransportType transportType, excludedTransport;
+ DomainnameToLower(resourceRecord->name, &lower);
+
+ LogInfo("external_stop_advertising_service: %s", RRDisplayString(&mDNSStorage, resourceRecord));
+
+ // For SRV records, update packet filter to to remove this port from list
+ if (resourceRecord->rrtype == kDNSType_SRV)
+ mDNSUpdatePacketFilter(resourceRecord);
+
+ rhs = DNSNameCompressionBuildLHS(&lower, resourceRecord->rrtype);
+ end = DNSNameCompressionBuildRHS(rhs, resourceRecord);
+ PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
+
+ transportType = xD2DInterfaceToTransportType(resourceRecord->InterfaceID, flags, & excludedTransport);
+ if (transportType == D2DTransportMax)
+ {
+ D2DTransportType i;
+ for (i = 0; i < D2DTransportMax; i++)
+ {
+ if (i == excludedTransport) continue;
+ if (D2DStopAdvertisingPairOnTransport) D2DStopAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
+ }
+ }
+ else
+ {
+ if (D2DStopAdvertisingPairOnTransport) D2DStopAdvertisingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
+ }
+}
+
+mDNSexport void external_start_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags)
+{
+ domainname lower;
+ mDNSu8 *rhs = NULL;
+ mDNSu8 *end = NULL;
+ mDNSBool AWDL_used = false; // whether AWDL was used for this resolve
+ D2DTransportType transportType, excludedTransport;
+ DomainnameToLower(SkipLeadingLabels(fqdn, 1), &lower);
+
+ LogInfo("external_start_resolving_service: %##s", fqdn->c);
+ rhs = DNSNameCompressionBuildLHS(&lower, kDNSType_PTR);
+ end = putDomainNameAsLabels(&compression_base_msg, rhs, compression_limit, fqdn);
+ PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
+
+ transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
+ if (transportType == D2DTransportMax)
+ {
+ // Resolving over all the transports, except for excludedTransport if set.
+ D2DTransportType i;
+ for (i = 0; i < D2DTransportMax; i++)
+ {
+ if (i == excludedTransport) continue;
+ if (D2DStartResolvingPairOnTransport) D2DStartResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
+
+ if (i == D2DAWDLTransport)
+ AWDL_used = true;
+ }
+ }
+ else
+ {
+ // Resolving over one specific transport.
+ if (D2DStartResolvingPairOnTransport) D2DStartResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
+
+ if (transportType == D2DAWDLTransport)
+ AWDL_used = true;
+ }
+
+ // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
+ // We only want these records going to AWDL, so use AWDLInterfaceID as the
+ // interface and don't set any other flags.
+ if (AWDL_used && AWDLInterfaceID)
+ {
+ LogInfo("external_start_resolving_service: browse for TXT and SRV over AWDL");
+ external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_TXT, NULL);
+ external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, NULL);
+ }
+}
+
+mDNSexport void external_stop_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags)
+{
+ domainname lower;
+ mDNSu8 *rhs = NULL;
+ mDNSu8 *end = NULL;
+ mDNSBool AWDL_used = false; // whether AWDL was used for this resolve
+ D2DTransportType transportType, excludedTransport;
+ DomainnameToLower(SkipLeadingLabels(fqdn, 1), &lower);
+
+ LogInfo("external_stop_resolving_service: %##s", fqdn->c);
+ rhs = DNSNameCompressionBuildLHS(&lower, kDNSType_PTR);
+ end = putDomainNameAsLabels(&compression_base_msg, rhs, compression_limit, fqdn);
+ PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
+
+ transportType = xD2DInterfaceToTransportType(InterfaceID, flags, & excludedTransport);
+ if (transportType == D2DTransportMax)
+ {
+ D2DTransportType i;
+ for (i = 0; i < D2DTransportMax; i++)
+ {
+ if (i == excludedTransport) continue;
+ if (D2DStopResolvingPairOnTransport) D2DStopResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, i);
+
+ if (i == D2DAWDLTransport)
+ AWDL_used = true;
+ }
+ }
+ else
+ {
+ if (D2DStopResolvingPairOnTransport) D2DStopResolvingPairOnTransport(compression_lhs, rhs - compression_lhs, rhs, end - rhs, transportType);
+
+ if (transportType == D2DAWDLTransport)
+ AWDL_used = true;
+ }
+
+ // AWDL wants the SRV and TXT record queries communicated over the D2D interface.
+ // We only want these records going to AWDL, so use AWDLInterfaceID as the
+ // interface and don't set any other flags.
+ if (AWDL_used && AWDLInterfaceID)
+ {
+ LogInfo("external_stop_resolving_service: stop browse for TXT and SRV on AWDL");
+ external_stop_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_TXT, NULL);
+ external_stop_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, NULL);
+ }
+}
+
+#elif APPLE_OSX_mDNSResponder
+
+mDNSexport void external_start_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags) { (void)m; (void)type; (void)qtype; (void)flags;}
+mDNSexport void external_stop_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags) { (void)m; (void)type; (void)qtype; (void)flags;}
+mDNSexport void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;}
+mDNSexport void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;}
+mDNSexport void external_start_resolving_service(const domainname *const fqdn, DNSServiceFlags flags) { (void)fqdn; (void)flags;}
+mDNSexport void external_stop_resolving_service(const domainname *const fqdn, DNSServiceFlags flags) { (void)fqdn; (void)flags;}
+
+#endif // ! NO_D2D
+
+// ***************************************************************************
+// Functions
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Utility Functions
+#endif
+
+// We only attempt to send and receive multicast packets on interfaces that are
+// (a) flagged as multicast-capable
+// (b) *not* flagged as point-to-point (e.g. modem)
+// Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
+// to run up the user's bill sending multicast traffic over a link where there's only a single device at the
+// other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
+#define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
+
+mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both strings are UTF-8 text
+{
+ static int notifyCount = 0;
+ if (notifyCount) return;
+
+ // If we display our alert early in the boot process, then it vanishes once the desktop appears.
+ // To avoid this, we don't try to display alerts in the first three minutes after boot.
+ if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return;
+
+ // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
+ #if !ForceAlerts
+ {
+ // Determine if we're at Apple (17.*.*.*)
+ NetworkInterfaceInfoOSX *i;
+ for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
+ if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && i->ifinfo.ip.ip.v4.b[0] == 17)
+ break;
+ if (!i) return; // If not at Apple, don't show the alert
+ }
+ #endif
+
+ LogMsg("%s", title);
+ LogMsg("%s", msg);
+ // Display a notification to the user
+ notifyCount++;
+
+#ifndef NO_CFUSERNOTIFICATION
+ mDNSNotify(title, msg);
+#endif /* NO_CFUSERNOTIFICATION */
+}
+
+// Returns true if it is an AppleTV based hardware running iOS, false otherwise
+mDNSlocal mDNSBool IsAppleTV(void)
+{
+#if TARGET_OS_EMBEDDED
+ static mDNSBool sInitialized = mDNSfalse;
+ static mDNSBool sIsAppleTV = mDNSfalse;
+ CFStringRef deviceClass = NULL;
+
+ if(!sInitialized)
+ {
+ deviceClass = (CFStringRef) MGCopyAnswer(kMGQDeviceClass, NULL);
+ if(deviceClass)
+ {
+ if(CFEqual(deviceClass, kMGDeviceClassAppleTV))
+ sIsAppleTV = mDNStrue;
+ CFRelease(deviceClass);
+ }
+ sInitialized = mDNStrue;
+ }
+ return(sIsAppleTV);
+#else
+ return mDNSfalse;
+#endif // TARGET_OS_EMBEDDED
+}
+
+mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh)
+{
+ static struct ifaddrs *ifa = NULL;
+
+ if (refresh && ifa)
+ {
+ freeifaddrs(ifa);
+ ifa = NULL;
+ }
+
+ if (ifa == NULL)
+ getifaddrs(&ifa);
+ return ifa;
+}
+
+mDNSlocal void DynamicStoreWrite(int key, const char* subkey, uintptr_t value, signed long valueCnt)
+{
+ CFStringRef sckey = NULL;
+ Boolean release_sckey = FALSE;
+ CFDataRef bytes = NULL;
+ CFPropertyListRef plist = NULL;
+ SCDynamicStoreRef store = NULL;
+
+ switch ((enum mDNSDynamicStoreSetConfigKey)key)
+ {
+ case kmDNSMulticastConfig:
+ sckey = CFSTR("State:/Network/" kDNSServiceCompMulticastDNS);
+ break;
+ case kmDNSDynamicConfig:
+ sckey = CFSTR("State:/Network/DynamicDNS");
+ break;
+ case kmDNSPrivateConfig:
+ sckey = CFSTR("State:/Network/" kDNSServiceCompPrivateDNS);
+ break;
+ case kmDNSBackToMyMacConfig:
+ sckey = CFSTR("State:/Network/BackToMyMac");
+ break;
+ case kmDNSSleepProxyServersState:
+ {
+ CFMutableStringRef tmp = CFStringCreateMutable(kCFAllocatorDefault, 0);
+ CFStringAppend(tmp, CFSTR("State:/Network/Interface/"));
+ CFStringAppendCString(tmp, subkey, kCFStringEncodingUTF8);
+ CFStringAppend(tmp, CFSTR("/SleepProxyServers"));
+ sckey = CFStringCreateCopy(kCFAllocatorDefault, tmp);
+ release_sckey = TRUE;
+ CFRelease(tmp);
+ break;
+ }
+ case kmDNSDebugState:
+ sckey = CFSTR("State:/Network/mDNSResponder/DebugState");
+ break;
+ default:
+ LogMsg("unrecognized key %d", key);
+ goto fin;
+ }
+ if (NULL == (bytes = CFDataCreateWithBytesNoCopy(NULL, (void *)value,
+ valueCnt, kCFAllocatorNull)))
+ {
+ LogMsg("CFDataCreateWithBytesNoCopy of value failed");
+ goto fin;
+ }
+ if (NULL == (plist = CFPropertyListCreateFromXMLData(NULL, bytes,
+ kCFPropertyListImmutable, NULL)))
+ {
+ LogMsg("CFPropertyListCreateFromXMLData of bytes failed");
+ goto fin;
+ }
+ CFRelease(bytes);
+ bytes = NULL;
+ if (NULL == (store = SCDynamicStoreCreate(NULL,
+ CFSTR(kmDNSResponderServName), NULL, NULL)))
+ {
+ LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
+ goto fin;
+ }
+ SCDynamicStoreSetValue(store, sckey, plist);
+
+fin:
+ if (NULL != bytes)
+ CFRelease(bytes);
+ if (NULL != plist)
+ CFRelease(plist);
+ if (NULL != store)
+ CFRelease(store);
+ if (release_sckey && sckey)
+ CFRelease(sckey);
+}
+
+mDNSexport void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropertyListRef value)
+{
+ CFPropertyListRef valueCopy;
+ char *subkeyCopy = NULL;
+ if (!value)
+ return;
+
+ // We need to copy the key and value before we dispatch off the block below as the
+ // caller will free the memory once we return from this function.
+ valueCopy = CFPropertyListCreateDeepCopy(NULL, value, kCFPropertyListImmutable);
+ if (!valueCopy)
+ {
+ LogMsg("mDNSDynamicStoreSetConfig: ERROR valueCopy NULL");
+ return;
+ }
+ if (subkey)
+ {
+ int len = strlen(subkey);
+ subkeyCopy = mDNSPlatformMemAllocate(len + 1);
+ if (!subkeyCopy)
+ {
+ LogMsg("mDNSDynamicStoreSetConfig: ERROR subkeyCopy NULL");
+ return;
+ }
+ mDNSPlatformMemCopy(subkeyCopy, subkey, len);
+ subkeyCopy[len] = 0;
+ }
+
+ dispatch_async(DynamicStoreQueue, ^{
+ CFWriteStreamRef stream = NULL;
+ CFDataRef bytes = NULL;
+ CFStringRef error;
+ CFIndex ret;
+
+ if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(NULL, NULL)))
+ {
+ LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCreateWithAllocatedBuffers failed (Object creation failed)");
+ goto END;
+ }
+ CFWriteStreamOpen(stream);
+ ret = CFPropertyListWriteToStream(valueCopy, stream, kCFPropertyListBinaryFormat_v1_0, &error);
+ if (ret == 0)
+ {
+ LogMsg("mDNSDynamicStoreSetConfig : CFPropertyListWriteToStream failed (Could not write property list to stream)");
+ goto END;
+ }
+ if (NULL == (bytes = CFWriteStreamCopyProperty(stream, kCFStreamPropertyDataWritten)))
+ {
+ LogMsg("mDNSDynamicStoreSetConfig : CFWriteStreamCopyProperty failed (Object creation failed) ");
+ goto END;
+ }
+ CFWriteStreamClose(stream);
+ CFRelease(stream);
+ stream = NULL;
+ LogInfo("mDNSDynamicStoreSetConfig: key %d subkey %s", key, subkeyCopy);
+ DynamicStoreWrite(key, subkeyCopy ? subkeyCopy : "", (uintptr_t)CFDataGetBytePtr(bytes), CFDataGetLength(bytes));
+
+ END:
+ CFRelease(valueCopy);
+ if (NULL != stream)
+ {
+ CFWriteStreamClose(stream);
+ CFRelease(stream);
+ }
+ if (NULL != bytes)
+ CFRelease(bytes);
+ if (subkeyCopy)
+ mDNSPlatformMemFree(subkeyCopy);
+ });
+}
+
+// To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type
+mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, const char *ifname, int type)
+{
+ NetworkInterfaceInfoOSX *i;
+ for (i = m->p->InterfaceList; i; i = i->next)
+ if (i->Exists && !strcmp(i->ifinfo.ifname, ifname) &&
+ ((type == AF_UNSPEC ) ||
+ (type == AF_INET && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
+ (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i);
+ return(NULL);
+}
+
+#if TARGET_OS_EMBEDDED
+mDNSlocal SCPreferencesRef mDNSManagedPrefsGet(void)
+{
+ SCPreferencesRef smDNSManagedPrefs = NULL;
+ smDNSManagedPrefs = SCPreferencesCreate(kCFAllocatorDefault, CFSTR("mDNSManagedPrefs"), kmDNSResponderManagedPrefsID);
+
+ return (smDNSManagedPrefs);
+}
+
+mDNSlocal mDNSBool GetmDNSManagedPrefKeyVal(SCPreferencesRef prefs, CFStringRef key)
+{
+ mDNSBool val = mDNSfalse;
+ CFBooleanRef val_cf = NULL;
+
+ if (prefs != NULL)
+ {
+ val_cf = SCPreferencesGetValue(prefs, key);
+ if (isA_CFBoolean(val_cf) != NULL)
+ val = CFBooleanGetValue(val_cf); //When mDNSResponder-Debug-profile is Installed
+ else
+ val = mDNSfalse; //When mDNSResponder-Debug-profile is Uninstalled
+ }
+ else
+ {
+ LogMsg("GetmDNSManagedPrefKeyVal: mDNSManagedPrefs are NULL!");
+ val = mDNSfalse;
+ }
+ if (val_cf)
+ CFRelease(val_cf);
+ return (val);
+}
+
+mDNSexport mDNSBool GetmDNSManagedPref(CFStringRef key)
+{
+ SCPreferencesRef managed = NULL;
+ mDNSBool ret_value;
+
+ managed = mDNSManagedPrefsGet();
+ ret_value = GetmDNSManagedPrefKeyVal(managed, key);
+
+ if (managed)
+ CFRelease(managed);
+ return (ret_value);
+}
+#endif //TARGET_OS_EMBEDDED
+
+mDNSlocal int myIfIndexToName(u_short ifindex, char *name)
+{
+ struct ifaddrs *ifa;
+ for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
+ if (ifa->ifa_addr->sa_family == AF_LINK)
+ if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == ifindex)
+ { strlcpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
+ return -1;
+}
+
+mDNSexport NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(const mDNS *const m, mDNSInterfaceID ifindex)
+{
+ mDNSu32 scope_id = (mDNSu32)(uintptr_t)ifindex;
+ NetworkInterfaceInfoOSX *i;
+
+ // Don't get tricked by inactive interfaces
+ for (i = m->p->InterfaceList; i; i = i->next)
+ if (i->Registered && i->scope_id == scope_id) return(i);
+
+ return mDNSNULL;
+}
+
+mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex)
+{
+ if (ifindex == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
+ if (ifindex == kDNSServiceInterfaceIndexP2P ) return(mDNSInterface_P2P);
+ if (ifindex == kDNSServiceInterfaceIndexAny ) return(mDNSNULL);
+
+ NetworkInterfaceInfoOSX* ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
+ if (!ifi)
+ {
+ // Not found. Make sure our interface list is up to date, then try again.
+ LogInfo("mDNSPlatformInterfaceIDfromInterfaceIndex: InterfaceID for interface index %d not found; Updating interface list", ifindex);
+ mDNSMacOSXNetworkChanged(m);
+ ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
+ }
+
+ if (!ifi) return(mDNSNULL);
+
+ return(ifi->ifinfo.InterfaceID);
+}
+
+
+mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange)
+{
+ NetworkInterfaceInfoOSX *i;
+ if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
+ if (id == mDNSInterface_P2P ) return(kDNSServiceInterfaceIndexP2P);
+ if (id == mDNSInterface_Any ) return(0);
+
+ mDNSu32 scope_id = (mDNSu32)(uintptr_t)id;
+
+ // Don't use i->Registered here, because we DO want to find inactive interfaces, which have no Registered set
+ for (i = m->p->InterfaceList; i; i = i->next)
+ if (i->scope_id == scope_id) return(i->scope_id);
+
+ // If we are supposed to suppress network change, return "id" back
+ if (suppressNetworkChange) return scope_id;
+
+ // Not found. Make sure our interface list is up to date, then try again.
+ LogInfo("Interface index for InterfaceID %p not found; Updating interface list", id);
+ mDNSMacOSXNetworkChanged(m);
+ for (i = m->p->InterfaceList; i; i = i->next)
+ if (i->scope_id == scope_id) return(i->scope_id);
+
+ return(0);
+}
+
+#if APPLE_OSX_mDNSResponder
+mDNSexport void mDNSASLLog(uuid_t *uuid, const char *subdomain, const char *result, const char *signature, const char *fmt, ...)
+{
+ if (iOSVers)
+ return; // No ASL on iOS
+
+ static char buffer[512];
+ aslmsg asl_msg = asl_new(ASL_TYPE_MSG);
+
+ if (!asl_msg) { LogMsg("mDNSASLLog: asl_new failed"); return; }
+ if (uuid)
+ {
+ char uuidStr[37];
+ uuid_unparse(*uuid, uuidStr);
+ asl_set (asl_msg, "com.apple.message.uuid", uuidStr);
+ }
+
+ static char domainBase[] = "com.apple.mDNSResponder.%s";
+ mDNS_snprintf (buffer, sizeof(buffer), domainBase, subdomain);
+ asl_set (asl_msg, "com.apple.message.domain", buffer);
+
+ if (result) asl_set(asl_msg, "com.apple.message.result", result);
+ if (signature) asl_set(asl_msg, "com.apple.message.signature", signature);
+
+ va_list ptr;
+ va_start(ptr,fmt);
+ mDNS_vsnprintf(buffer, sizeof(buffer), fmt, ptr);
+ va_end(ptr);
+
+ int old_filter = asl_set_filter(NULL,ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
+ asl_log(NULL, asl_msg, ASL_LEVEL_DEBUG, "%s", buffer);
+ asl_set_filter(NULL, old_filter);
+ asl_free(asl_msg);
+}
+
+
+mDNSlocal void mDNSLogDNSSECStatistics(mDNS *const m)
+{
+ char buffer[16];
+
+ aslmsg aslmsg = asl_new(ASL_TYPE_MSG);
+
+ // If we failed to allocate an aslmsg structure, keep accumulating
+ // the statistics and try again at the next log interval.
+ if (!aslmsg)
+ {
+ LogMsg("mDNSLogDNSSECStatistics: asl_new() failed!");
+ return;
+ }
+
+ asl_set(aslmsg,"com.apple.message.domain", "com.apple.mDNSResponder.DNSSECstatistics");
+
+ if (m->rrcache_totalused_unicast)
+ {
+ mDNS_snprintf(buffer, sizeof(buffer), "%u", (mDNSu32) ((unsigned long)(m->DNSSECStats.TotalMemUsed * 100))/m->rrcache_totalused_unicast);
+ }
+ else
+ {
+ LogMsg("mDNSLogDNSSECStatistics: unicast is zero");
+ buffer[0] = 0;
+ }
+ asl_set(aslmsg,"com.apple.message.MemUsage", buffer);
+
+ mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency0);
+ asl_set(aslmsg,"com.apple.message.Latency0", buffer);
+ mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency10);
+ asl_set(aslmsg,"com.apple.message.Latency10", buffer);
+ mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency20);
+ asl_set(aslmsg,"com.apple.message.Latency20", buffer);
+ mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency50);
+ asl_set(aslmsg,"com.apple.message.Latency50", buffer);
+ mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.Latency100);
+ asl_set(aslmsg,"com.apple.message.Latency100", buffer);
+
+ mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets0);
+ asl_set(aslmsg,"com.apple.message.ExtraPackets0", buffer);
+ mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets3);
+ asl_set(aslmsg,"com.apple.message.ExtraPackets3", buffer);
+ mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets7);
+ asl_set(aslmsg,"com.apple.message.ExtraPackets7", buffer);
+ mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.ExtraPackets10);
+ asl_set(aslmsg,"com.apple.message.ExtraPackets10", buffer);
+
+ // Ignore IndeterminateStatus as we don't log them
+ mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.SecureStatus);
+ asl_set(aslmsg,"com.apple.message.SecureStatus", buffer);
+ mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.InsecureStatus);
+ asl_set(aslmsg,"com.apple.message.InsecureStatus", buffer);
+ mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.BogusStatus);
+ asl_set(aslmsg,"com.apple.message.BogusStatus", buffer);
+ mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.NoResponseStatus);
+ asl_set(aslmsg,"com.apple.message.NoResponseStatus", buffer);
+
+ mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.NumProbesSent);
+ asl_set(aslmsg,"com.apple.message.NumProbesSent", buffer);
+ mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.MsgSize0);
+ asl_set(aslmsg,"com.apple.message.MsgSize0", buffer);
+ mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.MsgSize1);
+ asl_set(aslmsg,"com.apple.message.MsgSize1", buffer);
+ mDNS_snprintf(buffer, sizeof(buffer), "%u", m->DNSSECStats.MsgSize2);
+ asl_set(aslmsg,"com.apple.message.MsgSize2", buffer);
+
+ asl_log(NULL, aslmsg, ASL_LEVEL_NOTICE, "");
+ asl_free(aslmsg);
+}
+
+// Calculate packets per hour given total packet count and interval in seconds.
+// Cast one term of multiplication to (long) to use 64-bit arithmetic
+// and avoid a potential 32-bit overflow prior to the division.
+#define ONE_HOUR 3600
+#define PACKET_RATE(PACKETS, INTERVAL) (int)(((long) (PACKETS) * ONE_HOUR)/(INTERVAL))
+
+// Put packet rate data in discrete buckets.
+mDNSlocal int mDNSBucketData(int inputData, int interval)
+{
+ if (!interval)
+ {
+ LogMsg("mDNSBucketData: interval is zero!");
+ return 0;
+ }
+
+ int ratePerHour = PACKET_RATE(inputData, interval);
+ int bucket;
+
+ if (ratePerHour == 0)
+ bucket = 0;
+ else if (ratePerHour <= 10)
+ bucket = 10;
+ else if (ratePerHour <= 100)
+ bucket = 100;
+ else if (ratePerHour <= 1000)
+ bucket = 1000;
+ else if (ratePerHour <= 5000)
+ bucket = 5000;
+ else if (ratePerHour <= 10000)
+ bucket = 10000;
+ else if (ratePerHour <= 50000)
+ bucket = 50000;
+ else if (ratePerHour <= 100000)
+ bucket = 100000;
+ else if (ratePerHour <= 250000)
+ bucket = 250000;
+ else if (ratePerHour <= 500000)
+ bucket = 500000;
+ else
+ bucket = 1000000;
+
+ return bucket;
+}
+
+mDNSlocal void mDNSLogBonjourStatistics(mDNS *const m)
+{
+ static mDNSs32 last_PktNum, last_MPktNum;
+ static mDNSs32 last_UnicastPacketsSent, last_MulticastPacketsSent;
+ static mDNSs32 last_RemoteSubnet;
+
+ mDNSs32 interval;
+ char buffer[16];
+ mDNSs32 inMulticast = m->MPktNum - last_MPktNum;
+ mDNSs32 inUnicast = m->PktNum - last_PktNum - inMulticast;
+ mDNSs32 outUnicast = m->UnicastPacketsSent - last_UnicastPacketsSent;
+ mDNSs32 outMulticast = m->MulticastPacketsSent - last_MulticastPacketsSent;
+ mDNSs32 remoteSubnet = m->RemoteSubnet - last_RemoteSubnet;
+
+
+ // save starting values for new interval
+ last_PktNum = m->PktNum;
+ last_MPktNum = m->MPktNum;
+ last_UnicastPacketsSent = m->UnicastPacketsSent;
+ last_MulticastPacketsSent = m->MulticastPacketsSent;
+ last_RemoteSubnet = m->RemoteSubnet;
+
+ // Need a non-zero active time interval.
+ if (!m->ActiveStatTime)
+ return;
+
+ // Round interval time to nearest hour boundary. Less then 30 minutes rounds to zero.
+ interval = (m->ActiveStatTime + ONE_HOUR/2)/ONE_HOUR;
+
+ // Use a minimum of 30 minutes of awake time to calculate average packet rates.
+ // The rounded awake interval should not be greater than the rounded reporting
+ // interval.
+ if ((interval == 0) || (interval > (kDefaultNextStatsticsLogTime + ONE_HOUR/2)/ONE_HOUR))
+ return;
+
+ aslmsg aslmsg = asl_new(ASL_TYPE_MSG);
+
+ if (!aslmsg)
+ {
+ LogMsg("mDNSLogBonjourStatistics: asl_new() failed!");
+ return;
+ }
+ // log in MessageTracer format
+ asl_set(aslmsg,"com.apple.message.domain", "com.apple.mDNSResponder.statistics");
+
+ snprintf(buffer, sizeof(buffer), "%d", interval);
+ asl_set(aslmsg,"com.apple.message.interval", buffer);
+
+ // log the packet rates as packets per hour
+ snprintf(buffer, sizeof(buffer), "%d",
+ mDNSBucketData(inUnicast, m->ActiveStatTime));
+ asl_set(aslmsg,"com.apple.message.UnicastIn", buffer);
+
+ snprintf(buffer, sizeof(buffer), "%d",
+ mDNSBucketData(inMulticast, m->ActiveStatTime));
+ asl_set(aslmsg,"com.apple.message.MulticastIn", buffer);
+
+ snprintf(buffer, sizeof(buffer), "%d",
+ mDNSBucketData(outUnicast, m->ActiveStatTime));
+ asl_set(aslmsg,"com.apple.message.UnicastOut", buffer);
+
+ snprintf(buffer, sizeof(buffer), "%d",
+ mDNSBucketData(outMulticast, m->ActiveStatTime));
+ asl_set(aslmsg,"com.apple.message.MulticastOut", buffer);
+
+ snprintf(buffer, sizeof(buffer), "%d",
+ mDNSBucketData(remoteSubnet, m->ActiveStatTime));
+ asl_set(aslmsg,"com.apple.message.RemoteSubnet", buffer);
+
+ asl_log(NULL, aslmsg, ASL_LEVEL_NOTICE, "");
+
+ asl_free(aslmsg);
+}
+
+// Log multicast and unicast traffic statistics to MessageTracer on OSX
+mDNSexport void mDNSLogStatistics(mDNS *const m)
+{
+ // MessageTracer only available on OSX
+ if (iOSVers)
+ return;
+
+ mDNSs32 currentUTC = mDNSPlatformUTC();
+
+ // log runtime statistics
+ if ((currentUTC - m->NextStatLogTime) >= 0)
+ {
+ m->NextStatLogTime = currentUTC + kDefaultNextStatsticsLogTime;
+ // If StatStartTime is zero, it hasn't been reinitialized yet
+ // in the wakeup code path.
+ if (m->StatStartTime)
+ {
+ m->ActiveStatTime += currentUTC - m->StatStartTime;
+ }
+
+ // Only log statistics if we have recorded some active time during
+ // this statistics interval.
+ if (m->ActiveStatTime)
+ {
+ mDNSLogBonjourStatistics(m);
+ mDNSLogDNSSECStatistics(m);
+ }
+
+ // Start a new statistics gathering interval.
+ m->StatStartTime = currentUTC;
+ m->ActiveStatTime = 0;
+ }
+}
+
+#endif // APPLE_OSX_mDNSResponder
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - UDP & TCP send & receive
+#endif
+
+mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
+{
+ mDNSBool result = mDNSfalse;
+ SCNetworkConnectionFlags flags;
+ CFDataRef remote_addr;
+ CFMutableDictionaryRef options;
+ SCNetworkReachabilityRef ReachRef = NULL;
+
+ options = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ remote_addr = CFDataCreate(NULL, (const UInt8 *)addr, addr->sa_len);
+ CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, remote_addr);
+ CFDictionarySetValue(options, kSCNetworkReachabilityOptionServerBypass, kCFBooleanTrue);
+ ReachRef = SCNetworkReachabilityCreateWithOptions(kCFAllocatorDefault, options);
+ CFRelease(options);
+ CFRelease(remote_addr);
+
+ if (!ReachRef)
+ {
+ LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithOptions");
+ goto end;
+ }
+ if (!SCNetworkReachabilityGetFlags(ReachRef, &flags))
+ {
+ LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags");
+ goto end;
+ }
+ result = flags & kSCNetworkFlagsConnectionRequired;
+
+end:
+ if (ReachRef)
+ CFRelease(ReachRef);
+ return result;
+}
+
+// Set traffic class for socket
+mDNSlocal void setTrafficClass(int socketfd, mDNSBool useBackgroundTrafficClass)
+{
+ int traffic_class;
+
+ if (useBackgroundTrafficClass)
+ traffic_class = SO_TC_BK_SYS;
+ else
+ traffic_class = SO_TC_CTL;
+
+ (void) setsockopt(socketfd, SOL_SOCKET, SO_TRAFFIC_CLASS, (void *)&traffic_class, sizeof(traffic_class));
+}
+
+mDNSexport void mDNSPlatformSetDelegatePID(UDPSocket *src, const mDNSAddr *dst, DNSQuestion *q)
+{
+ if (src)
+ {
+ int s;
+
+ if (dst->type == mDNSAddrType_IPv4)
+ {
+ s = src->ss.sktv4;
+ }
+ else
+ {
+ s = src->ss.sktv6;
+ }
+
+ if (q->pid)
+ {
+ if (setsockopt(s, SOL_SOCKET, SO_DELEGATED, &q->pid, sizeof(q->pid)) == -1)
+ {
+ LogInfo("mDNSPlatformSetDelegatePID: Delegate PID failed %s for PID %d", strerror(errno), q->pid);
+ }
+ }
+ else
+ {
+ if (setsockopt(s, SOL_SOCKET, SO_DELEGATED_UUID, &q->uuid, sizeof(q->uuid)) == -1)
+ {
+ LogInfo("mDNSPlatformSetDelegatePID: Delegate UUID failed %s", strerror(errno));
+ }
+ }
+ }
+}
+
+// Note: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
+// Note: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
+// OR send via our primary v4 unicast socket
+// UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket
+mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
+ mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
+ mDNSIPPort dstPort, mDNSBool useBackgroundTrafficClass)
+{
+ NetworkInterfaceInfoOSX *info = mDNSNULL;
+ struct sockaddr_storage to;
+ int s = -1, err;
+ mStatus result = mStatus_NoError;
+
+ if (InterfaceID)
+ {
+ info = IfindexToInterfaceInfoOSX(m, InterfaceID);
+ if (info == NULL)
+ {
+ // We may not have registered interfaces with the "core" as we may not have
+ // seen any interface notifications yet. This typically happens during wakeup
+ // where we might try to send DNS requests (non-SuppressUnusable questions internal
+ // to mDNSResponder) before we receive network notifications.
+ LogInfo("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
+ return mStatus_BadParamErr;
+ }
+ }
+
+ char *ifa_name = InterfaceID ? info->ifinfo.ifname : "unicast";
+
+ if (dst->type == mDNSAddrType_IPv4)
+ {
+ struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
+ sin_to->sin_len = sizeof(*sin_to);
+ sin_to->sin_family = AF_INET;
+ sin_to->sin_port = dstPort.NotAnInteger;
+ sin_to->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
+ s = (src ? src->ss : m->p->permanentsockets).sktv4;
+
+ if (info) // Specify outgoing interface
+ {
+ if (!mDNSAddrIsDNSMulticast(dst))
+ {
+ #ifdef IP_BOUND_IF
+ if (info->scope_id == 0)
+ LogInfo("IP_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info, ifa_name);
+ else
+ setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
+ #else
+ {
+ static int displayed = 0;
+ if (displayed < 1000)
+ {
+ displayed++;
+ LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets");
+ }
+ }
+ #endif
+ }
+ else
+ #ifdef IP_MULTICAST_IFINDEX
+ {
+ err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IFINDEX, &info->scope_id, sizeof(info->scope_id));
+ // We get an error when we compile on a machine that supports this option and run the binary on
+ // a different machine that does not support it
+ if (err < 0)
+ {
+ if (errno != ENOPROTOOPT) LogInfo("mDNSPlatformSendUDP: setsockopt: IP_MUTLTICAST_IFINDEX returned %d", errno);
+ err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
+ if (err < 0 && !m->p->NetworkChanged)
+ LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
+ }
+ }
+ #else
+ {
+ err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
+ if (err < 0 && !m->p->NetworkChanged)
+ LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
+
+ }
+ #endif
+ }
+ }
+
+ else if (dst->type == mDNSAddrType_IPv6)
+ {
+ struct sockaddr_in6 *sin6_to = (struct sockaddr_in6*)&to;
+ sin6_to->sin6_len = sizeof(*sin6_to);
+ sin6_to->sin6_family = AF_INET6;
+ sin6_to->sin6_port = dstPort.NotAnInteger;
+ sin6_to->sin6_flowinfo = 0;
+ sin6_to->sin6_addr = *(struct in6_addr*)&dst->ip.v6;
+ sin6_to->sin6_scope_id = info ? info->scope_id : 0;
+ s = (src ? src->ss : m->p->permanentsockets).sktv6;
+ if (info && mDNSAddrIsDNSMulticast(dst)) // Specify outgoing interface
+ {
+ err = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &info->scope_id, sizeof(info->scope_id));
+ if (err < 0)
+ {
+ char name[IFNAMSIZ];
+ if (if_indextoname(info->scope_id, name) != NULL)
+ LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err, errno, strerror(errno));
+ else
+ LogInfo("setsockopt - IPV6_MUTLICAST_IF scopeid %d, not a valid interface", info->scope_id);
+ }
+ }
+ }
+
+ else
+ {
+ LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
+#if ForceAlerts
+ *(long*)0 = 0;
+#endif
+ return mStatus_BadParamErr;
+ }
+
+ if (s >= 0)
+ verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
+ InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
+ else
+ verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
+ InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort));
+
+ // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
+ // If we don't have the corresponding type of socket available, then return mStatus_Invalid
+ if (s < 0) return(mStatus_Invalid);
+
+ // switch to background traffic class for this message if requested
+ if (useBackgroundTrafficClass)
+ setTrafficClass(s, useBackgroundTrafficClass);
+
+ err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
+
+ // set traffic class back to default value
+ if (useBackgroundTrafficClass)
+ setTrafficClass(s, mDNSfalse);
+
+ if (err < 0)
+ {
+ static int MessageCount = 0;
+ LogInfo("mDNSPlatformSendUDP -> sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
+ s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
+ if (!mDNSAddressIsAllDNSLinkGroup(dst))
+ if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
+ // Don't report EHOSTUNREACH in the first three minutes after boot
+ // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
+ // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
+ if (errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(mStatus_TransientErr);
+ // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
+ if (errno == EADDRNOTAVAIL && m->p->NetworkChanged) return(mStatus_TransientErr);
+ if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
+ LogInfo("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
+ s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
+ else
+ {
+ MessageCount++;
+ if (MessageCount < 50) // Cap and ensure NO spamming of LogMsgs
+ LogMsg("mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu MessageCount is %d",
+ s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow), MessageCount);
+ else // If logging is enabled, remove the cap and log aggressively
+ LogInfo("mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu MessageCount is %d",
+ s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow), MessageCount);
+ }
+
+ result = mStatus_UnknownErr;
+ }
+
+#ifdef IP_BOUND_IF
+ if (dst->type == mDNSAddrType_IPv4 && info && !mDNSAddrIsDNSMulticast(dst))
+ {
+ static const mDNSu32 ifindex = 0;
+ setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex));
+ }
+#endif
+
+ return(result);
+}
+
+mDNSexport ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
+ struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char ifname[IF_NAMESIZE], mDNSu8 *ttl)
+{
+ static unsigned int numLogMessages = 0;
+ struct iovec databuffers = { (char *)buffer, max };
+ struct msghdr msg;
+ ssize_t n;
+ struct cmsghdr *cmPtr;
+ char ancillary[1024];
+
+ *ttl = 255; // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
+
+ // Set up the message
+ msg.msg_name = (caddr_t)from;
+ msg.msg_namelen = *fromlen;
+ msg.msg_iov = &databuffers;
+ msg.msg_iovlen = 1;
+ msg.msg_control = (caddr_t)&ancillary;
+ msg.msg_controllen = sizeof(ancillary);
+ msg.msg_flags = 0;
+
+ // Receive the data
+ n = recvmsg(s, &msg, 0);
+ if (n<0)
+ {
+ if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
+ return(-1);
+ }
+ if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
+ {
+ if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu, errno %d",
+ s, n, msg.msg_controllen, sizeof(struct cmsghdr), errno);
+ return(-1);
+ }
+ if (msg.msg_flags & MSG_CTRUNC)
+ {
+ if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
+ return(-1);
+ }
+
+ *fromlen = msg.msg_namelen;
+
+ // Parse each option out of the ancillary data.
+ for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
+ {
+ // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
+ if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
+ {
+ dstaddr->type = mDNSAddrType_IPv4;
+ dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr);
+ //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
+ }
+ if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
+ {
+ struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
+ if (sdl->sdl_nlen < IF_NAMESIZE)
+ {
+ mDNSPlatformMemCopy(ifname, sdl->sdl_data, sdl->sdl_nlen);
+ ifname[sdl->sdl_nlen] = 0;
+ // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
+ }
+ }
+ if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL)
+ *ttl = *(u_char*)CMSG_DATA(cmPtr);
+ if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
+ {
+ struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr);
+ dstaddr->type = mDNSAddrType_IPv6;
+ dstaddr->ip.v6 = *(mDNSv6Addr*)&ip6_info->ipi6_addr;
+ myIfIndexToName(ip6_info->ipi6_ifindex, ifname);
+ }
+ if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
+ *ttl = *(int*)CMSG_DATA(cmPtr);
+ }
+
+ return(n);
+}
+
+mDNSlocal mDNSInterfaceID FindMyInterface(mDNS *const m, const mDNSAddr *addr)
+{
+ NetworkInterfaceInfo *intf;
+
+ if (addr->type == mDNSAddrType_IPv4)
+ {
+ for (intf = m->HostInterfaces; intf; intf = intf->next)
+ {
+ if (intf->ip.type == addr->type && intf->McastTxRx)
+ {
+ if ((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) == 0)
+ {
+ return(intf->InterfaceID);
+ }
+ }
+ }
+ }
+
+ if (addr->type == mDNSAddrType_IPv6)
+ {
+ for (intf = m->HostInterfaces; intf; intf = intf->next)
+ {
+ if (intf->ip.type == addr->type && intf->McastTxRx)
+ {
+ if (((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) == 0) &&
+ ((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) == 0) &&
+ ((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) == 0) &&
+ (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) == 0)))
+ {
+ return(intf->InterfaceID);
+ }
+ }
+ }
+ }
+ return(mDNSInterface_Any);
+}
+
+mDNSexport mDNSBool mDNSPlatformPeekUDP(mDNS *const m, UDPSocket *src)
+{
+ // We should have a DNSMessage header followed by the question and an answer
+ // which also includes a CNAME (that's when this function is called). To keep it
+ // simple, we expect at least the size of DNSMessage header(12) and size of "A"
+ // record (14 bytes).
+ char buffer[26];
+ int ret;
+
+ (void) m;
+
+ if (!src)
+ return mDNSfalse;
+
+ ret = recv(src->ss.sktv4, buffer, sizeof(buffer), MSG_PEEK);
+ if (ret > 0)
+ return mDNStrue;
+ else
+ return mDNSfalse;
+}
+
+mDNSexport void myKQSocketCallBack(int s1, short filter, void *context)
+{
+ KQSocketSet *const ss = (KQSocketSet *)context;
+ mDNS *const m = ss->m;
+ int err = 0, count = 0, closed = 0;
+
+ if (filter != EVFILT_READ)
+ LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
+
+ if (s1 != ss->sktv4 && s1 != ss->sktv6)
+ {
+ LogMsg("myKQSocketCallBack: native socket %d", s1);
+ LogMsg("myKQSocketCallBack: sktv4 %d sktv6 %d", ss->sktv4, ss->sktv6);
+ }
+
+ while (!closed)
+ {
+ mDNSAddr senderAddr, destAddr;
+ mDNSIPPort senderPort;
+ struct sockaddr_storage from;
+ size_t fromlen = sizeof(from);
+ char packetifname[IF_NAMESIZE] = "";
+ mDNSu8 ttl;
+ err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl);
+ if (err < 0) break;
+
+ count++;
+ if (from.ss_family == AF_INET)
+ {
+ struct sockaddr_in *s = (struct sockaddr_in*)&from;
+ senderAddr.type = mDNSAddrType_IPv4;
+ senderAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr;
+ senderPort.NotAnInteger = s->sin_port;
+ //LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
+ }
+ else if (from.ss_family == AF_INET6)
+ {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&from;
+ senderAddr.type = mDNSAddrType_IPv6;
+ senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
+ senderPort.NotAnInteger = sin6->sin6_port;
+ //LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
+ }
+ else
+ {
+ LogMsg("myKQSocketCallBack from is unknown address family %d", from.ss_family);
+ return;
+ }
+
+ // Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
+ mDNSInterfaceID InterfaceID = mDNSNULL;
+ NetworkInterfaceInfoOSX *intf = m->p->InterfaceList;
+ while (intf)
+ {
+ if (intf->Exists && !strcmp(intf->ifinfo.ifname, packetifname))
+ break;
+ intf = intf->next;
+ }
+
+ // When going to sleep we deregister all our interfaces, but if the machine
+ // takes a few seconds to sleep we may continue to receive multicasts
+ // during that time, which would confuse mDNSCoreReceive, because as far
+ // as it's concerned, we should have no active interfaces any more.
+ // Hence we ignore multicasts for which we can find no matching InterfaceID.
+ if (intf)
+ InterfaceID = intf->ifinfo.InterfaceID;
+ else if (mDNSAddrIsDNSMulticast(&destAddr))
+ continue;
+
+ if (!InterfaceID)
+ {
+ InterfaceID = FindMyInterface(m, &destAddr);
+ }
+
+// LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
+// &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
+
+ // mDNSCoreReceive may close the socket we're reading from. We must break out of our
+ // loop when that happens, or we may try to read from an invalid FD. We do this by
+ // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us
+ // if it closes the socketset.
+ ss->closeFlag = &closed;
+
+ if (ss->proxy)
+ {
+ m->p->UDPProxyCallback(m, &m->p->UDPProxy, (unsigned char *)&m->imsg, (unsigned char*)&m->imsg + err, &senderAddr,
+ senderPort, &destAddr, ss->port, InterfaceID, NULL);
+ }
+ else
+ {
+ mDNSCoreReceive(m, &m->imsg, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, ss->port, InterfaceID);
+ }
+
+ // if we didn't close, we can safely dereference the socketset, and should to
+ // reset the closeFlag, since it points to something on the stack
+ if (!closed) ss->closeFlag = mDNSNULL;
+ }
+
+ if (err < 0 && (errno != EWOULDBLOCK || count == 0))
+ {
+ // Something is busted here.
+ // kqueue says there is a packet, but myrecvfrom says there is not.
+ // Try calling select() to get another opinion.
+ // Find out about other socket parameter that can help understand why select() says the socket is ready for read
+ // All of this is racy, as data may have arrived after the call to select()
+ static unsigned int numLogMessages = 0;
+ int save_errno = errno;
+ int so_error = -1;
+ int so_nread = -1;
+ int fionread = -1;
+ socklen_t solen = sizeof(int);
+ fd_set readfds;
+ struct timeval timeout;
+ int selectresult;
+ FD_ZERO(&readfds);
+ FD_SET(s1, &readfds);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
+ if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
+ LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno);
+ if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
+ LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno);
+ if (ioctl(s1, FIONREAD, &fionread) == -1)
+ LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno);
+ if (numLogMessages++ < 100)
+ LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
+ s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
+ if (numLogMessages > 5)
+ NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
+ "Congratulations, you've reproduced an elusive bug.\r"
+ "Please contact the current assignee of <rdar://problem/3375328>.\r"
+ "Alternatively, you can send email to radar-3387020 at group.apple.com. (Note number is different.)\r"
+ "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
+
+ sleep(1); // After logging this error, rate limit so we don't flood syslog
+ }
+}
+
+mDNSlocal void doTcpSocketCallback(TCPSocket *sock)
+{
+ mDNSBool c = !sock->connected;
+ sock->connected = mDNStrue;
+ sock->callback(sock, sock->context, c, sock->err);
+ // Note: the callback may call CloseConnection here, which frees the context structure!
+}
+
+#ifndef NO_SECURITYFRAMEWORK
+
+mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength)
+{
+ int ret = send(((TCPSocket *)connection)->fd, data, *dataLength, 0);
+ if (ret >= 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
+ if (ret >= 0) { *dataLength = ret; return(noErr); }
+ *dataLength = 0;
+ if (errno == EAGAIN ) return(errSSLWouldBlock);
+ if (errno == ENOENT ) return(errSSLClosedGraceful);
+ if (errno == EPIPE || errno == ECONNRESET) return(errSSLClosedAbort);
+ LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket *)connection)->fd, errno, strerror(errno));
+ return(errSSLClosedAbort);
+}
+
+mDNSlocal OSStatus tlsReadSock(SSLConnectionRef connection, void *data, size_t *dataLength)
+{
+ int ret = recv(((TCPSocket *)connection)->fd, data, *dataLength, 0);
+ if (ret > 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
+ if (ret > 0) { *dataLength = ret; return(noErr); }
+ *dataLength = 0;
+ if (ret == 0 || errno == ENOENT ) return(errSSLClosedGraceful);
+ if ( errno == EAGAIN ) return(errSSLWouldBlock);
+ if ( errno == ECONNRESET) return(errSSLClosedAbort);
+ LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno, strerror(errno));
+ return(errSSLClosedAbort);
+}
+
+mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, SSLProtocolSide pside, SSLConnectionType ctype)
+{
+ char domname_cstr[MAX_ESCAPED_DOMAIN_NAME];
+
+ sock->tlsContext = SSLCreateContext(kCFAllocatorDefault, pside, ctype);
+ if (!sock->tlsContext)
+ {
+ LogMsg("ERROR: tlsSetupSock: SSLCreateContext failed");
+ return(mStatus_UnknownErr);
+ }
+
+ mStatus err = SSLSetIOFuncs(sock->tlsContext, tlsReadSock, tlsWriteSock);
+ if (err)
+ {
+ LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err);
+ goto fail;
+ }
+
+ err = SSLSetConnection(sock->tlsContext, (SSLConnectionRef) sock);
+ if (err)
+ {
+ LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err);
+ goto fail;
+ }
+
+ // Instead of listing all the acceptable ciphers, we just disable the bad ciphers. It does not disable
+ // all the bad ciphers like RC4_MD5, but it assumes that the servers don't offer them.
+ err = SSLSetAllowAnonymousCiphers(sock->tlsContext, 0);
+ if (err)
+ {
+ LogMsg("ERROR: tlsSetupSock: SSLSetAllowAnonymousCiphers failed with error code: %d", err);
+ goto fail;
+ }
+
+ // We already checked for NULL in hostname and this should never happen. Hence, returning -1
+ // (error not in OSStatus space) is okay.
+ if (!sock->hostname.c[0])
+ {
+ LogMsg("ERROR: tlsSetupSock: hostname NULL");
+ err = -1;
+ goto fail;
+ }
+
+ ConvertDomainNameToCString(&sock->hostname, domname_cstr);
+ err = SSLSetPeerDomainName(sock->tlsContext, domname_cstr, strlen(domname_cstr));
+ if (err)
+ {
+ LogMsg("ERROR: tlsSetupSock: SSLSetPeerDomainname: %s failed with error code: %d", domname_cstr, err);
+ goto fail;
+ }
+
+ return(err);
+
+fail:
+ if (sock->tlsContext)
+ CFRelease(sock->tlsContext);
+ return(err);
+}
+
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+mDNSlocal void doSSLHandshake(TCPSocket *sock)
+{
+ mStatus err = SSLHandshake(sock->tlsContext);
+
+ //Can't have multiple threads in mDNS core. When MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM is
+ //defined, KQueueLock is a noop. Hence we need to serialize here
+ //
+ //NOTE: We just can't serialize doTcpSocketCallback alone on the main queue.
+ //We need the rest of the logic also. Otherwise, we can enable the READ
+ //events below, dispatch a doTcpSocketCallback on the main queue. Assume it is
+ //ConnFailed which means we are going to free the tcpInfo. While it
+ //is waiting to be dispatched, another read event can come into tcpKQSocketCallback
+ //and potentially call doTCPCallback with error which can close the fd and free the
+ //tcpInfo. Later when the thread gets dispatched it will crash because the tcpInfo
+ //is already freed.
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+
+ LogInfo("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
+
+ if (sock->handshake == handshake_to_be_closed)
+ {
+ LogInfo("SSLHandshake completed after close");
+ mDNSPlatformTCPCloseConnection(sock);
+ }
+ else
+ {
+ if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
+ else LogMsg("doSSLHandshake: sock->fd is -1");
+
+ if (err == errSSLWouldBlock)
+ sock->handshake = handshake_required;
+ else
+ {
+ if (err)
+ {
+ LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
+ CFRelease(sock->tlsContext);
+ sock->tlsContext = NULL;
+ }
+
+ sock->err = err ? mStatus_ConnFailed : 0;
+ sock->handshake = handshake_completed;
+
+ LogInfo("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
+ doTcpSocketCallback(sock);
+ }
+ }
+
+ LogInfo("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
+ return;
+ });
+}
+#else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+mDNSlocal void *doSSLHandshake(TCPSocket *sock)
+{
+ // Warning: Touching sock without the kqueue lock!
+ // We're protected because sock->handshake == handshake_in_progress
+ mDNS * const m = sock->m; // Get m now, as we may free sock if marked to be closed while we're waiting on SSLHandshake
+ mStatus err = SSLHandshake(sock->tlsContext);
+
+ KQueueLock(m);
+ debugf("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
+
+ if (sock->handshake == handshake_to_be_closed)
+ {
+ LogInfo("SSLHandshake completed after close");
+ mDNSPlatformTCPCloseConnection(sock);
+ }
+ else
+ {
+ if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
+ else LogMsg("doSSLHandshake: sock->fd is -1");
+
+ if (err == errSSLWouldBlock)
+ sock->handshake = handshake_required;
+ else
+ {
+ if (err)
+ {
+ LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
+ CFRelease(sock->tlsContext);
+ sock->tlsContext = NULL;
+ }
+
+ sock->err = err ? mStatus_ConnFailed : 0;
+ sock->handshake = handshake_completed;
+
+ debugf("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
+ doTcpSocketCallback(sock);
+ }
+ }
+
+ debugf("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
+ KQueueUnlock(m, "doSSLHandshake");
+ return NULL;
+}
+#endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+
+mDNSlocal void spawnSSLHandshake(TCPSocket* sock)
+{
+ debugf("spawnSSLHandshake %p: entry", sock);
+
+ if (sock->handshake != handshake_required) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock->handshake);
+ sock->handshake = handshake_in_progress;
+ KQueueSet(sock->fd, EV_DELETE, EVFILT_READ, sock->kqEntry);
+
+ // Dispatch it on a separate queue to help avoid blocking other threads/queues, and
+ // to limit the number of threads used for SSLHandshake
+ dispatch_async(SSLqueue, ^{doSSLHandshake(sock);});
+
+ debugf("spawnSSLHandshake %p: done for %d", sock, sock->fd);
+}
+
+#endif /* NO_SECURITYFRAMEWORK */
+
+mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context)
+{
+ TCPSocket *sock = context;
+ sock->err = mStatus_NoError;
+
+ //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
+ //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
+ // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
+ if (filter == EVFILT_WRITE)
+ KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, sock->kqEntry);
+
+ if (sock->flags & kTCPSocketFlags_UseTLS)
+ {
+#ifndef NO_SECURITYFRAMEWORK
+ if (!sock->setup)
+ {
+ sock->setup = mDNStrue;
+ sock->err = tlsSetupSock(sock, kSSLClientSide, kSSLStreamType);
+ if (sock->err)
+ {
+ LogMsg("ERROR: tcpKQSocketCallback: tlsSetupSock failed with error code: %d", sock->err);
+ return;
+ }
+ }
+ if (sock->handshake == handshake_required)
+ {
+ spawnSSLHandshake(sock);
+ return;
+ }
+ else if (sock->handshake == handshake_in_progress || sock->handshake == handshake_to_be_closed)
+ {
+ return;
+ }
+ else if (sock->handshake != handshake_completed)
+ {
+ if (!sock->err)
+ sock->err = mStatus_UnknownErr;
+ LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock->handshake);
+ }
+#else /* NO_SECURITYFRAMEWORK */
+ sock->err = mStatus_UnsupportedErr;
+#endif /* NO_SECURITYFRAMEWORK */
+ }
+
+ doTcpSocketCallback(sock);
+}
+
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+mDNSexport int KQueueSet(int fd, u_short flags, short filter, KQueueEntry *const entryRef)
+{
+ dispatch_queue_t queue = dispatch_get_main_queue();
+ dispatch_source_t source;
+ if (flags == EV_DELETE)
+ {
+ if (filter == EVFILT_READ)
+ {
+ dispatch_source_cancel(entryRef->readSource);
+ dispatch_release(entryRef->readSource);
+ entryRef->readSource = mDNSNULL;
+ debugf("KQueueSet: source cancel for read %p, %p", entryRef->readSource, entryRef->writeSource);
+ }
+ else if (filter == EVFILT_WRITE)
+ {
+ dispatch_source_cancel(entryRef->writeSource);
+ dispatch_release(entryRef->writeSource);
+ entryRef->writeSource = mDNSNULL;
+ debugf("KQueueSet: source cancel for write %p, %p", entryRef->readSource, entryRef->writeSource);
+ }
+ else
+ LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_DELETE", filter);
+ return 0;
+ }
+ if (flags != EV_ADD) LogMsg("KQueueSet: Invalid flags %d", flags);
+
+ if (filter == EVFILT_READ)
+ {
+ source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, queue);
+ }
+ else if (filter == EVFILT_WRITE)
+ {
+ source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, queue);
+ }
+ else
+ {
+ LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_ADD", filter);
+ return -1;
+ }
+ if (!source) return -1;
+ dispatch_source_set_event_handler(source, ^{
+
+ mDNSs32 stime = mDNSPlatformRawTime();
+ entryRef->KQcallback(fd, filter, entryRef->KQcontext);
+ mDNSs32 etime = mDNSPlatformRawTime();
+ if (etime - stime >= WatchDogReportingThreshold)
+ LogInfo("KQEntryCallback Block: WARNING: took %dms to complete", etime - stime);
+
+ // Trigger the event delivery to the application. Even though we trigger the
+ // event completion after handling every event source, these all will hopefully
+ // get merged
+ TriggerEventCompletion();
+
+ });
+ dispatch_source_set_cancel_handler(source, ^{
+ if (entryRef->fdClosed)
+ {
+ //LogMsg("CancelHandler: closing fd %d", fd);
+ close(fd);
+ }
+ });
+ dispatch_resume(source);
+ if (filter == EVFILT_READ)
+ entryRef->readSource = source;
+ else
+ entryRef->writeSource = source;
+
+ return 0;
+}
+
+mDNSexport void KQueueLock(mDNS *const m)
+{
+ (void)m; //unused
+}
+mDNSexport void KQueueUnlock(mDNS *const m, const char const *task)
+{
+ (void)m; //unused
+ (void)task; //unused
+}
+#else
+mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef)
+{
+ struct kevent new_event;
+ EV_SET(&new_event, fd, filter, flags, 0, 0, (void*)entryRef);
+ return (kevent(KQueueFD, &new_event, 1, NULL, 0, NULL) < 0) ? errno : 0;
+}
+
+mDNSexport void KQueueLock(mDNS *const m)
+{
+ pthread_mutex_lock(&m->p->BigMutex);
+ m->p->BigMutexStartTime = mDNSPlatformRawTime();
+}
+
+mDNSexport void KQueueUnlock(mDNS *const m, const char* task)
+{
+ mDNSs32 end = mDNSPlatformRawTime();
+ (void)task;
+ if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
+ LogInfo("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime);
+
+ pthread_mutex_unlock(&m->p->BigMutex);
+
+ char wake = 1;
+ if (send(m->p->WakeKQueueLoopFD, &wake, sizeof(wake), 0) == -1)
+ LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno, strerror(errno));
+}
+#endif
+
+mDNSexport void mDNSPlatformCloseFD(KQueueEntry *kq, int fd)
+{
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+ (void) fd; //unused
+ if (kq->readSource)
+ {
+ dispatch_source_cancel(kq->readSource);
+ kq->readSource = mDNSNULL;
+ }
+ if (kq->writeSource)
+ {
+ dispatch_source_cancel(kq->writeSource);
+ kq->writeSource = mDNSNULL;
+ }
+ // Close happens in the cancellation handler
+ debugf("mDNSPlatformCloseFD: resetting sources for %d", fd);
+ kq->fdClosed = mDNStrue;
+#else
+ (void)kq; //unused
+ close(fd);
+#endif
+}
+
+mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, u_short sa_family, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
+{
+ KQSocketSet *cp = &sock->ss;
+ int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
+ KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
+ const int on = 1; // "on" for setsockopt
+ mStatus err;
+
+ int skt = socket(sa_family, SOCK_STREAM, IPPROTO_TCP);
+ if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupTCPSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); }
+
+ // for TCP sockets, the traffic class is set once and not changed
+ setTrafficClass(skt, useBackgroundTrafficClass);
+
+ if (sa_family == AF_INET)
+ {
+ // Bind it
+ struct sockaddr_in addr;
+ mDNSPlatformMemZero(&addr, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = port->NotAnInteger;
+ err = bind(skt, (struct sockaddr*) &addr, sizeof(addr));
+ if (err < 0) { LogMsg("ERROR: bind %s", strerror(errno)); return err; }
+
+ // Receive interface identifiers
+ err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
+ if (err < 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); return err; }
+
+ mDNSPlatformMemZero(&addr, sizeof(addr));
+ socklen_t len = sizeof(addr);
+ err = getsockname(skt, (struct sockaddr*) &addr, &len);
+ if (err < 0) { LogMsg("getsockname - %s", strerror(errno)); return err; }
+
+ port->NotAnInteger = addr.sin_port;
+ }
+ else
+ {
+ // Bind it
+ struct sockaddr_in6 addr6;
+ mDNSPlatformMemZero(&addr6, sizeof(addr6));
+ addr6.sin6_family = AF_INET6;
+ addr6.sin6_port = port->NotAnInteger;
+ err = bind(skt, (struct sockaddr*) &addr6, sizeof(addr6));
+ if (err < 0) { LogMsg("ERROR: bind6 %s", strerror(errno)); return err; }
+
+ // We want to receive destination addresses and receive interface identifiers
+ err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
+ if (err < 0) { LogMsg("ERROR: setsockopt IPV6_RECVPKTINFO %s", strerror(errno)); return err; }
+
+ mDNSPlatformMemZero(&addr6, sizeof(addr6));
+ socklen_t len = sizeof(addr6);
+ err = getsockname(skt, (struct sockaddr *) &addr6, &len);
+ if (err < 0) { LogMsg("getsockname6 - %s", strerror(errno)); return err; }
+
+ port->NotAnInteger = addr6.sin6_port;
+
+ }
+ *s = skt;
+ k->KQcallback = tcpKQSocketCallback;
+ k->KQcontext = sock;
+ k->KQtask = "mDNSPlatformTCPSocket";
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+ k->readSource = mDNSNULL;
+ k->writeSource = mDNSNULL;
+ k->fdClosed = mDNSfalse;
+#endif
+ return mStatus_NoError;
+}
+
+mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
+{
+ mStatus err;
+ (void) m;
+
+ TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket));
+ if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); }
+
+ mDNSPlatformMemZero(sock, sizeof(TCPSocket));
+
+ sock->ss.m = m;
+ sock->ss.sktv4 = -1;
+ sock->ss.sktv6 = -1;
+ err = SetupTCPSocket(sock, AF_INET, port, useBackgroundTrafficClass);
+
+ if (!err)
+ {
+ err = SetupTCPSocket(sock, AF_INET6, port, useBackgroundTrafficClass);
+ if (err) { mDNSPlatformCloseFD(&sock->ss.kqsv4, sock->ss.sktv4); sock->ss.sktv4 = -1; }
+ }
+ if (err)
+ {
+ LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno));
+ freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
+ return(mDNSNULL);
+ }
+ // sock->fd is used as the default fd if the caller does not call mDNSPlatformTCPConnect
+ sock->fd = sock->ss.sktv4;
+ sock->callback = mDNSNULL;
+ sock->flags = flags;
+ sock->context = mDNSNULL;
+ sock->setup = mDNSfalse;
+ sock->connected = mDNSfalse;
+ sock->handshake = handshake_required;
+ sock->m = m;
+ sock->err = mStatus_NoError;
+
+ return sock;
+}
+
+mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
+{
+ KQSocketSet *cp = &sock->ss;
+ int *s = (dst->type == mDNSAddrType_IPv4) ? &cp->sktv4 : &cp->sktv6;
+ KQueueEntry *k = (dst->type == mDNSAddrType_IPv4) ? &cp->kqsv4 : &cp->kqsv6;
+ mStatus err = mStatus_NoError;
+ struct sockaddr_storage ss;
+
+ sock->callback = callback;
+ sock->context = context;
+ sock->setup = mDNSfalse;
+ sock->connected = mDNSfalse;
+ sock->handshake = handshake_required;
+ sock->err = mStatus_NoError;
+
+ if (hostname) { debugf("mDNSPlatformTCPConnect: hostname %##s", hostname->c); AssignDomainName(&sock->hostname, hostname); }
+
+ if (dst->type == mDNSAddrType_IPv4)
+ {
+ struct sockaddr_in *saddr = (struct sockaddr_in *)&ss;
+ mDNSPlatformMemZero(saddr, sizeof(*saddr));
+ saddr->sin_family = AF_INET;
+ saddr->sin_port = dstport.NotAnInteger;
+ saddr->sin_len = sizeof(*saddr);
+ saddr->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
+ }
+ else
+ {
+ struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&ss;
+ mDNSPlatformMemZero(saddr6, sizeof(*saddr6));
+ saddr6->sin6_family = AF_INET6;
+ saddr6->sin6_port = dstport.NotAnInteger;
+ saddr6->sin6_len = sizeof(*saddr6);
+ saddr6->sin6_addr = *(struct in6_addr *)&dst->ip.v6;
+ }
+
+ // Watch for connect complete (write is ready)
+ // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
+ if (KQueueSet(*s, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, k))
+ {
+ LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
+ return errno;
+ }
+
+ // Watch for incoming data
+ if (KQueueSet(*s, EV_ADD, EVFILT_READ, k))
+ {
+ LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
+ return errno;
+ }
+
+ if (fcntl(*s, F_SETFL, fcntl(*s, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
+ {
+ LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
+ return mStatus_UnknownErr;
+ }
+
+ // We bind to the interface and all subsequent packets including the SYN will be sent out
+ // on this interface
+ //
+ // Note: If we are in Active Directory domain, we may try TCP (if the response can't fit in
+ // UDP). mDNSInterface_Unicast indicates this case and not a valid interface.
+ if (InterfaceID && InterfaceID != mDNSInterface_Unicast)
+ {
+ NetworkInterfaceInfoOSX *info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
+ if (dst->type == mDNSAddrType_IPv4)
+ {
+ #ifdef IP_BOUND_IF
+ if (info) setsockopt(*s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
+ else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
+ #else
+ (void)InterfaceID; // Unused
+ (void)info; // Unused
+ #endif
+ }
+ else
+ {
+ #ifdef IPV6_BOUND_IF
+ if (info) setsockopt(*s, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
+ else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
+ #else
+ (void)InterfaceID; // Unused
+ (void)info; // Unused
+ #endif
+ }
+ }
+
+ // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
+ // from which we can infer the destination address family. Hence we need to remember that here.
+ // Instead of remembering the address family, we remember the right fd.
+ sock->fd = *s;
+ sock->kqEntry = k;
+ // initiate connection wth peer
+ if (connect(*s, (struct sockaddr *)&ss, ss.ss_len) < 0)
+ {
+ if (errno == EINPROGRESS) return mStatus_ConnPending;
+ if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
+ LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock->fd, errno, strerror(errno));
+ else
+ LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d", sock->fd, errno, strerror(errno), ss.ss_len);
+ return mStatus_ConnFailed;
+ }
+
+ LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
+ // kQueue should notify us, but this LogMsg is to help track down if it doesn't
+ return err;
+}
+
+// Why doesn't mDNSPlatformTCPAccept actually call accept() ?
+mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
+{
+ mStatus err = mStatus_NoError;
+
+ TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket));
+ if (!sock) return(mDNSNULL);
+
+ mDNSPlatformMemZero(sock, sizeof(*sock));
+ sock->fd = fd;
+ sock->flags = flags;
+
+ if (flags & kTCPSocketFlags_UseTLS)
+ {
+#ifndef NO_SECURITYFRAMEWORK
+ if (!ServerCerts) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err = mStatus_UnknownErr; goto exit; }
+
+ err = tlsSetupSock(sock, kSSLServerSide, kSSLStreamType);
+ if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err); goto exit; }
+
+ err = SSLSetCertificate(sock->tlsContext, ServerCerts);
+ if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err); goto exit; }
+#else
+ err = mStatus_UnsupportedErr;
+#endif /* NO_SECURITYFRAMEWORK */
+ }
+#ifndef NO_SECURITYFRAMEWORK
+exit:
+#endif
+
+ if (err) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock); return(mDNSNULL); }
+ return(sock);
+}
+
+mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
+{
+ mDNSu16 port;
+
+ port = -1;
+ if (sock)
+ {
+ port = sock->ss.port.NotAnInteger;
+ }
+ return port;
+}
+
+mDNSlocal void CloseSocketSet(KQSocketSet *ss)
+{
+ if (ss->sktv4 != -1)
+ {
+ mDNSPlatformCloseFD(&ss->kqsv4, ss->sktv4);
+ ss->sktv4 = -1;
+ }
+ if (ss->sktv6 != -1)
+ {
+ mDNSPlatformCloseFD(&ss->kqsv6, ss->sktv6);
+ ss->sktv6 = -1;
+ }
+ if (ss->closeFlag) *ss->closeFlag = 1;
+}
+
+mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
+{
+ if (sock)
+ {
+#ifndef NO_SECURITYFRAMEWORK
+ if (sock->tlsContext)
+ {
+ if (sock->handshake == handshake_in_progress) // SSLHandshake thread using this sock (esp. tlsContext)
+ {
+ LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress");
+ // When we come back from SSLHandshake, we will notice that a close was here and
+ // call this function again which will do the cleanup then.
+ sock->handshake = handshake_to_be_closed;
+ return;
+ }
+
+ SSLClose(sock->tlsContext);
+ CFRelease(sock->tlsContext);
+ sock->tlsContext = NULL;
+ }
+#endif /* NO_SECURITYFRAMEWORK */
+ if (sock->ss.sktv4 != -1)
+ shutdown(sock->ss.sktv4, 2);
+ if (sock->ss.sktv6 != -1)
+ shutdown(sock->ss.sktv6, 2);
+ CloseSocketSet(&sock->ss);
+ sock->fd = -1;
+
+ freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock);
+ }
+}
+
+mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
+{
+ ssize_t nread = 0;
+ *closed = mDNSfalse;
+
+ if (sock->flags & kTCPSocketFlags_UseTLS)
+ {
+#ifndef NO_SECURITYFRAMEWORK
+ if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; }
+ else if (sock->handshake == handshake_in_progress) return 0;
+ else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock->handshake);
+
+ //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
+ mStatus err = SSLRead(sock->tlsContext, buf, buflen, (size_t *)&nread);
+ //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
+ if (err == errSSLClosedGraceful) { nread = 0; *closed = mDNStrue; }
+ else if (err && err != errSSLWouldBlock)
+ { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err); nread = -1; *closed = mDNStrue; }
+#else
+ nread = -1;
+ *closed = mDNStrue;
+#endif /* NO_SECURITYFRAMEWORK */
+ }
+ else
+ {
+ static int CLOSEDcount = 0;
+ static int EAGAINcount = 0;
+ nread = recv(sock->fd, buf, buflen, 0);
+
+ if (nread > 0)
+ {
+ CLOSEDcount = 0;
+ EAGAINcount = 0;
+ } // On success, clear our error counters
+ else if (nread == 0)
+ {
+ *closed = mDNStrue;
+ if ((++CLOSEDcount % 1000) == 0)
+ {
+ LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock->fd, CLOSEDcount);
+ assert(CLOSEDcount < 1000);
+ // Recovery Mechanism to bail mDNSResponder out of trouble: Instead of logging the same error msg multiple times,
+ // crash mDNSResponder using assert() and restart fresh. See advantages below:
+ // 1.Better User Experience
+ // 2.CrashLogs frequency can be monitored
+ // 3.StackTrace can be used for more info
+ }
+ }
+ // else nread is negative -- see what kind of error we got
+ else if (errno == ECONNRESET) { nread = 0; *closed = mDNStrue; }
+ else if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno, strerror(errno)); nread = -1; }
+ else // errno is EAGAIN (EWOULDBLOCK) -- no data available
+ {
+ nread = 0;
+ if ((++EAGAINcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock->fd, EAGAINcount); sleep(1); }
+ }
+ }
+
+ return nread;
+}
+
+mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
+{
+ int nsent;
+
+ if (sock->flags & kTCPSocketFlags_UseTLS)
+ {
+#ifndef NO_SECURITYFRAMEWORK
+ size_t processed;
+ if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; }
+ if (sock->handshake == handshake_in_progress) return 0;
+ else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock->handshake);
+
+ mStatus err = SSLWrite(sock->tlsContext, msg, len, &processed);
+
+ if (!err) nsent = (int) processed;
+ else if (err == errSSLWouldBlock) nsent = 0;
+ else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err); nsent = -1; }
+#else
+ nsent = -1;
+#endif /* NO_SECURITYFRAMEWORK */
+ }
+ else
+ {
+ nsent = send(sock->fd, msg, len, 0);
+ if (nsent < 0)
+ {
+ if (errno == EAGAIN) nsent = 0;
+ else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno)); nsent = -1; }
+ }
+ }
+
+ return nsent;
+}
+
+mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
+{
+ return sock->fd;
+}
+
+// If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
+// If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
+mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport)
+{
+ int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
+ KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
+ const int on = 1;
+ const int twofivefive = 255;
+ mStatus err = mStatus_NoError;
+ char *errstr = mDNSNULL;
+ const int mtu = 0;
+
+ cp->closeFlag = mDNSNULL;
+
+ int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
+ if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); }
+
+ // set default traffic class
+ setTrafficClass(skt, mDNSfalse);
+
+#ifdef SO_RECV_ANYIF
+ // Enable inbound packets on IFEF_AWDL interface.
+ // Only done for multicast sockets, since we don't expect unicast socket operations
+ // on the IFEF_AWDL interface. Operation is a no-op for other interface types.
+ if (mDNSSameIPPort(port, MulticastDNSPort))
+ {
+ err = setsockopt(skt, SOL_SOCKET, SO_RECV_ANYIF, &on, sizeof(on));
+ if (err < 0) { errstr = "setsockopt - SO_RECV_ANYIF"; goto fail; }
+ }
+#endif // SO_RECV_ANYIF
+
+ // ... with a shared UDP port, if it's for multicast receiving
+ if (mDNSSameIPPort(port, MulticastDNSPort) || mDNSSameIPPort(port, NATPMPAnnouncementPort)) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
+ if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
+
+ if (sa_family == AF_INET)
+ {
+ // We want to receive destination addresses
+ err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
+ if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; }
+
+ // We want to receive interface identifiers
+ err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
+ if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; }
+
+ // We want to receive packet TTL value so we can check it
+ err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
+ // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
+
+ // Send unicast packets with TTL 255
+ err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
+ if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; }
+
+ // And multicast packets with TTL 255 too
+ err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
+ if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; }
+
+ // And start listening for packets
+ struct sockaddr_in listening_sockaddr;
+ listening_sockaddr.sin_family = AF_INET;
+ listening_sockaddr.sin_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
+ listening_sockaddr.sin_addr.s_addr = mDNSSameIPPort(port, NATPMPAnnouncementPort) ? AllHosts_v4.NotAnInteger : 0;
+ err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
+ if (err) { errstr = "bind"; goto fail; }
+ if (outport) outport->NotAnInteger = listening_sockaddr.sin_port;
+ }
+ else if (sa_family == AF_INET6)
+ {
+ // NAT-PMP Announcements make no sense on IPv6, and we don't support IPv6 for PCP, so bail early w/o error
+ if (mDNSSameIPPort(port, NATPMPAnnouncementPort)) { if (outport) *outport = zeroIPPort;return mStatus_NoError; }
+
+ // We want to receive destination addresses and receive interface identifiers
+ err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
+ if (err < 0) { errstr = "setsockopt - IPV6_RECVPKTINFO"; goto fail; }
+
+ // We want to receive packet hop count value so we can check it
+ err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on));
+ if (err < 0) { errstr = "setsockopt - IPV6_RECVHOPLIMIT"; goto fail; }
+
+ // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
+ // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
+ err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
+ if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; }
+
+ // Send unicast packets with TTL 255
+ err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
+ if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; }
+
+ // And multicast packets with TTL 255 too
+ err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
+ if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; }
+
+ // Want to receive our own packets
+ err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
+ if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; }
+
+ // Disable default option to send mDNSv6 packets at min IPv6 MTU: RFC 3542, Sec 11
+ err = setsockopt(skt, IPPROTO_IPV6, IPV6_USE_MIN_MTU, &mtu, sizeof(mtu));
+ if (err < 0) // Since it is an optimization if we fail just log the err, no need to close the skt
+ LogMsg("SetupSocket: setsockopt - IPV6_USE_MIN_MTU: IP6PO_MINMTU_DISABLE socket %d err %d errno %d (%s)",
+ skt, err, errno, strerror(errno));
+
+ // And start listening for packets
+ struct sockaddr_in6 listening_sockaddr6;
+ mDNSPlatformMemZero(&listening_sockaddr6, sizeof(listening_sockaddr6));
+ listening_sockaddr6.sin6_len = sizeof(listening_sockaddr6);
+ listening_sockaddr6.sin6_family = AF_INET6;
+ listening_sockaddr6.sin6_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping
+ listening_sockaddr6.sin6_flowinfo = 0;
+ listening_sockaddr6.sin6_addr = in6addr_any; // Want to receive multicasts AND unicasts on this socket
+ listening_sockaddr6.sin6_scope_id = 0;
+ err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
+ if (err) { errstr = "bind"; goto fail; }
+ if (outport) outport->NotAnInteger = listening_sockaddr6.sin6_port;
+ }
+
+ fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
+ fcntl(skt, F_SETFD, 1); // set close-on-exec
+ *s = skt;
+ k->KQcallback = myKQSocketCallBack;
+ k->KQcontext = cp;
+ k->KQtask = "UDP packet reception";
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+ k->readSource = mDNSNULL;
+ k->writeSource = mDNSNULL;
+ k->fdClosed = mDNSfalse;
+#endif
+ KQueueSet(*s, EV_ADD, EVFILT_READ, k);
+
+ return(err);
+
+fail:
+ // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
+ if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port))
+ LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr, skt, mDNSVal16(port), err, errno, strerror(errno));
+
+ // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port
+ if (!strcmp(errstr, "bind") && errno == EADDRINUSE)
+ {
+ err = EADDRINUSE;
+ if (mDNSSameIPPort(port, MulticastDNSPort))
+ NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
+ "Congratulations, you've reproduced an elusive bug.\r"
+ "Please contact the current assignee of <rdar://problem/3814904>.\r"
+ "Alternatively, you can send email to radar-3387020 at group.apple.com. (Note number is different.)\r"
+ "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
+ }
+
+ mDNSPlatformCloseFD(k, skt);
+ return(err);
+}
+
+mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport)
+{
+ mStatus err;
+ mDNSIPPort port = requestedport;
+ mDNSBool randomizePort = mDNSIPPortIsZero(requestedport);
+ int i = 10000; // Try at most 10000 times to get a unique random port
+ UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket));
+ if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
+ mDNSPlatformMemZero(p, sizeof(UDPSocket));
+ p->ss.port = zeroIPPort;
+ p->ss.m = m;
+ p->ss.sktv4 = -1;
+ p->ss.sktv6 = -1;
+ p->ss.proxy = mDNSfalse;
+
+ do
+ {
+ // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
+ if (randomizePort) port = mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
+ err = SetupSocket(&p->ss, port, AF_INET, &p->ss.port);
+ if (!err)
+ {
+ err = SetupSocket(&p->ss, port, AF_INET6, &p->ss.port);
+ if (err) { mDNSPlatformCloseFD(&p->ss.kqsv4, p->ss.sktv4); p->ss.sktv4 = -1; }
+ }
+ i--;
+ } while (err == EADDRINUSE && randomizePort && i);
+
+ if (err)
+ {
+ // In customer builds we don't want to log failures with port 5351, because this is a known issue
+ // of failing to bind to this port when Internet Sharing has already bound to it
+ // We also don't want to log about port 5350, due to a known bug when some other
+ // process is bound to it.
+ if (mDNSSameIPPort(requestedport, NATPMPPort) || mDNSSameIPPort(requestedport, NATPMPAnnouncementPort))
+ LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
+ else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
+ freeL("UDPSocket", p);
+ return(mDNSNULL);
+ }
+ return(p);
+}
+
+mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
+{
+ CloseSocketSet(&sock->ss);
+ freeL("UDPSocket", sock);
+}
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - BPF Raw packet sending/receiving
+#endif
+
+#if APPLE_OSX_mDNSResponder
+
+mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
+{
+ if (!InterfaceID) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
+ NetworkInterfaceInfoOSX *info;
+
+ info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
+ if (info == NULL)
+ {
+ LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
+ return;
+ }
+ if (info->BPF_fd < 0)
+ LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info->ifinfo.ifname, info->BPF_fd);
+ else
+ {
+ //LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname);
+ if (write(info->BPF_fd, msg, end - (mDNSu8 *)msg) < 0)
+ LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info->BPF_fd, errno, strerror(errno));
+ }
+}
+
+mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
+{
+ if (!InterfaceID) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: No InterfaceID specified"); return; }
+ NetworkInterfaceInfoOSX *info;
+ info = IfindexToInterfaceInfoOSX(m, InterfaceID);
+ if (info == NULL) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: Invalid interface index %p", InterfaceID); return; }
+ // Manually inject an entry into our local ARP cache.
+ // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.)
+ if (!mDNS_AddressIsLocalSubnet(m, InterfaceID, tpa, mDNSNULL))
+ LogSPS("Don't need address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha);
+ else
+ {
+ int result = mDNSSetLocalAddressCacheEntry(info->scope_id, tpa->type, tpa->ip.v6.b, tha->b);
+ if (result) LogMsg("Set local address cache entry for %s %#a %.6a failed: %d", info->ifinfo.ifname, tpa, tha, result);
+ else LogSPS("Set local address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha);
+ }
+}
+
+mDNSlocal void CloseBPF(NetworkInterfaceInfoOSX *const i)
+{
+ LogSPS("%s closing BPF fd %d", i->ifinfo.ifname, i->BPF_fd);
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+ // close will happen in the cancel handler
+ dispatch_source_cancel(i->BPF_source);
+#else
+
+ // Note: MUST NOT close() the underlying native BSD sockets.
+ // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because
+ // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them.
+ CFRunLoopRemoveSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode);
+ CFRelease(i->BPF_rls);
+ CFSocketInvalidate(i->BPF_cfs);
+ CFRelease(i->BPF_cfs);
+#endif
+ i->BPF_fd = -1;
+ if (i->BPF_mcfd >= 0) { close(i->BPF_mcfd); i->BPF_mcfd = -1; }
+}
+
+mDNSlocal void bpf_callback_common(NetworkInterfaceInfoOSX *info)
+{
+ KQueueLock(info->m);
+
+ // Now we've got the lock, make sure the kqueue thread didn't close the fd out from under us (will not be a problem once the OS X
+ // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition).
+ if (info->BPF_fd < 0) goto exit;
+
+ ssize_t n = read(info->BPF_fd, &info->m->imsg, info->BPF_len);
+ const mDNSu8 *ptr = (const mDNSu8 *)&info->m->imsg;
+ const mDNSu8 *end = (const mDNSu8 *)&info->m->imsg + n;
+ debugf("%3d: bpf_callback got %d bytes on %s", info->BPF_fd, n, info->ifinfo.ifname);
+
+ if (n<0)
+ {
+ /* <rdar://problem/10287386>
+ * sometimes there can be a race condition btw when the bpf socket
+ * gets data and the callback get scheduled and when we call BIOCSETF (which
+ * clears the socket). this can cause the read to hang for a really long time
+ * and effectively prevent us from responding to requests for long periods of time.
+ * to prevent this make the socket non blocking and just bail if we dont get anything
+ */
+ if (errno == EAGAIN)
+ {
+ LogMsg("bpf_callback got EAGAIN bailing");
+ goto exit;
+ }
+ LogMsg("Closing %s BPF fd %d due to error %d (%s)", info->ifinfo.ifname, info->BPF_fd, errno, strerror(errno));
+ CloseBPF(info);
+ goto exit;
+ }
+
+ while (ptr < end)
+ {
+ const struct bpf_hdr *const bh = (const struct bpf_hdr *)ptr;
+ debugf("%3d: bpf_callback ptr %p bh_hdrlen %d data %p bh_caplen %4d bh_datalen %4d next %p remaining %4d",
+ info->BPF_fd, ptr, bh->bh_hdrlen, ptr + bh->bh_hdrlen, bh->bh_caplen, bh->bh_datalen,
+ ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen), end - (ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen)));
+ // Note that BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header.
+ // Given that An Ethernet header is 14 bytes, this means that if the network layer header (e.g. IP header,
+ // ARP message, etc.) is 4-byte aligned, then necessarily the Ethernet header will be NOT be 4-byte aligned.
+ mDNSCoreReceiveRawPacket(info->m, ptr + bh->bh_hdrlen, ptr + bh->bh_hdrlen + bh->bh_caplen, info->ifinfo.InterfaceID);
+ ptr += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
+ }
+exit:
+ KQueueUnlock(info->m, "bpf_callback");
+}
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+mDNSlocal void bpf_callback_dispatch(NetworkInterfaceInfoOSX *const info)
+{
+ bpf_callback_common(info);
+}
+#else
+mDNSlocal void bpf_callback(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context)
+{
+ (void)cfs;
+ (void)CallBackType;
+ (void)address;
+ (void)data;
+ bpf_callback_common((NetworkInterfaceInfoOSX *)context);
+}
+#endif
+
+mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win)
+{
+ LogMsg("mDNSPlatformSendKeepalive called\n");
+ mDNSSendKeepalive(sadd->ip.v6.b, dadd->ip.v6.b, lport->NotAnInteger, rport->NotAnInteger, seq, ack, win);
+}
+
+mDNSexport mStatus mDNSPlatformClearSPSMACAddr(void)
+{
+ SCDynamicStoreRef store = NULL;
+ CFStringRef entityname = NULL;
+
+ if ((store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:ClearSPSMACAddress"), NULL, NULL)))
+ {
+ if ((entityname = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", "[^/]", "/BonjourSleepProxyAddress")))
+ {
+ if (SCDynamicStoreRemoveValue(store, entityname) == false)
+ LogMsg("mDNSPlatformClearSPSMACAddr: Unable to remove key");
+ }
+ }
+
+ if (entityname) CFRelease(entityname);
+ if (store) CFRelease(store);
+ return KERN_SUCCESS;
+}
+
+mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname)
+{
+ int family = (spsaddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
+ LogSPS("mDNSPlatformStoreSPSMACAddr : Storing %#a on interface %s", spsaddr, ifname);
+ mDNSStoreSPSMACAddress(family, spsaddr->ip.v6.b, ifname);
+ return KERN_SUCCESS;
+}
+
+mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNS *const m, mDNSAddr *raddr)
+{
+ int family = (raddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
+
+ mDNSGetRemoteMAC(m, family, raddr->ip.v6.b);
+ return KERN_SUCCESS;
+}
+
+mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNS *const m, mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
+{
+ mDNSs32 intfid;
+ mDNSs32 error = 0;
+ int family = (laddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
+
+ error = mDNSRetrieveTCPInfo(family, laddr->ip.v6.b, lport->NotAnInteger, raddr->ip.v6.b, rport->NotAnInteger, (uint32_t *)&(mti->seq), (uint32_t *)&(mti->ack), (uint16_t *)&(mti->window), (int32_t*)&intfid);
+ if (error != KERN_SUCCESS)
+ {
+ LogMsg("%s: mDNSRetrieveTCPInfo returned : %d", __func__, error);
+ return error;
+ }
+ mti->IntfId = mDNSPlatformInterfaceIDfromInterfaceIndex(m, intfid);
+ return error;
+}
+
+#define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
+
+mDNSlocal int CountProxyTargets(mDNS *const m, NetworkInterfaceInfoOSX *x, int *p4, int *p6)
+{
+ int numv4 = 0, numv6 = 0;
+ AuthRecord *rr;
+
+ for (rr = m->ResourceRecords; rr; rr=rr->next)
+ if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
+ {
+ if (p4) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x->BPF_fd, x->ifinfo.ifname, numv4, &rr->AddressProxy.ip.v4);
+ numv4++;
+ }
+
+ for (rr = m->ResourceRecords; rr; rr=rr->next)
+ if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
+ {
+ if (p6) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x->BPF_fd, x->ifinfo.ifname, numv6, &rr->AddressProxy.ip.v6);
+ numv6++;
+ }
+
+ if (p4) *p4 = numv4;
+ if (p6) *p6 = numv6;
+ return(numv4 + numv6);
+}
+
+mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
+{
+ NetworkInterfaceInfoOSX *x;
+
+ // Note: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also.
+ for (x = m->p->InterfaceList; x; x = x->next) if (x->ifinfo.InterfaceID == InterfaceID) break;
+
+ if (!x) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID); return; }
+
+ #define MAX_BPF_ADDRS 250
+ int numv4 = 0, numv6 = 0;
+
+ if (CountProxyTargets(m, x, &numv4, &numv6) > MAX_BPF_ADDRS)
+ {
+ LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4, numv6);
+ if (numv4 > MAX_BPF_ADDRS) numv4 = MAX_BPF_ADDRS;
+ numv6 = MAX_BPF_ADDRS - numv4;
+ }
+
+ LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC %.6a %d v4 %d v6", x->BPF_fd, x->ifinfo.ifname, &x->ifinfo.MAC, numv4, numv6);
+
+ // Caution: This is a static structure, so we need to be careful that any modifications we make to it
+ // are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times
+ static struct bpf_insn filter[17 + MAX_BPF_ADDRS] =
+ {
+ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), // 0 Read Ethertype (bytes 12,13)
+
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0806, 0, 1), // 1 If Ethertype == ARP goto next, else 3
+ BPF_STMT(BPF_RET + BPF_K, 42), // 2 Return 42-byte ARP
+
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0800, 4, 0), // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
+
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x86DD, 0, 9), // 4 If Ethertype == IPv6 goto next, else exit
+ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), // 5 Read Protocol and Hop Limit (bytes 20,21)
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x3AFF, 0, 9), // 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check
+ BPF_STMT(BPF_RET + BPF_K, 86), // 7 Return 86-byte ND
+
+ // Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for
+ BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 30), // 8 Read IPv4 Dst (bytes 30,31,32,33)
+ };
+
+ struct bpf_insn *pc = &filter[9];
+ struct bpf_insn *chk6 = pc + numv4 + 1; // numv4 address checks, plus a "return 0"
+ struct bpf_insn *fail = chk6 + 1 + numv6; // Get v6 Dst LSW, plus numv6 address checks
+ struct bpf_insn *ret4 = fail + 1;
+ struct bpf_insn *ret6 = ret4 + 4;
+
+ static const struct bpf_insn rf = BPF_STMT(BPF_RET + BPF_K, 0); // No match: Return nothing
+
+ static const struct bpf_insn g6 = BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 50); // Read IPv6 Dst LSW (bytes 50,51,52,53)
+
+ static const struct bpf_insn r4a = BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14); // Get IP Header length (normally 20)
+ static const struct bpf_insn r4b = BPF_STMT(BPF_LD + BPF_IMM, 54); // A = 54 (14-byte Ethernet plus 20-byte TCP + 20 bytes spare)
+ static const struct bpf_insn r4c = BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0); // A += IP Header length
+ static const struct bpf_insn r4d = BPF_STMT(BPF_RET + BPF_A, 0); // Success: Return Ethernet + IP + TCP + 20 bytes spare (normally 74)
+
+ static const struct bpf_insn r6a = BPF_STMT(BPF_RET + BPF_K, 94); // Success: Return Eth + IPv6 + TCP + 20 bytes spare
+
+ BPF_SetOffset(&filter[4], jf, fail); // If Ethertype not ARP, IPv4, or IPv6, fail
+ BPF_SetOffset(&filter[6], jf, chk6); // If IPv6 but not ICMPv6, go to IPv6 address list check
+
+ // BPF Byte-Order Note
+ // The BPF API designers apparently thought that programmers would not be smart enough to use htons
+ // and htonl correctly to convert numeric values to network byte order on little-endian machines,
+ // so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings
+ // that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc.
+ // As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API
+ // will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange
+ // that on little-endian machines we deliberately put addresses in memory with the bytes backwards,
+ // so that when the BPF API goes through and swaps them all, they end up back as they should be.
+ // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't*
+ // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly.
+
+ // IPSEC capture size notes:
+ // 8 bytes UDP header
+ // 4 bytes Non-ESP Marker
+ // 28 bytes IKE Header
+ // --
+ // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet.
+
+ AuthRecord *rr;
+ for (rr = m->ResourceRecords; rr; rr=rr->next)
+ if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
+ {
+ mDNSv4Addr a = rr->AddressProxy.ip.v4;
+ pc->code = BPF_JMP + BPF_JEQ + BPF_K;
+ BPF_SetOffset(pc, jt, ret4);
+ pc->jf = 0;
+ pc->k = (bpf_u_int32)a.b[0] << 24 | (bpf_u_int32)a.b[1] << 16 | (bpf_u_int32)a.b[2] << 8 | (bpf_u_int32)a.b[3];
+ pc++;
+ }
+ *pc++ = rf;
+
+ if (pc != chk6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc, chk6);
+ *pc++ = g6; // chk6 points here
+
+ // First cancel any previous ND group memberships we had, then create a fresh socket
+ if (x->BPF_mcfd >= 0) close(x->BPF_mcfd);
+ x->BPF_mcfd = socket(AF_INET6, SOCK_DGRAM, 0);
+
+ for (rr = m->ResourceRecords; rr; rr=rr->next)
+ if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
+ {
+ const mDNSv6Addr *const a = &rr->AddressProxy.ip.v6;
+ pc->code = BPF_JMP + BPF_JEQ + BPF_K;
+ BPF_SetOffset(pc, jt, ret6);
+ pc->jf = 0;
+ pc->k = (bpf_u_int32)a->b[0x0C] << 24 | (bpf_u_int32)a->b[0x0D] << 16 | (bpf_u_int32)a->b[0x0E] << 8 | (bpf_u_int32)a->b[0x0F];
+ pc++;
+
+ struct ipv6_mreq i6mr;
+ i6mr.ipv6mr_interface = x->scope_id;
+ i6mr.ipv6mr_multiaddr = *(const struct in6_addr*)&NDP_prefix;
+ i6mr.ipv6mr_multiaddr.s6_addr[0xD] = a->b[0xD];
+ i6mr.ipv6mr_multiaddr.s6_addr[0xE] = a->b[0xE];
+ i6mr.ipv6mr_multiaddr.s6_addr[0xF] = a->b[0xF];
+
+ // Do precautionary IPV6_LEAVE_GROUP first, necessary to clear stale kernel state
+ mStatus err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
+ if (err < 0 && (errno != EADDRNOTAVAIL))
+ LogMsg("mDNSPlatformUpdateProxyList: IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
+
+ err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
+ if (err < 0 && (errno != EADDRINUSE)) // Joining same group twice can give "Address already in use" error -- no need to report that
+ LogMsg("mDNSPlatformUpdateProxyList: IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
+
+ LogSPS("Joined IPv6 ND multicast group %.16a for %.16a", &i6mr.ipv6mr_multiaddr, a);
+ }
+
+ if (pc != fail) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc, fail);
+ *pc++ = rf; // fail points here
+
+ if (pc != ret4) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc, ret4);
+ *pc++ = r4a; // ret4 points here
+ *pc++ = r4b;
+ *pc++ = r4c;
+ *pc++ = r4d;
+
+ if (pc != ret6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc, ret6);
+ *pc++ = r6a; // ret6 points here
+
+ struct bpf_program prog = { pc - filter, filter };
+
+#if 0
+ // For debugging BPF filter program
+ unsigned int q;
+ for (q=0; q<prog.bf_len; q++)
+ LogSPS("mDNSPlatformUpdateProxyList: %2d { 0x%02x, %d, %d, 0x%08x },", q, prog.bf_insns[q].code, prog.bf_insns[q].jt, prog.bf_insns[q].jf, prog.bf_insns[q].k);
+#endif
+
+ if (!numv4 && !numv6)
+ {
+ LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
+ if (m->timenow == 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
+ // Schedule check to see if we can close this BPF_fd now
+ if (!m->p->NetworkChanged) m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
+ // prog.bf_len = 0; This seems to panic the kernel
+ if (x->BPF_fd < 0) return; // If we've already closed our BPF_fd, no need to generate an error message below
+ }
+
+ if (ioctl(x->BPF_fd, BIOCSETFNR, &prog) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) failed %d (%s)", prog.bf_len, errno, strerror(errno));
+ else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETFNR(%d) successful", prog.bf_len);
+}
+
+mDNSexport void mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd)
+{
+ mDNS_Lock(m);
+
+ NetworkInterfaceInfoOSX *i;
+ for (i = m->p->InterfaceList; i; i = i->next) if (i->BPF_fd == -2) break;
+ if (!i) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd); close(fd); }
+ else
+ {
+ LogSPS("%s using BPF fd %d", i->ifinfo.ifname, fd);
+
+ struct bpf_version v;
+ if (ioctl(fd, BIOCVERSION, &v) < 0)
+ LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
+ else if (BPF_MAJOR_VERSION != v.bv_major || BPF_MINOR_VERSION != v.bv_minor)
+ LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d",
+ fd, i->ifinfo.ifname, BPF_MAJOR_VERSION, BPF_MINOR_VERSION, v.bv_major, v.bv_minor);
+
+ if (ioctl(fd, BIOCGBLEN, &i->BPF_len) < 0)
+ LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
+
+ if (i->BPF_len > sizeof(m->imsg))
+ {
+ i->BPF_len = sizeof(m->imsg);
+ if (ioctl(fd, BIOCSBLEN, &i->BPF_len) < 0)
+ LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
+ else
+ LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", fd, i->ifinfo.ifname, i->BPF_len);
+ }
+
+ static const u_int opt_one = 1;
+ if (ioctl(fd, BIOCIMMEDIATE, &opt_one) < 0)
+ LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
+
+ //if (ioctl(fd, BIOCPROMISC, &opt_one) < 0)
+ // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
+
+ //if (ioctl(fd, BIOCSHDRCMPLT, &opt_one) < 0)
+ // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
+
+ /* <rdar://problem/10287386>
+ * make socket non blocking see comments in bpf_callback_common for more info
+ */
+ if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
+ {
+ LogMsg("mDNSPlatformReceiveBPF_fd: %d %s O_NONBLOCK failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
+ }
+
+ struct ifreq ifr;
+ mDNSPlatformMemZero(&ifr, sizeof(ifr));
+ strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
+ if (ioctl(fd, BIOCSETIF, &ifr) < 0)
+ { LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); i->BPF_fd = -3; }
+ else
+ {
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+ i->BPF_fd = fd;
+ i->BPF_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, dispatch_get_main_queue());
+ if (!i->BPF_source) {LogMsg("mDNSPlatformReceiveBPF_fd: dispatch source create failed"); return;}
+ dispatch_source_set_event_handler(i->BPF_source, ^{bpf_callback_dispatch(i);});
+ dispatch_source_set_cancel_handler(i->BPF_source, ^{close(fd);});
+ dispatch_resume(i->BPF_source);
+#else
+ CFSocketContext myCFSocketContext = { 0, i, NULL, NULL, NULL };
+ i->BPF_fd = fd;
+ i->BPF_cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, bpf_callback, &myCFSocketContext);
+ i->BPF_rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, i->BPF_cfs, 0);
+ CFRunLoopAddSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode);
+#endif
+ mDNSPlatformUpdateProxyList(m, i->ifinfo.InterfaceID);
+ }
+ }
+
+ mDNS_Unlock(m);
+}
+
+#endif // APPLE_OSX_mDNSResponder
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Key Management
+#endif
+
+#ifndef NO_SECURITYFRAMEWORK
+mDNSlocal CFArrayRef GetCertChain(SecIdentityRef identity)
+{
+ CFMutableArrayRef certChain = NULL;
+ if (!identity) { LogMsg("getCertChain: identity is NULL"); return(NULL); }
+ SecCertificateRef cert;
+ OSStatus err = SecIdentityCopyCertificate(identity, &cert);
+ if (err || !cert) LogMsg("getCertChain: SecIdentityCopyCertificate() returned %d", (int) err);
+ else
+ {
+ SecPolicySearchRef searchRef;
+ err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
+ if (err || !searchRef) LogMsg("getCertChain: SecPolicySearchCreate() returned %d", (int) err);
+ else
+ {
+ SecPolicyRef policy;
+ err = SecPolicySearchCopyNext(searchRef, &policy);
+ if (err || !policy) LogMsg("getCertChain: SecPolicySearchCopyNext() returned %d", (int) err);
+ else
+ {
+ CFArrayRef wrappedCert = CFArrayCreate(NULL, (const void**) &cert, 1, &kCFTypeArrayCallBacks);
+ if (!wrappedCert) LogMsg("getCertChain: wrappedCert is NULL");
+ else
+ {
+ SecTrustRef trust;
+ err = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
+ if (err || !trust) LogMsg("getCertChain: SecTrustCreateWithCertificates() returned %d", (int) err);
+ else
+ {
+ err = SecTrustEvaluate(trust, NULL);
+ if (err) LogMsg("getCertChain: SecTrustEvaluate() returned %d", (int) err);
+ else
+ {
+ CFArrayRef rawCertChain;
+ CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
+ err = SecTrustGetResult(trust, NULL, &rawCertChain, &statusChain);
+ if (err || !rawCertChain || !statusChain) LogMsg("getCertChain: SecTrustGetResult() returned %d", (int) err);
+ else
+ {
+ certChain = CFArrayCreateMutableCopy(NULL, 0, rawCertChain);
+ if (!certChain) LogMsg("getCertChain: certChain is NULL");
+ else
+ {
+ // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
+ // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
+ CFArraySetValueAtIndex(certChain, 0, identity);
+ // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
+ if (CFArrayGetCount(certChain) > 1) CFArrayRemoveValueAtIndex(certChain, CFArrayGetCount(certChain) - 1);
+ }
+ CFRelease(rawCertChain);
+ // Do not free statusChain:
+ // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
+ // certChain: Call the CFRelease function to release this object when you are finished with it.
+ // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
+ }
+ }
+ CFRelease(trust);
+ }
+ CFRelease(wrappedCert);
+ }
+ CFRelease(policy);
+ }
+ CFRelease(searchRef);
+ }
+ CFRelease(cert);
+ }
+ return certChain;
+}
+#endif /* NO_SECURITYFRAMEWORK */
+
+mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
+{
+#ifdef NO_SECURITYFRAMEWORK
+ return mStatus_UnsupportedErr;
+#else
+ SecIdentityRef identity = nil;
+ SecIdentitySearchRef srchRef = nil;
+ OSStatus err;
+
+ // search for "any" identity matching specified key use
+ // In this app, we expect there to be exactly one
+ err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_DECRYPT, &srchRef);
+ if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err); return err; }
+
+ err = SecIdentitySearchCopyNext(srchRef, &identity);
+ if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err); return err; }
+
+ if (CFGetTypeID(identity) != SecIdentityGetTypeID())
+ { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr; }
+
+ // Found one. Call getCertChain to create the correct certificate chain.
+ ServerCerts = GetCertChain(identity);
+ if (ServerCerts == nil) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: getCertChain error"); return mStatus_UnknownErr; }
+
+ return mStatus_NoError;
+#endif /* NO_SECURITYFRAMEWORK */
+}
+
+mDNSexport void mDNSPlatformTLSTearDownCerts(void)
+{
+#ifndef NO_SECURITYFRAMEWORK
+ if (ServerCerts) { CFRelease(ServerCerts); ServerCerts = NULL; }
+#endif /* NO_SECURITYFRAMEWORK */
+}
+
+// This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
+mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
+{
+ CFStringEncoding encoding = kCFStringEncodingUTF8;
+ CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
+ if (cfs)
+ {
+ CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
+ CFRelease(cfs);
+ }
+}
+
+// This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
+mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
+{
+ CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
+ if (cfs)
+ {
+ CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
+ CFRelease(cfs);
+ }
+}
+
+mDNSexport mDNSBool DictionaryIsEnabled(CFDictionaryRef dict)
+{
+ mDNSs32 val;
+ CFNumberRef state = (CFNumberRef)CFDictionaryGetValue(dict, CFSTR("Enabled"));
+ if (!state) return mDNSfalse;
+ if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val))
+ { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse; }
+ return val ? mDNStrue : mDNSfalse;
+}
+
+mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
+{
+ if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
+
+ if (sa->sa_family == AF_INET)
+ {
+ struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
+ ip->type = mDNSAddrType_IPv4;
+ ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
+ return(mStatus_NoError);
+ }
+
+ if (sa->sa_family == AF_INET6)
+ {
+ struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
+ // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
+ // value into the second word of the IPv6 link-local address, so they can just
+ // pass around IPv6 address structures instead of full sockaddr_in6 structures.
+ // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
+ // To work around this we always whack the second word of any IPv6 link-local address back to zero.
+ if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
+ ip->type = mDNSAddrType_IPv6;
+ ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
+ return(mStatus_NoError);
+ }
+
+ LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
+ return(mStatus_Invalid);
+}
+
+mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name)
+{
+ mDNSEthAddr eth = zeroEthAddr;
+ SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetBSSID"), NULL, NULL);
+ if (!store)
+ LogMsg("GetBSSID: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
+ else
+ {
+ CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name);
+ if (entityname)
+ {
+ CFDictionaryRef dict = SCDynamicStoreCopyValue(store, entityname);
+ if (dict)
+ {
+ CFRange range = { 0, 6 }; // Offset, length
+ CFDataRef data = CFDictionaryGetValue(dict, CFSTR("BSSID"));
+ if (data && CFDataGetLength(data) == 6) CFDataGetBytes(data, range, eth.b);
+ CFRelease(dict);
+ }
+ CFRelease(entityname);
+ }
+ CFRelease(store);
+ }
+ return(eth);
+}
+
+mDNSlocal int GetMAC(mDNSEthAddr *eth, u_short ifindex)
+{
+ struct ifaddrs *ifa;
+ for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
+ if (ifa->ifa_addr->sa_family == AF_LINK)
+ {
+ const struct sockaddr_dl *const sdl = (const struct sockaddr_dl *)ifa->ifa_addr;
+ if (sdl->sdl_index == ifindex)
+ { mDNSPlatformMemCopy(eth->b, sdl->sdl_data + sdl->sdl_nlen, 6); return 0; }
+ }
+ *eth = zeroEthAddr;
+ return -1;
+}
+
+#ifndef SIOCGIFWAKEFLAGS
+#define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
+#endif
+
+#ifndef IF_WAKE_ON_MAGIC_PACKET
+#define IF_WAKE_ON_MAGIC_PACKET 0x01
+#endif
+
+#ifndef ifr_wake_flags
+#define ifr_wake_flags ifr_ifru.ifru_intval
+#endif
+
+mDNSlocal mDNSBool CheckInterfaceSupport(NetworkInterfaceInfo *const intf, const char *key)
+{
+ io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
+ if (!service)
+ {
+ LogSPS("CheckInterfaceSupport: No service for interface %s", intf->ifname);
+ return mDNSfalse;
+ }
+
+ io_name_t n1, n2;
+ IOObjectGetClass(service, n1);
+ io_object_t parent;
+ mDNSBool ret = mDNSfalse;
+ kern_return_t kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
+ if (kr == KERN_SUCCESS)
+ {
+ CFStringRef keystr = CFStringCreateWithCString(NULL, key, kCFStringEncodingUTF8);
+ IOObjectGetClass(parent, n2);
+ LogSPS("CheckInterfaceSupport: Interface %s service %s parent %s", intf->ifname, n1, n2);
+ const CFTypeRef ref = IORegistryEntryCreateCFProperty(parent, keystr, kCFAllocatorDefault, mDNSNULL);
+ if (!ref)
+ {
+ LogSPS("CheckInterfaceSupport: No mDNS_IOREG_KEY for interface %s/%s/%s", intf->ifname, n1, n2);
+ ret = mDNSfalse;
+ }
+ else
+ {
+ ret = mDNStrue;
+ CFRelease(ref);
+ }
+ IOObjectRelease(parent);
+ CFRelease(keystr);
+ }
+ else
+ {
+ LogSPS("CheckInterfaceSupport: IORegistryEntryGetParentEntry for %s/%s failed %d", intf->ifname, n1, kr);
+ ret = mDNSfalse;
+ }
+ IOObjectRelease(service);
+ return ret;
+}
+
+
+mDNSlocal mDNSBool InterfaceSupportsKeepAlive(NetworkInterfaceInfo *const intf)
+{
+ return CheckInterfaceSupport(intf, mDNS_IOREG_KA_KEY);
+}
+
+mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i)
+{
+ if (!MulticastInterface(i) ) return(mDNSfalse); // We only use Sleep Proxy Service on multicast-capable interfaces
+ if (i->ifa_flags & IFF_LOOPBACK) return(mDNSfalse); // except loopback
+
+ // If the interface supports TCPKeepalive, it is capable of waking up for a magic packet
+ // This check is needed since the SIOCGIFWAKEFLAGS ioctl returns wrong values for WOMP capability
+ // when the power source is not AC Power.
+ if (InterfaceSupportsKeepAlive(&i->ifinfo))
+ {
+ LogSPS("NetWakeInterface: %s supports TCP Keepalive returning true", i->ifinfo.ifname);
+ return mDNStrue;
+ }
+
+ int s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) { LogMsg("NetWakeInterface socket failed %s error %d errno %d (%s)", i->ifinfo.ifname, s, errno, strerror(errno)); return(mDNSfalse); }
+
+ struct ifreq ifr;
+ strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
+ if (ioctl(s, SIOCGIFWAKEFLAGS, &ifr) < 0)
+ {
+ // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be
+ // 102 when compiling kernel code, and 45 when compiling user-level code. Since this
+ // error code is being returned from the kernel, we need to use the kernel version.
+ #define KERNEL_EOPNOTSUPP 102
+ if (errno != KERNEL_EOPNOTSUPP) // "Operation not supported on socket", the expected result on Leopard and earlier
+ LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i->ifinfo.ifname, errno, strerror(errno));
+ // If on Leopard or earlier, we get EOPNOTSUPP, so in that case
+ // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on.
+ ifr.ifr_wake_flags = (errno == KERNEL_EOPNOTSUPP && !(i)->BSSID.l[0] && i->m->SystemWakeOnLANEnabled) ? IF_WAKE_ON_MAGIC_PACKET : 0;
+ }
+
+ close(s);
+
+ // ifr.ifr_wake_flags = IF_WAKE_ON_MAGIC_PACKET; // For testing with MacBook Air, using a USB dongle that doesn't actually support Wake-On-LAN
+
+ LogSPS("%-6s %#-14a %s WOMP", i->ifinfo.ifname, &i->ifinfo.ip, (ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) ? "supports" : "no");
+
+ return((ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) != 0);
+}
+
+mDNSlocal u_int64_t getExtendedFlags(char * ifa_name)
+{
+ int sockFD;
+ struct ifreq ifr;
+
+ sockFD = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sockFD < 0)
+ {
+ LogMsg("getExtendedFlags: socket() call failed, errno = %d (%s)", errno, strerror(errno));
+ return 0;
+ }
+
+ ifr.ifr_addr.sa_family = AF_INET;
+ strlcpy(ifr.ifr_name, ifa_name, sizeof(ifr.ifr_name));
+
+ if (ioctl(sockFD, SIOCGIFEFLAGS, (caddr_t)&ifr) == -1)
+ {
+ LogMsg("getExtendedFlags: SIOCGIFEFLAGS failed, errno = %d (%s)", errno, strerror(errno));
+ ifr.ifr_eflags = 0;
+ }
+ LogInfo("getExtendedFlags: %s ifr_eflags = 0x%x", ifa_name, ifr.ifr_eflags);
+
+ close(sockFD);
+ return ifr.ifr_eflags;
+}
+
+// Returns pointer to newly created NetworkInterfaceInfoOSX object, or
+// pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
+// may return NULL if out of memory (unlikely) or parameters are invalid for some reason
+// (e.g. sa_family not AF_INET or AF_INET6)
+mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa, mDNSs32 utc)
+{
+ mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
+ mDNSEthAddr bssid = GetBSSID(ifa->ifa_name);
+ u_int64_t eflags = getExtendedFlags(ifa->ifa_name);
+
+ mDNSAddr ip, mask;
+ if (SetupAddr(&ip, ifa->ifa_addr ) != mStatus_NoError) return(NULL);
+ if (SetupAddr(&mask, ifa->ifa_netmask) != mStatus_NoError) return(NULL);
+
+ NetworkInterfaceInfoOSX **p;
+ for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
+ if (scope_id == (*p)->scope_id &&
+ mDNSSameAddress(&ip, &(*p)->ifinfo.ip) &&
+ mDNSSameEthAddress(&bssid, &(*p)->BSSID))
+ {
+ debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p, ifname before %s, after %s", scope_id, &bssid, &ip, *p, (*p)->ifinfo.ifname, ifa->ifa_name);
+ // The name should be updated to the new name so that we don't report a wrong name in our SIGINFO output.
+ // When interfaces are created with same MAC address, kernel resurrects the old interface.
+ // Even though the interface index is the same (which should be sufficient), when we receive a UDP packet
+ // we get the corresponding name for the interface index on which the packet was received and check against
+ // the InterfaceList for a matching name. So, keep the name in sync
+ strlcpy((*p)->ifinfo.ifname, ifa->ifa_name, sizeof((*p)->ifinfo.ifname));
+ (*p)->Exists = mDNStrue;
+ // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
+ if ((*p)->LastSeen != utc) (*p)->AppearanceTime = utc;
+
+ // If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected)
+ // we may need to start or stop or sleep proxy browse operation
+ const mDNSBool NetWake = NetWakeInterface(*p);
+ if ((*p)->ifinfo.NetWake != NetWake)
+ {
+ (*p)->ifinfo.NetWake = NetWake;
+ // If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly.
+ // If this interface is not already registered (i.e. it's a dormant interface we had in our list
+ // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet.
+ // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary.
+ if ((*p)->Registered)
+ {
+ mDNS_Lock(m);
+ if (NetWake) mDNS_ActivateNetWake_internal (m, &(*p)->ifinfo);
+ else mDNS_DeactivateNetWake_internal(m, &(*p)->ifinfo);
+ mDNS_Unlock(m);
+ }
+ }
+ // Reset the flag if it has changed this time.
+ (*p)->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue;
+
+ return(*p);
+ }
+
+ NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
+ debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
+ if (!i) return(mDNSNULL);
+ mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX));
+ i->ifinfo.InterfaceID = (mDNSInterfaceID)(uintptr_t)scope_id;
+ i->ifinfo.ip = ip;
+ i->ifinfo.mask = mask;
+ strlcpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
+ i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0;
+ // We can be configured to disable multicast advertisement, but we want to to support
+ // local-only services, which need a loopback address record.
+ i->ifinfo.Advertise = m->DivertMulticastAdvertisements ? ((ifa->ifa_flags & IFF_LOOPBACK) ? mDNStrue : mDNSfalse) : m->AdvertiseLocalAddresses;
+ i->ifinfo.McastTxRx = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList
+ i->ifinfo.Loopback = ((ifa->ifa_flags & IFF_LOOPBACK) != 0) ? mDNStrue : mDNSfalse;
+ i->ifinfo.IgnoreIPv4LL = ((eflags & IFEF_ARPLL) != 0) ? mDNSfalse : mDNStrue;
+ i->ifinfo.DirectLink = (eflags & IFEF_DIRECTLINK) ? mDNStrue: mDNSfalse;
+
+ i->next = mDNSNULL;
+ i->m = m;
+ i->Exists = mDNStrue;
+ i->Flashing = mDNSfalse;
+ i->Occulting = mDNSfalse;
+ i->D2DInterface = (eflags & IFEF_LOCALNET_PRIVATE) ? mDNStrue: mDNSfalse;
+ if (eflags & IFEF_AWDL)
+ {
+ AWDLInterfaceID = i->ifinfo.InterfaceID;
+ LogInfo("AddInterfaceToList: AWDLInterfaceID = %d", (int) AWDLInterfaceID);
+ }
+ i->AppearanceTime = utc; // Brand new interface; AppearanceTime is now
+ i->LastSeen = utc;
+ i->ifa_flags = ifa->ifa_flags;
+ i->scope_id = scope_id;
+ i->BSSID = bssid;
+ i->sa_family = ifa->ifa_addr->sa_family;
+ i->BPF_fd = -1;
+ i->BPF_mcfd = -1;
+ i->BPF_len = 0;
+ i->Registered = mDNSNULL;
+
+ // Do this AFTER i->BSSID has been set up
+ i->ifinfo.NetWake = NetWakeInterface(i);
+ GetMAC(&i->ifinfo.MAC, scope_id);
+ if (i->ifinfo.NetWake && !i->ifinfo.MAC.l[0])
+ LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i->ifinfo.MAC, scope_id, i->ifinfo.ifname, &ip);
+
+ *p = i;
+ return(i);
+}
+
+#if APPLE_OSX_mDNSResponder
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - AutoTunnel
+#endif
+
+#define kRacoonPort 4500
+
+static DomainAuthInfo* AnonymousRacoonConfig = mDNSNULL;
+
+#ifndef NO_SECURITYFRAMEWORK
+
+static CFMutableDictionaryRef domainStatusDict = NULL;
+
+mDNSlocal mStatus CheckQuestionForStatus(const DNSQuestion *const q)
+{
+ if (q->LongLived)
+ {
+ if (q->servAddr.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsOnes(q->servAddr.ip.v4))
+ return mStatus_NoSuchRecord;
+ else if (q->state == LLQ_Poll)
+ return mStatus_PollingMode;
+ else if (q->state != LLQ_Established && !q->DuplicateOf)
+ return mStatus_TransientErr;
+ }
+
+ return mStatus_NoError;
+}
+
+mDNSlocal mStatus UpdateLLQStatus(const mDNS *const m, char *buffer, int bufsz, const DomainAuthInfo *const info)
+{
+ mStatus status = mStatus_NoError;
+ DNSQuestion* q, *worst_q = mDNSNULL;
+ for (q = m->Questions; q; q=q->next)
+ if (q->AuthInfo == info)
+ {
+ mStatus newStatus = CheckQuestionForStatus(q);
+ if (newStatus == mStatus_NoSuchRecord) { status = newStatus; worst_q = q; break; }
+ else if (newStatus == mStatus_PollingMode) { status = newStatus; worst_q = q; }
+ else if (newStatus == mStatus_TransientErr && status == mStatus_NoError) { status = newStatus; worst_q = q; }
+ }
+
+ if (status == mStatus_NoError) mDNS_snprintf(buffer, bufsz, "Success");
+ else if (status == mStatus_NoSuchRecord) mDNS_snprintf(buffer, bufsz, "GetZoneData %s: %##s", worst_q->nta ? "not yet complete" : "failed", worst_q->qname.c);
+ else if (status == mStatus_PollingMode) mDNS_snprintf(buffer, bufsz, "Query polling %##s", worst_q->qname.c);
+ else if (status == mStatus_TransientErr) mDNS_snprintf(buffer, bufsz, "Query not yet established %##s", worst_q->qname.c);
+ return status;
+}
+
+mDNSlocal mStatus UpdateRRStatus(const mDNS *const m, char *buffer, int bufsz, const DomainAuthInfo *const info)
+{
+ AuthRecord *r;
+
+ if (info->deltime) return mStatus_NoError;
+ for (r = m->ResourceRecords; r; r = r->next)
+ {
+ // This function is called from UpdateAutoTunnelDomainStatus which in turn may be called from
+ // a callback e.g., CheckNATMappings. GetAuthInfoFor_internal does not like that (reentrancy being 1),
+ // hence we inline the code here. We just need the lock to walk the list of AuthInfos which the caller
+ // has already checked
+ const domainname *n = r->resrec.name;
+ while (n->c[0])
+ {
+ DomainAuthInfo *ptr;
+ for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
+ if (SameDomainName(&ptr->domain, n))
+ {
+ if (ptr == info && (r->updateError == mStatus_BadSig || r->updateError == mStatus_BadKey || r->updateError == mStatus_BadTime))
+ {
+ mDNS_snprintf(buffer, bufsz, "Resource record update failed for %##s", r->resrec.name);
+ return r->updateError;
+ }
+ }
+ n = (const domainname *)(n->c + 1 + n->c[0]);
+ }
+ }
+ return mStatus_NoError;
+}
+
+#endif // ndef NO_SECURITYFRAMEWORK
+
+// MUST be called with lock held
+mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAuthInfo *const info)
+{
+#ifdef NO_SECURITYFRAMEWORK
+ (void) m;
+ (void)info;
+#else
+ // Note that in the LLQNAT, the clientCallback being non-zero means it's in use,
+ // whereas in the AutoTunnelNAT, the clientContext being non-zero means it's in use
+ const NATTraversalInfo *const llq = m->LLQNAT.clientCallback ? &m->LLQNAT : mDNSNULL;
+ const NATTraversalInfo *const tun = m->AutoTunnelNAT.clientContext ? &m->AutoTunnelNAT : mDNSNULL;
+ char buffer[1024];
+ mDNSu32 buflen = 0;
+ CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ CFStringRef domain = NULL;
+ CFStringRef tmp = NULL;
+ CFNumberRef num = NULL;
+ mStatus status = mStatus_NoError;
+ mStatus llqStatus = mStatus_NoError;
+ char llqBuffer[1024];
+
+ mDNS_CheckLock(m);
+
+ if (!domainStatusDict)
+ {
+ domainStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ if (!domainStatusDict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; }
+ }
+
+ if (!dict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; }
+
+ buflen = mDNS_snprintf(buffer, sizeof(buffer), "%##s", info->domain.c);
+ domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
+ if (!domain) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString domain"); return; }
+
+ if (info->deltime)
+ {
+ if (CFDictionaryContainsKey(domainStatusDict, domain))
+ {
+ CFDictionaryRemoveValue(domainStatusDict, domain);
+ if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
+ }
+ CFRelease(domain);
+ CFRelease(dict);
+
+ return;
+ }
+
+ mDNS_snprintf(buffer, sizeof(buffer), "%#a", &m->Router);
+ tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
+ if (!tmp)
+ LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress");
+ else
+ {
+ CFDictionarySetValue(dict, CFSTR("RouterAddress"), tmp);
+ CFRelease(tmp);
+ }
+
+ if (llq)
+ {
+ mDNSu32 port = mDNSVal16(llq->ExternalPort);
+
+ num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
+ if (!num)
+ LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort");
+ else
+ {
+ CFDictionarySetValue(dict, CFSTR("LLQExternalPort"), num);
+ CFRelease(num);
+ }
+
+ if (llq->Result)
+ {
+ num = CFNumberCreate(NULL, kCFNumberSInt32Type, &llq->Result);
+ if (!num)
+ LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus");
+ else
+ {
+ CFDictionarySetValue(dict, CFSTR("LLQNPMStatus"), num);
+ CFRelease(num);
+ }
+ }
+ }
+
+ if (tun)
+ {
+ mDNSu32 port = mDNSVal16(tun->ExternalPort);
+
+ num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
+ if (!num)
+ LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort");
+ else
+ {
+ CFDictionarySetValue(dict, CFSTR("AutoTunnelExternalPort"), num);
+ CFRelease(num);
+ }
+
+ mDNS_snprintf(buffer, sizeof(buffer), "%.4a", &tun->ExternalAddress);
+ tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
+ if (!tmp)
+ LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress");
+ else
+ {
+ CFDictionarySetValue(dict, CFSTR("ExternalAddress"), tmp);
+ CFRelease(tmp);
+ }
+
+ if (tun->Result)
+ {
+ num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tun->Result);
+ if (!num)
+ LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus");
+ else
+ {
+ CFDictionarySetValue(dict, CFSTR("AutoTunnelNPMStatus"), num);
+ CFRelease(num);
+ }
+ }
+ }
+ if (tun || llq)
+ {
+ mDNSu32 code = m->LastNATMapResultCode;
+
+ num = CFNumberCreate(NULL, kCFNumberSInt32Type, &code);
+ if (!num)
+ LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode");
+ else
+ {
+ CFDictionarySetValue(dict, CFSTR("LastNATMapResultCode"), num);
+ CFRelease(num);
+ }
+ }
+
+ mDNS_snprintf(buffer, sizeof(buffer), "Success");
+ llqStatus = UpdateLLQStatus(m, llqBuffer, sizeof(llqBuffer), info);
+ status = UpdateRRStatus(m, buffer, sizeof(buffer), info);
+
+ // If we have a bad signature error updating a RR, it overrides any error as it needs to be
+ // reported so that it can be fixed automatically (or the user needs to be notified)
+ if (status != mStatus_NoError)
+ {
+ LogInfo("UpdateAutoTunnelDomainStatus: RR Status %d, %s", status, buffer);
+ }
+ else if (m->Router.type == mDNSAddrType_None)
+ {
+ status = mStatus_NoRouter;
+ mDNS_snprintf(buffer, sizeof(buffer), "No network connection - none");
+ }
+ else if (m->Router.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero(m->Router.ip.v4))
+ {
+ status = mStatus_NoRouter;
+ mDNS_snprintf(buffer, sizeof(buffer), "No network connection - v4 zero");
+ }
+ else if (mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress))
+ {
+ status = mStatus_ServiceNotRunning;
+ mDNS_snprintf(buffer, sizeof(buffer), "No inner address");
+ }
+ else if (!llq && !tun)
+ {
+ status = mStatus_NotInitializedErr;
+ mDNS_snprintf(buffer, sizeof(buffer), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
+ }
+ else if (llqStatus == mStatus_NoSuchRecord)
+ {
+ status = llqStatus;
+ mDNS_snprintf(buffer, sizeof(buffer), llqBuffer);
+ }
+ else if ((llq && llq->Result == mStatus_DoubleNAT) || (tun && tun->Result == mStatus_DoubleNAT))
+ {
+ status = mStatus_DoubleNAT;
+ mDNS_snprintf(buffer, sizeof(buffer), "Double NAT: Router is reporting a private address");
+ }
+ else if ((llq && llq->Result == mStatus_NATPortMappingDisabled) ||
+ (tun && tun->Result == mStatus_NATPortMappingDisabled) ||
+ (m->LastNATMapResultCode == NATErr_Refused && ((llq && !llq->Result && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && !tun->Result && mDNSIPPortIsZero(tun->ExternalPort)))))
+ {
+ status = mStatus_NATPortMappingDisabled;
+ mDNS_snprintf(buffer, sizeof(buffer), "PCP/NAT-PMP is disabled on the router");
+ }
+ else if ((llq && llq->Result) || (tun && tun->Result))
+ {
+ status = mStatus_NATTraversal;
+ mDNS_snprintf(buffer, sizeof(buffer), "Error obtaining NAT port mapping from router");
+ }
+ else if ((llq && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && mDNSIPPortIsZero(tun->ExternalPort)))
+ {
+ status = mStatus_NATTraversal;
+ mDNS_snprintf(buffer, sizeof(buffer), "Unable to obtain NAT port mapping from router");
+ }
+ else
+ {
+ status = llqStatus;
+ mDNS_snprintf(buffer, sizeof(buffer), llqBuffer);
+ LogInfo("UpdateAutoTunnelDomainStatus: LLQ Status %d, %s", status, buffer);
+ }
+
+ num = CFNumberCreate(NULL, kCFNumberSInt32Type, &status);
+ if (!num)
+ LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode");
+ else
+ {
+ CFDictionarySetValue(dict, CFSTR("StatusCode"), num);
+ CFRelease(num);
+ }
+
+ tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
+ if (!tmp)
+ LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage");
+ else
+ {
+ CFDictionarySetValue(dict, CFSTR("StatusMessage"), tmp);
+ CFRelease(tmp);
+ }
+
+ if (!CFDictionaryContainsKey(domainStatusDict, domain) ||
+ !CFEqual(dict, (CFMutableDictionaryRef)CFDictionaryGetValue(domainStatusDict, domain)))
+ {
+ CFDictionarySetValue(domainStatusDict, domain, dict);
+ if (!m->ShutdownTime)
+ {
+ static char statusBuf[16];
+ mDNS_snprintf(statusBuf, sizeof(statusBuf), "%d", (int)status);
+ mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.domainstatus", status ? "failure" : "success", statusBuf, "");
+ mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
+ }
+ }
+
+ CFRelease(domain);
+ CFRelease(dict);
+
+ debugf("UpdateAutoTunnelDomainStatus: %s", buffer);
+#endif // def NO_SECURITYFRAMEWORK
+}
+
+// MUST be called with lock held
+mDNSexport void UpdateAutoTunnelDomainStatuses(const mDNS *const m)
+{
+#ifdef NO_SECURITYFRAMEWORK
+ (void) m;
+#else
+ mDNS_CheckLock(m);
+ DomainAuthInfo* info;
+ for (info = m->AuthInfoList; info; info = info->next)
+ if (info->AutoTunnel && !info->deltime)
+ UpdateAutoTunnelDomainStatus(m, info);
+#endif // def NO_SECURITYFRAMEWORK
+}
+
+mDNSlocal void UpdateAnonymousRacoonConfig(mDNS *m) // Determine whether we need racoon to accept incoming connections
+{
+ DomainAuthInfo *info;
+
+ for (info = m->AuthInfoList; info; info = info->next)
+ if (info->AutoTunnel && !info->deltime && (!mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || !mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr)))
+ break;
+
+ if (info != AnonymousRacoonConfig)
+ {
+ AnonymousRacoonConfig = info;
+ // Create or revert configuration file, and start (or SIGHUP) Racoon
+ (void)mDNSConfigureServer(AnonymousRacoonConfig ? kmDNSUp : kmDNSDown, AnonymousRacoonConfig ? btmmprefix : mDNSNULL, AnonymousRacoonConfig ? &AnonymousRacoonConfig->domain : mDNSNULL);
+ }
+}
+
+mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
+
+// Caller must hold the lock
+mDNSlocal mDNSBool DeregisterAutoTunnelRecord(mDNS *m, DomainAuthInfo *info, AuthRecord* record)
+{
+ mDNS_CheckLock(m);
+
+ LogInfo("DeregisterAutoTunnelRecord %##s %##s", &info->domain.c, record->namestorage.c);
+
+ if (record->resrec.RecordType > kDNSRecordTypeDeregistering)
+ {
+ mStatus err = mDNS_Deregister_internal(m, record, mDNS_Dereg_normal);
+ if (err)
+ {
+ record->resrec.RecordType = kDNSRecordTypeUnregistered;
+ LogMsg("DeregisterAutoTunnelRecord error %d deregistering %##s %##s", err, info->domain.c, record->namestorage.c);
+ return mDNSfalse;
+ }
+ else LogInfo("DeregisterAutoTunnelRecord: Deregistered");
+ }
+ else LogInfo("DeregisterAutoTunnelRecord: Not deregistering, state:%d", record->resrec.RecordType);
+
+ return mDNStrue;
+}
+
+// Caller must hold the lock
+mDNSlocal void DeregisterAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
+{
+ if (!DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelHostRecord))
+ {
+ info->AutoTunnelHostRecord.namestorage.c[0] = 0;
+ m->NextSRVUpdate = NonZeroTime(m->timenow);
+ }
+}
+
+// Caller must hold the lock
+mDNSlocal void UpdateAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
+{
+ mStatus err;
+ mDNSBool NATProblem = mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result;
+
+ mDNS_CheckLock(m);
+
+ if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress) || (m->SleepState != SleepState_Awake && NATProblem))
+ {
+ LogInfo("UpdateAutoTunnelHostRecord: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) address(%.16a) sleepstate(%d)",
+ info->domain.c, info->AutoTunnelServiceStarted, info->deltime, &info->AutoTunnelInnerAddress, m->SleepState);
+ DeregisterAutoTunnelHostRecord(m, info);
+ }
+ else if (info->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered)
+ {
+ mDNS_SetupResourceRecord(&info->AutoTunnelHostRecord, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
+ kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
+ info->AutoTunnelHostRecord.namestorage.c[0] = 0;
+ AppendDomainLabel(&info->AutoTunnelHostRecord.namestorage, &m->hostlabel);
+ AppendDomainName (&info->AutoTunnelHostRecord.namestorage, &info->domain);
+ info->AutoTunnelHostRecord.resrec.rdata->u.ipv6 = info->AutoTunnelInnerAddress;
+ info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeKnownUnique;
+
+ err = mDNS_Register_internal(m, &info->AutoTunnelHostRecord);
+ if (err) LogMsg("UpdateAutoTunnelHostRecord error %d registering %##s", err, info->AutoTunnelHostRecord.namestorage.c);
+ else
+ {
+ // Make sure we trigger the registration of all SRV records in regState_NoTarget again
+ m->NextSRVUpdate = NonZeroTime(m->timenow);
+ LogInfo("UpdateAutoTunnelHostRecord registering %##s", info->AutoTunnelHostRecord.namestorage.c);
+ }
+ }
+ else LogInfo("UpdateAutoTunnelHostRecord: Type %d", info->AutoTunnelHostRecord.resrec.RecordType);
+}
+
+// Caller must hold the lock
+mDNSlocal void DeregisterAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
+{
+ LogInfo("DeregisterAutoTunnelServiceRecords %##s", info->domain.c);
+
+ DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelTarget);
+ DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelService);
+ UpdateAutoTunnelHostRecord(m, info);
+}
+
+// Caller must hold the lock
+mDNSlocal void UpdateAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
+{
+ mDNS_CheckLock(m);
+
+ if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result)
+ {
+ LogInfo("UpdateAutoTunnelServiceRecords: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) ExtPort(%d) NATResult(%d)", info->domain.c, info->AutoTunnelServiceStarted, info->deltime, mDNSVal16(m->AutoTunnelNAT.ExternalPort), m->AutoTunnelNAT.Result);
+ DeregisterAutoTunnelServiceRecords(m, info);
+ }
+ else
+ {
+ if (info->AutoTunnelTarget.resrec.RecordType == kDNSRecordTypeUnregistered)
+ {
+ // 1. Set up our address record for the external tunnel address
+ // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
+ mDNS_SetupResourceRecord(&info->AutoTunnelTarget, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL,
+ kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
+ AssignDomainName (&info->AutoTunnelTarget.namestorage, (const domainname*) "\x0B" "_autotunnel");
+ AppendDomainLabel(&info->AutoTunnelTarget.namestorage, &m->hostlabel);
+ AppendDomainName (&info->AutoTunnelTarget.namestorage, &info->domain);
+ info->AutoTunnelTarget.resrec.rdata->u.ipv4 = m->AutoTunnelNAT.ExternalAddress;
+ info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeKnownUnique;
+
+ mStatus err = mDNS_Register_internal(m, &info->AutoTunnelTarget);
+ if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelTarget.namestorage.c);
+ else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelTarget.namestorage.c);
+ }
+ else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Target state(%d)", info->AutoTunnelTarget.resrec.RecordType);
+
+ if (info->AutoTunnelService.resrec.RecordType == kDNSRecordTypeUnregistered)
+ {
+ // 2. Set up IKE tunnel's SRV record: _autotunnel._udp.AutoTunnelHost SRV 0 0 port AutoTunnelTarget
+ mDNS_SetupResourceRecord(&info->AutoTunnelService, mDNSNULL, mDNSInterface_Any, kDNSType_SRV, kHostNameTTL,
+ kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
+ AssignDomainName (&info->AutoTunnelService.namestorage, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
+ AppendDomainLabel(&info->AutoTunnelService.namestorage, &m->hostlabel);
+ AppendDomainName (&info->AutoTunnelService.namestorage, &info->domain);
+ info->AutoTunnelService.resrec.rdata->u.srv.priority = 0;
+ info->AutoTunnelService.resrec.rdata->u.srv.weight = 0;
+ info->AutoTunnelService.resrec.rdata->u.srv.port = m->AutoTunnelNAT.ExternalPort;
+ AssignDomainName(&info->AutoTunnelService.resrec.rdata->u.srv.target, &info->AutoTunnelTarget.namestorage);
+ info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeKnownUnique;
+
+ mStatus err = mDNS_Register_internal(m, &info->AutoTunnelService);
+ if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelService.namestorage.c);
+ else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelService.namestorage.c);
+ }
+ else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Service state(%d)", info->AutoTunnelService.resrec.RecordType);
+
+ UpdateAutoTunnelHostRecord(m, info);
+
+ LogInfo("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
+ info->AutoTunnelTarget.namestorage.c, &m->AdvertisedV4.ip.v4, mDNSVal16(m->AutoTunnelNAT.IntPort),
+ info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
+
+ }
+}
+
+// Caller must hold the lock
+mDNSlocal void DeregisterAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
+{
+ DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelDeviceInfo);
+}
+
+// Caller must hold the lock
+mDNSlocal void UpdateAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
+{
+ mDNS_CheckLock(m);
+
+ if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime)
+ DeregisterAutoTunnelDeviceInfoRecord(m, info);
+ else if (info->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered)
+ {
+ mDNS_SetupResourceRecord(&info->AutoTunnelDeviceInfo, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
+ ConstructServiceName(&info->AutoTunnelDeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &info->domain);
+
+ info->AutoTunnelDeviceInfo.resrec.rdlength = initializeDeviceInfoTXT(m, info->AutoTunnelDeviceInfo.resrec.rdata->u.data);
+ info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeKnownUnique;
+
+ mStatus err = mDNS_Register_internal(m, &info->AutoTunnelDeviceInfo);
+ if (err) LogMsg("UpdateAutoTunnelDeviceInfoRecord error %d registering %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
+ else LogInfo("UpdateAutoTunnelDeviceInfoRecord registering %##s", info->AutoTunnelDeviceInfo.namestorage.c);
+ }
+ else
+ LogInfo("UpdateAutoTunnelDeviceInfoRecord: not in Unregistered state: %d",info->AutoTunnelDeviceInfo.resrec.RecordType);
+}
+
+// Caller must hold the lock
+mDNSlocal void DeregisterAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
+{
+ LogInfo("DeregisterAutoTunnel6Record %##s", info->domain.c);
+
+ DeregisterAutoTunnelRecord(m, info, &info->AutoTunnel6Record);
+ UpdateAutoTunnelHostRecord(m, info);
+ UpdateAutoTunnelDomainStatus(m, info);
+}
+
+// Caller must hold the lock
+mDNSlocal void UpdateAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
+{
+ mDNS_CheckLock(m);
+
+ if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr) || m->SleepState != SleepState_Awake)
+ DeregisterAutoTunnel6Record(m, info);
+ else if (info->AutoTunnel6Record.resrec.RecordType == kDNSRecordTypeUnregistered)
+ {
+ mDNS_SetupResourceRecord(&info->AutoTunnel6Record, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
+ kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
+ AssignDomainName (&info->AutoTunnel6Record.namestorage, (const domainname*) "\x0C" "_autotunnel6");
+ AppendDomainLabel(&info->AutoTunnel6Record.namestorage, &m->hostlabel);
+ AppendDomainName (&info->AutoTunnel6Record.namestorage, &info->domain);
+ info->AutoTunnel6Record.resrec.rdata->u.ipv6 = m->AutoTunnelRelayAddr;
+ info->AutoTunnel6Record.resrec.RecordType = kDNSRecordTypeKnownUnique;
+
+ mStatus err = mDNS_Register_internal(m, &info->AutoTunnel6Record);
+ if (err) LogMsg("UpdateAutoTunnel6Record error %d registering %##s", err, info->AutoTunnel6Record.namestorage.c);
+ else LogInfo("UpdateAutoTunnel6Record registering %##s", info->AutoTunnel6Record.namestorage.c);
+
+ UpdateAutoTunnelHostRecord(m, info);
+
+ LogInfo("AutoTunnel6 server listening for connections on %##s[%.16a] :%##s[%.16a]",
+ info->AutoTunnel6Record.namestorage.c, &m->AutoTunnelRelayAddr,
+ info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
+
+ }
+ else LogInfo("UpdateAutoTunnel6Record NOOP state(%d)",info->AutoTunnel6Record.resrec.RecordType);
+}
+
+mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+{
+ DomainAuthInfo *info = (DomainAuthInfo *)rr->RecordContext;
+ if (result == mStatus_MemFree)
+ {
+ LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr));
+
+ mDNS_Lock(m);
+
+ // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister
+ if (rr == &info->AutoTunnelHostRecord)
+ {
+ rr->namestorage.c[0] = 0;
+ m->NextSRVUpdate = NonZeroTime(m->timenow);
+ LogInfo("AutoTunnelRecordCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
+ }
+ if (m->ShutdownTime)
+ {
+ LogInfo("AutoTunnelRecordCallback: Shutdown, returning");
+ mDNS_Unlock(m);
+ return;
+ }
+ if (rr == &info->AutoTunnelHostRecord)
+ {
+ LogInfo("AutoTunnelRecordCallback: calling UpdateAutoTunnelHostRecord");
+ UpdateAutoTunnelHostRecord(m,info);
+ }
+ else if (rr == &info->AutoTunnelDeviceInfo)
+ {
+ LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelDeviceInfoRecord");
+ UpdateAutoTunnelDeviceInfoRecord(m,info);
+ }
+ else if (rr == &info->AutoTunnelService || rr == &info->AutoTunnelTarget)
+ {
+ LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelServiceRecords");
+ UpdateAutoTunnelServiceRecords(m,info);
+ }
+ else if (rr == &info->AutoTunnel6Record)
+ {
+ LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnel6Record");
+ UpdateAutoTunnel6Record(m,info);
+ }
+
+ mDNS_Unlock(m);
+ }
+}
+
+mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n)
+{
+ DomainAuthInfo *info;
+
+ LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d",
+ n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort));
+
+ mDNS_Lock(m);
+
+ m->NextSRVUpdate = NonZeroTime(m->timenow);
+ LogInfo("AutoTunnelNATCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
+
+ for (info = m->AuthInfoList; info; info = info->next)
+ if (info->AutoTunnel)
+ UpdateAutoTunnelServiceRecords(m, info);
+
+ UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
+
+ UpdateAutoTunnelDomainStatuses(m);
+
+ mDNS_Unlock(m);
+}
+
+mDNSlocal void AutoTunnelHostNameChanged(mDNS *m, DomainAuthInfo *info)
+{
+ LogInfo("AutoTunnelHostNameChanged %#s.%##s", m->hostlabel.c, info->domain.c);
+
+ mDNS_Lock(m);
+ // We forcibly deregister the records that are based on the hostname.
+ // When deregistration of each completes, the MemFree callback will make the
+ // appropriate Update* call to use the new name to reregister.
+ DeregisterAutoTunnelHostRecord(m, info);
+ DeregisterAutoTunnelDeviceInfoRecord(m, info);
+ DeregisterAutoTunnelServiceRecords(m, info);
+ DeregisterAutoTunnel6Record(m, info);
+ m->NextSRVUpdate = NonZeroTime(m->timenow);
+ mDNS_Unlock(m);
+}
+
+// Must be called with the lock held
+mDNSexport void StartServerTunnel(mDNS *const m, DomainAuthInfo *const info)
+{
+ if (info->deltime) return;
+
+ if (info->AutoTunnelServiceStarted)
+ {
+ // On wake from sleep, this function will be called when determining SRV targets,
+ // and needs to re-register the host record for the target to be set correctly
+ UpdateAutoTunnelHostRecord(m, info);
+ return;
+ }
+
+ info->AutoTunnelServiceStarted = mDNStrue;
+
+ // Now that we have a service in this domain, we need to try to register the
+ // AutoTunnel records, because the relay connection & NAT-T may have already been
+ // started for another domain. If the relay connection is not up or the NAT-T has not
+ // yet succeeded, the Update* functions are smart enough to not register the records.
+ // Note: This should be done after we set AutoTunnelServiceStarted, as that variable is used to
+ // decide whether to register the AutoTunnel records in the calls below.
+ UpdateAutoTunnelServiceRecords(m, info);
+ UpdateAutoTunnel6Record(m, info);
+ UpdateAutoTunnelDeviceInfoRecord(m, info);
+ UpdateAutoTunnelHostRecord(m, info);
+
+ // If the global AutoTunnel NAT-T is not yet started, start it.
+ if (!m->AutoTunnelNAT.clientContext)
+ {
+ m->AutoTunnelNAT.clientCallback = AutoTunnelNATCallback;
+ m->AutoTunnelNAT.clientContext = (void*)1; // Means AutoTunnelNAT Traversal is active;
+ m->AutoTunnelNAT.Protocol = NATOp_MapUDP;
+ m->AutoTunnelNAT.IntPort = IPSECPort;
+ m->AutoTunnelNAT.RequestedPort = IPSECPort;
+ m->AutoTunnelNAT.NATLease = 0;
+ mStatus err = mDNS_StartNATOperation_internal(m, &m->AutoTunnelNAT);
+ if (err) LogMsg("StartServerTunnel: error %d starting NAT mapping", err);
+ }
+}
+
+mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew)
+{
+ mDNSv6Addr loc_outer6;
+ mDNSv6Addr rmt_outer6;
+
+ // When we are tunneling over IPv6 Relay address, the port number is zero
+ if (mDNSIPPortIsZero(tun->rmt_outer_port))
+ {
+ loc_outer6 = tun->loc_outer6;
+ rmt_outer6 = tun->rmt_outer6;
+ }
+ else
+ {
+ loc_outer6 = zerov6Addr;
+ loc_outer6.b[0] = tun->loc_outer.b[0];
+ loc_outer6.b[1] = tun->loc_outer.b[1];
+ loc_outer6.b[2] = tun->loc_outer.b[2];
+ loc_outer6.b[3] = tun->loc_outer.b[3];
+
+ rmt_outer6 = zerov6Addr;
+ rmt_outer6.b[0] = tun->rmt_outer.b[0];
+ rmt_outer6.b[1] = tun->rmt_outer.b[1];
+ rmt_outer6.b[2] = tun->rmt_outer.b[2];
+ rmt_outer6.b[3] = tun->rmt_outer.b[3];
+ }
+
+ return(mDNSAutoTunnelSetKeys(AddNew ? kmDNSAutoTunnelSetKeysReplace : kmDNSAutoTunnelSetKeysDelete, tun->loc_inner.b, loc_outer6.b, kRacoonPort, tun->rmt_inner.b, rmt_outer6.b, mDNSVal16(tun->rmt_outer_port), btmmprefix, SkipLeadingLabels(&tun->dstname, 1)));
+}
+
+// If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
+#define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
+
+mDNSlocal void ReissueBlockedQuestionWithType(mDNS *const m, domainname *d, mDNSBool success, mDNSu16 qtype)
+{
+ DNSQuestion *q = m->Questions;
+ while (q)
+ {
+ if (q->NoAnswer == NoAnswer_Suspended && q->qtype == qtype && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
+ {
+ LogInfo("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ mDNSQuestionCallback *tmp = q->QuestionCallback;
+ q->QuestionCallback = AutoTunnelCallback; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
+ mDNS_StopQuery(m, q);
+ mDNS_StartQuery(m, q);
+ q->QuestionCallback = tmp; // Restore QuestionCallback back to the real value
+ if (!success) q->NoAnswer = NoAnswer_Fail;
+ // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too.
+ // In general we have to assume that the question list might have changed in arbitrary ways.
+ // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
+ // already in use. The safest solution is just to go back to the start of the list and start again.
+ // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
+ // just one suspended question, so it's really a 2n algorithm.
+ q = m->Questions;
+ }
+ else
+ q = q->next;
+ }
+}
+
+mDNSlocal void ReissueBlockedQuestions(mDNS *const m, domainname *d, mDNSBool success)
+{
+ // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
+ // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
+ // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
+ // even if the name does have a valid AAAA record, we don't want clients trying to connect to it without a properly encrypted tunnel.
+ // 3. For A queries we never fabricate failures -- if a BTTM service is really using raw IPv4, then it doesn't need the IPv6 tunnel.
+ ReissueBlockedQuestionWithType(m, d, success, kDNSType_AAAA);
+ ReissueBlockedQuestionWithType(m, d, mDNStrue, kDNSType_A);
+}
+
+mDNSlocal void UnlinkAndReissueBlockedQuestions(mDNS *const m, ClientTunnel *tun, mDNSBool success)
+{
+ ClientTunnel **p = &m->TunnelClients;
+ while (*p != tun && *p) p = &(*p)->next;
+ if (*p) *p = tun->next;
+ ReissueBlockedQuestions(m, &tun->dstname, success);
+ LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun);
+ freeL("ClientTunnel", tun);
+}
+
+mDNSlocal mDNSBool TunnelClientDeleteMatching(mDNS *const m, ClientTunnel *tun, mDNSBool v6Tunnel)
+{
+ ClientTunnel **p;
+ mDNSBool needSetKeys = mDNStrue;
+
+ p = &tun->next;
+ while (*p)
+ {
+ // Is this a tunnel to the same host that we are trying to setup now?
+ if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
+ else
+ {
+ ClientTunnel *old = *p;
+ if (v6Tunnel)
+ {
+ if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
+ LogInfo("TunnelClientDeleteMatching: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
+ if (old->q.ThisQInterval >= 0)
+ {
+ LogInfo("TunnelClientDeleteMatching: Stopping query on IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
+ mDNS_StopQuery(m, &old->q);
+ }
+ else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
+ !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
+ !mDNSSameIPv6Address(old->loc_outer6, tun->loc_outer6) ||
+ !mDNSSameIPv6Address(old->rmt_outer6, tun->rmt_outer6))
+ {
+ // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
+ // the other parameters of the tunnel are different
+ LogInfo("TunnelClientDeleteMatching: Deleting existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
+ AutoTunnelSetKeys(old, mDNSfalse);
+ }
+ else
+ {
+ // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
+ // as "tun" and "old" are identical
+ LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c,
+ &old->rmt_inner);
+ needSetKeys = mDNSfalse;
+ }
+ }
+ else
+ {
+ if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
+ LogInfo("TunnelClientDeleteMatching: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
+ if (old->q.ThisQInterval >= 0)
+ {
+ LogInfo("TunnelClientDeleteMatching: Stopping query on IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
+ mDNS_StopQuery(m, &old->q);
+ }
+ else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
+ !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
+ !mDNSSameIPv4Address(old->loc_outer, tun->loc_outer) ||
+ !mDNSSameIPv4Address(old->rmt_outer, tun->rmt_outer) ||
+ !mDNSSameIPPort(old->rmt_outer_port, tun->rmt_outer_port))
+ {
+ // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
+ // the other parameters of the tunnel are different
+ LogInfo("TunnelClientDeleteMatching: Deleting existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
+ AutoTunnelSetKeys(old, mDNSfalse);
+ }
+ else
+ {
+ // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
+ // as "tun" and "old" are identical
+ LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c,
+ &old->rmt_inner);
+ needSetKeys = mDNSfalse;
+ }
+ }
+
+ *p = old->next;
+ LogInfo("TunnelClientDeleteMatching: Disposing ClientTunnel %p", old);
+ freeL("ClientTunnel", old);
+ }
+ }
+ return needSetKeys;
+}
+
+// v6Tunnel indicates whether to delete a tunnel whose outer header is IPv6. If false, outer IPv4
+// tunnel will be deleted
+mDNSlocal void TunnelClientDeleteAny(mDNS *const m, ClientTunnel *tun, mDNSBool v6Tunnel)
+{
+ ClientTunnel **p;
+
+ p = &tun->next;
+ while (*p)
+ {
+ // If there is more than one client tunnel to the same host, delete all of them.
+ // We do this by just checking against the EUI64 rather than the full address
+ if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
+ else
+ {
+ ClientTunnel *old = *p;
+ if (v6Tunnel)
+ {
+ if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
+ LogInfo("TunnelClientDeleteAny: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
+ }
+ else
+ {
+ if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
+ LogInfo("TunnelClientDeleteAny: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
+ }
+ if (old->q.ThisQInterval >= 0)
+ {
+ LogInfo("TunnelClientDeleteAny: Stopping query on AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
+ mDNS_StopQuery(m, &old->q);
+ }
+ else
+ {
+ LogInfo("TunnelClientDeleteAny: Deleting existing AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
+ AutoTunnelSetKeys(old, mDNSfalse);
+ }
+ *p = old->next;
+ LogInfo("TunnelClientDeleteAny: Disposing ClientTunnel %p", old);
+ freeL("ClientTunnel", old);
+ }
+ }
+}
+
+mDNSlocal void TunnelClientFinish(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer)
+{
+ mDNSBool needSetKeys = mDNStrue;
+ ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
+ mDNSBool v6Tunnel = mDNSfalse;
+ DomainAuthInfo *info;
+
+ // If the port is zero, then we have a relay address of the peer
+ if (mDNSIPPortIsZero(tun->rmt_outer_port))
+ v6Tunnel = mDNStrue;
+
+ if (v6Tunnel)
+ {
+ LogInfo("TunnelClientFinish: Relay address %.16a", &answer->rdata->u.ipv6);
+ tun->rmt_outer6 = answer->rdata->u.ipv6;
+ tun->loc_outer6 = m->AutoTunnelRelayAddr;
+ }
+ else
+ {
+ LogInfo("TunnelClientFinish: SRV target address %.4a", &answer->rdata->u.ipv4);
+ tun->rmt_outer = answer->rdata->u.ipv4;
+ mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
+ tmpDst.ip.v4 = tun->rmt_outer;
+ mDNSAddr tmpSrc = zeroAddr;
+ mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
+ if (tmpSrc.type == mDNSAddrType_IPv4) tun->loc_outer = tmpSrc.ip.v4;
+ else tun->loc_outer = m->AdvertisedV4.ip.v4;
+ }
+
+ question->ThisQInterval = -1; // So we know this tunnel setup has completed
+
+ info = GetAuthInfoForName(m, &tun->dstname);
+ if (!info)
+ {
+ LogMsg("TunnelClientFinish: Could not get AuthInfo for %##s", tun->dstname.c);
+ ReissueBlockedQuestions(m, &tun->dstname, mDNSfalse);
+ return;
+ }
+
+ tun->loc_inner = info->AutoTunnelInnerAddress;
+
+ // If we found a v6Relay address for our peer, delete all the v4Tunnels for our peer and
+ // look for existing tunnels to see whether they have the same information for our peer.
+ // If not, delete them and need to create a new tunnel. If they are same, just use the
+ // same tunnel. Do the similar thing if we found a v4Tunnel end point for our peer.
+ TunnelClientDeleteAny(m, tun, !v6Tunnel);
+ needSetKeys = TunnelClientDeleteMatching(m, tun, v6Tunnel);
+
+ if (needSetKeys) LogInfo("TunnelClientFinish: New %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
+ else LogInfo("TunnelClientFinish: Reusing exiting %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
+
+ mStatus result = needSetKeys ? AutoTunnelSetKeys(tun, mDNStrue) : mStatus_NoError;
+ static char msgbuf[32];
+ mDNS_snprintf(msgbuf, sizeof(msgbuf), "Tunnel setup - %d", result);
+ mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.config", result ? "failure" : "success", msgbuf, "");
+ // Kick off any questions that were held pending this tunnel setup
+ ReissueBlockedQuestions(m, &tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse);
+}
+
+mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
+{
+ ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
+ DomainAuthInfo *info;
+
+ LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype);
+
+ if (!AddRecord) return;
+ mDNS_StopQuery(m, question);
+
+ // If we are looking up the AAAA record for _autotunnel6, don't consider it as failure.
+ // The code below will look for _autotunnel._udp SRV record followed by A record
+ if (tun->tc_state != TC_STATE_AAAA_PEER_RELAY && !answer->rdlength)
+ {
+ LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
+ static char msgbuf[16];
+ mDNS_snprintf(msgbuf, sizeof(msgbuf), "%s lookup", DNSTypeName(question->qtype));
+ mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.config", "failure", msgbuf, "");
+ UnlinkAndReissueBlockedQuestions(m, tun, mDNSfalse);
+ return;
+ }
+
+ switch (tun->tc_state)
+ {
+ case TC_STATE_AAAA_PEER:
+ if (question->qtype != kDNSType_AAAA)
+ {
+ LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER", question->qtype);
+ }
+ info = GetAuthInfoForName(m, &tun->dstname);
+ if (!info)
+ {
+ LogMsg("AutoTunnelCallback: Could not get AuthInfo for %##s", tun->dstname.c);
+ UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
+ return;
+ }
+ if (mDNSSameIPv6Address(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
+ {
+ LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6);
+ UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
+ return;
+ }
+ if (info && mDNSSameIPv6NetworkPart(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
+ {
+ LogInfo("AutoTunnelCallback: suppressing tunnel to peer %.16a", &answer->rdata->u.ipv6);
+ UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
+ return;
+ }
+ tun->rmt_inner = answer->rdata->u.ipv6;
+ LogInfo("AutoTunnelCallback:TC_STATE_AAAA_PEER: dst host %.16a", &tun->rmt_inner);
+ if (!mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr))
+ {
+ LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA");
+ tun->tc_state = TC_STATE_AAAA_PEER_RELAY;
+ question->qtype = kDNSType_AAAA;
+ AssignDomainName(&question->qname, (const domainname*) "\x0C" "_autotunnel6");
+ }
+ else
+ {
+ LogInfo("AutoTunnelCallback: Looking up _autotunnel._udp SRV");
+ tun->tc_state = TC_STATE_SRV_PEER;
+ question->qtype = kDNSType_SRV;
+ AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
+ }
+ AppendDomainName(&question->qname, &tun->dstname);
+ mDNS_StartQuery(m, &tun->q);
+ return;
+ case TC_STATE_AAAA_PEER_RELAY:
+ if (question->qtype != kDNSType_AAAA)
+ {
+ LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER_RELAY", question->qtype);
+ }
+ // If it failed, look for the SRV record.
+ if (!answer->rdlength)
+ {
+ LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA failed, trying SRV");
+ tun->tc_state = TC_STATE_SRV_PEER;
+ AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
+ AppendDomainName(&question->qname, &tun->dstname);
+ question->qtype = kDNSType_SRV;
+ mDNS_StartQuery(m, &tun->q);
+ return;
+ }
+ TunnelClientFinish(m, question, answer);
+ return;
+ case TC_STATE_SRV_PEER:
+ if (question->qtype != kDNSType_SRV)
+ {
+ LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_SRV_PEER", question->qtype);
+ }
+ LogInfo("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c);
+ tun->tc_state = TC_STATE_ADDR_PEER;
+ AssignDomainName(&tun->q.qname, &answer->rdata->u.srv.target);
+ tun->rmt_outer_port = answer->rdata->u.srv.port;
+ question->qtype = kDNSType_A;
+ mDNS_StartQuery(m, &tun->q);
+ return;
+ case TC_STATE_ADDR_PEER:
+ if (question->qtype != kDNSType_A)
+ {
+ LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_ADDR_PEER", question->qtype);
+ }
+ TunnelClientFinish(m, question, answer);
+ return;
+ default:
+ LogMsg("AutoTunnelCallback: Unknown question %p", question);
+ }
+}
+
+// Must be called with the lock held
+mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q)
+{
+ ClientTunnel *p = mallocL("ClientTunnel", sizeof(ClientTunnel));
+ if (!p) return;
+ AssignDomainName(&p->dstname, &q->qname);
+ p->MarkedForDeletion = mDNSfalse;
+ p->loc_inner = zerov6Addr;
+ p->loc_outer = zerov4Addr;
+ p->loc_outer6 = zerov6Addr;
+ p->rmt_inner = zerov6Addr;
+ p->rmt_outer = zerov4Addr;
+ p->rmt_outer6 = zerov6Addr;
+ p->rmt_outer_port = zeroIPPort;
+ p->tc_state = TC_STATE_AAAA_PEER;
+ p->next = m->TunnelClients;
+ m->TunnelClients = p; // We intentionally build list in reverse order
+
+ p->q.InterfaceID = mDNSInterface_Any;
+ p->q.flags = 0;
+ p->q.Target = zeroAddr;
+ AssignDomainName(&p->q.qname, &q->qname);
+ p->q.qtype = kDNSType_AAAA;
+ p->q.qclass = kDNSClass_IN;
+ p->q.LongLived = mDNSfalse;
+ p->q.ExpectUnique = mDNStrue;
+ p->q.ForceMCast = mDNSfalse;
+ p->q.ReturnIntermed = mDNStrue;
+ p->q.SuppressUnusable = mDNSfalse;
+ p->q.SearchListIndex = 0;
+ p->q.AppendSearchDomains = 0;
+ p->q.RetryWithSearchDomains = mDNSfalse;
+ p->q.TimeoutQuestion = 0;
+ p->q.WakeOnResolve = 0;
+ p->q.UseBackgroundTrafficClass = mDNSfalse;
+ p->q.ValidationRequired = 0;
+ p->q.ValidatingResponse = 0;
+ p->q.ProxyQuestion = 0;
+ p->q.qnameOrig = mDNSNULL;
+ p->q.AnonInfo = mDNSNULL;
+ p->q.pid = mDNSPlatformGetPID();
+ p->q.QuestionCallback = AutoTunnelCallback;
+ p->q.QuestionContext = p;
+
+ LogInfo("AddNewClientTunnel start tun %p %##s (%s)%s", p, &q->qname.c, DNSTypeName(q->qtype), q->LongLived ? " LongLived" : "");
+ mDNS_StartQuery_internal(m, &p->q);
+}
+
+#endif // APPLE_OSX_mDNSResponder
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Power State & Configuration Change Management
+#endif
+
+mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
+{
+ mDNSBool foundav4 = mDNSfalse;
+ mDNSBool foundav6 = mDNSfalse;
+ struct ifaddrs *ifa = myGetIfAddrs(1);
+ struct ifaddrs *v4Loopback = NULL;
+ struct ifaddrs *v6Loopback = NULL;
+ char defaultname[64];
+ int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (InfoSocket < 3 && errno != EAFNOSUPPORT)
+ LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
+
+ while (ifa)
+ {
+#if LIST_ALL_INTERFACES
+ if (ifa->ifa_addr->sa_family == AF_APPLETALK)
+ LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
+ ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
+ else if (ifa->ifa_addr->sa_family == AF_LINK)
+ LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
+ ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
+ else if (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)
+ LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
+ ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
+ if (!(ifa->ifa_flags & IFF_UP))
+ LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
+ ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
+ if (!(ifa->ifa_flags & IFF_MULTICAST))
+ LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
+ ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
+ if (ifa->ifa_flags & IFF_POINTOPOINT)
+ LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
+ ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
+ if (ifa->ifa_flags & IFF_LOOPBACK)
+ LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
+ ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
+#endif
+
+ if (ifa->ifa_addr->sa_family == AF_LINK)
+ {
+ struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(m->PrimaryMAC) && mDNSSameEthAddress(&m->PrimaryMAC, &zeroEthAddr))
+ mDNSPlatformMemCopy(m->PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6);
+ }
+
+ if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr)
+ if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)
+ {
+ if (!ifa->ifa_netmask)
+ {
+ mDNSAddr ip;
+ SetupAddr(&ip, ifa->ifa_addr);
+ LogMsg("getifaddrs: ifa_netmask is NULL for %5s(%d) Flags %04X Family %2d %#a",
+ ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip);
+ }
+ // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be zero, so we don't complain about that
+ // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
+ else if (ifa->ifa_netmask->sa_family != ifa->ifa_addr->sa_family && ifa->ifa_netmask->sa_family != 0)
+ {
+ mDNSAddr ip;
+ SetupAddr(&ip, ifa->ifa_addr);
+ LogMsg("getifaddrs ifa_netmask for %5s(%d) Flags %04X Family %2d %#a has different family: %d",
+ ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family, &ip, ifa->ifa_netmask->sa_family);
+ }
+ // Currently we use a few internal ones like mDNSInterfaceID_LocalOnly etc. that are negative values (0, -1, -2).
+ else if ((int)if_nametoindex(ifa->ifa_name) <= 0)
+ {
+ LogMsg("UpdateInterfaceList: if_nametoindex returned zero/negative value for %5s(%d)", ifa->ifa_name, if_nametoindex(ifa->ifa_name));
+ }
+ else
+ {
+ // Make sure ifa_netmask->sa_family is set correctly
+ // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
+ ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family;
+ int ifru_flags6 = 0;
+
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+ if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0)
+ {
+ struct in6_ifreq ifr6;
+ mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
+ strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name));
+ ifr6.ifr_addr = *sin6;
+ if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1)
+ ifru_flags6 = ifr6.ifr_ifru.ifru_flags6;
+ verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6);
+ }
+
+ if (!(ifru_flags6 & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
+ {
+ if (ifa->ifa_flags & IFF_LOOPBACK)
+ {
+ if (ifa->ifa_addr->sa_family == AF_INET)
+ v4Loopback = ifa;
+ else if (sin6->sin6_addr.s6_addr[0] != 0xFD)
+ v6Loopback = ifa;
+ }
+ else
+ {
+ NetworkInterfaceInfoOSX *i = AddInterfaceToList(m, ifa, utc);
+ if (i && MulticastInterface(i) && i->ifinfo.Advertise)
+ {
+ if (ifa->ifa_addr->sa_family == AF_INET)
+ foundav4 = mDNStrue;
+ else
+ foundav6 = mDNStrue;
+ }
+ }
+ }
+ }
+ }
+ ifa = ifa->ifa_next;
+ }
+
+ // For efficiency, we don't register a loopback interface when other interfaces of that family are available and advertising
+ if (!foundav4 && v4Loopback) AddInterfaceToList(m, v4Loopback, utc);
+ if (!foundav6 && v6Loopback) AddInterfaceToList(m, v6Loopback, utc);
+
+ // Now the list is complete, set the McastTxRx setting for each interface.
+ NetworkInterfaceInfoOSX *i;
+ for (i = m->p->InterfaceList; i; i = i->next)
+ if (i->Exists)
+ {
+ mDNSBool txrx = MulticastInterface(i);
+ if (i->ifinfo.McastTxRx != txrx)
+ {
+ i->ifinfo.McastTxRx = txrx;
+ i->Exists = 2; // State change; need to deregister and reregister this interface
+ }
+ }
+
+ if (InfoSocket >= 0)
+ close(InfoSocket);
+
+ mDNS_snprintf(defaultname, sizeof(defaultname), "%.*s-%02X%02X%02X%02X%02X%02X", HINFO_HWstring_prefixlen, HINFO_HWstring,
+ m->PrimaryMAC.b[0], m->PrimaryMAC.b[1], m->PrimaryMAC.b[2], m->PrimaryMAC.b[3], m->PrimaryMAC.b[4], m->PrimaryMAC.b[5]);
+
+ // Set up the nice label
+ domainlabel nicelabel;
+ nicelabel.c[0] = 0;
+ GetUserSpecifiedFriendlyComputerName(&nicelabel);
+ if (nicelabel.c[0] == 0)
+ {
+ debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname);
+ MakeDomainLabelFromLiteralString(&nicelabel, defaultname);
+ }
+
+ // Set up the RFC 1034-compliant label
+ domainlabel hostlabel;
+ hostlabel.c[0] = 0;
+ GetUserSpecifiedLocalHostName(&hostlabel);
+ if (hostlabel.c[0] == 0)
+ {
+ debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname);
+ MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
+ }
+
+ mDNSBool namechange = mDNSfalse;
+
+ // We use a case-sensitive comparison here because even though changing the capitalization
+ // of the name alone is not significant to DNS, it's still a change from the user's point of view
+ if (SameDomainLabelCS(m->p->usernicelabel.c, nicelabel.c))
+ debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m->p->usernicelabel.c, m->nicelabel.c);
+ else
+ {
+ if (m->p->usernicelabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
+ LogMsg("User updated Computer Name from “%#s” to “%#s”", m->p->usernicelabel.c, nicelabel.c);
+ m->p->usernicelabel = m->nicelabel = nicelabel;
+ namechange = mDNStrue;
+ }
+
+ if (SameDomainLabelCS(m->p->userhostlabel.c, hostlabel.c))
+ debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m->p->userhostlabel.c, m->hostlabel.c);
+ else
+ {
+ if (m->p->userhostlabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
+ LogMsg("User updated Local Hostname from “%#s” to “%#s”", m->p->userhostlabel.c, hostlabel.c);
+ m->p->userhostlabel = m->hostlabel = hostlabel;
+ mDNS_SetFQDN(m);
+ namechange = mDNStrue;
+ }
+
+#if APPLE_OSX_mDNSResponder
+ if (namechange) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
+ {
+ DomainAuthInfo *info;
+ for (info = m->AuthInfoList; info; info = info->next)
+ if (info->AutoTunnel) AutoTunnelHostNameChanged(m, info);
+ }
+#endif // APPLE_OSX_mDNSResponder
+
+ return(mStatus_NoError);
+}
+
+// Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6
+// Returns -1 if all the one-bits are not contiguous
+mDNSlocal int CountMaskBits(mDNSAddr *mask)
+{
+ int i = 0, bits = 0;
+ int bytes = mask->type == mDNSAddrType_IPv4 ? 4 : mask->type == mDNSAddrType_IPv6 ? 16 : 0;
+ while (i < bytes)
+ {
+ mDNSu8 b = mask->ip.v6.b[i++];
+ while (b & 0x80) { bits++; b <<= 1; }
+ if (b) return(-1);
+ }
+ while (i < bytes) if (mask->ip.v6.b[i++]) return(-1);
+ return(bits);
+}
+
+// returns count of non-link local V4 addresses registered
+mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
+{
+ NetworkInterfaceInfoOSX *i;
+ int count = 0;
+ for (i = m->p->InterfaceList; i; i = i->next)
+ if (i->Exists)
+ {
+ NetworkInterfaceInfo *const n = &i->ifinfo;
+ NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AF_UNSPEC);
+ if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifinfo.ifname);
+
+ if (i->Registered && i->Registered != primary) // Sanity check
+ {
+ LogMsg("SetupActiveInterfaces ERROR! n->Registered %p != primary %p", i->Registered, primary);
+ i->Registered = mDNSNULL;
+ }
+
+ if (!i->Registered)
+ {
+ // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
+ // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
+ // If i->Registered is NOT set, then we haven't registered it and we should not try to deregister it
+ //
+
+ i->Registered = primary;
+
+ // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
+ // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
+ // If the interface is an old one that went away and came back in less than a minute, then we're in a flapping scenario.
+ i->Occulting = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
+
+ // Temporary fix to handle P2P flapping. P2P reuses the scope-id, mac address and the IP address
+ // everytime it creates a new interface. We think it is a duplicate and hence consider it
+ // as flashing and occulting, that is, flapping. If an interface is marked as flapping,
+ // mDNS_RegisterInterface() changes the probe delay from 1/2 second to 5 seconds and
+ // logs a warning message to system.log noting frequent interface transitions.
+ // Same logic applies when IFEF_DIRECTLINK flag is set on the interface.
+ if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->ifinfo.DirectLink)
+ {
+ LogInfo("SetupActiveInterfaces: %s interface registering %s %s", i->ifinfo.ifname,
+ i->Flashing ? " (Flashing)" : "",
+ i->Occulting ? " (Occulting)" : "");
+ mDNS_RegisterInterface(m, n, 0);
+ }
+ else
+ {
+ mDNS_RegisterInterface(m, n, i->Flashing && i->Occulting);
+ }
+
+ if (!mDNSAddressIsLinkLocal(&n->ip)) count++;
+ LogInfo("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
+ i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, primary, &n->ip, CountMaskBits(&n->mask),
+ i->Flashing ? " (Flashing)" : "",
+ i->Occulting ? " (Occulting)" : "",
+ n->InterfaceActive ? " (Primary)" : "");
+
+ if (!n->McastTxRx)
+ debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, &n->ip);
+ else
+ {
+ if (i->sa_family == AF_INET)
+ {
+ struct ip_mreq imr;
+ primary->ifa_v4addr.s_addr = n->ip.ip.v4.NotAnInteger;
+ imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
+ imr.imr_interface = primary->ifa_v4addr;
+
+ // If this is our *first* IPv4 instance for this interface name, we need to do a IP_DROP_MEMBERSHIP first,
+ // before trying to join the group, to clear out stale kernel state which may be lingering.
+ // In particular, this happens with removable network interfaces like USB Ethernet adapters -- the kernel has stale state
+ // from the last time the USB Ethernet adapter was connected, and part of the kernel thinks we've already joined the group
+ // on that interface (so we get EADDRINUSE when we try to join again) but a different part of the kernel thinks we haven't
+ // joined the group (so we receive no multicasts). Doing an IP_DROP_MEMBERSHIP before joining seems to flush the stale state.
+ // Also, trying to make the code leave the group when the adapter is removed doesn't work either,
+ // because by the time we get the configuration change notification, the interface is already gone,
+ // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address").
+ // <rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
+ if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET) == i)
+ {
+ LogInfo("SetupActiveInterfaces: %5s(%lu) Doing precautionary IP_DROP_MEMBERSHIP for %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
+ mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(imr));
+ if (err < 0 && (errno != EADDRNOTAVAIL))
+ LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err, errno, strerror(errno));
+ }
+
+ LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface);
+ mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
+ // Joining same group twice can give "Address already in use" error -- no need to report that
+ if (err < 0 && (errno != EADDRINUSE))
+ LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %d errno %d (%s) group %.4a on %.4a", err, errno, strerror(errno), &imr.imr_multiaddr, &imr.imr_interface);
+ }
+ if (i->sa_family == AF_INET6)
+ {
+ struct ipv6_mreq i6mr;
+ i6mr.ipv6mr_interface = primary->scope_id;
+ i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
+
+ if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET6) == i)
+ {
+ LogInfo("SetupActiveInterfaces: %5s(%lu) Doing precautionary IPV6_LEAVE_GROUP for %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
+ mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
+ if (err < 0 && (errno != EADDRNOTAVAIL))
+ LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
+ }
+
+ LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
+ mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
+ // Joining same group twice can give "Address already in use" error -- no need to report that
+ if (err < 0 && (errno != EADDRINUSE))
+ LogMsg("setsockopt - IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
+ }
+ }
+ }
+ }
+
+ return count;
+}
+
+mDNSlocal void MarkAllInterfacesInactive(mDNS *const m, mDNSs32 utc)
+{
+ NetworkInterfaceInfoOSX *i;
+ for (i = m->p->InterfaceList; i; i = i->next)
+ {
+ if (i->Exists) i->LastSeen = utc;
+ i->Exists = mDNSfalse;
+ }
+}
+
+// returns count of non-link local V4 addresses deregistered
+mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
+{
+ // First pass:
+ // If an interface is going away, then deregister this from the mDNSCore.
+ // We also have to deregister it if the primary interface that it's using for its InterfaceID is going away.
+ // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
+ // it refers to has gone away we'll crash.
+ NetworkInterfaceInfoOSX *i;
+ int count = 0;
+ for (i = m->p->InterfaceList; i; i = i->next)
+ {
+ // If this interface is no longer active, or its InterfaceID is changing, deregister it
+ NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AF_UNSPEC);
+ if (i->Registered)
+ if (i->Exists == 0 || i->Exists == 2 || i->Registered != primary)
+ {
+ i->Flashing = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->AppearanceTime < 60);
+ LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p(%p), primary %p, %#a/%d%s%s%s",
+ i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i, primary,
+ &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask),
+ i->Flashing ? " (Flashing)" : "",
+ i->Occulting ? " (Occulting)" : "",
+ i->ifinfo.InterfaceActive ? " (Primary)" : "");
+
+ // Temporary fix to handle P2P flapping. P2P reuses the scope-id, mac address and the IP address
+ // everytime it creates a new interface. We think it is a duplicate and hence consider it
+ // as flashing and occulting. The "core" does not flush the cache for this case. This leads to
+ // stale data returned to the application even after the interface is removed. The application
+ // then starts to send data but the new interface is not yet created.
+ // Same logic applies when IFEF_DIRECTLINK flag is set on the interface.
+ if ((strncmp(i->ifinfo.ifname, "p2p", 3) == 0) || i->ifinfo.DirectLink)
+ {
+ LogInfo("ClearInactiveInterfaces: %s interface deregistering %s %s", i->ifinfo.ifname,
+ i->Flashing ? " (Flashing)" : "",
+ i->Occulting ? " (Occulting)" : "");
+ mDNS_DeregisterInterface(m, &i->ifinfo, 0);
+ }
+ else
+ {
+ mDNS_DeregisterInterface(m, &i->ifinfo, i->Flashing && i->Occulting);
+ }
+ if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++;
+ i->Registered = mDNSNULL;
+ // Note: If i->Registered is set, that means we've called mDNS_RegisterInterface() for this interface,
+ // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
+ // If i->Registered is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it.
+
+ // Caution: If we ever decide to add code here to leave the multicast group, we need to make sure that this
+ // is the LAST representative of this physical interface, or we'll unsubscribe from the group prematurely.
+ }
+ }
+
+ // Second pass:
+ // Now that everything that's going to deregister has done so, we can clean up and free the memory
+ NetworkInterfaceInfoOSX **p = &m->p->InterfaceList;
+ while (*p)
+ {
+ i = *p;
+ // If no longer active, delete interface from list and free memory
+ if (!i->Exists)
+ {
+ if (i->LastSeen == utc) i->LastSeen = utc - 1;
+ mDNSBool delete = (NumCacheRecordsForInterfaceID(m, i->ifinfo.InterfaceID) == 0) && (utc - i->LastSeen >= 60);
+ LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p(%p) %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
+ i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i,
+ &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen,
+ i->ifinfo.InterfaceActive ? " (Primary)" : "");
+#if APPLE_OSX_mDNSResponder
+ if (i->BPF_fd >= 0) CloseBPF(i);
+#endif // APPLE_OSX_mDNSResponder
+ if (delete)
+ {
+ *p = i->next;
+ freeL("NetworkInterfaceInfoOSX", i);
+ continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
+ }
+ }
+ p = &i->next;
+ }
+ return count;
+}
+
+mDNSlocal void AppendDNameListElem(DNameListElem ***List, mDNSu32 uid, domainname *name)
+{
+ DNameListElem *dnle = (DNameListElem*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem));
+ if (!dnle) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
+ else
+ {
+ dnle->next = mDNSNULL;
+ dnle->uid = uid;
+ AssignDomainName(&dnle->name, name);
+ **List = dnle;
+ *List = &dnle->next;
+ }
+}
+
+mDNSlocal int compare_dns_configs(const void *aa, const void *bb)
+{
+ dns_resolver_t *a = *(dns_resolver_t**)aa;
+ dns_resolver_t *b = *(dns_resolver_t**)bb;
+
+ return (a->search_order < b->search_order) ? -1 : (a->search_order == b->search_order) ? 0 : 1;
+}
+
+mDNSlocal void UpdateSearchDomainHash(mDNS *const m, MD5_CTX *sdc, char *domain, mDNSInterfaceID InterfaceID)
+{
+ char *buf = ".";
+ mDNSu32 scopeid = 0;
+ char ifid_buf[16];
+
+ if (domain)
+ buf = domain;
+ //
+ // Hash the search domain name followed by the InterfaceID.
+ // As we have scoped search domains, we also included InterfaceID. If either of them change,
+ // we will detect it. Even if the order of them change, we will detect it.
+ //
+ // Note: We have to handle a few of these tricky cases.
+ //
+ // 1) Current: com, apple.com Changing to: comapple.com
+ // 2) Current: a.com,b.com Changing to a.comb.com
+ // 3) Current: a.com,b.com (ifid 8), Changing to a.com8b.com (ifid 8)
+ // 4) Current: a.com (ifid 12), Changing to a.com1 (ifid: 2)
+ //
+ // There are more variants of the above. The key thing is if we include the null in each case
+ // at the end of name and the InterfaceID, it will prevent a new name (which can't include
+ // NULL as part of the name) to be mistakenly thought of as a old name.
+
+ scopeid = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID, mDNStrue);
+ // mDNS_snprintf always null terminates
+ if (mDNS_snprintf(ifid_buf, sizeof(ifid_buf), "%u", scopeid) >= sizeof(ifid_buf))
+ LogMsg("UpdateSearchDomainHash: mDNS_snprintf failed for scopeid %u", scopeid);
+
+ LogInfo("UpdateSearchDomainHash: buf %s, ifid_buf %s", buf, ifid_buf);
+ MD5_Update(sdc, buf, strlen(buf) + 1);
+ MD5_Update(sdc, ifid_buf, strlen(ifid_buf) + 1);
+}
+
+mDNSlocal void FinalizeSearchDomainHash(mDNS *const m, MD5_CTX *sdc)
+{
+ mDNSu8 md5_hash[MD5_LEN];
+
+ MD5_Final(md5_hash, sdc);
+
+ if (memcmp(md5_hash, m->SearchDomainsHash, MD5_LEN))
+ {
+ // If the hash is different, either the search domains have changed or
+ // the ordering between them has changed. Restart the questions that
+ // would be affected by this.
+ LogInfo("FinalizeSearchDomains: The hash is different");
+ memcpy(m->SearchDomainsHash, md5_hash, MD5_LEN);
+ RetrySearchDomainQuestions(m);
+ }
+ else { LogInfo("FinalizeSearchDomains: The hash is same"); }
+}
+
+mDNSexport const char *DNSScopeToString(mDNSu32 scope)
+{
+ switch (scope)
+ {
+ case kScopeNone:
+ return "Unscoped";
+ case kScopeInterfaceID:
+ return "InterfaceScoped";
+ case kScopeServiceID:
+ return "ServiceScoped";
+ default:
+ return "Unknown";
+ }
+}
+
+mDNSlocal void ConfigSearchDomains(mDNS *const m, dns_resolver_t *resolver, mDNSInterfaceID interface, mDNSu32 scope, MD5_CTX *sdc)
+{
+ const char *scopeString = DNSScopeToString(scope);
+ int j;
+
+ if (scope != kScopeNone)
+ {
+ LogInfo("ConfigSearchDomains: (%s) Ignoring search domain for Interface %p", scopeString, interface);
+ return;
+ }
+ for (j = 0; j < resolver->n_search; j++)
+ {
+ LogInfo("ConfigSearchDomains: (%s) configuring search list %s", scopeString, resolver->search[j]);
+ UpdateSearchDomainHash(m, sdc, resolver->search[j], NULL);
+ mDNS_AddSearchDomain_CString(resolver->search[j], NULL);
+ }
+}
+
+mDNSlocal mDNSInterfaceID ConfigParseInterfaceID(mDNS *const m, mDNSu32 ifindex)
+{
+ NetworkInterfaceInfoOSX *ni;
+ mDNSInterfaceID interface;
+
+ for (ni = m->p->InterfaceList; ni; ni = ni->next)
+ {
+ if (ni->ifinfo.InterfaceID && ni->scope_id == ifindex)
+ break;
+ }
+ if (ni != NULL)
+ {
+ interface = ni->ifinfo.InterfaceID;
+ }
+ else
+ {
+ // In rare circumstances, we could potentially hit this case where we cannot parse the InterfaceID
+ // (see <rdar://problem/13214785>). At this point, we still accept the DNS Config from configd
+ // Note: We currently ack the whole dns configuration and not individual resolvers or DNS servers.
+ // As the caller is going to ack the configuration always, we have to add all the DNS servers
+ // in the configuration. Otherwise, we won't have any DNS servers up until the network change.
+
+ LogMsg("ConfigParseInterfaceID: interface specific index %d not found (interface may not be UP)",ifindex);
+
+ // Set the correct interface from configd before passing this to mDNS_AddDNSServer() below
+ interface = (mDNSInterfaceID)(unsigned long)ifindex;
+ }
+ return interface;
+}
+
+mDNSlocal void ConfigNonUnicastResolver(mDNS *const m, dns_resolver_t *r)
+{
+ char *opt = r->options;
+ domainname d;
+
+ if (opt && !strncmp(opt, "mdns", strlen(opt)))
+ {
+ if (!MakeDomainNameFromDNSNameString(&d, r->domain))
+ {
+ LogMsg("ConfigNonUnicastResolver: config->resolver bad domain %s", r->domain);
+ return;
+ }
+ mDNS_AddMcastResolver(m, &d, mDNSInterface_Any, r->timeout);
+ }
+}
+
+mDNSlocal void ConfigDNSServers(mDNS *const m, dns_resolver_t *r, mDNSInterfaceID interface, mDNSu32 scope, mDNSu16 resGroupID)
+{
+ int n;
+ domainname d;
+ int serviceID = 0;
+ mDNSBool cellIntf = mDNSfalse;
+ mDNSBool scopedDNS = mDNSfalse;
+ mDNSBool reqA, reqAAAA;
+
+ if (!r->domain || !*r->domain)
+ {
+ d.c[0] = 0;
+ }
+ else if (!MakeDomainNameFromDNSNameString(&d, r->domain))
+ {
+ LogMsg("ConfigDNSServers: bad domain %s", r->domain);
+ return;
+ }
+ // Parse the resolver specific attributes that affects all the DNS servers.
+ if (scope == kScopeInterfaceID)
+ {
+ scopedDNS = mDNStrue;
+ }
+ else if (scope == kScopeServiceID)
+ {
+ serviceID = r->service_identifier;
+ }
+
+#if TARGET_OS_IPHONE
+ cellIntf = (r->reach_flags & kSCNetworkReachabilityFlagsIsWWAN) ? mDNStrue : mDNSfalse;
+#endif
+ reqA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS ? mDNStrue : mDNSfalse);
+ reqAAAA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS ? mDNStrue : mDNSfalse);
+
+ for (n = 0; n < r->n_nameserver; n++)
+ {
+ mDNSAddr saddr;
+ DNSServer *s;
+
+ if (r->nameserver[n]->sa_family != AF_INET && r->nameserver[n]->sa_family != AF_INET6)
+ continue;
+
+ if (SetupAddr(&saddr, r->nameserver[n]))
+ {
+ LogMsg("ConfigDNSServers: Bad address");
+ continue;
+ }
+
+ // The timeout value is for all the DNS servers in a given resolver, hence we pass
+ // the timeout value only for the first DNSServer. If we don't have a value in the
+ // resolver, then use the core's default value
+ //
+ // Note: this assumes that when the core picks a list of DNSServers for a question,
+ // it takes the sum of all the timeout values for all DNS servers. By doing this, it
+ // tries all the DNS servers in a specified timeout
+ s = mDNS_AddDNSServer(m, &d, interface, serviceID, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort, scope,
+ (n == 0 ? (r->timeout ? r->timeout : DEFAULT_UDNS_TIMEOUT) : 0), cellIntf, resGroupID, reqA, reqAAAA, mDNStrue);
+ if (s)
+ {
+ LogInfo("ConfigDNSServers(%s): DNS server %#a:%d for domain %##s", DNSScopeToString(scope), &s->addr, mDNSVal16(s->port), d.c);
+ }
+ }
+}
+
+// ConfigResolvers is called for different types of resolvers: Unscoped resolver, Interface scope resolver and
+// Service scope resolvers. This is indicated by the scope argument.
+//
+// "resolver" has entries that should only be used for unscoped questions.
+//
+// "scoped_resolver" has entries that should only be used for Interface scoped question i.e., questions that specify an
+// interface index (q->InterfaceID)
+//
+// "service_specific_resolver" has entries that should be used for Service scoped question i.e., questions that specify
+// a service identifier (q->ServiceID)
+//
+mDNSlocal void ConfigResolvers(mDNS *const m, dns_config_t *config, mDNSu32 scope, mDNSBool setsearch, mDNSBool setservers, MD5_CTX *sdc, mDNSu16 resGroupID)
+{
+ int i;
+ dns_resolver_t **resolver;
+ int nresolvers;
+ const char *scopeString = DNSScopeToString(scope);
+ mDNSInterfaceID interface;
+
+ switch (scope)
+ {
+ case kScopeNone:
+ resolver = config->resolver;
+ nresolvers = config->n_resolver;
+ break;
+ case kScopeInterfaceID:
+ resolver = config->scoped_resolver;
+ nresolvers = config->n_scoped_resolver;
+ break;
+ case kScopeServiceID:
+ resolver = config->service_specific_resolver;
+ nresolvers = config->n_service_specific_resolver;
+ break;
+ default:
+ return;
+ }
+ qsort(resolver, nresolvers, sizeof(dns_resolver_t*), compare_dns_configs);
+
+ for (i = 0; i < nresolvers; i++)
+ {
+ dns_resolver_t *r = resolver[i];
+
+ LogInfo("ConfigResolvers: %s resolver[%d] domain %s n_nameserver %d", scopeString, i, r->domain, r->n_nameserver);
+
+ interface = mDNSInterface_Any;
+
+ // Parse the interface index
+ if (r->if_index != 0)
+ {
+ interface = ConfigParseInterfaceID(m, r->if_index);
+ }
+
+ if (setsearch)
+ {
+ ConfigSearchDomains(m, resolver[i], interface, scope, sdc);
+ // Parse other scoped resolvers for search lists
+ if (!setservers)
+ continue;
+ }
+
+ if (r->port == 5353 || r->n_nameserver == 0)
+ {
+ ConfigNonUnicastResolver(m, r);
+ }
+ else
+ {
+ // Each scoped resolver gets its own ID (i.e., they are in their own group) so that responses from the
+ // scoped resolver are not used by other non-scoped or scoped resolvers.
+ if (scope != kScopeNone)
+ resGroupID++;
+
+ ConfigDNSServers(m, r, interface, scope, resGroupID);
+ }
+ }
+}
+
+#if APPLE_OSX_mDNSResponder
+mDNSlocal mDNSBool QuestionValidForDNSTrigger(DNSQuestion *q)
+{
+ if (QuerySuppressed(q))
+ {
+ debugf("QuestionValidForDNSTrigger: Suppressed: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ return mDNSfalse;
+ }
+ if (mDNSOpaque16IsZero(q->TargetQID))
+ {
+ debugf("QuestionValidForDNSTrigger: Multicast: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ return mDNSfalse;
+ }
+ // If we answered using LocalOnly records e.g., /etc/hosts, don't consider that a valid response
+ // for trigger.
+ if (q->LOAddressAnswers)
+ {
+ debugf("QuestionValidForDNSTrigger: LocalOnly answers: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ return mDNSfalse;
+ }
+ return mDNStrue;
+}
+#endif
+
+// This function is called if we are not delivering unicast answers to "A" or "AAAA" questions.
+// We set our state appropriately so that if we start receiving answers, trigger the
+// upper layer to retry DNS questions.
+#if APPLE_OSX_mDNSResponder
+mDNSexport void mDNSPlatformUpdateDNSStatus(mDNS *const m, DNSQuestion *q)
+{
+ if (!QuestionValidForDNSTrigger(q))
+ return;
+
+ // Ignore applications that start and stop queries for no reason before we ever talk
+ // to any DNS server.
+ if (!q->triedAllServersOnce)
+ {
+ LogInfo("QuestionValidForDNSTrigger: question %##s (%s) stopped too soon", q->qname.c, DNSTypeName(q->qtype));
+ return;
+ }
+ if (q->qtype == kDNSType_A)
+ m->p->v4answers = 0;
+ if (q->qtype == kDNSType_AAAA)
+ m->p->v6answers = 0;
+ if (!m->p->v4answers || !m->p->v6answers)
+ {
+ LogInfo("mDNSPlatformUpdateDNSStatus: Trigger needed v4 %d, v6 %d, quesiton %##s (%s)", m->p->v4answers, m->p->v6answers, q->qname.c,
+ DNSTypeName(q->qtype));
+ }
+}
+#endif
+
+mDNSlocal void AckConfigd(mDNS *const m, dns_config_t *config)
+{
+ mDNS_CheckLock(m);
+
+ // Acking the configuration triggers configd to reissue the reachability queries
+ m->p->DNSTrigger = NonZeroTime(m->timenow);
+ _dns_configuration_ack(config, "com.apple.mDNSResponder");
+}
+
+// If v4q is non-NULL, it means we have received some answers for "A" type questions
+// If v6q is non-NULL, it means we have received some answers for "AAAA" type questions
+#if APPLE_OSX_mDNSResponder
+mDNSexport void mDNSPlatformTriggerDNSRetry(mDNS *const m, DNSQuestion *v4q, DNSQuestion *v6q)
+{
+ mDNSBool trigger = mDNSfalse;
+ mDNSs32 timenow;
+
+ // Don't send triggers too often.
+ // If we have started delivering answers to questions, we should send a trigger
+ // if the time permits. If we are delivering answers, we should set the state
+ // of v4answers/v6answers to 1 and avoid sending a trigger. But, we don't know
+ // whether the answers that are being delivered currently is for configd or some
+ // other application. If we set the v4answers/v6answers to 1 and not deliver a trigger,
+ // then we won't deliver the trigger later when it is okay to send one as the
+ // "answers" are already set to 1. Hence, don't affect the state of v4answers and
+ // v6answers if we are not delivering triggers.
+ mDNS_Lock(m);
+ timenow = m->timenow;
+ if (m->p->DNSTrigger && (timenow - m->p->DNSTrigger) < DNS_TRIGGER_INTERVAL)
+ {
+ if (!m->p->v4answers || !m->p->v6answers)
+ {
+ debugf("mDNSPlatformTriggerDNSRetry: not triggering, time since last trigger %d ms, v4ans %d, v6ans %d",
+ (timenow - m->p->DNSTrigger), m->p->v4answers, m->p->v6answers);
+ }
+ mDNS_Unlock(m);
+ return;
+ }
+ mDNS_Unlock(m);
+ if (v4q != NULL && QuestionValidForDNSTrigger(v4q))
+ {
+ int old = m->p->v4answers;
+
+ m->p->v4answers = 1;
+
+ // If there are IPv4 answers now and previously we did not have
+ // any answers, trigger a DNS change so that reachability
+ // can retry the queries again.
+ if (!old)
+ {
+ LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv4, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
+ v4q->qname.c, DNSTypeName(v4q->qtype));
+ trigger = mDNStrue;
+ }
+ }
+ if (v6q != NULL && QuestionValidForDNSTrigger(v6q))
+ {
+ int old = m->p->v6answers;
+
+ m->p->v6answers = 1;
+ // If there are IPv6 answers now and previously we did not have
+ // any answers, trigger a DNS change so that reachability
+ // can retry the queries again.
+ if (!old)
+ {
+ LogInfo("mDNSPlatformTriggerDNSRetry: Triggering because of IPv6, last trigger %d ms, %##s (%s)", (timenow - m->p->DNSTrigger),
+ v6q->qname.c, DNSTypeName(v6q->qtype));
+ trigger = mDNStrue;
+ }
+ }
+ if (trigger)
+ {
+ dns_config_t *config = dns_configuration_copy();
+ if (config)
+ {
+ mDNS_Lock(m);
+ AckConfigd(m, config);
+ mDNS_Unlock(m);
+ dns_configuration_free(config);
+ }
+ else
+ {
+ LogMsg("mDNSPlatformTriggerDNSRetry: ERROR!! configd did not return config");
+ }
+ }
+}
+
+mDNSlocal void SetupActiveDirectoryDomain(dns_config_t *config)
+{
+ // Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up
+ // by someone using Microsoft Active Directory using "local" as a private internal top-level domain
+ if (config->n_resolver && config->resolver[0]->domain && config->resolver[0]->n_nameserver &&
+ config->resolver[0]->nameserver[0])
+ {
+ MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, config->resolver[0]->domain);
+ }
+ else
+ {
+ ActiveDirectoryPrimaryDomain.c[0] = 0;
+ }
+
+ //MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, "test.local");
+ ActiveDirectoryPrimaryDomainLabelCount = CountLabels(&ActiveDirectoryPrimaryDomain);
+ if (config->n_resolver && config->resolver[0]->n_nameserver &&
+ SameDomainName(SkipLeadingLabels(&ActiveDirectoryPrimaryDomain, ActiveDirectoryPrimaryDomainLabelCount - 1), &localdomain))
+ {
+ SetupAddr(&ActiveDirectoryPrimaryDomainServer, config->resolver[0]->nameserver[0]);
+ }
+ else
+ {
+ AssignDomainName(&ActiveDirectoryPrimaryDomain, (const domainname *)"");
+ ActiveDirectoryPrimaryDomainLabelCount = 0;
+ ActiveDirectoryPrimaryDomainServer = zeroAddr;
+ }
+}
+#endif
+
+mDNSlocal void SetupDDNSDomains(domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains)
+{
+ int i;
+ char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
+ domainname d;
+
+ SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformSetDNSConfig"), NULL, NULL);
+ if (!store)
+ {
+ LogMsg("SetupDDNSDomains: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
+ }
+ else
+ {
+ CFDictionaryRef ddnsdict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DynamicDNS);
+ if (ddnsdict)
+ {
+ if (fqdn)
+ {
+ CFArrayRef fqdnArray = CFDictionaryGetValue(ddnsdict, CFSTR("HostNames"));
+ if (fqdnArray && CFArrayGetCount(fqdnArray) > 0)
+ {
+ // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list
+ CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0);
+ if (fqdnDict && DictionaryIsEnabled(fqdnDict))
+ {
+ CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
+ if (name)
+ {
+ if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
+ !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
+ LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
+ else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
+ }
+ }
+ }
+ }
+
+ if (RegDomains)
+ {
+ CFArrayRef regArray = CFDictionaryGetValue(ddnsdict, CFSTR("RegistrationDomains"));
+ if (regArray && CFArrayGetCount(regArray) > 0)
+ {
+ CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
+ if (regDict && DictionaryIsEnabled(regDict))
+ {
+ CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
+ if (name)
+ {
+ if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
+ !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
+ LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
+ else
+ {
+ debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf);
+ AppendDNameListElem(&RegDomains, 0, &d);
+ }
+ }
+ }
+ }
+ }
+
+ if (BrowseDomains)
+ {
+ CFArrayRef browseArray = CFDictionaryGetValue(ddnsdict, CFSTR("BrowseDomains"));
+ if (browseArray)
+ {
+ for (i = 0; i < CFArrayGetCount(browseArray); i++)
+ {
+ CFDictionaryRef browseDict = CFArrayGetValueAtIndex(browseArray, i);
+ if (browseDict && DictionaryIsEnabled(browseDict))
+ {
+ CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
+ if (name)
+ {
+ if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
+ !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0])
+ LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf[0] ? buf : "(unknown)");
+ else
+ {
+ debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf);
+ AppendDNameListElem(&BrowseDomains, 0, &d);
+ }
+ }
+ }
+ }
+ }
+ }
+ CFRelease(ddnsdict);
+ }
+
+ if (RegDomains)
+ {
+ CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
+ if (btmm)
+ {
+ CFIndex size = CFDictionaryGetCount(btmm);
+ const void *key[size];
+ const void *val[size];
+ CFDictionaryGetKeysAndValues(btmm, key, val);
+ for (i = 0; i < size; i++)
+ {
+ LogInfo("BackToMyMac %d", i);
+ if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
+ LogMsg("Can't read BackToMyMac %d key %s", i, buf);
+ else
+ {
+ mDNSu32 uid = atoi(buf);
+ if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
+ LogMsg("Can't read BackToMyMac %d val %s", i, buf);
+ else if (MakeDomainNameFromDNSNameString(&d, buf) && d.c[0])
+ {
+ LogInfo("BackToMyMac %d %d %##s", i, uid, d.c);
+ AppendDNameListElem(&RegDomains, uid, &d);
+ }
+ }
+ }
+ CFRelease(btmm);
+ }
+ }
+ CFRelease(store);
+ }
+}
+
+// Returns mDNSfalse, if it does not set the configuration i.e., if the DNS configuration did not change
+mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn,
+ DNameListElem **RegDomains, DNameListElem **BrowseDomains, mDNSBool ackConfig)
+{
+ MD5_CTX sdc; // search domain context
+ static mDNSu16 resolverGroupID = 0;
+
+ // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed
+ if (fqdn) fqdn->c[0] = 0;
+ if (RegDomains ) *RegDomains = NULL;
+ if (BrowseDomains) *BrowseDomains = NULL;
+
+ LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s",
+ setservers ? " setservers" : "",
+ setsearch ? " setsearch" : "",
+ fqdn ? " fqdn" : "",
+ RegDomains ? " RegDomains" : "",
+ BrowseDomains ? " BrowseDomains" : "");
+
+ if (setsearch) MD5_Init(&sdc);
+
+ // Add the inferred address-based configuration discovery domains
+ // (should really be in core code I think, not platform-specific)
+ if (setsearch)
+ {
+ struct ifaddrs *ifa = mDNSNULL;
+ struct sockaddr_in saddr;
+ mDNSPlatformMemZero(&saddr, sizeof(saddr));
+ saddr.sin_len = sizeof(saddr);
+ saddr.sin_family = AF_INET;
+ saddr.sin_port = 0;
+ saddr.sin_addr.s_addr = *(in_addr_t *)&m->Router.ip.v4;
+
+ // Don't add any reverse-IP search domains if doing the WAB bootstrap queries would cause dial-on-demand connection initiation
+ if (!AddrRequiresPPPConnection((struct sockaddr *)&saddr)) ifa = myGetIfAddrs(1);
+
+ while (ifa)
+ {
+ mDNSAddr a, n;
+ char buf[64];
+
+ if (ifa->ifa_addr->sa_family == AF_INET &&
+ ifa->ifa_netmask &&
+ !(ifa->ifa_flags & IFF_LOOPBACK) &&
+ !SetupAddr(&a, ifa->ifa_addr) &&
+ !mDNSv4AddressIsLinkLocal(&a.ip.v4) )
+ {
+ // Apparently it's normal for the sa_family of an ifa_netmask to sometimes be incorrect, so we explicitly fix it here before calling SetupAddr
+ // <rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
+ ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family; // Make sure ifa_netmask->sa_family is set correctly
+ SetupAddr(&n, ifa->ifa_netmask);
+ // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
+ mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", a.ip.v4.b[3] & n.ip.v4.b[3],
+ a.ip.v4.b[2] & n.ip.v4.b[2],
+ a.ip.v4.b[1] & n.ip.v4.b[1],
+ a.ip.v4.b[0] & n.ip.v4.b[0]);
+ UpdateSearchDomainHash(m, &sdc, buf, NULL);
+ mDNS_AddSearchDomain_CString(buf, mDNSNULL);
+ }
+ ifa = ifa->ifa_next;
+ }
+ }
+
+#ifndef MDNS_NO_DNSINFO
+ if (setservers || setsearch)
+ {
+ dns_config_t *config = dns_configuration_copy();
+ if (!config)
+ {
+ // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
+ // On 10.4, calls to dns_configuration_copy() early in the boot process often fail.
+ // Apparently this is expected behaviour -- "not a bug".
+ // Accordingly, we suppress syslog messages for the first three minutes after boot.
+ // If we are still getting failures after three minutes, then we log them.
+ if ((mDNSu32)mDNSPlatformRawTime() > (mDNSu32)(mDNSPlatformOneSecond * 180))
+ LogMsg("mDNSPlatformSetDNSConfig: Error: dns_configuration_copy returned NULL");
+ }
+ else
+ {
+ LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d, generation %llu", config->n_resolver, config->generation);
+ if (m->p->LastConfigGeneration == config->generation)
+ {
+ LogInfo("mDNSPlatformSetDNSConfig: generation number %llu same, not processing", config->generation);
+ dns_configuration_free(config);
+ SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
+ return mDNSfalse;
+ }
+#if APPLE_OSX_mDNSResponder
+ SetupActiveDirectoryDomain(config);
+#endif
+
+ // With scoped DNS, we don't want to answer a non-scoped question using a scoped cache entry
+ // and vice-versa. As we compare resolverGroupID for matching cache entry with question, we need
+ // to make sure that they don't match. We ensure this by always bumping up resolverGroupID between
+ // the two calls to ConfigResolvers DNSServers for scoped and non-scoped can never have the
+ // same resolverGroupID.
+ //
+ // All non-scoped resolvers use the same resolverGroupID i.e, we treat them all equally.
+ ConfigResolvers(m, config, kScopeNone, setsearch, setservers, &sdc, ++resolverGroupID);
+ resolverGroupID += config->n_resolver;
+
+ ConfigResolvers(m, config, kScopeInterfaceID, setsearch, setservers, &sdc, resolverGroupID);
+ resolverGroupID += config->n_scoped_resolver;
+
+ ConfigResolvers(m, config, kScopeServiceID, setsearch, setservers, &sdc, resolverGroupID);
+
+ // Acking provides a hint that we processed this current configuration and
+ // we will use that from now on, assuming we don't get another one immediately
+ // after we return from here.
+ if (ackConfig)
+ {
+ // Note: We have to set the generation number here when we are acking.
+ // For every DNS configuration change, we do the following:
+ //
+ // 1) Copy dns configuration, handle search domains change
+ // 2) Copy dns configuration, handle dns server change
+ //
+ // If we update the generation number at step (1), we won't process the
+ // DNS servers the second time because generation number would be the same.
+ // As we ack only when we process dns servers, we set the generation number
+ // during acking.
+ m->p->LastConfigGeneration = config->generation;
+ LogInfo("mDNSPlatformSetDNSConfig: Acking configuration setservers %d, setsearch %d", setservers, setsearch);
+ AckConfigd(m, config);
+ }
+ dns_configuration_free(config);
+ if (setsearch) FinalizeSearchDomainHash(m, &sdc);
+ setservers = mDNSfalse; // Done these now -- no need to fetch the same data from SCDynamicStore
+ setsearch = mDNSfalse;
+ }
+ }
+#endif // MDNS_NO_DNSINFO
+ SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
+ return mDNStrue;
+}
+
+
+mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r)
+{
+ char buf[256];
+ (void)m; // Unused
+
+ SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL, NULL);
+ if (!store)
+ LogMsg("mDNSPlatformGetPrimaryInterface: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
+ else
+ {
+ CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_IPv4);
+ if (dict)
+ {
+ r->type = mDNSAddrType_IPv4;
+ r->ip.v4 = zerov4Addr;
+ CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
+ if (string)
+ {
+ if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8))
+ LogMsg("Could not convert router to CString");
+ else
+ {
+ struct sockaddr_in saddr;
+ saddr.sin_len = sizeof(saddr);
+ saddr.sin_family = AF_INET;
+ saddr.sin_port = 0;
+ inet_aton(buf, &saddr.sin_addr);
+
+ *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr;
+ }
+ }
+
+ string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
+ if (string)
+ {
+ mDNSBool HavePrimaryGlobalv6 = mDNSfalse; // does the primary interface have a global v6 address?
+ struct ifaddrs *ifa = myGetIfAddrs(1);
+
+ *v4 = *v6 = zeroAddr;
+
+ if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8)) { LogMsg("Could not convert router to CString"); goto exit; }
+
+ // find primary interface in list
+ while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6))
+ {
+ mDNSAddr tmp6 = zeroAddr;
+ if (!strcmp(buf, ifa->ifa_name))
+ {
+ if (ifa->ifa_addr->sa_family == AF_INET)
+ {
+ if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4)) SetupAddr(v4, ifa->ifa_addr);
+ }
+ else if (ifa->ifa_addr->sa_family == AF_INET6)
+ {
+ SetupAddr(&tmp6, ifa->ifa_addr);
+ if (tmp6.ip.v6.b[0] >> 5 == 1) // global prefix: 001
+ { HavePrimaryGlobalv6 = mDNStrue; *v6 = tmp6; }
+ }
+ }
+ else
+ {
+ // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address
+ if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6->ip.v6.b[0])
+ {
+ SetupAddr(&tmp6, ifa->ifa_addr);
+ if (tmp6.ip.v6.b[0] >> 5 == 1) *v6 = tmp6;
+ }
+ }
+ ifa = ifa->ifa_next;
+ }
+
+ // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use
+ // V4 to communicate w/ our DNS server
+ }
+
+exit:
+ CFRelease(dict);
+ }
+ CFRelease(store);
+ }
+ return mStatus_NoError;
+}
+
+mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
+{
+ LogInfo("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status, dname->c);
+ char uname[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
+ ConvertDomainNameToCString(dname, uname);
+
+ char *p = uname;
+ while (*p)
+ {
+ *p = tolower(*p);
+ if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
+ p++;
+ }
+
+ // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity.
+ // That single entity is a CFDictionary with name "HostNames".
+ // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN
+ // in question, and the corresponding value is a CFDictionary giving the state for that FQDN.
+ // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.)
+ // The CFDictionary for each FQDN holds (at present) a single name/value pair,
+ // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
+
+ const CFStringRef StateKeys [1] = { CFSTR("HostNames") };
+ const CFStringRef HostKeys [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) };
+ const CFStringRef StatusKeys[1] = { CFSTR("Status") };
+ if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname);
+ else
+ {
+ const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
+ if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status);
+ else
+ {
+ const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
+ if (HostVals[0])
+ {
+ const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
+ if (StateVals[0])
+ {
+ CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ if (StateDict)
+ {
+ mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, mDNSNULL, StateDict);
+ CFRelease(StateDict);
+ }
+ CFRelease(StateVals[0]);
+ }
+ CFRelease(HostVals[0]);
+ }
+ CFRelease(StatusVals[0]);
+ }
+ CFRelease(HostKeys[0]);
+ }
+}
+
+#if APPLE_OSX_mDNSResponder
+#if !NO_AWACS
+
+// checks whether a domain is present in Setup:/Network/BackToMyMac. Just because there is a key in the
+// keychain for a domain, it does not become a valid BTMM domain. If things get inconsistent, this will
+// help catch it
+mDNSlocal mDNSBool IsBTMMDomain(domainname *d)
+{
+ SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:IsBTMMDomain"), NULL, NULL);
+ if (!store)
+ {
+ LogMsg("IsBTMMDomain: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
+ return mDNSfalse;
+ }
+ CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
+ if (btmm)
+ {
+ CFIndex size = CFDictionaryGetCount(btmm);
+ char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
+ const void *key[size];
+ const void *val[size];
+ domainname dom;
+ int i;
+ CFDictionaryGetKeysAndValues(btmm, key, val);
+ for (i = 0; i < size; i++)
+ {
+ LogInfo("BackToMyMac %d", i);
+ if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
+ LogMsg("IsBTMMDomain: ERROR!! Can't read BackToMyMac %d key %s", i, buf);
+ else
+ {
+ mDNSu32 uid = atoi(buf);
+ if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
+ LogMsg("IsBTMMDomain: Can't read BackToMyMac %d val %s", i, buf);
+ else if (MakeDomainNameFromDNSNameString(&dom, buf) && dom.c[0])
+ {
+ if (SameDomainName(&dom, d))
+ {
+ LogInfo("IsBTMMDomain: Domain %##s is a btmm domain, uid %u", d->c, uid);
+ CFRelease(btmm);
+ CFRelease(store);
+ return mDNStrue;
+ }
+ }
+ }
+ }
+ CFRelease(btmm);
+ }
+ CFRelease(store);
+ LogInfo("IsBTMMDomain: Domain %##s not a btmm domain", d->c);
+ return mDNSfalse;
+}
+
+// Appends data to the buffer
+mDNSlocal int AddOneItem(char *buf, int bufsz, char *data, int *currlen)
+{
+ int len;
+
+ len = strlcpy(buf + *currlen, data, bufsz - *currlen);
+ if (len >= (bufsz - *currlen))
+ {
+ // if we have exceeded the space in buf, it has already been NULL terminated
+ // and we have nothing more to do. Set currlen to the last byte so that the caller
+ // knows to do the right thing
+ LogMsg("AddOneItem: Exceeded the max buffer size currlen %d, len %d", *currlen, len);
+ *currlen = bufsz - 1;
+ return -1;
+ }
+ else { (*currlen) += len; }
+
+ buf[*currlen] = ',';
+ if (*currlen >= bufsz)
+ {
+ LogMsg("AddOneItem: ERROR!! How can currlen be %d", *currlen);
+ *currlen = bufsz - 1;
+ buf[*currlen] = 0;
+ return -1;
+ }
+ // if we have filled up the buffer exactly, then there is no more work to do
+ if (*currlen == bufsz - 1) { buf[*currlen] = 0; return -1; }
+ (*currlen)++;
+ return *currlen;
+}
+
+// If we have at least one BTMM domain, then trigger the connection to the relay. If we have no
+// BTMM domains, then bring down the connection to the relay.
+mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
+{
+ DomainAuthInfo *BTMMDomain = mDNSNULL;
+ DomainAuthInfo *FoundInList;
+ static mDNSBool AWACSDConnected = mDNSfalse;
+ char AllUsers[1024]; // maximum size of mach message
+ char AllPass[1024]; // maximum size of mach message
+ char username[MAX_DOMAIN_LABEL + 1];
+ int currulen = 0;
+ int currplen = 0;
+
+ // if a domain is being deleted, we want to send a disconnect. If we send a disconnect now,
+ // we may not be able to send the dns queries over the relay connection which may be needed
+ // for sending the deregistrations. Hence, we need to delay sending the disconnect. But we
+ // need to make sure that we send the disconnect before attempting the next connect as the
+ // awacs connections are redirected based on usernames.
+ //
+ // For now we send a disconnect immediately. When we start sending dns queries over the relay
+ // connection, we will need to fix this.
+
+ for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
+ if (!FoundInList->deltime && FoundInList->AutoTunnel && IsBTMMDomain(&FoundInList->domain))
+ {
+ // We need the passwd from the first domain.
+ BTMMDomain = FoundInList;
+ ConvertDomainLabelToCString_unescaped((domainlabel *)BTMMDomain->domain.c, username);
+ LogInfo("UpdateBTMMRelayConnection: user %s for domain %##s", username, BTMMDomain->domain.c);
+ if (AddOneItem(AllUsers, sizeof(AllUsers), username, &currulen) == -1) break;
+ if (AddOneItem(AllPass, sizeof(AllPass), BTMMDomain->b64keydata, &currplen) == -1) break;
+ }
+
+ if (BTMMDomain)
+ {
+ // In the normal case (where we neither exceed the buffer size nor write bytes that
+ // fit exactly into the buffer), currulen/currplen should be a different size than
+ // (AllUsers - 1) / (AllPass - 1). In that case, we need to override the "," with a NULL byte.
+
+ if (currulen != (int)(sizeof(AllUsers) - 1)) AllUsers[currulen - 1] = 0;
+ if (currplen != (int)(sizeof(AllPass) - 1)) AllPass[currplen - 1] = 0;
+
+ LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers);
+ AWACS_Connect(AllUsers, AllPass, "hello.connectivity.me.com");
+ AWACSDConnected = mDNStrue;
+ }
+ else
+ {
+ // Disconnect only if we connected previously
+ if (AWACSDConnected)
+ {
+ LogInfo("UpdateBTMMRelayConnection: AWS_Disconnect");
+ AWACS_Disconnect();
+ AWACSDConnected = mDNSfalse;
+ }
+ else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect");
+ }
+}
+#else
+mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
+{
+ (void) m; // Unused
+ LogInfo("UpdateBTMMRelayConnection: AWACS connection not started, no AWACS library");
+}
+#endif // ! NO_AWACS
+
+mDNSlocal void ProcessConndConfigChanges(mDNS *const m);
+
+#endif // APPLE_OSX_mDNSResponder
+
+// MUST be called holding the lock
+mDNSexport void SetDomainSecrets(mDNS *m)
+{
+#ifdef NO_SECURITYFRAMEWORK
+ (void) m;
+ LogMsg("Note: SetDomainSecrets: no keychain support");
+#else
+ mDNSBool haveAutoTunnels = mDNSfalse;
+
+ LogInfo("SetDomainSecrets");
+
+ // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
+ // In the case where the user simultaneously removes their DDNS host name and the key
+ // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
+ // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
+ // address records behind that we no longer have permission to delete.
+ DomainAuthInfo *ptr;
+ for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
+ ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
+
+#if APPLE_OSX_mDNSResponder
+ {
+ // Mark all TunnelClients for deletion
+ ClientTunnel *client;
+ for (client = m->TunnelClients; client; client = client->next)
+ {
+ LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c);
+ client->MarkedForDeletion = mDNStrue;
+ }
+ }
+#endif // APPLE_OSX_mDNSResponder
+
+ // String Array used to write list of private domains to Dynamic Store
+ CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ if (!sa) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
+ CFIndex i;
+ CFDataRef data = NULL;
+ const int itemsPerEntry = 4; // domain name, key name, key value, Name value
+ CFArrayRef secrets = NULL;
+ int err = mDNSKeychainGetSecrets(&secrets);
+ if (err || !secrets)
+ LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err, secrets);
+ else
+ {
+ CFIndex ArrayCount = CFArrayGetCount(secrets);
+ // Iterate through the secrets
+ for (i = 0; i < ArrayCount; ++i)
+ {
+ mDNSBool AutoTunnel;
+ int j, offset;
+ CFArrayRef entry = CFArrayGetValueAtIndex(secrets, i);
+ if (CFArrayGetTypeID() != CFGetTypeID(entry) || itemsPerEntry != CFArrayGetCount(entry))
+ { LogMsg("SetDomainSecrets: malformed entry %d, itemsPerEntry %d", i, itemsPerEntry); continue; }
+ for (j = 0; j < CFArrayGetCount(entry); ++j)
+ if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry, j)))
+ { LogMsg("SetDomainSecrets: malformed entry item %d", j); continue; }
+
+ // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
+
+ // Max legal domainname as C-string, including space for btmmprefix and terminating NUL
+ // Get DNS domain this key is for (kmDNSKcWhere)
+ char stringbuf[MAX_ESCAPED_DOMAIN_NAME + sizeof(btmmprefix)];
+ data = CFArrayGetValueAtIndex(entry, kmDNSKcWhere);
+ if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
+ { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data)); continue; }
+ CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
+ stringbuf[CFDataGetLength(data)] = '\0';
+
+ AutoTunnel = mDNSfalse;
+ offset = 0;
+ if (!strncmp(stringbuf, dnsprefix, strlen(dnsprefix)))
+ offset = strlen(dnsprefix);
+ else if (!strncmp(stringbuf, btmmprefix, strlen(btmmprefix)))
+ {
+ AutoTunnel = mDNStrue;
+ offset = strlen(btmmprefix);
+ }
+ domainname domain;
+ if (!MakeDomainNameFromDNSNameString(&domain, stringbuf + offset)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf); continue; }
+
+ // Get key name (kmDNSKcAccount)
+ data = CFArrayGetValueAtIndex(entry, kmDNSKcAccount);
+ if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
+ { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data)); continue; }
+ CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)stringbuf);
+ stringbuf[CFDataGetLength(data)] = '\0';
+
+ domainname keyname;
+ if (!MakeDomainNameFromDNSNameString(&keyname, stringbuf)) { LogMsg("SetDomainSecrets: bad key name %s", stringbuf); continue; }
+
+ // Get key data (kmDNSKcKey)
+ data = CFArrayGetValueAtIndex(entry, kmDNSKcKey);
+ if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
+ {
+ LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data));
+ continue;
+ }
+ CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
+ stringbuf[CFDataGetLength(data)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key
+
+ // Get the Name of the keychain entry (kmDNSKcName) host or host:port
+ // The hostname also has the port number and ":". It should take a maximum of 6 bytes.
+ char hostbuf[MAX_ESCAPED_DOMAIN_NAME + 6]; // Max legal domainname as C-string, including terminating NUL
+ data = CFArrayGetValueAtIndex(entry, kmDNSKcName);
+ if (CFDataGetLength(data) >= (int)sizeof(hostbuf))
+ {
+ LogMsg("SetDomainSecrets: host:port data too long: %d", CFDataGetLength(data));
+ continue;
+ }
+ CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)hostbuf);
+ hostbuf[CFDataGetLength(data)] = '\0';
+
+ domainname hostname;
+ mDNSIPPort port;
+ char *hptr;
+ hptr = strchr(hostbuf, ':');
+
+ port.NotAnInteger = 0;
+ if (hptr)
+ {
+ mDNSu8 *p;
+ mDNSu16 val = 0;
+
+ *hptr++ = '\0';
+ while(hptr && *hptr != 0)
+ {
+ if (*hptr < '0' || *hptr > '9')
+ { LogMsg("SetDomainSecrets: Malformed Port number %d, val %d", *hptr, val); val = 0; break;}
+ val = val * 10 + *hptr - '0';
+ hptr++;
+ }
+ if (!val) continue;
+ p = (mDNSu8 *)&val;
+ port.NotAnInteger = p[0] << 8 | p[1];
+ }
+ // The hostbuf is of the format dsid at hostname:port. We don't care about the dsid.
+ hptr = strchr(hostbuf, '@');
+ if (hptr)
+ hptr++;
+ else
+ hptr = hostbuf;
+ if (!MakeDomainNameFromDNSNameString(&hostname, hptr)) { LogMsg("SetDomainSecrets: bad host name %s", hptr); continue; }
+
+ DomainAuthInfo *FoundInList;
+ for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
+ if (SameDomainName(&FoundInList->domain, &domain)) break;
+
+#if APPLE_OSX_mDNSResponder
+ if (FoundInList)
+ {
+ // If any client tunnel destination is in this domain, set deletion flag to false
+ ClientTunnel *client;
+ for (client = m->TunnelClients; client; client = client->next)
+ if (FoundInList == GetAuthInfoForName_internal(m, &client->dstname))
+ {
+ LogInfo("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c);
+ client->MarkedForDeletion = mDNSfalse;
+ }
+ }
+
+#endif // APPLE_OSX_mDNSResponder
+
+ // Uncomment the line below to view the keys as they're read out of the system keychain
+ // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
+ //LogInfo("SetDomainSecrets: domain %##s keyname %##s key %s hostname %##s port %d", &domain.c, &keyname.c, stringbuf, hostname.c, (port.b[0] << 8 | port.b[1]));
+ LogInfo("SetDomainSecrets: domain %##s keyname %##s hostname %##s port %d", &domain.c, &keyname.c, hostname.c, (port.b[0] << 8 | port.b[1]));
+
+ // If didn't find desired domain in the list, make a new entry
+ ptr = FoundInList;
+ if (FoundInList && FoundInList->AutoTunnel && haveAutoTunnels == mDNSfalse) haveAutoTunnels = mDNStrue;
+ if (!FoundInList)
+ {
+ ptr = (DomainAuthInfo*)mallocL("DomainAuthInfo", sizeof(*ptr));
+ if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; }
+ }
+
+ //LogInfo("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
+
+ // It is an AutoTunnel if the keychains tells us so (with btmm prefix) or if it is a TunnelModeDomain
+ if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, stringbuf, &hostname, &port, AutoTunnel) == mStatus_BadParamErr)
+ {
+ if (!FoundInList) mDNSPlatformMemFree(ptr); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
+ continue;
+ }
+
+ ConvertDomainNameToCString(&domain, stringbuf);
+ CFStringRef cfs = CFStringCreateWithCString(NULL, stringbuf, kCFStringEncodingUTF8);
+ if (cfs) { CFArrayAppendValue(sa, cfs); CFRelease(cfs); }
+ }
+ CFRelease(secrets);
+ }
+
+ if (!privateDnsArray || !CFEqual(privateDnsArray, sa))
+ {
+ if (privateDnsArray)
+ CFRelease(privateDnsArray);
+
+ privateDnsArray = sa;
+ CFRetain(privateDnsArray);
+ mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
+ }
+ CFRelease(sa);
+
+#if APPLE_OSX_mDNSResponder
+ {
+ // clean up ClientTunnels
+ ClientTunnel **pp = &m->TunnelClients;
+ while (*pp)
+ {
+ if ((*pp)->MarkedForDeletion)
+ {
+ ClientTunnel *cur = *pp;
+ LogInfo("SetDomainSecrets: removing client %p %##s from list", cur, cur->dstname.c);
+ if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
+ AutoTunnelSetKeys(cur, mDNSfalse);
+ *pp = cur->next;
+ freeL("ClientTunnel", cur);
+ }
+ else
+ pp = &(*pp)->next;
+ }
+
+ mDNSBool needAutoTunnelNAT = mDNSfalse;
+ DomainAuthInfo *info;
+ for (info = m->AuthInfoList; info; info = info->next)
+ {
+ if (info->AutoTunnel)
+ {
+ UpdateAutoTunnelDeviceInfoRecord(m, info);
+ UpdateAutoTunnelHostRecord(m, info);
+ UpdateAutoTunnelServiceRecords(m, info);
+ UpdateAutoTunnel6Record(m, info);
+ if (info->deltime)
+ {
+ if (info->AutoTunnelServiceStarted) info->AutoTunnelServiceStarted = mDNSfalse;
+ }
+ else if (info->AutoTunnelServiceStarted)
+ needAutoTunnelNAT = true;
+
+ UpdateAutoTunnelDomainStatus(m, info);
+ }
+ }
+
+ // If the AutoTunnel NAT-T is no longer needed (& is currently running), stop it
+ if (!needAutoTunnelNAT && m->AutoTunnelNAT.clientContext)
+ {
+ // stop the NAT operation, reset port, cleanup state
+ mDNS_StopNATOperation_internal(m, &m->AutoTunnelNAT);
+ m->AutoTunnelNAT.ExternalAddress = zerov4Addr;
+ m->AutoTunnelNAT.NewAddress = zerov4Addr;
+ m->AutoTunnelNAT.ExternalPort = zeroIPPort;
+ m->AutoTunnelNAT.RequestedPort = zeroIPPort;
+ m->AutoTunnelNAT.Lifetime = 0;
+ m->AutoTunnelNAT.Result = mStatus_NoError;
+ m->AutoTunnelNAT.clientContext = mDNSNULL;
+ }
+
+ UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
+ ProcessConndConfigChanges(m); // Update AutoTunnelInnerAddress values and default ipsec policies as necessary
+ }
+#endif // APPLE_OSX_mDNSResponder
+
+ CheckSuppressUnusableQuestions(m);
+
+#endif /* NO_SECURITYFRAMEWORK */
+}
+
+mDNSlocal void SetLocalDomains(void)
+{
+ CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ if (!sa) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; }
+
+ CFArrayAppendValue(sa, CFSTR("local"));
+ CFArrayAppendValue(sa, CFSTR("254.169.in-addr.arpa"));
+ CFArrayAppendValue(sa, CFSTR("8.e.f.ip6.arpa"));
+ CFArrayAppendValue(sa, CFSTR("9.e.f.ip6.arpa"));
+ CFArrayAppendValue(sa, CFSTR("a.e.f.ip6.arpa"));
+ CFArrayAppendValue(sa, CFSTR("b.e.f.ip6.arpa"));
+
+ mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, mDNSNULL, sa);
+ CFRelease(sa);
+}
+
+mDNSlocal void GetCurrentPMSetting(const CFStringRef name, mDNSs32 *val)
+{
+#if USE_IOPMCOPYACTIVEPMPREFERENCES
+ CFTypeRef blob = NULL;
+ CFStringRef str = NULL;
+ CFDictionaryRef odict = NULL;
+ CFDictionaryRef idict = NULL;
+ CFNumberRef number = NULL;
+
+ blob = IOPSCopyPowerSourcesInfo();
+ if (!blob) { LogMsg("GetCurrentPMSetting: IOPSCopyPowerSourcesInfo failed!"); goto end; }
+
+ odict = IOPMCopyActivePMPreferences();
+ if (!odict) { LogMsg("GetCurrentPMSetting: IOPMCopyActivePMPreferences failed!"); goto end; }
+
+ str = IOPSGetProvidingPowerSourceType(blob);
+ if (!str) { LogMsg("GetCurrentPMSetting: IOPSGetProvidingPowerSourceType failed!"); goto end; }
+
+ idict = CFDictionaryGetValue(odict, str);
+ if (!idict)
+ {
+ char buf[256];
+ if (!CFStringGetCString(str, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
+ LogMsg("GetCurrentPMSetting: CFDictionaryGetValue (%s) failed!", buf);
+ goto end;
+ }
+
+ number = CFDictionaryGetValue(idict, name);
+ if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
+ *val = 0;
+end:
+ if (blob) CFRelease(blob);
+ if (odict) CFRelease(odict);
+
+#else
+
+ SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetCurrentPMSetting"), NULL, NULL);
+ if (!store) LogMsg("GetCurrentPMSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
+ else
+ {
+ CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_PowerSettings);
+ if (!dict) LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict");
+ else
+ {
+ CFNumberRef number = CFDictionaryGetValue(dict, name);
+ if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
+ *val = 0;
+ CFRelease(dict);
+ }
+ CFRelease(store);
+ }
+
+#endif
+}
+
+#if APPLE_OSX_mDNSResponder
+
+static CFMutableDictionaryRef spsStatusDict = NULL;
+static const CFStringRef kMetricRef = CFSTR("Metric");
+
+mDNSlocal void SPSStatusPutNumber(CFMutableDictionaryRef dict, const mDNSu8* const ptr, CFStringRef key)
+{
+ mDNSu8 tmp = (ptr[0] - '0') * 10 + ptr[1] - '0';
+ CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt8Type, &tmp);
+ if (!num)
+ LogMsg("SPSStatusPutNumber: Could not create CFNumber");
+ else
+ {
+ CFDictionarySetValue(dict, key, num);
+ CFRelease(num);
+ }
+}
+
+mDNSlocal CFMutableDictionaryRef SPSCreateDict(const mDNSu8* const ptr)
+{
+ CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ if (!dict) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict; }
+
+ char buffer[1024];
+ buffer[mDNS_snprintf(buffer, sizeof(buffer), "%##s", ptr) - 1] = 0;
+ CFStringRef spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
+ if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname full"); CFRelease(dict); return NULL; }
+ CFDictionarySetValue(dict, CFSTR("FullName"), spsname);
+ CFRelease(spsname);
+
+ if (ptr[0] >= 2) SPSStatusPutNumber(dict, ptr + 1, CFSTR("Type"));
+ if (ptr[0] >= 5) SPSStatusPutNumber(dict, ptr + 4, CFSTR("Portability"));
+ if (ptr[0] >= 8) SPSStatusPutNumber(dict, ptr + 7, CFSTR("MarginalPower"));
+ if (ptr[0] >= 11) SPSStatusPutNumber(dict, ptr +10, CFSTR("TotalPower"));
+
+ mDNSu32 tmp = SPSMetric(ptr);
+ CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tmp);
+ if (!num)
+ LogMsg("SPSCreateDict: Could not create CFNumber");
+ else
+ {
+ CFDictionarySetValue(dict, kMetricRef, num);
+ CFRelease(num);
+ }
+
+ if (ptr[0] >= 12)
+ {
+ memcpy(buffer, ptr + 13, ptr[0] - 12);
+ buffer[ptr[0] - 12] = 0;
+ spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
+ if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname"); CFRelease(dict); return NULL; }
+ else
+ {
+ CFDictionarySetValue(dict, CFSTR("PrettyName"), spsname);
+ CFRelease(spsname);
+ }
+ }
+
+ return dict;
+}
+
+mDNSlocal CFComparisonResult CompareSPSEntries(const void *val1, const void *val2, void *context)
+{
+ (void)context;
+ return CFNumberCompare((CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val1, kMetricRef),
+ (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val2, kMetricRef),
+ NULL);
+}
+
+mDNSlocal void UpdateSPSStatus(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
+{
+ NetworkInterfaceInfo* info = (NetworkInterfaceInfo*)question->QuestionContext;
+ debugf("UpdateSPSStatus: %s %##s %s %s", info->ifname, question->qname.c, AddRecord ? "Add" : "Rmv", answer ? RRDisplayString(m, answer) : "<null>");
+
+ mDNS_Lock(m);
+ mDNS_UpdateAllowSleep(m);
+ mDNS_Unlock(m);
+
+ if (answer && SPSMetric(answer->rdata->u.name.c) > 999999) return; // Ignore instances with invalid names
+
+ if (!spsStatusDict)
+ {
+ spsStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ if (!spsStatusDict) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; }
+ }
+
+ CFStringRef ifname = CFStringCreateWithCString(NULL, info->ifname, kCFStringEncodingUTF8);
+ if (!ifname) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; }
+
+ CFMutableArrayRef array = NULL;
+
+ if (!CFDictionaryGetValueIfPresent(spsStatusDict, ifname, (const void**) &array))
+ {
+ array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ if (!array) { LogMsg("UpdateSPSStatus: Could not create CFMutableArray"); CFRelease(ifname); return; }
+ CFDictionarySetValue(spsStatusDict, ifname, array);
+ CFRelease(array); // let go of our reference, now that the dict has one
+ }
+ else
+ if (!array) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info->ifname); CFRelease(ifname); return; }
+
+ if (!answer) // special call that means the question has been stopped (because the interface is going away)
+ CFArrayRemoveAllValues(array);
+ else
+ {
+ CFMutableDictionaryRef dict = SPSCreateDict(answer->rdata->u.name.c);
+ if (!dict) { CFRelease(ifname); return; }
+
+ if (AddRecord)
+ {
+ if (!CFArrayContainsValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict))
+ {
+ int i=0;
+ for (i=0; i<CFArrayGetCount(array); i++)
+ if (CompareSPSEntries(CFArrayGetValueAtIndex(array, i), dict, NULL) != kCFCompareLessThan)
+ break;
+ CFArrayInsertValueAtIndex(array, i, dict);
+ }
+ else LogMsg("UpdateSPSStatus: %s array already contains %##s", info->ifname, answer->rdata->u.name.c);
+ }
+ else
+ {
+ CFIndex i = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict);
+ if (i != -1) CFArrayRemoveValueAtIndex(array, i);
+ else LogMsg("UpdateSPSStatus: %s array does not contain %##s", info->ifname, answer->rdata->u.name.c);
+ }
+
+ CFRelease(dict);
+ }
+
+ if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, info->ifname, array);
+
+ CFRelease(ifname);
+}
+
+mDNSlocal mDNSs32 GetSystemSleepTimerSetting(void)
+{
+ mDNSs32 val = -1;
+ SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL, NULL);
+ if (!store)
+ LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
+ else
+ {
+ CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_PowerSettings);
+ if (dict)
+ {
+ CFNumberRef number = CFDictionaryGetValue(dict, CFSTR("System Sleep Timer"));
+ if (number) CFNumberGetValue(number, kCFNumberSInt32Type, &val);
+ CFRelease(dict);
+ }
+ CFRelease(store);
+ }
+ return val;
+}
+
+mDNSlocal void SetSPS(mDNS *const m)
+{
+
+ // If we ever want to know InternetSharing status in the future, use DNSXEnableProxy()
+ mDNSu8 sps = (OfferSleepProxyService && GetSystemSleepTimerSetting() == 0) ? mDNSSleepProxyMetric_IncidentalSoftware : 0;
+
+ // For devices that are not running NAT, but are set to never sleep, we may choose to act
+ // as a Sleep Proxy, but only for non-portable Macs (Portability > 35 means nominal weight < 3kg)
+ //if (sps > mDNSSleepProxyMetric_PrimarySoftware && SPMetricPortability > 35) sps = 0;
+
+ // If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery
+
+ // For devices that are unable to sleep at all to save power, or save 1W or less by sleeping,
+ // it makes sense for them to offer low-priority Sleep Proxy service on the network.
+ // We rate such a device as metric 70 ("Incidentally Available Hardware")
+ if (SPMetricMarginalPower <= 60 && !sps) sps = mDNSSleepProxyMetric_IncidentalHardware;
+
+ // If the launchd plist specifies an explicit value for the Intent Metric, then use that instead of the
+ // computed value (currently 40 "Primary Network Infrastructure Software" or 80 "Incidentally Available Software")
+ if (sps && OfferSleepProxyService && OfferSleepProxyService < 100) sps = OfferSleepProxyService;
+
+#ifdef NO_APPLETV_SLEEP_PROXY_ON_WIFI
+ // AppleTVs are not reliable sleep proxy servers on WiFi. Do not offer to be a BSP if the WiFi interface is active.
+ if (IsAppleTV())
+ {
+ NetworkInterfaceInfo *intf = mDNSNULL;
+ mDNSEthAddr bssid = zeroEthAddr;
+ for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
+ {
+ bssid = GetBSSID(intf->ifname);
+ if (!mDNSSameEthAddress(&bssid, &zeroEthAddr))
+ {
+ LogMsg("SetSPS: AppleTV on WiFi - not advertising BSP services");
+ sps = 0;
+ break;
+ }
+ }
+ }
+#endif // NO_APPLETV_SLEEP_PROXY_ON_WIFI
+
+ mDNSCoreBeSleepProxyServer(m, sps, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures);
+}
+
+// The definitions below should eventually come from some externally-supplied header file.
+// However, since these definitions can't really be changed without breaking binary compatibility,
+// they should never change, so in practice it should not be a big problem to have them defined here.
+
+enum
+{ // commands from the daemon to the driver
+ cmd_mDNSOffloadRR = 21, // give the mdns update buffer to the driver
+};
+
+typedef union { void *ptr; mDNSOpaque64 sixtyfourbits; } FatPtr;
+
+typedef struct
+{ // cmd_mDNSOffloadRR structure
+ uint32_t command; // set to OffloadRR
+ uint32_t rrBufferSize; // number of bytes of RR records
+ uint32_t numUDPPorts; // number of SRV UDP ports
+ uint32_t numTCPPorts; // number of SRV TCP ports
+ uint32_t numRRRecords; // number of RR records
+ uint32_t compression; // rrRecords - compression is base for compressed strings
+ FatPtr rrRecords; // address of array of pointers to the rr records
+ FatPtr udpPorts; // address of udp port list (SRV)
+ FatPtr tcpPorts; // address of tcp port list (SRV)
+} mDNSOffloadCmd;
+
+#include <IOKit/IOKitLib.h>
+#include <dns_util.h>
+
+mDNSlocal mDNSu16 GetPortArray(mDNS *const m, int trans, mDNSIPPort *portarray)
+{
+ const domainlabel *const tp = (trans == mDNSTransport_UDP) ? (const domainlabel *)"\x4_udp" : (const domainlabel *)"\x4_tcp";
+ int count = 0;
+ AuthRecord *rr;
+ for (rr = m->ResourceRecords; rr; rr=rr->next)
+ if (rr->resrec.rrtype == kDNSType_SRV && SameDomainLabel(ThirdLabel(rr->resrec.name)->c, tp->c))
+ {
+ if (portarray) portarray[count] = rr->resrec.rdata->u.srv.port;
+ count++;
+ }
+
+ // If Back to My Mac is on, also wake for packets to the IPSEC UDP port (4500)
+ if (trans == mDNSTransport_UDP && m->AutoTunnelNAT.clientContext)
+ {
+ LogSPS("GetPortArray Back to My Mac at %d", count);
+ if (portarray) portarray[count] = IPSECPort;
+ count++;
+ }
+ return(count);
+}
+
+#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
+mDNSlocal mDNSBool SupportsTCPKeepAlive()
+{
+ IOReturn ret = kIOReturnSuccess;
+ CFTypeRef obj = NULL;
+ mDNSBool supports = mDNSfalse;
+
+ ret = IOPlatformCopyFeatureActive(CFSTR("TCPKeepAliveDuringSleep"), &obj);
+ if ((kIOReturnSuccess == ret) && (obj != NULL))
+ {
+ supports = (obj == kCFBooleanTrue)? mDNStrue : mDNSfalse;
+ CFRelease(obj);
+ }
+ LogSPS("%s: The hardware %s TCP Keep Alive", __func__, (supports ? "supports" : "does not support"));
+ return supports;
+}
+
+mDNSlocal mDNSBool OnBattery(void)
+{
+ CFTypeRef powerInfo = IOPSCopyPowerSourcesInfo();
+ CFTypeRef powerSrc = IOPSGetProvidingPowerSourceType(powerInfo);
+ mDNSBool result = mDNSfalse;
+
+ if (powerInfo != NULL)
+ {
+ result = CFEqual(CFSTR(kIOPSBatteryPowerValue), powerSrc);
+ CFRelease(powerInfo);
+ }
+ LogSPS("%s: The system is on %s", __func__, (result)? "Battery" : "AC Power");
+ return result;
+}
+
+#endif // !TARGET_OS_EMBEDDED
+
+#define TfrRecordToNIC(RR) \
+ ((!(RR)->resrec.InterfaceID && ((RR)->ForceMCast || IsLocalDomain((RR)->resrec.name))))
+
+mDNSlocal mDNSu32 CountProxyRecords(mDNS *const m, uint32_t *const numbytes, NetworkInterfaceInfo *const intf, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
+{
+ *numbytes = 0;
+ int count = 0;
+
+ AuthRecord *rr;
+
+ for (rr = m->ResourceRecords; rr; rr=rr->next)
+ {
+ if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
+ {
+#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
+ mDNSBool isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
+ // Skip over all other records if we are registering TCP KeepAlive records only
+ // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive.
+ if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
+ continue;
+
+ // Update the record before calculating the number of bytes required
+ // We offload the TCP Keepalive record even if the update fails. When the driver gets the record, it will
+ // attempt to update the record again.
+ if (isKeepAliveRecord && (UpdateKeepaliveRData(m, rr, intf, mDNSfalse, mDNSNULL) != mStatus_NoError))
+ LogSPS("CountProxyRecords: Failed to update keepalive record - %s", ARDisplayString(m, rr));
+#else
+ (void) TCPKAOnly; // unused
+ (void) supportsTCPKA; // unused
+ (void) intf; // unused
+#endif // APPLE_OSX_mDNSResponder
+ if (TfrRecordToNIC(rr))
+ {
+ *numbytes += DomainNameLength(rr->resrec.name) + 10 + rr->resrec.rdestimate;
+ LogSPS("CountProxyRecords: %3d size %5d total %5d %s",
+ count, DomainNameLength(rr->resrec.name) + 10 + rr->resrec.rdestimate, *numbytes, ARDisplayString(m,rr));
+ count++;
+ }
+ }
+ }
+ return(count);
+}
+
+mDNSlocal void GetProxyRecords(mDNS *const m, DNSMessage *const msg, uint32_t *const numbytes, FatPtr *const records, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
+{
+ mDNSu8 *p = msg->data;
+ const mDNSu8 *const limit = p + *numbytes;
+ InitializeDNSMessage(&msg->h, zeroID, zeroID);
+
+ int count = 0;
+ AuthRecord *rr;
+
+ for (rr = m->ResourceRecords; rr; rr=rr->next)
+ {
+ if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
+ {
+#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
+ mDNSBool isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
+
+ // Skip over all other records if we are registering TCP KeepAlive records only
+ // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive
+ if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
+ continue;
+#else
+ (void) TCPKAOnly; // unused
+ (void) supportsTCPKA; // unused
+#endif // APPLE_OSX_mDNSResponder
+
+ if (TfrRecordToNIC(rr))
+ {
+ records[count].sixtyfourbits = zeroOpaque64;
+ records[count].ptr = p;
+ if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
+ rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the 'unique' bit so PutResourceRecord will set it
+ p = PutResourceRecordTTLWithLimit(msg, p, &msg->h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit);
+ rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear 'unique' bit back to normal state
+ LogSPS("GetProxyRecords: %3d start %p end %p size %5d total %5d %s",
+ count, records[count].ptr, p, p - (mDNSu8 *)records[count].ptr, p - msg->data, ARDisplayString(m,rr));
+ count++;
+ }
+ }
+ }
+ *numbytes = p - msg->data;
+}
+
+// If compiling with old headers and libraries (pre 10.5) that don't include IOConnectCallStructMethod
+// then we declare a dummy version here so that the code at least compiles
+#ifndef AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+static kern_return_t
+IOConnectCallStructMethod(
+ mach_port_t connection, // In
+ uint32_t selector, // In
+ const void *inputStruct, // In
+ size_t inputStructCnt, // In
+ void *outputStruct, // Out
+ size_t *outputStructCnt) // In/Out
+{
+ (void)connection;
+ (void)selector;
+ (void)inputStruct;
+ (void)inputStructCnt;
+ (void)outputStruct;
+ (void)outputStructCnt;
+ LogMsg("Compiled without IOConnectCallStructMethod");
+ return(KERN_FAILURE);
+}
+#endif
+
+mDNSexport mDNSBool SupportsInNICProxy(NetworkInterfaceInfo *const intf)
+{
+ if(!UseInternalSleepProxy)
+ {
+ LogSPS("SupportsInNICProxy: Internal Sleep Proxy is disabled");
+ return mDNSfalse;
+ }
+ return CheckInterfaceSupport(intf, mDNS_IOREG_KEY);
+}
+
+mDNSexport mStatus ActivateLocalProxy(mDNS *const m, NetworkInterfaceInfo *const intf) // Called with the lock held
+{
+ mStatus result = mStatus_UnknownErr;
+ mDNSBool TCPKAOnly = mDNSfalse;
+ mDNSBool supportsTCPKA = mDNSfalse;
+ mDNSBool onbattery = mDNSfalse;
+ io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
+
+#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
+ onbattery = OnBattery();
+ // Check if the interface supports TCP Keepalives and the system policy says it is ok to offload TCP Keepalive records
+ supportsTCPKA = (InterfaceSupportsKeepAlive(intf) && SupportsTCPKeepAlive());
+
+ // Only TCP Keepalive records are to be offloaded if
+ // - The system is on battery
+ // - OR wake for network access is not set but powernap is enabled
+ TCPKAOnly = supportsTCPKA && ((m->SystemWakeOnLANEnabled == mDNS_WakeOnBattery) || onbattery);
+#else
+ (void) onbattery; // unused;
+#endif
+ if (!service) { LogMsg("ActivateLocalProxy: No service for interface %s", intf->ifname); return(mStatus_UnknownErr); }
+
+ io_name_t n1, n2;
+ IOObjectGetClass(service, n1);
+ io_object_t parent;
+ kern_return_t kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
+ if (kr != KERN_SUCCESS) LogMsg("ActivateLocalProxy: IORegistryEntryGetParentEntry for %s/%s failed %d", intf->ifname, n1, kr);
+ else
+ {
+ IOObjectGetClass(parent, n2);
+ LogSPS("ActivateLocalProxy: Interface %s service %s parent %s", intf->ifname, n1, n2);
+ const CFTypeRef ref = IORegistryEntryCreateCFProperty(parent, CFSTR(mDNS_IOREG_KEY), kCFAllocatorDefault, mDNSNULL);
+ if (!ref) LogSPS("ActivateLocalProxy: No mDNS_IOREG_KEY for interface %s/%s/%s", intf->ifname, n1, n2);
+ else
+ {
+ if (CFGetTypeID(ref) != CFStringGetTypeID() || !CFEqual(ref, CFSTR(mDNS_IOREG_VALUE)))
+ LogMsg("ActivateLocalProxy: mDNS_IOREG_KEY for interface %s/%s/%s value %s != %s",
+ intf->ifname, n1, n2, CFStringGetCStringPtr(ref, mDNSNULL), mDNS_IOREG_VALUE);
+ else if (!UseInternalSleepProxy)
+ LogSPS("ActivateLocalProxy: Not using internal (NIC) sleep proxy for interface %s", intf->ifname);
+ else
+ {
+ io_connect_t conObj;
+ kr = IOServiceOpen(parent, mach_task_self(), mDNS_USER_CLIENT_CREATE_TYPE, &conObj);
+ if (kr != KERN_SUCCESS) LogMsg("ActivateLocalProxy: IOServiceOpen for %s/%s/%s failed %d", intf->ifname, n1, n2, kr);
+ else
+ {
+ mDNSOffloadCmd cmd;
+ mDNSPlatformMemZero(&cmd, sizeof(cmd)); // When compiling 32-bit, make sure top 32 bits of 64-bit pointers get initialized to zero
+ cmd.command = cmd_mDNSOffloadRR;
+ cmd.numUDPPorts = GetPortArray(m, mDNSTransport_UDP, mDNSNULL);
+ cmd.numTCPPorts = GetPortArray(m, mDNSTransport_TCP, mDNSNULL);
+ cmd.numRRRecords = CountProxyRecords(m, &cmd.rrBufferSize, intf, TCPKAOnly, supportsTCPKA);
+ cmd.compression = sizeof(DNSMessageHeader);
+
+ DNSMessage *msg = (DNSMessage *)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader) + cmd.rrBufferSize);
+ cmd.rrRecords.ptr = mallocL("mDNSOffloadCmd rrRecords", cmd.numRRRecords * sizeof(FatPtr));
+ cmd.udpPorts.ptr = mallocL("mDNSOffloadCmd udpPorts", cmd.numUDPPorts * sizeof(mDNSIPPort));
+ cmd.tcpPorts.ptr = mallocL("mDNSOffloadCmd tcpPorts", cmd.numTCPPorts * sizeof(mDNSIPPort));
+
+ LogSPS("ActivateLocalProxy: msg %p %d RR %p %d, UDP %p %d, TCP %p %d",
+ msg, cmd.rrBufferSize,
+ cmd.rrRecords.ptr, cmd.numRRRecords,
+ cmd.udpPorts.ptr, cmd.numUDPPorts,
+ cmd.tcpPorts.ptr, cmd.numTCPPorts);
+
+ if (!msg || !cmd.rrRecords.ptr || !cmd.udpPorts.ptr || !cmd.tcpPorts.ptr)
+ LogMsg("ActivateLocalProxy: Failed to allocate memory: msg %p %d RR %p %d, UDP %p %d, TCP %p %d",
+ msg, cmd.rrBufferSize,
+ cmd.rrRecords.ptr, cmd.numRRRecords,
+ cmd.udpPorts.ptr, cmd.numUDPPorts,
+ cmd.tcpPorts.ptr, cmd.numTCPPorts);
+ else
+ {
+ GetProxyRecords(m, msg, &cmd.rrBufferSize, cmd.rrRecords.ptr, TCPKAOnly, supportsTCPKA);
+ GetPortArray(m, mDNSTransport_UDP, cmd.udpPorts.ptr);
+ GetPortArray(m, mDNSTransport_TCP, cmd.tcpPorts.ptr);
+ char outputData[2];
+ size_t outputDataSize = sizeof(outputData);
+ kr = IOConnectCallStructMethod(conObj, 0, &cmd, sizeof(cmd), outputData, &outputDataSize);
+ LogSPS("ActivateLocalProxy: IOConnectCallStructMethod for %s/%s/%s %d", intf->ifname, n1, n2, kr);
+ if (kr == KERN_SUCCESS) result = mStatus_NoError;
+ }
+
+ if (cmd.tcpPorts.ptr) freeL("mDNSOffloadCmd udpPorts", cmd.tcpPorts.ptr);
+ if (cmd.udpPorts.ptr) freeL("mDNSOffloadCmd tcpPorts", cmd.udpPorts.ptr);
+ if (cmd.rrRecords.ptr) freeL("mDNSOffloadCmd rrRecords", cmd.rrRecords.ptr);
+ if (msg) freeL("mDNSOffloadCmd msg", msg);
+ IOServiceClose(conObj);
+ }
+ }
+ CFRelease(ref);
+ }
+ IOObjectRelease(parent);
+ }
+ IOObjectRelease(service);
+ return result;
+}
+
+#endif // APPLE_OSX_mDNSResponder
+
+mDNSlocal mDNSu8 SystemWakeForNetworkAccess(void)
+{
+ mDNSs32 val = 0;
+ mDNSu8 ret = (mDNSu8)mDNS_NoWake;
+
+ if (DisableSleepProxyClient)
+ {
+ LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
+ return mDNSfalse;
+ }
+
+ GetCurrentPMSetting(CFSTR("Wake On LAN"), &val);
+
+ ret = (mDNSu8)(val != 0) ? mDNS_WakeOnAC : mDNS_NoWake;
+
+#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
+ // If we have TCP Keepalive support, system is capable of registering for TCP Keepalives.
+ // Further policy decisions on whether to offload the records is handled during sleep processing.
+ if ((ret == mDNS_NoWake) && SupportsTCPKeepAlive())
+ ret = (mDNSu8)mDNS_WakeOnBattery;
+#endif // APPLE_OSX_mDNSResponder
+
+ LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", ret);
+ return ret;
+}
+
+mDNSlocal mDNSBool SystemSleepOnlyIfWakeOnLAN(void)
+{
+ mDNSs32 val = 0;
+ GetCurrentPMSetting(CFSTR("PrioritizeNetworkReachabilityOverSleep"), &val);
+ return val != 0 ? mDNStrue : mDNSfalse;
+}
+
+#if APPLE_OSX_mDNSResponder
+// When sleeping, we always ensure that the _autotunnel6 record (if connected to RR relay)
+// gets deregistered, so that older peers are forced to connect over direct UDP instead of
+// the RR relay.
+//
+// When sleeping w/o a successful AutoTunnel NAT Mapping, we ensure that all our BTMM
+// service records are deregistered, so they do not appear in peers' Finder sidebars.
+// We do this by checking for the (non-autotunnel) SRV records, as the PTR and TXT records
+// depend on their associated SRV record and therefore will be deregistered together in a
+// single update with the SRV record.
+//
+// Also, the per-zone _kerberos TXT record is always there, including while sleeping, so
+// its presence shouldn't delay sleep.
+//
+// Note that the order of record deregistration is: first _autotunnel6 (if connected to RR
+// relay) and host records get deregistered, then SRV (UpdateAllSrvRecords), PTR and TXT.
+//
+// Also note that returning false here will not delay sleep past the maximum of 10 seconds.
+mDNSexport mDNSBool RecordReadyForSleep(mDNS *const m, AuthRecord *rr)
+{
+ if (!AuthRecord_uDNS(rr)) return mDNStrue;
+
+ if ((rr->resrec.rrtype == kDNSType_AAAA) && SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0c_autotunnel6"))
+ {
+ LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
+ return mDNSfalse;
+ }
+
+ if ((mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result))
+ {
+ if (rr->resrec.rrtype == kDNSType_SRV && rr->state != regState_NoTarget && rr->zone
+ && !SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0b_autotunnel"))
+ {
+ DomainAuthInfo *info = GetAuthInfoForName_internal(m, rr->zone);
+ if (info && info->AutoTunnel)
+ {
+ LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
+ return mDNSfalse;
+ }
+ }
+ }
+
+ return mDNStrue;
+}
+
+// Caller must hold the lock
+mDNSexport void RemoveAutoTunnel6Record(mDNS *const m)
+{
+ DomainAuthInfo *info;
+ // Set the address to zero before calling UpdateAutoTunnel6Record, so that it will
+ // deregister the record, and the MemFree callback won't re-register.
+ m->AutoTunnelRelayAddr = zerov6Addr;
+ for (info = m->AuthInfoList; info; info = info->next)
+ if (info->AutoTunnel)
+ UpdateAutoTunnel6Record(m, info);
+}
+
+mDNSlocal mDNSBool IPv6AddressIsOnInterface(mDNSv6Addr ipv6Addr, char *ifname)
+{
+ struct ifaddrs *ifa;
+ struct ifaddrs *ifaddrs;
+ mDNSAddr addr;
+
+ if (if_nametoindex(ifname) == 0) {LogInfo("IPv6AddressIsOnInterface: Invalid name %s", ifname); return mDNSfalse;}
+
+ if (getifaddrs(&ifaddrs) < 0) {LogInfo("IPv6AddressIsOnInterface: getifaddrs failed"); return mDNSfalse;}
+
+ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next)
+ {
+ if (strncmp(ifa->ifa_name, ifname, IFNAMSIZ) != 0)
+ continue;
+ if ((ifa->ifa_flags & IFF_UP) == 0 || !ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ if (SetupAddr(&addr, ifa->ifa_addr) != mStatus_NoError)
+ {
+ LogInfo("IPv6AddressIsOnInterface: SetupAddr error, continuing to the next address");
+ continue;
+ }
+ if (mDNSSameIPv6Address(ipv6Addr, *(mDNSv6Addr*)&addr.ip.v6))
+ {
+ LogInfo("IPv6AddressIsOnInterface: found %.16a", &ipv6Addr);
+ break;
+ }
+ }
+ freeifaddrs(ifaddrs);
+ return ifa != NULL;
+}
+
+mDNSlocal mDNSv6Addr IPv6AddressFromString(char* buf)
+{
+ mDNSv6Addr retVal;
+ struct addrinfo hints;
+ struct addrinfo *res0;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET6;
+ hints.ai_flags = AI_NUMERICHOST;
+
+ int err = getaddrinfo(buf, NULL, &hints, &res0);
+ if (err)
+ return zerov6Addr;
+
+ retVal = *(mDNSv6Addr*)&((struct sockaddr_in6*)res0->ai_addr)->sin6_addr;
+
+ freeaddrinfo(res0);
+
+ return retVal;
+}
+
+mDNSlocal CFDictionaryRef CopyConnectivityBackToMyMacDict()
+{
+ SCDynamicStoreRef store = NULL;
+ CFDictionaryRef connd = NULL;
+ CFDictionaryRef BTMMDict = NULL;
+
+ store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:CopyConnectivityBackToMyMacDict"), NULL, NULL);
+ if (!store)
+ {
+ LogMsg("CopyConnectivityBackToMyMacDict: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
+ goto end;
+ }
+
+ connd = SCDynamicStoreCopyValue(store, NetworkChangedKey_BTMMConnectivity);
+ if (!connd)
+ {
+ LogInfo("CopyConnectivityBackToMyMacDict: SCDynamicStoreCopyValue failed: %s", SCErrorString(SCError()));
+ goto end;
+ }
+
+ BTMMDict = CFDictionaryGetValue(connd, CFSTR("BackToMyMac"));
+ if (!BTMMDict)
+ {
+ LogInfo("CopyConnectivityBackToMyMacDict: CFDictionaryGetValue: No value for BackToMyMac");
+ goto end;
+ }
+
+ // Non-dictionary is treated as non-existent dictionary
+ if (CFGetTypeID(BTMMDict) != CFDictionaryGetTypeID())
+ {
+ BTMMDict = NULL;
+ LogMsg("CopyConnectivityBackToMyMacDict: BackToMyMac not a dictionary");
+ goto end;
+ }
+
+ CFRetain(BTMMDict);
+
+end:
+ if (connd) CFRelease(connd);
+ if (store) CFRelease(store);
+
+ return BTMMDict;
+}
+
+#define MAX_IPV6_TEXTUAL 40
+
+mDNSlocal mDNSv6Addr ParseBackToMyMacAddr(CFDictionaryRef BTMMDict, CFStringRef ifKey, CFStringRef addrKey)
+{
+ mDNSv6Addr retVal = zerov6Addr;
+ CFTypeRef string = NULL;
+ char ifname[IFNAMSIZ];
+ char address[MAX_IPV6_TEXTUAL];
+
+ if (!BTMMDict)
+ return zerov6Addr;
+
+ if (!CFDictionaryGetValueIfPresent(BTMMDict, ifKey, &string))
+ {
+ LogInfo("ParseBackToMyMacAddr: interface key does not exist");
+ return zerov6Addr;
+ }
+
+ if (!CFStringGetCString(string, ifname, IFNAMSIZ, kCFStringEncodingUTF8))
+ {
+ LogMsg("ParseBackToMyMacAddr: Could not convert interface to CString");
+ return zerov6Addr;
+ }
+
+ if (!CFDictionaryGetValueIfPresent(BTMMDict, addrKey, &string))
+ {
+ LogMsg("ParseBackToMyMacAddr: address key does not exist, but interface key does");
+ return zerov6Addr;
+ }
+
+ if (!CFStringGetCString(string, address, sizeof(address), kCFStringEncodingUTF8))
+ {
+ LogMsg("ParseBackToMyMacAddr: Could not convert address to CString");
+ return zerov6Addr;
+ }
+
+ retVal = IPv6AddressFromString(address);
+ LogInfo("ParseBackToMyMacAddr: %s (%s) %.16a", ifname, address, &retVal);
+
+ if (mDNSIPv6AddressIsZero(retVal))
+ return zerov6Addr;
+
+ if (!IPv6AddressIsOnInterface(retVal, ifname))
+ {
+ LogMsg("ParseBackToMyMacAddr: %.16a is not on %s", &retVal, ifname);
+ return zerov6Addr;
+ }
+
+ return retVal;
+}
+
+mDNSlocal CFDictionaryRef GetBackToMyMacZones(CFDictionaryRef BTMMDict)
+{
+ CFTypeRef zones = NULL;
+
+ if (!BTMMDict)
+ return NULL;
+
+ if (!CFDictionaryGetValueIfPresent(BTMMDict, CFSTR("Zones"), &zones))
+ {
+ LogInfo("CopyBTMMZones: Zones key does not exist");
+ return NULL;
+ }
+
+ return zones;
+}
+
+mDNSlocal mDNSv6Addr ParseBackToMyMacZone(CFDictionaryRef zones, DomainAuthInfo* info)
+{
+ mDNSv6Addr addr = zerov6Addr;
+ char buffer[MAX_ESCAPED_DOMAIN_NAME];
+ CFStringRef domain = NULL;
+ CFTypeRef theZone = NULL;
+
+ if (!zones)
+ return addr;
+
+ ConvertDomainNameToCString(&info->domain, buffer);
+ domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
+ if (!domain)
+ return addr;
+
+ if (CFDictionaryGetValueIfPresent(zones, domain, &theZone))
+ addr = ParseBackToMyMacAddr(theZone, CFSTR("Interface"), CFSTR("Address"));
+
+ CFRelease(domain);
+
+ return addr;
+}
+
+mDNSlocal void SetupBackToMyMacInnerAddresses(mDNS *const m, CFDictionaryRef BTMMDict)
+{
+ DomainAuthInfo* info;
+ CFDictionaryRef zones = GetBackToMyMacZones(BTMMDict);
+ mDNSv6Addr newAddr;
+
+ for (info = m->AuthInfoList; info; info = info->next)
+ {
+ if (!info->AutoTunnel)
+ continue;
+
+ newAddr = ParseBackToMyMacZone(zones, info);
+
+ if (mDNSSameIPv6Address(newAddr, info->AutoTunnelInnerAddress))
+ continue;
+
+ info->AutoTunnelInnerAddress = newAddr;
+ DeregisterAutoTunnelHostRecord(m, info);
+ UpdateAutoTunnelHostRecord(m, info);
+ UpdateAutoTunnelDomainStatus(m, info);
+ }
+}
+
+// MUST be called holding the lock
+mDNSlocal void ProcessConndConfigChanges(mDNS *const m)
+{
+ CFDictionaryRef dict = CopyConnectivityBackToMyMacDict();
+ if (!dict)
+ LogInfo("ProcessConndConfigChanges: No BTMM dictionary");
+ mDNSv6Addr relayAddr = ParseBackToMyMacAddr(dict, CFSTR("RelayInterface"), CFSTR("RelayAddress"));
+
+ LogInfo("ProcessConndConfigChanges: relay %.16a", &relayAddr);
+
+ SetupBackToMyMacInnerAddresses(m, dict);
+
+ if (dict) CFRelease(dict);
+
+ if (!mDNSSameIPv6Address(relayAddr, m->AutoTunnelRelayAddr))
+ {
+ m->AutoTunnelRelayAddr = relayAddr;
+
+ DomainAuthInfo* info;
+ for (info = m->AuthInfoList; info; info = info->next)
+ if (info->AutoTunnel)
+ {
+ DeregisterAutoTunnel6Record(m, info);
+ UpdateAutoTunnel6Record(m, info);
+ UpdateAutoTunnelDomainStatus(m, info);
+ }
+
+ // Determine whether we need racoon to accept incoming connections
+ UpdateAnonymousRacoonConfig(m);
+ }
+
+ // If awacsd crashes or exits for some reason, restart it
+ UpdateBTMMRelayConnection(m);
+}
+#endif /* APPLE_OSX_mDNSResponder */
+
+mDNSlocal mDNSBool IsAppleNetwork(mDNS *const m)
+{
+ DNSServer *s;
+ // Determine if we're on AppleNW based on DNSServer having 17.x.y.z IPv4 addr
+ for (s = m->DNSServers; s; s = s->next)
+ {
+ if (s->addr.ip.v4.b[0] == 17)
+ {
+ LogInfo("IsAppleNetwork: Found 17.x.y.z DNSServer concluding that we are on AppleNW: %##s %#a", s->domain.c, &s->addr);
+ return mDNStrue;
+ }
+ }
+ return mDNSfalse;
+}
+
+mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
+{
+ LogInfo("*** Network Configuration Change *** (%d)%s",
+ m->p->NetworkChanged ? mDNS_TimeNow(m) - m->p->NetworkChanged : 0,
+ m->p->NetworkChanged ? "" : " (no scheduled configuration change)");
+ m->p->NetworkChanged = 0; // If we received a network change event and deferred processing, we're now dealing with it
+ mDNSs32 utc = mDNSPlatformUTC();
+ m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
+ m->SystemSleepOnlyIfWakeOnLAN = SystemSleepOnlyIfWakeOnLAN();
+ MarkAllInterfacesInactive(m, utc);
+ UpdateInterfaceList(m, utc);
+ ClearInactiveInterfaces(m, utc);
+ SetupActiveInterfaces(m, utc);
+
+#if APPLE_OSX_mDNSResponder
+
+ mDNS_Lock(m);
+ ProcessConndConfigChanges(m);
+ mDNS_Unlock(m);
+
+ // Scan to find client tunnels whose questions have completed,
+ // but whose local inner/outer addresses have changed since the tunnel was set up
+ ClientTunnel *p;
+ for (p = m->TunnelClients; p; p = p->next)
+ if (p->q.ThisQInterval < 0)
+ {
+ DomainAuthInfo* info = GetAuthInfoForName(m, &p->dstname);
+ if (!info)
+ {
+ LogMsg("mDNSMacOSXNetworkChanged: Could not get AuthInfo for %##s, removing tunnel keys", p->dstname.c);
+ AutoTunnelSetKeys(p, mDNSfalse);
+ }
+ else
+ {
+ mDNSv6Addr inner = info->AutoTunnelInnerAddress;
+
+ if (!mDNSIPPortIsZero(p->rmt_outer_port))
+ {
+ mDNSAddr tmpSrc = zeroAddr;
+ mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
+ tmpDst.ip.v4 = p->rmt_outer;
+ mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
+ if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
+ !mDNSSameIPv4Address(p->loc_outer, tmpSrc.ip.v4))
+ {
+ AutoTunnelSetKeys(p, mDNSfalse);
+ p->loc_inner = inner;
+ p->loc_outer = tmpSrc.ip.v4;
+ AutoTunnelSetKeys(p, mDNStrue);
+ }
+ }
+ else
+ {
+ if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
+ !mDNSSameIPv6Address(p->loc_outer6, m->AutoTunnelRelayAddr))
+ {
+ AutoTunnelSetKeys(p, mDNSfalse);
+ p->loc_inner = inner;
+ p->loc_outer6 = m->AutoTunnelRelayAddr;
+ AutoTunnelSetKeys(p, mDNStrue);
+ }
+ }
+ }
+ }
+
+ SetSPS(m);
+
+ NetworkInterfaceInfoOSX *i;
+ for (i = m->p->InterfaceList; i; i = i->next)
+ {
+ if (!m->SPSSocket) // Not being Sleep Proxy Server; close any open BPF fds
+ {
+ if (i->BPF_fd >= 0 && CountProxyTargets(m, i, mDNSNULL, mDNSNULL) == 0) CloseBPF(i);
+ }
+ else // else, we're Sleep Proxy Server; open BPF fds
+ {
+ if (i->Exists && i->Registered == i && i->ifinfo.McastTxRx && !(i->ifa_flags & IFF_LOOPBACK) && i->BPF_fd == -1)
+ { LogSPS("%s requesting BPF", i->ifinfo.ifname); i->BPF_fd = -2; mDNSRequestBPF(); }
+ }
+ }
+
+#endif // APPLE_OSX_mDNSResponder
+
+ uDNS_SetupDNSConfig(m);
+ mDNS_ConfigChanged(m);
+
+ if (IsAppleNetwork(m) != mDNS_McastTracingEnabled)
+ {
+ mDNS_McastTracingEnabled = mDNS_McastTracingEnabled ? mDNSfalse : mDNStrue;
+ LogMsg("mDNSMacOSXNetworkChanged: Multicast Tracing %s", mDNS_McastTracingEnabled ? "Enabled" : "Disabled");
+ UpdateDebugState();
+ }
+
+}
+
+// Called with KQueueLock & mDNS lock
+mDNSlocal void SetNetworkChanged(mDNS *const m, mDNSs32 delay)
+{
+ if (!m->p->NetworkChanged || m->p->NetworkChanged - NonZeroTime(m->timenow + delay) < 0)
+ {
+ m->p->NetworkChanged = NonZeroTime(m->timenow + delay);
+ LogInfo("SetNetworkChanged: scheduling in %d msec", delay);
+ }
+}
+
+// Called with KQueueLock & mDNS lock
+mDNSlocal void SetKeyChainTimer(mDNS *const m, mDNSs32 delay)
+{
+ // If it's not set or it needs to happen sooner than when it's currently set
+ if (!m->p->KeyChainTimer || m->p->KeyChainTimer - NonZeroTime(m->timenow + delay) > 0)
+ {
+ m->p->KeyChainTimer = NonZeroTime(m->timenow + delay);
+ LogInfo("SetKeyChainTimer: %d", delay);
+ }
+}
+
+// Copy the fourth slash-delimited element from either:
+// State:/Network/Interface/<bsdname>/IPv4
+// or
+// Setup:/Network/Service/<servicename>/Interface
+mDNSlocal CFStringRef CopyNameFromKey(CFStringRef key)
+{
+ CFArrayRef a;
+ CFStringRef name = NULL;
+
+ a = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
+ if (a && CFArrayGetCount(a) == 5) name = CFRetain(CFArrayGetValueAtIndex(a, 3));
+ if (a != NULL) CFRelease(a);
+
+ return name;
+}
+
+// Whether a key from a network change notification corresponds to
+// an IP service that is explicitly configured for IPv4 Link Local
+mDNSlocal mDNSBool ChangedKeysHaveIPv4LL(CFArrayRef inkeys)
+{
+ SCDynamicStoreRef store = NULL;
+ CFDictionaryRef dict = NULL;
+ CFMutableArrayRef a;
+ const void **keys = NULL, **vals = NULL;
+ CFStringRef pattern = NULL;
+ int i, ic, j, jc;
+ mDNSBool found = mDNSfalse;
+
+ jc = CFArrayGetCount(inkeys);
+ if (!jc) goto done;
+
+ store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:ChangedKeysHaveIPv4LL"), NULL, NULL);
+ if (store == NULL) goto done;
+
+ a = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ if (a == NULL) goto done;
+
+ // Setup:/Network/Service/[^/]+/Interface
+ pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetInterface);
+ if (pattern == NULL) goto done;
+ CFArrayAppendValue(a, pattern);
+ CFRelease(pattern);
+
+ // Setup:/Network/Service/[^/]+/IPv4
+ pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetIPv4);
+ if (pattern == NULL) goto done;
+ CFArrayAppendValue(a, pattern);
+ CFRelease(pattern);
+
+ dict = SCDynamicStoreCopyMultiple(store, NULL, a);
+ CFRelease(a);
+
+ if (!dict)
+ {
+ LogMsg("ChangedKeysHaveIPv4LL: Empty dictionary");
+ goto done;
+ }
+
+ ic = CFDictionaryGetCount(dict);
+ vals = mDNSPlatformMemAllocate(sizeof (void *) * ic);
+ keys = mDNSPlatformMemAllocate(sizeof (void *) * ic);
+ CFDictionaryGetKeysAndValues(dict, keys, vals);
+
+ for (j = 0; j < jc && !found; j++)
+ {
+ CFStringRef key = CFArrayGetValueAtIndex(inkeys, j);
+ CFStringRef ifname = NULL;
+
+ char buf[256];
+
+ // It would be nice to use a regex here
+ if (!CFStringHasPrefix(key, CFSTR("State:/Network/Interface/")) || !CFStringHasSuffix(key, kSCEntNetIPv4)) continue;
+
+ if ((ifname = CopyNameFromKey(key)) == NULL) continue;
+ if (mDNS_LoggingEnabled)
+ {
+ if (!CFStringGetCString(ifname, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
+ LogInfo("ChangedKeysHaveIPv4LL: potential ifname %s", buf);
+ }
+
+ for (i = 0; i < ic; i++)
+ {
+ CFDictionaryRef ipv4dict;
+ CFStringRef name;
+ CFStringRef serviceid;
+ CFStringRef configmethod;
+
+ if (!CFStringHasSuffix(keys[i], kSCEntNetInterface)) continue;
+
+ if (CFDictionaryGetTypeID() != CFGetTypeID(vals[i])) continue;
+
+ if ((name = CFDictionaryGetValue(vals[i], kSCPropNetInterfaceDeviceName)) == NULL) continue;
+
+ if (!CFEqual(ifname, name)) continue;
+
+ if ((serviceid = CopyNameFromKey(keys[i])) == NULL) continue;
+ if (mDNS_LoggingEnabled)
+ {
+ if (!CFStringGetCString(serviceid, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
+ LogInfo("ChangedKeysHaveIPv4LL: found serviceid %s", buf);
+ }
+
+ pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceid, kSCEntNetIPv4);
+ CFRelease(serviceid);
+ if (pattern == NULL) continue;
+
+ ipv4dict = CFDictionaryGetValue(dict, pattern);
+ CFRelease(pattern);
+ if (!ipv4dict || CFDictionaryGetTypeID() != CFGetTypeID(ipv4dict)) continue;
+
+ configmethod = CFDictionaryGetValue(ipv4dict, kSCPropNetIPv4ConfigMethod);
+ if (!configmethod) continue;
+
+ if (mDNS_LoggingEnabled)
+ {
+ if (!CFStringGetCString(configmethod, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
+ LogInfo("ChangedKeysHaveIPv4LL: configmethod %s", buf);
+ }
+
+ if (CFEqual(configmethod, kSCValNetIPv4ConfigMethodLinkLocal)) { found = mDNStrue; break; }
+ }
+
+ CFRelease(ifname);
+ }
+
+done:
+ if (vals != NULL) mDNSPlatformMemFree(vals);
+ if (keys != NULL) mDNSPlatformMemFree(keys);
+ if (dict != NULL) CFRelease(dict);
+ if (store != NULL) CFRelease(store);
+
+ return found;
+}
+
+mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
+{
+ (void)store; // Parameter not used
+ mDNSBool changeNow = mDNSfalse;
+ mDNS *const m = (mDNS *const)context;
+ KQueueLock(m);
+ mDNS_Lock(m);
+
+ mDNSs32 delay = mDNSPlatformOneSecond * 2; // Start off assuming a two-second delay
+
+ int c = CFArrayGetCount(changedKeys); // Count changes
+ CFRange range = { 0, c };
+ int c1 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Hostnames ) != 0);
+ int c2 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0);
+ int c3 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS ) != 0);
+ int c4 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DNS ) != 0);
+ if (c && c - c1 - c2 - c3 - c4 == 0)
+ delay = mDNSPlatformOneSecond/10; // If these were the only changes, shorten delay
+
+ // Do immediate network changed processing for "p2p*" interfaces and
+ // for interfaces with the IFEF_DIRECTLINK flag set.
+ {
+ CFArrayRef labels;
+ CFIndex n;
+ for (int i = 0; i < c; i++)
+ {
+ CFStringRef key = CFArrayGetValueAtIndex(changedKeys, i);
+
+ // Only look at keys with prefix "State:/Network/Interface/"
+ if (!CFStringHasPrefix(key, NetworkChangedKey_StateInterfacePrefix))
+ continue;
+
+ // And suffix "IPv6" or "IPv4".
+ if (!CFStringHasSuffix(key, kSCEntNetIPv6) && !CFStringHasSuffix(key, kSCEntNetIPv4))
+ continue;
+
+ labels = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
+ if (labels == NULL)
+ break;
+ n = CFArrayGetCount(labels);
+
+ // Interface changes will have keys of the form:
+ // State:/Network/Interface/<interfaceName>/IPv6
+ // Thus five '/' seperated fields, the 4th one being the <interfaceName> string.
+ if (n == 5)
+ {
+ char buf[256];
+
+ // The 4th label (index = 3) should be the interface name.
+ if (CFStringGetCString(CFArrayGetValueAtIndex(labels, 3), buf, sizeof(buf), kCFStringEncodingUTF8)
+ && (strstr(buf, "p2p") || (getExtendedFlags(buf) & IFEF_DIRECTLINK)))
+ {
+ LogInfo("NetworkChanged: interface %s, not delaying network change", buf);
+ changeNow = mDNStrue;
+ CFRelease(labels);
+ break;
+ }
+ }
+ CFRelease(labels);
+ }
+ }
+
+ mDNSBool btmmChanged = CFArrayContainsValue(changedKeys, range, NetworkChangedKey_BackToMyMac);
+ if (btmmChanged) delay = 0;
+
+ if (mDNS_LoggingEnabled)
+ {
+ int i;
+ for (i=0; i<c; i++)
+ {
+ char buf[256];
+ if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys, i), buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
+ LogInfo("*** NetworkChanged SC key: %s", buf);
+ }
+ LogInfo("*** NetworkChanged *** %d change%s %s%s%s%sdelay %d",
+ c, c>1 ? "s" : "",
+ c1 ? "(Local Hostname) " : "",
+ c2 ? "(Computer Name) " : "",
+ c3 ? "(DynamicDNS) " : "",
+ c4 ? "(DNS) " : "",
+ changeNow ? 0 : delay);
+ }
+
+ if (!changeNow)
+ SetNetworkChanged(m, delay);
+
+ // Other software might pick up these changes to register or browse in WAB or BTMM domains,
+ // so in order for secure updates to be made to the server, make sure to read the keychain and
+ // setup the DomainAuthInfo before handing the network change.
+ // If we don't, then we will first try to register services in the clear, then later setup the
+ // DomainAuthInfo, which is incorrect.
+ if (c3 || btmmChanged)
+ SetKeyChainTimer(m, delay);
+
+ mDNS_Unlock(m);
+
+ // If DNS settings changed, immediately force a reconfig (esp. cache flush)
+ // Similarly, if an interface changed that is explicitly IPv4 link local, immediately force a reconfig
+ if (c4 || ChangedKeysHaveIPv4LL(changedKeys) || changeNow) mDNSMacOSXNetworkChanged(m);
+
+ KQueueUnlock(m, "NetworkChanged");
+}
+
+#if APPLE_OSX_mDNSResponder
+mDNSlocal void RefreshSPSStatus(const void *key, const void *value, void *context)
+{
+ (void)context;
+ char buf[IFNAMSIZ];
+
+ CFStringRef ifnameStr = (CFStringRef)key;
+ CFArrayRef array = (CFArrayRef)value;
+ if (!CFStringGetCString(ifnameStr, buf, sizeof(buf), kCFStringEncodingUTF8))
+ buf[0] = 0;
+
+ LogInfo("RefreshSPSStatus: Updating SPS state for key %s, array count %d", buf, CFArrayGetCount(array));
+ mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, buf, value);
+}
+#endif
+
+mDNSlocal void DynamicStoreReconnected(SCDynamicStoreRef store, void *info)
+{
+ mDNS *const m = (mDNS *const)info;
+ (void)store;
+
+ LogInfo("DynamicStoreReconnected: Reconnected");
+
+ // State:/Network/MulticastDNS
+ SetLocalDomains();
+
+ // State:/Network/DynamicDNS
+ if (m->FQDN.c[0])
+ mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1);
+
+ // Note: PrivateDNS and BackToMyMac are automatically populated when configd is restarted
+ // as we receive network change notifications and thus not necessary. But we leave it here
+ // so that if things are done differently in the future, this code still works.
+
+ // State:/Network/PrivateDNS
+ if (privateDnsArray)
+ mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
+
+#if APPLE_OSX_mDNSResponder
+ mDNS_Lock(m);
+ // State:/Network/BackToMyMac
+ UpdateAutoTunnelDomainStatuses(m);
+ mDNS_Unlock(m);
+
+ // State:/Network/Interface/en0/SleepProxyServers
+ if (spsStatusDict)
+ CFDictionaryApplyFunction(spsStatusDict, RefreshSPSStatus, NULL);
+#endif
+}
+
+mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
+{
+ mStatus err = -1;
+ SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL };
+ SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged, &context);
+ CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ CFStringRef pattern1 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
+ CFStringRef pattern2 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
+ CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+
+ if (!store) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error; }
+ if (!keys || !pattern1 || !pattern2 || !patterns) goto error;
+
+ CFArrayAppendValue(keys, NetworkChangedKey_IPv4);
+ CFArrayAppendValue(keys, NetworkChangedKey_IPv6);
+ CFArrayAppendValue(keys, NetworkChangedKey_Hostnames);
+ CFArrayAppendValue(keys, NetworkChangedKey_Computername);
+ CFArrayAppendValue(keys, NetworkChangedKey_DNS);
+ CFArrayAppendValue(keys, NetworkChangedKey_DynamicDNS);
+ CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac);
+ CFArrayAppendValue(keys, NetworkChangedKey_PowerSettings); // should remove as part of <rdar://problem/6751656>
+ CFArrayAppendValue(keys, NetworkChangedKey_BTMMConnectivity);
+ CFArrayAppendValue(patterns, pattern1);
+ CFArrayAppendValue(patterns, pattern2);
+ CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
+ if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns))
+ { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error; }
+
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+ if (!SCDynamicStoreSetDispatchQueue(store, dispatch_get_main_queue()))
+ { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
+#else
+ m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
+ if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
+#endif
+ SCDynamicStoreSetDisconnectCallBack(store, DynamicStoreReconnected);
+ m->p->Store = store;
+ err = 0;
+ goto exit;
+
+error:
+ if (store) CFRelease(store);
+
+exit:
+ if (patterns) CFRelease(patterns);
+ if (pattern2) CFRelease(pattern2);
+ if (pattern1) CFRelease(pattern1);
+ if (keys) CFRelease(keys);
+
+ return(err);
+}
+
+#if 0 // <rdar://problem/6751656>
+mDNSlocal void PMChanged(void *context)
+{
+ mDNS *const m = (mDNS *const)context;
+
+ KQueueLock(m);
+ mDNS_Lock(m);
+
+ LogSPS("PMChanged");
+
+ SetNetworkChanged(m, mDNSPlatformOneSecond * 2);
+
+ mDNS_Unlock(m);
+ KQueueUnlock(m, "PMChanged");
+}
+
+mDNSlocal mStatus WatchForPMChanges(mDNS *const m)
+{
+ m->p->PMRLS = IOPMPrefsNotificationCreateRunLoopSource(PMChanged, m);
+ if (!m->p->PMRLS) { LogMsg("IOPMPrefsNotificationCreateRunLoopSource failed!"); return mStatus_UnknownErr; }
+
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->PMRLS, kCFRunLoopDefaultMode);
+
+ return mStatus_NoError;
+}
+#endif
+
+#if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
+
+mDNSlocal void mDNSSetPacketFilterRules(mDNS *const m, char * ifname, const ResourceRecord *const excludeRecord)
+{
+ AuthRecord *rr;
+ pfArray_t portArray;
+ pfArray_t protocolArray;
+ uint32_t count = 0;
+
+ for (rr = m->ResourceRecords; rr; rr=rr->next)
+ {
+ if ((rr->resrec.rrtype == kDNSServiceType_SRV)
+ && ((rr->ARType == AuthRecordAnyIncludeP2P) || (rr->ARType == AuthRecordAnyIncludeAWDLandP2P)))
+ {
+ const mDNSu8 *p;
+
+ if (count >= PFPortArraySize)
+ {
+ LogMsg("mDNSSetPacketFilterRules: %d service limit, skipping %s", PFPortArraySize, ARDisplayString(m, rr));
+ continue;
+ }
+
+ if (excludeRecord && IdenticalResourceRecord(&rr->resrec, excludeRecord))
+ {
+ LogInfo("mDNSSetPacketFilterRules: record being removed, skipping %s", ARDisplayString(m, rr));
+ continue;
+ }
+
+ LogInfo("mDNSSetPacketFilterRules: found %s", ARDisplayString(m, rr));
+
+ portArray[count] = rr->resrec.rdata->u.srv.port.NotAnInteger;
+
+ // Assume <Service Instance>.<App Protocol>.<Transport Protocol>.<Name>
+ p = rr->resrec.name->c;
+
+ // Skip to App Protocol
+ if (p[0]) p += 1 + p[0];
+
+ // Skip to Transport Protocol
+ if (p[0]) p += 1 + p[0];
+
+ if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp")) protocolArray[count] = IPPROTO_TCP;
+ else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp")) protocolArray[count] = IPPROTO_UDP;
+ else
+ {
+ LogMsg("mDNSSetPacketFilterRules: could not determine transport protocol of service");
+ LogMsg("mDNSSetPacketFilterRules: %s", ARDisplayString(m, rr));
+ return;
+ }
+ count++;
+ }
+ }
+ mDNSPacketFilterControl(PF_SET_RULES, ifname, count, portArray, protocolArray);
+}
+
+// If the p2p interface already exists, update the Bonjour packet filter rules for it.
+mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
+{
+ mDNS *const m = &mDNSStorage;
+
+ NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
+ while (intf)
+ {
+ if (strncmp(intf->ifname, "p2p", 3) == 0)
+ {
+ LogInfo("mDNSInitPacketFilter: Setting rules for ifname %s", intf->ifname);
+ mDNSSetPacketFilterRules(m, intf->ifname, excludeRecord);
+ break;
+ }
+ intf = GetFirstActiveInterface(intf->next);
+ }
+}
+
+#else // !TARGET_OS_EMBEDDED
+
+// Currently no packet filter setup required on embedded platforms.
+mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
+{
+ (void) excludeRecord; // unused
+}
+
+#endif // !TARGET_OS_EMBEDDED
+
+// Handle AWDL KEV_DL_MASTER_ELECTED event by restarting queries and advertisements
+// marked to include the AWDL interface.
+mDNSlocal void newMasterElected(mDNS *const m, struct net_event_data * ptr)
+{
+ char ifname[IFNAMSIZ];
+ mDNSu32 interfaceIndex;
+ DNSQuestion *q;
+ AuthRecord *rr;
+ NetworkInterfaceInfoOSX *infoOSX;
+ mDNSInterfaceID InterfaceID;
+
+ snprintf(ifname, IFNAMSIZ, "%s%d", ptr->if_name, ptr->if_unit);
+ interfaceIndex = if_nametoindex(ifname);
+
+ if (!interfaceIndex)
+ {
+ LogMsg("newMasterElected: if_nametoindex(%s) failed", ifname);
+ return;
+ }
+
+ LogInfo("newMasterElected: ifname = %s, interfaceIndex = %d", ifname, interfaceIndex);
+ infoOSX = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)interfaceIndex);
+
+ // Can get an KEV_DL_MASTER_ELECTED event prior to the interface existing
+ // when it is first brought up.
+ if (!infoOSX)
+ {
+ LogInfo("newMasterElected: interface not yet active");
+ return;
+ }
+ InterfaceID = infoOSX->ifinfo.InterfaceID;
+
+ for (q = m->Questions; q; q=q->next)
+ {
+ if ((!q->InterfaceID && (q->flags & kDNSServiceFlagsIncludeAWDL))
+ || q->InterfaceID == InterfaceID)
+ {
+ LogInfo("newMasterElected: restarting %s query for %##s", DNSTypeName(q->qtype), q->qname.c);
+ mDNSCoreRestartQuestion(m, q);
+ }
+ }
+
+ for (rr = m->ResourceRecords; rr; rr=rr->next)
+ {
+ if ((!rr->resrec.InterfaceID
+ && ((rr->ARType == AuthRecordAnyIncludeAWDL) || ((rr->ARType == AuthRecordAnyIncludeAWDLandP2P))))
+ || rr->resrec.InterfaceID == InterfaceID)
+ {
+ LogInfo("newMasterElected: restarting %s announcements for %##s", DNSTypeName(rr->resrec.rrtype), rr->namestorage.c);
+ mDNSCoreRestartRegistration(m, rr, -1);
+ }
+ }
+}
+
+// An ssth array of all zeroes indicates the peer has no services registered.
+mDNSlocal mDNSBool allZeroSSTH(struct opaque_presence_indication *op)
+{
+ int i;
+ int *intp = (int *) op->ssth;
+
+ // MAX_SSTH_SIZE should always be a multiple of sizeof(int), if
+ // it's not, print an error message and return false so that
+ // corresponding peer records are not flushed when KEV_DL_NODE_PRESENCE event
+ // is received.
+ if (MAX_SSTH_SIZE % sizeof(int))
+ {
+ LogInfo("allZeroSSTH: MAX_SSTH_SIZE = %d not a multiple of sizeof(int)", MAX_SSTH_SIZE);
+ return mDNSfalse;
+ }
+
+ for (i = 0; i < (int)(MAX_SSTH_SIZE / sizeof(int)); i++, intp++)
+ {
+ if (*intp)
+ return mDNSfalse;
+ }
+ return mDNStrue;
+}
+
+// mDNS_Reconfirm_internal() adds 33% to this interval, so the records should
+// be removed in 4 seconds.
+#define kAWDLReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 3)
+
+// Mark records from this peer for deletion from the cache.
+mDNSlocal void removeCachedPeerRecords(mDNS *const m, mDNSu32 ifindex, mDNSAddr *ap)
+{
+ mDNSu32 slot;
+ CacheGroup *cg;
+ CacheRecord *cr;
+ mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(m, ifindex);
+
+ if (!InterfaceID)
+ {
+ LogInfo("removeCachedPeerRecords: Invalid ifindex: %d", ifindex);
+ return;
+ }
+
+ FORALL_CACHERECORDS(slot, cg, cr)
+ {
+ if ((InterfaceID == cr->resrec.InterfaceID) && mDNSSameAddress(ap, & cr->sourceAddress))
+ {
+ LogInfo("removeCachedPeerRecords: %s %##s marking for deletion",
+ DNSTypeName(cr->resrec.rrtype), cr->resrec.name->c);
+ mDNS_Reconfirm_internal(m, cr, kAWDLReconfirmTime);
+ }
+ }
+}
+
+// Handle KEV_DL_NODE_PRESENCE event.
+mDNSlocal void nodePresence(mDNS *const m, struct kev_dl_node_presence * p)
+{
+ char buf[INET6_ADDRSTRLEN];
+ struct opaque_presence_indication *op = (struct opaque_presence_indication *) p->node_service_info;
+
+ if (inet_ntop(AF_INET6, & p->sin6_node_address.sin6_addr, buf, sizeof(buf)))
+ LogInfo("nodePresence: IPv6 address: %s, SUI %d", buf, op->SUI);
+ else
+ LogInfo("nodePresence: inet_ntop() error");
+
+ // AWDL will generate a KEV_DL_NODE_PRESENCE event with SSTH field of
+ // all zeroes when a node is present and has no services registered.
+ if (allZeroSSTH(op))
+ {
+ mDNSAddr peerAddr;
+
+ peerAddr.type = mDNSAddrType_IPv6;
+ peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
+
+ LogInfo("nodePresence: ssth is all zeroes, delete cached records from this peer");
+ removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr);
+ }
+}
+
+// Handle KEV_DL_NODE_ABSENCE event.
+mDNSlocal void nodeAbsence(mDNS *const m, struct kev_dl_node_absence * p)
+{
+ mDNSAddr peerAddr;
+ char buf[INET6_ADDRSTRLEN];
+
+ if (inet_ntop(AF_INET6, & p->sin6_node_address.sin6_addr, buf, sizeof(buf)))
+ LogInfo("nodeAbsence: IPv6 address: %s", buf);
+ else
+ LogInfo("nodeAbsence: inet_ntop() error");
+
+ peerAddr.type = mDNSAddrType_IPv6;
+ peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
+
+ LogInfo("nodeAbsence: delete cached records from this peer");
+ removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr);
+}
+
+mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context)
+{
+ mDNS *const m = (mDNS *const)context;
+
+ mDNS_Lock(m);
+
+ struct { struct kern_event_msg k; char extra[256]; } msg;
+ int bytes = recv(s1, &msg, sizeof(msg), 0);
+ if (bytes < 0)
+ LogMsg("SysEventCallBack: recv error %d errno %d (%s)", bytes, errno, strerror(errno));
+ else
+ {
+ LogInfo("SysEventCallBack got %d bytes size %d %X %s %X %s %X %s id %d code %d %s",
+ bytes, msg.k.total_size,
+ msg.k.vendor_code, msg.k.vendor_code == KEV_VENDOR_APPLE ? "KEV_VENDOR_APPLE" : "?",
+ msg.k.kev_class, msg.k.kev_class == KEV_NETWORK_CLASS ? "KEV_NETWORK_CLASS" : "?",
+ msg.k.kev_subclass, msg.k.kev_subclass == KEV_DL_SUBCLASS ? "KEV_DL_SUBCLASS" : "?",
+ msg.k.id, msg.k.event_code,
+ msg.k.event_code == KEV_DL_SIFFLAGS ? "KEV_DL_SIFFLAGS" :
+ msg.k.event_code == KEV_DL_SIFMETRICS ? "KEV_DL_SIFMETRICS" :
+ msg.k.event_code == KEV_DL_SIFMTU ? "KEV_DL_SIFMTU" :
+ msg.k.event_code == KEV_DL_SIFPHYS ? "KEV_DL_SIFPHYS" :
+ msg.k.event_code == KEV_DL_SIFMEDIA ? "KEV_DL_SIFMEDIA" :
+ msg.k.event_code == KEV_DL_SIFGENERIC ? "KEV_DL_SIFGENERIC" :
+ msg.k.event_code == KEV_DL_ADDMULTI ? "KEV_DL_ADDMULTI" :
+ msg.k.event_code == KEV_DL_DELMULTI ? "KEV_DL_DELMULTI" :
+ msg.k.event_code == KEV_DL_IF_ATTACHED ? "KEV_DL_IF_ATTACHED" :
+ msg.k.event_code == KEV_DL_IF_DETACHING ? "KEV_DL_IF_DETACHING" :
+ msg.k.event_code == KEV_DL_IF_DETACHED ? "KEV_DL_IF_DETACHED" :
+ msg.k.event_code == KEV_DL_LINK_OFF ? "KEV_DL_LINK_OFF" :
+ msg.k.event_code == KEV_DL_LINK_ON ? "KEV_DL_LINK_ON" :
+ msg.k.event_code == KEV_DL_PROTO_ATTACHED ? "KEV_DL_PROTO_ATTACHED" :
+ msg.k.event_code == KEV_DL_PROTO_DETACHED ? "KEV_DL_PROTO_DETACHED" :
+ msg.k.event_code == KEV_DL_LINK_ADDRESS_CHANGED ? "KEV_DL_LINK_ADDRESS_CHANGED" :
+ msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED ? "KEV_DL_WAKEFLAGS_CHANGED" :
+ msg.k.event_code == KEV_DL_IF_IDLE_ROUTE_REFCNT ? "KEV_DL_IF_IDLE_ROUTE_REFCNT" :
+ msg.k.event_code == KEV_DL_IFCAP_CHANGED ? "KEV_DL_IFCAP_CHANGED" :
+ msg.k.event_code == KEV_DL_LINK_QUALITY_METRIC_CHANGED ? "KEV_DL_LINK_QUALITY_METRIC_CHANGED" :
+ msg.k.event_code == KEV_DL_NODE_PRESENCE ? "KEV_DL_NODE_PRESENCE" :
+ msg.k.event_code == KEV_DL_NODE_ABSENCE ? "KEV_DL_NODE_ABSENCE" :
+ msg.k.event_code == KEV_DL_MASTER_ELECTED ? "KEV_DL_MASTER_ELECTED" :
+ "?");
+
+ if (msg.k.event_code == KEV_DL_NODE_PRESENCE)
+ nodePresence(m, (struct kev_dl_node_presence *) &msg.k.event_data);
+
+ if (msg.k.event_code == KEV_DL_NODE_ABSENCE)
+ nodeAbsence(m, (struct kev_dl_node_absence *) &msg.k.event_data);
+
+ if (msg.k.event_code == KEV_DL_MASTER_ELECTED)
+ newMasterElected(m, (struct net_event_data *) &msg.k.event_data);
+
+ // We receive network change notifications both through configd and through SYSPROTO_EVENT socket.
+ // Configd may not generate network change events for manually configured interfaces (i.e., non-DHCP)
+ // always during sleep/wakeup due to some race conditions (See radar:8666757). At the same time, if
+ // "Wake on Network Access" is not turned on, the notification will not have KEV_DL_WAKEFLAGS_CHANGED.
+ // Hence, during wake up, if we see a KEV_DL_LINK_ON (i.e., link is UP), we trigger a network change.
+
+ if (msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED || msg.k.event_code == KEV_DL_LINK_ON)
+ SetNetworkChanged(m, mDNSPlatformOneSecond * 2);
+
+#if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
+
+ // For p2p interfaces, need to open the advertised service port in the firewall.
+ if (msg.k.event_code == KEV_DL_IF_ATTACHED)
+ {
+ struct net_event_data * p;
+ p = (struct net_event_data *) &msg.k.event_data;
+
+ if (strncmp(p->if_name, "p2p", 3) == 0)
+ {
+ char ifname[IFNAMSIZ];
+ snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit);
+
+ LogInfo("SysEventCallBack: KEV_DL_IF_ATTACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name);
+
+ mDNSSetPacketFilterRules(m, ifname, NULL);
+ }
+ }
+
+ // For p2p interfaces, need to clear the firewall rules on interface detach
+ if (msg.k.event_code == KEV_DL_IF_DETACHED)
+ {
+ struct net_event_data * p;
+ p = (struct net_event_data *) &msg.k.event_data;
+
+ if (strncmp(p->if_name, "p2p", 3) == 0)
+ {
+ pfArray_t portArray, protocolArray; // not initialized since count is 0 for PF_CLEAR_RULES
+ char ifname[IFNAMSIZ];
+ snprintf(ifname, IFNAMSIZ, "%s%d", p->if_name, p->if_unit);
+
+ LogInfo("SysEventCallBack: KEV_DL_IF_DETACHED if_family = %d, if_unit = %d, if_name = %s", p->if_family, p->if_unit, p->if_name);
+
+ mDNSPacketFilterControl(PF_CLEAR_RULES, ifname, 0, portArray, protocolArray);
+ }
+ }
+#endif // !TARGET_OS_EMBEDDED
+
+ }
+
+ mDNS_Unlock(m);
+}
+
+mDNSlocal mStatus WatchForSysEvents(mDNS *const m)
+{
+ m->p->SysEventNotifier = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
+ if (m->p->SysEventNotifier < 0)
+ { LogMsg("WatchForSysEvents: socket failed error %d errno %d (%s)", m->p->SysEventNotifier, errno, strerror(errno)); return(mStatus_NoMemoryErr); }
+
+ struct kev_request kev_req = { KEV_VENDOR_APPLE, KEV_NETWORK_CLASS, KEV_DL_SUBCLASS };
+ int err = ioctl(m->p->SysEventNotifier, SIOCSKEVFILT, &kev_req);
+ if (err < 0)
+ {
+ LogMsg("WatchForSysEvents: SIOCSKEVFILT failed error %d errno %d (%s)", err, errno, strerror(errno));
+ close(m->p->SysEventNotifier);
+ m->p->SysEventNotifier = -1;
+ return(mStatus_UnknownErr);
+ }
+
+ m->p->SysEventKQueue.KQcallback = SysEventCallBack;
+ m->p->SysEventKQueue.KQcontext = m;
+ m->p->SysEventKQueue.KQtask = "System Event Notifier";
+ KQueueSet(m->p->SysEventNotifier, EV_ADD, EVFILT_READ, &m->p->SysEventKQueue);
+
+ return(mStatus_NoError);
+}
+
+#ifndef NO_SECURITYFRAMEWORK
+mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void *context)
+{
+ LogInfo("*** Keychain Changed ***");
+ mDNS *const m = (mDNS *const)context;
+ SecKeychainRef skc;
+ OSStatus err = SecKeychainCopyDefault(&skc);
+ if (!err)
+ {
+ if (info->keychain == skc)
+ {
+ // For delete events, attempt to verify what item was deleted fail because the item is already gone, so we just assume they may be relevant
+ mDNSBool relevant = (keychainEvent == kSecDeleteEvent);
+ if (!relevant)
+ {
+ UInt32 tags[3] = { kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr };
+ SecKeychainAttributeInfo attrInfo = { 3, tags, NULL }; // Count, array of tags, array of formats
+ SecKeychainAttributeList *a = NULL;
+ err = SecKeychainItemCopyAttributesAndData(info->item, &attrInfo, NULL, &a, NULL, NULL);
+ if (!err)
+ {
+ relevant = ((a->attr[0].length == 4 && (!strncasecmp(a->attr[0].data, "ddns", 4) || !strncasecmp(a->attr[0].data, "sndd", 4))) ||
+ (a->attr[1].length >= mDNSPlatformStrLen(dnsprefix) && (!strncasecmp(a->attr[1].data, dnsprefix, mDNSPlatformStrLen(dnsprefix)))) ||
+ (a->attr[1].length >= mDNSPlatformStrLen(btmmprefix) && (!strncasecmp(a->attr[1].data, btmmprefix, mDNSPlatformStrLen(btmmprefix)))));
+ SecKeychainItemFreeAttributesAndData(a, NULL);
+ }
+ }
+ if (relevant)
+ {
+ LogInfo("*** Keychain Changed *** KeychainEvent=%d %s",
+ keychainEvent,
+ keychainEvent == kSecAddEvent ? "kSecAddEvent" :
+ keychainEvent == kSecDeleteEvent ? "kSecDeleteEvent" :
+ keychainEvent == kSecUpdateEvent ? "kSecUpdateEvent" : "<Unknown>");
+ // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
+ KQueueLock(m);
+ mDNS_Lock(m);
+
+ // To not read the keychain twice: when BTMM is enabled, changes happen to the keychain
+ // then the BTMM DynStore dictionary, so delay reading the keychain for a second.
+ // NetworkChanged() will reset the keychain timer to fire immediately when the DynStore changes.
+ //
+ // In the "fixup" case where the BTMM DNS servers aren't accepting the key mDNSResponder has,
+ // the DynStore dictionary won't change (because the BTMM zone won't change). In that case,
+ // a one second delay is ok, as we'll still converge to correctness, and there's no race
+ // condition between the RegistrationDomain and the DomainAuthInfo.
+ //
+ // Lastly, non-BTMM WAB cases can use the keychain but not the DynStore, so we need to set
+ // the timer here, as it will not get set by NetworkChanged().
+ SetKeyChainTimer(m, mDNSPlatformOneSecond);
+
+ mDNS_Unlock(m);
+ KQueueUnlock(m, "KeychainChanged");
+ }
+ }
+ CFRelease(skc);
+ }
+
+ return 0;
+}
+#endif
+
+mDNSlocal void PowerOn(mDNS *const m)
+{
+ mDNSCoreMachineSleep(m, false); // Will set m->SleepState = SleepState_Awake;
+ if (m->p->WakeAtUTC)
+ {
+ long utc = mDNSPlatformUTC();
+ mDNSPowerRequest(-1,-1); // Need to explicitly clear any previous power requests -- they're not cleared automatically on wake
+ if (m->p->WakeAtUTC - utc > 30)
+ {
+ LogSPS("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m->p->WakeAtUTC - utc);
+ }
+ else if (utc - m->p->WakeAtUTC > 30)
+ {
+ LogSPS("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc - m->p->WakeAtUTC);
+ }
+ else if (IsAppleTV())
+ {
+ LogSPS("PowerChanged PowerOn %d seconds late, device is an AppleTV running iOS so not re-sleeping", utc - m->p->WakeAtUTC);
+ }
+ else
+ {
+ LogSPS("PowerChanged: Waking for network maintenance operations %d seconds early; re-sleeping in 20 seconds", m->p->WakeAtUTC - utc);
+ m->p->RequestReSleep = mDNS_TimeNow(m) + 20 * mDNSPlatformOneSecond;
+ }
+ }
+}
+
+mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
+{
+ mDNS *const m = (mDNS *const)refcon;
+ KQueueLock(m);
+ (void)service; // Parameter not used
+ debugf("PowerChanged %X %lX", messageType, messageArgument);
+
+ // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
+ m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
+
+ switch(messageType)
+ {
+ case kIOMessageCanSystemPowerOff: LogSPS("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240
+ case kIOMessageSystemWillPowerOff: LogSPS("PowerChanged kIOMessageSystemWillPowerOff"); // E0000250
+ mDNSCoreMachineSleep(m, true);
+ if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
+ break;
+ case kIOMessageSystemWillNotPowerOff: LogSPS("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
+ case kIOMessageCanSystemSleep: LogSPS("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270
+ case kIOMessageSystemWillSleep: LogSPS("PowerChanged kIOMessageSystemWillSleep"); // E0000280
+ mDNSCoreMachineSleep(m, true);
+ break;
+ case kIOMessageSystemWillNotSleep: LogSPS("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290
+ case kIOMessageSystemHasPoweredOn: LogSPS("PowerChanged kIOMessageSystemHasPoweredOn"); // E0000300
+ // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
+ if (m->SleepState)
+ {
+ LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m->SleepState);
+ PowerOn(m);
+ }
+ // Just to be safe, schedule a mDNSMacOSXNetworkChanged(), in case we never received
+ // the System Configuration Framework "network changed" event that we expect
+ // to receive some time shortly after the kIOMessageSystemWillPowerOn message
+ mDNS_Lock(m);
+ if (!m->p->NetworkChanged ||
+ m->p->NetworkChanged - NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2) < 0)
+ m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
+ mDNS_Unlock(m);
+
+ break;
+ case kIOMessageSystemWillRestart: LogSPS("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310
+ case kIOMessageSystemWillPowerOn: LogSPS("PowerChanged kIOMessageSystemWillPowerOn"); // E0000320
+
+ // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
+ if (m->SleepState != SleepState_Sleeping)
+ {
+ LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m->SleepState);
+ m->SleepState = SleepState_Sleeping;
+ mDNSMacOSXNetworkChanged(m);
+ }
+ PowerOn(m);
+ break;
+ default: LogSPS("PowerChanged unknown message %X", messageType); break;
+ }
+
+ if (messageType == kIOMessageSystemWillSleep) m->p->SleepCookie = (long)messageArgument;
+ else IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
+
+ KQueueUnlock(m, "PowerChanged Sleep/Wake");
+}
+
+// iPhone OS doesn't currently have SnowLeopard's IO Power Management
+// but it does define kIOPMAcknowledgmentOptionSystemCapabilityRequirements
+#if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && !TARGET_OS_EMBEDDED
+mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection, IOPMConnectionMessageToken token, IOPMSystemPowerStateCapabilities eventDescriptor)
+{
+ mDNS *const m = (mDNS *const)refcon;
+ KQueueLock(m);
+ LogSPS("SnowLeopardPowerChanged %X %X %X%s%s%s%s%s",
+ connection, token, eventDescriptor,
+ eventDescriptor & kIOPMSystemPowerStateCapabilityCPU ? " CPU" : "",
+ eventDescriptor & kIOPMSystemPowerStateCapabilityVideo ? " Video" : "",
+ eventDescriptor & kIOPMSystemPowerStateCapabilityAudio ? " Audio" : "",
+ eventDescriptor & kIOPMSystemPowerStateCapabilityNetwork ? " Network" : "",
+ eventDescriptor & kIOPMSystemPowerStateCapabilityDisk ? " Disk" : "");
+
+ // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting
+ m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
+
+ if (eventDescriptor & kIOPMSystemPowerStateCapabilityCPU)
+ {
+ // We might be in Sleeping or Transferring state. When we go from "wakeup" to "sleep" state, we don't
+ // go directly to sleep state, but transfer in to the sleep state during which SleepState is set to
+ // SleepState_Transferring. During that time, we might get another wakeup before we transition to Sleeping
+ // state. In that case, we need to acknowledge the previous "sleep" before we acknowledge the wakeup.
+ if (m->SleepLimit)
+ {
+ LogSPS("SnowLeopardPowerChanged: Waking up, Acking old Sleep, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
+ IOPMConnectionAcknowledgeEvent(connection, m->p->SleepCookie);
+ m->SleepLimit = 0;
+ }
+ LogSPS("SnowLeopardPowerChanged: Waking up, Acking Wakeup, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
+ // If the network notifications have already come before we got the wakeup, we ignored them and
+ // in case we get no more, we need to trigger one.
+ mDNS_Lock(m);
+ SetNetworkChanged(m, 2 * mDNSPlatformOneSecond);
+ mDNS_Unlock(m);
+ // CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down.
+ if (m->SleepState != SleepState_Awake) PowerOn(m);
+ IOPMConnectionAcknowledgeEvent(connection, token);
+ }
+ else
+ {
+ // CPU sleeping. Should not get this repeatedly -- once we're told that the CPU is halting
+ // we should hear nothing more until we're told that the CPU has started executing again.
+ if (m->SleepState) LogMsg("SnowLeopardPowerChanged: Sleep Error %X m->SleepState %d", eventDescriptor, m->SleepState);
+ //sleep(5);
+ //mDNSMacOSXNetworkChanged(m);
+ mDNSCoreMachineSleep(m, true);
+ //if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m);
+ m->p->SleepCookie = token;
+ }
+
+ KQueueUnlock(m, "SnowLeopardPowerChanged Sleep/Wake");
+}
+#endif
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - /etc/hosts support
+#endif
+
+// Implementation Notes
+//
+// As /etc/hosts file can be huge (1000s of entries - when this comment was written, the test file had about
+// 23000 entries with about 4000 duplicates), we can't use a linked list to store these entries. So, we parse
+// them into a hash table. The implementation need to be able to do the following things efficiently
+//
+// 1. Detect duplicates e.g., two entries with "1.2.3.4 foo"
+// 2. Detect whether /etc/hosts has changed and what has changed since the last read from the disk
+// 3. Ability to support multiple addresses per name e.g., "1.2.3.4 foo, 2.3.4.5 foo". To support this, we
+// need to be able set the RRSet of a resource record to the first one in the list and also update when
+// one of them go away. This is needed so that the core thinks that they are all part of the same RRSet and
+// not a duplicate
+// 4. Don't maintain any local state about any records registered with the core to detect changes to /etc/hosts
+//
+// CFDictionary is not a suitable candidate because it does not support duplicates and even if we use a custom
+// "hash" function to solve this, the others are hard to solve. Hence, we share the hash (AuthHash) implementation
+// of the core layer which does all of the above very efficiently
+
+#define ETCHOSTS_BUFSIZE 1024 // Buffer size to parse a single line in /etc/hosts
+
+mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
+{
+ (void)m; // unused
+ (void)rr;
+ (void)result;
+ if (result == mStatus_MemFree)
+ {
+ LogInfo("FreeEtcHosts: %s", ARDisplayString(m, rr));
+ freeL("etchosts", rr);
+ }
+}
+
+// Returns true on success and false on failure
+mDNSlocal mDNSBool mDNSMacOSXCreateEtcHostsEntry(mDNS *const m, const domainname *domain, const struct sockaddr *sa, const domainname *cname, char *ifname, AuthHash *auth)
+{
+ AuthRecord *rr;
+ mDNSu32 slot;
+ mDNSu32 namehash;
+ AuthGroup *ag;
+ mDNSInterfaceID InterfaceID = mDNSInterface_LocalOnly;
+ mDNSu16 rrtype;
+
+ if (!domain)
+ {
+ LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! name NULL");
+ return mDNSfalse;
+ }
+ if (!sa && !cname)
+ {
+ LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa and cname both NULL");
+ return mDNSfalse;
+ }
+
+ if (sa && sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
+ {
+ LogMsg("mDNSMacOSXCreateEtcHostsEntry: ERROR!! sa with bad family %d", sa->sa_family);
+ return mDNSfalse;
+ }
+
+
+ if (ifname)
+ {
+ mDNSu32 ifindex = if_nametoindex(ifname);
+ if (!ifindex)
+ {
+ LogMsg("mDNSMacOSXCreateEtcHostsEntry: hosts entry %##s with invalid ifname %s", domain->c, ifname);
+ return mDNSfalse;
+ }
+ InterfaceID = (mDNSInterfaceID)(uintptr_t)ifindex;
+ }
+
+ if (sa)
+ rrtype = (sa->sa_family == AF_INET ? kDNSType_A : kDNSType_AAAA);
+ else
+ rrtype = kDNSType_CNAME;
+
+ // Check for duplicates. See whether we parsed an entry before like this ?
+ slot = AuthHashSlot(domain);
+ namehash = DomainNameHashValue(domain);
+ ag = AuthGroupForName(auth, slot, namehash, domain);
+ if (ag)
+ {
+ rr = ag->members;
+ while (rr)
+ {
+ if (rr->resrec.rrtype == rrtype)
+ {
+ if (rrtype == kDNSType_A)
+ {
+ mDNSv4Addr ip;
+ ip.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
+ if (mDNSSameIPv4Address(rr->resrec.rdata->u.ipv4, ip))
+ {
+ LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv4 address for name %##s", domain->c);
+ return mDNSfalse;
+ }
+ }
+ else if (rrtype == kDNSType_AAAA)
+ {
+ mDNSv6Addr ip6;
+ ip6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0];
+ ip6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
+ ip6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
+ ip6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
+ if (mDNSSameIPv6Address(rr->resrec.rdata->u.ipv6, ip6))
+ {
+ LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv6 address for name %##s", domain->c);
+ return mDNSfalse;
+ }
+ }
+ else if (rrtype == kDNSType_CNAME)
+ {
+ if (SameDomainName(&rr->resrec.rdata->u.name, cname))
+ {
+ LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same cname %##s for name %##s", cname->c, domain->c);
+ return mDNSfalse;
+ }
+ }
+ }
+ rr = rr->next;
+ }
+ }
+ rr= mallocL("etchosts", sizeof(*rr));
+ if (rr == NULL) return mDNSfalse;
+ mDNSPlatformMemZero(rr, sizeof(*rr));
+ mDNS_SetupResourceRecord(rr, NULL, InterfaceID, rrtype, 1, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, FreeEtcHosts, NULL);
+ AssignDomainName(&rr->namestorage, domain);
+
+ if (sa)
+ {
+ rr->resrec.rdlength = sa->sa_family == AF_INET ? sizeof(mDNSv4Addr) : sizeof(mDNSv6Addr);
+ if (sa->sa_family == AF_INET)
+ rr->resrec.rdata->u.ipv4.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
+ else
+ {
+ rr->resrec.rdata->u.ipv6.l[0] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[0];
+ rr->resrec.rdata->u.ipv6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
+ rr->resrec.rdata->u.ipv6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
+ rr->resrec.rdata->u.ipv6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
+ }
+ }
+ else
+ {
+ rr->resrec.rdlength = DomainNameLength(cname);
+ rr->resrec.rdata->u.name.c[0] = 0;
+ AssignDomainName(&rr->resrec.rdata->u.name, cname);
+ }
+ rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
+ SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
+ LogInfo("mDNSMacOSXCreateEtcHostsEntry: Adding resource record %s", ARDisplayString(m, rr));
+ InsertAuthRecord(m, auth, rr);
+ return mDNStrue;
+}
+
+mDNSlocal int EtcHostsParseOneName(int start, int length, char *buffer, char **name)
+{
+ int i;
+
+ *name = NULL;
+ for (i = start; i < length; i++)
+ {
+ if (buffer[i] == '#')
+ return -1;
+ if (buffer[i] != ' ' && buffer[i] != ',' && buffer[i] != '\t')
+ {
+ *name = &buffer[i];
+
+ // Found the start of a name, find the end and null terminate
+ for (i++; i < length; i++)
+ {
+ if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
+ {
+ buffer[i] = 0;
+ break;
+ }
+ }
+ return i;
+ }
+ }
+ return -1;
+}
+
+mDNSlocal void mDNSMacOSXParseEtcHostsLine(mDNS *const m, char *buffer, ssize_t length, AuthHash *auth)
+{
+ int i;
+ int ifStart = 0;
+ char *ifname = NULL;
+ domainname name1d;
+ domainname name2d;
+ char *name1;
+ char *name2;
+ int aliasIndex;
+
+ //Ignore leading whitespaces and tabs
+ while (*buffer == ' ' || *buffer == '\t')
+ {
+ buffer++;
+ length--;
+ }
+
+ // Find the end of the address string
+ for (i = 0; i < length; i++)
+ {
+ if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t' || buffer[i] == '%')
+ {
+ if (buffer[i] == '%')
+ ifStart = i + 1;
+ buffer[i] = 0;
+ break;
+ }
+ }
+
+ // Convert the address string to an address
+ struct addrinfo hints;
+ bzero(&hints, sizeof(hints));
+ hints.ai_flags = AI_NUMERICHOST;
+ struct addrinfo *gairesults = NULL;
+ if (getaddrinfo(buffer, NULL, &hints, &gairesults) != 0)
+ {
+ LogInfo("mDNSMacOSXParseEtcHostsLine: getaddrinfo returning null");
+ return;
+ }
+
+ if (ifStart)
+ {
+ // Parse the interface
+ ifname = &buffer[ifStart];
+ for (i = ifStart + 1; i < length; i++)
+ {
+ if (buffer[i] == ' ' || buffer[i] == ',' || buffer[i] == '\t')
+ {
+ buffer[i] = 0;
+ break;
+ }
+ }
+ }
+
+ i = EtcHostsParseOneName(i + 1, length, buffer, &name1);
+ if (i == length)
+ {
+ // Common case (no aliases) : The entry is of the form "1.2.3.4 somehost" with no trailing white spaces/tabs etc.
+ if (!MakeDomainNameFromDNSNameString(&name1d, name1))
+ {
+ LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
+ freeaddrinfo(gairesults);
+ return;
+ }
+ mDNSMacOSXCreateEtcHostsEntry(m, &name1d, gairesults->ai_addr, mDNSNULL, ifname, auth);
+ }
+ else if (i != -1)
+ {
+ domainname first;
+ // We might have some extra white spaces at the end for the common case of "1.2.3.4 somehost".
+ // When we parse again below, EtchHostsParseOneName would return -1 and we will end up
+ // doing the right thing.
+ if (!MakeDomainNameFromDNSNameString(&first, name1))
+ {
+ LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name1);
+ freeaddrinfo(gairesults);
+ return;
+ }
+ // If the /etc/hosts has an entry like this
+ //
+ // 1.2.3.4 sun star bright
+ //
+ // star and bright are aliases (gethostbyname h_alias should point to these) and sun is the canonical
+ // name (getaddrinfo ai_cannonname and gethostbyname h_name points to "sun")
+ //
+ // To achieve this, we need to add the entry like this:
+ //
+ // star CNAME bright
+ // bright CNAME sun
+ // sun A 1.2.3.4
+ //
+ // We store the first name we parsed in "first". Then we parse additional names adding CNAME records
+ // till we reach the end. When we reach the end, we wrap around and add one final CNAME with the last
+ // entry and the first entry. Finally, we add the Address (A/AAAA) record.
+ aliasIndex = 0;
+ while (i <= length)
+ {
+ // Parse a name. If there are no names, we need to know whether we
+ // parsed CNAMEs before or not. If we parsed CNAMEs before, then we
+ // add a CNAME with the last name and the first name. Otherwise, this
+ // is same as the common case above where the line has just one name
+ // but with trailing white spaces.
+ i = EtcHostsParseOneName(i + 1, length, buffer, &name2);
+ if (name2)
+ {
+ if (!MakeDomainNameFromDNSNameString(&name2d, name2))
+ {
+ LogMsg("mDNSMacOSXParseEtcHostsLine: ERROR!! cannot convert to domain name %s", name2);
+ freeaddrinfo(gairesults);
+ return;
+ }
+ aliasIndex++;
+ }
+ else if (!aliasIndex)
+ {
+ // We have never parsed any aliases. This case happens if there
+ // is just one name and some extra white spaces at the end.
+ LogInfo("mDNSMacOSXParseEtcHostsLine: White space at the end of %##s", first.c);
+ break;
+ }
+ else
+ {
+ // We have parsed at least one alias before and we reached the end of the line.
+ // Setup a CNAME for the last name with "first" name as its RDATA
+ name2d.c[0] = 0;
+ AssignDomainName(&name2d, &first);
+ }
+
+ // Don't add a CNAME for the first alias we parse (see the example above).
+ // As we parse more, we might discover that there are no more aliases, in
+ // which case we would have set "name2d" to "first" above. We need to add
+ // the CNAME in that case.
+
+ if (aliasIndex > 1 || SameDomainName(&name2d, &first))
+ {
+ // Ignore if it points to itself
+ if (!SameDomainName(&name1d, &name2d))
+ {
+ if (!mDNSMacOSXCreateEtcHostsEntry(m, &name1d, mDNSNULL, &name2d, ifname, auth))
+ {
+ freeaddrinfo(gairesults);
+ return;
+ }
+ }
+ else
+ LogMsg("mDNSMacOSXParseEtcHostsLine: Ignoring entry with same names name1 %##s, name2 %##s", name1d.c, name2d.c);
+ }
+
+ // If we have already wrapped around, we just need to add the A/AAAA record alone
+ // which is done below
+ if (SameDomainName(&name2d, &first)) break;
+
+ // Remember the current name so that we can set the CNAME record if we parse one
+ // more name
+ name1d.c[0] = 0;
+ AssignDomainName(&name1d, &name2d);
+ }
+ // Added all the CNAMEs if any, add the "A/AAAA" record
+ mDNSMacOSXCreateEtcHostsEntry(m, &first, gairesults->ai_addr, mDNSNULL, ifname, auth);
+ }
+ freeaddrinfo(gairesults);
+}
+
+mDNSlocal void mDNSMacOSXParseEtcHosts(mDNS *const m, int fd, AuthHash *auth)
+{
+ mDNSBool good;
+ char buf[ETCHOSTS_BUFSIZE];
+ ssize_t len;
+ FILE *fp;
+
+ if (fd == -1) { LogInfo("mDNSMacOSXParseEtcHosts: fd is -1"); return; }
+
+ fp = fopen("/etc/hosts", "r");
+ if (!fp) { LogInfo("mDNSMacOSXParseEtcHosts: fp is NULL"); return; }
+
+ while (1)
+ {
+ good = (fgets(buf, ETCHOSTS_BUFSIZE, fp) != NULL);
+ if (!good) break;
+
+ // skip comment and empty lines
+ if (buf[0] == '#' || buf[0] == '\r' || buf[0] == '\n')
+ continue;
+
+ len = strlen(buf);
+ if (!len) break; // sanity check
+ //Check for end of line code(mostly only \n but pre-OS X Macs could have only \r)
+ if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
+ {
+ buf[len - 1] = '\0';
+ len = len - 1;
+ }
+ // fgets always null terminates and hence even if we have no
+ // newline at the end, it is null terminated. The callee
+ // (mDNSMacOSXParseEtcHostsLine) expects the length to be such that
+ // buf[length] is zero and hence we decrement len to reflect that.
+ if (len)
+ {
+ //Additional check when end of line code is 2 chars ie\r\n(DOS, other old OSes)
+ //here we need to check for just \r but taking extra caution.
+ if (buf[len - 1] == '\r' || buf[len - 1] == '\n')
+ {
+ buf[len - 1] = '\0';
+ len = len - 1;
+ }
+ }
+ if (!len) //Sanity Check: len should never be zero
+ {
+ LogMsg("mDNSMacOSXParseEtcHosts: Length is zero!");
+ continue;
+ }
+ mDNSMacOSXParseEtcHostsLine(m, buf, len, auth);
+ }
+ fclose(fp);
+}
+
+mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m);
+
+mDNSlocal int mDNSMacOSXGetEtcHostsFD(mDNS *const m)
+{
+#ifdef __DISPATCH_GROUP__
+ // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
+ static dispatch_queue_t etcq = 0;
+ static dispatch_source_t etcsrc = 0;
+ static dispatch_source_t hostssrc = 0;
+
+ // First time through? just schedule ourselves on the main queue and we'll do the work later
+ if (!etcq)
+ {
+ etcq = dispatch_get_main_queue();
+ if (etcq)
+ {
+ // Do this work on the queue, not here - solves potential synchronization issues
+ dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
+ }
+ return -1;
+ }
+
+ if (hostssrc) return dispatch_source_get_handle(hostssrc);
+#endif
+
+ int fd = open("/etc/hosts", O_RDONLY);
+
+#ifdef __DISPATCH_GROUP__
+ // Can't do this stuff to be notified of changes in /etc/hosts if we don't have libdispatch
+ if (fd == -1)
+ {
+ // If the open failed and we're already watching /etc, we're done
+ if (etcsrc) { LogInfo("mDNSMacOSXGetEtcHostsFD: Returning etcfd because no etchosts"); return fd; }
+
+ // we aren't watching /etc, we should be
+ fd = open("/etc", O_RDONLY);
+ if (fd == -1) { LogInfo("mDNSMacOSXGetEtcHostsFD: etc does not exist"); return -1; }
+ etcsrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd, DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME, etcq);
+ if (etcsrc == NULL)
+ {
+ close(fd);
+ return -1;
+ }
+ dispatch_source_set_event_handler(etcsrc,
+ ^{
+ u_int32_t flags = dispatch_source_get_data(etcsrc);
+ LogMsg("mDNSMacOSXGetEtcHostsFD: /etc changed 0x%x", flags);
+ if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0)
+ {
+ dispatch_source_cancel(etcsrc);
+ dispatch_release(etcsrc);
+ etcsrc = NULL;
+ dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
+ return;
+ }
+ if ((flags & DISPATCH_VNODE_WRITE) != 0 && hostssrc == NULL)
+ {
+ mDNSMacOSXUpdateEtcHosts(m);
+ }
+ });
+ dispatch_source_set_cancel_handler(etcsrc, ^{close(fd);});
+ dispatch_resume(etcsrc);
+
+ // Try and open /etc/hosts once more now that we're watching /etc, in case we missed the creation
+ fd = open("/etc/hosts", O_RDONLY | O_EVTONLY);
+ if (fd == -1) { LogMsg("mDNSMacOSXGetEtcHostsFD etc hosts does not exist, watching etc"); return -1; }
+ }
+
+ // create a dispatch source to watch for changes to hosts file
+ hostssrc = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, fd,
+ (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME |
+ DISPATCH_VNODE_ATTRIB | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_LINK | DISPATCH_VNODE_REVOKE), etcq);
+ if (hostssrc == NULL)
+ {
+ close(fd);
+ return -1;
+ }
+ dispatch_source_set_event_handler(hostssrc,
+ ^{
+ u_int32_t flags = dispatch_source_get_data(hostssrc);
+ LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts changed 0x%x", flags);
+ if ((flags & (DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME)) != 0)
+ {
+ dispatch_source_cancel(hostssrc);
+ dispatch_release(hostssrc);
+ hostssrc = NULL;
+ // Bug in LibDispatch: wait a second before scheduling the block. If we schedule
+ // the block immediately, we try to open the file and the file may not exist and may
+ // fail to get a notification in the future. When the file does not exist and
+ // we start to monitor the directory, on "dispatch_resume" of that source, there
+ // is no guarantee that the file creation will be notified always because when
+ // the dispatch_resume returns, the kevent manager may not have registered the
+ // kevent yet but the file may have been created
+ usleep(1000000);
+ dispatch_async(etcq, ^{mDNSMacOSXUpdateEtcHosts(m);});
+ return;
+ }
+ if ((flags & DISPATCH_VNODE_WRITE) != 0)
+ {
+ mDNSMacOSXUpdateEtcHosts(m);
+ }
+ });
+ dispatch_source_set_cancel_handler(hostssrc, ^{LogInfo("mDNSMacOSXGetEtcHostsFD: Closing etchosts fd %d", fd); close(fd);});
+ dispatch_resume(hostssrc);
+
+ // Cleanup /etc source, no need to watch it if we already have /etc/hosts
+ if (etcsrc)
+ {
+ dispatch_source_cancel(etcsrc);
+ dispatch_release(etcsrc);
+ etcsrc = NULL;
+ }
+
+ LogInfo("mDNSMacOSXGetEtcHostsFD: /etc/hosts being monitored, and not etc");
+ return hostssrc ? (int)dispatch_source_get_handle(hostssrc) : -1;
+#else
+ (void)m;
+ return fd;
+#endif
+}
+
+// When /etc/hosts is modified, flush all the cache records as there may be local
+// authoritative answers now
+mDNSlocal void FlushAllCacheRecords(mDNS *const m)
+{
+ CacheRecord *cr;
+ mDNSu32 slot;
+ CacheGroup *cg;
+
+ FORALL_CACHERECORDS(slot, cg, cr)
+ {
+ // Skip multicast.
+ if (cr->resrec.InterfaceID) continue;
+
+ // If a resource record can answer A or AAAA, they need to be flushed so that we will
+ // never used to deliver an ADD or RMV
+ if (RRTypeAnswersQuestionType(&cr->resrec, kDNSType_A) ||
+ RRTypeAnswersQuestionType(&cr->resrec, kDNSType_AAAA))
+ {
+ LogInfo("FlushAllCacheRecords: Purging Resourcerecord %s", CRDisplayString(m, cr));
+ mDNS_PurgeCacheResourceRecord(m, cr);
+ }
+ }
+}
+
+// Add new entries to the core. If justCheck is set, this function does not add, just returns true
+mDNSlocal mDNSBool EtcHostsAddNewEntries(mDNS *const m, AuthHash *newhosts, mDNSBool justCheck)
+{
+ AuthGroup *ag;
+ mDNSu32 slot;
+ AuthRecord *rr, *primary, *rrnext;
+ for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
+ for (ag = newhosts->rrauth_hash[slot]; ag; ag = ag->next)
+ {
+ primary = NULL;
+ for (rr = ag->members; rr; rr = rrnext)
+ {
+ rrnext = rr->next;
+ AuthGroup *ag1;
+ AuthRecord *rr1;
+ mDNSBool found = mDNSfalse;
+ ag1 = AuthGroupForRecord(&m->rrauth, slot, &rr->resrec);
+ if (ag1 && ag1->members)
+ {
+ if (!primary) primary = ag1->members;
+ rr1 = ag1->members;
+ while (rr1)
+ {
+ // We are not using InterfaceID in checking for duplicates. This means,
+ // if there are two addresses for a given name e.g., fe80::1%en0 and
+ // fe80::1%en1, we only add the first one. It is not clear whether
+ // this is a common case. To fix this, we also need to modify
+ // mDNS_Register_internal in how it handles duplicates. If it becomes a
+ // common case, we will fix it then.
+ if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
+ {
+ LogInfo("EtcHostsAddNewEntries: Skipping, not adding %s", ARDisplayString(m, rr1));
+ found = mDNStrue;
+ break;
+ }
+ rr1 = rr1->next;
+ }
+ }
+ if (!found)
+ {
+ if (justCheck)
+ {
+ LogInfo("EtcHostsAddNewEntries: Entry %s not registered with core yet", ARDisplayString(m, rr));
+ return mDNStrue;
+ }
+ RemoveAuthRecord(m, newhosts, rr);
+ // if there is no primary, point to self
+ rr->RRSet = (primary ? primary : rr);
+ rr->next = NULL;
+ LogInfo("EtcHostsAddNewEntries: Adding %s", ARDisplayString(m, rr));
+ if (mDNS_Register_internal(m, rr) != mStatus_NoError)
+ LogMsg("EtcHostsAddNewEntries: mDNS_Register failed for %s", ARDisplayString(m, rr));
+ }
+ }
+ }
+ return mDNSfalse;
+}
+
+// Delete entries from the core that are no longer needed. If justCheck is set, this function
+// does not delete, just returns true
+mDNSlocal mDNSBool EtcHostsDeleteOldEntries(mDNS *const m, AuthHash *newhosts, mDNSBool justCheck)
+{
+ AuthGroup *ag;
+ mDNSu32 slot;
+ AuthRecord *rr, *primary, *rrnext;
+ for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
+ for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next)
+ for (rr = ag->members; rr; rr = rrnext)
+ {
+ mDNSBool found = mDNSfalse;
+ AuthGroup *ag1;
+ AuthRecord *rr1;
+ rrnext = rr->next;
+ if (rr->RecordCallback != FreeEtcHosts) continue;
+ ag1 = AuthGroupForRecord(newhosts, slot, &rr->resrec);
+ if (ag1)
+ {
+ primary = rr1 = ag1->members;
+ while (rr1)
+ {
+ if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
+ {
+ LogInfo("EtcHostsDeleteOldEntries: Old record %s found in new, skipping", ARDisplayString(m, rr));
+ found = mDNStrue;
+ break;
+ }
+ rr1 = rr1->next;
+ }
+ }
+ // there is no corresponding record in newhosts for the same name. This means
+ // we should delete this from the core.
+ if (!found)
+ {
+ if (justCheck)
+ {
+ LogInfo("EtcHostsDeleteOldEntries: Record %s not found in new, deleting", ARDisplayString(m, rr));
+ return mDNStrue;
+ }
+ // if primary is going away, make sure that the rest of the records
+ // point to the new primary
+ if (rr == ag->members)
+ {
+ AuthRecord *new_primary = rr->next;
+ AuthRecord *r = new_primary;
+ while (r)
+ {
+ if (r->RRSet == rr)
+ {
+ LogInfo("EtcHostsDeleteOldEntries: Updating Resource Record %s to primary", ARDisplayString(m, r));
+ r->RRSet = new_primary;
+ }
+ else LogMsg("EtcHostsDeleteOldEntries: ERROR!! Resource Record %s not pointing to primary %##s", ARDisplayString(m, r), r->resrec.name);
+ r = r->next;
+ }
+ }
+ LogInfo("EtcHostsDeleteOldEntries: Deleting %s", ARDisplayString(m, rr));
+ mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
+ }
+ }
+ return mDNSfalse;
+}
+
+mDNSlocal void UpdateEtcHosts(mDNS *const m, void *context)
+{
+ AuthHash *newhosts = (AuthHash *)context;
+
+ mDNS_CheckLock(m);
+
+ //Delete old entries from the core if they are not present in the newhosts
+ EtcHostsDeleteOldEntries(m, newhosts, mDNSfalse);
+ // Add the new entries to the core if not already present in the core
+ EtcHostsAddNewEntries(m, newhosts, mDNSfalse);
+}
+
+mDNSlocal void FreeNewHosts(AuthHash *newhosts)
+{
+ mDNSu32 slot;
+ AuthGroup *ag, *agnext;
+ AuthRecord *rr, *rrnext;
+
+ for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
+ for (ag = newhosts->rrauth_hash[slot]; ag; ag = agnext)
+ {
+ agnext = ag->next;
+ for (rr = ag->members; rr; rr = rrnext)
+ {
+ rrnext = rr->next;
+ freeL("etchosts", rr);
+ }
+ freeL("AuthGroups", ag);
+ }
+}
+
+mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m)
+{
+ AuthHash newhosts;
+
+ // As we will be modifying the core, we can only have one thread running at
+ // any point in time.
+ KQueueLock(m);
+
+ mDNSPlatformMemZero(&newhosts, sizeof(AuthHash));
+
+ // Get the file desecriptor (will trigger us to start watching for changes)
+ int fd = mDNSMacOSXGetEtcHostsFD(m);
+ if (fd != -1)
+ {
+ LogInfo("mDNSMacOSXUpdateEtcHosts: Parsing /etc/hosts fd %d", fd);
+ mDNSMacOSXParseEtcHosts(m, fd, &newhosts);
+ }
+ else LogInfo("mDNSMacOSXUpdateEtcHosts: /etc/hosts is not present");
+
+ // Optimization: Detect whether /etc/hosts changed or not.
+ //
+ // 1. Check to see if there are any new entries. We do this by seeing whether any entries in
+ // newhosts is already registered with core. If we find at least one entry that is not
+ // registered with core, then it means we have work to do.
+ //
+ // 2. Next, we check to see if any of the entries that are registered with core is not present
+ // in newhosts. If we find at least one entry that is not present, it means we have work to
+ // do.
+ //
+ // Note: We may not have to hold the lock right here as KQueueLock is held which prevents any
+ // other thread from running. But mDNS_Lock is needed here as we will be traversing the core
+ // data structure in EtcHostsDeleteOldEntries/NewEntries which might expect the lock to be held
+ // in the future and this code does not have to change.
+ mDNS_Lock(m);
+ // Add the new entries to the core if not already present in the core
+ if (!EtcHostsAddNewEntries(m, &newhosts, mDNStrue))
+ {
+ // No new entries to add, check to see if we need to delete any old entries from the
+ // core if they are not present in the newhosts
+ if (!EtcHostsDeleteOldEntries(m, &newhosts, mDNStrue))
+ {
+ LogInfo("mDNSMacOSXUpdateEtcHosts: No work");
+ mDNS_Unlock(m);
+ KQueueUnlock(m, "/etc/hosts changed");
+ FreeNewHosts(&newhosts);
+ return;
+ }
+ }
+
+ // This will flush the cache, stop and start the query so that the queries
+ // can look at the /etc/hosts again
+ //
+ // Notes:
+ //
+ // We can't delete and free the records here. We wait for the mDNSCoreRestartAddressQueries to
+ // deliver RMV events. It has to be done in a deferred way because we can't deliver RMV
+ // events for local records *before* the RMV events for cache records. mDNSCoreRestartAddressQueries
+ // delivers these events in the right order and then calls us back to delete them.
+ //
+ // Similarly, we do a deferred Registration of the record because mDNSCoreRestartAddressQueries
+ // is a common function that looks at all local auth records and delivers a RMV including
+ // the records that we might add here. If we deliver a ADD here, it will get a RMV and then when
+ // the query is restarted, it will get another ADD. To avoid this (ADD-RMV-ADD), we defer registering
+ // the record until the RMVs are delivered in mDNSCoreRestartAddressQueries after which UpdateEtcHosts
+ // is called back where we do the Registration of the record. This results in RMV followed by ADD which
+ // looks normal.
+ mDNSCoreRestartAddressQueries(m, mDNSfalse, FlushAllCacheRecords, UpdateEtcHosts, &newhosts);
+ mDNS_Unlock(m);
+
+ KQueueUnlock(m, "/etc/hosts changed");
+ FreeNewHosts(&newhosts);
+}
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Initialization & Teardown
+#endif
+
+CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
+CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey;
+CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
+CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey;
+
+// Major version 13 is 10.9.x
+mDNSexport void mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring)
+{
+ int major = 0, minor = 0;
+ char letter = 0, prodname[256]="<Unknown>", prodvers[256]="<Unknown>", buildver[256]="<Unknown>";
+ CFDictionaryRef vers = _CFCopySystemVersionDictionary();
+ if (vers)
+ {
+ CFStringRef cfprodname = CFDictionaryGetValue(vers, _kCFSystemVersionProductNameKey);
+ CFStringRef cfprodvers = CFDictionaryGetValue(vers, _kCFSystemVersionProductVersionKey);
+ CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
+ if (cfprodname)
+ CFStringGetCString(cfprodname, prodname, sizeof(prodname), kCFStringEncodingUTF8);
+ if (cfprodvers)
+ CFStringGetCString(cfprodvers, prodvers, sizeof(prodvers), kCFStringEncodingUTF8);
+ if (cfbuildver && CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8))
+ sscanf(buildver, "%d%c%d", &major, &letter, &minor);
+ CFRelease(vers);
+ }
+ if (!major)
+ {
+ major = 13;
+ LogMsg("Note: No Major Build Version number found; assuming 13");
+ }
+ if (HINFO_SWstring)
+ mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, STRINGIFY(mDNSResponderVersion));
+ //LogMsg("%s %s (%s), %d %c %d", prodname, prodvers, buildver, major, letter, minor);
+
+ // If product name is "Mac OS X" (or similar) we set OSXVers, else we set iOSVers;
+ if ((prodname[0] & 0xDF) == 'M')
+ OSXVers = major;
+ else
+ iOSVers = major;
+}
+
+// Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
+// If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
+// we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
+mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
+{
+ int err = -1;
+ int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (s < 3)
+ LogMsg("mDNSPlatformInit_CanReceiveUnicast: socket error %d errno %d (%s)", s, errno, strerror(errno));
+ else
+ {
+ struct sockaddr_in s5353;
+ s5353.sin_family = AF_INET;
+ s5353.sin_port = MulticastDNSPort.NotAnInteger;
+ s5353.sin_addr.s_addr = 0;
+ err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
+ close(s);
+ }
+
+ if (err) LogMsg("No unicast UDP responses");
+ else debugf("Unicast UDP responses okay");
+ return(err == 0);
+}
+
+mDNSlocal void CreatePTRRecord(mDNS *const m, const domainname *domain)
+{
+ AuthRecord *rr;
+ const domainname *pname = (domainname *)"\x9" "localhost";
+
+ rr= mallocL("localhosts", sizeof(*rr));
+ if (rr == NULL) return;
+ mDNSPlatformMemZero(rr, sizeof(*rr));
+
+ mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, mDNSNULL, mDNSNULL);
+ AssignDomainName(&rr->namestorage, domain);
+
+ rr->resrec.rdlength = DomainNameLength(pname);
+ rr->resrec.rdata->u.name.c[0] = 0;
+ AssignDomainName(&rr->resrec.rdata->u.name, pname);
+
+ rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
+ SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
+ mDNS_Register(m, rr);
+}
+
+// Setup PTR records for 127.0.0.1 and ::1. This helps answering them locally rather than relying
+// on the external DNS server to answer this. Sometimes, the DNS servers don't respond in a timely
+// fashion and applications depending on this e.g., telnetd, times out after 30 seconds creating
+// a bad user experience. For now, we specifically create only localhosts to handle radar://9354225
+//
+// Note: We could have set this up while parsing the entries in /etc/hosts. But this is kept separate
+// intentionally to avoid adding to the complexity of code handling /etc/hosts.
+mDNSlocal void SetupLocalHostRecords(mDNS *const m)
+{
+ char buffer[MAX_REVERSE_MAPPING_NAME];
+ domainname name;
+ int i;
+ struct in6_addr addr;
+ mDNSu8 *ptr = addr.__u6_addr.__u6_addr8;
+
+ if (inet_pton(AF_INET, "127.0.0.1", &addr) == 1)
+ {
+ mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.",
+ ptr[3], ptr[2], ptr[1], ptr[0]);
+ MakeDomainNameFromDNSNameString(&name, buffer);
+ CreatePTRRecord(m, &name);
+ }
+ else LogMsg("SetupLocalHostRecords: ERROR!! inet_pton AF_INET failed");
+
+ if (inet_pton(AF_INET6, "::1", &addr) == 1)
+ {
+ for (i = 0; i < 16; i++)
+ {
+ static const char hexValues[] = "0123456789ABCDEF";
+ buffer[i * 4 ] = hexValues[ptr[15 - i] & 0x0F];
+ buffer[i * 4 + 1] = '.';
+ buffer[i * 4 + 2] = hexValues[ptr[15 - i] >> 4];
+ buffer[i * 4 + 3] = '.';
+ }
+ mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
+ MakeDomainNameFromDNSNameString(&name, buffer);
+ CreatePTRRecord(m, &name);
+ }
+ else LogMsg("SetupLocalHostRecords: ERROR!! inet_pton AF_INET6 failed");
+}
+
+// Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
+// 1) query for b._dns-sd._udp.local on LocalOnly interface
+// (.local manually generated via explicit callback)
+// 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
+// 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
+// 4) result above should generate a callback from question in (1). result added to global list
+// 5) global list delivered to client via GetSearchDomainList()
+// 6) client calls to enumerate domains now go over LocalOnly interface
+// (!!!KRS may add outgoing interface in addition)
+
+mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
+{
+ mStatus err;
+ m->p->CFRunLoop = CFRunLoopGetCurrent();
+
+ char HINFO_SWstring[256] = "";
+ mDNSMacOSXSystemBuildNumber(HINFO_SWstring);
+
+ err = mDNSHelperInit();
+ if (err)
+ return err;
+
+ DynamicStoreQueue = dispatch_queue_create("com.apple.mDNSResponder.DynamicStoreQueue", NULL);
+ if (DynamicStoreQueue == NULL)
+ {
+ LogMsg("dispatch_queue_create: DynamicStoreQueue NULL!");
+ return mStatus_NoMemoryErr;
+ }
+
+ // Store mDNSResponder Platform
+ if (OSXVers)
+ {
+ m->mDNS_plat = platform_OSX;
+ }
+ else if (iOSVers)
+ {
+ if (IsAppleTV())
+ m->mDNS_plat = platform_Atv;
+ else
+ m->mDNS_plat = platform_iOS;
+ }
+ else
+ {
+ m->mDNS_plat = platform_NonApple;
+ }
+
+ // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
+ // If we can't read the user's preferences, then we sleep a bit and try again, for up to five seconds before we give up.
+ int i;
+ for (i=0; i<100; i++)
+ {
+ domainlabel testlabel;
+ testlabel.c[0] = 0;
+ GetUserSpecifiedLocalHostName(&testlabel);
+ if (testlabel.c[0]) break;
+ usleep(50000);
+ }
+
+ m->hostlabel.c[0] = 0;
+
+ int get_model[2] = { CTL_HW, HW_MODEL };
+ size_t len_model = sizeof(HINFO_HWstring_buffer);
+
+ // Normal Apple model names are of the form "iPhone2,1", and
+ // internal code names are strings containing no commas, e.g. "N88AP".
+ // We used to ignore internal code names, but Apple now uses these internal code names
+ // even in released shipping products, so we no longer ignore strings containing no commas.
+// if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
+ if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0)
+ HINFO_HWstring = HINFO_HWstring_buffer;
+
+ // For names of the form "iPhone2,1" we use "iPhone" as the prefix for automatic name generation.
+ // For names of the form "N88AP" containg no comma, we use the entire string.
+ HINFO_HWstring_prefixlen = strchr(HINFO_HWstring_buffer, ',') ? strcspn(HINFO_HWstring, "0123456789") : strlen(HINFO_HWstring);
+
+ if (mDNSPlatformInit_CanReceiveUnicast())
+ m->CanReceiveUnicastOn5353 = mDNStrue;
+
+ mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring);
+ mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring);
+ if (hlen + slen < 254)
+ {
+ m->HIHardware.c[0] = hlen;
+ m->HISoftware.c[0] = slen;
+ mDNSPlatformMemCopy(&m->HIHardware.c[1], HINFO_HWstring, hlen);
+ mDNSPlatformMemCopy(&m->HISoftware.c[1], HINFO_SWstring, slen);
+ }
+
+ m->p->permanentsockets.port = MulticastDNSPort;
+ m->p->permanentsockets.m = m;
+ m->p->permanentsockets.sktv4 = -1;
+ m->p->permanentsockets.kqsv4.KQcallback = myKQSocketCallBack;
+ m->p->permanentsockets.kqsv4.KQcontext = &m->p->permanentsockets;
+ m->p->permanentsockets.kqsv4.KQtask = "UDP packet reception";
+ m->p->permanentsockets.sktv6 = -1;
+ m->p->permanentsockets.kqsv6.KQcallback = myKQSocketCallBack;
+ m->p->permanentsockets.kqsv6.KQcontext = &m->p->permanentsockets;
+ m->p->permanentsockets.kqsv6.KQtask = "UDP packet reception";
+
+ err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET, mDNSNULL);
+ err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET6, mDNSNULL);
+
+ struct sockaddr_in s4;
+ socklen_t n4 = sizeof(s4);
+ if (getsockname(m->p->permanentsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0)
+ LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno));
+ else
+ m->UnicastPort4.NotAnInteger = s4.sin_port;
+
+ if (m->p->permanentsockets.sktv6 >= 0)
+ {
+ struct sockaddr_in6 s6;
+ socklen_t n6 = sizeof(s6);
+ if (getsockname(m->p->permanentsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno));
+ else m->UnicastPort6.NotAnInteger = s6.sin6_port;
+ }
+
+ m->p->InterfaceList = mDNSNULL;
+ m->p->userhostlabel.c[0] = 0;
+ m->p->usernicelabel.c[0] = 0;
+ m->p->prevoldnicelabel.c[0] = 0;
+ m->p->prevnewnicelabel.c[0] = 0;
+ m->p->prevoldhostlabel.c[0] = 0;
+ m->p->prevnewhostlabel.c[0] = 0;
+ m->p->NotifyUser = 0;
+ m->p->KeyChainTimer = 0;
+ m->p->WakeAtUTC = 0;
+ m->p->RequestReSleep = 0;
+ // Assume that everything is good to begin with. If something is not working,
+ // we will detect that when we start sending questions.
+ m->p->v4answers = 1;
+ m->p->v6answers = 1;
+ m->p->DNSTrigger = 0;
+ m->p->LastConfigGeneration = 0;
+
+#if APPLE_OSX_mDNSResponder
+ uuid_generate(m->asl_uuid);
+#endif
+
+ m->AutoTunnelRelayAddr = zerov6Addr;
+
+ NetworkChangedKey_IPv4 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
+ NetworkChangedKey_IPv6 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
+ NetworkChangedKey_Hostnames = SCDynamicStoreKeyCreateHostNames(NULL);
+ NetworkChangedKey_Computername = SCDynamicStoreKeyCreateComputerName(NULL);
+ NetworkChangedKey_DNS = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
+ NetworkChangedKey_StateInterfacePrefix = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, CFSTR(""), NULL);
+ if (!NetworkChangedKey_IPv4 || !NetworkChangedKey_IPv6 || !NetworkChangedKey_Hostnames || !NetworkChangedKey_Computername || !NetworkChangedKey_DNS || !NetworkChangedKey_StateInterfacePrefix)
+ { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr); }
+
+ err = WatchForNetworkChanges(m);
+ if (err) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err); return(err); }
+
+#if 0 // <rdar://problem/6751656>
+ err = WatchForPMChanges(m);
+ if (err) { LogMsg("mDNSPlatformInit_setup: WatchForPMChanges failed %d", err); return(err); }
+#endif
+
+ err = WatchForSysEvents(m);
+ if (err) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err); return(err); }
+
+ mDNSs32 utc = mDNSPlatformUTC();
+ m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
+ UpdateInterfaceList(m, utc);
+ SetupActiveInterfaces(m, utc);
+
+ // Explicitly ensure that our Keychain operations utilize the system domain.
+#ifndef NO_SECURITYFRAMEWORK
+ SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
+#endif
+
+ mDNS_Lock(m);
+ SetDomainSecrets(m);
+ SetLocalDomains();
+ mDNS_Unlock(m);
+
+#ifndef NO_SECURITYFRAMEWORK
+ err = SecKeychainAddCallback(KeychainChanged, kSecAddEventMask|kSecDeleteEventMask|kSecUpdateEventMask, m);
+ if (err) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err); return(err); }
+#endif
+
+#if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_EMBEDDED
+ LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
+#else
+ IOPMConnection c;
+ IOReturn iopmerr = IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU, &c);
+ if (iopmerr) LogMsg("IOPMConnectionCreate failed %d", iopmerr);
+ else
+ {
+ iopmerr = IOPMConnectionSetNotification(c, m, SnowLeopardPowerChanged);
+ if (iopmerr) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr);
+ else
+ {
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+ IOPMConnectionSetDispatchQueue(c, dispatch_get_main_queue());
+ LogInfo("IOPMConnectionSetDispatchQueue is now running");
+#else
+ iopmerr = IOPMConnectionScheduleWithRunLoop(c, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+ if (iopmerr) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr);
+ LogInfo("IOPMConnectionScheduleWithRunLoop is now running");
+#endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
+ }
+ }
+ m->p->IOPMConnection = iopmerr ? mDNSNULL : c;
+ if (iopmerr) // If IOPMConnectionCreate unavailable or failed, proceed with old-style power notification code below
+#endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements
+ {
+ m->p->PowerConnection = IORegisterForSystemPower(m, &m->p->PowerPortRef, PowerChanged, &m->p->PowerNotifier);
+ if (!m->p->PowerConnection) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
+ else
+ {
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+ IONotificationPortSetDispatchQueue(m->p->PowerPortRef, dispatch_get_main_queue());
+#else
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
+#endif /* MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM */
+ }
+ }
+
+#if APPLE_OSX_mDNSResponder
+ // Note: We use SPMetricPortability > 35 to indicate a laptop of some kind
+ // SPMetricPortability <= 35 means nominally a non-portable machine (i.e. Mac mini or better)
+ // Apple TVs, AirPort base stations, and Time Capsules do not actually weigh 3kg, but we assign them
+ // higher 'nominal' masses to indicate they should be treated as being relatively less portable than a laptop
+ if (!strncasecmp(HINFO_HWstring, "Xserve", 6)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
+ else if (!strncasecmp(HINFO_HWstring, "RackMac", 7)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
+ else if (!strncasecmp(HINFO_HWstring, "MacPro", 6)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
+ else if (!strncasecmp(HINFO_HWstring, "PowerMac", 8)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 82 /* 160W */; SPMetricTotalPower = 83 /* 200W */; }
+ else if (!strncasecmp(HINFO_HWstring, "iMac", 4)) { SPMetricPortability = 30 /* 10kg */; SPMetricMarginalPower = 77 /* 50W */; SPMetricTotalPower = 78 /* 60W */; }
+ else if (!strncasecmp(HINFO_HWstring, "Macmini", 7)) { SPMetricPortability = 33 /* 5kg */; SPMetricMarginalPower = 73 /* 20W */; SPMetricTotalPower = 74 /* 25W */; }
+ else if (!strncasecmp(HINFO_HWstring, "TimeCapsule", 11)) { SPMetricPortability = 34 /* 4kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 13W */; }
+ else if (!strncasecmp(HINFO_HWstring, "AirPort", 7)) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 10 /* ~0W */; SPMetricTotalPower = 70 /* 12W */; }
+ else if ( IsAppleTV() ) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 60 /* 1W */; SPMetricTotalPower = 63 /* 2W */; }
+ else if (!strncasecmp(HINFO_HWstring, "MacBook", 7)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
+ else if (!strncasecmp(HINFO_HWstring, "PowerBook", 9)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; }
+ LogSPS("HW_MODEL: %.*s (%s) Portability %d Marginal Power %d Total Power %d Features %d",
+ HINFO_HWstring_prefixlen, HINFO_HWstring, HINFO_HWstring, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower, SPMetricFeatures);
+#endif // APPLE_OSX_mDNSResponder
+
+ // Currently this is not defined. SSL code will eventually fix this. If it becomes
+ // critical, we will define this to workaround the bug in SSL.
+#ifdef __SSL_NEEDS_SERIALIZATION__
+ SSLqueue = dispatch_queue_create("com.apple.mDNSResponder.SSLQueue", NULL);
+#else
+ SSLqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+#endif
+ if (SSLqueue == mDNSNULL) LogMsg("dispatch_queue_create: SSL queue NULL");
+
+ mDNSMacOSXUpdateEtcHosts(m);
+ SetupLocalHostRecords(m);
+ CUPInit(m);
+
+ return(mStatus_NoError);
+}
+
+mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
+{
+#if MDNS_NO_DNSINFO
+ LogMsg("Note: Compiled without Apple-specific Split-DNS support");
+#endif
+
+ // Adding interfaces will use this flag, so set it now.
+ m->DivertMulticastAdvertisements = !m->AdvertiseLocalAddresses;
+
+#if APPLE_OSX_mDNSResponder
+ m->SPSBrowseCallback = UpdateSPSStatus;
+#endif // APPLE_OSX_mDNSResponder
+
+ mStatus result = mDNSPlatformInit_setup(m);
+
+ // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
+ // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
+ if (result == mStatus_NoError)
+ {
+ mDNSCoreInitComplete(m, mStatus_NoError);
+
+#if !NO_D2D
+ // We only initialize if mDNSCore successfully initialized.
+ if (D2DInitialize)
+ {
+ D2DStatus ds = D2DInitialize(m->p->CFRunLoop, xD2DServiceCallback, m) ;
+ if (ds != kD2DSuccess)
+ LogMsg("D2DInitialiize failed: %d", ds);
+ else
+ LogMsg("D2DInitialize succeeded");
+ }
+#endif // ! NO_D2D
+
+ }
+ result = DNSSECCryptoInit(m);
+ return(result);
+}
+
+mDNSexport void mDNSPlatformClose(mDNS *const m)
+{
+ if (m->p->PowerConnection)
+ {
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+ IONotificationPortSetDispatchQueue(m->p->PowerPortRef, NULL);
+#else
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
+#endif
+ // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
+ // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
+ IODeregisterForSystemPower(&m->p->PowerNotifier);
+ IOServiceClose ( m->p->PowerConnection);
+ IONotificationPortDestroy ( m->p->PowerPortRef);
+ m->p->PowerConnection = 0;
+ }
+
+ if (m->p->Store)
+ {
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+ if (!SCDynamicStoreSetDispatchQueue(m->p->Store, NULL))
+ LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed");
+#else
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
+ CFRunLoopSourceInvalidate(m->p->StoreRLS);
+ CFRelease(m->p->StoreRLS);
+ m->p->StoreRLS = NULL;
+#endif
+ CFRelease(m->p->Store);
+ m->p->Store = NULL;
+ }
+
+ if (m->p->PMRLS)
+ {
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->PMRLS, kCFRunLoopDefaultMode);
+ CFRunLoopSourceInvalidate(m->p->PMRLS);
+ CFRelease(m->p->PMRLS);
+ m->p->PMRLS = NULL;
+ }
+
+ if (m->p->SysEventNotifier >= 0) { close(m->p->SysEventNotifier); m->p->SysEventNotifier = -1; }
+
+#if !NO_D2D
+ if (D2DTerminate)
+ {
+ D2DStatus ds = D2DTerminate();
+ if (ds != kD2DSuccess)
+ LogMsg("D2DTerminate failed: %d", ds);
+ else
+ LogMsg("D2DTerminate succeeded");
+ }
+#endif // ! NO_D2D
+
+ mDNSs32 utc = mDNSPlatformUTC();
+ MarkAllInterfacesInactive(m, utc);
+ ClearInactiveInterfaces(m, utc);
+ CloseSocketSet(&m->p->permanentsockets);
+
+#if APPLE_OSX_mDNSResponder
+ // clean up tunnels
+ while (m->TunnelClients)
+ {
+ ClientTunnel *cur = m->TunnelClients;
+ LogInfo("mDNSPlatformClose: removing client tunnel %p %##s from list", cur, cur->dstname.c);
+ if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
+ AutoTunnelSetKeys(cur, mDNSfalse);
+ m->TunnelClients = cur->next;
+ freeL("ClientTunnel", cur);
+ }
+
+ if (AnonymousRacoonConfig)
+ {
+ AnonymousRacoonConfig = mDNSNULL;
+ LogInfo("mDNSPlatformClose: Deconfiguring autotunnel");
+ (void)mDNSConfigureServer(kmDNSDown, mDNSNULL, mDNSNULL);
+ }
+#endif // APPLE_OSX_mDNSResponder
+}
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - General Platform Support Layer functions
+#endif
+
+mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
+{
+ return(arc4random());
+}
+
+mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000;
+mDNSexport mDNSu32 mDNSPlatformClockDivisor = 0;
+
+mDNSexport mStatus mDNSPlatformTimeInit(void)
+{
+ // Notes: Typical values for mach_timebase_info:
+ // tbi.numer = 1000 million
+ // tbi.denom = 33 million
+ // These are set such that (mach_absolute_time() * numer/denom) gives us nanoseconds;
+ // numer / denom = nanoseconds per hardware clock tick (e.g. 30);
+ // denom / numer = hardware clock ticks per nanosecond (e.g. 0.033)
+ // (denom*1000000) / numer = hardware clock ticks per millisecond (e.g. 33333)
+ // So: mach_absolute_time() / ((denom*1000000)/numer) = milliseconds
+ //
+ // Arithmetic notes:
+ // tbi.denom is at least 1, and not more than 2^32-1.
+ // Therefore (tbi.denom * 1000000) is at least one million, but cannot overflow a uint64_t.
+ // tbi.denom is at least 1, and not more than 2^32-1.
+ // Therefore clockdivisor should end up being a number roughly in the range 10^3 - 10^9.
+ // If clockdivisor is less than 10^3 then that means that the native clock frequency is less than 1MHz,
+ // which is unlikely on any current or future Macintosh.
+ // If clockdivisor is greater than 10^9 then that means the native clock frequency is greater than 1000GHz.
+ // When we ship Macs with clock frequencies above 1000GHz, we may have to update this code.
+ struct mach_timebase_info tbi;
+ kern_return_t result = mach_timebase_info(&tbi);
+ if (result == KERN_SUCCESS) mDNSPlatformClockDivisor = ((uint64_t)tbi.denom * 1000000) / tbi.numer;
+ return(result);
+}
+
+mDNSexport mDNSs32 mDNSPlatformRawTime(void)
+{
+ if (mDNSPlatformClockDivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
+
+ static uint64_t last_mach_absolute_time = 0;
+ //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
+ uint64_t this_mach_absolute_time = mach_absolute_time();
+ if ((int64_t)this_mach_absolute_time - (int64_t)last_mach_absolute_time < 0)
+ {
+ LogMsg("mDNSPlatformRawTime: last_mach_absolute_time %08X%08X", last_mach_absolute_time);
+ LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time);
+ // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
+ last_mach_absolute_time = this_mach_absolute_time;
+ // Note: This bug happens all the time on 10.3
+ NotifyOfElusiveBug("mach_absolute_time went backwards!",
+ "This error occurs from time to time, often on newly released hardware, "
+ "and usually the exact cause is different in each instance.\r\r"
+ "Please file a new Radar bug report with the title “mach_absolute_time went backwards” "
+ "and assign it to Radar Component “Kernel” Version “X”.");
+ }
+ last_mach_absolute_time = this_mach_absolute_time;
+
+ return((mDNSs32)(this_mach_absolute_time / mDNSPlatformClockDivisor));
+}
+
+mDNSexport mDNSs32 mDNSPlatformUTC(void)
+{
+ return time(NULL);
+}
+
+// Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
+mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; }
+mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; }
+mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { strcpy((char *)dst, (char *)src); }
+mDNSexport mDNSu32 mDNSPlatformStrLen ( const void *src) { return(strlen((char*)src)); }
+mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, mDNSu32 len) { memcpy(dst, src, len); }
+mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len) == 0); }
+mDNSexport int mDNSPlatformMemCmp(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len)); }
+mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) { memset(dst, 0, len); }
+mDNSexport void mDNSPlatformQsort ( void *base, int nel, int width, int (*compar)(const void *, const void *))
+{
+ return (qsort(base, nel, width, compar));
+}
+#if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
+mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
+#endif
+mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }
+
+mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason)
+{
+ if (allowSleep && m->p->IOPMAssertion)
+ {
+ LogInfo("%s Destroying NoIdleSleep power assertion", __FUNCTION__);
+ IOPMAssertionRelease(m->p->IOPMAssertion);
+ m->p->IOPMAssertion = 0;
+ }
+ else if (!allowSleep)
+ {
+#ifdef kIOPMAssertionTypeNoIdleSleep
+ if (m->p->IOPMAssertion)
+ {
+ IOPMAssertionRelease(m->p->IOPMAssertion);
+ m->p->IOPMAssertion = 0;
+ }
+
+ CFStringRef assertionName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s.%d %s"), getprogname(), getpid(), reason ? reason : "");
+ IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, assertionName ? assertionName : CFSTR("mDNSResponder"), &m->p->IOPMAssertion);
+ if (assertionName) CFRelease(assertionName);
+ LogInfo("%s Creating NoIdleSleep power assertion", __FUNCTION__);
+#endif
+ }
+}
+
+mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
+{
+ mDNSu32 ifindex;
+
+ // Sanity check
+ ifindex = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID, mDNStrue);
+ if (ifindex <= 0)
+ {
+ LogMsg("mDNSPlatformSendWakeupPacket: ERROR!! Invalid InterfaceID %u", ifindex);
+ return;
+ }
+ mDNSSendWakeupPacket(ifindex, EthAddr, IPAddr, iteration);
+}
+
+mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
+{
+ NetworkInterfaceInfoOSX *info;
+
+ if (InterfaceID == mDNSInterface_P2P)
+ return mDNStrue;
+
+ if ( (InterfaceID == mDNSInterface_Any)
+ || (InterfaceID == mDNSInterfaceMark)
+ || (InterfaceID == mDNSInterface_LocalOnly)
+ || (InterfaceID == mDNSInterface_Unicast))
+ return mDNSfalse;
+
+ info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
+ if (info == NULL)
+ {
+ // this log message can print when operations are stopped on an interface that has gone away
+ LogInfo("mDNSPlatformInterfaceIsD2D: Invalid interface index %d", InterfaceID);
+ return mDNSfalse;
+ }
+
+ return (mDNSBool) info->D2DInterface;
+}
+
+// Filter records send over P2P (D2D) type interfaces
+// Note that the terms P2P and D2D are used synonymously in the current code and comments.
+mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const NetworkInterfaceInfo *intf)
+{
+ // For an explicit match to a valid interface ID, return true.
+ if (rr->resrec.InterfaceID == intf->InterfaceID)
+ return mDNStrue;
+
+ // Only filtering records for D2D type interfaces, return true for all other interface types.
+ if (!mDNSPlatformInterfaceIsD2D(intf->InterfaceID))
+ return mDNStrue;
+
+ // If it's an AWDL interface the record must be explicitly marked to include AWDL.
+ if (intf->InterfaceID == AWDLInterfaceID)
+ {
+ if (rr->ARType == AuthRecordAnyIncludeAWDL || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
+ return mDNStrue;
+ else
+ return mDNSfalse;
+ }
+
+ // Send record if it is explicitly marked to include all other P2P type interfaces.
+ if (rr->ARType == AuthRecordAnyIncludeP2P || rr->ARType == AuthRecordAnyIncludeAWDLandP2P)
+ return mDNStrue;
+
+ // Don't send the record over this interface.
+ return mDNSfalse;
+}
+
+// Filter questions send over P2P (D2D) type interfaces.
+mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf)
+{
+ // For an explicit match to a valid interface ID, return true.
+ if (q->InterfaceID == intf->InterfaceID)
+ return mDNStrue;
+
+ // Only filtering questions for D2D type interfaces
+ if (!mDNSPlatformInterfaceIsD2D(intf->InterfaceID))
+ return mDNStrue;
+
+ // If it's an AWDL interface the question must be explicitly marked to include AWDL.
+ if (intf->InterfaceID == AWDLInterfaceID)
+ {
+ if (q->flags & kDNSServiceFlagsIncludeAWDL)
+ return mDNStrue;
+ else
+ return mDNSfalse;
+ }
+
+ // Sent question if it is explicitly marked to include all other P2P type interfaces.
+ if (q->flags & kDNSServiceFlagsIncludeP2P)
+ return mDNStrue;
+
+ // Don't send the question over this interface.
+ return mDNSfalse;
+}
+
+// Returns true unless record was received over the AWDL interface and
+// the question was not specific to the AWDL interface or did not specify kDNSServiceInterfaceIndexAny
+// with the kDNSServiceFlagsIncludeAWDL flag set.
+mDNSexport mDNSBool mDNSPlatformValidRecordForQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
+{
+ if (!rr->InterfaceID || (rr->InterfaceID == q->InterfaceID))
+ return mDNStrue;
+
+ if ((rr->InterfaceID == AWDLInterfaceID) && !(q->flags & kDNSServiceFlagsIncludeAWDL))
+ {
+ LogInfo("mDNSPlatformValidRecordForQuestion: Record recieved over AWDL not returned for %s %##s query",
+ DNSTypeName(q->qtype), q->qname.c);
+ return mDNSfalse;
+ }
+
+ return mDNStrue;
+}
+
+// formating time to RFC 4034 format
+mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize)
+{
+ struct tm tmTime;
+ time_t t = (time_t)te;
+ // Time since epoch : strftime takes "tm". Convert seconds to "tm" using
+ // gmtime_r first and then use strftime
+ gmtime_r(&t, &tmTime);
+ strftime((char *)buf, bufsize, "%Y%m%d%H%M%S", &tmTime);
+}
+
+mDNSexport mDNSs32 mDNSPlatformGetPID()
+{
+ return getpid();
+}
+
+// Schedule a function asynchronously on the main queue
+mDNSexport void mDNSPlatformDispatchAsync(mDNS *const m, void *context, AsyncDispatchFunc func)
+{
+ // KQueueLock/Unlock is used for two purposes
+ //
+ // 1. We can't be running along with the KQueue thread and hence acquiring the lock
+ // serializes the access to the "core"
+ //
+ // 2. KQueueUnlock also sends a message wake up the KQueue thread which in turn wakes
+ // up and calls udsserver_idle which schedules the messages across the uds socket.
+ // If "func" delivers something to the uds socket from the dispatch thread, it will
+ // not be delivered immediately if not for the Unlock.
+ dispatch_async(dispatch_get_main_queue(), ^{
+ KQueueLock(m);
+ func(m, context);
+ KQueueUnlock(m, "mDNSPlatformDispatchAsync");
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+ // KQueueUnlock is a noop. Hence, we need to run kick off the idle loop
+ // to handle any message that "func" might deliver.
+ TriggerEventCompletion();
+#endif
+ });
+}
+
+// definitions for device-info record construction
+#define DEVINFO_MODEL "model="
+#define DEVINFO_MODEL_LEN strlen(DEVINFO_MODEL)
+
+#define OSX_VER "osxvers="
+#define OSX_VER_LEN strlen(OSX_VER)
+#define VER_NUM_LEN 2 // 2 digits of version number added to base string
+
+// Bytes available in TXT record for model name after subtracting space for other
+// fixed size strings and their length bytes.
+#define MAX_MODEL_NAME_LEN (256 - (DEVINFO_MODEL_LEN + 1) - (OSX_VER_LEN + VER_NUM_LEN + 1))
+
+// Initialize device-info TXT record contents and return total length of record data.
+mDNSexport mDNSu32 initializeDeviceInfoTXT(mDNS *m, mDNSu8 *ptr)
+{
+ mDNSu8 *bufferStart = ptr;
+ mDNSu8 len = m->HIHardware.c[0] < MAX_MODEL_NAME_LEN ? m->HIHardware.c[0] : MAX_MODEL_NAME_LEN;
+
+ *ptr = DEVINFO_MODEL_LEN + len; // total length of DEVINFO_MODEL string plus the hardware name string
+ ptr++;
+ mDNSPlatformMemCopy(ptr, DEVINFO_MODEL, DEVINFO_MODEL_LEN);
+ ptr += DEVINFO_MODEL_LEN;
+ mDNSPlatformMemCopy(ptr, m->HIHardware.c + 1, len);
+ ptr += len;
+
+ // only include this string for OSX
+ if (OSXVers)
+ {
+ char ver_num[VER_NUM_LEN + 1]; // version digits + null written by snprintf
+ *ptr = OSX_VER_LEN + VER_NUM_LEN; // length byte
+ ptr++;
+ mDNSPlatformMemCopy(ptr, OSX_VER, OSX_VER_LEN);
+ ptr += OSX_VER_LEN;
+ // convert version number to ASCII, add 1 for terminating null byte written by snprintf()
+ snprintf(ver_num, VER_NUM_LEN + 1, "%d", OSXVers);
+ mDNSPlatformMemCopy(ptr, ver_num, VER_NUM_LEN);
+ ptr += VER_NUM_LEN;
+ }
+
+ return (ptr - bufferStart);
+}
Deleted: vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
===================================================================
--- vendor/apple/mDNSResponder/dist/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj 2014-06-30 23:58:12 UTC (rev 6706)
+++ vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj 2015-03-20 01:14:52 UTC (rev 6985)
@@ -1,3137 +0,0 @@
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 45;
- objects = {
-
-/* Begin PBXAggregateTarget section */
- 00AD62BB032D7A0C0CCA2C71 /* Build More */ = {
- isa = PBXAggregateTarget;
- buildConfigurationList = D284BE280ADD78180027CCDF /* Build configuration list for PBXAggregateTarget "Build More" */;
- buildPhases = (
- );
- dependencies = (
- 03067D860C849CC30022BE1F /* PBXTargetDependency */,
- D284BF2C0ADD815A0027CCDF /* PBXTargetDependency */,
- D284BF2E0ADD81600027CCDF /* PBXTargetDependency */,
- D284BF300ADD81630027CCDF /* PBXTargetDependency */,
- );
- name = "Build More";
- productName = "Build All";
- };
- 03067D640C83A3700022BE1F /* Build Some */ = {
- isa = PBXAggregateTarget;
- buildConfigurationList = 03067D730C83A3CB0022BE1F /* Build configuration list for PBXAggregateTarget "Build Some" */;
- buildPhases = (
- FF045B6A0C7E4AA600448140 /* ShellScript */,
- );
- dependencies = (
- 217A4C49138EE14C000A5BA8 /* PBXTargetDependency */,
- 03067D680C83A3830022BE1F /* PBXTargetDependency */,
- 03067D6A0C83A3890022BE1F /* PBXTargetDependency */,
- 03067D6C0C83A3920022BE1F /* PBXTargetDependency */,
- 03067D6E0C83A39C0022BE1F /* PBXTargetDependency */,
- 84C5B3411665544B00C324A8 /* PBXTargetDependency */,
- 72FB546A166D5FE40090B2D9 /* PBXTargetDependency */,
- );
- name = "Build Some";
- productName = "Build Some";
- };
- 2141DCF8123FFB5D0086D23E /* SystemLibraries */ = {
- isa = PBXAggregateTarget;
- buildConfigurationList = 2141DD08123FFB830086D23E /* Build configuration list for PBXAggregateTarget "SystemLibraries" */;
- buildPhases = (
- );
- dependencies = (
- 2141DD0E123FFC960086D23E /* PBXTargetDependency */,
- 2130257112400E9300AC839F /* PBXTargetDependency */,
- );
- name = SystemLibraries;
- productName = SystemLibraries;
- };
- 2141DD0B123FFC7F0086D23E /* SystemLibrariesStatic */ = {
- isa = PBXAggregateTarget;
- buildConfigurationList = 2141DD18123FFC990086D23E /* Build configuration list for PBXAggregateTarget "SystemLibrariesStatic" */;
- buildPhases = (
- );
- dependencies = (
- 215FFB1D124002CC00470DE1 /* PBXTargetDependency */,
- 215FFB1B124002C700470DE1 /* PBXTargetDependency */,
- 215FFB19124002C100470DE1 /* PBXTargetDependency */,
- );
- name = SystemLibrariesStatic;
- productName = SystemLibrariesStatic;
- };
- FFA572650AF190F10055A0F1 /* SystemLibrariesDynamic */ = {
- isa = PBXAggregateTarget;
- buildConfigurationList = FFA5726E0AF191200055A0F1 /* Build configuration list for PBXAggregateTarget "SystemLibrariesDynamic" */;
- buildPhases = (
- 1F7B473C12B82BFD00868AEF /* ShellScript */,
- );
- dependencies = (
- FFA572690AF190FF0055A0F1 /* PBXTargetDependency */,
- FFA5726B0AF191010055A0F1 /* PBXTargetDependency */,
- FFA5726D0AF191020055A0F1 /* PBXTargetDependency */,
- );
- name = SystemLibrariesDynamic;
- productName = SystemLibraries;
- };
- FFB7657B0AEED96B00583A2C /* Build All */ = {
- isa = PBXAggregateTarget;
- buildConfigurationList = FFB7657E0AEED99D00583A2C /* Build configuration list for PBXAggregateTarget "Build All" */;
- buildPhases = (
- );
- dependencies = (
- FFB7657D0AEED97F00583A2C /* PBXTargetDependency */,
- 2141DCFD123FFB7D0086D23E /* PBXTargetDependency */,
- );
- name = "Build All";
- productName = "Build All";
- };
-/* End PBXAggregateTarget section */
-
-/* Begin PBXBuildFile section */
- 21070E5F16486B9000A69507 /* DNSSECSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21070E5D16486B9000A69507 /* DNSSECSupport.c */; };
- 21070E6016486B9000A69507 /* DNSSECSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21070E5D16486B9000A69507 /* DNSSECSupport.c */; };
- 21070E6116486B9000A69507 /* DNSSECSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 21070E5E16486B9000A69507 /* DNSSECSupport.h */; };
- 21070E6216486B9000A69507 /* DNSSECSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 21070E5E16486B9000A69507 /* DNSSECSupport.h */; };
- 2120ABD516B71614007089B6 /* CUPolicy.c in Sources */ = {isa = PBXBuildFile; fileRef = 2120ABD416B71614007089B6 /* CUPolicy.c */; };
- 2120ABD616B71614007089B6 /* CUPolicy.c in Sources */ = {isa = PBXBuildFile; fileRef = 2120ABD416B71614007089B6 /* CUPolicy.c */; };
- 2124FA2C1471E98C0021D7BB /* nsec.h in Headers */ = {isa = PBXBuildFile; fileRef = 2124FA2B1471E98C0021D7BB /* nsec.h */; };
- 2124FA2D1471E98C0021D7BB /* nsec.h in Headers */ = {isa = PBXBuildFile; fileRef = 2124FA2B1471E98C0021D7BB /* nsec.h */; };
- 2124FA301471E9B50021D7BB /* dnssec.h in Headers */ = {isa = PBXBuildFile; fileRef = 2124FA2F1471E9B50021D7BB /* dnssec.h */; };
- 2124FA311471E9B50021D7BB /* dnssec.h in Headers */ = {isa = PBXBuildFile; fileRef = 2124FA2F1471E9B50021D7BB /* dnssec.h */; };
- 2124FA331471E9DE0021D7BB /* nsec.c in Sources */ = {isa = PBXBuildFile; fileRef = 2124FA321471E9DE0021D7BB /* nsec.c */; };
- 2124FA341471E9DE0021D7BB /* nsec.c in Sources */ = {isa = PBXBuildFile; fileRef = 2124FA321471E9DE0021D7BB /* nsec.c */; };
- 2127A47715C3C7B900A857FC /* nsec3.c in Sources */ = {isa = PBXBuildFile; fileRef = 2127A47515C3C7B900A857FC /* nsec3.c */; };
- 2127A47815C3C7B900A857FC /* nsec3.c in Sources */ = {isa = PBXBuildFile; fileRef = 2127A47515C3C7B900A857FC /* nsec3.c */; };
- 2127A47915C3C7B900A857FC /* nsec3.h in Headers */ = {isa = PBXBuildFile; fileRef = 2127A47615C3C7B900A857FC /* nsec3.h */; };
- 2127A47A15C3C7B900A857FC /* nsec3.h in Headers */ = {isa = PBXBuildFile; fileRef = 2127A47615C3C7B900A857FC /* nsec3.h */; };
- 213BDC6D147319F400000896 /* dnssec.c in Sources */ = {isa = PBXBuildFile; fileRef = 213BDC6C147319F400000896 /* dnssec.c */; };
- 213BDC6E147319F400000896 /* dnssec.c in Sources */ = {isa = PBXBuildFile; fileRef = 213BDC6C147319F400000896 /* dnssec.c */; };
- 213FB23C12028C4A002B3A08 /* BonjourEvents.c in Sources */ = {isa = PBXBuildFile; fileRef = 213FB22C12028B53002B3A08 /* BonjourEvents.c */; };
- 213FB23D12028C5A002B3A08 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
- 215FFAEE124000F900470DE1 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
- 215FFAEF124000F900470DE1 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; };
- 215FFAF0124000F900470DE1 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; };
- 215FFAF1124000F900470DE1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; };
- 215FFAF2124000F900470DE1 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; };
- 215FFAF3124000F900470DE1 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; };
- 215FFAF41240011800470DE1 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
- 215FFAF51240011800470DE1 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; };
- 215FFAF61240011800470DE1 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; };
- 215FFAF71240011800470DE1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; };
- 215FFAF81240011800470DE1 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; };
- 215FFAF91240011800470DE1 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; };
- 215FFAFA1240013400470DE1 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
- 215FFAFB1240013400470DE1 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; };
- 215FFAFC1240013400470DE1 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; };
- 215FFAFD1240013400470DE1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; };
- 215FFAFE1240013400470DE1 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; };
- 215FFAFF1240013400470DE1 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; };
- 216D9ACE1720C9F5008066E1 /* VPNService.c in Sources */ = {isa = PBXBuildFile; fileRef = 216D9ACD1720C9F5008066E1 /* VPNService.c */; };
- 216D9ACF1720C9F5008066E1 /* VPNService.c in Sources */ = {isa = PBXBuildFile; fileRef = 216D9ACD1720C9F5008066E1 /* VPNService.c */; };
- 218E8E51156D8C0300720DA0 /* dnsproxy.c in Sources */ = {isa = PBXBuildFile; fileRef = 218E8E4F156D8C0300720DA0 /* dnsproxy.c */; };
- 218E8E52156D8C0300720DA0 /* dnsproxy.c in Sources */ = {isa = PBXBuildFile; fileRef = 218E8E4F156D8C0300720DA0 /* dnsproxy.c */; };
- 218E8E53156D8C0300720DA0 /* dnsproxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 218E8E50156D8C0300720DA0 /* dnsproxy.h */; };
- 218E8E54156D8C0300720DA0 /* dnsproxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 218E8E50156D8C0300720DA0 /* dnsproxy.h */; };
- 219D5542149ED645004464AE /* libxml2.2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 219D5541149ED645004464AE /* libxml2.2.dylib */; };
- 219D5543149ED645004464AE /* libxml2.2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 219D5541149ED645004464AE /* libxml2.2.dylib */; };
- 21A57F4C145B2AE100939099 /* CryptoAlg.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F4A145B2AE100939099 /* CryptoAlg.c */; };
- 21A57F4D145B2AE100939099 /* CryptoAlg.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F4A145B2AE100939099 /* CryptoAlg.c */; };
- 21A57F4E145B2AE100939099 /* CryptoAlg.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A57F4B145B2AE100939099 /* CryptoAlg.h */; };
- 21A57F4F145B2AE100939099 /* CryptoAlg.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A57F4B145B2AE100939099 /* CryptoAlg.h */; };
- 21A57F53145B2B1400939099 /* CryptoSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F51145B2B1400939099 /* CryptoSupport.c */; };
- 21A57F54145B2B1400939099 /* CryptoSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F51145B2B1400939099 /* CryptoSupport.c */; };
- 21A57F55145B2B1400939099 /* CryptoSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A57F52145B2B1400939099 /* CryptoSupport.h */; };
- 21A57F56145B2B1400939099 /* CryptoSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A57F52145B2B1400939099 /* CryptoSupport.h */; };
- 21DCD05C1461B23700702FC8 /* CryptoAlg.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F4A145B2AE100939099 /* CryptoAlg.c */; };
- 21DCD05D1461B23700702FC8 /* CryptoAlg.h in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F4B145B2AE100939099 /* CryptoAlg.h */; };
- 21DD8FBF161E9A250033C8F8 /* anonymous.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DD8FBD161E9A250033C8F8 /* anonymous.c */; };
- 21DD8FC0161E9A250033C8F8 /* anonymous.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DD8FBD161E9A250033C8F8 /* anonymous.c */; };
- 21DD8FC1161E9A250033C8F8 /* anonymous.h in Headers */ = {isa = PBXBuildFile; fileRef = 21DD8FBE161E9A250033C8F8 /* anonymous.h */; };
- 21DD8FC2161E9A250033C8F8 /* anonymous.h in Headers */ = {isa = PBXBuildFile; fileRef = 21DD8FBE161E9A250033C8F8 /* anonymous.h */; };
- 21DED43515702C0F0060B6B9 /* DNSProxySupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DED43415702C0F0060B6B9 /* DNSProxySupport.c */; };
- 21DED43615702C0F0060B6B9 /* DNSProxySupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DED43415702C0F0060B6B9 /* DNSProxySupport.c */; };
- 2E0405F50C3195F700F13B59 /* helper.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405F40C3195F700F13B59 /* helper.c */; };
- 2E0405F60C31961100F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; settings = {ATTRIBUTES = (Client, Server, ); COMPILER_FLAGS = "-Wno-error"; }; };
- 2E0406150C3197CB00F13B59 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E0406140C3197CB00F13B59 /* libbsm.dylib */; };
- 2E04061F0C3198B700F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; };
- 2E0406200C3198B700F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; };
- 2E04070A0C31EEEC00F13B59 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
- 2E04070B0C31EEEC00F13B59 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
- 2E3552900C3A95C100CA1CB7 /* helper-error.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E35528F0C3A95C100CA1CB7 /* helper-error.h */; };
- 2E3552910C3A95C100CA1CB7 /* helper-error.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E35528F0C3A95C100CA1CB7 /* helper-error.h */; };
- 2E3552920C3A95C100CA1CB7 /* helper-error.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E35528F0C3A95C100CA1CB7 /* helper-error.h */; };
- 2E35529D0C3A9E7600CA1CB7 /* helper-error.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E35528F0C3A95C100CA1CB7 /* helper-error.h */; };
- 2E35529E0C3A9E7600CA1CB7 /* helper-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */; };
- 2E35529F0C3A9E7600CA1CB7 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; };
- 2E4D9B050C38C19500480551 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
- 2E8165E80C5980E300485EB2 /* libpfkey.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A8202520C56C36500DDFD48 /* libpfkey.h */; };
- 2E8165E90C5980EE00485EB2 /* pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 4A8202530C56C36600DDFD48 /* pfkey.c */; };
- 2E8165EA0C5980F700485EB2 /* ipsec_strerror.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A8202510C56C36500DDFD48 /* ipsec_strerror.h */; };
- 2E8165F90C59838100485EB2 /* libipsec.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E8165F60C59835F00485EB2 /* libipsec.dylib */; };
- 2E96A51D0C39BDAC0087C4D2 /* helper-main.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E0406CA0C31E9AD00F13B59 /* helper-main.c */; };
- 2E96A5260C39BE480087C4D2 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; };
- 2E96A5270C39BE480087C4D2 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; };
- 2E96A5300C39C1A50087C4D2 /* helper-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */; };
- 2E96A5320C39C1A50087C4D2 /* helper-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */; };
- 2EAE955A0C31F4D30021F738 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; };
- 2EC8F8EC0C39CCAC003C9C48 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; };
- 2ECC11A60C4FEC3800CB1885 /* helpermsg-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */; };
- 2ECC11A70C4FEC3800CB1885 /* helpermsg-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */; };
- 2ECC11A80C4FEC3800CB1885 /* helpermsg-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */; };
- 2EDC5E730C39EA640092701B /* helper-server.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EDC5E720C39EA640092701B /* helper-server.h */; };
- 2EDC5E740C39EA640092701B /* helper-server.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EDC5E720C39EA640092701B /* helper-server.h */; };
- 2EDC5E750C39EA640092701B /* helper-server.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EDC5E720C39EA640092701B /* helper-server.h */; };
- 4A7B9E8014FDA25000B84CC1 /* mDNSResponder.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4A7B9E7E14FDA1BB00B84CC1 /* mDNSResponder.plist */; };
- 4A7B9E8214FDA26C00B84CC1 /* mDNSResponder.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4A7B9E7C14FDA19F00B84CC1 /* mDNSResponder.txt */; };
- 4AAE0C9A0C68EA81003882A5 /* mDNSResponderHelper.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */; };
- 4BD2B63A134FE09F002B96D5 /* P2PPacketFilter.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BD2B638134FE09F002B96D5 /* P2PPacketFilter.c */; };
- 4BD2B63B134FE09F002B96D5 /* P2PPacketFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BD2B639134FE09F002B96D5 /* P2PPacketFilter.h */; };
- 72FB5467166D5FCA0090B2D9 /* dnsctl.c in Sources */ = {isa = PBXBuildFile; fileRef = 72FB545A166D5F960090B2D9 /* dnsctl.c */; };
- 72FB5468166D5FD20090B2D9 /* libdns_services.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 84C5B3351665529800C324A8 /* libdns_services.dylib */; };
- 8418673E15AB8C2D00BB7F70 /* com.apple.networking.mDNSResponder in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8418673A15AB8B6900BB7F70 /* com.apple.networking.mDNSResponder */; };
- 848DA5C7165477E000D2E8B4 /* xpc_services.c in Sources */ = {isa = PBXBuildFile; fileRef = 848DA5C6165477E000D2E8B4 /* xpc_services.c */; };
- 848DA5C8165477E000D2E8B4 /* xpc_services.c in Sources */ = {isa = PBXBuildFile; fileRef = 848DA5C6165477E000D2E8B4 /* xpc_services.c */; };
- 848DA5CA165477EB00D2E8B4 /* xpc_services.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5C9165477EB00D2E8B4 /* xpc_services.h */; };
- 848DA5CB165477EB00D2E8B4 /* xpc_services.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5C9165477EB00D2E8B4 /* xpc_services.h */; };
- 848DA5D616547F7200D2E8B4 /* dns_xpc.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5D516547F7200D2E8B4 /* dns_xpc.h */; };
- 848DA5D716547F7200D2E8B4 /* dns_xpc.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5D516547F7200D2E8B4 /* dns_xpc.h */; };
- 84C5B33C166553F100C324A8 /* dns_services.c in Sources */ = {isa = PBXBuildFile; fileRef = 84C5B339166553AF00C324A8 /* dns_services.c */; };
- 84C5B33D166553F900C324A8 /* dns_services.h in Headers */ = {isa = PBXBuildFile; fileRef = 84C5B338166553A000C324A8 /* dns_services.h */; settings = {ATTRIBUTES = (Private, ); }; };
- D284BE530ADD80740027CCDF /* DNSServiceDiscoveryDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 6575FBFF022EAFBA00000109 /* DNSServiceDiscoveryDefines.h */; };
- D284BE540ADD80740027CCDF /* dnssd_ipc.h in Headers */ = {isa = PBXBuildFile; fileRef = F5E11B5B04A28126019798ED /* dnssd_ipc.h */; };
- D284BE560ADD80740027CCDF /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Client, ); }; };
- D284BE570ADD80740027CCDF /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; settings = {ATTRIBUTES = (Server, ); }; };
- D284BE580ADD80740027CCDF /* mDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBE9022EAF5A00000109 /* mDNS.c */; };
- D284BE590ADD80740027CCDF /* uDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F70587CEF6001880B3 /* uDNS.c */; };
- D284BE5A0ADD80740027CCDF /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; };
- D284BE5B0ADD80740027CCDF /* DNSDigest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F461DB5062DBF2900672BF3 /* DNSDigest.c */; };
- D284BE5D0ADD80740027CCDF /* mDNSDebug.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */; };
- D284BE5E0ADD80740027CCDF /* uds_daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = F525E72804AA167501F1CF4D /* uds_daemon.c */; };
- D284BE5F0ADD80740027CCDF /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
- D284BE600ADD80740027CCDF /* PlatformCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FFCB6D73075D539900B8AF62 /* PlatformCommon.c */; };
- D284BE610ADD80740027CCDF /* mDNSMacOSX.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */; };
- D284BE620ADD80740027CCDF /* LegacyNATTraversal.c in Sources */ = {isa = PBXBuildFile; fileRef = 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */; };
- D284BE630ADD80740027CCDF /* daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEC022EAF7200000109 /* daemon.c */; };
- D284BE650ADD80740027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
- D284BE660ADD80740027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
- D284BE670ADD80740027CCDF /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; };
- D284BE680ADD80740027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
- D284BE6B0ADD80740027CCDF /* mDNSResponder.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FF485D5105632E0000130380 /* mDNSResponder.8 */; };
- D284BE780ADD80800027CCDF /* DNSServiceDiscoveryDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 6575FBFF022EAFBA00000109 /* DNSServiceDiscoveryDefines.h */; };
- D284BE790ADD80800027CCDF /* dnssd_ipc.h in Headers */ = {isa = PBXBuildFile; fileRef = F5E11B5B04A28126019798ED /* dnssd_ipc.h */; };
- D284BE7A0ADD80800027CCDF /* mDNSEmbeddedAPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 654BE64F02B63B93000001D1 /* mDNSEmbeddedAPI.h */; };
- D284BE7B0ADD80800027CCDF /* mDNSDebug.h in Headers */ = {isa = PBXBuildFile; fileRef = 654BE65002B63B93000001D1 /* mDNSDebug.h */; };
- D284BE7C0ADD80800027CCDF /* mDNSMacOSX.h in Headers */ = {isa = PBXBuildFile; fileRef = 000753D303367C1C0CCA2C71 /* mDNSMacOSX.h */; };
- D284BE7E0ADD80800027CCDF /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Client, ); }; };
- D284BE7F0ADD80800027CCDF /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; settings = {ATTRIBUTES = (Server, ); }; };
- D284BE800ADD80800027CCDF /* mDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBE9022EAF5A00000109 /* mDNS.c */; };
- D284BE810ADD80800027CCDF /* uDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F70587CEF6001880B3 /* uDNS.c */; };
- D284BE820ADD80800027CCDF /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; };
- D284BE830ADD80800027CCDF /* DNSDigest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F461DB5062DBF2900672BF3 /* DNSDigest.c */; };
- D284BE850ADD80800027CCDF /* mDNSDebug.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */; };
- D284BE860ADD80800027CCDF /* uds_daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = F525E72804AA167501F1CF4D /* uds_daemon.c */; };
- D284BE870ADD80800027CCDF /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
- D284BE880ADD80800027CCDF /* PlatformCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FFCB6D73075D539900B8AF62 /* PlatformCommon.c */; };
- D284BE890ADD80800027CCDF /* mDNSMacOSX.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */; };
- D284BE8A0ADD80800027CCDF /* LegacyNATTraversal.c in Sources */ = {isa = PBXBuildFile; fileRef = 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */; };
- D284BE8B0ADD80800027CCDF /* daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEC022EAF7200000109 /* daemon.c */; };
- D284BE8D0ADD80800027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
- D284BE8E0ADD80800027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
- D284BE8F0ADD80800027CCDF /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; };
- D284BE900ADD80800027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
- D284BEA80ADD80920027CCDF /* dns-sd.c in Sources */ = {isa = PBXBuildFile; fileRef = FF1C919F07021E3F001048AB /* dns-sd.c */; };
- D284BEAC0ADD80920027CCDF /* dns-sd.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FF1C919D07021D77001048AB /* dns-sd.1 */; };
- D284BEB70ADD809A0027CCDF /* JNISupport.c in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC44B0662DD1100335AB3 /* JNISupport.c */; };
- D284BEB90ADD809A0027CCDF /* JavaVM.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB2CC4680662DFF500335AB3 /* JavaVM.framework */; };
- D284BEC50ADD80A20027CCDF /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; };
- D284BEC60ADD80A20027CCDF /* DNSDigest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F461DB5062DBF2900672BF3 /* DNSDigest.c */; };
- D284BEC70ADD80A20027CCDF /* dnsextd.c in Sources */ = {isa = PBXBuildFile; fileRef = FF25794606C9A8BF00376F7B /* dnsextd.c */; };
- D284BEC80ADD80A20027CCDF /* mDNSDebug.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */; };
- D284BEC90ADD80A20027CCDF /* GenLinkedList.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE2C057E8F660085CAD0 /* GenLinkedList.c */; };
- D284BECA0ADD80A20027CCDF /* mDNSMacOSX.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */; };
- D284BECB0ADD80A20027CCDF /* dnsextd_lexer.l in Sources */ = {isa = PBXBuildFile; fileRef = FF13FFEA0A5DA44A00897C81 /* dnsextd_lexer.l */; settings = {COMPILER_FLAGS = "-Wno-error"; }; };
- D284BECC0ADD80A20027CCDF /* dnsextd_parser.y in Sources */ = {isa = PBXBuildFile; fileRef = FF13FFEC0A5DA45500897C81 /* dnsextd_parser.y */; };
- D284BECD0ADD80A20027CCDF /* PlatformCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FFCB6D73075D539900B8AF62 /* PlatformCommon.c */; };
- D284BECF0ADD80A20027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
- D284BED00ADD80A20027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
- D284BED10ADD80A20027CCDF /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; };
- D284BED20ADD80A20027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
- D284BED50ADD80A20027CCDF /* dnsextd.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FFF4F63A06CFE4DD00459EFD /* dnsextd.8 */; };
- D284BEDE0ADD80A70027CCDF /* ddnswriteconfig.m in Sources */ = {isa = PBXBuildFile; fileRef = FFFB0DAF07B43CBA00B88D48 /* ddnswriteconfig.m */; };
- D284BEE00ADD80A70027CCDF /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FFFB0DB407B43D2700B88D48 /* Foundation.framework */; };
- D284BEE10ADD80A70027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
- D284BEE20ADD80A70027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
- D284BEE30ADD80A70027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
- D284BEEF0ADD80B00027CCDF /* remove_idle.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2407B4464B00CE10E5 /* remove_idle.tiff */; };
- D284BEF00ADD80B00027CCDF /* add_pressed.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2507B4464B00CE10E5 /* add_pressed.tiff */; };
- D284BEF10ADD80B00027CCDF /* remove_disabled.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2607B4464B00CE10E5 /* remove_disabled.tiff */; };
- D284BEF20ADD80B00027CCDF /* add_idle.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2707B4464B00CE10E5 /* add_idle.tiff */; };
- D284BEF30ADD80B00027CCDF /* success.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2807B4464B00CE10E5 /* success.tiff */; };
- D284BEF40ADD80B00027CCDF /* remove_pressed.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2907B4464B00CE10E5 /* remove_pressed.tiff */; };
- D284BEF50ADD80B00027CCDF /* failure.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2A07B4464B00CE10E5 /* failure.tiff */; };
- D284BEF60ADD80B00027CCDF /* BonjourPref.icns in Resources */ = {isa = PBXBuildFile; fileRef = FF260A3207B4466900CE10E5 /* BonjourPref.icns */; };
- D284BEF70ADD80B00027CCDF /* BonjourPref.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A3307B4466900CE10E5 /* BonjourPref.tiff */; };
- D284BEF80ADD80B00027CCDF /* DNSServiceDiscoveryPref.nib in Resources */ = {isa = PBXBuildFile; fileRef = FF260A4807B4475600CE10E5 /* DNSServiceDiscoveryPref.nib */; };
- D284BEF90ADD80B00027CCDF /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FF260A4B07B4477F00CE10E5 /* InfoPlist.strings */; };
- D284BEFB0ADD80B00027CCDF /* inprogress.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF08480607CEB8E800AE6769 /* inprogress.tiff */; };
- D284BEFC0ADD80B00027CCDF /* installtool in Resources */ = {isa = PBXBuildFile; fileRef = FF354EB108516C63007C00E1 /* installtool */; };
- D284BEFE0ADD80B00027CCDF /* DNSServiceDiscoveryPref.m in Sources */ = {isa = PBXBuildFile; fileRef = FFFB0DAC07B43CBA00B88D48 /* DNSServiceDiscoveryPref.m */; };
- D284BEFF0ADD80B00027CCDF /* PrivilegedOperations.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFB0DAD07B43CBA00B88D48 /* PrivilegedOperations.c */; };
- D284BF000ADD80B00027CCDF /* ConfigurationAuthority.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFB0DAE07B43CBA00B88D48 /* ConfigurationAuthority.c */; };
- D284BF020ADD80B00027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
- D284BF030ADD80B00027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
- D284BF040ADD80B00027CCDF /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF2609FA07B4433800CE10E5 /* Cocoa.framework */; };
- D284BF050ADD80B00027CCDF /* PreferencePanes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */; };
- D284BF060ADD80B00027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
- FFA572330AF18F1C0055A0F1 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
- FFA572340AF18F1C0055A0F1 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; };
- FFA572350AF18F1C0055A0F1 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; };
- FFA5723F0AF18F450055A0F1 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
- FFA572400AF18F450055A0F1 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; };
- FFA572410AF18F450055A0F1 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; };
- FFA572490AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; };
- FFA5724A0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; };
- FFA5724B0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; };
- FFAE66F0105F0CD900162116 /* ddnswriteconfig in Resources */ = {isa = PBXBuildFile; fileRef = D284BEE80ADD80A70027CCDF /* ddnswriteconfig */; };
- FFB437150EB165BD00E17C68 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; };
- FFC22AA20B00F42A00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; };
- FFC22AA30B00F42B00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; };
- FFC22AA40B00F42C00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; };
- FFC22AA50B00F43000BAB070 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; };
- FFC22AA60B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; };
- FFC22AA70B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; };
- FFF589B70E37F66800EF515C /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; };
- FFF589C10E37F67E00EF515C /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; };
- FFFA38630AEEDB090065B80A /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; };
- FFFA38650AEEDB130065B80A /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; };
- FFFA38660AEEDB2B0065B80A /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
- FFFF8F810C3307C400722979 /* dnsextd.conf in CopyFiles */ = {isa = PBXBuildFile; fileRef = FFFF8F800C3307AC00722979 /* dnsextd.conf */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXBuildRule section */
- D284BF750ADD850C0027CCDF /* PBXBuildRule */ = {
- isa = PBXBuildRule;
- compilerSpec = com.apple.compilers.proxy.script;
- fileType = sourcecode.yacc;
- isEditable = 1;
- outputFiles = (
- "$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).h",
- "$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).c",
- );
- script = "echo NOOP yacc ${INPUT_FILE_PATH}";
- };
- D284BFB80ADD8E510027CCDF /* PBXBuildRule */ = {
- isa = PBXBuildRule;
- compilerSpec = com.apple.compilers.proxy.script;
- fileType = sourcecode.lex;
- isEditable = 1;
- outputFiles = (
- "$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).c",
- );
- script = "/usr/bin/flex -i -o${DERIVED_FILE_DIR}/${INPUT_FILE_BASE}.c ${INPUT_FILE_PATH}";
- };
-/* End PBXBuildRule section */
-
-/* Begin PBXContainerItemProxy section */
- 03067D670C83A3830022BE1F /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = D284BE500ADD80740027CCDF;
- remoteInfo = mDNSResponder;
- };
- 03067D690C83A3890022BE1F /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = D284BE750ADD80800027CCDF;
- remoteInfo = "mDNSResponder debug";
- };
- 03067D6B0C83A3920022BE1F /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = D284BEA50ADD80920027CCDF;
- remoteInfo = "dns-sd tool";
- };
- 03067D6D0C83A39C0022BE1F /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 2E0405EF0C31955500F13B59;
- remoteInfo = mDNSResponderHelper;
- };
- 03067D850C849CC30022BE1F /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 03067D640C83A3700022BE1F;
- remoteInfo = "Build Some";
- };
- 2130257012400E9300AC839F /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = FFA572650AF190F10055A0F1;
- remoteInfo = SystemLibrariesDynamic;
- };
- 2141DCFC123FFB7D0086D23E /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 2141DCF8123FFB5D0086D23E;
- remoteInfo = SystemLibraries;
- };
- 2141DD0D123FFC960086D23E /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 2141DD0B123FFC7F0086D23E;
- remoteInfo = SystemLibrariesStatic;
- };
- 215FFB18124002C100470DE1 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 2141DD1C123FFCDB0086D23E;
- remoteInfo = libdns_sd_static;
- };
- 215FFB1A124002C700470DE1 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 2141DD23123FFD0F0086D23E;
- remoteInfo = libdns_sd_debug_static;
- };
- 215FFB1C124002CC00470DE1 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 2141DD29123FFD2C0086D23E;
- remoteInfo = libdns_sd_profile_static;
- };
- 217A4C48138EE14C000A5BA8 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 213FB21712028A7A002B3A08;
- remoteInfo = BonjourEvents;
- };
- 4AE471690EAFF83800A6C5AD /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 4AE471670EAFF81900A6C5AD;
- remoteInfo = dns_sd.jar;
- };
- 72FB5469166D5FE40090B2D9 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 72FB545E166D5FB00090B2D9;
- remoteInfo = dnsctl;
- };
- 84C5B3401665544B00C324A8 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 84C5B3341665529800C324A8;
- remoteInfo = dns_services;
- };
- D284BF2B0ADD815A0027CCDF /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = D284BEBF0ADD80A20027CCDF;
- remoteInfo = dnsextd;
- };
- D284BF2D0ADD81600027CCDF /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = D284BEDB0ADD80A70027CCDF;
- remoteInfo = ddnswriteconfig;
- };
- D284BF2F0ADD81630027CCDF /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = D284BEEA0ADD80B00027CCDF;
- remoteInfo = PreferencePane;
- };
- FFA572680AF190FF0055A0F1 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = FFB765830AEED9C700583A2C;
- remoteInfo = libdns_sd;
- };
- FFA5726A0AF191010055A0F1 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = FFA572300AF18F1C0055A0F1;
- remoteInfo = "libdns_sd debug";
- };
- FFA5726C0AF191020055A0F1 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = FFA5723C0AF18F450055A0F1;
- remoteInfo = "libdns_sd profile";
- };
- FFAE66F8105F0CF100162116 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = D284BEDB0ADD80A70027CCDF;
- remoteInfo = ddnswriteconfig;
- };
- FFB7657C0AEED97F00583A2C /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 00AD62BB032D7A0C0CCA2C71;
- remoteInfo = "Build Main";
- };
-/* End PBXContainerItemProxy section */
-
-/* Begin PBXCopyFilesBuildPhase section */
- 4A7B9E7F14FDA21B00B84CC1 /* CopyFiles */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 8;
- dstPath = /usr/local/OpenSourceVersions;
- dstSubfolderSpec = 0;
- files = (
- 4A7B9E8014FDA25000B84CC1 /* mDNSResponder.plist in CopyFiles */,
- );
- runOnlyForDeploymentPostprocessing = 1;
- };
- 4A7B9E8114FDA25500B84CC1 /* CopyFiles */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 8;
- dstPath = /usr/local/OpenSourceLicenses;
- dstSubfolderSpec = 0;
- files = (
- 4A7B9E8214FDA26C00B84CC1 /* mDNSResponder.txt in CopyFiles */,
- );
- runOnlyForDeploymentPostprocessing = 1;
- };
- 4AAE0C5A0C68E6EC003882A5 /* CopyFiles */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 8;
- dstPath = /usr/share/man/man8;
- dstSubfolderSpec = 0;
- files = (
- 4AAE0C9A0C68EA81003882A5 /* mDNSResponderHelper.8 in CopyFiles */,
- );
- runOnlyForDeploymentPostprocessing = 1;
- };
- 72FB545D166D5FB00090B2D9 /* CopyFiles */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 12;
- dstPath = /usr/share/man/man1/;
- dstSubfolderSpec = 0;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 8418673D15AB8BFF00BB7F70 /* CopyFiles */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 8;
- dstPath = /private/etc/asl/;
- dstSubfolderSpec = 0;
- files = (
- 8418673E15AB8C2D00BB7F70 /* com.apple.networking.mDNSResponder in CopyFiles */,
- );
- runOnlyForDeploymentPostprocessing = 1;
- };
- D284BE6A0ADD80740027CCDF /* CopyFiles */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 8;
- dstPath = /usr/share/man/man8;
- dstSubfolderSpec = 0;
- files = (
- D284BE6B0ADD80740027CCDF /* mDNSResponder.8 in CopyFiles */,
- );
- runOnlyForDeploymentPostprocessing = 1;
- };
- D284BEAB0ADD80920027CCDF /* CopyFiles */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 8;
- dstPath = /usr/share/man/man1;
- dstSubfolderSpec = 0;
- files = (
- D284BEAC0ADD80920027CCDF /* dns-sd.1 in CopyFiles */,
- );
- runOnlyForDeploymentPostprocessing = 1;
- };
- D284BED40ADD80A20027CCDF /* CopyFiles */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 8;
- dstPath = /usr/share/man/man8;
- dstSubfolderSpec = 0;
- files = (
- D284BED50ADD80A20027CCDF /* dnsextd.8 in CopyFiles */,
- );
- runOnlyForDeploymentPostprocessing = 1;
- };
- FFFF8F770C32F0FD00722979 /* CopyFiles */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 8;
- dstPath = /private/etc;
- dstSubfolderSpec = 0;
- files = (
- FFFF8F810C3307C400722979 /* dnsextd.conf in CopyFiles */,
- );
- runOnlyForDeploymentPostprocessing = 1;
- };
-/* End PBXCopyFilesBuildPhase section */
-
-/* Begin PBXFileReference section */
- 000753D303367C1C0CCA2C71 /* mDNSMacOSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mDNSMacOSX.h; sourceTree = "<group>"; };
- 00CA213D02786FC30CCA2C71 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = "<absolute>"; };
- 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
- 21070E5D16486B9000A69507 /* DNSSECSupport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = DNSSECSupport.c; sourceTree = "<group>"; };
- 21070E5E16486B9000A69507 /* DNSSECSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNSSECSupport.h; sourceTree = "<group>"; };
- 2120ABD416B71614007089B6 /* CUPolicy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CUPolicy.c; sourceTree = "<group>"; };
- 2124FA2B1471E98C0021D7BB /* nsec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nsec.h; path = ../mDNSCore/nsec.h; sourceTree = "<group>"; };
- 2124FA2F1471E9B50021D7BB /* dnssec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dnssec.h; path = ../mDNSCore/dnssec.h; sourceTree = "<group>"; };
- 2124FA321471E9DE0021D7BB /* nsec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = nsec.c; path = ../mDNSCore/nsec.c; sourceTree = "<group>"; };
- 2127A47515C3C7B900A857FC /* nsec3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = nsec3.c; path = ../mDNSCore/nsec3.c; sourceTree = "<group>"; };
- 2127A47615C3C7B900A857FC /* nsec3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nsec3.h; path = ../mDNSCore/nsec3.h; sourceTree = "<group>"; };
- 213BDC6C147319F400000896 /* dnssec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssec.c; path = ../mDNSCore/dnssec.c; sourceTree = "<group>"; };
- 213FB21812028A7A002B3A08 /* BonjourEvents.plugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BonjourEvents.plugin; sourceTree = BUILT_PRODUCTS_DIR; };
- 213FB22C12028B53002B3A08 /* BonjourEvents.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = BonjourEvents.c; sourceTree = "<group>"; };
- 213FB22D12028B53002B3A08 /* BonjourEvents-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "BonjourEvents-Info.plist"; sourceTree = "<group>"; };
- 2141DD1D123FFCDB0086D23E /* libdns_sd.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdns_sd.a; sourceTree = BUILT_PRODUCTS_DIR; };
- 2141DD24123FFD0F0086D23E /* libdns_sd_debug.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdns_sd_debug.a; sourceTree = BUILT_PRODUCTS_DIR; };
- 2141DD2A123FFD2C0086D23E /* libdns_sd_profile.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdns_sd_profile.a; sourceTree = BUILT_PRODUCTS_DIR; };
- 216D9ACD1720C9F5008066E1 /* VPNService.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = VPNService.c; sourceTree = "<group>"; };
- 218E8E4F156D8C0300720DA0 /* dnsproxy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnsproxy.c; path = ../mDNSCore/dnsproxy.c; sourceTree = "<group>"; };
- 218E8E50156D8C0300720DA0 /* dnsproxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dnsproxy.h; path = ../mDNSCore/dnsproxy.h; sourceTree = "<group>"; };
- 219D5541149ED645004464AE /* libxml2.2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxml2.2.dylib; path = SDKs/MacOSX10.8.sdk/usr/lib/libxml2.2.dylib; sourceTree = DEVELOPER_DIR; };
- 21A57F4A145B2AE100939099 /* CryptoAlg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = CryptoAlg.c; path = ../mDNSCore/CryptoAlg.c; sourceTree = "<group>"; };
- 21A57F4B145B2AE100939099 /* CryptoAlg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CryptoAlg.h; path = ../mDNSCore/CryptoAlg.h; sourceTree = "<group>"; };
- 21A57F51145B2B1400939099 /* CryptoSupport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CryptoSupport.c; sourceTree = "<group>"; };
- 21A57F52145B2B1400939099 /* CryptoSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoSupport.h; sourceTree = "<group>"; };
- 21DD8FBD161E9A250033C8F8 /* anonymous.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = anonymous.c; path = ../mDNSCore/anonymous.c; sourceTree = "<group>"; };
- 21DD8FBE161E9A250033C8F8 /* anonymous.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = anonymous.h; path = ../mDNSCore/anonymous.h; sourceTree = "<group>"; };
- 21DED43415702C0F0060B6B9 /* DNSProxySupport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = DNSProxySupport.c; sourceTree = "<group>"; };
- 21F432971134AA6800581B69 /* WebFilterDNS.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebFilterDNS.framework; path = /System/Library/PrivateFrameworks/WebFilterDNS.framework; sourceTree = "<absolute>"; };
- 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.mig; path = helpermsg.defs; sourceTree = "<group>"; };
- 2E0405F00C31955500F13B59 /* mDNSResponderHelper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSResponderHelper; sourceTree = BUILT_PRODUCTS_DIR; };
- 2E0405F40C3195F700F13B59 /* helper.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = helper.c; sourceTree = "<group>"; };
- 2E0406140C3197CB00F13B59 /* libbsm.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbsm.dylib; path = /usr/lib/libbsm.dylib; sourceTree = "<absolute>"; };
- 2E0406CA0C31E9AD00F13B59 /* helper-main.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = "helper-main.c"; sourceTree = "<group>"; };
- 2E35528F0C3A95C100CA1CB7 /* helper-error.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "helper-error.h"; sourceTree = "<group>"; };
- 2E8165F60C59835F00485EB2 /* libipsec.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libipsec.dylib; path = /usr/lib/libipsec.dylib; sourceTree = "<absolute>"; };
- 2E96A5250C39BE480087C4D2 /* helper.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = helper.h; sourceTree = "<group>"; };
- 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "helper-stubs.c"; sourceTree = "<group>"; };
- 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "helpermsg-types.h"; sourceTree = "<group>"; };
- 2EDC5E720C39EA640092701B /* helper-server.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "helper-server.h"; sourceTree = "<group>"; };
- 4A2E69DD0F5475A3004A87B0 /* uds_daemon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = uds_daemon.h; path = ../mDNSShared/uds_daemon.h; sourceTree = SOURCE_ROOT; };
- 4A3600DF0F34F8CD00453EFB /* DeviceToDeviceManager.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DeviceToDeviceManager.framework; path = /System/Library/PrivateFrameworks/DeviceToDeviceManager.framework; sourceTree = "<absolute>"; };
- 4A7B9E7C14FDA19F00B84CC1 /* mDNSResponder.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = mDNSResponder.txt; sourceTree = "<group>"; };
- 4A7B9E7E14FDA1BB00B84CC1 /* mDNSResponder.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = mDNSResponder.plist; sourceTree = "<group>"; };
- 4A8202510C56C36500DDFD48 /* ipsec_strerror.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ipsec_strerror.h; sourceTree = "<group>"; };
- 4A8202520C56C36500DDFD48 /* libpfkey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libpfkey.h; sourceTree = "<group>"; };
- 4A8202530C56C36600DDFD48 /* pfkey.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pfkey.c; sourceTree = "<group>"; };
- 4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mDNSResponderHelper.8; sourceTree = SOURCE_ROOT; };
- 4ADB5F230F6AB9F400B95BF3 /* helper-entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "helper-entitlements.plist"; sourceTree = "<group>"; };
- 4BD2B638134FE09F002B96D5 /* P2PPacketFilter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = P2PPacketFilter.c; sourceTree = "<group>"; };
- 4BD2B639134FE09F002B96D5 /* P2PPacketFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = P2PPacketFilter.h; sourceTree = "<group>"; };
- 654BE64F02B63B93000001D1 /* mDNSEmbeddedAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mDNSEmbeddedAPI.h; path = ../mDNSCore/mDNSEmbeddedAPI.h; sourceTree = "<group>"; };
- 654BE65002B63B93000001D1 /* mDNSDebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mDNSDebug.h; path = ../mDNSCore/mDNSDebug.h; sourceTree = "<group>"; };
- 65713D46025A293200000109 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = /System/Library/Frameworks/SystemConfiguration.framework; sourceTree = "<absolute>"; };
- 6575FBE9022EAF5A00000109 /* mDNS.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = mDNS.c; path = ../mDNSCore/mDNS.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
- 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = mDNSMacOSX.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
- 6575FBEC022EAF7200000109 /* daemon.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = daemon.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
- 6575FBFF022EAFBA00000109 /* DNSServiceDiscoveryDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNSServiceDiscoveryDefines.h; sourceTree = "<group>"; };
- 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; path = DNSServiceDiscoveryReply.defs; sourceTree = "<group>"; };
- 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; path = DNSServiceDiscoveryRequest.defs; sourceTree = "<group>"; };
- 6575FC20022EB7AA00000109 /* SamplemDNSClient.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = SamplemDNSClient.c; sourceTree = SOURCE_ROOT; tabWidth = 4; usesTabs = 0; };
- 72FB545A166D5F960090B2D9 /* dnsctl.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dnsctl.c; path = ../Clients/dnsctl.c; sourceTree = "<group>"; };
- 72FB545F166D5FB00090B2D9 /* dnsctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dnsctl; sourceTree = BUILT_PRODUCTS_DIR; };
- 7F18A9F60587CEF6001880B3 /* DNSCommon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = DNSCommon.c; path = ../mDNSCore/DNSCommon.c; sourceTree = SOURCE_ROOT; };
- 7F18A9F70587CEF6001880B3 /* uDNS.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = uDNS.c; path = ../mDNSCore/uDNS.c; sourceTree = SOURCE_ROOT; };
- 7F461DB5062DBF2900672BF3 /* DNSDigest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = DNSDigest.c; path = ../mDNSCore/DNSDigest.c; sourceTree = SOURCE_ROOT; };
- 7F869685066EE02400D2A2DC /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = "<absolute>"; };
- 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = LegacyNATTraversal.c; sourceTree = SOURCE_ROOT; };
- 8418673A15AB8B6900BB7F70 /* com.apple.networking.mDNSResponder */ = {isa = PBXFileReference; lastKnownFileType = text; path = com.apple.networking.mDNSResponder; sourceTree = "<group>"; };
- 8418673C15AB8B8000BB7F70 /* mDNSResponderLogging.mobileconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = mDNSResponderLogging.mobileconfig; sourceTree = "<group>"; };
- 848DA5C6165477E000D2E8B4 /* xpc_services.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = xpc_services.c; path = Private/xpc_services.c; sourceTree = "<group>"; };
- 848DA5C9165477EB00D2E8B4 /* xpc_services.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = xpc_services.h; path = Private/xpc_services.h; sourceTree = "<group>"; };
- 848DA5D516547F7200D2E8B4 /* dns_xpc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dns_xpc.h; path = Private/dns_xpc.h; sourceTree = "<group>"; };
- 84C5B3351665529800C324A8 /* libdns_services.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libdns_services.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
- 84C5B338166553A000C324A8 /* dns_services.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dns_services.h; path = Private/dns_services.h; sourceTree = "<group>"; };
- 84C5B339166553AF00C324A8 /* dns_services.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dns_services.c; path = Private/dns_services.c; sourceTree = "<group>"; };
- D284BE730ADD80740027CCDF /* mDNSResponder */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSResponder; sourceTree = BUILT_PRODUCTS_DIR; };
- D284BE950ADD80800027CCDF /* mDNSResponder.debug */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSResponder.debug; sourceTree = BUILT_PRODUCTS_DIR; };
- D284BEB00ADD80920027CCDF /* dns-sd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "dns-sd"; sourceTree = BUILT_PRODUCTS_DIR; };
- D284BEBE0ADD809A0027CCDF /* libjdns_sd.jnilib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libjdns_sd.jnilib; sourceTree = BUILT_PRODUCTS_DIR; };
- D284BED90ADD80A20027CCDF /* dnsextd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dnsextd; sourceTree = BUILT_PRODUCTS_DIR; };
- D284BEE80ADD80A70027CCDF /* ddnswriteconfig */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ddnswriteconfig; sourceTree = BUILT_PRODUCTS_DIR; };
- D284BF0C0ADD80B00027CCDF /* Bonjour.prefPane */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Bonjour.prefPane; sourceTree = BUILT_PRODUCTS_DIR; };
- D284C04D0ADD95D30027CCDF /* Info-PreferencePane.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "Info-PreferencePane.plist"; path = "PreferencePane/Info-PreferencePane.plist"; sourceTree = "<group>"; };
- DB2CC4430662DD1100335AB3 /* BaseListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = BaseListener.java; path = ../mDNSShared/Java/BaseListener.java; sourceTree = SOURCE_ROOT; };
- DB2CC4440662DD1100335AB3 /* BrowseListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = BrowseListener.java; path = ../mDNSShared/Java/BrowseListener.java; sourceTree = SOURCE_ROOT; };
- DB2CC4450662DD1100335AB3 /* DNSRecord.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSRecord.java; path = ../mDNSShared/Java/DNSRecord.java; sourceTree = SOURCE_ROOT; };
- DB2CC4460662DD1100335AB3 /* DNSSD.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSD.java; path = ../mDNSShared/Java/DNSSD.java; sourceTree = SOURCE_ROOT; };
- DB2CC4470662DD1100335AB3 /* DNSSDException.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSDException.java; path = ../mDNSShared/Java/DNSSDException.java; sourceTree = SOURCE_ROOT; };
- DB2CC4480662DD1100335AB3 /* DNSSDRegistration.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSDRegistration.java; path = ../mDNSShared/Java/DNSSDRegistration.java; sourceTree = SOURCE_ROOT; };
- DB2CC4490662DD1100335AB3 /* DNSSDService.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSDService.java; path = ../mDNSShared/Java/DNSSDService.java; sourceTree = SOURCE_ROOT; };
- DB2CC44A0662DD1100335AB3 /* DomainListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DomainListener.java; path = ../mDNSShared/Java/DomainListener.java; sourceTree = SOURCE_ROOT; };
- DB2CC44B0662DD1100335AB3 /* JNISupport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = JNISupport.c; path = ../mDNSShared/Java/JNISupport.c; sourceTree = SOURCE_ROOT; };
- DB2CC44C0662DD1100335AB3 /* QueryListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = QueryListener.java; path = ../mDNSShared/Java/QueryListener.java; sourceTree = SOURCE_ROOT; };
- DB2CC44D0662DD1100335AB3 /* RegisterListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = RegisterListener.java; path = ../mDNSShared/Java/RegisterListener.java; sourceTree = SOURCE_ROOT; };
- DB2CC44E0662DD1100335AB3 /* ResolveListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = ResolveListener.java; path = ../mDNSShared/Java/ResolveListener.java; sourceTree = SOURCE_ROOT; };
- DB2CC44F0662DD1100335AB3 /* TXTRecord.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = TXTRecord.java; path = ../mDNSShared/Java/TXTRecord.java; sourceTree = SOURCE_ROOT; };
- DB2CC4680662DFF500335AB3 /* JavaVM.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaVM.framework; path = /System/Library/Frameworks/JavaVM.framework; sourceTree = "<absolute>"; };
- DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mDNSDebug.c; path = ../mDNSShared/mDNSDebug.c; sourceTree = SOURCE_ROOT; };
- DBAAFE2C057E8F660085CAD0 /* GenLinkedList.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = GenLinkedList.c; path = ../mDNSShared/GenLinkedList.c; sourceTree = SOURCE_ROOT; };
- F525E72804AA167501F1CF4D /* uds_daemon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = uds_daemon.c; path = ../mDNSShared/uds_daemon.c; sourceTree = SOURCE_ROOT; };
- F5E11B5A04A28126019798ED /* dnssd_ipc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssd_ipc.c; path = ../mDNSShared/dnssd_ipc.c; sourceTree = SOURCE_ROOT; };
- F5E11B5B04A28126019798ED /* dnssd_ipc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dnssd_ipc.h; path = ../mDNSShared/dnssd_ipc.h; sourceTree = SOURCE_ROOT; };
- FF08480607CEB8E800AE6769 /* inprogress.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = inprogress.tiff; path = PreferencePane/Artwork/inprogress.tiff; sourceTree = SOURCE_ROOT; };
- FF13FFEA0A5DA44A00897C81 /* dnsextd_lexer.l */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.lex; name = dnsextd_lexer.l; path = ../mDNSShared/dnsextd_lexer.l; sourceTree = SOURCE_ROOT; };
- FF13FFEC0A5DA45500897C81 /* dnsextd_parser.y */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.yacc; name = dnsextd_parser.y; path = ../mDNSShared/dnsextd_parser.y; sourceTree = SOURCE_ROOT; };
- FF1C919D07021D77001048AB /* dns-sd.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = "dns-sd.1"; path = "../mDNSShared/dns-sd.1"; sourceTree = SOURCE_ROOT; };
- FF1C919F07021E3F001048AB /* dns-sd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "dns-sd.c"; path = "../Clients/dns-sd.c"; sourceTree = SOURCE_ROOT; };
- FF25794606C9A8BF00376F7B /* dnsextd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnsextd.c; path = ../mDNSShared/dnsextd.c; sourceTree = SOURCE_ROOT; };
- FF2609FA07B4433800CE10E5 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
- FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PreferencePanes.framework; path = /System/Library/Frameworks/PreferencePanes.framework; sourceTree = "<absolute>"; };
- FF260A2407B4464B00CE10E5 /* remove_idle.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = remove_idle.tiff; path = PreferencePane/Artwork/remove_idle.tiff; sourceTree = SOURCE_ROOT; };
- FF260A2507B4464B00CE10E5 /* add_pressed.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = add_pressed.tiff; path = PreferencePane/Artwork/add_pressed.tiff; sourceTree = SOURCE_ROOT; };
- FF260A2607B4464B00CE10E5 /* remove_disabled.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = remove_disabled.tiff; path = PreferencePane/Artwork/remove_disabled.tiff; sourceTree = SOURCE_ROOT; };
- FF260A2707B4464B00CE10E5 /* add_idle.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = add_idle.tiff; path = PreferencePane/Artwork/add_idle.tiff; sourceTree = SOURCE_ROOT; };
- FF260A2807B4464B00CE10E5 /* success.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = success.tiff; path = PreferencePane/Artwork/success.tiff; sourceTree = SOURCE_ROOT; };
- FF260A2907B4464B00CE10E5 /* remove_pressed.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = remove_pressed.tiff; path = PreferencePane/Artwork/remove_pressed.tiff; sourceTree = SOURCE_ROOT; };
- FF260A2A07B4464B00CE10E5 /* failure.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = failure.tiff; path = PreferencePane/Artwork/failure.tiff; sourceTree = SOURCE_ROOT; };
- FF260A3207B4466900CE10E5 /* BonjourPref.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = BonjourPref.icns; path = PreferencePane/BonjourPref.icns; sourceTree = SOURCE_ROOT; };
- FF260A3307B4466900CE10E5 /* BonjourPref.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = BonjourPref.tiff; path = PreferencePane/BonjourPref.tiff; sourceTree = SOURCE_ROOT; };
- FF260A4907B4475600CE10E5 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib; sourceTree = SOURCE_ROOT; };
- FF260A4C07B4477F00CE10E5 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = PreferencePane/English.lproj/InfoPlist.strings; sourceTree = SOURCE_ROOT; };
- FF2C5FB00A48B8680066DA11 /* DNSSDRecordRegistrar.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSDRecordRegistrar.java; path = ../mDNSShared/Java/DNSSDRecordRegistrar.java; sourceTree = SOURCE_ROOT; };
- FF2C5FB20A48B86E0066DA11 /* RegisterRecordListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = RegisterRecordListener.java; path = ../mDNSShared/Java/RegisterRecordListener.java; sourceTree = SOURCE_ROOT; };
- FF354EB108516C63007C00E1 /* installtool */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; name = installtool; path = PreferencePane/installtool; sourceTree = SOURCE_ROOT; };
- FF485D5105632E0000130380 /* mDNSResponder.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = mDNSResponder.8; path = ../mDNSShared/mDNSResponder.8; sourceTree = SOURCE_ROOT; };
- FF5852100DD27BD300862BDF /* ClientCommon.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = ClientCommon.c; path = ../Clients/ClientCommon.c; sourceTree = SOURCE_ROOT; };
- FF85880B0BD599F40080D89F /* mDNSResponder.sb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mDNSResponder.sb; sourceTree = SOURCE_ROOT; };
- FFA572390AF18F1C0055A0F1 /* libsystem_dnssd_debug.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libsystem_dnssd_debug.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
- FFA572450AF18F450055A0F1 /* libsystem_dnssd_profile.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libsystem_dnssd_profile.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
- FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = DNSServiceDiscovery.c; sourceTree = "<group>"; };
- FFA572600AF1908D0055A0F1 /* DNSServiceDiscovery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNSServiceDiscovery.h; sourceTree = "<group>"; };
- FFA572630AF190C20055A0F1 /* dns_sd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dns_sd.h; path = ../mDNSShared/dns_sd.h; sourceTree = SOURCE_ROOT; };
- FFB765840AEED9C700583A2C /* libsystem_dnssd.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libsystem_dnssd.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
- FFCB6D73075D539900B8AF62 /* PlatformCommon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = PlatformCommon.c; path = ../mDNSShared/PlatformCommon.c; sourceTree = SOURCE_ROOT; };
- FFE6935007C2CA7F00283007 /* ConfigurationAuthority.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ConfigurationAuthority.h; path = PreferencePane/ConfigurationAuthority.h; sourceTree = SOURCE_ROOT; };
- FFE6935207C2CAA400283007 /* DNSServiceDiscoveryPref.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DNSServiceDiscoveryPref.h; path = PreferencePane/DNSServiceDiscoveryPref.h; sourceTree = SOURCE_ROOT; };
- FFE6935407C2CABD00283007 /* PrivilegedOperations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PrivilegedOperations.h; path = PreferencePane/PrivilegedOperations.h; sourceTree = SOURCE_ROOT; };
- FFF4F63A06CFE4DD00459EFD /* dnsextd.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = dnsextd.8; path = ../mDNSShared/dnsextd.8; sourceTree = SOURCE_ROOT; };
- FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssd_clientlib.c; path = ../mDNSShared/dnssd_clientlib.c; sourceTree = SOURCE_ROOT; };
- FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssd_clientstub.c; path = ../mDNSShared/dnssd_clientstub.c; sourceTree = SOURCE_ROOT; };
- FFFB0DAC07B43CBA00B88D48 /* DNSServiceDiscoveryPref.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNSServiceDiscoveryPref.m; sourceTree = "<group>"; };
- FFFB0DAD07B43CBA00B88D48 /* PrivilegedOperations.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = PrivilegedOperations.c; sourceTree = "<group>"; };
- FFFB0DAE07B43CBA00B88D48 /* ConfigurationAuthority.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ConfigurationAuthority.c; sourceTree = "<group>"; };
- FFFB0DAF07B43CBA00B88D48 /* ddnswriteconfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ddnswriteconfig.m; sourceTree = "<group>"; };
- FFFB0DB407B43D2700B88D48 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
- FFFF8F800C3307AC00722979 /* dnsextd.conf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = dnsextd.conf; path = ../mDNSShared/dnsextd.conf; sourceTree = SOURCE_ROOT; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
- 213FB21612028A7A002B3A08 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 213FB23D12028C5A002B3A08 /* CoreFoundation.framework in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 2141DD1B123FFCDB0086D23E /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 2141DD22123FFD0F0086D23E /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 2141DD28123FFD2C0086D23E /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 2E0405EE0C31955500F13B59 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- FFB437150EB165BD00E17C68 /* IOKit.framework in Frameworks */,
- 2E0406150C3197CB00F13B59 /* libbsm.dylib in Frameworks */,
- 2E04070A0C31EEEC00F13B59 /* CoreFoundation.framework in Frameworks */,
- 2E04070B0C31EEEC00F13B59 /* SystemConfiguration.framework in Frameworks */,
- 2E4D9B050C38C19500480551 /* Security.framework in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 72FB545C166D5FB00090B2D9 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 72FB5468166D5FD20090B2D9 /* libdns_services.dylib in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 84C5B3321665529800C324A8 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BE640ADD80740027CCDF /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D284BE650ADD80740027CCDF /* CoreFoundation.framework in Frameworks */,
- D284BE660ADD80740027CCDF /* SystemConfiguration.framework in Frameworks */,
- D284BE670ADD80740027CCDF /* IOKit.framework in Frameworks */,
- D284BE680ADD80740027CCDF /* Security.framework in Frameworks */,
- 219D5542149ED645004464AE /* libxml2.2.dylib in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BE8C0ADD80800027CCDF /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D284BE8D0ADD80800027CCDF /* CoreFoundation.framework in Frameworks */,
- D284BE8E0ADD80800027CCDF /* SystemConfiguration.framework in Frameworks */,
- D284BE8F0ADD80800027CCDF /* IOKit.framework in Frameworks */,
- D284BE900ADD80800027CCDF /* Security.framework in Frameworks */,
- 219D5543149ED645004464AE /* libxml2.2.dylib in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BEA90ADD80920027CCDF /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BEB80ADD809A0027CCDF /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D284BEB90ADD809A0027CCDF /* JavaVM.framework in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BECE0ADD80A20027CCDF /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D284BECF0ADD80A20027CCDF /* CoreFoundation.framework in Frameworks */,
- D284BED00ADD80A20027CCDF /* SystemConfiguration.framework in Frameworks */,
- D284BED10ADD80A20027CCDF /* IOKit.framework in Frameworks */,
- D284BED20ADD80A20027CCDF /* Security.framework in Frameworks */,
- 2E8165F90C59838100485EB2 /* libipsec.dylib in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BEDF0ADD80A70027CCDF /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D284BEE00ADD80A70027CCDF /* Foundation.framework in Frameworks */,
- D284BEE10ADD80A70027CCDF /* Security.framework in Frameworks */,
- D284BEE20ADD80A70027CCDF /* SystemConfiguration.framework in Frameworks */,
- D284BEE30ADD80A70027CCDF /* CoreFoundation.framework in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BF010ADD80B00027CCDF /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D284BF020ADD80B00027CCDF /* SystemConfiguration.framework in Frameworks */,
- D284BF030ADD80B00027CCDF /* Security.framework in Frameworks */,
- D284BF040ADD80B00027CCDF /* Cocoa.framework in Frameworks */,
- D284BF050ADD80B00027CCDF /* PreferencePanes.framework in Frameworks */,
- D284BF060ADD80B00027CCDF /* CoreFoundation.framework in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- FFA572360AF18F1C0055A0F1 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- FFA572420AF18F450055A0F1 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- FFB765820AEED9C700583A2C /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
- 08FB7794FE84155DC02AAC07 /* mDNSResponder */ = {
- isa = PBXGroup;
- children = (
- 08FB7795FE84155DC02AAC07 /* mDNS Server Sources */,
- 6575FC1F022EB78C00000109 /* Command-Line Clients */,
- 213FB20912028902002B3A08 /* Bonjour Events Plugin */,
- 6575FBFE022EAFA800000109 /* MIG files */,
- DB2CC4420662DCE500335AB3 /* Java Support */,
- FFFB0DA407B43BED00B88D48 /* PreferencePane */,
- 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
- 19C28FBDFE9D53C911CA2CBB /* Products */,
- );
- name = mDNSResponder;
- sourceTree = "<group>";
- };
- 08FB7795FE84155DC02AAC07 /* mDNS Server Sources */ = {
- isa = PBXGroup;
- children = (
- 216D9ACD1720C9F5008066E1 /* VPNService.c */,
- 2120ABD416B71614007089B6 /* CUPolicy.c */,
- 84C5B338166553A000C324A8 /* dns_services.h */,
- 72FB545A166D5F960090B2D9 /* dnsctl.c */,
- 84C5B339166553AF00C324A8 /* dns_services.c */,
- 848DA5D516547F7200D2E8B4 /* dns_xpc.h */,
- 848DA5C9165477EB00D2E8B4 /* xpc_services.h */,
- 848DA5C6165477E000D2E8B4 /* xpc_services.c */,
- 21070E5D16486B9000A69507 /* DNSSECSupport.c */,
- 21070E5E16486B9000A69507 /* DNSSECSupport.h */,
- 21DD8FBD161E9A250033C8F8 /* anonymous.c */,
- 21DD8FBE161E9A250033C8F8 /* anonymous.h */,
- 2127A47515C3C7B900A857FC /* nsec3.c */,
- 2127A47615C3C7B900A857FC /* nsec3.h */,
- 8418673C15AB8B8000BB7F70 /* mDNSResponderLogging.mobileconfig */,
- 8418673A15AB8B6900BB7F70 /* com.apple.networking.mDNSResponder */,
- 21DED43415702C0F0060B6B9 /* DNSProxySupport.c */,
- 218E8E4F156D8C0300720DA0 /* dnsproxy.c */,
- 218E8E50156D8C0300720DA0 /* dnsproxy.h */,
- 213BDC6C147319F400000896 /* dnssec.c */,
- 2124FA321471E9DE0021D7BB /* nsec.c */,
- 2124FA2F1471E9B50021D7BB /* dnssec.h */,
- 2124FA2B1471E98C0021D7BB /* nsec.h */,
- 21A57F51145B2B1400939099 /* CryptoSupport.c */,
- 21A57F52145B2B1400939099 /* CryptoSupport.h */,
- 21A57F4A145B2AE100939099 /* CryptoAlg.c */,
- 21A57F4B145B2AE100939099 /* CryptoAlg.h */,
- 4ADB5F230F6AB9F400B95BF3 /* helper-entitlements.plist */,
- 4A2E69DD0F5475A3004A87B0 /* uds_daemon.h */,
- 4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */,
- 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */,
- 2E35528F0C3A95C100CA1CB7 /* helper-error.h */,
- 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */,
- 2EDC5E720C39EA640092701B /* helper-server.h */,
- 2E96A5250C39BE480087C4D2 /* helper.h */,
- 2E0405F40C3195F700F13B59 /* helper.c */,
- 2E0406CA0C31E9AD00F13B59 /* helper-main.c */,
- 4A8202510C56C36500DDFD48 /* ipsec_strerror.h */,
- 4A8202520C56C36500DDFD48 /* libpfkey.h */,
- 4A8202530C56C36600DDFD48 /* pfkey.c */,
- 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */,
- 7F461DB5062DBF2900672BF3 /* DNSDigest.c */,
- F525E72804AA167501F1CF4D /* uds_daemon.c */,
- F5E11B5A04A28126019798ED /* dnssd_ipc.c */,
- F5E11B5B04A28126019798ED /* dnssd_ipc.h */,
- 6575FBEC022EAF7200000109 /* daemon.c */,
- 6575FBE9022EAF5A00000109 /* mDNS.c */,
- 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */,
- 654BE64F02B63B93000001D1 /* mDNSEmbeddedAPI.h */,
- 654BE65002B63B93000001D1 /* mDNSDebug.h */,
- DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */,
- 000753D303367C1C0CCA2C71 /* mDNSMacOSX.h */,
- DBAAFE2C057E8F660085CAD0 /* GenLinkedList.c */,
- FFCB6D73075D539900B8AF62 /* PlatformCommon.c */,
- FF1C919D07021D77001048AB /* dns-sd.1 */,
- FF485D5105632E0000130380 /* mDNSResponder.8 */,
- FFF4F63A06CFE4DD00459EFD /* dnsextd.8 */,
- FFFF8F800C3307AC00722979 /* dnsextd.conf */,
- FF85880B0BD599F40080D89F /* mDNSResponder.sb */,
- 4A7B9E7C14FDA19F00B84CC1 /* mDNSResponder.txt */,
- 4A7B9E7E14FDA1BB00B84CC1 /* mDNSResponder.plist */,
- 7F18A9F60587CEF6001880B3 /* DNSCommon.c */,
- 7F18A9F70587CEF6001880B3 /* uDNS.c */,
- FF25794606C9A8BF00376F7B /* dnsextd.c */,
- FF13FFEA0A5DA44A00897C81 /* dnsextd_lexer.l */,
- FF13FFEC0A5DA45500897C81 /* dnsextd_parser.y */,
- FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */,
- FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */,
- FFA572600AF1908D0055A0F1 /* DNSServiceDiscovery.h */,
- FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */,
- FFA572630AF190C20055A0F1 /* dns_sd.h */,
- 4BD2B638134FE09F002B96D5 /* P2PPacketFilter.c */,
- 4BD2B639134FE09F002B96D5 /* P2PPacketFilter.h */,
- );
- name = "mDNS Server Sources";
- sourceTree = "<group>";
- };
- 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = {
- isa = PBXGroup;
- children = (
- 219D5541149ED645004464AE /* libxml2.2.dylib */,
- 4A3600DF0F34F8CD00453EFB /* DeviceToDeviceManager.framework */,
- 2E8165F60C59835F00485EB2 /* libipsec.dylib */,
- 65713D46025A293200000109 /* SystemConfiguration.framework */,
- 2E0406140C3197CB00F13B59 /* libbsm.dylib */,
- 7F869685066EE02400D2A2DC /* Security.framework */,
- FFFB0DB407B43D2700B88D48 /* Foundation.framework */,
- 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */,
- 00CA213D02786FC30CCA2C71 /* IOKit.framework */,
- DB2CC4680662DFF500335AB3 /* JavaVM.framework */,
- FF2609FA07B4433800CE10E5 /* Cocoa.framework */,
- FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */,
- 21F432971134AA6800581B69 /* WebFilterDNS.framework */,
- );
- name = "External Frameworks and Libraries";
- sourceTree = "<group>";
- };
- 19C28FBDFE9D53C911CA2CBB /* Products */ = {
- isa = PBXGroup;
- children = (
- D284C04D0ADD95D30027CCDF /* Info-PreferencePane.plist */,
- D284BE730ADD80740027CCDF /* mDNSResponder */,
- D284BE950ADD80800027CCDF /* mDNSResponder.debug */,
- D284BEB00ADD80920027CCDF /* dns-sd */,
- D284BEBE0ADD809A0027CCDF /* libjdns_sd.jnilib */,
- D284BED90ADD80A20027CCDF /* dnsextd */,
- D284BEE80ADD80A70027CCDF /* ddnswriteconfig */,
- D284BF0C0ADD80B00027CCDF /* Bonjour.prefPane */,
- FFB765840AEED9C700583A2C /* libsystem_dnssd.dylib */,
- FFA572390AF18F1C0055A0F1 /* libsystem_dnssd_debug.dylib */,
- FFA572450AF18F450055A0F1 /* libsystem_dnssd_profile.dylib */,
- 2E0405F00C31955500F13B59 /* mDNSResponderHelper */,
- 213FB21812028A7A002B3A08 /* BonjourEvents.plugin */,
- 2141DD1D123FFCDB0086D23E /* libdns_sd.a */,
- 2141DD24123FFD0F0086D23E /* libdns_sd_debug.a */,
- 2141DD2A123FFD2C0086D23E /* libdns_sd_profile.a */,
- 84C5B3351665529800C324A8 /* libdns_services.dylib */,
- 72FB545F166D5FB00090B2D9 /* dnsctl */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- 213FB20912028902002B3A08 /* Bonjour Events Plugin */ = {
- isa = PBXGroup;
- children = (
- 213FB22C12028B53002B3A08 /* BonjourEvents.c */,
- 213FB22D12028B53002B3A08 /* BonjourEvents-Info.plist */,
- );
- name = "Bonjour Events Plugin";
- sourceTree = "<group>";
- };
- 6575FBFE022EAFA800000109 /* MIG files */ = {
- isa = PBXGroup;
- children = (
- 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */,
- 6575FBFF022EAFBA00000109 /* DNSServiceDiscoveryDefines.h */,
- 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */,
- 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */,
- );
- name = "MIG files";
- sourceTree = "<group>";
- };
- 6575FC1F022EB78C00000109 /* Command-Line Clients */ = {
- isa = PBXGroup;
- children = (
- 6575FC20022EB7AA00000109 /* SamplemDNSClient.c */,
- FF1C919F07021E3F001048AB /* dns-sd.c */,
- FF5852100DD27BD300862BDF /* ClientCommon.c */,
- );
- name = "Command-Line Clients";
- sourceTree = "<group>";
- };
- DB2CC4420662DCE500335AB3 /* Java Support */ = {
- isa = PBXGroup;
- children = (
- DB2CC4430662DD1100335AB3 /* BaseListener.java */,
- DB2CC4440662DD1100335AB3 /* BrowseListener.java */,
- DB2CC4450662DD1100335AB3 /* DNSRecord.java */,
- DB2CC4460662DD1100335AB3 /* DNSSD.java */,
- DB2CC4470662DD1100335AB3 /* DNSSDException.java */,
- DB2CC4480662DD1100335AB3 /* DNSSDRegistration.java */,
- DB2CC4490662DD1100335AB3 /* DNSSDService.java */,
- DB2CC44A0662DD1100335AB3 /* DomainListener.java */,
- DB2CC44B0662DD1100335AB3 /* JNISupport.c */,
- DB2CC44C0662DD1100335AB3 /* QueryListener.java */,
- DB2CC44D0662DD1100335AB3 /* RegisterListener.java */,
- DB2CC44E0662DD1100335AB3 /* ResolveListener.java */,
- DB2CC44F0662DD1100335AB3 /* TXTRecord.java */,
- FF2C5FB00A48B8680066DA11 /* DNSSDRecordRegistrar.java */,
- FF2C5FB20A48B86E0066DA11 /* RegisterRecordListener.java */,
- );
- name = "Java Support";
- sourceTree = "<group>";
- };
- FF260A2307B4463400CE10E5 /* Resources */ = {
- isa = PBXGroup;
- children = (
- FF260A2407B4464B00CE10E5 /* remove_idle.tiff */,
- FF260A2507B4464B00CE10E5 /* add_pressed.tiff */,
- FF260A2607B4464B00CE10E5 /* remove_disabled.tiff */,
- FF260A2707B4464B00CE10E5 /* add_idle.tiff */,
- FF260A2907B4464B00CE10E5 /* remove_pressed.tiff */,
- FF260A2807B4464B00CE10E5 /* success.tiff */,
- FF08480607CEB8E800AE6769 /* inprogress.tiff */,
- FF260A2A07B4464B00CE10E5 /* failure.tiff */,
- FF260A3207B4466900CE10E5 /* BonjourPref.icns */,
- FF260A3307B4466900CE10E5 /* BonjourPref.tiff */,
- FF354EB108516C63007C00E1 /* installtool */,
- FF260A4807B4475600CE10E5 /* DNSServiceDiscoveryPref.nib */,
- FF260A4B07B4477F00CE10E5 /* InfoPlist.strings */,
- );
- name = Resources;
- sourceTree = "<group>";
- };
- FFFB0DA407B43BED00B88D48 /* PreferencePane */ = {
- isa = PBXGroup;
- children = (
- FFE6935007C2CA7F00283007 /* ConfigurationAuthority.h */,
- FFFB0DAE07B43CBA00B88D48 /* ConfigurationAuthority.c */,
- FFE6935207C2CAA400283007 /* DNSServiceDiscoveryPref.h */,
- FFFB0DAC07B43CBA00B88D48 /* DNSServiceDiscoveryPref.m */,
- FFE6935407C2CABD00283007 /* PrivilegedOperations.h */,
- FFFB0DAD07B43CBA00B88D48 /* PrivilegedOperations.c */,
- FFFB0DAF07B43CBA00B88D48 /* ddnswriteconfig.m */,
- FF260A2307B4463400CE10E5 /* Resources */,
- );
- path = PreferencePane;
- sourceTree = SOURCE_ROOT;
- };
-/* End PBXGroup section */
-
-/* Begin PBXHeadersBuildPhase section */
- 2141DD19123FFCDB0086D23E /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 2141DD20123FFD0F0086D23E /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 2141DD26123FFD2C0086D23E /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 2EC8F8ED0C39CCCA003C9C48 /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 2EC8F8EC0C39CCAC003C9C48 /* helper.h in Headers */,
- 2EDC5E730C39EA640092701B /* helper-server.h in Headers */,
- 2E3552920C3A95C100CA1CB7 /* helper-error.h in Headers */,
- 2ECC11A80C4FEC3800CB1885 /* helpermsg-types.h in Headers */,
- 2E8165E80C5980E300485EB2 /* libpfkey.h in Headers */,
- 2E8165EA0C5980F700485EB2 /* ipsec_strerror.h in Headers */,
- 4BD2B63B134FE09F002B96D5 /* P2PPacketFilter.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 84C5B3331665529800C324A8 /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 84C5B33D166553F900C324A8 /* dns_services.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BE520ADD80740027CCDF /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D284BE530ADD80740027CCDF /* DNSServiceDiscoveryDefines.h in Headers */,
- D284BE540ADD80740027CCDF /* dnssd_ipc.h in Headers */,
- 2E96A5260C39BE480087C4D2 /* helper.h in Headers */,
- 2EDC5E750C39EA640092701B /* helper-server.h in Headers */,
- 2E3552900C3A95C100CA1CB7 /* helper-error.h in Headers */,
- 2ECC11A60C4FEC3800CB1885 /* helpermsg-types.h in Headers */,
- 21A57F4E145B2AE100939099 /* CryptoAlg.h in Headers */,
- 21A57F55145B2B1400939099 /* CryptoSupport.h in Headers */,
- 2124FA2C1471E98C0021D7BB /* nsec.h in Headers */,
- 2124FA301471E9B50021D7BB /* dnssec.h in Headers */,
- 218E8E53156D8C0300720DA0 /* dnsproxy.h in Headers */,
- 2127A47915C3C7B900A857FC /* nsec3.h in Headers */,
- 21DD8FC1161E9A250033C8F8 /* anonymous.h in Headers */,
- 21070E6116486B9000A69507 /* DNSSECSupport.h in Headers */,
- 848DA5CA165477EB00D2E8B4 /* xpc_services.h in Headers */,
- 848DA5D616547F7200D2E8B4 /* dns_xpc.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BE770ADD80800027CCDF /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D284BE780ADD80800027CCDF /* DNSServiceDiscoveryDefines.h in Headers */,
- D284BE790ADD80800027CCDF /* dnssd_ipc.h in Headers */,
- D284BE7A0ADD80800027CCDF /* mDNSEmbeddedAPI.h in Headers */,
- D284BE7B0ADD80800027CCDF /* mDNSDebug.h in Headers */,
- D284BE7C0ADD80800027CCDF /* mDNSMacOSX.h in Headers */,
- 2E96A5270C39BE480087C4D2 /* helper.h in Headers */,
- 2EDC5E740C39EA640092701B /* helper-server.h in Headers */,
- 2E3552910C3A95C100CA1CB7 /* helper-error.h in Headers */,
- 2ECC11A70C4FEC3800CB1885 /* helpermsg-types.h in Headers */,
- 21A57F4F145B2AE100939099 /* CryptoAlg.h in Headers */,
- 21A57F56145B2B1400939099 /* CryptoSupport.h in Headers */,
- 2124FA2D1471E98C0021D7BB /* nsec.h in Headers */,
- 2124FA311471E9B50021D7BB /* dnssec.h in Headers */,
- 218E8E54156D8C0300720DA0 /* dnsproxy.h in Headers */,
- 2127A47A15C3C7B900A857FC /* nsec3.h in Headers */,
- 21DD8FC2161E9A250033C8F8 /* anonymous.h in Headers */,
- 21070E6216486B9000A69507 /* DNSSECSupport.h in Headers */,
- 848DA5CB165477EB00D2E8B4 /* xpc_services.h in Headers */,
- 848DA5D716547F7200D2E8B4 /* dns_xpc.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BEA60ADD80920027CCDF /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BEB50ADD809A0027CCDF /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BEC20ADD80A20027CCDF /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 2E35529D0C3A9E7600CA1CB7 /* helper-error.h in Headers */,
- 2E35529F0C3A9E7600CA1CB7 /* helper.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BEDC0ADD80A70027CCDF /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BEED0ADD80B00027CCDF /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- FFA572310AF18F1C0055A0F1 /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- FFA5723D0AF18F450055A0F1 /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- FFB765800AEED9C700583A2C /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXHeadersBuildPhase section */
-
-/* Begin PBXLegacyTarget section */
- 4AE471670EAFF81900A6C5AD /* dns_sd.jar */ = {
- isa = PBXLegacyTarget;
- buildArgumentsString = "-f ${SRCROOT}/../mDNSPosix/Makefile OBJDIR=${CONFIGURATION_TEMP_DIR}/dns_sd.jar.build BUILDDIR=${BUILT_PRODUCTS_DIR} SHAREDDIR=${SRCROOT}/../mDNSShared os=x JavaForXcode_$(ACTION)";
- buildConfigurationList = 4AE471770EAFF84000A6C5AD /* Build configuration list for PBXLegacyTarget "dns_sd.jar" */;
- buildPhases = (
- );
- buildToolPath = /usr/bin/make;
- buildWorkingDirectory = "";
- comments = "Multiplatform .jar file that implements Java interface to DNS-SD";
- dependencies = (
- );
- name = dns_sd.jar;
- passBuildSettingsInEnvironment = 1;
- productName = dns_sd.jar;
- };
-/* End PBXLegacyTarget section */
-
-/* Begin PBXNativeTarget section */
- 213FB21712028A7A002B3A08 /* BonjourEvents */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 213FB21B12028A7C002B3A08 /* Build configuration list for PBXNativeTarget "BonjourEvents" */;
- buildPhases = (
- 213FB21412028A7A002B3A08 /* Resources */,
- 213FB21512028A7A002B3A08 /* Sources */,
- 213FB21612028A7A002B3A08 /* Frameworks */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = BonjourEvents;
- productName = BonjourEvents;
- productReference = 213FB21812028A7A002B3A08 /* BonjourEvents.plugin */;
- productType = "com.apple.product-type.bundle";
- };
- 2141DD1C123FFCDB0086D23E /* libdns_sd_static */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 2141DD1F123FFCF90086D23E /* Build configuration list for PBXNativeTarget "libdns_sd_static" */;
- buildPhases = (
- 2141DD19123FFCDB0086D23E /* Headers */,
- 2141DD1A123FFCDB0086D23E /* Sources */,
- 2141DD1B123FFCDB0086D23E /* Frameworks */,
- 2130256B12400DE600AC839F /* ShellScript */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = libdns_sd_static;
- productName = libdns_sd_static;
- productReference = 2141DD1D123FFCDB0086D23E /* libdns_sd.a */;
- productType = "com.apple.product-type.library.static";
- };
- 2141DD23123FFD0F0086D23E /* libdns_sd_debug_static */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 2141DD35123FFD3B0086D23E /* Build configuration list for PBXNativeTarget "libdns_sd_debug_static" */;
- buildPhases = (
- 2141DD20123FFD0F0086D23E /* Headers */,
- 2141DD21123FFD0F0086D23E /* Sources */,
- 2141DD22123FFD0F0086D23E /* Frameworks */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = libdns_sd_debug_static;
- productName = libdns_sd_debug_static;
- productReference = 2141DD24123FFD0F0086D23E /* libdns_sd_debug.a */;
- productType = "com.apple.product-type.library.static";
- };
- 2141DD29123FFD2C0086D23E /* libdns_sd_profile_static */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 2141DD36123FFD3B0086D23E /* Build configuration list for PBXNativeTarget "libdns_sd_profile_static" */;
- buildPhases = (
- 2141DD26123FFD2C0086D23E /* Headers */,
- 2141DD27123FFD2C0086D23E /* Sources */,
- 2141DD28123FFD2C0086D23E /* Frameworks */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = libdns_sd_profile_static;
- productName = libdns_sd_profile_static;
- productReference = 2141DD2A123FFD2C0086D23E /* libdns_sd_profile.a */;
- productType = "com.apple.product-type.library.static";
- };
- 2E0405EF0C31955500F13B59 /* mDNSResponderHelper */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 2E0405F30C31956600F13B59 /* Build configuration list for PBXNativeTarget "mDNSResponderHelper" */;
- buildPhases = (
- 030BBED60CE11EEC00472F0C /* ShellScript */,
- 2EC8F8ED0C39CCCA003C9C48 /* Headers */,
- 2E0405ED0C31955500F13B59 /* Sources */,
- 2E0405EE0C31955500F13B59 /* Frameworks */,
- 4AAE0C5A0C68E6EC003882A5 /* CopyFiles */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = mDNSResponderHelper;
- productName = mDNSResponderHelper;
- productReference = 2E0405F00C31955500F13B59 /* mDNSResponderHelper */;
- productType = "com.apple.product-type.tool";
- };
- 72FB545E166D5FB00090B2D9 /* dnsctl */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 72FB5465166D5FB00090B2D9 /* Build configuration list for PBXNativeTarget "dnsctl" */;
- buildPhases = (
- 72FB545B166D5FB00090B2D9 /* Sources */,
- 72FB545C166D5FB00090B2D9 /* Frameworks */,
- 72FB545D166D5FB00090B2D9 /* CopyFiles */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = dnsctl;
- productName = dnsctl;
- productReference = 72FB545F166D5FB00090B2D9 /* dnsctl */;
- productType = "com.apple.product-type.tool";
- };
- 84C5B3341665529800C324A8 /* dns_services */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 84C5B3361665529800C324A8 /* Build configuration list for PBXNativeTarget "dns_services" */;
- buildPhases = (
- 84C5B3311665529800C324A8 /* Sources */,
- 84C5B3321665529800C324A8 /* Frameworks */,
- 84C5B3331665529800C324A8 /* Headers */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = dns_services;
- productName = dns_services;
- productReference = 84C5B3351665529800C324A8 /* libdns_services.dylib */;
- productType = "com.apple.product-type.library.dynamic";
- };
- D284BE500ADD80740027CCDF /* mDNSResponder */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = D284BE6D0ADD80740027CCDF /* Build configuration list for PBXNativeTarget "mDNSResponder" */;
- buildPhases = (
- D284BE510ADD80740027CCDF /* ShellScript */,
- D284BE520ADD80740027CCDF /* Headers */,
- D284BE550ADD80740027CCDF /* Sources */,
- D284BE640ADD80740027CCDF /* Frameworks */,
- D284BE690ADD80740027CCDF /* Rez */,
- D284BE6A0ADD80740027CCDF /* CopyFiles */,
- 4A7B9E7F14FDA21B00B84CC1 /* CopyFiles */,
- 4A7B9E8114FDA25500B84CC1 /* CopyFiles */,
- D284BE6C0ADD80740027CCDF /* ShellScript */,
- 8418673D15AB8BFF00BB7F70 /* CopyFiles */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = mDNSResponder;
- productInstallPath = "${HOME}/bin";
- productName = mDNSResponder;
- productReference = D284BE730ADD80740027CCDF /* mDNSResponder */;
- productType = "com.apple.product-type.tool";
- };
- D284BE750ADD80800027CCDF /* mDNSResponder debug */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = D284BE920ADD80800027CCDF /* Build configuration list for PBXNativeTarget "mDNSResponder debug" */;
- buildPhases = (
- D284BE760ADD80800027CCDF /* ShellScript */,
- D284BE770ADD80800027CCDF /* Headers */,
- D284BE7D0ADD80800027CCDF /* Sources */,
- D284BE8C0ADD80800027CCDF /* Frameworks */,
- D284BE910ADD80800027CCDF /* Rez */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = "mDNSResponder debug";
- productName = mDNSResponder;
- productReference = D284BE950ADD80800027CCDF /* mDNSResponder.debug */;
- productType = "com.apple.product-type.tool";
- };
- D284BEA50ADD80920027CCDF /* dns-sd tool */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = D284BEAD0ADD80920027CCDF /* Build configuration list for PBXNativeTarget "dns-sd tool" */;
- buildPhases = (
- D284BEA60ADD80920027CCDF /* Headers */,
- D284BEA70ADD80920027CCDF /* Sources */,
- D284BEA90ADD80920027CCDF /* Frameworks */,
- D284BEAA0ADD80920027CCDF /* Rez */,
- D284BEAB0ADD80920027CCDF /* CopyFiles */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = "dns-sd tool";
- productInstallPath = /usr/bin;
- productName = "dns-sd command-line tool";
- productReference = D284BEB00ADD80920027CCDF /* dns-sd */;
- productType = "com.apple.product-type.tool";
- };
- D284BEB20ADD809A0027CCDF /* libjdns_sd.jnilib */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = D284BEBB0ADD809A0027CCDF /* Build configuration list for PBXNativeTarget "libjdns_sd.jnilib" */;
- buildPhases = (
- D284BEB50ADD809A0027CCDF /* Headers */,
- D284BEB60ADD809A0027CCDF /* Sources */,
- D284BEB80ADD809A0027CCDF /* Frameworks */,
- D284BEBA0ADD809A0027CCDF /* Rez */,
- );
- buildRules = (
- );
- comments = "Platform-specific JNI library that bridges dns_sd.jar to <dns_sd.h>.";
- dependencies = (
- 4AE4716A0EAFF83800A6C5AD /* PBXTargetDependency */,
- );
- name = libjdns_sd.jnilib;
- productInstallPath = /usr/lib/java;
- productName = libjdns_sd.jnilib;
- productReference = D284BEBE0ADD809A0027CCDF /* libjdns_sd.jnilib */;
- productType = "com.apple.product-type.library.dynamic";
- };
- D284BEBF0ADD80A20027CCDF /* dnsextd */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = D284BED60ADD80A20027CCDF /* Build configuration list for PBXNativeTarget "dnsextd" */;
- buildPhases = (
- D284BEC20ADD80A20027CCDF /* Headers */,
- 4A4EE3A413CB8E82005C624B /* Build yacc file into derived source files */,
- D284BEC40ADD80A20027CCDF /* Sources */,
- D284BECE0ADD80A20027CCDF /* Frameworks */,
- D284BED40ADD80A20027CCDF /* CopyFiles */,
- FFFF8F770C32F0FD00722979 /* CopyFiles */,
- FF37FAAD0BC581780044A5CF /* ShellScript */,
- );
- buildRules = (
- D284BFB80ADD8E510027CCDF /* PBXBuildRule */,
- D284BF750ADD850C0027CCDF /* PBXBuildRule */,
- );
- dependencies = (
- );
- name = dnsextd;
- productInstallPath = /usr/sbin;
- productName = mDNSResponder;
- productReference = D284BED90ADD80A20027CCDF /* dnsextd */;
- productType = "com.apple.product-type.tool";
- };
- D284BEDB0ADD80A70027CCDF /* ddnswriteconfig */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = D284BEE50ADD80A70027CCDF /* Build configuration list for PBXNativeTarget "ddnswriteconfig" */;
- buildPhases = (
- D284BEDC0ADD80A70027CCDF /* Headers */,
- D284BEDD0ADD80A70027CCDF /* Sources */,
- D284BEDF0ADD80A70027CCDF /* Frameworks */,
- D284BEE40ADD80A70027CCDF /* Rez */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = ddnswriteconfig;
- productInstallPath = "/Library/Application Support/Bonjour";
- productName = ddnswriteconfig;
- productReference = D284BEE80ADD80A70027CCDF /* ddnswriteconfig */;
- productType = "com.apple.product-type.tool";
- };
- D284BEEA0ADD80B00027CCDF /* PreferencePane */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = D284BF080ADD80B00027CCDF /* Build configuration list for PBXNativeTarget "PreferencePane" */;
- buildPhases = (
- D284BEED0ADD80B00027CCDF /* Headers */,
- D284BEEE0ADD80B00027CCDF /* Resources */,
- D284BEFD0ADD80B00027CCDF /* Sources */,
- D284BF010ADD80B00027CCDF /* Frameworks */,
- D284BF070ADD80B00027CCDF /* Rez */,
- );
- buildRules = (
- );
- dependencies = (
- FFAE66F9105F0CF100162116 /* PBXTargetDependency */,
- );
- name = PreferencePane;
- productInstallPath = "${SYSTEM_LIBRARY_DIR}/PreferencePanes";
- productName = PreferencePane;
- productReference = D284BF0C0ADD80B00027CCDF /* Bonjour.prefPane */;
- productType = "com.apple.product-type.bundle";
- };
- FFA572300AF18F1C0055A0F1 /* libdns_sd_debug_dynamic */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = FFA572370AF18F1C0055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd_debug_dynamic" */;
- buildPhases = (
- FFA572310AF18F1C0055A0F1 /* Headers */,
- FFA572320AF18F1C0055A0F1 /* Sources */,
- FFA572360AF18F1C0055A0F1 /* Frameworks */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = libdns_sd_debug_dynamic;
- productName = libdns_sd.dylib;
- productReference = FFA572390AF18F1C0055A0F1 /* libsystem_dnssd_debug.dylib */;
- productType = "com.apple.product-type.library.dynamic";
- };
- FFA5723C0AF18F450055A0F1 /* libdns_sd_profile_dynamic */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = FFA572430AF18F450055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd_profile_dynamic" */;
- buildPhases = (
- FFA5723D0AF18F450055A0F1 /* Headers */,
- FFA5723E0AF18F450055A0F1 /* Sources */,
- FFA572420AF18F450055A0F1 /* Frameworks */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = libdns_sd_profile_dynamic;
- productName = libdns_sd.dylib;
- productReference = FFA572450AF18F450055A0F1 /* libsystem_dnssd_profile.dylib */;
- productType = "com.apple.product-type.library.dynamic";
- };
- FFB765830AEED9C700583A2C /* libdns_sd_dynamic */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = FFB765890AEED9FB00583A2C /* Build configuration list for PBXNativeTarget "libdns_sd_dynamic" */;
- buildPhases = (
- FFB765800AEED9C700583A2C /* Headers */,
- FFB765810AEED9C700583A2C /* Sources */,
- FFB765820AEED9C700583A2C /* Frameworks */,
- 21DE714D115831CB00DD4BD1 /* ShellScript */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = libdns_sd_dynamic;
- productName = libdns_sd.dylib;
- productReference = FFB765840AEED9C700583A2C /* libsystem_dnssd.dylib */;
- productType = "com.apple.product-type.library.dynamic";
- };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
- 08FB7793FE84155DC02AAC07 /* Project object */ = {
- isa = PBXProject;
- attributes = {
- };
- buildConfigurationList = D284BE2B0ADD78180027CCDF /* Build configuration list for PBXProject "mDNSResponder" */;
- compatibilityVersion = "Xcode 3.1";
- developmentRegion = English;
- hasScannedForEncodings = 1;
- knownRegions = (
- English,
- Japanese,
- French,
- German,
- );
- mainGroup = 08FB7794FE84155DC02AAC07 /* mDNSResponder */;
- projectDirPath = "";
- projectRoot = "";
- targets = (
- 00AD62BB032D7A0C0CCA2C71 /* Build More */,
- 03067D640C83A3700022BE1F /* Build Some */,
- FFB7657B0AEED96B00583A2C /* Build All */,
- D284BE500ADD80740027CCDF /* mDNSResponder */,
- D284BE750ADD80800027CCDF /* mDNSResponder debug */,
- 2E0405EF0C31955500F13B59 /* mDNSResponderHelper */,
- D284BEA50ADD80920027CCDF /* dns-sd tool */,
- 4AE471670EAFF81900A6C5AD /* dns_sd.jar */,
- D284BEB20ADD809A0027CCDF /* libjdns_sd.jnilib */,
- D284BEBF0ADD80A20027CCDF /* dnsextd */,
- D284BEDB0ADD80A70027CCDF /* ddnswriteconfig */,
- D284BEEA0ADD80B00027CCDF /* PreferencePane */,
- FFB765830AEED9C700583A2C /* libdns_sd_dynamic */,
- FFA572300AF18F1C0055A0F1 /* libdns_sd_debug_dynamic */,
- FFA5723C0AF18F450055A0F1 /* libdns_sd_profile_dynamic */,
- FFA572650AF190F10055A0F1 /* SystemLibrariesDynamic */,
- 213FB21712028A7A002B3A08 /* BonjourEvents */,
- 2141DCF8123FFB5D0086D23E /* SystemLibraries */,
- 2141DD0B123FFC7F0086D23E /* SystemLibrariesStatic */,
- 2141DD1C123FFCDB0086D23E /* libdns_sd_static */,
- 2141DD23123FFD0F0086D23E /* libdns_sd_debug_static */,
- 2141DD29123FFD2C0086D23E /* libdns_sd_profile_static */,
- 84C5B3341665529800C324A8 /* dns_services */,
- 72FB545E166D5FB00090B2D9 /* dnsctl */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
- 213FB21412028A7A002B3A08 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BEEE0ADD80B00027CCDF /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D284BEEF0ADD80B00027CCDF /* remove_idle.tiff in Resources */,
- D284BEF00ADD80B00027CCDF /* add_pressed.tiff in Resources */,
- D284BEF10ADD80B00027CCDF /* remove_disabled.tiff in Resources */,
- D284BEF20ADD80B00027CCDF /* add_idle.tiff in Resources */,
- D284BEF30ADD80B00027CCDF /* success.tiff in Resources */,
- D284BEF40ADD80B00027CCDF /* remove_pressed.tiff in Resources */,
- D284BEF50ADD80B00027CCDF /* failure.tiff in Resources */,
- D284BEF60ADD80B00027CCDF /* BonjourPref.icns in Resources */,
- D284BEF70ADD80B00027CCDF /* BonjourPref.tiff in Resources */,
- D284BEF80ADD80B00027CCDF /* DNSServiceDiscoveryPref.nib in Resources */,
- D284BEF90ADD80B00027CCDF /* InfoPlist.strings in Resources */,
- D284BEFB0ADD80B00027CCDF /* inprogress.tiff in Resources */,
- D284BEFC0ADD80B00027CCDF /* installtool in Resources */,
- FFAE66F0105F0CD900162116 /* ddnswriteconfig in Resources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXRezBuildPhase section */
- D284BE690ADD80740027CCDF /* Rez */ = {
- isa = PBXRezBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BE910ADD80800027CCDF /* Rez */ = {
- isa = PBXRezBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BEAA0ADD80920027CCDF /* Rez */ = {
- isa = PBXRezBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BEBA0ADD809A0027CCDF /* Rez */ = {
- isa = PBXRezBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BEE40ADD80A70027CCDF /* Rez */ = {
- isa = PBXRezBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BF070ADD80B00027CCDF /* Rez */ = {
- isa = PBXRezBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXRezBuildPhase section */
-
-/* Begin PBXShellScriptBuildPhase section */
- 030BBED60CE11EEC00472F0C /* ShellScript */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputPaths = (
- );
- outputPaths = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "if [ -e \"${SDKROOT}/usr/include/vproc.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nelse\ntouch \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/lib/libipsec.dylib\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libipsec.a\"\nelse\necho \"#define MDNS_NO_IPSEC 1\" > ${CONFIGURATION_TEMP_DIR}/ipsec_options.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libipsec.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n";
- };
- 1F7B473C12B82BFD00868AEF /* ShellScript */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputPaths = (
- );
- outputPaths = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/bash;
- shellScript = "# check if we're building for the simulator and patch the \"id\" of the library (as reported by otool -D) to\n# be just /usr/lib/system/libsystem_sim_dnssd.dylib etc. Also remove the usr directory as it is not needed\n# for simulator\nif [ \"${RC_ProjectName%_Sim}\" != \"${RC_ProjectName}\" ] ; then\n\tif [ -d ${DSTROOT}${SDKROOT}/usr/lib/system ] ; then\n\t\tfor lib in ${DSTROOT}${SDKROOT}/usr/lib/system/*.dylib ; do\n\t\t\tinstall_name_tool -id \"${lib#${DSTROOT}${SDKROOT}}\" \"${lib}\"\n\t\tdone\n\tfi\n\trm -rf $DSTROOT/usr\nfi\n";
- };
- 2130256B12400DE600AC839F /* ShellScript */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 8;
- files = (
- );
- inputPaths = (
- );
- outputPaths = (
- );
- runOnlyForDeploymentPostprocessing = 1;
- shellPath = /bin/sh;
- shellScript = "#if we are building for simulator, change the installation path\nif [ \"${RC_ProjectName%_Sim}\" != \"${RC_ProjectName}\" ] ; then\n\tDSTROOT=${DSTROOT}${SDKROOT}\nfi\nmkdir -p \"$DSTROOT/usr/include\"\nsed 's/\\(^#define _DNS_SD_LIBDISPATCH \\)0$/\\1 1/' \"$SRCROOT/../mDNSShared/dns_sd.h\" > \"$DSTROOT/usr/include/dns_sd.h\"";
- };
- 21DE714D115831CB00DD4BD1 /* ShellScript */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 8;
- files = (
- );
- inputPaths = (
- );
- outputPaths = (
- );
- runOnlyForDeploymentPostprocessing = 1;
- shellPath = /bin/sh;
- shellScript = "#if we are building for simulator, change the installation path\nif [ \"${RC_ProjectName%_Sim}\" != \"${RC_ProjectName}\" ] ; then\n\tDSTROOT=${DSTROOT}${SDKROOT}\nfi\nmkdir -p \"$DSTROOT/usr/include\"\nsed 's/\\(^#define _DNS_SD_LIBDISPATCH \\)0$/\\1 1/' \"$SRCROOT/../mDNSShared/dns_sd.h\" > \"$DSTROOT/usr/include/dns_sd.h\"";
- };
- 4A4EE3A413CB8E82005C624B /* Build yacc file into derived source files */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputPaths = (
- "$(SRCROOT)/../mDNSShared/dnsextd_parser.y",
- );
- name = "Build yacc file into derived source files";
- outputPaths = (
- "$(DERIVED_FILE_DIR)/dnsextd_parser.c",
- "$(DERIVED_FILE_DIR)/dnsextd_parser.h",
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "/usr/bin/bison -o ${SCRIPT_OUTPUT_FILE_0} -d ${SCRIPT_INPUT_FILE_0}";
- };
- D284BE510ADD80740027CCDF /* ShellScript */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "if [ -e \"${SDKROOT}/usr/local/include/dnsinfo.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/sandbox.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/vproc.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nelse\ntouch \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/Frameworks/IOKit.framework/PrivateHeaders/pwr_mgt/IOPMLibPrivate.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/IOKit\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt\"\ntouch \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt/IOPMLibPrivate.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/PrivateFrameworks/DeviceToDeviceManager.framework/Headers/DeviceToDeviceManager.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager\"\necho \"#define NO_D2D 1\" > \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager/DeviceToDeviceManager.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/PrivateFrameworks/WebFilterDNS.framework/Headers/WebFilterDNS.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS\"\necho \"#define NO_WCF 1\" > \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS/WebFilterDNS.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/local/include/AWACS.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/AWACS.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libAWACS.a\"\nelse\necho \"#define NO_AWACS 1\" > \"${CONFIGURATION_T!
EMP_DIR}/AWACS.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libAWACS.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\"\nfi\n";
- };
- D284BE6C0ADD80740027CCDF /* ShellScript */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 8;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 1;
- shellPath = /bin/bash;
- shellScript = "# Install mDNSResponder.bundle containing language localizations\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices\ncp -R ${SRCROOT}/mDNSResponder-bundle ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle\n\n# Remove unwanted CVS directories\nfind ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -depth -name CVS -exec rm -rf {} \\;\n\n# Expand UTF-8 files to UTF-16 (at one time this appeared to be necessary, but it's not, so we don't do it any more)\n#foreach file (`find ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -name Localizable.strings`)\n#iconv -f utf-8 -t utf-16 ${file} > ${file}.new\n#mv -f ${file}.new ${file}\n#end\n\n# Remove French localization (not wanted for Apple B&I builds)\nrm -rf ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle/Resources/French.lproj\n\n# Copy Sandbox profile\nif [ ! -z \"${IPHONEOS_DEPLOYMENT_TARGET}\" ] ; then\n SANDBOXDST=\"${DSTROOT}/usr/local/share/sandbox/profiles/embedded/builtin\"\nelse\n SANDBOXDST=\"${DSTROOT}/usr/share/sandbox\"\nfi\n(umask 022; mkdir -p -m 0755 \"$SANDBOXDST\")\ncp \"${SRCROOT}/mDNSResponder.sb\" \"${SANDBOXDST}/mDNSResponder.sb\"\n";
- };
- D284BE760ADD80800027CCDF /* ShellScript */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "if [ -e \"${SDKROOT}/usr/local/include/dnsinfo.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/sandbox.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/vproc.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nelse\ntouch \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/Frameworks/IOKit.framework/PrivateHeaders/pwr_mgt/IOPMLibPrivate.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/IOKit\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt\"\ntouch \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt/IOPMLibPrivate.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/PrivateFrameworks/DeviceToDeviceManager.framework/Headers/DeviceToDeviceManager.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager\"\necho \"#define NO_D2D 1\" > \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager/DeviceToDeviceManager.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/PrivateFrameworks/WebFilterDNS.framework/Headers/WebFilterDNS.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS\"\necho \"#define NO_WCF 1\" > \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS/WebFilterDNS.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/local/include/AWACS.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/AWACS.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libAWACS.a\"\nelse\necho \"#define NO_AWACS 1\" > \"${CONFIGURATION_T!
EMP_DIR}/AWACS.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libAWACS.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\"\nfi";
- };
- FF045B6A0C7E4AA600448140 /* ShellScript */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 8;
- files = (
- );
- inputPaths = (
- );
- outputPaths = (
- );
- runOnlyForDeploymentPostprocessing = 1;
- shellPath = /bin/sh;
- shellScript = "# Install plists to tell launchd how to start mDNSResponder and mDNSResponderHelper\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons\n\nif [ \"${MACOSX_DEPLOYMENT_TARGET}\" == \"10.4\" ] ; then\ncp ${SRCROOT}/LaunchDaemonInfo-Tiger.plist ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponder.plist\ncp ${SRCROOT}/LaunchDaemonInfo-Tiger.helper.plist ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponderHelper.plist\nelse\ncp ${SRCROOT}/LaunchDaemonInfo.plist ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponder.plist\ncp ${SRCROOT}/LaunchDaemonInfo.helper.plist ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponderHelper.plist\nfi\n\nif [ ! -z \"${IPHONEOS_DEPLOYMENT_TARGET}\" ] ; then\nplutil -convert binary1 ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponder.plist\nplutil -convert binary1 ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponderHelper.plist\nfi\n";
- };
- FF37FAAD0BC581780044A5CF /* ShellScript */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 8;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 1;
- shellPath = /bin/tcsh;
- shellScript = "# Install plist to tell launchd how to start dnsextd\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons\ncp ${SRCROOT}/LaunchDaemonInfo.dnsextd.plist ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.dnsextd.plist\n";
- };
-/* End PBXShellScriptBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
- 213FB21512028A7A002B3A08 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 213FB23C12028C4A002B3A08 /* BonjourEvents.c in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 2141DD1A123FFCDB0086D23E /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 215FFAEE124000F900470DE1 /* dnssd_ipc.c in Sources */,
- 215FFAEF124000F900470DE1 /* dnssd_clientlib.c in Sources */,
- 215FFAF0124000F900470DE1 /* dnssd_clientstub.c in Sources */,
- 215FFAF1124000F900470DE1 /* DNSServiceDiscovery.c in Sources */,
- 215FFAF2124000F900470DE1 /* DNSServiceDiscoveryRequest.defs in Sources */,
- 215FFAF3124000F900470DE1 /* DNSServiceDiscoveryReply.defs in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 2141DD21123FFD0F0086D23E /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 215FFAF41240011800470DE1 /* dnssd_ipc.c in Sources */,
- 215FFAF51240011800470DE1 /* dnssd_clientlib.c in Sources */,
- 215FFAF61240011800470DE1 /* dnssd_clientstub.c in Sources */,
- 215FFAF71240011800470DE1 /* DNSServiceDiscovery.c in Sources */,
- 215FFAF81240011800470DE1 /* DNSServiceDiscoveryRequest.defs in Sources */,
- 215FFAF91240011800470DE1 /* DNSServiceDiscoveryReply.defs in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 2141DD27123FFD2C0086D23E /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 215FFAFA1240013400470DE1 /* dnssd_ipc.c in Sources */,
- 215FFAFB1240013400470DE1 /* dnssd_clientlib.c in Sources */,
- 215FFAFC1240013400470DE1 /* dnssd_clientstub.c in Sources */,
- 215FFAFD1240013400470DE1 /* DNSServiceDiscovery.c in Sources */,
- 215FFAFE1240013400470DE1 /* DNSServiceDiscoveryRequest.defs in Sources */,
- 215FFAFF1240013400470DE1 /* DNSServiceDiscoveryReply.defs in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 2E0405ED0C31955500F13B59 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 2E0405F50C3195F700F13B59 /* helper.c in Sources */,
- 2E0405F60C31961100F13B59 /* helpermsg.defs in Sources */,
- 2E96A51D0C39BDAC0087C4D2 /* helper-main.c in Sources */,
- 2E8165E90C5980EE00485EB2 /* pfkey.c in Sources */,
- 4BD2B63A134FE09F002B96D5 /* P2PPacketFilter.c in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 72FB545B166D5FB00090B2D9 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 72FB5467166D5FCA0090B2D9 /* dnsctl.c in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 84C5B3311665529800C324A8 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 84C5B33C166553F100C324A8 /* dns_services.c in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BE550ADD80740027CCDF /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D284BE560ADD80740027CCDF /* DNSServiceDiscoveryReply.defs in Sources */,
- D284BE570ADD80740027CCDF /* DNSServiceDiscoveryRequest.defs in Sources */,
- D284BE580ADD80740027CCDF /* mDNS.c in Sources */,
- D284BE590ADD80740027CCDF /* uDNS.c in Sources */,
- D284BE5A0ADD80740027CCDF /* DNSCommon.c in Sources */,
- D284BE5B0ADD80740027CCDF /* DNSDigest.c in Sources */,
- D284BE5D0ADD80740027CCDF /* mDNSDebug.c in Sources */,
- D284BE5E0ADD80740027CCDF /* uds_daemon.c in Sources */,
- D284BE5F0ADD80740027CCDF /* dnssd_ipc.c in Sources */,
- D284BE600ADD80740027CCDF /* PlatformCommon.c in Sources */,
- D284BE610ADD80740027CCDF /* mDNSMacOSX.c in Sources */,
- D284BE620ADD80740027CCDF /* LegacyNATTraversal.c in Sources */,
- D284BE630ADD80740027CCDF /* daemon.c in Sources */,
- 2E04061F0C3198B700F13B59 /* helpermsg.defs in Sources */,
- 2E96A5320C39C1A50087C4D2 /* helper-stubs.c in Sources */,
- 21A57F4C145B2AE100939099 /* CryptoAlg.c in Sources */,
- 21A57F53145B2B1400939099 /* CryptoSupport.c in Sources */,
- 2124FA331471E9DE0021D7BB /* nsec.c in Sources */,
- 213BDC6D147319F400000896 /* dnssec.c in Sources */,
- 218E8E51156D8C0300720DA0 /* dnsproxy.c in Sources */,
- 21DED43515702C0F0060B6B9 /* DNSProxySupport.c in Sources */,
- 216D9ACE1720C9F5008066E1 /* VPNService.c in Sources */,
- 2127A47715C3C7B900A857FC /* nsec3.c in Sources */,
- 21DD8FBF161E9A250033C8F8 /* anonymous.c in Sources */,
- 21070E5F16486B9000A69507 /* DNSSECSupport.c in Sources */,
- 848DA5C7165477E000D2E8B4 /* xpc_services.c in Sources */,
- 2120ABD516B71614007089B6 /* CUPolicy.c in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BE7D0ADD80800027CCDF /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D284BE7E0ADD80800027CCDF /* DNSServiceDiscoveryReply.defs in Sources */,
- D284BE7F0ADD80800027CCDF /* DNSServiceDiscoveryRequest.defs in Sources */,
- D284BE800ADD80800027CCDF /* mDNS.c in Sources */,
- D284BE810ADD80800027CCDF /* uDNS.c in Sources */,
- D284BE820ADD80800027CCDF /* DNSCommon.c in Sources */,
- D284BE830ADD80800027CCDF /* DNSDigest.c in Sources */,
- D284BE850ADD80800027CCDF /* mDNSDebug.c in Sources */,
- D284BE860ADD80800027CCDF /* uds_daemon.c in Sources */,
- D284BE870ADD80800027CCDF /* dnssd_ipc.c in Sources */,
- D284BE880ADD80800027CCDF /* PlatformCommon.c in Sources */,
- D284BE890ADD80800027CCDF /* mDNSMacOSX.c in Sources */,
- D284BE8A0ADD80800027CCDF /* LegacyNATTraversal.c in Sources */,
- D284BE8B0ADD80800027CCDF /* daemon.c in Sources */,
- 2E0406200C3198B700F13B59 /* helpermsg.defs in Sources */,
- 2E96A5300C39C1A50087C4D2 /* helper-stubs.c in Sources */,
- 21A57F4D145B2AE100939099 /* CryptoAlg.c in Sources */,
- 21A57F54145B2B1400939099 /* CryptoSupport.c in Sources */,
- 2124FA341471E9DE0021D7BB /* nsec.c in Sources */,
- 213BDC6E147319F400000896 /* dnssec.c in Sources */,
- 218E8E52156D8C0300720DA0 /* dnsproxy.c in Sources */,
- 21DED43615702C0F0060B6B9 /* DNSProxySupport.c in Sources */,
- 216D9ACF1720C9F5008066E1 /* VPNService.c in Sources */,
- 2127A47815C3C7B900A857FC /* nsec3.c in Sources */,
- 21DD8FC0161E9A250033C8F8 /* anonymous.c in Sources */,
- 21070E6016486B9000A69507 /* DNSSECSupport.c in Sources */,
- 848DA5C8165477E000D2E8B4 /* xpc_services.c in Sources */,
- 2120ABD616B71614007089B6 /* CUPolicy.c in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BEA70ADD80920027CCDF /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D284BEA80ADD80920027CCDF /* dns-sd.c in Sources */,
- FFF589B70E37F66800EF515C /* ClientCommon.c in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BEB60ADD809A0027CCDF /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D284BEB70ADD809A0027CCDF /* JNISupport.c in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BEC40ADD80A20027CCDF /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 21DCD05C1461B23700702FC8 /* CryptoAlg.c in Sources */,
- 21DCD05D1461B23700702FC8 /* CryptoAlg.h in Sources */,
- D284BEC50ADD80A20027CCDF /* DNSCommon.c in Sources */,
- D284BEC60ADD80A20027CCDF /* DNSDigest.c in Sources */,
- D284BEC70ADD80A20027CCDF /* dnsextd.c in Sources */,
- D284BEC80ADD80A20027CCDF /* mDNSDebug.c in Sources */,
- D284BEC90ADD80A20027CCDF /* GenLinkedList.c in Sources */,
- D284BECA0ADD80A20027CCDF /* mDNSMacOSX.c in Sources */,
- D284BECC0ADD80A20027CCDF /* dnsextd_parser.y in Sources */,
- D284BECB0ADD80A20027CCDF /* dnsextd_lexer.l in Sources */,
- D284BECD0ADD80A20027CCDF /* PlatformCommon.c in Sources */,
- 2EAE955A0C31F4D30021F738 /* helpermsg.defs in Sources */,
- 2E35529E0C3A9E7600CA1CB7 /* helper-stubs.c in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BEDD0ADD80A70027CCDF /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D284BEDE0ADD80A70027CCDF /* ddnswriteconfig.m in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D284BEFD0ADD80B00027CCDF /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D284BEFE0ADD80B00027CCDF /* DNSServiceDiscoveryPref.m in Sources */,
- D284BEFF0ADD80B00027CCDF /* PrivilegedOperations.c in Sources */,
- D284BF000ADD80B00027CCDF /* ConfigurationAuthority.c in Sources */,
- FFF589C10E37F67E00EF515C /* ClientCommon.c in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- FFA572320AF18F1C0055A0F1 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- FFA572330AF18F1C0055A0F1 /* dnssd_ipc.c in Sources */,
- FFA572340AF18F1C0055A0F1 /* dnssd_clientlib.c in Sources */,
- FFA572350AF18F1C0055A0F1 /* dnssd_clientstub.c in Sources */,
- FFA5724A0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */,
- FFC22AA40B00F42C00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */,
- FFC22AA60B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- FFA5723E0AF18F450055A0F1 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- FFA5723F0AF18F450055A0F1 /* dnssd_ipc.c in Sources */,
- FFA572400AF18F450055A0F1 /* dnssd_clientlib.c in Sources */,
- FFA572410AF18F450055A0F1 /* dnssd_clientstub.c in Sources */,
- FFA5724B0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */,
- FFC22AA30B00F42B00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */,
- FFC22AA70B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- FFB765810AEED9C700583A2C /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- FFFA38660AEEDB2B0065B80A /* dnssd_ipc.c in Sources */,
- FFFA38630AEEDB090065B80A /* dnssd_clientlib.c in Sources */,
- FFFA38650AEEDB130065B80A /* dnssd_clientstub.c in Sources */,
- FFA572490AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */,
- FFC22AA20B00F42A00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */,
- FFC22AA50B00F43000BAB070 /* DNSServiceDiscoveryReply.defs in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin PBXTargetDependency section */
- 03067D680C83A3830022BE1F /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = D284BE500ADD80740027CCDF /* mDNSResponder */;
- targetProxy = 03067D670C83A3830022BE1F /* PBXContainerItemProxy */;
- };
- 03067D6A0C83A3890022BE1F /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = D284BE750ADD80800027CCDF /* mDNSResponder debug */;
- targetProxy = 03067D690C83A3890022BE1F /* PBXContainerItemProxy */;
- };
- 03067D6C0C83A3920022BE1F /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = D284BEA50ADD80920027CCDF /* dns-sd tool */;
- targetProxy = 03067D6B0C83A3920022BE1F /* PBXContainerItemProxy */;
- };
- 03067D6E0C83A39C0022BE1F /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 2E0405EF0C31955500F13B59 /* mDNSResponderHelper */;
- targetProxy = 03067D6D0C83A39C0022BE1F /* PBXContainerItemProxy */;
- };
- 03067D860C849CC30022BE1F /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 03067D640C83A3700022BE1F /* Build Some */;
- targetProxy = 03067D850C849CC30022BE1F /* PBXContainerItemProxy */;
- };
- 2130257112400E9300AC839F /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = FFA572650AF190F10055A0F1 /* SystemLibrariesDynamic */;
- targetProxy = 2130257012400E9300AC839F /* PBXContainerItemProxy */;
- };
- 2141DCFD123FFB7D0086D23E /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 2141DCF8123FFB5D0086D23E /* SystemLibraries */;
- targetProxy = 2141DCFC123FFB7D0086D23E /* PBXContainerItemProxy */;
- };
- 2141DD0E123FFC960086D23E /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 2141DD0B123FFC7F0086D23E /* SystemLibrariesStatic */;
- targetProxy = 2141DD0D123FFC960086D23E /* PBXContainerItemProxy */;
- };
- 215FFB19124002C100470DE1 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 2141DD1C123FFCDB0086D23E /* libdns_sd_static */;
- targetProxy = 215FFB18124002C100470DE1 /* PBXContainerItemProxy */;
- };
- 215FFB1B124002C700470DE1 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 2141DD23123FFD0F0086D23E /* libdns_sd_debug_static */;
- targetProxy = 215FFB1A124002C700470DE1 /* PBXContainerItemProxy */;
- };
- 215FFB1D124002CC00470DE1 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 2141DD29123FFD2C0086D23E /* libdns_sd_profile_static */;
- targetProxy = 215FFB1C124002CC00470DE1 /* PBXContainerItemProxy */;
- };
- 217A4C49138EE14C000A5BA8 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 213FB21712028A7A002B3A08 /* BonjourEvents */;
- targetProxy = 217A4C48138EE14C000A5BA8 /* PBXContainerItemProxy */;
- };
- 4AE4716A0EAFF83800A6C5AD /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 4AE471670EAFF81900A6C5AD /* dns_sd.jar */;
- targetProxy = 4AE471690EAFF83800A6C5AD /* PBXContainerItemProxy */;
- };
- 72FB546A166D5FE40090B2D9 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 72FB545E166D5FB00090B2D9 /* dnsctl */;
- targetProxy = 72FB5469166D5FE40090B2D9 /* PBXContainerItemProxy */;
- };
- 84C5B3411665544B00C324A8 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 84C5B3341665529800C324A8 /* dns_services */;
- targetProxy = 84C5B3401665544B00C324A8 /* PBXContainerItemProxy */;
- };
- D284BF2C0ADD815A0027CCDF /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = D284BEBF0ADD80A20027CCDF /* dnsextd */;
- targetProxy = D284BF2B0ADD815A0027CCDF /* PBXContainerItemProxy */;
- };
- D284BF2E0ADD81600027CCDF /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = D284BEDB0ADD80A70027CCDF /* ddnswriteconfig */;
- targetProxy = D284BF2D0ADD81600027CCDF /* PBXContainerItemProxy */;
- };
- D284BF300ADD81630027CCDF /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = D284BEEA0ADD80B00027CCDF /* PreferencePane */;
- targetProxy = D284BF2F0ADD81630027CCDF /* PBXContainerItemProxy */;
- };
- FFA572690AF190FF0055A0F1 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = FFB765830AEED9C700583A2C /* libdns_sd_dynamic */;
- targetProxy = FFA572680AF190FF0055A0F1 /* PBXContainerItemProxy */;
- };
- FFA5726B0AF191010055A0F1 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = FFA572300AF18F1C0055A0F1 /* libdns_sd_debug_dynamic */;
- targetProxy = FFA5726A0AF191010055A0F1 /* PBXContainerItemProxy */;
- };
- FFA5726D0AF191020055A0F1 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = FFA5723C0AF18F450055A0F1 /* libdns_sd_profile_dynamic */;
- targetProxy = FFA5726C0AF191020055A0F1 /* PBXContainerItemProxy */;
- };
- FFAE66F9105F0CF100162116 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = D284BEDB0ADD80A70027CCDF /* ddnswriteconfig */;
- targetProxy = FFAE66F8105F0CF100162116 /* PBXContainerItemProxy */;
- };
- FFB7657D0AEED97F00583A2C /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 00AD62BB032D7A0C0CCA2C71 /* Build More */;
- targetProxy = FFB7657C0AEED97F00583A2C /* PBXContainerItemProxy */;
- };
-/* End PBXTargetDependency section */
-
-/* Begin PBXVariantGroup section */
- FF260A4807B4475600CE10E5 /* DNSServiceDiscoveryPref.nib */ = {
- isa = PBXVariantGroup;
- children = (
- FF260A4907B4475600CE10E5 /* English */,
- );
- name = DNSServiceDiscoveryPref.nib;
- path = PreferencePane;
- sourceTree = SOURCE_ROOT;
- };
- FF260A4B07B4477F00CE10E5 /* InfoPlist.strings */ = {
- isa = PBXVariantGroup;
- children = (
- FF260A4C07B4477F00CE10E5 /* English */,
- );
- name = InfoPlist.strings;
- path = PreferencePane;
- sourceTree = SOURCE_ROOT;
- };
-/* End PBXVariantGroup section */
-
-/* Begin XCBuildConfiguration section */
- 03067D740C83A3CB0022BE1F /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- COPY_PHASE_STRIP = NO;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- GCC_OPTIMIZATION_LEVEL = s;
- PRODUCT_NAME = "Build Some";
- };
- name = Development;
- };
- 213FB21A12028A7B002B3A08 /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- BUNDLE_LOADER = /usr/libexec/UserEventAgent;
- CODE_SIGN_IDENTITY = "-";
- COPY_PHASE_STRIP = NO;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_MODEL_TUNING = G5;
- INFOPLIST_FILE = "BonjourEvents-Info.plist";
- INSTALL_PATH = /System/Library/UserEventPlugins/;
- PREBINDING = NO;
- PRODUCT_NAME = BonjourEvents;
- PROVISIONING_PROFILE = "";
- WRAPPER_EXTENSION = plugin;
- };
- name = Development;
- };
- 2141DCF9123FFB5D0086D23E /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- COPY_PHASE_STRIP = NO;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_OPTIMIZATION_LEVEL = 0;
- PRODUCT_NAME = SystemLibraries;
- };
- name = Development;
- };
- 2141DD0C123FFC7F0086D23E /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- COPY_PHASE_STRIP = NO;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_OPTIMIZATION_LEVEL = s;
- PRODUCT_NAME = SystemLibrariesStatic;
- };
- name = Development;
- };
- 2141DD1E123FFCDB0086D23E /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
- CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
- COPY_PHASE_STRIP = NO;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "$(inherited)",
- "__DARWIN_NON_CANCELABLE=1",
- );
- HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/";
- INSTALLHDRS_COPY_PHASE = YES;
- INSTALLHDRS_SCRIPT_PHASE = YES;
- INSTALL_PATH = /usr/local/lib/system;
- PREBINDING = NO;
- PRODUCT_NAME = dns_sd;
- };
- name = Development;
- };
- 2141DD25123FFD100086D23E /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
- CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
- COPY_PHASE_STRIP = NO;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "$(inherited)",
- "__DARWIN_NON_CANCELABLE=1",
- );
- HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/";
- INSTALL_PATH = /usr/local/lib/system;
- PREBINDING = NO;
- PRODUCT_NAME = dns_sd_debug;
- };
- name = Development;
- };
- 2141DD2B123FFD2C0086D23E /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
- CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
- COPY_PHASE_STRIP = NO;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "$(inherited)",
- "__DARWIN_NON_CANCELABLE=1",
- );
- HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/";
- INSTALL_PATH = /usr/local/lib/system;
- PREBINDING = NO;
- PRODUCT_NAME = dns_sd_profile;
- };
- name = Development;
- };
- 2E0405F20C31955500F13B59 /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- "CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = "helper-entitlements.plist";
- CODE_SIGN_IDENTITY = "-";
- CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
- CONFIGURATION_TEMP_DIR = "$(PROJECT_TEMP_DIR)";
- COPY_PHASE_STRIP = NO;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_WARN_CHECK_SWITCH_STATEMENTS = NO;
- HEADER_SEARCH_PATHS = (
- "${CONFIGURATION_TEMP_DIR}",
- "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
- );
- INSTALL_PATH = /usr/sbin;
- LD_MAP_FILE_PATH = "$(TARGET_TEMP_DIR)/$(PRODUCT_NAME)-LinkMap-$(CURRENT_VARIANT)-$(CURRENT_ARCH).txt";
- LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
- MACOSX_DEPLOYMENT_TARGET = 10.5;
- "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = "$(inherited)";
- OTHER_LDFLAGS = (
- "$(inherited)",
- "-lipsec",
- );
- "OTHER_LDFLAGS[sdk=iphoneos*] [arch=*]" = "-lipsec -Wl,-pie";
- "OTHER_LDFLAGS[sdk=macosx*][arch=*]" = (
- "-lipsec",
- "-Wl,-pie",
- );
- PREBINDING = NO;
- PRODUCT_NAME = mDNSResponderHelper;
- PROVISIONING_PROFILE = "";
- };
- name = Development;
- };
- 4AE471680EAFF81900A6C5AD /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- COPY_PHASE_STRIP = NO;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_OPTIMIZATION_LEVEL = 0;
- PRODUCT_NAME = dns_sd.jar;
- };
- name = Development;
- };
- 72FB5466166D5FB00090B2D9 /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- ARCHS = "$(ARCHS_STANDARD_64_BIT)";
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- "CODE_SIGN_ENTITLEMENTS[sdk=*]" = "dnsctl-entitlements.plist";
- CODE_SIGN_IDENTITY = "-";
- COPY_PHASE_STRIP = NO;
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_ENABLE_OBJC_EXCEPTIONS = YES;
- GCC_OPTIMIZATION_LEVEL = s;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- GCC_STRICT_ALIASING = YES;
- GCC_SYMBOLS_PRIVATE_EXTERN = NO;
- GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
- GCC_WARN_ABOUT_RETURN_TYPE = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- INSTALL_PATH = /usr/bin;
- MACOSX_DEPLOYMENT_TARGET = 10.9;
- ONLY_ACTIVE_ARCH = NO;
- PRODUCT_NAME = "$(TARGET_NAME)";
- PROVISIONING_PROFILE = "";
- SDKROOT = macosx;
- };
- name = Development;
- };
- 84C5B3371665529800C324A8 /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- ARCHS = "$(ARCHS_STANDARD_64_BIT)";
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- COPY_PHASE_STRIP = NO;
- EXECUTABLE_PREFIX = lib;
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_ENABLE_OBJC_EXCEPTIONS = YES;
- GCC_OPTIMIZATION_LEVEL = s;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- GCC_SYMBOLS_PRIVATE_EXTERN = NO;
- GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
- GCC_WARN_ABOUT_RETURN_TYPE = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- INSTALL_PATH = /usr/lib;
- MACOSX_DEPLOYMENT_TARGET = 10.8;
- ONLY_ACTIVE_ARCH = NO;
- PRODUCT_NAME = "$(TARGET_NAME)";
- SDKROOT = macosx;
- };
- name = Development;
- };
- D284BE290ADD78180027CCDF /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
- CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- OTHER_CFLAGS = "";
- OTHER_LDFLAGS = "";
- OTHER_REZFLAGS = "";
- PRODUCT_NAME = "Build All";
- SECTORDER_FLAGS = "";
- };
- name = Development;
- };
- D284BE2C0ADD78180027CCDF /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
- DEAD_CODE_STRIPPING = YES;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "__APPLE_USE_RFC_3542=1",
- "_DNS_SD_LIBDISPATCH=1",
- "APPLE_OSX_mDNSResponder=1",
- "__MigTypeCheck=1",
- "mDNSResponderVersion=${MVERS}",
- _LEGACY_NAT_TRAVERSAL_,
- "_BUILDING_XCODE_PROJECT_=1",
- );
- GCC_TREAT_WARNINGS_AS_ERRORS = YES;
- GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
- MVERS = "\"(Engineering Build)\"";
- OTHER_CFLAGS = (
- "-DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS",
- "-fwrapv",
- );
- "OTHER_LDFLAGS[sdk=macosx*]" = "";
- PREBINDING = NO;
- STRIP_STYLE = debugging;
- WARNING_CFLAGS = (
- "-W",
- "-Wall",
- "-Wmissing-prototypes",
- "-Wno-four-char-constants",
- "-Wno-unknown-pragmas",
- "-Wshadow",
- );
- YACC_GENERATED_FILE_STEM = Standard;
- };
- name = Development;
- };
- D284BE6E0ADD80740027CCDF /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- "CODE_SIGN_ENTITLEMENTS[sdk=*]" = "mDNSResponder-entitlements.plist";
- CODE_SIGN_IDENTITY = "-";
- CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
- CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
- FRAMEWORK_SEARCH_PATHS = (
- "$(inherited)",
- "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
- );
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- HEADER_SEARCH_PATHS = (
- "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/PrivateHeaders",
- ../mDNSShared,
- "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
- "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
- "${CONFIGURATION_TEMP_DIR}",
- "$(SDKROOT)/usr/include/libxml2",
- );
- INSTALL_PATH = /usr/sbin;
- LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
- MACOSX_DEPLOYMENT_TARGET = 10.5;
- ORDER_FILE = "${SRCROOT}/mDNSResponder.order";
- OTHER_CFLAGS = (
- "$(inherited)",
- "-no-cpp-precomp",
- );
- "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = "$(inherited)";
- OTHER_LDFLAGS = "";
- "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = (
- "-Wl,-pie",
- "-weak_framework",
- DeviceToDeviceManager,
- "-lMobileGestalt",
- "-lcupolicy",
- );
- "OTHER_LDFLAGS[sdk=macosx*][arch=*]" = (
- "-Wl,-pie",
- "-lAWACS",
- "-weak_framework",
- WebFilterDNS,
- "-weak_framework",
- DeviceToDeviceManager,
- );
- "OTHER_LDFLAGS[sdk=macosx10.6][arch=*]" = "-lAWACS";
- OTHER_REZFLAGS = "";
- PRODUCT_NAME = mDNSResponder;
- PROVISIONING_PROFILE = "";
- REZ_EXECUTABLE = YES;
- };
- name = Development;
- };
- D284BE930ADD80800027CCDF /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
- CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
- FRAMEWORK_SEARCH_PATHS = (
- "$(inherited)",
- "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
- );
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- GCC_OPTIMIZATION_LEVEL = s;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "$(inherited)",
- "MDNS_DEBUGMSGS=1",
- );
- HEADER_SEARCH_PATHS = (
- "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/PrivateHeaders",
- ../mDNSShared,
- "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
- "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
- "${CONFIGURATION_TEMP_DIR}",
- "$(SDKROOT)/usr/include/libxml2",
- );
- LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
- MACOSX_DEPLOYMENT_TARGET = 10.5;
- OTHER_CFLAGS = (
- "$(inherited)",
- "-no-cpp-precomp",
- );
- OTHER_LDFLAGS = "";
- "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = (
- "-Wl,-pie",
- "-weak_framework",
- DeviceToDeviceManager,
- "-lMobileGestalt",
- "-lcupolicy",
- );
- "OTHER_LDFLAGS[sdk=macosx*][arch=*]" = (
- "-Wl,-pie",
- "-lAWACS",
- "-weak_framework",
- WebFilterDNS,
- "-weak_framework",
- DeviceToDeviceManager,
- );
- "OTHER_LDFLAGS[sdk=macosx10.6][arch=*]" = "-lAWACS";
- OTHER_REZFLAGS = "";
- PRODUCT_NAME = mDNSResponder.debug;
- REZ_EXECUTABLE = YES;
- SECTORDER_FLAGS = (
- "-sectorder",
- __TEXT,
- __text,
- mDNSResponder.order,
- );
- SKIP_INSTALL = YES;
- };
- name = Development;
- };
- D284BEAE0ADD80920027CCDF /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
- CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- HEADER_SEARCH_PATHS = (
- ../mDNSShared,
- "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
- );
- INSTALL_PATH = /usr/bin;
- OTHER_CFLAGS = "-no-cpp-precomp";
- OTHER_LDFLAGS = "";
- OTHER_REZFLAGS = "";
- PRODUCT_NAME = "dns-sd";
- REZ_EXECUTABLE = YES;
- SECTORDER_FLAGS = "";
- };
- name = Development;
- };
- D284BEBC0ADD809A0027CCDF /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
- CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
- DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 1;
- EXECUTABLE_EXTENSION = jnilib;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- GCC_SYMBOLS_PRIVATE_EXTERN = NO;
- HEADER_SEARCH_PATHS = (
- ../mDNSShared,
- "${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/A/Headers",
- "${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/1.3.1/Headers",
- "${PROJECT_DERIVED_FILE_DIR}",
- );
- INSTALL_PATH = /usr/lib/java;
- LIBRARY_STYLE = DYNAMIC;
- MACH_O_TYPE = mh_dylib;
- OTHER_CFLAGS = "";
- OTHER_LIBTOOL_FLAGS = "";
- OTHER_REZFLAGS = "";
- PRODUCT_NAME = libjdns_sd;
- REZ_EXECUTABLE = YES;
- SECTORDER_FLAGS = "";
- };
- name = Development;
- };
- D284BED70ADD80A20027CCDF /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
- CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
- FRAMEWORK_SEARCH_PATHS = "";
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- HEADER_SEARCH_PATHS = (
- "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
- "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
- "${CONFIGURATION_TEMP_DIR}",
- /System/Library/Frameworks/System.Framework/PrivateHeaders,
- );
- INSTALL_PATH = /usr/sbin;
- LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
- MACOSX_DEPLOYMENT_TARGET = 10.5;
- OTHER_CFLAGS = (
- "-no-cpp-precomp",
- "-UAPPLE_OSX_mDNSResponder",
- );
- OTHER_LDFLAGS = "";
- "OTHER_LDFLAGS[sdk=macosx*][arch=*]" = "-Wl,-pie";
- PRODUCT_NAME = dnsextd;
- SECTORDER_FLAGS = "";
- };
- name = Development;
- };
- D284BEE60ADD80A70027CCDF /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
- CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
- CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- INSTALL_PATH = "/Library/Application Support/Bonjour";
- MACOSX_DEPLOYMENT_TARGET = 10.5;
- OTHER_CFLAGS = "";
- OTHER_LDFLAGS = "";
- "OTHER_LDFLAGS[sdk=macosx*]" = "-Wl,-pie";
- OTHER_REZFLAGS = "";
- PRODUCT_NAME = ddnswriteconfig;
- REZ_EXECUTABLE = YES;
- SECTORDER_FLAGS = "";
- };
- name = Development;
- };
- D284BF090ADD80B00027CCDF /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
- CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
- CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
- EXPORTED_SYMBOLS_FILE = "";
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_ENABLE_OBJC_GC = supported;
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- GCC_SYMBOLS_PRIVATE_EXTERN = NO;
- INFOPLIST_FILE = "PreferencePane/Info-PreferencePane.plist";
- INSTALL_PATH = /AppleInternal/Library/PreferencePanes;
- MACOSX_DEPLOYMENT_TARGET = 10.5;
- OTHER_CFLAGS = "";
- OTHER_LDFLAGS = "-twolevel_namespace";
- OTHER_REZFLAGS = "";
- PRODUCT_NAME = Bonjour;
- SECTORDER_FLAGS = "";
- WRAPPER_EXTENSION = prefPane;
- };
- name = Development;
- };
- FFA572380AF18F1C0055A0F1 /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
- CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
- COPY_PHASE_STRIP = NO;
- DYLIB_CURRENT_VERSION = "$(RC_ProjectSourceVersion)";
- EXECUTABLE_EXTENSION = dylib;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "$(inherited)",
- "__DARWIN_NON_CANCELABLE=1",
- );
- HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/";
- INSTALL_PATH = /usr/lib/system;
- "INSTALL_PATH[sdk=iphonesimulator*]" = "$(SDKROOT)/usr/lib/system";
- LINK_WITH_STANDARD_LIBRARIES = NO;
- OTHER_LDFLAGS = (
- "-Wl,-umbrella,System",
- "-L/usr/lib/system",
- "-ldyld",
- "-lcompiler_rt",
- "-lsystem_kernel",
- "-lsystem_platform",
- "-lsystem_pthread",
- "-lsystem_malloc",
- "-lsystem_c",
- "-lsystem_blocks",
- "-ldispatch",
- "-llaunch",
- "-lsystem_asl",
- );
- "OTHER_LDFLAGS[sdk=iphonesimulator*]" = (
- "-Wl,-umbrella,System",
- "-L/usr/lib/system",
- "-ldyld_sim",
- "-lcompiler_rt_sim",
- "-lsystem_sim_c",
- "-lsystem_sim_blocks",
- "-ldispatch",
- "-Wl,-upward-lSystem",
- );
- PRODUCT_NAME = libsystem_dnssd_debug;
- "PRODUCT_NAME[sdk=iphonesimulator*]" = libsystem_sim_dnssd_debug;
- };
- name = Development;
- };
- FFA572440AF18F450055A0F1 /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
- CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
- COPY_PHASE_STRIP = NO;
- DYLIB_CURRENT_VERSION = "$(RC_ProjectSourceVersion)";
- EXECUTABLE_EXTENSION = dylib;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "$(inherited)",
- "__DARWIN_NON_CANCELABLE=1",
- );
- GENERATE_PROFILING_CODE = YES;
- HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/";
- INSTALL_PATH = /usr/lib/system;
- "INSTALL_PATH[sdk=iphonesimulator*]" = "$(SDKROOT)/usr/lib/system";
- LINK_WITH_STANDARD_LIBRARIES = NO;
- OTHER_LDFLAGS = (
- "-Wl,-umbrella,System",
- "-L/usr/lib/system",
- "-ldyld",
- "-lcompiler_rt",
- "-lsystem_kernel",
- "-lsystem_platform",
- "-lsystem_pthread",
- "-lsystem_malloc",
- "-lsystem_c",
- "-lsystem_blocks",
- "-ldispatch",
- "-llaunch",
- "-lsystem_asl",
- );
- "OTHER_LDFLAGS[sdk=iphonesimulator*]" = (
- "-Wl,-umbrella,System",
- "-L/usr/lib/system",
- "-ldyld_sim",
- "-lcompiler_rt_sim",
- "-lsystem_sim_c",
- "-lsystem_sim_blocks",
- "-ldispatch",
- "-Wl,-upward-lSystem",
- );
- PRODUCT_NAME = libsystem_dnssd_profile;
- "PRODUCT_NAME[sdk=iphonesimulator*]" = libsystem_sim_dnssd_profile;
- };
- name = Development;
- };
- FFA5726F0AF191200055A0F1 /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- COPY_PHASE_STRIP = NO;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- PRODUCT_NAME = SystemLibrariesDynamic;
- };
- name = Development;
- };
- FFB7657F0AEED99D00583A2C /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
- CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
- COPY_PHASE_STRIP = NO;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- PRODUCT_NAME = "Build All";
- };
- name = Development;
- };
- FFB7658A0AEED9FB00583A2C /* Development */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
- CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
- COPY_PHASE_STRIP = NO;
- DYLIB_CURRENT_VERSION = "$(RC_ProjectSourceVersion)";
- EXECUTABLE_EXTENSION = dylib;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "$(inherited)",
- "__DARWIN_NON_CANCELABLE=1",
- );
- HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/";
- INSTALLHDRS_COPY_PHASE = YES;
- INSTALLHDRS_SCRIPT_PHASE = YES;
- INSTALL_PATH = /usr/lib/system;
- "INSTALL_PATH[sdk=iphonesimulator*]" = "$(SDKROOT)/usr/lib/system";
- LINK_WITH_STANDARD_LIBRARIES = NO;
- OTHER_LDFLAGS = (
- "-Wl,-umbrella,System",
- "-L/usr/lib/system",
- "-ldyld",
- "-lcompiler_rt",
- "-lsystem_kernel",
- "-lsystem_platform",
- "-lsystem_pthread",
- "-lsystem_malloc",
- "-lsystem_c",
- "-lsystem_blocks",
- "-ldispatch",
- "-llaunch",
- "-lsystem_asl",
- );
- "OTHER_LDFLAGS[sdk=iphonesimulator*]" = (
- "-Wl,-umbrella,System",
- "-L/usr/lib/system",
- "-ldyld_sim",
- "-lcompiler_rt_sim",
- "-lsystem_sim_c",
- "-lsystem_sim_blocks",
- "-ldispatch",
- "-Wl,-upward-lSystem",
- );
- PRODUCT_NAME = libsystem_dnssd;
- "PRODUCT_NAME[sdk=iphonesimulator*]" = libsystem_sim_dnssd;
- };
- name = Development;
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- 03067D730C83A3CB0022BE1F /* Build configuration list for PBXAggregateTarget "Build Some" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 03067D740C83A3CB0022BE1F /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- 213FB21B12028A7C002B3A08 /* Build configuration list for PBXNativeTarget "BonjourEvents" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 213FB21A12028A7B002B3A08 /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- 2141DD08123FFB830086D23E /* Build configuration list for PBXAggregateTarget "SystemLibraries" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 2141DCF9123FFB5D0086D23E /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- 2141DD18123FFC990086D23E /* Build configuration list for PBXAggregateTarget "SystemLibrariesStatic" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 2141DD0C123FFC7F0086D23E /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- 2141DD1F123FFCF90086D23E /* Build configuration list for PBXNativeTarget "libdns_sd_static" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 2141DD1E123FFCDB0086D23E /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- 2141DD35123FFD3B0086D23E /* Build configuration list for PBXNativeTarget "libdns_sd_debug_static" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 2141DD25123FFD100086D23E /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- 2141DD36123FFD3B0086D23E /* Build configuration list for PBXNativeTarget "libdns_sd_profile_static" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 2141DD2B123FFD2C0086D23E /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- 2E0405F30C31956600F13B59 /* Build configuration list for PBXNativeTarget "mDNSResponderHelper" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 2E0405F20C31955500F13B59 /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- 4AE471770EAFF84000A6C5AD /* Build configuration list for PBXLegacyTarget "dns_sd.jar" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 4AE471680EAFF81900A6C5AD /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- 72FB5465166D5FB00090B2D9 /* Build configuration list for PBXNativeTarget "dnsctl" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 72FB5466166D5FB00090B2D9 /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- 84C5B3361665529800C324A8 /* Build configuration list for PBXNativeTarget "dns_services" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 84C5B3371665529800C324A8 /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- D284BE280ADD78180027CCDF /* Build configuration list for PBXAggregateTarget "Build More" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- D284BE290ADD78180027CCDF /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- D284BE2B0ADD78180027CCDF /* Build configuration list for PBXProject "mDNSResponder" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- D284BE2C0ADD78180027CCDF /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- D284BE6D0ADD80740027CCDF /* Build configuration list for PBXNativeTarget "mDNSResponder" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- D284BE6E0ADD80740027CCDF /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- D284BE920ADD80800027CCDF /* Build configuration list for PBXNativeTarget "mDNSResponder debug" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- D284BE930ADD80800027CCDF /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- D284BEAD0ADD80920027CCDF /* Build configuration list for PBXNativeTarget "dns-sd tool" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- D284BEAE0ADD80920027CCDF /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- D284BEBB0ADD809A0027CCDF /* Build configuration list for PBXNativeTarget "libjdns_sd.jnilib" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- D284BEBC0ADD809A0027CCDF /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- D284BED60ADD80A20027CCDF /* Build configuration list for PBXNativeTarget "dnsextd" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- D284BED70ADD80A20027CCDF /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- D284BEE50ADD80A70027CCDF /* Build configuration list for PBXNativeTarget "ddnswriteconfig" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- D284BEE60ADD80A70027CCDF /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- D284BF080ADD80B00027CCDF /* Build configuration list for PBXNativeTarget "PreferencePane" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- D284BF090ADD80B00027CCDF /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- FFA572370AF18F1C0055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd_debug_dynamic" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- FFA572380AF18F1C0055A0F1 /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- FFA572430AF18F450055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd_profile_dynamic" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- FFA572440AF18F450055A0F1 /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- FFA5726E0AF191200055A0F1 /* Build configuration list for PBXAggregateTarget "SystemLibrariesDynamic" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- FFA5726F0AF191200055A0F1 /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- FFB7657E0AEED99D00583A2C /* Build configuration list for PBXAggregateTarget "Build All" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- FFB7657F0AEED99D00583A2C /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
- FFB765890AEED9FB00583A2C /* Build configuration list for PBXNativeTarget "libdns_sd_dynamic" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- FFB7658A0AEED9FB00583A2C /* Development */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
- };
-/* End XCConfigurationList section */
- };
- rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
-}
Copied: vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj (from rev 6984, vendor/apple/mDNSResponder/dist/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj)
===================================================================
--- vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj (rev 0)
+++ vendor/apple/mDNSResponder/561.1.1/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj 2015-03-20 01:14:52 UTC (rev 6985)
@@ -0,0 +1,3128 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ 00AD62BB032D7A0C0CCA2C71 /* Build More */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = D284BE280ADD78180027CCDF /* Build configuration list for PBXAggregateTarget "Build More" */;
+ buildPhases = (
+ );
+ dependencies = (
+ 03067D860C849CC30022BE1F /* PBXTargetDependency */,
+ D284BF2C0ADD815A0027CCDF /* PBXTargetDependency */,
+ D284BF2E0ADD81600027CCDF /* PBXTargetDependency */,
+ D284BF300ADD81630027CCDF /* PBXTargetDependency */,
+ );
+ name = "Build More";
+ productName = "Build All";
+ };
+ 03067D640C83A3700022BE1F /* Build Some */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 03067D730C83A3CB0022BE1F /* Build configuration list for PBXAggregateTarget "Build Some" */;
+ buildPhases = (
+ FF045B6A0C7E4AA600448140 /* ShellScript */,
+ );
+ dependencies = (
+ 217A4C49138EE14C000A5BA8 /* PBXTargetDependency */,
+ 03067D680C83A3830022BE1F /* PBXTargetDependency */,
+ 03067D6A0C83A3890022BE1F /* PBXTargetDependency */,
+ 03067D6C0C83A3920022BE1F /* PBXTargetDependency */,
+ 03067D6E0C83A39C0022BE1F /* PBXTargetDependency */,
+ 84C5B3411665544B00C324A8 /* PBXTargetDependency */,
+ );
+ name = "Build Some";
+ productName = "Build Some";
+ };
+ 2141DCF8123FFB5D0086D23E /* SystemLibraries */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 2141DD08123FFB830086D23E /* Build configuration list for PBXAggregateTarget "SystemLibraries" */;
+ buildPhases = (
+ );
+ dependencies = (
+ 2141DD0E123FFC960086D23E /* PBXTargetDependency */,
+ 2130257112400E9300AC839F /* PBXTargetDependency */,
+ );
+ name = SystemLibraries;
+ productName = SystemLibraries;
+ };
+ 2141DD0B123FFC7F0086D23E /* SystemLibrariesStatic */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 2141DD18123FFC990086D23E /* Build configuration list for PBXAggregateTarget "SystemLibrariesStatic" */;
+ buildPhases = (
+ );
+ dependencies = (
+ 215FFB1D124002CC00470DE1 /* PBXTargetDependency */,
+ 215FFB1B124002C700470DE1 /* PBXTargetDependency */,
+ 215FFB19124002C100470DE1 /* PBXTargetDependency */,
+ );
+ name = SystemLibrariesStatic;
+ productName = SystemLibrariesStatic;
+ };
+ FFA572650AF190F10055A0F1 /* SystemLibrariesDynamic */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FFA5726E0AF191200055A0F1 /* Build configuration list for PBXAggregateTarget "SystemLibrariesDynamic" */;
+ buildPhases = (
+ );
+ dependencies = (
+ FFA572690AF190FF0055A0F1 /* PBXTargetDependency */,
+ FFA5726B0AF191010055A0F1 /* PBXTargetDependency */,
+ FFA5726D0AF191020055A0F1 /* PBXTargetDependency */,
+ );
+ name = SystemLibrariesDynamic;
+ productName = SystemLibraries;
+ };
+ FFB7657B0AEED96B00583A2C /* Build All */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FFB7657E0AEED99D00583A2C /* Build configuration list for PBXAggregateTarget "Build All" */;
+ buildPhases = (
+ );
+ dependencies = (
+ FFB7657D0AEED97F00583A2C /* PBXTargetDependency */,
+ 2141DCFD123FFB7D0086D23E /* PBXTargetDependency */,
+ );
+ name = "Build All";
+ productName = "Build All";
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ 21070E5F16486B9000A69507 /* DNSSECSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21070E5D16486B9000A69507 /* DNSSECSupport.c */; };
+ 21070E6016486B9000A69507 /* DNSSECSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21070E5D16486B9000A69507 /* DNSSECSupport.c */; };
+ 21070E6116486B9000A69507 /* DNSSECSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 21070E5E16486B9000A69507 /* DNSSECSupport.h */; };
+ 21070E6216486B9000A69507 /* DNSSECSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 21070E5E16486B9000A69507 /* DNSSECSupport.h */; };
+ 2120ABD516B71614007089B6 /* CUPolicy.c in Sources */ = {isa = PBXBuildFile; fileRef = 2120ABD416B71614007089B6 /* CUPolicy.c */; };
+ 2120ABD616B71614007089B6 /* CUPolicy.c in Sources */ = {isa = PBXBuildFile; fileRef = 2120ABD416B71614007089B6 /* CUPolicy.c */; };
+ 2124FA2C1471E98C0021D7BB /* nsec.h in Headers */ = {isa = PBXBuildFile; fileRef = 2124FA2B1471E98C0021D7BB /* nsec.h */; };
+ 2124FA2D1471E98C0021D7BB /* nsec.h in Headers */ = {isa = PBXBuildFile; fileRef = 2124FA2B1471E98C0021D7BB /* nsec.h */; };
+ 2124FA301471E9B50021D7BB /* dnssec.h in Headers */ = {isa = PBXBuildFile; fileRef = 2124FA2F1471E9B50021D7BB /* dnssec.h */; };
+ 2124FA311471E9B50021D7BB /* dnssec.h in Headers */ = {isa = PBXBuildFile; fileRef = 2124FA2F1471E9B50021D7BB /* dnssec.h */; };
+ 2124FA331471E9DE0021D7BB /* nsec.c in Sources */ = {isa = PBXBuildFile; fileRef = 2124FA321471E9DE0021D7BB /* nsec.c */; };
+ 2124FA341471E9DE0021D7BB /* nsec.c in Sources */ = {isa = PBXBuildFile; fileRef = 2124FA321471E9DE0021D7BB /* nsec.c */; };
+ 2127A47715C3C7B900A857FC /* nsec3.c in Sources */ = {isa = PBXBuildFile; fileRef = 2127A47515C3C7B900A857FC /* nsec3.c */; };
+ 2127A47815C3C7B900A857FC /* nsec3.c in Sources */ = {isa = PBXBuildFile; fileRef = 2127A47515C3C7B900A857FC /* nsec3.c */; };
+ 2127A47915C3C7B900A857FC /* nsec3.h in Headers */ = {isa = PBXBuildFile; fileRef = 2127A47615C3C7B900A857FC /* nsec3.h */; };
+ 2127A47A15C3C7B900A857FC /* nsec3.h in Headers */ = {isa = PBXBuildFile; fileRef = 2127A47615C3C7B900A857FC /* nsec3.h */; };
+ 213BDC6D147319F400000896 /* dnssec.c in Sources */ = {isa = PBXBuildFile; fileRef = 213BDC6C147319F400000896 /* dnssec.c */; };
+ 213BDC6E147319F400000896 /* dnssec.c in Sources */ = {isa = PBXBuildFile; fileRef = 213BDC6C147319F400000896 /* dnssec.c */; };
+ 213FB23C12028C4A002B3A08 /* BonjourEvents.c in Sources */ = {isa = PBXBuildFile; fileRef = 213FB22C12028B53002B3A08 /* BonjourEvents.c */; };
+ 213FB23D12028C5A002B3A08 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
+ 215FFAEE124000F900470DE1 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
+ 215FFAEF124000F900470DE1 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; };
+ 215FFAF0124000F900470DE1 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; };
+ 215FFAF1124000F900470DE1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; };
+ 215FFAF2124000F900470DE1 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; };
+ 215FFAF3124000F900470DE1 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; };
+ 215FFAF41240011800470DE1 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
+ 215FFAF51240011800470DE1 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; };
+ 215FFAF61240011800470DE1 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; };
+ 215FFAF71240011800470DE1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; };
+ 215FFAF81240011800470DE1 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; };
+ 215FFAF91240011800470DE1 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; };
+ 215FFAFA1240013400470DE1 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
+ 215FFAFB1240013400470DE1 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; };
+ 215FFAFC1240013400470DE1 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; };
+ 215FFAFD1240013400470DE1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; };
+ 215FFAFE1240013400470DE1 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; };
+ 215FFAFF1240013400470DE1 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; };
+ 216D9ACE1720C9F5008066E1 /* VPNService.c in Sources */ = {isa = PBXBuildFile; fileRef = 216D9ACD1720C9F5008066E1 /* VPNService.c */; };
+ 216D9ACF1720C9F5008066E1 /* VPNService.c in Sources */ = {isa = PBXBuildFile; fileRef = 216D9ACD1720C9F5008066E1 /* VPNService.c */; };
+ 218E8E51156D8C0300720DA0 /* dnsproxy.c in Sources */ = {isa = PBXBuildFile; fileRef = 218E8E4F156D8C0300720DA0 /* dnsproxy.c */; };
+ 218E8E52156D8C0300720DA0 /* dnsproxy.c in Sources */ = {isa = PBXBuildFile; fileRef = 218E8E4F156D8C0300720DA0 /* dnsproxy.c */; };
+ 218E8E53156D8C0300720DA0 /* dnsproxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 218E8E50156D8C0300720DA0 /* dnsproxy.h */; };
+ 218E8E54156D8C0300720DA0 /* dnsproxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 218E8E50156D8C0300720DA0 /* dnsproxy.h */; };
+ 219D5542149ED645004464AE /* libxml2.2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 219D5541149ED645004464AE /* libxml2.2.dylib */; };
+ 219D5543149ED645004464AE /* libxml2.2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 219D5541149ED645004464AE /* libxml2.2.dylib */; };
+ 21A57F4C145B2AE100939099 /* CryptoAlg.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F4A145B2AE100939099 /* CryptoAlg.c */; };
+ 21A57F4D145B2AE100939099 /* CryptoAlg.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F4A145B2AE100939099 /* CryptoAlg.c */; };
+ 21A57F4E145B2AE100939099 /* CryptoAlg.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A57F4B145B2AE100939099 /* CryptoAlg.h */; };
+ 21A57F4F145B2AE100939099 /* CryptoAlg.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A57F4B145B2AE100939099 /* CryptoAlg.h */; };
+ 21A57F53145B2B1400939099 /* CryptoSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F51145B2B1400939099 /* CryptoSupport.c */; };
+ 21A57F54145B2B1400939099 /* CryptoSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F51145B2B1400939099 /* CryptoSupport.c */; };
+ 21A57F55145B2B1400939099 /* CryptoSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A57F52145B2B1400939099 /* CryptoSupport.h */; };
+ 21A57F56145B2B1400939099 /* CryptoSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A57F52145B2B1400939099 /* CryptoSupport.h */; };
+ 21DCD05C1461B23700702FC8 /* CryptoAlg.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F4A145B2AE100939099 /* CryptoAlg.c */; };
+ 21DCD05D1461B23700702FC8 /* CryptoAlg.h in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F4B145B2AE100939099 /* CryptoAlg.h */; };
+ 21DD8FBF161E9A250033C8F8 /* anonymous.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DD8FBD161E9A250033C8F8 /* anonymous.c */; };
+ 21DD8FC0161E9A250033C8F8 /* anonymous.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DD8FBD161E9A250033C8F8 /* anonymous.c */; };
+ 21DD8FC1161E9A250033C8F8 /* anonymous.h in Headers */ = {isa = PBXBuildFile; fileRef = 21DD8FBE161E9A250033C8F8 /* anonymous.h */; };
+ 21DD8FC2161E9A250033C8F8 /* anonymous.h in Headers */ = {isa = PBXBuildFile; fileRef = 21DD8FBE161E9A250033C8F8 /* anonymous.h */; };
+ 21DED43515702C0F0060B6B9 /* DNSProxySupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DED43415702C0F0060B6B9 /* DNSProxySupport.c */; };
+ 21DED43615702C0F0060B6B9 /* DNSProxySupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DED43415702C0F0060B6B9 /* DNSProxySupport.c */; };
+ 2E0405F50C3195F700F13B59 /* helper.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405F40C3195F700F13B59 /* helper.c */; };
+ 2E0405F60C31961100F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; settings = {ATTRIBUTES = (Client, Server, ); COMPILER_FLAGS = "-Wno-error"; }; };
+ 2E0406150C3197CB00F13B59 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E0406140C3197CB00F13B59 /* libbsm.dylib */; };
+ 2E04061F0C3198B700F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; };
+ 2E0406200C3198B700F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; };
+ 2E04070A0C31EEEC00F13B59 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
+ 2E04070B0C31EEEC00F13B59 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
+ 2E3552900C3A95C100CA1CB7 /* helper-error.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E35528F0C3A95C100CA1CB7 /* helper-error.h */; };
+ 2E3552910C3A95C100CA1CB7 /* helper-error.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E35528F0C3A95C100CA1CB7 /* helper-error.h */; };
+ 2E3552920C3A95C100CA1CB7 /* helper-error.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E35528F0C3A95C100CA1CB7 /* helper-error.h */; };
+ 2E35529D0C3A9E7600CA1CB7 /* helper-error.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E35528F0C3A95C100CA1CB7 /* helper-error.h */; };
+ 2E35529E0C3A9E7600CA1CB7 /* helper-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */; };
+ 2E35529F0C3A9E7600CA1CB7 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; };
+ 2E4D9B050C38C19500480551 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
+ 2E8165E80C5980E300485EB2 /* libpfkey.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A8202520C56C36500DDFD48 /* libpfkey.h */; };
+ 2E8165E90C5980EE00485EB2 /* pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 4A8202530C56C36600DDFD48 /* pfkey.c */; };
+ 2E8165EA0C5980F700485EB2 /* ipsec_strerror.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A8202510C56C36500DDFD48 /* ipsec_strerror.h */; };
+ 2E8165F90C59838100485EB2 /* libipsec.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E8165F60C59835F00485EB2 /* libipsec.dylib */; };
+ 2E96A51D0C39BDAC0087C4D2 /* helper-main.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E0406CA0C31E9AD00F13B59 /* helper-main.c */; };
+ 2E96A5260C39BE480087C4D2 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; };
+ 2E96A5270C39BE480087C4D2 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; };
+ 2E96A5300C39C1A50087C4D2 /* helper-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */; };
+ 2E96A5320C39C1A50087C4D2 /* helper-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */; };
+ 2EAE955A0C31F4D30021F738 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; };
+ 2EC8F8EC0C39CCAC003C9C48 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; };
+ 2ECC11A60C4FEC3800CB1885 /* helpermsg-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */; };
+ 2ECC11A70C4FEC3800CB1885 /* helpermsg-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */; };
+ 2ECC11A80C4FEC3800CB1885 /* helpermsg-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */; };
+ 2EDC5E730C39EA640092701B /* helper-server.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EDC5E720C39EA640092701B /* helper-server.h */; };
+ 2EDC5E740C39EA640092701B /* helper-server.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EDC5E720C39EA640092701B /* helper-server.h */; };
+ 2EDC5E750C39EA640092701B /* helper-server.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EDC5E720C39EA640092701B /* helper-server.h */; };
+ 3F347CF6185D57CD00367B40 /* base.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 3F347CF5185D57CD00367B40 /* base.xcconfig */; };
+ 4A7B9E8014FDA25000B84CC1 /* mDNSResponder.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4A7B9E7E14FDA1BB00B84CC1 /* mDNSResponder.plist */; };
+ 4A7B9E8214FDA26C00B84CC1 /* mDNSResponder.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4A7B9E7C14FDA19F00B84CC1 /* mDNSResponder.txt */; };
+ 4AAE0C9A0C68EA81003882A5 /* mDNSResponderHelper.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */; };
+ 4BD2B63A134FE09F002B96D5 /* P2PPacketFilter.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BD2B638134FE09F002B96D5 /* P2PPacketFilter.c */; };
+ 4BD2B63B134FE09F002B96D5 /* P2PPacketFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BD2B639134FE09F002B96D5 /* P2PPacketFilter.h */; };
+ 72FB5467166D5FCA0090B2D9 /* dnsctl.c in Sources */ = {isa = PBXBuildFile; fileRef = 72FB545A166D5F960090B2D9 /* dnsctl.c */; };
+ 8415A6571897109000BDBA26 /* libdns_services.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8415A6561897109000BDBA26 /* libdns_services.dylib */; };
+ 8418673E15AB8C2D00BB7F70 /* com.apple.networking.mDNSResponder in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8418673A15AB8B6900BB7F70 /* com.apple.networking.mDNSResponder */; };
+ 848DA5C7165477E000D2E8B4 /* xpc_services.c in Sources */ = {isa = PBXBuildFile; fileRef = 848DA5C6165477E000D2E8B4 /* xpc_services.c */; };
+ 848DA5C8165477E000D2E8B4 /* xpc_services.c in Sources */ = {isa = PBXBuildFile; fileRef = 848DA5C6165477E000D2E8B4 /* xpc_services.c */; };
+ 848DA5CA165477EB00D2E8B4 /* xpc_services.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5C9165477EB00D2E8B4 /* xpc_services.h */; };
+ 848DA5CB165477EB00D2E8B4 /* xpc_services.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5C9165477EB00D2E8B4 /* xpc_services.h */; };
+ 848DA5D616547F7200D2E8B4 /* dns_xpc.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5D516547F7200D2E8B4 /* dns_xpc.h */; };
+ 848DA5D716547F7200D2E8B4 /* dns_xpc.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5D516547F7200D2E8B4 /* dns_xpc.h */; };
+ 84C5B33C166553F100C324A8 /* dns_services.c in Sources */ = {isa = PBXBuildFile; fileRef = 84C5B339166553AF00C324A8 /* dns_services.c */; };
+ 84F4C090188F050200D1E1DE /* dns_services_mdns.h in Headers */ = {isa = PBXBuildFile; fileRef = 84F4C08F188F04CF00D1E1DE /* dns_services_mdns.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ D284BE530ADD80740027CCDF /* DNSServiceDiscoveryDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 6575FBFF022EAFBA00000109 /* DNSServiceDiscoveryDefines.h */; };
+ D284BE540ADD80740027CCDF /* dnssd_ipc.h in Headers */ = {isa = PBXBuildFile; fileRef = F5E11B5B04A28126019798ED /* dnssd_ipc.h */; };
+ D284BE560ADD80740027CCDF /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Client, ); }; };
+ D284BE570ADD80740027CCDF /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; settings = {ATTRIBUTES = (Server, ); }; };
+ D284BE580ADD80740027CCDF /* mDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBE9022EAF5A00000109 /* mDNS.c */; };
+ D284BE590ADD80740027CCDF /* uDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F70587CEF6001880B3 /* uDNS.c */; };
+ D284BE5A0ADD80740027CCDF /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; };
+ D284BE5B0ADD80740027CCDF /* DNSDigest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F461DB5062DBF2900672BF3 /* DNSDigest.c */; };
+ D284BE5D0ADD80740027CCDF /* mDNSDebug.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */; };
+ D284BE5E0ADD80740027CCDF /* uds_daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = F525E72804AA167501F1CF4D /* uds_daemon.c */; };
+ D284BE5F0ADD80740027CCDF /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
+ D284BE600ADD80740027CCDF /* PlatformCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FFCB6D73075D539900B8AF62 /* PlatformCommon.c */; };
+ D284BE610ADD80740027CCDF /* mDNSMacOSX.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */; };
+ D284BE620ADD80740027CCDF /* LegacyNATTraversal.c in Sources */ = {isa = PBXBuildFile; fileRef = 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */; };
+ D284BE630ADD80740027CCDF /* daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEC022EAF7200000109 /* daemon.c */; };
+ D284BE650ADD80740027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
+ D284BE660ADD80740027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
+ D284BE670ADD80740027CCDF /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; };
+ D284BE680ADD80740027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
+ D284BE6B0ADD80740027CCDF /* mDNSResponder.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FF485D5105632E0000130380 /* mDNSResponder.8 */; };
+ D284BE780ADD80800027CCDF /* DNSServiceDiscoveryDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 6575FBFF022EAFBA00000109 /* DNSServiceDiscoveryDefines.h */; };
+ D284BE790ADD80800027CCDF /* dnssd_ipc.h in Headers */ = {isa = PBXBuildFile; fileRef = F5E11B5B04A28126019798ED /* dnssd_ipc.h */; };
+ D284BE7A0ADD80800027CCDF /* mDNSEmbeddedAPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 654BE64F02B63B93000001D1 /* mDNSEmbeddedAPI.h */; };
+ D284BE7B0ADD80800027CCDF /* mDNSDebug.h in Headers */ = {isa = PBXBuildFile; fileRef = 654BE65002B63B93000001D1 /* mDNSDebug.h */; };
+ D284BE7C0ADD80800027CCDF /* mDNSMacOSX.h in Headers */ = {isa = PBXBuildFile; fileRef = 000753D303367C1C0CCA2C71 /* mDNSMacOSX.h */; };
+ D284BE7E0ADD80800027CCDF /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Client, ); }; };
+ D284BE7F0ADD80800027CCDF /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; settings = {ATTRIBUTES = (Server, ); }; };
+ D284BE800ADD80800027CCDF /* mDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBE9022EAF5A00000109 /* mDNS.c */; };
+ D284BE810ADD80800027CCDF /* uDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F70587CEF6001880B3 /* uDNS.c */; };
+ D284BE820ADD80800027CCDF /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; };
+ D284BE830ADD80800027CCDF /* DNSDigest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F461DB5062DBF2900672BF3 /* DNSDigest.c */; };
+ D284BE850ADD80800027CCDF /* mDNSDebug.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */; };
+ D284BE860ADD80800027CCDF /* uds_daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = F525E72804AA167501F1CF4D /* uds_daemon.c */; };
+ D284BE870ADD80800027CCDF /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
+ D284BE880ADD80800027CCDF /* PlatformCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FFCB6D73075D539900B8AF62 /* PlatformCommon.c */; };
+ D284BE890ADD80800027CCDF /* mDNSMacOSX.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */; };
+ D284BE8A0ADD80800027CCDF /* LegacyNATTraversal.c in Sources */ = {isa = PBXBuildFile; fileRef = 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */; };
+ D284BE8B0ADD80800027CCDF /* daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEC022EAF7200000109 /* daemon.c */; };
+ D284BE8D0ADD80800027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
+ D284BE8E0ADD80800027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
+ D284BE8F0ADD80800027CCDF /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; };
+ D284BE900ADD80800027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
+ D284BEA80ADD80920027CCDF /* dns-sd.c in Sources */ = {isa = PBXBuildFile; fileRef = FF1C919F07021E3F001048AB /* dns-sd.c */; };
+ D284BEAC0ADD80920027CCDF /* dns-sd.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FF1C919D07021D77001048AB /* dns-sd.1 */; };
+ D284BEB70ADD809A0027CCDF /* JNISupport.c in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC44B0662DD1100335AB3 /* JNISupport.c */; };
+ D284BEB90ADD809A0027CCDF /* JavaVM.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB2CC4680662DFF500335AB3 /* JavaVM.framework */; };
+ D284BEC50ADD80A20027CCDF /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; };
+ D284BEC60ADD80A20027CCDF /* DNSDigest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F461DB5062DBF2900672BF3 /* DNSDigest.c */; };
+ D284BEC70ADD80A20027CCDF /* dnsextd.c in Sources */ = {isa = PBXBuildFile; fileRef = FF25794606C9A8BF00376F7B /* dnsextd.c */; };
+ D284BEC80ADD80A20027CCDF /* mDNSDebug.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */; };
+ D284BEC90ADD80A20027CCDF /* GenLinkedList.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE2C057E8F660085CAD0 /* GenLinkedList.c */; };
+ D284BECA0ADD80A20027CCDF /* mDNSMacOSX.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */; };
+ D284BECB0ADD80A20027CCDF /* dnsextd_lexer.l in Sources */ = {isa = PBXBuildFile; fileRef = FF13FFEA0A5DA44A00897C81 /* dnsextd_lexer.l */; settings = {COMPILER_FLAGS = "-Wno-error"; }; };
+ D284BECC0ADD80A20027CCDF /* dnsextd_parser.y in Sources */ = {isa = PBXBuildFile; fileRef = FF13FFEC0A5DA45500897C81 /* dnsextd_parser.y */; };
+ D284BECD0ADD80A20027CCDF /* PlatformCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FFCB6D73075D539900B8AF62 /* PlatformCommon.c */; };
+ D284BECF0ADD80A20027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
+ D284BED00ADD80A20027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
+ D284BED10ADD80A20027CCDF /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; };
+ D284BED20ADD80A20027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
+ D284BED50ADD80A20027CCDF /* dnsextd.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FFF4F63A06CFE4DD00459EFD /* dnsextd.8 */; };
+ D284BEDE0ADD80A70027CCDF /* ddnswriteconfig.m in Sources */ = {isa = PBXBuildFile; fileRef = FFFB0DAF07B43CBA00B88D48 /* ddnswriteconfig.m */; };
+ D284BEE00ADD80A70027CCDF /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FFFB0DB407B43D2700B88D48 /* Foundation.framework */; };
+ D284BEE10ADD80A70027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
+ D284BEE20ADD80A70027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
+ D284BEE30ADD80A70027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
+ D284BEEF0ADD80B00027CCDF /* remove_idle.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2407B4464B00CE10E5 /* remove_idle.tiff */; };
+ D284BEF00ADD80B00027CCDF /* add_pressed.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2507B4464B00CE10E5 /* add_pressed.tiff */; };
+ D284BEF10ADD80B00027CCDF /* remove_disabled.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2607B4464B00CE10E5 /* remove_disabled.tiff */; };
+ D284BEF20ADD80B00027CCDF /* add_idle.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2707B4464B00CE10E5 /* add_idle.tiff */; };
+ D284BEF30ADD80B00027CCDF /* success.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2807B4464B00CE10E5 /* success.tiff */; };
+ D284BEF40ADD80B00027CCDF /* remove_pressed.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2907B4464B00CE10E5 /* remove_pressed.tiff */; };
+ D284BEF50ADD80B00027CCDF /* failure.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2A07B4464B00CE10E5 /* failure.tiff */; };
+ D284BEF60ADD80B00027CCDF /* BonjourPref.icns in Resources */ = {isa = PBXBuildFile; fileRef = FF260A3207B4466900CE10E5 /* BonjourPref.icns */; };
+ D284BEF70ADD80B00027CCDF /* BonjourPref.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A3307B4466900CE10E5 /* BonjourPref.tiff */; };
+ D284BEF80ADD80B00027CCDF /* DNSServiceDiscoveryPref.nib in Resources */ = {isa = PBXBuildFile; fileRef = FF260A4807B4475600CE10E5 /* DNSServiceDiscoveryPref.nib */; };
+ D284BEF90ADD80B00027CCDF /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FF260A4B07B4477F00CE10E5 /* InfoPlist.strings */; };
+ D284BEFB0ADD80B00027CCDF /* inprogress.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF08480607CEB8E800AE6769 /* inprogress.tiff */; };
+ D284BEFC0ADD80B00027CCDF /* installtool in Resources */ = {isa = PBXBuildFile; fileRef = FF354EB108516C63007C00E1 /* installtool */; };
+ D284BEFE0ADD80B00027CCDF /* DNSServiceDiscoveryPref.m in Sources */ = {isa = PBXBuildFile; fileRef = FFFB0DAC07B43CBA00B88D48 /* DNSServiceDiscoveryPref.m */; };
+ D284BEFF0ADD80B00027CCDF /* PrivilegedOperations.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFB0DAD07B43CBA00B88D48 /* PrivilegedOperations.c */; };
+ D284BF000ADD80B00027CCDF /* ConfigurationAuthority.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFB0DAE07B43CBA00B88D48 /* ConfigurationAuthority.c */; };
+ D284BF020ADD80B00027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
+ D284BF030ADD80B00027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
+ D284BF040ADD80B00027CCDF /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF2609FA07B4433800CE10E5 /* Cocoa.framework */; };
+ D284BF050ADD80B00027CCDF /* PreferencePanes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */; };
+ D284BF060ADD80B00027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
+ FFA572330AF18F1C0055A0F1 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
+ FFA572340AF18F1C0055A0F1 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; };
+ FFA572350AF18F1C0055A0F1 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; };
+ FFA5723F0AF18F450055A0F1 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
+ FFA572400AF18F450055A0F1 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; };
+ FFA572410AF18F450055A0F1 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; };
+ FFA572490AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; };
+ FFA5724A0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; };
+ FFA5724B0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; };
+ FFAE66F0105F0CD900162116 /* ddnswriteconfig in Resources */ = {isa = PBXBuildFile; fileRef = D284BEE80ADD80A70027CCDF /* ddnswriteconfig */; };
+ FFB437150EB165BD00E17C68 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; };
+ FFC22AA20B00F42A00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; };
+ FFC22AA30B00F42B00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; };
+ FFC22AA40B00F42C00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; };
+ FFC22AA50B00F43000BAB070 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; };
+ FFC22AA60B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; };
+ FFC22AA70B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; };
+ FFF589B70E37F66800EF515C /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; };
+ FFF589C10E37F67E00EF515C /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; };
+ FFFA38630AEEDB090065B80A /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; };
+ FFFA38650AEEDB130065B80A /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; };
+ FFFA38660AEEDB2B0065B80A /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
+ FFFF8F810C3307C400722979 /* dnsextd.conf in CopyFiles */ = {isa = PBXBuildFile; fileRef = FFFF8F800C3307AC00722979 /* dnsextd.conf */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXBuildRule section */
+ D284BF750ADD850C0027CCDF /* PBXBuildRule */ = {
+ isa = PBXBuildRule;
+ compilerSpec = com.apple.compilers.proxy.script;
+ fileType = sourcecode.yacc;
+ isEditable = 1;
+ outputFiles = (
+ "$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).h",
+ "$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).c",
+ );
+ script = "echo NOOP yacc ${INPUT_FILE_PATH}";
+ };
+ D284BFB80ADD8E510027CCDF /* PBXBuildRule */ = {
+ isa = PBXBuildRule;
+ compilerSpec = com.apple.compilers.proxy.script;
+ fileType = sourcecode.lex;
+ isEditable = 1;
+ outputFiles = (
+ "$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).c",
+ );
+ script = "/usr/bin/flex -i -o${DERIVED_FILE_DIR}/${INPUT_FILE_BASE}.c ${INPUT_FILE_PATH}";
+ };
+/* End PBXBuildRule section */
+
+/* Begin PBXContainerItemProxy section */
+ 03067D670C83A3830022BE1F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = D284BE500ADD80740027CCDF;
+ remoteInfo = mDNSResponder;
+ };
+ 03067D690C83A3890022BE1F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = D284BE750ADD80800027CCDF;
+ remoteInfo = "mDNSResponder debug";
+ };
+ 03067D6B0C83A3920022BE1F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = D284BEA50ADD80920027CCDF;
+ remoteInfo = "dns-sd tool";
+ };
+ 03067D6D0C83A39C0022BE1F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 2E0405EF0C31955500F13B59;
+ remoteInfo = mDNSResponderHelper;
+ };
+ 03067D850C849CC30022BE1F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 03067D640C83A3700022BE1F;
+ remoteInfo = "Build Some";
+ };
+ 2130257012400E9300AC839F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FFA572650AF190F10055A0F1;
+ remoteInfo = SystemLibrariesDynamic;
+ };
+ 2141DCFC123FFB7D0086D23E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 2141DCF8123FFB5D0086D23E;
+ remoteInfo = SystemLibraries;
+ };
+ 2141DD0D123FFC960086D23E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 2141DD0B123FFC7F0086D23E;
+ remoteInfo = SystemLibrariesStatic;
+ };
+ 215FFB18124002C100470DE1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 2141DD1C123FFCDB0086D23E;
+ remoteInfo = libdns_sd_static;
+ };
+ 215FFB1A124002C700470DE1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 2141DD23123FFD0F0086D23E;
+ remoteInfo = libdns_sd_debug_static;
+ };
+ 215FFB1C124002CC00470DE1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 2141DD29123FFD2C0086D23E;
+ remoteInfo = libdns_sd_profile_static;
+ };
+ 217A4C48138EE14C000A5BA8 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 213FB21712028A7A002B3A08;
+ remoteInfo = BonjourEvents;
+ };
+ 4AE471690EAFF83800A6C5AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4AE471670EAFF81900A6C5AD;
+ remoteInfo = dns_sd.jar;
+ };
+ 84C5B3401665544B00C324A8 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 84C5B3341665529800C324A8;
+ remoteInfo = dns_services;
+ };
+ D284BF2B0ADD815A0027CCDF /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = D284BEBF0ADD80A20027CCDF;
+ remoteInfo = dnsextd;
+ };
+ D284BF2D0ADD81600027CCDF /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = D284BEDB0ADD80A70027CCDF;
+ remoteInfo = ddnswriteconfig;
+ };
+ D284BF2F0ADD81630027CCDF /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = D284BEEA0ADD80B00027CCDF;
+ remoteInfo = PreferencePane;
+ };
+ FFA572680AF190FF0055A0F1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FFB765830AEED9C700583A2C;
+ remoteInfo = libdns_sd;
+ };
+ FFA5726A0AF191010055A0F1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FFA572300AF18F1C0055A0F1;
+ remoteInfo = "libdns_sd debug";
+ };
+ FFA5726C0AF191020055A0F1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FFA5723C0AF18F450055A0F1;
+ remoteInfo = "libdns_sd profile";
+ };
+ FFAE66F8105F0CF100162116 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = D284BEDB0ADD80A70027CCDF;
+ remoteInfo = ddnswriteconfig;
+ };
+ FFB7657C0AEED97F00583A2C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 00AD62BB032D7A0C0CCA2C71;
+ remoteInfo = "Build Main";
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 4A7B9E7F14FDA21B00B84CC1 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/local/OpenSourceVersions;
+ dstSubfolderSpec = 0;
+ files = (
+ 4A7B9E8014FDA25000B84CC1 /* mDNSResponder.plist in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4A7B9E8114FDA25500B84CC1 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/local/OpenSourceLicenses;
+ dstSubfolderSpec = 0;
+ files = (
+ 4A7B9E8214FDA26C00B84CC1 /* mDNSResponder.txt in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4AAE0C5A0C68E6EC003882A5 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 4AAE0C9A0C68EA81003882A5 /* mDNSResponderHelper.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 72FB545D166D5FB00090B2D9 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 12;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 8418673D15AB8BFF00BB7F70 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /private/etc/asl/;
+ dstSubfolderSpec = 0;
+ files = (
+ 8418673E15AB8C2D00BB7F70 /* com.apple.networking.mDNSResponder in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ D284BE6A0ADD80740027CCDF /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ D284BE6B0ADD80740027CCDF /* mDNSResponder.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ D284BEAB0ADD80920027CCDF /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ D284BEAC0ADD80920027CCDF /* dns-sd.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ D284BED40ADD80A20027CCDF /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ D284BED50ADD80A20027CCDF /* dnsextd.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FFFF8F770C32F0FD00722979 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /private/etc;
+ dstSubfolderSpec = 0;
+ files = (
+ FFFF8F810C3307C400722979 /* dnsextd.conf in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 000753D303367C1C0CCA2C71 /* mDNSMacOSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mDNSMacOSX.h; sourceTree = "<group>"; };
+ 00CA213D02786FC30CCA2C71 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = "<absolute>"; };
+ 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
+ 21070E5D16486B9000A69507 /* DNSSECSupport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = DNSSECSupport.c; sourceTree = "<group>"; };
+ 21070E5E16486B9000A69507 /* DNSSECSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNSSECSupport.h; sourceTree = "<group>"; };
+ 2120ABD416B71614007089B6 /* CUPolicy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CUPolicy.c; sourceTree = "<group>"; };
+ 2124FA2B1471E98C0021D7BB /* nsec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nsec.h; path = ../mDNSCore/nsec.h; sourceTree = "<group>"; };
+ 2124FA2F1471E9B50021D7BB /* dnssec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dnssec.h; path = ../mDNSCore/dnssec.h; sourceTree = "<group>"; };
+ 2124FA321471E9DE0021D7BB /* nsec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = nsec.c; path = ../mDNSCore/nsec.c; sourceTree = "<group>"; };
+ 2127A47515C3C7B900A857FC /* nsec3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = nsec3.c; path = ../mDNSCore/nsec3.c; sourceTree = "<group>"; };
+ 2127A47615C3C7B900A857FC /* nsec3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nsec3.h; path = ../mDNSCore/nsec3.h; sourceTree = "<group>"; };
+ 213BDC6C147319F400000896 /* dnssec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssec.c; path = ../mDNSCore/dnssec.c; sourceTree = "<group>"; };
+ 213FB21812028A7A002B3A08 /* BonjourEvents.plugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BonjourEvents.plugin; sourceTree = BUILT_PRODUCTS_DIR; };
+ 213FB22C12028B53002B3A08 /* BonjourEvents.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = BonjourEvents.c; sourceTree = "<group>"; };
+ 213FB22D12028B53002B3A08 /* BonjourEvents-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "BonjourEvents-Info.plist"; sourceTree = "<group>"; };
+ 2141DD1D123FFCDB0086D23E /* libdns_sd.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdns_sd.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2141DD24123FFD0F0086D23E /* libdns_sd_debug.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdns_sd_debug.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2141DD2A123FFD2C0086D23E /* libdns_sd_profile.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdns_sd_profile.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 216D9ACD1720C9F5008066E1 /* VPNService.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = VPNService.c; sourceTree = "<group>"; };
+ 218E8E4F156D8C0300720DA0 /* dnsproxy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnsproxy.c; path = ../mDNSCore/dnsproxy.c; sourceTree = "<group>"; };
+ 218E8E50156D8C0300720DA0 /* dnsproxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dnsproxy.h; path = ../mDNSCore/dnsproxy.h; sourceTree = "<group>"; };
+ 219D5541149ED645004464AE /* libxml2.2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxml2.2.dylib; path = SDKs/MacOSX10.8.sdk/usr/lib/libxml2.2.dylib; sourceTree = DEVELOPER_DIR; };
+ 21A57F4A145B2AE100939099 /* CryptoAlg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = CryptoAlg.c; path = ../mDNSCore/CryptoAlg.c; sourceTree = "<group>"; };
+ 21A57F4B145B2AE100939099 /* CryptoAlg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CryptoAlg.h; path = ../mDNSCore/CryptoAlg.h; sourceTree = "<group>"; };
+ 21A57F51145B2B1400939099 /* CryptoSupport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CryptoSupport.c; sourceTree = "<group>"; };
+ 21A57F52145B2B1400939099 /* CryptoSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoSupport.h; sourceTree = "<group>"; };
+ 21DD8FBD161E9A250033C8F8 /* anonymous.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = anonymous.c; path = ../mDNSCore/anonymous.c; sourceTree = "<group>"; };
+ 21DD8FBE161E9A250033C8F8 /* anonymous.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = anonymous.h; path = ../mDNSCore/anonymous.h; sourceTree = "<group>"; };
+ 21DED43415702C0F0060B6B9 /* DNSProxySupport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = DNSProxySupport.c; sourceTree = "<group>"; };
+ 21F432971134AA6800581B69 /* WebFilterDNS.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebFilterDNS.framework; path = /System/Library/PrivateFrameworks/WebFilterDNS.framework; sourceTree = "<absolute>"; };
+ 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.mig; path = helpermsg.defs; sourceTree = "<group>"; };
+ 2E0405F00C31955500F13B59 /* mDNSResponderHelper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSResponderHelper; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2E0405F40C3195F700F13B59 /* helper.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = helper.c; sourceTree = "<group>"; };
+ 2E0406140C3197CB00F13B59 /* libbsm.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbsm.dylib; path = /usr/lib/libbsm.dylib; sourceTree = "<absolute>"; };
+ 2E0406CA0C31E9AD00F13B59 /* helper-main.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = "helper-main.c"; sourceTree = "<group>"; };
+ 2E35528F0C3A95C100CA1CB7 /* helper-error.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "helper-error.h"; sourceTree = "<group>"; };
+ 2E8165F60C59835F00485EB2 /* libipsec.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libipsec.dylib; path = /usr/lib/libipsec.dylib; sourceTree = "<absolute>"; };
+ 2E96A5250C39BE480087C4D2 /* helper.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = helper.h; sourceTree = "<group>"; };
+ 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "helper-stubs.c"; sourceTree = "<group>"; };
+ 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "helpermsg-types.h"; sourceTree = "<group>"; };
+ 2EDC5E720C39EA640092701B /* helper-server.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "helper-server.h"; sourceTree = "<group>"; };
+ 3F347CF5185D57CD00367B40 /* base.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = base.xcconfig; sourceTree = "<group>"; };
+ 4A2E69DD0F5475A3004A87B0 /* uds_daemon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = uds_daemon.h; path = ../mDNSShared/uds_daemon.h; sourceTree = SOURCE_ROOT; };
+ 4A3600DF0F34F8CD00453EFB /* DeviceToDeviceManager.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DeviceToDeviceManager.framework; path = /System/Library/PrivateFrameworks/DeviceToDeviceManager.framework; sourceTree = "<absolute>"; };
+ 4A7B9E7C14FDA19F00B84CC1 /* mDNSResponder.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = mDNSResponder.txt; sourceTree = "<group>"; };
+ 4A7B9E7E14FDA1BB00B84CC1 /* mDNSResponder.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = mDNSResponder.plist; sourceTree = "<group>"; };
+ 4A8202510C56C36500DDFD48 /* ipsec_strerror.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ipsec_strerror.h; sourceTree = "<group>"; };
+ 4A8202520C56C36500DDFD48 /* libpfkey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libpfkey.h; sourceTree = "<group>"; };
+ 4A8202530C56C36600DDFD48 /* pfkey.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pfkey.c; sourceTree = "<group>"; };
+ 4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mDNSResponderHelper.8; sourceTree = SOURCE_ROOT; };
+ 4ADB5F230F6AB9F400B95BF3 /* helper-entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "helper-entitlements.plist"; sourceTree = "<group>"; };
+ 4BD2B638134FE09F002B96D5 /* P2PPacketFilter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = P2PPacketFilter.c; sourceTree = "<group>"; };
+ 4BD2B639134FE09F002B96D5 /* P2PPacketFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = P2PPacketFilter.h; sourceTree = "<group>"; };
+ 654BE64F02B63B93000001D1 /* mDNSEmbeddedAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mDNSEmbeddedAPI.h; path = ../mDNSCore/mDNSEmbeddedAPI.h; sourceTree = "<group>"; };
+ 654BE65002B63B93000001D1 /* mDNSDebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mDNSDebug.h; path = ../mDNSCore/mDNSDebug.h; sourceTree = "<group>"; };
+ 65713D46025A293200000109 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = /System/Library/Frameworks/SystemConfiguration.framework; sourceTree = "<absolute>"; };
+ 6575FBE9022EAF5A00000109 /* mDNS.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = mDNS.c; path = ../mDNSCore/mDNS.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = mDNSMacOSX.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ 6575FBEC022EAF7200000109 /* daemon.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = daemon.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+ 6575FBFF022EAFBA00000109 /* DNSServiceDiscoveryDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNSServiceDiscoveryDefines.h; sourceTree = "<group>"; };
+ 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; path = DNSServiceDiscoveryReply.defs; sourceTree = "<group>"; };
+ 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; path = DNSServiceDiscoveryRequest.defs; sourceTree = "<group>"; };
+ 6575FC20022EB7AA00000109 /* SamplemDNSClient.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = SamplemDNSClient.c; sourceTree = SOURCE_ROOT; tabWidth = 4; usesTabs = 0; };
+ 72FB545A166D5F960090B2D9 /* dnsctl.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dnsctl.c; path = ../Clients/dnsctl.c; sourceTree = "<group>"; };
+ 72FB545F166D5FB00090B2D9 /* dnsctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dnsctl; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7F18A9F60587CEF6001880B3 /* DNSCommon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = DNSCommon.c; path = ../mDNSCore/DNSCommon.c; sourceTree = SOURCE_ROOT; };
+ 7F18A9F70587CEF6001880B3 /* uDNS.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = uDNS.c; path = ../mDNSCore/uDNS.c; sourceTree = SOURCE_ROOT; };
+ 7F461DB5062DBF2900672BF3 /* DNSDigest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = DNSDigest.c; path = ../mDNSCore/DNSDigest.c; sourceTree = SOURCE_ROOT; };
+ 7F869685066EE02400D2A2DC /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = "<absolute>"; };
+ 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = LegacyNATTraversal.c; sourceTree = SOURCE_ROOT; };
+ 8415A6561897109000BDBA26 /* libdns_services.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libdns_services.dylib; path = ../../../../../../../usr/lib/libdns_services.dylib; sourceTree = "<group>"; };
+ 8418673A15AB8B6900BB7F70 /* com.apple.networking.mDNSResponder */ = {isa = PBXFileReference; lastKnownFileType = text; path = com.apple.networking.mDNSResponder; sourceTree = "<group>"; };
+ 8418673C15AB8B8000BB7F70 /* mDNSResponderLogging.mobileconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = mDNSResponderLogging.mobileconfig; sourceTree = "<group>"; };
+ 848DA5C6165477E000D2E8B4 /* xpc_services.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = xpc_services.c; path = Private/xpc_services.c; sourceTree = "<group>"; };
+ 848DA5C9165477EB00D2E8B4 /* xpc_services.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = xpc_services.h; path = Private/xpc_services.h; sourceTree = "<group>"; };
+ 848DA5D516547F7200D2E8B4 /* dns_xpc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dns_xpc.h; path = Private/dns_xpc.h; sourceTree = "<group>"; };
+ 84C5B3351665529800C324A8 /* libdns_services_mdns.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libdns_services_mdns.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+ 84C5B339166553AF00C324A8 /* dns_services.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dns_services.c; path = Private/dns_services.c; sourceTree = "<group>"; };
+ 84F4C08F188F04CF00D1E1DE /* dns_services_mdns.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dns_services_mdns.h; path = Private/dns_services_mdns.h; sourceTree = "<group>"; };
+ D284BE730ADD80740027CCDF /* mDNSResponder */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSResponder; sourceTree = BUILT_PRODUCTS_DIR; };
+ D284BE950ADD80800027CCDF /* mDNSResponder.debug */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSResponder.debug; sourceTree = BUILT_PRODUCTS_DIR; };
+ D284BEB00ADD80920027CCDF /* dns-sd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "dns-sd"; sourceTree = BUILT_PRODUCTS_DIR; };
+ D284BEBE0ADD809A0027CCDF /* libjdns_sd.jnilib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libjdns_sd.jnilib; sourceTree = BUILT_PRODUCTS_DIR; };
+ D284BED90ADD80A20027CCDF /* dnsextd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dnsextd; sourceTree = BUILT_PRODUCTS_DIR; };
+ D284BEE80ADD80A70027CCDF /* ddnswriteconfig */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ddnswriteconfig; sourceTree = BUILT_PRODUCTS_DIR; };
+ D284BF0C0ADD80B00027CCDF /* Bonjour.prefPane */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Bonjour.prefPane; sourceTree = BUILT_PRODUCTS_DIR; };
+ D284C04D0ADD95D30027CCDF /* Info-PreferencePane.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "Info-PreferencePane.plist"; path = "PreferencePane/Info-PreferencePane.plist"; sourceTree = "<group>"; };
+ DB2CC4430662DD1100335AB3 /* BaseListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = BaseListener.java; path = ../mDNSShared/Java/BaseListener.java; sourceTree = SOURCE_ROOT; };
+ DB2CC4440662DD1100335AB3 /* BrowseListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = BrowseListener.java; path = ../mDNSShared/Java/BrowseListener.java; sourceTree = SOURCE_ROOT; };
+ DB2CC4450662DD1100335AB3 /* DNSRecord.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSRecord.java; path = ../mDNSShared/Java/DNSRecord.java; sourceTree = SOURCE_ROOT; };
+ DB2CC4460662DD1100335AB3 /* DNSSD.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSD.java; path = ../mDNSShared/Java/DNSSD.java; sourceTree = SOURCE_ROOT; };
+ DB2CC4470662DD1100335AB3 /* DNSSDException.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSDException.java; path = ../mDNSShared/Java/DNSSDException.java; sourceTree = SOURCE_ROOT; };
+ DB2CC4480662DD1100335AB3 /* DNSSDRegistration.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSDRegistration.java; path = ../mDNSShared/Java/DNSSDRegistration.java; sourceTree = SOURCE_ROOT; };
+ DB2CC4490662DD1100335AB3 /* DNSSDService.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSDService.java; path = ../mDNSShared/Java/DNSSDService.java; sourceTree = SOURCE_ROOT; };
+ DB2CC44A0662DD1100335AB3 /* DomainListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DomainListener.java; path = ../mDNSShared/Java/DomainListener.java; sourceTree = SOURCE_ROOT; };
+ DB2CC44B0662DD1100335AB3 /* JNISupport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = JNISupport.c; path = ../mDNSShared/Java/JNISupport.c; sourceTree = SOURCE_ROOT; };
+ DB2CC44C0662DD1100335AB3 /* QueryListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = QueryListener.java; path = ../mDNSShared/Java/QueryListener.java; sourceTree = SOURCE_ROOT; };
+ DB2CC44D0662DD1100335AB3 /* RegisterListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = RegisterListener.java; path = ../mDNSShared/Java/RegisterListener.java; sourceTree = SOURCE_ROOT; };
+ DB2CC44E0662DD1100335AB3 /* ResolveListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = ResolveListener.java; path = ../mDNSShared/Java/ResolveListener.java; sourceTree = SOURCE_ROOT; };
+ DB2CC44F0662DD1100335AB3 /* TXTRecord.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = TXTRecord.java; path = ../mDNSShared/Java/TXTRecord.java; sourceTree = SOURCE_ROOT; };
+ DB2CC4680662DFF500335AB3 /* JavaVM.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaVM.framework; path = /System/Library/Frameworks/JavaVM.framework; sourceTree = "<absolute>"; };
+ DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mDNSDebug.c; path = ../mDNSShared/mDNSDebug.c; sourceTree = SOURCE_ROOT; };
+ DBAAFE2C057E8F660085CAD0 /* GenLinkedList.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = GenLinkedList.c; path = ../mDNSShared/GenLinkedList.c; sourceTree = SOURCE_ROOT; };
+ F525E72804AA167501F1CF4D /* uds_daemon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = uds_daemon.c; path = ../mDNSShared/uds_daemon.c; sourceTree = SOURCE_ROOT; };
+ F5E11B5A04A28126019798ED /* dnssd_ipc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssd_ipc.c; path = ../mDNSShared/dnssd_ipc.c; sourceTree = SOURCE_ROOT; };
+ F5E11B5B04A28126019798ED /* dnssd_ipc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dnssd_ipc.h; path = ../mDNSShared/dnssd_ipc.h; sourceTree = SOURCE_ROOT; };
+ FF08480607CEB8E800AE6769 /* inprogress.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = inprogress.tiff; path = PreferencePane/Artwork/inprogress.tiff; sourceTree = SOURCE_ROOT; };
+ FF13FFEA0A5DA44A00897C81 /* dnsextd_lexer.l */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.lex; name = dnsextd_lexer.l; path = ../mDNSShared/dnsextd_lexer.l; sourceTree = SOURCE_ROOT; };
+ FF13FFEC0A5DA45500897C81 /* dnsextd_parser.y */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.yacc; name = dnsextd_parser.y; path = ../mDNSShared/dnsextd_parser.y; sourceTree = SOURCE_ROOT; };
+ FF1C919D07021D77001048AB /* dns-sd.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = "dns-sd.1"; path = "../mDNSShared/dns-sd.1"; sourceTree = SOURCE_ROOT; };
+ FF1C919F07021E3F001048AB /* dns-sd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "dns-sd.c"; path = "../Clients/dns-sd.c"; sourceTree = SOURCE_ROOT; };
+ FF25794606C9A8BF00376F7B /* dnsextd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnsextd.c; path = ../mDNSShared/dnsextd.c; sourceTree = SOURCE_ROOT; };
+ FF2609FA07B4433800CE10E5 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
+ FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PreferencePanes.framework; path = /System/Library/Frameworks/PreferencePanes.framework; sourceTree = "<absolute>"; };
+ FF260A2407B4464B00CE10E5 /* remove_idle.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = remove_idle.tiff; path = PreferencePane/Artwork/remove_idle.tiff; sourceTree = SOURCE_ROOT; };
+ FF260A2507B4464B00CE10E5 /* add_pressed.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = add_pressed.tiff; path = PreferencePane/Artwork/add_pressed.tiff; sourceTree = SOURCE_ROOT; };
+ FF260A2607B4464B00CE10E5 /* remove_disabled.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = remove_disabled.tiff; path = PreferencePane/Artwork/remove_disabled.tiff; sourceTree = SOURCE_ROOT; };
+ FF260A2707B4464B00CE10E5 /* add_idle.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = add_idle.tiff; path = PreferencePane/Artwork/add_idle.tiff; sourceTree = SOURCE_ROOT; };
+ FF260A2807B4464B00CE10E5 /* success.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = success.tiff; path = PreferencePane/Artwork/success.tiff; sourceTree = SOURCE_ROOT; };
+ FF260A2907B4464B00CE10E5 /* remove_pressed.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = remove_pressed.tiff; path = PreferencePane/Artwork/remove_pressed.tiff; sourceTree = SOURCE_ROOT; };
+ FF260A2A07B4464B00CE10E5 /* failure.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = failure.tiff; path = PreferencePane/Artwork/failure.tiff; sourceTree = SOURCE_ROOT; };
+ FF260A3207B4466900CE10E5 /* BonjourPref.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = BonjourPref.icns; path = PreferencePane/BonjourPref.icns; sourceTree = SOURCE_ROOT; };
+ FF260A3307B4466900CE10E5 /* BonjourPref.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = BonjourPref.tiff; path = PreferencePane/BonjourPref.tiff; sourceTree = SOURCE_ROOT; };
+ FF260A4907B4475600CE10E5 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib; sourceTree = SOURCE_ROOT; };
+ FF260A4C07B4477F00CE10E5 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = PreferencePane/English.lproj/InfoPlist.strings; sourceTree = SOURCE_ROOT; };
+ FF2C5FB00A48B8680066DA11 /* DNSSDRecordRegistrar.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSDRecordRegistrar.java; path = ../mDNSShared/Java/DNSSDRecordRegistrar.java; sourceTree = SOURCE_ROOT; };
+ FF2C5FB20A48B86E0066DA11 /* RegisterRecordListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = RegisterRecordListener.java; path = ../mDNSShared/Java/RegisterRecordListener.java; sourceTree = SOURCE_ROOT; };
+ FF354EB108516C63007C00E1 /* installtool */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; name = installtool; path = PreferencePane/installtool; sourceTree = SOURCE_ROOT; };
+ FF485D5105632E0000130380 /* mDNSResponder.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = mDNSResponder.8; path = ../mDNSShared/mDNSResponder.8; sourceTree = SOURCE_ROOT; };
+ FF5852100DD27BD300862BDF /* ClientCommon.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = ClientCommon.c; path = ../Clients/ClientCommon.c; sourceTree = SOURCE_ROOT; };
+ FF85880B0BD599F40080D89F /* mDNSResponder.sb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mDNSResponder.sb; sourceTree = SOURCE_ROOT; };
+ FFA572390AF18F1C0055A0F1 /* libsystem_dnssd_debug.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libsystem_dnssd_debug.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+ FFA572450AF18F450055A0F1 /* libsystem_dnssd_profile.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libsystem_dnssd_profile.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+ FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = DNSServiceDiscovery.c; sourceTree = "<group>"; };
+ FFA572600AF1908D0055A0F1 /* DNSServiceDiscovery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNSServiceDiscovery.h; sourceTree = "<group>"; };
+ FFA572630AF190C20055A0F1 /* dns_sd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dns_sd.h; path = ../mDNSShared/dns_sd.h; sourceTree = SOURCE_ROOT; };
+ FFB765840AEED9C700583A2C /* libsystem_dnssd.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libsystem_dnssd.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+ FFCB6D73075D539900B8AF62 /* PlatformCommon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = PlatformCommon.c; path = ../mDNSShared/PlatformCommon.c; sourceTree = SOURCE_ROOT; };
+ FFE6935007C2CA7F00283007 /* ConfigurationAuthority.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ConfigurationAuthority.h; path = PreferencePane/ConfigurationAuthority.h; sourceTree = SOURCE_ROOT; };
+ FFE6935207C2CAA400283007 /* DNSServiceDiscoveryPref.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DNSServiceDiscoveryPref.h; path = PreferencePane/DNSServiceDiscoveryPref.h; sourceTree = SOURCE_ROOT; };
+ FFE6935407C2CABD00283007 /* PrivilegedOperations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PrivilegedOperations.h; path = PreferencePane/PrivilegedOperations.h; sourceTree = SOURCE_ROOT; };
+ FFF4F63A06CFE4DD00459EFD /* dnsextd.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = dnsextd.8; path = ../mDNSShared/dnsextd.8; sourceTree = SOURCE_ROOT; };
+ FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssd_clientlib.c; path = ../mDNSShared/dnssd_clientlib.c; sourceTree = SOURCE_ROOT; };
+ FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssd_clientstub.c; path = ../mDNSShared/dnssd_clientstub.c; sourceTree = SOURCE_ROOT; };
+ FFFB0DAC07B43CBA00B88D48 /* DNSServiceDiscoveryPref.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNSServiceDiscoveryPref.m; sourceTree = "<group>"; };
+ FFFB0DAD07B43CBA00B88D48 /* PrivilegedOperations.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = PrivilegedOperations.c; sourceTree = "<group>"; };
+ FFFB0DAE07B43CBA00B88D48 /* ConfigurationAuthority.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ConfigurationAuthority.c; sourceTree = "<group>"; };
+ FFFB0DAF07B43CBA00B88D48 /* ddnswriteconfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ddnswriteconfig.m; sourceTree = "<group>"; };
+ FFFB0DB407B43D2700B88D48 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
+ FFFF8F800C3307AC00722979 /* dnsextd.conf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = dnsextd.conf; path = ../mDNSShared/dnsextd.conf; sourceTree = SOURCE_ROOT; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 213FB21612028A7A002B3A08 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 213FB23D12028C5A002B3A08 /* CoreFoundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2141DD1B123FFCDB0086D23E /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2141DD22123FFD0F0086D23E /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2141DD28123FFD2C0086D23E /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2E0405EE0C31955500F13B59 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FFB437150EB165BD00E17C68 /* IOKit.framework in Frameworks */,
+ 2E0406150C3197CB00F13B59 /* libbsm.dylib in Frameworks */,
+ 2E04070A0C31EEEC00F13B59 /* CoreFoundation.framework in Frameworks */,
+ 2E04070B0C31EEEC00F13B59 /* SystemConfiguration.framework in Frameworks */,
+ 2E4D9B050C38C19500480551 /* Security.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72FB545C166D5FB00090B2D9 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8415A6571897109000BDBA26 /* libdns_services.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 84C5B3321665529800C324A8 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BE640ADD80740027CCDF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BE650ADD80740027CCDF /* CoreFoundation.framework in Frameworks */,
+ D284BE660ADD80740027CCDF /* SystemConfiguration.framework in Frameworks */,
+ D284BE670ADD80740027CCDF /* IOKit.framework in Frameworks */,
+ D284BE680ADD80740027CCDF /* Security.framework in Frameworks */,
+ 219D5542149ED645004464AE /* libxml2.2.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BE8C0ADD80800027CCDF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BE8D0ADD80800027CCDF /* CoreFoundation.framework in Frameworks */,
+ D284BE8E0ADD80800027CCDF /* SystemConfiguration.framework in Frameworks */,
+ D284BE8F0ADD80800027CCDF /* IOKit.framework in Frameworks */,
+ D284BE900ADD80800027CCDF /* Security.framework in Frameworks */,
+ 219D5543149ED645004464AE /* libxml2.2.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEA90ADD80920027CCDF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEB80ADD809A0027CCDF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BEB90ADD809A0027CCDF /* JavaVM.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BECE0ADD80A20027CCDF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BECF0ADD80A20027CCDF /* CoreFoundation.framework in Frameworks */,
+ D284BED00ADD80A20027CCDF /* SystemConfiguration.framework in Frameworks */,
+ D284BED10ADD80A20027CCDF /* IOKit.framework in Frameworks */,
+ D284BED20ADD80A20027CCDF /* Security.framework in Frameworks */,
+ 2E8165F90C59838100485EB2 /* libipsec.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEDF0ADD80A70027CCDF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BEE00ADD80A70027CCDF /* Foundation.framework in Frameworks */,
+ D284BEE10ADD80A70027CCDF /* Security.framework in Frameworks */,
+ D284BEE20ADD80A70027CCDF /* SystemConfiguration.framework in Frameworks */,
+ D284BEE30ADD80A70027CCDF /* CoreFoundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BF010ADD80B00027CCDF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BF020ADD80B00027CCDF /* SystemConfiguration.framework in Frameworks */,
+ D284BF030ADD80B00027CCDF /* Security.framework in Frameworks */,
+ D284BF040ADD80B00027CCDF /* Cocoa.framework in Frameworks */,
+ D284BF050ADD80B00027CCDF /* PreferencePanes.framework in Frameworks */,
+ D284BF060ADD80B00027CCDF /* CoreFoundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FFA572360AF18F1C0055A0F1 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FFA572420AF18F450055A0F1 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FFB765820AEED9C700583A2C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 08FB7794FE84155DC02AAC07 /* mDNSResponder */ = {
+ isa = PBXGroup;
+ children = (
+ 8415A6561897109000BDBA26 /* libdns_services.dylib */,
+ 3F347CF5185D57CD00367B40 /* base.xcconfig */,
+ 08FB7795FE84155DC02AAC07 /* mDNS Server Sources */,
+ 6575FC1F022EB78C00000109 /* Command-Line Clients */,
+ 213FB20912028902002B3A08 /* Bonjour Events Plugin */,
+ 6575FBFE022EAFA800000109 /* MIG files */,
+ DB2CC4420662DCE500335AB3 /* Java Support */,
+ FFFB0DA407B43BED00B88D48 /* PreferencePane */,
+ 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
+ 19C28FBDFE9D53C911CA2CBB /* Products */,
+ );
+ name = mDNSResponder;
+ sourceTree = "<group>";
+ };
+ 08FB7795FE84155DC02AAC07 /* mDNS Server Sources */ = {
+ isa = PBXGroup;
+ children = (
+ 84F4C08F188F04CF00D1E1DE /* dns_services_mdns.h */,
+ 216D9ACD1720C9F5008066E1 /* VPNService.c */,
+ 2120ABD416B71614007089B6 /* CUPolicy.c */,
+ 72FB545A166D5F960090B2D9 /* dnsctl.c */,
+ 84C5B339166553AF00C324A8 /* dns_services.c */,
+ 848DA5D516547F7200D2E8B4 /* dns_xpc.h */,
+ 848DA5C9165477EB00D2E8B4 /* xpc_services.h */,
+ 848DA5C6165477E000D2E8B4 /* xpc_services.c */,
+ 21070E5D16486B9000A69507 /* DNSSECSupport.c */,
+ 21070E5E16486B9000A69507 /* DNSSECSupport.h */,
+ 21DD8FBD161E9A250033C8F8 /* anonymous.c */,
+ 21DD8FBE161E9A250033C8F8 /* anonymous.h */,
+ 2127A47515C3C7B900A857FC /* nsec3.c */,
+ 2127A47615C3C7B900A857FC /* nsec3.h */,
+ 8418673C15AB8B8000BB7F70 /* mDNSResponderLogging.mobileconfig */,
+ 8418673A15AB8B6900BB7F70 /* com.apple.networking.mDNSResponder */,
+ 21DED43415702C0F0060B6B9 /* DNSProxySupport.c */,
+ 218E8E4F156D8C0300720DA0 /* dnsproxy.c */,
+ 218E8E50156D8C0300720DA0 /* dnsproxy.h */,
+ 213BDC6C147319F400000896 /* dnssec.c */,
+ 2124FA321471E9DE0021D7BB /* nsec.c */,
+ 2124FA2F1471E9B50021D7BB /* dnssec.h */,
+ 2124FA2B1471E98C0021D7BB /* nsec.h */,
+ 21A57F51145B2B1400939099 /* CryptoSupport.c */,
+ 21A57F52145B2B1400939099 /* CryptoSupport.h */,
+ 21A57F4A145B2AE100939099 /* CryptoAlg.c */,
+ 21A57F4B145B2AE100939099 /* CryptoAlg.h */,
+ 4ADB5F230F6AB9F400B95BF3 /* helper-entitlements.plist */,
+ 4A2E69DD0F5475A3004A87B0 /* uds_daemon.h */,
+ 4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */,
+ 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */,
+ 2E35528F0C3A95C100CA1CB7 /* helper-error.h */,
+ 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */,
+ 2EDC5E720C39EA640092701B /* helper-server.h */,
+ 2E96A5250C39BE480087C4D2 /* helper.h */,
+ 2E0405F40C3195F700F13B59 /* helper.c */,
+ 2E0406CA0C31E9AD00F13B59 /* helper-main.c */,
+ 4A8202510C56C36500DDFD48 /* ipsec_strerror.h */,
+ 4A8202520C56C36500DDFD48 /* libpfkey.h */,
+ 4A8202530C56C36600DDFD48 /* pfkey.c */,
+ 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */,
+ 7F461DB5062DBF2900672BF3 /* DNSDigest.c */,
+ F525E72804AA167501F1CF4D /* uds_daemon.c */,
+ F5E11B5A04A28126019798ED /* dnssd_ipc.c */,
+ F5E11B5B04A28126019798ED /* dnssd_ipc.h */,
+ 6575FBEC022EAF7200000109 /* daemon.c */,
+ 6575FBE9022EAF5A00000109 /* mDNS.c */,
+ 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */,
+ 654BE64F02B63B93000001D1 /* mDNSEmbeddedAPI.h */,
+ 654BE65002B63B93000001D1 /* mDNSDebug.h */,
+ DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */,
+ 000753D303367C1C0CCA2C71 /* mDNSMacOSX.h */,
+ DBAAFE2C057E8F660085CAD0 /* GenLinkedList.c */,
+ FFCB6D73075D539900B8AF62 /* PlatformCommon.c */,
+ FF1C919D07021D77001048AB /* dns-sd.1 */,
+ FF485D5105632E0000130380 /* mDNSResponder.8 */,
+ FFF4F63A06CFE4DD00459EFD /* dnsextd.8 */,
+ FFFF8F800C3307AC00722979 /* dnsextd.conf */,
+ FF85880B0BD599F40080D89F /* mDNSResponder.sb */,
+ 4A7B9E7C14FDA19F00B84CC1 /* mDNSResponder.txt */,
+ 4A7B9E7E14FDA1BB00B84CC1 /* mDNSResponder.plist */,
+ 7F18A9F60587CEF6001880B3 /* DNSCommon.c */,
+ 7F18A9F70587CEF6001880B3 /* uDNS.c */,
+ FF25794606C9A8BF00376F7B /* dnsextd.c */,
+ FF13FFEA0A5DA44A00897C81 /* dnsextd_lexer.l */,
+ FF13FFEC0A5DA45500897C81 /* dnsextd_parser.y */,
+ FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */,
+ FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */,
+ FFA572600AF1908D0055A0F1 /* DNSServiceDiscovery.h */,
+ FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */,
+ FFA572630AF190C20055A0F1 /* dns_sd.h */,
+ 4BD2B638134FE09F002B96D5 /* P2PPacketFilter.c */,
+ 4BD2B639134FE09F002B96D5 /* P2PPacketFilter.h */,
+ );
+ name = "mDNS Server Sources";
+ sourceTree = "<group>";
+ };
+ 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ 219D5541149ED645004464AE /* libxml2.2.dylib */,
+ 4A3600DF0F34F8CD00453EFB /* DeviceToDeviceManager.framework */,
+ 2E8165F60C59835F00485EB2 /* libipsec.dylib */,
+ 65713D46025A293200000109 /* SystemConfiguration.framework */,
+ 2E0406140C3197CB00F13B59 /* libbsm.dylib */,
+ 7F869685066EE02400D2A2DC /* Security.framework */,
+ FFFB0DB407B43D2700B88D48 /* Foundation.framework */,
+ 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */,
+ 00CA213D02786FC30CCA2C71 /* IOKit.framework */,
+ DB2CC4680662DFF500335AB3 /* JavaVM.framework */,
+ FF2609FA07B4433800CE10E5 /* Cocoa.framework */,
+ FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */,
+ 21F432971134AA6800581B69 /* WebFilterDNS.framework */,
+ );
+ name = "External Frameworks and Libraries";
+ sourceTree = "<group>";
+ };
+ 19C28FBDFE9D53C911CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ D284C04D0ADD95D30027CCDF /* Info-PreferencePane.plist */,
+ D284BE730ADD80740027CCDF /* mDNSResponder */,
+ D284BE950ADD80800027CCDF /* mDNSResponder.debug */,
+ D284BEB00ADD80920027CCDF /* dns-sd */,
+ D284BEBE0ADD809A0027CCDF /* libjdns_sd.jnilib */,
+ D284BED90ADD80A20027CCDF /* dnsextd */,
+ D284BEE80ADD80A70027CCDF /* ddnswriteconfig */,
+ D284BF0C0ADD80B00027CCDF /* Bonjour.prefPane */,
+ FFB765840AEED9C700583A2C /* libsystem_dnssd.dylib */,
+ FFA572390AF18F1C0055A0F1 /* libsystem_dnssd_debug.dylib */,
+ FFA572450AF18F450055A0F1 /* libsystem_dnssd_profile.dylib */,
+ 2E0405F00C31955500F13B59 /* mDNSResponderHelper */,
+ 213FB21812028A7A002B3A08 /* BonjourEvents.plugin */,
+ 2141DD1D123FFCDB0086D23E /* libdns_sd.a */,
+ 2141DD24123FFD0F0086D23E /* libdns_sd_debug.a */,
+ 2141DD2A123FFD2C0086D23E /* libdns_sd_profile.a */,
+ 84C5B3351665529800C324A8 /* libdns_services_mdns.dylib */,
+ 72FB545F166D5FB00090B2D9 /* dnsctl */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 213FB20912028902002B3A08 /* Bonjour Events Plugin */ = {
+ isa = PBXGroup;
+ children = (
+ 213FB22C12028B53002B3A08 /* BonjourEvents.c */,
+ 213FB22D12028B53002B3A08 /* BonjourEvents-Info.plist */,
+ );
+ name = "Bonjour Events Plugin";
+ sourceTree = "<group>";
+ };
+ 6575FBFE022EAFA800000109 /* MIG files */ = {
+ isa = PBXGroup;
+ children = (
+ 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */,
+ 6575FBFF022EAFBA00000109 /* DNSServiceDiscoveryDefines.h */,
+ 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */,
+ 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */,
+ );
+ name = "MIG files";
+ sourceTree = "<group>";
+ };
+ 6575FC1F022EB78C00000109 /* Command-Line Clients */ = {
+ isa = PBXGroup;
+ children = (
+ 6575FC20022EB7AA00000109 /* SamplemDNSClient.c */,
+ FF1C919F07021E3F001048AB /* dns-sd.c */,
+ FF5852100DD27BD300862BDF /* ClientCommon.c */,
+ );
+ name = "Command-Line Clients";
+ sourceTree = "<group>";
+ };
+ DB2CC4420662DCE500335AB3 /* Java Support */ = {
+ isa = PBXGroup;
+ children = (
+ DB2CC4430662DD1100335AB3 /* BaseListener.java */,
+ DB2CC4440662DD1100335AB3 /* BrowseListener.java */,
+ DB2CC4450662DD1100335AB3 /* DNSRecord.java */,
+ DB2CC4460662DD1100335AB3 /* DNSSD.java */,
+ DB2CC4470662DD1100335AB3 /* DNSSDException.java */,
+ DB2CC4480662DD1100335AB3 /* DNSSDRegistration.java */,
+ DB2CC4490662DD1100335AB3 /* DNSSDService.java */,
+ DB2CC44A0662DD1100335AB3 /* DomainListener.java */,
+ DB2CC44B0662DD1100335AB3 /* JNISupport.c */,
+ DB2CC44C0662DD1100335AB3 /* QueryListener.java */,
+ DB2CC44D0662DD1100335AB3 /* RegisterListener.java */,
+ DB2CC44E0662DD1100335AB3 /* ResolveListener.java */,
+ DB2CC44F0662DD1100335AB3 /* TXTRecord.java */,
+ FF2C5FB00A48B8680066DA11 /* DNSSDRecordRegistrar.java */,
+ FF2C5FB20A48B86E0066DA11 /* RegisterRecordListener.java */,
+ );
+ name = "Java Support";
+ sourceTree = "<group>";
+ };
+ FF260A2307B4463400CE10E5 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ FF260A2407B4464B00CE10E5 /* remove_idle.tiff */,
+ FF260A2507B4464B00CE10E5 /* add_pressed.tiff */,
+ FF260A2607B4464B00CE10E5 /* remove_disabled.tiff */,
+ FF260A2707B4464B00CE10E5 /* add_idle.tiff */,
+ FF260A2907B4464B00CE10E5 /* remove_pressed.tiff */,
+ FF260A2807B4464B00CE10E5 /* success.tiff */,
+ FF08480607CEB8E800AE6769 /* inprogress.tiff */,
+ FF260A2A07B4464B00CE10E5 /* failure.tiff */,
+ FF260A3207B4466900CE10E5 /* BonjourPref.icns */,
+ FF260A3307B4466900CE10E5 /* BonjourPref.tiff */,
+ FF354EB108516C63007C00E1 /* installtool */,
+ FF260A4807B4475600CE10E5 /* DNSServiceDiscoveryPref.nib */,
+ FF260A4B07B4477F00CE10E5 /* InfoPlist.strings */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+ FFFB0DA407B43BED00B88D48 /* PreferencePane */ = {
+ isa = PBXGroup;
+ children = (
+ FFE6935007C2CA7F00283007 /* ConfigurationAuthority.h */,
+ FFFB0DAE07B43CBA00B88D48 /* ConfigurationAuthority.c */,
+ FFE6935207C2CAA400283007 /* DNSServiceDiscoveryPref.h */,
+ FFFB0DAC07B43CBA00B88D48 /* DNSServiceDiscoveryPref.m */,
+ FFE6935407C2CABD00283007 /* PrivilegedOperations.h */,
+ FFFB0DAD07B43CBA00B88D48 /* PrivilegedOperations.c */,
+ FFFB0DAF07B43CBA00B88D48 /* ddnswriteconfig.m */,
+ FF260A2307B4463400CE10E5 /* Resources */,
+ );
+ path = PreferencePane;
+ sourceTree = SOURCE_ROOT;
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 2141DD19123FFCDB0086D23E /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2141DD20123FFD0F0086D23E /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2141DD26123FFD2C0086D23E /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2EC8F8ED0C39CCCA003C9C48 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2EC8F8EC0C39CCAC003C9C48 /* helper.h in Headers */,
+ 2EDC5E730C39EA640092701B /* helper-server.h in Headers */,
+ 2E3552920C3A95C100CA1CB7 /* helper-error.h in Headers */,
+ 2ECC11A80C4FEC3800CB1885 /* helpermsg-types.h in Headers */,
+ 2E8165E80C5980E300485EB2 /* libpfkey.h in Headers */,
+ 2E8165EA0C5980F700485EB2 /* ipsec_strerror.h in Headers */,
+ 4BD2B63B134FE09F002B96D5 /* P2PPacketFilter.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 84C5B3331665529800C324A8 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 84F4C090188F050200D1E1DE /* dns_services_mdns.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BE520ADD80740027CCDF /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BE530ADD80740027CCDF /* DNSServiceDiscoveryDefines.h in Headers */,
+ D284BE540ADD80740027CCDF /* dnssd_ipc.h in Headers */,
+ 2E96A5260C39BE480087C4D2 /* helper.h in Headers */,
+ 2EDC5E750C39EA640092701B /* helper-server.h in Headers */,
+ 2E3552900C3A95C100CA1CB7 /* helper-error.h in Headers */,
+ 2ECC11A60C4FEC3800CB1885 /* helpermsg-types.h in Headers */,
+ 21A57F4E145B2AE100939099 /* CryptoAlg.h in Headers */,
+ 21A57F55145B2B1400939099 /* CryptoSupport.h in Headers */,
+ 2124FA2C1471E98C0021D7BB /* nsec.h in Headers */,
+ 2124FA301471E9B50021D7BB /* dnssec.h in Headers */,
+ 218E8E53156D8C0300720DA0 /* dnsproxy.h in Headers */,
+ 2127A47915C3C7B900A857FC /* nsec3.h in Headers */,
+ 21DD8FC1161E9A250033C8F8 /* anonymous.h in Headers */,
+ 21070E6116486B9000A69507 /* DNSSECSupport.h in Headers */,
+ 848DA5CA165477EB00D2E8B4 /* xpc_services.h in Headers */,
+ 848DA5D616547F7200D2E8B4 /* dns_xpc.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BE770ADD80800027CCDF /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BE780ADD80800027CCDF /* DNSServiceDiscoveryDefines.h in Headers */,
+ D284BE790ADD80800027CCDF /* dnssd_ipc.h in Headers */,
+ D284BE7A0ADD80800027CCDF /* mDNSEmbeddedAPI.h in Headers */,
+ D284BE7B0ADD80800027CCDF /* mDNSDebug.h in Headers */,
+ D284BE7C0ADD80800027CCDF /* mDNSMacOSX.h in Headers */,
+ 2E96A5270C39BE480087C4D2 /* helper.h in Headers */,
+ 2EDC5E740C39EA640092701B /* helper-server.h in Headers */,
+ 2E3552910C3A95C100CA1CB7 /* helper-error.h in Headers */,
+ 2ECC11A70C4FEC3800CB1885 /* helpermsg-types.h in Headers */,
+ 21A57F4F145B2AE100939099 /* CryptoAlg.h in Headers */,
+ 21A57F56145B2B1400939099 /* CryptoSupport.h in Headers */,
+ 2124FA2D1471E98C0021D7BB /* nsec.h in Headers */,
+ 2124FA311471E9B50021D7BB /* dnssec.h in Headers */,
+ 218E8E54156D8C0300720DA0 /* dnsproxy.h in Headers */,
+ 2127A47A15C3C7B900A857FC /* nsec3.h in Headers */,
+ 21DD8FC2161E9A250033C8F8 /* anonymous.h in Headers */,
+ 21070E6216486B9000A69507 /* DNSSECSupport.h in Headers */,
+ 848DA5CB165477EB00D2E8B4 /* xpc_services.h in Headers */,
+ 848DA5D716547F7200D2E8B4 /* dns_xpc.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEA60ADD80920027CCDF /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEB50ADD809A0027CCDF /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEC20ADD80A20027CCDF /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2E35529D0C3A9E7600CA1CB7 /* helper-error.h in Headers */,
+ 2E35529F0C3A9E7600CA1CB7 /* helper.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEDC0ADD80A70027CCDF /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEED0ADD80B00027CCDF /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FFA572310AF18F1C0055A0F1 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FFA5723D0AF18F450055A0F1 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FFB765800AEED9C700583A2C /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXLegacyTarget section */
+ 4AE471670EAFF81900A6C5AD /* dns_sd.jar */ = {
+ isa = PBXLegacyTarget;
+ buildArgumentsString = "-f ${SRCROOT}/../mDNSPosix/Makefile OBJDIR=${CONFIGURATION_TEMP_DIR}/dns_sd.jar.build BUILDDIR=${BUILT_PRODUCTS_DIR} SHAREDDIR=${SRCROOT}/../mDNSShared os=x JavaForXcode_$(ACTION)";
+ buildConfigurationList = 4AE471770EAFF84000A6C5AD /* Build configuration list for PBXLegacyTarget "dns_sd.jar" */;
+ buildPhases = (
+ );
+ buildToolPath = /usr/bin/make;
+ buildWorkingDirectory = "";
+ comments = "Multiplatform .jar file that implements Java interface to DNS-SD";
+ dependencies = (
+ );
+ name = dns_sd.jar;
+ passBuildSettingsInEnvironment = 1;
+ productName = dns_sd.jar;
+ };
+/* End PBXLegacyTarget section */
+
+/* Begin PBXNativeTarget section */
+ 213FB21712028A7A002B3A08 /* BonjourEvents */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 213FB21B12028A7C002B3A08 /* Build configuration list for PBXNativeTarget "BonjourEvents" */;
+ buildPhases = (
+ 213FB21412028A7A002B3A08 /* Resources */,
+ 213FB21512028A7A002B3A08 /* Sources */,
+ 213FB21612028A7A002B3A08 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = BonjourEvents;
+ productName = BonjourEvents;
+ productReference = 213FB21812028A7A002B3A08 /* BonjourEvents.plugin */;
+ productType = "com.apple.product-type.bundle";
+ };
+ 2141DD1C123FFCDB0086D23E /* libdns_sd_static */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2141DD1F123FFCF90086D23E /* Build configuration list for PBXNativeTarget "libdns_sd_static" */;
+ buildPhases = (
+ 2141DD19123FFCDB0086D23E /* Headers */,
+ 2141DD1A123FFCDB0086D23E /* Sources */,
+ 2141DD1B123FFCDB0086D23E /* Frameworks */,
+ 2130256B12400DE600AC839F /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = libdns_sd_static;
+ productName = libdns_sd_static;
+ productReference = 2141DD1D123FFCDB0086D23E /* libdns_sd.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+ 2141DD23123FFD0F0086D23E /* libdns_sd_debug_static */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2141DD35123FFD3B0086D23E /* Build configuration list for PBXNativeTarget "libdns_sd_debug_static" */;
+ buildPhases = (
+ 2141DD20123FFD0F0086D23E /* Headers */,
+ 2141DD21123FFD0F0086D23E /* Sources */,
+ 2141DD22123FFD0F0086D23E /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = libdns_sd_debug_static;
+ productName = libdns_sd_debug_static;
+ productReference = 2141DD24123FFD0F0086D23E /* libdns_sd_debug.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+ 2141DD29123FFD2C0086D23E /* libdns_sd_profile_static */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2141DD36123FFD3B0086D23E /* Build configuration list for PBXNativeTarget "libdns_sd_profile_static" */;
+ buildPhases = (
+ 2141DD26123FFD2C0086D23E /* Headers */,
+ 2141DD27123FFD2C0086D23E /* Sources */,
+ 2141DD28123FFD2C0086D23E /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = libdns_sd_profile_static;
+ productName = libdns_sd_profile_static;
+ productReference = 2141DD2A123FFD2C0086D23E /* libdns_sd_profile.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+ 2E0405EF0C31955500F13B59 /* mDNSResponderHelper */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2E0405F30C31956600F13B59 /* Build configuration list for PBXNativeTarget "mDNSResponderHelper" */;
+ buildPhases = (
+ 030BBED60CE11EEC00472F0C /* ShellScript */,
+ 2EC8F8ED0C39CCCA003C9C48 /* Headers */,
+ 2E0405ED0C31955500F13B59 /* Sources */,
+ 2E0405EE0C31955500F13B59 /* Frameworks */,
+ 4AAE0C5A0C68E6EC003882A5 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mDNSResponderHelper;
+ productName = mDNSResponderHelper;
+ productReference = 2E0405F00C31955500F13B59 /* mDNSResponderHelper */;
+ productType = "com.apple.product-type.tool";
+ };
+ 72FB545E166D5FB00090B2D9 /* dnsctl */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 72FB5465166D5FB00090B2D9 /* Build configuration list for PBXNativeTarget "dnsctl" */;
+ buildPhases = (
+ 72FB545B166D5FB00090B2D9 /* Sources */,
+ 72FB545C166D5FB00090B2D9 /* Frameworks */,
+ 72FB545D166D5FB00090B2D9 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = dnsctl;
+ productName = dnsctl;
+ productReference = 72FB545F166D5FB00090B2D9 /* dnsctl */;
+ productType = "com.apple.product-type.tool";
+ };
+ 84C5B3341665529800C324A8 /* dns_services */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 84C5B3361665529800C324A8 /* Build configuration list for PBXNativeTarget "dns_services" */;
+ buildPhases = (
+ 84C5B3311665529800C324A8 /* Sources */,
+ 84C5B3321665529800C324A8 /* Frameworks */,
+ 84C5B3331665529800C324A8 /* Headers */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = dns_services;
+ productName = dns_services;
+ productReference = 84C5B3351665529800C324A8 /* libdns_services_mdns.dylib */;
+ productType = "com.apple.product-type.library.dynamic";
+ };
+ D284BE500ADD80740027CCDF /* mDNSResponder */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = D284BE6D0ADD80740027CCDF /* Build configuration list for PBXNativeTarget "mDNSResponder" */;
+ buildPhases = (
+ D284BE510ADD80740027CCDF /* ShellScript */,
+ D284BE520ADD80740027CCDF /* Headers */,
+ D284BE550ADD80740027CCDF /* Sources */,
+ D284BE640ADD80740027CCDF /* Frameworks */,
+ D284BE690ADD80740027CCDF /* Rez */,
+ D284BE6A0ADD80740027CCDF /* CopyFiles */,
+ 4A7B9E7F14FDA21B00B84CC1 /* CopyFiles */,
+ 4A7B9E8114FDA25500B84CC1 /* CopyFiles */,
+ D284BE6C0ADD80740027CCDF /* ShellScript */,
+ 8418673D15AB8BFF00BB7F70 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mDNSResponder;
+ productInstallPath = "${HOME}/bin";
+ productName = mDNSResponder;
+ productReference = D284BE730ADD80740027CCDF /* mDNSResponder */;
+ productType = "com.apple.product-type.tool";
+ };
+ D284BE750ADD80800027CCDF /* mDNSResponder debug */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = D284BE920ADD80800027CCDF /* Build configuration list for PBXNativeTarget "mDNSResponder debug" */;
+ buildPhases = (
+ D284BE760ADD80800027CCDF /* ShellScript */,
+ D284BE770ADD80800027CCDF /* Headers */,
+ D284BE7D0ADD80800027CCDF /* Sources */,
+ D284BE8C0ADD80800027CCDF /* Frameworks */,
+ D284BE910ADD80800027CCDF /* Rez */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "mDNSResponder debug";
+ productName = mDNSResponder;
+ productReference = D284BE950ADD80800027CCDF /* mDNSResponder.debug */;
+ productType = "com.apple.product-type.tool";
+ };
+ D284BEA50ADD80920027CCDF /* dns-sd tool */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = D284BEAD0ADD80920027CCDF /* Build configuration list for PBXNativeTarget "dns-sd tool" */;
+ buildPhases = (
+ D284BEA60ADD80920027CCDF /* Headers */,
+ D284BEA70ADD80920027CCDF /* Sources */,
+ D284BEA90ADD80920027CCDF /* Frameworks */,
+ D284BEAA0ADD80920027CCDF /* Rez */,
+ D284BEAB0ADD80920027CCDF /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "dns-sd tool";
+ productInstallPath = /usr/bin;
+ productName = "dns-sd command-line tool";
+ productReference = D284BEB00ADD80920027CCDF /* dns-sd */;
+ productType = "com.apple.product-type.tool";
+ };
+ D284BEB20ADD809A0027CCDF /* libjdns_sd.jnilib */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = D284BEBB0ADD809A0027CCDF /* Build configuration list for PBXNativeTarget "libjdns_sd.jnilib" */;
+ buildPhases = (
+ D284BEB50ADD809A0027CCDF /* Headers */,
+ D284BEB60ADD809A0027CCDF /* Sources */,
+ D284BEB80ADD809A0027CCDF /* Frameworks */,
+ D284BEBA0ADD809A0027CCDF /* Rez */,
+ );
+ buildRules = (
+ );
+ comments = "Platform-specific JNI library that bridges dns_sd.jar to <dns_sd.h>.";
+ dependencies = (
+ 4AE4716A0EAFF83800A6C5AD /* PBXTargetDependency */,
+ );
+ name = libjdns_sd.jnilib;
+ productInstallPath = /usr/lib/java;
+ productName = libjdns_sd.jnilib;
+ productReference = D284BEBE0ADD809A0027CCDF /* libjdns_sd.jnilib */;
+ productType = "com.apple.product-type.library.dynamic";
+ };
+ D284BEBF0ADD80A20027CCDF /* dnsextd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = D284BED60ADD80A20027CCDF /* Build configuration list for PBXNativeTarget "dnsextd" */;
+ buildPhases = (
+ D284BEC20ADD80A20027CCDF /* Headers */,
+ 4A4EE3A413CB8E82005C624B /* Build yacc file into derived source files */,
+ D284BEC40ADD80A20027CCDF /* Sources */,
+ D284BECE0ADD80A20027CCDF /* Frameworks */,
+ D284BED40ADD80A20027CCDF /* CopyFiles */,
+ FFFF8F770C32F0FD00722979 /* CopyFiles */,
+ FF37FAAD0BC581780044A5CF /* ShellScript */,
+ );
+ buildRules = (
+ D284BFB80ADD8E510027CCDF /* PBXBuildRule */,
+ D284BF750ADD850C0027CCDF /* PBXBuildRule */,
+ );
+ dependencies = (
+ );
+ name = dnsextd;
+ productInstallPath = /usr/sbin;
+ productName = mDNSResponder;
+ productReference = D284BED90ADD80A20027CCDF /* dnsextd */;
+ productType = "com.apple.product-type.tool";
+ };
+ D284BEDB0ADD80A70027CCDF /* ddnswriteconfig */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = D284BEE50ADD80A70027CCDF /* Build configuration list for PBXNativeTarget "ddnswriteconfig" */;
+ buildPhases = (
+ D284BEDC0ADD80A70027CCDF /* Headers */,
+ D284BEDD0ADD80A70027CCDF /* Sources */,
+ D284BEDF0ADD80A70027CCDF /* Frameworks */,
+ D284BEE40ADD80A70027CCDF /* Rez */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ddnswriteconfig;
+ productInstallPath = "/Library/Application Support/Bonjour";
+ productName = ddnswriteconfig;
+ productReference = D284BEE80ADD80A70027CCDF /* ddnswriteconfig */;
+ productType = "com.apple.product-type.tool";
+ };
+ D284BEEA0ADD80B00027CCDF /* PreferencePane */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = D284BF080ADD80B00027CCDF /* Build configuration list for PBXNativeTarget "PreferencePane" */;
+ buildPhases = (
+ D284BEED0ADD80B00027CCDF /* Headers */,
+ D284BEEE0ADD80B00027CCDF /* Resources */,
+ D284BEFD0ADD80B00027CCDF /* Sources */,
+ D284BF010ADD80B00027CCDF /* Frameworks */,
+ D284BF070ADD80B00027CCDF /* Rez */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ FFAE66F9105F0CF100162116 /* PBXTargetDependency */,
+ );
+ name = PreferencePane;
+ productInstallPath = "${SYSTEM_LIBRARY_DIR}/PreferencePanes";
+ productName = PreferencePane;
+ productReference = D284BF0C0ADD80B00027CCDF /* Bonjour.prefPane */;
+ productType = "com.apple.product-type.bundle";
+ };
+ FFA572300AF18F1C0055A0F1 /* libdns_sd_debug_dynamic */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FFA572370AF18F1C0055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd_debug_dynamic" */;
+ buildPhases = (
+ FFA572310AF18F1C0055A0F1 /* Headers */,
+ FFA572320AF18F1C0055A0F1 /* Sources */,
+ FFA572360AF18F1C0055A0F1 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = libdns_sd_debug_dynamic;
+ productName = libdns_sd.dylib;
+ productReference = FFA572390AF18F1C0055A0F1 /* libsystem_dnssd_debug.dylib */;
+ productType = "com.apple.product-type.library.dynamic";
+ };
+ FFA5723C0AF18F450055A0F1 /* libdns_sd_profile_dynamic */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FFA572430AF18F450055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd_profile_dynamic" */;
+ buildPhases = (
+ FFA5723D0AF18F450055A0F1 /* Headers */,
+ FFA5723E0AF18F450055A0F1 /* Sources */,
+ FFA572420AF18F450055A0F1 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = libdns_sd_profile_dynamic;
+ productName = libdns_sd.dylib;
+ productReference = FFA572450AF18F450055A0F1 /* libsystem_dnssd_profile.dylib */;
+ productType = "com.apple.product-type.library.dynamic";
+ };
+ FFB765830AEED9C700583A2C /* libdns_sd_dynamic */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FFB765890AEED9FB00583A2C /* Build configuration list for PBXNativeTarget "libdns_sd_dynamic" */;
+ buildPhases = (
+ FFB765800AEED9C700583A2C /* Headers */,
+ FFB765810AEED9C700583A2C /* Sources */,
+ FFB765820AEED9C700583A2C /* Frameworks */,
+ 21DE714D115831CB00DD4BD1 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = libdns_sd_dynamic;
+ productName = libdns_sd.dylib;
+ productReference = FFB765840AEED9C700583A2C /* libsystem_dnssd.dylib */;
+ productType = "com.apple.product-type.library.dynamic";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 08FB7793FE84155DC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ };
+ buildConfigurationList = D284BE2B0ADD78180027CCDF /* Build configuration list for PBXProject "mDNSResponder" */;
+ compatibilityVersion = "Xcode 3.1";
+ developmentRegion = English;
+ hasScannedForEncodings = 1;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ );
+ mainGroup = 08FB7794FE84155DC02AAC07 /* mDNSResponder */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 00AD62BB032D7A0C0CCA2C71 /* Build More */,
+ 03067D640C83A3700022BE1F /* Build Some */,
+ FFB7657B0AEED96B00583A2C /* Build All */,
+ D284BE500ADD80740027CCDF /* mDNSResponder */,
+ D284BE750ADD80800027CCDF /* mDNSResponder debug */,
+ 2E0405EF0C31955500F13B59 /* mDNSResponderHelper */,
+ D284BEA50ADD80920027CCDF /* dns-sd tool */,
+ 4AE471670EAFF81900A6C5AD /* dns_sd.jar */,
+ D284BEB20ADD809A0027CCDF /* libjdns_sd.jnilib */,
+ D284BEBF0ADD80A20027CCDF /* dnsextd */,
+ D284BEDB0ADD80A70027CCDF /* ddnswriteconfig */,
+ D284BEEA0ADD80B00027CCDF /* PreferencePane */,
+ FFB765830AEED9C700583A2C /* libdns_sd_dynamic */,
+ FFA572300AF18F1C0055A0F1 /* libdns_sd_debug_dynamic */,
+ FFA5723C0AF18F450055A0F1 /* libdns_sd_profile_dynamic */,
+ FFA572650AF190F10055A0F1 /* SystemLibrariesDynamic */,
+ 213FB21712028A7A002B3A08 /* BonjourEvents */,
+ 2141DCF8123FFB5D0086D23E /* SystemLibraries */,
+ 2141DD0B123FFC7F0086D23E /* SystemLibrariesStatic */,
+ 2141DD1C123FFCDB0086D23E /* libdns_sd_static */,
+ 2141DD23123FFD0F0086D23E /* libdns_sd_debug_static */,
+ 2141DD29123FFD2C0086D23E /* libdns_sd_profile_static */,
+ 84C5B3341665529800C324A8 /* dns_services */,
+ 72FB545E166D5FB00090B2D9 /* dnsctl */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 213FB21412028A7A002B3A08 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEEE0ADD80B00027CCDF /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 3F347CF6185D57CD00367B40 /* base.xcconfig in Resources */,
+ D284BEEF0ADD80B00027CCDF /* remove_idle.tiff in Resources */,
+ D284BEF00ADD80B00027CCDF /* add_pressed.tiff in Resources */,
+ D284BEF10ADD80B00027CCDF /* remove_disabled.tiff in Resources */,
+ D284BEF20ADD80B00027CCDF /* add_idle.tiff in Resources */,
+ D284BEF30ADD80B00027CCDF /* success.tiff in Resources */,
+ D284BEF40ADD80B00027CCDF /* remove_pressed.tiff in Resources */,
+ D284BEF50ADD80B00027CCDF /* failure.tiff in Resources */,
+ D284BEF60ADD80B00027CCDF /* BonjourPref.icns in Resources */,
+ D284BEF70ADD80B00027CCDF /* BonjourPref.tiff in Resources */,
+ D284BEF80ADD80B00027CCDF /* DNSServiceDiscoveryPref.nib in Resources */,
+ D284BEF90ADD80B00027CCDF /* InfoPlist.strings in Resources */,
+ D284BEFB0ADD80B00027CCDF /* inprogress.tiff in Resources */,
+ D284BEFC0ADD80B00027CCDF /* installtool in Resources */,
+ FFAE66F0105F0CD900162116 /* ddnswriteconfig in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXRezBuildPhase section */
+ D284BE690ADD80740027CCDF /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BE910ADD80800027CCDF /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEAA0ADD80920027CCDF /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEBA0ADD809A0027CCDF /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEE40ADD80A70027CCDF /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BF070ADD80B00027CCDF /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXRezBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 030BBED60CE11EEC00472F0C /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "if [ -e \"${SDKROOT}/usr/local/include/vproc.h\" -o -e \"${SDKROOT}/usr/include/vproc.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nelse\ntouch \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/lib/libipsec.dylib\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libipsec.a\"\nelse\necho \"#define MDNS_NO_IPSEC 1\" > ${CONFIGURATION_TEMP_DIR}/ipsec_options.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libipsec.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n";
+ };
+ 2130256B12400DE600AC839F /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "DSTROOT=${DSTROOT}${INSTALL_PATH_PREFIX}\n\nmkdir -p \"$DSTROOT/usr/include\"\nsed 's/\\(^#define _DNS_SD_LIBDISPATCH \\)0$/\\1 1/' \"$SRCROOT/../mDNSShared/dns_sd.h\" > \"$DSTROOT/usr/include/dns_sd.h\"";
+ };
+ 21DE714D115831CB00DD4BD1 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "DSTROOT=${DSTROOT}${INSTALL_PATH_PREFIX}\nmkdir -p \"$DSTROOT/usr/include\"\nsed 's/\\(^#define _DNS_SD_LIBDISPATCH \\)0$/\\1 1/' \"$SRCROOT/../mDNSShared/dns_sd.h\" > \"$DSTROOT/usr/include/dns_sd.h\"";
+ };
+ 4A4EE3A413CB8E82005C624B /* Build yacc file into derived source files */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/../mDNSShared/dnsextd_parser.y",
+ );
+ name = "Build yacc file into derived source files";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/dnsextd_parser.c",
+ "$(DERIVED_FILE_DIR)/dnsextd_parser.h",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/usr/bin/bison -o ${SCRIPT_OUTPUT_FILE_0} -d ${SCRIPT_INPUT_FILE_0}";
+ };
+ D284BE510ADD80740027CCDF /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "if [ -e \"${SDKROOT}/usr/local/include/dnsinfo.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/sandbox.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/local/include/vproc.h\" -o -e \"${SDKROOT}/usr/include/vproc.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nelse\ntouch \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/Frameworks/IOKit.framework/PrivateHeaders/pwr_mgt/IOPMLibPrivate.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/IOKit\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt\"\ntouch \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt/IOPMLibPrivate.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/PrivateFrameworks/DeviceToDeviceManager.framework/Headers/DeviceToDeviceManager.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager\"\necho \"#define NO_D2D 1\" > \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager/DeviceToDeviceManager.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/PrivateFrameworks/WebFilterDNS.framework/Headers/WebFilterDNS.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS\"\necho \"#define NO_WCF 1\" > \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS/WebFilterDNS.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/local/include/AWACS.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/AWACS.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libAWACS.a\"\nelse\nec!
ho \"#define NO_AWACS 1\" > \"${CONFIGURATION_TEMP_DIR}/AWACS.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libAWACS.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\"\nfi\n";
+ };
+ D284BE6C0ADD80740027CCDF /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/bash;
+ shellScript = "# Install mDNSResponder.bundle containing language localizations\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices\ncp -R ${SRCROOT}/mDNSResponder-bundle ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle\n\n# Remove unwanted CVS directories\nfind ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -depth -name CVS -exec rm -rf {} \\;\n\n# Expand UTF-8 files to UTF-16 (at one time this appeared to be necessary, but it's not, so we don't do it any more)\n#foreach file (`find ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -name Localizable.strings`)\n#iconv -f utf-8 -t utf-16 ${file} > ${file}.new\n#mv -f ${file}.new ${file}\n#end\n\n# Remove French localization (not wanted for Apple B&I builds)\nrm -rf ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle/Resources/French.lproj\n\n# Copy Sandbox profile\nif [ ! -z \"${IPHONEOS_DEPLOYMENT_TARGET}\" ] ; then\n SANDBOXDST=\"${DSTROOT}/usr/local/share/sandbox/profiles/embedded/builtin\"\nelse\n SANDBOXDST=\"${DSTROOT}/usr/share/sandbox\"\nfi\n(umask 022; mkdir -p -m 0755 \"$SANDBOXDST\")\ncp \"${SRCROOT}/mDNSResponder.sb\" \"${SANDBOXDST}/mDNSResponder.sb\"\n";
+ };
+ D284BE760ADD80800027CCDF /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "if [ -e \"${SDKROOT}/usr/local/include/dnsinfo.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/sandbox.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/local/include/vproc.h\" -o -e \"${SDKROOT}/usr/include/vproc.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nelse\ntouch \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/Frameworks/IOKit.framework/PrivateHeaders/pwr_mgt/IOPMLibPrivate.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/IOKit\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt\"\ntouch \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt/IOPMLibPrivate.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/PrivateFrameworks/DeviceToDeviceManager.framework/Headers/DeviceToDeviceManager.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager\"\necho \"#define NO_D2D 1\" > \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager/DeviceToDeviceManager.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/PrivateFrameworks/WebFilterDNS.framework/Headers/WebFilterDNS.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS\"\necho \"#define NO_WCF 1\" > \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS/WebFilterDNS.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/local/include/AWACS.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/AWACS.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libAWACS.a\"\nelse\nec!
ho \"#define NO_AWACS 1\" > \"${CONFIGURATION_TEMP_DIR}/AWACS.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libAWACS.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\"\nfi";
+ };
+ FF045B6A0C7E4AA600448140 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "# Install plists to tell launchd how to start mDNSResponder and mDNSResponderHelper\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons\n\nif [ ! -z \"${IPHONEOS_DEPLOYMENT_TARGET}\" ] ; then\nplutil -convert binary1 ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponder.plist\nplutil -convert binary1 ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponderHelper.plist\nfi\n";
+ };
+ FF37FAAD0BC581780044A5CF /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/tcsh;
+ shellScript = "# Install plist to tell launchd how to start dnsextd\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons\ncp ${SRCROOT}/LaunchDaemonInfo.dnsextd.plist ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.dnsextd.plist\n";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 213FB21512028A7A002B3A08 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 213FB23C12028C4A002B3A08 /* BonjourEvents.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2141DD1A123FFCDB0086D23E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 215FFAEE124000F900470DE1 /* dnssd_ipc.c in Sources */,
+ 215FFAEF124000F900470DE1 /* dnssd_clientlib.c in Sources */,
+ 215FFAF0124000F900470DE1 /* dnssd_clientstub.c in Sources */,
+ 215FFAF1124000F900470DE1 /* DNSServiceDiscovery.c in Sources */,
+ 215FFAF2124000F900470DE1 /* DNSServiceDiscoveryRequest.defs in Sources */,
+ 215FFAF3124000F900470DE1 /* DNSServiceDiscoveryReply.defs in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2141DD21123FFD0F0086D23E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 215FFAF41240011800470DE1 /* dnssd_ipc.c in Sources */,
+ 215FFAF51240011800470DE1 /* dnssd_clientlib.c in Sources */,
+ 215FFAF61240011800470DE1 /* dnssd_clientstub.c in Sources */,
+ 215FFAF71240011800470DE1 /* DNSServiceDiscovery.c in Sources */,
+ 215FFAF81240011800470DE1 /* DNSServiceDiscoveryRequest.defs in Sources */,
+ 215FFAF91240011800470DE1 /* DNSServiceDiscoveryReply.defs in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2141DD27123FFD2C0086D23E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 215FFAFA1240013400470DE1 /* dnssd_ipc.c in Sources */,
+ 215FFAFB1240013400470DE1 /* dnssd_clientlib.c in Sources */,
+ 215FFAFC1240013400470DE1 /* dnssd_clientstub.c in Sources */,
+ 215FFAFD1240013400470DE1 /* DNSServiceDiscovery.c in Sources */,
+ 215FFAFE1240013400470DE1 /* DNSServiceDiscoveryRequest.defs in Sources */,
+ 215FFAFF1240013400470DE1 /* DNSServiceDiscoveryReply.defs in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 2E0405ED0C31955500F13B59 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2E0405F50C3195F700F13B59 /* helper.c in Sources */,
+ 2E0405F60C31961100F13B59 /* helpermsg.defs in Sources */,
+ 2E96A51D0C39BDAC0087C4D2 /* helper-main.c in Sources */,
+ 2E8165E90C5980EE00485EB2 /* pfkey.c in Sources */,
+ 4BD2B63A134FE09F002B96D5 /* P2PPacketFilter.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72FB545B166D5FB00090B2D9 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72FB5467166D5FCA0090B2D9 /* dnsctl.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 84C5B3311665529800C324A8 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 84C5B33C166553F100C324A8 /* dns_services.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BE550ADD80740027CCDF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BE560ADD80740027CCDF /* DNSServiceDiscoveryReply.defs in Sources */,
+ D284BE570ADD80740027CCDF /* DNSServiceDiscoveryRequest.defs in Sources */,
+ D284BE580ADD80740027CCDF /* mDNS.c in Sources */,
+ D284BE590ADD80740027CCDF /* uDNS.c in Sources */,
+ D284BE5A0ADD80740027CCDF /* DNSCommon.c in Sources */,
+ D284BE5B0ADD80740027CCDF /* DNSDigest.c in Sources */,
+ D284BE5D0ADD80740027CCDF /* mDNSDebug.c in Sources */,
+ D284BE5E0ADD80740027CCDF /* uds_daemon.c in Sources */,
+ D284BE5F0ADD80740027CCDF /* dnssd_ipc.c in Sources */,
+ D284BE600ADD80740027CCDF /* PlatformCommon.c in Sources */,
+ D284BE610ADD80740027CCDF /* mDNSMacOSX.c in Sources */,
+ D284BE620ADD80740027CCDF /* LegacyNATTraversal.c in Sources */,
+ D284BE630ADD80740027CCDF /* daemon.c in Sources */,
+ 2E04061F0C3198B700F13B59 /* helpermsg.defs in Sources */,
+ 2E96A5320C39C1A50087C4D2 /* helper-stubs.c in Sources */,
+ 21A57F4C145B2AE100939099 /* CryptoAlg.c in Sources */,
+ 21A57F53145B2B1400939099 /* CryptoSupport.c in Sources */,
+ 2124FA331471E9DE0021D7BB /* nsec.c in Sources */,
+ 213BDC6D147319F400000896 /* dnssec.c in Sources */,
+ 218E8E51156D8C0300720DA0 /* dnsproxy.c in Sources */,
+ 21DED43515702C0F0060B6B9 /* DNSProxySupport.c in Sources */,
+ 216D9ACE1720C9F5008066E1 /* VPNService.c in Sources */,
+ 2127A47715C3C7B900A857FC /* nsec3.c in Sources */,
+ 21DD8FBF161E9A250033C8F8 /* anonymous.c in Sources */,
+ 21070E5F16486B9000A69507 /* DNSSECSupport.c in Sources */,
+ 848DA5C7165477E000D2E8B4 /* xpc_services.c in Sources */,
+ 2120ABD516B71614007089B6 /* CUPolicy.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BE7D0ADD80800027CCDF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BE7E0ADD80800027CCDF /* DNSServiceDiscoveryReply.defs in Sources */,
+ D284BE7F0ADD80800027CCDF /* DNSServiceDiscoveryRequest.defs in Sources */,
+ D284BE800ADD80800027CCDF /* mDNS.c in Sources */,
+ D284BE810ADD80800027CCDF /* uDNS.c in Sources */,
+ D284BE820ADD80800027CCDF /* DNSCommon.c in Sources */,
+ D284BE830ADD80800027CCDF /* DNSDigest.c in Sources */,
+ D284BE850ADD80800027CCDF /* mDNSDebug.c in Sources */,
+ D284BE860ADD80800027CCDF /* uds_daemon.c in Sources */,
+ D284BE870ADD80800027CCDF /* dnssd_ipc.c in Sources */,
+ D284BE880ADD80800027CCDF /* PlatformCommon.c in Sources */,
+ D284BE890ADD80800027CCDF /* mDNSMacOSX.c in Sources */,
+ D284BE8A0ADD80800027CCDF /* LegacyNATTraversal.c in Sources */,
+ D284BE8B0ADD80800027CCDF /* daemon.c in Sources */,
+ 2E0406200C3198B700F13B59 /* helpermsg.defs in Sources */,
+ 2E96A5300C39C1A50087C4D2 /* helper-stubs.c in Sources */,
+ 21A57F4D145B2AE100939099 /* CryptoAlg.c in Sources */,
+ 21A57F54145B2B1400939099 /* CryptoSupport.c in Sources */,
+ 2124FA341471E9DE0021D7BB /* nsec.c in Sources */,
+ 213BDC6E147319F400000896 /* dnssec.c in Sources */,
+ 218E8E52156D8C0300720DA0 /* dnsproxy.c in Sources */,
+ 21DED43615702C0F0060B6B9 /* DNSProxySupport.c in Sources */,
+ 216D9ACF1720C9F5008066E1 /* VPNService.c in Sources */,
+ 2127A47815C3C7B900A857FC /* nsec3.c in Sources */,
+ 21DD8FC0161E9A250033C8F8 /* anonymous.c in Sources */,
+ 21070E6016486B9000A69507 /* DNSSECSupport.c in Sources */,
+ 848DA5C8165477E000D2E8B4 /* xpc_services.c in Sources */,
+ 2120ABD616B71614007089B6 /* CUPolicy.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEA70ADD80920027CCDF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BEA80ADD80920027CCDF /* dns-sd.c in Sources */,
+ FFF589B70E37F66800EF515C /* ClientCommon.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEB60ADD809A0027CCDF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BEB70ADD809A0027CCDF /* JNISupport.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEC40ADD80A20027CCDF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 21DCD05C1461B23700702FC8 /* CryptoAlg.c in Sources */,
+ 21DCD05D1461B23700702FC8 /* CryptoAlg.h in Sources */,
+ D284BEC50ADD80A20027CCDF /* DNSCommon.c in Sources */,
+ D284BEC60ADD80A20027CCDF /* DNSDigest.c in Sources */,
+ D284BEC70ADD80A20027CCDF /* dnsextd.c in Sources */,
+ D284BEC80ADD80A20027CCDF /* mDNSDebug.c in Sources */,
+ D284BEC90ADD80A20027CCDF /* GenLinkedList.c in Sources */,
+ D284BECA0ADD80A20027CCDF /* mDNSMacOSX.c in Sources */,
+ D284BECC0ADD80A20027CCDF /* dnsextd_parser.y in Sources */,
+ D284BECB0ADD80A20027CCDF /* dnsextd_lexer.l in Sources */,
+ D284BECD0ADD80A20027CCDF /* PlatformCommon.c in Sources */,
+ 2EAE955A0C31F4D30021F738 /* helpermsg.defs in Sources */,
+ 2E35529E0C3A9E7600CA1CB7 /* helper-stubs.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEDD0ADD80A70027CCDF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BEDE0ADD80A70027CCDF /* ddnswriteconfig.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ D284BEFD0ADD80B00027CCDF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D284BEFE0ADD80B00027CCDF /* DNSServiceDiscoveryPref.m in Sources */,
+ D284BEFF0ADD80B00027CCDF /* PrivilegedOperations.c in Sources */,
+ D284BF000ADD80B00027CCDF /* ConfigurationAuthority.c in Sources */,
+ FFF589C10E37F67E00EF515C /* ClientCommon.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FFA572320AF18F1C0055A0F1 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FFA572330AF18F1C0055A0F1 /* dnssd_ipc.c in Sources */,
+ FFA572340AF18F1C0055A0F1 /* dnssd_clientlib.c in Sources */,
+ FFA572350AF18F1C0055A0F1 /* dnssd_clientstub.c in Sources */,
+ FFA5724A0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */,
+ FFC22AA40B00F42C00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */,
+ FFC22AA60B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FFA5723E0AF18F450055A0F1 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FFA5723F0AF18F450055A0F1 /* dnssd_ipc.c in Sources */,
+ FFA572400AF18F450055A0F1 /* dnssd_clientlib.c in Sources */,
+ FFA572410AF18F450055A0F1 /* dnssd_clientstub.c in Sources */,
+ FFA5724B0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */,
+ FFC22AA30B00F42B00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */,
+ FFC22AA70B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FFB765810AEED9C700583A2C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FFFA38660AEEDB2B0065B80A /* dnssd_ipc.c in Sources */,
+ FFFA38630AEEDB090065B80A /* dnssd_clientlib.c in Sources */,
+ FFFA38650AEEDB130065B80A /* dnssd_clientstub.c in Sources */,
+ FFA572490AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */,
+ FFC22AA20B00F42A00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */,
+ FFC22AA50B00F43000BAB070 /* DNSServiceDiscoveryReply.defs in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 03067D680C83A3830022BE1F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = D284BE500ADD80740027CCDF /* mDNSResponder */;
+ targetProxy = 03067D670C83A3830022BE1F /* PBXContainerItemProxy */;
+ };
+ 03067D6A0C83A3890022BE1F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = D284BE750ADD80800027CCDF /* mDNSResponder debug */;
+ targetProxy = 03067D690C83A3890022BE1F /* PBXContainerItemProxy */;
+ };
+ 03067D6C0C83A3920022BE1F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = D284BEA50ADD80920027CCDF /* dns-sd tool */;
+ targetProxy = 03067D6B0C83A3920022BE1F /* PBXContainerItemProxy */;
+ };
+ 03067D6E0C83A39C0022BE1F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 2E0405EF0C31955500F13B59 /* mDNSResponderHelper */;
+ targetProxy = 03067D6D0C83A39C0022BE1F /* PBXContainerItemProxy */;
+ };
+ 03067D860C849CC30022BE1F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 03067D640C83A3700022BE1F /* Build Some */;
+ targetProxy = 03067D850C849CC30022BE1F /* PBXContainerItemProxy */;
+ };
+ 2130257112400E9300AC839F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FFA572650AF190F10055A0F1 /* SystemLibrariesDynamic */;
+ targetProxy = 2130257012400E9300AC839F /* PBXContainerItemProxy */;
+ };
+ 2141DCFD123FFB7D0086D23E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 2141DCF8123FFB5D0086D23E /* SystemLibraries */;
+ targetProxy = 2141DCFC123FFB7D0086D23E /* PBXContainerItemProxy */;
+ };
+ 2141DD0E123FFC960086D23E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 2141DD0B123FFC7F0086D23E /* SystemLibrariesStatic */;
+ targetProxy = 2141DD0D123FFC960086D23E /* PBXContainerItemProxy */;
+ };
+ 215FFB19124002C100470DE1 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 2141DD1C123FFCDB0086D23E /* libdns_sd_static */;
+ targetProxy = 215FFB18124002C100470DE1 /* PBXContainerItemProxy */;
+ };
+ 215FFB1B124002C700470DE1 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 2141DD23123FFD0F0086D23E /* libdns_sd_debug_static */;
+ targetProxy = 215FFB1A124002C700470DE1 /* PBXContainerItemProxy */;
+ };
+ 215FFB1D124002CC00470DE1 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 2141DD29123FFD2C0086D23E /* libdns_sd_profile_static */;
+ targetProxy = 215FFB1C124002CC00470DE1 /* PBXContainerItemProxy */;
+ };
+ 217A4C49138EE14C000A5BA8 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 213FB21712028A7A002B3A08 /* BonjourEvents */;
+ targetProxy = 217A4C48138EE14C000A5BA8 /* PBXContainerItemProxy */;
+ };
+ 4AE4716A0EAFF83800A6C5AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4AE471670EAFF81900A6C5AD /* dns_sd.jar */;
+ targetProxy = 4AE471690EAFF83800A6C5AD /* PBXContainerItemProxy */;
+ };
+ 84C5B3411665544B00C324A8 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 84C5B3341665529800C324A8 /* dns_services */;
+ targetProxy = 84C5B3401665544B00C324A8 /* PBXContainerItemProxy */;
+ };
+ D284BF2C0ADD815A0027CCDF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = D284BEBF0ADD80A20027CCDF /* dnsextd */;
+ targetProxy = D284BF2B0ADD815A0027CCDF /* PBXContainerItemProxy */;
+ };
+ D284BF2E0ADD81600027CCDF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = D284BEDB0ADD80A70027CCDF /* ddnswriteconfig */;
+ targetProxy = D284BF2D0ADD81600027CCDF /* PBXContainerItemProxy */;
+ };
+ D284BF300ADD81630027CCDF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = D284BEEA0ADD80B00027CCDF /* PreferencePane */;
+ targetProxy = D284BF2F0ADD81630027CCDF /* PBXContainerItemProxy */;
+ };
+ FFA572690AF190FF0055A0F1 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FFB765830AEED9C700583A2C /* libdns_sd_dynamic */;
+ targetProxy = FFA572680AF190FF0055A0F1 /* PBXContainerItemProxy */;
+ };
+ FFA5726B0AF191010055A0F1 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FFA572300AF18F1C0055A0F1 /* libdns_sd_debug_dynamic */;
+ targetProxy = FFA5726A0AF191010055A0F1 /* PBXContainerItemProxy */;
+ };
+ FFA5726D0AF191020055A0F1 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FFA5723C0AF18F450055A0F1 /* libdns_sd_profile_dynamic */;
+ targetProxy = FFA5726C0AF191020055A0F1 /* PBXContainerItemProxy */;
+ };
+ FFAE66F9105F0CF100162116 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = D284BEDB0ADD80A70027CCDF /* ddnswriteconfig */;
+ targetProxy = FFAE66F8105F0CF100162116 /* PBXContainerItemProxy */;
+ };
+ FFB7657D0AEED97F00583A2C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 00AD62BB032D7A0C0CCA2C71 /* Build More */;
+ targetProxy = FFB7657C0AEED97F00583A2C /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ FF260A4807B4475600CE10E5 /* DNSServiceDiscoveryPref.nib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ FF260A4907B4475600CE10E5 /* English */,
+ );
+ name = DNSServiceDiscoveryPref.nib;
+ path = PreferencePane;
+ sourceTree = SOURCE_ROOT;
+ };
+ FF260A4B07B4477F00CE10E5 /* InfoPlist.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ FF260A4C07B4477F00CE10E5 /* English */,
+ );
+ name = InfoPlist.strings;
+ path = PreferencePane;
+ sourceTree = SOURCE_ROOT;
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 03067D740C83A3CB0022BE1F /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_OPTIMIZATION_LEVEL = s;
+ PRODUCT_NAME = "Build Some";
+ };
+ name = Development;
+ };
+ 213FB21A12028A7B002B3A08 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ BUNDLE_LOADER = /usr/libexec/UserEventAgent;
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_MODEL_TUNING = G5;
+ INFOPLIST_FILE = "BonjourEvents-Info.plist";
+ INSTALL_PATH_ACTUAL = /System/Library/UserEventPlugins/;
+ PREBINDING = NO;
+ PRODUCT_NAME = BonjourEvents;
+ PROVISIONING_PROFILE = "";
+ WRAPPER_EXTENSION = plugin;
+ };
+ name = Development;
+ };
+ 2141DCF9123FFB5D0086D23E /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ PRODUCT_NAME = SystemLibraries;
+ };
+ name = Development;
+ };
+ 2141DD0C123FFC7F0086D23E /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = s;
+ PRODUCT_NAME = SystemLibrariesStatic;
+ };
+ name = Development;
+ };
+ 2141DD1E123FFCDB0086D23E /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "__DARWIN_NON_CANCELABLE=1",
+ );
+ HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/";
+ INSTALLHDRS_COPY_PHASE = YES;
+ INSTALLHDRS_SCRIPT_PHASE = YES;
+ INSTALL_PATH_ACTUAL = /usr/local/lib/system;
+ PREBINDING = NO;
+ PRODUCT_NAME = dns_sd;
+ "SKIP_INSTALL[sdk=iphonesimulator*]" = YES;
+ };
+ name = Development;
+ };
+ 2141DD25123FFD100086D23E /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "__DARWIN_NON_CANCELABLE=1",
+ );
+ HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/";
+ INSTALL_PATH_ACTUAL = /usr/local/lib/system;
+ PREBINDING = NO;
+ PRODUCT_NAME = dns_sd_debug;
+ "SKIP_INSTALL[sdk=iphonesimulator*]" = YES;
+ };
+ name = Development;
+ };
+ 2141DD2B123FFD2C0086D23E /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "__DARWIN_NON_CANCELABLE=1",
+ );
+ HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/";
+ INSTALL_PATH_ACTUAL = /usr/local/lib/system;
+ PREBINDING = NO;
+ PRODUCT_NAME = dns_sd_profile;
+ "SKIP_INSTALL[sdk=iphonesimulator*]" = YES;
+ };
+ name = Development;
+ };
+ 2E0405F20C31955500F13B59 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ "CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = "helper-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
+ CONFIGURATION_TEMP_DIR = "$(PROJECT_TEMP_DIR)";
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ GCC_WARN_CHECK_SWITCH_STATEMENTS = NO;
+ HEADER_SEARCH_PATHS = (
+ "${CONFIGURATION_TEMP_DIR}",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/usr/local/include",
+ );
+ INSTALL_PATH = "";
+ "INSTALL_PATH[sdk=macosx*]" = "";
+ INSTALL_PATH_ACTUAL = /usr/sbin;
+ LD_MAP_FILE_PATH = "$(TARGET_TEMP_DIR)/$(PRODUCT_NAME)-LinkMap-$(CURRENT_VARIANT)-$(CURRENT_ARCH).txt";
+ LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
+ MACOSX_DEPLOYMENT_TARGET = 10.5;
+ "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = "$(inherited)";
+ OTHER_LDFLAGS = (
+ "$(inherited)",
+ "-lipsec",
+ );
+ "OTHER_LDFLAGS[sdk=macosx*][arch=*]" = (
+ "-lipsec",
+ "-Wl,-pie",
+ );
+ PREBINDING = NO;
+ PRODUCT_NAME = mDNSResponderHelper;
+ PROVISIONING_PROFILE = "";
+ };
+ name = Development;
+ };
+ 4AE471680EAFF81900A6C5AD /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ PRODUCT_NAME = dns_sd.jar;
+ };
+ name = Development;
+ };
+ 72FB5466166D5FB00090B2D9 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_64_BIT)";
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_ENTITLEMENTS[sdk=*]" = "dnsctl-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_OPTIMIZATION_LEVEL = s;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_STRICT_ALIASING = YES;
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INSTALL_PATH_ACTUAL = /usr/bin;
+ MACOSX_DEPLOYMENT_TARGET = 10.9;
+ ONLY_ACTIVE_ARCH = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE = "";
+ SDKROOT = macosx;
+ };
+ name = Development;
+ };
+ 84C5B3371665529800C324A8 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_64_BIT)";
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ EXECUTABLE_PREFIX = lib;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_OPTIMIZATION_LEVEL = s;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INSTALL_PATH_ACTUAL = /usr/lib;
+ MACOSX_DEPLOYMENT_TARGET = 10.8;
+ ONLY_ACTIVE_ARCH = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)_mdns";
+ SDKROOT = macosx;
+ };
+ name = Development;
+ };
+ D284BE290ADD78180027CCDF /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = "Build All";
+ SECTORDER_FLAGS = "";
+ };
+ name = Development;
+ };
+ D284BE2C0ADD78180027CCDF /* Development */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 3F347CF5185D57CD00367B40 /* base.xcconfig */;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
+ DEAD_CODE_STRIPPING = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "__APPLE_USE_RFC_3542=1",
+ "_DNS_SD_LIBDISPATCH=1",
+ "APPLE_OSX_mDNSResponder=1",
+ "__MigTypeCheck=1",
+ "mDNSResponderVersion=${MVERS}",
+ _LEGACY_NAT_TRAVERSAL_,
+ "_BUILDING_XCODE_PROJECT_=1",
+ );
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ MVERS = "\"(Engineering Build)\"";
+ OTHER_CFLAGS = (
+ "-DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS",
+ "-fwrapv",
+ );
+ "OTHER_LDFLAGS[sdk=macosx*]" = "";
+ PREBINDING = NO;
+ STRIP_STYLE = debugging;
+ WARNING_CFLAGS = (
+ "-W",
+ "-Wall",
+ "-Wmissing-prototypes",
+ "-Wno-four-char-constants",
+ "-Wno-unknown-pragmas",
+ "-Wshadow",
+ );
+ YACC_GENERATED_FILE_STEM = Standard;
+ };
+ name = Development;
+ };
+ D284BE6E0ADD80740027CCDF /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ "CODE_SIGN_ENTITLEMENTS[sdk=*]" = "mDNSResponder-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ );
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/PrivateHeaders",
+ ../mDNSShared,
+ "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
+ "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
+ "${CONFIGURATION_TEMP_DIR}",
+ "$(SDKROOT)/usr/include/libxml2",
+ "$(SDKROOT)/usr/local/include/",
+ );
+ INSTALL_PATH = "";
+ "INSTALL_PATH[sdk=macosx*]" = "";
+ INSTALL_PATH_ACTUAL = /usr/sbin;
+ LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
+ MACOSX_DEPLOYMENT_TARGET = 10.5;
+ ORDER_FILE = "${SRCROOT}/mDNSResponder.order";
+ OTHER_CFLAGS = (
+ "$(inherited)",
+ "-no-cpp-precomp",
+ );
+ "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = "$(inherited)";
+ OTHER_LDFLAGS = "";
+ "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = (
+ "-Wl,-pie",
+ "-weak_framework",
+ DeviceToDeviceManager,
+ "-lMobileGestalt",
+ "-lcupolicy",
+ );
+ "OTHER_LDFLAGS[sdk=macosx*][arch=*]" = (
+ "-Wl,-pie",
+ "-lAWACS",
+ "-weak_framework",
+ WebFilterDNS,
+ "-weak_framework",
+ DeviceToDeviceManager,
+ );
+ "OTHER_LDFLAGS[sdk=macosx10.6][arch=*]" = "-lAWACS";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = mDNSResponder;
+ PROVISIONING_PROFILE = "";
+ REZ_EXECUTABLE = YES;
+ };
+ name = Development;
+ };
+ D284BE930ADD80800027CCDF /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ );
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_OPTIMIZATION_LEVEL = s;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "MDNS_DEBUGMSGS=1",
+ );
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/PrivateHeaders",
+ ../mDNSShared,
+ "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
+ "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
+ "${CONFIGURATION_TEMP_DIR}",
+ "$(SDKROOT)/usr/include/libxml2",
+ "$(SDKROOT)/usr/local/include",
+ );
+ LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
+ MACOSX_DEPLOYMENT_TARGET = 10.5;
+ OTHER_CFLAGS = (
+ "$(inherited)",
+ "-no-cpp-precomp",
+ );
+ OTHER_LDFLAGS = "";
+ "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = (
+ "-Wl,-pie",
+ "-weak_framework",
+ DeviceToDeviceManager,
+ "-lMobileGestalt",
+ "-lcupolicy",
+ );
+ "OTHER_LDFLAGS[sdk=macosx*][arch=*]" = (
+ "-Wl,-pie",
+ "-lAWACS",
+ "-weak_framework",
+ WebFilterDNS,
+ "-weak_framework",
+ DeviceToDeviceManager,
+ );
+ "OTHER_LDFLAGS[sdk=macosx10.6][arch=*]" = "-lAWACS";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = mDNSResponder.debug;
+ REZ_EXECUTABLE = YES;
+ SECTORDER_FLAGS = (
+ "-sectorder",
+ __TEXT,
+ __text,
+ mDNSResponder.order,
+ );
+ SKIP_INSTALL = YES;
+ };
+ name = Development;
+ };
+ D284BEAE0ADD80920027CCDF /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ HEADER_SEARCH_PATHS = (
+ ../mDNSShared,
+ "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
+ );
+ INSTALL_PATH_ACTUAL = /usr/bin;
+ OTHER_CFLAGS = "-no-cpp-precomp";
+ OTHER_LDFLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = "dns-sd";
+ REZ_EXECUTABLE = YES;
+ SECTORDER_FLAGS = "";
+ };
+ name = Development;
+ };
+ D284BEBC0ADD809A0027CCDF /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ EXECUTABLE_EXTENSION = jnilib;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ HEADER_SEARCH_PATHS = (
+ ../mDNSShared,
+ "${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/A/Headers",
+ "${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/1.3.1/Headers",
+ "${PROJECT_DERIVED_FILE_DIR}",
+ );
+ INSTALL_PATH_ACTUAL = /usr/lib/java;
+ LIBRARY_STYLE = DYNAMIC;
+ MACH_O_TYPE = mh_dylib;
+ OTHER_CFLAGS = "";
+ OTHER_LIBTOOL_FLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = libjdns_sd;
+ REZ_EXECUTABLE = YES;
+ SECTORDER_FLAGS = "";
+ };
+ name = Development;
+ };
+ D284BED70ADD80A20027CCDF /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ FRAMEWORK_SEARCH_PATHS = "";
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ HEADER_SEARCH_PATHS = (
+ "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
+ "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
+ "${CONFIGURATION_TEMP_DIR}",
+ /System/Library/Frameworks/System.Framework/PrivateHeaders,
+ );
+ INSTALL_PATH_ACTUAL = /usr/sbin;
+ LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
+ MACOSX_DEPLOYMENT_TARGET = 10.5;
+ OTHER_CFLAGS = (
+ "-no-cpp-precomp",
+ "-UAPPLE_OSX_mDNSResponder",
+ );
+ OTHER_LDFLAGS = "";
+ "OTHER_LDFLAGS[sdk=macosx*][arch=*]" = "-Wl,-pie";
+ PRODUCT_NAME = dnsextd;
+ SECTORDER_FLAGS = "";
+ };
+ name = Development;
+ };
+ D284BEE60ADD80A70027CCDF /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ INSTALL_PATH_ACTUAL = "/Library/Application Support/Bonjour";
+ MACOSX_DEPLOYMENT_TARGET = 10.5;
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = "";
+ "OTHER_LDFLAGS[sdk=macosx*]" = "-Wl,-pie";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = ddnswriteconfig;
+ REZ_EXECUTABLE = YES;
+ SECTORDER_FLAGS = "";
+ };
+ name = Development;
+ };
+ D284BF090ADD80B00027CCDF /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ EXPORTED_SYMBOLS_FILE = "";
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_OBJC_GC = supported;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ INFOPLIST_FILE = "PreferencePane/Info-PreferencePane.plist";
+ INSTALL_PATH_ACTUAL = /AppleInternal/Library/PreferencePanes;
+ MACOSX_DEPLOYMENT_TARGET = 10.5;
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = "-twolevel_namespace";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = Bonjour;
+ SECTORDER_FLAGS = "";
+ WRAPPER_EXTENSION = prefPane;
+ };
+ name = Development;
+ };
+ FFA572380AF18F1C0055A0F1 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ COPY_PHASE_STRIP = NO;
+ DYLIB_CURRENT_VERSION = "$(RC_ProjectSourceVersion)";
+ EXECUTABLE_EXTENSION = dylib;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "__DARWIN_NON_CANCELABLE=1",
+ );
+ HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/";
+ INSTALL_PATH_ACTUAL = /usr/lib/system;
+ LINK_WITH_STANDARD_LIBRARIES = NO;
+ OTHER_LDFLAGS = (
+ "-Wl,-umbrella,System",
+ "-L/usr/lib/system",
+ "-ldyld",
+ "-lcompiler_rt",
+ "-lsystem_kernel",
+ "-lsystem_platform",
+ "-lsystem_pthread",
+ "-lsystem_malloc",
+ "-lsystem_c",
+ "-lsystem_blocks",
+ "-ldispatch",
+ "-llaunch",
+ "-lsystem_asl",
+ );
+ "OTHER_LDFLAGS[sdk=iphonesimulator*]" = (
+ "-Wl,-umbrella,System",
+ "-L/usr/lib/system",
+ "-ldyld_sim",
+ "-lcompiler_rt_sim",
+ "-lsystem_sim_c",
+ "-lsystem_sim_blocks",
+ "-ldispatch",
+ "-Wl,-upward-lSystem",
+ );
+ PRODUCT_NAME = libsystem_dnssd_debug;
+ "PRODUCT_NAME[sdk=iphonesimulator*]" = libsystem_sim_dnssd_debug;
+ };
+ name = Development;
+ };
+ FFA572440AF18F450055A0F1 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ COPY_PHASE_STRIP = NO;
+ DYLIB_CURRENT_VERSION = "$(RC_ProjectSourceVersion)";
+ EXECUTABLE_EXTENSION = dylib;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "__DARWIN_NON_CANCELABLE=1",
+ );
+ GENERATE_PROFILING_CODE = YES;
+ HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/";
+ INSTALL_PATH_ACTUAL = /usr/lib/system;
+ LINK_WITH_STANDARD_LIBRARIES = NO;
+ OTHER_LDFLAGS = (
+ "-Wl,-umbrella,System",
+ "-L/usr/lib/system",
+ "-ldyld",
+ "-lcompiler_rt",
+ "-lsystem_kernel",
+ "-lsystem_platform",
+ "-lsystem_pthread",
+ "-lsystem_malloc",
+ "-lsystem_c",
+ "-lsystem_blocks",
+ "-ldispatch",
+ "-llaunch",
+ "-lsystem_asl",
+ );
+ "OTHER_LDFLAGS[sdk=iphonesimulator*]" = (
+ "-Wl,-umbrella,System",
+ "-L/usr/lib/system",
+ "-ldyld_sim",
+ "-lcompiler_rt_sim",
+ "-lsystem_sim_c",
+ "-lsystem_sim_blocks",
+ "-ldispatch",
+ "-Wl,-upward-lSystem",
+ );
+ PRODUCT_NAME = libsystem_dnssd_profile;
+ "PRODUCT_NAME[sdk=iphonesimulator*]" = libsystem_sim_dnssd_profile;
+ };
+ name = Development;
+ };
+ FFA5726F0AF191200055A0F1 /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ PRODUCT_NAME = SystemLibrariesDynamic;
+ };
+ name = Development;
+ };
+ FFB7657F0AEED99D00583A2C /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ PRODUCT_NAME = "Build All";
+ };
+ name = Development;
+ };
+ FFB7658A0AEED9FB00583A2C /* Development */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ COPY_PHASE_STRIP = NO;
+ DYLIB_CURRENT_VERSION = "$(RC_ProjectSourceVersion)";
+ EXECUTABLE_EXTENSION = dylib;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "__DARWIN_NON_CANCELABLE=1",
+ );
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/";
+ INSTALLHDRS_COPY_PHASE = YES;
+ INSTALLHDRS_SCRIPT_PHASE = YES;
+ INSTALL_PATH_ACTUAL = /usr/lib/system;
+ LINK_WITH_STANDARD_LIBRARIES = NO;
+ OTHER_LDFLAGS = (
+ "-Wl,-umbrella,System",
+ "-L/usr/lib/system",
+ "-ldyld",
+ "-lcompiler_rt",
+ "-lsystem_kernel",
+ "-lsystem_platform",
+ "-lsystem_pthread",
+ "-lsystem_malloc",
+ "-lsystem_c",
+ "-lsystem_blocks",
+ "-ldispatch",
+ "-llaunch",
+ "-lsystem_asl",
+ );
+ "OTHER_LDFLAGS[sdk=iphonesimulator*]" = (
+ "-Wl,-umbrella,System",
+ "-L/usr/lib/system",
+ "-ldyld_sim",
+ "-lcompiler_rt_sim",
+ "-lsystem_sim_c",
+ "-lsystem_sim_blocks",
+ "-ldispatch",
+ "-Wl,-upward-lSystem",
+ );
+ PRODUCT_NAME = libsystem_dnssd;
+ "PRODUCT_NAME[sdk=iphonesimulator*]" = libsystem_sim_dnssd;
+ };
+ name = Development;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 03067D730C83A3CB0022BE1F /* Build configuration list for PBXAggregateTarget "Build Some" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 03067D740C83A3CB0022BE1F /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ 213FB21B12028A7C002B3A08 /* Build configuration list for PBXNativeTarget "BonjourEvents" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 213FB21A12028A7B002B3A08 /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ 2141DD08123FFB830086D23E /* Build configuration list for PBXAggregateTarget "SystemLibraries" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2141DCF9123FFB5D0086D23E /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ 2141DD18123FFC990086D23E /* Build configuration list for PBXAggregateTarget "SystemLibrariesStatic" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2141DD0C123FFC7F0086D23E /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ 2141DD1F123FFCF90086D23E /* Build configuration list for PBXNativeTarget "libdns_sd_static" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2141DD1E123FFCDB0086D23E /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ 2141DD35123FFD3B0086D23E /* Build configuration list for PBXNativeTarget "libdns_sd_debug_static" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2141DD25123FFD100086D23E /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ 2141DD36123FFD3B0086D23E /* Build configuration list for PBXNativeTarget "libdns_sd_profile_static" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2141DD2B123FFD2C0086D23E /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ 2E0405F30C31956600F13B59 /* Build configuration list for PBXNativeTarget "mDNSResponderHelper" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2E0405F20C31955500F13B59 /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ 4AE471770EAFF84000A6C5AD /* Build configuration list for PBXLegacyTarget "dns_sd.jar" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4AE471680EAFF81900A6C5AD /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ 72FB5465166D5FB00090B2D9 /* Build configuration list for PBXNativeTarget "dnsctl" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 72FB5466166D5FB00090B2D9 /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ 84C5B3361665529800C324A8 /* Build configuration list for PBXNativeTarget "dns_services" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 84C5B3371665529800C324A8 /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ D284BE280ADD78180027CCDF /* Build configuration list for PBXAggregateTarget "Build More" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D284BE290ADD78180027CCDF /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ D284BE2B0ADD78180027CCDF /* Build configuration list for PBXProject "mDNSResponder" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D284BE2C0ADD78180027CCDF /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ D284BE6D0ADD80740027CCDF /* Build configuration list for PBXNativeTarget "mDNSResponder" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D284BE6E0ADD80740027CCDF /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ D284BE920ADD80800027CCDF /* Build configuration list for PBXNativeTarget "mDNSResponder debug" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D284BE930ADD80800027CCDF /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ D284BEAD0ADD80920027CCDF /* Build configuration list for PBXNativeTarget "dns-sd tool" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D284BEAE0ADD80920027CCDF /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ D284BEBB0ADD809A0027CCDF /* Build configuration list for PBXNativeTarget "libjdns_sd.jnilib" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D284BEBC0ADD809A0027CCDF /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ D284BED60ADD80A20027CCDF /* Build configuration list for PBXNativeTarget "dnsextd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D284BED70ADD80A20027CCDF /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ D284BEE50ADD80A70027CCDF /* Build configuration list for PBXNativeTarget "ddnswriteconfig" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D284BEE60ADD80A70027CCDF /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ D284BF080ADD80B00027CCDF /* Build configuration list for PBXNativeTarget "PreferencePane" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D284BF090ADD80B00027CCDF /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ FFA572370AF18F1C0055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd_debug_dynamic" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FFA572380AF18F1C0055A0F1 /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ FFA572430AF18F450055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd_profile_dynamic" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FFA572440AF18F450055A0F1 /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ FFA5726E0AF191200055A0F1 /* Build configuration list for PBXAggregateTarget "SystemLibrariesDynamic" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FFA5726F0AF191200055A0F1 /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ FFB7657E0AEED99D00583A2C /* Build configuration list for PBXAggregateTarget "Build All" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FFB7657F0AEED99D00583A2C /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+ FFB765890AEED9FB00583A2C /* Build configuration list for PBXNativeTarget "libdns_sd_dynamic" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FFB7658A0AEED9FB00583A2C /* Development */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Development;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
+}
Deleted: vendor/apple/mDNSResponder/561.1.1/mDNSPosix/mDNSPosix.c
===================================================================
--- vendor/apple/mDNSResponder/dist/mDNSPosix/mDNSPosix.c 2014-06-30 23:58:12 UTC (rev 6706)
+++ vendor/apple/mDNSResponder/561.1.1/mDNSPosix/mDNSPosix.c 2015-03-20 01:14:52 UTC (rev 6985)
@@ -1,1789 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
-#include "DNSCommon.h"
-#include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
-#include "dns_sd.h"
-#include "dnssec.h"
-#include "nsec.h"
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <syslog.h>
-#include <stdarg.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-#include <sys/select.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <time.h> // platform support for UTC time
-
-#if USES_NETLINK
-#include <asm/types.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-#else // USES_NETLINK
-#include <net/route.h>
-#include <net/if.h>
-#endif // USES_NETLINK
-
-#include "mDNSUNP.h"
-#include "GenLinkedList.h"
-
-// ***************************************************************************
-// Structures
-
-// We keep a list of client-supplied event sources in PosixEventSource records
-struct PosixEventSource
-{
- mDNSPosixEventCallback Callback;
- void *Context;
- int fd;
- struct PosixEventSource *Next;
-};
-typedef struct PosixEventSource PosixEventSource;
-
-// Context record for interface change callback
-struct IfChangeRec
-{
- int NotifySD;
- mDNS *mDNS;
-};
-typedef struct IfChangeRec IfChangeRec;
-
-// Note that static data is initialized to zero in (modern) C.
-static fd_set gEventFDs;
-static int gMaxFD; // largest fd in gEventFDs
-static GenLinkedList gEventSources; // linked list of PosixEventSource's
-static sigset_t gEventSignalSet; // Signals which event loop listens for
-static sigset_t gEventSignals; // Signals which were received while inside loop
-
-// ***************************************************************************
-// Globals (for debugging)
-
-static int num_registered_interfaces = 0;
-static int num_pkts_accepted = 0;
-static int num_pkts_rejected = 0;
-
-// ***************************************************************************
-// Functions
-
-int gMDNSPlatformPosixVerboseLevel = 0;
-
-#define PosixErrorToStatus(errNum) ((errNum) == 0 ? mStatus_NoError : mStatus_UnknownErr)
-
-mDNSlocal void SockAddrTomDNSAddr(const struct sockaddr *const sa, mDNSAddr *ipAddr, mDNSIPPort *ipPort)
-{
- switch (sa->sa_family)
- {
- case AF_INET:
- {
- struct sockaddr_in *sin = (struct sockaddr_in*)sa;
- ipAddr->type = mDNSAddrType_IPv4;
- ipAddr->ip.v4.NotAnInteger = sin->sin_addr.s_addr;
- if (ipPort) ipPort->NotAnInteger = sin->sin_port;
- break;
- }
-
-#if HAVE_IPV6
- case AF_INET6:
- {
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa;
-#ifndef NOT_HAVE_SA_LEN
- assert(sin6->sin6_len == sizeof(*sin6));
-#endif
- ipAddr->type = mDNSAddrType_IPv6;
- ipAddr->ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
- if (ipPort) ipPort->NotAnInteger = sin6->sin6_port;
- break;
- }
-#endif
-
- default:
- verbosedebugf("SockAddrTomDNSAddr: Uknown address family %d\n", sa->sa_family);
- ipAddr->type = mDNSAddrType_None;
- if (ipPort) ipPort->NotAnInteger = 0;
- break;
- }
-}
-
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark ***** Send and Receive
-#endif
-
-// mDNS core calls this routine when it needs to send a packet.
-mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
- mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
- mDNSIPPort dstPort, mDNSBool useBackgroundTrafficClass)
-{
- int err = 0;
- struct sockaddr_storage to;
- PosixNetworkInterface * thisIntf = (PosixNetworkInterface *)(InterfaceID);
- int sendingsocket = -1;
-
- (void)src; // Will need to use this parameter once we implement mDNSPlatformUDPSocket/mDNSPlatformUDPClose
- (void) useBackgroundTrafficClass;
-
- assert(m != NULL);
- assert(msg != NULL);
- assert(end != NULL);
- assert((((char *) end) - ((char *) msg)) > 0);
-
- if (dstPort.NotAnInteger == 0)
- {
- LogMsg("mDNSPlatformSendUDP: Invalid argument -dstPort is set to 0");
- return PosixErrorToStatus(EINVAL);
- }
- if (dst->type == mDNSAddrType_IPv4)
- {
- struct sockaddr_in *sin = (struct sockaddr_in*)&to;
-#ifndef NOT_HAVE_SA_LEN
- sin->sin_len = sizeof(*sin);
-#endif
- sin->sin_family = AF_INET;
- sin->sin_port = dstPort.NotAnInteger;
- sin->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
- sendingsocket = thisIntf ? thisIntf->multicastSocket4 : m->p->unicastSocket4;
- }
-
-#if HAVE_IPV6
- else if (dst->type == mDNSAddrType_IPv6)
- {
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&to;
- mDNSPlatformMemZero(sin6, sizeof(*sin6));
-#ifndef NOT_HAVE_SA_LEN
- sin6->sin6_len = sizeof(*sin6);
-#endif
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = dstPort.NotAnInteger;
- sin6->sin6_addr = *(struct in6_addr*)&dst->ip.v6;
- sendingsocket = thisIntf ? thisIntf->multicastSocket6 : m->p->unicastSocket6;
- }
-#endif
-
- if (sendingsocket >= 0)
- err = sendto(sendingsocket, msg, (char*)end - (char*)msg, 0, (struct sockaddr *)&to, GET_SA_LEN(to));
-
- if (err > 0) err = 0;
- else if (err < 0)
- {
- static int MessageCount = 0;
- // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
- if (!mDNSAddressIsAllDNSLinkGroup(dst))
- if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
-
- if (MessageCount < 1000)
- {
- MessageCount++;
- if (thisIntf)
- LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a on interface %#a/%s/%d",
- errno, strerror(errno), dst, &thisIntf->coreIntf.ip, thisIntf->intfName, thisIntf->index);
- else
- LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a", errno, strerror(errno), dst);
- }
- }
-
- return PosixErrorToStatus(err);
-}
-
-// This routine is called when the main loop detects that data is available on a socket.
-mDNSlocal void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int skt)
-{
- mDNSAddr senderAddr, destAddr;
- mDNSIPPort senderPort;
- ssize_t packetLen;
- DNSMessage packet;
- struct my_in_pktinfo packetInfo;
- struct sockaddr_storage from;
- socklen_t fromLen;
- int flags;
- mDNSu8 ttl;
- mDNSBool reject;
- const mDNSInterfaceID InterfaceID = intf ? intf->coreIntf.InterfaceID : NULL;
-
- assert(m != NULL);
- assert(skt >= 0);
-
- fromLen = sizeof(from);
- flags = 0;
- packetLen = recvfrom_flags(skt, &packet, sizeof(packet), &flags, (struct sockaddr *) &from, &fromLen, &packetInfo, &ttl);
-
- if (packetLen >= 0)
- {
- SockAddrTomDNSAddr((struct sockaddr*)&from, &senderAddr, &senderPort);
- SockAddrTomDNSAddr((struct sockaddr*)&packetInfo.ipi_addr, &destAddr, NULL);
-
- // If we have broken IP_RECVDSTADDR functionality (so far
- // I've only seen this on OpenBSD) then apply a hack to
- // convince mDNS Core that this isn't a spoof packet.
- // Basically what we do is check to see whether the
- // packet arrived as a multicast and, if so, set its
- // destAddr to the mDNS address.
- //
- // I must admit that I could just be doing something
- // wrong on OpenBSD and hence triggering this problem
- // but I'm at a loss as to how.
- //
- // If this platform doesn't have IP_PKTINFO or IP_RECVDSTADDR, then we have
- // no way to tell the destination address or interface this packet arrived on,
- // so all we can do is just assume it's a multicast
-
- #if HAVE_BROKEN_RECVDSTADDR || (!defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR))
- if ((destAddr.NotAnInteger == 0) && (flags & MSG_MCAST))
- {
- destAddr.type = senderAddr.type;
- if (senderAddr.type == mDNSAddrType_IPv4) destAddr.ip.v4 = AllDNSLinkGroup_v4.ip.v4;
- else if (senderAddr.type == mDNSAddrType_IPv6) destAddr.ip.v6 = AllDNSLinkGroup_v6.ip.v6;
- }
- #endif
-
- // We only accept the packet if the interface on which it came
- // in matches the interface associated with this socket.
- // We do this match by name or by index, depending on which
- // information is available. recvfrom_flags sets the name
- // to "" if the name isn't available, or the index to -1
- // if the index is available. This accomodates the various
- // different capabilities of our target platforms.
-
- reject = mDNSfalse;
- if (!intf)
- {
- // Ignore multicasts accidentally delivered to our unicast receiving socket
- if (mDNSAddrIsDNSMulticast(&destAddr)) packetLen = -1;
- }
- else
- {
- if (packetInfo.ipi_ifname[0] != 0) reject = (strcmp(packetInfo.ipi_ifname, intf->intfName) != 0);
- else if (packetInfo.ipi_ifindex != -1) reject = (packetInfo.ipi_ifindex != intf->index);
-
- if (reject)
- {
- verbosedebugf("SocketDataReady ignored a packet from %#a to %#a on interface %s/%d expecting %#a/%s/%d/%d",
- &senderAddr, &destAddr, packetInfo.ipi_ifname, packetInfo.ipi_ifindex,
- &intf->coreIntf.ip, intf->intfName, intf->index, skt);
- packetLen = -1;
- num_pkts_rejected++;
- if (num_pkts_rejected > (num_pkts_accepted + 1) * (num_registered_interfaces + 1) * 2)
- {
- fprintf(stderr,
- "*** WARNING: Received %d packets; Accepted %d packets; Rejected %d packets because of interface mismatch\n",
- num_pkts_accepted + num_pkts_rejected, num_pkts_accepted, num_pkts_rejected);
- num_pkts_accepted = 0;
- num_pkts_rejected = 0;
- }
- }
- else
- {
- verbosedebugf("SocketDataReady got a packet from %#a to %#a on interface %#a/%s/%d/%d",
- &senderAddr, &destAddr, &intf->coreIntf.ip, intf->intfName, intf->index, skt);
- num_pkts_accepted++;
- }
- }
- }
-
- if (packetLen >= 0)
- mDNSCoreReceive(m, &packet, (mDNSu8 *)&packet + packetLen,
- &senderAddr, senderPort, &destAddr, MulticastDNSPort, InterfaceID);
-}
-
-mDNSexport mDNSBool mDNSPlatformPeekUDP(mDNS *const m, UDPSocket *src)
-{
- (void)m; // unused
- (void)src; // unused
- return mDNSfalse;
-}
-
-mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS * const m, TCPSocketFlags flags, mDNSIPPort * port, mDNSBool useBackgroundTrafficClass)
-{
- (void)m; // Unused
- (void)flags; // Unused
- (void)port; // Unused
- (void)useBackgroundTrafficClass; // Unused
- return NULL;
-}
-
-mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int sd)
-{
- (void)flags; // Unused
- (void)sd; // Unused
- return NULL;
-}
-
-mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
-{
- (void)sock; // Unused
- return -1;
-}
-
-mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID,
- TCPConnectionCallback callback, void *context)
-{
- (void)sock; // Unused
- (void)dst; // Unused
- (void)dstport; // Unused
- (void)hostname; // Unused
- (void)InterfaceID; // Unused
- (void)callback; // Unused
- (void)context; // Unused
- return(mStatus_UnsupportedErr);
-}
-
-mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
-{
- (void)sock; // Unused
-}
-
-mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool * closed)
-{
- (void)sock; // Unused
- (void)buf; // Unused
- (void)buflen; // Unused
- (void)closed; // Unused
- return 0;
-}
-
-mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
-{
- (void)sock; // Unused
- (void)msg; // Unused
- (void)len; // Unused
- return 0;
-}
-
-mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS * const m, mDNSIPPort port)
-{
- (void)m; // Unused
- (void)port; // Unused
- return NULL;
-}
-
-mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
-{
- (void)sock; // Unused
-}
-
-mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
-{
- (void)m; // Unused
- (void)InterfaceID; // Unused
-}
-
-mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
-{
- (void)msg; // Unused
- (void)end; // Unused
- (void)InterfaceID; // Unused
-}
-
-mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
-{
- (void)m; // Unused
- (void)tpa; // Unused
- (void)tha; // Unused
- (void)InterfaceID; // Unused
-}
-
-mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
-{
- return(mStatus_UnsupportedErr);
-}
-
-mDNSexport void mDNSPlatformTLSTearDownCerts(void)
-{
-}
-
-mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason)
-{
- (void) m;
- (void) allowSleep;
- (void) reason;
-}
-
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - /etc/hosts support
-#endif
-
-mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
-{
- (void)m; // unused
- (void)rr;
- (void)result;
-}
-
-
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark ***** DDNS Config Platform Functions
-#endif
-
-mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains,
- DNameListElem **BrowseDomains, mDNSBool ackConfig)
-{
- (void) m;
- (void) setservers;
- (void) fqdn;
- (void) setsearch;
- (void) RegDomains;
- (void) BrowseDomains;
- (void) ackConfig;
-
- return mDNStrue;
-}
-
-mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS * const m, mDNSAddr * v4, mDNSAddr * v6, mDNSAddr * router)
-{
- (void) m;
- (void) v4;
- (void) v6;
- (void) router;
-
- return mStatus_UnsupportedErr;
-}
-
-mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
-{
- (void) dname;
- (void) status;
-}
-
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark ***** Init and Term
-#endif
-
-// This gets the current hostname, truncating it at the first dot if necessary
-mDNSlocal void GetUserSpecifiedRFC1034ComputerName(domainlabel *const namelabel)
-{
- int len = 0;
- gethostname((char *)(&namelabel->c[1]), MAX_DOMAIN_LABEL);
- while (len < MAX_DOMAIN_LABEL && namelabel->c[len+1] && namelabel->c[len+1] != '.') len++;
- namelabel->c[0] = len;
-}
-
-// On OS X this gets the text of the field labelled "Computer Name" in the Sharing Prefs Control Panel
-// Other platforms can either get the information from the appropriate place,
-// or they can alternatively just require all registering services to provide an explicit name
-mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
-{
- // On Unix we have no better name than the host name, so we just use that.
- GetUserSpecifiedRFC1034ComputerName(namelabel);
-}
-
-mDNSexport int ParseDNSServers(mDNS *m, const char *filePath)
-{
- char line[256];
- char nameserver[16];
- char keyword[11];
- int numOfServers = 0;
- FILE *fp = fopen(filePath, "r");
- if (fp == NULL) return -1;
- while (fgets(line,sizeof(line),fp))
- {
- struct in_addr ina;
- line[255]='\0'; // just to be safe
- if (sscanf(line,"%10s %15s", keyword, nameserver) != 2) continue; // it will skip whitespaces
- if (strncasecmp(keyword,"nameserver",10)) continue;
- if (inet_aton(nameserver, (struct in_addr *)&ina) != 0)
- {
- mDNSAddr DNSAddr;
- DNSAddr.type = mDNSAddrType_IPv4;
- DNSAddr.ip.v4.NotAnInteger = ina.s_addr;
- mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, 0, &DNSAddr, UnicastDNSPort, kScopeNone, 0, mDNSfalse, 0, mDNStrue, mDNStrue, mDNSfalse);
- numOfServers++;
- }
- }
- return (numOfServers > 0) ? 0 : -1;
-}
-
-// Searches the interface list looking for the named interface.
-// Returns a pointer to if it found, or NULL otherwise.
-mDNSlocal PosixNetworkInterface *SearchForInterfaceByName(mDNS *const m, const char *intfName)
-{
- PosixNetworkInterface *intf;
-
- assert(m != NULL);
- assert(intfName != NULL);
-
- intf = (PosixNetworkInterface*)(m->HostInterfaces);
- while ((intf != NULL) && (strcmp(intf->intfName, intfName) != 0))
- intf = (PosixNetworkInterface *)(intf->coreIntf.next);
-
- return intf;
-}
-
-mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 index)
-{
- PosixNetworkInterface *intf;
-
- assert(m != NULL);
-
- if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
- if (index == kDNSServiceInterfaceIndexP2P ) return(mDNSInterface_P2P);
- if (index == kDNSServiceInterfaceIndexAny ) return(mDNSInterface_Any);
-
- intf = (PosixNetworkInterface*)(m->HostInterfaces);
- while ((intf != NULL) && (mDNSu32) intf->index != index)
- intf = (PosixNetworkInterface *)(intf->coreIntf.next);
-
- return (mDNSInterfaceID) intf;
-}
-
-mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange)
-{
- PosixNetworkInterface *intf;
- (void) suppressNetworkChange; // Unused
-
- assert(m != NULL);
-
- if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
- if (id == mDNSInterface_P2P ) return(kDNSServiceInterfaceIndexP2P);
- if (id == mDNSInterface_Any ) return(kDNSServiceInterfaceIndexAny);
-
- intf = (PosixNetworkInterface*)(m->HostInterfaces);
- while ((intf != NULL) && (mDNSInterfaceID) intf != id)
- intf = (PosixNetworkInterface *)(intf->coreIntf.next);
-
- return intf ? intf->index : 0;
-}
-
-// Frees the specified PosixNetworkInterface structure. The underlying
-// interface must have already been deregistered with the mDNS core.
-mDNSlocal void FreePosixNetworkInterface(PosixNetworkInterface *intf)
-{
- assert(intf != NULL);
- if (intf->intfName != NULL) free((void *)intf->intfName);
- if (intf->multicastSocket4 != -1) assert(close(intf->multicastSocket4) == 0);
-#if HAVE_IPV6
- if (intf->multicastSocket6 != -1) assert(close(intf->multicastSocket6) == 0);
-#endif
- free(intf);
-}
-
-// Grab the first interface, deregister it, free it, and repeat until done.
-mDNSlocal void ClearInterfaceList(mDNS *const m)
-{
- assert(m != NULL);
-
- while (m->HostInterfaces)
- {
- PosixNetworkInterface *intf = (PosixNetworkInterface*)(m->HostInterfaces);
- mDNS_DeregisterInterface(m, &intf->coreIntf, mDNSfalse);
- if (gMDNSPlatformPosixVerboseLevel > 0) fprintf(stderr, "Deregistered interface %s\n", intf->intfName);
- FreePosixNetworkInterface(intf);
- }
- num_registered_interfaces = 0;
- num_pkts_accepted = 0;
- num_pkts_rejected = 0;
-}
-
-// Sets up a send/receive socket.
-// If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
-// If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
-mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interfaceIndex, int *sktPtr)
-{
- int err = 0;
- static const int kOn = 1;
- static const int kIntTwoFiveFive = 255;
- static const unsigned char kByteTwoFiveFive = 255;
- const mDNSBool JoinMulticastGroup = (port.NotAnInteger != 0);
-
- (void) interfaceIndex; // This parameter unused on plaforms that don't have IPv6
- assert(intfAddr != NULL);
- assert(sktPtr != NULL);
- assert(*sktPtr == -1);
-
- // Open the socket...
- if (intfAddr->sa_family == AF_INET) *sktPtr = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
-#if HAVE_IPV6
- else if (intfAddr->sa_family == AF_INET6) *sktPtr = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
-#endif
- else return EINVAL;
-
- if (*sktPtr < 0) { err = errno; perror((intfAddr->sa_family == AF_INET) ? "socket AF_INET" : "socket AF_INET6"); }
-
- // ... with a shared UDP port, if it's for multicast receiving
- if (err == 0 && port.NotAnInteger)
- {
- #if defined(SO_REUSEPORT)
- err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEPORT, &kOn, sizeof(kOn));
- #elif defined(SO_REUSEADDR)
- err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
- #else
- #error This platform has no way to avoid address busy errors on multicast.
- #endif
- if (err < 0) { err = errno; perror("setsockopt - SO_REUSExxxx"); }
- }
-
- // We want to receive destination addresses and interface identifiers.
- if (intfAddr->sa_family == AF_INET)
- {
- struct ip_mreq imr;
- struct sockaddr_in bindAddr;
- if (err == 0)
- {
- #if defined(IP_PKTINFO) // Linux
- err = setsockopt(*sktPtr, IPPROTO_IP, IP_PKTINFO, &kOn, sizeof(kOn));
- if (err < 0) { err = errno; perror("setsockopt - IP_PKTINFO"); }
- #elif defined(IP_RECVDSTADDR) || defined(IP_RECVIF) // BSD and Solaris
- #if defined(IP_RECVDSTADDR)
- err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVDSTADDR, &kOn, sizeof(kOn));
- if (err < 0) { err = errno; perror("setsockopt - IP_RECVDSTADDR"); }
- #endif
- #if defined(IP_RECVIF)
- if (err == 0)
- {
- err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVIF, &kOn, sizeof(kOn));
- if (err < 0) { err = errno; perror("setsockopt - IP_RECVIF"); }
- }
- #endif
- #else
- #warning This platform has no way to get the destination interface information -- will only work for single-homed hosts
- #endif
- }
- #if defined(IP_RECVTTL) // Linux
- if (err == 0)
- {
- setsockopt(*sktPtr, IPPROTO_IP, IP_RECVTTL, &kOn, sizeof(kOn));
- // We no longer depend on being able to get the received TTL, so don't worry if the option fails
- }
- #endif
-
- // Add multicast group membership on this interface
- if (err == 0 && JoinMulticastGroup)
- {
- imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
- imr.imr_interface = ((struct sockaddr_in*)intfAddr)->sin_addr;
- err = setsockopt(*sktPtr, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
- if (err < 0) { err = errno; perror("setsockopt - IP_ADD_MEMBERSHIP"); }
- }
-
- // Specify outgoing interface too
- if (err == 0 && JoinMulticastGroup)
- {
- err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_IF, &((struct sockaddr_in*)intfAddr)->sin_addr, sizeof(struct in_addr));
- if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_IF"); }
- }
-
- // Per the mDNS spec, send unicast packets with TTL 255
- if (err == 0)
- {
- err = setsockopt(*sktPtr, IPPROTO_IP, IP_TTL, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
- if (err < 0) { err = errno; perror("setsockopt - IP_TTL"); }
- }
-
- // and multicast packets with TTL 255 too
- // There's some debate as to whether IP_MULTICAST_TTL is an int or a byte so we just try both.
- if (err == 0)
- {
- err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL, &kByteTwoFiveFive, sizeof(kByteTwoFiveFive));
- if (err < 0 && errno == EINVAL)
- err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
- if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_TTL"); }
- }
-
- // And start listening for packets
- if (err == 0)
- {
- bindAddr.sin_family = AF_INET;
- bindAddr.sin_port = port.NotAnInteger;
- bindAddr.sin_addr.s_addr = INADDR_ANY; // Want to receive multicasts AND unicasts on this socket
- err = bind(*sktPtr, (struct sockaddr *) &bindAddr, sizeof(bindAddr));
- if (err < 0) { err = errno; perror("bind"); fflush(stderr); }
- }
- } // endif (intfAddr->sa_family == AF_INET)
-
-#if HAVE_IPV6
- else if (intfAddr->sa_family == AF_INET6)
- {
- struct ipv6_mreq imr6;
- struct sockaddr_in6 bindAddr6;
- #if defined(IPV6_PKTINFO)
- if (err == 0)
- {
- err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_2292_PKTINFO, &kOn, sizeof(kOn));
- if (err < 0) { err = errno; perror("setsockopt - IPV6_PKTINFO"); }
- }
- #else
- #warning This platform has no way to get the destination interface information for IPv6 -- will only work for single-homed hosts
- #endif
- #if defined(IPV6_HOPLIMIT)
- if (err == 0)
- {
- err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_2292_HOPLIMIT, &kOn, sizeof(kOn));
- if (err < 0) { err = errno; perror("setsockopt - IPV6_HOPLIMIT"); }
- }
- #endif
-
- // Add multicast group membership on this interface
- if (err == 0 && JoinMulticastGroup)
- {
- imr6.ipv6mr_multiaddr = *(const struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
- imr6.ipv6mr_interface = interfaceIndex;
- //LogMsg("Joining %.16a on %d", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface);
- err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_JOIN_GROUP, &imr6, sizeof(imr6));
- if (err < 0)
- {
- err = errno;
- verbosedebugf("IPV6_JOIN_GROUP %.16a on %d failed.\n", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface);
- perror("setsockopt - IPV6_JOIN_GROUP");
- }
- }
-
- // Specify outgoing interface too
- if (err == 0 && JoinMulticastGroup)
- {
- u_int multicast_if = interfaceIndex;
- err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_if, sizeof(multicast_if));
- if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_IF"); }
- }
-
- // We want to receive only IPv6 packets on this socket.
- // Without this option, we may get IPv4 addresses as mapped addresses.
- if (err == 0)
- {
- err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_V6ONLY, &kOn, sizeof(kOn));
- if (err < 0) { err = errno; perror("setsockopt - IPV6_V6ONLY"); }
- }
-
- // Per the mDNS spec, send unicast packets with TTL 255
- if (err == 0)
- {
- err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
- if (err < 0) { err = errno; perror("setsockopt - IPV6_UNICAST_HOPS"); }
- }
-
- // and multicast packets with TTL 255 too
- // There's some debate as to whether IPV6_MULTICAST_HOPS is an int or a byte so we just try both.
- if (err == 0)
- {
- err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kByteTwoFiveFive, sizeof(kByteTwoFiveFive));
- if (err < 0 && errno == EINVAL)
- err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
- if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_HOPS"); }
- }
-
- // And start listening for packets
- if (err == 0)
- {
- mDNSPlatformMemZero(&bindAddr6, sizeof(bindAddr6));
-#ifndef NOT_HAVE_SA_LEN
- bindAddr6.sin6_len = sizeof(bindAddr6);
-#endif
- bindAddr6.sin6_family = AF_INET6;
- bindAddr6.sin6_port = port.NotAnInteger;
- bindAddr6.sin6_flowinfo = 0;
- bindAddr6.sin6_addr = in6addr_any; // Want to receive multicasts AND unicasts on this socket
- bindAddr6.sin6_scope_id = 0;
- err = bind(*sktPtr, (struct sockaddr *) &bindAddr6, sizeof(bindAddr6));
- if (err < 0) { err = errno; perror("bind"); fflush(stderr); }
- }
- } // endif (intfAddr->sa_family == AF_INET6)
-#endif
-
- // Set the socket to non-blocking.
- if (err == 0)
- {
- err = fcntl(*sktPtr, F_GETFL, 0);
- if (err < 0) err = errno;
- else
- {
- err = fcntl(*sktPtr, F_SETFL, err | O_NONBLOCK);
- if (err < 0) err = errno;
- }
- }
-
- // Clean up
- if (err != 0 && *sktPtr != -1) { assert(close(*sktPtr) == 0); *sktPtr = -1; }
- assert((err == 0) == (*sktPtr != -1));
- return err;
-}
-
-// Creates a PosixNetworkInterface for the interface whose IP address is
-// intfAddr and whose name is intfName and registers it with mDNS core.
-mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct sockaddr *intfMask, const char *intfName, int intfIndex)
-{
- int err = 0;
- PosixNetworkInterface *intf;
- PosixNetworkInterface *alias = NULL;
-
- assert(m != NULL);
- assert(intfAddr != NULL);
- assert(intfName != NULL);
- assert(intfMask != NULL);
-
- // Allocate the interface structure itself.
- intf = (PosixNetworkInterface*)malloc(sizeof(*intf));
- if (intf == NULL) { assert(0); err = ENOMEM; }
-
- // And make a copy of the intfName.
- if (err == 0)
- {
- intf->intfName = strdup(intfName);
- if (intf->intfName == NULL) { assert(0); err = ENOMEM; }
- }
-
- if (err == 0)
- {
- // Set up the fields required by the mDNS core.
- SockAddrTomDNSAddr(intfAddr, &intf->coreIntf.ip, NULL);
- SockAddrTomDNSAddr(intfMask, &intf->coreIntf.mask, NULL);
-
- //LogMsg("SetupOneInterface: %#a %#a", &intf->coreIntf.ip, &intf->coreIntf.mask);
- strncpy(intf->coreIntf.ifname, intfName, sizeof(intf->coreIntf.ifname));
- intf->coreIntf.ifname[sizeof(intf->coreIntf.ifname)-1] = 0;
- intf->coreIntf.Advertise = m->AdvertiseLocalAddresses;
- intf->coreIntf.McastTxRx = mDNStrue;
-
- // Set up the extra fields in PosixNetworkInterface.
- assert(intf->intfName != NULL); // intf->intfName already set up above
- intf->index = intfIndex;
- intf->multicastSocket4 = -1;
-#if HAVE_IPV6
- intf->multicastSocket6 = -1;
-#endif
- alias = SearchForInterfaceByName(m, intf->intfName);
- if (alias == NULL) alias = intf;
- intf->coreIntf.InterfaceID = (mDNSInterfaceID)alias;
-
- if (alias != intf)
- debugf("SetupOneInterface: %s %#a is an alias of %#a", intfName, &intf->coreIntf.ip, &alias->coreIntf.ip);
- }
-
- // Set up the multicast socket
- if (err == 0)
- {
- if (alias->multicastSocket4 == -1 && intfAddr->sa_family == AF_INET)
- err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket4);
-#if HAVE_IPV6
- else if (alias->multicastSocket6 == -1 && intfAddr->sa_family == AF_INET6)
- err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket6);
-#endif
- }
-
- // If interface is a direct link, address record will be marked as kDNSRecordTypeKnownUnique
- // and skip the probe phase of the probe/announce packet sequence.
- intf->coreIntf.DirectLink = mDNSfalse;
-
- // The interface is all ready to go, let's register it with the mDNS core.
- if (err == 0)
- err = mDNS_RegisterInterface(m, &intf->coreIntf, mDNSfalse);
-
- // Clean up.
- if (err == 0)
- {
- num_registered_interfaces++;
- debugf("SetupOneInterface: %s %#a Registered", intf->intfName, &intf->coreIntf.ip);
- if (gMDNSPlatformPosixVerboseLevel > 0)
- fprintf(stderr, "Registered interface %s\n", intf->intfName);
- }
- else
- {
- // Use intfName instead of intf->intfName in the next line to avoid dereferencing NULL.
- debugf("SetupOneInterface: %s %#a failed to register %d", intfName, &intf->coreIntf.ip, err);
- if (intf) { FreePosixNetworkInterface(intf); intf = NULL; }
- }
-
- assert((err == 0) == (intf != NULL));
-
- return err;
-}
-
-// Call get_ifi_info() to obtain a list of active interfaces and call SetupOneInterface() on each one.
-mDNSlocal int SetupInterfaceList(mDNS *const m)
-{
- mDNSBool foundav4 = mDNSfalse;
- int err = 0;
- struct ifi_info *intfList = get_ifi_info(AF_INET, mDNStrue);
- struct ifi_info *firstLoopback = NULL;
-
- assert(m != NULL);
- debugf("SetupInterfaceList");
-
- if (intfList == NULL) err = ENOENT;
-
-#if HAVE_IPV6
- if (err == 0) /* Link the IPv6 list to the end of the IPv4 list */
- {
- struct ifi_info **p = &intfList;
- while (*p) p = &(*p)->ifi_next;
- *p = get_ifi_info(AF_INET6, mDNStrue);
- }
-#endif
-
- if (err == 0)
- {
- struct ifi_info *i = intfList;
- while (i)
- {
- if ( ((i->ifi_addr->sa_family == AF_INET)
-#if HAVE_IPV6
- || (i->ifi_addr->sa_family == AF_INET6)
-#endif
- ) && (i->ifi_flags & IFF_UP) && !(i->ifi_flags & IFF_POINTOPOINT))
- {
- if (i->ifi_flags & IFF_LOOPBACK)
- {
- if (firstLoopback == NULL)
- firstLoopback = i;
- }
- else
- {
- if (SetupOneInterface(m, i->ifi_addr, i->ifi_netmask, i->ifi_name, i->ifi_index) == 0)
- if (i->ifi_addr->sa_family == AF_INET)
- foundav4 = mDNStrue;
- }
- }
- i = i->ifi_next;
- }
-
- // If we found no normal interfaces but we did find a loopback interface, register the
- // loopback interface. This allows self-discovery if no interfaces are configured.
- // Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
- // In the interim, we skip loopback interface only if we found at least one v4 interface to use
- // if ((m->HostInterfaces == NULL) && (firstLoopback != NULL))
- if (!foundav4 && firstLoopback)
- (void) SetupOneInterface(m, firstLoopback->ifi_addr, firstLoopback->ifi_netmask, firstLoopback->ifi_name, firstLoopback->ifi_index);
- }
-
- // Clean up.
- if (intfList != NULL) free_ifi_info(intfList);
- return err;
-}
-
-#if USES_NETLINK
-
-// See <http://www.faqs.org/rfcs/rfc3549.html> for a description of NetLink
-
-// Open a socket that will receive interface change notifications
-mDNSlocal mStatus OpenIfNotifySocket(int *pFD)
-{
- mStatus err = mStatus_NoError;
- struct sockaddr_nl snl;
- int sock;
- int ret;
-
- sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (sock < 0)
- return errno;
-
- // Configure read to be non-blocking because inbound msg size is not known in advance
- (void) fcntl(sock, F_SETFL, O_NONBLOCK);
-
- /* Subscribe the socket to Link & IP addr notifications. */
- mDNSPlatformMemZero(&snl, sizeof snl);
- snl.nl_family = AF_NETLINK;
- snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
- ret = bind(sock, (struct sockaddr *) &snl, sizeof snl);
- if (0 == ret)
- *pFD = sock;
- else
- err = errno;
-
- return err;
-}
-
-#if MDNS_DEBUGMSGS
-mDNSlocal void PrintNetLinkMsg(const struct nlmsghdr *pNLMsg)
-{
- const char *kNLMsgTypes[] = { "", "NLMSG_NOOP", "NLMSG_ERROR", "NLMSG_DONE", "NLMSG_OVERRUN" };
- const char *kNLRtMsgTypes[] = { "RTM_NEWLINK", "RTM_DELLINK", "RTM_GETLINK", "RTM_NEWADDR", "RTM_DELADDR", "RTM_GETADDR" };
-
- printf("nlmsghdr len=%d, type=%s, flags=0x%x\n", pNLMsg->nlmsg_len,
- pNLMsg->nlmsg_type < RTM_BASE ? kNLMsgTypes[pNLMsg->nlmsg_type] : kNLRtMsgTypes[pNLMsg->nlmsg_type - RTM_BASE],
- pNLMsg->nlmsg_flags);
-
- if (RTM_NEWLINK <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETLINK)
- {
- struct ifinfomsg *pIfInfo = (struct ifinfomsg*) NLMSG_DATA(pNLMsg);
- printf("ifinfomsg family=%d, type=%d, index=%d, flags=0x%x, change=0x%x\n", pIfInfo->ifi_family,
- pIfInfo->ifi_type, pIfInfo->ifi_index, pIfInfo->ifi_flags, pIfInfo->ifi_change);
-
- }
- else if (RTM_NEWADDR <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETADDR)
- {
- struct ifaddrmsg *pIfAddr = (struct ifaddrmsg*) NLMSG_DATA(pNLMsg);
- printf("ifaddrmsg family=%d, index=%d, flags=0x%x\n", pIfAddr->ifa_family,
- pIfAddr->ifa_index, pIfAddr->ifa_flags);
- }
- printf("\n");
-}
-#endif
-
-mDNSlocal mDNSu32 ProcessRoutingNotification(int sd)
-// Read through the messages on sd and if any indicate that any interface records should
-// be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
-{
- ssize_t readCount;
- char buff[4096];
- struct nlmsghdr *pNLMsg = (struct nlmsghdr*) buff;
- mDNSu32 result = 0;
-
- // The structure here is more complex than it really ought to be because,
- // unfortunately, there's no good way to size a buffer in advance large
- // enough to hold all pending data and so avoid message fragmentation.
- // (Note that FIONREAD is not supported on AF_NETLINK.)
-
- readCount = read(sd, buff, sizeof buff);
- while (1)
- {
- // Make sure we've got an entire nlmsghdr in the buffer, and payload, too.
- // If not, discard already-processed messages in buffer and read more data.
- if (((char*) &pNLMsg[1] > (buff + readCount)) || // i.e. *pNLMsg extends off end of buffer
- ((char*) pNLMsg + pNLMsg->nlmsg_len > (buff + readCount)))
- {
- if (buff < (char*) pNLMsg) // we have space to shuffle
- {
- // discard processed data
- readCount -= ((char*) pNLMsg - buff);
- memmove(buff, pNLMsg, readCount);
- pNLMsg = (struct nlmsghdr*) buff;
-
- // read more data
- readCount += read(sd, buff + readCount, sizeof buff - readCount);
- continue; // spin around and revalidate with new readCount
- }
- else
- break; // Otherwise message does not fit in buffer
- }
-
-#if MDNS_DEBUGMSGS
- PrintNetLinkMsg(pNLMsg);
-#endif
-
- // Process the NetLink message
- if (pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK)
- result |= 1 << ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index;
- else if (pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR)
- result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index;
-
- // Advance pNLMsg to the next message in the buffer
- if ((pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE)
- {
- ssize_t len = readCount - ((char*)pNLMsg - buff);
- pNLMsg = NLMSG_NEXT(pNLMsg, len);
- }
- else
- break; // all done!
- }
-
- return result;
-}
-
-#else // USES_NETLINK
-
-// Open a socket that will receive interface change notifications
-mDNSlocal mStatus OpenIfNotifySocket(int *pFD)
-{
- *pFD = socket(AF_ROUTE, SOCK_RAW, 0);
-
- if (*pFD < 0)
- return mStatus_UnknownErr;
-
- // Configure read to be non-blocking because inbound msg size is not known in advance
- (void) fcntl(*pFD, F_SETFL, O_NONBLOCK);
-
- return mStatus_NoError;
-}
-
-#if MDNS_DEBUGMSGS
-mDNSlocal void PrintRoutingSocketMsg(const struct ifa_msghdr *pRSMsg)
-{
- const char *kRSMsgTypes[] = { "", "RTM_ADD", "RTM_DELETE", "RTM_CHANGE", "RTM_GET", "RTM_LOSING",
- "RTM_REDIRECT", "RTM_MISS", "RTM_LOCK", "RTM_OLDADD", "RTM_OLDDEL", "RTM_RESOLVE",
- "RTM_NEWADDR", "RTM_DELADDR", "RTM_IFINFO", "RTM_NEWMADDR", "RTM_DELMADDR" };
-
- int index = pRSMsg->ifam_type == RTM_IFINFO ? ((struct if_msghdr*) pRSMsg)->ifm_index : pRSMsg->ifam_index;
-
- printf("ifa_msghdr len=%d, type=%s, index=%d\n", pRSMsg->ifam_msglen, kRSMsgTypes[pRSMsg->ifam_type], index);
-}
-#endif
-
-mDNSlocal mDNSu32 ProcessRoutingNotification(int sd)
-// Read through the messages on sd and if any indicate that any interface records should
-// be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
-{
- ssize_t readCount;
- char buff[4096];
- struct ifa_msghdr *pRSMsg = (struct ifa_msghdr*) buff;
- mDNSu32 result = 0;
-
- readCount = read(sd, buff, sizeof buff);
- if (readCount < (ssize_t) sizeof(struct ifa_msghdr))
- return mStatus_UnsupportedErr; // cannot decipher message
-
-#if MDNS_DEBUGMSGS
- PrintRoutingSocketMsg(pRSMsg);
-#endif
-
- // Process the message
- if (pRSMsg->ifam_type == RTM_NEWADDR || pRSMsg->ifam_type == RTM_DELADDR ||
- pRSMsg->ifam_type == RTM_IFINFO)
- {
- if (pRSMsg->ifam_type == RTM_IFINFO)
- result |= 1 << ((struct if_msghdr*) pRSMsg)->ifm_index;
- else
- result |= 1 << pRSMsg->ifam_index;
- }
-
- return result;
-}
-
-#endif // USES_NETLINK
-
-// Called when data appears on interface change notification socket
-mDNSlocal void InterfaceChangeCallback(int fd, short filter, void *context)
-{
- IfChangeRec *pChgRec = (IfChangeRec*) context;
- fd_set readFDs;
- mDNSu32 changedInterfaces = 0;
- struct timeval zeroTimeout = { 0, 0 };
-
- (void)fd; // Unused
- (void)filter; // Unused
-
- FD_ZERO(&readFDs);
- FD_SET(pChgRec->NotifySD, &readFDs);
-
- do
- {
- changedInterfaces |= ProcessRoutingNotification(pChgRec->NotifySD);
- }
- while (0 < select(pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout));
-
- // Currently we rebuild the entire interface list whenever any interface change is
- // detected. If this ever proves to be a performance issue in a multi-homed
- // configuration, more care should be paid to changedInterfaces.
- if (changedInterfaces)
- mDNSPlatformPosixRefreshInterfaceList(pChgRec->mDNS);
-}
-
-// Register with either a Routing Socket or RtNetLink to listen for interface changes.
-mDNSlocal mStatus WatchForInterfaceChange(mDNS *const m)
-{
- mStatus err;
- IfChangeRec *pChgRec;
-
- pChgRec = (IfChangeRec*) mDNSPlatformMemAllocate(sizeof *pChgRec);
- if (pChgRec == NULL)
- return mStatus_NoMemoryErr;
-
- pChgRec->mDNS = m;
- err = OpenIfNotifySocket(&pChgRec->NotifySD);
- if (err == 0)
- err = mDNSPosixAddFDToEventLoop(pChgRec->NotifySD, InterfaceChangeCallback, pChgRec);
-
- return err;
-}
-
-// Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
-// If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
-// we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
-mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
-{
- int err;
- int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- struct sockaddr_in s5353;
- s5353.sin_family = AF_INET;
- s5353.sin_port = MulticastDNSPort.NotAnInteger;
- s5353.sin_addr.s_addr = 0;
- err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
- close(s);
- if (err) debugf("No unicast UDP responses");
- else debugf("Unicast UDP responses okay");
- return(err == 0);
-}
-
-// mDNS core calls this routine to initialise the platform-specific data.
-mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
-{
- int err = 0;
- struct sockaddr sa;
- assert(m != NULL);
-
- if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue;
-
- // Tell mDNS core the names of this machine.
-
- // Set up the nice label
- m->nicelabel.c[0] = 0;
- GetUserSpecifiedFriendlyComputerName(&m->nicelabel);
- if (m->nicelabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->nicelabel, "Computer");
-
- // Set up the RFC 1034-compliant label
- m->hostlabel.c[0] = 0;
- GetUserSpecifiedRFC1034ComputerName(&m->hostlabel);
- if (m->hostlabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->hostlabel, "Computer");
-
- mDNS_SetFQDN(m);
-
- sa.sa_family = AF_INET;
- m->p->unicastSocket4 = -1;
- if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket4);
-#if HAVE_IPV6
- sa.sa_family = AF_INET6;
- m->p->unicastSocket6 = -1;
- if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket6);
-#endif
-
- // Tell mDNS core about the network interfaces on this machine.
- if (err == mStatus_NoError) err = SetupInterfaceList(m);
-
- // Tell mDNS core about DNS Servers
- mDNS_Lock(m);
- if (err == mStatus_NoError) ParseDNSServers(m, uDNS_SERVERS_FILE);
- mDNS_Unlock(m);
-
- if (err == mStatus_NoError)
- {
- err = WatchForInterfaceChange(m);
- // Failure to observe interface changes is non-fatal.
- if (err != mStatus_NoError)
- {
- fprintf(stderr, "mDNS(%d) WARNING: Unable to detect interface changes (%d).\n", getpid(), err);
- err = mStatus_NoError;
- }
- }
-
- // We don't do asynchronous initialization on the Posix platform, so by the time
- // we get here the setup will already have succeeded or failed. If it succeeded,
- // we should just call mDNSCoreInitComplete() immediately.
- if (err == mStatus_NoError)
- mDNSCoreInitComplete(m, mStatus_NoError);
-
- return PosixErrorToStatus(err);
-}
-
-// mDNS core calls this routine to clean up the platform-specific data.
-// In our case all we need to do is to tear down every network interface.
-mDNSexport void mDNSPlatformClose(mDNS *const m)
-{
- assert(m != NULL);
- ClearInterfaceList(m);
- if (m->p->unicastSocket4 != -1) assert(close(m->p->unicastSocket4) == 0);
-#if HAVE_IPV6
- if (m->p->unicastSocket6 != -1) assert(close(m->p->unicastSocket6) == 0);
-#endif
-}
-
-mDNSexport mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m)
-{
- int err;
- ClearInterfaceList(m);
- err = SetupInterfaceList(m);
- return PosixErrorToStatus(err);
-}
-
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark ***** Locking
-#endif
-
-// On the Posix platform, locking is a no-op because we only ever enter
-// mDNS core on the main thread.
-
-// mDNS core calls this routine when it wants to prevent
-// the platform from reentering mDNS core code.
-mDNSexport void mDNSPlatformLock (const mDNS *const m)
-{
- (void) m; // Unused
-}
-
-// mDNS core calls this routine when it release the lock taken by
-// mDNSPlatformLock and allow the platform to reenter mDNS core code.
-mDNSexport void mDNSPlatformUnlock (const mDNS *const m)
-{
- (void) m; // Unused
-}
-
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark ***** Strings
-#endif
-
-// mDNS core calls this routine to copy C strings.
-// On the Posix platform this maps directly to the ANSI C strcpy.
-mDNSexport void mDNSPlatformStrCopy(void *dst, const void *src)
-{
- strcpy((char *)dst, (char *)src);
-}
-
-// mDNS core calls this routine to get the length of a C string.
-// On the Posix platform this maps directly to the ANSI C strlen.
-mDNSexport mDNSu32 mDNSPlatformStrLen (const void *src)
-{
- return strlen((char*)src);
-}
-
-// mDNS core calls this routine to copy memory.
-// On the Posix platform this maps directly to the ANSI C memcpy.
-mDNSexport void mDNSPlatformMemCopy(void *dst, const void *src, mDNSu32 len)
-{
- memcpy(dst, src, len);
-}
-
-// mDNS core calls this routine to test whether blocks of memory are byte-for-byte
-// identical. On the Posix platform this is a simple wrapper around ANSI C memcmp.
-mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len)
-{
- return memcmp(dst, src, len) == 0;
-}
-
-// If the caller wants to know the exact return of memcmp, then use this instead
-// of mDNSPlatformMemSame
-mDNSexport int mDNSPlatformMemCmp(const void *dst, const void *src, mDNSu32 len)
-{
- return (memcmp(dst, src, len));
-}
-
-mDNSexport void mDNSPlatformQsort(void *base, int nel, int width, int (*compar)(const void *, const void *))
-{
- return (qsort(base, nel, width, compar));
-}
-
-// DNSSEC stub functions
-mDNSexport void VerifySignature(mDNS *const m, DNSSECVerifier *dv, DNSQuestion *q)
-{
- (void)m;
- (void)dv;
- (void)q;
-}
-
-mDNSexport mDNSBool AddNSECSForCacheRecord(mDNS *const m, CacheRecord *crlist, CacheRecord *negcr, mDNSu8 rcode)
-{
- (void)m;
- (void)crlist;
- (void)negcr;
- (void)rcode;
- return mDNSfalse;
-}
-
-mDNSexport void BumpDNSSECStats(mDNS *const m, DNSSECStatsAction action, DNSSECStatsType type, mDNSu32 value)
-{
- (void)m;
- (void)action;
- (void)type;
- (void)value;
-}
-
-// Proxy stub functions
-mDNSexport mDNSu8 *DNSProxySetAttributes(DNSQuestion *q, DNSMessageHeader *h, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit)
-{
- (void) q;
- (void) h;
- (void) msg;
- (void) ptr;
- (void) limit;
-
- return ptr;
-}
-
-mDNSexport void DNSProxyInit(mDNS *const m, mDNSu32 IpIfArr[], mDNSu32 OpIf)
-{
- (void) m;
- (void) IpIfArr;
- (void) OpIf;
-}
-
-mDNSexport void DNSProxyTerminate(mDNS *const m)
-{
- (void) m;
-}
-
-// mDNS core calls this routine to clear blocks of memory.
-// On the Posix platform this is a simple wrapper around ANSI C memset.
-mDNSexport void mDNSPlatformMemZero(void *dst, mDNSu32 len)
-{
- memset(dst, 0, len);
-}
-
-mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(malloc(len)); }
-mDNSexport void mDNSPlatformMemFree (void *mem) { free(mem); }
-
-mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
-{
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return(tv.tv_usec);
-}
-
-mDNSexport mDNSs32 mDNSPlatformOneSecond = 1024;
-
-mDNSexport mStatus mDNSPlatformTimeInit(void)
-{
- // No special setup is required on Posix -- we just use gettimeofday();
- // This is not really safe, because gettimeofday can go backwards if the user manually changes the date or time
- // We should find a better way to do this
- return(mStatus_NoError);
-}
-
-mDNSexport mDNSs32 mDNSPlatformRawTime()
-{
- struct timeval tv;
- gettimeofday(&tv, NULL);
- // tv.tv_sec is seconds since 1st January 1970 (GMT, with no adjustment for daylight savings time)
- // tv.tv_usec is microseconds since the start of this second (i.e. values 0 to 999999)
- // We use the lower 22 bits of tv.tv_sec for the top 22 bits of our result
- // and we multiply tv.tv_usec by 16 / 15625 to get a value in the range 0-1023 to go in the bottom 10 bits.
- // This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second)
- // and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days).
- return((tv.tv_sec << 10) | (tv.tv_usec * 16 / 15625));
-}
-
-mDNSexport mDNSs32 mDNSPlatformUTC(void)
-{
- return time(NULL);
-}
-
-mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
-{
- (void) m;
- (void) InterfaceID;
- (void) EthAddr;
- (void) IPAddr;
- (void) iteration;
-}
-
-mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const NetworkInterfaceInfo *intf)
-{
- (void) rr;
- (void) intf;
-
- return 1;
-}
-
-mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf)
-{
- (void) q;
- (void) intf;
-
- return 1;
-}
-
-// Used for debugging purposes. For now, just set the buffer to zero
-mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize)
-{
- (void) te;
- if (bufsize) buf[0] = 0;
-}
-
-mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win)
-{
- (void) sadd; // Unused
- (void) dadd; // Unused
- (void) lport; // Unused
- (void) rport; // Unused
- (void) seq; // Unused
- (void) ack; // Unused
- (void) win; // Unused
-}
-
-mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNS *const m, mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
-{
- (void) m; // Unused
- (void) laddr; // Unused
- (void) raddr; // Unused
- (void) lport; // Unused
- (void) rport; // Unused
- (void) mti; // Unused
-
- return mStatus_NoError;
-}
-
-mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNS *const m, mDNSAddr *raddr)
-{
- (void) raddr; // Unused
- (void) m; // Unused
-
- return mStatus_NoError;
-}
-
-mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname)
-{
- (void) spsaddr; // Unused
- (void) ifname; // Unused
-
- return mStatus_NoError;
-}
-
-mDNSexport mStatus mDNSPlatformClearSPSMACAddr(void)
-{
- return mStatus_NoError;
-}
-
-mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
-{
- (void) sock; // unused
-
- return (mDNSu16)-1;
-}
-
-mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
-{
- (void) InterfaceID; // unused
-
- return mDNSfalse;
-}
-
-mDNSexport mDNSBool mDNSPlatformAllowPID(mDNS *const m, DNSQuestion *q)
-{
- (void) m;
- (void) q;
- return mDNStrue;
-}
-
-mDNSexport mDNSs32 mDNSPlatformGetServiceID(mDNS *const m, DNSQuestion *q)
-{
- (void) m;
- (void) q;
- return 0;
-}
-
-mDNSexport void mDNSPlatformSetDelegatePID(UDPSocket *src, const mDNSAddr *dst, DNSQuestion *q)
-{
- (void) src;
- (void) dst;
- (void) q;
-}
-
-mDNSexport mDNSs32 mDNSPlatformGetPID()
-{
- return 0;
-}
-
-mDNSlocal void mDNSPosixAddToFDSet(int *nfds, fd_set *readfds, int s)
-{
- if (*nfds < s + 1) *nfds = s + 1;
- FD_SET(s, readfds);
-}
-
-mDNSexport void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, struct timeval *timeout)
-{
- mDNSs32 ticks;
- struct timeval interval;
-
- // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
- mDNSs32 nextevent = mDNS_Execute(m);
-
- // 2. Build our list of active file descriptors
- PosixNetworkInterface *info = (PosixNetworkInterface *)(m->HostInterfaces);
- if (m->p->unicastSocket4 != -1) mDNSPosixAddToFDSet(nfds, readfds, m->p->unicastSocket4);
-#if HAVE_IPV6
- if (m->p->unicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, m->p->unicastSocket6);
-#endif
- while (info)
- {
- if (info->multicastSocket4 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket4);
-#if HAVE_IPV6
- if (info->multicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket6);
-#endif
- info = (PosixNetworkInterface *)(info->coreIntf.next);
- }
-
- // 3. Calculate the time remaining to the next scheduled event (in struct timeval format)
- ticks = nextevent - mDNS_TimeNow(m);
- if (ticks < 1) ticks = 1;
- interval.tv_sec = ticks >> 10; // The high 22 bits are seconds
- interval.tv_usec = ((ticks & 0x3FF) * 15625) / 16; // The low 10 bits are 1024ths
-
- // 4. If client's proposed timeout is more than what we want, then reduce it
- if (timeout->tv_sec > interval.tv_sec ||
- (timeout->tv_sec == interval.tv_sec && timeout->tv_usec > interval.tv_usec))
- *timeout = interval;
-}
-
-mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds)
-{
- PosixNetworkInterface *info;
- assert(m != NULL);
- assert(readfds != NULL);
- info = (PosixNetworkInterface *)(m->HostInterfaces);
-
- if (m->p->unicastSocket4 != -1 && FD_ISSET(m->p->unicastSocket4, readfds))
- {
- FD_CLR(m->p->unicastSocket4, readfds);
- SocketDataReady(m, NULL, m->p->unicastSocket4);
- }
-#if HAVE_IPV6
- if (m->p->unicastSocket6 != -1 && FD_ISSET(m->p->unicastSocket6, readfds))
- {
- FD_CLR(m->p->unicastSocket6, readfds);
- SocketDataReady(m, NULL, m->p->unicastSocket6);
- }
-#endif
-
- while (info)
- {
- if (info->multicastSocket4 != -1 && FD_ISSET(info->multicastSocket4, readfds))
- {
- FD_CLR(info->multicastSocket4, readfds);
- SocketDataReady(m, info, info->multicastSocket4);
- }
-#if HAVE_IPV6
- if (info->multicastSocket6 != -1 && FD_ISSET(info->multicastSocket6, readfds))
- {
- FD_CLR(info->multicastSocket6, readfds);
- SocketDataReady(m, info, info->multicastSocket6);
- }
-#endif
- info = (PosixNetworkInterface *)(info->coreIntf.next);
- }
-}
-
-// update gMaxFD
-mDNSlocal void DetermineMaxEventFD(void)
-{
- PosixEventSource *iSource;
-
- gMaxFD = 0;
- for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
- if (gMaxFD < iSource->fd)
- gMaxFD = iSource->fd;
-}
-
-// Add a file descriptor to the set that mDNSPosixRunEventLoopOnce() listens to.
-mStatus mDNSPosixAddFDToEventLoop(int fd, mDNSPosixEventCallback callback, void *context)
-{
- PosixEventSource *newSource;
-
- if (gEventSources.LinkOffset == 0)
- InitLinkedList(&gEventSources, offsetof(PosixEventSource, Next));
-
- if (fd >= (int) FD_SETSIZE || fd < 0)
- return mStatus_UnsupportedErr;
- if (callback == NULL)
- return mStatus_BadParamErr;
-
- newSource = (PosixEventSource*) malloc(sizeof *newSource);
- if (NULL == newSource)
- return mStatus_NoMemoryErr;
-
- newSource->Callback = callback;
- newSource->Context = context;
- newSource->fd = fd;
-
- AddToTail(&gEventSources, newSource);
- FD_SET(fd, &gEventFDs);
-
- DetermineMaxEventFD();
-
- return mStatus_NoError;
-}
-
-// Remove a file descriptor from the set that mDNSPosixRunEventLoopOnce() listens to.
-mStatus mDNSPosixRemoveFDFromEventLoop(int fd)
-{
- PosixEventSource *iSource;
-
- for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
- {
- if (fd == iSource->fd)
- {
- FD_CLR(fd, &gEventFDs);
- RemoveFromList(&gEventSources, iSource);
- free(iSource);
- DetermineMaxEventFD();
- return mStatus_NoError;
- }
- }
- return mStatus_NoSuchNameErr;
-}
-
-// Simply note the received signal in gEventSignals.
-mDNSlocal void NoteSignal(int signum)
-{
- sigaddset(&gEventSignals, signum);
-}
-
-// Tell the event package to listen for signal and report it in mDNSPosixRunEventLoopOnce().
-mStatus mDNSPosixListenForSignalInEventLoop(int signum)
-{
- struct sigaction action;
- mStatus err;
-
- mDNSPlatformMemZero(&action, sizeof action); // more portable than member-wise assignment
- action.sa_handler = NoteSignal;
- err = sigaction(signum, &action, (struct sigaction*) NULL);
-
- sigaddset(&gEventSignalSet, signum);
-
- return err;
-}
-
-// Tell the event package to stop listening for signal in mDNSPosixRunEventLoopOnce().
-mStatus mDNSPosixIgnoreSignalInEventLoop(int signum)
-{
- struct sigaction action;
- mStatus err;
-
- mDNSPlatformMemZero(&action, sizeof action); // more portable than member-wise assignment
- action.sa_handler = SIG_DFL;
- err = sigaction(signum, &action, (struct sigaction*) NULL);
-
- sigdelset(&gEventSignalSet, signum);
-
- return err;
-}
-
-// Do a single pass through the attendent event sources and dispatch any found to their callbacks.
-// Return as soon as internal timeout expires, or a signal we're listening for is received.
-mStatus mDNSPosixRunEventLoopOnce(mDNS *m, const struct timeval *pTimeout,
- sigset_t *pSignalsReceived, mDNSBool *pDataDispatched)
-{
- fd_set listenFDs = gEventFDs;
- int fdMax = 0, numReady;
- struct timeval timeout = *pTimeout;
-
- // Include the sockets that are listening to the wire in our select() set
- mDNSPosixGetFDSet(m, &fdMax, &listenFDs, &timeout); // timeout may get modified
- if (fdMax < gMaxFD)
- fdMax = gMaxFD;
-
- numReady = select(fdMax + 1, &listenFDs, (fd_set*) NULL, (fd_set*) NULL, &timeout);
-
- // If any data appeared, invoke its callback
- if (numReady > 0)
- {
- PosixEventSource *iSource;
-
- (void) mDNSPosixProcessFDSet(m, &listenFDs); // call this first to process wire data for clients
-
- for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
- {
- if (FD_ISSET(iSource->fd, &listenFDs))
- {
- iSource->Callback(iSource->fd, 0, iSource->Context);
- break; // in case callback removed elements from gEventSources
- }
- }
- *pDataDispatched = mDNStrue;
- }
- else
- *pDataDispatched = mDNSfalse;
-
- (void) sigprocmask(SIG_BLOCK, &gEventSignalSet, (sigset_t*) NULL);
- *pSignalsReceived = gEventSignals;
- sigemptyset(&gEventSignals);
- (void) sigprocmask(SIG_UNBLOCK, &gEventSignalSet, (sigset_t*) NULL);
-
- return mStatus_NoError;
-}
Copied: vendor/apple/mDNSResponder/561.1.1/mDNSPosix/mDNSPosix.c (from rev 6984, vendor/apple/mDNSResponder/dist/mDNSPosix/mDNSPosix.c)
===================================================================
--- vendor/apple/mDNSResponder/561.1.1/mDNSPosix/mDNSPosix.c (rev 0)
+++ vendor/apple/mDNSResponder/561.1.1/mDNSPosix/mDNSPosix.c 2015-03-20 01:14:52 UTC (rev 6985)
@@ -0,0 +1,1789 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
+#include "DNSCommon.h"
+#include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
+#include "dns_sd.h"
+#include "dnssec.h"
+#include "nsec.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/select.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <time.h> // platform support for UTC time
+
+#if USES_NETLINK
+#include <asm/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#else // USES_NETLINK
+#include <net/route.h>
+#include <net/if.h>
+#endif // USES_NETLINK
+
+#include "mDNSUNP.h"
+#include "GenLinkedList.h"
+
+// ***************************************************************************
+// Structures
+
+// We keep a list of client-supplied event sources in PosixEventSource records
+struct PosixEventSource
+{
+ mDNSPosixEventCallback Callback;
+ void *Context;
+ int fd;
+ struct PosixEventSource *Next;
+};
+typedef struct PosixEventSource PosixEventSource;
+
+// Context record for interface change callback
+struct IfChangeRec
+{
+ int NotifySD;
+ mDNS *mDNS;
+};
+typedef struct IfChangeRec IfChangeRec;
+
+// Note that static data is initialized to zero in (modern) C.
+static fd_set gEventFDs;
+static int gMaxFD; // largest fd in gEventFDs
+static GenLinkedList gEventSources; // linked list of PosixEventSource's
+static sigset_t gEventSignalSet; // Signals which event loop listens for
+static sigset_t gEventSignals; // Signals which were received while inside loop
+
+// ***************************************************************************
+// Globals (for debugging)
+
+static int num_registered_interfaces = 0;
+static int num_pkts_accepted = 0;
+static int num_pkts_rejected = 0;
+
+// ***************************************************************************
+// Functions
+
+int gMDNSPlatformPosixVerboseLevel = 0;
+
+#define PosixErrorToStatus(errNum) ((errNum) == 0 ? mStatus_NoError : mStatus_UnknownErr)
+
+mDNSlocal void SockAddrTomDNSAddr(const struct sockaddr *const sa, mDNSAddr *ipAddr, mDNSIPPort *ipPort)
+{
+ switch (sa->sa_family)
+ {
+ case AF_INET:
+ {
+ struct sockaddr_in *sin = (struct sockaddr_in*)sa;
+ ipAddr->type = mDNSAddrType_IPv4;
+ ipAddr->ip.v4.NotAnInteger = sin->sin_addr.s_addr;
+ if (ipPort) ipPort->NotAnInteger = sin->sin_port;
+ break;
+ }
+
+#if HAVE_IPV6
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa;
+#ifndef NOT_HAVE_SA_LEN
+ assert(sin6->sin6_len == sizeof(*sin6));
+#endif
+ ipAddr->type = mDNSAddrType_IPv6;
+ ipAddr->ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
+ if (ipPort) ipPort->NotAnInteger = sin6->sin6_port;
+ break;
+ }
+#endif
+
+ default:
+ verbosedebugf("SockAddrTomDNSAddr: Uknown address family %d\n", sa->sa_family);
+ ipAddr->type = mDNSAddrType_None;
+ if (ipPort) ipPort->NotAnInteger = 0;
+ break;
+ }
+}
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark ***** Send and Receive
+#endif
+
+// mDNS core calls this routine when it needs to send a packet.
+mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
+ mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
+ mDNSIPPort dstPort, mDNSBool useBackgroundTrafficClass)
+{
+ int err = 0;
+ struct sockaddr_storage to;
+ PosixNetworkInterface * thisIntf = (PosixNetworkInterface *)(InterfaceID);
+ int sendingsocket = -1;
+
+ (void)src; // Will need to use this parameter once we implement mDNSPlatformUDPSocket/mDNSPlatformUDPClose
+ (void) useBackgroundTrafficClass;
+
+ assert(m != NULL);
+ assert(msg != NULL);
+ assert(end != NULL);
+ assert((((char *) end) - ((char *) msg)) > 0);
+
+ if (dstPort.NotAnInteger == 0)
+ {
+ LogMsg("mDNSPlatformSendUDP: Invalid argument -dstPort is set to 0");
+ return PosixErrorToStatus(EINVAL);
+ }
+ if (dst->type == mDNSAddrType_IPv4)
+ {
+ struct sockaddr_in *sin = (struct sockaddr_in*)&to;
+#ifndef NOT_HAVE_SA_LEN
+ sin->sin_len = sizeof(*sin);
+#endif
+ sin->sin_family = AF_INET;
+ sin->sin_port = dstPort.NotAnInteger;
+ sin->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
+ sendingsocket = thisIntf ? thisIntf->multicastSocket4 : m->p->unicastSocket4;
+ }
+
+#if HAVE_IPV6
+ else if (dst->type == mDNSAddrType_IPv6)
+ {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&to;
+ mDNSPlatformMemZero(sin6, sizeof(*sin6));
+#ifndef NOT_HAVE_SA_LEN
+ sin6->sin6_len = sizeof(*sin6);
+#endif
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = dstPort.NotAnInteger;
+ sin6->sin6_addr = *(struct in6_addr*)&dst->ip.v6;
+ sendingsocket = thisIntf ? thisIntf->multicastSocket6 : m->p->unicastSocket6;
+ }
+#endif
+
+ if (sendingsocket >= 0)
+ err = sendto(sendingsocket, msg, (char*)end - (char*)msg, 0, (struct sockaddr *)&to, GET_SA_LEN(to));
+
+ if (err > 0) err = 0;
+ else if (err < 0)
+ {
+ static int MessageCount = 0;
+ // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
+ if (!mDNSAddressIsAllDNSLinkGroup(dst))
+ if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
+
+ if (MessageCount < 1000)
+ {
+ MessageCount++;
+ if (thisIntf)
+ LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a on interface %#a/%s/%d",
+ errno, strerror(errno), dst, &thisIntf->coreIntf.ip, thisIntf->intfName, thisIntf->index);
+ else
+ LogMsg("mDNSPlatformSendUDP got error %d (%s) sending packet to %#a", errno, strerror(errno), dst);
+ }
+ }
+
+ return PosixErrorToStatus(err);
+}
+
+// This routine is called when the main loop detects that data is available on a socket.
+mDNSlocal void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int skt)
+{
+ mDNSAddr senderAddr, destAddr;
+ mDNSIPPort senderPort;
+ ssize_t packetLen;
+ DNSMessage packet;
+ struct my_in_pktinfo packetInfo;
+ struct sockaddr_storage from;
+ socklen_t fromLen;
+ int flags;
+ mDNSu8 ttl;
+ mDNSBool reject;
+ const mDNSInterfaceID InterfaceID = intf ? intf->coreIntf.InterfaceID : NULL;
+
+ assert(m != NULL);
+ assert(skt >= 0);
+
+ fromLen = sizeof(from);
+ flags = 0;
+ packetLen = recvfrom_flags(skt, &packet, sizeof(packet), &flags, (struct sockaddr *) &from, &fromLen, &packetInfo, &ttl);
+
+ if (packetLen >= 0)
+ {
+ SockAddrTomDNSAddr((struct sockaddr*)&from, &senderAddr, &senderPort);
+ SockAddrTomDNSAddr((struct sockaddr*)&packetInfo.ipi_addr, &destAddr, NULL);
+
+ // If we have broken IP_RECVDSTADDR functionality (so far
+ // I've only seen this on OpenBSD) then apply a hack to
+ // convince mDNS Core that this isn't a spoof packet.
+ // Basically what we do is check to see whether the
+ // packet arrived as a multicast and, if so, set its
+ // destAddr to the mDNS address.
+ //
+ // I must admit that I could just be doing something
+ // wrong on OpenBSD and hence triggering this problem
+ // but I'm at a loss as to how.
+ //
+ // If this platform doesn't have IP_PKTINFO or IP_RECVDSTADDR, then we have
+ // no way to tell the destination address or interface this packet arrived on,
+ // so all we can do is just assume it's a multicast
+
+ #if HAVE_BROKEN_RECVDSTADDR || (!defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR))
+ if ((destAddr.NotAnInteger == 0) && (flags & MSG_MCAST))
+ {
+ destAddr.type = senderAddr.type;
+ if (senderAddr.type == mDNSAddrType_IPv4) destAddr.ip.v4 = AllDNSLinkGroup_v4.ip.v4;
+ else if (senderAddr.type == mDNSAddrType_IPv6) destAddr.ip.v6 = AllDNSLinkGroup_v6.ip.v6;
+ }
+ #endif
+
+ // We only accept the packet if the interface on which it came
+ // in matches the interface associated with this socket.
+ // We do this match by name or by index, depending on which
+ // information is available. recvfrom_flags sets the name
+ // to "" if the name isn't available, or the index to -1
+ // if the index is available. This accomodates the various
+ // different capabilities of our target platforms.
+
+ reject = mDNSfalse;
+ if (!intf)
+ {
+ // Ignore multicasts accidentally delivered to our unicast receiving socket
+ if (mDNSAddrIsDNSMulticast(&destAddr)) packetLen = -1;
+ }
+ else
+ {
+ if (packetInfo.ipi_ifname[0] != 0) reject = (strcmp(packetInfo.ipi_ifname, intf->intfName) != 0);
+ else if (packetInfo.ipi_ifindex != -1) reject = (packetInfo.ipi_ifindex != intf->index);
+
+ if (reject)
+ {
+ verbosedebugf("SocketDataReady ignored a packet from %#a to %#a on interface %s/%d expecting %#a/%s/%d/%d",
+ &senderAddr, &destAddr, packetInfo.ipi_ifname, packetInfo.ipi_ifindex,
+ &intf->coreIntf.ip, intf->intfName, intf->index, skt);
+ packetLen = -1;
+ num_pkts_rejected++;
+ if (num_pkts_rejected > (num_pkts_accepted + 1) * (num_registered_interfaces + 1) * 2)
+ {
+ fprintf(stderr,
+ "*** WARNING: Received %d packets; Accepted %d packets; Rejected %d packets because of interface mismatch\n",
+ num_pkts_accepted + num_pkts_rejected, num_pkts_accepted, num_pkts_rejected);
+ num_pkts_accepted = 0;
+ num_pkts_rejected = 0;
+ }
+ }
+ else
+ {
+ verbosedebugf("SocketDataReady got a packet from %#a to %#a on interface %#a/%s/%d/%d",
+ &senderAddr, &destAddr, &intf->coreIntf.ip, intf->intfName, intf->index, skt);
+ num_pkts_accepted++;
+ }
+ }
+ }
+
+ if (packetLen >= 0)
+ mDNSCoreReceive(m, &packet, (mDNSu8 *)&packet + packetLen,
+ &senderAddr, senderPort, &destAddr, MulticastDNSPort, InterfaceID);
+}
+
+mDNSexport mDNSBool mDNSPlatformPeekUDP(mDNS *const m, UDPSocket *src)
+{
+ (void)m; // unused
+ (void)src; // unused
+ return mDNSfalse;
+}
+
+mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS * const m, TCPSocketFlags flags, mDNSIPPort * port, mDNSBool useBackgroundTrafficClass)
+{
+ (void)m; // Unused
+ (void)flags; // Unused
+ (void)port; // Unused
+ (void)useBackgroundTrafficClass; // Unused
+ return NULL;
+}
+
+mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int sd)
+{
+ (void)flags; // Unused
+ (void)sd; // Unused
+ return NULL;
+}
+
+mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
+{
+ (void)sock; // Unused
+ return -1;
+}
+
+mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID,
+ TCPConnectionCallback callback, void *context)
+{
+ (void)sock; // Unused
+ (void)dst; // Unused
+ (void)dstport; // Unused
+ (void)hostname; // Unused
+ (void)InterfaceID; // Unused
+ (void)callback; // Unused
+ (void)context; // Unused
+ return(mStatus_UnsupportedErr);
+}
+
+mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
+{
+ (void)sock; // Unused
+}
+
+mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool * closed)
+{
+ (void)sock; // Unused
+ (void)buf; // Unused
+ (void)buflen; // Unused
+ (void)closed; // Unused
+ return 0;
+}
+
+mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
+{
+ (void)sock; // Unused
+ (void)msg; // Unused
+ (void)len; // Unused
+ return 0;
+}
+
+mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS * const m, mDNSIPPort port)
+{
+ (void)m; // Unused
+ (void)port; // Unused
+ return NULL;
+}
+
+mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
+{
+ (void)sock; // Unused
+}
+
+mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
+{
+ (void)m; // Unused
+ (void)InterfaceID; // Unused
+}
+
+mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
+{
+ (void)msg; // Unused
+ (void)end; // Unused
+ (void)InterfaceID; // Unused
+}
+
+mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
+{
+ (void)m; // Unused
+ (void)tpa; // Unused
+ (void)tha; // Unused
+ (void)InterfaceID; // Unused
+}
+
+mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
+{
+ return(mStatus_UnsupportedErr);
+}
+
+mDNSexport void mDNSPlatformTLSTearDownCerts(void)
+{
+}
+
+mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason)
+{
+ (void) m;
+ (void) allowSleep;
+ (void) reason;
+}
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - /etc/hosts support
+#endif
+
+mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
+{
+ (void)m; // unused
+ (void)rr;
+ (void)result;
+}
+
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark ***** DDNS Config Platform Functions
+#endif
+
+mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains,
+ DNameListElem **BrowseDomains, mDNSBool ackConfig)
+{
+ (void) m;
+ (void) setservers;
+ (void) fqdn;
+ (void) setsearch;
+ (void) RegDomains;
+ (void) BrowseDomains;
+ (void) ackConfig;
+
+ return mDNStrue;
+}
+
+mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS * const m, mDNSAddr * v4, mDNSAddr * v6, mDNSAddr * router)
+{
+ (void) m;
+ (void) v4;
+ (void) v6;
+ (void) router;
+
+ return mStatus_UnsupportedErr;
+}
+
+mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
+{
+ (void) dname;
+ (void) status;
+}
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark ***** Init and Term
+#endif
+
+// This gets the current hostname, truncating it at the first dot if necessary
+mDNSlocal void GetUserSpecifiedRFC1034ComputerName(domainlabel *const namelabel)
+{
+ int len = 0;
+ gethostname((char *)(&namelabel->c[1]), MAX_DOMAIN_LABEL);
+ while (len < MAX_DOMAIN_LABEL && namelabel->c[len+1] && namelabel->c[len+1] != '.') len++;
+ namelabel->c[0] = len;
+}
+
+// On OS X this gets the text of the field labelled "Computer Name" in the Sharing Prefs Control Panel
+// Other platforms can either get the information from the appropriate place,
+// or they can alternatively just require all registering services to provide an explicit name
+mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
+{
+ // On Unix we have no better name than the host name, so we just use that.
+ GetUserSpecifiedRFC1034ComputerName(namelabel);
+}
+
+mDNSexport int ParseDNSServers(mDNS *m, const char *filePath)
+{
+ char line[256];
+ char nameserver[16];
+ char keyword[11];
+ int numOfServers = 0;
+ FILE *fp = fopen(filePath, "r");
+ if (fp == NULL) return -1;
+ while (fgets(line,sizeof(line),fp))
+ {
+ struct in_addr ina;
+ line[255]='\0'; // just to be safe
+ if (sscanf(line,"%10s %15s", keyword, nameserver) != 2) continue; // it will skip whitespaces
+ if (strncasecmp(keyword,"nameserver",10)) continue;
+ if (inet_aton(nameserver, (struct in_addr *)&ina) != 0)
+ {
+ mDNSAddr DNSAddr;
+ DNSAddr.type = mDNSAddrType_IPv4;
+ DNSAddr.ip.v4.NotAnInteger = ina.s_addr;
+ mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, 0, &DNSAddr, UnicastDNSPort, kScopeNone, 0, mDNSfalse, 0, mDNStrue, mDNStrue, mDNSfalse);
+ numOfServers++;
+ }
+ }
+ return (numOfServers > 0) ? 0 : -1;
+}
+
+// Searches the interface list looking for the named interface.
+// Returns a pointer to if it found, or NULL otherwise.
+mDNSlocal PosixNetworkInterface *SearchForInterfaceByName(mDNS *const m, const char *intfName)
+{
+ PosixNetworkInterface *intf;
+
+ assert(m != NULL);
+ assert(intfName != NULL);
+
+ intf = (PosixNetworkInterface*)(m->HostInterfaces);
+ while ((intf != NULL) && (strcmp(intf->intfName, intfName) != 0))
+ intf = (PosixNetworkInterface *)(intf->coreIntf.next);
+
+ return intf;
+}
+
+mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 index)
+{
+ PosixNetworkInterface *intf;
+
+ assert(m != NULL);
+
+ if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
+ if (index == kDNSServiceInterfaceIndexP2P ) return(mDNSInterface_P2P);
+ if (index == kDNSServiceInterfaceIndexAny ) return(mDNSInterface_Any);
+
+ intf = (PosixNetworkInterface*)(m->HostInterfaces);
+ while ((intf != NULL) && (mDNSu32) intf->index != index)
+ intf = (PosixNetworkInterface *)(intf->coreIntf.next);
+
+ return (mDNSInterfaceID) intf;
+}
+
+mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange)
+{
+ PosixNetworkInterface *intf;
+ (void) suppressNetworkChange; // Unused
+
+ assert(m != NULL);
+
+ if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
+ if (id == mDNSInterface_P2P ) return(kDNSServiceInterfaceIndexP2P);
+ if (id == mDNSInterface_Any ) return(kDNSServiceInterfaceIndexAny);
+
+ intf = (PosixNetworkInterface*)(m->HostInterfaces);
+ while ((intf != NULL) && (mDNSInterfaceID) intf != id)
+ intf = (PosixNetworkInterface *)(intf->coreIntf.next);
+
+ return intf ? intf->index : 0;
+}
+
+// Frees the specified PosixNetworkInterface structure. The underlying
+// interface must have already been deregistered with the mDNS core.
+mDNSlocal void FreePosixNetworkInterface(PosixNetworkInterface *intf)
+{
+ assert(intf != NULL);
+ if (intf->intfName != NULL) free((void *)intf->intfName);
+ if (intf->multicastSocket4 != -1) assert(close(intf->multicastSocket4) == 0);
+#if HAVE_IPV6
+ if (intf->multicastSocket6 != -1) assert(close(intf->multicastSocket6) == 0);
+#endif
+ free(intf);
+}
+
+// Grab the first interface, deregister it, free it, and repeat until done.
+mDNSlocal void ClearInterfaceList(mDNS *const m)
+{
+ assert(m != NULL);
+
+ while (m->HostInterfaces)
+ {
+ PosixNetworkInterface *intf = (PosixNetworkInterface*)(m->HostInterfaces);
+ mDNS_DeregisterInterface(m, &intf->coreIntf, mDNSfalse);
+ if (gMDNSPlatformPosixVerboseLevel > 0) fprintf(stderr, "Deregistered interface %s\n", intf->intfName);
+ FreePosixNetworkInterface(intf);
+ }
+ num_registered_interfaces = 0;
+ num_pkts_accepted = 0;
+ num_pkts_rejected = 0;
+}
+
+// Sets up a send/receive socket.
+// If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
+// If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
+mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interfaceIndex, int *sktPtr)
+{
+ int err = 0;
+ static const int kOn = 1;
+ static const int kIntTwoFiveFive = 255;
+ static const unsigned char kByteTwoFiveFive = 255;
+ const mDNSBool JoinMulticastGroup = (port.NotAnInteger != 0);
+
+ (void) interfaceIndex; // This parameter unused on plaforms that don't have IPv6
+ assert(intfAddr != NULL);
+ assert(sktPtr != NULL);
+ assert(*sktPtr == -1);
+
+ // Open the socket...
+ if (intfAddr->sa_family == AF_INET) *sktPtr = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+#if HAVE_IPV6
+ else if (intfAddr->sa_family == AF_INET6) *sktPtr = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+#endif
+ else return EINVAL;
+
+ if (*sktPtr < 0) { err = errno; perror((intfAddr->sa_family == AF_INET) ? "socket AF_INET" : "socket AF_INET6"); }
+
+ // ... with a shared UDP port, if it's for multicast receiving
+ if (err == 0 && port.NotAnInteger)
+ {
+ #if defined(SO_REUSEPORT)
+ err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEPORT, &kOn, sizeof(kOn));
+ #elif defined(SO_REUSEADDR)
+ err = setsockopt(*sktPtr, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
+ #else
+ #error This platform has no way to avoid address busy errors on multicast.
+ #endif
+ if (err < 0) { err = errno; perror("setsockopt - SO_REUSExxxx"); }
+ }
+
+ // We want to receive destination addresses and interface identifiers.
+ if (intfAddr->sa_family == AF_INET)
+ {
+ struct ip_mreq imr;
+ struct sockaddr_in bindAddr;
+ if (err == 0)
+ {
+ #if defined(IP_PKTINFO) // Linux
+ err = setsockopt(*sktPtr, IPPROTO_IP, IP_PKTINFO, &kOn, sizeof(kOn));
+ if (err < 0) { err = errno; perror("setsockopt - IP_PKTINFO"); }
+ #elif defined(IP_RECVDSTADDR) || defined(IP_RECVIF) // BSD and Solaris
+ #if defined(IP_RECVDSTADDR)
+ err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVDSTADDR, &kOn, sizeof(kOn));
+ if (err < 0) { err = errno; perror("setsockopt - IP_RECVDSTADDR"); }
+ #endif
+ #if defined(IP_RECVIF)
+ if (err == 0)
+ {
+ err = setsockopt(*sktPtr, IPPROTO_IP, IP_RECVIF, &kOn, sizeof(kOn));
+ if (err < 0) { err = errno; perror("setsockopt - IP_RECVIF"); }
+ }
+ #endif
+ #else
+ #warning This platform has no way to get the destination interface information -- will only work for single-homed hosts
+ #endif
+ }
+ #if defined(IP_RECVTTL) // Linux
+ if (err == 0)
+ {
+ setsockopt(*sktPtr, IPPROTO_IP, IP_RECVTTL, &kOn, sizeof(kOn));
+ // We no longer depend on being able to get the received TTL, so don't worry if the option fails
+ }
+ #endif
+
+ // Add multicast group membership on this interface
+ if (err == 0 && JoinMulticastGroup)
+ {
+ imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
+ imr.imr_interface = ((struct sockaddr_in*)intfAddr)->sin_addr;
+ err = setsockopt(*sktPtr, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr));
+ if (err < 0) { err = errno; perror("setsockopt - IP_ADD_MEMBERSHIP"); }
+ }
+
+ // Specify outgoing interface too
+ if (err == 0 && JoinMulticastGroup)
+ {
+ err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_IF, &((struct sockaddr_in*)intfAddr)->sin_addr, sizeof(struct in_addr));
+ if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_IF"); }
+ }
+
+ // Per the mDNS spec, send unicast packets with TTL 255
+ if (err == 0)
+ {
+ err = setsockopt(*sktPtr, IPPROTO_IP, IP_TTL, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
+ if (err < 0) { err = errno; perror("setsockopt - IP_TTL"); }
+ }
+
+ // and multicast packets with TTL 255 too
+ // There's some debate as to whether IP_MULTICAST_TTL is an int or a byte so we just try both.
+ if (err == 0)
+ {
+ err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL, &kByteTwoFiveFive, sizeof(kByteTwoFiveFive));
+ if (err < 0 && errno == EINVAL)
+ err = setsockopt(*sktPtr, IPPROTO_IP, IP_MULTICAST_TTL, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
+ if (err < 0) { err = errno; perror("setsockopt - IP_MULTICAST_TTL"); }
+ }
+
+ // And start listening for packets
+ if (err == 0)
+ {
+ bindAddr.sin_family = AF_INET;
+ bindAddr.sin_port = port.NotAnInteger;
+ bindAddr.sin_addr.s_addr = INADDR_ANY; // Want to receive multicasts AND unicasts on this socket
+ err = bind(*sktPtr, (struct sockaddr *) &bindAddr, sizeof(bindAddr));
+ if (err < 0) { err = errno; perror("bind"); fflush(stderr); }
+ }
+ } // endif (intfAddr->sa_family == AF_INET)
+
+#if HAVE_IPV6
+ else if (intfAddr->sa_family == AF_INET6)
+ {
+ struct ipv6_mreq imr6;
+ struct sockaddr_in6 bindAddr6;
+ #if defined(IPV6_PKTINFO)
+ if (err == 0)
+ {
+ err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_2292_PKTINFO, &kOn, sizeof(kOn));
+ if (err < 0) { err = errno; perror("setsockopt - IPV6_PKTINFO"); }
+ }
+ #else
+ #warning This platform has no way to get the destination interface information for IPv6 -- will only work for single-homed hosts
+ #endif
+ #if defined(IPV6_HOPLIMIT)
+ if (err == 0)
+ {
+ err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_2292_HOPLIMIT, &kOn, sizeof(kOn));
+ if (err < 0) { err = errno; perror("setsockopt - IPV6_HOPLIMIT"); }
+ }
+ #endif
+
+ // Add multicast group membership on this interface
+ if (err == 0 && JoinMulticastGroup)
+ {
+ imr6.ipv6mr_multiaddr = *(const struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6;
+ imr6.ipv6mr_interface = interfaceIndex;
+ //LogMsg("Joining %.16a on %d", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface);
+ err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_JOIN_GROUP, &imr6, sizeof(imr6));
+ if (err < 0)
+ {
+ err = errno;
+ verbosedebugf("IPV6_JOIN_GROUP %.16a on %d failed.\n", &imr6.ipv6mr_multiaddr, imr6.ipv6mr_interface);
+ perror("setsockopt - IPV6_JOIN_GROUP");
+ }
+ }
+
+ // Specify outgoing interface too
+ if (err == 0 && JoinMulticastGroup)
+ {
+ u_int multicast_if = interfaceIndex;
+ err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_if, sizeof(multicast_if));
+ if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_IF"); }
+ }
+
+ // We want to receive only IPv6 packets on this socket.
+ // Without this option, we may get IPv4 addresses as mapped addresses.
+ if (err == 0)
+ {
+ err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_V6ONLY, &kOn, sizeof(kOn));
+ if (err < 0) { err = errno; perror("setsockopt - IPV6_V6ONLY"); }
+ }
+
+ // Per the mDNS spec, send unicast packets with TTL 255
+ if (err == 0)
+ {
+ err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
+ if (err < 0) { err = errno; perror("setsockopt - IPV6_UNICAST_HOPS"); }
+ }
+
+ // and multicast packets with TTL 255 too
+ // There's some debate as to whether IPV6_MULTICAST_HOPS is an int or a byte so we just try both.
+ if (err == 0)
+ {
+ err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kByteTwoFiveFive, sizeof(kByteTwoFiveFive));
+ if (err < 0 && errno == EINVAL)
+ err = setsockopt(*sktPtr, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kIntTwoFiveFive, sizeof(kIntTwoFiveFive));
+ if (err < 0) { err = errno; perror("setsockopt - IPV6_MULTICAST_HOPS"); }
+ }
+
+ // And start listening for packets
+ if (err == 0)
+ {
+ mDNSPlatformMemZero(&bindAddr6, sizeof(bindAddr6));
+#ifndef NOT_HAVE_SA_LEN
+ bindAddr6.sin6_len = sizeof(bindAddr6);
+#endif
+ bindAddr6.sin6_family = AF_INET6;
+ bindAddr6.sin6_port = port.NotAnInteger;
+ bindAddr6.sin6_flowinfo = 0;
+ bindAddr6.sin6_addr = in6addr_any; // Want to receive multicasts AND unicasts on this socket
+ bindAddr6.sin6_scope_id = 0;
+ err = bind(*sktPtr, (struct sockaddr *) &bindAddr6, sizeof(bindAddr6));
+ if (err < 0) { err = errno; perror("bind"); fflush(stderr); }
+ }
+ } // endif (intfAddr->sa_family == AF_INET6)
+#endif
+
+ // Set the socket to non-blocking.
+ if (err == 0)
+ {
+ err = fcntl(*sktPtr, F_GETFL, 0);
+ if (err < 0) err = errno;
+ else
+ {
+ err = fcntl(*sktPtr, F_SETFL, err | O_NONBLOCK);
+ if (err < 0) err = errno;
+ }
+ }
+
+ // Clean up
+ if (err != 0 && *sktPtr != -1) { assert(close(*sktPtr) == 0); *sktPtr = -1; }
+ assert((err == 0) == (*sktPtr != -1));
+ return err;
+}
+
+// Creates a PosixNetworkInterface for the interface whose IP address is
+// intfAddr and whose name is intfName and registers it with mDNS core.
+mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct sockaddr *intfMask, const char *intfName, int intfIndex)
+{
+ int err = 0;
+ PosixNetworkInterface *intf;
+ PosixNetworkInterface *alias = NULL;
+
+ assert(m != NULL);
+ assert(intfAddr != NULL);
+ assert(intfName != NULL);
+ assert(intfMask != NULL);
+
+ // Allocate the interface structure itself.
+ intf = (PosixNetworkInterface*)malloc(sizeof(*intf));
+ if (intf == NULL) { assert(0); err = ENOMEM; }
+
+ // And make a copy of the intfName.
+ if (err == 0)
+ {
+ intf->intfName = strdup(intfName);
+ if (intf->intfName == NULL) { assert(0); err = ENOMEM; }
+ }
+
+ if (err == 0)
+ {
+ // Set up the fields required by the mDNS core.
+ SockAddrTomDNSAddr(intfAddr, &intf->coreIntf.ip, NULL);
+ SockAddrTomDNSAddr(intfMask, &intf->coreIntf.mask, NULL);
+
+ //LogMsg("SetupOneInterface: %#a %#a", &intf->coreIntf.ip, &intf->coreIntf.mask);
+ strncpy(intf->coreIntf.ifname, intfName, sizeof(intf->coreIntf.ifname));
+ intf->coreIntf.ifname[sizeof(intf->coreIntf.ifname)-1] = 0;
+ intf->coreIntf.Advertise = m->AdvertiseLocalAddresses;
+ intf->coreIntf.McastTxRx = mDNStrue;
+
+ // Set up the extra fields in PosixNetworkInterface.
+ assert(intf->intfName != NULL); // intf->intfName already set up above
+ intf->index = intfIndex;
+ intf->multicastSocket4 = -1;
+#if HAVE_IPV6
+ intf->multicastSocket6 = -1;
+#endif
+ alias = SearchForInterfaceByName(m, intf->intfName);
+ if (alias == NULL) alias = intf;
+ intf->coreIntf.InterfaceID = (mDNSInterfaceID)alias;
+
+ if (alias != intf)
+ debugf("SetupOneInterface: %s %#a is an alias of %#a", intfName, &intf->coreIntf.ip, &alias->coreIntf.ip);
+ }
+
+ // Set up the multicast socket
+ if (err == 0)
+ {
+ if (alias->multicastSocket4 == -1 && intfAddr->sa_family == AF_INET)
+ err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket4);
+#if HAVE_IPV6
+ else if (alias->multicastSocket6 == -1 && intfAddr->sa_family == AF_INET6)
+ err = SetupSocket(intfAddr, MulticastDNSPort, intf->index, &alias->multicastSocket6);
+#endif
+ }
+
+ // If interface is a direct link, address record will be marked as kDNSRecordTypeKnownUnique
+ // and skip the probe phase of the probe/announce packet sequence.
+ intf->coreIntf.DirectLink = mDNSfalse;
+
+ // The interface is all ready to go, let's register it with the mDNS core.
+ if (err == 0)
+ err = mDNS_RegisterInterface(m, &intf->coreIntf, mDNSfalse);
+
+ // Clean up.
+ if (err == 0)
+ {
+ num_registered_interfaces++;
+ debugf("SetupOneInterface: %s %#a Registered", intf->intfName, &intf->coreIntf.ip);
+ if (gMDNSPlatformPosixVerboseLevel > 0)
+ fprintf(stderr, "Registered interface %s\n", intf->intfName);
+ }
+ else
+ {
+ // Use intfName instead of intf->intfName in the next line to avoid dereferencing NULL.
+ debugf("SetupOneInterface: %s %#a failed to register %d", intfName, &intf->coreIntf.ip, err);
+ if (intf) { FreePosixNetworkInterface(intf); intf = NULL; }
+ }
+
+ assert((err == 0) == (intf != NULL));
+
+ return err;
+}
+
+// Call get_ifi_info() to obtain a list of active interfaces and call SetupOneInterface() on each one.
+mDNSlocal int SetupInterfaceList(mDNS *const m)
+{
+ mDNSBool foundav4 = mDNSfalse;
+ int err = 0;
+ struct ifi_info *intfList = get_ifi_info(AF_INET, mDNStrue);
+ struct ifi_info *firstLoopback = NULL;
+
+ assert(m != NULL);
+ debugf("SetupInterfaceList");
+
+ if (intfList == NULL) err = ENOENT;
+
+#if HAVE_IPV6
+ if (err == 0) /* Link the IPv6 list to the end of the IPv4 list */
+ {
+ struct ifi_info **p = &intfList;
+ while (*p) p = &(*p)->ifi_next;
+ *p = get_ifi_info(AF_INET6, mDNStrue);
+ }
+#endif
+
+ if (err == 0)
+ {
+ struct ifi_info *i = intfList;
+ while (i)
+ {
+ if ( ((i->ifi_addr->sa_family == AF_INET)
+#if HAVE_IPV6
+ || (i->ifi_addr->sa_family == AF_INET6)
+#endif
+ ) && (i->ifi_flags & IFF_UP) && !(i->ifi_flags & IFF_POINTOPOINT))
+ {
+ if (i->ifi_flags & IFF_LOOPBACK)
+ {
+ if (firstLoopback == NULL)
+ firstLoopback = i;
+ }
+ else
+ {
+ if (SetupOneInterface(m, i->ifi_addr, i->ifi_netmask, i->ifi_name, i->ifi_index) == 0)
+ if (i->ifi_addr->sa_family == AF_INET)
+ foundav4 = mDNStrue;
+ }
+ }
+ i = i->ifi_next;
+ }
+
+ // If we found no normal interfaces but we did find a loopback interface, register the
+ // loopback interface. This allows self-discovery if no interfaces are configured.
+ // Temporary workaround: Multicast loopback on IPv6 interfaces appears not to work.
+ // In the interim, we skip loopback interface only if we found at least one v4 interface to use
+ // if ((m->HostInterfaces == NULL) && (firstLoopback != NULL))
+ if (!foundav4 && firstLoopback)
+ (void) SetupOneInterface(m, firstLoopback->ifi_addr, firstLoopback->ifi_netmask, firstLoopback->ifi_name, firstLoopback->ifi_index);
+ }
+
+ // Clean up.
+ if (intfList != NULL) free_ifi_info(intfList);
+ return err;
+}
+
+#if USES_NETLINK
+
+// See <http://www.faqs.org/rfcs/rfc3549.html> for a description of NetLink
+
+// Open a socket that will receive interface change notifications
+mDNSlocal mStatus OpenIfNotifySocket(int *pFD)
+{
+ mStatus err = mStatus_NoError;
+ struct sockaddr_nl snl;
+ int sock;
+ int ret;
+
+ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock < 0)
+ return errno;
+
+ // Configure read to be non-blocking because inbound msg size is not known in advance
+ (void) fcntl(sock, F_SETFL, O_NONBLOCK);
+
+ /* Subscribe the socket to Link & IP addr notifications. */
+ mDNSPlatformMemZero(&snl, sizeof snl);
+ snl.nl_family = AF_NETLINK;
+ snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
+ ret = bind(sock, (struct sockaddr *) &snl, sizeof snl);
+ if (0 == ret)
+ *pFD = sock;
+ else
+ err = errno;
+
+ return err;
+}
+
+#if MDNS_DEBUGMSGS
+mDNSlocal void PrintNetLinkMsg(const struct nlmsghdr *pNLMsg)
+{
+ const char *kNLMsgTypes[] = { "", "NLMSG_NOOP", "NLMSG_ERROR", "NLMSG_DONE", "NLMSG_OVERRUN" };
+ const char *kNLRtMsgTypes[] = { "RTM_NEWLINK", "RTM_DELLINK", "RTM_GETLINK", "RTM_NEWADDR", "RTM_DELADDR", "RTM_GETADDR" };
+
+ printf("nlmsghdr len=%d, type=%s, flags=0x%x\n", pNLMsg->nlmsg_len,
+ pNLMsg->nlmsg_type < RTM_BASE ? kNLMsgTypes[pNLMsg->nlmsg_type] : kNLRtMsgTypes[pNLMsg->nlmsg_type - RTM_BASE],
+ pNLMsg->nlmsg_flags);
+
+ if (RTM_NEWLINK <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETLINK)
+ {
+ struct ifinfomsg *pIfInfo = (struct ifinfomsg*) NLMSG_DATA(pNLMsg);
+ printf("ifinfomsg family=%d, type=%d, index=%d, flags=0x%x, change=0x%x\n", pIfInfo->ifi_family,
+ pIfInfo->ifi_type, pIfInfo->ifi_index, pIfInfo->ifi_flags, pIfInfo->ifi_change);
+
+ }
+ else if (RTM_NEWADDR <= pNLMsg->nlmsg_type && pNLMsg->nlmsg_type <= RTM_GETADDR)
+ {
+ struct ifaddrmsg *pIfAddr = (struct ifaddrmsg*) NLMSG_DATA(pNLMsg);
+ printf("ifaddrmsg family=%d, index=%d, flags=0x%x\n", pIfAddr->ifa_family,
+ pIfAddr->ifa_index, pIfAddr->ifa_flags);
+ }
+ printf("\n");
+}
+#endif
+
+mDNSlocal mDNSu32 ProcessRoutingNotification(int sd)
+// Read through the messages on sd and if any indicate that any interface records should
+// be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
+{
+ ssize_t readCount;
+ char buff[4096];
+ struct nlmsghdr *pNLMsg = (struct nlmsghdr*) buff;
+ mDNSu32 result = 0;
+
+ // The structure here is more complex than it really ought to be because,
+ // unfortunately, there's no good way to size a buffer in advance large
+ // enough to hold all pending data and so avoid message fragmentation.
+ // (Note that FIONREAD is not supported on AF_NETLINK.)
+
+ readCount = read(sd, buff, sizeof buff);
+ while (1)
+ {
+ // Make sure we've got an entire nlmsghdr in the buffer, and payload, too.
+ // If not, discard already-processed messages in buffer and read more data.
+ if (((char*) &pNLMsg[1] > (buff + readCount)) || // i.e. *pNLMsg extends off end of buffer
+ ((char*) pNLMsg + pNLMsg->nlmsg_len > (buff + readCount)))
+ {
+ if (buff < (char*) pNLMsg) // we have space to shuffle
+ {
+ // discard processed data
+ readCount -= ((char*) pNLMsg - buff);
+ memmove(buff, pNLMsg, readCount);
+ pNLMsg = (struct nlmsghdr*) buff;
+
+ // read more data
+ readCount += read(sd, buff + readCount, sizeof buff - readCount);
+ continue; // spin around and revalidate with new readCount
+ }
+ else
+ break; // Otherwise message does not fit in buffer
+ }
+
+#if MDNS_DEBUGMSGS
+ PrintNetLinkMsg(pNLMsg);
+#endif
+
+ // Process the NetLink message
+ if (pNLMsg->nlmsg_type == RTM_GETLINK || pNLMsg->nlmsg_type == RTM_NEWLINK)
+ result |= 1 << ((struct ifinfomsg*) NLMSG_DATA(pNLMsg))->ifi_index;
+ else if (pNLMsg->nlmsg_type == RTM_DELADDR || pNLMsg->nlmsg_type == RTM_NEWADDR)
+ result |= 1 << ((struct ifaddrmsg*) NLMSG_DATA(pNLMsg))->ifa_index;
+
+ // Advance pNLMsg to the next message in the buffer
+ if ((pNLMsg->nlmsg_flags & NLM_F_MULTI) != 0 && pNLMsg->nlmsg_type != NLMSG_DONE)
+ {
+ ssize_t len = readCount - ((char*)pNLMsg - buff);
+ pNLMsg = NLMSG_NEXT(pNLMsg, len);
+ }
+ else
+ break; // all done!
+ }
+
+ return result;
+}
+
+#else // USES_NETLINK
+
+// Open a socket that will receive interface change notifications
+mDNSlocal mStatus OpenIfNotifySocket(int *pFD)
+{
+ *pFD = socket(AF_ROUTE, SOCK_RAW, 0);
+
+ if (*pFD < 0)
+ return mStatus_UnknownErr;
+
+ // Configure read to be non-blocking because inbound msg size is not known in advance
+ (void) fcntl(*pFD, F_SETFL, O_NONBLOCK);
+
+ return mStatus_NoError;
+}
+
+#if MDNS_DEBUGMSGS
+mDNSlocal void PrintRoutingSocketMsg(const struct ifa_msghdr *pRSMsg)
+{
+ const char *kRSMsgTypes[] = { "", "RTM_ADD", "RTM_DELETE", "RTM_CHANGE", "RTM_GET", "RTM_LOSING",
+ "RTM_REDIRECT", "RTM_MISS", "RTM_LOCK", "RTM_OLDADD", "RTM_OLDDEL", "RTM_RESOLVE",
+ "RTM_NEWADDR", "RTM_DELADDR", "RTM_IFINFO", "RTM_NEWMADDR", "RTM_DELMADDR" };
+
+ int index = pRSMsg->ifam_type == RTM_IFINFO ? ((struct if_msghdr*) pRSMsg)->ifm_index : pRSMsg->ifam_index;
+
+ printf("ifa_msghdr len=%d, type=%s, index=%d\n", pRSMsg->ifam_msglen, kRSMsgTypes[pRSMsg->ifam_type], index);
+}
+#endif
+
+mDNSlocal mDNSu32 ProcessRoutingNotification(int sd)
+// Read through the messages on sd and if any indicate that any interface records should
+// be torn down and rebuilt, return affected indices as a bitmask. Otherwise return 0.
+{
+ ssize_t readCount;
+ char buff[4096];
+ struct ifa_msghdr *pRSMsg = (struct ifa_msghdr*) buff;
+ mDNSu32 result = 0;
+
+ readCount = read(sd, buff, sizeof buff);
+ if (readCount < (ssize_t) sizeof(struct ifa_msghdr))
+ return mStatus_UnsupportedErr; // cannot decipher message
+
+#if MDNS_DEBUGMSGS
+ PrintRoutingSocketMsg(pRSMsg);
+#endif
+
+ // Process the message
+ if (pRSMsg->ifam_type == RTM_NEWADDR || pRSMsg->ifam_type == RTM_DELADDR ||
+ pRSMsg->ifam_type == RTM_IFINFO)
+ {
+ if (pRSMsg->ifam_type == RTM_IFINFO)
+ result |= 1 << ((struct if_msghdr*) pRSMsg)->ifm_index;
+ else
+ result |= 1 << pRSMsg->ifam_index;
+ }
+
+ return result;
+}
+
+#endif // USES_NETLINK
+
+// Called when data appears on interface change notification socket
+mDNSlocal void InterfaceChangeCallback(int fd, short filter, void *context)
+{
+ IfChangeRec *pChgRec = (IfChangeRec*) context;
+ fd_set readFDs;
+ mDNSu32 changedInterfaces = 0;
+ struct timeval zeroTimeout = { 0, 0 };
+
+ (void)fd; // Unused
+ (void)filter; // Unused
+
+ FD_ZERO(&readFDs);
+ FD_SET(pChgRec->NotifySD, &readFDs);
+
+ do
+ {
+ changedInterfaces |= ProcessRoutingNotification(pChgRec->NotifySD);
+ }
+ while (0 < select(pChgRec->NotifySD + 1, &readFDs, (fd_set*) NULL, (fd_set*) NULL, &zeroTimeout));
+
+ // Currently we rebuild the entire interface list whenever any interface change is
+ // detected. If this ever proves to be a performance issue in a multi-homed
+ // configuration, more care should be paid to changedInterfaces.
+ if (changedInterfaces)
+ mDNSPlatformPosixRefreshInterfaceList(pChgRec->mDNS);
+}
+
+// Register with either a Routing Socket or RtNetLink to listen for interface changes.
+mDNSlocal mStatus WatchForInterfaceChange(mDNS *const m)
+{
+ mStatus err;
+ IfChangeRec *pChgRec;
+
+ pChgRec = (IfChangeRec*) mDNSPlatformMemAllocate(sizeof *pChgRec);
+ if (pChgRec == NULL)
+ return mStatus_NoMemoryErr;
+
+ pChgRec->mDNS = m;
+ err = OpenIfNotifySocket(&pChgRec->NotifySD);
+ if (err == 0)
+ err = mDNSPosixAddFDToEventLoop(pChgRec->NotifySD, InterfaceChangeCallback, pChgRec);
+
+ return err;
+}
+
+// Test to see if we're the first client running on UDP port 5353, by trying to bind to 5353 without using SO_REUSEPORT.
+// If we fail, someone else got here first. That's not a big problem; we can share the port for multicast responses --
+// we just need to be aware that we shouldn't expect to successfully receive unicast UDP responses.
+mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
+{
+ int err;
+ int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ struct sockaddr_in s5353;
+ s5353.sin_family = AF_INET;
+ s5353.sin_port = MulticastDNSPort.NotAnInteger;
+ s5353.sin_addr.s_addr = 0;
+ err = bind(s, (struct sockaddr *)&s5353, sizeof(s5353));
+ close(s);
+ if (err) debugf("No unicast UDP responses");
+ else debugf("Unicast UDP responses okay");
+ return(err == 0);
+}
+
+// mDNS core calls this routine to initialise the platform-specific data.
+mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
+{
+ int err = 0;
+ struct sockaddr sa;
+ assert(m != NULL);
+
+ if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue;
+
+ // Tell mDNS core the names of this machine.
+
+ // Set up the nice label
+ m->nicelabel.c[0] = 0;
+ GetUserSpecifiedFriendlyComputerName(&m->nicelabel);
+ if (m->nicelabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->nicelabel, "Computer");
+
+ // Set up the RFC 1034-compliant label
+ m->hostlabel.c[0] = 0;
+ GetUserSpecifiedRFC1034ComputerName(&m->hostlabel);
+ if (m->hostlabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->hostlabel, "Computer");
+
+ mDNS_SetFQDN(m);
+
+ sa.sa_family = AF_INET;
+ m->p->unicastSocket4 = -1;
+ if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket4);
+#if HAVE_IPV6
+ sa.sa_family = AF_INET6;
+ m->p->unicastSocket6 = -1;
+ if (err == mStatus_NoError) err = SetupSocket(&sa, zeroIPPort, 0, &m->p->unicastSocket6);
+#endif
+
+ // Tell mDNS core about the network interfaces on this machine.
+ if (err == mStatus_NoError) err = SetupInterfaceList(m);
+
+ // Tell mDNS core about DNS Servers
+ mDNS_Lock(m);
+ if (err == mStatus_NoError) ParseDNSServers(m, uDNS_SERVERS_FILE);
+ mDNS_Unlock(m);
+
+ if (err == mStatus_NoError)
+ {
+ err = WatchForInterfaceChange(m);
+ // Failure to observe interface changes is non-fatal.
+ if (err != mStatus_NoError)
+ {
+ fprintf(stderr, "mDNS(%d) WARNING: Unable to detect interface changes (%d).\n", getpid(), err);
+ err = mStatus_NoError;
+ }
+ }
+
+ // We don't do asynchronous initialization on the Posix platform, so by the time
+ // we get here the setup will already have succeeded or failed. If it succeeded,
+ // we should just call mDNSCoreInitComplete() immediately.
+ if (err == mStatus_NoError)
+ mDNSCoreInitComplete(m, mStatus_NoError);
+
+ return PosixErrorToStatus(err);
+}
+
+// mDNS core calls this routine to clean up the platform-specific data.
+// In our case all we need to do is to tear down every network interface.
+mDNSexport void mDNSPlatformClose(mDNS *const m)
+{
+ assert(m != NULL);
+ ClearInterfaceList(m);
+ if (m->p->unicastSocket4 != -1) assert(close(m->p->unicastSocket4) == 0);
+#if HAVE_IPV6
+ if (m->p->unicastSocket6 != -1) assert(close(m->p->unicastSocket6) == 0);
+#endif
+}
+
+mDNSexport mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m)
+{
+ int err;
+ ClearInterfaceList(m);
+ err = SetupInterfaceList(m);
+ return PosixErrorToStatus(err);
+}
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark ***** Locking
+#endif
+
+// On the Posix platform, locking is a no-op because we only ever enter
+// mDNS core on the main thread.
+
+// mDNS core calls this routine when it wants to prevent
+// the platform from reentering mDNS core code.
+mDNSexport void mDNSPlatformLock (const mDNS *const m)
+{
+ (void) m; // Unused
+}
+
+// mDNS core calls this routine when it release the lock taken by
+// mDNSPlatformLock and allow the platform to reenter mDNS core code.
+mDNSexport void mDNSPlatformUnlock (const mDNS *const m)
+{
+ (void) m; // Unused
+}
+
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark ***** Strings
+#endif
+
+// mDNS core calls this routine to copy C strings.
+// On the Posix platform this maps directly to the ANSI C strcpy.
+mDNSexport void mDNSPlatformStrCopy(void *dst, const void *src)
+{
+ strcpy((char *)dst, (char *)src);
+}
+
+// mDNS core calls this routine to get the length of a C string.
+// On the Posix platform this maps directly to the ANSI C strlen.
+mDNSexport mDNSu32 mDNSPlatformStrLen (const void *src)
+{
+ return strlen((char*)src);
+}
+
+// mDNS core calls this routine to copy memory.
+// On the Posix platform this maps directly to the ANSI C memcpy.
+mDNSexport void mDNSPlatformMemCopy(void *dst, const void *src, mDNSu32 len)
+{
+ memcpy(dst, src, len);
+}
+
+// mDNS core calls this routine to test whether blocks of memory are byte-for-byte
+// identical. On the Posix platform this is a simple wrapper around ANSI C memcmp.
+mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len)
+{
+ return memcmp(dst, src, len) == 0;
+}
+
+// If the caller wants to know the exact return of memcmp, then use this instead
+// of mDNSPlatformMemSame
+mDNSexport int mDNSPlatformMemCmp(const void *dst, const void *src, mDNSu32 len)
+{
+ return (memcmp(dst, src, len));
+}
+
+mDNSexport void mDNSPlatformQsort(void *base, int nel, int width, int (*compar)(const void *, const void *))
+{
+ return (qsort(base, nel, width, compar));
+}
+
+// DNSSEC stub functions
+mDNSexport void VerifySignature(mDNS *const m, DNSSECVerifier *dv, DNSQuestion *q)
+{
+ (void)m;
+ (void)dv;
+ (void)q;
+}
+
+mDNSexport mDNSBool AddNSECSForCacheRecord(mDNS *const m, CacheRecord *crlist, CacheRecord *negcr, mDNSu8 rcode)
+{
+ (void)m;
+ (void)crlist;
+ (void)negcr;
+ (void)rcode;
+ return mDNSfalse;
+}
+
+mDNSexport void BumpDNSSECStats(mDNS *const m, DNSSECStatsAction action, DNSSECStatsType type, mDNSu32 value)
+{
+ (void)m;
+ (void)action;
+ (void)type;
+ (void)value;
+}
+
+// Proxy stub functions
+mDNSexport mDNSu8 *DNSProxySetAttributes(DNSQuestion *q, DNSMessageHeader *h, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit)
+{
+ (void) q;
+ (void) h;
+ (void) msg;
+ (void) ptr;
+ (void) limit;
+
+ return ptr;
+}
+
+mDNSexport void DNSProxyInit(mDNS *const m, mDNSu32 IpIfArr[], mDNSu32 OpIf)
+{
+ (void) m;
+ (void) IpIfArr;
+ (void) OpIf;
+}
+
+mDNSexport void DNSProxyTerminate(mDNS *const m)
+{
+ (void) m;
+}
+
+// mDNS core calls this routine to clear blocks of memory.
+// On the Posix platform this is a simple wrapper around ANSI C memset.
+mDNSexport void mDNSPlatformMemZero(void *dst, mDNSu32 len)
+{
+ memset(dst, 0, len);
+}
+
+mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(malloc(len)); }
+mDNSexport void mDNSPlatformMemFree (void *mem) { free(mem); }
+
+mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return(tv.tv_usec);
+}
+
+mDNSexport mDNSs32 mDNSPlatformOneSecond = 1024;
+
+mDNSexport mStatus mDNSPlatformTimeInit(void)
+{
+ // No special setup is required on Posix -- we just use gettimeofday();
+ // This is not really safe, because gettimeofday can go backwards if the user manually changes the date or time
+ // We should find a better way to do this
+ return(mStatus_NoError);
+}
+
+mDNSexport mDNSs32 mDNSPlatformRawTime()
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ // tv.tv_sec is seconds since 1st January 1970 (GMT, with no adjustment for daylight savings time)
+ // tv.tv_usec is microseconds since the start of this second (i.e. values 0 to 999999)
+ // We use the lower 22 bits of tv.tv_sec for the top 22 bits of our result
+ // and we multiply tv.tv_usec by 16 / 15625 to get a value in the range 0-1023 to go in the bottom 10 bits.
+ // This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second)
+ // and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days).
+ return((tv.tv_sec << 10) | (tv.tv_usec * 16 / 15625));
+}
+
+mDNSexport mDNSs32 mDNSPlatformUTC(void)
+{
+ return time(NULL);
+}
+
+mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
+{
+ (void) m;
+ (void) InterfaceID;
+ (void) EthAddr;
+ (void) IPAddr;
+ (void) iteration;
+}
+
+mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const NetworkInterfaceInfo *intf)
+{
+ (void) rr;
+ (void) intf;
+
+ return 1;
+}
+
+mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf)
+{
+ (void) q;
+ (void) intf;
+
+ return 1;
+}
+
+// Used for debugging purposes. For now, just set the buffer to zero
+mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize)
+{
+ (void) te;
+ if (bufsize) buf[0] = 0;
+}
+
+mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win)
+{
+ (void) sadd; // Unused
+ (void) dadd; // Unused
+ (void) lport; // Unused
+ (void) rport; // Unused
+ (void) seq; // Unused
+ (void) ack; // Unused
+ (void) win; // Unused
+}
+
+mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNS *const m, mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
+{
+ (void) m; // Unused
+ (void) laddr; // Unused
+ (void) raddr; // Unused
+ (void) lport; // Unused
+ (void) rport; // Unused
+ (void) mti; // Unused
+
+ return mStatus_NoError;
+}
+
+mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNS *const m, mDNSAddr *raddr)
+{
+ (void) raddr; // Unused
+ (void) m; // Unused
+
+ return mStatus_NoError;
+}
+
+mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname)
+{
+ (void) spsaddr; // Unused
+ (void) ifname; // Unused
+
+ return mStatus_NoError;
+}
+
+mDNSexport mStatus mDNSPlatformClearSPSMACAddr(void)
+{
+ return mStatus_NoError;
+}
+
+mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
+{
+ (void) sock; // unused
+
+ return (mDNSu16)-1;
+}
+
+mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
+{
+ (void) InterfaceID; // unused
+
+ return mDNSfalse;
+}
+
+mDNSexport mDNSBool mDNSPlatformAllowPID(mDNS *const m, DNSQuestion *q)
+{
+ (void) m;
+ (void) q;
+ return mDNStrue;
+}
+
+mDNSexport mDNSs32 mDNSPlatformGetServiceID(mDNS *const m, DNSQuestion *q)
+{
+ (void) m;
+ (void) q;
+ return -1;
+}
+
+mDNSexport void mDNSPlatformSetDelegatePID(UDPSocket *src, const mDNSAddr *dst, DNSQuestion *q)
+{
+ (void) src;
+ (void) dst;
+ (void) q;
+}
+
+mDNSexport mDNSs32 mDNSPlatformGetPID()
+{
+ return 0;
+}
+
+mDNSlocal void mDNSPosixAddToFDSet(int *nfds, fd_set *readfds, int s)
+{
+ if (*nfds < s + 1) *nfds = s + 1;
+ FD_SET(s, readfds);
+}
+
+mDNSexport void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, struct timeval *timeout)
+{
+ mDNSs32 ticks;
+ struct timeval interval;
+
+ // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
+ mDNSs32 nextevent = mDNS_Execute(m);
+
+ // 2. Build our list of active file descriptors
+ PosixNetworkInterface *info = (PosixNetworkInterface *)(m->HostInterfaces);
+ if (m->p->unicastSocket4 != -1) mDNSPosixAddToFDSet(nfds, readfds, m->p->unicastSocket4);
+#if HAVE_IPV6
+ if (m->p->unicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, m->p->unicastSocket6);
+#endif
+ while (info)
+ {
+ if (info->multicastSocket4 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket4);
+#if HAVE_IPV6
+ if (info->multicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket6);
+#endif
+ info = (PosixNetworkInterface *)(info->coreIntf.next);
+ }
+
+ // 3. Calculate the time remaining to the next scheduled event (in struct timeval format)
+ ticks = nextevent - mDNS_TimeNow(m);
+ if (ticks < 1) ticks = 1;
+ interval.tv_sec = ticks >> 10; // The high 22 bits are seconds
+ interval.tv_usec = ((ticks & 0x3FF) * 15625) / 16; // The low 10 bits are 1024ths
+
+ // 4. If client's proposed timeout is more than what we want, then reduce it
+ if (timeout->tv_sec > interval.tv_sec ||
+ (timeout->tv_sec == interval.tv_sec && timeout->tv_usec > interval.tv_usec))
+ *timeout = interval;
+}
+
+mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds)
+{
+ PosixNetworkInterface *info;
+ assert(m != NULL);
+ assert(readfds != NULL);
+ info = (PosixNetworkInterface *)(m->HostInterfaces);
+
+ if (m->p->unicastSocket4 != -1 && FD_ISSET(m->p->unicastSocket4, readfds))
+ {
+ FD_CLR(m->p->unicastSocket4, readfds);
+ SocketDataReady(m, NULL, m->p->unicastSocket4);
+ }
+#if HAVE_IPV6
+ if (m->p->unicastSocket6 != -1 && FD_ISSET(m->p->unicastSocket6, readfds))
+ {
+ FD_CLR(m->p->unicastSocket6, readfds);
+ SocketDataReady(m, NULL, m->p->unicastSocket6);
+ }
+#endif
+
+ while (info)
+ {
+ if (info->multicastSocket4 != -1 && FD_ISSET(info->multicastSocket4, readfds))
+ {
+ FD_CLR(info->multicastSocket4, readfds);
+ SocketDataReady(m, info, info->multicastSocket4);
+ }
+#if HAVE_IPV6
+ if (info->multicastSocket6 != -1 && FD_ISSET(info->multicastSocket6, readfds))
+ {
+ FD_CLR(info->multicastSocket6, readfds);
+ SocketDataReady(m, info, info->multicastSocket6);
+ }
+#endif
+ info = (PosixNetworkInterface *)(info->coreIntf.next);
+ }
+}
+
+// update gMaxFD
+mDNSlocal void DetermineMaxEventFD(void)
+{
+ PosixEventSource *iSource;
+
+ gMaxFD = 0;
+ for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
+ if (gMaxFD < iSource->fd)
+ gMaxFD = iSource->fd;
+}
+
+// Add a file descriptor to the set that mDNSPosixRunEventLoopOnce() listens to.
+mStatus mDNSPosixAddFDToEventLoop(int fd, mDNSPosixEventCallback callback, void *context)
+{
+ PosixEventSource *newSource;
+
+ if (gEventSources.LinkOffset == 0)
+ InitLinkedList(&gEventSources, offsetof(PosixEventSource, Next));
+
+ if (fd >= (int) FD_SETSIZE || fd < 0)
+ return mStatus_UnsupportedErr;
+ if (callback == NULL)
+ return mStatus_BadParamErr;
+
+ newSource = (PosixEventSource*) malloc(sizeof *newSource);
+ if (NULL == newSource)
+ return mStatus_NoMemoryErr;
+
+ newSource->Callback = callback;
+ newSource->Context = context;
+ newSource->fd = fd;
+
+ AddToTail(&gEventSources, newSource);
+ FD_SET(fd, &gEventFDs);
+
+ DetermineMaxEventFD();
+
+ return mStatus_NoError;
+}
+
+// Remove a file descriptor from the set that mDNSPosixRunEventLoopOnce() listens to.
+mStatus mDNSPosixRemoveFDFromEventLoop(int fd)
+{
+ PosixEventSource *iSource;
+
+ for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
+ {
+ if (fd == iSource->fd)
+ {
+ FD_CLR(fd, &gEventFDs);
+ RemoveFromList(&gEventSources, iSource);
+ free(iSource);
+ DetermineMaxEventFD();
+ return mStatus_NoError;
+ }
+ }
+ return mStatus_NoSuchNameErr;
+}
+
+// Simply note the received signal in gEventSignals.
+mDNSlocal void NoteSignal(int signum)
+{
+ sigaddset(&gEventSignals, signum);
+}
+
+// Tell the event package to listen for signal and report it in mDNSPosixRunEventLoopOnce().
+mStatus mDNSPosixListenForSignalInEventLoop(int signum)
+{
+ struct sigaction action;
+ mStatus err;
+
+ mDNSPlatformMemZero(&action, sizeof action); // more portable than member-wise assignment
+ action.sa_handler = NoteSignal;
+ err = sigaction(signum, &action, (struct sigaction*) NULL);
+
+ sigaddset(&gEventSignalSet, signum);
+
+ return err;
+}
+
+// Tell the event package to stop listening for signal in mDNSPosixRunEventLoopOnce().
+mStatus mDNSPosixIgnoreSignalInEventLoop(int signum)
+{
+ struct sigaction action;
+ mStatus err;
+
+ mDNSPlatformMemZero(&action, sizeof action); // more portable than member-wise assignment
+ action.sa_handler = SIG_DFL;
+ err = sigaction(signum, &action, (struct sigaction*) NULL);
+
+ sigdelset(&gEventSignalSet, signum);
+
+ return err;
+}
+
+// Do a single pass through the attendent event sources and dispatch any found to their callbacks.
+// Return as soon as internal timeout expires, or a signal we're listening for is received.
+mStatus mDNSPosixRunEventLoopOnce(mDNS *m, const struct timeval *pTimeout,
+ sigset_t *pSignalsReceived, mDNSBool *pDataDispatched)
+{
+ fd_set listenFDs = gEventFDs;
+ int fdMax = 0, numReady;
+ struct timeval timeout = *pTimeout;
+
+ // Include the sockets that are listening to the wire in our select() set
+ mDNSPosixGetFDSet(m, &fdMax, &listenFDs, &timeout); // timeout may get modified
+ if (fdMax < gMaxFD)
+ fdMax = gMaxFD;
+
+ numReady = select(fdMax + 1, &listenFDs, (fd_set*) NULL, (fd_set*) NULL, &timeout);
+
+ // If any data appeared, invoke its callback
+ if (numReady > 0)
+ {
+ PosixEventSource *iSource;
+
+ (void) mDNSPosixProcessFDSet(m, &listenFDs); // call this first to process wire data for clients
+
+ for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
+ {
+ if (FD_ISSET(iSource->fd, &listenFDs))
+ {
+ iSource->Callback(iSource->fd, 0, iSource->Context);
+ break; // in case callback removed elements from gEventSources
+ }
+ }
+ *pDataDispatched = mDNStrue;
+ }
+ else
+ *pDataDispatched = mDNSfalse;
+
+ (void) sigprocmask(SIG_BLOCK, &gEventSignalSet, (sigset_t*) NULL);
+ *pSignalsReceived = gEventSignals;
+ sigemptyset(&gEventSignals);
+ (void) sigprocmask(SIG_UNBLOCK, &gEventSignalSet, (sigset_t*) NULL);
+
+ return mStatus_NoError;
+}
Deleted: vendor/apple/mDNSResponder/561.1.1/mDNSShared/dns_sd.h
===================================================================
--- vendor/apple/mDNSResponder/dist/mDNSShared/dns_sd.h 2014-06-30 23:58:12 UTC (rev 6706)
+++ vendor/apple/mDNSResponder/561.1.1/mDNSShared/dns_sd.h 2015-03-20 01:14:52 UTC (rev 6985)
@@ -1,2657 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2013 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-
-/*! @header DNS Service Discovery
- *
- * @discussion This section describes the functions, callbacks, and data structures
- * that make up the DNS Service Discovery API.
- *
- * The DNS Service Discovery API is part of Bonjour, Apple's implementation
- * of zero-configuration networking (ZEROCONF).
- *
- * Bonjour allows you to register a network service, such as a
- * printer or file server, so that it can be found by name or browsed
- * for by service type and domain. Using Bonjour, applications can
- * discover what services are available on the network, along with
- * all the information -- such as name, IP address, and port --
- * necessary to access a particular service.
- *
- * In effect, Bonjour combines the functions of a local DNS server and
- * AppleTalk. Bonjour allows applications to provide user-friendly printer
- * and server browsing, among other things, over standard IP networks.
- * This behavior is a result of combining protocols such as multicast and
- * DNS to add new functionality to the network (such as multicast DNS).
- *
- * Bonjour gives applications easy access to services over local IP
- * networks without requiring the service or the application to support
- * an AppleTalk or a Netbeui stack, and without requiring a DNS server
- * for the local network.
- */
-
-
-/* _DNS_SD_H contains the mDNSResponder version number for this header file, formatted as follows:
- * Major part of the build number * 10000 +
- * minor part of the build number * 100
- * For example, Mac OS X 10.4.9 has mDNSResponder-108.4, which would be represented as
- * version 1080400. This allows C code to do simple greater-than and less-than comparisons:
- * e.g. an application that requires the DNSServiceGetProperty() call (new in mDNSResponder-126) can check:
- *
- * #if _DNS_SD_H+0 >= 1260000
- * ... some C code that calls DNSServiceGetProperty() ...
- * #endif
- *
- * The version defined in this header file symbol allows for compile-time
- * checking, so that C code building with earlier versions of the header file
- * can avoid compile errors trying to use functions that aren't even defined
- * in those earlier versions. Similar checks may also be performed at run-time:
- * => weak linking -- to avoid link failures if run with an earlier
- * version of the library that's missing some desired symbol, or
- * => DNSServiceGetProperty(DaemonVersion) -- to verify whether the running daemon
- * ("system service" on Windows) meets some required minimum functionality level.
- */
-
-#ifndef _DNS_SD_H
-#define _DNS_SD_H 5410000
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Set to 1 if libdispatch is supported
- * Note: May also be set by project and/or Makefile
- */
-#ifndef _DNS_SD_LIBDISPATCH
-#define _DNS_SD_LIBDISPATCH 0
-#endif /* ndef _DNS_SD_LIBDISPATCH */
-
-/* standard calling convention under Win32 is __stdcall */
-/* Note: When compiling Intel EFI (Extensible Firmware Interface) under MS Visual Studio, the */
-/* _WIN32 symbol is defined by the compiler even though it's NOT compiling code for Windows32 */
-#if defined(_WIN32) && !defined(EFI32) && !defined(EFI64)
-#define DNSSD_API __stdcall
-#else
-#define DNSSD_API
-#endif
-
-/* stdint.h does not exist on FreeBSD 4.x; its types are defined in sys/types.h instead */
-#if defined(__FreeBSD__) && (__FreeBSD__ < 5)
-#include <sys/types.h>
-
-/* Likewise, on Sun, standard integer types are in sys/types.h */
-#elif defined(__sun__)
-#include <sys/types.h>
-
-/* EFI does not have stdint.h, or anything else equivalent */
-#elif defined(EFI32) || defined(EFI64) || defined(EFIX64)
-#include "Tiano.h"
-#if !defined(_STDINT_H_)
-typedef UINT8 uint8_t;
-typedef INT8 int8_t;
-typedef UINT16 uint16_t;
-typedef INT16 int16_t;
-typedef UINT32 uint32_t;
-typedef INT32 int32_t;
-#endif
-/* Windows has its own differences */
-#elif defined(_WIN32)
-#include <windows.h>
-#define _UNUSED
-#ifndef _MSL_STDINT_H
-typedef UINT8 uint8_t;
-typedef INT8 int8_t;
-typedef UINT16 uint16_t;
-typedef INT16 int16_t;
-typedef UINT32 uint32_t;
-typedef INT32 int32_t;
-#endif
-
-/* All other Posix platforms use stdint.h */
-#else
-#include <stdint.h>
-#endif
-
-#if _DNS_SD_LIBDISPATCH
-#include <dispatch/dispatch.h>
-#endif
-
-/* DNSServiceRef, DNSRecordRef
- *
- * Opaque internal data types.
- * Note: client is responsible for serializing access to these structures if
- * they are shared between concurrent threads.
- */
-
-typedef struct _DNSServiceRef_t *DNSServiceRef;
-typedef struct _DNSRecordRef_t *DNSRecordRef;
-
-struct sockaddr;
-
-/*! @enum General flags
- * Most DNS-SD API functions and callbacks include a DNSServiceFlags parameter.
- * As a general rule, any given bit in the 32-bit flags field has a specific fixed meaning,
- * regardless of the function or callback being used. For any given function or callback,
- * typically only a subset of the possible flags are meaningful, and all others should be zero.
- * The discussion section for each API call describes which flags are valid for that call
- * and callback. In some cases, for a particular call, it may be that no flags are currently
- * defined, in which case the DNSServiceFlags parameter exists purely to allow future expansion.
- * In all cases, developers should expect that in future releases, it is possible that new flag
- * values will be defined, and write code with this in mind. For example, code that tests
- * if (flags == kDNSServiceFlagsAdd) ...
- * will fail if, in a future release, another bit in the 32-bit flags field is also set.
- * The reliable way to test whether a particular bit is set is not with an equality test,
- * but with a bitwise mask:
- * if (flags & kDNSServiceFlagsAdd) ...
- * With the exception of kDNSServiceFlagsValidate, each flag can be valid(be set)
- * EITHER only as an input to one of the DNSService*() APIs OR only as an output
- * (provide status) through any of the callbacks used. For example, kDNSServiceFlagsAdd
- * can be set only as an output in the callback, whereas the kDNSServiceFlagsIncludeP2P
- * can be set only as an input to the DNSService*() APIs. See comments on kDNSServiceFlagsValidate
- * defined in enum below.
- */
-enum
-{
- kDNSServiceFlagsMoreComing = 0x1,
- /* MoreComing indicates to a callback that at least one more result is
- * queued and will be delivered following immediately after this one.
- * When the MoreComing flag is set, applications should not immediately
- * update their UI, because this can result in a great deal of ugly flickering
- * on the screen, and can waste a great deal of CPU time repeatedly updating
- * the screen with content that is then immediately erased, over and over.
- * Applications should wait until MoreComing is not set, and then
- * update their UI when no more changes are imminent.
- * When MoreComing is not set, that doesn't mean there will be no more
- * answers EVER, just that there are no more answers immediately
- * available right now at this instant. If more answers become available
- * in the future they will be delivered as usual.
- */
-
- kDNSServiceFlagsAdd = 0x2,
- kDNSServiceFlagsDefault = 0x4,
- /* Flags for domain enumeration and browse/query reply callbacks.
- * "Default" applies only to enumeration and is only valid in
- * conjunction with "Add". An enumeration callback with the "Add"
- * flag NOT set indicates a "Remove", i.e. the domain is no longer
- * valid.
- */
-
- kDNSServiceFlagsNoAutoRename = 0x8,
- /* Flag for specifying renaming behavior on name conflict when registering
- * non-shared records. By default, name conflicts are automatically handled
- * by renaming the service. NoAutoRename overrides this behavior - with this
- * flag set, name conflicts will result in a callback. The NoAutorename flag
- * is only valid if a name is explicitly specified when registering a service
- * (i.e. the default name is not used.)
- */
-
- kDNSServiceFlagsShared = 0x10,
- kDNSServiceFlagsUnique = 0x20,
- /* Flag for registering individual records on a connected
- * DNSServiceRef. Shared indicates that there may be multiple records
- * with this name on the network (e.g. PTR records). Unique indicates that the
- * record's name is to be unique on the network (e.g. SRV records).
- */
-
- kDNSServiceFlagsBrowseDomains = 0x40,
- kDNSServiceFlagsRegistrationDomains = 0x80,
- /* Flags for specifying domain enumeration type in DNSServiceEnumerateDomains.
- * BrowseDomains enumerates domains recommended for browsing, RegistrationDomains
- * enumerates domains recommended for registration.
- */
-
- kDNSServiceFlagsLongLivedQuery = 0x100,
- /* Flag for creating a long-lived unicast query for the DNSServiceQueryRecord call. */
-
- kDNSServiceFlagsAllowRemoteQuery = 0x200,
- /* Flag for creating a record for which we will answer remote queries
- * (queries from hosts more than one hop away; hosts not directly connected to the local link).
- */
-
- kDNSServiceFlagsForceMulticast = 0x400,
- /* Flag for signifying that a query or registration should be performed exclusively via multicast
- * DNS, even for a name in a domain (e.g. foo.apple.com.) that would normally imply unicast DNS.
- */
-
- kDNSServiceFlagsForce = 0x800, // This flag is deprecated.
-
- kDNSServiceFlagsKnownUnique = 0x800,
- /*
- * Client guarantees that record names are unique, so we can skip sending out initial
- * probe messages. Standard name conflict resolution is still done if a conflict is discovered.
- * Currently only valid for a DNSServiceRegister call.
- */
-
- kDNSServiceFlagsReturnIntermediates = 0x1000,
- /* Flag for returning intermediate results.
- * For example, if a query results in an authoritative NXDomain (name does not exist)
- * then that result is returned to the client. However the query is not implicitly
- * cancelled -- it remains active and if the answer subsequently changes
- * (e.g. because a VPN tunnel is subsequently established) then that positive
- * result will still be returned to the client.
- * Similarly, if a query results in a CNAME record, then in addition to following
- * the CNAME referral, the intermediate CNAME result is also returned to the client.
- * When this flag is not set, NXDomain errors are not returned, and CNAME records
- * are followed silently without informing the client of the intermediate steps.
- * (In earlier builds this flag was briefly calledkDNSServiceFlagsReturnCNAME)
- */
-
- kDNSServiceFlagsNonBrowsable = 0x2000,
- /* A service registered with the NonBrowsable flag set can be resolved using
- * DNSServiceResolve(), but will not be discoverable using DNSServiceBrowse().
- * This is for cases where the name is actually a GUID; it is found by other means;
- * there is no end-user benefit to browsing to find a long list of opaque GUIDs.
- * Using the NonBrowsable flag creates SRV+TXT without the cost of also advertising
- * an associated PTR record.
- */
-
- kDNSServiceFlagsShareConnection = 0x4000,
- /* For efficiency, clients that perform many concurrent operations may want to use a
- * single Unix Domain Socket connection with the background daemon, instead of having a
- * separate connection for each independent operation. To use this mode, clients first
- * call DNSServiceCreateConnection(&MainRef) to initialize the main DNSServiceRef.
- * For each subsequent operation that is to share that same connection, the client copies
- * the MainRef, and then passes the address of that copy, setting the ShareConnection flag
- * to tell the library that this DNSServiceRef is not a typical uninitialized DNSServiceRef;
- * it's a copy of an existing DNSServiceRef whose connection information should be reused.
- *
- * For example:
- *
- * DNSServiceErrorType error;
- * DNSServiceRef MainRef;
- * error = DNSServiceCreateConnection(&MainRef);
- * if (error) ...
- * DNSServiceRef BrowseRef = MainRef; // Important: COPY the primary DNSServiceRef first...
- * error = DNSServiceBrowse(&BrowseRef, kDNSServiceFlagsShareConnection, ...); // then use the copy
- * if (error) ...
- * ...
- * DNSServiceRefDeallocate(BrowseRef); // Terminate the browse operation
- * DNSServiceRefDeallocate(MainRef); // Terminate the shared connection
- *
- * Notes:
- *
- * 1. Collective kDNSServiceFlagsMoreComing flag
- * When callbacks are invoked using a shared DNSServiceRef, the
- * kDNSServiceFlagsMoreComing flag applies collectively to *all* active
- * operations sharing the same parent DNSServiceRef. If the MoreComing flag is
- * set it means that there are more results queued on this parent DNSServiceRef,
- * but not necessarily more results for this particular callback function.
- * The implication of this for client programmers is that when a callback
- * is invoked with the MoreComing flag set, the code should update its
- * internal data structures with the new result, and set a variable indicating
- * that its UI needs to be updated. Then, later when a callback is eventually
- * invoked with the MoreComing flag not set, the code should update *all*
- * stale UI elements related to that shared parent DNSServiceRef that need
- * updating, not just the UI elements related to the particular callback
- * that happened to be the last one to be invoked.
- *
- * 2. Canceling operations and kDNSServiceFlagsMoreComing
- * Whenever you cancel any operation for which you had deferred UI updates
- * waiting because of a kDNSServiceFlagsMoreComing flag, you should perform
- * those deferred UI updates. This is because, after cancelling the operation,
- * you can no longer wait for a callback *without* MoreComing set, to tell
- * you do perform your deferred UI updates (the operation has been canceled,
- * so there will be no more callbacks). An implication of the collective
- * kDNSServiceFlagsMoreComing flag for shared connections is that this
- * guideline applies more broadly -- any time you cancel an operation on
- * a shared connection, you should perform all deferred UI updates for all
- * operations sharing that connection. This is because the MoreComing flag
- * might have been referring to events coming for the operation you canceled,
- * which will now not be coming because the operation has been canceled.
- *
- * 3. Only share DNSServiceRef's created with DNSServiceCreateConnection
- * Calling DNSServiceCreateConnection(&ref) creates a special shareable DNSServiceRef.
- * DNSServiceRef's created by other calls like DNSServiceBrowse() or DNSServiceResolve()
- * cannot be shared by copying them and using kDNSServiceFlagsShareConnection.
- *
- * 4. Don't Double-Deallocate
- * Calling DNSServiceRefDeallocate(ref) for a particular operation's DNSServiceRef terminates
- * just that operation. Calling DNSServiceRefDeallocate(ref) for the main shared DNSServiceRef
- * (the parent DNSServiceRef, originally created by DNSServiceCreateConnection(&ref))
- * automatically terminates the shared connection and all operations that were still using it.
- * After doing this, DO NOT then attempt to deallocate any remaining subordinate DNSServiceRef's.
- * The memory used by those subordinate DNSServiceRef's has already been freed, so any attempt
- * to do a DNSServiceRefDeallocate (or any other operation) on them will result in accesses
- * to freed memory, leading to crashes or other equally undesirable results.
- *
- * 5. Thread Safety
- * The dns_sd.h API does not presuppose any particular threading model, and consequently
- * does no locking of its own (which would require linking some specific threading library).
- * If client code calls API routines on the same DNSServiceRef concurrently
- * from multiple threads, it is the client's responsibility to use a mutext
- * lock or take similar appropriate precautions to serialize those calls.
- */
-
- kDNSServiceFlagsSuppressUnusable = 0x8000,
- /*
- * This flag is meaningful only in DNSServiceQueryRecord which suppresses unusable queries on the
- * wire. If "hostname" is a wide-area unicast DNS hostname (i.e. not a ".local." name)
- * but this host has no routable IPv6 address, then the call will not try to look up IPv6 addresses
- * for "hostname", since any addresses it found would be unlikely to be of any use anyway. Similarly,
- * if this host has no routable IPv4 address, the call will not try to look up IPv4 addresses for
- * "hostname".
- */
-
- kDNSServiceFlagsTimeout = 0x10000,
- /*
- * When kDNServiceFlagsTimeout is passed to DNSServiceQueryRecord or DNSServiceGetAddrInfo, the query is
- * stopped after a certain number of seconds have elapsed. The time at which the query will be stopped
- * is determined by the system and cannot be configured by the user. The query will be stopped irrespective
- * of whether a response was given earlier or not. When the query is stopped, the callback will be called
- * with an error code of kDNSServiceErr_Timeout and a NULL sockaddr will be returned for DNSServiceGetAddrInfo
- * and zero length rdata will be returned for DNSServiceQueryRecord.
- */
-
- kDNSServiceFlagsIncludeP2P = 0x20000,
- /*
- * Include P2P interfaces when kDNSServiceInterfaceIndexAny is specified.
- * By default, specifying kDNSServiceInterfaceIndexAny does not include P2P interfaces.
- */
-
- kDNSServiceFlagsWakeOnResolve = 0x40000,
- /*
- * This flag is meaningful only in DNSServiceResolve. When set, it tries to send a magic packet
- * to wake up the client.
- */
-
- kDNSServiceFlagsBackgroundTrafficClass = 0x80000,
- /*
- * This flag is meaningful in DNSServiceBrowse, DNSServiceGetAddrInfo, DNSServiceQueryRecord,
- * and DNSServiceResolve. When set, it uses the background traffic
- * class for packets that service the request.
- */
-
- kDNSServiceFlagsIncludeAWDL = 0x100000,
- /*
- * Include AWDL interface when kDNSServiceInterfaceIndexAny is specified.
- */
-
- kDNSServiceFlagsValidate = 0x200000,
- /*
- * This flag is meaningful in DNSServiceGetAddrInfo and DNSServiceQueryRecord. This is the ONLY flag to be valid
- * as an input to the APIs and also an output through the callbacks in the APIs.
- *
- * When this flag is passed to DNSServiceQueryRecord and DNSServiceGetAddrInfo to resolve unicast names,
- * the response will be validated using DNSSEC. The validation results are delivered using the flags field in
- * the callback and kDNSServiceFlagsValidate is marked in the flags to indicate that DNSSEC status is also available.
- * When the callback is called to deliver the query results, the validation results may or may not be available.
- * If it is not delivered along with the results, the validation status is delivered when the validation completes.
- *
- * When the validation results are delivered in the callback, it is indicated by marking the flags with
- * kDNSServiceFlagsValidate and kDNSServiceFlagsAdd along with the DNSSEC status flags (described below) and a NULL
- * sockaddr will be returned for DNSServiceGetAddrInfo and zero length rdata will be returned for DNSServiceQueryRecord.
- * DNSSEC validation results are for the whole RRSet and not just individual records delivered in the callback. When
- * kDNSServiceFlagsAdd is not set in the flags, applications should implicitly assume that the DNSSEC status of the
- * RRSet that has been delivered up until that point is not valid anymore, till another callback is called with
- * kDNSServiceFlagsAdd and kDNSServiceFlagsValidate.
- *
- * The following four flags indicate the status of the DNSSEC validation and marked in the flags field of the callback.
- * When any of the four flags is set, kDNSServiceFlagsValidate will also be set. To check the validation status, the
- * other applicable output flags should be masked. See kDNSServiceOutputFlags below.
- */
-
- kDNSServiceFlagsSecure = 0x200010,
- /*
- * The response has been validated by verifying all the signaures in the response and was able to
- * build a successful authentication chain starting from a known trust anchor.
- */
-
- kDNSServiceFlagsInsecure = 0x200020,
- /*
- * A chain of trust cannot be built starting from a known trust anchor to the response.
- */
-
- kDNSServiceFlagsBogus = 0x200040,
- /*
- * If the response cannot be verified to be secure due to expired signatures, missing signatures etc.,
- * then the results are considered to be bogus.
- */
-
- kDNSServiceFlagsIndeterminate = 0x200080,
- /*
- * There is no valid trust anchor that can be used to determine whether a response is secure or not.
- */
-
- kDNSServiceFlagsUnicastResponse = 0x400000,
- /*
- * Request unicast response to query.
- */
- kDNSServiceFlagsValidateOptional = 0x800000,
-
- /*
- * This flag is identical to kDNSServiceFlagsValidate except for the case where the response
- * cannot be validated. If this flag is set in DNSServiceQueryRecord or DNSServiceGetAddrInfo,
- * the DNSSEC records will be requested for validation. If they cannot be received for some reason
- * during the validation (e.g., zone is not signed, zone is signed but cannot be traced back to
- * root, recursive server does not understand DNSSEC etc.), then this will fallback to the default
- * behavior where the validation will not be performed and no DNSSEC results will be provided.
- *
- * If the zone is signed and there is a valid path to a known trust anchor configured in the system
- * and the application requires DNSSEC validation irrespective of the DNSSEC awareness in the current
- * network, then this option MUST not be used. This is only intended to be used during the transition
- * period where the different nodes participating in the DNS resolution may not understand DNSSEC or
- * managed properly (e.g. missing DS record) but still want to be able to resolve DNS successfully.
- */
-
- kDNSServiceFlagsWakeOnlyService = 0x1000000,
- /*
- * This flag is meaningful only in DNSServiceRegister. When set, the service will not be registered
- * with sleep proxy server during sleep.
- */
-
- kDNSServiceFlagsThresholdOne = 0x2000000,
- kDNSServiceFlagsThresholdFinder = 0x4000000,
- kDNSServiceFlagsThresholdReached = kDNSServiceFlagsThresholdOne,
- /*
- * kDNSServiceFlagsThresholdOne is meaningful only in DNSServiceBrowse. When set,
- * the system will stop issuing browse queries on the network once the number
- * of answers returned is one or more. It will issue queries on the network
- * again if the number of answers drops to zero.
- * This flag is for Apple internal use only. Third party developers
- * should not rely on this behavior being supported in any given software release.
- *
- * kDNSServiceFlagsThresholdFinder is meaningful only in DNSServiceBrowse. When set,
- * the system will stop issuing browse queries on the network once the number
- * of answers has reached the threshold set for Finder.
- * It will issue queries on the network again if the number of answers drops below
- * this threshold.
- * This flag is for Apple internal use only. Third party developers
- * should not rely on this behavior being supported in any given software release.
- *
- * When kDNSServiceFlagsThresholdReached is set in the client callback add or remove event,
- * it indicates that the browse answer threshold has been reached and no
- * browse requests will be generated on the network until the number of answers falls
- * below the threshold value. Add and remove events can still occur based
- * on incoming Bonjour traffic observed by the system.
- * The set of services return to the client is not guaranteed to represent the
- * entire set of services present on the network once the threshold has been reached.
- *
- * Note, while kDNSServiceFlagsThresholdReached and kDNSServiceFlagsThresholdOne
- * have the same value, there isn't a conflict because kDNSServiceFlagsThresholdReached
- * is only set in the callbacks and kDNSServiceFlagsThresholdOne is only set on
- * input to a DNSServiceBrowse call.
- */
-};
-
-#define kDNSServiceOutputFlags (kDNSServiceFlagsValidate | kDNSServiceFlagsValidateOptional | kDNSServiceFlagsMoreComing | kDNSServiceFlagsAdd | kDNSServiceFlagsDefault)
- /* All the output flags excluding the DNSSEC Status flags. Typically used to check DNSSEC Status */
-
-/* Possible protocol values */
-enum
-{
- /* for DNSServiceGetAddrInfo() */
- kDNSServiceProtocol_IPv4 = 0x01,
- kDNSServiceProtocol_IPv6 = 0x02,
- /* 0x04 and 0x08 reserved for future internetwork protocols */
-
- /* for DNSServiceNATPortMappingCreate() */
- kDNSServiceProtocol_UDP = 0x10,
- kDNSServiceProtocol_TCP = 0x20
- /* 0x40 and 0x80 reserved for future transport protocols, e.g. SCTP [RFC 2960]
- * or DCCP [RFC 4340]. If future NAT gateways are created that support port
- * mappings for these protocols, new constants will be defined here.
- */
-};
-
-/*
- * The values for DNS Classes and Types are listed in RFC 1035, and are available
- * on every OS in its DNS header file. Unfortunately every OS does not have the
- * same header file containing DNS Class and Type constants, and the names of
- * the constants are not consistent. For example, BIND 8 uses "T_A",
- * BIND 9 uses "ns_t_a", Windows uses "DNS_TYPE_A", etc.
- * For this reason, these constants are also listed here, so that code using
- * the DNS-SD programming APIs can use these constants, so that the same code
- * can compile on all our supported platforms.
- */
-
-enum
-{
- kDNSServiceClass_IN = 1 /* Internet */
-};
-
-enum
-{
- kDNSServiceType_A = 1, /* Host address. */
- kDNSServiceType_NS = 2, /* Authoritative server. */
- kDNSServiceType_MD = 3, /* Mail destination. */
- kDNSServiceType_MF = 4, /* Mail forwarder. */
- kDNSServiceType_CNAME = 5, /* Canonical name. */
- kDNSServiceType_SOA = 6, /* Start of authority zone. */
- kDNSServiceType_MB = 7, /* Mailbox domain name. */
- kDNSServiceType_MG = 8, /* Mail group member. */
- kDNSServiceType_MR = 9, /* Mail rename name. */
- kDNSServiceType_NULL = 10, /* Null resource record. */
- kDNSServiceType_WKS = 11, /* Well known service. */
- kDNSServiceType_PTR = 12, /* Domain name pointer. */
- kDNSServiceType_HINFO = 13, /* Host information. */
- kDNSServiceType_MINFO = 14, /* Mailbox information. */
- kDNSServiceType_MX = 15, /* Mail routing information. */
- kDNSServiceType_TXT = 16, /* One or more text strings (NOT "zero or more..."). */
- kDNSServiceType_RP = 17, /* Responsible person. */
- kDNSServiceType_AFSDB = 18, /* AFS cell database. */
- kDNSServiceType_X25 = 19, /* X_25 calling address. */
- kDNSServiceType_ISDN = 20, /* ISDN calling address. */
- kDNSServiceType_RT = 21, /* Router. */
- kDNSServiceType_NSAP = 22, /* NSAP address. */
- kDNSServiceType_NSAP_PTR = 23, /* Reverse NSAP lookup (deprecated). */
- kDNSServiceType_SIG = 24, /* Security signature. */
- kDNSServiceType_KEY = 25, /* Security key. */
- kDNSServiceType_PX = 26, /* X.400 mail mapping. */
- kDNSServiceType_GPOS = 27, /* Geographical position (withdrawn). */
- kDNSServiceType_AAAA = 28, /* IPv6 Address. */
- kDNSServiceType_LOC = 29, /* Location Information. */
- kDNSServiceType_NXT = 30, /* Next domain (security). */
- kDNSServiceType_EID = 31, /* Endpoint identifier. */
- kDNSServiceType_NIMLOC = 32, /* Nimrod Locator. */
- kDNSServiceType_SRV = 33, /* Server Selection. */
- kDNSServiceType_ATMA = 34, /* ATM Address */
- kDNSServiceType_NAPTR = 35, /* Naming Authority PoinTeR */
- kDNSServiceType_KX = 36, /* Key Exchange */
- kDNSServiceType_CERT = 37, /* Certification record */
- kDNSServiceType_A6 = 38, /* IPv6 Address (deprecated) */
- kDNSServiceType_DNAME = 39, /* Non-terminal DNAME (for IPv6) */
- kDNSServiceType_SINK = 40, /* Kitchen sink (experimental) */
- kDNSServiceType_OPT = 41, /* EDNS0 option (meta-RR) */
- kDNSServiceType_APL = 42, /* Address Prefix List */
- kDNSServiceType_DS = 43, /* Delegation Signer */
- kDNSServiceType_SSHFP = 44, /* SSH Key Fingerprint */
- kDNSServiceType_IPSECKEY = 45, /* IPSECKEY */
- kDNSServiceType_RRSIG = 46, /* RRSIG */
- kDNSServiceType_NSEC = 47, /* Denial of Existence */
- kDNSServiceType_DNSKEY = 48, /* DNSKEY */
- kDNSServiceType_DHCID = 49, /* DHCP Client Identifier */
- kDNSServiceType_NSEC3 = 50, /* Hashed Authenticated Denial of Existence */
- kDNSServiceType_NSEC3PARAM = 51, /* Hashed Authenticated Denial of Existence */
-
- kDNSServiceType_HIP = 55, /* Host Identity Protocol */
-
- kDNSServiceType_SPF = 99, /* Sender Policy Framework for E-Mail */
- kDNSServiceType_UINFO = 100, /* IANA-Reserved */
- kDNSServiceType_UID = 101, /* IANA-Reserved */
- kDNSServiceType_GID = 102, /* IANA-Reserved */
- kDNSServiceType_UNSPEC = 103, /* IANA-Reserved */
-
- kDNSServiceType_TKEY = 249, /* Transaction key */
- kDNSServiceType_TSIG = 250, /* Transaction signature. */
- kDNSServiceType_IXFR = 251, /* Incremental zone transfer. */
- kDNSServiceType_AXFR = 252, /* Transfer zone of authority. */
- kDNSServiceType_MAILB = 253, /* Transfer mailbox records. */
- kDNSServiceType_MAILA = 254, /* Transfer mail agent records. */
- kDNSServiceType_ANY = 255 /* Wildcard match. */
-};
-
-/* possible error code values */
-enum
-{
- kDNSServiceErr_NoError = 0,
- kDNSServiceErr_Unknown = -65537, /* 0xFFFE FFFF */
- kDNSServiceErr_NoSuchName = -65538,
- kDNSServiceErr_NoMemory = -65539,
- kDNSServiceErr_BadParam = -65540,
- kDNSServiceErr_BadReference = -65541,
- kDNSServiceErr_BadState = -65542,
- kDNSServiceErr_BadFlags = -65543,
- kDNSServiceErr_Unsupported = -65544,
- kDNSServiceErr_NotInitialized = -65545,
- kDNSServiceErr_AlreadyRegistered = -65547,
- kDNSServiceErr_NameConflict = -65548,
- kDNSServiceErr_Invalid = -65549,
- kDNSServiceErr_Firewall = -65550,
- kDNSServiceErr_Incompatible = -65551, /* client library incompatible with daemon */
- kDNSServiceErr_BadInterfaceIndex = -65552,
- kDNSServiceErr_Refused = -65553,
- kDNSServiceErr_NoSuchRecord = -65554,
- kDNSServiceErr_NoAuth = -65555,
- kDNSServiceErr_NoSuchKey = -65556,
- kDNSServiceErr_NATTraversal = -65557,
- kDNSServiceErr_DoubleNAT = -65558,
- kDNSServiceErr_BadTime = -65559, /* Codes up to here existed in Tiger */
- kDNSServiceErr_BadSig = -65560,
- kDNSServiceErr_BadKey = -65561,
- kDNSServiceErr_Transient = -65562,
- kDNSServiceErr_ServiceNotRunning = -65563, /* Background daemon not running */
- kDNSServiceErr_NATPortMappingUnsupported = -65564, /* NAT doesn't support PCP, NAT-PMP or UPnP */
- kDNSServiceErr_NATPortMappingDisabled = -65565, /* NAT supports PCP, NAT-PMP or UPnP, but it's disabled by the administrator */
- kDNSServiceErr_NoRouter = -65566, /* No router currently configured (probably no network connectivity) */
- kDNSServiceErr_PollingMode = -65567,
- kDNSServiceErr_Timeout = -65568
-
- /* mDNS Error codes are in the range
- * FFFE FF00 (-65792) to FFFE FFFF (-65537) */
-};
-
-/* Maximum length, in bytes, of a service name represented as a */
-/* literal C-String, including the terminating NULL at the end. */
-
-#define kDNSServiceMaxServiceName 64
-
-/* Maximum length, in bytes, of a domain name represented as an *escaped* C-String */
-/* including the final trailing dot, and the C-String terminating NULL at the end. */
-
-#define kDNSServiceMaxDomainName 1009
-
-/*
- * Notes on DNS Name Escaping
- * -- or --
- * "Why is kDNSServiceMaxDomainName 1009, when the maximum legal domain name is 256 bytes?"
- *
- * All strings used in the DNS-SD APIs are UTF-8 strings. Apart from the exceptions noted below,
- * the APIs expect the strings to be properly escaped, using the conventional DNS escaping rules:
- *
- * '\\' represents a single literal '\' in the name
- * '\.' represents a single literal '.' in the name
- * '\ddd', where ddd is a three-digit decimal value from 000 to 255,
- * represents a single literal byte with that value.
- * A bare unescaped '.' is a label separator, marking a boundary between domain and subdomain.
- *
- * The exceptions, that do not use escaping, are the routines where the full
- * DNS name of a resource is broken, for convenience, into servicename/regtype/domain.
- * In these routines, the "servicename" is NOT escaped. It does not need to be, since
- * it is, by definition, just a single literal string. Any characters in that string
- * represent exactly what they are. The "regtype" portion is, technically speaking,
- * escaped, but since legal regtypes are only allowed to contain letters, digits,
- * and hyphens, there is nothing to escape, so the issue is moot. The "domain"
- * portion is also escaped, though most domains in use on the public Internet
- * today, like regtypes, don't contain any characters that need to be escaped.
- * As DNS-SD becomes more popular, rich-text domains for service discovery will
- * become common, so software should be written to cope with domains with escaping.
- *
- * The servicename may be up to 63 bytes of UTF-8 text (not counting the C-String
- * terminating NULL at the end). The regtype is of the form _service._tcp or
- * _service._udp, where the "service" part is 1-15 characters, which may be
- * letters, digits, or hyphens. The domain part of the three-part name may be
- * any legal domain, providing that the resulting servicename+regtype+domain
- * name does not exceed 256 bytes.
- *
- * For most software, these issues are transparent. When browsing, the discovered
- * servicenames should simply be displayed as-is. When resolving, the discovered
- * servicename/regtype/domain are simply passed unchanged to DNSServiceResolve().
- * When a DNSServiceResolve() succeeds, the returned fullname is already in
- * the correct format to pass to standard system DNS APIs such as res_query().
- * For converting from servicename/regtype/domain to a single properly-escaped
- * full DNS name, the helper function DNSServiceConstructFullName() is provided.
- *
- * The following (highly contrived) example illustrates the escaping process.
- * Suppose you have an service called "Dr. Smith\Dr. Johnson", of type "_ftp._tcp"
- * in subdomain "4th. Floor" of subdomain "Building 2" of domain "apple.com."
- * The full (escaped) DNS name of this service's SRV record would be:
- * Dr\.\032Smith\\Dr\.\032Johnson._ftp._tcp.4th\.\032Floor.Building\0322.apple.com.
- */
-
-
-/*
- * Constants for specifying an interface index
- *
- * Specific interface indexes are identified via a 32-bit unsigned integer returned
- * by the if_nametoindex() family of calls.
- *
- * If the client passes 0 for interface index, that means "do the right thing",
- * which (at present) means, "if the name is in an mDNS local multicast domain
- * (e.g. 'local.', '254.169.in-addr.arpa.', '{8,9,A,B}.E.F.ip6.arpa.') then multicast
- * on all applicable interfaces, otherwise send via unicast to the appropriate
- * DNS server." Normally, most clients will use 0 for interface index to
- * automatically get the default sensible behaviour.
- *
- * If the client passes a positive interface index, then for multicast names that
- * indicates to do the operation only on that one interface. For unicast names the
- * interface index is ignored unless kDNSServiceFlagsForceMulticast is also set.
- *
- * If the client passes kDNSServiceInterfaceIndexLocalOnly when registering
- * a service, then that service will be found *only* by other local clients
- * on the same machine that are browsing using kDNSServiceInterfaceIndexLocalOnly
- * or kDNSServiceInterfaceIndexAny.
- * If a client has a 'private' service, accessible only to other processes
- * running on the same machine, this allows the client to advertise that service
- * in a way such that it does not inadvertently appear in service lists on
- * all the other machines on the network.
- *
- * If the client passes kDNSServiceInterfaceIndexLocalOnly when browsing
- * then it will find *all* records registered on that same local machine.
- * Clients explicitly wishing to discover *only* LocalOnly services can
- * accomplish this by inspecting the interfaceIndex of each service reported
- * to their DNSServiceBrowseReply() callback function, and discarding those
- * where the interface index is not kDNSServiceInterfaceIndexLocalOnly.
- *
- * kDNSServiceInterfaceIndexP2P is meaningful only in Browse, QueryRecord, Register,
- * and Resolve operations. It should not be used in other DNSService APIs.
- *
- * - If kDNSServiceInterfaceIndexP2P is passed to DNSServiceBrowse or
- * DNSServiceQueryRecord, it restricts the operation to P2P.
- *
- * - If kDNSServiceInterfaceIndexP2P is passed to DNSServiceRegister, it is
- * mapped internally to kDNSServiceInterfaceIndexAny with the kDNSServiceFlagsIncludeP2P
- * set.
- *
- * - If kDNSServiceInterfaceIndexP2P is passed to DNSServiceResolve, it is
- * mapped internally to kDNSServiceInterfaceIndexAny with the kDNSServiceFlagsIncludeP2P
- * set, because resolving a P2P service may create and/or enable an interface whose
- * index is not known a priori. The resolve callback will indicate the index of the
- * interface via which the service can be accessed.
- *
- * If applications pass kDNSServiceInterfaceIndexAny to DNSServiceBrowse
- * or DNSServiceQueryRecord, they must set the kDNSServiceFlagsIncludeP2P flag
- * to include P2P. In this case, if a service instance or the record being queried
- * is found over P2P, the resulting ADD event will indicate kDNSServiceInterfaceIndexP2P
- * as the interface index.
- */
-
-#define kDNSServiceInterfaceIndexAny 0
-#define kDNSServiceInterfaceIndexLocalOnly ((uint32_t)-1)
-#define kDNSServiceInterfaceIndexUnicast ((uint32_t)-2)
-#define kDNSServiceInterfaceIndexP2P ((uint32_t)-3)
-
-typedef uint32_t DNSServiceFlags;
-typedef uint32_t DNSServiceProtocol;
-typedef int32_t DNSServiceErrorType;
-
-
-/*********************************************************************************************
-*
-* Version checking
-*
-*********************************************************************************************/
-
-/* DNSServiceGetProperty() Parameters:
- *
- * property: The requested property.
- * Currently the only property defined is kDNSServiceProperty_DaemonVersion.
- *
- * result: Place to store result.
- * For retrieving DaemonVersion, this should be the address of a uint32_t.
- *
- * size: Pointer to uint32_t containing size of the result location.
- * For retrieving DaemonVersion, this should be sizeof(uint32_t).
- * On return the uint32_t is updated to the size of the data returned.
- * For DaemonVersion, the returned size is always sizeof(uint32_t), but
- * future properties could be defined which return variable-sized results.
- *
- * return value: Returns kDNSServiceErr_NoError on success, or kDNSServiceErr_ServiceNotRunning
- * if the daemon (or "system service" on Windows) is not running.
- */
-
-DNSServiceErrorType DNSSD_API DNSServiceGetProperty
-(
- const char *property, /* Requested property (i.e. kDNSServiceProperty_DaemonVersion) */
- void *result, /* Pointer to place to store result */
- uint32_t *size /* size of result location */
-);
-
-/*
- * When requesting kDNSServiceProperty_DaemonVersion, the result pointer must point
- * to a 32-bit unsigned integer, and the size parameter must be set to sizeof(uint32_t).
- *
- * On return, the 32-bit unsigned integer contains the version number, formatted as follows:
- * Major part of the build number * 10000 +
- * minor part of the build number * 100
- *
- * For example, Mac OS X 10.4.9 has mDNSResponder-108.4, which would be represented as
- * version 1080400. This allows applications to do simple greater-than and less-than comparisons:
- * e.g. an application that requires at least mDNSResponder-108.4 can check:
- *
- * if (version >= 1080400) ...
- *
- * Example usage:
- *
- * uint32_t version;
- * uint32_t size = sizeof(version);
- * DNSServiceErrorType err = DNSServiceGetProperty(kDNSServiceProperty_DaemonVersion, &version, &size);
- * if (!err) printf("Bonjour version is %d.%d\n", version / 10000, version / 100 % 100);
- */
-
-#define kDNSServiceProperty_DaemonVersion "DaemonVersion"
-
-
-// Map the source port of the local UDP socket that was opened for sending the DNS query
-// to the process ID of the application that triggered the DNS resolution.
-//
-/* DNSServiceGetPID() Parameters:
- *
- * srcport: Source port (in network byte order) of the UDP socket that was created by
- * mDNSResponder to send the DNS query on the wire.
- *
- * pid: Process ID of the application that started the name resolution which triggered
- * mDNSResponder to send the query on the wire. The value can be -1 if the srcport
- * cannot be mapped.
- *
- * return value: Returns kDNSServiceErr_NoError on success, or kDNSServiceErr_ServiceNotRunning
- * if the daemon is not running. The value of the pid is undefined if the return
- * value has error.
- */
-DNSServiceErrorType DNSSD_API DNSServiceGetPID
-(
- uint16_t srcport,
- int32_t *pid
-);
-
-/*********************************************************************************************
-*
-* Unix Domain Socket access, DNSServiceRef deallocation, and data processing functions
-*
-*********************************************************************************************/
-
-/* DNSServiceRefSockFD()
- *
- * Access underlying Unix domain socket for an initialized DNSServiceRef.
- * The DNS Service Discovery implementation uses this socket to communicate between the client and
- * the mDNSResponder daemon. The application MUST NOT directly read from or write to this socket.
- * Access to the socket is provided so that it can be used as a kqueue event source, a CFRunLoop
- * event source, in a select() loop, etc. When the underlying event management subsystem (kqueue/
- * select/CFRunLoop etc.) indicates to the client that data is available for reading on the
- * socket, the client should call DNSServiceProcessResult(), which will extract the daemon's
- * reply from the socket, and pass it to the appropriate application callback. By using a run
- * loop or select(), results from the daemon can be processed asynchronously. Alternatively,
- * a client can choose to fork a thread and have it loop calling "DNSServiceProcessResult(ref);"
- * If DNSServiceProcessResult() is called when no data is available for reading on the socket, it
- * will block until data does become available, and then process the data and return to the caller.
- * When data arrives on the socket, the client is responsible for calling DNSServiceProcessResult(ref)
- * in a timely fashion -- if the client allows a large backlog of data to build up the daemon
- * may terminate the connection.
- *
- * sdRef: A DNSServiceRef initialized by any of the DNSService calls.
- *
- * return value: The DNSServiceRef's underlying socket descriptor, or -1 on
- * error.
- */
-
-int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef);
-
-
-/* DNSServiceProcessResult()
- *
- * Read a reply from the daemon, calling the appropriate application callback. This call will
- * block until the daemon's response is received. Use DNSServiceRefSockFD() in
- * conjunction with a run loop or select() to determine the presence of a response from the
- * server before calling this function to process the reply without blocking. Call this function
- * at any point if it is acceptable to block until the daemon's response arrives. Note that the
- * client is responsible for ensuring that DNSServiceProcessResult() is called whenever there is
- * a reply from the daemon - the daemon may terminate its connection with a client that does not
- * process the daemon's responses.
- *
- * sdRef: A DNSServiceRef initialized by any of the DNSService calls
- * that take a callback parameter.
- *
- * return value: Returns kDNSServiceErr_NoError on success, otherwise returns
- * an error code indicating the specific failure that occurred.
- */
-
-DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef);
-
-
-/* DNSServiceRefDeallocate()
- *
- * Terminate a connection with the daemon and free memory associated with the DNSServiceRef.
- * Any services or records registered with this DNSServiceRef will be deregistered. Any
- * Browse, Resolve, or Query operations called with this reference will be terminated.
- *
- * Note: If the reference's underlying socket is used in a run loop or select() call, it should
- * be removed BEFORE DNSServiceRefDeallocate() is called, as this function closes the reference's
- * socket.
- *
- * Note: If the reference was initialized with DNSServiceCreateConnection(), any DNSRecordRefs
- * created via this reference will be invalidated by this call - the resource records are
- * deregistered, and their DNSRecordRefs may not be used in subsequent functions. Similarly,
- * if the reference was initialized with DNSServiceRegister, and an extra resource record was
- * added to the service via DNSServiceAddRecord(), the DNSRecordRef created by the Add() call
- * is invalidated when this function is called - the DNSRecordRef may not be used in subsequent
- * functions.
- *
- * Note: This call is to be used only with the DNSServiceRef defined by this API.
- *
- * sdRef: A DNSServiceRef initialized by any of the DNSService calls.
- *
- */
-
-void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef);
-
-
-/*********************************************************************************************
-*
-* Domain Enumeration
-*
-*********************************************************************************************/
-
-/* DNSServiceEnumerateDomains()
- *
- * Asynchronously enumerate domains available for browsing and registration.
- *
- * The enumeration MUST be cancelled via DNSServiceRefDeallocate() when no more domains
- * are to be found.
- *
- * Note that the names returned are (like all of DNS-SD) UTF-8 strings,
- * and are escaped using standard DNS escaping rules.
- * (See "Notes on DNS Name Escaping" earlier in this file for more details.)
- * A graphical browser displaying a hierarchical tree-structured view should cut
- * the names at the bare dots to yield individual labels, then de-escape each
- * label according to the escaping rules, and then display the resulting UTF-8 text.
- *
- * DNSServiceDomainEnumReply Callback Parameters:
- *
- * sdRef: The DNSServiceRef initialized by DNSServiceEnumerateDomains().
- *
- * flags: Possible values are:
- * kDNSServiceFlagsMoreComing
- * kDNSServiceFlagsAdd
- * kDNSServiceFlagsDefault
- *
- * interfaceIndex: Specifies the interface on which the domain exists. (The index for a given
- * interface is determined via the if_nametoindex() family of calls.)
- *
- * errorCode: Will be kDNSServiceErr_NoError (0) on success, otherwise indicates
- * the failure that occurred (other parameters are undefined if errorCode is nonzero).
- *
- * replyDomain: The name of the domain.
- *
- * context: The context pointer passed to DNSServiceEnumerateDomains.
- *
- */
-
-typedef void (DNSSD_API *DNSServiceDomainEnumReply)
-(
- DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char *replyDomain,
- void *context
-);
-
-
-/* DNSServiceEnumerateDomains() Parameters:
- *
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
- * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
- * and the enumeration operation will run indefinitely until the client
- * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
- *
- * flags: Possible values are:
- * kDNSServiceFlagsBrowseDomains to enumerate domains recommended for browsing.
- * kDNSServiceFlagsRegistrationDomains to enumerate domains recommended
- * for registration.
- *
- * interfaceIndex: If non-zero, specifies the interface on which to look for domains.
- * (the index for a given interface is determined via the if_nametoindex()
- * family of calls.) Most applications will pass 0 to enumerate domains on
- * all interfaces. See "Constants for specifying an interface index" for more details.
- *
- * callBack: The function to be called when a domain is found or the call asynchronously
- * fails.
- *
- * context: An application context pointer which is passed to the callback function
- * (may be NULL).
- *
- * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
- * errors are delivered to the callback), otherwise returns an error code indicating
- * the error that occurred (the callback is not invoked and the DNSServiceRef
- * is not initialized).
- */
-
-DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
-(
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceDomainEnumReply callBack,
- void *context /* may be NULL */
-);
-
-
-/*********************************************************************************************
-*
-* Service Registration
-*
-*********************************************************************************************/
-
-/* Register a service that is discovered via Browse() and Resolve() calls.
- *
- * DNSServiceRegisterReply() Callback Parameters:
- *
- * sdRef: The DNSServiceRef initialized by DNSServiceRegister().
- *
- * flags: When a name is successfully registered, the callback will be
- * invoked with the kDNSServiceFlagsAdd flag set. When Wide-Area
- * DNS-SD is in use, it is possible for a single service to get
- * more than one success callback (e.g. one in the "local" multicast
- * DNS domain, and another in a wide-area unicast DNS domain).
- * If a successfully-registered name later suffers a name conflict
- * or similar problem and has to be deregistered, the callback will
- * be invoked with the kDNSServiceFlagsAdd flag not set. The callback
- * is *not* invoked in the case where the caller explicitly terminates
- * the service registration by calling DNSServiceRefDeallocate(ref);
- *
- * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will
- * indicate the failure that occurred (including name conflicts,
- * if the kDNSServiceFlagsNoAutoRename flag was used when registering.)
- * Other parameters are undefined if errorCode is nonzero.
- *
- * name: The service name registered (if the application did not specify a name in
- * DNSServiceRegister(), this indicates what name was automatically chosen).
- *
- * regtype: The type of service registered, as it was passed to the callout.
- *
- * domain: The domain on which the service was registered (if the application did not
- * specify a domain in DNSServiceRegister(), this indicates the default domain
- * on which the service was registered).
- *
- * context: The context pointer that was passed to the callout.
- *
- */
-
-typedef void (DNSSD_API *DNSServiceRegisterReply)
-(
- DNSServiceRef sdRef,
- DNSServiceFlags flags,
- DNSServiceErrorType errorCode,
- const char *name,
- const char *regtype,
- const char *domain,
- void *context
-);
-
-
-/* DNSServiceRegister() Parameters:
- *
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
- * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
- * and the registration will remain active indefinitely until the client
- * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
- *
- * interfaceIndex: If non-zero, specifies the interface on which to register the service
- * (the index for a given interface is determined via the if_nametoindex()
- * family of calls.) Most applications will pass 0 to register on all
- * available interfaces. See "Constants for specifying an interface index" for more details.
- *
- * flags: Indicates the renaming behavior on name conflict (most applications
- * will pass 0). See flag definitions above for details.
- *
- * name: If non-NULL, specifies the service name to be registered.
- * Most applications will not specify a name, in which case the computer
- * name is used (this name is communicated to the client via the callback).
- * If a name is specified, it must be 1-63 bytes of UTF-8 text.
- * If the name is longer than 63 bytes it will be automatically truncated
- * to a legal length, unless the NoAutoRename flag is set,
- * in which case kDNSServiceErr_BadParam will be returned.
- *
- * regtype: The service type followed by the protocol, separated by a dot
- * (e.g. "_ftp._tcp"). The service type must be an underscore, followed
- * by 1-15 characters, which may be letters, digits, or hyphens.
- * The transport protocol must be "_tcp" or "_udp". New service types
- * should be registered at <http://www.dns-sd.org/ServiceTypes.html>.
- *
- * Additional subtypes of the primary service type (where a service
- * type has defined subtypes) follow the primary service type in a
- * comma-separated list, with no additional spaces, e.g.
- * "_primarytype._tcp,_subtype1,_subtype2,_subtype3"
- * Subtypes provide a mechanism for filtered browsing: A client browsing
- * for "_primarytype._tcp" will discover all instances of this type;
- * a client browsing for "_primarytype._tcp,_subtype2" will discover only
- * those instances that were registered with "_subtype2" in their list of
- * registered subtypes.
- *
- * The subtype mechanism can be illustrated with some examples using the
- * dns-sd command-line tool:
- *
- * % dns-sd -R Simple _test._tcp "" 1001 &
- * % dns-sd -R Better _test._tcp,HasFeatureA "" 1002 &
- * % dns-sd -R Best _test._tcp,HasFeatureA,HasFeatureB "" 1003 &
- *
- * Now:
- * % dns-sd -B _test._tcp # will find all three services
- * % dns-sd -B _test._tcp,HasFeatureA # finds "Better" and "Best"
- * % dns-sd -B _test._tcp,HasFeatureB # finds only "Best"
- *
- * Subtype labels may be up to 63 bytes long, and may contain any eight-
- * bit byte values, including zero bytes. However, due to the nature of
- * using a C-string-based API, conventional DNS escaping must be used for
- * dots ('.'), commas (','), backslashes ('\') and zero bytes, as shown below:
- *
- * % dns-sd -R Test '_test._tcp,s\.one,s\,two,s\\three,s\000four' local 123
- *
- * When a service is registered, all the clients browsing for the registered
- * type ("regtype") will discover it. If the discovery should be
- * restricted to a smaller set of well known peers, the service can be
- * registered with additional data (group identifier) that is known
- * only to a smaller set of peers. The group identifier should follow primary
- * service type using a colon (":") as a delimeter. If subtypes are also present,
- * it should be given before the subtype as shown below.
- *
- * % dns-sd -R _test1 _http._tcp:mygroup1 local 1001
- * % dns-sd -R _test2 _http._tcp:mygroup2 local 1001
- * % dns-sd -R _test3 _http._tcp:mygroup3,HasFeatureA local 1001
- *
- * Now:
- * % dns-sd -B _http._tcp:"mygroup1" # will discover only test1
- * % dns-sd -B _http._tcp:"mygroup2" # will discover only test2
- * % dns-sd -B _http._tcp:"mygroup3",HasFeatureA # will discover only test3
- *
- * By specifying the group information, only the members of that group are
- * discovered.
- *
- * The group identifier itself is not sent in clear. Only a hash of the group
- * identifier is sent and the clients discover them anonymously. The group identifier
- * may be up to 256 bytes long and may contain any eight bit values except comma which
- * should be escaped.
- *
- * domain: If non-NULL, specifies the domain on which to advertise the service.
- * Most applications will not specify a domain, instead automatically
- * registering in the default domain(s).
- *
- * host: If non-NULL, specifies the SRV target host name. Most applications
- * will not specify a host, instead automatically using the machine's
- * default host name(s). Note that specifying a non-NULL host does NOT
- * create an address record for that host - the application is responsible
- * for ensuring that the appropriate address record exists, or creating it
- * via DNSServiceRegisterRecord().
- *
- * port: The port, in network byte order, on which the service accepts connections.
- * Pass 0 for a "placeholder" service (i.e. a service that will not be discovered
- * by browsing, but will cause a name conflict if another client tries to
- * register that same name). Most clients will not use placeholder services.
- *
- * txtLen: The length of the txtRecord, in bytes. Must be zero if the txtRecord is NULL.
- *
- * txtRecord: The TXT record rdata. A non-NULL txtRecord MUST be a properly formatted DNS
- * TXT record, i.e. <length byte> <data> <length byte> <data> ...
- * Passing NULL for the txtRecord is allowed as a synonym for txtLen=1, txtRecord="",
- * i.e. it creates a TXT record of length one containing a single empty string.
- * RFC 1035 doesn't allow a TXT record to contain *zero* strings, so a single empty
- * string is the smallest legal DNS TXT record.
- * As with the other parameters, the DNSServiceRegister call copies the txtRecord
- * data; e.g. if you allocated the storage for the txtRecord parameter with malloc()
- * then you can safely free that memory right after the DNSServiceRegister call returns.
- *
- * callBack: The function to be called when the registration completes or asynchronously
- * fails. The client MAY pass NULL for the callback - The client will NOT be notified
- * of the default values picked on its behalf, and the client will NOT be notified of any
- * asynchronous errors (e.g. out of memory errors, etc.) that may prevent the registration
- * of the service. The client may NOT pass the NoAutoRename flag if the callback is NULL.
- * The client may still deregister the service at any time via DNSServiceRefDeallocate().
- *
- * context: An application context pointer which is passed to the callback function
- * (may be NULL).
- *
- * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
- * errors are delivered to the callback), otherwise returns an error code indicating
- * the error that occurred (the callback is never invoked and the DNSServiceRef
- * is not initialized).
- */
-
-DNSServiceErrorType DNSSD_API DNSServiceRegister
-(
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- const char *name, /* may be NULL */
- const char *regtype,
- const char *domain, /* may be NULL */
- const char *host, /* may be NULL */
- uint16_t port, /* In network byte order */
- uint16_t txtLen,
- const void *txtRecord, /* may be NULL */
- DNSServiceRegisterReply callBack, /* may be NULL */
- void *context /* may be NULL */
-);
-
-
-/* DNSServiceAddRecord()
- *
- * Add a record to a registered service. The name of the record will be the same as the
- * registered service's name.
- * The record can later be updated or deregistered by passing the RecordRef initialized
- * by this function to DNSServiceUpdateRecord() or DNSServiceRemoveRecord().
- *
- * Note that the DNSServiceAddRecord/UpdateRecord/RemoveRecord are *NOT* thread-safe
- * with respect to a single DNSServiceRef. If you plan to have multiple threads
- * in your program simultaneously add, update, or remove records from the same
- * DNSServiceRef, then it's the caller's responsibility to use a mutext lock
- * or take similar appropriate precautions to serialize those calls.
- *
- * Parameters;
- *
- * sdRef: A DNSServiceRef initialized by DNSServiceRegister().
- *
- * RecordRef: A pointer to an uninitialized DNSRecordRef. Upon succesfull completion of this
- * call, this ref may be passed to DNSServiceUpdateRecord() or DNSServiceRemoveRecord().
- * If the above DNSServiceRef is passed to DNSServiceRefDeallocate(), RecordRef is also
- * invalidated and may not be used further.
- *
- * flags: Currently ignored, reserved for future use.
- *
- * rrtype: The type of the record (e.g. kDNSServiceType_TXT, kDNSServiceType_SRV, etc)
- *
- * rdlen: The length, in bytes, of the rdata.
- *
- * rdata: The raw rdata to be contained in the added resource record.
- *
- * ttl: The time to live of the resource record, in seconds.
- * Most clients should pass 0 to indicate that the system should
- * select a sensible default value.
- *
- * return value: Returns kDNSServiceErr_NoError on success, otherwise returns an
- * error code indicating the error that occurred (the RecordRef is not initialized).
- */
-
-DNSServiceErrorType DNSSD_API DNSServiceAddRecord
-(
- DNSServiceRef sdRef,
- DNSRecordRef *RecordRef,
- DNSServiceFlags flags,
- uint16_t rrtype,
- uint16_t rdlen,
- const void *rdata,
- uint32_t ttl
-);
-
-
-/* DNSServiceUpdateRecord
- *
- * Update a registered resource record. The record must either be:
- * - The primary txt record of a service registered via DNSServiceRegister()
- * - A record added to a registered service via DNSServiceAddRecord()
- * - An individual record registered by DNSServiceRegisterRecord()
- *
- * Parameters:
- *
- * sdRef: A DNSServiceRef that was initialized by DNSServiceRegister()
- * or DNSServiceCreateConnection().
- *
- * RecordRef: A DNSRecordRef initialized by DNSServiceAddRecord, or NULL to update the
- * service's primary txt record.
- *
- * flags: Currently ignored, reserved for future use.
- *
- * rdlen: The length, in bytes, of the new rdata.
- *
- * rdata: The new rdata to be contained in the updated resource record.
- *
- * ttl: The time to live of the updated resource record, in seconds.
- * Most clients should pass 0 to indicate that the system should
- * select a sensible default value.
- *
- * return value: Returns kDNSServiceErr_NoError on success, otherwise returns an
- * error code indicating the error that occurred.
- */
-
-DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
-(
- DNSServiceRef sdRef,
- DNSRecordRef RecordRef, /* may be NULL */
- DNSServiceFlags flags,
- uint16_t rdlen,
- const void *rdata,
- uint32_t ttl
-);
-
-
-/* DNSServiceRemoveRecord
- *
- * Remove a record previously added to a service record set via DNSServiceAddRecord(), or deregister
- * an record registered individually via DNSServiceRegisterRecord().
- *
- * Parameters:
- *
- * sdRef: A DNSServiceRef initialized by DNSServiceRegister() (if the
- * record being removed was registered via DNSServiceAddRecord()) or by
- * DNSServiceCreateConnection() (if the record being removed was registered via
- * DNSServiceRegisterRecord()).
- *
- * recordRef: A DNSRecordRef initialized by a successful call to DNSServiceAddRecord()
- * or DNSServiceRegisterRecord().
- *
- * flags: Currently ignored, reserved for future use.
- *
- * return value: Returns kDNSServiceErr_NoError on success, otherwise returns an
- * error code indicating the error that occurred.
- */
-
-DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
-(
- DNSServiceRef sdRef,
- DNSRecordRef RecordRef,
- DNSServiceFlags flags
-);
-
-
-/*********************************************************************************************
-*
-* Service Discovery
-*
-*********************************************************************************************/
-
-/* Browse for instances of a service.
- *
- * DNSServiceBrowseReply() Parameters:
- *
- * sdRef: The DNSServiceRef initialized by DNSServiceBrowse().
- *
- * flags: Possible values are kDNSServiceFlagsMoreComing and kDNSServiceFlagsAdd.
- * See flag definitions for details.
- *
- * interfaceIndex: The interface on which the service is advertised. This index should
- * be passed to DNSServiceResolve() when resolving the service.
- *
- * errorCode: Will be kDNSServiceErr_NoError (0) on success, otherwise will
- * indicate the failure that occurred. Other parameters are undefined if
- * the errorCode is nonzero.
- *
- * serviceName: The discovered service name. This name should be displayed to the user,
- * and stored for subsequent use in the DNSServiceResolve() call.
- *
- * regtype: The service type, which is usually (but not always) the same as was passed
- * to DNSServiceBrowse(). One case where the discovered service type may
- * not be the same as the requested service type is when using subtypes:
- * The client may want to browse for only those ftp servers that allow
- * anonymous connections. The client will pass the string "_ftp._tcp,_anon"
- * to DNSServiceBrowse(), but the type of the service that's discovered
- * is simply "_ftp._tcp". The regtype for each discovered service instance
- * should be stored along with the name, so that it can be passed to
- * DNSServiceResolve() when the service is later resolved.
- *
- * domain: The domain of the discovered service instance. This may or may not be the
- * same as the domain that was passed to DNSServiceBrowse(). The domain for each
- * discovered service instance should be stored along with the name, so that
- * it can be passed to DNSServiceResolve() when the service is later resolved.
- *
- * context: The context pointer that was passed to the callout.
- *
- */
-
-typedef void (DNSSD_API *DNSServiceBrowseReply)
-(
- DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char *serviceName,
- const char *regtype,
- const char *replyDomain,
- void *context
-);
-
-
-/* DNSServiceBrowse() Parameters:
- *
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
- * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
- * and the browse operation will run indefinitely until the client
- * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
- *
- * flags: Currently ignored, reserved for future use.
- *
- * interfaceIndex: If non-zero, specifies the interface on which to browse for services
- * (the index for a given interface is determined via the if_nametoindex()
- * family of calls.) Most applications will pass 0 to browse on all available
- * interfaces. See "Constants for specifying an interface index" for more details.
- *
- * regtype: The service type being browsed for followed by the protocol, separated by a
- * dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
- * A client may optionally specify a single subtype to perform filtered browsing:
- * e.g. browsing for "_primarytype._tcp,_subtype" will discover only those
- * instances of "_primarytype._tcp" that were registered specifying "_subtype"
- * in their list of registered subtypes. Additionally, a group identifier may
- * also be specified before the subtype e.g., _primarytype._tcp:GroupID, which
- * will discover only the members that register the service with GroupID. See
- * DNSServiceRegister for more details.
- *
- * domain: If non-NULL, specifies the domain on which to browse for services.
- * Most applications will not specify a domain, instead browsing on the
- * default domain(s).
- *
- * callBack: The function to be called when an instance of the service being browsed for
- * is found, or if the call asynchronously fails.
- *
- * context: An application context pointer which is passed to the callback function
- * (may be NULL).
- *
- * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
- * errors are delivered to the callback), otherwise returns an error code indicating
- * the error that occurred (the callback is not invoked and the DNSServiceRef
- * is not initialized).
- */
-
-DNSServiceErrorType DNSSD_API DNSServiceBrowse
-(
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- const char *regtype,
- const char *domain, /* may be NULL */
- DNSServiceBrowseReply callBack,
- void *context /* may be NULL */
-);
-
-
-/* DNSServiceResolve()
- *
- * Resolve a service name discovered via DNSServiceBrowse() to a target host name, port number, and
- * txt record.
- *
- * Note: Applications should NOT use DNSServiceResolve() solely for txt record monitoring - use
- * DNSServiceQueryRecord() instead, as it is more efficient for this task.
- *
- * Note: When the desired results have been returned, the client MUST terminate the resolve by calling
- * DNSServiceRefDeallocate().
- *
- * Note: DNSServiceResolve() behaves correctly for typical services that have a single SRV record
- * and a single TXT record. To resolve non-standard services with multiple SRV or TXT records,
- * DNSServiceQueryRecord() should be used.
- *
- * DNSServiceResolveReply Callback Parameters:
- *
- * sdRef: The DNSServiceRef initialized by DNSServiceResolve().
- *
- * flags: Possible values: kDNSServiceFlagsMoreComing
- *
- * interfaceIndex: The interface on which the service was resolved.
- *
- * errorCode: Will be kDNSServiceErr_NoError (0) on success, otherwise will
- * indicate the failure that occurred. Other parameters are undefined if
- * the errorCode is nonzero.
- *
- * fullname: The full service domain name, in the form <servicename>.<protocol>.<domain>.
- * (This name is escaped following standard DNS rules, making it suitable for
- * passing to standard system DNS APIs such as res_query(), or to the
- * special-purpose functions included in this API that take fullname parameters.
- * See "Notes on DNS Name Escaping" earlier in this file for more details.)
- *
- * hosttarget: The target hostname of the machine providing the service. This name can
- * be passed to functions like gethostbyname() to identify the host's IP address.
- *
- * port: The port, in network byte order, on which connections are accepted for this service.
- *
- * txtLen: The length of the txt record, in bytes.
- *
- * txtRecord: The service's primary txt record, in standard txt record format.
- *
- * context: The context pointer that was passed to the callout.
- *
- * NOTE: In earlier versions of this header file, the txtRecord parameter was declared "const char *"
- * This is incorrect, since it contains length bytes which are values in the range 0 to 255, not -128 to +127.
- * Depending on your compiler settings, this change may cause signed/unsigned mismatch warnings.
- * These should be fixed by updating your own callback function definition to match the corrected
- * function signature using "const unsigned char *txtRecord". Making this change may also fix inadvertent
- * bugs in your callback function, where it could have incorrectly interpreted a length byte with value 250
- * as being -6 instead, with various bad consequences ranging from incorrect operation to software crashes.
- * If you need to maintain portable code that will compile cleanly with both the old and new versions of
- * this header file, you should update your callback function definition to use the correct unsigned value,
- * and then in the place where you pass your callback function to DNSServiceResolve(), use a cast to eliminate
- * the compiler warning, e.g.:
- * DNSServiceResolve(sd, flags, index, name, regtype, domain, (DNSServiceResolveReply)MyCallback, context);
- * This will ensure that your code compiles cleanly without warnings (and more importantly, works correctly)
- * with both the old header and with the new corrected version.
- *
- */
-
-typedef void (DNSSD_API *DNSServiceResolveReply)
-(
- DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char *fullname,
- const char *hosttarget,
- uint16_t port, /* In network byte order */
- uint16_t txtLen,
- const unsigned char *txtRecord,
- void *context
-);
-
-
-/* DNSServiceResolve() Parameters
- *
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
- * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
- * and the resolve operation will run indefinitely until the client
- * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
- *
- * flags: Specifying kDNSServiceFlagsForceMulticast will cause query to be
- * performed with a link-local mDNS query, even if the name is an
- * apparently non-local name (i.e. a name not ending in ".local.")
- *
- * interfaceIndex: The interface on which to resolve the service. If this resolve call is
- * as a result of a currently active DNSServiceBrowse() operation, then the
- * interfaceIndex should be the index reported in the DNSServiceBrowseReply
- * callback. If this resolve call is using information previously saved
- * (e.g. in a preference file) for later use, then use interfaceIndex 0, because
- * the desired service may now be reachable via a different physical interface.
- * See "Constants for specifying an interface index" for more details.
- *
- * name: The name of the service instance to be resolved, as reported to the
- * DNSServiceBrowseReply() callback.
- *
- * regtype: The type of the service instance to be resolved, as reported to the
- * DNSServiceBrowseReply() callback.
- *
- * domain: The domain of the service instance to be resolved, as reported to the
- * DNSServiceBrowseReply() callback.
- *
- * callBack: The function to be called when a result is found, or if the call
- * asynchronously fails.
- *
- * context: An application context pointer which is passed to the callback function
- * (may be NULL).
- *
- * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
- * errors are delivered to the callback), otherwise returns an error code indicating
- * the error that occurred (the callback is never invoked and the DNSServiceRef
- * is not initialized).
- */
-
-DNSServiceErrorType DNSSD_API DNSServiceResolve
-(
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- const char *name,
- const char *regtype,
- const char *domain,
- DNSServiceResolveReply callBack,
- void *context /* may be NULL */
-);
-
-
-/*********************************************************************************************
-*
-* Querying Individual Specific Records
-*
-*********************************************************************************************/
-
-/* DNSServiceQueryRecord
- *
- * Query for an arbitrary DNS record.
- *
- * DNSServiceQueryRecordReply() Callback Parameters:
- *
- * sdRef: The DNSServiceRef initialized by DNSServiceQueryRecord().
- *
- * flags: Possible values are kDNSServiceFlagsMoreComing and
- * kDNSServiceFlagsAdd. The Add flag is NOT set for PTR records
- * with a ttl of 0, i.e. "Remove" events.
- *
- * interfaceIndex: The interface on which the query was resolved (the index for a given
- * interface is determined via the if_nametoindex() family of calls).
- * See "Constants for specifying an interface index" for more details.
- *
- * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will
- * indicate the failure that occurred. Other parameters are undefined if
- * errorCode is nonzero.
- *
- * fullname: The resource record's full domain name.
- *
- * rrtype: The resource record's type (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
- *
- * rrclass: The class of the resource record (usually kDNSServiceClass_IN).
- *
- * rdlen: The length, in bytes, of the resource record rdata.
- *
- * rdata: The raw rdata of the resource record.
- *
- * ttl: If the client wishes to cache the result for performance reasons,
- * the TTL indicates how long the client may legitimately hold onto
- * this result, in seconds. After the TTL expires, the client should
- * consider the result no longer valid, and if it requires this data
- * again, it should be re-fetched with a new query. Of course, this
- * only applies to clients that cancel the asynchronous operation when
- * they get a result. Clients that leave the asynchronous operation
- * running can safely assume that the data remains valid until they
- * get another callback telling them otherwise.
- *
- * context: The context pointer that was passed to the callout.
- *
- */
-
-typedef void (DNSSD_API *DNSServiceQueryRecordReply)
-(
- DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char *fullname,
- uint16_t rrtype,
- uint16_t rrclass,
- uint16_t rdlen,
- const void *rdata,
- uint32_t ttl,
- void *context
-);
-
-
-/* DNSServiceQueryRecord() Parameters:
- *
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
- * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
- * and the query operation will run indefinitely until the client
- * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
- *
- * flags: kDNSServiceFlagsForceMulticast or kDNSServiceFlagsLongLivedQuery.
- * Pass kDNSServiceFlagsLongLivedQuery to create a "long-lived" unicast
- * query to a unicast DNS server that implements the protocol. This flag
- * has no effect on link-local multicast queries.
- *
- * interfaceIndex: If non-zero, specifies the interface on which to issue the query
- * (the index for a given interface is determined via the if_nametoindex()
- * family of calls.) Passing 0 causes the name to be queried for on all
- * interfaces. See "Constants for specifying an interface index" for more details.
- *
- * fullname: The full domain name of the resource record to be queried for.
- *
- * rrtype: The numerical type of the resource record to be queried for
- * (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
- *
- * rrclass: The class of the resource record (usually kDNSServiceClass_IN).
- *
- * callBack: The function to be called when a result is found, or if the call
- * asynchronously fails.
- *
- * context: An application context pointer which is passed to the callback function
- * (may be NULL).
- *
- * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
- * errors are delivered to the callback), otherwise returns an error code indicating
- * the error that occurred (the callback is never invoked and the DNSServiceRef
- * is not initialized).
- */
-
-DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
-(
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- const char *fullname,
- uint16_t rrtype,
- uint16_t rrclass,
- DNSServiceQueryRecordReply callBack,
- void *context /* may be NULL */
-);
-
-
-/*********************************************************************************************
-*
-* Unified lookup of both IPv4 and IPv6 addresses for a fully qualified hostname
-*
-*********************************************************************************************/
-
-/* DNSServiceGetAddrInfo
- *
- * Queries for the IP address of a hostname by using either Multicast or Unicast DNS.
- *
- * DNSServiceGetAddrInfoReply() parameters:
- *
- * sdRef: The DNSServiceRef initialized by DNSServiceGetAddrInfo().
- *
- * flags: Possible values are kDNSServiceFlagsMoreComing and
- * kDNSServiceFlagsAdd.
- *
- * interfaceIndex: The interface to which the answers pertain.
- *
- * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will
- * indicate the failure that occurred. Other parameters are
- * undefined if errorCode is nonzero.
- *
- * hostname: The fully qualified domain name of the host to be queried for.
- *
- * address: IPv4 or IPv6 address.
- *
- * ttl: If the client wishes to cache the result for performance reasons,
- * the TTL indicates how long the client may legitimately hold onto
- * this result, in seconds. After the TTL expires, the client should
- * consider the result no longer valid, and if it requires this data
- * again, it should be re-fetched with a new query. Of course, this
- * only applies to clients that cancel the asynchronous operation when
- * they get a result. Clients that leave the asynchronous operation
- * running can safely assume that the data remains valid until they
- * get another callback telling them otherwise.
- *
- * context: The context pointer that was passed to the callout.
- *
- */
-
-typedef void (DNSSD_API *DNSServiceGetAddrInfoReply)
-(
- DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char *hostname,
- const struct sockaddr *address,
- uint32_t ttl,
- void *context
-);
-
-
-/* DNSServiceGetAddrInfo() Parameters:
- *
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds then it
- * initializes the DNSServiceRef, returns kDNSServiceErr_NoError, and the query
- * begins and will last indefinitely until the client terminates the query
- * by passing this DNSServiceRef to DNSServiceRefDeallocate().
- *
- * flags: kDNSServiceFlagsForceMulticast or kDNSServiceFlagsLongLivedQuery.
- * Pass kDNSServiceFlagsLongLivedQuery to create a "long-lived" unicast
- * query to a unicast DNS server that implements the protocol. This flag
- * has no effect on link-local multicast queries.
- *
- * interfaceIndex: The interface on which to issue the query. Passing 0 causes the query to be
- * sent on all active interfaces via Multicast or the primary interface via Unicast.
- *
- * protocol: Pass in kDNSServiceProtocol_IPv4 to look up IPv4 addresses, or kDNSServiceProtocol_IPv6
- * to look up IPv6 addresses, or both to look up both kinds. If neither flag is
- * set, the system will apply an intelligent heuristic, which is (currently)
- * that it will attempt to look up both, except:
- *
- * * If "hostname" is a wide-area unicast DNS hostname (i.e. not a ".local." name)
- * but this host has no routable IPv6 address, then the call will not try to
- * look up IPv6 addresses for "hostname", since any addresses it found would be
- * unlikely to be of any use anyway. Similarly, if this host has no routable
- * IPv4 address, the call will not try to look up IPv4 addresses for "hostname".
- *
- * hostname: The fully qualified domain name of the host to be queried for.
- *
- * callBack: The function to be called when the query succeeds or fails asynchronously.
- *
- * context: An application context pointer which is passed to the callback function
- * (may be NULL).
- *
- * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
- * errors are delivered to the callback), otherwise returns an error code indicating
- * the error that occurred.
- */
-
-DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo
-(
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceProtocol protocol,
- const char *hostname,
- DNSServiceGetAddrInfoReply callBack,
- void *context /* may be NULL */
-);
-
-
-/*********************************************************************************************
-*
-* Special Purpose Calls:
-* DNSServiceCreateConnection(), DNSServiceRegisterRecord(), DNSServiceReconfirmRecord()
-* (most applications will not use these)
-*
-*********************************************************************************************/
-
-/* DNSServiceCreateConnection()
- *
- * Create a connection to the daemon allowing efficient registration of
- * multiple individual records.
- *
- * Parameters:
- *
- * sdRef: A pointer to an uninitialized DNSServiceRef. Deallocating
- * the reference (via DNSServiceRefDeallocate()) severs the
- * connection and deregisters all records registered on this connection.
- *
- * return value: Returns kDNSServiceErr_NoError on success, otherwise returns
- * an error code indicating the specific failure that occurred (in which
- * case the DNSServiceRef is not initialized).
- */
-
-DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef);
-
-/* DNSServiceRegisterRecord
- *
- * Register an individual resource record on a connected DNSServiceRef.
- *
- * Note that name conflicts occurring for records registered via this call must be handled
- * by the client in the callback.
- *
- * DNSServiceRegisterRecordReply() parameters:
- *
- * sdRef: The connected DNSServiceRef initialized by
- * DNSServiceCreateConnection().
- *
- * RecordRef: The DNSRecordRef initialized by DNSServiceRegisterRecord(). If the above
- * DNSServiceRef is passed to DNSServiceRefDeallocate(), this DNSRecordRef is
- * invalidated, and may not be used further.
- *
- * flags: Currently unused, reserved for future use.
- *
- * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will
- * indicate the failure that occurred (including name conflicts.)
- * Other parameters are undefined if errorCode is nonzero.
- *
- * context: The context pointer that was passed to the callout.
- *
- */
-
-typedef void (DNSSD_API *DNSServiceRegisterRecordReply)
-(
- DNSServiceRef sdRef,
- DNSRecordRef RecordRef,
- DNSServiceFlags flags,
- DNSServiceErrorType errorCode,
- void *context
-);
-
-
-/* DNSServiceRegisterRecord() Parameters:
- *
- * sdRef: A DNSServiceRef initialized by DNSServiceCreateConnection().
- *
- * RecordRef: A pointer to an uninitialized DNSRecordRef. Upon succesfull completion of this
- * call, this ref may be passed to DNSServiceUpdateRecord() or DNSServiceRemoveRecord().
- * (To deregister ALL records registered on a single connected DNSServiceRef
- * and deallocate each of their corresponding DNSServiceRecordRefs, call
- * DNSServiceRefDeallocate()).
- *
- * flags: Possible values are kDNSServiceFlagsShared or kDNSServiceFlagsUnique
- * (see flag type definitions for details).
- *
- * interfaceIndex: If non-zero, specifies the interface on which to register the record
- * (the index for a given interface is determined via the if_nametoindex()
- * family of calls.) Passing 0 causes the record to be registered on all interfaces.
- * See "Constants for specifying an interface index" for more details.
- *
- * fullname: The full domain name of the resource record.
- *
- * rrtype: The numerical type of the resource record (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
- *
- * rrclass: The class of the resource record (usually kDNSServiceClass_IN)
- *
- * rdlen: Length, in bytes, of the rdata.
- *
- * rdata: A pointer to the raw rdata, as it is to appear in the DNS record.
- *
- * ttl: The time to live of the resource record, in seconds.
- * Most clients should pass 0 to indicate that the system should
- * select a sensible default value.
- *
- * callBack: The function to be called when a result is found, or if the call
- * asynchronously fails (e.g. because of a name conflict.)
- *
- * context: An application context pointer which is passed to the callback function
- * (may be NULL).
- *
- * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
- * errors are delivered to the callback), otherwise returns an error code indicating
- * the error that occurred (the callback is never invoked and the DNSRecordRef is
- * not initialized).
- */
-
-DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
-(
- DNSServiceRef sdRef,
- DNSRecordRef *RecordRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- const char *fullname,
- uint16_t rrtype,
- uint16_t rrclass,
- uint16_t rdlen,
- const void *rdata,
- uint32_t ttl,
- DNSServiceRegisterRecordReply callBack,
- void *context /* may be NULL */
-);
-
-
-/* DNSServiceReconfirmRecord
- *
- * Instruct the daemon to verify the validity of a resource record that appears
- * to be out of date (e.g. because TCP connection to a service's target failed.)
- * Causes the record to be flushed from the daemon's cache (as well as all other
- * daemons' caches on the network) if the record is determined to be invalid.
- * Use this routine conservatively. Reconfirming a record necessarily consumes
- * network bandwidth, so this should not be done indiscriminately.
- *
- * Parameters:
- *
- * flags: Not currently used.
- *
- * interfaceIndex: Specifies the interface of the record in question.
- * The caller must specify the interface.
- * This API (by design) causes increased network traffic, so it requires
- * the caller to be precise about which record should be reconfirmed.
- * It is not possible to pass zero for the interface index to perform
- * a "wildcard" reconfirmation, where *all* matching records are reconfirmed.
- *
- * fullname: The resource record's full domain name.
- *
- * rrtype: The resource record's type (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
- *
- * rrclass: The class of the resource record (usually kDNSServiceClass_IN).
- *
- * rdlen: The length, in bytes, of the resource record rdata.
- *
- * rdata: The raw rdata of the resource record.
- *
- */
-
-DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
-(
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- const char *fullname,
- uint16_t rrtype,
- uint16_t rrclass,
- uint16_t rdlen,
- const void *rdata
-);
-
-
-/*********************************************************************************************
-*
-* NAT Port Mapping
-*
-*********************************************************************************************/
-
-/* DNSServiceNATPortMappingCreate
- *
- * Request a port mapping in the NAT gateway, which maps a port on the local machine
- * to an external port on the NAT. The NAT should support either PCP, NAT-PMP or the
- * UPnP/IGD protocol for this API to create a successful mapping. Note that this API
- * currently supports IPv4 addresses/mappings only. If the NAT gateway supports PCP and
- * returns an IPv6 address (incorrectly, since this API specifically requests IPv4
- * addresses), the DNSServiceNATPortMappingReply callback will be invoked with errorCode
- * kDNSServiceErr_NATPortMappingUnsupported.
- *
- * The port mapping will be renewed indefinitely until the client process exits, or
- * explicitly terminates the port mapping request by calling DNSServiceRefDeallocate().
- * The client callback will be invoked, informing the client of the NAT gateway's
- * external IP address and the external port that has been allocated for this client.
- * The client should then record this external IP address and port using whatever
- * directory service mechanism it is using to enable peers to connect to it.
- * (Clients advertising services using Wide-Area DNS-SD DO NOT need to use this API
- * -- when a client calls DNSServiceRegister() NAT mappings are automatically created
- * and the external IP address and port for the service are recorded in the global DNS.
- * Only clients using some directory mechanism other than Wide-Area DNS-SD need to use
- * this API to explicitly map their own ports.)
- *
- * It's possible that the client callback could be called multiple times, for example
- * if the NAT gateway's IP address changes, or if a configuration change results in a
- * different external port being mapped for this client. Over the lifetime of any long-lived
- * port mapping, the client should be prepared to handle these notifications of changes
- * in the environment, and should update its recorded address and/or port as appropriate.
- *
- * NOTE: There are two unusual aspects of how the DNSServiceNATPortMappingCreate API works,
- * which were intentionally designed to help simplify client code:
- *
- * 1. It's not an error to request a NAT mapping when the machine is not behind a NAT gateway.
- * In other NAT mapping APIs, if you request a NAT mapping and the machine is not behind a NAT
- * gateway, then the API returns an error code -- it can't get you a NAT mapping if there's no
- * NAT gateway. The DNSServiceNATPortMappingCreate API takes a different view. Working out
- * whether or not you need a NAT mapping can be tricky and non-obvious, particularly on
- * a machine with multiple active network interfaces. Rather than make every client recreate
- * this logic for deciding whether a NAT mapping is required, the PortMapping API does that
- * work for you. If the client calls the PortMapping API when the machine already has a
- * routable public IP address, then instead of complaining about it and giving an error,
- * the PortMapping API just invokes your callback, giving the machine's public address
- * and your own port number. This means you don't need to write code to work out whether
- * your client needs to call the PortMapping API -- just call it anyway, and if it wasn't
- * necessary, no harm is done:
- *
- * - If the machine already has a routable public IP address, then your callback
- * will just be invoked giving your own address and port.
- * - If a NAT mapping is required and obtained, then your callback will be invoked
- * giving you the external address and port.
- * - If a NAT mapping is required but not obtained from the local NAT gateway,
- * or the machine has no network connectivity, then your callback will be
- * invoked giving zero address and port.
- *
- * 2. In other NAT mapping APIs, if a laptop computer is put to sleep and woken up on a new
- * network, it's the client's job to notice this, and work out whether a NAT mapping
- * is required on the new network, and make a new NAT mapping request if necessary.
- * The DNSServiceNATPortMappingCreate API does this for you, automatically.
- * The client just needs to make one call to the PortMapping API, and its callback will
- * be invoked any time the mapping state changes. This property complements point (1) above.
- * If the client didn't make a NAT mapping request just because it determined that one was
- * not required at that particular moment in time, the client would then have to monitor
- * for network state changes to determine if a NAT port mapping later became necessary.
- * By unconditionally making a NAT mapping request, even when a NAT mapping not to be
- * necessary, the PortMapping API will then begin monitoring network state changes on behalf of
- * the client, and if a NAT mapping later becomes necessary, it will automatically create a NAT
- * mapping and inform the client with a new callback giving the new address and port information.
- *
- * DNSServiceNATPortMappingReply() parameters:
- *
- * sdRef: The DNSServiceRef initialized by DNSServiceNATPortMappingCreate().
- *
- * flags: Currently unused, reserved for future use.
- *
- * interfaceIndex: The interface through which the NAT gateway is reached.
- *
- * errorCode: Will be kDNSServiceErr_NoError on success.
- * Will be kDNSServiceErr_DoubleNAT when the NAT gateway is itself behind one or
- * more layers of NAT, in which case the other parameters have the defined values.
- * For other failures, will indicate the failure that occurred, and the other
- * parameters are undefined.
- *
- * externalAddress: Four byte IPv4 address in network byte order.
- *
- * protocol: Will be kDNSServiceProtocol_UDP or kDNSServiceProtocol_TCP or both.
- *
- * internalPort: The port on the local machine that was mapped.
- *
- * externalPort: The actual external port in the NAT gateway that was mapped.
- * This is likely to be different than the requested external port.
- *
- * ttl: The lifetime of the NAT port mapping created on the gateway.
- * This controls how quickly stale mappings will be garbage-collected
- * if the client machine crashes, suffers a power failure, is disconnected
- * from the network, or suffers some other unfortunate demise which
- * causes it to vanish without explicitly removing its NAT port mapping.
- * It's possible that the ttl value will differ from the requested ttl value.
- *
- * context: The context pointer that was passed to the callout.
- *
- */
-
-typedef void (DNSSD_API *DNSServiceNATPortMappingReply)
-(
- DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- uint32_t externalAddress, /* four byte IPv4 address in network byte order */
- DNSServiceProtocol protocol,
- uint16_t internalPort, /* In network byte order */
- uint16_t externalPort, /* In network byte order and may be different than the requested port */
- uint32_t ttl, /* may be different than the requested ttl */
- void *context
-);
-
-
-/* DNSServiceNATPortMappingCreate() Parameters:
- *
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds then it
- * initializes the DNSServiceRef, returns kDNSServiceErr_NoError, and the nat
- * port mapping will last indefinitely until the client terminates the port
- * mapping request by passing this DNSServiceRef to DNSServiceRefDeallocate().
- *
- * flags: Currently ignored, reserved for future use.
- *
- * interfaceIndex: The interface on which to create port mappings in a NAT gateway. Passing 0 causes
- * the port mapping request to be sent on the primary interface.
- *
- * protocol: To request a port mapping, pass in kDNSServiceProtocol_UDP, or kDNSServiceProtocol_TCP,
- * or (kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP) to map both.
- * The local listening port number must also be specified in the internalPort parameter.
- * To just discover the NAT gateway's external IP address, pass zero for protocol,
- * internalPort, externalPort and ttl.
- *
- * internalPort: The port number in network byte order on the local machine which is listening for packets.
- *
- * externalPort: The requested external port in network byte order in the NAT gateway that you would
- * like to map to the internal port. Pass 0 if you don't care which external port is chosen for you.
- *
- * ttl: The requested renewal period of the NAT port mapping, in seconds.
- * If the client machine crashes, suffers a power failure, is disconnected from
- * the network, or suffers some other unfortunate demise which causes it to vanish
- * unexpectedly without explicitly removing its NAT port mappings, then the NAT gateway
- * will garbage-collect old stale NAT port mappings when their lifetime expires.
- * Requesting a short TTL causes such orphaned mappings to be garbage-collected
- * more promptly, but consumes system resources and network bandwidth with
- * frequent renewal packets to keep the mapping from expiring.
- * Requesting a long TTL is more efficient on the network, but in the event of the
- * client vanishing, stale NAT port mappings will not be garbage-collected as quickly.
- * Most clients should pass 0 to use a system-wide default value.
- *
- * callBack: The function to be called when the port mapping request succeeds or fails asynchronously.
- *
- * context: An application context pointer which is passed to the callback function
- * (may be NULL).
- *
- * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
- * errors are delivered to the callback), otherwise returns an error code indicating
- * the error that occurred.
- *
- * If you don't actually want a port mapped, and are just calling the API
- * because you want to find out the NAT's external IP address (e.g. for UI
- * display) then pass zero for protocol, internalPort, externalPort and ttl.
- */
-
-DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
-(
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceProtocol protocol, /* TCP and/or UDP */
- uint16_t internalPort, /* network byte order */
- uint16_t externalPort, /* network byte order */
- uint32_t ttl, /* time to live in seconds */
- DNSServiceNATPortMappingReply callBack,
- void *context /* may be NULL */
-);
-
-
-/*********************************************************************************************
-*
-* General Utility Functions
-*
-*********************************************************************************************/
-
-/* DNSServiceConstructFullName()
- *
- * Concatenate a three-part domain name (as returned by the above callbacks) into a
- * properly-escaped full domain name. Note that callbacks in the above functions ALREADY ESCAPE
- * strings where necessary.
- *
- * Parameters:
- *
- * fullName: A pointer to a buffer that where the resulting full domain name is to be written.
- * The buffer must be kDNSServiceMaxDomainName (1009) bytes in length to
- * accommodate the longest legal domain name without buffer overrun.
- *
- * service: The service name - any dots or backslashes must NOT be escaped.
- * May be NULL (to construct a PTR record name, e.g.
- * "_ftp._tcp.apple.com.").
- *
- * regtype: The service type followed by the protocol, separated by a dot
- * (e.g. "_ftp._tcp").
- *
- * domain: The domain name, e.g. "apple.com.". Literal dots or backslashes,
- * if any, must be escaped, e.g. "1st\. Floor.apple.com."
- *
- * return value: Returns kDNSServiceErr_NoError (0) on success, kDNSServiceErr_BadParam on error.
- *
- */
-
-DNSServiceErrorType DNSSD_API DNSServiceConstructFullName
-(
- char * const fullName,
- const char * const service, /* may be NULL */
- const char * const regtype,
- const char * const domain
-);
-
-
-/*********************************************************************************************
-*
-* TXT Record Construction Functions
-*
-*********************************************************************************************/
-
-/*
- * A typical calling sequence for TXT record construction is something like:
- *
- * Client allocates storage for TXTRecord data (e.g. declare buffer on the stack)
- * TXTRecordCreate();
- * TXTRecordSetValue();
- * TXTRecordSetValue();
- * TXTRecordSetValue();
- * ...
- * DNSServiceRegister( ... TXTRecordGetLength(), TXTRecordGetBytesPtr() ... );
- * TXTRecordDeallocate();
- * Explicitly deallocate storage for TXTRecord data (if not allocated on the stack)
- */
-
-
-/* TXTRecordRef
- *
- * Opaque internal data type.
- * Note: Represents a DNS-SD TXT record.
- */
-
-typedef union _TXTRecordRef_t { char PrivateData[16]; char *ForceNaturalAlignment; } TXTRecordRef;
-
-
-/* TXTRecordCreate()
- *
- * Creates a new empty TXTRecordRef referencing the specified storage.
- *
- * If the buffer parameter is NULL, or the specified storage size is not
- * large enough to hold a key subsequently added using TXTRecordSetValue(),
- * then additional memory will be added as needed using malloc().
- *
- * On some platforms, when memory is low, malloc() may fail. In this
- * case, TXTRecordSetValue() will return kDNSServiceErr_NoMemory, and this
- * error condition will need to be handled as appropriate by the caller.
- *
- * You can avoid the need to handle this error condition if you ensure
- * that the storage you initially provide is large enough to hold all
- * the key/value pairs that are to be added to the record.
- * The caller can precompute the exact length required for all of the
- * key/value pairs to be added, or simply provide a fixed-sized buffer
- * known in advance to be large enough.
- * A no-value (key-only) key requires (1 + key length) bytes.
- * A key with empty value requires (1 + key length + 1) bytes.
- * A key with non-empty value requires (1 + key length + 1 + value length).
- * For most applications, DNS-SD TXT records are generally
- * less than 100 bytes, so in most cases a simple fixed-sized
- * 256-byte buffer will be more than sufficient.
- * Recommended size limits for DNS-SD TXT Records are discussed in
- * <http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt>
- *
- * Note: When passing parameters to and from these TXT record APIs,
- * the key name does not include the '=' character. The '=' character
- * is the separator between the key and value in the on-the-wire
- * packet format; it is not part of either the key or the value.
- *
- * txtRecord: A pointer to an uninitialized TXTRecordRef.
- *
- * bufferLen: The size of the storage provided in the "buffer" parameter.
- *
- * buffer: Optional caller-supplied storage used to hold the TXTRecord data.
- * This storage must remain valid for as long as
- * the TXTRecordRef.
- */
-
-void DNSSD_API TXTRecordCreate
-(
- TXTRecordRef *txtRecord,
- uint16_t bufferLen,
- void *buffer
-);
-
-
-/* TXTRecordDeallocate()
- *
- * Releases any resources allocated in the course of preparing a TXT Record
- * using TXTRecordCreate()/TXTRecordSetValue()/TXTRecordRemoveValue().
- * Ownership of the buffer provided in TXTRecordCreate() returns to the client.
- *
- * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate().
- *
- */
-
-void DNSSD_API TXTRecordDeallocate
-(
- TXTRecordRef *txtRecord
-);
-
-
-/* TXTRecordSetValue()
- *
- * Adds a key (optionally with value) to a TXTRecordRef. If the "key" already
- * exists in the TXTRecordRef, then the current value will be replaced with
- * the new value.
- * Keys may exist in four states with respect to a given TXT record:
- * - Absent (key does not appear at all)
- * - Present with no value ("key" appears alone)
- * - Present with empty value ("key=" appears in TXT record)
- * - Present with non-empty value ("key=value" appears in TXT record)
- * For more details refer to "Data Syntax for DNS-SD TXT Records" in
- * <http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt>
- *
- * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate().
- *
- * key: A null-terminated string which only contains printable ASCII
- * values (0x20-0x7E), excluding '=' (0x3D). Keys should be
- * 9 characters or fewer (not counting the terminating null).
- *
- * valueSize: The size of the value.
- *
- * value: Any binary value. For values that represent
- * textual data, UTF-8 is STRONGLY recommended.
- * For values that represent textual data, valueSize
- * should NOT include the terminating null (if any)
- * at the end of the string.
- * If NULL, then "key" will be added with no value.
- * If non-NULL but valueSize is zero, then "key=" will be
- * added with empty value.
- *
- * return value: Returns kDNSServiceErr_NoError on success.
- * Returns kDNSServiceErr_Invalid if the "key" string contains
- * illegal characters.
- * Returns kDNSServiceErr_NoMemory if adding this key would
- * exceed the available storage.
- */
-
-DNSServiceErrorType DNSSD_API TXTRecordSetValue
-(
- TXTRecordRef *txtRecord,
- const char *key,
- uint8_t valueSize, /* may be zero */
- const void *value /* may be NULL */
-);
-
-
-/* TXTRecordRemoveValue()
- *
- * Removes a key from a TXTRecordRef. The "key" must be an
- * ASCII string which exists in the TXTRecordRef.
- *
- * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate().
- *
- * key: A key name which exists in the TXTRecordRef.
- *
- * return value: Returns kDNSServiceErr_NoError on success.
- * Returns kDNSServiceErr_NoSuchKey if the "key" does not
- * exist in the TXTRecordRef.
- */
-
-DNSServiceErrorType DNSSD_API TXTRecordRemoveValue
-(
- TXTRecordRef *txtRecord,
- const char *key
-);
-
-
-/* TXTRecordGetLength()
- *
- * Allows you to determine the length of the raw bytes within a TXTRecordRef.
- *
- * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate().
- *
- * return value: Returns the size of the raw bytes inside a TXTRecordRef
- * which you can pass directly to DNSServiceRegister() or
- * to DNSServiceUpdateRecord().
- * Returns 0 if the TXTRecordRef is empty.
- */
-
-uint16_t DNSSD_API TXTRecordGetLength
-(
- const TXTRecordRef *txtRecord
-);
-
-
-/* TXTRecordGetBytesPtr()
- *
- * Allows you to retrieve a pointer to the raw bytes within a TXTRecordRef.
- *
- * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate().
- *
- * return value: Returns a pointer to the raw bytes inside the TXTRecordRef
- * which you can pass directly to DNSServiceRegister() or
- * to DNSServiceUpdateRecord().
- */
-
-const void * DNSSD_API TXTRecordGetBytesPtr
-(
- const TXTRecordRef *txtRecord
-);
-
-
-/*********************************************************************************************
-*
-* TXT Record Parsing Functions
-*
-*********************************************************************************************/
-
-/*
- * A typical calling sequence for TXT record parsing is something like:
- *
- * Receive TXT record data in DNSServiceResolve() callback
- * if (TXTRecordContainsKey(txtLen, txtRecord, "key")) then do something
- * val1ptr = TXTRecordGetValuePtr(txtLen, txtRecord, "key1", &len1);
- * val2ptr = TXTRecordGetValuePtr(txtLen, txtRecord, "key2", &len2);
- * ...
- * memcpy(myval1, val1ptr, len1);
- * memcpy(myval2, val2ptr, len2);
- * ...
- * return;
- *
- * If you wish to retain the values after return from the DNSServiceResolve()
- * callback, then you need to copy the data to your own storage using memcpy()
- * or similar, as shown in the example above.
- *
- * If for some reason you need to parse a TXT record you built yourself
- * using the TXT record construction functions above, then you can do
- * that using TXTRecordGetLength and TXTRecordGetBytesPtr calls:
- * TXTRecordGetValue(TXTRecordGetLength(x), TXTRecordGetBytesPtr(x), key, &len);
- *
- * Most applications only fetch keys they know about from a TXT record and
- * ignore the rest.
- * However, some debugging tools wish to fetch and display all keys.
- * To do that, use the TXTRecordGetCount() and TXTRecordGetItemAtIndex() calls.
- */
-
-/* TXTRecordContainsKey()
- *
- * Allows you to determine if a given TXT Record contains a specified key.
- *
- * txtLen: The size of the received TXT Record.
- *
- * txtRecord: Pointer to the received TXT Record bytes.
- *
- * key: A null-terminated ASCII string containing the key name.
- *
- * return value: Returns 1 if the TXT Record contains the specified key.
- * Otherwise, it returns 0.
- */
-
-int DNSSD_API TXTRecordContainsKey
-(
- uint16_t txtLen,
- const void *txtRecord,
- const char *key
-);
-
-
-/* TXTRecordGetValuePtr()
- *
- * Allows you to retrieve the value for a given key from a TXT Record.
- *
- * txtLen: The size of the received TXT Record
- *
- * txtRecord: Pointer to the received TXT Record bytes.
- *
- * key: A null-terminated ASCII string containing the key name.
- *
- * valueLen: On output, will be set to the size of the "value" data.
- *
- * return value: Returns NULL if the key does not exist in this TXT record,
- * or exists with no value (to differentiate between
- * these two cases use TXTRecordContainsKey()).
- * Returns pointer to location within TXT Record bytes
- * if the key exists with empty or non-empty value.
- * For empty value, valueLen will be zero.
- * For non-empty value, valueLen will be length of value data.
- */
-
-const void * DNSSD_API TXTRecordGetValuePtr
-(
- uint16_t txtLen,
- const void *txtRecord,
- const char *key,
- uint8_t *valueLen
-);
-
-
-/* TXTRecordGetCount()
- *
- * Returns the number of keys stored in the TXT Record. The count
- * can be used with TXTRecordGetItemAtIndex() to iterate through the keys.
- *
- * txtLen: The size of the received TXT Record.
- *
- * txtRecord: Pointer to the received TXT Record bytes.
- *
- * return value: Returns the total number of keys in the TXT Record.
- *
- */
-
-uint16_t DNSSD_API TXTRecordGetCount
-(
- uint16_t txtLen,
- const void *txtRecord
-);
-
-
-/* TXTRecordGetItemAtIndex()
- *
- * Allows you to retrieve a key name and value pointer, given an index into
- * a TXT Record. Legal index values range from zero to TXTRecordGetCount()-1.
- * It's also possible to iterate through keys in a TXT record by simply
- * calling TXTRecordGetItemAtIndex() repeatedly, beginning with index zero
- * and increasing until TXTRecordGetItemAtIndex() returns kDNSServiceErr_Invalid.
- *
- * On return:
- * For keys with no value, *value is set to NULL and *valueLen is zero.
- * For keys with empty value, *value is non-NULL and *valueLen is zero.
- * For keys with non-empty value, *value is non-NULL and *valueLen is non-zero.
- *
- * txtLen: The size of the received TXT Record.
- *
- * txtRecord: Pointer to the received TXT Record bytes.
- *
- * itemIndex: An index into the TXT Record.
- *
- * keyBufLen: The size of the string buffer being supplied.
- *
- * key: A string buffer used to store the key name.
- * On return, the buffer contains a null-terminated C string
- * giving the key name. DNS-SD TXT keys are usually
- * 9 characters or fewer. To hold the maximum possible
- * key name, the buffer should be 256 bytes long.
- *
- * valueLen: On output, will be set to the size of the "value" data.
- *
- * value: On output, *value is set to point to location within TXT
- * Record bytes that holds the value data.
- *
- * return value: Returns kDNSServiceErr_NoError on success.
- * Returns kDNSServiceErr_NoMemory if keyBufLen is too short.
- * Returns kDNSServiceErr_Invalid if index is greater than
- * TXTRecordGetCount()-1.
- */
-
-DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex
-(
- uint16_t txtLen,
- const void *txtRecord,
- uint16_t itemIndex,
- uint16_t keyBufLen,
- char *key,
- uint8_t *valueLen,
- const void **value
-);
-
-#if _DNS_SD_LIBDISPATCH
-/*
- * DNSServiceSetDispatchQueue
- *
- * Allows you to schedule a DNSServiceRef on a serial dispatch queue for receiving asynchronous
- * callbacks. It's the clients responsibility to ensure that the provided dispatch queue is running.
- *
- * A typical application that uses CFRunLoopRun or dispatch_main on its main thread will
- * usually schedule DNSServiceRefs on its main queue (which is always a serial queue)
- * using "DNSServiceSetDispatchQueue(sdref, dispatch_get_main_queue());"
- *
- * If there is any error during the processing of events, the application callback will
- * be called with an error code. For shared connections, each subordinate DNSServiceRef
- * will get its own error callback. Currently these error callbacks only happen
- * if the mDNSResponder daemon is manually terminated or crashes, and the error
- * code in this case is kDNSServiceErr_ServiceNotRunning. The application must call
- * DNSServiceRefDeallocate to free the DNSServiceRef when it gets such an error code.
- * These error callbacks are rare and should not normally happen on customer machines,
- * but application code should be written defensively to handle such error callbacks
- * gracefully if they occur.
- *
- * After using DNSServiceSetDispatchQueue on a DNSServiceRef, calling DNSServiceProcessResult
- * on the same DNSServiceRef will result in undefined behavior and should be avoided.
- *
- * Once the application successfully schedules a DNSServiceRef on a serial dispatch queue using
- * DNSServiceSetDispatchQueue, it cannot remove the DNSServiceRef from the dispatch queue, or use
- * DNSServiceSetDispatchQueue a second time to schedule the DNSServiceRef onto a different serial dispatch
- * queue. Once scheduled onto a dispatch queue a DNSServiceRef will deliver events to that queue until
- * the application no longer requires that operation and terminates it using DNSServiceRefDeallocate.
- *
- * service: DNSServiceRef that was allocated and returned to the application, when the
- * application calls one of the DNSService API.
- *
- * queue: dispatch queue where the application callback will be scheduled
- *
- * return value: Returns kDNSServiceErr_NoError on success.
- * Returns kDNSServiceErr_NoMemory if it cannot create a dispatch source
- * Returns kDNSServiceErr_BadParam if the service param is invalid or the
- * queue param is invalid
- */
-
-DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue
-(
- DNSServiceRef service,
- dispatch_queue_t queue
-);
-#endif //_DNS_SD_LIBDISPATCH
-
-#if !defined(_WIN32)
-typedef void (DNSSD_API *DNSServiceSleepKeepaliveReply)
-(
- DNSServiceRef sdRef,
- DNSServiceErrorType errorCode,
- void *context
-);
-DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
-(
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- int fd,
- unsigned int timeout,
- DNSServiceSleepKeepaliveReply callBack,
- void *context
-);
-#endif
-
-#ifdef APPLE_OSX_mDNSResponder
-/* DNSServiceCreateDelegateConnection()
- *
- * Create a delegate connection to the daemon allowing efficient registration of
- * multiple individual records.
- *
- * Parameters:
- *
- * sdRef: A pointer to an uninitialized DNSServiceRef. Deallocating
- * the reference (via DNSServiceRefDeallocate()) severs the
- * connection and deregisters all records registered on this connection.
- *
- * pid : Process ID of the delegate
- *
- * uuid: UUID of the delegate
- *
- * Note that only one of the two arguments (pid or uuid) can be specified. If pid
- * is zero, uuid will be assumed to be a valid value; otherwise pid will be used.
- *
- * return value: Returns kDNSServiceErr_NoError on success, otherwise returns
- * an error code indicating the specific failure that occurred (in which
- * case the DNSServiceRef is not initialized). kDNSServiceErr_NotAuth is
- * returned to indicate that the calling process does not have entitlements
- * to use this API.
- */
-DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid);
-#endif
-
-#ifdef __APPLE_API_PRIVATE
-
-#define kDNSServiceCompPrivateDNS "PrivateDNS"
-#define kDNSServiceCompMulticastDNS "MulticastDNS"
-
-#endif //__APPLE_API_PRIVATE
-
-/* Some C compiler cleverness. We can make the compiler check certain things for us,
- * and report errors at compile-time if anything is wrong. The usual way to do this would
- * be to use a run-time "if" statement or the conventional run-time "assert" mechanism, but
- * then you don't find out what's wrong until you run the software. This way, if the assertion
- * condition is false, the array size is negative, and the complier complains immediately.
- */
-
-struct CompileTimeAssertionChecks_DNS_SD
-{
- char assert0[(sizeof(union _TXTRecordRef_t) == 16) ? 1 : -1];
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _DNS_SD_H */
Copied: vendor/apple/mDNSResponder/561.1.1/mDNSShared/dns_sd.h (from rev 6984, vendor/apple/mDNSResponder/dist/mDNSShared/dns_sd.h)
===================================================================
--- vendor/apple/mDNSResponder/561.1.1/mDNSShared/dns_sd.h (rev 0)
+++ vendor/apple/mDNSResponder/561.1.1/mDNSShared/dns_sd.h 2015-03-20 01:14:52 UTC (rev 6985)
@@ -0,0 +1,2660 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2003-2013 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/*! @header DNS Service Discovery
+ *
+ * @discussion This section describes the functions, callbacks, and data structures
+ * that make up the DNS Service Discovery API.
+ *
+ * The DNS Service Discovery API is part of Bonjour, Apple's implementation
+ * of zero-configuration networking (ZEROCONF).
+ *
+ * Bonjour allows you to register a network service, such as a
+ * printer or file server, so that it can be found by name or browsed
+ * for by service type and domain. Using Bonjour, applications can
+ * discover what services are available on the network, along with
+ * all the information -- such as name, IP address, and port --
+ * necessary to access a particular service.
+ *
+ * In effect, Bonjour combines the functions of a local DNS server and
+ * AppleTalk. Bonjour allows applications to provide user-friendly printer
+ * and server browsing, among other things, over standard IP networks.
+ * This behavior is a result of combining protocols such as multicast and
+ * DNS to add new functionality to the network (such as multicast DNS).
+ *
+ * Bonjour gives applications easy access to services over local IP
+ * networks without requiring the service or the application to support
+ * an AppleTalk or a Netbeui stack, and without requiring a DNS server
+ * for the local network.
+ */
+
+/* _DNS_SD_H contains the API version number for this header file
+ * The API version defined in this header file symbol allows for compile-time
+ * checking, so that C code building with earlier versions of the header file
+ * can avoid compile errors trying to use functions that aren't even defined
+ * in those earlier versions. Similar checks may also be performed at run-time:
+ * => weak linking -- to avoid link failures if run with an earlier
+ * version of the library that's missing some desired symbol, or
+ * => DNSServiceGetProperty(DaemonVersion) -- to verify whether the running daemon
+ * ("system service" on Windows) meets some required minimum functionality level.
+ */
+
+#ifndef _DNS_SD_H
+#define _DNS_SD_H 5610101
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Set to 1 if libdispatch is supported
+ * Note: May also be set by project and/or Makefile
+ */
+#ifndef _DNS_SD_LIBDISPATCH
+#define _DNS_SD_LIBDISPATCH 0
+#endif /* ndef _DNS_SD_LIBDISPATCH */
+
+/* standard calling convention under Win32 is __stdcall */
+/* Note: When compiling Intel EFI (Extensible Firmware Interface) under MS Visual Studio, the */
+/* _WIN32 symbol is defined by the compiler even though it's NOT compiling code for Windows32 */
+#if defined(_WIN32) && !defined(EFI32) && !defined(EFI64)
+#define DNSSD_API __stdcall
+#else
+#define DNSSD_API
+#endif
+
+/* stdint.h does not exist on FreeBSD 4.x; its types are defined in sys/types.h instead */
+#if defined(__FreeBSD__) && (__FreeBSD__ < 5)
+#include <sys/types.h>
+
+/* Likewise, on Sun, standard integer types are in sys/types.h */
+#elif defined(__sun__)
+#include <sys/types.h>
+
+/* EFI does not have stdint.h, or anything else equivalent */
+#elif defined(EFI32) || defined(EFI64) || defined(EFIX64)
+#include "Tiano.h"
+#if !defined(_STDINT_H_)
+typedef UINT8 uint8_t;
+typedef INT8 int8_t;
+typedef UINT16 uint16_t;
+typedef INT16 int16_t;
+typedef UINT32 uint32_t;
+typedef INT32 int32_t;
+#endif
+/* Windows has its own differences */
+#elif defined(_WIN32)
+#include <windows.h>
+#define _UNUSED
+#ifndef _MSL_STDINT_H
+typedef UINT8 uint8_t;
+typedef INT8 int8_t;
+typedef UINT16 uint16_t;
+typedef INT16 int16_t;
+typedef UINT32 uint32_t;
+typedef INT32 int32_t;
+#endif
+
+/* All other Posix platforms use stdint.h */
+#else
+#include <stdint.h>
+#endif
+
+#if _DNS_SD_LIBDISPATCH
+#include <dispatch/dispatch.h>
+#endif
+
+/* DNSServiceRef, DNSRecordRef
+ *
+ * Opaque internal data types.
+ * Note: client is responsible for serializing access to these structures if
+ * they are shared between concurrent threads.
+ */
+
+typedef struct _DNSServiceRef_t *DNSServiceRef;
+typedef struct _DNSRecordRef_t *DNSRecordRef;
+
+struct sockaddr;
+
+/*! @enum General flags
+ * Most DNS-SD API functions and callbacks include a DNSServiceFlags parameter.
+ * As a general rule, any given bit in the 32-bit flags field has a specific fixed meaning,
+ * regardless of the function or callback being used. For any given function or callback,
+ * typically only a subset of the possible flags are meaningful, and all others should be zero.
+ * The discussion section for each API call describes which flags are valid for that call
+ * and callback. In some cases, for a particular call, it may be that no flags are currently
+ * defined, in which case the DNSServiceFlags parameter exists purely to allow future expansion.
+ * In all cases, developers should expect that in future releases, it is possible that new flag
+ * values will be defined, and write code with this in mind. For example, code that tests
+ * if (flags == kDNSServiceFlagsAdd) ...
+ * will fail if, in a future release, another bit in the 32-bit flags field is also set.
+ * The reliable way to test whether a particular bit is set is not with an equality test,
+ * but with a bitwise mask:
+ * if (flags & kDNSServiceFlagsAdd) ...
+ * With the exception of kDNSServiceFlagsValidate, each flag can be valid(be set)
+ * EITHER only as an input to one of the DNSService*() APIs OR only as an output
+ * (provide status) through any of the callbacks used. For example, kDNSServiceFlagsAdd
+ * can be set only as an output in the callback, whereas the kDNSServiceFlagsIncludeP2P
+ * can be set only as an input to the DNSService*() APIs. See comments on kDNSServiceFlagsValidate
+ * defined in enum below.
+ */
+enum
+{
+ kDNSServiceFlagsMoreComing = 0x1,
+ /* MoreComing indicates to a callback that at least one more result is
+ * queued and will be delivered following immediately after this one.
+ * When the MoreComing flag is set, applications should not immediately
+ * update their UI, because this can result in a great deal of ugly flickering
+ * on the screen, and can waste a great deal of CPU time repeatedly updating
+ * the screen with content that is then immediately erased, over and over.
+ * Applications should wait until MoreComing is not set, and then
+ * update their UI when no more changes are imminent.
+ * When MoreComing is not set, that doesn't mean there will be no more
+ * answers EVER, just that there are no more answers immediately
+ * available right now at this instant. If more answers become available
+ * in the future they will be delivered as usual.
+ */
+
+ kDNSServiceFlagsAdd = 0x2,
+ kDNSServiceFlagsDefault = 0x4,
+ /* Flags for domain enumeration and browse/query reply callbacks.
+ * "Default" applies only to enumeration and is only valid in
+ * conjunction with "Add". An enumeration callback with the "Add"
+ * flag NOT set indicates a "Remove", i.e. the domain is no longer
+ * valid.
+ */
+
+ kDNSServiceFlagsNoAutoRename = 0x8,
+ /* Flag for specifying renaming behavior on name conflict when registering
+ * non-shared records. By default, name conflicts are automatically handled
+ * by renaming the service. NoAutoRename overrides this behavior - with this
+ * flag set, name conflicts will result in a callback. The NoAutorename flag
+ * is only valid if a name is explicitly specified when registering a service
+ * (i.e. the default name is not used.)
+ */
+
+ kDNSServiceFlagsShared = 0x10,
+ kDNSServiceFlagsUnique = 0x20,
+ /* Flag for registering individual records on a connected
+ * DNSServiceRef. Shared indicates that there may be multiple records
+ * with this name on the network (e.g. PTR records). Unique indicates that the
+ * record's name is to be unique on the network (e.g. SRV records).
+ */
+
+ kDNSServiceFlagsBrowseDomains = 0x40,
+ kDNSServiceFlagsRegistrationDomains = 0x80,
+ /* Flags for specifying domain enumeration type in DNSServiceEnumerateDomains.
+ * BrowseDomains enumerates domains recommended for browsing, RegistrationDomains
+ * enumerates domains recommended for registration.
+ */
+
+ kDNSServiceFlagsLongLivedQuery = 0x100,
+ /* Flag for creating a long-lived unicast query for the DNSServiceQueryRecord call. */
+
+ kDNSServiceFlagsAllowRemoteQuery = 0x200,
+ /* Flag for creating a record for which we will answer remote queries
+ * (queries from hosts more than one hop away; hosts not directly connected to the local link).
+ */
+
+ kDNSServiceFlagsForceMulticast = 0x400,
+ /* Flag for signifying that a query or registration should be performed exclusively via multicast
+ * DNS, even for a name in a domain (e.g. foo.apple.com.) that would normally imply unicast DNS.
+ */
+
+ kDNSServiceFlagsForce = 0x800, // This flag is deprecated.
+
+ kDNSServiceFlagsKnownUnique = 0x800,
+ /*
+ * Client guarantees that record names are unique, so we can skip sending out initial
+ * probe messages. Standard name conflict resolution is still done if a conflict is discovered.
+ * Currently only valid for a DNSServiceRegister call.
+ */
+
+ kDNSServiceFlagsReturnIntermediates = 0x1000,
+ /* Flag for returning intermediate results.
+ * For example, if a query results in an authoritative NXDomain (name does not exist)
+ * then that result is returned to the client. However the query is not implicitly
+ * cancelled -- it remains active and if the answer subsequently changes
+ * (e.g. because a VPN tunnel is subsequently established) then that positive
+ * result will still be returned to the client.
+ * Similarly, if a query results in a CNAME record, then in addition to following
+ * the CNAME referral, the intermediate CNAME result is also returned to the client.
+ * When this flag is not set, NXDomain errors are not returned, and CNAME records
+ * are followed silently without informing the client of the intermediate steps.
+ * (In earlier builds this flag was briefly calledkDNSServiceFlagsReturnCNAME)
+ */
+
+ kDNSServiceFlagsNonBrowsable = 0x2000,
+ /* A service registered with the NonBrowsable flag set can be resolved using
+ * DNSServiceResolve(), but will not be discoverable using DNSServiceBrowse().
+ * This is for cases where the name is actually a GUID; it is found by other means;
+ * there is no end-user benefit to browsing to find a long list of opaque GUIDs.
+ * Using the NonBrowsable flag creates SRV+TXT without the cost of also advertising
+ * an associated PTR record.
+ */
+
+ kDNSServiceFlagsShareConnection = 0x4000,
+ /* For efficiency, clients that perform many concurrent operations may want to use a
+ * single Unix Domain Socket connection with the background daemon, instead of having a
+ * separate connection for each independent operation. To use this mode, clients first
+ * call DNSServiceCreateConnection(&MainRef) to initialize the main DNSServiceRef.
+ * For each subsequent operation that is to share that same connection, the client copies
+ * the MainRef, and then passes the address of that copy, setting the ShareConnection flag
+ * to tell the library that this DNSServiceRef is not a typical uninitialized DNSServiceRef;
+ * it's a copy of an existing DNSServiceRef whose connection information should be reused.
+ *
+ * For example:
+ *
+ * DNSServiceErrorType error;
+ * DNSServiceRef MainRef;
+ * error = DNSServiceCreateConnection(&MainRef);
+ * if (error) ...
+ * DNSServiceRef BrowseRef = MainRef; // Important: COPY the primary DNSServiceRef first...
+ * error = DNSServiceBrowse(&BrowseRef, kDNSServiceFlagsShareConnection, ...); // then use the copy
+ * if (error) ...
+ * ...
+ * DNSServiceRefDeallocate(BrowseRef); // Terminate the browse operation
+ * DNSServiceRefDeallocate(MainRef); // Terminate the shared connection
+ * Also see Point 4.(Don't Double-Deallocate if the MainRef has been Deallocated) in Notes below:
+ *
+ * Notes:
+ *
+ * 1. Collective kDNSServiceFlagsMoreComing flag
+ * When callbacks are invoked using a shared DNSServiceRef, the
+ * kDNSServiceFlagsMoreComing flag applies collectively to *all* active
+ * operations sharing the same parent DNSServiceRef. If the MoreComing flag is
+ * set it means that there are more results queued on this parent DNSServiceRef,
+ * but not necessarily more results for this particular callback function.
+ * The implication of this for client programmers is that when a callback
+ * is invoked with the MoreComing flag set, the code should update its
+ * internal data structures with the new result, and set a variable indicating
+ * that its UI needs to be updated. Then, later when a callback is eventually
+ * invoked with the MoreComing flag not set, the code should update *all*
+ * stale UI elements related to that shared parent DNSServiceRef that need
+ * updating, not just the UI elements related to the particular callback
+ * that happened to be the last one to be invoked.
+ *
+ * 2. Canceling operations and kDNSServiceFlagsMoreComing
+ * Whenever you cancel any operation for which you had deferred UI updates
+ * waiting because of a kDNSServiceFlagsMoreComing flag, you should perform
+ * those deferred UI updates. This is because, after cancelling the operation,
+ * you can no longer wait for a callback *without* MoreComing set, to tell
+ * you do perform your deferred UI updates (the operation has been canceled,
+ * so there will be no more callbacks). An implication of the collective
+ * kDNSServiceFlagsMoreComing flag for shared connections is that this
+ * guideline applies more broadly -- any time you cancel an operation on
+ * a shared connection, you should perform all deferred UI updates for all
+ * operations sharing that connection. This is because the MoreComing flag
+ * might have been referring to events coming for the operation you canceled,
+ * which will now not be coming because the operation has been canceled.
+ *
+ * 3. Only share DNSServiceRef's created with DNSServiceCreateConnection
+ * Calling DNSServiceCreateConnection(&ref) creates a special shareable DNSServiceRef.
+ * DNSServiceRef's created by other calls like DNSServiceBrowse() or DNSServiceResolve()
+ * cannot be shared by copying them and using kDNSServiceFlagsShareConnection.
+ *
+ * 4. Don't Double-Deallocate if the MainRef has been Deallocated
+ * Calling DNSServiceRefDeallocate(ref) for a particular operation's DNSServiceRef terminates
+ * just that operation. Calling DNSServiceRefDeallocate(ref) for the main shared DNSServiceRef
+ * (the parent DNSServiceRef, originally created by DNSServiceCreateConnection(&ref))
+ * automatically terminates the shared connection and all operations that were still using it.
+ * After doing this, DO NOT then attempt to deallocate any remaining subordinate DNSServiceRef's.
+ * The memory used by those subordinate DNSServiceRef's has already been freed, so any attempt
+ * to do a DNSServiceRefDeallocate (or any other operation) on them will result in accesses
+ * to freed memory, leading to crashes or other equally undesirable results.
+ *
+ * 5. Thread Safety
+ * The dns_sd.h API does not presuppose any particular threading model, and consequently
+ * does no locking of its own (which would require linking some specific threading library).
+ * If client code calls API routines on the same DNSServiceRef concurrently
+ * from multiple threads, it is the client's responsibility to use a mutext
+ * lock or take similar appropriate precautions to serialize those calls.
+ */
+
+ kDNSServiceFlagsSuppressUnusable = 0x8000,
+ /*
+ * This flag is meaningful only in DNSServiceQueryRecord which suppresses unusable queries on the
+ * wire. If "hostname" is a wide-area unicast DNS hostname (i.e. not a ".local." name)
+ * but this host has no routable IPv6 address, then the call will not try to look up IPv6 addresses
+ * for "hostname", since any addresses it found would be unlikely to be of any use anyway. Similarly,
+ * if this host has no routable IPv4 address, the call will not try to look up IPv4 addresses for
+ * "hostname".
+ */
+
+ kDNSServiceFlagsTimeout = 0x10000,
+ /*
+ * When kDNServiceFlagsTimeout is passed to DNSServiceQueryRecord or DNSServiceGetAddrInfo, the query is
+ * stopped after a certain number of seconds have elapsed. The time at which the query will be stopped
+ * is determined by the system and cannot be configured by the user. The query will be stopped irrespective
+ * of whether a response was given earlier or not. When the query is stopped, the callback will be called
+ * with an error code of kDNSServiceErr_Timeout and a NULL sockaddr will be returned for DNSServiceGetAddrInfo
+ * and zero length rdata will be returned for DNSServiceQueryRecord.
+ */
+
+ kDNSServiceFlagsIncludeP2P = 0x20000,
+ /*
+ * Include P2P interfaces when kDNSServiceInterfaceIndexAny is specified.
+ * By default, specifying kDNSServiceInterfaceIndexAny does not include P2P interfaces.
+ */
+
+ kDNSServiceFlagsWakeOnResolve = 0x40000,
+ /*
+ * This flag is meaningful only in DNSServiceResolve. When set, it tries to send a magic packet
+ * to wake up the client.
+ */
+
+ kDNSServiceFlagsBackgroundTrafficClass = 0x80000,
+ /*
+ * This flag is meaningful for Unicast DNS queries. When set, it uses the background traffic
+ * class for packets that service the request.
+ */
+
+ kDNSServiceFlagsIncludeAWDL = 0x100000,
+ /*
+ * Include AWDL interface when kDNSServiceInterfaceIndexAny is specified.
+ */
+
+ kDNSServiceFlagsValidate = 0x200000,
+ /*
+ * This flag is meaningful in DNSServiceGetAddrInfo and DNSServiceQueryRecord. This is the ONLY flag to be valid
+ * as an input to the APIs and also an output through the callbacks in the APIs.
+ *
+ * When this flag is passed to DNSServiceQueryRecord and DNSServiceGetAddrInfo to resolve unicast names,
+ * the response will be validated using DNSSEC. The validation results are delivered using the flags field in
+ * the callback and kDNSServiceFlagsValidate is marked in the flags to indicate that DNSSEC status is also available.
+ * When the callback is called to deliver the query results, the validation results may or may not be available.
+ * If it is not delivered along with the results, the validation status is delivered when the validation completes.
+ *
+ * When the validation results are delivered in the callback, it is indicated by marking the flags with
+ * kDNSServiceFlagsValidate and kDNSServiceFlagsAdd along with the DNSSEC status flags (described below) and a NULL
+ * sockaddr will be returned for DNSServiceGetAddrInfo and zero length rdata will be returned for DNSServiceQueryRecord.
+ * DNSSEC validation results are for the whole RRSet and not just individual records delivered in the callback. When
+ * kDNSServiceFlagsAdd is not set in the flags, applications should implicitly assume that the DNSSEC status of the
+ * RRSet that has been delivered up until that point is not valid anymore, till another callback is called with
+ * kDNSServiceFlagsAdd and kDNSServiceFlagsValidate.
+ *
+ * The following four flags indicate the status of the DNSSEC validation and marked in the flags field of the callback.
+ * When any of the four flags is set, kDNSServiceFlagsValidate will also be set. To check the validation status, the
+ * other applicable output flags should be masked. See kDNSServiceOutputFlags below.
+ */
+
+ kDNSServiceFlagsSecure = 0x200010,
+ /*
+ * The response has been validated by verifying all the signaures in the response and was able to
+ * build a successful authentication chain starting from a known trust anchor.
+ */
+
+ kDNSServiceFlagsInsecure = 0x200020,
+ /*
+ * A chain of trust cannot be built starting from a known trust anchor to the response.
+ */
+
+ kDNSServiceFlagsBogus = 0x200040,
+ /*
+ * If the response cannot be verified to be secure due to expired signatures, missing signatures etc.,
+ * then the results are considered to be bogus.
+ */
+
+ kDNSServiceFlagsIndeterminate = 0x200080,
+ /*
+ * There is no valid trust anchor that can be used to determine whether a response is secure or not.
+ */
+
+ kDNSServiceFlagsUnicastResponse = 0x400000,
+ /*
+ * Request unicast response to query.
+ */
+ kDNSServiceFlagsValidateOptional = 0x800000,
+
+ /*
+ * This flag is identical to kDNSServiceFlagsValidate except for the case where the response
+ * cannot be validated. If this flag is set in DNSServiceQueryRecord or DNSServiceGetAddrInfo,
+ * the DNSSEC records will be requested for validation. If they cannot be received for some reason
+ * during the validation (e.g., zone is not signed, zone is signed but cannot be traced back to
+ * root, recursive server does not understand DNSSEC etc.), then this will fallback to the default
+ * behavior where the validation will not be performed and no DNSSEC results will be provided.
+ *
+ * If the zone is signed and there is a valid path to a known trust anchor configured in the system
+ * and the application requires DNSSEC validation irrespective of the DNSSEC awareness in the current
+ * network, then this option MUST not be used. This is only intended to be used during the transition
+ * period where the different nodes participating in the DNS resolution may not understand DNSSEC or
+ * managed properly (e.g. missing DS record) but still want to be able to resolve DNS successfully.
+ */
+
+ kDNSServiceFlagsWakeOnlyService = 0x1000000,
+ /*
+ * This flag is meaningful only in DNSServiceRegister. When set, the service will not be registered
+ * with sleep proxy server during sleep.
+ */
+
+ kDNSServiceFlagsThresholdOne = 0x2000000,
+ kDNSServiceFlagsThresholdFinder = 0x4000000,
+ kDNSServiceFlagsThresholdReached = kDNSServiceFlagsThresholdOne,
+ /*
+ * kDNSServiceFlagsThresholdOne is meaningful only in DNSServiceBrowse. When set,
+ * the system will stop issuing browse queries on the network once the number
+ * of answers returned is one or more. It will issue queries on the network
+ * again if the number of answers drops to zero.
+ * This flag is for Apple internal use only. Third party developers
+ * should not rely on this behavior being supported in any given software release.
+ *
+ * kDNSServiceFlagsThresholdFinder is meaningful only in DNSServiceBrowse. When set,
+ * the system will stop issuing browse queries on the network once the number
+ * of answers has reached the threshold set for Finder.
+ * It will issue queries on the network again if the number of answers drops below
+ * this threshold.
+ * This flag is for Apple internal use only. Third party developers
+ * should not rely on this behavior being supported in any given software release.
+ *
+ * When kDNSServiceFlagsThresholdReached is set in the client callback add or remove event,
+ * it indicates that the browse answer threshold has been reached and no
+ * browse requests will be generated on the network until the number of answers falls
+ * below the threshold value. Add and remove events can still occur based
+ * on incoming Bonjour traffic observed by the system.
+ * The set of services return to the client is not guaranteed to represent the
+ * entire set of services present on the network once the threshold has been reached.
+ *
+ * Note, while kDNSServiceFlagsThresholdReached and kDNSServiceFlagsThresholdOne
+ * have the same value, there isn't a conflict because kDNSServiceFlagsThresholdReached
+ * is only set in the callbacks and kDNSServiceFlagsThresholdOne is only set on
+ * input to a DNSServiceBrowse call.
+ */
+ kDNSServiceFlagsDenyCellular = 0x8000000,
+ /*
+ * This flag is meaningful only for Unicast DNS queries. When set, the kernel will restrict
+ * DNS resolutions on the cellular interface for that request.
+ */
+
+ kDNSServiceFlagsServiceIndex = 0x10000000,
+ /*
+ * This flag is meaningful only for DNSServiceGetAddrInfo() for Unicast DNS queries.
+ * When set, DNSServiceGetAddrInfo() will interpret the "interfaceIndex" argument of the call
+ * as the "serviceIndex".
+ */
+
+ kDNSServiceFlagsDenyExpensive = 0x20000000
+ /*
+ * This flag is meaningful only for Unicast DNS queries. When set, the kernel will restrict
+ * DNS resolutions on interfaces defined as expensive for that request.
+ */
+
+};
+
+#define kDNSServiceOutputFlags (kDNSServiceFlagsValidate | kDNSServiceFlagsValidateOptional | kDNSServiceFlagsMoreComing | kDNSServiceFlagsAdd | kDNSServiceFlagsDefault)
+ /* All the output flags excluding the DNSSEC Status flags. Typically used to check DNSSEC Status */
+
+/* Possible protocol values */
+enum
+{
+ /* for DNSServiceGetAddrInfo() */
+ kDNSServiceProtocol_IPv4 = 0x01,
+ kDNSServiceProtocol_IPv6 = 0x02,
+ /* 0x04 and 0x08 reserved for future internetwork protocols */
+
+ /* for DNSServiceNATPortMappingCreate() */
+ kDNSServiceProtocol_UDP = 0x10,
+ kDNSServiceProtocol_TCP = 0x20
+ /* 0x40 and 0x80 reserved for future transport protocols, e.g. SCTP [RFC 2960]
+ * or DCCP [RFC 4340]. If future NAT gateways are created that support port
+ * mappings for these protocols, new constants will be defined here.
+ */
+};
+
+/*
+ * The values for DNS Classes and Types are listed in RFC 1035, and are available
+ * on every OS in its DNS header file. Unfortunately every OS does not have the
+ * same header file containing DNS Class and Type constants, and the names of
+ * the constants are not consistent. For example, BIND 8 uses "T_A",
+ * BIND 9 uses "ns_t_a", Windows uses "DNS_TYPE_A", etc.
+ * For this reason, these constants are also listed here, so that code using
+ * the DNS-SD programming APIs can use these constants, so that the same code
+ * can compile on all our supported platforms.
+ */
+
+enum
+{
+ kDNSServiceClass_IN = 1 /* Internet */
+};
+
+enum
+{
+ kDNSServiceType_A = 1, /* Host address. */
+ kDNSServiceType_NS = 2, /* Authoritative server. */
+ kDNSServiceType_MD = 3, /* Mail destination. */
+ kDNSServiceType_MF = 4, /* Mail forwarder. */
+ kDNSServiceType_CNAME = 5, /* Canonical name. */
+ kDNSServiceType_SOA = 6, /* Start of authority zone. */
+ kDNSServiceType_MB = 7, /* Mailbox domain name. */
+ kDNSServiceType_MG = 8, /* Mail group member. */
+ kDNSServiceType_MR = 9, /* Mail rename name. */
+ kDNSServiceType_NULL = 10, /* Null resource record. */
+ kDNSServiceType_WKS = 11, /* Well known service. */
+ kDNSServiceType_PTR = 12, /* Domain name pointer. */
+ kDNSServiceType_HINFO = 13, /* Host information. */
+ kDNSServiceType_MINFO = 14, /* Mailbox information. */
+ kDNSServiceType_MX = 15, /* Mail routing information. */
+ kDNSServiceType_TXT = 16, /* One or more text strings (NOT "zero or more..."). */
+ kDNSServiceType_RP = 17, /* Responsible person. */
+ kDNSServiceType_AFSDB = 18, /* AFS cell database. */
+ kDNSServiceType_X25 = 19, /* X_25 calling address. */
+ kDNSServiceType_ISDN = 20, /* ISDN calling address. */
+ kDNSServiceType_RT = 21, /* Router. */
+ kDNSServiceType_NSAP = 22, /* NSAP address. */
+ kDNSServiceType_NSAP_PTR = 23, /* Reverse NSAP lookup (deprecated). */
+ kDNSServiceType_SIG = 24, /* Security signature. */
+ kDNSServiceType_KEY = 25, /* Security key. */
+ kDNSServiceType_PX = 26, /* X.400 mail mapping. */
+ kDNSServiceType_GPOS = 27, /* Geographical position (withdrawn). */
+ kDNSServiceType_AAAA = 28, /* IPv6 Address. */
+ kDNSServiceType_LOC = 29, /* Location Information. */
+ kDNSServiceType_NXT = 30, /* Next domain (security). */
+ kDNSServiceType_EID = 31, /* Endpoint identifier. */
+ kDNSServiceType_NIMLOC = 32, /* Nimrod Locator. */
+ kDNSServiceType_SRV = 33, /* Server Selection. */
+ kDNSServiceType_ATMA = 34, /* ATM Address */
+ kDNSServiceType_NAPTR = 35, /* Naming Authority PoinTeR */
+ kDNSServiceType_KX = 36, /* Key Exchange */
+ kDNSServiceType_CERT = 37, /* Certification record */
+ kDNSServiceType_A6 = 38, /* IPv6 Address (deprecated) */
+ kDNSServiceType_DNAME = 39, /* Non-terminal DNAME (for IPv6) */
+ kDNSServiceType_SINK = 40, /* Kitchen sink (experimental) */
+ kDNSServiceType_OPT = 41, /* EDNS0 option (meta-RR) */
+ kDNSServiceType_APL = 42, /* Address Prefix List */
+ kDNSServiceType_DS = 43, /* Delegation Signer */
+ kDNSServiceType_SSHFP = 44, /* SSH Key Fingerprint */
+ kDNSServiceType_IPSECKEY = 45, /* IPSECKEY */
+ kDNSServiceType_RRSIG = 46, /* RRSIG */
+ kDNSServiceType_NSEC = 47, /* Denial of Existence */
+ kDNSServiceType_DNSKEY = 48, /* DNSKEY */
+ kDNSServiceType_DHCID = 49, /* DHCP Client Identifier */
+ kDNSServiceType_NSEC3 = 50, /* Hashed Authenticated Denial of Existence */
+ kDNSServiceType_NSEC3PARAM = 51, /* Hashed Authenticated Denial of Existence */
+
+ kDNSServiceType_HIP = 55, /* Host Identity Protocol */
+
+ kDNSServiceType_SPF = 99, /* Sender Policy Framework for E-Mail */
+ kDNSServiceType_UINFO = 100, /* IANA-Reserved */
+ kDNSServiceType_UID = 101, /* IANA-Reserved */
+ kDNSServiceType_GID = 102, /* IANA-Reserved */
+ kDNSServiceType_UNSPEC = 103, /* IANA-Reserved */
+
+ kDNSServiceType_TKEY = 249, /* Transaction key */
+ kDNSServiceType_TSIG = 250, /* Transaction signature. */
+ kDNSServiceType_IXFR = 251, /* Incremental zone transfer. */
+ kDNSServiceType_AXFR = 252, /* Transfer zone of authority. */
+ kDNSServiceType_MAILB = 253, /* Transfer mailbox records. */
+ kDNSServiceType_MAILA = 254, /* Transfer mail agent records. */
+ kDNSServiceType_ANY = 255 /* Wildcard match. */
+};
+
+/* possible error code values */
+enum
+{
+ kDNSServiceErr_NoError = 0,
+ kDNSServiceErr_Unknown = -65537, /* 0xFFFE FFFF */
+ kDNSServiceErr_NoSuchName = -65538,
+ kDNSServiceErr_NoMemory = -65539,
+ kDNSServiceErr_BadParam = -65540,
+ kDNSServiceErr_BadReference = -65541,
+ kDNSServiceErr_BadState = -65542,
+ kDNSServiceErr_BadFlags = -65543,
+ kDNSServiceErr_Unsupported = -65544,
+ kDNSServiceErr_NotInitialized = -65545,
+ kDNSServiceErr_AlreadyRegistered = -65547,
+ kDNSServiceErr_NameConflict = -65548,
+ kDNSServiceErr_Invalid = -65549,
+ kDNSServiceErr_Firewall = -65550,
+ kDNSServiceErr_Incompatible = -65551, /* client library incompatible with daemon */
+ kDNSServiceErr_BadInterfaceIndex = -65552,
+ kDNSServiceErr_Refused = -65553,
+ kDNSServiceErr_NoSuchRecord = -65554,
+ kDNSServiceErr_NoAuth = -65555,
+ kDNSServiceErr_NoSuchKey = -65556,
+ kDNSServiceErr_NATTraversal = -65557,
+ kDNSServiceErr_DoubleNAT = -65558,
+ kDNSServiceErr_BadTime = -65559, /* Codes up to here existed in Tiger */
+ kDNSServiceErr_BadSig = -65560,
+ kDNSServiceErr_BadKey = -65561,
+ kDNSServiceErr_Transient = -65562,
+ kDNSServiceErr_ServiceNotRunning = -65563, /* Background daemon not running */
+ kDNSServiceErr_NATPortMappingUnsupported = -65564, /* NAT doesn't support PCP, NAT-PMP or UPnP */
+ kDNSServiceErr_NATPortMappingDisabled = -65565, /* NAT supports PCP, NAT-PMP or UPnP, but it's disabled by the administrator */
+ kDNSServiceErr_NoRouter = -65566, /* No router currently configured (probably no network connectivity) */
+ kDNSServiceErr_PollingMode = -65567,
+ kDNSServiceErr_Timeout = -65568
+
+ /* mDNS Error codes are in the range
+ * FFFE FF00 (-65792) to FFFE FFFF (-65537) */
+};
+
+/* Maximum length, in bytes, of a service name represented as a */
+/* literal C-String, including the terminating NULL at the end. */
+
+#define kDNSServiceMaxServiceName 64
+
+/* Maximum length, in bytes, of a domain name represented as an *escaped* C-String */
+/* including the final trailing dot, and the C-String terminating NULL at the end. */
+
+#define kDNSServiceMaxDomainName 1009
+
+/*
+ * Notes on DNS Name Escaping
+ * -- or --
+ * "Why is kDNSServiceMaxDomainName 1009, when the maximum legal domain name is 256 bytes?"
+ *
+ * All strings used in the DNS-SD APIs are UTF-8 strings. Apart from the exceptions noted below,
+ * the APIs expect the strings to be properly escaped, using the conventional DNS escaping rules:
+ *
+ * '\\' represents a single literal '\' in the name
+ * '\.' represents a single literal '.' in the name
+ * '\ddd', where ddd is a three-digit decimal value from 000 to 255,
+ * represents a single literal byte with that value.
+ * A bare unescaped '.' is a label separator, marking a boundary between domain and subdomain.
+ *
+ * The exceptions, that do not use escaping, are the routines where the full
+ * DNS name of a resource is broken, for convenience, into servicename/regtype/domain.
+ * In these routines, the "servicename" is NOT escaped. It does not need to be, since
+ * it is, by definition, just a single literal string. Any characters in that string
+ * represent exactly what they are. The "regtype" portion is, technically speaking,
+ * escaped, but since legal regtypes are only allowed to contain letters, digits,
+ * and hyphens, there is nothing to escape, so the issue is moot. The "domain"
+ * portion is also escaped, though most domains in use on the public Internet
+ * today, like regtypes, don't contain any characters that need to be escaped.
+ * As DNS-SD becomes more popular, rich-text domains for service discovery will
+ * become common, so software should be written to cope with domains with escaping.
+ *
+ * The servicename may be up to 63 bytes of UTF-8 text (not counting the C-String
+ * terminating NULL at the end). The regtype is of the form _service._tcp or
+ * _service._udp, where the "service" part is 1-15 characters, which may be
+ * letters, digits, or hyphens. The domain part of the three-part name may be
+ * any legal domain, providing that the resulting servicename+regtype+domain
+ * name does not exceed 256 bytes.
+ *
+ * For most software, these issues are transparent. When browsing, the discovered
+ * servicenames should simply be displayed as-is. When resolving, the discovered
+ * servicename/regtype/domain are simply passed unchanged to DNSServiceResolve().
+ * When a DNSServiceResolve() succeeds, the returned fullname is already in
+ * the correct format to pass to standard system DNS APIs such as res_query().
+ * For converting from servicename/regtype/domain to a single properly-escaped
+ * full DNS name, the helper function DNSServiceConstructFullName() is provided.
+ *
+ * The following (highly contrived) example illustrates the escaping process.
+ * Suppose you have an service called "Dr. Smith\Dr. Johnson", of type "_ftp._tcp"
+ * in subdomain "4th. Floor" of subdomain "Building 2" of domain "apple.com."
+ * The full (escaped) DNS name of this service's SRV record would be:
+ * Dr\.\032Smith\\Dr\.\032Johnson._ftp._tcp.4th\.\032Floor.Building\0322.apple.com.
+ */
+
+
+/*
+ * Constants for specifying an interface index
+ *
+ * Specific interface indexes are identified via a 32-bit unsigned integer returned
+ * by the if_nametoindex() family of calls.
+ *
+ * If the client passes 0 for interface index, that means "do the right thing",
+ * which (at present) means, "if the name is in an mDNS local multicast domain
+ * (e.g. 'local.', '254.169.in-addr.arpa.', '{8,9,A,B}.E.F.ip6.arpa.') then multicast
+ * on all applicable interfaces, otherwise send via unicast to the appropriate
+ * DNS server." Normally, most clients will use 0 for interface index to
+ * automatically get the default sensible behaviour.
+ *
+ * If the client passes a positive interface index, then for multicast names that
+ * indicates to do the operation only on that one interface. For unicast names the
+ * interface index is ignored unless kDNSServiceFlagsForceMulticast is also set.
+ *
+ * If the client passes kDNSServiceInterfaceIndexLocalOnly when registering
+ * a service, then that service will be found *only* by other local clients
+ * on the same machine that are browsing using kDNSServiceInterfaceIndexLocalOnly
+ * or kDNSServiceInterfaceIndexAny.
+ * If a client has a 'private' service, accessible only to other processes
+ * running on the same machine, this allows the client to advertise that service
+ * in a way such that it does not inadvertently appear in service lists on
+ * all the other machines on the network.
+ *
+ * If the client passes kDNSServiceInterfaceIndexLocalOnly when browsing
+ * then it will find *all* records registered on that same local machine.
+ * Clients explicitly wishing to discover *only* LocalOnly services can
+ * accomplish this by inspecting the interfaceIndex of each service reported
+ * to their DNSServiceBrowseReply() callback function, and discarding those
+ * where the interface index is not kDNSServiceInterfaceIndexLocalOnly.
+ *
+ * kDNSServiceInterfaceIndexP2P is meaningful only in Browse, QueryRecord, Register,
+ * and Resolve operations. It should not be used in other DNSService APIs.
+ *
+ * - If kDNSServiceInterfaceIndexP2P is passed to DNSServiceBrowse or
+ * DNSServiceQueryRecord, it restricts the operation to P2P.
+ *
+ * - If kDNSServiceInterfaceIndexP2P is passed to DNSServiceRegister, it is
+ * mapped internally to kDNSServiceInterfaceIndexAny with the kDNSServiceFlagsIncludeP2P
+ * set.
+ *
+ * - If kDNSServiceInterfaceIndexP2P is passed to DNSServiceResolve, it is
+ * mapped internally to kDNSServiceInterfaceIndexAny with the kDNSServiceFlagsIncludeP2P
+ * set, because resolving a P2P service may create and/or enable an interface whose
+ * index is not known a priori. The resolve callback will indicate the index of the
+ * interface via which the service can be accessed.
+ *
+ * If applications pass kDNSServiceInterfaceIndexAny to DNSServiceBrowse
+ * or DNSServiceQueryRecord, they must set the kDNSServiceFlagsIncludeP2P flag
+ * to include P2P. In this case, if a service instance or the record being queried
+ * is found over P2P, the resulting ADD event will indicate kDNSServiceInterfaceIndexP2P
+ * as the interface index.
+ */
+
+#define kDNSServiceInterfaceIndexAny 0
+#define kDNSServiceInterfaceIndexLocalOnly ((uint32_t)-1)
+#define kDNSServiceInterfaceIndexUnicast ((uint32_t)-2)
+#define kDNSServiceInterfaceIndexP2P ((uint32_t)-3)
+
+typedef uint32_t DNSServiceFlags;
+typedef uint32_t DNSServiceProtocol;
+typedef int32_t DNSServiceErrorType;
+
+
+/*********************************************************************************************
+*
+* Version checking
+*
+*********************************************************************************************/
+
+/* DNSServiceGetProperty() Parameters:
+ *
+ * property: The requested property.
+ * Currently the only property defined is kDNSServiceProperty_DaemonVersion.
+ *
+ * result: Place to store result.
+ * For retrieving DaemonVersion, this should be the address of a uint32_t.
+ *
+ * size: Pointer to uint32_t containing size of the result location.
+ * For retrieving DaemonVersion, this should be sizeof(uint32_t).
+ * On return the uint32_t is updated to the size of the data returned.
+ * For DaemonVersion, the returned size is always sizeof(uint32_t), but
+ * future properties could be defined which return variable-sized results.
+ *
+ * return value: Returns kDNSServiceErr_NoError on success, or kDNSServiceErr_ServiceNotRunning
+ * if the daemon (or "system service" on Windows) is not running.
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceGetProperty
+(
+ const char *property, /* Requested property (i.e. kDNSServiceProperty_DaemonVersion) */
+ void *result, /* Pointer to place to store result */
+ uint32_t *size /* size of result location */
+);
+
+/*
+ * When requesting kDNSServiceProperty_DaemonVersion, the result pointer must point
+ * to a 32-bit unsigned integer, and the size parameter must be set to sizeof(uint32_t).
+ *
+ * On return, the 32-bit unsigned integer contains the API version number
+ *
+ * For example, Mac OS X 10.4.9 has API version 1080400.
+ * This allows applications to do simple greater-than and less-than comparisons:
+ * e.g. an application that requires at least API version 1080400 can check:
+ * if (version >= 1080400) ...
+ *
+ * Example usage:
+ * uint32_t version;
+ * uint32_t size = sizeof(version);
+ * DNSServiceErrorType err = DNSServiceGetProperty(kDNSServiceProperty_DaemonVersion, &version, &size);
+ * if (!err) printf("DNS_SD API version is %d.%d\n", version / 10000, version / 100 % 100);
+ */
+
+#define kDNSServiceProperty_DaemonVersion "DaemonVersion"
+
+
+// Map the source port of the local UDP socket that was opened for sending the DNS query
+// to the process ID of the application that triggered the DNS resolution.
+//
+/* DNSServiceGetPID() Parameters:
+ *
+ * srcport: Source port (in network byte order) of the UDP socket that was created by
+ * the daemon to send the DNS query on the wire.
+ *
+ * pid: Process ID of the application that started the name resolution which triggered
+ * the daemon to send the query on the wire. The value can be -1 if the srcport
+ * cannot be mapped.
+ *
+ * return value: Returns kDNSServiceErr_NoError on success, or kDNSServiceErr_ServiceNotRunning
+ * if the daemon is not running. The value of the pid is undefined if the return
+ * value has error.
+ */
+DNSServiceErrorType DNSSD_API DNSServiceGetPID
+(
+ uint16_t srcport,
+ int32_t *pid
+);
+
+/*********************************************************************************************
+*
+* Unix Domain Socket access, DNSServiceRef deallocation, and data processing functions
+*
+*********************************************************************************************/
+
+/* DNSServiceRefSockFD()
+ *
+ * Access underlying Unix domain socket for an initialized DNSServiceRef.
+ * The DNS Service Discovery implementation uses this socket to communicate between the client and
+ * the daemon. The application MUST NOT directly read from or write to this socket.
+ * Access to the socket is provided so that it can be used as a kqueue event source, a CFRunLoop
+ * event source, in a select() loop, etc. When the underlying event management subsystem (kqueue/
+ * select/CFRunLoop etc.) indicates to the client that data is available for reading on the
+ * socket, the client should call DNSServiceProcessResult(), which will extract the daemon's
+ * reply from the socket, and pass it to the appropriate application callback. By using a run
+ * loop or select(), results from the daemon can be processed asynchronously. Alternatively,
+ * a client can choose to fork a thread and have it loop calling "DNSServiceProcessResult(ref);"
+ * If DNSServiceProcessResult() is called when no data is available for reading on the socket, it
+ * will block until data does become available, and then process the data and return to the caller.
+ * The application is reponsible for checking the return value of DNSServiceProcessResult() to determine
+ * if the socket is valid and if it should continue to process data on the socket.
+ * When data arrives on the socket, the client is responsible for calling DNSServiceProcessResult(ref)
+ * in a timely fashion -- if the client allows a large backlog of data to build up the daemon
+ * may terminate the connection.
+ *
+ * sdRef: A DNSServiceRef initialized by any of the DNSService calls.
+ *
+ * return value: The DNSServiceRef's underlying socket descriptor, or -1 on
+ * error.
+ */
+
+int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef);
+
+
+/* DNSServiceProcessResult()
+ *
+ * Read a reply from the daemon, calling the appropriate application callback. This call will
+ * block until the daemon's response is received. Use DNSServiceRefSockFD() in
+ * conjunction with a run loop or select() to determine the presence of a response from the
+ * server before calling this function to process the reply without blocking. Call this function
+ * at any point if it is acceptable to block until the daemon's response arrives. Note that the
+ * client is responsible for ensuring that DNSServiceProcessResult() is called whenever there is
+ * a reply from the daemon - the daemon may terminate its connection with a client that does not
+ * process the daemon's responses.
+ *
+ * sdRef: A DNSServiceRef initialized by any of the DNSService calls
+ * that take a callback parameter.
+ *
+ * return value: Returns kDNSServiceErr_NoError on success, otherwise returns
+ * an error code indicating the specific failure that occurred.
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef);
+
+
+/* DNSServiceRefDeallocate()
+ *
+ * Terminate a connection with the daemon and free memory associated with the DNSServiceRef.
+ * Any services or records registered with this DNSServiceRef will be deregistered. Any
+ * Browse, Resolve, or Query operations called with this reference will be terminated.
+ *
+ * Note: If the reference's underlying socket is used in a run loop or select() call, it should
+ * be removed BEFORE DNSServiceRefDeallocate() is called, as this function closes the reference's
+ * socket.
+ *
+ * Note: If the reference was initialized with DNSServiceCreateConnection(), any DNSRecordRefs
+ * created via this reference will be invalidated by this call - the resource records are
+ * deregistered, and their DNSRecordRefs may not be used in subsequent functions. Similarly,
+ * if the reference was initialized with DNSServiceRegister, and an extra resource record was
+ * added to the service via DNSServiceAddRecord(), the DNSRecordRef created by the Add() call
+ * is invalidated when this function is called - the DNSRecordRef may not be used in subsequent
+ * functions.
+ *
+ * Note: This call is to be used only with the DNSServiceRef defined by this API.
+ *
+ * sdRef: A DNSServiceRef initialized by any of the DNSService calls.
+ *
+ */
+
+void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef);
+
+
+/*********************************************************************************************
+*
+* Domain Enumeration
+*
+*********************************************************************************************/
+
+/* DNSServiceEnumerateDomains()
+ *
+ * Asynchronously enumerate domains available for browsing and registration.
+ *
+ * The enumeration MUST be cancelled via DNSServiceRefDeallocate() when no more domains
+ * are to be found.
+ *
+ * Note that the names returned are (like all of DNS-SD) UTF-8 strings,
+ * and are escaped using standard DNS escaping rules.
+ * (See "Notes on DNS Name Escaping" earlier in this file for more details.)
+ * A graphical browser displaying a hierarchical tree-structured view should cut
+ * the names at the bare dots to yield individual labels, then de-escape each
+ * label according to the escaping rules, and then display the resulting UTF-8 text.
+ *
+ * DNSServiceDomainEnumReply Callback Parameters:
+ *
+ * sdRef: The DNSServiceRef initialized by DNSServiceEnumerateDomains().
+ *
+ * flags: Possible values are:
+ * kDNSServiceFlagsMoreComing
+ * kDNSServiceFlagsAdd
+ * kDNSServiceFlagsDefault
+ *
+ * interfaceIndex: Specifies the interface on which the domain exists. (The index for a given
+ * interface is determined via the if_nametoindex() family of calls.)
+ *
+ * errorCode: Will be kDNSServiceErr_NoError (0) on success, otherwise indicates
+ * the failure that occurred (other parameters are undefined if errorCode is nonzero).
+ *
+ * replyDomain: The name of the domain.
+ *
+ * context: The context pointer passed to DNSServiceEnumerateDomains.
+ *
+ */
+
+typedef void (DNSSD_API *DNSServiceDomainEnumReply)
+(
+ DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char *replyDomain,
+ void *context
+);
+
+
+/* DNSServiceEnumerateDomains() Parameters:
+ *
+ * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
+ * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
+ * and the enumeration operation will run indefinitely until the client
+ * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ *
+ * flags: Possible values are:
+ * kDNSServiceFlagsBrowseDomains to enumerate domains recommended for browsing.
+ * kDNSServiceFlagsRegistrationDomains to enumerate domains recommended
+ * for registration.
+ *
+ * interfaceIndex: If non-zero, specifies the interface on which to look for domains.
+ * (the index for a given interface is determined via the if_nametoindex()
+ * family of calls.) Most applications will pass 0 to enumerate domains on
+ * all interfaces. See "Constants for specifying an interface index" for more details.
+ *
+ * callBack: The function to be called when a domain is found or the call asynchronously
+ * fails.
+ *
+ * context: An application context pointer which is passed to the callback function
+ * (may be NULL).
+ *
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
+ * errors are delivered to the callback), otherwise returns an error code indicating
+ * the error that occurred (the callback is not invoked and the DNSServiceRef
+ * is not initialized).
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceDomainEnumReply callBack,
+ void *context /* may be NULL */
+);
+
+
+/*********************************************************************************************
+*
+* Service Registration
+*
+*********************************************************************************************/
+
+/* Register a service that is discovered via Browse() and Resolve() calls.
+ *
+ * DNSServiceRegisterReply() Callback Parameters:
+ *
+ * sdRef: The DNSServiceRef initialized by DNSServiceRegister().
+ *
+ * flags: When a name is successfully registered, the callback will be
+ * invoked with the kDNSServiceFlagsAdd flag set. When Wide-Area
+ * DNS-SD is in use, it is possible for a single service to get
+ * more than one success callback (e.g. one in the "local" multicast
+ * DNS domain, and another in a wide-area unicast DNS domain).
+ * If a successfully-registered name later suffers a name conflict
+ * or similar problem and has to be deregistered, the callback will
+ * be invoked with the kDNSServiceFlagsAdd flag not set. The callback
+ * is *not* invoked in the case where the caller explicitly terminates
+ * the service registration by calling DNSServiceRefDeallocate(ref);
+ *
+ * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will
+ * indicate the failure that occurred (including name conflicts,
+ * if the kDNSServiceFlagsNoAutoRename flag was used when registering.)
+ * Other parameters are undefined if errorCode is nonzero.
+ *
+ * name: The service name registered (if the application did not specify a name in
+ * DNSServiceRegister(), this indicates what name was automatically chosen).
+ *
+ * regtype: The type of service registered, as it was passed to the callout.
+ *
+ * domain: The domain on which the service was registered (if the application did not
+ * specify a domain in DNSServiceRegister(), this indicates the default domain
+ * on which the service was registered).
+ *
+ * context: The context pointer that was passed to the callout.
+ *
+ */
+
+typedef void (DNSSD_API *DNSServiceRegisterReply)
+(
+ DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ DNSServiceErrorType errorCode,
+ const char *name,
+ const char *regtype,
+ const char *domain,
+ void *context
+);
+
+
+/* DNSServiceRegister() Parameters:
+ *
+ * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
+ * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
+ * and the registration will remain active indefinitely until the client
+ * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ *
+ * interfaceIndex: If non-zero, specifies the interface on which to register the service
+ * (the index for a given interface is determined via the if_nametoindex()
+ * family of calls.) Most applications will pass 0 to register on all
+ * available interfaces. See "Constants for specifying an interface index" for more details.
+ *
+ * flags: Indicates the renaming behavior on name conflict (most applications
+ * will pass 0). See flag definitions above for details.
+ *
+ * name: If non-NULL, specifies the service name to be registered.
+ * Most applications will not specify a name, in which case the computer
+ * name is used (this name is communicated to the client via the callback).
+ * If a name is specified, it must be 1-63 bytes of UTF-8 text.
+ * If the name is longer than 63 bytes it will be automatically truncated
+ * to a legal length, unless the NoAutoRename flag is set,
+ * in which case kDNSServiceErr_BadParam will be returned.
+ *
+ * regtype: The service type followed by the protocol, separated by a dot
+ * (e.g. "_ftp._tcp"). The service type must be an underscore, followed
+ * by 1-15 characters, which may be letters, digits, or hyphens.
+ * The transport protocol must be "_tcp" or "_udp". New service types
+ * should be registered at <http://www.dns-sd.org/ServiceTypes.html>.
+ *
+ * Additional subtypes of the primary service type (where a service
+ * type has defined subtypes) follow the primary service type in a
+ * comma-separated list, with no additional spaces, e.g.
+ * "_primarytype._tcp,_subtype1,_subtype2,_subtype3"
+ * Subtypes provide a mechanism for filtered browsing: A client browsing
+ * for "_primarytype._tcp" will discover all instances of this type;
+ * a client browsing for "_primarytype._tcp,_subtype2" will discover only
+ * those instances that were registered with "_subtype2" in their list of
+ * registered subtypes.
+ *
+ * The subtype mechanism can be illustrated with some examples using the
+ * dns-sd command-line tool:
+ *
+ * % dns-sd -R Simple _test._tcp "" 1001 &
+ * % dns-sd -R Better _test._tcp,HasFeatureA "" 1002 &
+ * % dns-sd -R Best _test._tcp,HasFeatureA,HasFeatureB "" 1003 &
+ *
+ * Now:
+ * % dns-sd -B _test._tcp # will find all three services
+ * % dns-sd -B _test._tcp,HasFeatureA # finds "Better" and "Best"
+ * % dns-sd -B _test._tcp,HasFeatureB # finds only "Best"
+ *
+ * Subtype labels may be up to 63 bytes long, and may contain any eight-
+ * bit byte values, including zero bytes. However, due to the nature of
+ * using a C-string-based API, conventional DNS escaping must be used for
+ * dots ('.'), commas (','), backslashes ('\') and zero bytes, as shown below:
+ *
+ * % dns-sd -R Test '_test._tcp,s\.one,s\,two,s\\three,s\000four' local 123
+ *
+ * When a service is registered, all the clients browsing for the registered
+ * type ("regtype") will discover it. If the discovery should be
+ * restricted to a smaller set of well known peers, the service can be
+ * registered with additional data (group identifier) that is known
+ * only to a smaller set of peers. The group identifier should follow primary
+ * service type using a colon (":") as a delimeter. If subtypes are also present,
+ * it should be given before the subtype as shown below.
+ *
+ * % dns-sd -R _test1 _http._tcp:mygroup1 local 1001
+ * % dns-sd -R _test2 _http._tcp:mygroup2 local 1001
+ * % dns-sd -R _test3 _http._tcp:mygroup3,HasFeatureA local 1001
+ *
+ * Now:
+ * % dns-sd -B _http._tcp:"mygroup1" # will discover only test1
+ * % dns-sd -B _http._tcp:"mygroup2" # will discover only test2
+ * % dns-sd -B _http._tcp:"mygroup3",HasFeatureA # will discover only test3
+ *
+ * By specifying the group information, only the members of that group are
+ * discovered.
+ *
+ * The group identifier itself is not sent in clear. Only a hash of the group
+ * identifier is sent and the clients discover them anonymously. The group identifier
+ * may be up to 256 bytes long and may contain any eight bit values except comma which
+ * should be escaped.
+ *
+ * domain: If non-NULL, specifies the domain on which to advertise the service.
+ * Most applications will not specify a domain, instead automatically
+ * registering in the default domain(s).
+ *
+ * host: If non-NULL, specifies the SRV target host name. Most applications
+ * will not specify a host, instead automatically using the machine's
+ * default host name(s). Note that specifying a non-NULL host does NOT
+ * create an address record for that host - the application is responsible
+ * for ensuring that the appropriate address record exists, or creating it
+ * via DNSServiceRegisterRecord().
+ *
+ * port: The port, in network byte order, on which the service accepts connections.
+ * Pass 0 for a "placeholder" service (i.e. a service that will not be discovered
+ * by browsing, but will cause a name conflict if another client tries to
+ * register that same name). Most clients will not use placeholder services.
+ *
+ * txtLen: The length of the txtRecord, in bytes. Must be zero if the txtRecord is NULL.
+ *
+ * txtRecord: The TXT record rdata. A non-NULL txtRecord MUST be a properly formatted DNS
+ * TXT record, i.e. <length byte> <data> <length byte> <data> ...
+ * Passing NULL for the txtRecord is allowed as a synonym for txtLen=1, txtRecord="",
+ * i.e. it creates a TXT record of length one containing a single empty string.
+ * RFC 1035 doesn't allow a TXT record to contain *zero* strings, so a single empty
+ * string is the smallest legal DNS TXT record.
+ * As with the other parameters, the DNSServiceRegister call copies the txtRecord
+ * data; e.g. if you allocated the storage for the txtRecord parameter with malloc()
+ * then you can safely free that memory right after the DNSServiceRegister call returns.
+ *
+ * callBack: The function to be called when the registration completes or asynchronously
+ * fails. The client MAY pass NULL for the callback - The client will NOT be notified
+ * of the default values picked on its behalf, and the client will NOT be notified of any
+ * asynchronous errors (e.g. out of memory errors, etc.) that may prevent the registration
+ * of the service. The client may NOT pass the NoAutoRename flag if the callback is NULL.
+ * The client may still deregister the service at any time via DNSServiceRefDeallocate().
+ *
+ * context: An application context pointer which is passed to the callback function
+ * (may be NULL).
+ *
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
+ * errors are delivered to the callback), otherwise returns an error code indicating
+ * the error that occurred (the callback is never invoked and the DNSServiceRef
+ * is not initialized).
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceRegister
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *name, /* may be NULL */
+ const char *regtype,
+ const char *domain, /* may be NULL */
+ const char *host, /* may be NULL */
+ uint16_t port, /* In network byte order */
+ uint16_t txtLen,
+ const void *txtRecord, /* may be NULL */
+ DNSServiceRegisterReply callBack, /* may be NULL */
+ void *context /* may be NULL */
+);
+
+
+/* DNSServiceAddRecord()
+ *
+ * Add a record to a registered service. The name of the record will be the same as the
+ * registered service's name.
+ * The record can later be updated or deregistered by passing the RecordRef initialized
+ * by this function to DNSServiceUpdateRecord() or DNSServiceRemoveRecord().
+ *
+ * Note that the DNSServiceAddRecord/UpdateRecord/RemoveRecord are *NOT* thread-safe
+ * with respect to a single DNSServiceRef. If you plan to have multiple threads
+ * in your program simultaneously add, update, or remove records from the same
+ * DNSServiceRef, then it's the caller's responsibility to use a mutext lock
+ * or take similar appropriate precautions to serialize those calls.
+ *
+ * Parameters;
+ *
+ * sdRef: A DNSServiceRef initialized by DNSServiceRegister().
+ *
+ * RecordRef: A pointer to an uninitialized DNSRecordRef. Upon succesfull completion of this
+ * call, this ref may be passed to DNSServiceUpdateRecord() or DNSServiceRemoveRecord().
+ * If the above DNSServiceRef is passed to DNSServiceRefDeallocate(), RecordRef is also
+ * invalidated and may not be used further.
+ *
+ * flags: Currently ignored, reserved for future use.
+ *
+ * rrtype: The type of the record (e.g. kDNSServiceType_TXT, kDNSServiceType_SRV, etc)
+ *
+ * rdlen: The length, in bytes, of the rdata.
+ *
+ * rdata: The raw rdata to be contained in the added resource record.
+ *
+ * ttl: The time to live of the resource record, in seconds.
+ * Most clients should pass 0 to indicate that the system should
+ * select a sensible default value.
+ *
+ * return value: Returns kDNSServiceErr_NoError on success, otherwise returns an
+ * error code indicating the error that occurred (the RecordRef is not initialized).
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceAddRecord
+(
+ DNSServiceRef sdRef,
+ DNSRecordRef *RecordRef,
+ DNSServiceFlags flags,
+ uint16_t rrtype,
+ uint16_t rdlen,
+ const void *rdata,
+ uint32_t ttl
+);
+
+
+/* DNSServiceUpdateRecord
+ *
+ * Update a registered resource record. The record must either be:
+ * - The primary txt record of a service registered via DNSServiceRegister()
+ * - A record added to a registered service via DNSServiceAddRecord()
+ * - An individual record registered by DNSServiceRegisterRecord()
+ *
+ * Parameters:
+ *
+ * sdRef: A DNSServiceRef that was initialized by DNSServiceRegister()
+ * or DNSServiceCreateConnection().
+ *
+ * RecordRef: A DNSRecordRef initialized by DNSServiceAddRecord, or NULL to update the
+ * service's primary txt record.
+ *
+ * flags: Currently ignored, reserved for future use.
+ *
+ * rdlen: The length, in bytes, of the new rdata.
+ *
+ * rdata: The new rdata to be contained in the updated resource record.
+ *
+ * ttl: The time to live of the updated resource record, in seconds.
+ * Most clients should pass 0 to indicate that the system should
+ * select a sensible default value.
+ *
+ * return value: Returns kDNSServiceErr_NoError on success, otherwise returns an
+ * error code indicating the error that occurred.
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
+(
+ DNSServiceRef sdRef,
+ DNSRecordRef RecordRef, /* may be NULL */
+ DNSServiceFlags flags,
+ uint16_t rdlen,
+ const void *rdata,
+ uint32_t ttl
+);
+
+
+/* DNSServiceRemoveRecord
+ *
+ * Remove a record previously added to a service record set via DNSServiceAddRecord(), or deregister
+ * an record registered individually via DNSServiceRegisterRecord().
+ *
+ * Parameters:
+ *
+ * sdRef: A DNSServiceRef initialized by DNSServiceRegister() (if the
+ * record being removed was registered via DNSServiceAddRecord()) or by
+ * DNSServiceCreateConnection() (if the record being removed was registered via
+ * DNSServiceRegisterRecord()).
+ *
+ * recordRef: A DNSRecordRef initialized by a successful call to DNSServiceAddRecord()
+ * or DNSServiceRegisterRecord().
+ *
+ * flags: Currently ignored, reserved for future use.
+ *
+ * return value: Returns kDNSServiceErr_NoError on success, otherwise returns an
+ * error code indicating the error that occurred.
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
+(
+ DNSServiceRef sdRef,
+ DNSRecordRef RecordRef,
+ DNSServiceFlags flags
+);
+
+
+/*********************************************************************************************
+*
+* Service Discovery
+*
+*********************************************************************************************/
+
+/* Browse for instances of a service.
+ *
+ * DNSServiceBrowseReply() Parameters:
+ *
+ * sdRef: The DNSServiceRef initialized by DNSServiceBrowse().
+ *
+ * flags: Possible values are kDNSServiceFlagsMoreComing and kDNSServiceFlagsAdd.
+ * See flag definitions for details.
+ *
+ * interfaceIndex: The interface on which the service is advertised. This index should
+ * be passed to DNSServiceResolve() when resolving the service.
+ *
+ * errorCode: Will be kDNSServiceErr_NoError (0) on success, otherwise will
+ * indicate the failure that occurred. Other parameters are undefined if
+ * the errorCode is nonzero.
+ *
+ * serviceName: The discovered service name. This name should be displayed to the user,
+ * and stored for subsequent use in the DNSServiceResolve() call.
+ *
+ * regtype: The service type, which is usually (but not always) the same as was passed
+ * to DNSServiceBrowse(). One case where the discovered service type may
+ * not be the same as the requested service type is when using subtypes:
+ * The client may want to browse for only those ftp servers that allow
+ * anonymous connections. The client will pass the string "_ftp._tcp,_anon"
+ * to DNSServiceBrowse(), but the type of the service that's discovered
+ * is simply "_ftp._tcp". The regtype for each discovered service instance
+ * should be stored along with the name, so that it can be passed to
+ * DNSServiceResolve() when the service is later resolved.
+ *
+ * domain: The domain of the discovered service instance. This may or may not be the
+ * same as the domain that was passed to DNSServiceBrowse(). The domain for each
+ * discovered service instance should be stored along with the name, so that
+ * it can be passed to DNSServiceResolve() when the service is later resolved.
+ *
+ * context: The context pointer that was passed to the callout.
+ *
+ */
+
+typedef void (DNSSD_API *DNSServiceBrowseReply)
+(
+ DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char *serviceName,
+ const char *regtype,
+ const char *replyDomain,
+ void *context
+);
+
+
+/* DNSServiceBrowse() Parameters:
+ *
+ * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
+ * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
+ * and the browse operation will run indefinitely until the client
+ * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ *
+ * flags: Currently ignored, reserved for future use.
+ *
+ * interfaceIndex: If non-zero, specifies the interface on which to browse for services
+ * (the index for a given interface is determined via the if_nametoindex()
+ * family of calls.) Most applications will pass 0 to browse on all available
+ * interfaces. See "Constants for specifying an interface index" for more details.
+ *
+ * regtype: The service type being browsed for followed by the protocol, separated by a
+ * dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
+ * A client may optionally specify a single subtype to perform filtered browsing:
+ * e.g. browsing for "_primarytype._tcp,_subtype" will discover only those
+ * instances of "_primarytype._tcp" that were registered specifying "_subtype"
+ * in their list of registered subtypes. Additionally, a group identifier may
+ * also be specified before the subtype e.g., _primarytype._tcp:GroupID, which
+ * will discover only the members that register the service with GroupID. See
+ * DNSServiceRegister for more details.
+ *
+ * domain: If non-NULL, specifies the domain on which to browse for services.
+ * Most applications will not specify a domain, instead browsing on the
+ * default domain(s).
+ *
+ * callBack: The function to be called when an instance of the service being browsed for
+ * is found, or if the call asynchronously fails.
+ *
+ * context: An application context pointer which is passed to the callback function
+ * (may be NULL).
+ *
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
+ * errors are delivered to the callback), otherwise returns an error code indicating
+ * the error that occurred (the callback is not invoked and the DNSServiceRef
+ * is not initialized).
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceBrowse
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *regtype,
+ const char *domain, /* may be NULL */
+ DNSServiceBrowseReply callBack,
+ void *context /* may be NULL */
+);
+
+
+/* DNSServiceResolve()
+ *
+ * Resolve a service name discovered via DNSServiceBrowse() to a target host name, port number, and
+ * txt record.
+ *
+ * Note: Applications should NOT use DNSServiceResolve() solely for txt record monitoring - use
+ * DNSServiceQueryRecord() instead, as it is more efficient for this task.
+ *
+ * Note: When the desired results have been returned, the client MUST terminate the resolve by calling
+ * DNSServiceRefDeallocate().
+ *
+ * Note: DNSServiceResolve() behaves correctly for typical services that have a single SRV record
+ * and a single TXT record. To resolve non-standard services with multiple SRV or TXT records,
+ * DNSServiceQueryRecord() should be used.
+ *
+ * DNSServiceResolveReply Callback Parameters:
+ *
+ * sdRef: The DNSServiceRef initialized by DNSServiceResolve().
+ *
+ * flags: Possible values: kDNSServiceFlagsMoreComing
+ *
+ * interfaceIndex: The interface on which the service was resolved.
+ *
+ * errorCode: Will be kDNSServiceErr_NoError (0) on success, otherwise will
+ * indicate the failure that occurred. Other parameters are undefined if
+ * the errorCode is nonzero.
+ *
+ * fullname: The full service domain name, in the form <servicename>.<protocol>.<domain>.
+ * (This name is escaped following standard DNS rules, making it suitable for
+ * passing to standard system DNS APIs such as res_query(), or to the
+ * special-purpose functions included in this API that take fullname parameters.
+ * See "Notes on DNS Name Escaping" earlier in this file for more details.)
+ *
+ * hosttarget: The target hostname of the machine providing the service. This name can
+ * be passed to functions like gethostbyname() to identify the host's IP address.
+ *
+ * port: The port, in network byte order, on which connections are accepted for this service.
+ *
+ * txtLen: The length of the txt record, in bytes.
+ *
+ * txtRecord: The service's primary txt record, in standard txt record format.
+ *
+ * context: The context pointer that was passed to the callout.
+ *
+ * NOTE: In earlier versions of this header file, the txtRecord parameter was declared "const char *"
+ * This is incorrect, since it contains length bytes which are values in the range 0 to 255, not -128 to +127.
+ * Depending on your compiler settings, this change may cause signed/unsigned mismatch warnings.
+ * These should be fixed by updating your own callback function definition to match the corrected
+ * function signature using "const unsigned char *txtRecord". Making this change may also fix inadvertent
+ * bugs in your callback function, where it could have incorrectly interpreted a length byte with value 250
+ * as being -6 instead, with various bad consequences ranging from incorrect operation to software crashes.
+ * If you need to maintain portable code that will compile cleanly with both the old and new versions of
+ * this header file, you should update your callback function definition to use the correct unsigned value,
+ * and then in the place where you pass your callback function to DNSServiceResolve(), use a cast to eliminate
+ * the compiler warning, e.g.:
+ * DNSServiceResolve(sd, flags, index, name, regtype, domain, (DNSServiceResolveReply)MyCallback, context);
+ * This will ensure that your code compiles cleanly without warnings (and more importantly, works correctly)
+ * with both the old header and with the new corrected version.
+ *
+ */
+
+typedef void (DNSSD_API *DNSServiceResolveReply)
+(
+ DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char *fullname,
+ const char *hosttarget,
+ uint16_t port, /* In network byte order */
+ uint16_t txtLen,
+ const unsigned char *txtRecord,
+ void *context
+);
+
+
+/* DNSServiceResolve() Parameters
+ *
+ * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
+ * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
+ * and the resolve operation will run indefinitely until the client
+ * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ *
+ * flags: Specifying kDNSServiceFlagsForceMulticast will cause query to be
+ * performed with a link-local mDNS query, even if the name is an
+ * apparently non-local name (i.e. a name not ending in ".local.")
+ *
+ * interfaceIndex: The interface on which to resolve the service. If this resolve call is
+ * as a result of a currently active DNSServiceBrowse() operation, then the
+ * interfaceIndex should be the index reported in the DNSServiceBrowseReply
+ * callback. If this resolve call is using information previously saved
+ * (e.g. in a preference file) for later use, then use interfaceIndex 0, because
+ * the desired service may now be reachable via a different physical interface.
+ * See "Constants for specifying an interface index" for more details.
+ *
+ * name: The name of the service instance to be resolved, as reported to the
+ * DNSServiceBrowseReply() callback.
+ *
+ * regtype: The type of the service instance to be resolved, as reported to the
+ * DNSServiceBrowseReply() callback.
+ *
+ * domain: The domain of the service instance to be resolved, as reported to the
+ * DNSServiceBrowseReply() callback.
+ *
+ * callBack: The function to be called when a result is found, or if the call
+ * asynchronously fails.
+ *
+ * context: An application context pointer which is passed to the callback function
+ * (may be NULL).
+ *
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
+ * errors are delivered to the callback), otherwise returns an error code indicating
+ * the error that occurred (the callback is never invoked and the DNSServiceRef
+ * is not initialized).
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceResolve
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *name,
+ const char *regtype,
+ const char *domain,
+ DNSServiceResolveReply callBack,
+ void *context /* may be NULL */
+);
+
+
+/*********************************************************************************************
+*
+* Querying Individual Specific Records
+*
+*********************************************************************************************/
+
+/* DNSServiceQueryRecord
+ *
+ * Query for an arbitrary DNS record.
+ *
+ * DNSServiceQueryRecordReply() Callback Parameters:
+ *
+ * sdRef: The DNSServiceRef initialized by DNSServiceQueryRecord().
+ *
+ * flags: Possible values are kDNSServiceFlagsMoreComing and
+ * kDNSServiceFlagsAdd. The Add flag is NOT set for PTR records
+ * with a ttl of 0, i.e. "Remove" events.
+ *
+ * interfaceIndex: The interface on which the query was resolved (the index for a given
+ * interface is determined via the if_nametoindex() family of calls).
+ * See "Constants for specifying an interface index" for more details.
+ *
+ * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will
+ * indicate the failure that occurred. Other parameters are undefined if
+ * errorCode is nonzero.
+ *
+ * fullname: The resource record's full domain name.
+ *
+ * rrtype: The resource record's type (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
+ *
+ * rrclass: The class of the resource record (usually kDNSServiceClass_IN).
+ *
+ * rdlen: The length, in bytes, of the resource record rdata.
+ *
+ * rdata: The raw rdata of the resource record.
+ *
+ * ttl: If the client wishes to cache the result for performance reasons,
+ * the TTL indicates how long the client may legitimately hold onto
+ * this result, in seconds. After the TTL expires, the client should
+ * consider the result no longer valid, and if it requires this data
+ * again, it should be re-fetched with a new query. Of course, this
+ * only applies to clients that cancel the asynchronous operation when
+ * they get a result. Clients that leave the asynchronous operation
+ * running can safely assume that the data remains valid until they
+ * get another callback telling them otherwise.
+ *
+ * context: The context pointer that was passed to the callout.
+ *
+ */
+
+typedef void (DNSSD_API *DNSServiceQueryRecordReply)
+(
+ DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char *fullname,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ uint16_t rdlen,
+ const void *rdata,
+ uint32_t ttl,
+ void *context
+);
+
+
+/* DNSServiceQueryRecord() Parameters:
+ *
+ * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
+ * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
+ * and the query operation will run indefinitely until the client
+ * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ *
+ * flags: kDNSServiceFlagsForceMulticast or kDNSServiceFlagsLongLivedQuery.
+ * Pass kDNSServiceFlagsLongLivedQuery to create a "long-lived" unicast
+ * query to a unicast DNS server that implements the protocol. This flag
+ * has no effect on link-local multicast queries.
+ *
+ * interfaceIndex: If non-zero, specifies the interface on which to issue the query
+ * (the index for a given interface is determined via the if_nametoindex()
+ * family of calls.) Passing 0 causes the name to be queried for on all
+ * interfaces. See "Constants for specifying an interface index" for more details.
+ *
+ * fullname: The full domain name of the resource record to be queried for.
+ *
+ * rrtype: The numerical type of the resource record to be queried for
+ * (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
+ *
+ * rrclass: The class of the resource record (usually kDNSServiceClass_IN).
+ *
+ * callBack: The function to be called when a result is found, or if the call
+ * asynchronously fails.
+ *
+ * context: An application context pointer which is passed to the callback function
+ * (may be NULL).
+ *
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
+ * errors are delivered to the callback), otherwise returns an error code indicating
+ * the error that occurred (the callback is never invoked and the DNSServiceRef
+ * is not initialized).
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *fullname,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ DNSServiceQueryRecordReply callBack,
+ void *context /* may be NULL */
+);
+
+
+/*********************************************************************************************
+*
+* Unified lookup of both IPv4 and IPv6 addresses for a fully qualified hostname
+*
+*********************************************************************************************/
+
+/* DNSServiceGetAddrInfo
+ *
+ * Queries for the IP address of a hostname by using either Multicast or Unicast DNS.
+ *
+ * DNSServiceGetAddrInfoReply() parameters:
+ *
+ * sdRef: The DNSServiceRef initialized by DNSServiceGetAddrInfo().
+ *
+ * flags: Possible values are kDNSServiceFlagsMoreComing and
+ * kDNSServiceFlagsAdd.
+ *
+ * interfaceIndex: The interface to which the answers pertain.
+ *
+ * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will
+ * indicate the failure that occurred. Other parameters are
+ * undefined if errorCode is nonzero.
+ *
+ * hostname: The fully qualified domain name of the host to be queried for.
+ *
+ * address: IPv4 or IPv6 address.
+ *
+ * ttl: If the client wishes to cache the result for performance reasons,
+ * the TTL indicates how long the client may legitimately hold onto
+ * this result, in seconds. After the TTL expires, the client should
+ * consider the result no longer valid, and if it requires this data
+ * again, it should be re-fetched with a new query. Of course, this
+ * only applies to clients that cancel the asynchronous operation when
+ * they get a result. Clients that leave the asynchronous operation
+ * running can safely assume that the data remains valid until they
+ * get another callback telling them otherwise.
+ *
+ * context: The context pointer that was passed to the callout.
+ *
+ */
+
+typedef void (DNSSD_API *DNSServiceGetAddrInfoReply)
+(
+ DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char *hostname,
+ const struct sockaddr *address,
+ uint32_t ttl,
+ void *context
+);
+
+
+/* DNSServiceGetAddrInfo() Parameters:
+ *
+ * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds then it
+ * initializes the DNSServiceRef, returns kDNSServiceErr_NoError, and the query
+ * begins and will last indefinitely until the client terminates the query
+ * by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ *
+ * flags: kDNSServiceFlagsForceMulticast
+ *
+ * interfaceIndex: The interface on which to issue the query. Passing 0 causes the query to be
+ * sent on all active interfaces via Multicast or the primary interface via Unicast.
+ *
+ * protocol: Pass in kDNSServiceProtocol_IPv4 to look up IPv4 addresses, or kDNSServiceProtocol_IPv6
+ * to look up IPv6 addresses, or both to look up both kinds. If neither flag is
+ * set, the system will apply an intelligent heuristic, which is (currently)
+ * that it will attempt to look up both, except:
+ *
+ * * If "hostname" is a wide-area unicast DNS hostname (i.e. not a ".local." name)
+ * but this host has no routable IPv6 address, then the call will not try to
+ * look up IPv6 addresses for "hostname", since any addresses it found would be
+ * unlikely to be of any use anyway. Similarly, if this host has no routable
+ * IPv4 address, the call will not try to look up IPv4 addresses for "hostname".
+ *
+ * hostname: The fully qualified domain name of the host to be queried for.
+ *
+ * callBack: The function to be called when the query succeeds or fails asynchronously.
+ *
+ * context: An application context pointer which is passed to the callback function
+ * (may be NULL).
+ *
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
+ * errors are delivered to the callback), otherwise returns an error code indicating
+ * the error that occurred.
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceProtocol protocol,
+ const char *hostname,
+ DNSServiceGetAddrInfoReply callBack,
+ void *context /* may be NULL */
+);
+
+
+/*********************************************************************************************
+*
+* Special Purpose Calls:
+* DNSServiceCreateConnection(), DNSServiceRegisterRecord(), DNSServiceReconfirmRecord()
+* (most applications will not use these)
+*
+*********************************************************************************************/
+
+/* DNSServiceCreateConnection()
+ *
+ * Create a connection to the daemon allowing efficient registration of
+ * multiple individual records.
+ *
+ * Parameters:
+ *
+ * sdRef: A pointer to an uninitialized DNSServiceRef. Deallocating
+ * the reference (via DNSServiceRefDeallocate()) severs the
+ * connection and deregisters all records registered on this connection.
+ *
+ * return value: Returns kDNSServiceErr_NoError on success, otherwise returns
+ * an error code indicating the specific failure that occurred (in which
+ * case the DNSServiceRef is not initialized).
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef);
+
+/* DNSServiceRegisterRecord
+ *
+ * Register an individual resource record on a connected DNSServiceRef.
+ *
+ * Note that name conflicts occurring for records registered via this call must be handled
+ * by the client in the callback.
+ *
+ * DNSServiceRegisterRecordReply() parameters:
+ *
+ * sdRef: The connected DNSServiceRef initialized by
+ * DNSServiceCreateConnection().
+ *
+ * RecordRef: The DNSRecordRef initialized by DNSServiceRegisterRecord(). If the above
+ * DNSServiceRef is passed to DNSServiceRefDeallocate(), this DNSRecordRef is
+ * invalidated, and may not be used further.
+ *
+ * flags: Currently unused, reserved for future use.
+ *
+ * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will
+ * indicate the failure that occurred (including name conflicts.)
+ * Other parameters are undefined if errorCode is nonzero.
+ *
+ * context: The context pointer that was passed to the callout.
+ *
+ */
+
+typedef void (DNSSD_API *DNSServiceRegisterRecordReply)
+(
+ DNSServiceRef sdRef,
+ DNSRecordRef RecordRef,
+ DNSServiceFlags flags,
+ DNSServiceErrorType errorCode,
+ void *context
+);
+
+
+/* DNSServiceRegisterRecord() Parameters:
+ *
+ * sdRef: A DNSServiceRef initialized by DNSServiceCreateConnection().
+ *
+ * RecordRef: A pointer to an uninitialized DNSRecordRef. Upon succesfull completion of this
+ * call, this ref may be passed to DNSServiceUpdateRecord() or DNSServiceRemoveRecord().
+ * (To deregister ALL records registered on a single connected DNSServiceRef
+ * and deallocate each of their corresponding DNSServiceRecordRefs, call
+ * DNSServiceRefDeallocate()).
+ *
+ * flags: Possible values are kDNSServiceFlagsShared or kDNSServiceFlagsUnique
+ * (see flag type definitions for details).
+ *
+ * interfaceIndex: If non-zero, specifies the interface on which to register the record
+ * (the index for a given interface is determined via the if_nametoindex()
+ * family of calls.) Passing 0 causes the record to be registered on all interfaces.
+ * See "Constants for specifying an interface index" for more details.
+ *
+ * fullname: The full domain name of the resource record.
+ *
+ * rrtype: The numerical type of the resource record (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
+ *
+ * rrclass: The class of the resource record (usually kDNSServiceClass_IN)
+ *
+ * rdlen: Length, in bytes, of the rdata.
+ *
+ * rdata: A pointer to the raw rdata, as it is to appear in the DNS record.
+ *
+ * ttl: The time to live of the resource record, in seconds.
+ * Most clients should pass 0 to indicate that the system should
+ * select a sensible default value.
+ *
+ * callBack: The function to be called when a result is found, or if the call
+ * asynchronously fails (e.g. because of a name conflict.)
+ *
+ * context: An application context pointer which is passed to the callback function
+ * (may be NULL).
+ *
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
+ * errors are delivered to the callback), otherwise returns an error code indicating
+ * the error that occurred (the callback is never invoked and the DNSRecordRef is
+ * not initialized).
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
+(
+ DNSServiceRef sdRef,
+ DNSRecordRef *RecordRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *fullname,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ uint16_t rdlen,
+ const void *rdata,
+ uint32_t ttl,
+ DNSServiceRegisterRecordReply callBack,
+ void *context /* may be NULL */
+);
+
+
+/* DNSServiceReconfirmRecord
+ *
+ * Instruct the daemon to verify the validity of a resource record that appears
+ * to be out of date (e.g. because TCP connection to a service's target failed.)
+ * Causes the record to be flushed from the daemon's cache (as well as all other
+ * daemons' caches on the network) if the record is determined to be invalid.
+ * Use this routine conservatively. Reconfirming a record necessarily consumes
+ * network bandwidth, so this should not be done indiscriminately.
+ *
+ * Parameters:
+ *
+ * flags: Not currently used.
+ *
+ * interfaceIndex: Specifies the interface of the record in question.
+ * The caller must specify the interface.
+ * This API (by design) causes increased network traffic, so it requires
+ * the caller to be precise about which record should be reconfirmed.
+ * It is not possible to pass zero for the interface index to perform
+ * a "wildcard" reconfirmation, where *all* matching records are reconfirmed.
+ *
+ * fullname: The resource record's full domain name.
+ *
+ * rrtype: The resource record's type (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc)
+ *
+ * rrclass: The class of the resource record (usually kDNSServiceClass_IN).
+ *
+ * rdlen: The length, in bytes, of the resource record rdata.
+ *
+ * rdata: The raw rdata of the resource record.
+ *
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
+(
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *fullname,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ uint16_t rdlen,
+ const void *rdata
+);
+
+
+/*********************************************************************************************
+*
+* NAT Port Mapping
+*
+*********************************************************************************************/
+
+/* DNSServiceNATPortMappingCreate
+ *
+ * Request a port mapping in the NAT gateway, which maps a port on the local machine
+ * to an external port on the NAT. The NAT should support either PCP, NAT-PMP or the
+ * UPnP/IGD protocol for this API to create a successful mapping. Note that this API
+ * currently supports IPv4 addresses/mappings only. If the NAT gateway supports PCP and
+ * returns an IPv6 address (incorrectly, since this API specifically requests IPv4
+ * addresses), the DNSServiceNATPortMappingReply callback will be invoked with errorCode
+ * kDNSServiceErr_NATPortMappingUnsupported.
+ *
+ * The port mapping will be renewed indefinitely until the client process exits, or
+ * explicitly terminates the port mapping request by calling DNSServiceRefDeallocate().
+ * The client callback will be invoked, informing the client of the NAT gateway's
+ * external IP address and the external port that has been allocated for this client.
+ * The client should then record this external IP address and port using whatever
+ * directory service mechanism it is using to enable peers to connect to it.
+ * (Clients advertising services using Wide-Area DNS-SD DO NOT need to use this API
+ * -- when a client calls DNSServiceRegister() NAT mappings are automatically created
+ * and the external IP address and port for the service are recorded in the global DNS.
+ * Only clients using some directory mechanism other than Wide-Area DNS-SD need to use
+ * this API to explicitly map their own ports.)
+ *
+ * It's possible that the client callback could be called multiple times, for example
+ * if the NAT gateway's IP address changes, or if a configuration change results in a
+ * different external port being mapped for this client. Over the lifetime of any long-lived
+ * port mapping, the client should be prepared to handle these notifications of changes
+ * in the environment, and should update its recorded address and/or port as appropriate.
+ *
+ * NOTE: There are two unusual aspects of how the DNSServiceNATPortMappingCreate API works,
+ * which were intentionally designed to help simplify client code:
+ *
+ * 1. It's not an error to request a NAT mapping when the machine is not behind a NAT gateway.
+ * In other NAT mapping APIs, if you request a NAT mapping and the machine is not behind a NAT
+ * gateway, then the API returns an error code -- it can't get you a NAT mapping if there's no
+ * NAT gateway. The DNSServiceNATPortMappingCreate API takes a different view. Working out
+ * whether or not you need a NAT mapping can be tricky and non-obvious, particularly on
+ * a machine with multiple active network interfaces. Rather than make every client recreate
+ * this logic for deciding whether a NAT mapping is required, the PortMapping API does that
+ * work for you. If the client calls the PortMapping API when the machine already has a
+ * routable public IP address, then instead of complaining about it and giving an error,
+ * the PortMapping API just invokes your callback, giving the machine's public address
+ * and your own port number. This means you don't need to write code to work out whether
+ * your client needs to call the PortMapping API -- just call it anyway, and if it wasn't
+ * necessary, no harm is done:
+ *
+ * - If the machine already has a routable public IP address, then your callback
+ * will just be invoked giving your own address and port.
+ * - If a NAT mapping is required and obtained, then your callback will be invoked
+ * giving you the external address and port.
+ * - If a NAT mapping is required but not obtained from the local NAT gateway,
+ * or the machine has no network connectivity, then your callback will be
+ * invoked giving zero address and port.
+ *
+ * 2. In other NAT mapping APIs, if a laptop computer is put to sleep and woken up on a new
+ * network, it's the client's job to notice this, and work out whether a NAT mapping
+ * is required on the new network, and make a new NAT mapping request if necessary.
+ * The DNSServiceNATPortMappingCreate API does this for you, automatically.
+ * The client just needs to make one call to the PortMapping API, and its callback will
+ * be invoked any time the mapping state changes. This property complements point (1) above.
+ * If the client didn't make a NAT mapping request just because it determined that one was
+ * not required at that particular moment in time, the client would then have to monitor
+ * for network state changes to determine if a NAT port mapping later became necessary.
+ * By unconditionally making a NAT mapping request, even when a NAT mapping not to be
+ * necessary, the PortMapping API will then begin monitoring network state changes on behalf of
+ * the client, and if a NAT mapping later becomes necessary, it will automatically create a NAT
+ * mapping and inform the client with a new callback giving the new address and port information.
+ *
+ * DNSServiceNATPortMappingReply() parameters:
+ *
+ * sdRef: The DNSServiceRef initialized by DNSServiceNATPortMappingCreate().
+ *
+ * flags: Currently unused, reserved for future use.
+ *
+ * interfaceIndex: The interface through which the NAT gateway is reached.
+ *
+ * errorCode: Will be kDNSServiceErr_NoError on success.
+ * Will be kDNSServiceErr_DoubleNAT when the NAT gateway is itself behind one or
+ * more layers of NAT, in which case the other parameters have the defined values.
+ * For other failures, will indicate the failure that occurred, and the other
+ * parameters are undefined.
+ *
+ * externalAddress: Four byte IPv4 address in network byte order.
+ *
+ * protocol: Will be kDNSServiceProtocol_UDP or kDNSServiceProtocol_TCP or both.
+ *
+ * internalPort: The port on the local machine that was mapped.
+ *
+ * externalPort: The actual external port in the NAT gateway that was mapped.
+ * This is likely to be different than the requested external port.
+ *
+ * ttl: The lifetime of the NAT port mapping created on the gateway.
+ * This controls how quickly stale mappings will be garbage-collected
+ * if the client machine crashes, suffers a power failure, is disconnected
+ * from the network, or suffers some other unfortunate demise which
+ * causes it to vanish without explicitly removing its NAT port mapping.
+ * It's possible that the ttl value will differ from the requested ttl value.
+ *
+ * context: The context pointer that was passed to the callout.
+ *
+ */
+
+typedef void (DNSSD_API *DNSServiceNATPortMappingReply)
+(
+ DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ uint32_t externalAddress, /* four byte IPv4 address in network byte order */
+ DNSServiceProtocol protocol,
+ uint16_t internalPort, /* In network byte order */
+ uint16_t externalPort, /* In network byte order and may be different than the requested port */
+ uint32_t ttl, /* may be different than the requested ttl */
+ void *context
+);
+
+
+/* DNSServiceNATPortMappingCreate() Parameters:
+ *
+ * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds then it
+ * initializes the DNSServiceRef, returns kDNSServiceErr_NoError, and the nat
+ * port mapping will last indefinitely until the client terminates the port
+ * mapping request by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ *
+ * flags: Currently ignored, reserved for future use.
+ *
+ * interfaceIndex: The interface on which to create port mappings in a NAT gateway. Passing 0 causes
+ * the port mapping request to be sent on the primary interface.
+ *
+ * protocol: To request a port mapping, pass in kDNSServiceProtocol_UDP, or kDNSServiceProtocol_TCP,
+ * or (kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP) to map both.
+ * The local listening port number must also be specified in the internalPort parameter.
+ * To just discover the NAT gateway's external IP address, pass zero for protocol,
+ * internalPort, externalPort and ttl.
+ *
+ * internalPort: The port number in network byte order on the local machine which is listening for packets.
+ *
+ * externalPort: The requested external port in network byte order in the NAT gateway that you would
+ * like to map to the internal port. Pass 0 if you don't care which external port is chosen for you.
+ *
+ * ttl: The requested renewal period of the NAT port mapping, in seconds.
+ * If the client machine crashes, suffers a power failure, is disconnected from
+ * the network, or suffers some other unfortunate demise which causes it to vanish
+ * unexpectedly without explicitly removing its NAT port mappings, then the NAT gateway
+ * will garbage-collect old stale NAT port mappings when their lifetime expires.
+ * Requesting a short TTL causes such orphaned mappings to be garbage-collected
+ * more promptly, but consumes system resources and network bandwidth with
+ * frequent renewal packets to keep the mapping from expiring.
+ * Requesting a long TTL is more efficient on the network, but in the event of the
+ * client vanishing, stale NAT port mappings will not be garbage-collected as quickly.
+ * Most clients should pass 0 to use a system-wide default value.
+ *
+ * callBack: The function to be called when the port mapping request succeeds or fails asynchronously.
+ *
+ * context: An application context pointer which is passed to the callback function
+ * (may be NULL).
+ *
+ * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous
+ * errors are delivered to the callback), otherwise returns an error code indicating
+ * the error that occurred.
+ *
+ * If you don't actually want a port mapped, and are just calling the API
+ * because you want to find out the NAT's external IP address (e.g. for UI
+ * display) then pass zero for protocol, internalPort, externalPort and ttl.
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceProtocol protocol, /* TCP and/or UDP */
+ uint16_t internalPort, /* network byte order */
+ uint16_t externalPort, /* network byte order */
+ uint32_t ttl, /* time to live in seconds */
+ DNSServiceNATPortMappingReply callBack,
+ void *context /* may be NULL */
+);
+
+
+/*********************************************************************************************
+*
+* General Utility Functions
+*
+*********************************************************************************************/
+
+/* DNSServiceConstructFullName()
+ *
+ * Concatenate a three-part domain name (as returned by the above callbacks) into a
+ * properly-escaped full domain name. Note that callbacks in the above functions ALREADY ESCAPE
+ * strings where necessary.
+ *
+ * Parameters:
+ *
+ * fullName: A pointer to a buffer that where the resulting full domain name is to be written.
+ * The buffer must be kDNSServiceMaxDomainName (1009) bytes in length to
+ * accommodate the longest legal domain name without buffer overrun.
+ *
+ * service: The service name - any dots or backslashes must NOT be escaped.
+ * May be NULL (to construct a PTR record name, e.g.
+ * "_ftp._tcp.apple.com.").
+ *
+ * regtype: The service type followed by the protocol, separated by a dot
+ * (e.g. "_ftp._tcp").
+ *
+ * domain: The domain name, e.g. "apple.com.". Literal dots or backslashes,
+ * if any, must be escaped, e.g. "1st\. Floor.apple.com."
+ *
+ * return value: Returns kDNSServiceErr_NoError (0) on success, kDNSServiceErr_BadParam on error.
+ *
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceConstructFullName
+(
+ char * const fullName,
+ const char * const service, /* may be NULL */
+ const char * const regtype,
+ const char * const domain
+);
+
+
+/*********************************************************************************************
+*
+* TXT Record Construction Functions
+*
+*********************************************************************************************/
+
+/*
+ * A typical calling sequence for TXT record construction is something like:
+ *
+ * Client allocates storage for TXTRecord data (e.g. declare buffer on the stack)
+ * TXTRecordCreate();
+ * TXTRecordSetValue();
+ * TXTRecordSetValue();
+ * TXTRecordSetValue();
+ * ...
+ * DNSServiceRegister( ... TXTRecordGetLength(), TXTRecordGetBytesPtr() ... );
+ * TXTRecordDeallocate();
+ * Explicitly deallocate storage for TXTRecord data (if not allocated on the stack)
+ */
+
+
+/* TXTRecordRef
+ *
+ * Opaque internal data type.
+ * Note: Represents a DNS-SD TXT record.
+ */
+
+typedef union _TXTRecordRef_t { char PrivateData[16]; char *ForceNaturalAlignment; } TXTRecordRef;
+
+
+/* TXTRecordCreate()
+ *
+ * Creates a new empty TXTRecordRef referencing the specified storage.
+ *
+ * If the buffer parameter is NULL, or the specified storage size is not
+ * large enough to hold a key subsequently added using TXTRecordSetValue(),
+ * then additional memory will be added as needed using malloc().
+ *
+ * On some platforms, when memory is low, malloc() may fail. In this
+ * case, TXTRecordSetValue() will return kDNSServiceErr_NoMemory, and this
+ * error condition will need to be handled as appropriate by the caller.
+ *
+ * You can avoid the need to handle this error condition if you ensure
+ * that the storage you initially provide is large enough to hold all
+ * the key/value pairs that are to be added to the record.
+ * The caller can precompute the exact length required for all of the
+ * key/value pairs to be added, or simply provide a fixed-sized buffer
+ * known in advance to be large enough.
+ * A no-value (key-only) key requires (1 + key length) bytes.
+ * A key with empty value requires (1 + key length + 1) bytes.
+ * A key with non-empty value requires (1 + key length + 1 + value length).
+ * For most applications, DNS-SD TXT records are generally
+ * less than 100 bytes, so in most cases a simple fixed-sized
+ * 256-byte buffer will be more than sufficient.
+ * Recommended size limits for DNS-SD TXT Records are discussed in
+ * <http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt>
+ *
+ * Note: When passing parameters to and from these TXT record APIs,
+ * the key name does not include the '=' character. The '=' character
+ * is the separator between the key and value in the on-the-wire
+ * packet format; it is not part of either the key or the value.
+ *
+ * txtRecord: A pointer to an uninitialized TXTRecordRef.
+ *
+ * bufferLen: The size of the storage provided in the "buffer" parameter.
+ *
+ * buffer: Optional caller-supplied storage used to hold the TXTRecord data.
+ * This storage must remain valid for as long as
+ * the TXTRecordRef.
+ */
+
+void DNSSD_API TXTRecordCreate
+(
+ TXTRecordRef *txtRecord,
+ uint16_t bufferLen,
+ void *buffer
+);
+
+
+/* TXTRecordDeallocate()
+ *
+ * Releases any resources allocated in the course of preparing a TXT Record
+ * using TXTRecordCreate()/TXTRecordSetValue()/TXTRecordRemoveValue().
+ * Ownership of the buffer provided in TXTRecordCreate() returns to the client.
+ *
+ * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate().
+ *
+ */
+
+void DNSSD_API TXTRecordDeallocate
+(
+ TXTRecordRef *txtRecord
+);
+
+
+/* TXTRecordSetValue()
+ *
+ * Adds a key (optionally with value) to a TXTRecordRef. If the "key" already
+ * exists in the TXTRecordRef, then the current value will be replaced with
+ * the new value.
+ * Keys may exist in four states with respect to a given TXT record:
+ * - Absent (key does not appear at all)
+ * - Present with no value ("key" appears alone)
+ * - Present with empty value ("key=" appears in TXT record)
+ * - Present with non-empty value ("key=value" appears in TXT record)
+ * For more details refer to "Data Syntax for DNS-SD TXT Records" in
+ * <http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt>
+ *
+ * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate().
+ *
+ * key: A null-terminated string which only contains printable ASCII
+ * values (0x20-0x7E), excluding '=' (0x3D). Keys should be
+ * 9 characters or fewer (not counting the terminating null).
+ *
+ * valueSize: The size of the value.
+ *
+ * value: Any binary value. For values that represent
+ * textual data, UTF-8 is STRONGLY recommended.
+ * For values that represent textual data, valueSize
+ * should NOT include the terminating null (if any)
+ * at the end of the string.
+ * If NULL, then "key" will be added with no value.
+ * If non-NULL but valueSize is zero, then "key=" will be
+ * added with empty value.
+ *
+ * return value: Returns kDNSServiceErr_NoError on success.
+ * Returns kDNSServiceErr_Invalid if the "key" string contains
+ * illegal characters.
+ * Returns kDNSServiceErr_NoMemory if adding this key would
+ * exceed the available storage.
+ */
+
+DNSServiceErrorType DNSSD_API TXTRecordSetValue
+(
+ TXTRecordRef *txtRecord,
+ const char *key,
+ uint8_t valueSize, /* may be zero */
+ const void *value /* may be NULL */
+);
+
+
+/* TXTRecordRemoveValue()
+ *
+ * Removes a key from a TXTRecordRef. The "key" must be an
+ * ASCII string which exists in the TXTRecordRef.
+ *
+ * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate().
+ *
+ * key: A key name which exists in the TXTRecordRef.
+ *
+ * return value: Returns kDNSServiceErr_NoError on success.
+ * Returns kDNSServiceErr_NoSuchKey if the "key" does not
+ * exist in the TXTRecordRef.
+ */
+
+DNSServiceErrorType DNSSD_API TXTRecordRemoveValue
+(
+ TXTRecordRef *txtRecord,
+ const char *key
+);
+
+
+/* TXTRecordGetLength()
+ *
+ * Allows you to determine the length of the raw bytes within a TXTRecordRef.
+ *
+ * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate().
+ *
+ * return value: Returns the size of the raw bytes inside a TXTRecordRef
+ * which you can pass directly to DNSServiceRegister() or
+ * to DNSServiceUpdateRecord().
+ * Returns 0 if the TXTRecordRef is empty.
+ */
+
+uint16_t DNSSD_API TXTRecordGetLength
+(
+ const TXTRecordRef *txtRecord
+);
+
+
+/* TXTRecordGetBytesPtr()
+ *
+ * Allows you to retrieve a pointer to the raw bytes within a TXTRecordRef.
+ *
+ * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate().
+ *
+ * return value: Returns a pointer to the raw bytes inside the TXTRecordRef
+ * which you can pass directly to DNSServiceRegister() or
+ * to DNSServiceUpdateRecord().
+ */
+
+const void * DNSSD_API TXTRecordGetBytesPtr
+(
+ const TXTRecordRef *txtRecord
+);
+
+
+/*********************************************************************************************
+*
+* TXT Record Parsing Functions
+*
+*********************************************************************************************/
+
+/*
+ * A typical calling sequence for TXT record parsing is something like:
+ *
+ * Receive TXT record data in DNSServiceResolve() callback
+ * if (TXTRecordContainsKey(txtLen, txtRecord, "key")) then do something
+ * val1ptr = TXTRecordGetValuePtr(txtLen, txtRecord, "key1", &len1);
+ * val2ptr = TXTRecordGetValuePtr(txtLen, txtRecord, "key2", &len2);
+ * ...
+ * memcpy(myval1, val1ptr, len1);
+ * memcpy(myval2, val2ptr, len2);
+ * ...
+ * return;
+ *
+ * If you wish to retain the values after return from the DNSServiceResolve()
+ * callback, then you need to copy the data to your own storage using memcpy()
+ * or similar, as shown in the example above.
+ *
+ * If for some reason you need to parse a TXT record you built yourself
+ * using the TXT record construction functions above, then you can do
+ * that using TXTRecordGetLength and TXTRecordGetBytesPtr calls:
+ * TXTRecordGetValue(TXTRecordGetLength(x), TXTRecordGetBytesPtr(x), key, &len);
+ *
+ * Most applications only fetch keys they know about from a TXT record and
+ * ignore the rest.
+ * However, some debugging tools wish to fetch and display all keys.
+ * To do that, use the TXTRecordGetCount() and TXTRecordGetItemAtIndex() calls.
+ */
+
+/* TXTRecordContainsKey()
+ *
+ * Allows you to determine if a given TXT Record contains a specified key.
+ *
+ * txtLen: The size of the received TXT Record.
+ *
+ * txtRecord: Pointer to the received TXT Record bytes.
+ *
+ * key: A null-terminated ASCII string containing the key name.
+ *
+ * return value: Returns 1 if the TXT Record contains the specified key.
+ * Otherwise, it returns 0.
+ */
+
+int DNSSD_API TXTRecordContainsKey
+(
+ uint16_t txtLen,
+ const void *txtRecord,
+ const char *key
+);
+
+
+/* TXTRecordGetValuePtr()
+ *
+ * Allows you to retrieve the value for a given key from a TXT Record.
+ *
+ * txtLen: The size of the received TXT Record
+ *
+ * txtRecord: Pointer to the received TXT Record bytes.
+ *
+ * key: A null-terminated ASCII string containing the key name.
+ *
+ * valueLen: On output, will be set to the size of the "value" data.
+ *
+ * return value: Returns NULL if the key does not exist in this TXT record,
+ * or exists with no value (to differentiate between
+ * these two cases use TXTRecordContainsKey()).
+ * Returns pointer to location within TXT Record bytes
+ * if the key exists with empty or non-empty value.
+ * For empty value, valueLen will be zero.
+ * For non-empty value, valueLen will be length of value data.
+ */
+
+const void * DNSSD_API TXTRecordGetValuePtr
+(
+ uint16_t txtLen,
+ const void *txtRecord,
+ const char *key,
+ uint8_t *valueLen
+);
+
+
+/* TXTRecordGetCount()
+ *
+ * Returns the number of keys stored in the TXT Record. The count
+ * can be used with TXTRecordGetItemAtIndex() to iterate through the keys.
+ *
+ * txtLen: The size of the received TXT Record.
+ *
+ * txtRecord: Pointer to the received TXT Record bytes.
+ *
+ * return value: Returns the total number of keys in the TXT Record.
+ *
+ */
+
+uint16_t DNSSD_API TXTRecordGetCount
+(
+ uint16_t txtLen,
+ const void *txtRecord
+);
+
+
+/* TXTRecordGetItemAtIndex()
+ *
+ * Allows you to retrieve a key name and value pointer, given an index into
+ * a TXT Record. Legal index values range from zero to TXTRecordGetCount()-1.
+ * It's also possible to iterate through keys in a TXT record by simply
+ * calling TXTRecordGetItemAtIndex() repeatedly, beginning with index zero
+ * and increasing until TXTRecordGetItemAtIndex() returns kDNSServiceErr_Invalid.
+ *
+ * On return:
+ * For keys with no value, *value is set to NULL and *valueLen is zero.
+ * For keys with empty value, *value is non-NULL and *valueLen is zero.
+ * For keys with non-empty value, *value is non-NULL and *valueLen is non-zero.
+ *
+ * txtLen: The size of the received TXT Record.
+ *
+ * txtRecord: Pointer to the received TXT Record bytes.
+ *
+ * itemIndex: An index into the TXT Record.
+ *
+ * keyBufLen: The size of the string buffer being supplied.
+ *
+ * key: A string buffer used to store the key name.
+ * On return, the buffer contains a null-terminated C string
+ * giving the key name. DNS-SD TXT keys are usually
+ * 9 characters or fewer. To hold the maximum possible
+ * key name, the buffer should be 256 bytes long.
+ *
+ * valueLen: On output, will be set to the size of the "value" data.
+ *
+ * value: On output, *value is set to point to location within TXT
+ * Record bytes that holds the value data.
+ *
+ * return value: Returns kDNSServiceErr_NoError on success.
+ * Returns kDNSServiceErr_NoMemory if keyBufLen is too short.
+ * Returns kDNSServiceErr_Invalid if index is greater than
+ * TXTRecordGetCount()-1.
+ */
+
+DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex
+(
+ uint16_t txtLen,
+ const void *txtRecord,
+ uint16_t itemIndex,
+ uint16_t keyBufLen,
+ char *key,
+ uint8_t *valueLen,
+ const void **value
+);
+
+#if _DNS_SD_LIBDISPATCH
+/*
+ * DNSServiceSetDispatchQueue
+ *
+ * Allows you to schedule a DNSServiceRef on a serial dispatch queue for receiving asynchronous
+ * callbacks. It's the clients responsibility to ensure that the provided dispatch queue is running.
+ *
+ * A typical application that uses CFRunLoopRun or dispatch_main on its main thread will
+ * usually schedule DNSServiceRefs on its main queue (which is always a serial queue)
+ * using "DNSServiceSetDispatchQueue(sdref, dispatch_get_main_queue());"
+ *
+ * If there is any error during the processing of events, the application callback will
+ * be called with an error code. For shared connections, each subordinate DNSServiceRef
+ * will get its own error callback. Currently these error callbacks only happen
+ * if the daemon is manually terminated or crashes, and the error
+ * code in this case is kDNSServiceErr_ServiceNotRunning. The application must call
+ * DNSServiceRefDeallocate to free the DNSServiceRef when it gets such an error code.
+ * These error callbacks are rare and should not normally happen on customer machines,
+ * but application code should be written defensively to handle such error callbacks
+ * gracefully if they occur.
+ *
+ * After using DNSServiceSetDispatchQueue on a DNSServiceRef, calling DNSServiceProcessResult
+ * on the same DNSServiceRef will result in undefined behavior and should be avoided.
+ *
+ * Once the application successfully schedules a DNSServiceRef on a serial dispatch queue using
+ * DNSServiceSetDispatchQueue, it cannot remove the DNSServiceRef from the dispatch queue, or use
+ * DNSServiceSetDispatchQueue a second time to schedule the DNSServiceRef onto a different serial dispatch
+ * queue. Once scheduled onto a dispatch queue a DNSServiceRef will deliver events to that queue until
+ * the application no longer requires that operation and terminates it using DNSServiceRefDeallocate.
+ *
+ * service: DNSServiceRef that was allocated and returned to the application, when the
+ * application calls one of the DNSService API.
+ *
+ * queue: dispatch queue where the application callback will be scheduled
+ *
+ * return value: Returns kDNSServiceErr_NoError on success.
+ * Returns kDNSServiceErr_NoMemory if it cannot create a dispatch source
+ * Returns kDNSServiceErr_BadParam if the service param is invalid or the
+ * queue param is invalid
+ */
+
+DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue
+(
+ DNSServiceRef service,
+ dispatch_queue_t queue
+);
+#endif //_DNS_SD_LIBDISPATCH
+
+#if !defined(_WIN32)
+typedef void (DNSSD_API *DNSServiceSleepKeepaliveReply)
+(
+ DNSServiceRef sdRef,
+ DNSServiceErrorType errorCode,
+ void *context
+);
+DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ int fd,
+ unsigned int timeout,
+ DNSServiceSleepKeepaliveReply callBack,
+ void *context
+);
+#endif
+
+#ifdef APPLE_OSX_mDNSResponder
+/* DNSServiceCreateDelegateConnection()
+ *
+ * Create a delegate connection to the daemon allowing efficient registration of
+ * multiple individual records.
+ *
+ * Parameters:
+ *
+ * sdRef: A pointer to an uninitialized DNSServiceRef. Deallocating
+ * the reference (via DNSServiceRefDeallocate()) severs the
+ * connection and deregisters all records registered on this connection.
+ *
+ * pid : Process ID of the delegate
+ *
+ * uuid: UUID of the delegate
+ *
+ * Note that only one of the two arguments (pid or uuid) can be specified. If pid
+ * is zero, uuid will be assumed to be a valid value; otherwise pid will be used.
+ *
+ * return value: Returns kDNSServiceErr_NoError on success, otherwise returns
+ * an error code indicating the specific failure that occurred (in which
+ * case the DNSServiceRef is not initialized). kDNSServiceErr_NotAuth is
+ * returned to indicate that the calling process does not have entitlements
+ * to use this API.
+ */
+DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid);
+#endif
+
+#ifdef __APPLE_API_PRIVATE
+
+#define kDNSServiceCompPrivateDNS "PrivateDNS"
+#define kDNSServiceCompMulticastDNS "MulticastDNS"
+
+#endif //__APPLE_API_PRIVATE
+
+/* Some C compiler cleverness. We can make the compiler check certain things for us,
+ * and report errors at compile-time if anything is wrong. The usual way to do this would
+ * be to use a run-time "if" statement or the conventional run-time "assert" mechanism, but
+ * then you don't find out what's wrong until you run the software. This way, if the assertion
+ * condition is false, the array size is negative, and the complier complains immediately.
+ */
+
+struct CompileTimeAssertionChecks_DNS_SD
+{
+ char assert0[(sizeof(union _TXTRecordRef_t) == 16) ? 1 : -1];
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DNS_SD_H */
Deleted: vendor/apple/mDNSResponder/561.1.1/mDNSShared/dnssd_clientstub.c
===================================================================
--- vendor/apple/mDNSResponder/dist/mDNSShared/dnssd_clientstub.c 2014-06-30 23:58:12 UTC (rev 6706)
+++ vendor/apple/mDNSResponder/561.1.1/mDNSShared/dnssd_clientstub.c 2015-03-20 01:14:52 UTC (rev 6985)
@@ -1,2363 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2004, Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <errno.h>
-#include <stdlib.h>
-
-#if APPLE_OSX_mDNSResponder
-#include <mach-o/dyld.h>
-#include <uuid/uuid.h>
-#include <TargetConditionals.h>
-#endif
-
-#include "dnssd_ipc.h"
-
-static int gDaemonErr = kDNSServiceErr_NoError;
-
-#if defined(_WIN32)
-
- #define _SSIZE_T
- #include <CommonServices.h>
- #include <DebugServices.h>
- #include <winsock2.h>
- #include <ws2tcpip.h>
- #include <windows.h>
- #include <stdarg.h>
- #include <stdio.h>
-
- #define sockaddr_mdns sockaddr_in
- #define AF_MDNS AF_INET
-
-// Disable warning: "'type cast' : from data pointer 'void *' to function pointer"
- #pragma warning(disable:4055)
-
-// Disable warning: "nonstandard extension, function/data pointer conversion in expression"
- #pragma warning(disable:4152)
-
-extern BOOL IsSystemServiceDisabled();
-
- #define sleep(X) Sleep((X) * 1000)
-
-static int g_initWinsock = 0;
- #define LOG_WARNING kDebugLevelWarning
- #define LOG_INFO kDebugLevelInfo
-static void syslog( int priority, const char * message, ...)
-{
- va_list args;
- int len;
- char * buffer;
- DWORD err = WSAGetLastError();
- (void) priority;
- va_start( args, message );
- len = _vscprintf( message, args ) + 1;
- buffer = malloc( len * sizeof(char) );
- if ( buffer ) { vsprintf( buffer, message, args ); OutputDebugString( buffer ); free( buffer ); }
- WSASetLastError( err );
-}
-#else
-
- #include <sys/fcntl.h> // For O_RDWR etc.
- #include <sys/time.h>
- #include <sys/socket.h>
- #include <syslog.h>
-
- #define sockaddr_mdns sockaddr_un
- #define AF_MDNS AF_LOCAL
-
-#endif
-
-// <rdar://problem/4096913> Specifies how many times we'll try and connect to the server.
-
-#define DNSSD_CLIENT_MAXTRIES 4
-
-// Uncomment the line below to use the old error return mechanism of creating a temporary named socket (e.g. in /var/tmp)
-//#define USE_NAMED_ERROR_RETURN_SOCKET 1
-
-// If the UDS client has not received a response from the daemon in 60 secs, it is unlikely to get one
-// Note: Timeout of 3 secs should be sufficient in normal scenarios, but 60 secs is chosen as a safeguard since
-// some clients may come up before mDNSResponder itself after a BOOT and on rare ocassions IOPM/Keychain/D2D calls
-// in mDNSResponder's INIT may take a much longer time to return
-#define DNSSD_CLIENT_TIMEOUT 60
-
-#ifndef CTL_PATH_PREFIX
-#define CTL_PATH_PREFIX "/var/tmp/dnssd_result_socket."
-#endif
-
-typedef struct
-{
- ipc_msg_hdr ipc_hdr;
- DNSServiceFlags cb_flags;
- uint32_t cb_interface;
- DNSServiceErrorType cb_err;
-} CallbackHeader;
-
-typedef struct _DNSServiceRef_t DNSServiceOp;
-typedef struct _DNSRecordRef_t DNSRecord;
-
-#if !defined(_WIN32)
-typedef struct
-{
- void *AppCallback; // Client callback function and context
- void *AppContext;
-} SleepKAContext;
-#endif
-
-// client stub callback to process message from server and deliver results to client application
-typedef void (*ProcessReplyFn)(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *msg, const char *const end);
-
-#define ValidatorBits 0x12345678
-#define DNSServiceRefValid(X) (dnssd_SocketValid((X)->sockfd) && (((X)->sockfd ^ (X)->validator) == ValidatorBits))
-
-// When using kDNSServiceFlagsShareConnection, there is one primary _DNSServiceOp_t, and zero or more subordinates
-// For the primary, the 'next' field points to the first subordinate, and its 'next' field points to the next, and so on.
-// For the primary, the 'primary' field is NULL; for subordinates the 'primary' field points back to the associated primary
-//
-// _DNS_SD_LIBDISPATCH is defined where libdispatch/GCD is available. This does not mean that the application will use the
-// DNSServiceSetDispatchQueue API. Hence any new code guarded with _DNS_SD_LIBDISPATCH should still be backwards compatible.
-struct _DNSServiceRef_t
-{
- DNSServiceOp *next; // For shared connection
- DNSServiceOp *primary; // For shared connection
- dnssd_sock_t sockfd; // Connected socket between client and daemon
- dnssd_sock_t validator; // Used to detect memory corruption, double disposals, etc.
- client_context_t uid; // For shared connection requests, each subordinate DNSServiceRef has its own ID,
- // unique within the scope of the same shared parent DNSServiceRef
- uint32_t op; // request_op_t or reply_op_t
- uint32_t max_index; // Largest assigned record index - 0 if no additional records registered
- uint32_t logcounter; // Counter used to control number of syslog messages we write
- int *moreptr; // Set while DNSServiceProcessResult working on this particular DNSServiceRef
- ProcessReplyFn ProcessReply; // Function pointer to the code to handle received messages
- void *AppCallback; // Client callback function and context
- void *AppContext;
- DNSRecord *rec;
-#if _DNS_SD_LIBDISPATCH
- dispatch_source_t disp_source;
- dispatch_queue_t disp_queue;
-#endif
- void *kacontext;
-};
-
-struct _DNSRecordRef_t
-{
- DNSRecord *recnext;
- void *AppContext;
- DNSServiceRegisterRecordReply AppCallback;
- DNSRecordRef recref;
- uint32_t record_index; // index is unique to the ServiceDiscoveryRef
- client_context_t uid; // For demultiplexing multiple DNSServiceRegisterRecord calls
- DNSServiceOp *sdr;
-};
-
-// Write len bytes. Return 0 on success, -1 on error
-static int write_all(dnssd_sock_t sd, char *buf, size_t len)
-{
- // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
- //if (send(sd, buf, len, MSG_WAITALL) != len) return -1;
- while (len)
- {
- ssize_t num_written = send(sd, buf, (long)len, 0);
- if (num_written < 0 || (size_t)num_written > len)
- {
- // Should never happen. If it does, it indicates some OS bug,
- // or that the mDNSResponder daemon crashed (which should never happen).
- #if !defined(__ppc__) && defined(SO_ISDEFUNCT)
- int defunct;
- socklen_t dlen = sizeof (defunct);
- if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0)
- syslog(LOG_WARNING, "dnssd_clientstub write_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
- if (!defunct)
- syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
- (long)num_written, (long)len,
- (num_written < 0) ? dnssd_errno : 0,
- (num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
- else
- syslog(LOG_INFO, "dnssd_clientstub write_all(%d) DEFUNCT", sd);
- #else
- syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
- (long)num_written, (long)len,
- (num_written < 0) ? dnssd_errno : 0,
- (num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
- #endif
- return -1;
- }
- buf += num_written;
- len -= num_written;
- }
- return 0;
-}
-
-enum { read_all_success = 0, read_all_fail = -1, read_all_wouldblock = -2 };
-
-// Read len bytes. Return 0 on success, read_all_fail on error, or read_all_wouldblock for
-static int read_all(dnssd_sock_t sd, char *buf, int len)
-{
- // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
- //if (recv(sd, buf, len, MSG_WAITALL) != len) return -1;
-
- while (len)
- {
- ssize_t num_read = recv(sd, buf, len, 0);
- // It is valid to get an interrupted system call error e.g., somebody attaching
- // in a debugger, retry without failing
- if ((num_read < 0) && (errno == EINTR))
- {
- syslog(LOG_INFO, "dnssd_clientstub read_all: EINTR continue");
- continue;
- }
- if ((num_read == 0) || (num_read < 0) || (num_read > len))
- {
- int printWarn = 0;
- int defunct = 0;
- // Should never happen. If it does, it indicates some OS bug,
- // or that the mDNSResponder daemon crashed (which should never happen).
-#if defined(WIN32)
- // <rdar://problem/7481776> Suppress logs for "A non-blocking socket operation
- // could not be completed immediately"
- if (WSAGetLastError() != WSAEWOULDBLOCK)
- printWarn = 1;
-#endif
-#if !defined(__ppc__) && defined(SO_ISDEFUNCT)
- {
- socklen_t dlen = sizeof (defunct);
- if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0)
- syslog(LOG_WARNING, "dnssd_clientstub read_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
- }
- if (!defunct)
- printWarn = 1;
-#endif
- if (printWarn)
- syslog(LOG_WARNING, "dnssd_clientstub read_all(%d) failed %ld/%ld %d %s", sd,
- (long)num_read, (long)len,
- (num_read < 0) ? dnssd_errno : 0,
- (num_read < 0) ? dnssd_strerror(dnssd_errno) : "");
- else if (defunct)
- syslog(LOG_INFO, "dnssd_clientstub read_all(%d) DEFUNCT", sd);
- return (num_read < 0 && dnssd_errno == dnssd_EWOULDBLOCK) ? read_all_wouldblock : read_all_fail;
- }
- buf += num_read;
- len -= num_read;
- }
- return read_all_success;
-}
-
-// Returns 1 if more bytes remain to be read on socket descriptor sd, 0 otherwise
-static int more_bytes(dnssd_sock_t sd)
-{
- struct timeval tv = { 0, 0 };
- fd_set readfds;
- fd_set *fs;
- int ret;
-
- if (sd < FD_SETSIZE)
- {
- fs = &readfds;
- FD_ZERO(fs);
- }
- else
- {
- // Compute the number of integers needed for storing "sd". Internally fd_set is stored
- // as an array of ints with one bit for each fd and hence we need to compute
- // the number of ints needed rather than the number of bytes. If "sd" is 32, we need
- // two ints and not just one.
- int nfdbits = sizeof (int) * 8;
- int nints = (sd/nfdbits) + 1;
- fs = (fd_set *)calloc(nints, sizeof(int));
- if (fs == NULL)
- {
- syslog(LOG_WARNING, "dnssd_clientstub more_bytes: malloc failed");
- return 0;
- }
- }
- FD_SET(sd, fs);
- ret = select((int)sd+1, fs, (fd_set*)NULL, (fd_set*)NULL, &tv);
- if (fs != &readfds)
- free(fs);
- return (ret > 0);
-}
-
-// set_waitlimit() implements a timeout using select. It is called from deliver_request() before recv() OR accept()
-// to ensure the UDS clients are not blocked in these system calls indefinitely.
-// Note: Ideally one should never be blocked here, because it indicates either mDNSResponder daemon is not yet up/hung/
-// superbusy/crashed or some other OS bug. For eg: On Windows which suffers from 3rd party software
-// (primarily 3rd party firewall software) interfering with proper functioning of the TCP protocol stack it is possible
-// the next operation on this socket(recv/accept) is blocked since we depend on TCP to communicate with the system service.
-static int set_waitlimit(dnssd_sock_t sock, int timeout)
-{
- // To prevent stack corruption since select does not work with timeout if fds > FD_SETSIZE(1024)
- if (!gDaemonErr && sock < FD_SETSIZE)
- {
- struct timeval tv;
- fd_set set;
-
- FD_ZERO(&set);
- FD_SET(sock, &set);
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
- if (!select((int)(sock + 1), &set, NULL, NULL, &tv))
- {
- // Ideally one should never hit this case: See comments before set_waitlimit()
- syslog(LOG_WARNING, "dnssd_clientstub set_waitlimit:_daemon timed out (%d secs) without any response: Socket %d", timeout, sock);
- gDaemonErr = kDNSServiceErr_Timeout;
- }
- }
- return gDaemonErr;
-}
-
-/* create_hdr
- *
- * allocate and initialize an ipc message header. Value of len should initially be the
- * length of the data, and is set to the value of the data plus the header. data_start
- * is set to point to the beginning of the data section. SeparateReturnSocket should be
- * non-zero for calls that can't receive an immediate error return value on their primary
- * socket, and therefore require a separate return path for the error code result.
- * if zero, the path to a control socket is appended at the beginning of the message buffer.
- * data_start is set past this string.
- */
-static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int SeparateReturnSocket, DNSServiceOp *ref)
-{
- char *msg = NULL;
- ipc_msg_hdr *hdr;
- int datalen;
-#if !defined(USE_TCP_LOOPBACK)
- char ctrl_path[64] = ""; // "/var/tmp/dnssd_result_socket.xxxxxxxxxx-xxx-xxxxxx"
-#endif
-
- if (SeparateReturnSocket)
- {
-#if defined(USE_TCP_LOOPBACK)
- *len += 2; // Allocate space for two-byte port number
-#elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
- struct timeval tv;
- if (gettimeofday(&tv, NULL) < 0)
- { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: gettimeofday failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); return NULL; }
- sprintf(ctrl_path, "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX, (int)getpid(),
- (unsigned long)(tv.tv_sec & 0xFFF), (unsigned long)(tv.tv_usec));
- *len += strlen(ctrl_path) + 1;
-#else
- *len += 1; // Allocate space for single zero byte (empty C string)
-#endif
- }
-
- datalen = (int) *len;
- *len += sizeof(ipc_msg_hdr);
-
- // Write message to buffer
- msg = malloc(*len);
- if (!msg) { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: malloc failed"); return NULL; }
-
- memset(msg, 0, *len);
- hdr = (ipc_msg_hdr *)msg;
- hdr->version = VERSION;
- hdr->datalen = datalen;
- hdr->ipc_flags = 0;
- hdr->op = op;
- hdr->client_context = ref->uid;
- hdr->reg_index = 0;
- *data_start = msg + sizeof(ipc_msg_hdr);
-#if defined(USE_TCP_LOOPBACK)
- // Put dummy data in for the port, since we don't know what it is yet.
- // The data will get filled in before we send the message. This happens in deliver_request().
- if (SeparateReturnSocket) put_uint16(0, data_start);
-#else
- if (SeparateReturnSocket) put_string(ctrl_path, data_start);
-#endif
- return hdr;
-}
-
-static void FreeDNSRecords(DNSServiceOp *sdRef)
-{
- DNSRecord *rec = sdRef->rec;
- while (rec)
- {
- DNSRecord *next = rec->recnext;
- free(rec);
- rec = next;
- }
-}
-
-static void FreeDNSServiceOp(DNSServiceOp *x)
-{
- // We don't use our DNSServiceRefValid macro here because if we're cleaning up after a socket() call failed
- // then sockfd could legitimately contain a failing value (e.g. dnssd_InvalidSocket)
- if ((x->sockfd ^ x->validator) != ValidatorBits)
- syslog(LOG_WARNING, "dnssd_clientstub attempt to dispose invalid DNSServiceRef %p %08X %08X", x, x->sockfd, x->validator);
- else
- {
- x->next = NULL;
- x->primary = NULL;
- x->sockfd = dnssd_InvalidSocket;
- x->validator = 0xDDDDDDDD;
- x->op = request_op_none;
- x->max_index = 0;
- x->logcounter = 0;
- x->moreptr = NULL;
- x->ProcessReply = NULL;
- x->AppCallback = NULL;
- x->AppContext = NULL;
-#if _DNS_SD_LIBDISPATCH
- if (x->disp_source) dispatch_release(x->disp_source);
- x->disp_source = NULL;
- x->disp_queue = NULL;
-#endif
- // DNSRecords may have been added to subordinate sdRef e.g., DNSServiceRegister/DNSServiceAddRecord
- // or on the main sdRef e.g., DNSServiceCreateConnection/DNSServiveRegisterRecord. DNSRecords may have
- // been freed if the application called DNSRemoveRecord
- FreeDNSRecords(x);
- if (x->kacontext)
- {
- free(x->kacontext);
- x->kacontext = NULL;
- }
- free(x);
- }
-}
-
-// Return a connected service ref (deallocate with DNSServiceRefDeallocate)
-static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags flags, uint32_t op, ProcessReplyFn ProcessReply, void *AppCallback, void *AppContext)
-{
- int NumTries = 0;
-
- dnssd_sockaddr_t saddr;
- DNSServiceOp *sdr;
-
- if (!ref)
- {
- syslog(LOG_WARNING, "dnssd_clientstub DNSService operation with NULL DNSServiceRef");
- return kDNSServiceErr_BadParam;
- }
-
- if (flags & kDNSServiceFlagsShareConnection)
- {
- if (!*ref)
- {
- syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with NULL DNSServiceRef");
- return kDNSServiceErr_BadParam;
- }
- if (!DNSServiceRefValid(*ref) || ((*ref)->op != connection_request && (*ref)->op != connection_delegate_request) || (*ref)->primary)
- {
- syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with invalid DNSServiceRef %p %08X %08X op %d",
- (*ref), (*ref)->sockfd, (*ref)->validator, (*ref)->op);
- *ref = NULL;
- return kDNSServiceErr_BadReference;
- }
- }
-
- #if defined(_WIN32)
- if (!g_initWinsock)
- {
- WSADATA wsaData;
- g_initWinsock = 1;
- if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { *ref = NULL; return kDNSServiceErr_ServiceNotRunning; }
- }
- // <rdar://problem/4096913> If the system service is disabled, we only want to try to connect once
- if (IsSystemServiceDisabled())
- NumTries = DNSSD_CLIENT_MAXTRIES;
- #endif
-
- sdr = malloc(sizeof(DNSServiceOp));
- if (!sdr)
- {
- syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: malloc failed");
- *ref = NULL;
- return kDNSServiceErr_NoMemory;
- }
- sdr->next = NULL;
- sdr->primary = NULL;
- sdr->sockfd = dnssd_InvalidSocket;
- sdr->validator = sdr->sockfd ^ ValidatorBits;
- sdr->op = op;
- sdr->max_index = 0;
- sdr->logcounter = 0;
- sdr->moreptr = NULL;
- sdr->uid.u32[0] = 0;
- sdr->uid.u32[1] = 0;
- sdr->ProcessReply = ProcessReply;
- sdr->AppCallback = AppCallback;
- sdr->AppContext = AppContext;
- sdr->rec = NULL;
-#if _DNS_SD_LIBDISPATCH
- sdr->disp_source = NULL;
- sdr->disp_queue = NULL;
-#endif
- sdr->kacontext = NULL;
-
- if (flags & kDNSServiceFlagsShareConnection)
- {
- DNSServiceOp **p = &(*ref)->next; // Append ourselves to end of primary's list
- while (*p)
- p = &(*p)->next;
- *p = sdr;
- // Preincrement counter before we use it -- it helps with debugging if we know the all-zeroes ID should never appear
- if (++(*ref)->uid.u32[0] == 0)
- ++(*ref)->uid.u32[1]; // In parent DNSServiceOp increment UID counter
- sdr->primary = *ref; // Set our primary pointer
- sdr->sockfd = (*ref)->sockfd; // Inherit primary's socket
- sdr->validator = (*ref)->validator;
- sdr->uid = (*ref)->uid;
- //printf("ConnectToServer sharing socket %d\n", sdr->sockfd);
- }
- else
- {
- #ifdef SO_NOSIGPIPE
- const unsigned long optval = 1;
- #endif
- *ref = NULL;
- sdr->sockfd = socket(AF_DNSSD, SOCK_STREAM, 0);
- sdr->validator = sdr->sockfd ^ ValidatorBits;
- if (!dnssd_SocketValid(sdr->sockfd))
- {
- syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: socket failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
- FreeDNSServiceOp(sdr);
- return kDNSServiceErr_NoMemory;
- }
- #ifdef SO_NOSIGPIPE
- // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
- if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
- syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_NOSIGPIPE failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
- #endif
- #if defined(USE_TCP_LOOPBACK)
- saddr.sin_family = AF_INET;
- saddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
- saddr.sin_port = htons(MDNS_TCP_SERVERPORT);
- #else
- saddr.sun_family = AF_LOCAL;
- strcpy(saddr.sun_path, MDNS_UDS_SERVERPATH);
- #if !defined(__ppc__) && defined(SO_DEFUNCTOK)
- {
- int defunct = 1;
- if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0)
- syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
- }
- #endif
- #endif
-
- while (1)
- {
- int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
- if (!err)
- break; // If we succeeded, return sdr
- // If we failed, then it may be because the daemon is still launching.
- // This can happen for processes that launch early in the boot process, while the
- // daemon is still coming up. Rather than fail here, we wait 1 sec and try again.
- // If, after DNSSD_CLIENT_MAXTRIES, we still can't connect to the daemon,
- // then we give up and return a failure code.
- if (++NumTries < DNSSD_CLIENT_MAXTRIES)
- {
- syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect()-> No of tries: %d", NumTries);
- sleep(1); // Sleep a bit, then try again
- }
- else
- {
- syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect() failed Socket:%d Err:%d Errno:%d %s",
- sdr->sockfd, err, dnssd_errno, dnssd_strerror(dnssd_errno));
- dnssd_close(sdr->sockfd);
- FreeDNSServiceOp(sdr);
- return kDNSServiceErr_ServiceNotRunning;
- }
- }
- //printf("ConnectToServer opened socket %d\n", sdr->sockfd);
- }
-
- *ref = sdr;
- return kDNSServiceErr_NoError;
-}
-
-#define deliver_request_bailout(MSG) \
- do { syslog(LOG_WARNING, "dnssd_clientstub deliver_request: %s failed %d (%s)", (MSG), dnssd_errno, dnssd_strerror(dnssd_errno)); goto cleanup; } while(0)
-
-static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
-{
- uint32_t datalen = hdr->datalen; // We take a copy here because we're going to convert hdr->datalen to network byte order
- #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
- char *const data = (char *)hdr + sizeof(ipc_msg_hdr);
- #endif
- dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
- DNSServiceErrorType err = kDNSServiceErr_Unknown; // Default for the "goto cleanup" cases
- int MakeSeparateReturnSocket = 0;
-
- // Note: need to check hdr->op, not sdr->op.
- // hdr->op contains the code for the specific operation we're currently doing, whereas sdr->op
- // contains the original parent DNSServiceOp (e.g. for an add_record_request, hdr->op will be
- // add_record_request but the parent sdr->op will be connection_request or reg_service_request)
- if (sdr->primary ||
- hdr->op == reg_record_request || hdr->op == add_record_request || hdr->op == update_record_request || hdr->op == remove_record_request)
- MakeSeparateReturnSocket = 1;
-
- if (!DNSServiceRefValid(sdr))
- {
- if (hdr)
- free(hdr);
- syslog(LOG_WARNING, "dnssd_clientstub deliver_request: invalid DNSServiceRef %p %08X %08X", sdr, sdr->sockfd, sdr->validator);
- return kDNSServiceErr_BadReference;
- }
-
- if (!hdr)
- {
- syslog(LOG_WARNING, "dnssd_clientstub deliver_request: !hdr");
- return kDNSServiceErr_Unknown;
- }
-
- if (MakeSeparateReturnSocket)
- {
- #if defined(USE_TCP_LOOPBACK)
- {
- union { uint16_t s; u_char b[2]; } port;
- dnssd_sockaddr_t caddr;
- dnssd_socklen_t len = (dnssd_socklen_t) sizeof(caddr);
- listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
- if (!dnssd_SocketValid(listenfd)) deliver_request_bailout("TCP socket");
-
- caddr.sin_family = AF_INET;
- caddr.sin_port = 0;
- caddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
- if (bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr)) < 0) deliver_request_bailout("TCP bind");
- if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) deliver_request_bailout("TCP getsockname");
- if (listen(listenfd, 1) < 0) deliver_request_bailout("TCP listen");
- port.s = caddr.sin_port;
- data[0] = port.b[0]; // don't switch the byte order, as the
- data[1] = port.b[1]; // daemon expects it in network byte order
- }
- #elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
- {
- mode_t mask;
- int bindresult;
- dnssd_sockaddr_t caddr;
- listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
- if (!dnssd_SocketValid(listenfd)) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET socket");
-
- caddr.sun_family = AF_LOCAL;
- // According to Stevens (section 3.2), there is no portable way to
- // determine whether sa_len is defined on a particular platform.
- #ifndef NOT_HAVE_SA_LEN
- caddr.sun_len = sizeof(struct sockaddr_un);
- #endif
- strcpy(caddr.sun_path, data);
- mask = umask(0);
- bindresult = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr));
- umask(mask);
- if (bindresult < 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET bind");
- if (listen(listenfd, 1) < 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET listen");
- }
- #else
- {
- dnssd_sock_t sp[2];
- if (socketpair(AF_DNSSD, SOCK_STREAM, 0, sp) < 0) deliver_request_bailout("socketpair");
- else
- {
- errsd = sp[0]; // We'll read our four-byte error code from sp[0]
- listenfd = sp[1]; // We'll send sp[1] to the daemon
- #if !defined(__ppc__) && defined(SO_DEFUNCTOK)
- {
- int defunct = 1;
- if (setsockopt(errsd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0)
- syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
- }
- #endif
- }
- }
- #endif
- }
-
-#if !defined(USE_TCP_LOOPBACK) && !defined(USE_NAMED_ERROR_RETURN_SOCKET)
- // If we're going to make a separate error return socket, and pass it to the daemon
- // using sendmsg, then we'll hold back one data byte to go with it.
- // On some versions of Unix (including Leopard) sending a control message without
- // any associated data does not work reliably -- e.g. one particular issue we ran
- // into is that if the receiving program is in a kqueue loop waiting to be notified
- // of the received message, it doesn't get woken up when the control message arrives.
- if (MakeSeparateReturnSocket || sdr->op == send_bpf)
- datalen--; // Okay to use sdr->op when checking for op == send_bpf
-#endif
-
- // At this point, our listening socket is set up and waiting, if necessary, for the daemon to connect back to
- ConvertHeaderBytes(hdr);
- //syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %lu bytes", (unsigned long)(datalen + sizeof(ipc_msg_hdr)));
- //if (MakeSeparateReturnSocket) syslog(LOG_WARNING, "dnssd_clientstub deliver_request name is %s", data);
-#if TEST_SENDING_ONE_BYTE_AT_A_TIME
- unsigned int i;
- for (i=0; i<datalen + sizeof(ipc_msg_hdr); i++)
- {
- syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %d", i);
- if (write_all(sdr->sockfd, ((char *)hdr)+i, 1) < 0)
- { syslog(LOG_WARNING, "write_all (byte %u) failed", i); goto cleanup; }
- usleep(10000);
- }
-#else
- if (write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr)) < 0)
- {
- // write_all already prints an error message if there is an error writing to
- // the socket except for DEFUNCT. Logging here is unnecessary and also wrong
- // in the case of DEFUNCT sockets
- syslog(LOG_INFO, "dnssd_clientstub deliver_request ERROR: write_all(%d, %lu bytes) failed",
- sdr->sockfd, (unsigned long)(datalen + sizeof(ipc_msg_hdr)));
- goto cleanup;
- }
-#endif
-
- if (!MakeSeparateReturnSocket)
- errsd = sdr->sockfd;
- if (MakeSeparateReturnSocket || sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf
- {
-#if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
- // At this point we may wait in accept for a few milliseconds waiting for the daemon to connect back to us,
- // but that's okay -- the daemon should not take more than a few milliseconds to respond.
- // set_waitlimit() ensures we do not block indefinitely just in case something is wrong
- dnssd_sockaddr_t daddr;
- dnssd_socklen_t len = sizeof(daddr);
- if ((err = set_waitlimit(listenfd, DNSSD_CLIENT_TIMEOUT)) != kDNSServiceErr_NoError)
- goto cleanup;
- errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
- if (!dnssd_SocketValid(errsd))
- deliver_request_bailout("accept");
-#else
-
- struct iovec vec = { ((char *)hdr) + sizeof(ipc_msg_hdr) + datalen, 1 }; // Send the last byte along with the SCM_RIGHTS
- struct msghdr msg;
- struct cmsghdr *cmsg;
- char cbuf[CMSG_SPACE(4 * sizeof(dnssd_sock_t))];
-
- msg.msg_name = 0;
- msg.msg_namelen = 0;
- msg.msg_iov = &vec;
- msg.msg_iovlen = 1;
- msg.msg_flags = 0;
- if (MakeSeparateReturnSocket || sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf
- {
- if (sdr->op == send_bpf)
- {
- int i;
- char p[12]; // Room for "/dev/bpf999" with terminating null
- for (i=0; i<100; i++)
- {
- snprintf(p, sizeof(p), "/dev/bpf%d", i);
- listenfd = open(p, O_RDWR, 0);
- //if (dnssd_SocketValid(listenfd)) syslog(LOG_WARNING, "Sending fd %d for %s", listenfd, p);
- if (!dnssd_SocketValid(listenfd) && dnssd_errno != EBUSY)
- syslog(LOG_WARNING, "Error opening %s %d (%s)", p, dnssd_errno, dnssd_strerror(dnssd_errno));
- if (dnssd_SocketValid(listenfd) || dnssd_errno != EBUSY) break;
- }
- }
- msg.msg_control = cbuf;
- msg.msg_controllen = CMSG_LEN(sizeof(dnssd_sock_t));
-
- cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_len = CMSG_LEN(sizeof(dnssd_sock_t));
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- *((dnssd_sock_t *)CMSG_DATA(cmsg)) = listenfd;
- }
-
-#if TEST_KQUEUE_CONTROL_MESSAGE_BUG
- sleep(1);
-#endif
-
-#if DEBUG_64BIT_SCM_RIGHTS
- syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d %ld %ld %ld/%ld/%ld/%ld",
- errsd, listenfd, sizeof(dnssd_sock_t), sizeof(void*),
- sizeof(struct cmsghdr) + sizeof(dnssd_sock_t),
- CMSG_LEN(sizeof(dnssd_sock_t)), (long)CMSG_SPACE(sizeof(dnssd_sock_t)),
- (long)((char*)CMSG_DATA(cmsg) + 4 - cbuf));
-#endif // DEBUG_64BIT_SCM_RIGHTS
-
- if (sendmsg(sdr->sockfd, &msg, 0) < 0)
- {
- syslog(LOG_WARNING, "dnssd_clientstub deliver_request ERROR: sendmsg failed read sd=%d write sd=%d errno %d (%s)",
- errsd, listenfd, dnssd_errno, dnssd_strerror(dnssd_errno));
- err = kDNSServiceErr_Incompatible;
- goto cleanup;
- }
-
-#if DEBUG_64BIT_SCM_RIGHTS
- syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d okay", errsd, listenfd);
-#endif // DEBUG_64BIT_SCM_RIGHTS
-
-#endif
- // Close our end of the socketpair *before* calling read_all() to get the four-byte error code.
- // Otherwise, if the daemon closes our socket (or crashes), we will have to wait for a timeout
- // in read_all() because the socket is not closed (we still have an open reference to it)
- // Note: listenfd is overwritten in the case of send_bpf above and that will be closed here
- // for send_bpf operation.
- dnssd_close(listenfd);
- listenfd = dnssd_InvalidSocket; // Make sure we don't close it a second time in the cleanup handling below
- }
-
- // At this point we may wait in read_all for a few milliseconds waiting for the daemon to send us the error code,
- // but that's okay -- the daemon should not take more than a few milliseconds to respond.
- // set_waitlimit() ensures we do not block indefinitely just in case something is wrong
- if (sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf
- err = kDNSServiceErr_NoError;
- else if ((err = set_waitlimit(errsd, DNSSD_CLIENT_TIMEOUT)) == kDNSServiceErr_NoError)
- {
- if (read_all(errsd, (char*)&err, (int)sizeof(err)) < 0)
- err = kDNSServiceErr_ServiceNotRunning; // On failure read_all will have written a message to syslog for us
- else
- err = ntohl(err);
- }
- //syslog(LOG_WARNING, "dnssd_clientstub deliver_request: retrieved error code %d", err);
-
-cleanup:
- if (MakeSeparateReturnSocket)
- {
- if (dnssd_SocketValid(listenfd)) dnssd_close(listenfd);
- if (dnssd_SocketValid(errsd)) dnssd_close(errsd);
-#if defined(USE_NAMED_ERROR_RETURN_SOCKET)
- // syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removing UDS: %s", data);
- if (unlink(data) != 0)
- syslog(LOG_WARNING, "dnssd_clientstub WARNING: unlink(\"%s\") failed errno %d (%s)", data, dnssd_errno, dnssd_strerror(dnssd_errno));
- // else syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removed UDS: %s", data);
-#endif
- }
-
- free(hdr);
- return err;
-}
-
-int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef)
-{
- if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with NULL DNSServiceRef"); return dnssd_InvalidSocket; }
-
- if (!DNSServiceRefValid(sdRef))
- {
- syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with invalid DNSServiceRef %p %08X %08X",
- sdRef, sdRef->sockfd, sdRef->validator);
- return dnssd_InvalidSocket;
- }
-
- if (sdRef->primary)
- {
- syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef);
- return dnssd_InvalidSocket;
- }
-
- return (int) sdRef->sockfd;
-}
-
-#if _DNS_SD_LIBDISPATCH
-static void CallbackWithError(DNSServiceRef sdRef, DNSServiceErrorType error)
-{
- DNSServiceOp *sdr = sdRef;
- DNSServiceOp *sdrNext;
- DNSRecord *rec;
- DNSRecord *recnext;
- int morebytes;
-
- while (sdr)
- {
- // We can't touch the sdr after the callback as it can be deallocated in the callback
- sdrNext = sdr->next;
- morebytes = 1;
- sdr->moreptr = &morebytes;
- switch (sdr->op)
- {
- case resolve_request:
- if (sdr->AppCallback) ((DNSServiceResolveReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL, sdr->AppContext);
- break;
- case query_request:
- if (sdr->AppCallback) ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL, 0, sdr->AppContext);
- break;
- case addrinfo_request:
- if (sdr->AppCallback) ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, NULL, 0, sdr->AppContext);
- break;
- case browse_request:
- if (sdr->AppCallback) ((DNSServiceBrowseReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, NULL, sdr->AppContext);
- break;
- case reg_service_request:
- if (sdr->AppCallback) ((DNSServiceRegisterReply) sdr->AppCallback)(sdr, 0, error, NULL, 0, NULL, sdr->AppContext);
- break;
- case enumeration_request:
- if (sdr->AppCallback) ((DNSServiceDomainEnumReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, sdr->AppContext);
- break;
- case connection_request:
- case connection_delegate_request:
- // This means Register Record, walk the list of DNSRecords to do the callback
- rec = sdr->rec;
- while (rec)
- {
- recnext = rec->recnext;
- if (rec->AppCallback) ((DNSServiceRegisterRecordReply)rec->AppCallback)(sdr, 0, 0, error, rec->AppContext);
- // The Callback can call DNSServiceRefDeallocate which in turn frees sdr and all the records.
- // Detect that and return early
- if (!morebytes) {syslog(LOG_WARNING, "dnssdclientstub:Record: CallbackwithError morebytes zero"); return;}
- rec = recnext;
- }
- break;
- case port_mapping_request:
- if (sdr->AppCallback) ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, 0, 0, error, 0, 0, 0, 0, 0, sdr->AppContext);
- break;
- default:
- syslog(LOG_WARNING, "dnssd_clientstub CallbackWithError called with bad op %d", sdr->op);
- }
- // If DNSServiceRefDeallocate was called in the callback, morebytes will be zero. As the sdRef
- // (and its subordinates) have been freed, we should not proceed further. Note that when we
- // call the callback with a subordinate sdRef the application can call DNSServiceRefDeallocate
- // on the main sdRef and DNSServiceRefDeallocate handles this case by walking all the sdRefs and
- // clears the moreptr so that we can terminate here.
- //
- // If DNSServiceRefDeallocate was not called in the callback, then set moreptr to NULL so that
- // we don't access the stack variable after we return from this function.
- if (!morebytes) {syslog(LOG_WARNING, "dnssdclientstub:sdRef: CallbackwithError morebytes zero sdr %p", sdr); return;}
- else {sdr->moreptr = NULL;}
- sdr = sdrNext;
- }
-}
-#endif // _DNS_SD_LIBDISPATCH
-
-// Handle reply from server, calling application client callback. If there is no reply
-// from the daemon on the socket contained in sdRef, the call will block.
-DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
-{
- int morebytes = 0;
-
- if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
-
- if (!DNSServiceRefValid(sdRef))
- {
- syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
- return kDNSServiceErr_BadReference;
- }
-
- if (sdRef->primary)
- {
- syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef);
- return kDNSServiceErr_BadReference;
- }
-
- if (!sdRef->ProcessReply)
- {
- static int num_logs = 0;
- if (num_logs < 10) syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function");
- if (num_logs < 1000) num_logs++;else sleep(1);
- return kDNSServiceErr_BadReference;
- }
-
- do
- {
- CallbackHeader cbh;
- char *data;
-
- // return NoError on EWOULDBLOCK. This will handle the case
- // where a non-blocking socket is told there is data, but it was a false positive.
- // On error, read_all will write a message to syslog for us, so don't need to duplicate that here
- // Note: If we want to properly support using non-blocking sockets in the future
- int result = read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr));
- if (result == read_all_fail)
- {
- // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
- // in the callback.
- sdRef->ProcessReply = NULL;
-#if _DNS_SD_LIBDISPATCH
- // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult
- // is not called by the application and hence need to communicate the error. Cancel the
- // source so that we don't get any more events
- // Note: read_all fails if we could not read from the daemon which can happen if the
- // daemon dies or the file descriptor is disconnected (defunct).
- if (sdRef->disp_source)
- {
- dispatch_source_cancel(sdRef->disp_source);
- dispatch_release(sdRef->disp_source);
- sdRef->disp_source = NULL;
- CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning);
- }
-#endif
- // Don't touch sdRef anymore as it might have been deallocated
- return kDNSServiceErr_ServiceNotRunning;
- }
- else if (result == read_all_wouldblock)
- {
- if (morebytes && sdRef->logcounter < 100)
- {
- sdRef->logcounter++;
- syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult error: select indicated data was waiting but read_all returned EWOULDBLOCK");
- }
- return kDNSServiceErr_NoError;
- }
-
- ConvertHeaderBytes(&cbh.ipc_hdr);
- if (cbh.ipc_hdr.version != VERSION)
- {
- syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult daemon version %d does not match client version %d", cbh.ipc_hdr.version, VERSION);
- sdRef->ProcessReply = NULL;
- return kDNSServiceErr_Incompatible;
- }
-
- data = malloc(cbh.ipc_hdr.datalen);
- if (!data) return kDNSServiceErr_NoMemory;
- if (read_all(sdRef->sockfd, data, cbh.ipc_hdr.datalen) < 0) // On error, read_all will write a message to syslog for us
- {
- // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
- // in the callback.
- sdRef->ProcessReply = NULL;
-#if _DNS_SD_LIBDISPATCH
- // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult
- // is not called by the application and hence need to communicate the error. Cancel the
- // source so that we don't get any more events
- if (sdRef->disp_source)
- {
- dispatch_source_cancel(sdRef->disp_source);
- dispatch_release(sdRef->disp_source);
- sdRef->disp_source = NULL;
- CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning);
- }
-#endif
- // Don't touch sdRef anymore as it might have been deallocated
- free(data);
- return kDNSServiceErr_ServiceNotRunning;
- }
- else
- {
- const char *ptr = data;
- cbh.cb_flags = get_flags (&ptr, data + cbh.ipc_hdr.datalen);
- cbh.cb_interface = get_uint32 (&ptr, data + cbh.ipc_hdr.datalen);
- cbh.cb_err = get_error_code(&ptr, data + cbh.ipc_hdr.datalen);
-
- // CAUTION: We have to handle the case where the client calls DNSServiceRefDeallocate from within the callback function.
- // To do this we set moreptr to point to morebytes. If the client does call DNSServiceRefDeallocate(),
- // then that routine will clear morebytes for us, and cause us to exit our loop.
- morebytes = more_bytes(sdRef->sockfd);
- if (morebytes)
- {
- cbh.cb_flags |= kDNSServiceFlagsMoreComing;
- sdRef->moreptr = &morebytes;
- }
- if (ptr) sdRef->ProcessReply(sdRef, &cbh, ptr, data + cbh.ipc_hdr.datalen);
- // Careful code here:
- // If morebytes is non-zero, that means we set sdRef->moreptr above, and the operation was not
- // cancelled out from under us, so now we need to clear sdRef->moreptr so we don't leave a stray
- // dangling pointer pointing to a long-gone stack variable.
- // If morebytes is zero, then one of two thing happened:
- // (a) morebytes was 0 above, so we didn't set sdRef->moreptr, so we don't need to clear it
- // (b) morebytes was 1 above, and we set sdRef->moreptr, but the operation was cancelled (with DNSServiceRefDeallocate()),
- // so we MUST NOT try to dereference our stale sdRef pointer.
- if (morebytes) sdRef->moreptr = NULL;
- }
- free(data);
- } while (morebytes);
-
- return kDNSServiceErr_NoError;
-}
-
-void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef)
-{
- if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with NULL DNSServiceRef"); return; }
-
- if (!DNSServiceRefValid(sdRef)) // Also verifies dnssd_SocketValid(sdRef->sockfd) for us too
- {
- syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
- return;
- }
-
- // If we're in the middle of a DNSServiceProcessResult() invocation for this DNSServiceRef, clear its morebytes flag to break it out of its while loop
- if (sdRef->moreptr) *(sdRef->moreptr) = 0;
-
- if (sdRef->primary) // If this is a subordinate DNSServiceOp, just send a 'stop' command
- {
- DNSServiceOp **p = &sdRef->primary->next;
- while (*p && *p != sdRef) p = &(*p)->next;
- if (*p)
- {
- char *ptr;
- size_t len = 0;
- ipc_msg_hdr *hdr = create_hdr(cancel_request, &len, &ptr, 0, sdRef);
- if (hdr)
- {
- ConvertHeaderBytes(hdr);
- write_all(sdRef->sockfd, (char *)hdr, len);
- free(hdr);
- }
- *p = sdRef->next;
- FreeDNSServiceOp(sdRef);
- }
- }
- else // else, make sure to terminate all subordinates as well
- {
-#if _DNS_SD_LIBDISPATCH
- // The cancel handler will close the fd if a dispatch source has been set
- if (sdRef->disp_source)
- {
- // By setting the ProcessReply to NULL, we make sure that we never call
- // the application callbacks ever, after returning from this function. We
- // assume that DNSServiceRefDeallocate is called from the serial queue
- // that was passed to DNSServiceSetDispatchQueue. Hence, dispatch_source_cancel
- // should cancel all the blocks on the queue and hence there should be no more
- // callbacks when we return from this function. Setting ProcessReply to NULL
- // provides extra protection.
- sdRef->ProcessReply = NULL;
- dispatch_source_cancel(sdRef->disp_source);
- dispatch_release(sdRef->disp_source);
- sdRef->disp_source = NULL;
- }
- // if disp_queue is set, it means it used the DNSServiceSetDispatchQueue API. In that case,
- // when the source was cancelled, the fd was closed in the handler. Currently the source
- // is cancelled only when the mDNSResponder daemon dies
- else if (!sdRef->disp_queue) dnssd_close(sdRef->sockfd);
-#else
- dnssd_close(sdRef->sockfd);
-#endif
- // Free DNSRecords added in DNSRegisterRecord if they have not
- // been freed in DNSRemoveRecord
- while (sdRef)
- {
- DNSServiceOp *p = sdRef;
- sdRef = sdRef->next;
- // When there is an error reading from the daemon e.g., bad fd, CallbackWithError
- // is called which sets moreptr. It might set the moreptr on a subordinate sdRef
- // but the application might call DNSServiceRefDeallocate with the main sdRef from
- // the callback. Hence, when we loop through the subordinate sdRefs, we need
- // to clear the moreptr so that CallbackWithError can terminate itself instead of
- // walking through the freed sdRefs.
- if (p->moreptr) *(p->moreptr) = 0;
- FreeDNSServiceOp(p);
- }
- }
-}
-
-DNSServiceErrorType DNSSD_API DNSServiceGetProperty(const char *property, void *result, uint32_t *size)
-{
- char *ptr;
- size_t len = strlen(property) + 1;
- ipc_msg_hdr *hdr;
- DNSServiceOp *tmp;
- uint32_t actualsize;
-
- DNSServiceErrorType err = ConnectToServer(&tmp, 0, getproperty_request, NULL, NULL, NULL);
- if (err) return err;
-
- hdr = create_hdr(getproperty_request, &len, &ptr, 0, tmp);
- if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
-
- put_string(property, &ptr);
- err = deliver_request(hdr, tmp); // Will free hdr for us
- if (read_all(tmp->sockfd, (char*)&actualsize, (int)sizeof(actualsize)) < 0)
- { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
-
- actualsize = ntohl(actualsize);
- if (read_all(tmp->sockfd, (char*)result, actualsize < *size ? actualsize : *size) < 0)
- { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
- DNSServiceRefDeallocate(tmp);
-
- // Swap version result back to local process byte order
- if (!strcmp(property, kDNSServiceProperty_DaemonVersion) && *size >= 4)
- *(uint32_t*)result = ntohl(*(uint32_t*)result);
-
- *size = actualsize;
- return kDNSServiceErr_NoError;
-}
-
-DNSServiceErrorType DNSSD_API DNSServiceGetPID(const uint16_t srcport, int32_t *pid)
-{
- char *ptr;
- ipc_msg_hdr *hdr;
- DNSServiceOp *tmp;
- size_t len = sizeof(int32_t);
-
- DNSServiceErrorType err = ConnectToServer(&tmp, 0, getpid_request, NULL, NULL, NULL);
- if (err)
- return err;
-
- hdr = create_hdr(getpid_request, &len, &ptr, 0, tmp);
- if (!hdr)
- {
- DNSServiceRefDeallocate(tmp);
- return kDNSServiceErr_NoMemory;
- }
-
- put_uint16(srcport, &ptr);
- err = deliver_request(hdr, tmp); // Will free hdr for us
-
- if (read_all(tmp->sockfd, (char*)pid, sizeof(int32_t)) < 0)
- {
- DNSServiceRefDeallocate(tmp);
- return kDNSServiceErr_ServiceNotRunning;
- }
-
- DNSServiceRefDeallocate(tmp);
- return kDNSServiceErr_NoError;
-}
-
-static void handle_resolve_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *end)
-{
- char fullname[kDNSServiceMaxDomainName];
- char target[kDNSServiceMaxDomainName];
- uint16_t txtlen;
- union { uint16_t s; u_char b[2]; } port;
- unsigned char *txtrecord;
-
- get_string(&data, end, fullname, kDNSServiceMaxDomainName);
- get_string(&data, end, target, kDNSServiceMaxDomainName);
- if (!data || data + 2 > end) goto fail;
-
- port.b[0] = *data++;
- port.b[1] = *data++;
- txtlen = get_uint16(&data, end);
- txtrecord = (unsigned char *)get_rdata(&data, end, txtlen);
-
- if (!data) goto fail;
- ((DNSServiceResolveReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, fullname, target, port.s, txtlen, txtrecord, sdr->AppContext);
- return;
- // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
-fail:
- syslog(LOG_WARNING, "dnssd_clientstub handle_resolve_response: error reading result from daemon");
-}
-
-#if APPLE_OSX_mDNSResponder
-
-static int32_t libSystemVersion = 0;
-
-// Return true if the application linked against a version of libsystem where P2P
-// interfaces were included by default when using kDNSServiceInterfaceIndexAny.
-// Using 160.0.0 == 0xa00000 as the version threshold.
-static int includeP2PWithIndexAny()
-{
- if (libSystemVersion == 0)
- libSystemVersion = NSVersionOfLinkTimeLibrary("System");
-
- if (libSystemVersion < 0xa00000)
- return 1;
- else
- return 0;
-}
-
-#else // APPLE_OSX_mDNSResponder
-
-// always return false for non Apple platforms
-static int includeP2PWithIndexAny()
-{
- return 0;
-}
-
-#endif // APPLE_OSX_mDNSResponder
-
-DNSServiceErrorType DNSSD_API DNSServiceResolve
-(
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- const char *name,
- const char *regtype,
- const char *domain,
- DNSServiceResolveReply callBack,
- void *context
-)
-{
- char *ptr;
- size_t len;
- ipc_msg_hdr *hdr;
- DNSServiceErrorType err;
-
- if (!name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam;
-
- // Need a real InterfaceID for WakeOnResolve
- if ((flags & kDNSServiceFlagsWakeOnResolve) != 0 &&
- ((interfaceIndex == kDNSServiceInterfaceIndexAny) ||
- (interfaceIndex == kDNSServiceInterfaceIndexLocalOnly) ||
- (interfaceIndex == kDNSServiceInterfaceIndexUnicast) ||
- (interfaceIndex == kDNSServiceInterfaceIndexP2P)))
- {
- return kDNSServiceErr_BadParam;
- }
-
- if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
- flags |= kDNSServiceFlagsIncludeP2P;
-
- err = ConnectToServer(sdRef, flags, resolve_request, handle_resolve_response, callBack, context);
- if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
-
- // Calculate total message length
- len = sizeof(flags);
- len += sizeof(interfaceIndex);
- len += strlen(name) + 1;
- len += strlen(regtype) + 1;
- len += strlen(domain) + 1;
-
- hdr = create_hdr(resolve_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
- if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
-
- put_flags(flags, &ptr);
- put_uint32(interfaceIndex, &ptr);
- put_string(name, &ptr);
- put_string(regtype, &ptr);
- put_string(domain, &ptr);
-
- err = deliver_request(hdr, *sdRef); // Will free hdr for us
- if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
- return err;
-}
-
-static void handle_query_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
-{
- uint32_t ttl;
- char name[kDNSServiceMaxDomainName];
- uint16_t rrtype, rrclass, rdlen;
- const char *rdata;
-
- get_string(&data, end, name, kDNSServiceMaxDomainName);
- rrtype = get_uint16(&data, end);
- rrclass = get_uint16(&data, end);
- rdlen = get_uint16(&data, end);
- rdata = get_rdata(&data, end, rdlen);
- ttl = get_uint32(&data, end);
-
- if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_query_response: error reading result from daemon");
- else ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, name, rrtype, rrclass, rdlen, rdata, ttl, sdr->AppContext);
- // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
-}
-
-DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
-(
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- const char *name,
- uint16_t rrtype,
- uint16_t rrclass,
- DNSServiceQueryRecordReply callBack,
- void *context
-)
-{
- char *ptr;
- size_t len;
- ipc_msg_hdr *hdr;
- DNSServiceErrorType err;
-
- if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
- flags |= kDNSServiceFlagsIncludeP2P;
-
- err = ConnectToServer(sdRef, flags, query_request, handle_query_response, callBack, context);
- if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
-
- if (!name) name = "\0";
-
- // Calculate total message length
- len = sizeof(flags);
- len += sizeof(uint32_t); // interfaceIndex
- len += strlen(name) + 1;
- len += 2 * sizeof(uint16_t); // rrtype, rrclass
-
- hdr = create_hdr(query_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
- if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
-
- put_flags(flags, &ptr);
- put_uint32(interfaceIndex, &ptr);
- put_string(name, &ptr);
- put_uint16(rrtype, &ptr);
- put_uint16(rrclass, &ptr);
-
- err = deliver_request(hdr, *sdRef); // Will free hdr for us
- if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
- return err;
-}
-
-static void handle_addrinfo_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
-{
- char hostname[kDNSServiceMaxDomainName];
- uint16_t rrtype, rrclass, rdlen;
- const char *rdata;
- uint32_t ttl;
-
- get_string(&data, end, hostname, kDNSServiceMaxDomainName);
- rrtype = get_uint16(&data, end);
- rrclass = get_uint16(&data, end);
- rdlen = get_uint16(&data, end);
- rdata = get_rdata (&data, end, rdlen);
- ttl = get_uint32(&data, end);
-
- // We only generate client callbacks for A and AAAA results (including NXDOMAIN results for
- // those types, if the client has requested those with the kDNSServiceFlagsReturnIntermediates).
- // Other result types, specifically CNAME referrals, are not communicated to the client, because
- // the DNSServiceGetAddrInfoReply interface doesn't have any meaningful way to communiate CNAME referrals.
- if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_addrinfo_response: error reading result from daemon");
- else if (rrtype == kDNSServiceType_A || rrtype == kDNSServiceType_AAAA)
- {
- struct sockaddr_in sa4;
- struct sockaddr_in6 sa6;
- const struct sockaddr *const sa = (rrtype == kDNSServiceType_A) ? (struct sockaddr*)&sa4 : (struct sockaddr*)&sa6;
- if (rrtype == kDNSServiceType_A)
- {
- memset(&sa4, 0, sizeof(sa4));
- #ifndef NOT_HAVE_SA_LEN
- sa4.sin_len = sizeof(struct sockaddr_in);
- #endif
- sa4.sin_family = AF_INET;
- // sin_port = 0;
- if (!cbh->cb_err) memcpy(&sa4.sin_addr, rdata, rdlen);
- }
- else
- {
- memset(&sa6, 0, sizeof(sa6));
- #ifndef NOT_HAVE_SA_LEN
- sa6.sin6_len = sizeof(struct sockaddr_in6);
- #endif
- sa6.sin6_family = AF_INET6;
- // sin6_port = 0;
- // sin6_flowinfo = 0;
- // sin6_scope_id = 0;
- if (!cbh->cb_err)
- {
- memcpy(&sa6.sin6_addr, rdata, rdlen);
- if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr)) sa6.sin6_scope_id = cbh->cb_interface;
- }
- }
- // Validation results are always delivered separately from the actual results of the
- // DNSServiceGetAddrInfo. Set the "addr" to NULL as per the documentation.
- //
- // Note: If we deliver validation results along with the "addr" in the future, we need
- // a way to differentiate the negative response from validation-only response as both
- // has zero address.
- if (!(cbh->cb_flags & kDNSServiceFlagsValidate))
- ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, sa, ttl, sdr->AppContext);
- else
- ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, NULL, 0, sdr->AppContext);
- // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
- }
-}
-
-DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo
-(
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- uint32_t protocol,
- const char *hostname,
- DNSServiceGetAddrInfoReply callBack,
- void *context /* may be NULL */
-)
-{
- char *ptr;
- size_t len;
- ipc_msg_hdr *hdr;
- DNSServiceErrorType err;
-
- if (!hostname) return kDNSServiceErr_BadParam;
-
- err = ConnectToServer(sdRef, flags, addrinfo_request, handle_addrinfo_response, callBack, context);
- if (err)
- {
- return err; // On error ConnectToServer leaves *sdRef set to NULL
- }
-
- // Calculate total message length
- len = sizeof(flags);
- len += sizeof(uint32_t); // interfaceIndex
- len += sizeof(uint32_t); // protocol
- len += strlen(hostname) + 1;
-
- hdr = create_hdr(addrinfo_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
- if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
-
- put_flags(flags, &ptr);
- put_uint32(interfaceIndex, &ptr);
- put_uint32(protocol, &ptr);
- put_string(hostname, &ptr);
-
- err = deliver_request(hdr, *sdRef); // Will free hdr for us
- if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
- return err;
-}
-
-static void handle_browse_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
-{
- char replyName[256], replyType[kDNSServiceMaxDomainName], replyDomain[kDNSServiceMaxDomainName];
- get_string(&data, end, replyName, 256);
- get_string(&data, end, replyType, kDNSServiceMaxDomainName);
- get_string(&data, end, replyDomain, kDNSServiceMaxDomainName);
- if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_browse_response: error reading result from daemon");
- else ((DNSServiceBrowseReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, replyName, replyType, replyDomain, sdr->AppContext);
- // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
-}
-
-DNSServiceErrorType DNSSD_API DNSServiceBrowse
-(
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- const char *regtype,
- const char *domain,
- DNSServiceBrowseReply callBack,
- void *context
-)
-{
- char *ptr;
- size_t len;
- ipc_msg_hdr *hdr;
- DNSServiceErrorType err;
-
- if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
- flags |= kDNSServiceFlagsIncludeP2P;
-
- err = ConnectToServer(sdRef, flags, browse_request, handle_browse_response, callBack, context);
- if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
-
- if (!domain) domain = "";
- len = sizeof(flags);
- len += sizeof(interfaceIndex);
- len += strlen(regtype) + 1;
- len += strlen(domain) + 1;
-
- hdr = create_hdr(browse_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
- if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
-
- put_flags(flags, &ptr);
- put_uint32(interfaceIndex, &ptr);
- put_string(regtype, &ptr);
- put_string(domain, &ptr);
-
- err = deliver_request(hdr, *sdRef); // Will free hdr for us
- if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
- return err;
-}
-
-DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain);
-DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain)
-{
- DNSServiceOp *tmp;
- char *ptr;
- size_t len = sizeof(flags) + strlen(domain) + 1;
- ipc_msg_hdr *hdr;
- DNSServiceErrorType err = ConnectToServer(&tmp, 0, setdomain_request, NULL, NULL, NULL);
- if (err) return err;
-
- hdr = create_hdr(setdomain_request, &len, &ptr, 0, tmp);
- if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
-
- put_flags(flags, &ptr);
- put_string(domain, &ptr);
- err = deliver_request(hdr, tmp); // Will free hdr for us
- DNSServiceRefDeallocate(tmp);
- return err;
-}
-
-static void handle_regservice_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
-{
- char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName];
- get_string(&data, end, name, 256);
- get_string(&data, end, regtype, kDNSServiceMaxDomainName);
- get_string(&data, end, domain, kDNSServiceMaxDomainName);
- if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_regservice_response: error reading result from daemon");
- else ((DNSServiceRegisterReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_err, name, regtype, domain, sdr->AppContext);
- // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
-}
-
-DNSServiceErrorType DNSSD_API DNSServiceRegister
-(
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- const char *name,
- const char *regtype,
- const char *domain,
- const char *host,
- uint16_t PortInNetworkByteOrder,
- uint16_t txtLen,
- const void *txtRecord,
- DNSServiceRegisterReply callBack,
- void *context
-)
-{
- char *ptr;
- size_t len;
- ipc_msg_hdr *hdr;
- DNSServiceErrorType err;
- union { uint16_t s; u_char b[2]; } port = { PortInNetworkByteOrder };
-
- if (!name) name = "";
- if (!regtype) return kDNSServiceErr_BadParam;
- if (!domain) domain = "";
- if (!host) host = "";
- if (!txtRecord) txtRecord = (void*)"";
-
- // No callback must have auto-rename
- if (!callBack && (flags & kDNSServiceFlagsNoAutoRename)) return kDNSServiceErr_BadParam;
-
- if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
- flags |= kDNSServiceFlagsIncludeP2P;
-
- err = ConnectToServer(sdRef, flags, reg_service_request, callBack ? handle_regservice_response : NULL, callBack, context);
- if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
-
- len = sizeof(DNSServiceFlags);
- len += sizeof(uint32_t); // interfaceIndex
- len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4;
- len += 2 * sizeof(uint16_t); // port, txtLen
- len += txtLen;
-
- hdr = create_hdr(reg_service_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
- if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
-
- // If it is going over a shared connection, then don't set the IPC_FLAGS_NOREPLY
- // as it affects all the operations over the shared connection. This is not
- // a normal case and hence receiving the response back from the daemon and
- // discarding it in ConnectionResponse is okay.
-
- if (!(flags & kDNSServiceFlagsShareConnection) && !callBack) hdr->ipc_flags |= IPC_FLAGS_NOREPLY;
-
- put_flags(flags, &ptr);
- put_uint32(interfaceIndex, &ptr);
- put_string(name, &ptr);
- put_string(regtype, &ptr);
- put_string(domain, &ptr);
- put_string(host, &ptr);
- *ptr++ = port.b[0];
- *ptr++ = port.b[1];
- put_uint16(txtLen, &ptr);
- put_rdata(txtLen, txtRecord, &ptr);
-
- err = deliver_request(hdr, *sdRef); // Will free hdr for us
- if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
- return err;
-}
-
-static void handle_enumeration_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
-{
- char domain[kDNSServiceMaxDomainName];
- get_string(&data, end, domain, kDNSServiceMaxDomainName);
- if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_enumeration_response: error reading result from daemon");
- else ((DNSServiceDomainEnumReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, domain, sdr->AppContext);
- // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
-}
-
-DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
-(
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceDomainEnumReply callBack,
- void *context
-)
-{
- char *ptr;
- size_t len;
- ipc_msg_hdr *hdr;
- DNSServiceErrorType err;
-
- int f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0;
- int f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0;
- if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
-
- err = ConnectToServer(sdRef, flags, enumeration_request, handle_enumeration_response, callBack, context);
- if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
-
- len = sizeof(DNSServiceFlags);
- len += sizeof(uint32_t);
-
- hdr = create_hdr(enumeration_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
- if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
-
- put_flags(flags, &ptr);
- put_uint32(interfaceIndex, &ptr);
-
- err = deliver_request(hdr, *sdRef); // Will free hdr for us
- if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
- return err;
-}
-
-static void ConnectionResponse(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *const data, const char *const end)
-{
- (void)data; // Unused
-
- //printf("ConnectionResponse got %d\n", cbh->ipc_hdr.op);
- if (cbh->ipc_hdr.op != reg_record_reply_op)
- {
- // When using kDNSServiceFlagsShareConnection, need to search the list of associated DNSServiceOps
- // to find the one this response is intended for, and then call through to its ProcessReply handler.
- // We start with our first subordinate DNSServiceRef -- don't want to accidentally match the parent DNSServiceRef.
- DNSServiceOp *op = sdr->next;
- while (op && (op->uid.u32[0] != cbh->ipc_hdr.client_context.u32[0] || op->uid.u32[1] != cbh->ipc_hdr.client_context.u32[1]))
- op = op->next;
- // Note: We may sometimes not find a matching DNSServiceOp, in the case where the client has
- // cancelled the subordinate DNSServiceOp, but there are still messages in the pipeline from the daemon
- if (op && op->ProcessReply) op->ProcessReply(op, cbh, data, end);
- // WARNING: Don't touch op or sdr after this -- client may have called DNSServiceRefDeallocate
- return;
- }
- else
- {
- DNSRecordRef rec;
- for (rec = sdr->rec; rec; rec = rec->recnext)
- {
- if (rec->uid.u32[0] == cbh->ipc_hdr.client_context.u32[0] && rec->uid.u32[1] == cbh->ipc_hdr.client_context.u32[1])
- break;
- }
- // The record might have been freed already and hence not an
- // error if the record is not found.
- if (!rec)
- {
- syslog(LOG_INFO, "ConnectionResponse: Record not found");
- return;
- }
- if (rec->sdr != sdr)
- {
- syslog(LOG_WARNING, "ConnectionResponse: Record sdr mismatch: rec %p sdr %p", rec->sdr, sdr);
- return;
- }
-
- if (sdr->op == connection_request || sdr->op == connection_delegate_request)
- {
- rec->AppCallback(rec->sdr, rec, cbh->cb_flags, cbh->cb_err, rec->AppContext);
- }
- else
- {
- syslog(LOG_WARNING, "dnssd_clientstub ConnectionResponse: sdr->op != connection_request");
- rec->AppCallback(rec->sdr, rec, 0, kDNSServiceErr_Unknown, rec->AppContext);
- }
- // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
- }
-}
-
-DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef)
-{
- char *ptr;
- size_t len = 0;
- ipc_msg_hdr *hdr;
- DNSServiceErrorType err = ConnectToServer(sdRef, 0, connection_request, ConnectionResponse, NULL, NULL);
- if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
-
- hdr = create_hdr(connection_request, &len, &ptr, 0, *sdRef);
- if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
-
- err = deliver_request(hdr, *sdRef); // Will free hdr for us
- if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
- return err;
-}
-
-#if APPLE_OSX_mDNSResponder && !TARGET_IPHONE_SIMULATOR
-DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid)
-{
- char *ptr;
- size_t len = 0;
- ipc_msg_hdr *hdr;
-
- DNSServiceErrorType err = ConnectToServer(sdRef, 0, connection_delegate_request, ConnectionResponse, NULL, NULL);
- if (err)
- {
- return err; // On error ConnectToServer leaves *sdRef set to NULL
- }
-
- // Only one of the two options can be set. If pid is zero, uuid is used.
- // If both are specified only pid will be used. We send across the pid
- // so that the daemon knows what to read from the socket.
-
- len += sizeof(int32_t);
-
- hdr = create_hdr(connection_delegate_request, &len, &ptr, 0, *sdRef);
- if (!hdr)
- {
- DNSServiceRefDeallocate(*sdRef);
- *sdRef = NULL;
- return kDNSServiceErr_NoMemory;
- }
-
- if (pid && setsockopt((*sdRef)->sockfd, SOL_SOCKET, SO_DELEGATED, &pid, sizeof(pid)) == -1)
- {
- // Free the hdr in case we return before calling deliver_request()
- if (hdr)
- free(hdr);
- DNSServiceRefDeallocate(*sdRef);
- *sdRef = NULL;
- return kDNSServiceErr_NoAuth;
- }
-
- if (!pid && setsockopt((*sdRef)->sockfd, SOL_SOCKET, SO_DELEGATED_UUID, uuid, sizeof(uuid_t)) == -1)
- {
- // Free the hdr in case we return before calling deliver_request()
- if (hdr)
- free(hdr);
- DNSServiceRefDeallocate(*sdRef);
- *sdRef = NULL;
- return kDNSServiceErr_NoAuth;
- }
-
- put_uint32(pid, &ptr);
-
- err = deliver_request(hdr, *sdRef); // Will free hdr for us
- if (err)
- {
- DNSServiceRefDeallocate(*sdRef);
- *sdRef = NULL;
- }
- return err;
-}
-#elif TARGET_IPHONE_SIMULATOR // This hack is for Simulator platform only
-DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid)
-{
- (void) pid;
- (void) uuid;
- return DNSServiceCreateConnection(sdRef);
-}
-#endif
-
-DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
-(
- DNSServiceRef sdRef,
- DNSRecordRef *RecordRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- const char *fullname,
- uint16_t rrtype,
- uint16_t rrclass,
- uint16_t rdlen,
- const void *rdata,
- uint32_t ttl,
- DNSServiceRegisterRecordReply callBack,
- void *context
-)
-{
- char *ptr;
- size_t len;
- ipc_msg_hdr *hdr = NULL;
- DNSRecordRef rref = NULL;
- DNSRecord **p;
- int f1 = (flags & kDNSServiceFlagsShared) != 0;
- int f2 = (flags & kDNSServiceFlagsUnique) != 0;
- if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
-
- if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
- flags |= kDNSServiceFlagsIncludeP2P;
-
- if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
-
- if (!DNSServiceRefValid(sdRef))
- {
- syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
- return kDNSServiceErr_BadReference;
- }
-
- if (sdRef->op != connection_request && sdRef->op != connection_delegate_request)
- {
- syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with non-DNSServiceCreateConnection DNSServiceRef %p %d", sdRef, sdRef->op);
- return kDNSServiceErr_BadReference;
- }
-
- *RecordRef = NULL;
-
- len = sizeof(DNSServiceFlags);
- len += 2 * sizeof(uint32_t); // interfaceIndex, ttl
- len += 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen
- len += strlen(fullname) + 1;
- len += rdlen;
-
- // Bump up the uid. Normally for shared operations (kDNSServiceFlagsShareConnection), this
- // is done in ConnectToServer. For DNSServiceRegisterRecord, ConnectToServer has already
- // been called. As multiple DNSServiceRegisterRecords can be multiplexed over a single
- // connection, we need a way to demultiplex the response so that the callback corresponding
- // to the right DNSServiceRegisterRecord instance can be called. Use the same mechanism that
- // is used by kDNSServiceFlagsShareConnection. create_hdr copies the uid value to ipc
- // hdr->client_context which will be returned in the ipc response.
- if (++sdRef->uid.u32[0] == 0)
- ++sdRef->uid.u32[1];
- hdr = create_hdr(reg_record_request, &len, &ptr, 1, sdRef);
- if (!hdr) return kDNSServiceErr_NoMemory;
-
- put_flags(flags, &ptr);
- put_uint32(interfaceIndex, &ptr);
- put_string(fullname, &ptr);
- put_uint16(rrtype, &ptr);
- put_uint16(rrclass, &ptr);
- put_uint16(rdlen, &ptr);
- put_rdata(rdlen, rdata, &ptr);
- put_uint32(ttl, &ptr);
-
- rref = malloc(sizeof(DNSRecord));
- if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; }
- rref->AppContext = context;
- rref->AppCallback = callBack;
- rref->record_index = sdRef->max_index++;
- rref->sdr = sdRef;
- rref->recnext = NULL;
- *RecordRef = rref;
- // Remember the uid that we are sending across so that we can match
- // when the response comes back.
- rref->uid = sdRef->uid;
- hdr->reg_index = rref->record_index;
-
- p = &(sdRef)->rec;
- while (*p) p = &(*p)->recnext;
- *p = rref;
-
- return deliver_request(hdr, sdRef); // Will free hdr for us
-}
-
-// sdRef returned by DNSServiceRegister()
-DNSServiceErrorType DNSSD_API DNSServiceAddRecord
-(
- DNSServiceRef sdRef,
- DNSRecordRef *RecordRef,
- DNSServiceFlags flags,
- uint16_t rrtype,
- uint16_t rdlen,
- const void *rdata,
- uint32_t ttl
-)
-{
- ipc_msg_hdr *hdr;
- size_t len = 0;
- char *ptr;
- DNSRecordRef rref;
- DNSRecord **p;
-
- if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
- if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSRecordRef pointer"); return kDNSServiceErr_BadParam; }
- if (sdRef->op != reg_service_request)
- {
- syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with non-DNSServiceRegister DNSServiceRef %p %d", sdRef, sdRef->op);
- return kDNSServiceErr_BadReference;
- }
-
- if (!DNSServiceRefValid(sdRef))
- {
- syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
- return kDNSServiceErr_BadReference;
- }
-
- *RecordRef = NULL;
-
- len += 2 * sizeof(uint16_t); // rrtype, rdlen
- len += rdlen;
- len += sizeof(uint32_t);
- len += sizeof(DNSServiceFlags);
-
- hdr = create_hdr(add_record_request, &len, &ptr, 1, sdRef);
- if (!hdr) return kDNSServiceErr_NoMemory;
- put_flags(flags, &ptr);
- put_uint16(rrtype, &ptr);
- put_uint16(rdlen, &ptr);
- put_rdata(rdlen, rdata, &ptr);
- put_uint32(ttl, &ptr);
-
- rref = malloc(sizeof(DNSRecord));
- if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; }
- rref->AppContext = NULL;
- rref->AppCallback = NULL;
- rref->record_index = sdRef->max_index++;
- rref->sdr = sdRef;
- rref->recnext = NULL;
- *RecordRef = rref;
- hdr->reg_index = rref->record_index;
-
- p = &(sdRef)->rec;
- while (*p) p = &(*p)->recnext;
- *p = rref;
-
- return deliver_request(hdr, sdRef); // Will free hdr for us
-}
-
-// DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
-DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
-(
- DNSServiceRef sdRef,
- DNSRecordRef RecordRef,
- DNSServiceFlags flags,
- uint16_t rdlen,
- const void *rdata,
- uint32_t ttl
-)
-{
- ipc_msg_hdr *hdr;
- size_t len = 0;
- char *ptr;
-
- if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
-
- if (!DNSServiceRefValid(sdRef))
- {
- syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
- return kDNSServiceErr_BadReference;
- }
-
- // Note: RecordRef is allowed to be NULL
-
- len += sizeof(uint16_t);
- len += rdlen;
- len += sizeof(uint32_t);
- len += sizeof(DNSServiceFlags);
-
- hdr = create_hdr(update_record_request, &len, &ptr, 1, sdRef);
- if (!hdr) return kDNSServiceErr_NoMemory;
- hdr->reg_index = RecordRef ? RecordRef->record_index : TXT_RECORD_INDEX;
- put_flags(flags, &ptr);
- put_uint16(rdlen, &ptr);
- put_rdata(rdlen, rdata, &ptr);
- put_uint32(ttl, &ptr);
- return deliver_request(hdr, sdRef); // Will free hdr for us
-}
-
-DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
-(
- DNSServiceRef sdRef,
- DNSRecordRef RecordRef,
- DNSServiceFlags flags
-)
-{
- ipc_msg_hdr *hdr;
- size_t len = 0;
- char *ptr;
- DNSServiceErrorType err;
-
- if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
- if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSRecordRef"); return kDNSServiceErr_BadParam; }
- if (!sdRef->max_index) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with bad DNSServiceRef"); return kDNSServiceErr_BadReference; }
-
- if (!DNSServiceRefValid(sdRef))
- {
- syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
- return kDNSServiceErr_BadReference;
- }
-
- len += sizeof(flags);
- hdr = create_hdr(remove_record_request, &len, &ptr, 1, sdRef);
- if (!hdr) return kDNSServiceErr_NoMemory;
- hdr->reg_index = RecordRef->record_index;
- put_flags(flags, &ptr);
- err = deliver_request(hdr, sdRef); // Will free hdr for us
- if (!err)
- {
- // This RecordRef could have been allocated in DNSServiceRegisterRecord or DNSServiceAddRecord.
- // If so, delink from the list before freeing
- DNSRecord **p = &sdRef->rec;
- while (*p && *p != RecordRef) p = &(*p)->recnext;
- if (*p) *p = RecordRef->recnext;
- free(RecordRef);
- }
- return err;
-}
-
-DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
-(
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- const char *fullname,
- uint16_t rrtype,
- uint16_t rrclass,
- uint16_t rdlen,
- const void *rdata
-)
-{
- char *ptr;
- size_t len;
- ipc_msg_hdr *hdr;
- DNSServiceOp *tmp;
-
- DNSServiceErrorType err = ConnectToServer(&tmp, flags, reconfirm_record_request, NULL, NULL, NULL);
- if (err) return err;
-
- len = sizeof(DNSServiceFlags);
- len += sizeof(uint32_t);
- len += strlen(fullname) + 1;
- len += 3 * sizeof(uint16_t);
- len += rdlen;
- hdr = create_hdr(reconfirm_record_request, &len, &ptr, 0, tmp);
- if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
-
- put_flags(flags, &ptr);
- put_uint32(interfaceIndex, &ptr);
- put_string(fullname, &ptr);
- put_uint16(rrtype, &ptr);
- put_uint16(rrclass, &ptr);
- put_uint16(rdlen, &ptr);
- put_rdata(rdlen, rdata, &ptr);
-
- err = deliver_request(hdr, tmp); // Will free hdr for us
- DNSServiceRefDeallocate(tmp);
- return err;
-}
-
-
-static void handle_port_mapping_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
-{
- union { uint32_t l; u_char b[4]; } addr;
- uint8_t protocol;
- union { uint16_t s; u_char b[2]; } internalPort;
- union { uint16_t s; u_char b[2]; } externalPort;
- uint32_t ttl;
-
- if (!data || data + 13 > end) goto fail;
-
- addr.b[0] = *data++;
- addr.b[1] = *data++;
- addr.b[2] = *data++;
- addr.b[3] = *data++;
- protocol = *data++;
- internalPort.b[0] = *data++;
- internalPort.b[1] = *data++;
- externalPort.b[0] = *data++;
- externalPort.b[1] = *data++;
- ttl = get_uint32(&data, end);
- if (!data) goto fail;
-
- ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, addr.l, protocol, internalPort.s, externalPort.s, ttl, sdr->AppContext);
- return;
- // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
-
- fail :
- syslog(LOG_WARNING, "dnssd_clientstub handle_port_mapping_response: error reading result from daemon");
-}
-
-DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
-(
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- uint32_t protocol, /* TCP and/or UDP */
- uint16_t internalPortInNetworkByteOrder,
- uint16_t externalPortInNetworkByteOrder,
- uint32_t ttl, /* time to live in seconds */
- DNSServiceNATPortMappingReply callBack,
- void *context /* may be NULL */
-)
-{
- char *ptr;
- size_t len;
- ipc_msg_hdr *hdr;
- union { uint16_t s; u_char b[2]; } internalPort = { internalPortInNetworkByteOrder };
- union { uint16_t s; u_char b[2]; } externalPort = { externalPortInNetworkByteOrder };
-
- DNSServiceErrorType err = ConnectToServer(sdRef, flags, port_mapping_request, handle_port_mapping_response, callBack, context);
- if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
-
- len = sizeof(flags);
- len += sizeof(interfaceIndex);
- len += sizeof(protocol);
- len += sizeof(internalPort);
- len += sizeof(externalPort);
- len += sizeof(ttl);
-
- hdr = create_hdr(port_mapping_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
- if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
-
- put_flags(flags, &ptr);
- put_uint32(interfaceIndex, &ptr);
- put_uint32(protocol, &ptr);
- *ptr++ = internalPort.b[0];
- *ptr++ = internalPort.b[1];
- *ptr++ = externalPort.b[0];
- *ptr++ = externalPort.b[1];
- put_uint32(ttl, &ptr);
-
- err = deliver_request(hdr, *sdRef); // Will free hdr for us
- if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
- return err;
-}
-
-#if _DNS_SD_LIBDISPATCH
-DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue
-(
- DNSServiceRef service,
- dispatch_queue_t queue
-)
-{
- int dnssd_fd = DNSServiceRefSockFD(service);
- if (dnssd_fd == dnssd_InvalidSocket) return kDNSServiceErr_BadParam;
- if (!queue)
- {
- syslog(LOG_WARNING, "dnssd_clientstub: DNSServiceSetDispatchQueue dispatch queue NULL");
- return kDNSServiceErr_BadParam;
- }
- if (service->disp_queue)
- {
- syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch queue set already");
- return kDNSServiceErr_BadParam;
- }
- if (service->disp_source)
- {
- syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch source set already");
- return kDNSServiceErr_BadParam;
- }
- service->disp_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, dnssd_fd, 0, queue);
- if (!service->disp_source)
- {
- syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch_source_create failed");
- return kDNSServiceErr_NoMemory;
- }
- service->disp_queue = queue;
- dispatch_source_set_event_handler(service->disp_source, ^{DNSServiceProcessResult(service);});
- dispatch_source_set_cancel_handler(service->disp_source, ^{dnssd_close(dnssd_fd);});
- dispatch_resume(service->disp_source);
- return kDNSServiceErr_NoError;
-}
-#endif // _DNS_SD_LIBDISPATCH
-
-#if !defined(_WIN32)
-
-static void DNSSD_API SleepKeepaliveCallback(DNSServiceRef sdRef, DNSRecordRef rec, const DNSServiceFlags flags,
- DNSServiceErrorType errorCode, void *context)
-{
- SleepKAContext *ka = (SleepKAContext *)context;
- (void)rec; // Unused
- (void)flags; // Unused
-
- if (sdRef->kacontext != context)
- syslog(LOG_WARNING, "SleepKeepaliveCallback context mismatch");
-
- if (ka->AppCallback)
- ((DNSServiceSleepKeepaliveReply)ka->AppCallback)(sdRef, errorCode, ka->AppContext);
-}
-
-DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
-(
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- int fd,
- unsigned int timeout,
- DNSServiceSleepKeepaliveReply callBack,
- void *context
-)
-{
- char source_str[INET6_ADDRSTRLEN];
- char target_str[INET6_ADDRSTRLEN];
- struct sockaddr_storage lss;
- struct sockaddr_storage rss;
- socklen_t len1, len2;
- unsigned int len, proxyreclen;
- char buf[256];
- DNSServiceErrorType err;
- DNSRecordRef record = NULL;
- char name[10];
- char recname[128];
- SleepKAContext *ka;
- unsigned int i, unique;
-
-
- (void) flags; //unused
- if (!timeout) return kDNSServiceErr_BadParam;
-
-
- len1 = sizeof(lss);
- if (getsockname(fd, (struct sockaddr *)&lss, &len1) < 0)
- {
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive: getsockname %d\n", errno);
- return kDNSServiceErr_BadParam;
- }
-
- len2 = sizeof(rss);
- if (getpeername(fd, (struct sockaddr *)&rss, &len2) < 0)
- {
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive: getpeername %d\n", errno);
- return kDNSServiceErr_BadParam;
- }
-
- if (len1 != len2)
- {
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive local/remote info not same");
- return kDNSServiceErr_Unknown;
- }
-
- unique = 0;
- if (lss.ss_family == AF_INET)
- {
- struct sockaddr_in *sl = (struct sockaddr_in *)&lss;
- struct sockaddr_in *sr = (struct sockaddr_in *)&rss;
- unsigned char *ptr = (unsigned char *)&sl->sin_addr;
-
- if (!inet_ntop(AF_INET, (const void *)&sr->sin_addr, target_str, sizeof (target_str)))
- {
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive remote info failed %d", errno);
- return kDNSServiceErr_Unknown;
- }
- if (!inet_ntop(AF_INET, (const void *)&sl->sin_addr, source_str, sizeof (source_str)))
- {
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive local info failed %d", errno);
- return kDNSServiceErr_Unknown;
- }
- // Sum of all bytes in the local address and port should result in a unique
- // number in the local network
- for (i = 0; i < sizeof(struct in_addr); i++)
- unique += ptr[i];
- unique += sl->sin_port;
- len = snprintf(buf+1, sizeof(buf) - 1, "t=%u h=%s d=%s l=%u r=%u", timeout, source_str, target_str, ntohs(sl->sin_port), ntohs(sr->sin_port));
- }
- else
- {
- struct sockaddr_in6 *sl6 = (struct sockaddr_in6 *)&lss;
- struct sockaddr_in6 *sr6 = (struct sockaddr_in6 *)&rss;
- unsigned char *ptr = (unsigned char *)&sl6->sin6_addr;
-
- if (!inet_ntop(AF_INET6, (const void *)&sr6->sin6_addr, target_str, sizeof (target_str)))
- {
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive remote6 info failed %d", errno);
- return kDNSServiceErr_Unknown;
- }
- if (!inet_ntop(AF_INET6, (const void *)&sl6->sin6_addr, source_str, sizeof (source_str)))
- {
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive local6 info failed %d", errno);
- return kDNSServiceErr_Unknown;
- }
- for (i = 0; i < sizeof(struct in6_addr); i++)
- unique += ptr[i];
- unique += sl6->sin6_port;
- len = snprintf(buf+1, sizeof(buf) - 1, "t=%u H=%s D=%s l=%u r=%u", timeout, source_str, target_str, ntohs(sl6->sin6_port), ntohs(sr6->sin6_port));
- }
-
- if (len >= (sizeof(buf) - 1))
- {
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit local/remote info");
- return kDNSServiceErr_Unknown;
- }
- // Include the NULL byte also in the first byte. The total length of the record includes the
- // first byte also.
- buf[0] = len + 1;
- proxyreclen = len + 2;
-
- len = snprintf(name, sizeof(name), "%u", unique);
- if (len >= sizeof(name))
- {
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit unique");
- return kDNSServiceErr_Unknown;
- }
-
- len = snprintf(recname, sizeof(recname), "%s.%s", name, "_keepalive._dns-sd._udp.local");
- if (len >= sizeof(recname))
- {
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit name");
- return kDNSServiceErr_Unknown;
- }
-
- ka = malloc(sizeof(SleepKAContext));
- if (!ka) return kDNSServiceErr_NoMemory;
- ka->AppCallback = callBack;
- ka->AppContext = context;
-
- err = DNSServiceCreateConnection(sdRef);
- if (err)
- {
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive cannot create connection");
- free(ka);
- return err;
- }
-
- // we don't care about the "record". When sdRef gets deallocated later, it will be freed too
- err = DNSServiceRegisterRecord(*sdRef, &record, kDNSServiceFlagsUnique, 0, recname,
- kDNSServiceType_NULL, kDNSServiceClass_IN, proxyreclen, buf, kDNSServiceInterfaceIndexAny, SleepKeepaliveCallback, ka);
- if (err)
- {
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive cannot create connection");
- free(ka);
- return err;
- }
- (*sdRef)->kacontext = ka;
- return kDNSServiceErr_NoError;
-}
-#endif
Copied: vendor/apple/mDNSResponder/561.1.1/mDNSShared/dnssd_clientstub.c (from rev 6984, vendor/apple/mDNSResponder/dist/mDNSShared/dnssd_clientstub.c)
===================================================================
--- vendor/apple/mDNSResponder/561.1.1/mDNSShared/dnssd_clientstub.c (rev 0)
+++ vendor/apple/mDNSResponder/561.1.1/mDNSShared/dnssd_clientstub.c 2015-03-20 01:14:52 UTC (rev 6985)
@@ -0,0 +1,2370 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2003-2004, Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+
+#if APPLE_OSX_mDNSResponder
+#include <mach-o/dyld.h>
+#include <uuid/uuid.h>
+#include <TargetConditionals.h>
+#endif
+
+#include "dnssd_ipc.h"
+
+#if defined(_WIN32)
+
+ #define _SSIZE_T
+ #include <CommonServices.h>
+ #include <DebugServices.h>
+ #include <winsock2.h>
+ #include <ws2tcpip.h>
+ #include <windows.h>
+ #include <stdarg.h>
+ #include <stdio.h>
+
+ #define sockaddr_mdns sockaddr_in
+ #define AF_MDNS AF_INET
+
+// Disable warning: "'type cast' : from data pointer 'void *' to function pointer"
+ #pragma warning(disable:4055)
+
+// Disable warning: "nonstandard extension, function/data pointer conversion in expression"
+ #pragma warning(disable:4152)
+
+extern BOOL IsSystemServiceDisabled();
+
+ #define sleep(X) Sleep((X) * 1000)
+
+static int g_initWinsock = 0;
+ #define LOG_WARNING kDebugLevelWarning
+ #define LOG_INFO kDebugLevelInfo
+static void syslog( int priority, const char * message, ...)
+{
+ va_list args;
+ int len;
+ char * buffer;
+ DWORD err = WSAGetLastError();
+ (void) priority;
+ va_start( args, message );
+ len = _vscprintf( message, args ) + 1;
+ buffer = malloc( len * sizeof(char) );
+ if ( buffer ) { vsprintf( buffer, message, args ); OutputDebugString( buffer ); free( buffer ); }
+ WSASetLastError( err );
+}
+#else
+
+ #include <sys/fcntl.h> // For O_RDWR etc.
+ #include <sys/time.h>
+ #include <sys/socket.h>
+ #include <syslog.h>
+
+ #define sockaddr_mdns sockaddr_un
+ #define AF_MDNS AF_LOCAL
+
+#endif
+
+// <rdar://problem/4096913> Specifies how many times we'll try and connect to the server.
+
+#define DNSSD_CLIENT_MAXTRIES 4
+
+// Uncomment the line below to use the old error return mechanism of creating a temporary named socket (e.g. in /var/tmp)
+//#define USE_NAMED_ERROR_RETURN_SOCKET 1
+
+// If the UDS client has not received a response from the daemon in 60 secs, it is unlikely to get one
+// Note: Timeout of 3 secs should be sufficient in normal scenarios, but 60 secs is chosen as a safeguard since
+// some clients may come up before mDNSResponder itself after a BOOT and on rare ocassions IOPM/Keychain/D2D calls
+// in mDNSResponder's INIT may take a much longer time to return
+#define DNSSD_CLIENT_TIMEOUT 60
+
+#ifndef CTL_PATH_PREFIX
+#define CTL_PATH_PREFIX "/var/tmp/dnssd_result_socket."
+#endif
+
+typedef struct
+{
+ ipc_msg_hdr ipc_hdr;
+ DNSServiceFlags cb_flags;
+ uint32_t cb_interface;
+ DNSServiceErrorType cb_err;
+} CallbackHeader;
+
+typedef struct _DNSServiceRef_t DNSServiceOp;
+typedef struct _DNSRecordRef_t DNSRecord;
+
+#if !defined(_WIN32)
+typedef struct
+{
+ void *AppCallback; // Client callback function and context
+ void *AppContext;
+} SleepKAContext;
+#endif
+
+// client stub callback to process message from server and deliver results to client application
+typedef void (*ProcessReplyFn)(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *msg, const char *const end);
+
+#define ValidatorBits 0x12345678
+#define DNSServiceRefValid(X) (dnssd_SocketValid((X)->sockfd) && (((X)->sockfd ^ (X)->validator) == ValidatorBits))
+
+// When using kDNSServiceFlagsShareConnection, there is one primary _DNSServiceOp_t, and zero or more subordinates
+// For the primary, the 'next' field points to the first subordinate, and its 'next' field points to the next, and so on.
+// For the primary, the 'primary' field is NULL; for subordinates the 'primary' field points back to the associated primary
+//
+// _DNS_SD_LIBDISPATCH is defined where libdispatch/GCD is available. This does not mean that the application will use the
+// DNSServiceSetDispatchQueue API. Hence any new code guarded with _DNS_SD_LIBDISPATCH should still be backwards compatible.
+struct _DNSServiceRef_t
+{
+ DNSServiceOp *next; // For shared connection
+ DNSServiceOp *primary; // For shared connection
+ dnssd_sock_t sockfd; // Connected socket between client and daemon
+ dnssd_sock_t validator; // Used to detect memory corruption, double disposals, etc.
+ client_context_t uid; // For shared connection requests, each subordinate DNSServiceRef has its own ID,
+ // unique within the scope of the same shared parent DNSServiceRef
+ uint32_t op; // request_op_t or reply_op_t
+ uint32_t max_index; // Largest assigned record index - 0 if no additional records registered
+ uint32_t logcounter; // Counter used to control number of syslog messages we write
+ int *moreptr; // Set while DNSServiceProcessResult working on this particular DNSServiceRef
+ ProcessReplyFn ProcessReply; // Function pointer to the code to handle received messages
+ void *AppCallback; // Client callback function and context
+ void *AppContext;
+ DNSRecord *rec;
+#if _DNS_SD_LIBDISPATCH
+ dispatch_source_t disp_source;
+ dispatch_queue_t disp_queue;
+#endif
+ void *kacontext;
+};
+
+struct _DNSRecordRef_t
+{
+ DNSRecord *recnext;
+ void *AppContext;
+ DNSServiceRegisterRecordReply AppCallback;
+ DNSRecordRef recref;
+ uint32_t record_index; // index is unique to the ServiceDiscoveryRef
+ client_context_t uid; // For demultiplexing multiple DNSServiceRegisterRecord calls
+ DNSServiceOp *sdr;
+};
+
+// Write len bytes. Return 0 on success, -1 on error
+static int write_all(dnssd_sock_t sd, char *buf, size_t len)
+{
+ // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
+ //if (send(sd, buf, len, MSG_WAITALL) != len) return -1;
+ while (len)
+ {
+ ssize_t num_written = send(sd, buf, (long)len, 0);
+ if (num_written < 0 || (size_t)num_written > len)
+ {
+ // Should never happen. If it does, it indicates some OS bug,
+ // or that the mDNSResponder daemon crashed (which should never happen).
+ #if !defined(__ppc__) && defined(SO_ISDEFUNCT)
+ int defunct;
+ socklen_t dlen = sizeof (defunct);
+ if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0)
+ syslog(LOG_WARNING, "dnssd_clientstub write_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
+ if (!defunct)
+ syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
+ (long)num_written, (long)len,
+ (num_written < 0) ? dnssd_errno : 0,
+ (num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
+ else
+ syslog(LOG_INFO, "dnssd_clientstub write_all(%d) DEFUNCT", sd);
+ #else
+ syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
+ (long)num_written, (long)len,
+ (num_written < 0) ? dnssd_errno : 0,
+ (num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
+ #endif
+ return -1;
+ }
+ buf += num_written;
+ len -= num_written;
+ }
+ return 0;
+}
+
+enum { read_all_success = 0, read_all_fail = -1, read_all_wouldblock = -2 };
+
+// Read len bytes. Return 0 on success, read_all_fail on error, or read_all_wouldblock for
+static int read_all(dnssd_sock_t sd, char *buf, int len)
+{
+ // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
+ //if (recv(sd, buf, len, MSG_WAITALL) != len) return -1;
+
+ while (len)
+ {
+ ssize_t num_read = recv(sd, buf, len, 0);
+ // It is valid to get an interrupted system call error e.g., somebody attaching
+ // in a debugger, retry without failing
+ if ((num_read < 0) && (errno == EINTR))
+ {
+ syslog(LOG_INFO, "dnssd_clientstub read_all: EINTR continue");
+ continue;
+ }
+ if ((num_read == 0) || (num_read < 0) || (num_read > len))
+ {
+ int printWarn = 0;
+ int defunct = 0;
+ // Should never happen. If it does, it indicates some OS bug,
+ // or that the mDNSResponder daemon crashed (which should never happen).
+#if defined(WIN32)
+ // <rdar://problem/7481776> Suppress logs for "A non-blocking socket operation
+ // could not be completed immediately"
+ if (WSAGetLastError() != WSAEWOULDBLOCK)
+ printWarn = 1;
+#endif
+#if !defined(__ppc__) && defined(SO_ISDEFUNCT)
+ {
+ socklen_t dlen = sizeof (defunct);
+ if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0)
+ syslog(LOG_WARNING, "dnssd_clientstub read_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
+ }
+ if (!defunct)
+ printWarn = 1;
+#endif
+ if (printWarn)
+ syslog(LOG_WARNING, "dnssd_clientstub read_all(%d) failed %ld/%ld %d %s", sd,
+ (long)num_read, (long)len,
+ (num_read < 0) ? dnssd_errno : 0,
+ (num_read < 0) ? dnssd_strerror(dnssd_errno) : "");
+ else if (defunct)
+ syslog(LOG_INFO, "dnssd_clientstub read_all(%d) DEFUNCT", sd);
+ return (num_read < 0 && dnssd_errno == dnssd_EWOULDBLOCK) ? read_all_wouldblock : read_all_fail;
+ }
+ buf += num_read;
+ len -= num_read;
+ }
+ return read_all_success;
+}
+
+// Returns 1 if more bytes remain to be read on socket descriptor sd, 0 otherwise
+static int more_bytes(dnssd_sock_t sd)
+{
+ struct timeval tv = { 0, 0 };
+ fd_set readfds;
+ fd_set *fs;
+ int ret;
+
+ if (sd < FD_SETSIZE)
+ {
+ fs = &readfds;
+ FD_ZERO(fs);
+ }
+ else
+ {
+ // Compute the number of integers needed for storing "sd". Internally fd_set is stored
+ // as an array of ints with one bit for each fd and hence we need to compute
+ // the number of ints needed rather than the number of bytes. If "sd" is 32, we need
+ // two ints and not just one.
+ int nfdbits = sizeof (int) * 8;
+ int nints = (sd/nfdbits) + 1;
+ fs = (fd_set *)calloc(nints, sizeof(int));
+ if (fs == NULL)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub more_bytes: malloc failed");
+ return 0;
+ }
+ }
+ FD_SET(sd, fs);
+ ret = select((int)sd+1, fs, (fd_set*)NULL, (fd_set*)NULL, &tv);
+ if (fs != &readfds)
+ free(fs);
+ return (ret > 0);
+}
+
+// set_waitlimit() implements a timeout using select. It is called from deliver_request() before recv() OR accept()
+// to ensure the UDS clients are not blocked in these system calls indefinitely.
+// Note: Ideally one should never be blocked here, because it indicates either mDNSResponder daemon is not yet up/hung/
+// superbusy/crashed or some other OS bug. For eg: On Windows which suffers from 3rd party software
+// (primarily 3rd party firewall software) interfering with proper functioning of the TCP protocol stack it is possible
+// the next operation on this socket(recv/accept) is blocked since we depend on TCP to communicate with the system service.
+static int set_waitlimit(dnssd_sock_t sock, int timeout)
+{
+ int gDaemonErr = kDNSServiceErr_NoError;
+
+ // To prevent stack corruption since select does not work with timeout if fds > FD_SETSIZE(1024)
+ if (!gDaemonErr && sock < FD_SETSIZE)
+ {
+ struct timeval tv;
+ fd_set set;
+
+ FD_ZERO(&set);
+ FD_SET(sock, &set);
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+ if (!select((int)(sock + 1), &set, NULL, NULL, &tv))
+ {
+ // Ideally one should never hit this case: See comments before set_waitlimit()
+ syslog(LOG_WARNING, "dnssd_clientstub set_waitlimit:_daemon timed out (%d secs) without any response: Socket %d", timeout, sock);
+ gDaemonErr = kDNSServiceErr_Timeout;
+ }
+ }
+ return gDaemonErr;
+}
+
+/* create_hdr
+ *
+ * allocate and initialize an ipc message header. Value of len should initially be the
+ * length of the data, and is set to the value of the data plus the header. data_start
+ * is set to point to the beginning of the data section. SeparateReturnSocket should be
+ * non-zero for calls that can't receive an immediate error return value on their primary
+ * socket, and therefore require a separate return path for the error code result.
+ * if zero, the path to a control socket is appended at the beginning of the message buffer.
+ * data_start is set past this string.
+ */
+static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int SeparateReturnSocket, DNSServiceOp *ref)
+{
+ char *msg = NULL;
+ ipc_msg_hdr *hdr;
+ int datalen;
+#if !defined(USE_TCP_LOOPBACK)
+ char ctrl_path[64] = ""; // "/var/tmp/dnssd_result_socket.xxxxxxxxxx-xxx-xxxxxx"
+#endif
+
+ if (SeparateReturnSocket)
+ {
+#if defined(USE_TCP_LOOPBACK)
+ *len += 2; // Allocate space for two-byte port number
+#elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
+ struct timeval tv;
+ if (gettimeofday(&tv, NULL) < 0)
+ { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: gettimeofday failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); return NULL; }
+ sprintf(ctrl_path, "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX, (int)getpid(),
+ (unsigned long)(tv.tv_sec & 0xFFF), (unsigned long)(tv.tv_usec));
+ *len += strlen(ctrl_path) + 1;
+#else
+ *len += 1; // Allocate space for single zero byte (empty C string)
+#endif
+ }
+
+ datalen = (int) *len;
+ *len += sizeof(ipc_msg_hdr);
+
+ // Write message to buffer
+ msg = malloc(*len);
+ if (!msg) { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: malloc failed"); return NULL; }
+
+ memset(msg, 0, *len);
+ hdr = (ipc_msg_hdr *)msg;
+ hdr->version = VERSION;
+ hdr->datalen = datalen;
+ hdr->ipc_flags = 0;
+ hdr->op = op;
+ hdr->client_context = ref->uid;
+ hdr->reg_index = 0;
+ *data_start = msg + sizeof(ipc_msg_hdr);
+#if defined(USE_TCP_LOOPBACK)
+ // Put dummy data in for the port, since we don't know what it is yet.
+ // The data will get filled in before we send the message. This happens in deliver_request().
+ if (SeparateReturnSocket) put_uint16(0, data_start);
+#else
+ if (SeparateReturnSocket) put_string(ctrl_path, data_start);
+#endif
+ return hdr;
+}
+
+static void FreeDNSRecords(DNSServiceOp *sdRef)
+{
+ DNSRecord *rec = sdRef->rec;
+ while (rec)
+ {
+ DNSRecord *next = rec->recnext;
+ free(rec);
+ rec = next;
+ }
+}
+
+static void FreeDNSServiceOp(DNSServiceOp *x)
+{
+ // We don't use our DNSServiceRefValid macro here because if we're cleaning up after a socket() call failed
+ // then sockfd could legitimately contain a failing value (e.g. dnssd_InvalidSocket)
+ if ((x->sockfd ^ x->validator) != ValidatorBits)
+ syslog(LOG_WARNING, "dnssd_clientstub attempt to dispose invalid DNSServiceRef %p %08X %08X", x, x->sockfd, x->validator);
+ else
+ {
+ x->next = NULL;
+ x->primary = NULL;
+ x->sockfd = dnssd_InvalidSocket;
+ x->validator = 0xDDDDDDDD;
+ x->op = request_op_none;
+ x->max_index = 0;
+ x->logcounter = 0;
+ x->moreptr = NULL;
+ x->ProcessReply = NULL;
+ x->AppCallback = NULL;
+ x->AppContext = NULL;
+#if _DNS_SD_LIBDISPATCH
+ if (x->disp_source) dispatch_release(x->disp_source);
+ x->disp_source = NULL;
+ x->disp_queue = NULL;
+#endif
+ // DNSRecords may have been added to subordinate sdRef e.g., DNSServiceRegister/DNSServiceAddRecord
+ // or on the main sdRef e.g., DNSServiceCreateConnection/DNSServiveRegisterRecord. DNSRecords may have
+ // been freed if the application called DNSRemoveRecord
+ FreeDNSRecords(x);
+ if (x->kacontext)
+ {
+ free(x->kacontext);
+ x->kacontext = NULL;
+ }
+ free(x);
+ }
+}
+
+// Return a connected service ref (deallocate with DNSServiceRefDeallocate)
+static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags flags, uint32_t op, ProcessReplyFn ProcessReply, void *AppCallback, void *AppContext)
+{
+ int NumTries = 0;
+
+ dnssd_sockaddr_t saddr;
+ DNSServiceOp *sdr;
+
+ if (!ref)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSService operation with NULL DNSServiceRef");
+ return kDNSServiceErr_BadParam;
+ }
+
+ if (flags & kDNSServiceFlagsShareConnection)
+ {
+ if (!*ref)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with NULL DNSServiceRef");
+ return kDNSServiceErr_BadParam;
+ }
+ if (!DNSServiceRefValid(*ref) || ((*ref)->op != connection_request && (*ref)->op != connection_delegate_request) || (*ref)->primary)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with invalid DNSServiceRef %p %08X %08X op %d",
+ (*ref), (*ref)->sockfd, (*ref)->validator, (*ref)->op);
+ *ref = NULL;
+ return kDNSServiceErr_BadReference;
+ }
+ }
+
+ #if defined(_WIN32)
+ if (!g_initWinsock)
+ {
+ WSADATA wsaData;
+ g_initWinsock = 1;
+ if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { *ref = NULL; return kDNSServiceErr_ServiceNotRunning; }
+ }
+ // <rdar://problem/4096913> If the system service is disabled, we only want to try to connect once
+ if (IsSystemServiceDisabled())
+ NumTries = DNSSD_CLIENT_MAXTRIES;
+ #endif
+
+ sdr = malloc(sizeof(DNSServiceOp));
+ if (!sdr)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: malloc failed");
+ *ref = NULL;
+ return kDNSServiceErr_NoMemory;
+ }
+ sdr->next = NULL;
+ sdr->primary = NULL;
+ sdr->sockfd = dnssd_InvalidSocket;
+ sdr->validator = sdr->sockfd ^ ValidatorBits;
+ sdr->op = op;
+ sdr->max_index = 0;
+ sdr->logcounter = 0;
+ sdr->moreptr = NULL;
+ sdr->uid.u32[0] = 0;
+ sdr->uid.u32[1] = 0;
+ sdr->ProcessReply = ProcessReply;
+ sdr->AppCallback = AppCallback;
+ sdr->AppContext = AppContext;
+ sdr->rec = NULL;
+#if _DNS_SD_LIBDISPATCH
+ sdr->disp_source = NULL;
+ sdr->disp_queue = NULL;
+#endif
+ sdr->kacontext = NULL;
+
+ if (flags & kDNSServiceFlagsShareConnection)
+ {
+ DNSServiceOp **p = &(*ref)->next; // Append ourselves to end of primary's list
+ while (*p)
+ p = &(*p)->next;
+ *p = sdr;
+ // Preincrement counter before we use it -- it helps with debugging if we know the all-zeroes ID should never appear
+ if (++(*ref)->uid.u32[0] == 0)
+ ++(*ref)->uid.u32[1]; // In parent DNSServiceOp increment UID counter
+ sdr->primary = *ref; // Set our primary pointer
+ sdr->sockfd = (*ref)->sockfd; // Inherit primary's socket
+ sdr->validator = (*ref)->validator;
+ sdr->uid = (*ref)->uid;
+ //printf("ConnectToServer sharing socket %d\n", sdr->sockfd);
+ }
+ else
+ {
+ #ifdef SO_NOSIGPIPE
+ const unsigned long optval = 1;
+ #endif
+ #ifndef USE_TCP_LOOPBACK
+ char* uds_serverpath = getenv(MDNS_UDS_SERVERPATH_ENVVAR);
+ if (uds_serverpath == NULL)
+ uds_serverpath = MDNS_UDS_SERVERPATH;
+ #endif
+ *ref = NULL;
+ sdr->sockfd = socket(AF_DNSSD, SOCK_STREAM, 0);
+ sdr->validator = sdr->sockfd ^ ValidatorBits;
+ if (!dnssd_SocketValid(sdr->sockfd))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: socket failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
+ FreeDNSServiceOp(sdr);
+ return kDNSServiceErr_NoMemory;
+ }
+ #ifdef SO_NOSIGPIPE
+ // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
+ if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_NOSIGPIPE failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
+ #endif
+ #if defined(USE_TCP_LOOPBACK)
+ saddr.sin_family = AF_INET;
+ saddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
+ saddr.sin_port = htons(MDNS_TCP_SERVERPORT);
+ #else
+ saddr.sun_family = AF_LOCAL;
+ strcpy(saddr.sun_path, uds_serverpath);
+ #if !defined(__ppc__) && defined(SO_DEFUNCTOK)
+ {
+ int defunct = 1;
+ if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0)
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
+ }
+ #endif
+ #endif
+
+ while (1)
+ {
+ int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
+ if (!err)
+ break; // If we succeeded, return sdr
+ // If we failed, then it may be because the daemon is still launching.
+ // This can happen for processes that launch early in the boot process, while the
+ // daemon is still coming up. Rather than fail here, we wait 1 sec and try again.
+ // If, after DNSSD_CLIENT_MAXTRIES, we still can't connect to the daemon,
+ // then we give up and return a failure code.
+ if (++NumTries < DNSSD_CLIENT_MAXTRIES)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect()-> No of tries: %d", NumTries);
+ sleep(1); // Sleep a bit, then try again
+ }
+ else
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect() failed path:%s Socket:%d Err:%d Errno:%d %s",
+ uds_serverpath, sdr->sockfd, err, dnssd_errno, dnssd_strerror(dnssd_errno));
+ dnssd_close(sdr->sockfd);
+ FreeDNSServiceOp(sdr);
+ return kDNSServiceErr_ServiceNotRunning;
+ }
+ }
+ //printf("ConnectToServer opened socket %d\n", sdr->sockfd);
+ }
+
+ *ref = sdr;
+ return kDNSServiceErr_NoError;
+}
+
+#define deliver_request_bailout(MSG) \
+ do { syslog(LOG_WARNING, "dnssd_clientstub deliver_request: %s failed %d (%s)", (MSG), dnssd_errno, dnssd_strerror(dnssd_errno)); goto cleanup; } while(0)
+
+static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
+{
+ uint32_t datalen = hdr->datalen; // We take a copy here because we're going to convert hdr->datalen to network byte order
+ #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
+ char *const data = (char *)hdr + sizeof(ipc_msg_hdr);
+ #endif
+ dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
+ DNSServiceErrorType err = kDNSServiceErr_Unknown; // Default for the "goto cleanup" cases
+ int MakeSeparateReturnSocket = 0;
+
+ // Note: need to check hdr->op, not sdr->op.
+ // hdr->op contains the code for the specific operation we're currently doing, whereas sdr->op
+ // contains the original parent DNSServiceOp (e.g. for an add_record_request, hdr->op will be
+ // add_record_request but the parent sdr->op will be connection_request or reg_service_request)
+ if (sdr->primary ||
+ hdr->op == reg_record_request || hdr->op == add_record_request || hdr->op == update_record_request || hdr->op == remove_record_request)
+ MakeSeparateReturnSocket = 1;
+
+ if (!DNSServiceRefValid(sdr))
+ {
+ if (hdr)
+ free(hdr);
+ syslog(LOG_WARNING, "dnssd_clientstub deliver_request: invalid DNSServiceRef %p %08X %08X", sdr, sdr->sockfd, sdr->validator);
+ return kDNSServiceErr_BadReference;
+ }
+
+ if (!hdr)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub deliver_request: !hdr");
+ return kDNSServiceErr_Unknown;
+ }
+
+ if (MakeSeparateReturnSocket)
+ {
+ #if defined(USE_TCP_LOOPBACK)
+ {
+ union { uint16_t s; u_char b[2]; } port;
+ dnssd_sockaddr_t caddr;
+ dnssd_socklen_t len = (dnssd_socklen_t) sizeof(caddr);
+ listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
+ if (!dnssd_SocketValid(listenfd)) deliver_request_bailout("TCP socket");
+
+ caddr.sin_family = AF_INET;
+ caddr.sin_port = 0;
+ caddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
+ if (bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr)) < 0) deliver_request_bailout("TCP bind");
+ if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) deliver_request_bailout("TCP getsockname");
+ if (listen(listenfd, 1) < 0) deliver_request_bailout("TCP listen");
+ port.s = caddr.sin_port;
+ data[0] = port.b[0]; // don't switch the byte order, as the
+ data[1] = port.b[1]; // daemon expects it in network byte order
+ }
+ #elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
+ {
+ mode_t mask;
+ int bindresult;
+ dnssd_sockaddr_t caddr;
+ listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
+ if (!dnssd_SocketValid(listenfd)) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET socket");
+
+ caddr.sun_family = AF_LOCAL;
+ // According to Stevens (section 3.2), there is no portable way to
+ // determine whether sa_len is defined on a particular platform.
+ #ifndef NOT_HAVE_SA_LEN
+ caddr.sun_len = sizeof(struct sockaddr_un);
+ #endif
+ strcpy(caddr.sun_path, data);
+ mask = umask(0);
+ bindresult = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr));
+ umask(mask);
+ if (bindresult < 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET bind");
+ if (listen(listenfd, 1) < 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET listen");
+ }
+ #else
+ {
+ dnssd_sock_t sp[2];
+ if (socketpair(AF_DNSSD, SOCK_STREAM, 0, sp) < 0) deliver_request_bailout("socketpair");
+ else
+ {
+ errsd = sp[0]; // We'll read our four-byte error code from sp[0]
+ listenfd = sp[1]; // We'll send sp[1] to the daemon
+ #if !defined(__ppc__) && defined(SO_DEFUNCTOK)
+ {
+ int defunct = 1;
+ if (setsockopt(errsd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0)
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
+ }
+ #endif
+ }
+ }
+ #endif
+ }
+
+#if !defined(USE_TCP_LOOPBACK) && !defined(USE_NAMED_ERROR_RETURN_SOCKET)
+ // If we're going to make a separate error return socket, and pass it to the daemon
+ // using sendmsg, then we'll hold back one data byte to go with it.
+ // On some versions of Unix (including Leopard) sending a control message without
+ // any associated data does not work reliably -- e.g. one particular issue we ran
+ // into is that if the receiving program is in a kqueue loop waiting to be notified
+ // of the received message, it doesn't get woken up when the control message arrives.
+ if (MakeSeparateReturnSocket || sdr->op == send_bpf)
+ datalen--; // Okay to use sdr->op when checking for op == send_bpf
+#endif
+
+ // At this point, our listening socket is set up and waiting, if necessary, for the daemon to connect back to
+ ConvertHeaderBytes(hdr);
+ //syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %lu bytes", (unsigned long)(datalen + sizeof(ipc_msg_hdr)));
+ //if (MakeSeparateReturnSocket) syslog(LOG_WARNING, "dnssd_clientstub deliver_request name is %s", data);
+#if TEST_SENDING_ONE_BYTE_AT_A_TIME
+ unsigned int i;
+ for (i=0; i<datalen + sizeof(ipc_msg_hdr); i++)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %d", i);
+ if (write_all(sdr->sockfd, ((char *)hdr)+i, 1) < 0)
+ { syslog(LOG_WARNING, "write_all (byte %u) failed", i); goto cleanup; }
+ usleep(10000);
+ }
+#else
+ if (write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr)) < 0)
+ {
+ // write_all already prints an error message if there is an error writing to
+ // the socket except for DEFUNCT. Logging here is unnecessary and also wrong
+ // in the case of DEFUNCT sockets
+ syslog(LOG_INFO, "dnssd_clientstub deliver_request ERROR: write_all(%d, %lu bytes) failed",
+ sdr->sockfd, (unsigned long)(datalen + sizeof(ipc_msg_hdr)));
+ goto cleanup;
+ }
+#endif
+
+ if (!MakeSeparateReturnSocket)
+ errsd = sdr->sockfd;
+ if (MakeSeparateReturnSocket || sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf
+ {
+#if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
+ // At this point we may wait in accept for a few milliseconds waiting for the daemon to connect back to us,
+ // but that's okay -- the daemon should not take more than a few milliseconds to respond.
+ // set_waitlimit() ensures we do not block indefinitely just in case something is wrong
+ dnssd_sockaddr_t daddr;
+ dnssd_socklen_t len = sizeof(daddr);
+ if ((err = set_waitlimit(listenfd, DNSSD_CLIENT_TIMEOUT)) != kDNSServiceErr_NoError)
+ goto cleanup;
+ errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
+ if (!dnssd_SocketValid(errsd))
+ deliver_request_bailout("accept");
+#else
+
+ struct iovec vec = { ((char *)hdr) + sizeof(ipc_msg_hdr) + datalen, 1 }; // Send the last byte along with the SCM_RIGHTS
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ char cbuf[CMSG_SPACE(4 * sizeof(dnssd_sock_t))];
+
+ msg.msg_name = 0;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &vec;
+ msg.msg_iovlen = 1;
+ msg.msg_flags = 0;
+ if (MakeSeparateReturnSocket || sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf
+ {
+ if (sdr->op == send_bpf)
+ {
+ int i;
+ char p[12]; // Room for "/dev/bpf999" with terminating null
+ for (i=0; i<100; i++)
+ {
+ snprintf(p, sizeof(p), "/dev/bpf%d", i);
+ listenfd = open(p, O_RDWR, 0);
+ //if (dnssd_SocketValid(listenfd)) syslog(LOG_WARNING, "Sending fd %d for %s", listenfd, p);
+ if (!dnssd_SocketValid(listenfd) && dnssd_errno != EBUSY)
+ syslog(LOG_WARNING, "Error opening %s %d (%s)", p, dnssd_errno, dnssd_strerror(dnssd_errno));
+ if (dnssd_SocketValid(listenfd) || dnssd_errno != EBUSY) break;
+ }
+ }
+ msg.msg_control = cbuf;
+ msg.msg_controllen = CMSG_LEN(sizeof(dnssd_sock_t));
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len = CMSG_LEN(sizeof(dnssd_sock_t));
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ *((dnssd_sock_t *)CMSG_DATA(cmsg)) = listenfd;
+ }
+
+#if TEST_KQUEUE_CONTROL_MESSAGE_BUG
+ sleep(1);
+#endif
+
+#if DEBUG_64BIT_SCM_RIGHTS
+ syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d %ld %ld %ld/%ld/%ld/%ld",
+ errsd, listenfd, sizeof(dnssd_sock_t), sizeof(void*),
+ sizeof(struct cmsghdr) + sizeof(dnssd_sock_t),
+ CMSG_LEN(sizeof(dnssd_sock_t)), (long)CMSG_SPACE(sizeof(dnssd_sock_t)),
+ (long)((char*)CMSG_DATA(cmsg) + 4 - cbuf));
+#endif // DEBUG_64BIT_SCM_RIGHTS
+
+ if (sendmsg(sdr->sockfd, &msg, 0) < 0)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub deliver_request ERROR: sendmsg failed read sd=%d write sd=%d errno %d (%s)",
+ errsd, listenfd, dnssd_errno, dnssd_strerror(dnssd_errno));
+ err = kDNSServiceErr_Incompatible;
+ goto cleanup;
+ }
+
+#if DEBUG_64BIT_SCM_RIGHTS
+ syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d okay", errsd, listenfd);
+#endif // DEBUG_64BIT_SCM_RIGHTS
+
+#endif
+ // Close our end of the socketpair *before* calling read_all() to get the four-byte error code.
+ // Otherwise, if the daemon closes our socket (or crashes), we will have to wait for a timeout
+ // in read_all() because the socket is not closed (we still have an open reference to it)
+ // Note: listenfd is overwritten in the case of send_bpf above and that will be closed here
+ // for send_bpf operation.
+ dnssd_close(listenfd);
+ listenfd = dnssd_InvalidSocket; // Make sure we don't close it a second time in the cleanup handling below
+ }
+
+ // At this point we may wait in read_all for a few milliseconds waiting for the daemon to send us the error code,
+ // but that's okay -- the daemon should not take more than a few milliseconds to respond.
+ // set_waitlimit() ensures we do not block indefinitely just in case something is wrong
+ if (sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf
+ err = kDNSServiceErr_NoError;
+ else if ((err = set_waitlimit(errsd, DNSSD_CLIENT_TIMEOUT)) == kDNSServiceErr_NoError)
+ {
+ if (read_all(errsd, (char*)&err, (int)sizeof(err)) < 0)
+ err = kDNSServiceErr_ServiceNotRunning; // On failure read_all will have written a message to syslog for us
+ else
+ err = ntohl(err);
+ }
+ //syslog(LOG_WARNING, "dnssd_clientstub deliver_request: retrieved error code %d", err);
+
+cleanup:
+ if (MakeSeparateReturnSocket)
+ {
+ if (dnssd_SocketValid(listenfd)) dnssd_close(listenfd);
+ if (dnssd_SocketValid(errsd)) dnssd_close(errsd);
+#if defined(USE_NAMED_ERROR_RETURN_SOCKET)
+ // syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removing UDS: %s", data);
+ if (unlink(data) != 0)
+ syslog(LOG_WARNING, "dnssd_clientstub WARNING: unlink(\"%s\") failed errno %d (%s)", data, dnssd_errno, dnssd_strerror(dnssd_errno));
+ // else syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removed UDS: %s", data);
+#endif
+ }
+
+ free(hdr);
+ return err;
+}
+
+int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef)
+{
+ if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with NULL DNSServiceRef"); return dnssd_InvalidSocket; }
+
+ if (!DNSServiceRefValid(sdRef))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with invalid DNSServiceRef %p %08X %08X",
+ sdRef, sdRef->sockfd, sdRef->validator);
+ return dnssd_InvalidSocket;
+ }
+
+ if (sdRef->primary)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef);
+ return dnssd_InvalidSocket;
+ }
+
+ return (int) sdRef->sockfd;
+}
+
+#if _DNS_SD_LIBDISPATCH
+static void CallbackWithError(DNSServiceRef sdRef, DNSServiceErrorType error)
+{
+ DNSServiceOp *sdr = sdRef;
+ DNSServiceOp *sdrNext;
+ DNSRecord *rec;
+ DNSRecord *recnext;
+ int morebytes;
+
+ while (sdr)
+ {
+ // We can't touch the sdr after the callback as it can be deallocated in the callback
+ sdrNext = sdr->next;
+ morebytes = 1;
+ sdr->moreptr = &morebytes;
+ switch (sdr->op)
+ {
+ case resolve_request:
+ if (sdr->AppCallback) ((DNSServiceResolveReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL, sdr->AppContext);
+ break;
+ case query_request:
+ if (sdr->AppCallback) ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL, 0, sdr->AppContext);
+ break;
+ case addrinfo_request:
+ if (sdr->AppCallback) ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, NULL, 0, sdr->AppContext);
+ break;
+ case browse_request:
+ if (sdr->AppCallback) ((DNSServiceBrowseReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, NULL, sdr->AppContext);
+ break;
+ case reg_service_request:
+ if (sdr->AppCallback) ((DNSServiceRegisterReply) sdr->AppCallback)(sdr, 0, error, NULL, 0, NULL, sdr->AppContext);
+ break;
+ case enumeration_request:
+ if (sdr->AppCallback) ((DNSServiceDomainEnumReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, sdr->AppContext);
+ break;
+ case connection_request:
+ case connection_delegate_request:
+ // This means Register Record, walk the list of DNSRecords to do the callback
+ rec = sdr->rec;
+ while (rec)
+ {
+ recnext = rec->recnext;
+ if (rec->AppCallback) ((DNSServiceRegisterRecordReply)rec->AppCallback)(sdr, 0, 0, error, rec->AppContext);
+ // The Callback can call DNSServiceRefDeallocate which in turn frees sdr and all the records.
+ // Detect that and return early
+ if (!morebytes) {syslog(LOG_WARNING, "dnssdclientstub:Record: CallbackwithError morebytes zero"); return;}
+ rec = recnext;
+ }
+ break;
+ case port_mapping_request:
+ if (sdr->AppCallback) ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, 0, 0, error, 0, 0, 0, 0, 0, sdr->AppContext);
+ break;
+ default:
+ syslog(LOG_WARNING, "dnssd_clientstub CallbackWithError called with bad op %d", sdr->op);
+ }
+ // If DNSServiceRefDeallocate was called in the callback, morebytes will be zero. As the sdRef
+ // (and its subordinates) have been freed, we should not proceed further. Note that when we
+ // call the callback with a subordinate sdRef the application can call DNSServiceRefDeallocate
+ // on the main sdRef and DNSServiceRefDeallocate handles this case by walking all the sdRefs and
+ // clears the moreptr so that we can terminate here.
+ //
+ // If DNSServiceRefDeallocate was not called in the callback, then set moreptr to NULL so that
+ // we don't access the stack variable after we return from this function.
+ if (!morebytes) {syslog(LOG_WARNING, "dnssdclientstub:sdRef: CallbackwithError morebytes zero sdr %p", sdr); return;}
+ else {sdr->moreptr = NULL;}
+ sdr = sdrNext;
+ }
+}
+#endif // _DNS_SD_LIBDISPATCH
+
+// Handle reply from server, calling application client callback. If there is no reply
+// from the daemon on the socket contained in sdRef, the call will block.
+DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
+{
+ int morebytes = 0;
+
+ if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
+
+ if (!DNSServiceRefValid(sdRef))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+ return kDNSServiceErr_BadReference;
+ }
+
+ if (sdRef->primary)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef);
+ return kDNSServiceErr_BadReference;
+ }
+
+ if (!sdRef->ProcessReply)
+ {
+ static int num_logs = 0;
+ if (num_logs < 10) syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function");
+ if (num_logs < 1000) num_logs++;else sleep(1);
+ return kDNSServiceErr_BadReference;
+ }
+
+ do
+ {
+ CallbackHeader cbh;
+ char *data;
+
+ // return NoError on EWOULDBLOCK. This will handle the case
+ // where a non-blocking socket is told there is data, but it was a false positive.
+ // On error, read_all will write a message to syslog for us, so don't need to duplicate that here
+ // Note: If we want to properly support using non-blocking sockets in the future
+ int result = read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr));
+ if (result == read_all_fail)
+ {
+ // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
+ // in the callback.
+ sdRef->ProcessReply = NULL;
+#if _DNS_SD_LIBDISPATCH
+ // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult
+ // is not called by the application and hence need to communicate the error. Cancel the
+ // source so that we don't get any more events
+ // Note: read_all fails if we could not read from the daemon which can happen if the
+ // daemon dies or the file descriptor is disconnected (defunct).
+ if (sdRef->disp_source)
+ {
+ dispatch_source_cancel(sdRef->disp_source);
+ dispatch_release(sdRef->disp_source);
+ sdRef->disp_source = NULL;
+ CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning);
+ }
+#endif
+ // Don't touch sdRef anymore as it might have been deallocated
+ return kDNSServiceErr_ServiceNotRunning;
+ }
+ else if (result == read_all_wouldblock)
+ {
+ if (morebytes && sdRef->logcounter < 100)
+ {
+ sdRef->logcounter++;
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult error: select indicated data was waiting but read_all returned EWOULDBLOCK");
+ }
+ return kDNSServiceErr_NoError;
+ }
+
+ ConvertHeaderBytes(&cbh.ipc_hdr);
+ if (cbh.ipc_hdr.version != VERSION)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult daemon version %d does not match client version %d", cbh.ipc_hdr.version, VERSION);
+ sdRef->ProcessReply = NULL;
+ return kDNSServiceErr_Incompatible;
+ }
+
+ data = malloc(cbh.ipc_hdr.datalen);
+ if (!data) return kDNSServiceErr_NoMemory;
+ if (read_all(sdRef->sockfd, data, cbh.ipc_hdr.datalen) < 0) // On error, read_all will write a message to syslog for us
+ {
+ // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
+ // in the callback.
+ sdRef->ProcessReply = NULL;
+#if _DNS_SD_LIBDISPATCH
+ // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult
+ // is not called by the application and hence need to communicate the error. Cancel the
+ // source so that we don't get any more events
+ if (sdRef->disp_source)
+ {
+ dispatch_source_cancel(sdRef->disp_source);
+ dispatch_release(sdRef->disp_source);
+ sdRef->disp_source = NULL;
+ CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning);
+ }
+#endif
+ // Don't touch sdRef anymore as it might have been deallocated
+ free(data);
+ return kDNSServiceErr_ServiceNotRunning;
+ }
+ else
+ {
+ const char *ptr = data;
+ cbh.cb_flags = get_flags (&ptr, data + cbh.ipc_hdr.datalen);
+ cbh.cb_interface = get_uint32 (&ptr, data + cbh.ipc_hdr.datalen);
+ cbh.cb_err = get_error_code(&ptr, data + cbh.ipc_hdr.datalen);
+
+ // CAUTION: We have to handle the case where the client calls DNSServiceRefDeallocate from within the callback function.
+ // To do this we set moreptr to point to morebytes. If the client does call DNSServiceRefDeallocate(),
+ // then that routine will clear morebytes for us, and cause us to exit our loop.
+ morebytes = more_bytes(sdRef->sockfd);
+ if (morebytes)
+ {
+ cbh.cb_flags |= kDNSServiceFlagsMoreComing;
+ sdRef->moreptr = &morebytes;
+ }
+ if (ptr) sdRef->ProcessReply(sdRef, &cbh, ptr, data + cbh.ipc_hdr.datalen);
+ // Careful code here:
+ // If morebytes is non-zero, that means we set sdRef->moreptr above, and the operation was not
+ // cancelled out from under us, so now we need to clear sdRef->moreptr so we don't leave a stray
+ // dangling pointer pointing to a long-gone stack variable.
+ // If morebytes is zero, then one of two thing happened:
+ // (a) morebytes was 0 above, so we didn't set sdRef->moreptr, so we don't need to clear it
+ // (b) morebytes was 1 above, and we set sdRef->moreptr, but the operation was cancelled (with DNSServiceRefDeallocate()),
+ // so we MUST NOT try to dereference our stale sdRef pointer.
+ if (morebytes) sdRef->moreptr = NULL;
+ }
+ free(data);
+ } while (morebytes);
+
+ return kDNSServiceErr_NoError;
+}
+
+void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef)
+{
+ if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with NULL DNSServiceRef"); return; }
+
+ if (!DNSServiceRefValid(sdRef)) // Also verifies dnssd_SocketValid(sdRef->sockfd) for us too
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+ return;
+ }
+
+ // If we're in the middle of a DNSServiceProcessResult() invocation for this DNSServiceRef, clear its morebytes flag to break it out of its while loop
+ if (sdRef->moreptr) *(sdRef->moreptr) = 0;
+
+ if (sdRef->primary) // If this is a subordinate DNSServiceOp, just send a 'stop' command
+ {
+ DNSServiceOp **p = &sdRef->primary->next;
+ while (*p && *p != sdRef) p = &(*p)->next;
+ if (*p)
+ {
+ char *ptr;
+ size_t len = 0;
+ ipc_msg_hdr *hdr = create_hdr(cancel_request, &len, &ptr, 0, sdRef);
+ if (hdr)
+ {
+ ConvertHeaderBytes(hdr);
+ write_all(sdRef->sockfd, (char *)hdr, len);
+ free(hdr);
+ }
+ *p = sdRef->next;
+ FreeDNSServiceOp(sdRef);
+ }
+ }
+ else // else, make sure to terminate all subordinates as well
+ {
+#if _DNS_SD_LIBDISPATCH
+ // The cancel handler will close the fd if a dispatch source has been set
+ if (sdRef->disp_source)
+ {
+ // By setting the ProcessReply to NULL, we make sure that we never call
+ // the application callbacks ever, after returning from this function. We
+ // assume that DNSServiceRefDeallocate is called from the serial queue
+ // that was passed to DNSServiceSetDispatchQueue. Hence, dispatch_source_cancel
+ // should cancel all the blocks on the queue and hence there should be no more
+ // callbacks when we return from this function. Setting ProcessReply to NULL
+ // provides extra protection.
+ sdRef->ProcessReply = NULL;
+ dispatch_source_cancel(sdRef->disp_source);
+ dispatch_release(sdRef->disp_source);
+ sdRef->disp_source = NULL;
+ }
+ // if disp_queue is set, it means it used the DNSServiceSetDispatchQueue API. In that case,
+ // when the source was cancelled, the fd was closed in the handler. Currently the source
+ // is cancelled only when the mDNSResponder daemon dies
+ else if (!sdRef->disp_queue) dnssd_close(sdRef->sockfd);
+#else
+ dnssd_close(sdRef->sockfd);
+#endif
+ // Free DNSRecords added in DNSRegisterRecord if they have not
+ // been freed in DNSRemoveRecord
+ while (sdRef)
+ {
+ DNSServiceOp *p = sdRef;
+ sdRef = sdRef->next;
+ // When there is an error reading from the daemon e.g., bad fd, CallbackWithError
+ // is called which sets moreptr. It might set the moreptr on a subordinate sdRef
+ // but the application might call DNSServiceRefDeallocate with the main sdRef from
+ // the callback. Hence, when we loop through the subordinate sdRefs, we need
+ // to clear the moreptr so that CallbackWithError can terminate itself instead of
+ // walking through the freed sdRefs.
+ if (p->moreptr) *(p->moreptr) = 0;
+ FreeDNSServiceOp(p);
+ }
+ }
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceGetProperty(const char *property, void *result, uint32_t *size)
+{
+ char *ptr;
+ size_t len = strlen(property) + 1;
+ ipc_msg_hdr *hdr;
+ DNSServiceOp *tmp;
+ uint32_t actualsize;
+
+ DNSServiceErrorType err = ConnectToServer(&tmp, 0, getproperty_request, NULL, NULL, NULL);
+ if (err) return err;
+
+ hdr = create_hdr(getproperty_request, &len, &ptr, 0, tmp);
+ if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
+
+ put_string(property, &ptr);
+ err = deliver_request(hdr, tmp); // Will free hdr for us
+ if (read_all(tmp->sockfd, (char*)&actualsize, (int)sizeof(actualsize)) < 0)
+ { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
+
+ actualsize = ntohl(actualsize);
+ if (read_all(tmp->sockfd, (char*)result, actualsize < *size ? actualsize : *size) < 0)
+ { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
+ DNSServiceRefDeallocate(tmp);
+
+ // Swap version result back to local process byte order
+ if (!strcmp(property, kDNSServiceProperty_DaemonVersion) && *size >= 4)
+ *(uint32_t*)result = ntohl(*(uint32_t*)result);
+
+ *size = actualsize;
+ return kDNSServiceErr_NoError;
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceGetPID(const uint16_t srcport, int32_t *pid)
+{
+ char *ptr;
+ ipc_msg_hdr *hdr;
+ DNSServiceOp *tmp;
+ size_t len = sizeof(int32_t);
+
+ DNSServiceErrorType err = ConnectToServer(&tmp, 0, getpid_request, NULL, NULL, NULL);
+ if (err)
+ return err;
+
+ hdr = create_hdr(getpid_request, &len, &ptr, 0, tmp);
+ if (!hdr)
+ {
+ DNSServiceRefDeallocate(tmp);
+ return kDNSServiceErr_NoMemory;
+ }
+
+ put_uint16(srcport, &ptr);
+ err = deliver_request(hdr, tmp); // Will free hdr for us
+
+ if (read_all(tmp->sockfd, (char*)pid, sizeof(int32_t)) < 0)
+ {
+ DNSServiceRefDeallocate(tmp);
+ return kDNSServiceErr_ServiceNotRunning;
+ }
+
+ DNSServiceRefDeallocate(tmp);
+ return kDNSServiceErr_NoError;
+}
+
+static void handle_resolve_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *end)
+{
+ char fullname[kDNSServiceMaxDomainName];
+ char target[kDNSServiceMaxDomainName];
+ uint16_t txtlen;
+ union { uint16_t s; u_char b[2]; } port;
+ unsigned char *txtrecord;
+
+ get_string(&data, end, fullname, kDNSServiceMaxDomainName);
+ get_string(&data, end, target, kDNSServiceMaxDomainName);
+ if (!data || data + 2 > end) goto fail;
+
+ port.b[0] = *data++;
+ port.b[1] = *data++;
+ txtlen = get_uint16(&data, end);
+ txtrecord = (unsigned char *)get_rdata(&data, end, txtlen);
+
+ if (!data) goto fail;
+ ((DNSServiceResolveReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, fullname, target, port.s, txtlen, txtrecord, sdr->AppContext);
+ return;
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+fail:
+ syslog(LOG_WARNING, "dnssd_clientstub handle_resolve_response: error reading result from daemon");
+}
+
+#if TARGET_OS_EMBEDDED
+
+static int32_t libSystemVersion = 0;
+
+// Return true if the iOS application linked against a version of libsystem where P2P
+// interfaces were included by default when using kDNSServiceInterfaceIndexAny.
+// Using 160.0.0 == 0xa00000 as the version threshold.
+static int includeP2PWithIndexAny()
+{
+ if (libSystemVersion == 0)
+ libSystemVersion = NSVersionOfLinkTimeLibrary("System");
+
+ if (libSystemVersion < 0xa00000)
+ return 1;
+ else
+ return 0;
+}
+
+#else // TARGET_OS_EMBEDDED
+
+// always return false for non iOS platforms
+static int includeP2PWithIndexAny()
+{
+ return 0;
+}
+
+#endif // TARGET_OS_EMBEDDED
+
+DNSServiceErrorType DNSSD_API DNSServiceResolve
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *name,
+ const char *regtype,
+ const char *domain,
+ DNSServiceResolveReply callBack,
+ void *context
+)
+{
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err;
+
+ if (!name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam;
+
+ // Need a real InterfaceID for WakeOnResolve
+ if ((flags & kDNSServiceFlagsWakeOnResolve) != 0 &&
+ ((interfaceIndex == kDNSServiceInterfaceIndexAny) ||
+ (interfaceIndex == kDNSServiceInterfaceIndexLocalOnly) ||
+ (interfaceIndex == kDNSServiceInterfaceIndexUnicast) ||
+ (interfaceIndex == kDNSServiceInterfaceIndexP2P)))
+ {
+ return kDNSServiceErr_BadParam;
+ }
+
+ if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
+ flags |= kDNSServiceFlagsIncludeP2P;
+
+ err = ConnectToServer(sdRef, flags, resolve_request, handle_resolve_response, callBack, context);
+ if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
+
+ // Calculate total message length
+ len = sizeof(flags);
+ len += sizeof(interfaceIndex);
+ len += strlen(name) + 1;
+ len += strlen(regtype) + 1;
+ len += strlen(domain) + 1;
+
+ hdr = create_hdr(resolve_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_string(name, &ptr);
+ put_string(regtype, &ptr);
+ put_string(domain, &ptr);
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+ return err;
+}
+
+static void handle_query_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
+{
+ uint32_t ttl;
+ char name[kDNSServiceMaxDomainName];
+ uint16_t rrtype, rrclass, rdlen;
+ const char *rdata;
+
+ get_string(&data, end, name, kDNSServiceMaxDomainName);
+ rrtype = get_uint16(&data, end);
+ rrclass = get_uint16(&data, end);
+ rdlen = get_uint16(&data, end);
+ rdata = get_rdata(&data, end, rdlen);
+ ttl = get_uint32(&data, end);
+
+ if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_query_response: error reading result from daemon");
+ else ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, name, rrtype, rrclass, rdlen, rdata, ttl, sdr->AppContext);
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *name,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ DNSServiceQueryRecordReply callBack,
+ void *context
+)
+{
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err;
+
+ if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
+ flags |= kDNSServiceFlagsIncludeP2P;
+
+ err = ConnectToServer(sdRef, flags, query_request, handle_query_response, callBack, context);
+ if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
+
+ if (!name) name = "\0";
+
+ // Calculate total message length
+ len = sizeof(flags);
+ len += sizeof(uint32_t); // interfaceIndex
+ len += strlen(name) + 1;
+ len += 2 * sizeof(uint16_t); // rrtype, rrclass
+
+ hdr = create_hdr(query_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_string(name, &ptr);
+ put_uint16(rrtype, &ptr);
+ put_uint16(rrclass, &ptr);
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+ return err;
+}
+
+static void handle_addrinfo_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
+{
+ char hostname[kDNSServiceMaxDomainName];
+ uint16_t rrtype, rrclass, rdlen;
+ const char *rdata;
+ uint32_t ttl;
+
+ get_string(&data, end, hostname, kDNSServiceMaxDomainName);
+ rrtype = get_uint16(&data, end);
+ rrclass = get_uint16(&data, end);
+ rdlen = get_uint16(&data, end);
+ rdata = get_rdata (&data, end, rdlen);
+ ttl = get_uint32(&data, end);
+
+ // We only generate client callbacks for A and AAAA results (including NXDOMAIN results for
+ // those types, if the client has requested those with the kDNSServiceFlagsReturnIntermediates).
+ // Other result types, specifically CNAME referrals, are not communicated to the client, because
+ // the DNSServiceGetAddrInfoReply interface doesn't have any meaningful way to communiate CNAME referrals.
+ if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_addrinfo_response: error reading result from daemon");
+ else if (rrtype == kDNSServiceType_A || rrtype == kDNSServiceType_AAAA)
+ {
+ struct sockaddr_in sa4;
+ struct sockaddr_in6 sa6;
+ const struct sockaddr *const sa = (rrtype == kDNSServiceType_A) ? (struct sockaddr*)&sa4 : (struct sockaddr*)&sa6;
+ if (rrtype == kDNSServiceType_A)
+ {
+ memset(&sa4, 0, sizeof(sa4));
+ #ifndef NOT_HAVE_SA_LEN
+ sa4.sin_len = sizeof(struct sockaddr_in);
+ #endif
+ sa4.sin_family = AF_INET;
+ // sin_port = 0;
+ if (!cbh->cb_err) memcpy(&sa4.sin_addr, rdata, rdlen);
+ }
+ else
+ {
+ memset(&sa6, 0, sizeof(sa6));
+ #ifndef NOT_HAVE_SA_LEN
+ sa6.sin6_len = sizeof(struct sockaddr_in6);
+ #endif
+ sa6.sin6_family = AF_INET6;
+ // sin6_port = 0;
+ // sin6_flowinfo = 0;
+ // sin6_scope_id = 0;
+ if (!cbh->cb_err)
+ {
+ memcpy(&sa6.sin6_addr, rdata, rdlen);
+ if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr)) sa6.sin6_scope_id = cbh->cb_interface;
+ }
+ }
+ // Validation results are always delivered separately from the actual results of the
+ // DNSServiceGetAddrInfo. Set the "addr" to NULL as per the documentation.
+ //
+ // Note: If we deliver validation results along with the "addr" in the future, we need
+ // a way to differentiate the negative response from validation-only response as both
+ // has zero address.
+ if (!(cbh->cb_flags & kDNSServiceFlagsValidate))
+ ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, sa, ttl, sdr->AppContext);
+ else
+ ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, NULL, 0, sdr->AppContext);
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+ }
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ uint32_t protocol,
+ const char *hostname,
+ DNSServiceGetAddrInfoReply callBack,
+ void *context /* may be NULL */
+)
+{
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err;
+
+ if (!hostname) return kDNSServiceErr_BadParam;
+
+ err = ConnectToServer(sdRef, flags, addrinfo_request, handle_addrinfo_response, callBack, context);
+ if (err)
+ {
+ return err; // On error ConnectToServer leaves *sdRef set to NULL
+ }
+
+ // Calculate total message length
+ len = sizeof(flags);
+ len += sizeof(uint32_t); // interfaceIndex
+ len += sizeof(uint32_t); // protocol
+ len += strlen(hostname) + 1;
+
+ hdr = create_hdr(addrinfo_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_uint32(protocol, &ptr);
+ put_string(hostname, &ptr);
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+ return err;
+}
+
+static void handle_browse_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
+{
+ char replyName[256], replyType[kDNSServiceMaxDomainName], replyDomain[kDNSServiceMaxDomainName];
+ get_string(&data, end, replyName, 256);
+ get_string(&data, end, replyType, kDNSServiceMaxDomainName);
+ get_string(&data, end, replyDomain, kDNSServiceMaxDomainName);
+ if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_browse_response: error reading result from daemon");
+ else ((DNSServiceBrowseReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, replyName, replyType, replyDomain, sdr->AppContext);
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceBrowse
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *regtype,
+ const char *domain,
+ DNSServiceBrowseReply callBack,
+ void *context
+)
+{
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err;
+
+ if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
+ flags |= kDNSServiceFlagsIncludeP2P;
+
+ err = ConnectToServer(sdRef, flags, browse_request, handle_browse_response, callBack, context);
+ if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
+
+ if (!domain) domain = "";
+ len = sizeof(flags);
+ len += sizeof(interfaceIndex);
+ len += strlen(regtype) + 1;
+ len += strlen(domain) + 1;
+
+ hdr = create_hdr(browse_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_string(regtype, &ptr);
+ put_string(domain, &ptr);
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+ return err;
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain);
+DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain)
+{
+ DNSServiceOp *tmp;
+ char *ptr;
+ size_t len = sizeof(flags) + strlen(domain) + 1;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err = ConnectToServer(&tmp, 0, setdomain_request, NULL, NULL, NULL);
+ if (err) return err;
+
+ hdr = create_hdr(setdomain_request, &len, &ptr, 0, tmp);
+ if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_string(domain, &ptr);
+ err = deliver_request(hdr, tmp); // Will free hdr for us
+ DNSServiceRefDeallocate(tmp);
+ return err;
+}
+
+static void handle_regservice_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
+{
+ char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName];
+ get_string(&data, end, name, 256);
+ get_string(&data, end, regtype, kDNSServiceMaxDomainName);
+ get_string(&data, end, domain, kDNSServiceMaxDomainName);
+ if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_regservice_response: error reading result from daemon");
+ else ((DNSServiceRegisterReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_err, name, regtype, domain, sdr->AppContext);
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceRegister
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *name,
+ const char *regtype,
+ const char *domain,
+ const char *host,
+ uint16_t PortInNetworkByteOrder,
+ uint16_t txtLen,
+ const void *txtRecord,
+ DNSServiceRegisterReply callBack,
+ void *context
+)
+{
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err;
+ union { uint16_t s; u_char b[2]; } port = { PortInNetworkByteOrder };
+
+ if (!name) name = "";
+ if (!regtype) return kDNSServiceErr_BadParam;
+ if (!domain) domain = "";
+ if (!host) host = "";
+ if (!txtRecord) txtRecord = (void*)"";
+
+ // No callback must have auto-rename
+ if (!callBack && (flags & kDNSServiceFlagsNoAutoRename)) return kDNSServiceErr_BadParam;
+
+ if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
+ flags |= kDNSServiceFlagsIncludeP2P;
+
+ err = ConnectToServer(sdRef, flags, reg_service_request, callBack ? handle_regservice_response : NULL, callBack, context);
+ if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
+
+ len = sizeof(DNSServiceFlags);
+ len += sizeof(uint32_t); // interfaceIndex
+ len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4;
+ len += 2 * sizeof(uint16_t); // port, txtLen
+ len += txtLen;
+
+ hdr = create_hdr(reg_service_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+ // If it is going over a shared connection, then don't set the IPC_FLAGS_NOREPLY
+ // as it affects all the operations over the shared connection. This is not
+ // a normal case and hence receiving the response back from the daemon and
+ // discarding it in ConnectionResponse is okay.
+
+ if (!(flags & kDNSServiceFlagsShareConnection) && !callBack) hdr->ipc_flags |= IPC_FLAGS_NOREPLY;
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_string(name, &ptr);
+ put_string(regtype, &ptr);
+ put_string(domain, &ptr);
+ put_string(host, &ptr);
+ *ptr++ = port.b[0];
+ *ptr++ = port.b[1];
+ put_uint16(txtLen, &ptr);
+ put_rdata(txtLen, txtRecord, &ptr);
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+ return err;
+}
+
+static void handle_enumeration_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
+{
+ char domain[kDNSServiceMaxDomainName];
+ get_string(&data, end, domain, kDNSServiceMaxDomainName);
+ if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_enumeration_response: error reading result from daemon");
+ else ((DNSServiceDomainEnumReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, domain, sdr->AppContext);
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceDomainEnumReply callBack,
+ void *context
+)
+{
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err;
+
+ int f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0;
+ int f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0;
+ if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
+
+ err = ConnectToServer(sdRef, flags, enumeration_request, handle_enumeration_response, callBack, context);
+ if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
+
+ len = sizeof(DNSServiceFlags);
+ len += sizeof(uint32_t);
+
+ hdr = create_hdr(enumeration_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+ return err;
+}
+
+static void ConnectionResponse(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *const data, const char *const end)
+{
+ (void)data; // Unused
+
+ //printf("ConnectionResponse got %d\n", cbh->ipc_hdr.op);
+ if (cbh->ipc_hdr.op != reg_record_reply_op)
+ {
+ // When using kDNSServiceFlagsShareConnection, need to search the list of associated DNSServiceOps
+ // to find the one this response is intended for, and then call through to its ProcessReply handler.
+ // We start with our first subordinate DNSServiceRef -- don't want to accidentally match the parent DNSServiceRef.
+ DNSServiceOp *op = sdr->next;
+ while (op && (op->uid.u32[0] != cbh->ipc_hdr.client_context.u32[0] || op->uid.u32[1] != cbh->ipc_hdr.client_context.u32[1]))
+ op = op->next;
+ // Note: We may sometimes not find a matching DNSServiceOp, in the case where the client has
+ // cancelled the subordinate DNSServiceOp, but there are still messages in the pipeline from the daemon
+ if (op && op->ProcessReply) op->ProcessReply(op, cbh, data, end);
+ // WARNING: Don't touch op or sdr after this -- client may have called DNSServiceRefDeallocate
+ return;
+ }
+ else
+ {
+ DNSRecordRef rec;
+ for (rec = sdr->rec; rec; rec = rec->recnext)
+ {
+ if (rec->uid.u32[0] == cbh->ipc_hdr.client_context.u32[0] && rec->uid.u32[1] == cbh->ipc_hdr.client_context.u32[1])
+ break;
+ }
+ // The record might have been freed already and hence not an
+ // error if the record is not found.
+ if (!rec)
+ {
+ syslog(LOG_INFO, "ConnectionResponse: Record not found");
+ return;
+ }
+ if (rec->sdr != sdr)
+ {
+ syslog(LOG_WARNING, "ConnectionResponse: Record sdr mismatch: rec %p sdr %p", rec->sdr, sdr);
+ return;
+ }
+
+ if (sdr->op == connection_request || sdr->op == connection_delegate_request)
+ {
+ rec->AppCallback(rec->sdr, rec, cbh->cb_flags, cbh->cb_err, rec->AppContext);
+ }
+ else
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectionResponse: sdr->op != connection_request");
+ rec->AppCallback(rec->sdr, rec, 0, kDNSServiceErr_Unknown, rec->AppContext);
+ }
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+ }
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef)
+{
+ char *ptr;
+ size_t len = 0;
+ ipc_msg_hdr *hdr;
+ DNSServiceErrorType err = ConnectToServer(sdRef, 0, connection_request, ConnectionResponse, NULL, NULL);
+ if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
+
+ hdr = create_hdr(connection_request, &len, &ptr, 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+ return err;
+}
+
+#if APPLE_OSX_mDNSResponder && !TARGET_IPHONE_SIMULATOR
+DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid)
+{
+ char *ptr;
+ size_t len = 0;
+ ipc_msg_hdr *hdr;
+
+ DNSServiceErrorType err = ConnectToServer(sdRef, 0, connection_delegate_request, ConnectionResponse, NULL, NULL);
+ if (err)
+ {
+ return err; // On error ConnectToServer leaves *sdRef set to NULL
+ }
+
+ // Only one of the two options can be set. If pid is zero, uuid is used.
+ // If both are specified only pid will be used. We send across the pid
+ // so that the daemon knows what to read from the socket.
+
+ len += sizeof(int32_t);
+
+ hdr = create_hdr(connection_delegate_request, &len, &ptr, 0, *sdRef);
+ if (!hdr)
+ {
+ DNSServiceRefDeallocate(*sdRef);
+ *sdRef = NULL;
+ return kDNSServiceErr_NoMemory;
+ }
+
+ if (pid && setsockopt((*sdRef)->sockfd, SOL_SOCKET, SO_DELEGATED, &pid, sizeof(pid)) == -1)
+ {
+ syslog(LOG_WARNING, "dnssdclientstub: Could not setsockopt() for PID[%d], no entitlements or process(pid) invalid errno:%d (%s)", pid, errno, strerror(errno));
+ // Free the hdr in case we return before calling deliver_request()
+ if (hdr)
+ free(hdr);
+ DNSServiceRefDeallocate(*sdRef);
+ *sdRef = NULL;
+ return kDNSServiceErr_NoAuth;
+ }
+
+ if (!pid && setsockopt((*sdRef)->sockfd, SOL_SOCKET, SO_DELEGATED_UUID, uuid, sizeof(uuid_t)) == -1)
+ {
+ syslog(LOG_WARNING, "dnssdclientstub: Could not setsockopt() for UUID, no entitlements or process(uuid) invalid errno:%d (%s) ", errno, strerror(errno));
+ // Free the hdr in case we return before calling deliver_request()
+ if (hdr)
+ free(hdr);
+ DNSServiceRefDeallocate(*sdRef);
+ *sdRef = NULL;
+ return kDNSServiceErr_NoAuth;
+ }
+
+ put_uint32(pid, &ptr);
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err)
+ {
+ DNSServiceRefDeallocate(*sdRef);
+ *sdRef = NULL;
+ }
+ return err;
+}
+#elif TARGET_IPHONE_SIMULATOR // This hack is for Simulator platform only
+DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid)
+{
+ (void) pid;
+ (void) uuid;
+ return DNSServiceCreateConnection(sdRef);
+}
+#endif
+
+DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
+(
+ DNSServiceRef sdRef,
+ DNSRecordRef *RecordRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *fullname,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ uint16_t rdlen,
+ const void *rdata,
+ uint32_t ttl,
+ DNSServiceRegisterRecordReply callBack,
+ void *context
+)
+{
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr = NULL;
+ DNSRecordRef rref = NULL;
+ DNSRecord **p;
+ int f1 = (flags & kDNSServiceFlagsShared) != 0;
+ int f2 = (flags & kDNSServiceFlagsUnique) != 0;
+ if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
+
+ if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
+ flags |= kDNSServiceFlagsIncludeP2P;
+
+ if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
+
+ if (!DNSServiceRefValid(sdRef))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+ return kDNSServiceErr_BadReference;
+ }
+
+ if (sdRef->op != connection_request && sdRef->op != connection_delegate_request)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with non-DNSServiceCreateConnection DNSServiceRef %p %d", sdRef, sdRef->op);
+ return kDNSServiceErr_BadReference;
+ }
+
+ *RecordRef = NULL;
+
+ len = sizeof(DNSServiceFlags);
+ len += 2 * sizeof(uint32_t); // interfaceIndex, ttl
+ len += 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen
+ len += strlen(fullname) + 1;
+ len += rdlen;
+
+ // Bump up the uid. Normally for shared operations (kDNSServiceFlagsShareConnection), this
+ // is done in ConnectToServer. For DNSServiceRegisterRecord, ConnectToServer has already
+ // been called. As multiple DNSServiceRegisterRecords can be multiplexed over a single
+ // connection, we need a way to demultiplex the response so that the callback corresponding
+ // to the right DNSServiceRegisterRecord instance can be called. Use the same mechanism that
+ // is used by kDNSServiceFlagsShareConnection. create_hdr copies the uid value to ipc
+ // hdr->client_context which will be returned in the ipc response.
+ if (++sdRef->uid.u32[0] == 0)
+ ++sdRef->uid.u32[1];
+ hdr = create_hdr(reg_record_request, &len, &ptr, 1, sdRef);
+ if (!hdr) return kDNSServiceErr_NoMemory;
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_string(fullname, &ptr);
+ put_uint16(rrtype, &ptr);
+ put_uint16(rrclass, &ptr);
+ put_uint16(rdlen, &ptr);
+ put_rdata(rdlen, rdata, &ptr);
+ put_uint32(ttl, &ptr);
+
+ rref = malloc(sizeof(DNSRecord));
+ if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; }
+ rref->AppContext = context;
+ rref->AppCallback = callBack;
+ rref->record_index = sdRef->max_index++;
+ rref->sdr = sdRef;
+ rref->recnext = NULL;
+ *RecordRef = rref;
+ // Remember the uid that we are sending across so that we can match
+ // when the response comes back.
+ rref->uid = sdRef->uid;
+ hdr->reg_index = rref->record_index;
+
+ p = &(sdRef)->rec;
+ while (*p) p = &(*p)->recnext;
+ *p = rref;
+
+ return deliver_request(hdr, sdRef); // Will free hdr for us
+}
+
+// sdRef returned by DNSServiceRegister()
+DNSServiceErrorType DNSSD_API DNSServiceAddRecord
+(
+ DNSServiceRef sdRef,
+ DNSRecordRef *RecordRef,
+ DNSServiceFlags flags,
+ uint16_t rrtype,
+ uint16_t rdlen,
+ const void *rdata,
+ uint32_t ttl
+)
+{
+ ipc_msg_hdr *hdr;
+ size_t len = 0;
+ char *ptr;
+ DNSRecordRef rref;
+ DNSRecord **p;
+
+ if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
+ if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSRecordRef pointer"); return kDNSServiceErr_BadParam; }
+ if (sdRef->op != reg_service_request)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with non-DNSServiceRegister DNSServiceRef %p %d", sdRef, sdRef->op);
+ return kDNSServiceErr_BadReference;
+ }
+
+ if (!DNSServiceRefValid(sdRef))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+ return kDNSServiceErr_BadReference;
+ }
+
+ *RecordRef = NULL;
+
+ len += 2 * sizeof(uint16_t); // rrtype, rdlen
+ len += rdlen;
+ len += sizeof(uint32_t);
+ len += sizeof(DNSServiceFlags);
+
+ hdr = create_hdr(add_record_request, &len, &ptr, 1, sdRef);
+ if (!hdr) return kDNSServiceErr_NoMemory;
+ put_flags(flags, &ptr);
+ put_uint16(rrtype, &ptr);
+ put_uint16(rdlen, &ptr);
+ put_rdata(rdlen, rdata, &ptr);
+ put_uint32(ttl, &ptr);
+
+ rref = malloc(sizeof(DNSRecord));
+ if (!rref) { free(hdr); return kDNSServiceErr_NoMemory; }
+ rref->AppContext = NULL;
+ rref->AppCallback = NULL;
+ rref->record_index = sdRef->max_index++;
+ rref->sdr = sdRef;
+ rref->recnext = NULL;
+ *RecordRef = rref;
+ hdr->reg_index = rref->record_index;
+
+ p = &(sdRef)->rec;
+ while (*p) p = &(*p)->recnext;
+ *p = rref;
+
+ return deliver_request(hdr, sdRef); // Will free hdr for us
+}
+
+// DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
+DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
+(
+ DNSServiceRef sdRef,
+ DNSRecordRef RecordRef,
+ DNSServiceFlags flags,
+ uint16_t rdlen,
+ const void *rdata,
+ uint32_t ttl
+)
+{
+ ipc_msg_hdr *hdr;
+ size_t len = 0;
+ char *ptr;
+
+ if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
+
+ if (!DNSServiceRefValid(sdRef))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+ return kDNSServiceErr_BadReference;
+ }
+
+ // Note: RecordRef is allowed to be NULL
+
+ len += sizeof(uint16_t);
+ len += rdlen;
+ len += sizeof(uint32_t);
+ len += sizeof(DNSServiceFlags);
+
+ hdr = create_hdr(update_record_request, &len, &ptr, 1, sdRef);
+ if (!hdr) return kDNSServiceErr_NoMemory;
+ hdr->reg_index = RecordRef ? RecordRef->record_index : TXT_RECORD_INDEX;
+ put_flags(flags, &ptr);
+ put_uint16(rdlen, &ptr);
+ put_rdata(rdlen, rdata, &ptr);
+ put_uint32(ttl, &ptr);
+ return deliver_request(hdr, sdRef); // Will free hdr for us
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
+(
+ DNSServiceRef sdRef,
+ DNSRecordRef RecordRef,
+ DNSServiceFlags flags
+)
+{
+ ipc_msg_hdr *hdr;
+ size_t len = 0;
+ char *ptr;
+ DNSServiceErrorType err;
+
+ if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
+ if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSRecordRef"); return kDNSServiceErr_BadParam; }
+ if (!sdRef->max_index) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with bad DNSServiceRef"); return kDNSServiceErr_BadReference; }
+
+ if (!DNSServiceRefValid(sdRef))
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
+ return kDNSServiceErr_BadReference;
+ }
+
+ len += sizeof(flags);
+ hdr = create_hdr(remove_record_request, &len, &ptr, 1, sdRef);
+ if (!hdr) return kDNSServiceErr_NoMemory;
+ hdr->reg_index = RecordRef->record_index;
+ put_flags(flags, &ptr);
+ err = deliver_request(hdr, sdRef); // Will free hdr for us
+ if (!err)
+ {
+ // This RecordRef could have been allocated in DNSServiceRegisterRecord or DNSServiceAddRecord.
+ // If so, delink from the list before freeing
+ DNSRecord **p = &sdRef->rec;
+ while (*p && *p != RecordRef) p = &(*p)->recnext;
+ if (*p) *p = RecordRef->recnext;
+ free(RecordRef);
+ }
+ return err;
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
+(
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *fullname,
+ uint16_t rrtype,
+ uint16_t rrclass,
+ uint16_t rdlen,
+ const void *rdata
+)
+{
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ DNSServiceOp *tmp;
+
+ DNSServiceErrorType err = ConnectToServer(&tmp, flags, reconfirm_record_request, NULL, NULL, NULL);
+ if (err) return err;
+
+ len = sizeof(DNSServiceFlags);
+ len += sizeof(uint32_t);
+ len += strlen(fullname) + 1;
+ len += 3 * sizeof(uint16_t);
+ len += rdlen;
+ hdr = create_hdr(reconfirm_record_request, &len, &ptr, 0, tmp);
+ if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_string(fullname, &ptr);
+ put_uint16(rrtype, &ptr);
+ put_uint16(rrclass, &ptr);
+ put_uint16(rdlen, &ptr);
+ put_rdata(rdlen, rdata, &ptr);
+
+ err = deliver_request(hdr, tmp); // Will free hdr for us
+ DNSServiceRefDeallocate(tmp);
+ return err;
+}
+
+
+static void handle_port_mapping_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
+{
+ union { uint32_t l; u_char b[4]; } addr;
+ uint8_t protocol;
+ union { uint16_t s; u_char b[2]; } internalPort;
+ union { uint16_t s; u_char b[2]; } externalPort;
+ uint32_t ttl;
+
+ if (!data || data + 13 > end) goto fail;
+
+ addr.b[0] = *data++;
+ addr.b[1] = *data++;
+ addr.b[2] = *data++;
+ addr.b[3] = *data++;
+ protocol = *data++;
+ internalPort.b[0] = *data++;
+ internalPort.b[1] = *data++;
+ externalPort.b[0] = *data++;
+ externalPort.b[1] = *data++;
+ ttl = get_uint32(&data, end);
+ if (!data) goto fail;
+
+ ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, addr.l, protocol, internalPort.s, externalPort.s, ttl, sdr->AppContext);
+ return;
+ // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+
+ fail :
+ syslog(LOG_WARNING, "dnssd_clientstub handle_port_mapping_response: error reading result from daemon");
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ uint32_t protocol, /* TCP and/or UDP */
+ uint16_t internalPortInNetworkByteOrder,
+ uint16_t externalPortInNetworkByteOrder,
+ uint32_t ttl, /* time to live in seconds */
+ DNSServiceNATPortMappingReply callBack,
+ void *context /* may be NULL */
+)
+{
+ char *ptr;
+ size_t len;
+ ipc_msg_hdr *hdr;
+ union { uint16_t s; u_char b[2]; } internalPort = { internalPortInNetworkByteOrder };
+ union { uint16_t s; u_char b[2]; } externalPort = { externalPortInNetworkByteOrder };
+
+ DNSServiceErrorType err = ConnectToServer(sdRef, flags, port_mapping_request, handle_port_mapping_response, callBack, context);
+ if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
+
+ len = sizeof(flags);
+ len += sizeof(interfaceIndex);
+ len += sizeof(protocol);
+ len += sizeof(internalPort);
+ len += sizeof(externalPort);
+ len += sizeof(ttl);
+
+ hdr = create_hdr(port_mapping_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
+ if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
+
+ put_flags(flags, &ptr);
+ put_uint32(interfaceIndex, &ptr);
+ put_uint32(protocol, &ptr);
+ *ptr++ = internalPort.b[0];
+ *ptr++ = internalPort.b[1];
+ *ptr++ = externalPort.b[0];
+ *ptr++ = externalPort.b[1];
+ put_uint32(ttl, &ptr);
+
+ err = deliver_request(hdr, *sdRef); // Will free hdr for us
+ if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
+ return err;
+}
+
+#if _DNS_SD_LIBDISPATCH
+DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue
+(
+ DNSServiceRef service,
+ dispatch_queue_t queue
+)
+{
+ int dnssd_fd = DNSServiceRefSockFD(service);
+ if (dnssd_fd == dnssd_InvalidSocket) return kDNSServiceErr_BadParam;
+ if (!queue)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub: DNSServiceSetDispatchQueue dispatch queue NULL");
+ return kDNSServiceErr_BadParam;
+ }
+ if (service->disp_queue)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch queue set already");
+ return kDNSServiceErr_BadParam;
+ }
+ if (service->disp_source)
+ {
+ syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch source set already");
+ return kDNSServiceErr_BadParam;
+ }
+ service->disp_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, dnssd_fd, 0, queue);
+ if (!service->disp_source)
+ {
+ syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch_source_create failed");
+ return kDNSServiceErr_NoMemory;
+ }
+ service->disp_queue = queue;
+ dispatch_source_set_event_handler(service->disp_source, ^{DNSServiceProcessResult(service);});
+ dispatch_source_set_cancel_handler(service->disp_source, ^{dnssd_close(dnssd_fd);});
+ dispatch_resume(service->disp_source);
+ return kDNSServiceErr_NoError;
+}
+#endif // _DNS_SD_LIBDISPATCH
+
+#if !defined(_WIN32)
+
+static void DNSSD_API SleepKeepaliveCallback(DNSServiceRef sdRef, DNSRecordRef rec, const DNSServiceFlags flags,
+ DNSServiceErrorType errorCode, void *context)
+{
+ SleepKAContext *ka = (SleepKAContext *)context;
+ (void)rec; // Unused
+ (void)flags; // Unused
+
+ if (sdRef->kacontext != context)
+ syslog(LOG_WARNING, "SleepKeepaliveCallback context mismatch");
+
+ if (ka->AppCallback)
+ ((DNSServiceSleepKeepaliveReply)ka->AppCallback)(sdRef, errorCode, ka->AppContext);
+}
+
+DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
+(
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ int fd,
+ unsigned int timeout,
+ DNSServiceSleepKeepaliveReply callBack,
+ void *context
+)
+{
+ char source_str[INET6_ADDRSTRLEN];
+ char target_str[INET6_ADDRSTRLEN];
+ struct sockaddr_storage lss;
+ struct sockaddr_storage rss;
+ socklen_t len1, len2;
+ unsigned int len, proxyreclen;
+ char buf[256];
+ DNSServiceErrorType err;
+ DNSRecordRef record = NULL;
+ char name[10];
+ char recname[128];
+ SleepKAContext *ka;
+ unsigned int i, unique;
+
+
+ (void) flags; //unused
+ if (!timeout) return kDNSServiceErr_BadParam;
+
+
+ len1 = sizeof(lss);
+ if (getsockname(fd, (struct sockaddr *)&lss, &len1) < 0)
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive: getsockname %d\n", errno);
+ return kDNSServiceErr_BadParam;
+ }
+
+ len2 = sizeof(rss);
+ if (getpeername(fd, (struct sockaddr *)&rss, &len2) < 0)
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive: getpeername %d\n", errno);
+ return kDNSServiceErr_BadParam;
+ }
+
+ if (len1 != len2)
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive local/remote info not same");
+ return kDNSServiceErr_Unknown;
+ }
+
+ unique = 0;
+ if (lss.ss_family == AF_INET)
+ {
+ struct sockaddr_in *sl = (struct sockaddr_in *)&lss;
+ struct sockaddr_in *sr = (struct sockaddr_in *)&rss;
+ unsigned char *ptr = (unsigned char *)&sl->sin_addr;
+
+ if (!inet_ntop(AF_INET, (const void *)&sr->sin_addr, target_str, sizeof (target_str)))
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive remote info failed %d", errno);
+ return kDNSServiceErr_Unknown;
+ }
+ if (!inet_ntop(AF_INET, (const void *)&sl->sin_addr, source_str, sizeof (source_str)))
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive local info failed %d", errno);
+ return kDNSServiceErr_Unknown;
+ }
+ // Sum of all bytes in the local address and port should result in a unique
+ // number in the local network
+ for (i = 0; i < sizeof(struct in_addr); i++)
+ unique += ptr[i];
+ unique += sl->sin_port;
+ len = snprintf(buf+1, sizeof(buf) - 1, "t=%u h=%s d=%s l=%u r=%u", timeout, source_str, target_str, ntohs(sl->sin_port), ntohs(sr->sin_port));
+ }
+ else
+ {
+ struct sockaddr_in6 *sl6 = (struct sockaddr_in6 *)&lss;
+ struct sockaddr_in6 *sr6 = (struct sockaddr_in6 *)&rss;
+ unsigned char *ptr = (unsigned char *)&sl6->sin6_addr;
+
+ if (!inet_ntop(AF_INET6, (const void *)&sr6->sin6_addr, target_str, sizeof (target_str)))
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive remote6 info failed %d", errno);
+ return kDNSServiceErr_Unknown;
+ }
+ if (!inet_ntop(AF_INET6, (const void *)&sl6->sin6_addr, source_str, sizeof (source_str)))
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive local6 info failed %d", errno);
+ return kDNSServiceErr_Unknown;
+ }
+ for (i = 0; i < sizeof(struct in6_addr); i++)
+ unique += ptr[i];
+ unique += sl6->sin6_port;
+ len = snprintf(buf+1, sizeof(buf) - 1, "t=%u H=%s D=%s l=%u r=%u", timeout, source_str, target_str, ntohs(sl6->sin6_port), ntohs(sr6->sin6_port));
+ }
+
+ if (len >= (sizeof(buf) - 1))
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit local/remote info");
+ return kDNSServiceErr_Unknown;
+ }
+ // Include the NULL byte also in the first byte. The total length of the record includes the
+ // first byte also.
+ buf[0] = len + 1;
+ proxyreclen = len + 2;
+
+ len = snprintf(name, sizeof(name), "%u", unique);
+ if (len >= sizeof(name))
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit unique");
+ return kDNSServiceErr_Unknown;
+ }
+
+ len = snprintf(recname, sizeof(recname), "%s.%s", name, "_keepalive._dns-sd._udp.local");
+ if (len >= sizeof(recname))
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit name");
+ return kDNSServiceErr_Unknown;
+ }
+
+ ka = malloc(sizeof(SleepKAContext));
+ if (!ka) return kDNSServiceErr_NoMemory;
+ ka->AppCallback = callBack;
+ ka->AppContext = context;
+
+ err = DNSServiceCreateConnection(sdRef);
+ if (err)
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive cannot create connection");
+ free(ka);
+ return err;
+ }
+
+ // we don't care about the "record". When sdRef gets deallocated later, it will be freed too
+ err = DNSServiceRegisterRecord(*sdRef, &record, kDNSServiceFlagsUnique, 0, recname,
+ kDNSServiceType_NULL, kDNSServiceClass_IN, proxyreclen, buf, kDNSServiceInterfaceIndexAny, SleepKeepaliveCallback, ka);
+ if (err)
+ {
+ syslog(LOG_WARNING, "DNSServiceSleepKeepalive cannot create connection");
+ free(ka);
+ return err;
+ }
+ (*sdRef)->kacontext = ka;
+ return kDNSServiceErr_NoError;
+}
+#endif
Deleted: vendor/apple/mDNSResponder/561.1.1/mDNSShared/dnssd_ipc.h
===================================================================
--- vendor/apple/mDNSResponder/dist/mDNSShared/dnssd_ipc.h 2014-06-30 23:58:12 UTC (rev 6706)
+++ vendor/apple/mDNSResponder/561.1.1/mDNSShared/dnssd_ipc.h 2015-03-20 01:14:52 UTC (rev 6985)
@@ -1,221 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2004, Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef DNSSD_IPC_H
-#define DNSSD_IPC_H
-
-#include "dns_sd.h"
-
-//
-// Common cross platform services
-//
-#if defined(WIN32)
-# include <winsock2.h>
-# define dnssd_InvalidSocket INVALID_SOCKET
-# define dnssd_SocketValid(s) ((s) != INVALID_SOCKET)
-# define dnssd_EWOULDBLOCK WSAEWOULDBLOCK
-# define dnssd_EINTR WSAEINTR
-# define dnssd_ECONNRESET WSAECONNRESET
-# define dnssd_sock_t SOCKET
-# define dnssd_socklen_t int
-# define dnssd_close(sock) closesocket(sock)
-# define dnssd_errno WSAGetLastError()
-# define dnssd_strerror(X) win32_strerror(X)
-# define ssize_t int
-# define getpid _getpid
-# define unlink _unlink
-extern char *win32_strerror(int inErrorCode);
-#else
-# include <sys/types.h>
-# include <unistd.h>
-# include <sys/un.h>
-# include <string.h>
-# include <stdio.h>
-# include <stdlib.h>
-# include <sys/stat.h>
-# include <sys/socket.h>
-# include <netinet/in.h>
-# include <arpa/inet.h>
-# define dnssd_InvalidSocket -1
-# define dnssd_SocketValid(s) ((s) >= 0)
-# define dnssd_EWOULDBLOCK EWOULDBLOCK
-# define dnssd_EINTR EINTR
-# define dnssd_ECONNRESET ECONNRESET
-# define dnssd_EPIPE EPIPE
-# define dnssd_sock_t int
-# define dnssd_socklen_t unsigned int
-# define dnssd_close(sock) close(sock)
-# define dnssd_errno errno
-# define dnssd_strerror(X) strerror(X)
-#endif
-
-#if defined(USE_TCP_LOOPBACK)
-# define AF_DNSSD AF_INET
-# define MDNS_TCP_SERVERADDR "127.0.0.1"
-# define MDNS_TCP_SERVERPORT 5354
-# define LISTENQ 5
-# define dnssd_sockaddr_t struct sockaddr_in
-#else
-# define AF_DNSSD AF_LOCAL
-# ifndef MDNS_UDS_SERVERPATH
-# define MDNS_UDS_SERVERPATH "/var/run/mDNSResponder"
-# endif
-# define LISTENQ 100
-// longest legal control path length
-# define MAX_CTLPATH 256
-# define dnssd_sockaddr_t struct sockaddr_un
-#endif
-
-// Compatibility workaround
-#ifndef AF_LOCAL
-#define AF_LOCAL AF_UNIX
-#endif
-
-// General UDS constants
-#define TXT_RECORD_INDEX ((uint32_t)(-1)) // record index for default text record
-
-// IPC data encoding constants and types
-#define VERSION 1
-#define IPC_FLAGS_NOREPLY 1 // set flag if no asynchronous replies are to be sent to client
-
-// Structure packing macro. If we're not using GNUC, it's not fatal. Most compilers naturally pack the on-the-wire
-// structures correctly anyway, so a plain "struct" is usually fine. In the event that structures are not packed
-// correctly, our compile-time assertion checks will catch it and prevent inadvertent generation of non-working code.
-#ifndef packedstruct
- #if ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 9)))
- #define packedstruct struct __attribute__((__packed__))
- #define packedunion union __attribute__((__packed__))
- #else
- #define packedstruct struct
- #define packedunion union
- #endif
-#endif
-
-typedef enum
-{
- request_op_none = 0, // No request yet received on this connection
- connection_request = 1, // connected socket via DNSServiceConnect()
- reg_record_request, // reg/remove record only valid for connected sockets
- remove_record_request,
- enumeration_request,
- reg_service_request,
- browse_request,
- resolve_request,
- query_request,
- reconfirm_record_request,
- add_record_request,
- update_record_request,
- setdomain_request, // Up to here is in Tiger and B4W 1.0.3
- getproperty_request, // New in B4W 1.0.4
- port_mapping_request, // New in Leopard and B4W 2.0
- addrinfo_request,
- send_bpf, // New in SL
- getpid_request,
- release_request,
- connection_delegate_request,
-
- cancel_request = 63
-} request_op_t;
-
-typedef enum
-{
- enumeration_reply_op = 64,
- reg_service_reply_op,
- browse_reply_op,
- resolve_reply_op,
- query_reply_op,
- reg_record_reply_op, // Up to here is in Tiger and B4W 1.0.3
- getproperty_reply_op, // New in B4W 1.0.4
- port_mapping_reply_op, // New in Leopard and B4W 2.0
- addrinfo_reply_op
-} reply_op_t;
-
-#if defined(_WIN64)
-# pragma pack(push,4)
-#endif
-
-// Define context object big enough to hold a 64-bit pointer,
-// to accomodate 64-bit clients communicating with 32-bit daemon.
-// There's no reason for the daemon to ever be a 64-bit process, but its clients might be
-typedef packedunion
-{
- void *context;
- uint32_t u32[2];
-} client_context_t;
-
-typedef packedstruct
-{
- uint32_t version;
- uint32_t datalen;
- uint32_t ipc_flags;
- uint32_t op; // request_op_t or reply_op_t
- client_context_t client_context; // context passed from client, returned by server in corresponding reply
- uint32_t reg_index; // identifier for a record registered via DNSServiceRegisterRecord() on a
- // socket connected by DNSServiceCreateConnection(). Must be unique in the scope of the connection, such that and
- // index/socket pair uniquely identifies a record. (Used to select records for removal by DNSServiceRemoveRecord())
-} ipc_msg_hdr;
-
-#if defined(_WIN64)
-# pragma pack(pop)
-#endif
-
-// routines to write to and extract data from message buffers.
-// caller responsible for bounds checking.
-// ptr is the address of the pointer to the start of the field.
-// it is advanced to point to the next field, or the end of the message
-
-void put_uint32(const uint32_t l, char **ptr);
-uint32_t get_uint32(const char **ptr, const char *end);
-
-void put_uint16(uint16_t s, char **ptr);
-uint16_t get_uint16(const char **ptr, const char *end);
-
-#define put_flags put_uint32
-#define get_flags get_uint32
-
-#define put_error_code put_uint32
-#define get_error_code get_uint32
-
-int put_string(const char *str, char **ptr);
-int get_string(const char **ptr, const char *const end, char *buffer, int buflen);
-
-void put_rdata(const int rdlen, const unsigned char *rdata, char **ptr);
-const char *get_rdata(const char **ptr, const char *end, int rdlen); // return value is rdata pointed to by *ptr -
-// rdata is not copied from buffer.
-
-void ConvertHeaderBytes(ipc_msg_hdr *hdr);
-
-struct CompileTimeAssertionChecks_dnssd_ipc
-{
- // Check that the compiler generated our on-the-wire packet format structure definitions
- // properly packed, without adding padding bytes to align fields on 32-bit or 64-bit boundaries.
- char assert0[(sizeof(client_context_t) == 8) ? 1 : -1];
- char assert1[(sizeof(ipc_msg_hdr) == 28) ? 1 : -1];
-};
-
-#endif // DNSSD_IPC_H
Copied: vendor/apple/mDNSResponder/561.1.1/mDNSShared/dnssd_ipc.h (from rev 6984, vendor/apple/mDNSResponder/dist/mDNSShared/dnssd_ipc.h)
===================================================================
--- vendor/apple/mDNSResponder/561.1.1/mDNSShared/dnssd_ipc.h (rev 0)
+++ vendor/apple/mDNSResponder/561.1.1/mDNSShared/dnssd_ipc.h 2015-03-20 01:14:52 UTC (rev 6985)
@@ -0,0 +1,222 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2003-2004, Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DNSSD_IPC_H
+#define DNSSD_IPC_H
+
+#include "dns_sd.h"
+
+//
+// Common cross platform services
+//
+#if defined(WIN32)
+# include <winsock2.h>
+# define dnssd_InvalidSocket INVALID_SOCKET
+# define dnssd_SocketValid(s) ((s) != INVALID_SOCKET)
+# define dnssd_EWOULDBLOCK WSAEWOULDBLOCK
+# define dnssd_EINTR WSAEINTR
+# define dnssd_ECONNRESET WSAECONNRESET
+# define dnssd_sock_t SOCKET
+# define dnssd_socklen_t int
+# define dnssd_close(sock) closesocket(sock)
+# define dnssd_errno WSAGetLastError()
+# define dnssd_strerror(X) win32_strerror(X)
+# define ssize_t int
+# define getpid _getpid
+# define unlink _unlink
+extern char *win32_strerror(int inErrorCode);
+#else
+# include <sys/types.h>
+# include <unistd.h>
+# include <sys/un.h>
+# include <string.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <sys/stat.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# define dnssd_InvalidSocket -1
+# define dnssd_SocketValid(s) ((s) >= 0)
+# define dnssd_EWOULDBLOCK EWOULDBLOCK
+# define dnssd_EINTR EINTR
+# define dnssd_ECONNRESET ECONNRESET
+# define dnssd_EPIPE EPIPE
+# define dnssd_sock_t int
+# define dnssd_socklen_t unsigned int
+# define dnssd_close(sock) close(sock)
+# define dnssd_errno errno
+# define dnssd_strerror(X) strerror(X)
+#endif
+
+#if defined(USE_TCP_LOOPBACK)
+# define AF_DNSSD AF_INET
+# define MDNS_TCP_SERVERADDR "127.0.0.1"
+# define MDNS_TCP_SERVERPORT 5354
+# define LISTENQ 5
+# define dnssd_sockaddr_t struct sockaddr_in
+#else
+# define AF_DNSSD AF_LOCAL
+# ifndef MDNS_UDS_SERVERPATH
+# define MDNS_UDS_SERVERPATH "/var/run/mDNSResponder"
+# endif
+# define MDNS_UDS_SERVERPATH_ENVVAR "DNSSD_UDS_PATH"
+# define LISTENQ 100
+// longest legal control path length
+# define MAX_CTLPATH 256
+# define dnssd_sockaddr_t struct sockaddr_un
+#endif
+
+// Compatibility workaround
+#ifndef AF_LOCAL
+#define AF_LOCAL AF_UNIX
+#endif
+
+// General UDS constants
+#define TXT_RECORD_INDEX ((uint32_t)(-1)) // record index for default text record
+
+// IPC data encoding constants and types
+#define VERSION 1
+#define IPC_FLAGS_NOREPLY 1 // set flag if no asynchronous replies are to be sent to client
+
+// Structure packing macro. If we're not using GNUC, it's not fatal. Most compilers naturally pack the on-the-wire
+// structures correctly anyway, so a plain "struct" is usually fine. In the event that structures are not packed
+// correctly, our compile-time assertion checks will catch it and prevent inadvertent generation of non-working code.
+#ifndef packedstruct
+ #if ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 9)))
+ #define packedstruct struct __attribute__((__packed__))
+ #define packedunion union __attribute__((__packed__))
+ #else
+ #define packedstruct struct
+ #define packedunion union
+ #endif
+#endif
+
+typedef enum
+{
+ request_op_none = 0, // No request yet received on this connection
+ connection_request = 1, // connected socket via DNSServiceConnect()
+ reg_record_request, // reg/remove record only valid for connected sockets
+ remove_record_request,
+ enumeration_request,
+ reg_service_request,
+ browse_request,
+ resolve_request,
+ query_request,
+ reconfirm_record_request,
+ add_record_request,
+ update_record_request,
+ setdomain_request, // Up to here is in Tiger and B4W 1.0.3
+ getproperty_request, // New in B4W 1.0.4
+ port_mapping_request, // New in Leopard and B4W 2.0
+ addrinfo_request,
+ send_bpf, // New in SL
+ getpid_request,
+ release_request,
+ connection_delegate_request,
+
+ cancel_request = 63
+} request_op_t;
+
+typedef enum
+{
+ enumeration_reply_op = 64,
+ reg_service_reply_op,
+ browse_reply_op,
+ resolve_reply_op,
+ query_reply_op,
+ reg_record_reply_op, // Up to here is in Tiger and B4W 1.0.3
+ getproperty_reply_op, // New in B4W 1.0.4
+ port_mapping_reply_op, // New in Leopard and B4W 2.0
+ addrinfo_reply_op
+} reply_op_t;
+
+#if defined(_WIN64)
+# pragma pack(push,4)
+#endif
+
+// Define context object big enough to hold a 64-bit pointer,
+// to accomodate 64-bit clients communicating with 32-bit daemon.
+// There's no reason for the daemon to ever be a 64-bit process, but its clients might be
+typedef packedunion
+{
+ void *context;
+ uint32_t u32[2];
+} client_context_t;
+
+typedef packedstruct
+{
+ uint32_t version;
+ uint32_t datalen;
+ uint32_t ipc_flags;
+ uint32_t op; // request_op_t or reply_op_t
+ client_context_t client_context; // context passed from client, returned by server in corresponding reply
+ uint32_t reg_index; // identifier for a record registered via DNSServiceRegisterRecord() on a
+ // socket connected by DNSServiceCreateConnection(). Must be unique in the scope of the connection, such that and
+ // index/socket pair uniquely identifies a record. (Used to select records for removal by DNSServiceRemoveRecord())
+} ipc_msg_hdr;
+
+#if defined(_WIN64)
+# pragma pack(pop)
+#endif
+
+// routines to write to and extract data from message buffers.
+// caller responsible for bounds checking.
+// ptr is the address of the pointer to the start of the field.
+// it is advanced to point to the next field, or the end of the message
+
+void put_uint32(const uint32_t l, char **ptr);
+uint32_t get_uint32(const char **ptr, const char *end);
+
+void put_uint16(uint16_t s, char **ptr);
+uint16_t get_uint16(const char **ptr, const char *end);
+
+#define put_flags put_uint32
+#define get_flags get_uint32
+
+#define put_error_code put_uint32
+#define get_error_code get_uint32
+
+int put_string(const char *str, char **ptr);
+int get_string(const char **ptr, const char *const end, char *buffer, int buflen);
+
+void put_rdata(const int rdlen, const unsigned char *rdata, char **ptr);
+const char *get_rdata(const char **ptr, const char *end, int rdlen); // return value is rdata pointed to by *ptr -
+// rdata is not copied from buffer.
+
+void ConvertHeaderBytes(ipc_msg_hdr *hdr);
+
+struct CompileTimeAssertionChecks_dnssd_ipc
+{
+ // Check that the compiler generated our on-the-wire packet format structure definitions
+ // properly packed, without adding padding bytes to align fields on 32-bit or 64-bit boundaries.
+ char assert0[(sizeof(client_context_t) == 8) ? 1 : -1];
+ char assert1[(sizeof(ipc_msg_hdr) == 28) ? 1 : -1];
+};
+
+#endif // DNSSD_IPC_H
Deleted: vendor/apple/mDNSResponder/561.1.1/mDNSWindows/mDNSWin32.c
===================================================================
--- vendor/apple/mDNSResponder/dist/mDNSWindows/mDNSWin32.c 2014-06-30 23:58:12 UTC (rev 6706)
+++ vendor/apple/mDNSResponder/561.1.1/mDNSWindows/mDNSWin32.c 2015-03-20 01:14:52 UTC (rev 6985)
@@ -1,5197 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2013 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-
- To Do:
-
- - Get unicode name of machine for nice name instead of just the host name.
- - Use the IPv6 Internet Connection Firewall API to allow IPv6 mDNS without manually changing the firewall.
- - Get DNS server address(es) from Windows and provide them to the uDNS layer.
- - Implement TCP support for truncated packets (only stubs now).
-
-*/
-
-#define _CRT_RAND_S
-
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <crtdbg.h>
-#include <string.h>
-
-#include "Poll.h"
-#include "CommonServices.h"
-#include "DebugServices.h"
-#include "Firewall.h"
-#include "RegNames.h"
-#include "Secret.h"
-#include <dns_sd.h>
-
-#include <Iphlpapi.h>
-#include <mswsock.h>
-#include <process.h>
-#include <ntsecapi.h>
-#include <lm.h>
-#include <winioctl.h>
-#include <ntddndis.h> // This defines the IOCTL constants.
-
-#include "mDNSEmbeddedAPI.h"
-#include "GenLinkedList.h"
-#include "DNSCommon.h"
-#include "mDNSWin32.h"
-#include "dnssec.h"
-#include "nsec.h"
-
-#if 0
-#pragma mark == Constants ==
-#endif
-
-//===========================================================================================================================
-// Constants
-//===========================================================================================================================
-
-#define DEBUG_NAME "[mDNSWin32] "
-
-#define MDNS_WINDOWS_USE_IPV6_IF_ADDRS 1
-#define MDNS_WINDOWS_ENABLE_IPV4 1
-#define MDNS_WINDOWS_ENABLE_IPV6 1
-#define MDNS_FIX_IPHLPAPI_PREFIX_BUG 1
-#define MDNS_SET_HINFO_STRINGS 0
-
-#define kMDNSDefaultName "My Computer"
-
-#define kWinSockMajorMin 2
-#define kWinSockMinorMin 2
-
-#define kRegistryMaxKeyLength 255
-#define kRegistryMaxValueName 16383
-
-static GUID kWSARecvMsgGUID = WSAID_WSARECVMSG;
-
-#define kIPv6IfIndexBase (10000000L)
-#define SMBPortAsNumber 445
-#define DEVICE_PREFIX "\\\\.\\"
-
-#if 0
-#pragma mark == Prototypes ==
-#endif
-
-//===========================================================================================================================
-// Prototypes
-//===========================================================================================================================
-
-mDNSlocal mStatus SetupNiceName( mDNS * const inMDNS );
-mDNSlocal mStatus SetupHostName( mDNS * const inMDNS );
-mDNSlocal mStatus SetupName( mDNS * const inMDNS );
-mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inIFA, mDNSInterfaceData **outIFD );
-mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD );
-mDNSlocal void CALLBACK FreeInterface( mDNSInterfaceData *inIFD );
-mDNSlocal mStatus SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, mDNSIPPort port, SocketRef *outSocketRef );
-mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort );
-mDNSlocal OSStatus GetWindowsVersionString( char *inBuffer, size_t inBufferSize );
-mDNSlocal int getifaddrs( struct ifaddrs **outAddrs );
-mDNSlocal void freeifaddrs( struct ifaddrs *inAddrs );
-
-
-
-// Platform Accessors
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo;
-struct mDNSPlatformInterfaceInfo
-{
- const char * name;
- mDNSAddr ip;
-};
-
-
-mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID );
-mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo );
-
-
-// Wakeup Structs
-
-#define kUnicastWakeupNumTries ( 1 )
-#define kUnicastWakeupSleepBetweenTries ( 0 )
-#define kMulticastWakeupNumTries ( 18 )
-#define kMulticastWakeupSleepBetweenTries ( 100 )
-
-typedef struct MulticastWakeupStruct
-{
- mDNS *inMDNS;
- struct sockaddr_in addr;
- INT addrLen;
- unsigned char data[ 102 ];
- INT dataLen;
- INT numTries;
- INT msecSleep;
-} MulticastWakeupStruct;
-
-
-// Utilities
-
-#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
- mDNSlocal int getifaddrs_ipv6( struct ifaddrs **outAddrs );
-#endif
-
-mDNSlocal int getifaddrs_ipv4( struct ifaddrs **outAddrs );
-
-
-mDNSlocal DWORD GetPrimaryInterface();
-mDNSlocal mStatus AddressToIndexAndMask( struct sockaddr * address, uint32_t * index, struct sockaddr * mask );
-mDNSlocal mDNSBool CanReceiveUnicast( void );
-mDNSlocal mDNSBool IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS * addr );
-
-mDNSlocal mStatus StringToAddress( mDNSAddr * ip, LPSTR string );
-mDNSlocal mStatus RegQueryString( HKEY key, LPCSTR param, LPSTR * string, DWORD * stringLen, DWORD * enabled );
-mDNSlocal struct ifaddrs* myGetIfAddrs(int refresh);
-mDNSlocal OSStatus TCHARtoUTF8( const TCHAR *inString, char *inBuffer, size_t inBufferSize );
-mDNSlocal OSStatus WindowsLatin1toUTF8( const char *inString, char *inBuffer, size_t inBufferSize );
-mDNSlocal void CALLBACK TCPSocketNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context );
-mDNSlocal void TCPCloseSocket( TCPSocket * socket );
-mDNSlocal void CALLBACK UDPSocketNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context );
-mDNSlocal void UDPCloseSocket( UDPSocket * sock );
-mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa);
-mDNSlocal void GetDDNSFQDN( domainname *const fqdn );
-#ifdef UNICODE
-mDNSlocal void GetDDNSDomains( DNameListElem ** domains, LPCWSTR lpSubKey );
-#else
-mDNSlocal void GetDDNSDomains( DNameListElem ** domains, LPCSTR lpSubKey );
-#endif
-mDNSlocal void SetDomainSecrets( mDNS * const inMDNS );
-mDNSlocal void SetDomainSecret( mDNS * const m, const domainname * inDomain );
-mDNSlocal VOID CALLBACK CheckFileSharesProc( LPVOID arg, DWORD dwTimerLowValue, DWORD dwTimerHighValue );
-mDNSlocal void CheckFileShares( mDNS * const inMDNS );
-mDNSlocal void SMBCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
-mDNSlocal mDNSu8 IsWOMPEnabledForAdapter( const char * adapterName );
-mDNSlocal void SendWakeupPacket( mDNS * const inMDNS, LPSOCKADDR addr, INT addrlen, const char * buf, INT buflen, INT numTries, INT msecSleep );
-mDNSlocal void _cdecl SendMulticastWakeupPacket( void *arg );
-
-#ifdef __cplusplus
- }
-#endif
-
-#if 0
-#pragma mark == Globals ==
-#endif
-
-//===========================================================================================================================
-// Globals
-//===========================================================================================================================
-
-mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport;
-mDNSs32 mDNSPlatformOneSecond = 0;
-mDNSlocal UDPSocket * gUDPSockets = NULL;
-mDNSlocal int gUDPNumSockets = 0;
-mDNSlocal BOOL gEnableIPv6 = TRUE;
-
-#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
-
- typedef DWORD
- ( WINAPI * GetAdaptersAddressesFunctionPtr )(
- ULONG inFamily,
- DWORD inFlags,
- PVOID inReserved,
- PIP_ADAPTER_ADDRESSES inAdapter,
- PULONG outBufferSize );
-
- mDNSlocal HMODULE gIPHelperLibraryInstance = NULL;
- mDNSlocal GetAdaptersAddressesFunctionPtr gGetAdaptersAddressesFunctionPtr = NULL;
-
-#endif
-
-
-#ifndef HCRYPTPROV
- typedef ULONG_PTR HCRYPTPROV; // WinCrypt.h, line 249
-#endif
-
-
-#ifndef CRYPT_MACHINE_KEYSET
-# define CRYPT_MACHINE_KEYSET 0x00000020
-#endif
-
-#ifndef CRYPT_NEWKEYSET
-# define CRYPT_NEWKEYSET 0x00000008
-#endif
-
-#ifndef PROV_RSA_FULL
-# define PROV_RSA_FULL 1
-#endif
-
-typedef BOOL (__stdcall *fnCryptGenRandom)( HCRYPTPROV, DWORD, BYTE* );
-typedef BOOL (__stdcall *fnCryptAcquireContext)( HCRYPTPROV*, LPCTSTR, LPCTSTR, DWORD, DWORD);
-typedef BOOL (__stdcall *fnCryptReleaseContext)(HCRYPTPROV, DWORD);
-
-static fnCryptAcquireContext g_lpCryptAcquireContext = NULL;
-static fnCryptReleaseContext g_lpCryptReleaseContext = NULL;
-static fnCryptGenRandom g_lpCryptGenRandom = NULL;
-static HINSTANCE g_hAAPI32 = NULL;
-static HCRYPTPROV g_hProvider = ( ULONG_PTR ) NULL;
-
-
-typedef DNSServiceErrorType ( DNSSD_API *DNSServiceRegisterFunc )
- (
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- const char *name, /* may be NULL */
- const char *regtype,
- const char *domain, /* may be NULL */
- const char *host, /* may be NULL */
- uint16_t port,
- uint16_t txtLen,
- const void *txtRecord, /* may be NULL */
- DNSServiceRegisterReply callBack, /* may be NULL */
- void *context /* may be NULL */
- );
-
-
-typedef void ( DNSSD_API *DNSServiceRefDeallocateFunc )( DNSServiceRef sdRef );
-
-mDNSlocal HMODULE gDNSSDLibrary = NULL;
-mDNSlocal DNSServiceRegisterFunc gDNSServiceRegister = NULL;
-mDNSlocal DNSServiceRefDeallocateFunc gDNSServiceRefDeallocate = NULL;
-mDNSlocal HANDLE gSMBThread = NULL;
-mDNSlocal HANDLE gSMBThreadRegisterEvent = NULL;
-mDNSlocal HANDLE gSMBThreadDeregisterEvent = NULL;
-mDNSlocal HANDLE gSMBThreadStopEvent = NULL;
-mDNSlocal HANDLE gSMBThreadQuitEvent = NULL;
-
-#define kSMBStopEvent ( WAIT_OBJECT_0 + 0 )
-#define kSMBRegisterEvent ( WAIT_OBJECT_0 + 1 )
-#define kSMBDeregisterEvent ( WAIT_OBJECT_0 + 2 )
-
-
-#if 0
-#pragma mark -
-#pragma mark == Platform Support ==
-#endif
-
-//===========================================================================================================================
-// mDNSPlatformInit
-//===========================================================================================================================
-
-mDNSexport mStatus mDNSPlatformInit( mDNS * const inMDNS )
-{
- mStatus err;
- OSVERSIONINFO osInfo;
- BOOL ok;
- WSADATA wsaData;
- int supported;
- struct sockaddr_in sa4;
- struct sockaddr_in6 sa6;
- int sa4len;
- int sa6len;
- DWORD size;
-
- dlog( kDebugLevelTrace, DEBUG_NAME "platform init\n" );
-
- // Initialize variables. If the PlatformSupport pointer is not null then just assume that a non-Apple client is
- // calling mDNS_Init and wants to provide its own storage for the platform-specific data so do not overwrite it.
-
- mDNSPlatformMemZero( &gMDNSPlatformSupport, sizeof( gMDNSPlatformSupport ) );
- if( !inMDNS->p ) inMDNS->p = &gMDNSPlatformSupport;
- inMDNS->p->mainThread = OpenThread( THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId() );
- require_action( inMDNS->p->mainThread, exit, err = mStatus_UnknownErr );
- inMDNS->p->checkFileSharesTimer = CreateWaitableTimer( NULL, FALSE, NULL );
- require_action( inMDNS->p->checkFileSharesTimer, exit, err = mStatus_UnknownErr );
- inMDNS->p->checkFileSharesTimeout = 10; // Retry time for CheckFileShares() in seconds
- mDNSPlatformOneSecond = 1000; // Use milliseconds as the quantum of time
-
- // Get OS version info
-
- osInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
- ok = GetVersionEx( &osInfo );
- err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
- require_noerr( err, exit );
- inMDNS->p->osMajorVersion = osInfo.dwMajorVersion;
- inMDNS->p->osMinorVersion = osInfo.dwMinorVersion;
-
- // Don't enable IPv6 on anything less recent than Windows Vista
-
- if ( inMDNS->p->osMajorVersion < 6 )
- {
- gEnableIPv6 = FALSE;
- }
-
- // Startup WinSock 2.2 or later.
-
- err = WSAStartup( MAKEWORD( kWinSockMajorMin, kWinSockMinorMin ), &wsaData );
- require_noerr( err, exit );
-
- supported = ( ( LOBYTE( wsaData.wVersion ) == kWinSockMajorMin ) && ( HIBYTE( wsaData.wVersion ) == kWinSockMinorMin ) );
- require_action( supported, exit, err = mStatus_UnsupportedErr );
-
- inMDNS->CanReceiveUnicastOn5353 = CanReceiveUnicast();
-
- // Setup the HINFO HW strings.
- //<rdar://problem/7245119> device-info should have model=Windows
-
- strcpy_s( ( char* ) &inMDNS->HIHardware.c[ 1 ], sizeof( inMDNS->HIHardware.c ) - 2, "Windows" );
- inMDNS->HIHardware.c[ 0 ] = ( mDNSu8 ) mDNSPlatformStrLen( &inMDNS->HIHardware.c[ 1 ] );
- dlog( kDebugLevelInfo, DEBUG_NAME "HIHardware: %#s\n", inMDNS->HIHardware.c );
-
- // Setup the HINFO SW strings.
-#if ( MDNS_SET_HINFO_STRINGS )
- mDNS_snprintf( (char *) &inMDNS->HISoftware.c[ 1 ], sizeof( inMDNS->HISoftware.c ) - 2,
- "mDNSResponder (%s %s)", __DATE__, __TIME__ );
- inMDNS->HISoftware.c[ 0 ] = (mDNSu8) mDNSPlatformStrLen( &inMDNS->HISoftware.c[ 1 ] );
- dlog( kDebugLevelInfo, DEBUG_NAME "HISoftware: %#s\n", inMDNS->HISoftware.c );
-#endif
-
- // Set up the IPv4 unicast socket
-
- inMDNS->p->unicastSock4.fd = INVALID_SOCKET;
- inMDNS->p->unicastSock4.recvMsgPtr = NULL;
- inMDNS->p->unicastSock4.ifd = NULL;
- inMDNS->p->unicastSock4.next = NULL;
- inMDNS->p->unicastSock4.m = inMDNS;
-
-#if ( MDNS_WINDOWS_ENABLE_IPV4 )
-
- sa4.sin_family = AF_INET;
- sa4.sin_addr.s_addr = INADDR_ANY;
- err = SetupSocket( inMDNS, (const struct sockaddr*) &sa4, zeroIPPort, &inMDNS->p->unicastSock4.fd );
- check_noerr( err );
- sa4len = sizeof( sa4 );
- err = getsockname( inMDNS->p->unicastSock4.fd, (struct sockaddr*) &sa4, &sa4len );
- require_noerr( err, exit );
- inMDNS->p->unicastSock4.port.NotAnInteger = sa4.sin_port;
- inMDNS->UnicastPort4 = inMDNS->p->unicastSock4.port;
- err = WSAIoctl( inMDNS->p->unicastSock4.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &inMDNS->p->unicastSock4.recvMsgPtr, sizeof( inMDNS->p->unicastSock4.recvMsgPtr ), &size, NULL, NULL );
-
- if ( err )
- {
- inMDNS->p->unicastSock4.recvMsgPtr = NULL;
- }
-
- err = mDNSPollRegisterSocket( inMDNS->p->unicastSock4.fd, FD_READ, UDPSocketNotification, &inMDNS->p->unicastSock4 );
- require_noerr( err, exit );
-
-#endif
-
- // Set up the IPv6 unicast socket
-
- inMDNS->p->unicastSock6.fd = INVALID_SOCKET;
- inMDNS->p->unicastSock6.recvMsgPtr = NULL;
- inMDNS->p->unicastSock6.ifd = NULL;
- inMDNS->p->unicastSock6.next = NULL;
- inMDNS->p->unicastSock6.m = inMDNS;
-
-#if ( MDNS_WINDOWS_ENABLE_IPV6 )
-
- if ( gEnableIPv6 )
- {
- sa6.sin6_family = AF_INET6;
- sa6.sin6_addr = in6addr_any;
- sa6.sin6_scope_id = 0;
-
- // This call will fail if the machine hasn't installed IPv6. In that case,
- // the error will be WSAEAFNOSUPPORT.
-
- err = SetupSocket( inMDNS, (const struct sockaddr*) &sa6, zeroIPPort, &inMDNS->p->unicastSock6.fd );
- require_action( !err || ( err == WSAEAFNOSUPPORT ), exit, err = (mStatus) WSAGetLastError() );
- err = kNoErr;
-
- // If we weren't able to create the socket (because IPv6 hasn't been installed) don't do this
-
- if ( inMDNS->p->unicastSock6.fd != INVALID_SOCKET )
- {
- sa6len = sizeof( sa6 );
- err = getsockname( inMDNS->p->unicastSock6.fd, (struct sockaddr*) &sa6, &sa6len );
- require_noerr( err, exit );
- inMDNS->p->unicastSock6.port.NotAnInteger = sa6.sin6_port;
- inMDNS->UnicastPort6 = inMDNS->p->unicastSock6.port;
-
- err = WSAIoctl( inMDNS->p->unicastSock6.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &inMDNS->p->unicastSock6.recvMsgPtr, sizeof( inMDNS->p->unicastSock6.recvMsgPtr ), &size, NULL, NULL );
-
- if ( err != 0 )
- {
- inMDNS->p->unicastSock6.recvMsgPtr = NULL;
- }
-
- err = mDNSPollRegisterSocket( inMDNS->p->unicastSock6.fd, FD_READ, UDPSocketNotification, &inMDNS->p->unicastSock6 );
- require_noerr( err, exit );
- }
- }
-
-#endif
-
- // Notify core of domain secret keys
-
- SetDomainSecrets( inMDNS );
-
- // Success!
-
- mDNSCoreInitComplete( inMDNS, err );
-
-
-exit:
-
- if ( err )
- {
- mDNSPlatformClose( inMDNS );
- }
-
- dlog( kDebugLevelTrace, DEBUG_NAME "platform init done (err=%d %m)\n", err, err );
- return( err );
-}
-
-//===========================================================================================================================
-// mDNSPlatformClose
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformClose( mDNS * const inMDNS )
-{
- mStatus err;
-
- dlog( kDebugLevelTrace, DEBUG_NAME "platform close\n" );
- check( inMDNS );
-
- if ( gSMBThread != NULL )
- {
- dlog( kDebugLevelTrace, DEBUG_NAME "tearing down smb registration thread\n" );
- SetEvent( gSMBThreadStopEvent );
-
- if ( WaitForSingleObject( gSMBThreadQuitEvent, 5 * 1000 ) == WAIT_OBJECT_0 )
- {
- if ( gSMBThreadQuitEvent )
- {
- CloseHandle( gSMBThreadQuitEvent );
- gSMBThreadQuitEvent = NULL;
- }
-
- if ( gSMBThreadStopEvent )
- {
- CloseHandle( gSMBThreadStopEvent );
- gSMBThreadStopEvent = NULL;
- }
-
- if ( gSMBThreadDeregisterEvent )
- {
- CloseHandle( gSMBThreadDeregisterEvent );
- gSMBThreadDeregisterEvent = NULL;
- }
-
- if ( gSMBThreadRegisterEvent )
- {
- CloseHandle( gSMBThreadRegisterEvent );
- gSMBThreadRegisterEvent = NULL;
- }
-
- if ( gDNSSDLibrary )
- {
- FreeLibrary( gDNSSDLibrary );
- gDNSSDLibrary = NULL;
- }
- }
- else
- {
- LogMsg( "Unable to stop SMBThread" );
- }
-
- inMDNS->p->smbFileSharing = mDNSfalse;
- inMDNS->p->smbPrintSharing = mDNSfalse;
- }
-
- // Tear everything down in reverse order to how it was set up.
-
- err = TearDownInterfaceList( inMDNS );
- check_noerr( err );
- check( !inMDNS->p->inactiveInterfaceList );
-
-#if ( MDNS_WINDOWS_ENABLE_IPV4 )
-
- UDPCloseSocket( &inMDNS->p->unicastSock4 );
-
-#endif
-
-#if ( MDNS_WINDOWS_ENABLE_IPV6 )
-
- if ( gEnableIPv6 )
- {
- UDPCloseSocket( &inMDNS->p->unicastSock6 );
- }
-
-#endif
-
- // Free the DLL needed for IPv6 support.
-
-#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
- if( gIPHelperLibraryInstance )
- {
- gGetAdaptersAddressesFunctionPtr = NULL;
-
- FreeLibrary( gIPHelperLibraryInstance );
- gIPHelperLibraryInstance = NULL;
- }
-#endif
-
- if ( g_hAAPI32 )
- {
- // Release any resources
-
- if ( g_hProvider && g_lpCryptReleaseContext )
- {
- ( g_lpCryptReleaseContext )( g_hProvider, 0 );
- }
-
- // Free the AdvApi32.dll
-
- FreeLibrary( g_hAAPI32 );
-
- // And reset all the data
-
- g_lpCryptAcquireContext = NULL;
- g_lpCryptReleaseContext = NULL;
- g_lpCryptGenRandom = NULL;
- g_hProvider = ( ULONG_PTR ) NULL;
- g_hAAPI32 = NULL;
- }
-
- WSACleanup();
-
- dlog( kDebugLevelTrace, DEBUG_NAME "platform close done\n" );
-}
-
-
-//===========================================================================================================================
-// mDNSPlatformLock
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformLock( const mDNS * const inMDNS )
-{
- ( void ) inMDNS;
-}
-
-//===========================================================================================================================
-// mDNSPlatformUnlock
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformUnlock( const mDNS * const inMDNS )
-{
- ( void ) inMDNS;
-}
-
-//===========================================================================================================================
-// mDNSPlatformStrCopy
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformStrCopy( void *inDst, const void *inSrc )
-{
- check( inSrc );
- check( inDst );
-
- strcpy( (char *) inDst, (const char*) inSrc );
-}
-
-//===========================================================================================================================
-// mDNSPlatformStrLen
-//===========================================================================================================================
-
-mDNSexport mDNSu32 mDNSPlatformStrLen( const void *inSrc )
-{
- check( inSrc );
-
- return( (mDNSu32) strlen( (const char *) inSrc ) );
-}
-
-//===========================================================================================================================
-// mDNSPlatformMemCopy
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformMemCopy( void *inDst, const void *inSrc, mDNSu32 inSize )
-{
- check( inSrc );
- check( inDst );
-
- memcpy( inDst, inSrc, inSize );
-}
-
-//===========================================================================================================================
-// mDNSPlatformMemSame
-//===========================================================================================================================
-
-mDNSexport mDNSBool mDNSPlatformMemSame( const void *inDst, const void *inSrc, mDNSu32 inSize )
-{
- check( inSrc );
- check( inDst );
-
- return( (mDNSBool)( memcmp( inSrc, inDst, inSize ) == 0 ) );
-}
-
-//===========================================================================================================================
-// mDNSPlatformMemCmp
-//===========================================================================================================================
-
-mDNSexport int mDNSPlatformMemCmp( const void *inDst, const void *inSrc, mDNSu32 inSize )
-{
- check( inSrc );
- check( inDst );
-
- return( memcmp( inSrc, inDst, inSize ) );
-}
-
-mDNSexport void mDNSPlatformQsort(void *base, int nel, int width, int (*compar)(const void *, const void *))
-{
- (void)base;
- (void)nel;
- (void)width;
- (void)compar;
-}
-
-// DNSSEC stub functions
-mDNSexport void VerifySignature(mDNS *const m, DNSSECVerifier *dv, DNSQuestion *q)
- {
- (void)m;
- (void)dv;
- (void)q;
- }
-
-mDNSexport mDNSBool AddNSECSForCacheRecord(mDNS *const m, CacheRecord *crlist, CacheRecord *negcr, mDNSu8 rcode)
- {
- (void)m;
- (void)crlist;
- (void)negcr;
- (void)rcode;
- return mDNSfalse;
- }
-
-mDNSexport void BumpDNSSECStats(mDNS *const m, DNSSECStatsAction action, DNSSECStatsType type, mDNSu32 value)
- {
- (void)m;
- (void)action;
- (void)type;
- (void)value;
- }
-
-// Proxy stub functions
-mDNSexport mDNSu8 *DNSProxySetAttributes(DNSQuestion *q, DNSMessageHeader *h, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit)
-{
- (void) q;
- (void) h;
- (void) msg;
- (void) ptr;
- (void) limit;
-
- return ptr;
-}
-
-mDNSexport void DNSProxyInit(mDNS *const m, mDNSu32 IpIfArr[], mDNSu32 OpIf)
-{
- (void) m;
- (void) IpIfArr;
- (void) OpIf;
-}
-
-mDNSexport void DNSProxyTerminate(mDNS *const m)
-{
- (void) m;
-}
-
-//===========================================================================================================================
-// mDNSPlatformMemZero
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformMemZero( void *inDst, mDNSu32 inSize )
-{
- check( inDst );
-
- memset( inDst, 0, inSize );
-}
-
-//===========================================================================================================================
-// mDNSPlatformMemAllocate
-//===========================================================================================================================
-
-mDNSexport void * mDNSPlatformMemAllocate( mDNSu32 inSize )
-{
- void * mem;
-
- check( inSize > 0 );
-
- mem = malloc( inSize );
- check( mem );
-
- return( mem );
-}
-
-//===========================================================================================================================
-// mDNSPlatformMemFree
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformMemFree( void *inMem )
-{
- check( inMem );
-
- free( inMem );
-}
-
-//===========================================================================================================================
-// mDNSPlatformRandomNumber
-//===========================================================================================================================
-
-mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
-{
- unsigned int randomNumber;
- errno_t err;
-
- err = rand_s( &randomNumber );
- require_noerr( err, exit );
-
-exit:
-
- if ( err )
- {
- randomNumber = rand();
- }
-
- return ( mDNSu32 ) randomNumber;
-}
-
-//===========================================================================================================================
-// mDNSPlatformTimeInit
-//===========================================================================================================================
-
-mDNSexport mStatus mDNSPlatformTimeInit( void )
-{
- // No special setup is required on Windows -- we just use GetTickCount().
- return( mStatus_NoError );
-}
-
-//===========================================================================================================================
-// mDNSPlatformRawTime
-//===========================================================================================================================
-
-mDNSexport mDNSs32 mDNSPlatformRawTime( void )
-{
- return( (mDNSs32) GetTickCount() );
-}
-
-//===========================================================================================================================
-// mDNSPlatformUTC
-//===========================================================================================================================
-
-mDNSexport mDNSs32 mDNSPlatformUTC( void )
-{
- return ( mDNSs32 ) time( NULL );
-}
-
-//===========================================================================================================================
-// mDNSPlatformInterfaceNameToID
-//===========================================================================================================================
-
-mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID )
-{
- mStatus err;
- mDNSInterfaceData * ifd;
-
- check( inMDNS );
- check( inMDNS->p );
- check( inName );
-
- // Search for an interface with the specified name,
-
- for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
- {
- if( strcmp( ifd->name, inName ) == 0 )
- {
- break;
- }
- }
- require_action_quiet( ifd, exit, err = mStatus_NoSuchNameErr );
-
- // Success!
-
- if( outID )
- {
- *outID = (mDNSInterfaceID) ifd;
- }
- err = mStatus_NoError;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// mDNSPlatformInterfaceIDToInfo
-//===========================================================================================================================
-
-mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo )
-{
- mStatus err;
- mDNSInterfaceData * ifd;
-
- check( inMDNS );
- check( inID );
- check( outInfo );
-
- // Search for an interface with the specified ID,
-
- for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
- {
- if( ifd == (mDNSInterfaceData *) inID )
- {
- break;
- }
- }
- require_action_quiet( ifd, exit, err = mStatus_NoSuchNameErr );
-
- // Success!
-
- outInfo->name = ifd->name;
- outInfo->ip = ifd->interfaceInfo.ip;
- err = mStatus_NoError;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// mDNSPlatformInterfaceIDfromInterfaceIndex
-//===========================================================================================================================
-
-mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS * const inMDNS, mDNSu32 inIndex )
-{
- mDNSInterfaceID id;
-
- id = mDNSNULL;
- if( inIndex == kDNSServiceInterfaceIndexLocalOnly )
- {
- id = mDNSInterface_LocalOnly;
- }
- else if( inIndex != 0 )
- {
- mDNSInterfaceData * ifd;
-
- for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
- {
- if( ( ifd->scopeID == inIndex ) && ifd->interfaceInfo.InterfaceActive )
- {
- id = ifd->interfaceInfo.InterfaceID;
- break;
- }
- }
- check( ifd );
- }
- return( id );
-}
-
-//===========================================================================================================================
-// mDNSPlatformInterfaceIndexfromInterfaceID
-//===========================================================================================================================
-
-mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSBool suppressNetworkChange )
-{
- mDNSu32 index;
-
- (void) suppressNetworkChange;
-
- index = 0;
- if( inID == mDNSInterface_LocalOnly )
- {
- index = (mDNSu32) kDNSServiceInterfaceIndexLocalOnly;
- }
- else if( inID )
- {
- mDNSInterfaceData * ifd;
-
- // Search active interfaces.
- for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
- {
- if( (mDNSInterfaceID) ifd == inID )
- {
- index = ifd->scopeID;
- break;
- }
- }
-
- // Search inactive interfaces too so remove events for inactive interfaces report the old interface index.
-
- if( !ifd )
- {
- for( ifd = inMDNS->p->inactiveInterfaceList; ifd; ifd = ifd->next )
- {
- if( (mDNSInterfaceID) ifd == inID )
- {
- index = ifd->scopeID;
- break;
- }
- }
- }
- check( ifd );
- }
- return( index );
-}
-
-
-//===========================================================================================================================
-// mDNSPlatformTCPSocket
-//===========================================================================================================================
-
-TCPSocket *
-mDNSPlatformTCPSocket
- (
- mDNS * const m,
- TCPSocketFlags flags,
- mDNSIPPort * port,
- mDNSBool useBackgroundTrafficClass
- )
-{
- TCPSocket * sock = NULL;
- u_long on = 1; // "on" for setsockopt
- struct sockaddr_in saddr;
- int len;
- mStatus err = mStatus_NoError;
-
- DEBUG_UNUSED( m );
- DEBUG_UNUSED( useBackgroundTrafficClass );
-
- require_action( flags == 0, exit, err = mStatus_UnsupportedErr );
-
- // Setup connection data object
-
- sock = (TCPSocket *) malloc( sizeof( TCPSocket ) );
- require_action( sock, exit, err = mStatus_NoMemoryErr );
- mDNSPlatformMemZero( sock, sizeof( TCPSocket ) );
- sock->fd = INVALID_SOCKET;
- sock->flags = flags;
- sock->m = m;
-
- mDNSPlatformMemZero(&saddr, sizeof(saddr));
- saddr.sin_family = AF_INET;
- saddr.sin_addr.s_addr = htonl( INADDR_ANY );
- saddr.sin_port = port->NotAnInteger;
-
- // Create the socket
-
- sock->fd = socket(AF_INET, SOCK_STREAM, 0);
- err = translate_errno( sock->fd != INVALID_SOCKET, WSAGetLastError(), mStatus_UnknownErr );
- require_noerr( err, exit );
-
- // bind
-
- err = bind( sock->fd, ( struct sockaddr* ) &saddr, sizeof( saddr ) );
- err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
- require_noerr( err, exit );
-
- // Set it to be non-blocking
-
- err = ioctlsocket( sock->fd, FIONBIO, &on );
- err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
- require_noerr( err, exit );
-
- // Get port number
-
- mDNSPlatformMemZero( &saddr, sizeof( saddr ) );
- len = sizeof( saddr );
-
- err = getsockname( sock->fd, ( struct sockaddr* ) &saddr, &len );
- err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
- require_noerr( err, exit );
-
- port->NotAnInteger = saddr.sin_port;
-
-exit:
-
- if ( err && sock )
- {
- TCPCloseSocket( sock );
- free( sock );
- sock = mDNSNULL;
- }
-
- return sock;
-}
-
-//===========================================================================================================================
-// mDNSPlatformTCPConnect
-//===========================================================================================================================
-
-mStatus
-mDNSPlatformTCPConnect
- (
- TCPSocket * sock,
- const mDNSAddr * inDstIP,
- mDNSOpaque16 inDstPort,
- domainname * hostname,
- mDNSInterfaceID inInterfaceID,
- TCPConnectionCallback inCallback,
- void * inContext
- )
-{
- struct sockaddr_in saddr;
- mStatus err = mStatus_NoError;
-
- DEBUG_UNUSED( hostname );
- DEBUG_UNUSED( inInterfaceID );
-
- if ( inDstIP->type != mDNSAddrType_IPv4 )
- {
- LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: operation not supported");
- return mStatus_UnknownErr;
- }
-
- // Setup connection data object
-
- sock->userCallback = inCallback;
- sock->userContext = inContext;
-
- mDNSPlatformMemZero(&saddr, sizeof(saddr));
- saddr.sin_family = AF_INET;
- saddr.sin_port = inDstPort.NotAnInteger;
- memcpy(&saddr.sin_addr, &inDstIP->ip.v4.NotAnInteger, sizeof(saddr.sin_addr));
-
- // Try and do connect
-
- err = connect( sock->fd, ( struct sockaddr* ) &saddr, sizeof( saddr ) );
- require_action( !err || ( WSAGetLastError() == WSAEWOULDBLOCK ), exit, err = mStatus_ConnFailed );
- sock->connected = !err ? TRUE : FALSE;
-
- err = mDNSPollRegisterSocket( sock->fd, FD_CONNECT | FD_READ | FD_CLOSE, TCPSocketNotification, sock );
- require_noerr( err, exit );
-
-exit:
-
- if ( !err )
- {
- err = sock->connected ? mStatus_ConnEstablished : mStatus_ConnPending;
- }
-
- return err;
-}
-
-
-//===========================================================================================================================
-// mDNSPlatformTCPAccept
-//===========================================================================================================================
-
-mDNSexport
-mDNSexport TCPSocket *mDNSPlatformTCPAccept( TCPSocketFlags flags, int fd )
- {
- TCPSocket * sock = NULL;
- mStatus err = mStatus_NoError;
-
- require_action( !flags, exit, err = mStatus_UnsupportedErr );
-
- sock = malloc( sizeof( TCPSocket ) );
- require_action( sock, exit, err = mStatus_NoMemoryErr );
-
- mDNSPlatformMemZero( sock, sizeof( *sock ) );
-
- sock->fd = fd;
- sock->flags = flags;
-
-exit:
-
- if ( err && sock )
- {
- free( sock );
- sock = NULL;
- }
-
- return sock;
- }
-
-
-//===========================================================================================================================
-// mDNSPlatformTCPCloseConnection
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformTCPCloseConnection( TCPSocket *sock )
-{
- check( sock );
-
- if ( sock )
- {
- dlog( kDebugLevelChatty, DEBUG_NAME "mDNSPlatformTCPCloseConnection 0x%x:%d\n", sock, sock->fd );
-
- if ( sock->fd != INVALID_SOCKET )
- {
- mDNSPollUnregisterSocket( sock->fd );
- closesocket( sock->fd );
- sock->fd = INVALID_SOCKET;
- }
-
- free( sock );
- }
-}
-
-
-//===========================================================================================================================
-// mDNSPlatformReadTCP
-//===========================================================================================================================
-
-mDNSexport long mDNSPlatformReadTCP( TCPSocket *sock, void *inBuffer, unsigned long inBufferSize, mDNSBool * closed )
-{
- int nread;
- OSStatus err;
-
- *closed = mDNSfalse;
- nread = recv( sock->fd, inBuffer, inBufferSize, 0 );
- err = translate_errno( ( nread >= 0 ), WSAGetLastError(), mStatus_UnknownErr );
-
- if ( nread > 0 )
- {
- dlog( kDebugLevelChatty, DEBUG_NAME "mDNSPlatformReadTCP: 0x%x:%d read %d bytes\n", sock, sock->fd, nread );
- }
- else if ( !nread )
- {
- *closed = mDNStrue;
- }
- else if ( err == WSAECONNRESET )
- {
- *closed = mDNStrue;
- nread = 0;
- }
- else if ( err == WSAEWOULDBLOCK )
- {
- nread = 0;
- }
- else
- {
- LogMsg( "ERROR: mDNSPlatformReadTCP - recv: %d\n", err );
- nread = -1;
- }
-
- return nread;
-}
-
-
-//===========================================================================================================================
-// mDNSPlatformWriteTCP
-//===========================================================================================================================
-
-mDNSexport long mDNSPlatformWriteTCP( TCPSocket *sock, const char *inMsg, unsigned long inMsgSize )
-{
- int nsent;
- OSStatus err;
-
- nsent = send( sock->fd, inMsg, inMsgSize, 0 );
-
- err = translate_errno( ( nsent >= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK ), WSAGetLastError(), mStatus_UnknownErr );
- require_noerr( err, exit );
-
- if ( nsent < 0)
- {
- nsent = 0;
- }
-
-exit:
-
- return nsent;
-}
-
-//===========================================================================================================================
-// mDNSPlatformTCPGetFD
-//===========================================================================================================================
-
-mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock )
-{
- return ( int ) sock->fd;
-}
-
-
-
-//===========================================================================================================================
-// TCPSocketNotification
-//===========================================================================================================================
-
-mDNSlocal void CALLBACK
-TCPSocketNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context )
-{
- TCPSocket *tcpSock = ( TCPSocket* ) context;
- TCPConnectionCallback callback;
- int err;
-
- DEBUG_UNUSED( sock );
-
- require_action( tcpSock, exit, err = mStatus_BadParamErr );
- callback = ( TCPConnectionCallback ) tcpSock->userCallback;
- require_action( callback, exit, err = mStatus_BadParamErr );
-
- if ( event && ( event->lNetworkEvents & FD_CONNECT ) )
- {
- if ( event->iErrorCode[ FD_CONNECT_BIT ] == 0 )
- {
- callback( tcpSock, tcpSock->userContext, mDNStrue, 0 );
- tcpSock->connected = mDNStrue;
- }
- else
- {
- callback( tcpSock, tcpSock->userContext, mDNSfalse, event->iErrorCode[ FD_CONNECT_BIT ] );
- }
- }
- else
- {
- callback( tcpSock, tcpSock->userContext, mDNSfalse, 0 );
- }
-
-exit:
-
- return;
-}
-
-
-
-//===========================================================================================================================
-// mDNSPlatformUDPSocket
-//===========================================================================================================================
-
-mDNSexport UDPSocket* mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport)
-{
- UDPSocket* sock = NULL;
- mDNSIPPort port = requestedport;
- mStatus err = mStatus_NoError;
- unsigned i;
-
- // Setup connection data object
-
- sock = ( UDPSocket* ) malloc(sizeof( UDPSocket ) );
- require_action( sock, exit, err = mStatus_NoMemoryErr );
- memset( sock, 0, sizeof( UDPSocket ) );
-
- // Create the socket
-
- sock->fd = INVALID_SOCKET;
- sock->recvMsgPtr = m->p->unicastSock4.recvMsgPtr;
- sock->addr = m->p->unicastSock4.addr;
- sock->ifd = NULL;
- sock->m = m;
-
- // Try at most 10000 times to get a unique random port
-
- for (i=0; i<10000; i++)
- {
- struct sockaddr_in saddr;
-
- saddr.sin_family = AF_INET;
- saddr.sin_addr.s_addr = 0;
-
- // The kernel doesn't do cryptographically strong random port
- // allocation, so we do it ourselves here
-
- if (mDNSIPPortIsZero(requestedport))
- {
- port = mDNSOpaque16fromIntVal( ( mDNSu16 ) ( 0xC000 + mDNSRandom(0x3FFF) ) );
- }
-
- saddr.sin_port = port.NotAnInteger;
-
- err = SetupSocket(m, ( struct sockaddr* ) &saddr, port, &sock->fd );
- if (!err) break;
- }
-
- require_noerr( err, exit );
-
- // Set the port
-
- sock->port = port;
-
- // Arm the completion routine
-
- err = mDNSPollRegisterSocket( sock->fd, FD_READ, UDPSocketNotification, sock );
- require_noerr( err, exit );
-
- // Bookkeeping
-
- sock->next = gUDPSockets;
- gUDPSockets = sock;
- gUDPNumSockets++;
-
-exit:
-
- if ( err && sock )
- {
- UDPCloseSocket( sock );
- free( sock );
- sock = NULL;
- }
-
- return sock;
-}
-
-//===========================================================================================================================
-// mDNSPlatformUDPClose
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformUDPClose( UDPSocket *sock )
-{
- UDPSocket * current = gUDPSockets;
- UDPSocket * last = NULL;
-
- while ( current )
- {
- if ( current == sock )
- {
- if ( last == NULL )
- {
- gUDPSockets = sock->next;
- }
- else
- {
- last->next = sock->next;
- }
-
- UDPCloseSocket( sock );
- free( sock );
-
- gUDPNumSockets--;
-
- break;
- }
-
- last = current;
- current = current->next;
- }
-}
-
-
-//===========================================================================================================================
-// mDNSPlatformSendUDP
-//===========================================================================================================================
-
-mDNSexport mStatus
- mDNSPlatformSendUDP(
- const mDNS * const inMDNS,
- const void * const inMsg,
- const mDNSu8 * const inMsgEnd,
- mDNSInterfaceID inInterfaceID,
- UDPSocket * inSrcSocket,
- const mDNSAddr * inDstIP,
- mDNSIPPort inDstPort,
- mDNSBool useBackgroundTrafficClass )
-{
- SOCKET sendingsocket = INVALID_SOCKET;
- mStatus err = mStatus_NoError;
- mDNSInterfaceData * ifd = (mDNSInterfaceData*) inInterfaceID;
- struct sockaddr_storage addr;
- int n;
-
- DEBUG_USE_ONLY( inMDNS );
- DEBUG_USE_ONLY( useBackgroundTrafficClass );
-
- n = (int)( inMsgEnd - ( (const mDNSu8 * const) inMsg ) );
- check( inMDNS );
- check( inMsg );
- check( inMsgEnd );
- check( inDstIP );
-
- dlog( kDebugLevelChatty, DEBUG_NAME "platform send %d bytes to %#a:%u\n", n, inDstIP, ntohs( inDstPort.NotAnInteger ) );
-
- if( inDstIP->type == mDNSAddrType_IPv4 )
- {
- struct sockaddr_in * sa4;
-
- sa4 = (struct sockaddr_in *) &addr;
- sa4->sin_family = AF_INET;
- sa4->sin_port = inDstPort.NotAnInteger;
- sa4->sin_addr.s_addr = inDstIP->ip.v4.NotAnInteger;
- sendingsocket = ifd ? ifd->sock.fd : inMDNS->p->unicastSock4.fd;
-
- if (inSrcSocket) { sendingsocket = inSrcSocket->fd; debugf("mDNSPlatformSendUDP using port %d, static port %d, sock %d", mDNSVal16(inSrcSocket->port), inMDNS->p->unicastSock4.fd, sendingsocket); }
- }
- else if( inDstIP->type == mDNSAddrType_IPv6 )
- {
- struct sockaddr_in6 * sa6;
-
- sa6 = (struct sockaddr_in6 *) &addr;
- sa6->sin6_family = AF_INET6;
- sa6->sin6_port = inDstPort.NotAnInteger;
- sa6->sin6_flowinfo = 0;
- sa6->sin6_addr = *( (struct in6_addr *) &inDstIP->ip.v6 );
- sa6->sin6_scope_id = 0; // Windows requires the scope ID to be zero. IPV6_MULTICAST_IF specifies interface.
- sendingsocket = ifd ? ifd->sock.fd : inMDNS->p->unicastSock6.fd;
- }
- else
- {
- dlog( kDebugLevelError, DEBUG_NAME "%s: dst is not an IPv4 or IPv6 address (type=%d)\n", __ROUTINE__, inDstIP->type );
- err = mStatus_BadParamErr;
- goto exit;
- }
-
- if (IsValidSocket(sendingsocket))
- {
- n = sendto( sendingsocket, (char *) inMsg, n, 0, (struct sockaddr *) &addr, sizeof( addr ) );
- err = translate_errno( n > 0, errno_compat(), kWriteErr );
-
- if ( err )
- {
- // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
-
- if ( !mDNSAddressIsAllDNSLinkGroup( inDstIP ) && ( WSAGetLastError() == WSAEHOSTDOWN || WSAGetLastError() == WSAENETDOWN || WSAGetLastError() == WSAEHOSTUNREACH || WSAGetLastError() == WSAENETUNREACH ) )
- {
- err = mStatus_TransientErr;
- }
- else
- {
- require_noerr( err, exit );
- }
- }
- }
-
-exit:
- return( err );
-}
-
-
-mDNSexport mDNSBool mDNSPlatformPeekUDP(mDNS *const m, UDPSocket *src)
-{
- DEBUG_UNUSED( m );
- DEBUG_UNUSED( src );
- return mDNSfalse;
-}
-
-mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
- {
- DEBUG_UNUSED( m );
- DEBUG_UNUSED( InterfaceID );
- }
-
-
-mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason)
- {
- DEBUG_UNUSED( m );
- DEBUG_UNUSED( allowSleep );
- DEBUG_UNUSED( reason );
- }
-
-//===========================================================================================================================
-// mDNSPlatformSendRawPacket
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *ethaddr, char *ipaddr, int iteration)
-{
- unsigned char mac[ 6 ];
- unsigned char buf[ 102 ];
- char hex[ 3 ] = { 0 };
- unsigned char *bufPtr = buf;
- struct sockaddr_storage saddr;
- INT len = sizeof( saddr );
- mDNSBool unicast = mDNSfalse;
- MulticastWakeupStruct *info;
- int i;
- mStatus err;
-
- (void) InterfaceID;
-
- require_action( ethaddr, exit, err = mStatus_BadParamErr );
-
- for ( i = 0; i < 6; i++ )
- {
- memcpy( hex, ethaddr + ( i * 3 ), 2 );
- mac[ i ] = ( unsigned char ) strtoul( hex, NULL, 16 );
- }
-
- memset( buf, 0, sizeof( buf ) );
-
- for ( i = 0; i < 6; i++ )
- {
- *bufPtr++ = 0xff;
- }
-
- for ( i = 0; i < 16; i++ )
- {
- memcpy( bufPtr, mac, sizeof( mac ) );
- bufPtr += sizeof( mac );
- }
-
- if ( ipaddr )
- {
- if ( WSAStringToAddressA( ipaddr, AF_INET, NULL, ( LPSOCKADDR ) &saddr, &len ) == 0 )
- {
- struct sockaddr_in * saddr4 = ( struct sockaddr_in* ) &saddr;
- saddr4->sin_port = htons( 9 );
- len = sizeof( *saddr4 );
-
- if ( saddr4->sin_addr.s_addr != htonl( INADDR_ANY ) )
- {
- unicast = mDNStrue;
- }
- }
- else if ( WSAStringToAddressA( ipaddr, AF_INET6, NULL, ( LPSOCKADDR ) &saddr, &len ) == 0 )
- {
- mDNSInterfaceData *ifd = ( mDNSInterfaceData* ) InterfaceID;
- struct sockaddr_in6 * saddr6 = ( struct sockaddr_in6* ) &saddr;
- saddr6->sin6_port = htons( 9 );
-
- if ( ifd != NULL )
- {
- saddr6->sin6_scope_id = ifd->scopeID;
- }
-
- len = sizeof( *saddr6 );
-
- if ( memcmp( &saddr6->sin6_addr, &in6addr_any, sizeof( IN6_ADDR ) ) != 0 )
- {
- unicast = mDNStrue;
- }
- }
- }
-
- if ( ( iteration < 2 ) && ( unicast ) )
- {
- SendWakeupPacket( m, ( LPSOCKADDR ) &saddr, len, ( const char* ) buf, sizeof( buf ), kUnicastWakeupNumTries, kUnicastWakeupSleepBetweenTries );
- }
-
- info = ( MulticastWakeupStruct* ) malloc( sizeof( MulticastWakeupStruct ) );
- require_action( info, exit, err = mStatus_NoMemoryErr );
- info->inMDNS = m;
- memset( &info->addr, 0, sizeof( info->addr ) );
- info->addr.sin_family = AF_INET;
- info->addr.sin_addr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
- info->addr.sin_port = htons( 9 );
- info->addrLen = sizeof( info->addr );
- memcpy( info->data, buf, sizeof( buf ) );
- info->dataLen = sizeof( buf );
- info->numTries = kMulticastWakeupNumTries;
- info->msecSleep = kMulticastWakeupSleepBetweenTries;
-
- _beginthread( SendMulticastWakeupPacket, 0, ( void* ) info );
-
-exit:
-
- return;
-}
-
-
-mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const NetworkInterfaceInfo *intf)
-{
- DEBUG_UNUSED( rr );
- DEBUG_UNUSED( intf );
-
- return mDNStrue;
-}
-
-mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf)
-{
- DEBUG_UNUSED( q );
- DEBUG_UNUSED( intf );
-
- return mDNStrue;
-}
-
-mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
- {
- DEBUG_UNUSED( msg );
- DEBUG_UNUSED( end );
- DEBUG_UNUSED( InterfaceID );
- }
-
-// Used for debugging purposes. For now, just set the buffer to zero
-mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize)
- {
- DEBUG_UNUSED( te );
- if (bufsize) buf[0] = 0;
- }
-
-
-mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
- {
- DEBUG_UNUSED( m );
- DEBUG_UNUSED( tpa );
- DEBUG_UNUSED( tha );
- DEBUG_UNUSED( InterfaceID );
- }
-
-
-mDNSexport void mDNSPlatformReceiveRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
- {
- DEBUG_UNUSED( msg );
- DEBUG_UNUSED( end );
- DEBUG_UNUSED( InterfaceID );
- }
-
-mDNSexport void mDNSPlatformSetLocalARP( const mDNSv4Addr * const tpa, const mDNSEthAddr * const tha, mDNSInterfaceID InterfaceID )
- {
- DEBUG_UNUSED( tpa );
- DEBUG_UNUSED( tha );
- DEBUG_UNUSED( InterfaceID );
- }
-
-mDNSexport void mDNSPlatformWriteDebugMsg(const char *msg)
- {
- dlog( kDebugLevelInfo, "%s\n", msg );
- }
-
-mDNSexport void mDNSPlatformWriteLogMsg( const char * ident, const char * msg, mDNSLogLevel_t loglevel )
- {
- extern mDNS mDNSStorage;
- int type;
-
- DEBUG_UNUSED( ident );
-
- type = EVENTLOG_ERROR_TYPE;
-
- switch (loglevel)
- {
- case MDNS_LOG_MSG: type = EVENTLOG_ERROR_TYPE; break;
- case MDNS_LOG_OPERATION: type = EVENTLOG_WARNING_TYPE; break;
- case MDNS_LOG_SPS: type = EVENTLOG_INFORMATION_TYPE; break;
- case MDNS_LOG_INFO: type = EVENTLOG_INFORMATION_TYPE; break;
- case MDNS_LOG_DEBUG: type = EVENTLOG_INFORMATION_TYPE; break;
- default:
- fprintf(stderr, "Unknown loglevel %d, assuming LOG_ERR\n", loglevel);
- fflush(stderr);
- }
-
- mDNSStorage.p->reportStatusFunc( type, msg );
- dlog( kDebugLevelInfo, "%s\n", msg );
- }
-
-mDNSexport void mDNSPlatformSourceAddrForDest( mDNSAddr * const src, const mDNSAddr * const dst )
- {
- DEBUG_UNUSED( src );
- DEBUG_UNUSED( dst );
- }
-
-//===========================================================================================================================
-// mDNSPlatformTLSSetupCerts
-//===========================================================================================================================
-
-mDNSexport mStatus
-mDNSPlatformTLSSetupCerts(void)
-{
- return mStatus_UnsupportedErr;
-}
-
-//===========================================================================================================================
-// mDNSPlatformTLSTearDownCerts
-//===========================================================================================================================
-
-mDNSexport void
-mDNSPlatformTLSTearDownCerts(void)
-{
-}
-
-//===========================================================================================================================
-// mDNSPlatformSetDNSConfig
-//===========================================================================================================================
-
-mDNSlocal void SetDNSServers( mDNS *const m );
-mDNSlocal void SetSearchDomainList( void );
-
-mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **regDomains, DNameListElem **browseDomains, mDNSBool ackConfig)
-{
- (void) ackConfig;
-
- if (setservers) SetDNSServers(m);
- if (setsearch) SetSearchDomainList();
-
- if ( fqdn )
- {
- GetDDNSFQDN( fqdn );
- }
-
- if ( browseDomains )
- {
- GetDDNSDomains( browseDomains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSBrowseDomains );
- }
-
- if ( regDomains )
- {
- GetDDNSDomains( regDomains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains );
- }
- return mDNStrue;
-}
-
-
-//===========================================================================================================================
-// mDNSPlatformDynDNSHostNameStatusChanged
-//===========================================================================================================================
-
-mDNSexport void
-mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
-{
- char uname[MAX_ESCAPED_DOMAIN_NAME];
- BYTE bStatus;
- LPCTSTR name;
- HKEY key = NULL;
- mStatus err;
- char * p;
-
- ConvertDomainNameToCString(dname, uname);
-
- p = uname;
-
- while (*p)
- {
- *p = (char) tolower(*p);
- if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
- p++;
- }
-
- check( strlen( p ) <= MAX_ESCAPED_DOMAIN_NAME );
- name = kServiceParametersNode TEXT("\\DynDNS\\State\\HostNames");
- err = RegCreateKey( HKEY_LOCAL_MACHINE, name, &key );
- require_noerr( err, exit );
-
- bStatus = ( status ) ? 0 : 1;
- err = RegSetValueEx( key, kServiceDynDNSStatus, 0, REG_DWORD, (const LPBYTE) &bStatus, sizeof(DWORD) );
- require_noerr( err, exit );
-
-exit:
-
- if ( key )
- {
- RegCloseKey( key );
- }
-
- return;
-}
-
-
-//===========================================================================================================================
-// SetDomainSecrets
-//===========================================================================================================================
-
-// This routine needs to be called whenever the system secrets database changes.
-// We call it from DynDNSConfigDidChange and mDNSPlatformInit
-
-void
-SetDomainSecrets( mDNS * const m )
-{
- DomainAuthInfo *ptr;
- domainname fqdn;
- DNameListElem * regDomains = NULL;
-
- // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
- // In the case where the user simultaneously removes their DDNS host name and the key
- // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
- // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
- // address records behind that we no longer have permission to delete.
-
- for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
- ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
-
- GetDDNSFQDN( &fqdn );
-
- if ( fqdn.c[ 0 ] )
- {
- SetDomainSecret( m, &fqdn );
- }
-
- GetDDNSDomains( ®Domains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains );
-
- while ( regDomains )
- {
- DNameListElem * current = regDomains;
- SetDomainSecret( m, ¤t->name );
- regDomains = regDomains->next;
- free( current );
- }
-}
-
-
-//===========================================================================================================================
-// SetSearchDomainList
-//===========================================================================================================================
-
-mDNSlocal void SetDomainFromDHCP( void );
-mDNSlocal void SetReverseMapSearchDomainList( void );
-
-mDNSlocal void
-SetSearchDomainList( void )
-{
- char * searchList = NULL;
- DWORD searchListLen;
- //DNameListElem * head = NULL;
- //DNameListElem * current = NULL;
- char * tok;
- HKEY key;
- mStatus err;
-
- err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &key );
- require_noerr( err, exit );
-
- err = RegQueryString( key, "SearchList", &searchList, &searchListLen, NULL );
- require_noerr( err, exit );
-
- // Windows separates the search domains with ','
-
- tok = strtok( searchList, "," );
- while ( tok )
- {
- if ( ( strcmp( tok, "" ) != 0 ) && ( strcmp( tok, "." ) != 0 ) )
- mDNS_AddSearchDomain_CString(tok, mDNSNULL);
- tok = strtok( NULL, "," );
- }
-
-exit:
-
- if ( searchList )
- {
- free( searchList );
- }
-
- if ( key )
- {
- RegCloseKey( key );
- }
-
- SetDomainFromDHCP();
- SetReverseMapSearchDomainList();
-}
-
-
-//===========================================================================================================================
-// SetReverseMapSearchDomainList
-//===========================================================================================================================
-
-mDNSlocal void
-SetReverseMapSearchDomainList( void )
-{
- struct ifaddrs * ifa;
-
- ifa = myGetIfAddrs( 1 );
- while (ifa)
- {
- mDNSAddr addr;
-
- if (ifa->ifa_addr->sa_family == AF_INET && !SetupAddr(&addr, ifa->ifa_addr) && !(ifa->ifa_flags & IFF_LOOPBACK) && ifa->ifa_netmask)
- {
- mDNSAddr netmask;
- char buffer[256];
-
- if (!SetupAddr(&netmask, ifa->ifa_netmask))
- {
- sprintf(buffer, "%d.%d.%d.%d.in-addr.arpa.", addr.ip.v4.b[3] & netmask.ip.v4.b[3],
- addr.ip.v4.b[2] & netmask.ip.v4.b[2],
- addr.ip.v4.b[1] & netmask.ip.v4.b[1],
- addr.ip.v4.b[0] & netmask.ip.v4.b[0]);
- mDNS_AddSearchDomain_CString(buffer, mDNSNULL);
- }
- }
-
- ifa = ifa->ifa_next;
- }
-
- return;
-}
-
-
-//===========================================================================================================================
-// SetDNSServers
-//===========================================================================================================================
-
-mDNSlocal void
-SetDNSServers( mDNS *const m )
-{
- PIP_PER_ADAPTER_INFO pAdapterInfo = NULL;
- FIXED_INFO * fixedInfo = NULL;
- ULONG bufLen = 0;
- IP_ADDR_STRING * dnsServerList;
- IP_ADDR_STRING * ipAddr;
- DWORD index;
- int i = 0;
- mStatus err = kUnknownErr;
-
- // Get the primary interface.
-
- index = GetPrimaryInterface();
-
- // This should have the interface index of the primary index. Fall back in cases where
- // it can't be determined.
-
- if ( index )
- {
- bufLen = 0;
-
- for ( i = 0; i < 100; i++ )
- {
- err = GetPerAdapterInfo( index, pAdapterInfo, &bufLen );
-
- if ( err != ERROR_BUFFER_OVERFLOW )
- {
- break;
- }
-
- pAdapterInfo = (PIP_PER_ADAPTER_INFO) realloc( pAdapterInfo, bufLen );
- require_action( pAdapterInfo, exit, err = mStatus_NoMemoryErr );
- }
-
- require_noerr( err, exit );
-
- dnsServerList = &pAdapterInfo->DnsServerList;
- }
- else
- {
- bufLen = sizeof( FIXED_INFO );
-
- for ( i = 0; i < 100; i++ )
- {
- if ( fixedInfo )
- {
- GlobalFree( fixedInfo );
- fixedInfo = NULL;
- }
-
- fixedInfo = (FIXED_INFO*) GlobalAlloc( GPTR, bufLen );
- require_action( fixedInfo, exit, err = mStatus_NoMemoryErr );
-
- err = GetNetworkParams( fixedInfo, &bufLen );
-
- if ( err != ERROR_BUFFER_OVERFLOW )
- {
- break;
- }
- }
-
- require_noerr( err, exit );
-
- dnsServerList = &fixedInfo->DnsServerList;
- }
-
- for ( ipAddr = dnsServerList; ipAddr; ipAddr = ipAddr->Next )
- {
- mDNSAddr addr;
- err = StringToAddress( &addr, ipAddr->IpAddress.String );
- if ( !err ) mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, 0, &addr, UnicastDNSPort, kScopeNone, DEFAULT_UDNS_TIMEOUT, mDNSfalse, 0, mDNStrue, mDNStrue, mDNSfalse);
- }
-
-exit:
-
- if ( pAdapterInfo )
- {
- free( pAdapterInfo );
- }
-
- if ( fixedInfo )
- {
- GlobalFree( fixedInfo );
- }
-}
-
-
-//===========================================================================================================================
-// SetDomainFromDHCP
-//===========================================================================================================================
-
-mDNSlocal void
-SetDomainFromDHCP( void )
-{
- int i = 0;
- IP_ADAPTER_INFO * pAdapterInfo;
- IP_ADAPTER_INFO * pAdapter;
- DWORD bufLen;
- DWORD index;
- HKEY key = NULL;
- LPSTR domain = NULL;
- DWORD dwSize;
- mStatus err = mStatus_NoError;
-
- pAdapterInfo = NULL;
-
- for ( i = 0; i < 100; i++ )
- {
- err = GetAdaptersInfo( pAdapterInfo, &bufLen);
-
- if ( err != ERROR_BUFFER_OVERFLOW )
- {
- break;
- }
-
- pAdapterInfo = (IP_ADAPTER_INFO*) realloc( pAdapterInfo, bufLen );
- require_action( pAdapterInfo, exit, err = kNoMemoryErr );
- }
-
- require_noerr( err, exit );
-
- index = GetPrimaryInterface();
-
- for ( pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next )
- {
- if ( pAdapter->IpAddressList.IpAddress.String &&
- pAdapter->IpAddressList.IpAddress.String[0] &&
- pAdapter->GatewayList.IpAddress.String &&
- pAdapter->GatewayList.IpAddress.String[0] &&
- ( !index || ( pAdapter->Index == index ) ) )
- {
- // Found one that will work
-
- char keyName[1024];
-
- _snprintf( keyName, 1024, "%s%s", "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\", pAdapter->AdapterName );
-
- err = RegCreateKeyA( HKEY_LOCAL_MACHINE, keyName, &key );
- require_noerr( err, exit );
-
- err = RegQueryString( key, "Domain", &domain, &dwSize, NULL );
- check_noerr( err );
-
- if ( !domain || !domain[0] )
- {
- if ( domain )
- {
- free( domain );
- domain = NULL;
- }
-
- err = RegQueryString( key, "DhcpDomain", &domain, &dwSize, NULL );
- check_noerr( err );
- }
-
- if ( domain && domain[0] ) mDNS_AddSearchDomain_CString(domain, mDNSNULL);
-
- break;
- }
- }
-
-exit:
-
- if ( pAdapterInfo )
- {
- free( pAdapterInfo );
- }
-
- if ( domain )
- {
- free( domain );
- }
-
- if ( key )
- {
- RegCloseKey( key );
- }
-}
-
-
-//===========================================================================================================================
-// mDNSPlatformGetPrimaryInterface
-//===========================================================================================================================
-
-mDNSexport mStatus
-mDNSPlatformGetPrimaryInterface( mDNS * const m, mDNSAddr * v4, mDNSAddr * v6, mDNSAddr * router )
-{
- IP_ADAPTER_INFO * pAdapterInfo;
- IP_ADAPTER_INFO * pAdapter;
- DWORD bufLen;
- int i;
- BOOL found;
- DWORD index;
- mStatus err = mStatus_NoError;
-
- DEBUG_UNUSED( m );
-
- *v6 = zeroAddr;
-
- pAdapterInfo = NULL;
- bufLen = 0;
- found = FALSE;
-
- for ( i = 0; i < 100; i++ )
- {
- err = GetAdaptersInfo( pAdapterInfo, &bufLen);
-
- if ( err != ERROR_BUFFER_OVERFLOW )
- {
- break;
- }
-
- pAdapterInfo = (IP_ADAPTER_INFO*) realloc( pAdapterInfo, bufLen );
- require_action( pAdapterInfo, exit, err = kNoMemoryErr );
- }
-
- require_noerr( err, exit );
-
- index = GetPrimaryInterface();
-
- for ( pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next )
- {
- if ( pAdapter->IpAddressList.IpAddress.String &&
- pAdapter->IpAddressList.IpAddress.String[0] &&
- pAdapter->GatewayList.IpAddress.String &&
- pAdapter->GatewayList.IpAddress.String[0] &&
- ( StringToAddress( v4, pAdapter->IpAddressList.IpAddress.String ) == mStatus_NoError ) &&
- ( StringToAddress( router, pAdapter->GatewayList.IpAddress.String ) == mStatus_NoError ) &&
- ( !index || ( pAdapter->Index == index ) ) )
- {
- // Found one that will work
-
- if ( pAdapter->AddressLength == sizeof( m->PrimaryMAC ) )
- {
- memcpy( &m->PrimaryMAC, pAdapter->Address, pAdapter->AddressLength );
- }
-
- found = TRUE;
- break;
- }
- }
-
-exit:
-
- if ( pAdapterInfo )
- {
- free( pAdapterInfo );
- }
-
- return err;
-}
-
-mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win)
- {
- (void) sadd; // Unused
- (void) dadd; // Unused
- (void) lport; // Unused
- (void) rport; // Unused
- (void) seq; // Unused
- (void) ack; // Unused
- (void) win; // Unused
- }
-
-mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNSAddr *raddr, char *eth)
- {
- (void) raddr; // Unused
- (void) eth; // Unused
- }
-
-mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname)
- {
- (void) spsaddr; // Unused
- (void) ifname; // Unused
- }
-
-mDNSexport mStatus mDNSPlatformClearSPSMACAddr(void)
- {
- }
-
-mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNS *const m, mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
- {
- (void) m; // Unused
- (void) laddr; // Unused
- (void) raddr; // Unused
- (void) lport; // Unused
- (void) rport; // Unused
- (void) mti; // Unused
- }
-
-mDNSexport mDNSBool mDNSPlatformAllowPID(mDNS *const m, DNSQuestion *q)
- {
- (void) m;
- (void) q;
- return mDNStrue;
- }
-
-mDNSexport mDNSs32 mDNSPlatformGetServiceID(mDNS *const m, DNSQuestion *q)
- {
- (void) m;
- (void) q;
- return 0;
- }
-
-mDNSexport void mDNSPlatformSetDelegatePID(UDPSocket *src, const mDNSAddr *dst, DNSQuestion *q)
- {
- (void) src;
- (void) dst;
- (void) q;
- }
-
-mDNSexport mDNSs32 mDNSPlatformGetPID()
- {
- return 0;
- }
-
-mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
-{
- DEBUG_UNUSED( sock );
-
- return (mDNSu16)-1;
-}
-
-mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
-{
- DEBUG_UNUSED( InterfaceID );
-
- return mDNSfalse;
-}
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-// debugf_
-//===========================================================================================================================
-#if( MDNS_DEBUGMSGS )
-mDNSexport void debugf_( const char *inFormat, ... )
-{
- char buffer[ 512 ];
- va_list args;
- mDNSu32 length;
-
- va_start( args, inFormat );
- length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
- va_end( args );
-
- dlog( kDebugLevelInfo, "%s\n", buffer );
-}
-#endif
-
-//===========================================================================================================================
-// verbosedebugf_
-//===========================================================================================================================
-
-#if( MDNS_DEBUGMSGS > 1 )
-mDNSexport void verbosedebugf_( const char *inFormat, ... )
-{
- char buffer[ 512 ];
- va_list args;
- mDNSu32 length;
-
- va_start( args, inFormat );
- length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
- va_end( args );
-
- dlog( kDebugLevelVerbose, "%s\n", buffer );
-}
-#endif
-
-
-#if 0
-#pragma mark -
-#pragma mark == Platform Internals ==
-#endif
-
-
-//===========================================================================================================================
-// SetupNiceName
-//===========================================================================================================================
-
-mStatus SetupNiceName( mDNS * const inMDNS )
-{
- HKEY descKey = NULL;
- char utf8[ 256 ];
- LPCTSTR s;
- LPWSTR joinName;
- NETSETUP_JOIN_STATUS joinStatus;
- mStatus err = 0;
- DWORD namelen;
- BOOL ok;
-
- check( inMDNS );
-
- // Set up the nice name.
- utf8[0] = '\0';
-
- // First try and open the registry key that contains the computer description value
- s = TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters");
- err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, s, 0, KEY_READ, &descKey);
- check_translated_errno( err == 0, errno_compat(), kNameErr );
-
- if ( !err )
- {
- TCHAR desc[256];
- DWORD descSize = sizeof( desc );
-
- // look for the computer description
- err = RegQueryValueEx( descKey, TEXT("srvcomment"), 0, NULL, (LPBYTE) &desc, &descSize);
-
- if ( !err )
- {
- err = TCHARtoUTF8( desc, utf8, sizeof( utf8 ) );
- }
-
- if ( err )
- {
- utf8[ 0 ] = '\0';
- }
- }
-
- // if we can't find it in the registry, then use the hostname of the machine
- if ( err || ( utf8[ 0 ] == '\0' ) )
- {
- TCHAR hostname[256];
-
- namelen = sizeof( hostname ) / sizeof( TCHAR );
-
- ok = GetComputerNameExW( ComputerNamePhysicalDnsHostname, hostname, &namelen );
- err = translate_errno( ok, (mStatus) GetLastError(), kNameErr );
- check_noerr( err );
-
- if( !err )
- {
- err = TCHARtoUTF8( hostname, utf8, sizeof( utf8 ) );
- }
-
- if ( err )
- {
- utf8[ 0 ] = '\0';
- }
- }
-
- // if we can't get the hostname
- if ( err || ( utf8[ 0 ] == '\0' ) )
- {
- // Invalidate name so fall back to a default name.
-
- strcpy( utf8, kMDNSDefaultName );
- }
-
- utf8[ sizeof( utf8 ) - 1 ] = '\0';
- inMDNS->nicelabel.c[ 0 ] = (mDNSu8) (strlen( utf8 ) < MAX_DOMAIN_LABEL ? strlen( utf8 ) : MAX_DOMAIN_LABEL);
- memcpy( &inMDNS->nicelabel.c[ 1 ], utf8, inMDNS->nicelabel.c[ 0 ] );
-
- dlog( kDebugLevelInfo, DEBUG_NAME "nice name \"%.*s\"\n", inMDNS->nicelabel.c[ 0 ], &inMDNS->nicelabel.c[ 1 ] );
-
- if ( descKey )
- {
- RegCloseKey( descKey );
- }
-
- ZeroMemory( inMDNS->p->nbname, sizeof( inMDNS->p->nbname ) );
- ZeroMemory( inMDNS->p->nbdomain, sizeof( inMDNS->p->nbdomain ) );
-
- namelen = sizeof( inMDNS->p->nbname );
- ok = GetComputerNameExA( ComputerNamePhysicalNetBIOS, inMDNS->p->nbname, &namelen );
- check( ok );
- if ( ok ) dlog( kDebugLevelInfo, DEBUG_NAME "netbios name \"%s\"\n", inMDNS->p->nbname );
-
- err = NetGetJoinInformation( NULL, &joinName, &joinStatus );
- check ( err == NERR_Success );
- if ( err == NERR_Success )
- {
- if ( ( joinStatus == NetSetupWorkgroupName ) || ( joinStatus == NetSetupDomainName ) )
- {
- err = TCHARtoUTF8( joinName, inMDNS->p->nbdomain, sizeof( inMDNS->p->nbdomain ) );
- check( !err );
- if ( !err ) dlog( kDebugLevelInfo, DEBUG_NAME "netbios domain/workgroup \"%s\"\n", inMDNS->p->nbdomain );
- }
-
- NetApiBufferFree( joinName );
- joinName = NULL;
- }
-
- err = 0;
-
- return( err );
-}
-
-//===========================================================================================================================
-// SetupHostName
-//===========================================================================================================================
-
-mDNSlocal mStatus SetupHostName( mDNS * const inMDNS )
-{
- mStatus err = 0;
- char tempString[ 256 ];
- DWORD tempStringLen;
- domainlabel tempLabel;
- BOOL ok;
-
- check( inMDNS );
-
- // Set up the nice name.
- tempString[ 0 ] = '\0';
-
- // use the hostname of the machine
- tempStringLen = sizeof( tempString );
- ok = GetComputerNameExA( ComputerNamePhysicalDnsHostname, tempString, &tempStringLen );
- err = translate_errno( ok, (mStatus) GetLastError(), kNameErr );
- check_noerr( err );
-
- // if we can't get the hostname
- if( err || ( tempString[ 0 ] == '\0' ) )
- {
- // Invalidate name so fall back to a default name.
-
- strcpy( tempString, kMDNSDefaultName );
- }
-
- tempString[ sizeof( tempString ) - 1 ] = '\0';
- tempLabel.c[ 0 ] = (mDNSu8) (strlen( tempString ) < MAX_DOMAIN_LABEL ? strlen( tempString ) : MAX_DOMAIN_LABEL );
- memcpy( &tempLabel.c[ 1 ], tempString, tempLabel.c[ 0 ] );
-
- // Set up the host name.
-
- ConvertUTF8PstringToRFC1034HostLabel( tempLabel.c, &inMDNS->hostlabel );
- if( inMDNS->hostlabel.c[ 0 ] == 0 )
- {
- // Nice name has no characters that are representable as an RFC1034 name (e.g. Japanese) so use the default.
-
- MakeDomainLabelFromLiteralString( &inMDNS->hostlabel, kMDNSDefaultName );
- }
-
- check( inMDNS->hostlabel.c[ 0 ] != 0 );
-
- mDNS_SetFQDN( inMDNS );
-
- dlog( kDebugLevelInfo, DEBUG_NAME "host name \"%.*s\"\n", inMDNS->hostlabel.c[ 0 ], &inMDNS->hostlabel.c[ 1 ] );
-
- return( err );
-}
-
-//===========================================================================================================================
-// SetupName
-//===========================================================================================================================
-
-mDNSlocal mStatus SetupName( mDNS * const inMDNS )
-{
- mStatus err = 0;
-
- check( inMDNS );
-
- err = SetupNiceName( inMDNS );
- check_noerr( err );
-
- err = SetupHostName( inMDNS );
- check_noerr( err );
-
- return err;
-}
-
-
-//===========================================================================================================================
-// SetupInterfaceList
-//===========================================================================================================================
-
-mStatus SetupInterfaceList( mDNS * const inMDNS )
-{
- mStatus err;
- mDNSInterfaceData ** next;
- mDNSInterfaceData * ifd;
- struct ifaddrs * addrs;
- struct ifaddrs * p;
- struct ifaddrs * loopbackv4;
- struct ifaddrs * loopbackv6;
- u_int flagMask;
- u_int flagTest;
- mDNSBool foundv4;
- mDNSBool foundv6;
- mDNSBool foundUnicastSock4DestAddr;
- mDNSBool foundUnicastSock6DestAddr;
-
- dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface list\n" );
- check( inMDNS );
- check( inMDNS->p );
-
- inMDNS->p->registeredLoopback4 = mDNSfalse;
- inMDNS->p->nextDHCPLeaseExpires = 0x7FFFFFFF;
- addrs = NULL;
- foundv4 = mDNSfalse;
- foundv6 = mDNSfalse;
- foundUnicastSock4DestAddr = mDNSfalse;
- foundUnicastSock6DestAddr = mDNSfalse;
-
- // Tear down any existing interfaces that may be set up.
-
- TearDownInterfaceList( inMDNS );
-
- // Set up the name of this machine.
-
- err = SetupName( inMDNS );
- check_noerr( err );
-
- // Set up IPv4 interface(s). We have to set up IPv4 first so any IPv6 interface with an IPv4-routable address
- // can refer to the IPv4 interface when it registers to allow DNS AAAA records over the IPv4 interface.
-
- err = getifaddrs( &addrs );
- require_noerr( err, exit );
-
- loopbackv4 = NULL;
- loopbackv6 = NULL;
- next = &inMDNS->p->interfaceList;
-
- flagMask = IFF_UP | IFF_MULTICAST;
- flagTest = IFF_UP | IFF_MULTICAST;
-
-#if( MDNS_WINDOWS_ENABLE_IPV4 )
- for( p = addrs; p; p = p->ifa_next )
- {
- if( !p->ifa_addr || ( p->ifa_addr->sa_family != AF_INET ) || ( ( p->ifa_flags & flagMask ) != flagTest ) )
- {
- continue;
- }
- if( p->ifa_flags & IFF_LOOPBACK )
- {
- if( !loopbackv4 )
- {
- loopbackv4 = p;
- }
- continue;
- }
- dlog( kDebugLevelVerbose, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
- p->ifa_name ? p->ifa_name : "<null>", p->ifa_extra.index, p->ifa_addr );
-
- err = SetupInterface( inMDNS, p, &ifd );
- require_noerr( err, exit );
-
- // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
- // register him, but we also want to note that we haven't found a v4 interface
- // so that we register loopback so same host operations work
-
- if ( ifd->interfaceInfo.McastTxRx == mDNStrue )
- {
- foundv4 = mDNStrue;
- }
-
- if ( p->ifa_dhcpEnabled && ( p->ifa_dhcpLeaseExpires < inMDNS->p->nextDHCPLeaseExpires ) )
- {
- inMDNS->p->nextDHCPLeaseExpires = p->ifa_dhcpLeaseExpires;
- }
-
- // If we're on a platform that doesn't have WSARecvMsg(), there's no way
- // of determing the destination address of a packet that is sent to us.
- // For multicast packets, that's easy to determine. But for the unicast
- // sockets, we'll fake it by taking the address of the first interface
- // that is successfully setup.
-
- if ( !foundUnicastSock4DestAddr )
- {
- inMDNS->p->unicastSock4.addr = ifd->interfaceInfo.ip;
- foundUnicastSock4DestAddr = TRUE;
- }
-
- *next = ifd;
- next = &ifd->next;
- ++inMDNS->p->interfaceCount;
- }
-#endif
-
- // Set up IPv6 interface(s) after IPv4 is set up (see IPv4 notes above for reasoning).
-
-#if( MDNS_WINDOWS_ENABLE_IPV6 )
-
- if ( gEnableIPv6 )
- {
- for( p = addrs; p; p = p->ifa_next )
- {
- if( !p->ifa_addr || ( p->ifa_addr->sa_family != AF_INET6 ) || ( ( p->ifa_flags & flagMask ) != flagTest ) )
- {
- continue;
- }
- if( p->ifa_flags & IFF_LOOPBACK )
- {
- if( !loopbackv6 )
- {
- loopbackv6 = p;
- }
- continue;
- }
- dlog( kDebugLevelVerbose, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
- p->ifa_name ? p->ifa_name : "<null>", p->ifa_extra.index, p->ifa_addr );
-
- err = SetupInterface( inMDNS, p, &ifd );
- require_noerr( err, exit );
-
- // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
- // register him, but we also want to note that we haven't found a v4 interface
- // so that we register loopback so same host operations work
-
- if ( ifd->interfaceInfo.McastTxRx == mDNStrue )
- {
- foundv6 = mDNStrue;
- }
-
- // If we're on a platform that doesn't have WSARecvMsg(), there's no way
- // of determing the destination address of a packet that is sent to us.
- // For multicast packets, that's easy to determine. But for the unicast
- // sockets, we'll fake it by taking the address of the first interface
- // that is successfully setup.
-
- if ( !foundUnicastSock6DestAddr )
- {
- inMDNS->p->unicastSock6.addr = ifd->interfaceInfo.ip;
- foundUnicastSock6DestAddr = TRUE;
- }
-
- *next = ifd;
- next = &ifd->next;
- ++inMDNS->p->interfaceCount;
- }
- }
-
-#endif
-
- // If there are no real interfaces, but there is a loopback interface, use that so same-machine operations work.
-
-#if( !MDNS_WINDOWS_ENABLE_IPV4 && !MDNS_WINDOWS_ENABLE_IPV6 )
-
- flagMask |= IFF_LOOPBACK;
- flagTest |= IFF_LOOPBACK;
-
- for( p = addrs; p; p = p->ifa_next )
- {
- if( !p->ifa_addr || ( ( p->ifa_flags & flagMask ) != flagTest ) )
- {
- continue;
- }
- if( ( p->ifa_addr->sa_family != AF_INET ) && ( p->ifa_addr->sa_family != AF_INET6 ) )
- {
- continue;
- }
-
- v4loopback = p;
- break;
- }
-
-#endif
-
- if ( !foundv4 && loopbackv4 )
- {
- dlog( kDebugLevelInfo, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
- loopbackv4->ifa_name ? loopbackv4->ifa_name : "<null>", loopbackv4->ifa_extra.index, loopbackv4->ifa_addr );
-
- err = SetupInterface( inMDNS, loopbackv4, &ifd );
- require_noerr( err, exit );
-
- inMDNS->p->registeredLoopback4 = mDNStrue;
-
-#if( MDNS_WINDOWS_ENABLE_IPV4 )
-
- // If we're on a platform that doesn't have WSARecvMsg(), there's no way
- // of determing the destination address of a packet that is sent to us.
- // For multicast packets, that's easy to determine. But for the unicast
- // sockets, we'll fake it by taking the address of the first interface
- // that is successfully setup.
-
- if ( !foundUnicastSock4DestAddr )
- {
- inMDNS->p->unicastSock4.addr = ifd->sock.addr;
- foundUnicastSock4DestAddr = TRUE;
- }
-#endif
-
- *next = ifd;
- next = &ifd->next;
- ++inMDNS->p->interfaceCount;
- }
-
- if ( !foundv6 && loopbackv6 )
- {
- dlog( kDebugLevelInfo, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
- loopbackv6->ifa_name ? loopbackv6->ifa_name : "<null>", loopbackv6->ifa_extra.index, loopbackv6->ifa_addr );
-
- err = SetupInterface( inMDNS, loopbackv6, &ifd );
- require_noerr( err, exit );
-
-#if( MDNS_WINDOWS_ENABLE_IPV6 )
-
- if ( gEnableIPv6 )
- {
- // If we're on a platform that doesn't have WSARecvMsg(), there's no way
- // of determing the destination address of a packet that is sent to us.
- // For multicast packets, that's easy to determine. But for the unicast
- // sockets, we'll fake it by taking the address of the first interface
- // that is successfully setup.
-
- if ( !foundUnicastSock6DestAddr )
- {
- inMDNS->p->unicastSock6.addr = ifd->sock.addr;
- foundUnicastSock6DestAddr = TRUE;
- }
- }
-
-#endif
-
- *next = ifd;
- next = &ifd->next;
- ++inMDNS->p->interfaceCount;
- }
-
- CheckFileShares( inMDNS );
-
-exit:
- if( err )
- {
- TearDownInterfaceList( inMDNS );
- }
- if( addrs )
- {
- freeifaddrs( addrs );
- }
- dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface list done (err=%d %m)\n", err, err );
- return( err );
-}
-
-//===========================================================================================================================
-// TearDownInterfaceList
-//===========================================================================================================================
-
-mStatus TearDownInterfaceList( mDNS * const inMDNS )
-{
- mDNSInterfaceData ** p;
- mDNSInterfaceData * ifd;
-
- dlog( kDebugLevelTrace, DEBUG_NAME "tearing down interface list\n" );
- check( inMDNS );
- check( inMDNS->p );
-
- // Free any interfaces that were previously marked inactive and are no longer referenced by the mDNS cache.
- // Interfaces are marked inactive, but not deleted immediately if they were still referenced by the mDNS cache
- // so that remove events that occur after an interface goes away can still report the correct interface.
-
- p = &inMDNS->p->inactiveInterfaceList;
- while( *p )
- {
- ifd = *p;
- if( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) ifd ) > 0 )
- {
- p = &ifd->next;
- continue;
- }
-
- dlog( kDebugLevelInfo, DEBUG_NAME "freeing unreferenced, inactive interface %#p %#a\n", ifd, &ifd->interfaceInfo.ip );
- *p = ifd->next;
-
- QueueUserAPC( ( PAPCFUNC ) FreeInterface, inMDNS->p->mainThread, ( ULONG_PTR ) ifd );
- }
-
- // Tear down all the interfaces.
-
- while( inMDNS->p->interfaceList )
- {
- ifd = inMDNS->p->interfaceList;
- inMDNS->p->interfaceList = ifd->next;
-
- TearDownInterface( inMDNS, ifd );
- }
- inMDNS->p->interfaceCount = 0;
-
- dlog( kDebugLevelTrace, DEBUG_NAME "tearing down interface list done\n" );
- return( mStatus_NoError );
-}
-
-//===========================================================================================================================
-// SetupInterface
-//===========================================================================================================================
-
-mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inIFA, mDNSInterfaceData **outIFD )
-{
- mDNSInterfaceData * ifd;
- mDNSInterfaceData * p;
- mStatus err;
-
- ifd = NULL;
- dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface\n" );
- check( inMDNS );
- check( inMDNS->p );
- check( inIFA );
- check( inIFA->ifa_addr );
- check( outIFD );
-
- // Allocate memory for the interface and initialize it.
-
- ifd = (mDNSInterfaceData *) calloc( 1, sizeof( *ifd ) );
- require_action( ifd, exit, err = mStatus_NoMemoryErr );
- ifd->sock.fd = kInvalidSocketRef;
- ifd->sock.ifd = ifd;
- ifd->sock.next = NULL;
- ifd->sock.m = inMDNS;
- ifd->index = inIFA->ifa_extra.index;
- ifd->scopeID = inIFA->ifa_extra.index;
- check( strlen( inIFA->ifa_name ) < sizeof( ifd->name ) );
- strncpy( ifd->name, inIFA->ifa_name, sizeof( ifd->name ) - 1 );
- ifd->name[ sizeof( ifd->name ) - 1 ] = '\0';
-
- strncpy(ifd->interfaceInfo.ifname, inIFA->ifa_name, sizeof(ifd->interfaceInfo.ifname));
- ifd->interfaceInfo.ifname[sizeof(ifd->interfaceInfo.ifname)-1] = 0;
-
- // We always send and receive using IPv4, but to reduce traffic, we send and receive using IPv6 only on interfaces
- // that have no routable IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being
- // on a large configured network, which means there's a good chance that most or all the other devices on that
- // network should also have v4. By doing this we lose the ability to talk to true v6-only devices on that link,
- // but we cut the packet rate in half. At this time, reducing the packet rate is more important than v6-only
- // devices on a large configured network, so we are willing to make that sacrifice.
-
- ifd->interfaceInfo.McastTxRx = ( ( inIFA->ifa_flags & IFF_MULTICAST ) && !( inIFA->ifa_flags & IFF_POINTTOPOINT ) ) ? mDNStrue : mDNSfalse;
- ifd->interfaceInfo.InterfaceID = NULL;
-
- for( p = inMDNS->p->interfaceList; p; p = p->next )
- {
- if ( strcmp( p->name, ifd->name ) == 0 )
- {
- if (!ifd->interfaceInfo.InterfaceID)
- {
- ifd->interfaceInfo.InterfaceID = (mDNSInterfaceID) p;
- }
-
- if ( ( inIFA->ifa_addr->sa_family != AF_INET ) &&
- ( p->interfaceInfo.ip.type == mDNSAddrType_IPv4 ) &&
- ( p->interfaceInfo.ip.ip.v4.b[ 0 ] != 169 || p->interfaceInfo.ip.ip.v4.b[ 1 ] != 254 ) )
- {
- ifd->interfaceInfo.McastTxRx = mDNSfalse;
- }
-
- break;
- }
- }
-
- if ( !ifd->interfaceInfo.InterfaceID )
- {
- ifd->interfaceInfo.InterfaceID = (mDNSInterfaceID) ifd;
- }
-
- // Set up a socket for this interface (if needed).
-
- if( ifd->interfaceInfo.McastTxRx )
- {
- DWORD size;
-
- err = SetupSocket( inMDNS, inIFA->ifa_addr, MulticastDNSPort, &ifd->sock.fd );
- require_noerr( err, exit );
- ifd->sock.addr = ( inIFA->ifa_addr->sa_family == AF_INET6 ) ? AllDNSLinkGroup_v6 : AllDNSLinkGroup_v4;
- ifd->sock.port = MulticastDNSPort;
-
- // Get a ptr to the WSARecvMsg function, if supported. Otherwise, we'll fallback to recvfrom.
-
- err = WSAIoctl( ifd->sock.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &ifd->sock.recvMsgPtr, sizeof( ifd->sock.recvMsgPtr ), &size, NULL, NULL );
-
- if ( err )
- {
- ifd->sock.recvMsgPtr = NULL;
- }
- }
-
- if ( inIFA->ifa_dhcpEnabled && ( inIFA->ifa_dhcpLeaseExpires < inMDNS->p->nextDHCPLeaseExpires ) )
- {
- inMDNS->p->nextDHCPLeaseExpires = inIFA->ifa_dhcpLeaseExpires;
- }
-
- ifd->interfaceInfo.NetWake = inIFA->ifa_womp;
-
- // Register this interface with mDNS.
-
- err = SockAddrToMDNSAddr( inIFA->ifa_addr, &ifd->interfaceInfo.ip, NULL );
- require_noerr( err, exit );
-
- err = SockAddrToMDNSAddr( inIFA->ifa_netmask, &ifd->interfaceInfo.mask, NULL );
- require_noerr( err, exit );
-
- memcpy( ifd->interfaceInfo.MAC.b, inIFA->ifa_physaddr, sizeof( ifd->interfaceInfo.MAC.b ) );
-
- ifd->interfaceInfo.Advertise = ( mDNSu8 ) inMDNS->AdvertiseLocalAddresses;
-
- if ( ifd->sock.fd != kInvalidSocketRef )
- {
- err = mDNSPollRegisterSocket( ifd->sock.fd, FD_READ, UDPSocketNotification, &ifd->sock );
- require_noerr( err, exit );
- }
-
- // If interface is a direct link, address record will be marked as kDNSRecordTypeKnownUnique
- // and skip the probe phase of the probe/announce packet sequence.
- ifd->interfaceInfo.DirectLink = mDNSfalse;
-
- err = mDNS_RegisterInterface( inMDNS, &ifd->interfaceInfo, mDNSfalse );
- require_noerr( err, exit );
- ifd->hostRegistered = mDNStrue;
-
- dlog( kDebugLevelInfo, DEBUG_NAME "Registered interface %##a with mDNS\n", inIFA->ifa_addr );
-
- // Success!
-
- *outIFD = ifd;
- ifd = NULL;
-
-exit:
-
- if( ifd )
- {
- TearDownInterface( inMDNS, ifd );
- }
- dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface done (err=%d %m)\n", err, err );
- return( err );
-}
-
-//===========================================================================================================================
-// TearDownInterface
-//===========================================================================================================================
-
-mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD )
-{
- check( inMDNS );
- check( inIFD );
-
- // Deregister this interface with mDNS.
-
- dlog( kDebugLevelInfo, DEBUG_NAME "Deregistering interface %#a with mDNS\n", &inIFD->interfaceInfo.ip );
-
- if( inIFD->hostRegistered )
- {
- inIFD->hostRegistered = mDNSfalse;
- mDNS_DeregisterInterface( inMDNS, &inIFD->interfaceInfo, mDNSfalse );
- }
-
- // Tear down the multicast socket.
-
- UDPCloseSocket( &inIFD->sock );
-
- // If the interface is still referenced by items in the mDNS cache then put it on the inactive list. This keeps
- // the InterfaceID valid so remove events report the correct interface. If it is no longer referenced, free it.
-
- if( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) inIFD ) > 0 )
- {
- inIFD->next = inMDNS->p->inactiveInterfaceList;
- inMDNS->p->inactiveInterfaceList = inIFD;
- dlog( kDebugLevelInfo, DEBUG_NAME "deferring free of interface %#p %#a\n", inIFD, &inIFD->interfaceInfo.ip );
- }
- else
- {
- dlog( kDebugLevelInfo, DEBUG_NAME "freeing interface %#p %#a immediately\n", inIFD, &inIFD->interfaceInfo.ip );
- QueueUserAPC( ( PAPCFUNC ) FreeInterface, inMDNS->p->mainThread, ( ULONG_PTR ) inIFD );
- }
-
- return( mStatus_NoError );
-}
-
-mDNSlocal void CALLBACK FreeInterface( mDNSInterfaceData *inIFD )
-{
- free( inIFD );
-}
-
-//===========================================================================================================================
-// SetupSocket
-//===========================================================================================================================
-
-mDNSlocal mStatus SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, mDNSIPPort port, SocketRef *outSocketRef )
-{
- mStatus err;
- SocketRef sock;
- int option;
- DWORD bytesReturned = 0;
- BOOL behavior = FALSE;
-
- DEBUG_UNUSED( inMDNS );
-
- dlog( kDebugLevelTrace, DEBUG_NAME "setting up socket %##a\n", inAddr );
- check( inMDNS );
- check( outSocketRef );
-
- // Set up an IPv4 or IPv6 UDP socket.
-
- sock = socket( inAddr->sa_family, SOCK_DGRAM, IPPROTO_UDP );
- err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
- require_noerr( err, exit );
-
- // Turn on reuse address option so multiple servers can listen for Multicast DNS packets,
- // if we're creating a multicast socket
-
- if ( !mDNSIPPortIsZero( port ) )
- {
- option = 1;
- err = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (char *) &option, sizeof( option ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
- }
-
- // <rdar://problem/7894393> Bonjour for Windows broken on Windows XP
- //
- // Not sure why, but the default behavior for sockets is to behave incorrectly
- // when using them in Overlapped I/O mode on XP. According to MSDN:
- //
- // SIO_UDP_CONNRESET (opcode setting: I, T==3)
- // Windows XP: Controls whether UDP PORT_UNREACHABLE messages are reported. Set to TRUE to enable reporting.
- // Set to FALSE to disable reporting.
- //
- // Packet traces from misbehaving Bonjour installations showed that ICMP port unreachable
- // messages were being sent to us after we sent out packets to a multicast address. This is clearly
- // incorrect behavior, but should be harmless. However, after receiving a port unreachable error, WinSock
- // will no longer receive any packets from that socket, which is not harmless. This behavior is only
- // seen on XP.
- //
- // So we turn off port unreachable reporting to make sure our sockets that are reading
- // multicast packets function correctly under all circumstances.
-
- err = WSAIoctl( sock, SIO_UDP_CONNRESET, &behavior, sizeof(behavior), NULL, 0, &bytesReturned, NULL, NULL );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- if( inAddr->sa_family == AF_INET )
- {
- mDNSv4Addr ipv4;
- struct sockaddr_in sa4;
- struct ip_mreq mreqv4;
-
- // Bind the socket to the desired port
-
- ipv4.NotAnInteger = ( (const struct sockaddr_in *) inAddr )->sin_addr.s_addr;
- mDNSPlatformMemZero( &sa4, sizeof( sa4 ) );
- sa4.sin_family = AF_INET;
- sa4.sin_port = port.NotAnInteger;
- sa4.sin_addr.s_addr = ipv4.NotAnInteger;
-
- err = bind( sock, (struct sockaddr *) &sa4, sizeof( sa4 ) );
- check_translated_errno( err == 0, errno_compat(), kUnknownErr );
-
- // Turn on option to receive destination addresses and receiving interface.
-
- option = 1;
- err = setsockopt( sock, IPPROTO_IP, IP_PKTINFO, (char *) &option, sizeof( option ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- if ( !mDNSIPPortIsZero( port ) )
- {
- // Join the all-DNS multicast group so we receive Multicast DNS packets
-
- mreqv4.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
- mreqv4.imr_interface.s_addr = ipv4.NotAnInteger;
- err = setsockopt( sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreqv4, sizeof( mreqv4 ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- // Specify the interface to send multicast packets on this socket.
-
- sa4.sin_addr.s_addr = ipv4.NotAnInteger;
- err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_IF, (char *) &sa4.sin_addr, sizeof( sa4.sin_addr ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
-
- option = 1;
- err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &option, sizeof( option ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
- }
-
- // Send unicast packets with TTL 255 (helps against spoofing).
-
- option = 255;
- err = setsockopt( sock, IPPROTO_IP, IP_TTL, (char *) &option, sizeof( option ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- // Send multicast packets with TTL 255 (helps against spoofing).
-
- option = 255;
- err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &option, sizeof( option ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- }
- else if( inAddr->sa_family == AF_INET6 )
- {
- struct sockaddr_in6 * sa6p;
- struct sockaddr_in6 sa6;
- struct ipv6_mreq mreqv6;
-
- sa6p = (struct sockaddr_in6 *) inAddr;
-
- // Bind the socket to the desired port
-
- mDNSPlatformMemZero( &sa6, sizeof( sa6 ) );
- sa6.sin6_family = AF_INET6;
- sa6.sin6_port = port.NotAnInteger;
- sa6.sin6_flowinfo = 0;
- sa6.sin6_addr = sa6p->sin6_addr;
- sa6.sin6_scope_id = sa6p->sin6_scope_id;
-
- err = bind( sock, (struct sockaddr *) &sa6, sizeof( sa6 ) );
- check_translated_errno( err == 0, errno_compat(), kUnknownErr );
-
- // Turn on option to receive destination addresses and receiving interface.
-
- option = 1;
- err = setsockopt( sock, IPPROTO_IPV6, IPV6_PKTINFO, (char *) &option, sizeof( option ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- // We only want to receive IPv6 packets (not IPv4-mapped IPv6 addresses) because we have a separate socket
- // for IPv4, but the IPv6 stack in Windows currently doesn't support IPv4-mapped IPv6 addresses and doesn't
- // support the IPV6_V6ONLY socket option so the following code would typically not be executed (or needed).
-
- #if( defined( IPV6_V6ONLY ) )
- option = 1;
- err = setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &option, sizeof( option ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
- #endif
-
- if ( !mDNSIPPortIsZero( port ) )
- {
- // Join the all-DNS multicast group so we receive Multicast DNS packets.
-
- mreqv6.ipv6mr_multiaddr = *( (struct in6_addr *) &AllDNSLinkGroup_v6.ip.v6 );
- mreqv6.ipv6mr_interface = sa6p->sin6_scope_id;
- err = setsockopt( sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &mreqv6, sizeof( mreqv6 ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- // Specify the interface to send multicast packets on this socket.
-
- option = (int) sa6p->sin6_scope_id;
- err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &option, sizeof( option ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
-
- option = 1;
- err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &option, sizeof( option ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
- }
-
- // Send unicast packets with TTL 255 (helps against spoofing).
-
- option = 255;
- err = setsockopt( sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *) &option, sizeof( option ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- // Send multicast packets with TTL 255 (helps against spoofing).
-
- option = 255;
- err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &option, sizeof( option ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
- }
- else
- {
- dlog( kDebugLevelError, DEBUG_NAME "%s: unsupport socket family (%d)\n", __ROUTINE__, inAddr->sa_family );
- err = kUnsupportedErr;
- goto exit;
- }
-
- // Success!
-
- *outSocketRef = sock;
- sock = kInvalidSocketRef;
- err = mStatus_NoError;
-
-exit:
- if( IsValidSocket( sock ) )
- {
- close_compat( sock );
- }
- return( err );
-}
-
-//===========================================================================================================================
-// SetupSocket
-//===========================================================================================================================
-
-mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort )
-{
- mStatus err;
-
- check( inSA );
- check( outIP );
-
- if( inSA->sa_family == AF_INET )
- {
- struct sockaddr_in * sa4;
-
- sa4 = (struct sockaddr_in *) inSA;
- outIP->type = mDNSAddrType_IPv4;
- outIP->ip.v4.NotAnInteger = sa4->sin_addr.s_addr;
- if( outPort )
- {
- outPort->NotAnInteger = sa4->sin_port;
- }
- err = mStatus_NoError;
- }
- else if( inSA->sa_family == AF_INET6 )
- {
- struct sockaddr_in6 * sa6;
-
- sa6 = (struct sockaddr_in6 *) inSA;
- outIP->type = mDNSAddrType_IPv6;
- outIP->ip.v6 = *( (mDNSv6Addr *) &sa6->sin6_addr );
- if( IN6_IS_ADDR_LINKLOCAL( &sa6->sin6_addr ) )
- {
- outIP->ip.v6.w[ 1 ] = 0;
- }
- if( outPort )
- {
- outPort->NotAnInteger = sa6->sin6_port;
- }
- err = mStatus_NoError;
- }
- else
- {
- dlog( kDebugLevelError, DEBUG_NAME "%s: invalid sa_family %d", __ROUTINE__, inSA->sa_family );
- err = mStatus_BadParamErr;
- }
- return( err );
-}
-
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-// UDPSocketNotification
-//===========================================================================================================================
-
-mDNSlocal void CALLBACK
-UDPSocketNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context )
-{
- UDPSocket *udpSock = ( UDPSocket* ) context;
- WSAMSG wmsg;
- WSABUF wbuf;
- struct sockaddr_storage sockSrcAddr; // This is filled in by the WSARecv* function
- INT sockSrcAddrLen; // See above
- mDNSAddr srcAddr;
- mDNSInterfaceID iid;
- mDNSIPPort srcPort;
- mDNSAddr dstAddr;
- mDNSIPPort dstPort;
- uint8_t controlBuffer[ 128 ];
- mDNSu8 * end;
- int num;
- DWORD numTries;
- mStatus err;
-
- DEBUG_UNUSED( sock );
- DEBUG_UNUSED( event );
-
- require_action( udpSock != NULL, exit, err = mStatus_BadStateErr );
-
- dlog( kDebugLevelChatty, DEBUG_NAME "%s: sock = %d\n", __ROUTINE__, udpSock->fd );
-
- // Initialize the buffer structure
-
- wbuf.buf = (char *) &udpSock->packet;
- wbuf.len = (u_long) sizeof( udpSock->packet );
- sockSrcAddrLen = sizeof( sockSrcAddr );
-
- numTries = 0;
-
- do
- {
- if ( udpSock->recvMsgPtr )
- {
- DWORD size;
-
- wmsg.name = ( LPSOCKADDR ) &sockSrcAddr;
- wmsg.namelen = sockSrcAddrLen;
- wmsg.lpBuffers = &wbuf;
- wmsg.dwBufferCount = 1;
- wmsg.Control.buf = ( CHAR* ) controlBuffer;
- wmsg.Control.len = sizeof( controlBuffer );
- wmsg.dwFlags = 0;
-
- err = udpSock->recvMsgPtr( udpSock->fd, &wmsg, &size, NULL, NULL );
- err = translate_errno( ( err == 0 ), (OSStatus) WSAGetLastError(), kUnknownErr );
- num = ( int ) size;
-
- // <rdar://problem/7824093> iTunes 9.1 fails to install with Bonjour service on Windows 7 Ultimate
- //
- // There seems to be a bug in some network device drivers that involves calling WSARecvMsg().
- // Although all the parameters to WSARecvMsg() are correct, it returns a
- // WSAEFAULT error code when there is no actual error. We have found experientially that falling
- // back to using WSARecvFrom() when this happens will work correctly.
-
- if ( err == WSAEFAULT ) udpSock->recvMsgPtr = NULL;
- }
- else
- {
- DWORD flags = 0;
-
- num = WSARecvFrom( udpSock->fd, &wbuf, 1, NULL, &flags, ( LPSOCKADDR ) &sockSrcAddr, &sockSrcAddrLen, NULL, NULL );
- err = translate_errno( ( num >= 0 ), ( OSStatus ) WSAGetLastError(), kUnknownErr );
- }
-
- // According to MSDN <http://msdn.microsoft.com/en-us/library/ms741687(VS.85).aspx>:
- //
- // "WSAECONNRESET: For a UDP datagram socket, this error would indicate that a previous
- // send operation resulted in an ICMP "Port Unreachable" message."
- //
- // Because this is the case, we want to ignore this error and try again. Just in case
- // this is some kind of pathological condition, we'll break out of the retry loop
- // after 100 iterations
-
- require_action( !err || ( err == WSAECONNRESET ) || ( err == WSAEFAULT ), exit, err = WSAGetLastError() );
- }
- while ( ( ( err == WSAECONNRESET ) || ( err == WSAEFAULT ) ) && ( numTries++ < 100 ) );
-
- require_noerr( err, exit );
-
- // Translate the source of this packet into mDNS data types
-
- SockAddrToMDNSAddr( (struct sockaddr* ) &sockSrcAddr, &srcAddr, &srcPort );
-
- // Initialize the destination of this packet. Just in case
- // we can't determine this info because we couldn't call
- // WSARecvMsg (recvMsgPtr)
-
- dstAddr = udpSock->addr;
- dstPort = udpSock->port;
-
- if ( udpSock->recvMsgPtr )
- {
- LPWSACMSGHDR header;
- LPWSACMSGHDR last = NULL;
- int count = 0;
-
- // Parse the control information. Reject packets received on the wrong interface.
-
- // <rdar://problem/7832196> INSTALL: Bonjour 2.0 on Windows can not start / stop
- //
- // There seems to be an interaction between Bullguard and this next bit of code.
- // When a user's machine is running Bullguard, the control information that is
- // returned is corrupted, and the code would go into an infinite loop. We'll add
- // two bits of defensive coding here. The first will check that each pointer to
- // the LPWSACMSGHDR that is returned in the for loop is different than the last.
- // This fixes the problem with Bullguard. The second will break out of this loop
- // after 100 iterations, just in case the corruption isn't caught by the first
- // check.
-
- for ( header = WSA_CMSG_FIRSTHDR( &wmsg ); header; header = WSA_CMSG_NXTHDR( &wmsg, header ) )
- {
- if ( ( header != last ) && ( ++count < 100 ) )
- {
- last = header;
-
- if ( ( header->cmsg_level == IPPROTO_IP ) && ( header->cmsg_type == IP_PKTINFO ) )
- {
- IN_PKTINFO * ipv4PacketInfo;
-
- ipv4PacketInfo = (IN_PKTINFO *) WSA_CMSG_DATA( header );
-
- if ( udpSock->ifd != NULL )
- {
- require_action( ipv4PacketInfo->ipi_ifindex == udpSock->ifd->index, exit, err = ( DWORD ) kMismatchErr );
- }
-
- dstAddr.type = mDNSAddrType_IPv4;
- dstAddr.ip.v4.NotAnInteger = ipv4PacketInfo->ipi_addr.s_addr;
- }
- else if( ( header->cmsg_level == IPPROTO_IPV6 ) && ( header->cmsg_type == IPV6_PKTINFO ) )
- {
- IN6_PKTINFO * ipv6PacketInfo;
-
- ipv6PacketInfo = (IN6_PKTINFO *) WSA_CMSG_DATA( header );
-
- if ( udpSock->ifd != NULL )
- {
- require_action( ipv6PacketInfo->ipi6_ifindex == ( udpSock->ifd->index - kIPv6IfIndexBase ), exit, err = ( DWORD ) kMismatchErr );
- }
-
- dstAddr.type = mDNSAddrType_IPv6;
- dstAddr.ip.v6 = *( (mDNSv6Addr *) &ipv6PacketInfo->ipi6_addr );
- }
- }
- else
- {
- static BOOL loggedMessage = FALSE;
-
- if ( !loggedMessage )
- {
- LogMsg( "UDPEndRecv: WSARecvMsg control information error." );
- loggedMessage = TRUE;
- }
-
- break;
- }
- }
- }
-
- dlog( kDebugLevelChatty, DEBUG_NAME "packet received\n" );
- dlog( kDebugLevelChatty, DEBUG_NAME " size = %d\n", num );
- dlog( kDebugLevelChatty, DEBUG_NAME " src = %#a:%u\n", &srcAddr, ntohs( srcPort.NotAnInteger ) );
- dlog( kDebugLevelChatty, DEBUG_NAME " dst = %#a:%u\n", &dstAddr, ntohs( dstPort.NotAnInteger ) );
-
- if ( udpSock->ifd != NULL )
- {
- dlog( kDebugLevelChatty, DEBUG_NAME " interface = %#a (index=0x%08X)\n", &udpSock->ifd->interfaceInfo.ip, udpSock->ifd->index );
- }
-
- dlog( kDebugLevelChatty, DEBUG_NAME "\n" );
-
- iid = udpSock->ifd ? udpSock->ifd->interfaceInfo.InterfaceID : NULL;
- end = ( (mDNSu8 *) &udpSock->packet ) + num;
-
- mDNSCoreReceive( udpSock->m, &udpSock->packet, end, &srcAddr, srcPort, &dstAddr, dstPort, iid );
-
-exit:
-
- return;
-}
-
-
-//===========================================================================================================================
-// InterfaceListDidChange
-//===========================================================================================================================
-void InterfaceListDidChange( mDNS * const inMDNS )
-{
- mStatus err;
-
- dlog( kDebugLevelInfo, DEBUG_NAME "interface list changed\n" );
- check( inMDNS );
-
- // Tear down the existing interfaces and set up new ones using the new IP info.
-
- err = TearDownInterfaceList( inMDNS );
- check_noerr( err );
-
- err = SetupInterfaceList( inMDNS );
- check_noerr( err );
-
- err = uDNS_SetupDNSConfig( inMDNS );
- check_noerr( err );
-
- // Inform clients of the change.
-
- mDNS_ConfigChanged(inMDNS);
-
- // Force mDNS to update.
-
- mDNSCoreMachineSleep( inMDNS, mDNSfalse ); // What is this for? Mac OS X does not do this
-}
-
-
-//===========================================================================================================================
-// ComputerDescriptionDidChange
-//===========================================================================================================================
-void ComputerDescriptionDidChange( mDNS * const inMDNS )
-{
- dlog( kDebugLevelInfo, DEBUG_NAME "computer description has changed\n" );
- check( inMDNS );
-
- // redo the names
- SetupNiceName( inMDNS );
-}
-
-
-//===========================================================================================================================
-// TCPIPConfigDidChange
-//===========================================================================================================================
-void TCPIPConfigDidChange( mDNS * const inMDNS )
-{
- mStatus err;
-
- dlog( kDebugLevelInfo, DEBUG_NAME "TCP/IP config has changed\n" );
- check( inMDNS );
-
- err = uDNS_SetupDNSConfig( inMDNS );
- check_noerr( err );
-}
-
-
-//===========================================================================================================================
-// DynDNSConfigDidChange
-//===========================================================================================================================
-void DynDNSConfigDidChange( mDNS * const inMDNS )
-{
- mStatus err;
-
- dlog( kDebugLevelInfo, DEBUG_NAME "DynDNS config has changed\n" );
- check( inMDNS );
-
- SetDomainSecrets( inMDNS );
-
- err = uDNS_SetupDNSConfig( inMDNS );
- check_noerr( err );
-}
-
-
-//===========================================================================================================================
-// FileSharingDidChange
-//===========================================================================================================================
-void FileSharingDidChange( mDNS * const inMDNS )
-{
- dlog( kDebugLevelInfo, DEBUG_NAME "File shares has changed\n" );
- check( inMDNS );
-
- CheckFileShares( inMDNS );
-}
-
-
-//===========================================================================================================================
-// FilewallDidChange
-//===========================================================================================================================
-void FirewallDidChange( mDNS * const inMDNS )
-{
- dlog( kDebugLevelInfo, DEBUG_NAME "Firewall has changed\n" );
- check( inMDNS );
-
- CheckFileShares( inMDNS );
-}
-
-
-#if 0
-#pragma mark -
-#pragma mark == Utilities ==
-#endif
-
-//===========================================================================================================================
-// getifaddrs
-//===========================================================================================================================
-
-mDNSlocal int getifaddrs( struct ifaddrs **outAddrs )
-{
- int err;
-
-#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
-
- // Try to the load the GetAdaptersAddresses function from the IP Helpers DLL. This API is only available on Windows
- // XP or later. Looking up the symbol at runtime allows the code to still work on older systems without that API.
-
- if( !gIPHelperLibraryInstance )
- {
- gIPHelperLibraryInstance = LoadLibrary( TEXT( "Iphlpapi" ) );
- if( gIPHelperLibraryInstance )
- {
- gGetAdaptersAddressesFunctionPtr =
- (GetAdaptersAddressesFunctionPtr) GetProcAddress( gIPHelperLibraryInstance, "GetAdaptersAddresses" );
- if( !gGetAdaptersAddressesFunctionPtr )
- {
- BOOL ok;
-
- ok = FreeLibrary( gIPHelperLibraryInstance );
- check_translated_errno( ok, GetLastError(), kUnknownErr );
- gIPHelperLibraryInstance = NULL;
- }
- }
- }
-
- // Use the new IPv6-capable routine if supported. Otherwise, fall back to the old and compatible IPv4-only code.
- // <rdar://problem/4278934> Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 fails
- // <rdar://problem/6145913> Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 returns no addrs
-
- if( !gGetAdaptersAddressesFunctionPtr || ( ( ( err = getifaddrs_ipv6( outAddrs ) ) != mStatus_NoError ) || ( ( outAddrs != NULL ) && ( *outAddrs == NULL ) ) ) )
- {
- err = getifaddrs_ipv4( outAddrs );
- require_noerr( err, exit );
- }
-
-#else
-
- err = getifaddrs_ipv4( outAddrs );
- require_noerr( err, exit );
-
-#endif
-
-exit:
- return( err );
-}
-
-#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
-//===========================================================================================================================
-// getifaddrs_ipv6
-//===========================================================================================================================
-
-mDNSlocal int getifaddrs_ipv6( struct ifaddrs **outAddrs )
-{
- DWORD err;
- int i;
- DWORD flags;
- struct ifaddrs * head;
- struct ifaddrs ** next;
- IP_ADAPTER_ADDRESSES * iaaList;
- ULONG iaaListSize;
- IP_ADAPTER_ADDRESSES * iaa;
- size_t size;
- struct ifaddrs * ifa;
-
- check( gGetAdaptersAddressesFunctionPtr );
-
- head = NULL;
- next = &head;
- iaaList = NULL;
-
- // Get the list of interfaces. The first call gets the size and the second call gets the actual data.
- // This loops to handle the case where the interface changes in the window after getting the size, but before the
- // second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
-
- flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
- i = 0;
- for( ;; )
- {
- iaaListSize = 0;
- err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, NULL, &iaaListSize );
- check( err == ERROR_BUFFER_OVERFLOW );
- check( iaaListSize >= sizeof( IP_ADAPTER_ADDRESSES ) );
-
- iaaList = (IP_ADAPTER_ADDRESSES *) malloc( iaaListSize );
- require_action( iaaList, exit, err = ERROR_NOT_ENOUGH_MEMORY );
-
- err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, iaaList, &iaaListSize );
- if( err == ERROR_SUCCESS ) break;
-
- free( iaaList );
- iaaList = NULL;
- ++i;
- require( i < 100, exit );
- dlog( kDebugLevelWarning, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__, i, err, err );
- }
-
- for( iaa = iaaList; iaa; iaa = iaa->Next )
- {
- int addrIndex;
- IP_ADAPTER_UNICAST_ADDRESS * addr;
- DWORD ipv6IfIndex;
- IP_ADAPTER_PREFIX * firstPrefix;
-
- if( iaa->IfIndex > 0xFFFFFF )
- {
- dlog( kDebugLevelAlert, DEBUG_NAME "%s: IPv4 ifindex out-of-range (0x%08X)\n", __ROUTINE__, iaa->IfIndex );
- }
- if( iaa->Ipv6IfIndex > 0xFF )
- {
- dlog( kDebugLevelAlert, DEBUG_NAME "%s: IPv6 ifindex out-of-range (0x%08X)\n", __ROUTINE__, iaa->Ipv6IfIndex );
- }
-
- // For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the
- // following code to crash when iterating through the prefix list. This seems
- // to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
- // This shouldn't happen according to Microsoft docs which states:
- //
- // "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
- //
- // So the data structure seems to be corrupted when we return from
- // GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
- // sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
- // modify iaa to have the correct values.
-
- if ( iaa->Length >= sizeof( IP_ADAPTER_ADDRESSES ) )
- {
- ipv6IfIndex = iaa->Ipv6IfIndex;
- firstPrefix = iaa->FirstPrefix;
- }
- else
- {
- ipv6IfIndex = 0;
- firstPrefix = NULL;
- }
-
- // Skip pseudo and tunnel interfaces.
-
- if( ( ( ipv6IfIndex == 1 ) && ( iaa->IfType != IF_TYPE_SOFTWARE_LOOPBACK ) ) || ( iaa->IfType == IF_TYPE_TUNNEL ) )
- {
- continue;
- }
-
- // Add each address as a separate interface to emulate the way getifaddrs works.
-
- for( addrIndex = 0, addr = iaa->FirstUnicastAddress; addr; ++addrIndex, addr = addr->Next )
- {
- int family;
- IP_ADAPTER_PREFIX * prefix;
- uint32_t ipv4Index;
- struct sockaddr_in ipv4Netmask;
-
- family = addr->Address.lpSockaddr->sa_family;
- if( ( family != AF_INET ) && ( family != AF_INET6 ) ) continue;
-
- // <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
- // Seems as if the problem here is a buggy implementation of some network interface
- // driver. It is reporting that is has a link-local address when it is actually
- // disconnected. This was causing a problem in AddressToIndexAndMask.
- // The solution is to call AddressToIndexAndMask first, and if unable to lookup
- // the address, to ignore that address.
-
- ipv4Index = 0;
- memset( &ipv4Netmask, 0, sizeof( ipv4Netmask ) );
-
- if ( family == AF_INET )
- {
- err = AddressToIndexAndMask( addr->Address.lpSockaddr, &ipv4Index, ( struct sockaddr* ) &ipv4Netmask );
-
- if ( err )
- {
- err = 0;
- continue;
- }
- }
-
- ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
- require_action( ifa, exit, err = WSAENOBUFS );
-
- *next = ifa;
- next = &ifa->ifa_next;
-
- // Get the name.
-
- size = strlen( iaa->AdapterName ) + 1;
- ifa->ifa_name = (char *) malloc( size );
- require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
- memcpy( ifa->ifa_name, iaa->AdapterName, size );
-
- // Get interface flags.
-
- ifa->ifa_flags = 0;
- if( iaa->OperStatus == IfOperStatusUp ) ifa->ifa_flags |= IFF_UP;
- if( iaa->IfType == IF_TYPE_SOFTWARE_LOOPBACK ) ifa->ifa_flags |= IFF_LOOPBACK;
- else if ( IsPointToPoint( addr ) ) ifa->ifa_flags |= IFF_POINTTOPOINT;
- if( !( iaa->Flags & IP_ADAPTER_NO_MULTICAST ) ) ifa->ifa_flags |= IFF_MULTICAST;
-
-
- // <rdar://problem/4045657> Interface index being returned is 512
- //
- // Windows does not have a uniform scheme for IPv4 and IPv6 interface indexes.
- // This code used to shift the IPv4 index up to ensure uniqueness between
- // it and IPv6 indexes. Although this worked, it was somewhat confusing to developers, who
- // then see interface indexes passed back that don't correspond to anything
- // that is seen in Win32 APIs or command line tools like "route". As a relatively
- // small percentage of developers are actively using IPv6, it seems to
- // make sense to make our use of IPv4 as confusion free as possible.
- // So now, IPv6 interface indexes will be shifted up by a
- // constant value which will serve to uniquely identify them, and we will
- // leave IPv4 interface indexes unmodified.
-
- switch( family )
- {
- case AF_INET: ifa->ifa_extra.index = iaa->IfIndex; break;
- case AF_INET6: ifa->ifa_extra.index = ipv6IfIndex + kIPv6IfIndexBase; break;
- default: break;
- }
-
- // Get lease lifetime
-
- if ( ( iaa->IfType != IF_TYPE_SOFTWARE_LOOPBACK ) && ( addr->LeaseLifetime != 0 ) && ( addr->ValidLifetime != 0xFFFFFFFF ) )
- {
- ifa->ifa_dhcpEnabled = TRUE;
- ifa->ifa_dhcpLeaseExpires = time( NULL ) + addr->ValidLifetime;
- }
- else
- {
- ifa->ifa_dhcpEnabled = FALSE;
- ifa->ifa_dhcpLeaseExpires = 0;
- }
-
- if ( iaa->PhysicalAddressLength == sizeof( ifa->ifa_physaddr ) )
- {
- memcpy( ifa->ifa_physaddr, iaa->PhysicalAddress, iaa->PhysicalAddressLength );
- }
-
- // Because we don't get notified of womp changes, we're going to just assume
- // that all wired interfaces have it enabled. Before we go to sleep, we'll check
- // if the interface actually supports it, and update mDNS->SystemWakeOnLANEnabled
- // accordingly
-
- ifa->ifa_womp = ( iaa->IfType == IF_TYPE_ETHERNET_CSMACD ) ? mDNStrue : mDNSfalse;
-
- // Get address.
-
- switch( family )
- {
- case AF_INET:
- case AF_INET6:
- ifa->ifa_addr = (struct sockaddr *) calloc( 1, (size_t) addr->Address.iSockaddrLength );
- require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
- memcpy( ifa->ifa_addr, addr->Address.lpSockaddr, (size_t) addr->Address.iSockaddrLength );
- break;
-
- default:
- break;
- }
- check( ifa->ifa_addr );
-
- // Get subnet mask (IPv4)/link prefix (IPv6). It is specified as a bit length (e.g. 24 for 255.255.255.0).
-
- switch ( family )
- {
- case AF_INET:
- {
- struct sockaddr_in * sa4;
-
- sa4 = (struct sockaddr_in *) calloc( 1, sizeof( *sa4 ) );
- require_action( sa4, exit, err = WSAENOBUFS );
- sa4->sin_family = AF_INET;
- sa4->sin_addr.s_addr = ipv4Netmask.sin_addr.s_addr;
-
- dlog( kDebugLevelInfo, DEBUG_NAME "%s: IPv4 mask = %s\n", __ROUTINE__, inet_ntoa( sa4->sin_addr ) );
- ifa->ifa_netmask = (struct sockaddr *) sa4;
- break;
- }
-
- case AF_INET6:
- {
- struct sockaddr_in6 *sa6;
- char buf[ 256 ] = { 0 };
- DWORD buflen = sizeof( buf );
-
- sa6 = (struct sockaddr_in6 *) calloc( 1, sizeof( *sa6 ) );
- require_action( sa6, exit, err = WSAENOBUFS );
- sa6->sin6_family = AF_INET6;
- memset( sa6->sin6_addr.s6_addr, 0xFF, sizeof( sa6->sin6_addr.s6_addr ) );
- ifa->ifa_netmask = (struct sockaddr *) sa6;
-
- for ( prefix = firstPrefix; prefix; prefix = prefix->Next )
- {
- IN6_ADDR mask;
- IN6_ADDR maskedAddr;
- int maskIndex;
- DWORD len;
-
- // According to MSDN:
- // "On Windows Vista and later, the linked IP_ADAPTER_PREFIX structures pointed to by the FirstPrefix member
- // include three IP adapter prefixes for each IP address assigned to the adapter. These include the host IP address prefix,
- // the subnet IP address prefix, and the subnet broadcast IP address prefix.
- // In addition, for each adapter there is a multicast address prefix and a broadcast address prefix.
- // On Windows XP with SP1 and later prior to Windows Vista, the linked IP_ADAPTER_PREFIX structures pointed to by the FirstPrefix member
- // include only a single IP adapter prefix for each IP address assigned to the adapter."
-
- // We're only interested in the subnet IP address prefix. We'll determine if the prefix is the
- // subnet prefix by masking our address with a mask (computed from the prefix length) and see if that is the same
- // as the prefix address.
-
- if ( ( prefix->PrefixLength == 0 ) ||
- ( prefix->PrefixLength > 128 ) ||
- ( addr->Address.iSockaddrLength != prefix->Address.iSockaddrLength ) ||
- ( memcmp( addr->Address.lpSockaddr, prefix->Address.lpSockaddr, addr->Address.iSockaddrLength ) == 0 ) )
- {
- continue;
- }
-
- // Compute the mask
-
- memset( mask.s6_addr, 0, sizeof( mask.s6_addr ) );
-
- for ( len = (int) prefix->PrefixLength, maskIndex = 0; len > 0; len -= 8 )
- {
- uint8_t maskByte = ( len >= 8 ) ? 0xFF : (uint8_t)( ( 0xFFU << ( 8 - len ) ) & 0xFFU );
- mask.s6_addr[ maskIndex++ ] = maskByte;
- }
-
- // Apply the mask
-
- for ( i = 0; i < 16; i++ )
- {
- maskedAddr.s6_addr[ i ] = ( ( struct sockaddr_in6* ) addr->Address.lpSockaddr )->sin6_addr.s6_addr[ i ] & mask.s6_addr[ i ];
- }
-
- // Compare
-
- if ( memcmp( ( ( struct sockaddr_in6* ) prefix->Address.lpSockaddr )->sin6_addr.s6_addr, maskedAddr.s6_addr, sizeof( maskedAddr.s6_addr ) ) == 0 )
- {
- memcpy( sa6->sin6_addr.s6_addr, mask.s6_addr, sizeof( mask.s6_addr ) );
- break;
- }
- }
-
- WSAAddressToStringA( ( LPSOCKADDR ) sa6, sizeof( struct sockaddr_in6 ), NULL, buf, &buflen );
- dlog( kDebugLevelInfo, DEBUG_NAME "%s: IPv6 mask = %s\n", __ROUTINE__, buf );
-
- break;
- }
-
- default:
- break;
- }
- }
- }
-
- // Success!
-
- if( outAddrs )
- {
- *outAddrs = head;
- head = NULL;
- }
- err = ERROR_SUCCESS;
-
-exit:
- if( head )
- {
- freeifaddrs( head );
- }
- if( iaaList )
- {
- free( iaaList );
- }
- return( (int) err );
-}
-
-#endif // MDNS_WINDOWS_USE_IPV6_IF_ADDRS
-
-//===========================================================================================================================
-// getifaddrs_ipv4
-//===========================================================================================================================
-
-mDNSlocal int getifaddrs_ipv4( struct ifaddrs **outAddrs )
-{
- int err;
- SOCKET sock;
- DWORD size;
- DWORD actualSize;
- INTERFACE_INFO * buffer;
- INTERFACE_INFO * tempBuffer;
- INTERFACE_INFO * ifInfo;
- int n;
- int i;
- struct ifaddrs * head;
- struct ifaddrs ** next;
- struct ifaddrs * ifa;
-
- sock = INVALID_SOCKET;
- buffer = NULL;
- head = NULL;
- next = &head;
-
- // Get the interface list. WSAIoctl is called with SIO_GET_INTERFACE_LIST, but since this does not provide a
- // way to determine the size of the interface list beforehand, we have to start with an initial size guess and
- // call WSAIoctl repeatedly with increasing buffer sizes until it succeeds. Limit this to 100 tries for safety.
-
- sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
- err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
- require_noerr( err, exit );
-
- n = 0;
- size = 16 * sizeof( INTERFACE_INFO );
- for( ;; )
- {
- tempBuffer = (INTERFACE_INFO *) realloc( buffer, size );
- require_action( tempBuffer, exit, err = WSAENOBUFS );
- buffer = tempBuffer;
-
- err = WSAIoctl( sock, SIO_GET_INTERFACE_LIST, NULL, 0, buffer, size, &actualSize, NULL, NULL );
- if( err == 0 )
- {
- break;
- }
-
- ++n;
- require_action( n < 100, exit, err = WSAEADDRNOTAVAIL );
-
- size += ( 16 * sizeof( INTERFACE_INFO ) );
- }
- check( actualSize <= size );
- check( ( actualSize % sizeof( INTERFACE_INFO ) ) == 0 );
- n = (int)( actualSize / sizeof( INTERFACE_INFO ) );
-
- // Process the raw interface list and build a linked list of IPv4 interfaces.
-
- for( i = 0; i < n; ++i )
- {
- uint32_t ifIndex;
- struct sockaddr_in netmask;
-
- ifInfo = &buffer[ i ];
- if( ifInfo->iiAddress.Address.sa_family != AF_INET )
- {
- continue;
- }
-
- // <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
- // See comment in getifaddrs_ipv6
-
- ifIndex = 0;
- memset( &netmask, 0, sizeof( netmask ) );
- err = AddressToIndexAndMask( ( struct sockaddr* ) &ifInfo->iiAddress.AddressIn, &ifIndex, ( struct sockaddr* ) &netmask );
-
- if ( err )
- {
- continue;
- }
-
- ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
- require_action( ifa, exit, err = WSAENOBUFS );
-
- *next = ifa;
- next = &ifa->ifa_next;
-
- // Get the name.
-
- ifa->ifa_name = (char *) malloc( 16 );
- require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
- sprintf( ifa->ifa_name, "%d", i + 1 );
-
- // Get interface flags.
-
- ifa->ifa_flags = (u_int) ifInfo->iiFlags;
-
- // Get addresses.
-
- if ( ifInfo->iiAddress.Address.sa_family == AF_INET )
- {
- struct sockaddr_in * sa4;
-
- sa4 = &ifInfo->iiAddress.AddressIn;
- ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sa4 ) );
- require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
- memcpy( ifa->ifa_addr, sa4, sizeof( *sa4 ) );
-
- ifa->ifa_netmask = (struct sockaddr*) calloc(1, sizeof( *sa4 ) );
- require_action( ifa->ifa_netmask, exit, err = WSAENOBUFS );
-
- // <rdar://problem/4076478> Service won't start on Win2K. The address
- // family field was not being initialized.
-
- ifa->ifa_netmask->sa_family = AF_INET;
- ( ( struct sockaddr_in* ) ifa->ifa_netmask )->sin_addr = netmask.sin_addr;
- ifa->ifa_extra.index = ifIndex;
- }
- else
- {
- // Emulate an interface index.
-
- ifa->ifa_extra.index = (uint32_t)( i + 1 );
- }
- }
-
- // Success!
-
- if( outAddrs )
- {
- *outAddrs = head;
- head = NULL;
- }
- err = 0;
-
-exit:
-
- if( head )
- {
- freeifaddrs( head );
- }
- if( buffer )
- {
- free( buffer );
- }
- if( sock != INVALID_SOCKET )
- {
- closesocket( sock );
- }
- return( err );
-}
-
-//===========================================================================================================================
-// freeifaddrs
-//===========================================================================================================================
-
-mDNSlocal void freeifaddrs( struct ifaddrs *inIFAs )
-{
- struct ifaddrs * p;
- struct ifaddrs * q;
-
- // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
-
- for( p = inIFAs; p; p = q )
- {
- q = p->ifa_next;
-
- if( p->ifa_name )
- {
- free( p->ifa_name );
- p->ifa_name = NULL;
- }
- if( p->ifa_addr )
- {
- free( p->ifa_addr );
- p->ifa_addr = NULL;
- }
- if( p->ifa_netmask )
- {
- free( p->ifa_netmask );
- p->ifa_netmask = NULL;
- }
- if( p->ifa_broadaddr )
- {
- free( p->ifa_broadaddr );
- p->ifa_broadaddr = NULL;
- }
- if( p->ifa_dstaddr )
- {
- free( p->ifa_dstaddr );
- p->ifa_dstaddr = NULL;
- }
- if( p->ifa_data )
- {
- free( p->ifa_data );
- p->ifa_data = NULL;
- }
- free( p );
- }
-}
-
-
-//===========================================================================================================================
-// GetPrimaryInterface
-//===========================================================================================================================
-
-mDNSlocal DWORD
-GetPrimaryInterface()
-{
- PMIB_IPFORWARDTABLE pIpForwardTable = NULL;
- DWORD dwSize = 0;
- BOOL bOrder = FALSE;
- OSStatus err;
- DWORD index = 0;
- DWORD metric = 0;
- unsigned long int i;
-
- // Find out how big our buffer needs to be.
-
- err = GetIpForwardTable(NULL, &dwSize, bOrder);
- require_action( err == ERROR_INSUFFICIENT_BUFFER, exit, err = kUnknownErr );
-
- // Allocate the memory for the table
-
- pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc( dwSize );
- require_action( pIpForwardTable, exit, err = kNoMemoryErr );
-
- // Now get the table.
-
- err = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
- require_noerr( err, exit );
-
-
- // Search for the row in the table we want.
-
- for ( i = 0; i < pIpForwardTable->dwNumEntries; i++)
- {
- // Look for a default route
-
- if ( pIpForwardTable->table[i].dwForwardDest == 0 )
- {
- if ( index && ( pIpForwardTable->table[i].dwForwardMetric1 >= metric ) )
- {
- continue;
- }
-
- index = pIpForwardTable->table[i].dwForwardIfIndex;
- metric = pIpForwardTable->table[i].dwForwardMetric1;
- }
- }
-
-exit:
-
- if ( pIpForwardTable != NULL )
- {
- free( pIpForwardTable );
- }
-
- return index;
-}
-
-
-//===========================================================================================================================
-// AddressToIndexAndMask
-//===========================================================================================================================
-
-mDNSlocal mStatus
-AddressToIndexAndMask( struct sockaddr * addr, uint32_t * ifIndex, struct sockaddr * mask )
-{
- // Before calling AddIPAddress we use GetIpAddrTable to get
- // an adapter to which we can add the IP.
-
- PMIB_IPADDRTABLE pIPAddrTable = NULL;
- DWORD dwSize = 0;
- mStatus err = mStatus_UnknownErr;
- DWORD i;
-
- // For now, this is only for IPv4 addresses. That is why we can safely cast
- // addr's to sockaddr_in.
-
- require_action( addr->sa_family == AF_INET, exit, err = mStatus_UnknownErr );
-
- // Make an initial call to GetIpAddrTable to get the
- // necessary size into the dwSize variable
-
- for ( i = 0; i < 100; i++ )
- {
- err = GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
-
- if ( err != ERROR_INSUFFICIENT_BUFFER )
- {
- break;
- }
-
- pIPAddrTable = (MIB_IPADDRTABLE *) realloc( pIPAddrTable, dwSize );
- require_action( pIPAddrTable, exit, err = WSAENOBUFS );
- }
-
- require_noerr( err, exit );
- err = mStatus_UnknownErr;
-
- for ( i = 0; i < pIPAddrTable->dwNumEntries; i++ )
- {
- if ( ( ( struct sockaddr_in* ) addr )->sin_addr.s_addr == pIPAddrTable->table[i].dwAddr )
- {
- *ifIndex = pIPAddrTable->table[i].dwIndex;
- ( ( struct sockaddr_in*) mask )->sin_addr.s_addr = pIPAddrTable->table[i].dwMask;
- err = mStatus_NoError;
- break;
- }
- }
-
-exit:
-
- if ( pIPAddrTable )
- {
- free( pIPAddrTable );
- }
-
- return err;
-}
-
-
-//===========================================================================================================================
-// CanReceiveUnicast
-//===========================================================================================================================
-
-mDNSlocal mDNSBool CanReceiveUnicast( void )
-{
- mDNSBool ok;
- SocketRef sock;
- struct sockaddr_in addr;
-
- // Try to bind to the port without the SO_REUSEADDR option to test if someone else has already bound to it.
-
- sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
- check_translated_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
- ok = IsValidSocket( sock );
- if( ok )
- {
- mDNSPlatformMemZero( &addr, sizeof( addr ) );
- addr.sin_family = AF_INET;
- addr.sin_port = MulticastDNSPort.NotAnInteger;
- addr.sin_addr.s_addr = htonl( INADDR_ANY );
-
- ok = ( bind( sock, (struct sockaddr *) &addr, sizeof( addr ) ) == 0 );
- close_compat( sock );
- }
-
- dlog( kDebugLevelInfo, DEBUG_NAME "Unicast UDP responses %s\n", ok ? "okay" : "*not allowed*" );
- return( ok );
-}
-
-
-//===========================================================================================================================
-// IsPointToPoint
-//===========================================================================================================================
-
-mDNSlocal mDNSBool IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS * addr )
-{
- struct ifaddrs * addrs = NULL;
- struct ifaddrs * p = NULL;
- OSStatus err;
- mDNSBool ret = mDNSfalse;
-
- // For now, only works for IPv4 interfaces
-
- if ( addr->Address.lpSockaddr->sa_family == AF_INET )
- {
- // The getifaddrs_ipv4 call will give us correct information regarding IFF_POINTTOPOINT flags.
-
- err = getifaddrs_ipv4( &addrs );
- require_noerr( err, exit );
-
- for ( p = addrs; p; p = p->ifa_next )
- {
- if ( ( addr->Address.lpSockaddr->sa_family == p->ifa_addr->sa_family ) &&
- ( ( ( struct sockaddr_in* ) addr->Address.lpSockaddr )->sin_addr.s_addr == ( ( struct sockaddr_in* ) p->ifa_addr )->sin_addr.s_addr ) )
- {
- ret = ( p->ifa_flags & IFF_POINTTOPOINT ) ? mDNStrue : mDNSfalse;
- break;
- }
- }
- }
-
-exit:
-
- if ( addrs )
- {
- freeifaddrs( addrs );
- }
-
- return ret;
-}
-
-
-//===========================================================================================================================
-// GetWindowsVersionString
-//===========================================================================================================================
-
-mDNSlocal OSStatus GetWindowsVersionString( char *inBuffer, size_t inBufferSize )
-{
-#if( !defined( VER_PLATFORM_WIN32_CE ) )
- #define VER_PLATFORM_WIN32_CE 3
-#endif
-
- OSStatus err;
- OSVERSIONINFO osInfo;
- BOOL ok;
- const char * versionString;
- DWORD platformID;
- DWORD majorVersion;
- DWORD minorVersion;
- DWORD buildNumber;
-
- versionString = "unknown Windows version";
-
- osInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
- ok = GetVersionEx( &osInfo );
- err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
- require_noerr( err, exit );
-
- platformID = osInfo.dwPlatformId;
- majorVersion = osInfo.dwMajorVersion;
- minorVersion = osInfo.dwMinorVersion;
- buildNumber = osInfo.dwBuildNumber & 0xFFFF;
-
- if( ( platformID == VER_PLATFORM_WIN32_WINDOWS ) && ( majorVersion == 4 ) )
- {
- if( ( minorVersion < 10 ) && ( buildNumber == 950 ) )
- {
- versionString = "Windows 95";
- }
- else if( ( minorVersion < 10 ) && ( ( buildNumber > 950 ) && ( buildNumber <= 1080 ) ) )
- {
- versionString = "Windows 95 SP1";
- }
- else if( ( minorVersion < 10 ) && ( buildNumber > 1080 ) )
- {
- versionString = "Windows 95 OSR2";
- }
- else if( ( minorVersion == 10 ) && ( buildNumber == 1998 ) )
- {
- versionString = "Windows 98";
- }
- else if( ( minorVersion == 10 ) && ( ( buildNumber > 1998 ) && ( buildNumber < 2183 ) ) )
- {
- versionString = "Windows 98 SP1";
- }
- else if( ( minorVersion == 10 ) && ( buildNumber >= 2183 ) )
- {
- versionString = "Windows 98 SE";
- }
- else if( minorVersion == 90 )
- {
- versionString = "Windows ME";
- }
- }
- else if( platformID == VER_PLATFORM_WIN32_NT )
- {
- if( ( majorVersion == 3 ) && ( minorVersion == 51 ) )
- {
- versionString = "Windows NT 3.51";
- }
- else if( ( majorVersion == 4 ) && ( minorVersion == 0 ) )
- {
- versionString = "Windows NT 4";
- }
- else if( ( majorVersion == 5 ) && ( minorVersion == 0 ) )
- {
- versionString = "Windows 2000";
- }
- else if( ( majorVersion == 5 ) && ( minorVersion == 1 ) )
- {
- versionString = "Windows XP";
- }
- else if( ( majorVersion == 5 ) && ( minorVersion == 2 ) )
- {
- versionString = "Windows Server 2003";
- }
- }
- else if( platformID == VER_PLATFORM_WIN32_CE )
- {
- versionString = "Windows CE";
- }
-
-exit:
- if( inBuffer && ( inBufferSize > 0 ) )
- {
- inBufferSize -= 1;
- strncpy( inBuffer, versionString, inBufferSize );
- inBuffer[ inBufferSize ] = '\0';
- }
- return( err );
-}
-
-
-//===========================================================================================================================
-// RegQueryString
-//===========================================================================================================================
-
-mDNSlocal mStatus
-RegQueryString( HKEY key, LPCSTR valueName, LPSTR * string, DWORD * stringLen, DWORD * enabled )
-{
- DWORD type;
- int i;
- mStatus err;
-
- *stringLen = MAX_ESCAPED_DOMAIN_NAME;
- *string = NULL;
- i = 0;
-
- do
- {
- if ( *string )
- {
- free( *string );
- }
-
- *string = (char*) malloc( *stringLen );
- require_action( *string, exit, err = mStatus_NoMemoryErr );
-
- err = RegQueryValueExA( key, valueName, 0, &type, (LPBYTE) *string, stringLen );
-
- i++;
- }
- while ( ( err == ERROR_MORE_DATA ) && ( i < 100 ) );
-
- require_noerr_quiet( err, exit );
-
- if ( enabled )
- {
- DWORD dwSize = sizeof( DWORD );
-
- err = RegQueryValueEx( key, TEXT("Enabled"), NULL, NULL, (LPBYTE) enabled, &dwSize );
- check_noerr( err );
-
- err = kNoErr;
- }
-
-exit:
-
- return err;
-}
-
-
-//===========================================================================================================================
-// StringToAddress
-//===========================================================================================================================
-
-mDNSlocal mStatus StringToAddress( mDNSAddr * ip, LPSTR string )
-{
- struct sockaddr_in6 sa6;
- struct sockaddr_in sa4;
- INT dwSize;
- mStatus err;
-
- sa6.sin6_family = AF_INET6;
- dwSize = sizeof( sa6 );
-
- err = WSAStringToAddressA( string, AF_INET6, NULL, (struct sockaddr*) &sa6, &dwSize );
-
- if ( err == mStatus_NoError )
- {
- err = SetupAddr( ip, (struct sockaddr*) &sa6 );
- require_noerr( err, exit );
- }
- else
- {
- sa4.sin_family = AF_INET;
- dwSize = sizeof( sa4 );
-
- err = WSAStringToAddressA( string, AF_INET, NULL, (struct sockaddr*) &sa4, &dwSize );
- err = translate_errno( err == 0, WSAGetLastError(), kUnknownErr );
- require_noerr( err, exit );
-
- err = SetupAddr( ip, (struct sockaddr*) &sa4 );
- require_noerr( err, exit );
- }
-
-exit:
-
- return err;
-}
-
-
-//===========================================================================================================================
-// myGetIfAddrs
-//===========================================================================================================================
-
-mDNSlocal struct ifaddrs*
-myGetIfAddrs(int refresh)
-{
- static struct ifaddrs *ifa = NULL;
-
- if (refresh && ifa)
- {
- freeifaddrs(ifa);
- ifa = NULL;
- }
-
- if (ifa == NULL)
- {
- getifaddrs(&ifa);
- }
-
- return ifa;
-}
-
-
-//===========================================================================================================================
-// TCHARtoUTF8
-//===========================================================================================================================
-
-mDNSlocal OSStatus
-TCHARtoUTF8( const TCHAR *inString, char *inBuffer, size_t inBufferSize )
-{
-#if( defined( UNICODE ) || defined( _UNICODE ) )
- OSStatus err;
- int len;
-
- len = WideCharToMultiByte( CP_UTF8, 0, inString, -1, inBuffer, (int) inBufferSize, NULL, NULL );
- err = translate_errno( len > 0, errno_compat(), kUnknownErr );
- require_noerr( err, exit );
-
-exit:
- return( err );
-#else
- return( WindowsLatin1toUTF8( inString, inBuffer, inBufferSize ) );
-#endif
-}
-
-
-//===========================================================================================================================
-// WindowsLatin1toUTF8
-//===========================================================================================================================
-
-mDNSlocal OSStatus
-WindowsLatin1toUTF8( const char *inString, char *inBuffer, size_t inBufferSize )
-{
- OSStatus err;
- WCHAR * utf16;
- int len;
-
- utf16 = NULL;
-
- // Windows doesn't support going directly from Latin-1 to UTF-8 so we have to go from Latin-1 to UTF-16 first.
-
- len = MultiByteToWideChar( CP_ACP, 0, inString, -1, NULL, 0 );
- err = translate_errno( len > 0, errno_compat(), kUnknownErr );
- require_noerr( err, exit );
-
- utf16 = (WCHAR *) malloc( len * sizeof( *utf16 ) );
- require_action( utf16, exit, err = kNoMemoryErr );
-
- len = MultiByteToWideChar( CP_ACP, 0, inString, -1, utf16, len );
- err = translate_errno( len > 0, errno_compat(), kUnknownErr );
- require_noerr( err, exit );
-
- // Now convert the temporary UTF-16 to UTF-8.
-
- len = WideCharToMultiByte( CP_UTF8, 0, utf16, -1, inBuffer, (int) inBufferSize, NULL, NULL );
- err = translate_errno( len > 0, errno_compat(), kUnknownErr );
- require_noerr( err, exit );
-
-exit:
- if( utf16 ) free( utf16 );
- return( err );
-}
-
-
-//===========================================================================================================================
-// TCPCloseSocket
-//===========================================================================================================================
-
-mDNSlocal void
-TCPCloseSocket( TCPSocket * sock )
-{
- dlog( kDebugLevelChatty, DEBUG_NAME "closing TCPSocket 0x%x:%d\n", sock, sock->fd );
-
- if ( sock->fd != INVALID_SOCKET )
- {
- closesocket( sock->fd );
- sock->fd = INVALID_SOCKET;
- }
-}
-
-
-//===========================================================================================================================
-// UDPCloseSocket
-//===========================================================================================================================
-
-mDNSlocal void
-UDPCloseSocket( UDPSocket * sock )
-{
- dlog( kDebugLevelChatty, DEBUG_NAME "closing UDPSocket %d\n", sock->fd );
-
- if ( sock->fd != INVALID_SOCKET )
- {
- mDNSPollUnregisterSocket( sock->fd );
- closesocket( sock->fd );
- sock->fd = INVALID_SOCKET;
- }
-}
-
-
-//===========================================================================================================================
-// SetupAddr
-//===========================================================================================================================
-
-mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
- {
- if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
-
- if (sa->sa_family == AF_INET)
- {
- struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
- ip->type = mDNSAddrType_IPv4;
- ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
- return(mStatus_NoError);
- }
-
- if (sa->sa_family == AF_INET6)
- {
- struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
- ip->type = mDNSAddrType_IPv6;
- if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.u.Word[1] = 0;
- ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
- return(mStatus_NoError);
- }
-
- LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
- return(mStatus_Invalid);
- }
-
-
-mDNSlocal void GetDDNSFQDN( domainname *const fqdn )
-{
- LPSTR name = NULL;
- DWORD dwSize;
- DWORD enabled;
- HKEY key = NULL;
- OSStatus err;
-
- check( fqdn );
-
- // Initialize
-
- fqdn->c[0] = '\0';
-
- // Get info from Bonjour registry key
-
- err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSHostNames, &key );
- require_noerr( err, exit );
-
- err = RegQueryString( key, "", &name, &dwSize, &enabled );
- if ( !err && ( name[0] != '\0' ) && enabled )
- {
- if ( !MakeDomainNameFromDNSNameString( fqdn, name ) || !fqdn->c[0] )
- {
- dlog( kDebugLevelError, "bad DDNS host name in registry: %s", name[0] ? name : "(unknown)");
- }
- }
-
-exit:
-
- if ( key )
- {
- RegCloseKey( key );
- key = NULL;
- }
-
- if ( name )
- {
- free( name );
- name = NULL;
- }
-}
-
-
-#ifdef UNICODE
-mDNSlocal void GetDDNSDomains( DNameListElem ** domains, LPCWSTR lpSubKey )
-#else
-mDNSlocal void GetDDNSConfig( DNameListElem ** domains, LPCSTR lpSubKey )
-#endif
-{
- char subKeyName[kRegistryMaxKeyLength + 1];
- DWORD cSubKeys = 0;
- DWORD cbMaxSubKey;
- DWORD cchMaxClass;
- DWORD dwSize;
- HKEY key = NULL;
- HKEY subKey = NULL;
- domainname dname;
- DWORD i;
- OSStatus err;
-
- check( domains );
-
- // Initialize
-
- *domains = NULL;
-
- err = RegCreateKey( HKEY_LOCAL_MACHINE, lpSubKey, &key );
- require_noerr( err, exit );
-
- // Get information about this node
-
- err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );
- require_noerr( err, exit );
-
- for ( i = 0; i < cSubKeys; i++)
- {
- DWORD enabled;
-
- dwSize = kRegistryMaxKeyLength;
-
- err = RegEnumKeyExA( key, i, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
-
- if ( !err )
- {
- err = RegOpenKeyExA( key, subKeyName, 0, KEY_READ, &subKey );
- require_noerr( err, exit );
-
- dwSize = sizeof( DWORD );
- err = RegQueryValueExA( subKey, "Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
-
- if ( !err && ( subKeyName[0] != '\0' ) && enabled )
- {
- if ( !MakeDomainNameFromDNSNameString( &dname, subKeyName ) || !dname.c[0] )
- {
- dlog( kDebugLevelError, "bad DDNS domain in registry: %s", subKeyName[0] ? subKeyName : "(unknown)");
- }
- else
- {
- DNameListElem * domain = (DNameListElem*) malloc( sizeof( DNameListElem ) );
- require_action( domain, exit, err = mStatus_NoMemoryErr );
-
- AssignDomainName(&domain->name, &dname);
- domain->next = *domains;
-
- *domains = domain;
- }
- }
-
- RegCloseKey( subKey );
- subKey = NULL;
- }
- }
-
-exit:
-
- if ( subKey )
- {
- RegCloseKey( subKey );
- }
-
- if ( key )
- {
- RegCloseKey( key );
- }
-}
-
-
-mDNSlocal void SetDomainSecret( mDNS * const m, const domainname * inDomain )
-{
- char domainUTF8[ 256 ];
- DomainAuthInfo *foundInList;
- DomainAuthInfo *ptr;
- char outDomain[ 256 ];
- char outKey[ 256 ];
- char outSecret[ 256 ];
- OSStatus err;
-
- ConvertDomainNameToCString( inDomain, domainUTF8 );
-
- // If we're able to find a secret for this domain
-
- if ( LsaGetSecret( domainUTF8, outDomain, sizeof( outDomain ), outKey, sizeof( outKey ), outSecret, sizeof( outSecret ) ) )
- {
- domainname domain;
- domainname key;
-
- // Tell the core about this secret
-
- MakeDomainNameFromDNSNameString( &domain, outDomain );
- MakeDomainNameFromDNSNameString( &key, outKey );
-
- for (foundInList = m->AuthInfoList; foundInList; foundInList = foundInList->next)
- if (SameDomainName(&foundInList->domain, &domain ) ) break;
-
- ptr = foundInList;
-
- if (!ptr)
- {
- ptr = (DomainAuthInfo*)malloc(sizeof(DomainAuthInfo));
- require_action( ptr, exit, err = mStatus_NoMemoryErr );
- }
-
- err = mDNS_SetSecretForDomain(m, ptr, &domain, &key, outSecret, NULL, NULL, FALSE );
- require_action( err != mStatus_BadParamErr, exit, if (!foundInList ) mDNSPlatformMemFree( ptr ) );
-
- debugf("Setting shared secret for zone %s with key %##s", outDomain, key.c);
- }
-
-exit:
-
- return;
-}
-
-
-mDNSlocal VOID CALLBACK
-CheckFileSharesProc( LPVOID arg, DWORD dwTimerLowValue, DWORD dwTimerHighValue )
-{
- mDNS * const m = ( mDNS * const ) arg;
-
- ( void ) dwTimerLowValue;
- ( void ) dwTimerHighValue;
-
- CheckFileShares( m );
-}
-
-
-mDNSlocal unsigned __stdcall
-SMBRegistrationThread( void * arg )
-{
- mDNS * const m = ( mDNS * const ) arg;
- DNSServiceRef sref = NULL;
- HANDLE handles[ 3 ];
- mDNSu8 txtBuf[ 256 ];
- mDNSu8 * txtPtr;
- size_t keyLen;
- size_t valLen;
- mDNSIPPort port = { { SMBPortAsNumber >> 8, SMBPortAsNumber & 0xFF } };
- DNSServiceErrorType err;
-
- DEBUG_UNUSED( arg );
-
- handles[ 0 ] = gSMBThreadStopEvent;
- handles[ 1 ] = gSMBThreadRegisterEvent;
- handles[ 2 ] = gSMBThreadDeregisterEvent;
-
- memset( txtBuf, 0, sizeof( txtBuf ) );
- txtPtr = txtBuf;
- keyLen = strlen( "netbios=" );
- valLen = strlen( m->p->nbname );
- require_action( valLen < 32, exit, err = kUnknownErr ); // This should never happen, but check to avoid further memory corruption
- *txtPtr++ = ( mDNSu8 ) ( keyLen + valLen );
- memcpy( txtPtr, "netbios=", keyLen );
- txtPtr += keyLen;
- if ( valLen ) { memcpy( txtPtr, m->p->nbname, valLen ); txtPtr += ( mDNSu8 ) valLen; }
- keyLen = strlen( "domain=" );
- valLen = strlen( m->p->nbdomain );
- require_action( valLen < 32, exit, err = kUnknownErr ); // This should never happen, but check to avoid further memory corruption
- *txtPtr++ = ( mDNSu8 )( keyLen + valLen );
- memcpy( txtPtr, "domain=", keyLen );
- txtPtr += keyLen;
- if ( valLen ) { memcpy( txtPtr, m->p->nbdomain, valLen ); txtPtr += valLen; }
-
- for ( ;; )
- {
- DWORD ret;
-
- ret = WaitForMultipleObjects( 3, handles, FALSE, INFINITE );
-
- if ( ret != WAIT_FAILED )
- {
- if ( ret == kSMBStopEvent )
- {
- break;
- }
- else if ( ret == kSMBRegisterEvent )
- {
- err = gDNSServiceRegister( &sref, 0, 0, NULL, "_smb._tcp,_file", NULL, NULL, ( uint16_t ) port.NotAnInteger, ( mDNSu16 )( txtPtr - txtBuf ), txtBuf, NULL, NULL );
-
- if ( err )
- {
- LogMsg( "SMBRegistrationThread: DNSServiceRegister returned %d\n", err );
- sref = NULL;
- break;
- }
- }
- else if ( ret == kSMBDeregisterEvent )
- {
- if ( sref )
- {
- gDNSServiceRefDeallocate( sref );
- sref = NULL;
- }
- }
- }
- else
- {
- LogMsg( "SMBRegistrationThread: WaitForMultipleObjects returned %d\n", GetLastError() );
- break;
- }
- }
-
-exit:
-
- if ( sref != NULL )
- {
- gDNSServiceRefDeallocate( sref );
- sref = NULL;
- }
-
- SetEvent( gSMBThreadQuitEvent );
- _endthreadex( 0 );
- return 0;
-}
-
-
-mDNSlocal void
-CheckFileShares( mDNS * const m )
-{
- PSHARE_INFO_1 bufPtr = ( PSHARE_INFO_1 ) NULL;
- DWORD entriesRead = 0;
- DWORD totalEntries = 0;
- DWORD resume = 0;
- mDNSBool advertise = mDNSfalse;
- mDNSBool fileSharing = mDNSfalse;
- mDNSBool printSharing = mDNSfalse;
- HKEY key = NULL;
- BOOL retry = FALSE;
- NET_API_STATUS res;
- mStatus err;
-
- check( m );
-
- // Only do this if we're not shutting down
-
- require_action_quiet( m->AdvertiseLocalAddresses && !m->ShutdownTime, exit, err = kNoErr );
-
- err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Services\\SMB", &key );
-
- if ( !err )
- {
- DWORD dwSize = sizeof( DWORD );
- RegQueryValueEx( key, L"Advertise", NULL, NULL, (LPBYTE) &advertise, &dwSize );
- }
-
- if ( advertise && mDNSIsFileAndPrintSharingEnabled( &retry ) )
- {
- dlog( kDebugLevelTrace, DEBUG_NAME "Sharing is enabled\n" );
-
- res = NetShareEnum( NULL, 1, ( LPBYTE* )&bufPtr, MAX_PREFERRED_LENGTH, &entriesRead, &totalEntries, &resume );
-
- if ( ( res == ERROR_SUCCESS ) || ( res == ERROR_MORE_DATA ) )
- {
- PSHARE_INFO_1 p = bufPtr;
- DWORD i;
-
- for( i = 0; i < entriesRead; i++ )
- {
- // We are only interested if the user is sharing anything other
- // than the built-in "print$" source
-
- if ( ( p->shi1_type == STYPE_DISKTREE ) && ( wcscmp( p->shi1_netname, TEXT( "print$" ) ) != 0 ) )
- {
- fileSharing = mDNStrue;
- }
- else if ( p->shi1_type == STYPE_PRINTQ )
- {
- printSharing = mDNStrue;
- }
-
- p++;
- }
-
- NetApiBufferFree( bufPtr );
- bufPtr = NULL;
- retry = FALSE;
- }
- else if ( res == NERR_ServerNotStarted )
- {
- retry = TRUE;
- }
- }
-
- if ( retry )
- {
- __int64 qwTimeout;
- LARGE_INTEGER liTimeout;
-
- qwTimeout = -m->p->checkFileSharesTimeout * 10000000;
- liTimeout.LowPart = ( DWORD )( qwTimeout & 0xFFFFFFFF );
- liTimeout.HighPart = ( LONG )( qwTimeout >> 32 );
-
- SetWaitableTimer( m->p->checkFileSharesTimer, &liTimeout, 0, CheckFileSharesProc, m, FALSE );
- }
-
- if ( !m->p->smbFileSharing && fileSharing )
- {
- if ( !gSMBThread )
- {
- if ( !gDNSSDLibrary )
- {
- gDNSSDLibrary = LoadLibrary( TEXT( "dnssd.dll" ) );
- require_action( gDNSSDLibrary, exit, err = GetLastError() );
- }
-
- if ( !gDNSServiceRegister )
- {
- gDNSServiceRegister = ( DNSServiceRegisterFunc ) GetProcAddress( gDNSSDLibrary, "DNSServiceRegister" );
- require_action( gDNSServiceRegister, exit, err = GetLastError() );
- }
-
- if ( !gDNSServiceRefDeallocate )
- {
- gDNSServiceRefDeallocate = ( DNSServiceRefDeallocateFunc ) GetProcAddress( gDNSSDLibrary, "DNSServiceRefDeallocate" );
- require_action( gDNSServiceRefDeallocate, exit, err = GetLastError() );
- }
-
- if ( !gSMBThreadRegisterEvent )
- {
- gSMBThreadRegisterEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
- require_action( gSMBThreadRegisterEvent != NULL, exit, err = GetLastError() );
- }
-
- if ( !gSMBThreadDeregisterEvent )
- {
- gSMBThreadDeregisterEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
- require_action( gSMBThreadDeregisterEvent != NULL, exit, err = GetLastError() );
- }
-
- if ( !gSMBThreadStopEvent )
- {
- gSMBThreadStopEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
- require_action( gSMBThreadStopEvent != NULL, exit, err = GetLastError() );
- }
-
- if ( !gSMBThreadQuitEvent )
- {
- gSMBThreadQuitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
- require_action( gSMBThreadQuitEvent != NULL, exit, err = GetLastError() );
- }
-
- gSMBThread = ( HANDLE ) _beginthreadex( NULL, 0, SMBRegistrationThread, m, 0, NULL );
- require_action( gSMBThread != NULL, exit, err = GetLastError() );
- }
-
- SetEvent( gSMBThreadRegisterEvent );
-
- m->p->smbFileSharing = mDNStrue;
- }
- else if ( m->p->smbFileSharing && !fileSharing )
- {
- dlog( kDebugLevelTrace, DEBUG_NAME "deregistering smb type\n" );
-
- if ( gSMBThreadDeregisterEvent != NULL )
- {
- SetEvent( gSMBThreadDeregisterEvent );
- }
-
- m->p->smbFileSharing = mDNSfalse;
- }
-
-exit:
-
- if ( key )
- {
- RegCloseKey( key );
- }
-}
-
-
-BOOL
-IsWOMPEnabled( mDNS * const m )
-{
- BOOL enabled;
-
- mDNSInterfaceData * ifd;
-
- enabled = FALSE;
-
- for( ifd = m->p->interfaceList; ifd; ifd = ifd->next )
- {
- if ( IsWOMPEnabledForAdapter( ifd->name ) )
- {
- enabled = TRUE;
- break;
- }
- }
-
- return enabled;
-}
-
-
-mDNSlocal mDNSu8
-IsWOMPEnabledForAdapter( const char * adapterName )
-{
- char fileName[80];
- NDIS_OID oid;
- DWORD count;
- HANDLE handle = INVALID_HANDLE_VALUE;
- NDIS_PNP_CAPABILITIES * pNPC = NULL;
- int err;
- mDNSu8 ok = TRUE;
-
- require_action( adapterName != NULL, exit, ok = FALSE );
-
- dlog( kDebugLevelTrace, DEBUG_NAME "IsWOMPEnabledForAdapter: %s\n", adapterName );
-
- // Construct a device name to pass to CreateFile
-
- strncpy_s( fileName, sizeof( fileName ), DEVICE_PREFIX, strlen( DEVICE_PREFIX ) );
- strcat_s( fileName, sizeof( fileName ), adapterName );
- handle = CreateFileA( fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, INVALID_HANDLE_VALUE );
- require_action ( handle != INVALID_HANDLE_VALUE, exit, ok = FALSE );
-
- // We successfully opened the driver, format the IOCTL to pass the driver.
-
- oid = OID_PNP_CAPABILITIES;
- pNPC = ( NDIS_PNP_CAPABILITIES * ) malloc( sizeof( NDIS_PNP_CAPABILITIES ) );
- require_action( pNPC != NULL, exit, ok = FALSE );
- ok = ( mDNSu8 ) DeviceIoControl( handle, IOCTL_NDIS_QUERY_GLOBAL_STATS, &oid, sizeof( oid ), pNPC, sizeof( NDIS_PNP_CAPABILITIES ), &count, NULL );
- err = translate_errno( ok, GetLastError(), kUnknownErr );
- require_action( !err, exit, ok = FALSE );
- ok = ( mDNSu8 ) ( ( count == sizeof( NDIS_PNP_CAPABILITIES ) ) && ( pNPC->Flags & NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE ) );
-
-exit:
-
- if ( pNPC != NULL )
- {
- free( pNPC );
- }
-
- if ( handle != INVALID_HANDLE_VALUE )
- {
- CloseHandle( handle );
- }
-
- dlog( kDebugLevelTrace, DEBUG_NAME "IsWOMPEnabledForAdapter returns %s\n", ok ? "true" : "false" );
-
- return ( mDNSu8 ) ok;
-}
-
-
-mDNSlocal void
-SendWakeupPacket( mDNS * const inMDNS, LPSOCKADDR addr, INT addrlen, const char * buf, INT buflen, INT numTries, INT msecSleep )
-{
- mDNSBool repeat = ( numTries == 1 ) ? mDNStrue : mDNSfalse;
- SOCKET sock;
- int num;
- mStatus err;
-
- ( void ) inMDNS;
-
- sock = socket( addr->sa_family, SOCK_DGRAM, IPPROTO_UDP );
- require_action( sock != INVALID_SOCKET, exit, err = mStatus_UnknownErr );
-
- while ( numTries-- )
- {
- num = sendto( sock, ( const char* ) buf, buflen, 0, addr, addrlen );
-
- if ( num != buflen )
- {
- LogMsg( "SendWakeupPacket error: sent %d bytes: %d\n", num, WSAGetLastError() );
- }
-
- if ( repeat )
- {
- num = sendto( sock, buf, buflen, 0, addr, addrlen );
-
- if ( num != buflen )
- {
- LogMsg( "SendWakeupPacket error: sent %d bytes: %d\n", num, WSAGetLastError() );
- }
- }
-
- if ( msecSleep )
- {
- Sleep( msecSleep );
- }
- }
-
-exit:
-
- if ( sock != INVALID_SOCKET )
- {
- closesocket( sock );
- }
-}
-
-
-mDNSlocal void _cdecl
-SendMulticastWakeupPacket( void *arg )
-{
- MulticastWakeupStruct *info = ( MulticastWakeupStruct* ) arg;
-
- if ( info )
- {
- SendWakeupPacket( info->inMDNS, ( LPSOCKADDR ) &info->addr, sizeof( info->addr ), ( const char* ) info->data, sizeof( info->data ), info->numTries, info->msecSleep );
- free( info );
- }
-
- _endthread();
-}
-
-
-mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
-{
- DEBUG_UNUSED( m );
- DEBUG_UNUSED( rr );
- DEBUG_UNUSED( result );
-}
Copied: vendor/apple/mDNSResponder/561.1.1/mDNSWindows/mDNSWin32.c (from rev 6984, vendor/apple/mDNSResponder/dist/mDNSWindows/mDNSWin32.c)
===================================================================
--- vendor/apple/mDNSResponder/561.1.1/mDNSWindows/mDNSWin32.c (rev 0)
+++ vendor/apple/mDNSResponder/561.1.1/mDNSWindows/mDNSWin32.c 2015-03-20 01:14:52 UTC (rev 6985)
@@ -0,0 +1,5197 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002-2013 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+
+ To Do:
+
+ - Get unicode name of machine for nice name instead of just the host name.
+ - Use the IPv6 Internet Connection Firewall API to allow IPv6 mDNS without manually changing the firewall.
+ - Get DNS server address(es) from Windows and provide them to the uDNS layer.
+ - Implement TCP support for truncated packets (only stubs now).
+
+*/
+
+#define _CRT_RAND_S
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <crtdbg.h>
+#include <string.h>
+
+#include "Poll.h"
+#include "CommonServices.h"
+#include "DebugServices.h"
+#include "Firewall.h"
+#include "RegNames.h"
+#include "Secret.h"
+#include <dns_sd.h>
+
+#include <Iphlpapi.h>
+#include <mswsock.h>
+#include <process.h>
+#include <ntsecapi.h>
+#include <lm.h>
+#include <winioctl.h>
+#include <ntddndis.h> // This defines the IOCTL constants.
+
+#include "mDNSEmbeddedAPI.h"
+#include "GenLinkedList.h"
+#include "DNSCommon.h"
+#include "mDNSWin32.h"
+#include "dnssec.h"
+#include "nsec.h"
+
+#if 0
+#pragma mark == Constants ==
+#endif
+
+//===========================================================================================================================
+// Constants
+//===========================================================================================================================
+
+#define DEBUG_NAME "[mDNSWin32] "
+
+#define MDNS_WINDOWS_USE_IPV6_IF_ADDRS 1
+#define MDNS_WINDOWS_ENABLE_IPV4 1
+#define MDNS_WINDOWS_ENABLE_IPV6 1
+#define MDNS_FIX_IPHLPAPI_PREFIX_BUG 1
+#define MDNS_SET_HINFO_STRINGS 0
+
+#define kMDNSDefaultName "My Computer"
+
+#define kWinSockMajorMin 2
+#define kWinSockMinorMin 2
+
+#define kRegistryMaxKeyLength 255
+#define kRegistryMaxValueName 16383
+
+static GUID kWSARecvMsgGUID = WSAID_WSARECVMSG;
+
+#define kIPv6IfIndexBase (10000000L)
+#define SMBPortAsNumber 445
+#define DEVICE_PREFIX "\\\\.\\"
+
+#if 0
+#pragma mark == Prototypes ==
+#endif
+
+//===========================================================================================================================
+// Prototypes
+//===========================================================================================================================
+
+mDNSlocal mStatus SetupNiceName( mDNS * const inMDNS );
+mDNSlocal mStatus SetupHostName( mDNS * const inMDNS );
+mDNSlocal mStatus SetupName( mDNS * const inMDNS );
+mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inIFA, mDNSInterfaceData **outIFD );
+mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD );
+mDNSlocal void CALLBACK FreeInterface( mDNSInterfaceData *inIFD );
+mDNSlocal mStatus SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, mDNSIPPort port, SocketRef *outSocketRef );
+mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort );
+mDNSlocal OSStatus GetWindowsVersionString( char *inBuffer, size_t inBufferSize );
+mDNSlocal int getifaddrs( struct ifaddrs **outAddrs );
+mDNSlocal void freeifaddrs( struct ifaddrs *inAddrs );
+
+
+
+// Platform Accessors
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo;
+struct mDNSPlatformInterfaceInfo
+{
+ const char * name;
+ mDNSAddr ip;
+};
+
+
+mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID );
+mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo );
+
+
+// Wakeup Structs
+
+#define kUnicastWakeupNumTries ( 1 )
+#define kUnicastWakeupSleepBetweenTries ( 0 )
+#define kMulticastWakeupNumTries ( 18 )
+#define kMulticastWakeupSleepBetweenTries ( 100 )
+
+typedef struct MulticastWakeupStruct
+{
+ mDNS *inMDNS;
+ struct sockaddr_in addr;
+ INT addrLen;
+ unsigned char data[ 102 ];
+ INT dataLen;
+ INT numTries;
+ INT msecSleep;
+} MulticastWakeupStruct;
+
+
+// Utilities
+
+#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
+ mDNSlocal int getifaddrs_ipv6( struct ifaddrs **outAddrs );
+#endif
+
+mDNSlocal int getifaddrs_ipv4( struct ifaddrs **outAddrs );
+
+
+mDNSlocal DWORD GetPrimaryInterface();
+mDNSlocal mStatus AddressToIndexAndMask( struct sockaddr * address, uint32_t * index, struct sockaddr * mask );
+mDNSlocal mDNSBool CanReceiveUnicast( void );
+mDNSlocal mDNSBool IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS * addr );
+
+mDNSlocal mStatus StringToAddress( mDNSAddr * ip, LPSTR string );
+mDNSlocal mStatus RegQueryString( HKEY key, LPCSTR param, LPSTR * string, DWORD * stringLen, DWORD * enabled );
+mDNSlocal struct ifaddrs* myGetIfAddrs(int refresh);
+mDNSlocal OSStatus TCHARtoUTF8( const TCHAR *inString, char *inBuffer, size_t inBufferSize );
+mDNSlocal OSStatus WindowsLatin1toUTF8( const char *inString, char *inBuffer, size_t inBufferSize );
+mDNSlocal void CALLBACK TCPSocketNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context );
+mDNSlocal void TCPCloseSocket( TCPSocket * socket );
+mDNSlocal void CALLBACK UDPSocketNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context );
+mDNSlocal void UDPCloseSocket( UDPSocket * sock );
+mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa);
+mDNSlocal void GetDDNSFQDN( domainname *const fqdn );
+#ifdef UNICODE
+mDNSlocal void GetDDNSDomains( DNameListElem ** domains, LPCWSTR lpSubKey );
+#else
+mDNSlocal void GetDDNSDomains( DNameListElem ** domains, LPCSTR lpSubKey );
+#endif
+mDNSlocal void SetDomainSecrets( mDNS * const inMDNS );
+mDNSlocal void SetDomainSecret( mDNS * const m, const domainname * inDomain );
+mDNSlocal VOID CALLBACK CheckFileSharesProc( LPVOID arg, DWORD dwTimerLowValue, DWORD dwTimerHighValue );
+mDNSlocal void CheckFileShares( mDNS * const inMDNS );
+mDNSlocal void SMBCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
+mDNSlocal mDNSu8 IsWOMPEnabledForAdapter( const char * adapterName );
+mDNSlocal void SendWakeupPacket( mDNS * const inMDNS, LPSOCKADDR addr, INT addrlen, const char * buf, INT buflen, INT numTries, INT msecSleep );
+mDNSlocal void _cdecl SendMulticastWakeupPacket( void *arg );
+
+#ifdef __cplusplus
+ }
+#endif
+
+#if 0
+#pragma mark == Globals ==
+#endif
+
+//===========================================================================================================================
+// Globals
+//===========================================================================================================================
+
+mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport;
+mDNSs32 mDNSPlatformOneSecond = 0;
+mDNSlocal UDPSocket * gUDPSockets = NULL;
+mDNSlocal int gUDPNumSockets = 0;
+mDNSlocal BOOL gEnableIPv6 = TRUE;
+
+#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
+
+ typedef DWORD
+ ( WINAPI * GetAdaptersAddressesFunctionPtr )(
+ ULONG inFamily,
+ DWORD inFlags,
+ PVOID inReserved,
+ PIP_ADAPTER_ADDRESSES inAdapter,
+ PULONG outBufferSize );
+
+ mDNSlocal HMODULE gIPHelperLibraryInstance = NULL;
+ mDNSlocal GetAdaptersAddressesFunctionPtr gGetAdaptersAddressesFunctionPtr = NULL;
+
+#endif
+
+
+#ifndef HCRYPTPROV
+ typedef ULONG_PTR HCRYPTPROV; // WinCrypt.h, line 249
+#endif
+
+
+#ifndef CRYPT_MACHINE_KEYSET
+# define CRYPT_MACHINE_KEYSET 0x00000020
+#endif
+
+#ifndef CRYPT_NEWKEYSET
+# define CRYPT_NEWKEYSET 0x00000008
+#endif
+
+#ifndef PROV_RSA_FULL
+# define PROV_RSA_FULL 1
+#endif
+
+typedef BOOL (__stdcall *fnCryptGenRandom)( HCRYPTPROV, DWORD, BYTE* );
+typedef BOOL (__stdcall *fnCryptAcquireContext)( HCRYPTPROV*, LPCTSTR, LPCTSTR, DWORD, DWORD);
+typedef BOOL (__stdcall *fnCryptReleaseContext)(HCRYPTPROV, DWORD);
+
+static fnCryptAcquireContext g_lpCryptAcquireContext = NULL;
+static fnCryptReleaseContext g_lpCryptReleaseContext = NULL;
+static fnCryptGenRandom g_lpCryptGenRandom = NULL;
+static HINSTANCE g_hAAPI32 = NULL;
+static HCRYPTPROV g_hProvider = ( ULONG_PTR ) NULL;
+
+
+typedef DNSServiceErrorType ( DNSSD_API *DNSServiceRegisterFunc )
+ (
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *name, /* may be NULL */
+ const char *regtype,
+ const char *domain, /* may be NULL */
+ const char *host, /* may be NULL */
+ uint16_t port,
+ uint16_t txtLen,
+ const void *txtRecord, /* may be NULL */
+ DNSServiceRegisterReply callBack, /* may be NULL */
+ void *context /* may be NULL */
+ );
+
+
+typedef void ( DNSSD_API *DNSServiceRefDeallocateFunc )( DNSServiceRef sdRef );
+
+mDNSlocal HMODULE gDNSSDLibrary = NULL;
+mDNSlocal DNSServiceRegisterFunc gDNSServiceRegister = NULL;
+mDNSlocal DNSServiceRefDeallocateFunc gDNSServiceRefDeallocate = NULL;
+mDNSlocal HANDLE gSMBThread = NULL;
+mDNSlocal HANDLE gSMBThreadRegisterEvent = NULL;
+mDNSlocal HANDLE gSMBThreadDeregisterEvent = NULL;
+mDNSlocal HANDLE gSMBThreadStopEvent = NULL;
+mDNSlocal HANDLE gSMBThreadQuitEvent = NULL;
+
+#define kSMBStopEvent ( WAIT_OBJECT_0 + 0 )
+#define kSMBRegisterEvent ( WAIT_OBJECT_0 + 1 )
+#define kSMBDeregisterEvent ( WAIT_OBJECT_0 + 2 )
+
+
+#if 0
+#pragma mark -
+#pragma mark == Platform Support ==
+#endif
+
+//===========================================================================================================================
+// mDNSPlatformInit
+//===========================================================================================================================
+
+mDNSexport mStatus mDNSPlatformInit( mDNS * const inMDNS )
+{
+ mStatus err;
+ OSVERSIONINFO osInfo;
+ BOOL ok;
+ WSADATA wsaData;
+ int supported;
+ struct sockaddr_in sa4;
+ struct sockaddr_in6 sa6;
+ int sa4len;
+ int sa6len;
+ DWORD size;
+
+ dlog( kDebugLevelTrace, DEBUG_NAME "platform init\n" );
+
+ // Initialize variables. If the PlatformSupport pointer is not null then just assume that a non-Apple client is
+ // calling mDNS_Init and wants to provide its own storage for the platform-specific data so do not overwrite it.
+
+ mDNSPlatformMemZero( &gMDNSPlatformSupport, sizeof( gMDNSPlatformSupport ) );
+ if( !inMDNS->p ) inMDNS->p = &gMDNSPlatformSupport;
+ inMDNS->p->mainThread = OpenThread( THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId() );
+ require_action( inMDNS->p->mainThread, exit, err = mStatus_UnknownErr );
+ inMDNS->p->checkFileSharesTimer = CreateWaitableTimer( NULL, FALSE, NULL );
+ require_action( inMDNS->p->checkFileSharesTimer, exit, err = mStatus_UnknownErr );
+ inMDNS->p->checkFileSharesTimeout = 10; // Retry time for CheckFileShares() in seconds
+ mDNSPlatformOneSecond = 1000; // Use milliseconds as the quantum of time
+
+ // Get OS version info
+
+ osInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
+ ok = GetVersionEx( &osInfo );
+ err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
+ require_noerr( err, exit );
+ inMDNS->p->osMajorVersion = osInfo.dwMajorVersion;
+ inMDNS->p->osMinorVersion = osInfo.dwMinorVersion;
+
+ // Don't enable IPv6 on anything less recent than Windows Vista
+
+ if ( inMDNS->p->osMajorVersion < 6 )
+ {
+ gEnableIPv6 = FALSE;
+ }
+
+ // Startup WinSock 2.2 or later.
+
+ err = WSAStartup( MAKEWORD( kWinSockMajorMin, kWinSockMinorMin ), &wsaData );
+ require_noerr( err, exit );
+
+ supported = ( ( LOBYTE( wsaData.wVersion ) == kWinSockMajorMin ) && ( HIBYTE( wsaData.wVersion ) == kWinSockMinorMin ) );
+ require_action( supported, exit, err = mStatus_UnsupportedErr );
+
+ inMDNS->CanReceiveUnicastOn5353 = CanReceiveUnicast();
+
+ // Setup the HINFO HW strings.
+ //<rdar://problem/7245119> device-info should have model=Windows
+
+ strcpy_s( ( char* ) &inMDNS->HIHardware.c[ 1 ], sizeof( inMDNS->HIHardware.c ) - 2, "Windows" );
+ inMDNS->HIHardware.c[ 0 ] = ( mDNSu8 ) mDNSPlatformStrLen( &inMDNS->HIHardware.c[ 1 ] );
+ dlog( kDebugLevelInfo, DEBUG_NAME "HIHardware: %#s\n", inMDNS->HIHardware.c );
+
+ // Setup the HINFO SW strings.
+#if ( MDNS_SET_HINFO_STRINGS )
+ mDNS_snprintf( (char *) &inMDNS->HISoftware.c[ 1 ], sizeof( inMDNS->HISoftware.c ) - 2,
+ "mDNSResponder (%s %s)", __DATE__, __TIME__ );
+ inMDNS->HISoftware.c[ 0 ] = (mDNSu8) mDNSPlatformStrLen( &inMDNS->HISoftware.c[ 1 ] );
+ dlog( kDebugLevelInfo, DEBUG_NAME "HISoftware: %#s\n", inMDNS->HISoftware.c );
+#endif
+
+ // Set up the IPv4 unicast socket
+
+ inMDNS->p->unicastSock4.fd = INVALID_SOCKET;
+ inMDNS->p->unicastSock4.recvMsgPtr = NULL;
+ inMDNS->p->unicastSock4.ifd = NULL;
+ inMDNS->p->unicastSock4.next = NULL;
+ inMDNS->p->unicastSock4.m = inMDNS;
+
+#if ( MDNS_WINDOWS_ENABLE_IPV4 )
+
+ sa4.sin_family = AF_INET;
+ sa4.sin_addr.s_addr = INADDR_ANY;
+ err = SetupSocket( inMDNS, (const struct sockaddr*) &sa4, zeroIPPort, &inMDNS->p->unicastSock4.fd );
+ check_noerr( err );
+ sa4len = sizeof( sa4 );
+ err = getsockname( inMDNS->p->unicastSock4.fd, (struct sockaddr*) &sa4, &sa4len );
+ require_noerr( err, exit );
+ inMDNS->p->unicastSock4.port.NotAnInteger = sa4.sin_port;
+ inMDNS->UnicastPort4 = inMDNS->p->unicastSock4.port;
+ err = WSAIoctl( inMDNS->p->unicastSock4.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &inMDNS->p->unicastSock4.recvMsgPtr, sizeof( inMDNS->p->unicastSock4.recvMsgPtr ), &size, NULL, NULL );
+
+ if ( err )
+ {
+ inMDNS->p->unicastSock4.recvMsgPtr = NULL;
+ }
+
+ err = mDNSPollRegisterSocket( inMDNS->p->unicastSock4.fd, FD_READ, UDPSocketNotification, &inMDNS->p->unicastSock4 );
+ require_noerr( err, exit );
+
+#endif
+
+ // Set up the IPv6 unicast socket
+
+ inMDNS->p->unicastSock6.fd = INVALID_SOCKET;
+ inMDNS->p->unicastSock6.recvMsgPtr = NULL;
+ inMDNS->p->unicastSock6.ifd = NULL;
+ inMDNS->p->unicastSock6.next = NULL;
+ inMDNS->p->unicastSock6.m = inMDNS;
+
+#if ( MDNS_WINDOWS_ENABLE_IPV6 )
+
+ if ( gEnableIPv6 )
+ {
+ sa6.sin6_family = AF_INET6;
+ sa6.sin6_addr = in6addr_any;
+ sa6.sin6_scope_id = 0;
+
+ // This call will fail if the machine hasn't installed IPv6. In that case,
+ // the error will be WSAEAFNOSUPPORT.
+
+ err = SetupSocket( inMDNS, (const struct sockaddr*) &sa6, zeroIPPort, &inMDNS->p->unicastSock6.fd );
+ require_action( !err || ( err == WSAEAFNOSUPPORT ), exit, err = (mStatus) WSAGetLastError() );
+ err = kNoErr;
+
+ // If we weren't able to create the socket (because IPv6 hasn't been installed) don't do this
+
+ if ( inMDNS->p->unicastSock6.fd != INVALID_SOCKET )
+ {
+ sa6len = sizeof( sa6 );
+ err = getsockname( inMDNS->p->unicastSock6.fd, (struct sockaddr*) &sa6, &sa6len );
+ require_noerr( err, exit );
+ inMDNS->p->unicastSock6.port.NotAnInteger = sa6.sin6_port;
+ inMDNS->UnicastPort6 = inMDNS->p->unicastSock6.port;
+
+ err = WSAIoctl( inMDNS->p->unicastSock6.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &inMDNS->p->unicastSock6.recvMsgPtr, sizeof( inMDNS->p->unicastSock6.recvMsgPtr ), &size, NULL, NULL );
+
+ if ( err != 0 )
+ {
+ inMDNS->p->unicastSock6.recvMsgPtr = NULL;
+ }
+
+ err = mDNSPollRegisterSocket( inMDNS->p->unicastSock6.fd, FD_READ, UDPSocketNotification, &inMDNS->p->unicastSock6 );
+ require_noerr( err, exit );
+ }
+ }
+
+#endif
+
+ // Notify core of domain secret keys
+
+ SetDomainSecrets( inMDNS );
+
+ // Success!
+
+ mDNSCoreInitComplete( inMDNS, err );
+
+
+exit:
+
+ if ( err )
+ {
+ mDNSPlatformClose( inMDNS );
+ }
+
+ dlog( kDebugLevelTrace, DEBUG_NAME "platform init done (err=%d %m)\n", err, err );
+ return( err );
+}
+
+//===========================================================================================================================
+// mDNSPlatformClose
+//===========================================================================================================================
+
+mDNSexport void mDNSPlatformClose( mDNS * const inMDNS )
+{
+ mStatus err;
+
+ dlog( kDebugLevelTrace, DEBUG_NAME "platform close\n" );
+ check( inMDNS );
+
+ if ( gSMBThread != NULL )
+ {
+ dlog( kDebugLevelTrace, DEBUG_NAME "tearing down smb registration thread\n" );
+ SetEvent( gSMBThreadStopEvent );
+
+ if ( WaitForSingleObject( gSMBThreadQuitEvent, 5 * 1000 ) == WAIT_OBJECT_0 )
+ {
+ if ( gSMBThreadQuitEvent )
+ {
+ CloseHandle( gSMBThreadQuitEvent );
+ gSMBThreadQuitEvent = NULL;
+ }
+
+ if ( gSMBThreadStopEvent )
+ {
+ CloseHandle( gSMBThreadStopEvent );
+ gSMBThreadStopEvent = NULL;
+ }
+
+ if ( gSMBThreadDeregisterEvent )
+ {
+ CloseHandle( gSMBThreadDeregisterEvent );
+ gSMBThreadDeregisterEvent = NULL;
+ }
+
+ if ( gSMBThreadRegisterEvent )
+ {
+ CloseHandle( gSMBThreadRegisterEvent );
+ gSMBThreadRegisterEvent = NULL;
+ }
+
+ if ( gDNSSDLibrary )
+ {
+ FreeLibrary( gDNSSDLibrary );
+ gDNSSDLibrary = NULL;
+ }
+ }
+ else
+ {
+ LogMsg( "Unable to stop SMBThread" );
+ }
+
+ inMDNS->p->smbFileSharing = mDNSfalse;
+ inMDNS->p->smbPrintSharing = mDNSfalse;
+ }
+
+ // Tear everything down in reverse order to how it was set up.
+
+ err = TearDownInterfaceList( inMDNS );
+ check_noerr( err );
+ check( !inMDNS->p->inactiveInterfaceList );
+
+#if ( MDNS_WINDOWS_ENABLE_IPV4 )
+
+ UDPCloseSocket( &inMDNS->p->unicastSock4 );
+
+#endif
+
+#if ( MDNS_WINDOWS_ENABLE_IPV6 )
+
+ if ( gEnableIPv6 )
+ {
+ UDPCloseSocket( &inMDNS->p->unicastSock6 );
+ }
+
+#endif
+
+ // Free the DLL needed for IPv6 support.
+
+#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
+ if( gIPHelperLibraryInstance )
+ {
+ gGetAdaptersAddressesFunctionPtr = NULL;
+
+ FreeLibrary( gIPHelperLibraryInstance );
+ gIPHelperLibraryInstance = NULL;
+ }
+#endif
+
+ if ( g_hAAPI32 )
+ {
+ // Release any resources
+
+ if ( g_hProvider && g_lpCryptReleaseContext )
+ {
+ ( g_lpCryptReleaseContext )( g_hProvider, 0 );
+ }
+
+ // Free the AdvApi32.dll
+
+ FreeLibrary( g_hAAPI32 );
+
+ // And reset all the data
+
+ g_lpCryptAcquireContext = NULL;
+ g_lpCryptReleaseContext = NULL;
+ g_lpCryptGenRandom = NULL;
+ g_hProvider = ( ULONG_PTR ) NULL;
+ g_hAAPI32 = NULL;
+ }
+
+ WSACleanup();
+
+ dlog( kDebugLevelTrace, DEBUG_NAME "platform close done\n" );
+}
+
+
+//===========================================================================================================================
+// mDNSPlatformLock
+//===========================================================================================================================
+
+mDNSexport void mDNSPlatformLock( const mDNS * const inMDNS )
+{
+ ( void ) inMDNS;
+}
+
+//===========================================================================================================================
+// mDNSPlatformUnlock
+//===========================================================================================================================
+
+mDNSexport void mDNSPlatformUnlock( const mDNS * const inMDNS )
+{
+ ( void ) inMDNS;
+}
+
+//===========================================================================================================================
+// mDNSPlatformStrCopy
+//===========================================================================================================================
+
+mDNSexport void mDNSPlatformStrCopy( void *inDst, const void *inSrc )
+{
+ check( inSrc );
+ check( inDst );
+
+ strcpy( (char *) inDst, (const char*) inSrc );
+}
+
+//===========================================================================================================================
+// mDNSPlatformStrLen
+//===========================================================================================================================
+
+mDNSexport mDNSu32 mDNSPlatformStrLen( const void *inSrc )
+{
+ check( inSrc );
+
+ return( (mDNSu32) strlen( (const char *) inSrc ) );
+}
+
+//===========================================================================================================================
+// mDNSPlatformMemCopy
+//===========================================================================================================================
+
+mDNSexport void mDNSPlatformMemCopy( void *inDst, const void *inSrc, mDNSu32 inSize )
+{
+ check( inSrc );
+ check( inDst );
+
+ memcpy( inDst, inSrc, inSize );
+}
+
+//===========================================================================================================================
+// mDNSPlatformMemSame
+//===========================================================================================================================
+
+mDNSexport mDNSBool mDNSPlatformMemSame( const void *inDst, const void *inSrc, mDNSu32 inSize )
+{
+ check( inSrc );
+ check( inDst );
+
+ return( (mDNSBool)( memcmp( inSrc, inDst, inSize ) == 0 ) );
+}
+
+//===========================================================================================================================
+// mDNSPlatformMemCmp
+//===========================================================================================================================
+
+mDNSexport int mDNSPlatformMemCmp( const void *inDst, const void *inSrc, mDNSu32 inSize )
+{
+ check( inSrc );
+ check( inDst );
+
+ return( memcmp( inSrc, inDst, inSize ) );
+}
+
+mDNSexport void mDNSPlatformQsort(void *base, int nel, int width, int (*compar)(const void *, const void *))
+{
+ (void)base;
+ (void)nel;
+ (void)width;
+ (void)compar;
+}
+
+// DNSSEC stub functions
+mDNSexport void VerifySignature(mDNS *const m, DNSSECVerifier *dv, DNSQuestion *q)
+ {
+ (void)m;
+ (void)dv;
+ (void)q;
+ }
+
+mDNSexport mDNSBool AddNSECSForCacheRecord(mDNS *const m, CacheRecord *crlist, CacheRecord *negcr, mDNSu8 rcode)
+ {
+ (void)m;
+ (void)crlist;
+ (void)negcr;
+ (void)rcode;
+ return mDNSfalse;
+ }
+
+mDNSexport void BumpDNSSECStats(mDNS *const m, DNSSECStatsAction action, DNSSECStatsType type, mDNSu32 value)
+ {
+ (void)m;
+ (void)action;
+ (void)type;
+ (void)value;
+ }
+
+// Proxy stub functions
+mDNSexport mDNSu8 *DNSProxySetAttributes(DNSQuestion *q, DNSMessageHeader *h, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit)
+{
+ (void) q;
+ (void) h;
+ (void) msg;
+ (void) ptr;
+ (void) limit;
+
+ return ptr;
+}
+
+mDNSexport void DNSProxyInit(mDNS *const m, mDNSu32 IpIfArr[], mDNSu32 OpIf)
+{
+ (void) m;
+ (void) IpIfArr;
+ (void) OpIf;
+}
+
+mDNSexport void DNSProxyTerminate(mDNS *const m)
+{
+ (void) m;
+}
+
+//===========================================================================================================================
+// mDNSPlatformMemZero
+//===========================================================================================================================
+
+mDNSexport void mDNSPlatformMemZero( void *inDst, mDNSu32 inSize )
+{
+ check( inDst );
+
+ memset( inDst, 0, inSize );
+}
+
+//===========================================================================================================================
+// mDNSPlatformMemAllocate
+//===========================================================================================================================
+
+mDNSexport void * mDNSPlatformMemAllocate( mDNSu32 inSize )
+{
+ void * mem;
+
+ check( inSize > 0 );
+
+ mem = malloc( inSize );
+ check( mem );
+
+ return( mem );
+}
+
+//===========================================================================================================================
+// mDNSPlatformMemFree
+//===========================================================================================================================
+
+mDNSexport void mDNSPlatformMemFree( void *inMem )
+{
+ check( inMem );
+
+ free( inMem );
+}
+
+//===========================================================================================================================
+// mDNSPlatformRandomNumber
+//===========================================================================================================================
+
+mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
+{
+ unsigned int randomNumber;
+ errno_t err;
+
+ err = rand_s( &randomNumber );
+ require_noerr( err, exit );
+
+exit:
+
+ if ( err )
+ {
+ randomNumber = rand();
+ }
+
+ return ( mDNSu32 ) randomNumber;
+}
+
+//===========================================================================================================================
+// mDNSPlatformTimeInit
+//===========================================================================================================================
+
+mDNSexport mStatus mDNSPlatformTimeInit( void )
+{
+ // No special setup is required on Windows -- we just use GetTickCount().
+ return( mStatus_NoError );
+}
+
+//===========================================================================================================================
+// mDNSPlatformRawTime
+//===========================================================================================================================
+
+mDNSexport mDNSs32 mDNSPlatformRawTime( void )
+{
+ return( (mDNSs32) GetTickCount() );
+}
+
+//===========================================================================================================================
+// mDNSPlatformUTC
+//===========================================================================================================================
+
+mDNSexport mDNSs32 mDNSPlatformUTC( void )
+{
+ return ( mDNSs32 ) time( NULL );
+}
+
+//===========================================================================================================================
+// mDNSPlatformInterfaceNameToID
+//===========================================================================================================================
+
+mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID )
+{
+ mStatus err;
+ mDNSInterfaceData * ifd;
+
+ check( inMDNS );
+ check( inMDNS->p );
+ check( inName );
+
+ // Search for an interface with the specified name,
+
+ for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
+ {
+ if( strcmp( ifd->name, inName ) == 0 )
+ {
+ break;
+ }
+ }
+ require_action_quiet( ifd, exit, err = mStatus_NoSuchNameErr );
+
+ // Success!
+
+ if( outID )
+ {
+ *outID = (mDNSInterfaceID) ifd;
+ }
+ err = mStatus_NoError;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// mDNSPlatformInterfaceIDToInfo
+//===========================================================================================================================
+
+mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo )
+{
+ mStatus err;
+ mDNSInterfaceData * ifd;
+
+ check( inMDNS );
+ check( inID );
+ check( outInfo );
+
+ // Search for an interface with the specified ID,
+
+ for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
+ {
+ if( ifd == (mDNSInterfaceData *) inID )
+ {
+ break;
+ }
+ }
+ require_action_quiet( ifd, exit, err = mStatus_NoSuchNameErr );
+
+ // Success!
+
+ outInfo->name = ifd->name;
+ outInfo->ip = ifd->interfaceInfo.ip;
+ err = mStatus_NoError;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// mDNSPlatformInterfaceIDfromInterfaceIndex
+//===========================================================================================================================
+
+mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS * const inMDNS, mDNSu32 inIndex )
+{
+ mDNSInterfaceID id;
+
+ id = mDNSNULL;
+ if( inIndex == kDNSServiceInterfaceIndexLocalOnly )
+ {
+ id = mDNSInterface_LocalOnly;
+ }
+ else if( inIndex != 0 )
+ {
+ mDNSInterfaceData * ifd;
+
+ for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
+ {
+ if( ( ifd->scopeID == inIndex ) && ifd->interfaceInfo.InterfaceActive )
+ {
+ id = ifd->interfaceInfo.InterfaceID;
+ break;
+ }
+ }
+ check( ifd );
+ }
+ return( id );
+}
+
+//===========================================================================================================================
+// mDNSPlatformInterfaceIndexfromInterfaceID
+//===========================================================================================================================
+
+mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSBool suppressNetworkChange )
+{
+ mDNSu32 index;
+
+ (void) suppressNetworkChange;
+
+ index = 0;
+ if( inID == mDNSInterface_LocalOnly )
+ {
+ index = (mDNSu32) kDNSServiceInterfaceIndexLocalOnly;
+ }
+ else if( inID )
+ {
+ mDNSInterfaceData * ifd;
+
+ // Search active interfaces.
+ for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
+ {
+ if( (mDNSInterfaceID) ifd == inID )
+ {
+ index = ifd->scopeID;
+ break;
+ }
+ }
+
+ // Search inactive interfaces too so remove events for inactive interfaces report the old interface index.
+
+ if( !ifd )
+ {
+ for( ifd = inMDNS->p->inactiveInterfaceList; ifd; ifd = ifd->next )
+ {
+ if( (mDNSInterfaceID) ifd == inID )
+ {
+ index = ifd->scopeID;
+ break;
+ }
+ }
+ }
+ check( ifd );
+ }
+ return( index );
+}
+
+
+//===========================================================================================================================
+// mDNSPlatformTCPSocket
+//===========================================================================================================================
+
+TCPSocket *
+mDNSPlatformTCPSocket
+ (
+ mDNS * const m,
+ TCPSocketFlags flags,
+ mDNSIPPort * port,
+ mDNSBool useBackgroundTrafficClass
+ )
+{
+ TCPSocket * sock = NULL;
+ u_long on = 1; // "on" for setsockopt
+ struct sockaddr_in saddr;
+ int len;
+ mStatus err = mStatus_NoError;
+
+ DEBUG_UNUSED( m );
+ DEBUG_UNUSED( useBackgroundTrafficClass );
+
+ require_action( flags == 0, exit, err = mStatus_UnsupportedErr );
+
+ // Setup connection data object
+
+ sock = (TCPSocket *) malloc( sizeof( TCPSocket ) );
+ require_action( sock, exit, err = mStatus_NoMemoryErr );
+ mDNSPlatformMemZero( sock, sizeof( TCPSocket ) );
+ sock->fd = INVALID_SOCKET;
+ sock->flags = flags;
+ sock->m = m;
+
+ mDNSPlatformMemZero(&saddr, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ saddr.sin_addr.s_addr = htonl( INADDR_ANY );
+ saddr.sin_port = port->NotAnInteger;
+
+ // Create the socket
+
+ sock->fd = socket(AF_INET, SOCK_STREAM, 0);
+ err = translate_errno( sock->fd != INVALID_SOCKET, WSAGetLastError(), mStatus_UnknownErr );
+ require_noerr( err, exit );
+
+ // bind
+
+ err = bind( sock->fd, ( struct sockaddr* ) &saddr, sizeof( saddr ) );
+ err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
+ require_noerr( err, exit );
+
+ // Set it to be non-blocking
+
+ err = ioctlsocket( sock->fd, FIONBIO, &on );
+ err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
+ require_noerr( err, exit );
+
+ // Get port number
+
+ mDNSPlatformMemZero( &saddr, sizeof( saddr ) );
+ len = sizeof( saddr );
+
+ err = getsockname( sock->fd, ( struct sockaddr* ) &saddr, &len );
+ err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
+ require_noerr( err, exit );
+
+ port->NotAnInteger = saddr.sin_port;
+
+exit:
+
+ if ( err && sock )
+ {
+ TCPCloseSocket( sock );
+ free( sock );
+ sock = mDNSNULL;
+ }
+
+ return sock;
+}
+
+//===========================================================================================================================
+// mDNSPlatformTCPConnect
+//===========================================================================================================================
+
+mStatus
+mDNSPlatformTCPConnect
+ (
+ TCPSocket * sock,
+ const mDNSAddr * inDstIP,
+ mDNSOpaque16 inDstPort,
+ domainname * hostname,
+ mDNSInterfaceID inInterfaceID,
+ TCPConnectionCallback inCallback,
+ void * inContext
+ )
+{
+ struct sockaddr_in saddr;
+ mStatus err = mStatus_NoError;
+
+ DEBUG_UNUSED( hostname );
+ DEBUG_UNUSED( inInterfaceID );
+
+ if ( inDstIP->type != mDNSAddrType_IPv4 )
+ {
+ LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: operation not supported");
+ return mStatus_UnknownErr;
+ }
+
+ // Setup connection data object
+
+ sock->userCallback = inCallback;
+ sock->userContext = inContext;
+
+ mDNSPlatformMemZero(&saddr, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ saddr.sin_port = inDstPort.NotAnInteger;
+ memcpy(&saddr.sin_addr, &inDstIP->ip.v4.NotAnInteger, sizeof(saddr.sin_addr));
+
+ // Try and do connect
+
+ err = connect( sock->fd, ( struct sockaddr* ) &saddr, sizeof( saddr ) );
+ require_action( !err || ( WSAGetLastError() == WSAEWOULDBLOCK ), exit, err = mStatus_ConnFailed );
+ sock->connected = !err ? TRUE : FALSE;
+
+ err = mDNSPollRegisterSocket( sock->fd, FD_CONNECT | FD_READ | FD_CLOSE, TCPSocketNotification, sock );
+ require_noerr( err, exit );
+
+exit:
+
+ if ( !err )
+ {
+ err = sock->connected ? mStatus_ConnEstablished : mStatus_ConnPending;
+ }
+
+ return err;
+}
+
+
+//===========================================================================================================================
+// mDNSPlatformTCPAccept
+//===========================================================================================================================
+
+mDNSexport
+mDNSexport TCPSocket *mDNSPlatformTCPAccept( TCPSocketFlags flags, int fd )
+ {
+ TCPSocket * sock = NULL;
+ mStatus err = mStatus_NoError;
+
+ require_action( !flags, exit, err = mStatus_UnsupportedErr );
+
+ sock = malloc( sizeof( TCPSocket ) );
+ require_action( sock, exit, err = mStatus_NoMemoryErr );
+
+ mDNSPlatformMemZero( sock, sizeof( *sock ) );
+
+ sock->fd = fd;
+ sock->flags = flags;
+
+exit:
+
+ if ( err && sock )
+ {
+ free( sock );
+ sock = NULL;
+ }
+
+ return sock;
+ }
+
+
+//===========================================================================================================================
+// mDNSPlatformTCPCloseConnection
+//===========================================================================================================================
+
+mDNSexport void mDNSPlatformTCPCloseConnection( TCPSocket *sock )
+{
+ check( sock );
+
+ if ( sock )
+ {
+ dlog( kDebugLevelChatty, DEBUG_NAME "mDNSPlatformTCPCloseConnection 0x%x:%d\n", sock, sock->fd );
+
+ if ( sock->fd != INVALID_SOCKET )
+ {
+ mDNSPollUnregisterSocket( sock->fd );
+ closesocket( sock->fd );
+ sock->fd = INVALID_SOCKET;
+ }
+
+ free( sock );
+ }
+}
+
+
+//===========================================================================================================================
+// mDNSPlatformReadTCP
+//===========================================================================================================================
+
+mDNSexport long mDNSPlatformReadTCP( TCPSocket *sock, void *inBuffer, unsigned long inBufferSize, mDNSBool * closed )
+{
+ int nread;
+ OSStatus err;
+
+ *closed = mDNSfalse;
+ nread = recv( sock->fd, inBuffer, inBufferSize, 0 );
+ err = translate_errno( ( nread >= 0 ), WSAGetLastError(), mStatus_UnknownErr );
+
+ if ( nread > 0 )
+ {
+ dlog( kDebugLevelChatty, DEBUG_NAME "mDNSPlatformReadTCP: 0x%x:%d read %d bytes\n", sock, sock->fd, nread );
+ }
+ else if ( !nread )
+ {
+ *closed = mDNStrue;
+ }
+ else if ( err == WSAECONNRESET )
+ {
+ *closed = mDNStrue;
+ nread = 0;
+ }
+ else if ( err == WSAEWOULDBLOCK )
+ {
+ nread = 0;
+ }
+ else
+ {
+ LogMsg( "ERROR: mDNSPlatformReadTCP - recv: %d\n", err );
+ nread = -1;
+ }
+
+ return nread;
+}
+
+
+//===========================================================================================================================
+// mDNSPlatformWriteTCP
+//===========================================================================================================================
+
+mDNSexport long mDNSPlatformWriteTCP( TCPSocket *sock, const char *inMsg, unsigned long inMsgSize )
+{
+ int nsent;
+ OSStatus err;
+
+ nsent = send( sock->fd, inMsg, inMsgSize, 0 );
+
+ err = translate_errno( ( nsent >= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK ), WSAGetLastError(), mStatus_UnknownErr );
+ require_noerr( err, exit );
+
+ if ( nsent < 0)
+ {
+ nsent = 0;
+ }
+
+exit:
+
+ return nsent;
+}
+
+//===========================================================================================================================
+// mDNSPlatformTCPGetFD
+//===========================================================================================================================
+
+mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock )
+{
+ return ( int ) sock->fd;
+}
+
+
+
+//===========================================================================================================================
+// TCPSocketNotification
+//===========================================================================================================================
+
+mDNSlocal void CALLBACK
+TCPSocketNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context )
+{
+ TCPSocket *tcpSock = ( TCPSocket* ) context;
+ TCPConnectionCallback callback;
+ int err;
+
+ DEBUG_UNUSED( sock );
+
+ require_action( tcpSock, exit, err = mStatus_BadParamErr );
+ callback = ( TCPConnectionCallback ) tcpSock->userCallback;
+ require_action( callback, exit, err = mStatus_BadParamErr );
+
+ if ( event && ( event->lNetworkEvents & FD_CONNECT ) )
+ {
+ if ( event->iErrorCode[ FD_CONNECT_BIT ] == 0 )
+ {
+ callback( tcpSock, tcpSock->userContext, mDNStrue, 0 );
+ tcpSock->connected = mDNStrue;
+ }
+ else
+ {
+ callback( tcpSock, tcpSock->userContext, mDNSfalse, event->iErrorCode[ FD_CONNECT_BIT ] );
+ }
+ }
+ else
+ {
+ callback( tcpSock, tcpSock->userContext, mDNSfalse, 0 );
+ }
+
+exit:
+
+ return;
+}
+
+
+
+//===========================================================================================================================
+// mDNSPlatformUDPSocket
+//===========================================================================================================================
+
+mDNSexport UDPSocket* mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport)
+{
+ UDPSocket* sock = NULL;
+ mDNSIPPort port = requestedport;
+ mStatus err = mStatus_NoError;
+ unsigned i;
+
+ // Setup connection data object
+
+ sock = ( UDPSocket* ) malloc(sizeof( UDPSocket ) );
+ require_action( sock, exit, err = mStatus_NoMemoryErr );
+ memset( sock, 0, sizeof( UDPSocket ) );
+
+ // Create the socket
+
+ sock->fd = INVALID_SOCKET;
+ sock->recvMsgPtr = m->p->unicastSock4.recvMsgPtr;
+ sock->addr = m->p->unicastSock4.addr;
+ sock->ifd = NULL;
+ sock->m = m;
+
+ // Try at most 10000 times to get a unique random port
+
+ for (i=0; i<10000; i++)
+ {
+ struct sockaddr_in saddr;
+
+ saddr.sin_family = AF_INET;
+ saddr.sin_addr.s_addr = 0;
+
+ // The kernel doesn't do cryptographically strong random port
+ // allocation, so we do it ourselves here
+
+ if (mDNSIPPortIsZero(requestedport))
+ {
+ port = mDNSOpaque16fromIntVal( ( mDNSu16 ) ( 0xC000 + mDNSRandom(0x3FFF) ) );
+ }
+
+ saddr.sin_port = port.NotAnInteger;
+
+ err = SetupSocket(m, ( struct sockaddr* ) &saddr, port, &sock->fd );
+ if (!err) break;
+ }
+
+ require_noerr( err, exit );
+
+ // Set the port
+
+ sock->port = port;
+
+ // Arm the completion routine
+
+ err = mDNSPollRegisterSocket( sock->fd, FD_READ, UDPSocketNotification, sock );
+ require_noerr( err, exit );
+
+ // Bookkeeping
+
+ sock->next = gUDPSockets;
+ gUDPSockets = sock;
+ gUDPNumSockets++;
+
+exit:
+
+ if ( err && sock )
+ {
+ UDPCloseSocket( sock );
+ free( sock );
+ sock = NULL;
+ }
+
+ return sock;
+}
+
+//===========================================================================================================================
+// mDNSPlatformUDPClose
+//===========================================================================================================================
+
+mDNSexport void mDNSPlatformUDPClose( UDPSocket *sock )
+{
+ UDPSocket * current = gUDPSockets;
+ UDPSocket * last = NULL;
+
+ while ( current )
+ {
+ if ( current == sock )
+ {
+ if ( last == NULL )
+ {
+ gUDPSockets = sock->next;
+ }
+ else
+ {
+ last->next = sock->next;
+ }
+
+ UDPCloseSocket( sock );
+ free( sock );
+
+ gUDPNumSockets--;
+
+ break;
+ }
+
+ last = current;
+ current = current->next;
+ }
+}
+
+
+//===========================================================================================================================
+// mDNSPlatformSendUDP
+//===========================================================================================================================
+
+mDNSexport mStatus
+ mDNSPlatformSendUDP(
+ const mDNS * const inMDNS,
+ const void * const inMsg,
+ const mDNSu8 * const inMsgEnd,
+ mDNSInterfaceID inInterfaceID,
+ UDPSocket * inSrcSocket,
+ const mDNSAddr * inDstIP,
+ mDNSIPPort inDstPort,
+ mDNSBool useBackgroundTrafficClass )
+{
+ SOCKET sendingsocket = INVALID_SOCKET;
+ mStatus err = mStatus_NoError;
+ mDNSInterfaceData * ifd = (mDNSInterfaceData*) inInterfaceID;
+ struct sockaddr_storage addr;
+ int n;
+
+ DEBUG_USE_ONLY( inMDNS );
+ DEBUG_USE_ONLY( useBackgroundTrafficClass );
+
+ n = (int)( inMsgEnd - ( (const mDNSu8 * const) inMsg ) );
+ check( inMDNS );
+ check( inMsg );
+ check( inMsgEnd );
+ check( inDstIP );
+
+ dlog( kDebugLevelChatty, DEBUG_NAME "platform send %d bytes to %#a:%u\n", n, inDstIP, ntohs( inDstPort.NotAnInteger ) );
+
+ if( inDstIP->type == mDNSAddrType_IPv4 )
+ {
+ struct sockaddr_in * sa4;
+
+ sa4 = (struct sockaddr_in *) &addr;
+ sa4->sin_family = AF_INET;
+ sa4->sin_port = inDstPort.NotAnInteger;
+ sa4->sin_addr.s_addr = inDstIP->ip.v4.NotAnInteger;
+ sendingsocket = ifd ? ifd->sock.fd : inMDNS->p->unicastSock4.fd;
+
+ if (inSrcSocket) { sendingsocket = inSrcSocket->fd; debugf("mDNSPlatformSendUDP using port %d, static port %d, sock %d", mDNSVal16(inSrcSocket->port), inMDNS->p->unicastSock4.fd, sendingsocket); }
+ }
+ else if( inDstIP->type == mDNSAddrType_IPv6 )
+ {
+ struct sockaddr_in6 * sa6;
+
+ sa6 = (struct sockaddr_in6 *) &addr;
+ sa6->sin6_family = AF_INET6;
+ sa6->sin6_port = inDstPort.NotAnInteger;
+ sa6->sin6_flowinfo = 0;
+ sa6->sin6_addr = *( (struct in6_addr *) &inDstIP->ip.v6 );
+ sa6->sin6_scope_id = 0; // Windows requires the scope ID to be zero. IPV6_MULTICAST_IF specifies interface.
+ sendingsocket = ifd ? ifd->sock.fd : inMDNS->p->unicastSock6.fd;
+ }
+ else
+ {
+ dlog( kDebugLevelError, DEBUG_NAME "%s: dst is not an IPv4 or IPv6 address (type=%d)\n", __ROUTINE__, inDstIP->type );
+ err = mStatus_BadParamErr;
+ goto exit;
+ }
+
+ if (IsValidSocket(sendingsocket))
+ {
+ n = sendto( sendingsocket, (char *) inMsg, n, 0, (struct sockaddr *) &addr, sizeof( addr ) );
+ err = translate_errno( n > 0, errno_compat(), kWriteErr );
+
+ if ( err )
+ {
+ // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
+
+ if ( !mDNSAddressIsAllDNSLinkGroup( inDstIP ) && ( WSAGetLastError() == WSAEHOSTDOWN || WSAGetLastError() == WSAENETDOWN || WSAGetLastError() == WSAEHOSTUNREACH || WSAGetLastError() == WSAENETUNREACH ) )
+ {
+ err = mStatus_TransientErr;
+ }
+ else
+ {
+ require_noerr( err, exit );
+ }
+ }
+ }
+
+exit:
+ return( err );
+}
+
+
+mDNSexport mDNSBool mDNSPlatformPeekUDP(mDNS *const m, UDPSocket *src)
+{
+ DEBUG_UNUSED( m );
+ DEBUG_UNUSED( src );
+ return mDNSfalse;
+}
+
+mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
+ {
+ DEBUG_UNUSED( m );
+ DEBUG_UNUSED( InterfaceID );
+ }
+
+
+mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason)
+ {
+ DEBUG_UNUSED( m );
+ DEBUG_UNUSED( allowSleep );
+ DEBUG_UNUSED( reason );
+ }
+
+//===========================================================================================================================
+// mDNSPlatformSendRawPacket
+//===========================================================================================================================
+
+mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *ethaddr, char *ipaddr, int iteration)
+{
+ unsigned char mac[ 6 ];
+ unsigned char buf[ 102 ];
+ char hex[ 3 ] = { 0 };
+ unsigned char *bufPtr = buf;
+ struct sockaddr_storage saddr;
+ INT len = sizeof( saddr );
+ mDNSBool unicast = mDNSfalse;
+ MulticastWakeupStruct *info;
+ int i;
+ mStatus err;
+
+ (void) InterfaceID;
+
+ require_action( ethaddr, exit, err = mStatus_BadParamErr );
+
+ for ( i = 0; i < 6; i++ )
+ {
+ memcpy( hex, ethaddr + ( i * 3 ), 2 );
+ mac[ i ] = ( unsigned char ) strtoul( hex, NULL, 16 );
+ }
+
+ memset( buf, 0, sizeof( buf ) );
+
+ for ( i = 0; i < 6; i++ )
+ {
+ *bufPtr++ = 0xff;
+ }
+
+ for ( i = 0; i < 16; i++ )
+ {
+ memcpy( bufPtr, mac, sizeof( mac ) );
+ bufPtr += sizeof( mac );
+ }
+
+ if ( ipaddr )
+ {
+ if ( WSAStringToAddressA( ipaddr, AF_INET, NULL, ( LPSOCKADDR ) &saddr, &len ) == 0 )
+ {
+ struct sockaddr_in * saddr4 = ( struct sockaddr_in* ) &saddr;
+ saddr4->sin_port = htons( 9 );
+ len = sizeof( *saddr4 );
+
+ if ( saddr4->sin_addr.s_addr != htonl( INADDR_ANY ) )
+ {
+ unicast = mDNStrue;
+ }
+ }
+ else if ( WSAStringToAddressA( ipaddr, AF_INET6, NULL, ( LPSOCKADDR ) &saddr, &len ) == 0 )
+ {
+ mDNSInterfaceData *ifd = ( mDNSInterfaceData* ) InterfaceID;
+ struct sockaddr_in6 * saddr6 = ( struct sockaddr_in6* ) &saddr;
+ saddr6->sin6_port = htons( 9 );
+
+ if ( ifd != NULL )
+ {
+ saddr6->sin6_scope_id = ifd->scopeID;
+ }
+
+ len = sizeof( *saddr6 );
+
+ if ( memcmp( &saddr6->sin6_addr, &in6addr_any, sizeof( IN6_ADDR ) ) != 0 )
+ {
+ unicast = mDNStrue;
+ }
+ }
+ }
+
+ if ( ( iteration < 2 ) && ( unicast ) )
+ {
+ SendWakeupPacket( m, ( LPSOCKADDR ) &saddr, len, ( const char* ) buf, sizeof( buf ), kUnicastWakeupNumTries, kUnicastWakeupSleepBetweenTries );
+ }
+
+ info = ( MulticastWakeupStruct* ) malloc( sizeof( MulticastWakeupStruct ) );
+ require_action( info, exit, err = mStatus_NoMemoryErr );
+ info->inMDNS = m;
+ memset( &info->addr, 0, sizeof( info->addr ) );
+ info->addr.sin_family = AF_INET;
+ info->addr.sin_addr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
+ info->addr.sin_port = htons( 9 );
+ info->addrLen = sizeof( info->addr );
+ memcpy( info->data, buf, sizeof( buf ) );
+ info->dataLen = sizeof( buf );
+ info->numTries = kMulticastWakeupNumTries;
+ info->msecSleep = kMulticastWakeupSleepBetweenTries;
+
+ _beginthread( SendMulticastWakeupPacket, 0, ( void* ) info );
+
+exit:
+
+ return;
+}
+
+
+mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const NetworkInterfaceInfo *intf)
+{
+ DEBUG_UNUSED( rr );
+ DEBUG_UNUSED( intf );
+
+ return mDNStrue;
+}
+
+mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf)
+{
+ DEBUG_UNUSED( q );
+ DEBUG_UNUSED( intf );
+
+ return mDNStrue;
+}
+
+mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
+ {
+ DEBUG_UNUSED( msg );
+ DEBUG_UNUSED( end );
+ DEBUG_UNUSED( InterfaceID );
+ }
+
+// Used for debugging purposes. For now, just set the buffer to zero
+mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize)
+ {
+ DEBUG_UNUSED( te );
+ if (bufsize) buf[0] = 0;
+ }
+
+
+mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
+ {
+ DEBUG_UNUSED( m );
+ DEBUG_UNUSED( tpa );
+ DEBUG_UNUSED( tha );
+ DEBUG_UNUSED( InterfaceID );
+ }
+
+
+mDNSexport void mDNSPlatformReceiveRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
+ {
+ DEBUG_UNUSED( msg );
+ DEBUG_UNUSED( end );
+ DEBUG_UNUSED( InterfaceID );
+ }
+
+mDNSexport void mDNSPlatformSetLocalARP( const mDNSv4Addr * const tpa, const mDNSEthAddr * const tha, mDNSInterfaceID InterfaceID )
+ {
+ DEBUG_UNUSED( tpa );
+ DEBUG_UNUSED( tha );
+ DEBUG_UNUSED( InterfaceID );
+ }
+
+mDNSexport void mDNSPlatformWriteDebugMsg(const char *msg)
+ {
+ dlog( kDebugLevelInfo, "%s\n", msg );
+ }
+
+mDNSexport void mDNSPlatformWriteLogMsg( const char * ident, const char * msg, mDNSLogLevel_t loglevel )
+ {
+ extern mDNS mDNSStorage;
+ int type;
+
+ DEBUG_UNUSED( ident );
+
+ type = EVENTLOG_ERROR_TYPE;
+
+ switch (loglevel)
+ {
+ case MDNS_LOG_MSG: type = EVENTLOG_ERROR_TYPE; break;
+ case MDNS_LOG_OPERATION: type = EVENTLOG_WARNING_TYPE; break;
+ case MDNS_LOG_SPS: type = EVENTLOG_INFORMATION_TYPE; break;
+ case MDNS_LOG_INFO: type = EVENTLOG_INFORMATION_TYPE; break;
+ case MDNS_LOG_DEBUG: type = EVENTLOG_INFORMATION_TYPE; break;
+ default:
+ fprintf(stderr, "Unknown loglevel %d, assuming LOG_ERR\n", loglevel);
+ fflush(stderr);
+ }
+
+ mDNSStorage.p->reportStatusFunc( type, msg );
+ dlog( kDebugLevelInfo, "%s\n", msg );
+ }
+
+mDNSexport void mDNSPlatformSourceAddrForDest( mDNSAddr * const src, const mDNSAddr * const dst )
+ {
+ DEBUG_UNUSED( src );
+ DEBUG_UNUSED( dst );
+ }
+
+//===========================================================================================================================
+// mDNSPlatformTLSSetupCerts
+//===========================================================================================================================
+
+mDNSexport mStatus
+mDNSPlatformTLSSetupCerts(void)
+{
+ return mStatus_UnsupportedErr;
+}
+
+//===========================================================================================================================
+// mDNSPlatformTLSTearDownCerts
+//===========================================================================================================================
+
+mDNSexport void
+mDNSPlatformTLSTearDownCerts(void)
+{
+}
+
+//===========================================================================================================================
+// mDNSPlatformSetDNSConfig
+//===========================================================================================================================
+
+mDNSlocal void SetDNSServers( mDNS *const m );
+mDNSlocal void SetSearchDomainList( void );
+
+mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **regDomains, DNameListElem **browseDomains, mDNSBool ackConfig)
+{
+ (void) ackConfig;
+
+ if (setservers) SetDNSServers(m);
+ if (setsearch) SetSearchDomainList();
+
+ if ( fqdn )
+ {
+ GetDDNSFQDN( fqdn );
+ }
+
+ if ( browseDomains )
+ {
+ GetDDNSDomains( browseDomains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSBrowseDomains );
+ }
+
+ if ( regDomains )
+ {
+ GetDDNSDomains( regDomains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains );
+ }
+ return mDNStrue;
+}
+
+
+//===========================================================================================================================
+// mDNSPlatformDynDNSHostNameStatusChanged
+//===========================================================================================================================
+
+mDNSexport void
+mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
+{
+ char uname[MAX_ESCAPED_DOMAIN_NAME];
+ BYTE bStatus;
+ LPCTSTR name;
+ HKEY key = NULL;
+ mStatus err;
+ char * p;
+
+ ConvertDomainNameToCString(dname, uname);
+
+ p = uname;
+
+ while (*p)
+ {
+ *p = (char) tolower(*p);
+ if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
+ p++;
+ }
+
+ check( strlen( p ) <= MAX_ESCAPED_DOMAIN_NAME );
+ name = kServiceParametersNode TEXT("\\DynDNS\\State\\HostNames");
+ err = RegCreateKey( HKEY_LOCAL_MACHINE, name, &key );
+ require_noerr( err, exit );
+
+ bStatus = ( status ) ? 0 : 1;
+ err = RegSetValueEx( key, kServiceDynDNSStatus, 0, REG_DWORD, (const LPBYTE) &bStatus, sizeof(DWORD) );
+ require_noerr( err, exit );
+
+exit:
+
+ if ( key )
+ {
+ RegCloseKey( key );
+ }
+
+ return;
+}
+
+
+//===========================================================================================================================
+// SetDomainSecrets
+//===========================================================================================================================
+
+// This routine needs to be called whenever the system secrets database changes.
+// We call it from DynDNSConfigDidChange and mDNSPlatformInit
+
+void
+SetDomainSecrets( mDNS * const m )
+{
+ DomainAuthInfo *ptr;
+ domainname fqdn;
+ DNameListElem * regDomains = NULL;
+
+ // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
+ // In the case where the user simultaneously removes their DDNS host name and the key
+ // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
+ // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
+ // address records behind that we no longer have permission to delete.
+
+ for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
+ ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
+
+ GetDDNSFQDN( &fqdn );
+
+ if ( fqdn.c[ 0 ] )
+ {
+ SetDomainSecret( m, &fqdn );
+ }
+
+ GetDDNSDomains( ®Domains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains );
+
+ while ( regDomains )
+ {
+ DNameListElem * current = regDomains;
+ SetDomainSecret( m, ¤t->name );
+ regDomains = regDomains->next;
+ free( current );
+ }
+}
+
+
+//===========================================================================================================================
+// SetSearchDomainList
+//===========================================================================================================================
+
+mDNSlocal void SetDomainFromDHCP( void );
+mDNSlocal void SetReverseMapSearchDomainList( void );
+
+mDNSlocal void
+SetSearchDomainList( void )
+{
+ char * searchList = NULL;
+ DWORD searchListLen;
+ //DNameListElem * head = NULL;
+ //DNameListElem * current = NULL;
+ char * tok;
+ HKEY key;
+ mStatus err;
+
+ err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &key );
+ require_noerr( err, exit );
+
+ err = RegQueryString( key, "SearchList", &searchList, &searchListLen, NULL );
+ require_noerr( err, exit );
+
+ // Windows separates the search domains with ','
+
+ tok = strtok( searchList, "," );
+ while ( tok )
+ {
+ if ( ( strcmp( tok, "" ) != 0 ) && ( strcmp( tok, "." ) != 0 ) )
+ mDNS_AddSearchDomain_CString(tok, mDNSNULL);
+ tok = strtok( NULL, "," );
+ }
+
+exit:
+
+ if ( searchList )
+ {
+ free( searchList );
+ }
+
+ if ( key )
+ {
+ RegCloseKey( key );
+ }
+
+ SetDomainFromDHCP();
+ SetReverseMapSearchDomainList();
+}
+
+
+//===========================================================================================================================
+// SetReverseMapSearchDomainList
+//===========================================================================================================================
+
+mDNSlocal void
+SetReverseMapSearchDomainList( void )
+{
+ struct ifaddrs * ifa;
+
+ ifa = myGetIfAddrs( 1 );
+ while (ifa)
+ {
+ mDNSAddr addr;
+
+ if (ifa->ifa_addr->sa_family == AF_INET && !SetupAddr(&addr, ifa->ifa_addr) && !(ifa->ifa_flags & IFF_LOOPBACK) && ifa->ifa_netmask)
+ {
+ mDNSAddr netmask;
+ char buffer[256];
+
+ if (!SetupAddr(&netmask, ifa->ifa_netmask))
+ {
+ sprintf(buffer, "%d.%d.%d.%d.in-addr.arpa.", addr.ip.v4.b[3] & netmask.ip.v4.b[3],
+ addr.ip.v4.b[2] & netmask.ip.v4.b[2],
+ addr.ip.v4.b[1] & netmask.ip.v4.b[1],
+ addr.ip.v4.b[0] & netmask.ip.v4.b[0]);
+ mDNS_AddSearchDomain_CString(buffer, mDNSNULL);
+ }
+ }
+
+ ifa = ifa->ifa_next;
+ }
+
+ return;
+}
+
+
+//===========================================================================================================================
+// SetDNSServers
+//===========================================================================================================================
+
+mDNSlocal void
+SetDNSServers( mDNS *const m )
+{
+ PIP_PER_ADAPTER_INFO pAdapterInfo = NULL;
+ FIXED_INFO * fixedInfo = NULL;
+ ULONG bufLen = 0;
+ IP_ADDR_STRING * dnsServerList;
+ IP_ADDR_STRING * ipAddr;
+ DWORD index;
+ int i = 0;
+ mStatus err = kUnknownErr;
+
+ // Get the primary interface.
+
+ index = GetPrimaryInterface();
+
+ // This should have the interface index of the primary index. Fall back in cases where
+ // it can't be determined.
+
+ if ( index )
+ {
+ bufLen = 0;
+
+ for ( i = 0; i < 100; i++ )
+ {
+ err = GetPerAdapterInfo( index, pAdapterInfo, &bufLen );
+
+ if ( err != ERROR_BUFFER_OVERFLOW )
+ {
+ break;
+ }
+
+ pAdapterInfo = (PIP_PER_ADAPTER_INFO) realloc( pAdapterInfo, bufLen );
+ require_action( pAdapterInfo, exit, err = mStatus_NoMemoryErr );
+ }
+
+ require_noerr( err, exit );
+
+ dnsServerList = &pAdapterInfo->DnsServerList;
+ }
+ else
+ {
+ bufLen = sizeof( FIXED_INFO );
+
+ for ( i = 0; i < 100; i++ )
+ {
+ if ( fixedInfo )
+ {
+ GlobalFree( fixedInfo );
+ fixedInfo = NULL;
+ }
+
+ fixedInfo = (FIXED_INFO*) GlobalAlloc( GPTR, bufLen );
+ require_action( fixedInfo, exit, err = mStatus_NoMemoryErr );
+
+ err = GetNetworkParams( fixedInfo, &bufLen );
+
+ if ( err != ERROR_BUFFER_OVERFLOW )
+ {
+ break;
+ }
+ }
+
+ require_noerr( err, exit );
+
+ dnsServerList = &fixedInfo->DnsServerList;
+ }
+
+ for ( ipAddr = dnsServerList; ipAddr; ipAddr = ipAddr->Next )
+ {
+ mDNSAddr addr;
+ err = StringToAddress( &addr, ipAddr->IpAddress.String );
+ if ( !err ) mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, 0, &addr, UnicastDNSPort, kScopeNone, DEFAULT_UDNS_TIMEOUT, mDNSfalse, 0, mDNStrue, mDNStrue, mDNSfalse);
+ }
+
+exit:
+
+ if ( pAdapterInfo )
+ {
+ free( pAdapterInfo );
+ }
+
+ if ( fixedInfo )
+ {
+ GlobalFree( fixedInfo );
+ }
+}
+
+
+//===========================================================================================================================
+// SetDomainFromDHCP
+//===========================================================================================================================
+
+mDNSlocal void
+SetDomainFromDHCP( void )
+{
+ int i = 0;
+ IP_ADAPTER_INFO * pAdapterInfo;
+ IP_ADAPTER_INFO * pAdapter;
+ DWORD bufLen;
+ DWORD index;
+ HKEY key = NULL;
+ LPSTR domain = NULL;
+ DWORD dwSize;
+ mStatus err = mStatus_NoError;
+
+ pAdapterInfo = NULL;
+
+ for ( i = 0; i < 100; i++ )
+ {
+ err = GetAdaptersInfo( pAdapterInfo, &bufLen);
+
+ if ( err != ERROR_BUFFER_OVERFLOW )
+ {
+ break;
+ }
+
+ pAdapterInfo = (IP_ADAPTER_INFO*) realloc( pAdapterInfo, bufLen );
+ require_action( pAdapterInfo, exit, err = kNoMemoryErr );
+ }
+
+ require_noerr( err, exit );
+
+ index = GetPrimaryInterface();
+
+ for ( pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next )
+ {
+ if ( pAdapter->IpAddressList.IpAddress.String &&
+ pAdapter->IpAddressList.IpAddress.String[0] &&
+ pAdapter->GatewayList.IpAddress.String &&
+ pAdapter->GatewayList.IpAddress.String[0] &&
+ ( !index || ( pAdapter->Index == index ) ) )
+ {
+ // Found one that will work
+
+ char keyName[1024];
+
+ _snprintf( keyName, 1024, "%s%s", "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\", pAdapter->AdapterName );
+
+ err = RegCreateKeyA( HKEY_LOCAL_MACHINE, keyName, &key );
+ require_noerr( err, exit );
+
+ err = RegQueryString( key, "Domain", &domain, &dwSize, NULL );
+ check_noerr( err );
+
+ if ( !domain || !domain[0] )
+ {
+ if ( domain )
+ {
+ free( domain );
+ domain = NULL;
+ }
+
+ err = RegQueryString( key, "DhcpDomain", &domain, &dwSize, NULL );
+ check_noerr( err );
+ }
+
+ if ( domain && domain[0] ) mDNS_AddSearchDomain_CString(domain, mDNSNULL);
+
+ break;
+ }
+ }
+
+exit:
+
+ if ( pAdapterInfo )
+ {
+ free( pAdapterInfo );
+ }
+
+ if ( domain )
+ {
+ free( domain );
+ }
+
+ if ( key )
+ {
+ RegCloseKey( key );
+ }
+}
+
+
+//===========================================================================================================================
+// mDNSPlatformGetPrimaryInterface
+//===========================================================================================================================
+
+mDNSexport mStatus
+mDNSPlatformGetPrimaryInterface( mDNS * const m, mDNSAddr * v4, mDNSAddr * v6, mDNSAddr * router )
+{
+ IP_ADAPTER_INFO * pAdapterInfo;
+ IP_ADAPTER_INFO * pAdapter;
+ DWORD bufLen;
+ int i;
+ BOOL found;
+ DWORD index;
+ mStatus err = mStatus_NoError;
+
+ DEBUG_UNUSED( m );
+
+ *v6 = zeroAddr;
+
+ pAdapterInfo = NULL;
+ bufLen = 0;
+ found = FALSE;
+
+ for ( i = 0; i < 100; i++ )
+ {
+ err = GetAdaptersInfo( pAdapterInfo, &bufLen);
+
+ if ( err != ERROR_BUFFER_OVERFLOW )
+ {
+ break;
+ }
+
+ pAdapterInfo = (IP_ADAPTER_INFO*) realloc( pAdapterInfo, bufLen );
+ require_action( pAdapterInfo, exit, err = kNoMemoryErr );
+ }
+
+ require_noerr( err, exit );
+
+ index = GetPrimaryInterface();
+
+ for ( pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next )
+ {
+ if ( pAdapter->IpAddressList.IpAddress.String &&
+ pAdapter->IpAddressList.IpAddress.String[0] &&
+ pAdapter->GatewayList.IpAddress.String &&
+ pAdapter->GatewayList.IpAddress.String[0] &&
+ ( StringToAddress( v4, pAdapter->IpAddressList.IpAddress.String ) == mStatus_NoError ) &&
+ ( StringToAddress( router, pAdapter->GatewayList.IpAddress.String ) == mStatus_NoError ) &&
+ ( !index || ( pAdapter->Index == index ) ) )
+ {
+ // Found one that will work
+
+ if ( pAdapter->AddressLength == sizeof( m->PrimaryMAC ) )
+ {
+ memcpy( &m->PrimaryMAC, pAdapter->Address, pAdapter->AddressLength );
+ }
+
+ found = TRUE;
+ break;
+ }
+ }
+
+exit:
+
+ if ( pAdapterInfo )
+ {
+ free( pAdapterInfo );
+ }
+
+ return err;
+}
+
+mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win)
+ {
+ (void) sadd; // Unused
+ (void) dadd; // Unused
+ (void) lport; // Unused
+ (void) rport; // Unused
+ (void) seq; // Unused
+ (void) ack; // Unused
+ (void) win; // Unused
+ }
+
+mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNSAddr *raddr, char *eth)
+ {
+ (void) raddr; // Unused
+ (void) eth; // Unused
+ }
+
+mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname)
+ {
+ (void) spsaddr; // Unused
+ (void) ifname; // Unused
+ }
+
+mDNSexport mStatus mDNSPlatformClearSPSMACAddr(void)
+ {
+ }
+
+mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNS *const m, mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
+ {
+ (void) m; // Unused
+ (void) laddr; // Unused
+ (void) raddr; // Unused
+ (void) lport; // Unused
+ (void) rport; // Unused
+ (void) mti; // Unused
+ }
+
+mDNSexport mDNSBool mDNSPlatformAllowPID(mDNS *const m, DNSQuestion *q)
+ {
+ (void) m;
+ (void) q;
+ return mDNStrue;
+ }
+
+mDNSexport mDNSs32 mDNSPlatformGetServiceID(mDNS *const m, DNSQuestion *q)
+ {
+ (void) m;
+ (void) q;
+ return -1;
+ }
+
+mDNSexport void mDNSPlatformSetDelegatePID(UDPSocket *src, const mDNSAddr *dst, DNSQuestion *q)
+ {
+ (void) src;
+ (void) dst;
+ (void) q;
+ }
+
+mDNSexport mDNSs32 mDNSPlatformGetPID()
+ {
+ return 0;
+ }
+
+mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
+{
+ DEBUG_UNUSED( sock );
+
+ return (mDNSu16)-1;
+}
+
+mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
+{
+ DEBUG_UNUSED( InterfaceID );
+
+ return mDNSfalse;
+}
+
+#if 0
+#pragma mark -
+#endif
+
+//===========================================================================================================================
+// debugf_
+//===========================================================================================================================
+#if( MDNS_DEBUGMSGS )
+mDNSexport void debugf_( const char *inFormat, ... )
+{
+ char buffer[ 512 ];
+ va_list args;
+ mDNSu32 length;
+
+ va_start( args, inFormat );
+ length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
+ va_end( args );
+
+ dlog( kDebugLevelInfo, "%s\n", buffer );
+}
+#endif
+
+//===========================================================================================================================
+// verbosedebugf_
+//===========================================================================================================================
+
+#if( MDNS_DEBUGMSGS > 1 )
+mDNSexport void verbosedebugf_( const char *inFormat, ... )
+{
+ char buffer[ 512 ];
+ va_list args;
+ mDNSu32 length;
+
+ va_start( args, inFormat );
+ length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
+ va_end( args );
+
+ dlog( kDebugLevelVerbose, "%s\n", buffer );
+}
+#endif
+
+
+#if 0
+#pragma mark -
+#pragma mark == Platform Internals ==
+#endif
+
+
+//===========================================================================================================================
+// SetupNiceName
+//===========================================================================================================================
+
+mStatus SetupNiceName( mDNS * const inMDNS )
+{
+ HKEY descKey = NULL;
+ char utf8[ 256 ];
+ LPCTSTR s;
+ LPWSTR joinName;
+ NETSETUP_JOIN_STATUS joinStatus;
+ mStatus err = 0;
+ DWORD namelen;
+ BOOL ok;
+
+ check( inMDNS );
+
+ // Set up the nice name.
+ utf8[0] = '\0';
+
+ // First try and open the registry key that contains the computer description value
+ s = TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters");
+ err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, s, 0, KEY_READ, &descKey);
+ check_translated_errno( err == 0, errno_compat(), kNameErr );
+
+ if ( !err )
+ {
+ TCHAR desc[256];
+ DWORD descSize = sizeof( desc );
+
+ // look for the computer description
+ err = RegQueryValueEx( descKey, TEXT("srvcomment"), 0, NULL, (LPBYTE) &desc, &descSize);
+
+ if ( !err )
+ {
+ err = TCHARtoUTF8( desc, utf8, sizeof( utf8 ) );
+ }
+
+ if ( err )
+ {
+ utf8[ 0 ] = '\0';
+ }
+ }
+
+ // if we can't find it in the registry, then use the hostname of the machine
+ if ( err || ( utf8[ 0 ] == '\0' ) )
+ {
+ TCHAR hostname[256];
+
+ namelen = sizeof( hostname ) / sizeof( TCHAR );
+
+ ok = GetComputerNameExW( ComputerNamePhysicalDnsHostname, hostname, &namelen );
+ err = translate_errno( ok, (mStatus) GetLastError(), kNameErr );
+ check_noerr( err );
+
+ if( !err )
+ {
+ err = TCHARtoUTF8( hostname, utf8, sizeof( utf8 ) );
+ }
+
+ if ( err )
+ {
+ utf8[ 0 ] = '\0';
+ }
+ }
+
+ // if we can't get the hostname
+ if ( err || ( utf8[ 0 ] == '\0' ) )
+ {
+ // Invalidate name so fall back to a default name.
+
+ strcpy( utf8, kMDNSDefaultName );
+ }
+
+ utf8[ sizeof( utf8 ) - 1 ] = '\0';
+ inMDNS->nicelabel.c[ 0 ] = (mDNSu8) (strlen( utf8 ) < MAX_DOMAIN_LABEL ? strlen( utf8 ) : MAX_DOMAIN_LABEL);
+ memcpy( &inMDNS->nicelabel.c[ 1 ], utf8, inMDNS->nicelabel.c[ 0 ] );
+
+ dlog( kDebugLevelInfo, DEBUG_NAME "nice name \"%.*s\"\n", inMDNS->nicelabel.c[ 0 ], &inMDNS->nicelabel.c[ 1 ] );
+
+ if ( descKey )
+ {
+ RegCloseKey( descKey );
+ }
+
+ ZeroMemory( inMDNS->p->nbname, sizeof( inMDNS->p->nbname ) );
+ ZeroMemory( inMDNS->p->nbdomain, sizeof( inMDNS->p->nbdomain ) );
+
+ namelen = sizeof( inMDNS->p->nbname );
+ ok = GetComputerNameExA( ComputerNamePhysicalNetBIOS, inMDNS->p->nbname, &namelen );
+ check( ok );
+ if ( ok ) dlog( kDebugLevelInfo, DEBUG_NAME "netbios name \"%s\"\n", inMDNS->p->nbname );
+
+ err = NetGetJoinInformation( NULL, &joinName, &joinStatus );
+ check ( err == NERR_Success );
+ if ( err == NERR_Success )
+ {
+ if ( ( joinStatus == NetSetupWorkgroupName ) || ( joinStatus == NetSetupDomainName ) )
+ {
+ err = TCHARtoUTF8( joinName, inMDNS->p->nbdomain, sizeof( inMDNS->p->nbdomain ) );
+ check( !err );
+ if ( !err ) dlog( kDebugLevelInfo, DEBUG_NAME "netbios domain/workgroup \"%s\"\n", inMDNS->p->nbdomain );
+ }
+
+ NetApiBufferFree( joinName );
+ joinName = NULL;
+ }
+
+ err = 0;
+
+ return( err );
+}
+
+//===========================================================================================================================
+// SetupHostName
+//===========================================================================================================================
+
+mDNSlocal mStatus SetupHostName( mDNS * const inMDNS )
+{
+ mStatus err = 0;
+ char tempString[ 256 ];
+ DWORD tempStringLen;
+ domainlabel tempLabel;
+ BOOL ok;
+
+ check( inMDNS );
+
+ // Set up the nice name.
+ tempString[ 0 ] = '\0';
+
+ // use the hostname of the machine
+ tempStringLen = sizeof( tempString );
+ ok = GetComputerNameExA( ComputerNamePhysicalDnsHostname, tempString, &tempStringLen );
+ err = translate_errno( ok, (mStatus) GetLastError(), kNameErr );
+ check_noerr( err );
+
+ // if we can't get the hostname
+ if( err || ( tempString[ 0 ] == '\0' ) )
+ {
+ // Invalidate name so fall back to a default name.
+
+ strcpy( tempString, kMDNSDefaultName );
+ }
+
+ tempString[ sizeof( tempString ) - 1 ] = '\0';
+ tempLabel.c[ 0 ] = (mDNSu8) (strlen( tempString ) < MAX_DOMAIN_LABEL ? strlen( tempString ) : MAX_DOMAIN_LABEL );
+ memcpy( &tempLabel.c[ 1 ], tempString, tempLabel.c[ 0 ] );
+
+ // Set up the host name.
+
+ ConvertUTF8PstringToRFC1034HostLabel( tempLabel.c, &inMDNS->hostlabel );
+ if( inMDNS->hostlabel.c[ 0 ] == 0 )
+ {
+ // Nice name has no characters that are representable as an RFC1034 name (e.g. Japanese) so use the default.
+
+ MakeDomainLabelFromLiteralString( &inMDNS->hostlabel, kMDNSDefaultName );
+ }
+
+ check( inMDNS->hostlabel.c[ 0 ] != 0 );
+
+ mDNS_SetFQDN( inMDNS );
+
+ dlog( kDebugLevelInfo, DEBUG_NAME "host name \"%.*s\"\n", inMDNS->hostlabel.c[ 0 ], &inMDNS->hostlabel.c[ 1 ] );
+
+ return( err );
+}
+
+//===========================================================================================================================
+// SetupName
+//===========================================================================================================================
+
+mDNSlocal mStatus SetupName( mDNS * const inMDNS )
+{
+ mStatus err = 0;
+
+ check( inMDNS );
+
+ err = SetupNiceName( inMDNS );
+ check_noerr( err );
+
+ err = SetupHostName( inMDNS );
+ check_noerr( err );
+
+ return err;
+}
+
+
+//===========================================================================================================================
+// SetupInterfaceList
+//===========================================================================================================================
+
+mStatus SetupInterfaceList( mDNS * const inMDNS )
+{
+ mStatus err;
+ mDNSInterfaceData ** next;
+ mDNSInterfaceData * ifd;
+ struct ifaddrs * addrs;
+ struct ifaddrs * p;
+ struct ifaddrs * loopbackv4;
+ struct ifaddrs * loopbackv6;
+ u_int flagMask;
+ u_int flagTest;
+ mDNSBool foundv4;
+ mDNSBool foundv6;
+ mDNSBool foundUnicastSock4DestAddr;
+ mDNSBool foundUnicastSock6DestAddr;
+
+ dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface list\n" );
+ check( inMDNS );
+ check( inMDNS->p );
+
+ inMDNS->p->registeredLoopback4 = mDNSfalse;
+ inMDNS->p->nextDHCPLeaseExpires = 0x7FFFFFFF;
+ addrs = NULL;
+ foundv4 = mDNSfalse;
+ foundv6 = mDNSfalse;
+ foundUnicastSock4DestAddr = mDNSfalse;
+ foundUnicastSock6DestAddr = mDNSfalse;
+
+ // Tear down any existing interfaces that may be set up.
+
+ TearDownInterfaceList( inMDNS );
+
+ // Set up the name of this machine.
+
+ err = SetupName( inMDNS );
+ check_noerr( err );
+
+ // Set up IPv4 interface(s). We have to set up IPv4 first so any IPv6 interface with an IPv4-routable address
+ // can refer to the IPv4 interface when it registers to allow DNS AAAA records over the IPv4 interface.
+
+ err = getifaddrs( &addrs );
+ require_noerr( err, exit );
+
+ loopbackv4 = NULL;
+ loopbackv6 = NULL;
+ next = &inMDNS->p->interfaceList;
+
+ flagMask = IFF_UP | IFF_MULTICAST;
+ flagTest = IFF_UP | IFF_MULTICAST;
+
+#if( MDNS_WINDOWS_ENABLE_IPV4 )
+ for( p = addrs; p; p = p->ifa_next )
+ {
+ if( !p->ifa_addr || ( p->ifa_addr->sa_family != AF_INET ) || ( ( p->ifa_flags & flagMask ) != flagTest ) )
+ {
+ continue;
+ }
+ if( p->ifa_flags & IFF_LOOPBACK )
+ {
+ if( !loopbackv4 )
+ {
+ loopbackv4 = p;
+ }
+ continue;
+ }
+ dlog( kDebugLevelVerbose, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
+ p->ifa_name ? p->ifa_name : "<null>", p->ifa_extra.index, p->ifa_addr );
+
+ err = SetupInterface( inMDNS, p, &ifd );
+ require_noerr( err, exit );
+
+ // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
+ // register him, but we also want to note that we haven't found a v4 interface
+ // so that we register loopback so same host operations work
+
+ if ( ifd->interfaceInfo.McastTxRx == mDNStrue )
+ {
+ foundv4 = mDNStrue;
+ }
+
+ if ( p->ifa_dhcpEnabled && ( p->ifa_dhcpLeaseExpires < inMDNS->p->nextDHCPLeaseExpires ) )
+ {
+ inMDNS->p->nextDHCPLeaseExpires = p->ifa_dhcpLeaseExpires;
+ }
+
+ // If we're on a platform that doesn't have WSARecvMsg(), there's no way
+ // of determing the destination address of a packet that is sent to us.
+ // For multicast packets, that's easy to determine. But for the unicast
+ // sockets, we'll fake it by taking the address of the first interface
+ // that is successfully setup.
+
+ if ( !foundUnicastSock4DestAddr )
+ {
+ inMDNS->p->unicastSock4.addr = ifd->interfaceInfo.ip;
+ foundUnicastSock4DestAddr = TRUE;
+ }
+
+ *next = ifd;
+ next = &ifd->next;
+ ++inMDNS->p->interfaceCount;
+ }
+#endif
+
+ // Set up IPv6 interface(s) after IPv4 is set up (see IPv4 notes above for reasoning).
+
+#if( MDNS_WINDOWS_ENABLE_IPV6 )
+
+ if ( gEnableIPv6 )
+ {
+ for( p = addrs; p; p = p->ifa_next )
+ {
+ if( !p->ifa_addr || ( p->ifa_addr->sa_family != AF_INET6 ) || ( ( p->ifa_flags & flagMask ) != flagTest ) )
+ {
+ continue;
+ }
+ if( p->ifa_flags & IFF_LOOPBACK )
+ {
+ if( !loopbackv6 )
+ {
+ loopbackv6 = p;
+ }
+ continue;
+ }
+ dlog( kDebugLevelVerbose, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
+ p->ifa_name ? p->ifa_name : "<null>", p->ifa_extra.index, p->ifa_addr );
+
+ err = SetupInterface( inMDNS, p, &ifd );
+ require_noerr( err, exit );
+
+ // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
+ // register him, but we also want to note that we haven't found a v4 interface
+ // so that we register loopback so same host operations work
+
+ if ( ifd->interfaceInfo.McastTxRx == mDNStrue )
+ {
+ foundv6 = mDNStrue;
+ }
+
+ // If we're on a platform that doesn't have WSARecvMsg(), there's no way
+ // of determing the destination address of a packet that is sent to us.
+ // For multicast packets, that's easy to determine. But for the unicast
+ // sockets, we'll fake it by taking the address of the first interface
+ // that is successfully setup.
+
+ if ( !foundUnicastSock6DestAddr )
+ {
+ inMDNS->p->unicastSock6.addr = ifd->interfaceInfo.ip;
+ foundUnicastSock6DestAddr = TRUE;
+ }
+
+ *next = ifd;
+ next = &ifd->next;
+ ++inMDNS->p->interfaceCount;
+ }
+ }
+
+#endif
+
+ // If there are no real interfaces, but there is a loopback interface, use that so same-machine operations work.
+
+#if( !MDNS_WINDOWS_ENABLE_IPV4 && !MDNS_WINDOWS_ENABLE_IPV6 )
+
+ flagMask |= IFF_LOOPBACK;
+ flagTest |= IFF_LOOPBACK;
+
+ for( p = addrs; p; p = p->ifa_next )
+ {
+ if( !p->ifa_addr || ( ( p->ifa_flags & flagMask ) != flagTest ) )
+ {
+ continue;
+ }
+ if( ( p->ifa_addr->sa_family != AF_INET ) && ( p->ifa_addr->sa_family != AF_INET6 ) )
+ {
+ continue;
+ }
+
+ v4loopback = p;
+ break;
+ }
+
+#endif
+
+ if ( !foundv4 && loopbackv4 )
+ {
+ dlog( kDebugLevelInfo, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
+ loopbackv4->ifa_name ? loopbackv4->ifa_name : "<null>", loopbackv4->ifa_extra.index, loopbackv4->ifa_addr );
+
+ err = SetupInterface( inMDNS, loopbackv4, &ifd );
+ require_noerr( err, exit );
+
+ inMDNS->p->registeredLoopback4 = mDNStrue;
+
+#if( MDNS_WINDOWS_ENABLE_IPV4 )
+
+ // If we're on a platform that doesn't have WSARecvMsg(), there's no way
+ // of determing the destination address of a packet that is sent to us.
+ // For multicast packets, that's easy to determine. But for the unicast
+ // sockets, we'll fake it by taking the address of the first interface
+ // that is successfully setup.
+
+ if ( !foundUnicastSock4DestAddr )
+ {
+ inMDNS->p->unicastSock4.addr = ifd->sock.addr;
+ foundUnicastSock4DestAddr = TRUE;
+ }
+#endif
+
+ *next = ifd;
+ next = &ifd->next;
+ ++inMDNS->p->interfaceCount;
+ }
+
+ if ( !foundv6 && loopbackv6 )
+ {
+ dlog( kDebugLevelInfo, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
+ loopbackv6->ifa_name ? loopbackv6->ifa_name : "<null>", loopbackv6->ifa_extra.index, loopbackv6->ifa_addr );
+
+ err = SetupInterface( inMDNS, loopbackv6, &ifd );
+ require_noerr( err, exit );
+
+#if( MDNS_WINDOWS_ENABLE_IPV6 )
+
+ if ( gEnableIPv6 )
+ {
+ // If we're on a platform that doesn't have WSARecvMsg(), there's no way
+ // of determing the destination address of a packet that is sent to us.
+ // For multicast packets, that's easy to determine. But for the unicast
+ // sockets, we'll fake it by taking the address of the first interface
+ // that is successfully setup.
+
+ if ( !foundUnicastSock6DestAddr )
+ {
+ inMDNS->p->unicastSock6.addr = ifd->sock.addr;
+ foundUnicastSock6DestAddr = TRUE;
+ }
+ }
+
+#endif
+
+ *next = ifd;
+ next = &ifd->next;
+ ++inMDNS->p->interfaceCount;
+ }
+
+ CheckFileShares( inMDNS );
+
+exit:
+ if( err )
+ {
+ TearDownInterfaceList( inMDNS );
+ }
+ if( addrs )
+ {
+ freeifaddrs( addrs );
+ }
+ dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface list done (err=%d %m)\n", err, err );
+ return( err );
+}
+
+//===========================================================================================================================
+// TearDownInterfaceList
+//===========================================================================================================================
+
+mStatus TearDownInterfaceList( mDNS * const inMDNS )
+{
+ mDNSInterfaceData ** p;
+ mDNSInterfaceData * ifd;
+
+ dlog( kDebugLevelTrace, DEBUG_NAME "tearing down interface list\n" );
+ check( inMDNS );
+ check( inMDNS->p );
+
+ // Free any interfaces that were previously marked inactive and are no longer referenced by the mDNS cache.
+ // Interfaces are marked inactive, but not deleted immediately if they were still referenced by the mDNS cache
+ // so that remove events that occur after an interface goes away can still report the correct interface.
+
+ p = &inMDNS->p->inactiveInterfaceList;
+ while( *p )
+ {
+ ifd = *p;
+ if( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) ifd ) > 0 )
+ {
+ p = &ifd->next;
+ continue;
+ }
+
+ dlog( kDebugLevelInfo, DEBUG_NAME "freeing unreferenced, inactive interface %#p %#a\n", ifd, &ifd->interfaceInfo.ip );
+ *p = ifd->next;
+
+ QueueUserAPC( ( PAPCFUNC ) FreeInterface, inMDNS->p->mainThread, ( ULONG_PTR ) ifd );
+ }
+
+ // Tear down all the interfaces.
+
+ while( inMDNS->p->interfaceList )
+ {
+ ifd = inMDNS->p->interfaceList;
+ inMDNS->p->interfaceList = ifd->next;
+
+ TearDownInterface( inMDNS, ifd );
+ }
+ inMDNS->p->interfaceCount = 0;
+
+ dlog( kDebugLevelTrace, DEBUG_NAME "tearing down interface list done\n" );
+ return( mStatus_NoError );
+}
+
+//===========================================================================================================================
+// SetupInterface
+//===========================================================================================================================
+
+mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inIFA, mDNSInterfaceData **outIFD )
+{
+ mDNSInterfaceData * ifd;
+ mDNSInterfaceData * p;
+ mStatus err;
+
+ ifd = NULL;
+ dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface\n" );
+ check( inMDNS );
+ check( inMDNS->p );
+ check( inIFA );
+ check( inIFA->ifa_addr );
+ check( outIFD );
+
+ // Allocate memory for the interface and initialize it.
+
+ ifd = (mDNSInterfaceData *) calloc( 1, sizeof( *ifd ) );
+ require_action( ifd, exit, err = mStatus_NoMemoryErr );
+ ifd->sock.fd = kInvalidSocketRef;
+ ifd->sock.ifd = ifd;
+ ifd->sock.next = NULL;
+ ifd->sock.m = inMDNS;
+ ifd->index = inIFA->ifa_extra.index;
+ ifd->scopeID = inIFA->ifa_extra.index;
+ check( strlen( inIFA->ifa_name ) < sizeof( ifd->name ) );
+ strncpy( ifd->name, inIFA->ifa_name, sizeof( ifd->name ) - 1 );
+ ifd->name[ sizeof( ifd->name ) - 1 ] = '\0';
+
+ strncpy(ifd->interfaceInfo.ifname, inIFA->ifa_name, sizeof(ifd->interfaceInfo.ifname));
+ ifd->interfaceInfo.ifname[sizeof(ifd->interfaceInfo.ifname)-1] = 0;
+
+ // We always send and receive using IPv4, but to reduce traffic, we send and receive using IPv6 only on interfaces
+ // that have no routable IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being
+ // on a large configured network, which means there's a good chance that most or all the other devices on that
+ // network should also have v4. By doing this we lose the ability to talk to true v6-only devices on that link,
+ // but we cut the packet rate in half. At this time, reducing the packet rate is more important than v6-only
+ // devices on a large configured network, so we are willing to make that sacrifice.
+
+ ifd->interfaceInfo.McastTxRx = ( ( inIFA->ifa_flags & IFF_MULTICAST ) && !( inIFA->ifa_flags & IFF_POINTTOPOINT ) ) ? mDNStrue : mDNSfalse;
+ ifd->interfaceInfo.InterfaceID = NULL;
+
+ for( p = inMDNS->p->interfaceList; p; p = p->next )
+ {
+ if ( strcmp( p->name, ifd->name ) == 0 )
+ {
+ if (!ifd->interfaceInfo.InterfaceID)
+ {
+ ifd->interfaceInfo.InterfaceID = (mDNSInterfaceID) p;
+ }
+
+ if ( ( inIFA->ifa_addr->sa_family != AF_INET ) &&
+ ( p->interfaceInfo.ip.type == mDNSAddrType_IPv4 ) &&
+ ( p->interfaceInfo.ip.ip.v4.b[ 0 ] != 169 || p->interfaceInfo.ip.ip.v4.b[ 1 ] != 254 ) )
+ {
+ ifd->interfaceInfo.McastTxRx = mDNSfalse;
+ }
+
+ break;
+ }
+ }
+
+ if ( !ifd->interfaceInfo.InterfaceID )
+ {
+ ifd->interfaceInfo.InterfaceID = (mDNSInterfaceID) ifd;
+ }
+
+ // Set up a socket for this interface (if needed).
+
+ if( ifd->interfaceInfo.McastTxRx )
+ {
+ DWORD size;
+
+ err = SetupSocket( inMDNS, inIFA->ifa_addr, MulticastDNSPort, &ifd->sock.fd );
+ require_noerr( err, exit );
+ ifd->sock.addr = ( inIFA->ifa_addr->sa_family == AF_INET6 ) ? AllDNSLinkGroup_v6 : AllDNSLinkGroup_v4;
+ ifd->sock.port = MulticastDNSPort;
+
+ // Get a ptr to the WSARecvMsg function, if supported. Otherwise, we'll fallback to recvfrom.
+
+ err = WSAIoctl( ifd->sock.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &ifd->sock.recvMsgPtr, sizeof( ifd->sock.recvMsgPtr ), &size, NULL, NULL );
+
+ if ( err )
+ {
+ ifd->sock.recvMsgPtr = NULL;
+ }
+ }
+
+ if ( inIFA->ifa_dhcpEnabled && ( inIFA->ifa_dhcpLeaseExpires < inMDNS->p->nextDHCPLeaseExpires ) )
+ {
+ inMDNS->p->nextDHCPLeaseExpires = inIFA->ifa_dhcpLeaseExpires;
+ }
+
+ ifd->interfaceInfo.NetWake = inIFA->ifa_womp;
+
+ // Register this interface with mDNS.
+
+ err = SockAddrToMDNSAddr( inIFA->ifa_addr, &ifd->interfaceInfo.ip, NULL );
+ require_noerr( err, exit );
+
+ err = SockAddrToMDNSAddr( inIFA->ifa_netmask, &ifd->interfaceInfo.mask, NULL );
+ require_noerr( err, exit );
+
+ memcpy( ifd->interfaceInfo.MAC.b, inIFA->ifa_physaddr, sizeof( ifd->interfaceInfo.MAC.b ) );
+
+ ifd->interfaceInfo.Advertise = ( mDNSu8 ) inMDNS->AdvertiseLocalAddresses;
+
+ if ( ifd->sock.fd != kInvalidSocketRef )
+ {
+ err = mDNSPollRegisterSocket( ifd->sock.fd, FD_READ, UDPSocketNotification, &ifd->sock );
+ require_noerr( err, exit );
+ }
+
+ // If interface is a direct link, address record will be marked as kDNSRecordTypeKnownUnique
+ // and skip the probe phase of the probe/announce packet sequence.
+ ifd->interfaceInfo.DirectLink = mDNSfalse;
+
+ err = mDNS_RegisterInterface( inMDNS, &ifd->interfaceInfo, mDNSfalse );
+ require_noerr( err, exit );
+ ifd->hostRegistered = mDNStrue;
+
+ dlog( kDebugLevelInfo, DEBUG_NAME "Registered interface %##a with mDNS\n", inIFA->ifa_addr );
+
+ // Success!
+
+ *outIFD = ifd;
+ ifd = NULL;
+
+exit:
+
+ if( ifd )
+ {
+ TearDownInterface( inMDNS, ifd );
+ }
+ dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface done (err=%d %m)\n", err, err );
+ return( err );
+}
+
+//===========================================================================================================================
+// TearDownInterface
+//===========================================================================================================================
+
+mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD )
+{
+ check( inMDNS );
+ check( inIFD );
+
+ // Deregister this interface with mDNS.
+
+ dlog( kDebugLevelInfo, DEBUG_NAME "Deregistering interface %#a with mDNS\n", &inIFD->interfaceInfo.ip );
+
+ if( inIFD->hostRegistered )
+ {
+ inIFD->hostRegistered = mDNSfalse;
+ mDNS_DeregisterInterface( inMDNS, &inIFD->interfaceInfo, mDNSfalse );
+ }
+
+ // Tear down the multicast socket.
+
+ UDPCloseSocket( &inIFD->sock );
+
+ // If the interface is still referenced by items in the mDNS cache then put it on the inactive list. This keeps
+ // the InterfaceID valid so remove events report the correct interface. If it is no longer referenced, free it.
+
+ if( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) inIFD ) > 0 )
+ {
+ inIFD->next = inMDNS->p->inactiveInterfaceList;
+ inMDNS->p->inactiveInterfaceList = inIFD;
+ dlog( kDebugLevelInfo, DEBUG_NAME "deferring free of interface %#p %#a\n", inIFD, &inIFD->interfaceInfo.ip );
+ }
+ else
+ {
+ dlog( kDebugLevelInfo, DEBUG_NAME "freeing interface %#p %#a immediately\n", inIFD, &inIFD->interfaceInfo.ip );
+ QueueUserAPC( ( PAPCFUNC ) FreeInterface, inMDNS->p->mainThread, ( ULONG_PTR ) inIFD );
+ }
+
+ return( mStatus_NoError );
+}
+
+mDNSlocal void CALLBACK FreeInterface( mDNSInterfaceData *inIFD )
+{
+ free( inIFD );
+}
+
+//===========================================================================================================================
+// SetupSocket
+//===========================================================================================================================
+
+mDNSlocal mStatus SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, mDNSIPPort port, SocketRef *outSocketRef )
+{
+ mStatus err;
+ SocketRef sock;
+ int option;
+ DWORD bytesReturned = 0;
+ BOOL behavior = FALSE;
+
+ DEBUG_UNUSED( inMDNS );
+
+ dlog( kDebugLevelTrace, DEBUG_NAME "setting up socket %##a\n", inAddr );
+ check( inMDNS );
+ check( outSocketRef );
+
+ // Set up an IPv4 or IPv6 UDP socket.
+
+ sock = socket( inAddr->sa_family, SOCK_DGRAM, IPPROTO_UDP );
+ err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
+ require_noerr( err, exit );
+
+ // Turn on reuse address option so multiple servers can listen for Multicast DNS packets,
+ // if we're creating a multicast socket
+
+ if ( !mDNSIPPortIsZero( port ) )
+ {
+ option = 1;
+ err = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (char *) &option, sizeof( option ) );
+ check_translated_errno( err == 0, errno_compat(), kOptionErr );
+ }
+
+ // <rdar://problem/7894393> Bonjour for Windows broken on Windows XP
+ //
+ // Not sure why, but the default behavior for sockets is to behave incorrectly
+ // when using them in Overlapped I/O mode on XP. According to MSDN:
+ //
+ // SIO_UDP_CONNRESET (opcode setting: I, T==3)
+ // Windows XP: Controls whether UDP PORT_UNREACHABLE messages are reported. Set to TRUE to enable reporting.
+ // Set to FALSE to disable reporting.
+ //
+ // Packet traces from misbehaving Bonjour installations showed that ICMP port unreachable
+ // messages were being sent to us after we sent out packets to a multicast address. This is clearly
+ // incorrect behavior, but should be harmless. However, after receiving a port unreachable error, WinSock
+ // will no longer receive any packets from that socket, which is not harmless. This behavior is only
+ // seen on XP.
+ //
+ // So we turn off port unreachable reporting to make sure our sockets that are reading
+ // multicast packets function correctly under all circumstances.
+
+ err = WSAIoctl( sock, SIO_UDP_CONNRESET, &behavior, sizeof(behavior), NULL, 0, &bytesReturned, NULL, NULL );
+ check_translated_errno( err == 0, errno_compat(), kOptionErr );
+
+ if( inAddr->sa_family == AF_INET )
+ {
+ mDNSv4Addr ipv4;
+ struct sockaddr_in sa4;
+ struct ip_mreq mreqv4;
+
+ // Bind the socket to the desired port
+
+ ipv4.NotAnInteger = ( (const struct sockaddr_in *) inAddr )->sin_addr.s_addr;
+ mDNSPlatformMemZero( &sa4, sizeof( sa4 ) );
+ sa4.sin_family = AF_INET;
+ sa4.sin_port = port.NotAnInteger;
+ sa4.sin_addr.s_addr = ipv4.NotAnInteger;
+
+ err = bind( sock, (struct sockaddr *) &sa4, sizeof( sa4 ) );
+ check_translated_errno( err == 0, errno_compat(), kUnknownErr );
+
+ // Turn on option to receive destination addresses and receiving interface.
+
+ option = 1;
+ err = setsockopt( sock, IPPROTO_IP, IP_PKTINFO, (char *) &option, sizeof( option ) );
+ check_translated_errno( err == 0, errno_compat(), kOptionErr );
+
+ if ( !mDNSIPPortIsZero( port ) )
+ {
+ // Join the all-DNS multicast group so we receive Multicast DNS packets
+
+ mreqv4.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
+ mreqv4.imr_interface.s_addr = ipv4.NotAnInteger;
+ err = setsockopt( sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreqv4, sizeof( mreqv4 ) );
+ check_translated_errno( err == 0, errno_compat(), kOptionErr );
+
+ // Specify the interface to send multicast packets on this socket.
+
+ sa4.sin_addr.s_addr = ipv4.NotAnInteger;
+ err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_IF, (char *) &sa4.sin_addr, sizeof( sa4.sin_addr ) );
+ check_translated_errno( err == 0, errno_compat(), kOptionErr );
+
+ // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
+
+ option = 1;
+ err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &option, sizeof( option ) );
+ check_translated_errno( err == 0, errno_compat(), kOptionErr );
+ }
+
+ // Send unicast packets with TTL 255 (helps against spoofing).
+
+ option = 255;
+ err = setsockopt( sock, IPPROTO_IP, IP_TTL, (char *) &option, sizeof( option ) );
+ check_translated_errno( err == 0, errno_compat(), kOptionErr );
+
+ // Send multicast packets with TTL 255 (helps against spoofing).
+
+ option = 255;
+ err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &option, sizeof( option ) );
+ check_translated_errno( err == 0, errno_compat(), kOptionErr );
+
+ }
+ else if( inAddr->sa_family == AF_INET6 )
+ {
+ struct sockaddr_in6 * sa6p;
+ struct sockaddr_in6 sa6;
+ struct ipv6_mreq mreqv6;
+
+ sa6p = (struct sockaddr_in6 *) inAddr;
+
+ // Bind the socket to the desired port
+
+ mDNSPlatformMemZero( &sa6, sizeof( sa6 ) );
+ sa6.sin6_family = AF_INET6;
+ sa6.sin6_port = port.NotAnInteger;
+ sa6.sin6_flowinfo = 0;
+ sa6.sin6_addr = sa6p->sin6_addr;
+ sa6.sin6_scope_id = sa6p->sin6_scope_id;
+
+ err = bind( sock, (struct sockaddr *) &sa6, sizeof( sa6 ) );
+ check_translated_errno( err == 0, errno_compat(), kUnknownErr );
+
+ // Turn on option to receive destination addresses and receiving interface.
+
+ option = 1;
+ err = setsockopt( sock, IPPROTO_IPV6, IPV6_PKTINFO, (char *) &option, sizeof( option ) );
+ check_translated_errno( err == 0, errno_compat(), kOptionErr );
+
+ // We only want to receive IPv6 packets (not IPv4-mapped IPv6 addresses) because we have a separate socket
+ // for IPv4, but the IPv6 stack in Windows currently doesn't support IPv4-mapped IPv6 addresses and doesn't
+ // support the IPV6_V6ONLY socket option so the following code would typically not be executed (or needed).
+
+ #if( defined( IPV6_V6ONLY ) )
+ option = 1;
+ err = setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &option, sizeof( option ) );
+ check_translated_errno( err == 0, errno_compat(), kOptionErr );
+ #endif
+
+ if ( !mDNSIPPortIsZero( port ) )
+ {
+ // Join the all-DNS multicast group so we receive Multicast DNS packets.
+
+ mreqv6.ipv6mr_multiaddr = *( (struct in6_addr *) &AllDNSLinkGroup_v6.ip.v6 );
+ mreqv6.ipv6mr_interface = sa6p->sin6_scope_id;
+ err = setsockopt( sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &mreqv6, sizeof( mreqv6 ) );
+ check_translated_errno( err == 0, errno_compat(), kOptionErr );
+
+ // Specify the interface to send multicast packets on this socket.
+
+ option = (int) sa6p->sin6_scope_id;
+ err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &option, sizeof( option ) );
+ check_translated_errno( err == 0, errno_compat(), kOptionErr );
+
+ // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
+
+ option = 1;
+ err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &option, sizeof( option ) );
+ check_translated_errno( err == 0, errno_compat(), kOptionErr );
+ }
+
+ // Send unicast packets with TTL 255 (helps against spoofing).
+
+ option = 255;
+ err = setsockopt( sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *) &option, sizeof( option ) );
+ check_translated_errno( err == 0, errno_compat(), kOptionErr );
+
+ // Send multicast packets with TTL 255 (helps against spoofing).
+
+ option = 255;
+ err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &option, sizeof( option ) );
+ check_translated_errno( err == 0, errno_compat(), kOptionErr );
+ }
+ else
+ {
+ dlog( kDebugLevelError, DEBUG_NAME "%s: unsupport socket family (%d)\n", __ROUTINE__, inAddr->sa_family );
+ err = kUnsupportedErr;
+ goto exit;
+ }
+
+ // Success!
+
+ *outSocketRef = sock;
+ sock = kInvalidSocketRef;
+ err = mStatus_NoError;
+
+exit:
+ if( IsValidSocket( sock ) )
+ {
+ close_compat( sock );
+ }
+ return( err );
+}
+
+//===========================================================================================================================
+// SetupSocket
+//===========================================================================================================================
+
+mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort )
+{
+ mStatus err;
+
+ check( inSA );
+ check( outIP );
+
+ if( inSA->sa_family == AF_INET )
+ {
+ struct sockaddr_in * sa4;
+
+ sa4 = (struct sockaddr_in *) inSA;
+ outIP->type = mDNSAddrType_IPv4;
+ outIP->ip.v4.NotAnInteger = sa4->sin_addr.s_addr;
+ if( outPort )
+ {
+ outPort->NotAnInteger = sa4->sin_port;
+ }
+ err = mStatus_NoError;
+ }
+ else if( inSA->sa_family == AF_INET6 )
+ {
+ struct sockaddr_in6 * sa6;
+
+ sa6 = (struct sockaddr_in6 *) inSA;
+ outIP->type = mDNSAddrType_IPv6;
+ outIP->ip.v6 = *( (mDNSv6Addr *) &sa6->sin6_addr );
+ if( IN6_IS_ADDR_LINKLOCAL( &sa6->sin6_addr ) )
+ {
+ outIP->ip.v6.w[ 1 ] = 0;
+ }
+ if( outPort )
+ {
+ outPort->NotAnInteger = sa6->sin6_port;
+ }
+ err = mStatus_NoError;
+ }
+ else
+ {
+ dlog( kDebugLevelError, DEBUG_NAME "%s: invalid sa_family %d", __ROUTINE__, inSA->sa_family );
+ err = mStatus_BadParamErr;
+ }
+ return( err );
+}
+
+
+#if 0
+#pragma mark -
+#endif
+
+//===========================================================================================================================
+// UDPSocketNotification
+//===========================================================================================================================
+
+mDNSlocal void CALLBACK
+UDPSocketNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context )
+{
+ UDPSocket *udpSock = ( UDPSocket* ) context;
+ WSAMSG wmsg;
+ WSABUF wbuf;
+ struct sockaddr_storage sockSrcAddr; // This is filled in by the WSARecv* function
+ INT sockSrcAddrLen; // See above
+ mDNSAddr srcAddr;
+ mDNSInterfaceID iid;
+ mDNSIPPort srcPort;
+ mDNSAddr dstAddr;
+ mDNSIPPort dstPort;
+ uint8_t controlBuffer[ 128 ];
+ mDNSu8 * end;
+ int num;
+ DWORD numTries;
+ mStatus err;
+
+ DEBUG_UNUSED( sock );
+ DEBUG_UNUSED( event );
+
+ require_action( udpSock != NULL, exit, err = mStatus_BadStateErr );
+
+ dlog( kDebugLevelChatty, DEBUG_NAME "%s: sock = %d\n", __ROUTINE__, udpSock->fd );
+
+ // Initialize the buffer structure
+
+ wbuf.buf = (char *) &udpSock->packet;
+ wbuf.len = (u_long) sizeof( udpSock->packet );
+ sockSrcAddrLen = sizeof( sockSrcAddr );
+
+ numTries = 0;
+
+ do
+ {
+ if ( udpSock->recvMsgPtr )
+ {
+ DWORD size;
+
+ wmsg.name = ( LPSOCKADDR ) &sockSrcAddr;
+ wmsg.namelen = sockSrcAddrLen;
+ wmsg.lpBuffers = &wbuf;
+ wmsg.dwBufferCount = 1;
+ wmsg.Control.buf = ( CHAR* ) controlBuffer;
+ wmsg.Control.len = sizeof( controlBuffer );
+ wmsg.dwFlags = 0;
+
+ err = udpSock->recvMsgPtr( udpSock->fd, &wmsg, &size, NULL, NULL );
+ err = translate_errno( ( err == 0 ), (OSStatus) WSAGetLastError(), kUnknownErr );
+ num = ( int ) size;
+
+ // <rdar://problem/7824093> iTunes 9.1 fails to install with Bonjour service on Windows 7 Ultimate
+ //
+ // There seems to be a bug in some network device drivers that involves calling WSARecvMsg().
+ // Although all the parameters to WSARecvMsg() are correct, it returns a
+ // WSAEFAULT error code when there is no actual error. We have found experientially that falling
+ // back to using WSARecvFrom() when this happens will work correctly.
+
+ if ( err == WSAEFAULT ) udpSock->recvMsgPtr = NULL;
+ }
+ else
+ {
+ DWORD flags = 0;
+
+ num = WSARecvFrom( udpSock->fd, &wbuf, 1, NULL, &flags, ( LPSOCKADDR ) &sockSrcAddr, &sockSrcAddrLen, NULL, NULL );
+ err = translate_errno( ( num >= 0 ), ( OSStatus ) WSAGetLastError(), kUnknownErr );
+ }
+
+ // According to MSDN <http://msdn.microsoft.com/en-us/library/ms741687(VS.85).aspx>:
+ //
+ // "WSAECONNRESET: For a UDP datagram socket, this error would indicate that a previous
+ // send operation resulted in an ICMP "Port Unreachable" message."
+ //
+ // Because this is the case, we want to ignore this error and try again. Just in case
+ // this is some kind of pathological condition, we'll break out of the retry loop
+ // after 100 iterations
+
+ require_action( !err || ( err == WSAECONNRESET ) || ( err == WSAEFAULT ), exit, err = WSAGetLastError() );
+ }
+ while ( ( ( err == WSAECONNRESET ) || ( err == WSAEFAULT ) ) && ( numTries++ < 100 ) );
+
+ require_noerr( err, exit );
+
+ // Translate the source of this packet into mDNS data types
+
+ SockAddrToMDNSAddr( (struct sockaddr* ) &sockSrcAddr, &srcAddr, &srcPort );
+
+ // Initialize the destination of this packet. Just in case
+ // we can't determine this info because we couldn't call
+ // WSARecvMsg (recvMsgPtr)
+
+ dstAddr = udpSock->addr;
+ dstPort = udpSock->port;
+
+ if ( udpSock->recvMsgPtr )
+ {
+ LPWSACMSGHDR header;
+ LPWSACMSGHDR last = NULL;
+ int count = 0;
+
+ // Parse the control information. Reject packets received on the wrong interface.
+
+ // <rdar://problem/7832196> INSTALL: Bonjour 2.0 on Windows can not start / stop
+ //
+ // There seems to be an interaction between Bullguard and this next bit of code.
+ // When a user's machine is running Bullguard, the control information that is
+ // returned is corrupted, and the code would go into an infinite loop. We'll add
+ // two bits of defensive coding here. The first will check that each pointer to
+ // the LPWSACMSGHDR that is returned in the for loop is different than the last.
+ // This fixes the problem with Bullguard. The second will break out of this loop
+ // after 100 iterations, just in case the corruption isn't caught by the first
+ // check.
+
+ for ( header = WSA_CMSG_FIRSTHDR( &wmsg ); header; header = WSA_CMSG_NXTHDR( &wmsg, header ) )
+ {
+ if ( ( header != last ) && ( ++count < 100 ) )
+ {
+ last = header;
+
+ if ( ( header->cmsg_level == IPPROTO_IP ) && ( header->cmsg_type == IP_PKTINFO ) )
+ {
+ IN_PKTINFO * ipv4PacketInfo;
+
+ ipv4PacketInfo = (IN_PKTINFO *) WSA_CMSG_DATA( header );
+
+ if ( udpSock->ifd != NULL )
+ {
+ require_action( ipv4PacketInfo->ipi_ifindex == udpSock->ifd->index, exit, err = ( DWORD ) kMismatchErr );
+ }
+
+ dstAddr.type = mDNSAddrType_IPv4;
+ dstAddr.ip.v4.NotAnInteger = ipv4PacketInfo->ipi_addr.s_addr;
+ }
+ else if( ( header->cmsg_level == IPPROTO_IPV6 ) && ( header->cmsg_type == IPV6_PKTINFO ) )
+ {
+ IN6_PKTINFO * ipv6PacketInfo;
+
+ ipv6PacketInfo = (IN6_PKTINFO *) WSA_CMSG_DATA( header );
+
+ if ( udpSock->ifd != NULL )
+ {
+ require_action( ipv6PacketInfo->ipi6_ifindex == ( udpSock->ifd->index - kIPv6IfIndexBase ), exit, err = ( DWORD ) kMismatchErr );
+ }
+
+ dstAddr.type = mDNSAddrType_IPv6;
+ dstAddr.ip.v6 = *( (mDNSv6Addr *) &ipv6PacketInfo->ipi6_addr );
+ }
+ }
+ else
+ {
+ static BOOL loggedMessage = FALSE;
+
+ if ( !loggedMessage )
+ {
+ LogMsg( "UDPEndRecv: WSARecvMsg control information error." );
+ loggedMessage = TRUE;
+ }
+
+ break;
+ }
+ }
+ }
+
+ dlog( kDebugLevelChatty, DEBUG_NAME "packet received\n" );
+ dlog( kDebugLevelChatty, DEBUG_NAME " size = %d\n", num );
+ dlog( kDebugLevelChatty, DEBUG_NAME " src = %#a:%u\n", &srcAddr, ntohs( srcPort.NotAnInteger ) );
+ dlog( kDebugLevelChatty, DEBUG_NAME " dst = %#a:%u\n", &dstAddr, ntohs( dstPort.NotAnInteger ) );
+
+ if ( udpSock->ifd != NULL )
+ {
+ dlog( kDebugLevelChatty, DEBUG_NAME " interface = %#a (index=0x%08X)\n", &udpSock->ifd->interfaceInfo.ip, udpSock->ifd->index );
+ }
+
+ dlog( kDebugLevelChatty, DEBUG_NAME "\n" );
+
+ iid = udpSock->ifd ? udpSock->ifd->interfaceInfo.InterfaceID : NULL;
+ end = ( (mDNSu8 *) &udpSock->packet ) + num;
+
+ mDNSCoreReceive( udpSock->m, &udpSock->packet, end, &srcAddr, srcPort, &dstAddr, dstPort, iid );
+
+exit:
+
+ return;
+}
+
+
+//===========================================================================================================================
+// InterfaceListDidChange
+//===========================================================================================================================
+void InterfaceListDidChange( mDNS * const inMDNS )
+{
+ mStatus err;
+
+ dlog( kDebugLevelInfo, DEBUG_NAME "interface list changed\n" );
+ check( inMDNS );
+
+ // Tear down the existing interfaces and set up new ones using the new IP info.
+
+ err = TearDownInterfaceList( inMDNS );
+ check_noerr( err );
+
+ err = SetupInterfaceList( inMDNS );
+ check_noerr( err );
+
+ err = uDNS_SetupDNSConfig( inMDNS );
+ check_noerr( err );
+
+ // Inform clients of the change.
+
+ mDNS_ConfigChanged(inMDNS);
+
+ // Force mDNS to update.
+
+ mDNSCoreMachineSleep( inMDNS, mDNSfalse ); // What is this for? Mac OS X does not do this
+}
+
+
+//===========================================================================================================================
+// ComputerDescriptionDidChange
+//===========================================================================================================================
+void ComputerDescriptionDidChange( mDNS * const inMDNS )
+{
+ dlog( kDebugLevelInfo, DEBUG_NAME "computer description has changed\n" );
+ check( inMDNS );
+
+ // redo the names
+ SetupNiceName( inMDNS );
+}
+
+
+//===========================================================================================================================
+// TCPIPConfigDidChange
+//===========================================================================================================================
+void TCPIPConfigDidChange( mDNS * const inMDNS )
+{
+ mStatus err;
+
+ dlog( kDebugLevelInfo, DEBUG_NAME "TCP/IP config has changed\n" );
+ check( inMDNS );
+
+ err = uDNS_SetupDNSConfig( inMDNS );
+ check_noerr( err );
+}
+
+
+//===========================================================================================================================
+// DynDNSConfigDidChange
+//===========================================================================================================================
+void DynDNSConfigDidChange( mDNS * const inMDNS )
+{
+ mStatus err;
+
+ dlog( kDebugLevelInfo, DEBUG_NAME "DynDNS config has changed\n" );
+ check( inMDNS );
+
+ SetDomainSecrets( inMDNS );
+
+ err = uDNS_SetupDNSConfig( inMDNS );
+ check_noerr( err );
+}
+
+
+//===========================================================================================================================
+// FileSharingDidChange
+//===========================================================================================================================
+void FileSharingDidChange( mDNS * const inMDNS )
+{
+ dlog( kDebugLevelInfo, DEBUG_NAME "File shares has changed\n" );
+ check( inMDNS );
+
+ CheckFileShares( inMDNS );
+}
+
+
+//===========================================================================================================================
+// FilewallDidChange
+//===========================================================================================================================
+void FirewallDidChange( mDNS * const inMDNS )
+{
+ dlog( kDebugLevelInfo, DEBUG_NAME "Firewall has changed\n" );
+ check( inMDNS );
+
+ CheckFileShares( inMDNS );
+}
+
+
+#if 0
+#pragma mark -
+#pragma mark == Utilities ==
+#endif
+
+//===========================================================================================================================
+// getifaddrs
+//===========================================================================================================================
+
+mDNSlocal int getifaddrs( struct ifaddrs **outAddrs )
+{
+ int err;
+
+#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
+
+ // Try to the load the GetAdaptersAddresses function from the IP Helpers DLL. This API is only available on Windows
+ // XP or later. Looking up the symbol at runtime allows the code to still work on older systems without that API.
+
+ if( !gIPHelperLibraryInstance )
+ {
+ gIPHelperLibraryInstance = LoadLibrary( TEXT( "Iphlpapi" ) );
+ if( gIPHelperLibraryInstance )
+ {
+ gGetAdaptersAddressesFunctionPtr =
+ (GetAdaptersAddressesFunctionPtr) GetProcAddress( gIPHelperLibraryInstance, "GetAdaptersAddresses" );
+ if( !gGetAdaptersAddressesFunctionPtr )
+ {
+ BOOL ok;
+
+ ok = FreeLibrary( gIPHelperLibraryInstance );
+ check_translated_errno( ok, GetLastError(), kUnknownErr );
+ gIPHelperLibraryInstance = NULL;
+ }
+ }
+ }
+
+ // Use the new IPv6-capable routine if supported. Otherwise, fall back to the old and compatible IPv4-only code.
+ // <rdar://problem/4278934> Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 fails
+ // <rdar://problem/6145913> Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 returns no addrs
+
+ if( !gGetAdaptersAddressesFunctionPtr || ( ( ( err = getifaddrs_ipv6( outAddrs ) ) != mStatus_NoError ) || ( ( outAddrs != NULL ) && ( *outAddrs == NULL ) ) ) )
+ {
+ err = getifaddrs_ipv4( outAddrs );
+ require_noerr( err, exit );
+ }
+
+#else
+
+ err = getifaddrs_ipv4( outAddrs );
+ require_noerr( err, exit );
+
+#endif
+
+exit:
+ return( err );
+}
+
+#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
+//===========================================================================================================================
+// getifaddrs_ipv6
+//===========================================================================================================================
+
+mDNSlocal int getifaddrs_ipv6( struct ifaddrs **outAddrs )
+{
+ DWORD err;
+ int i;
+ DWORD flags;
+ struct ifaddrs * head;
+ struct ifaddrs ** next;
+ IP_ADAPTER_ADDRESSES * iaaList;
+ ULONG iaaListSize;
+ IP_ADAPTER_ADDRESSES * iaa;
+ size_t size;
+ struct ifaddrs * ifa;
+
+ check( gGetAdaptersAddressesFunctionPtr );
+
+ head = NULL;
+ next = &head;
+ iaaList = NULL;
+
+ // Get the list of interfaces. The first call gets the size and the second call gets the actual data.
+ // This loops to handle the case where the interface changes in the window after getting the size, but before the
+ // second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
+
+ flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
+ i = 0;
+ for( ;; )
+ {
+ iaaListSize = 0;
+ err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, NULL, &iaaListSize );
+ check( err == ERROR_BUFFER_OVERFLOW );
+ check( iaaListSize >= sizeof( IP_ADAPTER_ADDRESSES ) );
+
+ iaaList = (IP_ADAPTER_ADDRESSES *) malloc( iaaListSize );
+ require_action( iaaList, exit, err = ERROR_NOT_ENOUGH_MEMORY );
+
+ err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, iaaList, &iaaListSize );
+ if( err == ERROR_SUCCESS ) break;
+
+ free( iaaList );
+ iaaList = NULL;
+ ++i;
+ require( i < 100, exit );
+ dlog( kDebugLevelWarning, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__, i, err, err );
+ }
+
+ for( iaa = iaaList; iaa; iaa = iaa->Next )
+ {
+ int addrIndex;
+ IP_ADAPTER_UNICAST_ADDRESS * addr;
+ DWORD ipv6IfIndex;
+ IP_ADAPTER_PREFIX * firstPrefix;
+
+ if( iaa->IfIndex > 0xFFFFFF )
+ {
+ dlog( kDebugLevelAlert, DEBUG_NAME "%s: IPv4 ifindex out-of-range (0x%08X)\n", __ROUTINE__, iaa->IfIndex );
+ }
+ if( iaa->Ipv6IfIndex > 0xFF )
+ {
+ dlog( kDebugLevelAlert, DEBUG_NAME "%s: IPv6 ifindex out-of-range (0x%08X)\n", __ROUTINE__, iaa->Ipv6IfIndex );
+ }
+
+ // For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the
+ // following code to crash when iterating through the prefix list. This seems
+ // to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
+ // This shouldn't happen according to Microsoft docs which states:
+ //
+ // "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
+ //
+ // So the data structure seems to be corrupted when we return from
+ // GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
+ // sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
+ // modify iaa to have the correct values.
+
+ if ( iaa->Length >= sizeof( IP_ADAPTER_ADDRESSES ) )
+ {
+ ipv6IfIndex = iaa->Ipv6IfIndex;
+ firstPrefix = iaa->FirstPrefix;
+ }
+ else
+ {
+ ipv6IfIndex = 0;
+ firstPrefix = NULL;
+ }
+
+ // Skip pseudo and tunnel interfaces.
+
+ if( ( ( ipv6IfIndex == 1 ) && ( iaa->IfType != IF_TYPE_SOFTWARE_LOOPBACK ) ) || ( iaa->IfType == IF_TYPE_TUNNEL ) )
+ {
+ continue;
+ }
+
+ // Add each address as a separate interface to emulate the way getifaddrs works.
+
+ for( addrIndex = 0, addr = iaa->FirstUnicastAddress; addr; ++addrIndex, addr = addr->Next )
+ {
+ int family;
+ IP_ADAPTER_PREFIX * prefix;
+ uint32_t ipv4Index;
+ struct sockaddr_in ipv4Netmask;
+
+ family = addr->Address.lpSockaddr->sa_family;
+ if( ( family != AF_INET ) && ( family != AF_INET6 ) ) continue;
+
+ // <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
+ // Seems as if the problem here is a buggy implementation of some network interface
+ // driver. It is reporting that is has a link-local address when it is actually
+ // disconnected. This was causing a problem in AddressToIndexAndMask.
+ // The solution is to call AddressToIndexAndMask first, and if unable to lookup
+ // the address, to ignore that address.
+
+ ipv4Index = 0;
+ memset( &ipv4Netmask, 0, sizeof( ipv4Netmask ) );
+
+ if ( family == AF_INET )
+ {
+ err = AddressToIndexAndMask( addr->Address.lpSockaddr, &ipv4Index, ( struct sockaddr* ) &ipv4Netmask );
+
+ if ( err )
+ {
+ err = 0;
+ continue;
+ }
+ }
+
+ ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
+ require_action( ifa, exit, err = WSAENOBUFS );
+
+ *next = ifa;
+ next = &ifa->ifa_next;
+
+ // Get the name.
+
+ size = strlen( iaa->AdapterName ) + 1;
+ ifa->ifa_name = (char *) malloc( size );
+ require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
+ memcpy( ifa->ifa_name, iaa->AdapterName, size );
+
+ // Get interface flags.
+
+ ifa->ifa_flags = 0;
+ if( iaa->OperStatus == IfOperStatusUp ) ifa->ifa_flags |= IFF_UP;
+ if( iaa->IfType == IF_TYPE_SOFTWARE_LOOPBACK ) ifa->ifa_flags |= IFF_LOOPBACK;
+ else if ( IsPointToPoint( addr ) ) ifa->ifa_flags |= IFF_POINTTOPOINT;
+ if( !( iaa->Flags & IP_ADAPTER_NO_MULTICAST ) ) ifa->ifa_flags |= IFF_MULTICAST;
+
+
+ // <rdar://problem/4045657> Interface index being returned is 512
+ //
+ // Windows does not have a uniform scheme for IPv4 and IPv6 interface indexes.
+ // This code used to shift the IPv4 index up to ensure uniqueness between
+ // it and IPv6 indexes. Although this worked, it was somewhat confusing to developers, who
+ // then see interface indexes passed back that don't correspond to anything
+ // that is seen in Win32 APIs or command line tools like "route". As a relatively
+ // small percentage of developers are actively using IPv6, it seems to
+ // make sense to make our use of IPv4 as confusion free as possible.
+ // So now, IPv6 interface indexes will be shifted up by a
+ // constant value which will serve to uniquely identify them, and we will
+ // leave IPv4 interface indexes unmodified.
+
+ switch( family )
+ {
+ case AF_INET: ifa->ifa_extra.index = iaa->IfIndex; break;
+ case AF_INET6: ifa->ifa_extra.index = ipv6IfIndex + kIPv6IfIndexBase; break;
+ default: break;
+ }
+
+ // Get lease lifetime
+
+ if ( ( iaa->IfType != IF_TYPE_SOFTWARE_LOOPBACK ) && ( addr->LeaseLifetime != 0 ) && ( addr->ValidLifetime != 0xFFFFFFFF ) )
+ {
+ ifa->ifa_dhcpEnabled = TRUE;
+ ifa->ifa_dhcpLeaseExpires = time( NULL ) + addr->ValidLifetime;
+ }
+ else
+ {
+ ifa->ifa_dhcpEnabled = FALSE;
+ ifa->ifa_dhcpLeaseExpires = 0;
+ }
+
+ if ( iaa->PhysicalAddressLength == sizeof( ifa->ifa_physaddr ) )
+ {
+ memcpy( ifa->ifa_physaddr, iaa->PhysicalAddress, iaa->PhysicalAddressLength );
+ }
+
+ // Because we don't get notified of womp changes, we're going to just assume
+ // that all wired interfaces have it enabled. Before we go to sleep, we'll check
+ // if the interface actually supports it, and update mDNS->SystemWakeOnLANEnabled
+ // accordingly
+
+ ifa->ifa_womp = ( iaa->IfType == IF_TYPE_ETHERNET_CSMACD ) ? mDNStrue : mDNSfalse;
+
+ // Get address.
+
+ switch( family )
+ {
+ case AF_INET:
+ case AF_INET6:
+ ifa->ifa_addr = (struct sockaddr *) calloc( 1, (size_t) addr->Address.iSockaddrLength );
+ require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
+ memcpy( ifa->ifa_addr, addr->Address.lpSockaddr, (size_t) addr->Address.iSockaddrLength );
+ break;
+
+ default:
+ break;
+ }
+ check( ifa->ifa_addr );
+
+ // Get subnet mask (IPv4)/link prefix (IPv6). It is specified as a bit length (e.g. 24 for 255.255.255.0).
+
+ switch ( family )
+ {
+ case AF_INET:
+ {
+ struct sockaddr_in * sa4;
+
+ sa4 = (struct sockaddr_in *) calloc( 1, sizeof( *sa4 ) );
+ require_action( sa4, exit, err = WSAENOBUFS );
+ sa4->sin_family = AF_INET;
+ sa4->sin_addr.s_addr = ipv4Netmask.sin_addr.s_addr;
+
+ dlog( kDebugLevelInfo, DEBUG_NAME "%s: IPv4 mask = %s\n", __ROUTINE__, inet_ntoa( sa4->sin_addr ) );
+ ifa->ifa_netmask = (struct sockaddr *) sa4;
+ break;
+ }
+
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sa6;
+ char buf[ 256 ] = { 0 };
+ DWORD buflen = sizeof( buf );
+
+ sa6 = (struct sockaddr_in6 *) calloc( 1, sizeof( *sa6 ) );
+ require_action( sa6, exit, err = WSAENOBUFS );
+ sa6->sin6_family = AF_INET6;
+ memset( sa6->sin6_addr.s6_addr, 0xFF, sizeof( sa6->sin6_addr.s6_addr ) );
+ ifa->ifa_netmask = (struct sockaddr *) sa6;
+
+ for ( prefix = firstPrefix; prefix; prefix = prefix->Next )
+ {
+ IN6_ADDR mask;
+ IN6_ADDR maskedAddr;
+ int maskIndex;
+ DWORD len;
+
+ // According to MSDN:
+ // "On Windows Vista and later, the linked IP_ADAPTER_PREFIX structures pointed to by the FirstPrefix member
+ // include three IP adapter prefixes for each IP address assigned to the adapter. These include the host IP address prefix,
+ // the subnet IP address prefix, and the subnet broadcast IP address prefix.
+ // In addition, for each adapter there is a multicast address prefix and a broadcast address prefix.
+ // On Windows XP with SP1 and later prior to Windows Vista, the linked IP_ADAPTER_PREFIX structures pointed to by the FirstPrefix member
+ // include only a single IP adapter prefix for each IP address assigned to the adapter."
+
+ // We're only interested in the subnet IP address prefix. We'll determine if the prefix is the
+ // subnet prefix by masking our address with a mask (computed from the prefix length) and see if that is the same
+ // as the prefix address.
+
+ if ( ( prefix->PrefixLength == 0 ) ||
+ ( prefix->PrefixLength > 128 ) ||
+ ( addr->Address.iSockaddrLength != prefix->Address.iSockaddrLength ) ||
+ ( memcmp( addr->Address.lpSockaddr, prefix->Address.lpSockaddr, addr->Address.iSockaddrLength ) == 0 ) )
+ {
+ continue;
+ }
+
+ // Compute the mask
+
+ memset( mask.s6_addr, 0, sizeof( mask.s6_addr ) );
+
+ for ( len = (int) prefix->PrefixLength, maskIndex = 0; len > 0; len -= 8 )
+ {
+ uint8_t maskByte = ( len >= 8 ) ? 0xFF : (uint8_t)( ( 0xFFU << ( 8 - len ) ) & 0xFFU );
+ mask.s6_addr[ maskIndex++ ] = maskByte;
+ }
+
+ // Apply the mask
+
+ for ( i = 0; i < 16; i++ )
+ {
+ maskedAddr.s6_addr[ i ] = ( ( struct sockaddr_in6* ) addr->Address.lpSockaddr )->sin6_addr.s6_addr[ i ] & mask.s6_addr[ i ];
+ }
+
+ // Compare
+
+ if ( memcmp( ( ( struct sockaddr_in6* ) prefix->Address.lpSockaddr )->sin6_addr.s6_addr, maskedAddr.s6_addr, sizeof( maskedAddr.s6_addr ) ) == 0 )
+ {
+ memcpy( sa6->sin6_addr.s6_addr, mask.s6_addr, sizeof( mask.s6_addr ) );
+ break;
+ }
+ }
+
+ WSAAddressToStringA( ( LPSOCKADDR ) sa6, sizeof( struct sockaddr_in6 ), NULL, buf, &buflen );
+ dlog( kDebugLevelInfo, DEBUG_NAME "%s: IPv6 mask = %s\n", __ROUTINE__, buf );
+
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+ }
+
+ // Success!
+
+ if( outAddrs )
+ {
+ *outAddrs = head;
+ head = NULL;
+ }
+ err = ERROR_SUCCESS;
+
+exit:
+ if( head )
+ {
+ freeifaddrs( head );
+ }
+ if( iaaList )
+ {
+ free( iaaList );
+ }
+ return( (int) err );
+}
+
+#endif // MDNS_WINDOWS_USE_IPV6_IF_ADDRS
+
+//===========================================================================================================================
+// getifaddrs_ipv4
+//===========================================================================================================================
+
+mDNSlocal int getifaddrs_ipv4( struct ifaddrs **outAddrs )
+{
+ int err;
+ SOCKET sock;
+ DWORD size;
+ DWORD actualSize;
+ INTERFACE_INFO * buffer;
+ INTERFACE_INFO * tempBuffer;
+ INTERFACE_INFO * ifInfo;
+ int n;
+ int i;
+ struct ifaddrs * head;
+ struct ifaddrs ** next;
+ struct ifaddrs * ifa;
+
+ sock = INVALID_SOCKET;
+ buffer = NULL;
+ head = NULL;
+ next = &head;
+
+ // Get the interface list. WSAIoctl is called with SIO_GET_INTERFACE_LIST, but since this does not provide a
+ // way to determine the size of the interface list beforehand, we have to start with an initial size guess and
+ // call WSAIoctl repeatedly with increasing buffer sizes until it succeeds. Limit this to 100 tries for safety.
+
+ sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
+ err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
+ require_noerr( err, exit );
+
+ n = 0;
+ size = 16 * sizeof( INTERFACE_INFO );
+ for( ;; )
+ {
+ tempBuffer = (INTERFACE_INFO *) realloc( buffer, size );
+ require_action( tempBuffer, exit, err = WSAENOBUFS );
+ buffer = tempBuffer;
+
+ err = WSAIoctl( sock, SIO_GET_INTERFACE_LIST, NULL, 0, buffer, size, &actualSize, NULL, NULL );
+ if( err == 0 )
+ {
+ break;
+ }
+
+ ++n;
+ require_action( n < 100, exit, err = WSAEADDRNOTAVAIL );
+
+ size += ( 16 * sizeof( INTERFACE_INFO ) );
+ }
+ check( actualSize <= size );
+ check( ( actualSize % sizeof( INTERFACE_INFO ) ) == 0 );
+ n = (int)( actualSize / sizeof( INTERFACE_INFO ) );
+
+ // Process the raw interface list and build a linked list of IPv4 interfaces.
+
+ for( i = 0; i < n; ++i )
+ {
+ uint32_t ifIndex;
+ struct sockaddr_in netmask;
+
+ ifInfo = &buffer[ i ];
+ if( ifInfo->iiAddress.Address.sa_family != AF_INET )
+ {
+ continue;
+ }
+
+ // <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
+ // See comment in getifaddrs_ipv6
+
+ ifIndex = 0;
+ memset( &netmask, 0, sizeof( netmask ) );
+ err = AddressToIndexAndMask( ( struct sockaddr* ) &ifInfo->iiAddress.AddressIn, &ifIndex, ( struct sockaddr* ) &netmask );
+
+ if ( err )
+ {
+ continue;
+ }
+
+ ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
+ require_action( ifa, exit, err = WSAENOBUFS );
+
+ *next = ifa;
+ next = &ifa->ifa_next;
+
+ // Get the name.
+
+ ifa->ifa_name = (char *) malloc( 16 );
+ require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
+ sprintf( ifa->ifa_name, "%d", i + 1 );
+
+ // Get interface flags.
+
+ ifa->ifa_flags = (u_int) ifInfo->iiFlags;
+
+ // Get addresses.
+
+ if ( ifInfo->iiAddress.Address.sa_family == AF_INET )
+ {
+ struct sockaddr_in * sa4;
+
+ sa4 = &ifInfo->iiAddress.AddressIn;
+ ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sa4 ) );
+ require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
+ memcpy( ifa->ifa_addr, sa4, sizeof( *sa4 ) );
+
+ ifa->ifa_netmask = (struct sockaddr*) calloc(1, sizeof( *sa4 ) );
+ require_action( ifa->ifa_netmask, exit, err = WSAENOBUFS );
+
+ // <rdar://problem/4076478> Service won't start on Win2K. The address
+ // family field was not being initialized.
+
+ ifa->ifa_netmask->sa_family = AF_INET;
+ ( ( struct sockaddr_in* ) ifa->ifa_netmask )->sin_addr = netmask.sin_addr;
+ ifa->ifa_extra.index = ifIndex;
+ }
+ else
+ {
+ // Emulate an interface index.
+
+ ifa->ifa_extra.index = (uint32_t)( i + 1 );
+ }
+ }
+
+ // Success!
+
+ if( outAddrs )
+ {
+ *outAddrs = head;
+ head = NULL;
+ }
+ err = 0;
+
+exit:
+
+ if( head )
+ {
+ freeifaddrs( head );
+ }
+ if( buffer )
+ {
+ free( buffer );
+ }
+ if( sock != INVALID_SOCKET )
+ {
+ closesocket( sock );
+ }
+ return( err );
+}
+
+//===========================================================================================================================
+// freeifaddrs
+//===========================================================================================================================
+
+mDNSlocal void freeifaddrs( struct ifaddrs *inIFAs )
+{
+ struct ifaddrs * p;
+ struct ifaddrs * q;
+
+ // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
+
+ for( p = inIFAs; p; p = q )
+ {
+ q = p->ifa_next;
+
+ if( p->ifa_name )
+ {
+ free( p->ifa_name );
+ p->ifa_name = NULL;
+ }
+ if( p->ifa_addr )
+ {
+ free( p->ifa_addr );
+ p->ifa_addr = NULL;
+ }
+ if( p->ifa_netmask )
+ {
+ free( p->ifa_netmask );
+ p->ifa_netmask = NULL;
+ }
+ if( p->ifa_broadaddr )
+ {
+ free( p->ifa_broadaddr );
+ p->ifa_broadaddr = NULL;
+ }
+ if( p->ifa_dstaddr )
+ {
+ free( p->ifa_dstaddr );
+ p->ifa_dstaddr = NULL;
+ }
+ if( p->ifa_data )
+ {
+ free( p->ifa_data );
+ p->ifa_data = NULL;
+ }
+ free( p );
+ }
+}
+
+
+//===========================================================================================================================
+// GetPrimaryInterface
+//===========================================================================================================================
+
+mDNSlocal DWORD
+GetPrimaryInterface()
+{
+ PMIB_IPFORWARDTABLE pIpForwardTable = NULL;
+ DWORD dwSize = 0;
+ BOOL bOrder = FALSE;
+ OSStatus err;
+ DWORD index = 0;
+ DWORD metric = 0;
+ unsigned long int i;
+
+ // Find out how big our buffer needs to be.
+
+ err = GetIpForwardTable(NULL, &dwSize, bOrder);
+ require_action( err == ERROR_INSUFFICIENT_BUFFER, exit, err = kUnknownErr );
+
+ // Allocate the memory for the table
+
+ pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc( dwSize );
+ require_action( pIpForwardTable, exit, err = kNoMemoryErr );
+
+ // Now get the table.
+
+ err = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
+ require_noerr( err, exit );
+
+
+ // Search for the row in the table we want.
+
+ for ( i = 0; i < pIpForwardTable->dwNumEntries; i++)
+ {
+ // Look for a default route
+
+ if ( pIpForwardTable->table[i].dwForwardDest == 0 )
+ {
+ if ( index && ( pIpForwardTable->table[i].dwForwardMetric1 >= metric ) )
+ {
+ continue;
+ }
+
+ index = pIpForwardTable->table[i].dwForwardIfIndex;
+ metric = pIpForwardTable->table[i].dwForwardMetric1;
+ }
+ }
+
+exit:
+
+ if ( pIpForwardTable != NULL )
+ {
+ free( pIpForwardTable );
+ }
+
+ return index;
+}
+
+
+//===========================================================================================================================
+// AddressToIndexAndMask
+//===========================================================================================================================
+
+mDNSlocal mStatus
+AddressToIndexAndMask( struct sockaddr * addr, uint32_t * ifIndex, struct sockaddr * mask )
+{
+ // Before calling AddIPAddress we use GetIpAddrTable to get
+ // an adapter to which we can add the IP.
+
+ PMIB_IPADDRTABLE pIPAddrTable = NULL;
+ DWORD dwSize = 0;
+ mStatus err = mStatus_UnknownErr;
+ DWORD i;
+
+ // For now, this is only for IPv4 addresses. That is why we can safely cast
+ // addr's to sockaddr_in.
+
+ require_action( addr->sa_family == AF_INET, exit, err = mStatus_UnknownErr );
+
+ // Make an initial call to GetIpAddrTable to get the
+ // necessary size into the dwSize variable
+
+ for ( i = 0; i < 100; i++ )
+ {
+ err = GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
+
+ if ( err != ERROR_INSUFFICIENT_BUFFER )
+ {
+ break;
+ }
+
+ pIPAddrTable = (MIB_IPADDRTABLE *) realloc( pIPAddrTable, dwSize );
+ require_action( pIPAddrTable, exit, err = WSAENOBUFS );
+ }
+
+ require_noerr( err, exit );
+ err = mStatus_UnknownErr;
+
+ for ( i = 0; i < pIPAddrTable->dwNumEntries; i++ )
+ {
+ if ( ( ( struct sockaddr_in* ) addr )->sin_addr.s_addr == pIPAddrTable->table[i].dwAddr )
+ {
+ *ifIndex = pIPAddrTable->table[i].dwIndex;
+ ( ( struct sockaddr_in*) mask )->sin_addr.s_addr = pIPAddrTable->table[i].dwMask;
+ err = mStatus_NoError;
+ break;
+ }
+ }
+
+exit:
+
+ if ( pIPAddrTable )
+ {
+ free( pIPAddrTable );
+ }
+
+ return err;
+}
+
+
+//===========================================================================================================================
+// CanReceiveUnicast
+//===========================================================================================================================
+
+mDNSlocal mDNSBool CanReceiveUnicast( void )
+{
+ mDNSBool ok;
+ SocketRef sock;
+ struct sockaddr_in addr;
+
+ // Try to bind to the port without the SO_REUSEADDR option to test if someone else has already bound to it.
+
+ sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
+ check_translated_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
+ ok = IsValidSocket( sock );
+ if( ok )
+ {
+ mDNSPlatformMemZero( &addr, sizeof( addr ) );
+ addr.sin_family = AF_INET;
+ addr.sin_port = MulticastDNSPort.NotAnInteger;
+ addr.sin_addr.s_addr = htonl( INADDR_ANY );
+
+ ok = ( bind( sock, (struct sockaddr *) &addr, sizeof( addr ) ) == 0 );
+ close_compat( sock );
+ }
+
+ dlog( kDebugLevelInfo, DEBUG_NAME "Unicast UDP responses %s\n", ok ? "okay" : "*not allowed*" );
+ return( ok );
+}
+
+
+//===========================================================================================================================
+// IsPointToPoint
+//===========================================================================================================================
+
+mDNSlocal mDNSBool IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS * addr )
+{
+ struct ifaddrs * addrs = NULL;
+ struct ifaddrs * p = NULL;
+ OSStatus err;
+ mDNSBool ret = mDNSfalse;
+
+ // For now, only works for IPv4 interfaces
+
+ if ( addr->Address.lpSockaddr->sa_family == AF_INET )
+ {
+ // The getifaddrs_ipv4 call will give us correct information regarding IFF_POINTTOPOINT flags.
+
+ err = getifaddrs_ipv4( &addrs );
+ require_noerr( err, exit );
+
+ for ( p = addrs; p; p = p->ifa_next )
+ {
+ if ( ( addr->Address.lpSockaddr->sa_family == p->ifa_addr->sa_family ) &&
+ ( ( ( struct sockaddr_in* ) addr->Address.lpSockaddr )->sin_addr.s_addr == ( ( struct sockaddr_in* ) p->ifa_addr )->sin_addr.s_addr ) )
+ {
+ ret = ( p->ifa_flags & IFF_POINTTOPOINT ) ? mDNStrue : mDNSfalse;
+ break;
+ }
+ }
+ }
+
+exit:
+
+ if ( addrs )
+ {
+ freeifaddrs( addrs );
+ }
+
+ return ret;
+}
+
+
+//===========================================================================================================================
+// GetWindowsVersionString
+//===========================================================================================================================
+
+mDNSlocal OSStatus GetWindowsVersionString( char *inBuffer, size_t inBufferSize )
+{
+#if( !defined( VER_PLATFORM_WIN32_CE ) )
+ #define VER_PLATFORM_WIN32_CE 3
+#endif
+
+ OSStatus err;
+ OSVERSIONINFO osInfo;
+ BOOL ok;
+ const char * versionString;
+ DWORD platformID;
+ DWORD majorVersion;
+ DWORD minorVersion;
+ DWORD buildNumber;
+
+ versionString = "unknown Windows version";
+
+ osInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
+ ok = GetVersionEx( &osInfo );
+ err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
+ require_noerr( err, exit );
+
+ platformID = osInfo.dwPlatformId;
+ majorVersion = osInfo.dwMajorVersion;
+ minorVersion = osInfo.dwMinorVersion;
+ buildNumber = osInfo.dwBuildNumber & 0xFFFF;
+
+ if( ( platformID == VER_PLATFORM_WIN32_WINDOWS ) && ( majorVersion == 4 ) )
+ {
+ if( ( minorVersion < 10 ) && ( buildNumber == 950 ) )
+ {
+ versionString = "Windows 95";
+ }
+ else if( ( minorVersion < 10 ) && ( ( buildNumber > 950 ) && ( buildNumber <= 1080 ) ) )
+ {
+ versionString = "Windows 95 SP1";
+ }
+ else if( ( minorVersion < 10 ) && ( buildNumber > 1080 ) )
+ {
+ versionString = "Windows 95 OSR2";
+ }
+ else if( ( minorVersion == 10 ) && ( buildNumber == 1998 ) )
+ {
+ versionString = "Windows 98";
+ }
+ else if( ( minorVersion == 10 ) && ( ( buildNumber > 1998 ) && ( buildNumber < 2183 ) ) )
+ {
+ versionString = "Windows 98 SP1";
+ }
+ else if( ( minorVersion == 10 ) && ( buildNumber >= 2183 ) )
+ {
+ versionString = "Windows 98 SE";
+ }
+ else if( minorVersion == 90 )
+ {
+ versionString = "Windows ME";
+ }
+ }
+ else if( platformID == VER_PLATFORM_WIN32_NT )
+ {
+ if( ( majorVersion == 3 ) && ( minorVersion == 51 ) )
+ {
+ versionString = "Windows NT 3.51";
+ }
+ else if( ( majorVersion == 4 ) && ( minorVersion == 0 ) )
+ {
+ versionString = "Windows NT 4";
+ }
+ else if( ( majorVersion == 5 ) && ( minorVersion == 0 ) )
+ {
+ versionString = "Windows 2000";
+ }
+ else if( ( majorVersion == 5 ) && ( minorVersion == 1 ) )
+ {
+ versionString = "Windows XP";
+ }
+ else if( ( majorVersion == 5 ) && ( minorVersion == 2 ) )
+ {
+ versionString = "Windows Server 2003";
+ }
+ }
+ else if( platformID == VER_PLATFORM_WIN32_CE )
+ {
+ versionString = "Windows CE";
+ }
+
+exit:
+ if( inBuffer && ( inBufferSize > 0 ) )
+ {
+ inBufferSize -= 1;
+ strncpy( inBuffer, versionString, inBufferSize );
+ inBuffer[ inBufferSize ] = '\0';
+ }
+ return( err );
+}
+
+
+//===========================================================================================================================
+// RegQueryString
+//===========================================================================================================================
+
+mDNSlocal mStatus
+RegQueryString( HKEY key, LPCSTR valueName, LPSTR * string, DWORD * stringLen, DWORD * enabled )
+{
+ DWORD type;
+ int i;
+ mStatus err;
+
+ *stringLen = MAX_ESCAPED_DOMAIN_NAME;
+ *string = NULL;
+ i = 0;
+
+ do
+ {
+ if ( *string )
+ {
+ free( *string );
+ }
+
+ *string = (char*) malloc( *stringLen );
+ require_action( *string, exit, err = mStatus_NoMemoryErr );
+
+ err = RegQueryValueExA( key, valueName, 0, &type, (LPBYTE) *string, stringLen );
+
+ i++;
+ }
+ while ( ( err == ERROR_MORE_DATA ) && ( i < 100 ) );
+
+ require_noerr_quiet( err, exit );
+
+ if ( enabled )
+ {
+ DWORD dwSize = sizeof( DWORD );
+
+ err = RegQueryValueEx( key, TEXT("Enabled"), NULL, NULL, (LPBYTE) enabled, &dwSize );
+ check_noerr( err );
+
+ err = kNoErr;
+ }
+
+exit:
+
+ return err;
+}
+
+
+//===========================================================================================================================
+// StringToAddress
+//===========================================================================================================================
+
+mDNSlocal mStatus StringToAddress( mDNSAddr * ip, LPSTR string )
+{
+ struct sockaddr_in6 sa6;
+ struct sockaddr_in sa4;
+ INT dwSize;
+ mStatus err;
+
+ sa6.sin6_family = AF_INET6;
+ dwSize = sizeof( sa6 );
+
+ err = WSAStringToAddressA( string, AF_INET6, NULL, (struct sockaddr*) &sa6, &dwSize );
+
+ if ( err == mStatus_NoError )
+ {
+ err = SetupAddr( ip, (struct sockaddr*) &sa6 );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ sa4.sin_family = AF_INET;
+ dwSize = sizeof( sa4 );
+
+ err = WSAStringToAddressA( string, AF_INET, NULL, (struct sockaddr*) &sa4, &dwSize );
+ err = translate_errno( err == 0, WSAGetLastError(), kUnknownErr );
+ require_noerr( err, exit );
+
+ err = SetupAddr( ip, (struct sockaddr*) &sa4 );
+ require_noerr( err, exit );
+ }
+
+exit:
+
+ return err;
+}
+
+
+//===========================================================================================================================
+// myGetIfAddrs
+//===========================================================================================================================
+
+mDNSlocal struct ifaddrs*
+myGetIfAddrs(int refresh)
+{
+ static struct ifaddrs *ifa = NULL;
+
+ if (refresh && ifa)
+ {
+ freeifaddrs(ifa);
+ ifa = NULL;
+ }
+
+ if (ifa == NULL)
+ {
+ getifaddrs(&ifa);
+ }
+
+ return ifa;
+}
+
+
+//===========================================================================================================================
+// TCHARtoUTF8
+//===========================================================================================================================
+
+mDNSlocal OSStatus
+TCHARtoUTF8( const TCHAR *inString, char *inBuffer, size_t inBufferSize )
+{
+#if( defined( UNICODE ) || defined( _UNICODE ) )
+ OSStatus err;
+ int len;
+
+ len = WideCharToMultiByte( CP_UTF8, 0, inString, -1, inBuffer, (int) inBufferSize, NULL, NULL );
+ err = translate_errno( len > 0, errno_compat(), kUnknownErr );
+ require_noerr( err, exit );
+
+exit:
+ return( err );
+#else
+ return( WindowsLatin1toUTF8( inString, inBuffer, inBufferSize ) );
+#endif
+}
+
+
+//===========================================================================================================================
+// WindowsLatin1toUTF8
+//===========================================================================================================================
+
+mDNSlocal OSStatus
+WindowsLatin1toUTF8( const char *inString, char *inBuffer, size_t inBufferSize )
+{
+ OSStatus err;
+ WCHAR * utf16;
+ int len;
+
+ utf16 = NULL;
+
+ // Windows doesn't support going directly from Latin-1 to UTF-8 so we have to go from Latin-1 to UTF-16 first.
+
+ len = MultiByteToWideChar( CP_ACP, 0, inString, -1, NULL, 0 );
+ err = translate_errno( len > 0, errno_compat(), kUnknownErr );
+ require_noerr( err, exit );
+
+ utf16 = (WCHAR *) malloc( len * sizeof( *utf16 ) );
+ require_action( utf16, exit, err = kNoMemoryErr );
+
+ len = MultiByteToWideChar( CP_ACP, 0, inString, -1, utf16, len );
+ err = translate_errno( len > 0, errno_compat(), kUnknownErr );
+ require_noerr( err, exit );
+
+ // Now convert the temporary UTF-16 to UTF-8.
+
+ len = WideCharToMultiByte( CP_UTF8, 0, utf16, -1, inBuffer, (int) inBufferSize, NULL, NULL );
+ err = translate_errno( len > 0, errno_compat(), kUnknownErr );
+ require_noerr( err, exit );
+
+exit:
+ if( utf16 ) free( utf16 );
+ return( err );
+}
+
+
+//===========================================================================================================================
+// TCPCloseSocket
+//===========================================================================================================================
+
+mDNSlocal void
+TCPCloseSocket( TCPSocket * sock )
+{
+ dlog( kDebugLevelChatty, DEBUG_NAME "closing TCPSocket 0x%x:%d\n", sock, sock->fd );
+
+ if ( sock->fd != INVALID_SOCKET )
+ {
+ closesocket( sock->fd );
+ sock->fd = INVALID_SOCKET;
+ }
+}
+
+
+//===========================================================================================================================
+// UDPCloseSocket
+//===========================================================================================================================
+
+mDNSlocal void
+UDPCloseSocket( UDPSocket * sock )
+{
+ dlog( kDebugLevelChatty, DEBUG_NAME "closing UDPSocket %d\n", sock->fd );
+
+ if ( sock->fd != INVALID_SOCKET )
+ {
+ mDNSPollUnregisterSocket( sock->fd );
+ closesocket( sock->fd );
+ sock->fd = INVALID_SOCKET;
+ }
+}
+
+
+//===========================================================================================================================
+// SetupAddr
+//===========================================================================================================================
+
+mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
+ {
+ if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
+
+ if (sa->sa_family == AF_INET)
+ {
+ struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
+ ip->type = mDNSAddrType_IPv4;
+ ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
+ return(mStatus_NoError);
+ }
+
+ if (sa->sa_family == AF_INET6)
+ {
+ struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
+ ip->type = mDNSAddrType_IPv6;
+ if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.u.Word[1] = 0;
+ ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
+ return(mStatus_NoError);
+ }
+
+ LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
+ return(mStatus_Invalid);
+ }
+
+
+mDNSlocal void GetDDNSFQDN( domainname *const fqdn )
+{
+ LPSTR name = NULL;
+ DWORD dwSize;
+ DWORD enabled;
+ HKEY key = NULL;
+ OSStatus err;
+
+ check( fqdn );
+
+ // Initialize
+
+ fqdn->c[0] = '\0';
+
+ // Get info from Bonjour registry key
+
+ err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSHostNames, &key );
+ require_noerr( err, exit );
+
+ err = RegQueryString( key, "", &name, &dwSize, &enabled );
+ if ( !err && ( name[0] != '\0' ) && enabled )
+ {
+ if ( !MakeDomainNameFromDNSNameString( fqdn, name ) || !fqdn->c[0] )
+ {
+ dlog( kDebugLevelError, "bad DDNS host name in registry: %s", name[0] ? name : "(unknown)");
+ }
+ }
+
+exit:
+
+ if ( key )
+ {
+ RegCloseKey( key );
+ key = NULL;
+ }
+
+ if ( name )
+ {
+ free( name );
+ name = NULL;
+ }
+}
+
+
+#ifdef UNICODE
+mDNSlocal void GetDDNSDomains( DNameListElem ** domains, LPCWSTR lpSubKey )
+#else
+mDNSlocal void GetDDNSConfig( DNameListElem ** domains, LPCSTR lpSubKey )
+#endif
+{
+ char subKeyName[kRegistryMaxKeyLength + 1];
+ DWORD cSubKeys = 0;
+ DWORD cbMaxSubKey;
+ DWORD cchMaxClass;
+ DWORD dwSize;
+ HKEY key = NULL;
+ HKEY subKey = NULL;
+ domainname dname;
+ DWORD i;
+ OSStatus err;
+
+ check( domains );
+
+ // Initialize
+
+ *domains = NULL;
+
+ err = RegCreateKey( HKEY_LOCAL_MACHINE, lpSubKey, &key );
+ require_noerr( err, exit );
+
+ // Get information about this node
+
+ err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );
+ require_noerr( err, exit );
+
+ for ( i = 0; i < cSubKeys; i++)
+ {
+ DWORD enabled;
+
+ dwSize = kRegistryMaxKeyLength;
+
+ err = RegEnumKeyExA( key, i, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
+
+ if ( !err )
+ {
+ err = RegOpenKeyExA( key, subKeyName, 0, KEY_READ, &subKey );
+ require_noerr( err, exit );
+
+ dwSize = sizeof( DWORD );
+ err = RegQueryValueExA( subKey, "Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
+
+ if ( !err && ( subKeyName[0] != '\0' ) && enabled )
+ {
+ if ( !MakeDomainNameFromDNSNameString( &dname, subKeyName ) || !dname.c[0] )
+ {
+ dlog( kDebugLevelError, "bad DDNS domain in registry: %s", subKeyName[0] ? subKeyName : "(unknown)");
+ }
+ else
+ {
+ DNameListElem * domain = (DNameListElem*) malloc( sizeof( DNameListElem ) );
+ require_action( domain, exit, err = mStatus_NoMemoryErr );
+
+ AssignDomainName(&domain->name, &dname);
+ domain->next = *domains;
+
+ *domains = domain;
+ }
+ }
+
+ RegCloseKey( subKey );
+ subKey = NULL;
+ }
+ }
+
+exit:
+
+ if ( subKey )
+ {
+ RegCloseKey( subKey );
+ }
+
+ if ( key )
+ {
+ RegCloseKey( key );
+ }
+}
+
+
+mDNSlocal void SetDomainSecret( mDNS * const m, const domainname * inDomain )
+{
+ char domainUTF8[ 256 ];
+ DomainAuthInfo *foundInList;
+ DomainAuthInfo *ptr;
+ char outDomain[ 256 ];
+ char outKey[ 256 ];
+ char outSecret[ 256 ];
+ OSStatus err;
+
+ ConvertDomainNameToCString( inDomain, domainUTF8 );
+
+ // If we're able to find a secret for this domain
+
+ if ( LsaGetSecret( domainUTF8, outDomain, sizeof( outDomain ), outKey, sizeof( outKey ), outSecret, sizeof( outSecret ) ) )
+ {
+ domainname domain;
+ domainname key;
+
+ // Tell the core about this secret
+
+ MakeDomainNameFromDNSNameString( &domain, outDomain );
+ MakeDomainNameFromDNSNameString( &key, outKey );
+
+ for (foundInList = m->AuthInfoList; foundInList; foundInList = foundInList->next)
+ if (SameDomainName(&foundInList->domain, &domain ) ) break;
+
+ ptr = foundInList;
+
+ if (!ptr)
+ {
+ ptr = (DomainAuthInfo*)malloc(sizeof(DomainAuthInfo));
+ require_action( ptr, exit, err = mStatus_NoMemoryErr );
+ }
+
+ err = mDNS_SetSecretForDomain(m, ptr, &domain, &key, outSecret, NULL, NULL, FALSE );
+ require_action( err != mStatus_BadParamErr, exit, if (!foundInList ) mDNSPlatformMemFree( ptr ) );
+
+ debugf("Setting shared secret for zone %s with key %##s", outDomain, key.c);
+ }
+
+exit:
+
+ return;
+}
+
+
+mDNSlocal VOID CALLBACK
+CheckFileSharesProc( LPVOID arg, DWORD dwTimerLowValue, DWORD dwTimerHighValue )
+{
+ mDNS * const m = ( mDNS * const ) arg;
+
+ ( void ) dwTimerLowValue;
+ ( void ) dwTimerHighValue;
+
+ CheckFileShares( m );
+}
+
+
+mDNSlocal unsigned __stdcall
+SMBRegistrationThread( void * arg )
+{
+ mDNS * const m = ( mDNS * const ) arg;
+ DNSServiceRef sref = NULL;
+ HANDLE handles[ 3 ];
+ mDNSu8 txtBuf[ 256 ];
+ mDNSu8 * txtPtr;
+ size_t keyLen;
+ size_t valLen;
+ mDNSIPPort port = { { SMBPortAsNumber >> 8, SMBPortAsNumber & 0xFF } };
+ DNSServiceErrorType err;
+
+ DEBUG_UNUSED( arg );
+
+ handles[ 0 ] = gSMBThreadStopEvent;
+ handles[ 1 ] = gSMBThreadRegisterEvent;
+ handles[ 2 ] = gSMBThreadDeregisterEvent;
+
+ memset( txtBuf, 0, sizeof( txtBuf ) );
+ txtPtr = txtBuf;
+ keyLen = strlen( "netbios=" );
+ valLen = strlen( m->p->nbname );
+ require_action( valLen < 32, exit, err = kUnknownErr ); // This should never happen, but check to avoid further memory corruption
+ *txtPtr++ = ( mDNSu8 ) ( keyLen + valLen );
+ memcpy( txtPtr, "netbios=", keyLen );
+ txtPtr += keyLen;
+ if ( valLen ) { memcpy( txtPtr, m->p->nbname, valLen ); txtPtr += ( mDNSu8 ) valLen; }
+ keyLen = strlen( "domain=" );
+ valLen = strlen( m->p->nbdomain );
+ require_action( valLen < 32, exit, err = kUnknownErr ); // This should never happen, but check to avoid further memory corruption
+ *txtPtr++ = ( mDNSu8 )( keyLen + valLen );
+ memcpy( txtPtr, "domain=", keyLen );
+ txtPtr += keyLen;
+ if ( valLen ) { memcpy( txtPtr, m->p->nbdomain, valLen ); txtPtr += valLen; }
+
+ for ( ;; )
+ {
+ DWORD ret;
+
+ ret = WaitForMultipleObjects( 3, handles, FALSE, INFINITE );
+
+ if ( ret != WAIT_FAILED )
+ {
+ if ( ret == kSMBStopEvent )
+ {
+ break;
+ }
+ else if ( ret == kSMBRegisterEvent )
+ {
+ err = gDNSServiceRegister( &sref, 0, 0, NULL, "_smb._tcp,_file", NULL, NULL, ( uint16_t ) port.NotAnInteger, ( mDNSu16 )( txtPtr - txtBuf ), txtBuf, NULL, NULL );
+
+ if ( err )
+ {
+ LogMsg( "SMBRegistrationThread: DNSServiceRegister returned %d\n", err );
+ sref = NULL;
+ break;
+ }
+ }
+ else if ( ret == kSMBDeregisterEvent )
+ {
+ if ( sref )
+ {
+ gDNSServiceRefDeallocate( sref );
+ sref = NULL;
+ }
+ }
+ }
+ else
+ {
+ LogMsg( "SMBRegistrationThread: WaitForMultipleObjects returned %d\n", GetLastError() );
+ break;
+ }
+ }
+
+exit:
+
+ if ( sref != NULL )
+ {
+ gDNSServiceRefDeallocate( sref );
+ sref = NULL;
+ }
+
+ SetEvent( gSMBThreadQuitEvent );
+ _endthreadex( 0 );
+ return 0;
+}
+
+
+mDNSlocal void
+CheckFileShares( mDNS * const m )
+{
+ PSHARE_INFO_1 bufPtr = ( PSHARE_INFO_1 ) NULL;
+ DWORD entriesRead = 0;
+ DWORD totalEntries = 0;
+ DWORD resume = 0;
+ mDNSBool advertise = mDNSfalse;
+ mDNSBool fileSharing = mDNSfalse;
+ mDNSBool printSharing = mDNSfalse;
+ HKEY key = NULL;
+ BOOL retry = FALSE;
+ NET_API_STATUS res;
+ mStatus err;
+
+ check( m );
+
+ // Only do this if we're not shutting down
+
+ require_action_quiet( m->AdvertiseLocalAddresses && !m->ShutdownTime, exit, err = kNoErr );
+
+ err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Services\\SMB", &key );
+
+ if ( !err )
+ {
+ DWORD dwSize = sizeof( DWORD );
+ RegQueryValueEx( key, L"Advertise", NULL, NULL, (LPBYTE) &advertise, &dwSize );
+ }
+
+ if ( advertise && mDNSIsFileAndPrintSharingEnabled( &retry ) )
+ {
+ dlog( kDebugLevelTrace, DEBUG_NAME "Sharing is enabled\n" );
+
+ res = NetShareEnum( NULL, 1, ( LPBYTE* )&bufPtr, MAX_PREFERRED_LENGTH, &entriesRead, &totalEntries, &resume );
+
+ if ( ( res == ERROR_SUCCESS ) || ( res == ERROR_MORE_DATA ) )
+ {
+ PSHARE_INFO_1 p = bufPtr;
+ DWORD i;
+
+ for( i = 0; i < entriesRead; i++ )
+ {
+ // We are only interested if the user is sharing anything other
+ // than the built-in "print$" source
+
+ if ( ( p->shi1_type == STYPE_DISKTREE ) && ( wcscmp( p->shi1_netname, TEXT( "print$" ) ) != 0 ) )
+ {
+ fileSharing = mDNStrue;
+ }
+ else if ( p->shi1_type == STYPE_PRINTQ )
+ {
+ printSharing = mDNStrue;
+ }
+
+ p++;
+ }
+
+ NetApiBufferFree( bufPtr );
+ bufPtr = NULL;
+ retry = FALSE;
+ }
+ else if ( res == NERR_ServerNotStarted )
+ {
+ retry = TRUE;
+ }
+ }
+
+ if ( retry )
+ {
+ __int64 qwTimeout;
+ LARGE_INTEGER liTimeout;
+
+ qwTimeout = -m->p->checkFileSharesTimeout * 10000000;
+ liTimeout.LowPart = ( DWORD )( qwTimeout & 0xFFFFFFFF );
+ liTimeout.HighPart = ( LONG )( qwTimeout >> 32 );
+
+ SetWaitableTimer( m->p->checkFileSharesTimer, &liTimeout, 0, CheckFileSharesProc, m, FALSE );
+ }
+
+ if ( !m->p->smbFileSharing && fileSharing )
+ {
+ if ( !gSMBThread )
+ {
+ if ( !gDNSSDLibrary )
+ {
+ gDNSSDLibrary = LoadLibrary( TEXT( "dnssd.dll" ) );
+ require_action( gDNSSDLibrary, exit, err = GetLastError() );
+ }
+
+ if ( !gDNSServiceRegister )
+ {
+ gDNSServiceRegister = ( DNSServiceRegisterFunc ) GetProcAddress( gDNSSDLibrary, "DNSServiceRegister" );
+ require_action( gDNSServiceRegister, exit, err = GetLastError() );
+ }
+
+ if ( !gDNSServiceRefDeallocate )
+ {
+ gDNSServiceRefDeallocate = ( DNSServiceRefDeallocateFunc ) GetProcAddress( gDNSSDLibrary, "DNSServiceRefDeallocate" );
+ require_action( gDNSServiceRefDeallocate, exit, err = GetLastError() );
+ }
+
+ if ( !gSMBThreadRegisterEvent )
+ {
+ gSMBThreadRegisterEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ require_action( gSMBThreadRegisterEvent != NULL, exit, err = GetLastError() );
+ }
+
+ if ( !gSMBThreadDeregisterEvent )
+ {
+ gSMBThreadDeregisterEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ require_action( gSMBThreadDeregisterEvent != NULL, exit, err = GetLastError() );
+ }
+
+ if ( !gSMBThreadStopEvent )
+ {
+ gSMBThreadStopEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ require_action( gSMBThreadStopEvent != NULL, exit, err = GetLastError() );
+ }
+
+ if ( !gSMBThreadQuitEvent )
+ {
+ gSMBThreadQuitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ require_action( gSMBThreadQuitEvent != NULL, exit, err = GetLastError() );
+ }
+
+ gSMBThread = ( HANDLE ) _beginthreadex( NULL, 0, SMBRegistrationThread, m, 0, NULL );
+ require_action( gSMBThread != NULL, exit, err = GetLastError() );
+ }
+
+ SetEvent( gSMBThreadRegisterEvent );
+
+ m->p->smbFileSharing = mDNStrue;
+ }
+ else if ( m->p->smbFileSharing && !fileSharing )
+ {
+ dlog( kDebugLevelTrace, DEBUG_NAME "deregistering smb type\n" );
+
+ if ( gSMBThreadDeregisterEvent != NULL )
+ {
+ SetEvent( gSMBThreadDeregisterEvent );
+ }
+
+ m->p->smbFileSharing = mDNSfalse;
+ }
+
+exit:
+
+ if ( key )
+ {
+ RegCloseKey( key );
+ }
+}
+
+
+BOOL
+IsWOMPEnabled( mDNS * const m )
+{
+ BOOL enabled;
+
+ mDNSInterfaceData * ifd;
+
+ enabled = FALSE;
+
+ for( ifd = m->p->interfaceList; ifd; ifd = ifd->next )
+ {
+ if ( IsWOMPEnabledForAdapter( ifd->name ) )
+ {
+ enabled = TRUE;
+ break;
+ }
+ }
+
+ return enabled;
+}
+
+
+mDNSlocal mDNSu8
+IsWOMPEnabledForAdapter( const char * adapterName )
+{
+ char fileName[80];
+ NDIS_OID oid;
+ DWORD count;
+ HANDLE handle = INVALID_HANDLE_VALUE;
+ NDIS_PNP_CAPABILITIES * pNPC = NULL;
+ int err;
+ mDNSu8 ok = TRUE;
+
+ require_action( adapterName != NULL, exit, ok = FALSE );
+
+ dlog( kDebugLevelTrace, DEBUG_NAME "IsWOMPEnabledForAdapter: %s\n", adapterName );
+
+ // Construct a device name to pass to CreateFile
+
+ strncpy_s( fileName, sizeof( fileName ), DEVICE_PREFIX, strlen( DEVICE_PREFIX ) );
+ strcat_s( fileName, sizeof( fileName ), adapterName );
+ handle = CreateFileA( fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, INVALID_HANDLE_VALUE );
+ require_action ( handle != INVALID_HANDLE_VALUE, exit, ok = FALSE );
+
+ // We successfully opened the driver, format the IOCTL to pass the driver.
+
+ oid = OID_PNP_CAPABILITIES;
+ pNPC = ( NDIS_PNP_CAPABILITIES * ) malloc( sizeof( NDIS_PNP_CAPABILITIES ) );
+ require_action( pNPC != NULL, exit, ok = FALSE );
+ ok = ( mDNSu8 ) DeviceIoControl( handle, IOCTL_NDIS_QUERY_GLOBAL_STATS, &oid, sizeof( oid ), pNPC, sizeof( NDIS_PNP_CAPABILITIES ), &count, NULL );
+ err = translate_errno( ok, GetLastError(), kUnknownErr );
+ require_action( !err, exit, ok = FALSE );
+ ok = ( mDNSu8 ) ( ( count == sizeof( NDIS_PNP_CAPABILITIES ) ) && ( pNPC->Flags & NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE ) );
+
+exit:
+
+ if ( pNPC != NULL )
+ {
+ free( pNPC );
+ }
+
+ if ( handle != INVALID_HANDLE_VALUE )
+ {
+ CloseHandle( handle );
+ }
+
+ dlog( kDebugLevelTrace, DEBUG_NAME "IsWOMPEnabledForAdapter returns %s\n", ok ? "true" : "false" );
+
+ return ( mDNSu8 ) ok;
+}
+
+
+mDNSlocal void
+SendWakeupPacket( mDNS * const inMDNS, LPSOCKADDR addr, INT addrlen, const char * buf, INT buflen, INT numTries, INT msecSleep )
+{
+ mDNSBool repeat = ( numTries == 1 ) ? mDNStrue : mDNSfalse;
+ SOCKET sock;
+ int num;
+ mStatus err;
+
+ ( void ) inMDNS;
+
+ sock = socket( addr->sa_family, SOCK_DGRAM, IPPROTO_UDP );
+ require_action( sock != INVALID_SOCKET, exit, err = mStatus_UnknownErr );
+
+ while ( numTries-- )
+ {
+ num = sendto( sock, ( const char* ) buf, buflen, 0, addr, addrlen );
+
+ if ( num != buflen )
+ {
+ LogMsg( "SendWakeupPacket error: sent %d bytes: %d\n", num, WSAGetLastError() );
+ }
+
+ if ( repeat )
+ {
+ num = sendto( sock, buf, buflen, 0, addr, addrlen );
+
+ if ( num != buflen )
+ {
+ LogMsg( "SendWakeupPacket error: sent %d bytes: %d\n", num, WSAGetLastError() );
+ }
+ }
+
+ if ( msecSleep )
+ {
+ Sleep( msecSleep );
+ }
+ }
+
+exit:
+
+ if ( sock != INVALID_SOCKET )
+ {
+ closesocket( sock );
+ }
+}
+
+
+mDNSlocal void _cdecl
+SendMulticastWakeupPacket( void *arg )
+{
+ MulticastWakeupStruct *info = ( MulticastWakeupStruct* ) arg;
+
+ if ( info )
+ {
+ SendWakeupPacket( info->inMDNS, ( LPSOCKADDR ) &info->addr, sizeof( info->addr ), ( const char* ) info->data, sizeof( info->data ), info->numTries, info->msecSleep );
+ free( info );
+ }
+
+ _endthread();
+}
+
+
+mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
+{
+ DEBUG_UNUSED( m );
+ DEBUG_UNUSED( rr );
+ DEBUG_UNUSED( result );
+}
More information about the Midnightbsd-cvs
mailing list