summaryrefslogtreecommitdiffstats
path: root/mDNSResponder/mDNSMacOSX
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2014-01-30 13:52:13 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2014-01-30 16:23:04 +0100
commit9449f151d0ccf3ac755d5f2bd9b4057ae2b03157 (patch)
treeada21dc6aa0b146c62a7561a08fb51fe4a8922ee /mDNSResponder/mDNSMacOSX
parentDHCPCD(8): Add MASTER_ONLY option (diff)
downloadrtems-libbsd-9449f151d0ccf3ac755d5f2bd9b4057ae2b03157.tar.bz2
mDNS: Import
The sources can be obtained via: http://opensource.apple.com/tarballs/mDNSResponder/mDNSResponder-544.tar.gz
Diffstat (limited to 'mDNSResponder/mDNSMacOSX')
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourEvents-Info.plist49
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourEvents.c991
-rw-r--r--mDNSResponder/mDNSMacOSX/CUPolicy.c91
-rw-r--r--mDNSResponder/mDNSMacOSX/CryptoSupport.c738
-rw-r--r--mDNSResponder/mDNSMacOSX/CryptoSupport.h22
-rw-r--r--mDNSResponder/mDNSMacOSX/DNSProxySupport.c543
-rw-r--r--mDNSResponder/mDNSMacOSX/DNSSECSupport.c645
-rw-r--r--mDNSResponder/mDNSMacOSX/DNSSECSupport.h24
-rw-r--r--mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.c674
-rw-r--r--mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.h314
-rw-r--r--mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryDefines.h31
-rw-r--r--mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryReply.defs60
-rw-r--r--mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryRequest.defs80
-rw-r--r--mDNSResponder/mDNSMacOSX/LaunchDaemonInfo-Tiger.helper.plist18
-rw-r--r--mDNSResponder/mDNSMacOSX/LaunchDaemonInfo-Tiger.plist17
-rw-r--r--mDNSResponder/mDNSMacOSX/LaunchDaemonInfo.dnsextd.plist17
-rw-r--r--mDNSResponder/mDNSMacOSX/LaunchDaemonInfo.helper.plist25
-rw-r--r--mDNSResponder/mDNSMacOSX/LaunchDaemonInfo.plist45
-rw-r--r--mDNSResponder/mDNSMacOSX/LegacyNATTraversal.c933
-rw-r--r--mDNSResponder/mDNSMacOSX/P2PPacketFilter.c298
-rw-r--r--mDNSResponder/mDNSMacOSX/P2PPacketFilter.h31
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_idle.tiffbin0 -> 728 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_pressed.tiffbin0 -> 688 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/failure.tiffbin0 -> 638 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/inprogress.tiffbin0 -> 644 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_disabled.tiffbin0 -> 698 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_idle.tiffbin0 -> 694 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_pressed.tiffbin0 -> 656 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/success.tiffbin0 -> 676 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPref.icnsbin0 -> 39193 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPref.tiffbin0 -> 2430 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c180
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.h52
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationRights.h49
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.h170
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m1194
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/classes.nib59
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/info.nib18
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/keyedobjects.nibbin0 -> 21082 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/InfoPlist.stringsbin0 -> 484 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Info-PreferencePane.plist36
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.c230
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.h70
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/ddnswriteconfig.m442
-rwxr-xr-xmDNSResponder/mDNSMacOSX/PreferencePane/installtool94
-rw-r--r--mDNSResponder/mDNSMacOSX/Private/dns_services.c212
-rw-r--r--mDNSResponder/mDNSMacOSX/Private/dns_services.h124
-rw-r--r--mDNSResponder/mDNSMacOSX/Private/dns_xpc.h33
-rw-r--r--mDNSResponder/mDNSMacOSX/Private/xpc_services.c255
-rw-r--r--mDNSResponder/mDNSMacOSX/Private/xpc_services.h21
-rw-r--r--mDNSResponder/mDNSMacOSX/README.privsep40
-rw-r--r--mDNSResponder/mDNSMacOSX/VPNService.c35
-rw-r--r--mDNSResponder/mDNSMacOSX/com.apple.networking.mDNSResponder1
-rw-r--r--mDNSResponder/mDNSMacOSX/daemon.c3052
-rw-r--r--mDNSResponder/mDNSMacOSX/dnsctl-entitlements.plist8
-rw-r--r--mDNSResponder/mDNSMacOSX/helper-entitlements.plist12
-rw-r--r--mDNSResponder/mDNSMacOSX/helper-error.h49
-rw-r--r--mDNSResponder/mDNSMacOSX/helper-main.c298
-rw-r--r--mDNSResponder/mDNSMacOSX/helper-server.h31
-rw-r--r--mDNSResponder/mDNSMacOSX/helper-stubs.c496
-rw-r--r--mDNSResponder/mDNSMacOSX/helper.c2867
-rw-r--r--mDNSResponder/mDNSMacOSX/helper.h84
-rw-r--r--mDNSResponder/mDNSMacOSX/helpermsg-types.h30
-rw-r--r--mDNSResponder/mDNSMacOSX/helpermsg.defs143
-rw-r--r--mDNSResponder/mDNSMacOSX/ipsec_strerror.h78
-rw-r--r--mDNSResponder/mDNSMacOSX/libpfkey.h105
-rw-r--r--mDNSResponder/mDNSMacOSX/mDNSMacOSX.c10442
-rw-r--r--mDNSResponder/mDNSMacOSX/mDNSMacOSX.h295
-rw-r--r--mDNSResponder/mDNSMacOSX/mDNSResponder-bundle/Resources/English.lproj/Localizable.strings13
-rw-r--r--mDNSResponder/mDNSMacOSX/mDNSResponder-bundle/Resources/French.lproj/Localizable.strings13
-rw-r--r--mDNSResponder/mDNSMacOSX/mDNSResponder-entitlements.plist24
-rw-r--r--mDNSResponder/mDNSMacOSX/mDNSResponder.order314
-rw-r--r--mDNSResponder/mDNSMacOSX/mDNSResponder.pbproj/project.pbxproj2338
-rw-r--r--mDNSResponder/mDNSMacOSX/mDNSResponder.plist31
-rw-r--r--mDNSResponder/mDNSMacOSX/mDNSResponder.sb151
-rw-r--r--mDNSResponder/mDNSMacOSX/mDNSResponder.txt55
-rw-r--r--mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj3137
-rw-r--r--mDNSResponder/mDNSMacOSX/mDNSResponderHelper.854
-rw-r--r--mDNSResponder/mDNSMacOSX/mDNSResponderHelper.plist13
-rw-r--r--mDNSResponder/mDNSMacOSX/mDNSResponderLogging.mobileconfig57
-rw-r--r--mDNSResponder/mDNSMacOSX/pfkey.c2138
81 files changed, 35289 insertions, 0 deletions
diff --git a/mDNSResponder/mDNSMacOSX/BonjourEvents-Info.plist b/mDNSResponder/mDNSMacOSX/BonjourEvents-Info.plist
new file mode 100644
index 00000000..473d4143
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourEvents-Info.plist
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.apple.${PRODUCT_NAME:rfc1034identifier}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFPlugInDynamicRegisterFunction</key>
+ <string></string>
+ <key>CFPlugInDynamicRegistration</key>
+ <string>NO</string>
+ <key>CFPlugInFactories</key>
+ <dict>
+ <key>FB86416D-6164-2070-726F-70735C216EC0</key>
+ <string>UserEventAgentFactory</string>
+ </dict>
+ <key>CFPlugInTypes</key>
+ <dict>
+ <key>FC86416D-6164-2070-726F-70735C216EC0</key>
+ <array>
+ <string>FB86416D-6164-2070-726F-70735C216EC0</string>
+ </array>
+ </dict>
+ <key>CFPlugInUnloadFunction</key>
+ <string></string>
+ <key>LimitLoadToSessionType</key>
+ <array>
+ <string>System</string>
+ <string>Aqua</string>
+ </array>
+</dict>
+</plist>
diff --git a/mDNSResponder/mDNSMacOSX/BonjourEvents.c b/mDNSResponder/mDNSMacOSX/BonjourEvents.c
new file mode 100644
index 00000000..b9308189
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourEvents.c
@@ -0,0 +1,991 @@
+/* -*- 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);
+}
+
diff --git a/mDNSResponder/mDNSMacOSX/CUPolicy.c b/mDNSResponder/mDNSMacOSX/CUPolicy.c
new file mode 100644
index 00000000..434e65cd
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/CUPolicy.c
@@ -0,0 +1,91 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 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.
+ */
+
+#include "mDNSMacOSX.h"
+#include <network/config.h>
+
+#if TARGET_OS_IPHONE
+
+mDNSexport void CUPInit(mDNS *const m)
+{
+
+ m->p->handle = cellular_usage_policy_create_client();
+ if (!m->p->handle)
+ {
+ LogMsg("CUPInit: cellular_usage_policy_create_client failed");
+ }
+}
+
+mDNSexport mDNSBool mDNSPlatformAllowPID(mDNS *const m, DNSQuestion *q)
+{
+ // Currently the policy applies only for DNS requests sent over cellular interface
+ if (m->p->handle && q->qDNSServer && q->qDNSServer->cellIntf)
+ {
+ mDNSBool allowed;
+ if (q->pid)
+ {
+ allowed = (mDNSBool) cellular_usage_policy_is_data_allowed_for_pid(m->p->handle, q->pid);
+ if (!allowed)
+ {
+ xpc_object_t pidx = xpc_uint64_create(q->pid);
+ if (pidx)
+ {
+ network_config_cellular_blocked_notify(pidx, NULL, NULL);
+ LogInfo("mDNSPlaformAllowPID: Notified PID(%d) for %##s (%s)", q->pid, q->qname.c, DNSTypeName(q->qtype));
+ xpc_release(pidx);
+ }
+ }
+ }
+ else
+ {
+ allowed = (mDNSBool) cellular_usage_policy_is_data_allowed_for_uuid(m->p->handle, q->uuid);
+ if (!allowed)
+ {
+ xpc_object_t uuidx = xpc_uuid_create(q->uuid);
+ if (uuidx)
+ {
+ network_config_cellular_blocked_notify(NULL, uuidx, NULL);
+ LogInfo("mDNSPlaformAllowPID: Notified UUID for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ xpc_release(uuidx);
+ }
+ }
+ }
+ return allowed;
+ }
+ else
+ {
+ return mDNStrue;
+ }
+}
+
+#else // TARGET_OS_IPHONE
+
+mDNSexport void CUPInit(mDNS *const m)
+{
+ (void)m; //unused
+}
+
+mDNSexport mDNSBool mDNSPlatformAllowPID(mDNS *const m, DNSQuestion *q)
+{
+ (void)m; //unused
+ (void)q; //unused
+ //LogMsg("mDNSPlatformAllowPID: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ return mDNStrue;
+}
+
+#endif // TARGET_OS_IPHONE
+
diff --git a/mDNSResponder/mDNSMacOSX/CryptoSupport.c b/mDNSResponder/mDNSMacOSX/CryptoSupport.c
new file mode 100644
index 00000000..408b3a22
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/CryptoSupport.c
@@ -0,0 +1,738 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2011 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.
+ */
+
+// ***************************************************************************
+// CryptoSupport.c
+// Supporting routines for DNSSEC crypto
+// ***************************************************************************
+
+#include "mDNSEmbeddedAPI.h"
+#include <CommonCrypto/CommonDigest.h> // For Hash algorithms SHA1 etc.
+#include <dispatch/dispatch.h> // For Base32/Base64 encoding/decoding
+#include <dispatch/private.h> // dispatch_data_create_with_transform
+#include "CryptoAlg.h"
+#include "CryptoSupport.h"
+#include "dnssec.h"
+#include "DNSSECSupport.h"
+
+#if TARGET_OS_IPHONE
+#include "SecRSAKey.h" // For RSA_SHA1 etc. verification
+#else
+#include <Security/Security.h>
+#endif
+
+#if !TARGET_OS_IPHONE
+mDNSlocal SecKeyRef SecKeyCreateRSAPublicKey_OSX(unsigned char *asn1, int length);
+#endif
+
+typedef struct
+{
+ dispatch_data_t encData;
+ dispatch_data_t encMap;
+ dispatch_data_t encNULL;
+}encContext;
+
+mDNSlocal mStatus enc_create(AlgContext *ctx)
+{
+ encContext *ptr;
+
+ switch (ctx->alg)
+ {
+ case ENC_BASE32:
+ case ENC_BASE64:
+ ptr = (encContext *)mDNSPlatformMemAllocate(sizeof(encContext));
+ if (!ptr) return mStatus_NoMemoryErr;
+ break;
+ default:
+ LogMsg("enc_create: Unsupported algorithm %d", ctx->alg);
+ return mStatus_BadParamErr;
+ }
+ ptr->encData = NULL;
+ ptr->encMap = NULL;
+ // The encoded data is not NULL terminated. So, we concatenate a null byte later when we encode and map
+ // the real data.
+ ptr->encNULL = dispatch_data_create("", 1, dispatch_get_global_queue(0, 0), ^{});
+ if (!ptr->encNULL)
+ {
+ mDNSPlatformMemFree(ptr);
+ return mStatus_NoMemoryErr;
+ }
+ ctx->context = ptr;
+ return mStatus_NoError;
+}
+
+mDNSlocal mStatus enc_destroy(AlgContext *ctx)
+{
+ encContext *ptr = (encContext *)ctx->context;
+ if (ptr->encData) dispatch_release(ptr->encData);
+ if (ptr->encMap) dispatch_release(ptr->encMap);
+ if (ptr->encNULL) dispatch_release(ptr->encNULL);
+ mDNSPlatformMemFree(ptr);
+ return mStatus_NoError;
+}
+
+mDNSlocal mStatus enc_add(AlgContext *ctx, const void *data, mDNSu32 len)
+{
+ switch (ctx->alg)
+ {
+ case ENC_BASE32:
+ case ENC_BASE64:
+ {
+ encContext *ptr = (encContext *)ctx->context;
+ dispatch_data_t src_data = dispatch_data_create(data, len, dispatch_get_global_queue(0, 0), ^{});
+ if (!src_data)
+ {
+ LogMsg("enc_add: dispatch_data_create src failed");
+ return mStatus_BadParamErr;
+ }
+ dispatch_data_t dest_data = dispatch_data_create_with_transform(src_data, DISPATCH_DATA_FORMAT_TYPE_NONE,
+ (ctx->alg == ENC_BASE32 ? DISPATCH_DATA_FORMAT_TYPE_BASE32HEX : DISPATCH_DATA_FORMAT_TYPE_BASE64));
+ dispatch_release(src_data);
+ if (!dest_data)
+ {
+ LogMsg("enc_add: dispatch_data_create dst failed");
+ return mStatus_BadParamErr;
+ }
+ ptr->encData = dest_data;
+
+ return mStatus_NoError;
+ }
+ default:
+ LogMsg("enc_add: Unsupported algorithm %d", ctx->alg);
+ return mStatus_BadParamErr;
+ }
+}
+
+mDNSlocal mDNSu8* enc_encode(AlgContext *ctx)
+{
+ const void *result = NULL;
+
+ switch (ctx->alg)
+ {
+ case ENC_BASE32:
+ case ENC_BASE64:
+ {
+ encContext *ptr = (encContext *)ctx->context;
+ size_t size;
+ dispatch_data_t dest_data = ptr->encData;
+ dispatch_data_t data = dispatch_data_create_concat(dest_data, ptr->encNULL);
+
+ if (!data)
+ {
+ LogMsg("enc_encode: cannot concatenate");
+ return NULL;
+ }
+
+ dispatch_data_t map = dispatch_data_create_map(data, &result, &size);
+ if (!map)
+ {
+ LogMsg("enc_encode: cannot create map %d", ctx->alg);
+ return NULL;
+ }
+ dispatch_release(dest_data);
+ ptr->encData = data;
+ ptr->encMap = map;
+
+ return (mDNSu8 *)result;
+ }
+ default:
+ LogMsg("enc_encode: Unsupported algorithm %d", ctx->alg);
+ return mDNSNULL;
+ }
+}
+
+mDNSlocal mStatus sha_create(AlgContext *ctx)
+{
+ mDNSu8 *ptr;
+ switch (ctx->alg)
+ {
+ case SHA1_DIGEST_TYPE:
+ ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA1_CTX));
+ if (!ptr) return mStatus_NoMemoryErr;
+ CC_SHA1_Init((CC_SHA1_CTX *)ptr);
+ break;
+ case SHA256_DIGEST_TYPE:
+ ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA256_CTX));
+ if (!ptr) return mStatus_NoMemoryErr;
+ CC_SHA256_Init((CC_SHA256_CTX *)ptr);
+ break;
+ default:
+ LogMsg("sha_create: Unsupported algorithm %d", ctx->alg);
+ return mStatus_BadParamErr;
+ }
+ ctx->context = ptr;
+ return mStatus_NoError;
+}
+
+mDNSlocal mStatus sha_destroy(AlgContext *ctx)
+{
+ mDNSPlatformMemFree(ctx->context);
+ return mStatus_NoError;
+}
+
+mDNSlocal mDNSu32 sha_len(AlgContext *ctx)
+{
+ switch (ctx->alg)
+ {
+ case SHA1_DIGEST_TYPE:
+ return CC_SHA1_DIGEST_LENGTH;
+ case SHA256_DIGEST_TYPE:
+ return CC_SHA256_DIGEST_LENGTH;
+ default:
+ LogMsg("sha_len: Unsupported algorithm %d", ctx->alg);
+ return mStatus_BadParamErr;
+ }
+}
+
+mDNSlocal mStatus sha_add(AlgContext *ctx, const void *data, mDNSu32 len)
+{
+ switch (ctx->alg)
+ {
+ case SHA1_DIGEST_TYPE:
+ CC_SHA1_Update((CC_SHA1_CTX *)ctx->context, data, len);
+ break;
+ case SHA256_DIGEST_TYPE:
+ CC_SHA256_Update((CC_SHA256_CTX *)ctx->context, data, len);
+ break;
+ default:
+ LogMsg("sha_add: Unsupported algorithm %d", ctx->alg);
+ return mStatus_BadParamErr;
+ }
+ return mStatus_NoError;
+}
+
+mDNSlocal mStatus sha_verify(AlgContext *ctx, mDNSu8 *key, mDNSu32 keylen, mDNSu8 *digestIn, mDNSu32 dlen)
+{
+ mDNSu8 digest[CC_SHA512_DIGEST_LENGTH];
+ mDNSu32 digestLen;
+
+ (void) key; //unused
+ (void)keylen; //unused
+ switch (ctx->alg)
+ {
+ case SHA1_DIGEST_TYPE:
+ digestLen = CC_SHA1_DIGEST_LENGTH;
+ CC_SHA1_Final(digest, (CC_SHA1_CTX *)ctx->context);
+ break;
+ case SHA256_DIGEST_TYPE:
+ digestLen = CC_SHA256_DIGEST_LENGTH;
+ CC_SHA256_Final(digest, (CC_SHA256_CTX *)ctx->context);
+ break;
+ default:
+ LogMsg("sha_verify: Unsupported algorithm %d", ctx->alg);
+ return mStatus_BadParamErr;
+ }
+ if (dlen != digestLen)
+ {
+ LogMsg("sha_verify(Alg %d): digest len mismatch len %u, expected %u", ctx->alg, (unsigned int)dlen, (unsigned int)digestLen);
+ return mStatus_BadParamErr;
+ }
+ if (!memcmp(digest, digestIn, digestLen))
+ return mStatus_NoError;
+ else
+ return mStatus_NoAuth;
+}
+
+mDNSlocal mStatus sha_final(AlgContext *ctx, void *digestOut, mDNSu32 dlen)
+{
+ mDNSu8 digest[CC_SHA512_DIGEST_LENGTH];
+ mDNSu32 digestLen;
+
+ switch (ctx->alg)
+ {
+ case SHA1_DIGEST_TYPE:
+ digestLen = CC_SHA1_DIGEST_LENGTH;
+ CC_SHA1_Final(digest, (CC_SHA1_CTX *)ctx->context);
+ break;
+ case SHA256_DIGEST_TYPE:
+ digestLen = CC_SHA256_DIGEST_LENGTH;
+ CC_SHA256_Final(digest, (CC_SHA256_CTX *)ctx->context);
+ break;
+ default:
+ LogMsg("sha_final: Unsupported algorithm %d", ctx->alg);
+ return mStatus_BadParamErr;
+ }
+ if (dlen != digestLen)
+ {
+ LogMsg("sha_final(Alg %d): digest len mismatch len %u, expected %u", ctx->alg, (unsigned int)dlen, (unsigned int)digestLen);
+ return mStatus_BadParamErr;
+ }
+ memcpy(digestOut, digest, digestLen);
+ return mStatus_NoError;
+}
+
+mDNSlocal mStatus rsa_sha_create(AlgContext *ctx)
+{
+ mDNSu8 *ptr;
+ switch (ctx->alg)
+ {
+ case CRYPTO_RSA_NSEC3_SHA1:
+ case CRYPTO_RSA_SHA1:
+ ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA1_CTX));
+ if (!ptr) return mStatus_NoMemoryErr;
+ CC_SHA1_Init((CC_SHA1_CTX *)ptr);
+ break;
+ case CRYPTO_RSA_SHA256:
+ ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA256_CTX));
+ if (!ptr) return mStatus_NoMemoryErr;
+ CC_SHA256_Init((CC_SHA256_CTX *)ptr);
+ break;
+ case CRYPTO_RSA_SHA512:
+ ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA512_CTX));
+ if (!ptr) return mStatus_NoMemoryErr;
+ CC_SHA512_Init((CC_SHA512_CTX *)ptr);
+ break;
+ default:
+ LogMsg("rsa_sha_create: Unsupported algorithm %d", ctx->alg);
+ return mStatus_BadParamErr;
+ }
+ ctx->context = ptr;
+ return mStatus_NoError;
+}
+
+mDNSlocal mStatus rsa_sha_destroy(AlgContext *ctx)
+{
+ mDNSPlatformMemFree(ctx->context);
+ return mStatus_NoError;
+}
+
+mDNSlocal mDNSu32 rsa_sha_len(AlgContext *ctx)
+{
+ switch (ctx->alg)
+ {
+ case CRYPTO_RSA_NSEC3_SHA1:
+ case CRYPTO_RSA_SHA1:
+ return CC_SHA1_DIGEST_LENGTH;
+ case CRYPTO_RSA_SHA256:
+ return CC_SHA256_DIGEST_LENGTH;
+ case CRYPTO_RSA_SHA512:
+ return CC_SHA512_DIGEST_LENGTH;
+ default:
+ LogMsg("rsa_sha_len: Unsupported algorithm %d", ctx->alg);
+ return mStatus_BadParamErr;
+ }
+}
+
+mDNSlocal mStatus rsa_sha_add(AlgContext *ctx, const void *data, mDNSu32 len)
+{
+ switch (ctx->alg)
+ {
+ case CRYPTO_RSA_NSEC3_SHA1:
+ case CRYPTO_RSA_SHA1:
+ CC_SHA1_Update((CC_SHA1_CTX *)ctx->context, data, len);
+ break;
+ case CRYPTO_RSA_SHA256:
+ CC_SHA256_Update((CC_SHA256_CTX *)ctx->context, data, len);
+ break;
+ case CRYPTO_RSA_SHA512:
+ CC_SHA512_Update((CC_SHA512_CTX *)ctx->context, data, len);
+ break;
+ default:
+ LogMsg("rsa_sha_add: Unsupported algorithm %d", ctx->alg);
+ return mStatus_BadParamErr;
+ }
+ return mStatus_NoError;
+}
+
+mDNSlocal SecKeyRef rfc3110_import(const mDNSu8 *data, const mDNSu32 len)
+{
+ static const int max_key_bytes = 4096 / 8; // max DNSSEC supported modulus is 4096 bits
+ static const int max_exp_bytes = 3; // DNSSEC supports 1 or 3 bytes for exponent
+ static const int asn1_cmd_bytes = 3; // since there is an ASN1 SEQ and two INTs
+ //static const int asn1_max_len_bytes = asn1_cmd_bytes * 3; // capped at 3 due to max payload size
+ static const int asn1_max_len_bytes = 3 * 3; // capped at 3 due to max payload size
+ unsigned char asn1[max_key_bytes + 1 + max_exp_bytes + asn1_cmd_bytes + asn1_max_len_bytes]; // +1 is for leading 0 for non negative asn1 number
+ const mDNSu8 *modulus;
+ unsigned int modulus_length;
+ unsigned int exp_length;
+ mDNSu32 index = 0;
+ mDNSu32 asn1_length = 0;
+ unsigned int i;
+
+ // Validate Input
+ if (!data)
+ return NULL;
+
+ // we have to have at least 1 byte for the length
+ if (len < 1)
+ return NULL;
+
+ // Parse Modulus and Exponent
+ exp_length = data[0];
+
+ // we have to have at least len byte + size of exponent
+ if (len < 1+exp_length)
+ return NULL;
+
+ // -1 is for the exp_length byte
+ modulus_length = len - 1 - exp_length;
+
+ // rfc3110 limits modulus to 4096 bits
+ if (modulus_length > 512)
+ return NULL;
+
+ if (modulus_length < 1)
+ return NULL;
+
+ // add 1 to modulus length for pre-ceding 0 t make ASN1 value non-negative
+ ++modulus_length;
+
+ // 1 is to skip exp_length byte
+ modulus = &data[1+exp_length];
+
+ // 2 bytes for commands since first doesn't count
+ // 2 bytes for min 1 byte length field
+ asn1_length = modulus_length + exp_length + 2 + 2;
+
+ // account for modulus length causing INT length field to grow
+ if (modulus_length > 0xFF)
+ asn1_length += 2;
+ else if (modulus_length >= 128)
+ ++asn1_length;
+
+ // Construct ASN1 formatted public key
+ // Write ASN1 SEQ byte
+ asn1[index++] = 0x30;
+
+ // Write ASN1 length for SEQ
+ if (asn1_length < 128)
+ {
+ asn1[index++] = asn1_length & 0xFF;
+ }
+ else
+ {
+ asn1[index++] = (0x80 | ((asn1_length & 0xFF00) ? 2 : 1));
+ if (asn1_length & 0xFF00)
+ asn1[index++] = (asn1_length & 0xFF00) >> 8;
+ asn1[index++] = asn1_length & 0xFF;
+ }
+
+ // Write ASN1 INT for modulus
+ asn1[index++] = 0x02;
+ // Write ASN1 length for INT
+ if (modulus_length < 128)
+ {
+ asn1[index++] = asn1_length & 0xFF;
+ }
+ else
+ {
+ asn1[index++] = 0x80 | ((modulus_length & 0xFF00) ? 2 : 1);
+ if (modulus_length & 0xFF00)
+ asn1[index++] = (modulus_length & 0xFF00) >> 8;
+ asn1[index++] = modulus_length & 0xFF;
+ }
+
+ // Write preceding 0 so our integer isn't negative
+ asn1[index++] = 0x00;
+ // Write actual modulus (-1 for preceding 0)
+ memcpy(&asn1[index], (void *)modulus, modulus_length-1);
+ index += modulus_length-1;
+
+ // Write ASN1 INT for exponent
+ asn1[index++] = 0x02;
+ // Write ASN1 length for INT
+ asn1[index++] = exp_length & 0xFF;
+ // Write exponent bytes
+ for (i = 1; i <= exp_length; i++)
+ asn1[index++] = data[i];
+
+#if TARGET_OS_IPHONE
+ // index contains bytes written, use it for length
+ return (SecKeyCreateRSAPublicKey(NULL, asn1, index, kSecKeyEncodingPkcs1));
+#else
+ return (SecKeyCreateRSAPublicKey_OSX(asn1, index));
+#endif
+}
+
+#if TARGET_OS_IPHONE
+mDNSlocal mStatus rsa_sha_verify(AlgContext *ctx, mDNSu8 *key, mDNSu32 keylen, mDNSu8 *signature, mDNSu32 siglen)
+{
+ SecKeyRef keyref;
+ OSStatus result;
+ mDNSu8 digest[CC_SHA512_DIGEST_LENGTH];
+ int digestlen;
+ int cryptoAlg;
+
+ switch (ctx->alg)
+ {
+ case CRYPTO_RSA_NSEC3_SHA1:
+ case CRYPTO_RSA_SHA1:
+ cryptoAlg = kSecPaddingPKCS1SHA1;
+ digestlen = CC_SHA1_DIGEST_LENGTH;
+ CC_SHA1_Final(digest, (CC_SHA1_CTX *)ctx->context);
+ break;
+ case CRYPTO_RSA_SHA256:
+ cryptoAlg = kSecPaddingPKCS1SHA256;
+ digestlen = CC_SHA256_DIGEST_LENGTH;
+ CC_SHA256_Final(digest, (CC_SHA256_CTX *)ctx->context);
+ break;
+ case CRYPTO_RSA_SHA512:
+ cryptoAlg = kSecPaddingPKCS1SHA512;
+ digestlen = CC_SHA512_DIGEST_LENGTH;
+ CC_SHA512_Final(digest, (CC_SHA512_CTX *)ctx->context);
+ break;
+ default:
+ LogMsg("rsa_sha_verify: Unsupported algorithm %d", ctx->alg);
+ return mStatus_BadParamErr;
+ }
+
+ keyref = rfc3110_import(key, keylen);
+ if (!keyref)
+ {
+ LogMsg("rsa_sha_verify: Error decoding rfc3110 key data");
+ return mStatus_NoMemoryErr;
+ }
+ result = SecKeyRawVerify(keyref, cryptoAlg, digest, digestlen, signature, siglen);
+ CFRelease(keyref);
+ if (result != noErr)
+ {
+ LogMsg("rsa_sha_verify: Failed for alg %d", ctx->alg);
+ return mStatus_BadParamErr;
+ }
+ else
+ {
+ LogInfo("rsa_sha_verify: Passed for alg %d", ctx->alg);
+ return mStatus_NoError;
+ }
+}
+#else // TARGET_OS_IPHONE
+
+mDNSlocal SecKeyRef SecKeyCreateRSAPublicKey_OSX(unsigned char *asn1, int length)
+{
+ SecKeyRef result = NULL;
+
+ SecExternalFormat extFormat = kSecFormatBSAFE;
+ SecExternalItemType itemType = kSecItemTypePublicKey;
+ CFArrayRef outArray = NULL;
+
+ CFDataRef keyData = CFDataCreate(NULL, asn1, length);
+ if (!keyData)
+ return NULL;
+
+ OSStatus err = SecItemImport(keyData, NULL, &extFormat, &itemType, 0, NULL, NULL, &outArray);
+
+ CFRelease(keyData);
+ if (noErr != err || outArray == NULL)
+ {
+ if (outArray)
+ CFRelease(outArray);
+ return NULL;
+ }
+
+ result = (SecKeyRef)CFArrayGetValueAtIndex(outArray, 0);
+ if (result == NULL)
+ {
+ CFRelease(outArray);
+ return NULL;
+ }
+
+ CFRetain(result);
+ CFRelease(outArray);
+ return result;
+}
+
+mDNSlocal Boolean VerifyData(SecKeyRef key, CFStringRef digestStr, mDNSu8 *digest, int dlen, int digestlenAttr, mDNSu8 *sig, int siglen, CFStringRef digest_type)
+{
+ CFErrorRef error;
+ Boolean ret;
+
+ CFDataRef signature = CFDataCreate(NULL, sig, siglen);
+ if (!signature)
+ return false;
+
+ SecTransformRef verifyXForm = SecVerifyTransformCreate(key, signature, &error);
+ CFRelease(signature);
+ if (verifyXForm == NULL)
+ {
+ return false;
+ }
+
+ // tell the transform what type of data it is geting
+ if (!SecTransformSetAttribute(verifyXForm, kSecInputIsAttributeName, digest_type, &error))
+ {
+ LogMsg("VerifyData: SecTransformSetAttribute digest_type");
+ goto err;
+ }
+
+ if (!SecTransformSetAttribute(verifyXForm, kSecDigestTypeAttribute, digestStr, &error))
+ {
+ LogMsg("VerifyData: SecTransformSetAttribute digestStr");
+ goto err;
+ }
+
+ CFNumberRef digestLengthRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &digestlenAttr);
+ if (digestLengthRef == NULL)
+ {
+ LogMsg("VerifyData: CFNumberCreate failed");
+ goto err;
+ }
+
+ ret = SecTransformSetAttribute(verifyXForm, kSecDigestLengthAttribute, digestLengthRef, &error);
+ CFRelease(digestLengthRef);
+ if (!ret)
+ {
+ LogMsg("VerifyData: SecTransformSetAttribute digestLengthRef");
+ goto err;
+ }
+
+ CFDataRef dataToSign = CFDataCreate(NULL, digest, dlen);
+ if (dataToSign == NULL)
+ {
+ LogMsg("VerifyData: CFDataCreate failed");
+ goto err;
+ }
+
+ ret = SecTransformSetAttribute(verifyXForm, kSecTransformInputAttributeName, dataToSign, &error);
+ CFRelease(dataToSign);
+ if (!ret)
+ {
+ LogMsg("VerifyData: SecTransformSetAttribute TransformAttributeName");
+ goto err;
+ }
+
+ CFBooleanRef boolRef = SecTransformExecute(verifyXForm, &error);
+ CFRelease(verifyXForm);
+
+ if (error != NULL)
+ {
+ CFStringRef errStr = CFErrorCopyDescription(error);
+ char errorbuf[128];
+ errorbuf[0] = 0;
+ if (errStr != NULL)
+ {
+ if (!CFStringGetCString(errStr, errorbuf, sizeof(errorbuf), kCFStringEncodingUTF8))
+ {
+ LogMsg("VerifyData: CFStringGetCString failed");
+ }
+ }
+ LogMsg("VerifyData: SecTransformExecute failed with %s", errorbuf);
+ return false;
+ }
+ return CFEqual(boolRef, kCFBooleanTrue);
+err:
+ CFRelease(verifyXForm);
+ return false;
+}
+
+mDNSlocal mStatus rsa_sha_verify(AlgContext *ctx, mDNSu8 *key, mDNSu32 keylen, mDNSu8 *signature, mDNSu32 siglen)
+{
+ SecKeyRef keyref;
+ mDNSu8 digest[CC_SHA512_DIGEST_LENGTH];
+ int digestlen;
+ int digestlenAttr;
+ CFStringRef digestStr;
+ mDNSBool ret;
+
+ switch (ctx->alg)
+ {
+ case CRYPTO_RSA_NSEC3_SHA1:
+ case CRYPTO_RSA_SHA1:
+ digestStr = kSecDigestSHA1;
+ digestlen = CC_SHA1_DIGEST_LENGTH;
+ digestlenAttr = 0;
+ CC_SHA1_Final(digest, (CC_SHA1_CTX *)ctx->context);
+ break;
+ case CRYPTO_RSA_SHA256:
+ digestStr = kSecDigestSHA2;
+ digestlen = CC_SHA256_DIGEST_LENGTH;
+ digestlenAttr = 256;
+ CC_SHA256_Final(digest, (CC_SHA256_CTX *)ctx->context);
+ break;
+ case CRYPTO_RSA_SHA512:
+ digestStr = kSecDigestSHA2;
+ digestlen = CC_SHA512_DIGEST_LENGTH;
+ digestlenAttr = 512;
+ CC_SHA512_Final(digest, (CC_SHA512_CTX *)ctx->context);
+ break;
+ default:
+ LogMsg("rsa_sha_verify: Unsupported algorithm %d", ctx->alg);
+ return mStatus_BadParamErr;
+ }
+
+ keyref = rfc3110_import(key, keylen);
+ if (!keyref)
+ {
+ LogMsg("rsa_sha_verify: Error decoding rfc3110 key data");
+ return mStatus_NoMemoryErr;
+ }
+ ret = VerifyData(keyref, digestStr, digest, digestlen, digestlenAttr, signature, siglen, kSecInputIsDigest);
+ CFRelease(keyref);
+ if (!ret)
+ {
+ LogMsg("rsa_sha_verify: Failed for alg %d", ctx->alg);
+ return mStatus_BadParamErr;
+ }
+ else
+ {
+ LogInfo("rsa_sha_verify: Passed for alg %d", ctx->alg);
+ return mStatus_NoError;
+ }
+}
+#endif // TARGET_OS_IPHONE
+
+AlgFuncs sha_funcs = {sha_create, sha_destroy, sha_len, sha_add, sha_verify, mDNSNULL, sha_final};
+AlgFuncs rsa_sha_funcs = {rsa_sha_create, rsa_sha_destroy, rsa_sha_len, rsa_sha_add, rsa_sha_verify, mDNSNULL, mDNSNULL};
+AlgFuncs enc_funcs = {enc_create, enc_destroy, mDNSNULL, enc_add, mDNSNULL, enc_encode, mDNSNULL};
+
+#ifndef DNSSEC_DISABLED
+
+mDNSexport mStatus DNSSECCryptoInit(mDNS *const m)
+{
+ mStatus result;
+
+ result = DigestAlgInit(SHA1_DIGEST_TYPE, &sha_funcs);
+ if (result != mStatus_NoError)
+ return result;
+ result = DigestAlgInit(SHA256_DIGEST_TYPE, &sha_funcs);
+ if (result != mStatus_NoError)
+ return result;
+ result = CryptoAlgInit(CRYPTO_RSA_SHA1, &rsa_sha_funcs);
+ if (result != mStatus_NoError)
+ return result;
+ result = CryptoAlgInit(CRYPTO_RSA_NSEC3_SHA1, &rsa_sha_funcs);
+ if (result != mStatus_NoError)
+ return result;
+ result = CryptoAlgInit(CRYPTO_RSA_SHA256, &rsa_sha_funcs);
+ if (result != mStatus_NoError)
+ return result;
+ result = CryptoAlgInit(CRYPTO_RSA_SHA512, &rsa_sha_funcs);
+ if (result != mStatus_NoError)
+ return result;
+ result = EncAlgInit(ENC_BASE32, &enc_funcs);
+ if (result != mStatus_NoError)
+ return result;
+ result = EncAlgInit(ENC_BASE64, &enc_funcs);
+ if (result != mStatus_NoError)
+ return result;
+
+ result = DNSSECPlatformInit(m);
+
+ return result;
+}
+
+#else // !DNSSEC_DISABLED
+
+mDNSexport mStatus DNSSECCryptoInit(mDNS *const m)
+{
+ (void) m;
+
+ return mStatus_NoError;
+}
+
+#endif // !DNSSEC_DISABLED
+
+
diff --git a/mDNSResponder/mDNSMacOSX/CryptoSupport.h b/mDNSResponder/mDNSMacOSX/CryptoSupport.h
new file mode 100644
index 00000000..9c0fd079
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/CryptoSupport.h
@@ -0,0 +1,22 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2011 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.
+ */
+#ifndef __CRYPTO_SUPPORT_H
+#define __CRYPTO_SUPPORT_H
+
+extern mStatus DNSSECCryptoInit(mDNS *const m);
+
+#endif // __CRYPTO_SUPPORT_H
diff --git a/mDNSResponder/mDNSMacOSX/DNSProxySupport.c b/mDNSResponder/mDNSMacOSX/DNSProxySupport.c
new file mode 100644
index 00000000..042bbc80
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DNSProxySupport.c
@@ -0,0 +1,543 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2011 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"
+#include "mDNSMacOSX.h"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/event.h>
+
+#define ValidSocket(s) ((s) >= 0)
+
+// Global to store the 4 DNS Proxy Listeners (UDPv4/6, TCPv4/6)
+static int dp_listener[4];
+
+#define NUM_PROXY_TCP_CONNS 100
+
+typedef struct
+{
+ TCPSocket sock;
+ DNSMessage *reply;
+ mDNSu16 replyLen;
+ mDNSu32 nread;
+} ProxyTCPInfo_t;
+
+// returns -1 for failures including the other end closing the socket
+// returns 0 if successful in reading data, but still not read the data fully
+// returns 1 if successful in reading all the data
+mDNSlocal int ProxyTCPRead(ProxyTCPInfo_t *tcpInfo)
+{
+ long n;
+ mDNSBool closed;
+
+ if (tcpInfo->nread < 2) // First read the two-byte length preceeding the DNS message
+ {
+ mDNSu8 *lenptr = (mDNSu8 *)&tcpInfo->replyLen;
+ n = mDNSPlatformReadTCP(&tcpInfo->sock, lenptr + tcpInfo->nread, 2 - tcpInfo->nread, &closed);
+ if (n < 0 || closed)
+ {
+ LogMsg("ProxyTCPRead: attempt to read message length failed");
+ return -1;
+ }
+
+ tcpInfo->nread += n;
+ if (tcpInfo->nread < 2)
+ {
+ LogMsg("ProxyTCPRead: nread %d, n %d", tcpInfo->nread, n);
+ return 0;
+ }
+
+ tcpInfo->replyLen = (mDNSu16)((mDNSu16)lenptr[0] << 8 | lenptr[1]);
+ if (tcpInfo->replyLen < sizeof(DNSMessageHeader))
+ {
+ LogMsg("ProxyTCPRead: Message length too short (%d bytes)", tcpInfo->replyLen);
+ return -1;
+ }
+
+ tcpInfo->reply = mallocL("ProxyTCPInfo", tcpInfo->replyLen);
+ if (!tcpInfo->reply)
+ {
+ LogMsg("ProxyTCPRead: Memory failure");
+ return -1;
+ }
+ }
+
+ n = mDNSPlatformReadTCP(&tcpInfo->sock, ((char *)tcpInfo->reply) + (tcpInfo->nread - 2), tcpInfo->replyLen - (tcpInfo->nread - 2), &closed);
+
+ if (n < 0 || closed)
+ {
+ LogMsg("ProxyTCPRead: read failure n %d, closed %d", n, closed);
+ return -1;
+ }
+ tcpInfo->nread += n;
+ if ((tcpInfo->nread - 2) != tcpInfo->replyLen)
+ return 0;
+ else
+ return 1;
+}
+
+mDNSlocal void ProxyTCPSocketCallBack(int s1, short filter, void *context)
+{
+ int ret;
+ struct sockaddr_storage from;
+ struct sockaddr_storage to;
+ mDNSAddr senderAddr, destAddr;
+ mDNSIPPort senderPort;
+ ProxyTCPInfo_t *ti = (ProxyTCPInfo_t *)context;
+ TCPSocket *sock = &ti->sock;
+ KQSocketSet *kq = &sock->ss;
+
+ (void) filter;
+
+ ret = ProxyTCPRead(ti);
+ if (ret == -1)
+ {
+ mDNSPlatformDisposeProxyContext(ti);
+ return;
+ }
+ else if (!ret)
+ {
+ debugf("ProxyTCPReceive: Not yet read completely Actual length %d, Read length %d", ti->replyLen, ti->nread);
+ return;
+ }
+ // We read all the data and hence not interested in read events anymore
+ KQueueSet(s1, EV_DELETE, EVFILT_READ, sock->kqEntry);
+
+ mDNSPlatformMemZero(&to, sizeof(to));
+ mDNSPlatformMemZero(&from, sizeof(from));
+ socklen_t len = sizeof(to);
+ ret = getsockname(s1, (struct sockaddr*) &to, &len);
+ if (ret < 0)
+ {
+ LogMsg("ProxyTCPReceive: getsockname(fd=%d) errno %d", s1, errno);
+ mDNSPlatformDisposeProxyContext(ti);
+ return;
+ }
+ ret = getpeername(s1, (struct sockaddr*) &from, &len);
+ if (ret < 0)
+ {
+ LogMsg("ProxyTCPReceive: getpeername(fd=%d) errno %d", s1, errno);
+ mDNSPlatformDisposeProxyContext(ti);
+ return;
+ }
+
+ 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;
+
+ s = (struct sockaddr_in *)&to;
+ destAddr.type = mDNSAddrType_IPv4;
+ destAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr;
+
+ LogInfo("ProxyTCPReceive received IPv4 packet(len %d) from %#-15a to %#-15a on skt %d %s", ti->replyLen, &senderAddr, &destAddr, s1, NULL);
+ }
+ 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;
+
+ sin6 = (struct sockaddr_in6 *)&to;
+ destAddr.type = mDNSAddrType_IPv6;
+ destAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
+
+ LogInfo("ProxyTCPReceive received IPv6 packet(len %d) from %#-15a to %#-15a on skt %d %s", ti->replyLen, &senderAddr, &destAddr, s1, NULL);
+ }
+ else
+ {
+ LogMsg("ProxyTCPReceive from is unknown address family %d", from.ss_family);
+ mDNSPlatformDisposeProxyContext(ti);
+ return;
+ }
+
+ // We pass sock for the TCPSocket and the "ti" for context as that's what we want to free at the end.
+ // In the UDP case, there is just a single socket and nothing to free. Hence, the context (last argument)
+ // would be NULL.
+ kq->m->p->TCPProxyCallback(kq->m, sock, ti->reply, (mDNSu8 *)ti->reply + ti->replyLen, &senderAddr, senderPort, &destAddr,
+ UnicastDNSPort, 0, ti);
+}
+
+mDNSlocal void ProxyTCPAccept(int s1, short filter, void *context)
+{
+ int newfd;
+ struct sockaddr_storage ss;
+ socklen_t sslen = sizeof(ss);
+ const int on = 1;
+ KQSocketSet *listenSet = (KQSocketSet *)context;
+
+ (void) filter;
+
+ while ((newfd = accept(s1, (struct sockaddr *)&ss, &sslen)) != -1)
+ {
+ int err;
+ int *s;
+ KQueueEntry *k;
+ KQSocketSet *kq;
+
+ // Even though we just need a single KQueueEntry, for simplicity we re-use
+ // the KQSocketSet
+ ProxyTCPInfo_t *ti = mallocL("ProxyTCPContext", sizeof(ProxyTCPInfo_t));
+ if (!ti)
+ {
+ LogMsg("ProxyTCPAccept: cannot allocate TCPSocket");
+ close(newfd);
+ return;
+ }
+ mDNSPlatformMemZero(ti, sizeof(ProxyTCPInfo_t));
+ TCPSocket *sock = &ti->sock;
+
+ kq = &sock->ss;
+ kq->sktv4 = -1;
+ kq->sktv6 = -1;
+ kq->m = listenSet->m;
+
+ fcntl(newfd, F_SETFL, fcntl(newfd, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
+ if (ss.ss_family == AF_INET)
+ {
+ s = &kq->sktv4;
+ k = &kq->kqsv4;
+ // Receive interface identifiers
+ err = setsockopt(newfd, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
+ if (err)
+ {
+ LogMsg("ProxyTCPAccept: IP_RECVIF %d errno %d (%s)", newfd, errno, strerror(errno));
+ mDNSPlatformDisposeProxyContext(ti);
+ return;
+ }
+ }
+ else
+ {
+ s = &kq->sktv6;
+ k = &kq->kqsv6;
+ // We want to receive destination addresses and receive interface identifiers
+ err = setsockopt(newfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
+ if (err)
+ {
+ LogMsg("ProxyTCPAccept: IP_RECVPKTINFO %d errno %d (%s)", newfd, errno, strerror(errno));
+ mDNSPlatformDisposeProxyContext(ti);
+ return;
+ }
+ }
+ *s = newfd;
+ // 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 = newfd;
+ sock->kqEntry = k;
+
+ k->KQcallback = ProxyTCPSocketCallBack;
+ k->KQcontext = ti;
+ k->KQtask = "TCP Proxy 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);
+ }
+}
+
+mDNSlocal mStatus SetupUDPProxySocket(mDNS *const m, int skt, KQSocketSet *cp, u_short sa_family, mDNSBool useBackgroundTrafficClass)
+{
+ int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
+ KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
+ const int on = 1;
+ mDNSIPPort port;
+ mStatus err = mStatus_NoError;
+
+ cp->m = m;
+ port = cp->port;
+ cp->closeFlag = mDNSNULL;
+
+ // set default traffic class
+ // setTrafficClass(skt, mDNSfalse);
+ (void) useBackgroundTrafficClass;
+
+ if (sa_family == AF_INET)
+ {
+ err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
+ if (err < 0)
+ {
+ LogMsg("SetupUDPProxySocket: IP_RECVDSTADDR %d errno %d (%s)", skt, errno, strerror(errno));
+ return err;
+ }
+
+ // We want to receive interface identifiers
+ err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
+ if (err < 0)
+ {
+ LogMsg("SetupUDPProxySocket: IP_RECVIF %d errno %d (%s)", skt, errno, strerror(errno));
+ return err;
+ }
+ }
+ else if (sa_family == AF_INET6)
+ {
+ // We want to receive destination addresses and receive interface identifiers
+ err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
+ if (err < 0)
+ {
+ LogMsg("SetupUDPProxySocket: IPV6_RECVPKTINFO %d errno %d (%s)", skt, errno, strerror(errno));
+ return err;
+ }
+
+ // 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)
+ {
+ LogMsg("SetupUDPProxySocket: IPV6_RECVHOPLIMIT %d errno %d (%s)", skt, errno, strerror(errno));
+ return err;
+ }
+ }
+ else
+ {
+ LogMsg("SetupUDPProxySocket: wrong family %d", sa_family);
+ return -1;
+ }
+
+ if (fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK) < 0)
+ {
+ LogMsg("SetupUDPProxySocket: fnctl failed %d", errno);
+ return -1;
+ }
+
+ *s = skt;
+ //k->KQcallback = ProxyUDPSocketCallBack;
+ k->KQcallback = myKQSocketCallBack;
+ k->KQcontext = cp;
+ k->KQtask = "UDP Proxy 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);
+}
+
+mDNSlocal mStatus SetupTCPProxySocket(mDNS *const m, int skt, KQSocketSet *cp, u_short sa_family, mDNSBool useBackgroundTrafficClass)
+{
+ int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
+ KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
+ mDNSIPPort port;
+ mStatus err;
+
+ cp->m = m;
+ port = cp->port;
+ // XXX may not be used by the TCP codepath
+ cp->closeFlag = mDNSNULL;
+
+ // for TCP sockets, the traffic class is set once and not changed
+ // setTrafficClass(skt, useBackgroundTrafficClass);
+ (void) useBackgroundTrafficClass;
+
+ // All the socket setup has already been done
+ err = listen(skt, NUM_PROXY_TCP_CONNS);
+ if (err)
+ {
+ LogMsg("SetupTCPProxySocket: listen %d errno %d (%s)", skt, errno, strerror(errno));
+ return err;
+ }
+ fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
+
+ *s = skt;
+ k->KQcallback = ProxyTCPAccept;
+ k->KQcontext = cp;
+ k->KQtask = "TCP Accept";
+#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 mStatus_NoError;
+}
+
+mDNSlocal void BindDPSocket(int fd, int sa_family)
+{
+ int err;
+ const int on = 1;
+
+ if (sa_family == AF_INET)
+ {
+ struct sockaddr_in addr;
+
+ err = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
+ if (err < 0)
+ LogMsg("BindDPSocket: setsockopt SO_REUSEPORT failed for V4 %d errno %d (%s)", fd, errno, strerror(errno));
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(53);
+
+ err = bind(fd, (struct sockaddr*) &addr, sizeof(addr));
+ if (err)
+ {
+ LogMsg("BindDPSocket: bind %d errno %d (%s)", fd, errno, strerror(errno));
+ return;
+ }
+ }
+ else
+ {
+ struct sockaddr_in6 addr6;
+
+ // 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(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
+ if (err < 0)
+ {
+ LogMsg("DPFBindSocket: setsockopt IPV6_V6ONLY %d errno %d (%s)", fd, errno, strerror(errno));
+ return;
+ }
+ err = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
+ if (err < 0)
+ LogMsg("BindDPSocket: setsockopt SO_REUSEPORT failed for V6 %d errno %d (%s)", fd, errno, strerror(errno));
+
+ memset(&addr6, 0, sizeof(addr6));
+ addr6.sin6_family = AF_INET6;
+ addr6.sin6_port = htons(53);
+
+ err = bind(fd, (struct sockaddr*) &addr6, sizeof(addr6));
+ if (err)
+ {
+ LogMsg("BindDPSocket: bind6 %d errno %d (%s)", fd, errno, strerror(errno));
+ return;
+ }
+ }
+}
+
+// Setup DNS Proxy Skts in main kevent loop and set the skt options
+mDNSlocal void SetupDNSProxySkts(mDNS *const m, int fd[4])
+{
+ int i;
+ mStatus err;
+ KQSocketSet *udpSS;
+ KQSocketSet *tcpSS;
+
+ udpSS = &m->p->UDPProxy.ss;
+ tcpSS = &m->p->TCPProxy.ss;
+ udpSS->port = UnicastDNSPort;
+ tcpSS->port = UnicastDNSPort;
+
+ LogMsg("SetupDNSProxySkts: %d, %d, %d, %d", fd[0], fd[1], fd[2], fd[3]);
+
+ // myKQSocketCallBack checks for proxy and calls the m->p->ProxyCallback instead of mDNSCoreReceive
+ udpSS->proxy = mDNStrue;
+ err = SetupUDPProxySocket(m, fd[0], udpSS, AF_INET, mDNSfalse);
+ if (err)
+ LogMsg("SetupDNSProxySkts: ERROR!! UDPv4 Socket");
+
+ err = SetupUDPProxySocket(m, fd[1], udpSS, AF_INET6, mDNSfalse);
+ if (err)
+ LogMsg("SetupDNSProxySkts: ERROR!! UDPv6 Socket");
+
+ err = SetupTCPProxySocket(m, fd[2], tcpSS, AF_INET, mDNSfalse);
+ if (err)
+ LogMsg("SetupDNSProxySkts: ERROR!! TCPv4 Socket");
+
+ err = SetupTCPProxySocket(m, fd[3], tcpSS, AF_INET6, mDNSfalse);
+ if (err)
+ LogMsg("SetupDNSProxySkts: ERROR!! TCPv6 Socket");
+
+ for (i = 0; i < 4; i++)
+ dp_listener[i] = fd[i];
+}
+
+// Create and bind the DNS Proxy Skts for use
+mDNSexport void mDNSPlatformInitDNSProxySkts(mDNS *const m, ProxyCallback UDPCallback, ProxyCallback TCPCallback)
+{
+ int dpskt[4];
+
+ dpskt[0] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ dpskt[1] = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ dpskt[2] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ dpskt[3] = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
+
+ // Close all DNS Proxy skts in case any of them are invalid
+ if (!ValidSocket(dpskt[0]) || !ValidSocket(dpskt[1]) ||
+ !ValidSocket(dpskt[2]) || !ValidSocket(dpskt[3]))
+ {
+ if (ValidSocket(dpskt[0]))
+ close(dpskt[0]);
+ if (ValidSocket(dpskt[1]))
+ close(dpskt[1]);
+ if (ValidSocket(dpskt[2]))
+ close(dpskt[2]);
+ if (ValidSocket(dpskt[3]))
+ close(dpskt[3]);
+ }
+
+ BindDPSocket(dpskt[0], AF_INET);
+ BindDPSocket(dpskt[1], AF_INET6);
+ BindDPSocket(dpskt[2], AF_INET);
+ BindDPSocket(dpskt[3], AF_INET6);
+
+ LogInfo("mDNSPlatformInitDNSProxySkts: Opened Listener Sockets for DNS Proxy : %d, %d, %d, %d",
+ dpskt[0], dpskt[1], dpskt[2], dpskt[3]);
+
+ m->p->UDPProxyCallback = UDPCallback;
+ m->p->TCPProxyCallback = TCPCallback;
+
+ SetupDNSProxySkts(m, dpskt);
+}
+
+mDNSexport void mDNSPlatformCloseDNSProxySkts(mDNS *const m)
+{
+ (void) m;
+ int i;
+ for (i = 0; i < 4; i++)
+ close(dp_listener[i]);
+ LogInfo("mDNSPlatformCloseDNSProxySkts: Closing DNS Proxy Listener Sockets");
+}
+
+mDNSexport void mDNSPlatformDisposeProxyContext(void *context)
+{
+ ProxyTCPInfo_t *ti;
+ TCPSocket *sock;
+ KQSocketSet *kq;
+
+ if (!context)
+ return;
+
+ ti = (ProxyTCPInfo_t *)context;
+ sock = &ti->sock;
+
+ kq = &sock->ss;
+ if (kq->sktv4 != -1)
+ {
+ shutdown(kq->sktv4, 2);
+ mDNSPlatformCloseFD(&kq->kqsv4, kq->sktv4);
+ }
+ if (kq->sktv6 != -1)
+ {
+ shutdown(kq->sktv6, 2);
+ mDNSPlatformCloseFD(&kq->kqsv6, kq->sktv6);
+ }
+ if (kq->closeFlag)
+ *kq->closeFlag = 1;
+
+ if (ti->reply)
+ freeL("ProxyTCPInfoLen", ti->reply);
+ freeL("ProxyTCPContext", ti);
+}
+
diff --git a/mDNSResponder/mDNSMacOSX/DNSSECSupport.c b/mDNSResponder/mDNSMacOSX/DNSSECSupport.c
new file mode 100644
index 00000000..e1255c4d
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DNSSECSupport.c
@@ -0,0 +1,645 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2012 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.
+ */
+
+// ***************************************************************************
+// DNSSECSupport.c: Platform specific support for DNSSEC like fetching root
+// trust anchor and dnssec probes etc.
+// ***************************************************************************
+
+#include "mDNSEmbeddedAPI.h"
+#include "DNSCommon.h" // For mDNS_Lock, mDNS_Random
+#include "dnssec.h"
+#include "DNSSECSupport.h"
+
+#include <CommonCrypto/CommonDigest.h> // For Hash algorithms SHA1 etc.
+
+// Following are needed for fetching the root trust anchor dynamically
+#include <CoreFoundation/CoreFoundation.h>
+#include <libxml2/libxml/parser.h>
+#include <libxml2/libxml/tree.h>
+#include <libxml2/libxml/xmlmemory.h>
+#include <notify.h>
+
+// 30 days
+#define ROOT_TA_UPDATE_INTERVAL (30 * 24 * 3600) // seconds
+
+// After 100 days, the test anchors are not valid. Just an arbitrary number
+// to configure validUntil.
+#define TEST_TA_EXPIRE_INTERVAL (100 * 24 * 4600)
+
+// When we can't fetch the root TA due to network errors etc., we start off a timer
+// to fire at 60 seconds and then keep doubling it till we fetch it
+#define InitialTAFetchInterval 60
+
+#if !TARGET_OS_IPHONE
+DNSQuestion DNSSECProbeQuestion;
+#endif
+
+mDNSlocal int RegisterNotification(mDNS *const m, unsigned int interval);
+
+mDNSlocal void LinkTrustAnchor(mDNS *const m, TrustAnchor *ta)
+{
+ int length = 0;
+ int i;
+ mDNSu8 *p;
+ TrustAnchor **t = &m->TrustAnchors;
+ char buffer[256];
+
+ while (*t)
+ t = &((*t)->next);
+ *t = ta;
+
+ buffer[0] = 0;
+ p = ta->rds.digest;
+ for (i = 0; i < ta->digestLen; i++)
+ {
+ length += mDNS_snprintf(buffer+length, sizeof(buffer)-1-length, "%x", p[i]);
+ }
+ LogInfo("LinkTrustAnchor: Zone %##s, keytag %d, alg %d, digestType %d, digestLen %d, digest %s", ta->zone.c, ta->rds.keyTag,
+ ta->rds.alg, ta->rds.digestType, ta->digestLen, buffer);
+}
+
+mDNSlocal void DelTrustAnchor(mDNS *const m, const domainname *zone)
+{
+ TrustAnchor **ta = &m->TrustAnchors;
+ TrustAnchor *tmp;
+
+ while (*ta && !SameDomainName(&(*ta)->zone, zone))
+ ta = &(*ta)->next;
+
+ // First time, we won't find the TrustAnchor in the list as it has
+ // not been added.
+ if (!(*ta))
+ return;
+
+ tmp = *ta;
+ *ta = (*ta)->next; // Cut this record from the list
+ tmp->next = mDNSNULL;
+ if (tmp->rds.digest)
+ mDNSPlatformMemFree(tmp->rds.digest);
+ mDNSPlatformMemFree(tmp);
+}
+
+mDNSlocal void AddTrustAnchor(mDNS *const m, const domainname *zone, mDNSu16 keytag, mDNSu8 alg, mDNSu8 digestType, int diglen,
+ mDNSu8 *digest)
+{
+ TrustAnchor *ta, *tmp;
+ mDNSu32 t = (mDNSu32) time(NULL);
+
+ // Check for duplicates
+ tmp = m->TrustAnchors;
+ while (tmp)
+ {
+ if (SameDomainName(zone, &tmp->zone) && tmp->rds.keyTag == keytag && tmp->rds.alg == alg && tmp->rds.digestType == digestType &&
+ !memcmp(tmp->rds.digest, digest, diglen))
+ {
+ LogMsg("AddTrustAnchors: Found a duplicate");
+ return;
+ }
+ tmp = tmp->next;
+ }
+
+ ta = (TrustAnchor *)mDNSPlatformMemAllocate(sizeof(TrustAnchor));
+ if (!ta)
+ {
+ LogMsg("AddTrustAnchor: malloc failure ta");
+ return;
+ }
+ ta->rds.keyTag = keytag;
+ ta->rds.alg = alg;
+ ta->rds.digestType = digestType;
+ ta->rds.digest = digest;
+ ta->digestLen = diglen;
+ ta->validFrom = t;
+ ta->validUntil = t + TEST_TA_EXPIRE_INTERVAL;
+ AssignDomainName(&ta->zone, zone);
+ ta->next = mDNSNULL;
+
+ LinkTrustAnchor(m, ta);
+}
+
+#define HexVal(X) ( ((X) >= '0' && (X) <= '9') ? ((X) - '0' ) : \
+ ((X) >= 'A' && (X) <= 'F') ? ((X) - 'A' + 10) : \
+ ((X) >= 'a' && (X) <= 'f') ? ((X) - 'a' + 10) : -1)
+
+mDNSlocal mDNSu8 *ConvertDigest(char *digest, int digestType, int *diglen)
+{
+ int i, j;
+ mDNSu8 *dig;
+
+ switch (digestType)
+ {
+ case SHA1_DIGEST_TYPE:
+ *diglen = CC_SHA1_DIGEST_LENGTH;
+ break;
+ case SHA256_DIGEST_TYPE:
+ *diglen = CC_SHA256_DIGEST_LENGTH;
+ break;
+ default:
+ LogMsg("ConvertDigest: digest type %d not supported", digestType);
+ return mDNSNULL;
+ }
+ dig = mDNSPlatformMemAllocate(*diglen);
+ if (!dig)
+ {
+ LogMsg("ConvertDigest: malloc failure");
+ return mDNSNULL;
+ }
+
+ for (j=0,i=0; i<*diglen*2; i+=2)
+ {
+ int l, h;
+ l = HexVal(digest[i]);
+ h = HexVal(digest[i+1]);
+ if (l<0 || h<0) { LogMsg("ConvertDigest: Cannot convert digest"); return NULL;}
+ dig[j++] = (mDNSu8)((l << 4) | h);
+ }
+ return dig;
+}
+
+// All the children are in a linked list
+//
+// <TrustAnchor> has two children: <Zone> and <KeyDigest>
+// <KeyDigest> has four children <KeyTag> <Algorithm> <DigestType> <Digest>
+//
+// Returns false if failed to parse the element i.e., malformed xml document.
+// Validity of the actual values itself is done outside the function.
+mDNSlocal mDNSBool ParseElementChildren(xmlDocPtr tadoc, xmlNode *node, TrustAnchor *ta)
+{
+ xmlNode *cur_node;
+ xmlChar *val1, *val2, *val;
+ char *invalid = NULL;
+
+ val = val1 = val2 = NULL;
+
+ for (cur_node = node; cur_node; cur_node = cur_node->next)
+ {
+ invalid = NULL;
+ val1 = val2 = NULL;
+
+ val = xmlNodeListGetString(tadoc, cur_node->xmlChildrenNode, 1);
+ if (!val)
+ {
+ LogInfo("ParseElementChildren: NULL value for %s", cur_node->name);
+ continue;
+ }
+ if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Zone"))
+ {
+ // MaeDomainNameFromDNSNameString does not work for "."
+ if (!xmlStrcmp(val, (const xmlChar *)"."))
+ {
+ ta->zone.c[0] = 0;
+ }
+ else if (!MakeDomainNameFromDNSNameString(&ta->zone, (char *)val))
+ {
+ LogMsg("ParseElementChildren: Cannot parse Zone %s", val);
+ goto error;
+ }
+ else
+ {
+ LogInfo("ParseElementChildren: Element %s, value %##s", cur_node->name, ta->zone.c);
+ }
+ }
+ else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"KeyTag"))
+ {
+ ta->rds.keyTag = strtol((const char *)val, &invalid, 10);
+ if (*invalid != '\0')
+ {
+ LogMsg("ParseElementChildren: KeyTag invalid character %d", *invalid);
+ goto error;
+ }
+ else
+ {
+ LogInfo("ParseElementChildren: Element %s, value %d", cur_node->name, ta->rds.keyTag);
+ }
+ }
+ else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Algorithm"))
+ {
+ ta->rds.alg = strtol((const char *)val, &invalid, 10);
+ if (*invalid != '\0')
+ {
+ LogMsg("ParseElementChildren: Algorithm invalid character %c", *invalid);
+ goto error;
+ }
+ else
+ {
+ LogInfo("ParseElementChildren: Element %s, value %d", cur_node->name, ta->rds.alg);
+ }
+ }
+ else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"DigestType"))
+ {
+ ta->rds.digestType = strtol((const char *)val, &invalid, 10);
+ if (*invalid != '\0')
+ {
+ LogMsg("ParseElementChildren: Algorithm invalid character %c", *invalid);
+ goto error;
+ }
+ else
+ {
+ LogInfo("ParseElementChildren: Element %s, value %d", cur_node->name, ta->rds.digestType);
+ }
+ }
+ else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Digest"))
+ {
+ int diglen;
+ mDNSu8 *dig = ConvertDigest((char *)val, ta->rds.digestType, &diglen);
+ if (dig)
+ {
+ LogInfo("ParseElementChildren: Element %s, digest %s", cur_node->name, val);
+ ta->digestLen = diglen;
+ ta->rds.digest = dig;
+ }
+ else
+ {
+ LogMsg("ParseElementChildren: Element %s, NULL digest", cur_node->name);
+ goto error;
+ }
+ }
+ else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"KeyDigest"))
+ {
+ struct tm tm;
+ val1 = xmlGetProp(cur_node, (const xmlChar *)"validFrom");
+ if (val1)
+ {
+ char *s = strptime((const char *)val1, "%Y-%m-%dT%H:%M:%S", &tm);
+ if (!s)
+ {
+ LogMsg("ParseElementChildren: Parsing ValidFrom failed %s", val1);
+ goto error;
+ }
+ else
+ {
+ ta->validFrom = (mDNSu32)timegm(&tm);
+ }
+ }
+ val2 = xmlGetProp(cur_node, (const xmlChar *)"validUntil");
+ if (val2)
+ {
+ char *s = strptime((const char *)val2, "%Y-%m-%dT%H:%M:%S", &tm);
+ if (!s)
+ {
+ LogMsg("ParseElementChildren: Parsing ValidFrom failed %s", val2);
+ goto error;
+ }
+ else
+ {
+ ta->validUntil = (mDNSu32)timegm(&tm);
+ }
+ }
+ else
+ {
+ // If there is no validUntil, set it to the next probing interval
+ mDNSu32 t = (mDNSu32) time(NULL);
+ ta->validUntil = t + ROOT_TA_UPDATE_INTERVAL;
+ }
+ LogInfo("ParseElementChildren: ValidFrom time %u, validUntil %u", (unsigned)ta->validFrom, (unsigned)ta->validUntil);
+ }
+ if (val1)
+ xmlFree(val1);
+ if (val2)
+ xmlFree(val2);
+ if (val)
+ xmlFree(val);
+ }
+ return mDNStrue;
+error:
+ if (val1)
+ xmlFree(val1);
+ if (val2)
+ xmlFree(val2);
+ if (val)
+ xmlFree(val);
+ return mDNSfalse;
+}
+
+mDNSlocal mDNSBool ValidateTrustAnchor(TrustAnchor *ta)
+{
+ time_t currTime = time(NULL);
+
+ // Currently only support trust anchor for root.
+ if (!SameDomainName(&ta->zone, (const domainname *)"\000"))
+ {
+ LogInfo("ParseElementChildren: Zone %##s not root", ta->zone.c);
+ return mDNSfalse;
+ }
+
+ switch (ta->rds.digestType)
+ {
+ case SHA1_DIGEST_TYPE:
+ if (ta->digestLen != CC_SHA1_DIGEST_LENGTH)
+ {
+ LogMsg("ValidateTrustAnchor: Invalid digest len %d for SHA1", ta->digestLen);
+ return mDNSfalse;
+ }
+ break;
+ case SHA256_DIGEST_TYPE:
+ if (ta->digestLen != CC_SHA256_DIGEST_LENGTH)
+ {
+ LogMsg("ValidateTrustAnchor: Invalid digest len %d for SHA256", ta->digestLen);
+ return mDNSfalse;
+ }
+ break;
+ default:
+ LogMsg("ValidateTrustAnchor: digest type %d not supported", ta->rds.digestType);
+ return mDNSfalse;
+ }
+ if (!ta->rds.digest)
+ {
+ LogMsg("ValidateTrustAnchor: digest NULL for %d", ta->rds.digestType);
+ return mDNSfalse;
+ }
+ switch (ta->rds.alg)
+ {
+ case CRYPTO_RSA_SHA512:
+ case CRYPTO_RSA_SHA256:
+ case CRYPTO_RSA_NSEC3_SHA1:
+ case CRYPTO_RSA_SHA1:
+ break;
+ default:
+ LogMsg("ValidateTrustAnchor: Algorithm %d not supported", ta->rds.alg);
+ return mDNSfalse;
+ }
+
+ if (DNS_SERIAL_LT(currTime, ta->validFrom))
+ {
+ LogMsg("ValidateTrustAnchor: Invalid ValidFrom time %u, currtime %u", (unsigned)ta->validFrom, (unsigned)currTime);
+ return mDNSfalse;
+ }
+ if (DNS_SERIAL_LT(ta->validUntil, currTime))
+ {
+ LogMsg("ValidateTrustAnchor: Invalid ValidUntil time %u, currtime %u", (unsigned)ta->validUntil, (unsigned)currTime);
+ return mDNSfalse;
+ }
+ return mDNStrue;
+}
+
+mDNSlocal mDNSBool ParseElement(xmlDocPtr tadoc, xmlNode * a_node, TrustAnchor *ta)
+{
+ xmlNode *cur_node = NULL;
+
+ for (cur_node = a_node; cur_node; cur_node = cur_node->next)
+ {
+ if (cur_node->type == XML_ELEMENT_NODE)
+ {
+ // There could be multiple KeyDigests per TrustAnchor. We keep parsing till we
+ // reach the last one or we encounter an error in parsing the document.
+ if (!xmlStrcmp(cur_node->name, (const xmlChar *)"KeyDigest"))
+ {
+ if (ta->rds.digest)
+ mDNSPlatformMemFree(ta->rds.digest);
+ ta->rds.digestType = 0;
+ ta->digestLen = 0;
+ }
+ if (!ParseElementChildren(tadoc, cur_node->children, ta))
+ return mDNSfalse;
+ if (!ParseElement(tadoc, cur_node->children, ta))
+ return mDNSfalse;
+ }
+ }
+ return mDNStrue;
+}
+
+mDNSlocal void TAComplete(mDNS *const m, void *context)
+{
+ TrustAnchor *ta = (TrustAnchor *)context;
+
+ DelTrustAnchor(m, &ta->zone);
+ LinkTrustAnchor(m, ta);
+}
+
+mDNSlocal void FetchRootTA(mDNS *const m)
+{
+ CFStringRef urlString = CFSTR("https://data.iana.org/root-anchors/root-anchors.xml");
+ CFDataRef xmlData;
+ CFStringRef fileRef = NULL;
+ const char *xmlFileName = NULL;
+ char buf[512];
+ CFURLRef url = NULL;
+ static unsigned int RootTAFetchInterval = InitialTAFetchInterval;
+
+ (void) m;
+
+ TrustAnchor *ta = (TrustAnchor *)mDNSPlatformMemAllocate(sizeof(TrustAnchor));
+ if (!ta)
+ {
+ LogMsg("FetchRootTA: TrustAnchor alloc failed");
+ return;
+ }
+ memset(ta, 0, sizeof(TrustAnchor));
+
+ url = CFURLCreateWithString(NULL, urlString, NULL);
+ if (!url)
+ {
+ LogMsg("FetchRootTA: CFURLCreateWithString error");
+ mDNSPlatformMemFree(ta);
+ return;
+ }
+
+ // If we can't fetch the XML file e.g., network problems, trigger a timer. All other failures
+ // should hardly happen in practice for which schedule the normal interval to refetch the TA.
+ if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, url, &xmlData, NULL, NULL, NULL))
+ {
+ LogInfo("FetchRootTA: CFURLCreateDataAndPropertiesFromResource error");
+ CFRelease(url);
+ mDNSPlatformMemFree(ta);
+ RegisterNotification(m, RootTAFetchInterval);
+ RootTAFetchInterval *= 2 + 1;
+ return;
+ }
+
+ // get the name of the last component from the url, libxml will use it if
+ // it has to report an error
+ fileRef = CFURLCopyLastPathComponent(url);
+ if (fileRef)
+ {
+ xmlFileName = CFStringGetCStringPtr(fileRef, kCFStringEncodingUTF8);
+ if (!xmlFileName)
+ {
+ if (!CFStringGetCString(fileRef, buf, sizeof(buf), kCFStringEncodingUTF8) )
+ strlcpy(buf, "nofile.xml", sizeof(buf));
+ xmlFileName = (const char *)buf;
+ }
+ }
+
+ // Parse the XML and get the CFXMLTree.
+ xmlDocPtr tadoc = xmlReadMemory((const char*)CFDataGetBytePtr(xmlData),
+ (int)CFDataGetLength(xmlData), xmlFileName, NULL, 0);
+
+ CFRelease(fileRef);
+ CFRelease(url);
+ CFRelease(xmlData);
+
+ if (!tadoc)
+ {
+ LogMsg("FetchRootTA: xmlReadMemory failed");
+ goto done;
+ }
+
+ xmlNodePtr root = xmlDocGetRootElement(tadoc);
+ if (!root)
+ {
+ LogMsg("FetchRootTA: Cannot get root element");
+ goto done;
+ }
+
+ if (ParseElement(tadoc, root, ta) && ValidateTrustAnchor(ta))
+ {
+ // Do the actual addition of TA on the main queue.
+ mDNSPlatformDispatchAsync(m, ta, TAComplete);
+ }
+ else
+ {
+ if (ta->rds.digest)
+ mDNSPlatformMemFree(ta->rds.digest);
+ mDNSPlatformMemFree(ta);
+ }
+done:
+ if (tadoc)
+ xmlFreeDoc(tadoc);
+ RegisterNotification(m, ROOT_TA_UPDATE_INTERVAL);
+ RootTAFetchInterval = InitialTAFetchInterval;
+ return;
+}
+
+
+#if APPLE_OSX_mDNSResponder && !TARGET_OS_IPHONE
+mDNSlocal void DNSSECProbeCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
+{
+ if (!AddRecord)
+ return;
+
+ mDNS_Lock(m);
+ if ((m->timenow - question->StopTime) >= 0)
+ {
+ mDNS_Unlock(m);
+ LogDNSSEC("DNSSECProbeCallback: Question %##s (%s) timed out", question->qname.c, DNSTypeName(question->qtype));
+ mDNS_StopQuery(m, question);
+ return;
+ }
+ mDNS_Unlock(m);
+
+ // Wait till we get the DNSSEC results. If we get a negative response e.g., no DNS servers, the
+ // question will be restarted by the core and we should have the DNSSEC results eventually.
+ if (AddRecord != QC_dnssec)
+ {
+ LogDNSSEC("DNSSECProbeCallback: Question %##s (%s)", question->qname.c, DNSTypeName(question->qtype), RRDisplayString(m, answer));
+ return;
+ }
+
+ LogDNSSEC("DNSSECProbeCallback: Question %##s (%s), DNSSEC status %s", question->qname.c, DNSTypeName(question->qtype),
+ DNSSECStatusName(question->ValidationStatus));
+
+ mDNS_StopQuery(m, question);
+}
+
+// Send a DNSSEC probe just for the sake of collecting DNSSEC statistics.
+mDNSexport void DNSSECProbe(mDNS *const m)
+{
+ mDNSu32 rand;
+
+ if (DNSSECProbeQuestion.ThisQInterval != -1)
+ return;
+
+ rand = mDNSRandom(0x3FFFFFFF) % 100;
+ // Probe 5% of the time
+ if (rand > 5)
+ return;
+
+ mDNS_DropLockBeforeCallback();
+ InitializeQuestion(m, &DNSSECProbeQuestion, mDNSInterface_Any, (const domainname *)"\003com", kDNSType_DS, DNSSECProbeCallback, mDNSNULL);
+ DNSSECProbeQuestion.ValidatingResponse = 0;
+ DNSSECProbeQuestion.ValidationRequired = DNSSEC_VALIDATION_SECURE;
+
+ BumpDNSSECStats(m, kStatsActionIncrement, kStatsTypeProbe, 1);
+ mDNS_StartQuery(m, &DNSSECProbeQuestion);
+ mDNS_ReclaimLockAfterCallback();
+}
+#endif // APPLE_OSX_mDNSResponder && !TARGET_OS_IPHONE
+
+// For now we fetch the root trust anchor and update the local copy
+mDNSexport void UpdateTrustAnchors(mDNS *const m)
+{
+ // Register for a notification to fire immediately which in turn will update
+ // the trust anchor
+ if (RegisterNotification(m, 1))
+ {
+ LogMsg("UpdateTrustAnchors: ERROR!! failed to register for notification");
+ }
+}
+
+mDNSlocal int RegisterNotification(mDNS *const m, unsigned int interval)
+{
+ int len = strlen("com.apple.system.notify.service.timer:+") + 21; // 21 bytes to accomodate the interval
+ char buffer[len];
+ unsigned int blen;
+ int status;
+
+ // Starting "interval" second from now (+ below indicates relative) register for a notification
+ blen = mDNS_snprintf(buffer, sizeof(buffer), "com.apple.system.notify.service.timer:+%us", interval);
+ if (blen >= sizeof(buffer))
+ {
+ LogMsg("RegisterNotification: Buffer too small blen %d, buffer size %d", blen, sizeof(buffer));
+ return -1;
+ }
+ LogInfo("RegisterNotification: buffer %s", buffer);
+ if (m->notifyToken)
+ {
+ notify_cancel(m->notifyToken);
+ m->notifyToken = 0;
+ }
+ status = notify_register_dispatch(buffer, &m->notifyToken,
+ dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
+ ^(int t) { (void) t; FetchRootTA(m); });
+
+ if (status != NOTIFY_STATUS_OK)
+ {
+ LogMsg("RegisterNotification: notify_register_dispatch failed");
+ return -1;
+ }
+ return 0;
+}
+
+mDNSexport mStatus DNSSECPlatformInit(mDNS *const m)
+{
+ int diglen;
+
+ m->TrustAnchors = mDNSNULL;
+ m->notifyToken = 0;
+
+ // Add a couple of trust anchors for testing purposes.
+ mDNSlocal const domainname *testZone = (const domainname*)"\007example";
+
+ char *digest = "F122E47B5B7D2B6A5CC0A21EADA11D96BB9CC927";
+ mDNSu8 *dig = ConvertDigest(digest, 1, &diglen);
+ AddTrustAnchor(m, testZone, 23044, 5, 1, diglen, dig);
+
+ char *digest1 = "D795AE5E1AFB200C6139474199B70EAD3F3484553FD97BE5A43704B8A4791F21";
+ dig = ConvertDigest(digest1, 2, &diglen);
+ AddTrustAnchor(m, testZone, 23044, 5, 2, diglen, dig);
+
+ // Add the TA for root zone manually here. We will dynamically fetch the root TA and
+ // update it shortly. If that fails e.g., disconnected from the network, we still
+ // have something to work with.
+ char *digest2 = "49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5";
+ dig = ConvertDigest(digest2, 2, &diglen);
+ AddTrustAnchor(m, (const domainname *)"\000", 19036, 8, 2, diglen, dig);
+
+#if !TARGET_OS_IPHONE
+ DNSSECProbeQuestion.ThisQInterval = -1;
+#endif
+ return mStatus_NoError;
+}
diff --git a/mDNSResponder/mDNSMacOSX/DNSSECSupport.h b/mDNSResponder/mDNSMacOSX/DNSSECSupport.h
new file mode 100644
index 00000000..2310fc2a
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DNSSECSupport.h
@@ -0,0 +1,24 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2012 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.
+ */
+
+#ifndef __DNSSEC_SUPPORT_H
+#define __DNSSEC_SUPPORT_H
+
+extern mStatus DNSSECPlatformInit(mDNS *const m);
+extern void UpdateTrustAnchors(mDNS *const m);
+
+#endif // __DNSSEC_SUPPORT_H
diff --git a/mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.c b/mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.c
new file mode 100644
index 00000000..717efca2
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.c
@@ -0,0 +1,674 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002 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.
+ */
+
+// Suppress "warning: 'DNSServiceDiscoveryMachPort' is deprecated" messages -- we already know this code is building the deprecated API
+// Since we compile with all warnings treated as errors, we have to turn off the warnings here or the project won't compile
+#include <AvailabilityMacros.h>
+#undef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED
+#define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED
+#undef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3
+#define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3
+
+#include "../mDNSMacOSX/DNSServiceDiscovery.h"
+#include "DNSServiceDiscoveryDefines.h"
+#include "DNSServiceDiscoveryReplyServer.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <servers/bootstrap.h>
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <pthread.h>
+
+#include <netinet/in.h>
+
+extern boolean_t DNSServiceDiscoveryReply_server(
+ mach_msg_header_t *InHeadP,
+ mach_msg_header_t *OutHeadP);
+
+extern
+kern_return_t DNSServiceBrowserCreate_rpc
+(
+ mach_port_t server,
+ mach_port_t client,
+ DNSCString regtype,
+ DNSCString domain
+);
+
+extern
+kern_return_t DNSServiceDomainEnumerationCreate_rpc
+(
+ mach_port_t server,
+ mach_port_t client,
+ int registrationDomains
+);
+
+extern
+kern_return_t DNSServiceRegistrationCreate_rpc
+(
+ mach_port_t server,
+ mach_port_t client,
+ DNSCString name,
+ DNSCString regtype,
+ DNSCString domain,
+ IPPort port,
+ DNSCString txtRecord
+);
+
+extern
+kern_return_t DNSServiceResolverResolve_rpc
+(
+ mach_port_t server,
+ mach_port_t client,
+ DNSCString name,
+ DNSCString regtype,
+ DNSCString domain
+);
+
+extern
+kern_return_t DNSServiceRegistrationAddRecord_rpc
+(
+ mach_port_t server,
+ mach_port_t client,
+ int type,
+ record_data_t data,
+ mach_msg_type_number_t record_dataCnt,
+ uint32_t ttl,
+ natural_t *reference
+);
+
+extern
+int DNSServiceRegistrationUpdateRecord_rpc
+(
+ mach_port_t server,
+ mach_port_t client,
+ natural_t reference,
+ record_data_t data,
+ mach_msg_type_number_t record_dataCnt,
+ uint32_t ttl
+);
+
+extern
+kern_return_t DNSServiceRegistrationRemoveRecord_rpc
+(
+ mach_port_t server,
+ mach_port_t client,
+ natural_t reference
+);
+
+struct a_requests {
+ struct a_requests *next;
+ mach_port_t client_port;
+ union {
+ DNSServiceBrowserReply browserCallback;
+ DNSServiceDomainEnumerationReply enumCallback;
+ DNSServiceRegistrationReply regCallback;
+ DNSServiceResolverReply resolveCallback;
+ } callout;
+ void *context;
+};
+
+static struct a_requests *a_requests = NULL;
+static pthread_mutex_t a_requests_lock = PTHREAD_MUTEX_INITIALIZER;
+
+typedef struct _dns_service_discovery_t {
+ mach_port_t port;
+} dns_service_discovery_t;
+
+static mach_port_t DNSServiceDiscoveryLookupServer(void)
+{
+ static mach_port_t sndPort = MACH_PORT_NULL;
+ kern_return_t result;
+
+ if (sndPort != MACH_PORT_NULL) {
+ return sndPort;
+ }
+
+ result = bootstrap_look_up(bootstrap_port, DNS_SERVICE_DISCOVERY_SERVER, &sndPort);
+ if (result != KERN_SUCCESS) {
+ printf("%s(): {%s:%d} bootstrap_look_up() failed: $%x\n", __FUNCTION__, __FILE__, __LINE__, (int) result);
+ sndPort = MACH_PORT_NULL;
+ }
+
+
+ return sndPort;
+}
+
+static void _increaseQueueLengthOnPort(mach_port_t port)
+{
+ mach_port_limits_t qlimits;
+ kern_return_t result;
+
+ qlimits.mpl_qlimit = 16;
+ result = mach_port_set_attributes(mach_task_self(), port, MACH_PORT_LIMITS_INFO, (mach_port_info_t)&qlimits, MACH_PORT_LIMITS_INFO_COUNT);
+
+ if (result != KERN_SUCCESS) {
+ printf("%s(): {%s:%d} mach_port_set_attributes() failed: $%x %s\n", __FUNCTION__, __FILE__, __LINE__, (int) result, mach_error_string(result));
+ }
+}
+
+dns_service_discovery_ref DNSServiceBrowserCreate (const char *regtype, const char *domain, DNSServiceBrowserReply callBack,void *context)
+{
+ mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+ mach_port_t clientPort;
+ kern_return_t result;
+ dns_service_discovery_ref return_t;
+ struct a_requests *request;
+
+ if (!serverPort) {
+ return NULL;
+ }
+
+ result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port receive creation failed, %s\n", mach_error_string(result));
+ return NULL;
+ }
+ result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port send creation failed, %s\n", mach_error_string(result));
+ mach_port_destroy(mach_task_self(), clientPort);
+ return NULL;
+ }
+ _increaseQueueLengthOnPort(clientPort);
+
+ return_t = malloc(sizeof(dns_service_discovery_t));
+ return_t->port = clientPort;
+
+ request = malloc(sizeof(struct a_requests));
+ request->client_port = clientPort;
+ request->context = context;
+ request->callout.browserCallback = callBack;
+
+ result = DNSServiceBrowserCreate_rpc(serverPort, clientPort, (char *)regtype, (char *)domain);
+
+ if (result != KERN_SUCCESS) {
+ printf("There was an error creating a browser, %s\n", mach_error_string(result));
+ free(request);
+ return NULL;
+ }
+
+ pthread_mutex_lock(&a_requests_lock);
+ request->next = a_requests;
+ a_requests = request;
+ pthread_mutex_unlock(&a_requests_lock);
+
+ return return_t;
+}
+
+/* Service Enumeration */
+
+dns_service_discovery_ref DNSServiceDomainEnumerationCreate (int registrationDomains, DNSServiceDomainEnumerationReply callBack, void *context)
+{
+ mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+ mach_port_t clientPort;
+ kern_return_t result;
+ dns_service_discovery_ref return_t;
+ struct a_requests *request;
+
+ if (!serverPort) {
+ return NULL;
+ }
+
+ result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port receive creation failed, %s\n", mach_error_string(result));
+ return NULL;
+ }
+ result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port send creation failed, %s\n", mach_error_string(result));
+ mach_port_destroy(mach_task_self(), clientPort);
+ return NULL;
+ }
+ _increaseQueueLengthOnPort(clientPort);
+
+ return_t = malloc(sizeof(dns_service_discovery_t));
+ return_t->port = clientPort;
+
+ request = malloc(sizeof(struct a_requests));
+ request->client_port = clientPort;
+ request->context = context;
+ request->callout.enumCallback = callBack;
+
+ result = DNSServiceDomainEnumerationCreate_rpc(serverPort, clientPort, registrationDomains);
+
+ if (result != KERN_SUCCESS) {
+ printf("There was an error creating an enumerator, %s\n", mach_error_string(result));
+ free(request);
+ return NULL;
+ }
+
+ pthread_mutex_lock(&a_requests_lock);
+ request->next = a_requests;
+ a_requests = request;
+ pthread_mutex_unlock(&a_requests_lock);
+
+ return return_t;
+}
+
+
+/* Service Registration */
+
+dns_service_discovery_ref DNSServiceRegistrationCreate
+ (const char *name, const char *regtype, const char *domain, uint16_t port, const char *txtRecord, DNSServiceRegistrationReply callBack, void *context)
+{
+ mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+ mach_port_t clientPort;
+ kern_return_t result;
+ dns_service_discovery_ref return_t;
+ struct a_requests *request;
+ IPPort IpPort;
+ char *portptr = (char *)&port;
+
+ if (!serverPort) {
+ return NULL;
+ }
+
+ if (!txtRecord) {
+ txtRecord = "";
+ }
+
+ result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port receive creation failed, %s\n", mach_error_string(result));
+ return NULL;
+ }
+ result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port send creation failed, %s\n", mach_error_string(result));
+ mach_port_destroy(mach_task_self(), clientPort);
+ return NULL;
+ }
+ _increaseQueueLengthOnPort(clientPort);
+
+ return_t = malloc(sizeof(dns_service_discovery_t));
+ return_t->port = clientPort;
+
+ request = malloc(sizeof(struct a_requests));
+ request->client_port = clientPort;
+ request->context = context;
+ request->callout.regCallback = callBack;
+
+ // older versions of this code passed the port via mach IPC as an int.
+ // we continue to pass it as 4 bytes to maintain binary compatibility,
+ // but now ensure that the network byte order is preserved by using a struct
+ IpPort.bytes[0] = 0;
+ IpPort.bytes[1] = 0;
+ IpPort.bytes[2] = portptr[0];
+ IpPort.bytes[3] = portptr[1];
+
+ result = DNSServiceRegistrationCreate_rpc(serverPort, clientPort, (char *)name, (char *)regtype, (char *)domain, IpPort, (char *)txtRecord);
+
+ if (result != KERN_SUCCESS) {
+ printf("There was an error creating a resolve, %s\n", mach_error_string(result));
+ free(request);
+ return NULL;
+ }
+
+ pthread_mutex_lock(&a_requests_lock);
+ request->next = a_requests;
+ a_requests = request;
+ pthread_mutex_unlock(&a_requests_lock);
+
+ return return_t;
+}
+
+/* Resolver requests */
+
+dns_service_discovery_ref DNSServiceResolverResolve(const char *name, const char *regtype, const char *domain, DNSServiceResolverReply callBack, void *context)
+{
+ mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+ mach_port_t clientPort;
+ kern_return_t result;
+ dns_service_discovery_ref return_t;
+ struct a_requests *request;
+
+ if (!serverPort) {
+ return NULL;
+ }
+
+ result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port receive creation failed, %s\n", mach_error_string(result));
+ return NULL;
+ }
+ result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND);
+ if (result != KERN_SUCCESS) {
+ printf("Mach port send creation failed, %s\n", mach_error_string(result));
+ mach_port_destroy(mach_task_self(), clientPort);
+ return NULL;
+ }
+ _increaseQueueLengthOnPort(clientPort);
+
+ return_t = malloc(sizeof(dns_service_discovery_t));
+ return_t->port = clientPort;
+
+ request = malloc(sizeof(struct a_requests));
+ request->client_port = clientPort;
+ request->context = context;
+ request->callout.resolveCallback = callBack;
+
+ DNSServiceResolverResolve_rpc(serverPort, clientPort, (char *)name, (char *)regtype, (char *)domain);
+
+ pthread_mutex_lock(&a_requests_lock);
+ request->next = a_requests;
+ a_requests = request;
+ pthread_mutex_unlock(&a_requests_lock);
+
+ return return_t;
+}
+
+DNSRecordReference DNSServiceRegistrationAddRecord(dns_service_discovery_ref ref, uint16_t rrtype, uint16_t rdlen, const char *rdata, uint32_t ttl)
+{
+ mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+ mach_port_t clientPort;
+ natural_t reference = 0;
+ kern_return_t result = KERN_SUCCESS;
+
+ if (!serverPort) {
+ return kDNSServiceDiscoveryUnknownErr;
+ }
+
+ clientPort = DNSServiceDiscoveryMachPort(ref);
+
+ if (!clientPort) {
+ return kDNSServiceDiscoveryUnknownErr;
+ }
+
+ result = DNSServiceRegistrationAddRecord_rpc(serverPort, clientPort, rrtype, (record_data_t)rdata, rdlen, ttl, &reference);
+
+ if (result != KERN_SUCCESS) {
+ printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result));
+ }
+
+ return reference;
+}
+
+DNSServiceRegistrationReplyErrorType DNSServiceRegistrationUpdateRecord(dns_service_discovery_ref ref, DNSRecordReference reference, uint16_t rdlen, const char *rdata, uint32_t ttl)
+{
+ mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+ mach_port_t clientPort;
+ kern_return_t result = KERN_SUCCESS;
+
+ if (!serverPort) {
+ return kDNSServiceDiscoveryUnknownErr;
+ }
+
+ clientPort = DNSServiceDiscoveryMachPort(ref);
+
+ if (!clientPort) {
+ return kDNSServiceDiscoveryUnknownErr;
+ }
+
+ result = DNSServiceRegistrationUpdateRecord_rpc(serverPort, clientPort, (natural_t)reference, (record_data_t)rdata, rdlen, ttl);
+ if (result != KERN_SUCCESS) {
+ printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result));
+ return result;
+ }
+
+ return kDNSServiceDiscoveryNoError;
+}
+
+
+DNSServiceRegistrationReplyErrorType DNSServiceRegistrationRemoveRecord(dns_service_discovery_ref ref, DNSRecordReference reference)
+{
+ mach_port_t serverPort = DNSServiceDiscoveryLookupServer();
+ mach_port_t clientPort;
+ kern_return_t result = KERN_SUCCESS;
+
+ if (!serverPort) {
+ return kDNSServiceDiscoveryUnknownErr;
+ }
+
+ clientPort = DNSServiceDiscoveryMachPort(ref);
+
+ if (!clientPort) {
+ return kDNSServiceDiscoveryUnknownErr;
+ }
+
+ result = DNSServiceRegistrationRemoveRecord_rpc(serverPort, clientPort, (natural_t)reference);
+
+ if (result != KERN_SUCCESS) {
+ printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result));
+ return result;
+ }
+
+ return kDNSServiceDiscoveryNoError;
+}
+
+void DNSServiceDiscovery_handleReply(void *replyMsg)
+{
+ unsigned long result = 0xFFFFFFFF;
+ mach_msg_header_t * msgSendBufPtr;
+ mach_msg_header_t * receivedMessage;
+ unsigned msgSendBufLength;
+
+ msgSendBufLength = internal_DNSServiceDiscoveryReply_subsystem.maxsize;
+ msgSendBufPtr = (mach_msg_header_t *) malloc(msgSendBufLength);
+
+
+ receivedMessage = ( mach_msg_header_t * ) replyMsg;
+
+ // Call DNSServiceDiscoveryReply_server to change mig-generated message into a
+ // genuine mach message. It will then cause the callback to get called.
+ result = DNSServiceDiscoveryReply_server ( receivedMessage, msgSendBufPtr );
+ ( void ) mach_msg_send ( msgSendBufPtr );
+ free(msgSendBufPtr);
+}
+
+mach_port_t DNSServiceDiscoveryMachPort(dns_service_discovery_ref dnsServiceDiscovery)
+{
+ return dnsServiceDiscovery->port;
+}
+
+void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery)
+{
+ struct a_requests *request0, *request;
+ mach_port_t reply = dnsServiceDiscovery->port;
+
+ if (dnsServiceDiscovery->port) {
+ pthread_mutex_lock(&a_requests_lock);
+ request0 = NULL;
+ request = a_requests;
+ while (request) {
+ if (request->client_port == reply) {
+ /* request info found, remove from list */
+ if (request0) {
+ request0->next = request->next;
+ } else {
+ a_requests = request->next;
+ }
+ break;
+ } else {
+ /* not info for this request, skip to next */
+ request0 = request;
+ request = request->next;
+ }
+
+ }
+ pthread_mutex_unlock(&a_requests_lock);
+
+ free(request);
+
+ mach_port_destroy(mach_task_self(), dnsServiceDiscovery->port);
+
+ free(dnsServiceDiscovery);
+ }
+ return;
+}
+
+// reply functions, calls the users setup callbacks with function pointers
+
+kern_return_t internal_DNSServiceDomainEnumerationReply_rpc
+(
+ mach_port_t reply,
+ int resultType,
+ DNSCString replyDomain,
+ int flags
+)
+{
+ struct a_requests *request;
+ void *requestContext = NULL;
+ DNSServiceDomainEnumerationReply callback = NULL;
+
+ pthread_mutex_lock(&a_requests_lock);
+ request = a_requests;
+ while (request) {
+ if (request->client_port == reply) {
+ break;
+ }
+ request = request->next;
+ }
+
+ if (request != NULL) {
+ callback = (*request->callout.enumCallback);
+ requestContext = request->context;
+ }
+ pthread_mutex_unlock(&a_requests_lock);
+
+ if (request != NULL) {
+ (callback)(resultType, replyDomain, flags, requestContext);
+ }
+
+ return KERN_SUCCESS;
+
+}
+
+kern_return_t internal_DNSServiceBrowserReply_rpc
+(
+ mach_port_t reply,
+ int resultType,
+ DNSCString replyName,
+ DNSCString replyType,
+ DNSCString replyDomain,
+ int flags
+)
+{
+ struct a_requests *request;
+ void *requestContext = NULL;
+ DNSServiceBrowserReply callback = NULL;
+
+ pthread_mutex_lock(&a_requests_lock);
+ request = a_requests;
+ while (request) {
+ if (request->client_port == reply) {
+ break;
+ }
+ request = request->next;
+ }
+ if (request != NULL) {
+ callback = (*request->callout.browserCallback);
+ requestContext = request->context;
+ }
+
+ pthread_mutex_unlock(&a_requests_lock);
+
+ if (request != NULL) {
+ (callback)(resultType, replyName, replyType, replyDomain, flags, requestContext);
+ }
+
+ return KERN_SUCCESS;
+}
+
+
+kern_return_t internal_DNSServiceRegistrationReply_rpc
+(
+ mach_port_t reply,
+ int resultType
+)
+{
+ struct a_requests *request;
+ void *requestContext = NULL;
+ DNSServiceRegistrationReply callback = NULL;
+
+ pthread_mutex_lock(&a_requests_lock);
+ request = a_requests;
+ while (request) {
+ if (request->client_port == reply) {
+ break;
+ }
+ request = request->next;
+ }
+ if (request != NULL) {
+ callback = (*request->callout.regCallback);
+ requestContext = request->context;
+ }
+
+ pthread_mutex_unlock(&a_requests_lock);
+ if (request != NULL) {
+ (callback)(resultType, requestContext);
+ }
+ return KERN_SUCCESS;
+}
+
+
+kern_return_t internal_DNSServiceResolverReply_rpc
+(
+ mach_port_t reply,
+ sockaddr_t interface,
+ sockaddr_t address,
+ DNSCString txtRecord,
+ int flags
+)
+{
+ struct sockaddr *interface_storage = NULL;
+ struct sockaddr *address_storage = NULL;
+ struct a_requests *request;
+ void *requestContext = NULL;
+ DNSServiceResolverReply callback = NULL;
+
+ if (interface) {
+ int len = ((struct sockaddr *)interface)->sa_len;
+ interface_storage = (struct sockaddr *)malloc(len);
+ memcpy(interface_storage, interface, len);
+ }
+
+ if (address) {
+ int len = ((struct sockaddr *)address)->sa_len;
+ address_storage = (struct sockaddr *)malloc(len);
+ memcpy(address_storage, address, len);
+ }
+
+ pthread_mutex_lock(&a_requests_lock);
+ request = a_requests;
+ while (request) {
+ if (request->client_port == reply) {
+ break;
+ }
+ request = request->next;
+ }
+
+ if (request != NULL) {
+ callback = (*request->callout.resolveCallback);
+ requestContext = request->context;
+ }
+ pthread_mutex_unlock(&a_requests_lock);
+
+ if (request != NULL) {
+ (callback)(interface_storage, address_storage, txtRecord, flags, requestContext);
+ }
+
+ if (interface) {
+ free(interface_storage);
+ }
+ if (address) {
+ free(address_storage);
+ }
+
+ return KERN_SUCCESS;
+}
diff --git a/mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.h b/mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.h
new file mode 100644
index 00000000..ae736477
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DNSServiceDiscovery.h
@@ -0,0 +1,314 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002 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.
+ */
+
+/*! @header DNS Service Discovery (Deprecated Mach-based API)
+ *
+ * @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 necessary access information-such as name, IP address, and port
+ * number-for a given 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.
+ *
+ * Note that this API was deprecated in Mac OS X 10.3, and replaced
+ * by the portable cross-platform /usr/include/dns_sd.h API.
+ */
+
+#ifndef __DNS_SERVICE_DISCOVERY_H
+#define __DNS_SERVICE_DISCOVERY_H
+
+#include <mach/mach_types.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/cdefs.h>
+
+#include <netinet/in.h>
+
+#include <AvailabilityMacros.h>
+
+__BEGIN_DECLS
+
+/* Opaque internal data type */
+typedef struct _dns_service_discovery_t * dns_service_discovery_ref;
+
+/* possible reply flags values */
+
+enum {
+ kDNSServiceDiscoveryNoFlags = 0,
+ kDNSServiceDiscoveryMoreRepliesImmediately = 1 << 0,
+};
+
+
+/* possible error code values */
+typedef enum
+{
+ kDNSServiceDiscoveryWaiting = 1,
+ kDNSServiceDiscoveryNoError = 0,
+ // mDNS Error codes are in the range
+ // FFFE FF00 (-65792) to FFFE FFFF (-65537)
+ kDNSServiceDiscoveryUnknownErr = -65537, // 0xFFFE FFFF
+ kDNSServiceDiscoveryNoSuchNameErr = -65538,
+ kDNSServiceDiscoveryNoMemoryErr = -65539,
+ kDNSServiceDiscoveryBadParamErr = -65540,
+ kDNSServiceDiscoveryBadReferenceErr = -65541,
+ kDNSServiceDiscoveryBadStateErr = -65542,
+ kDNSServiceDiscoveryBadFlagsErr = -65543,
+ kDNSServiceDiscoveryUnsupportedErr = -65544,
+ kDNSServiceDiscoveryNotInitializedErr = -65545,
+ kDNSServiceDiscoveryNoCache = -65546,
+ kDNSServiceDiscoveryAlreadyRegistered = -65547,
+ kDNSServiceDiscoveryNameConflict = -65548,
+ kDNSServiceDiscoveryInvalid = -65549,
+ kDNSServiceDiscoveryMemFree = -65792 // 0xFFFE FF00
+} DNSServiceRegistrationReplyErrorType;
+
+typedef uint32_t DNSRecordReference;
+
+
+/*!
+ @function DNSServiceResolver_handleReply
+ @discussion This function should be called with the Mach message sent
+ to the port returned by the call to DNSServiceResolverResolve.
+ The reply message will be interpreted and will result in a
+ call to the specified callout function.
+ @param replyMsg The Mach message.
+ */
+void DNSServiceDiscovery_handleReply(void *replyMsg);
+
+/* Service Registration */
+
+typedef void (*DNSServiceRegistrationReply)(
+ DNSServiceRegistrationReplyErrorType errorCode,
+ void *context
+ );
+
+/*!
+ @function DNSServiceRegistrationCreate
+ @discussion Register a named service with DNS Service Discovery
+ @param name The name of this service instance (e.g. "Steve's Printer")
+ @param regtype The service type (e.g. "_printer._tcp." -- see
+ RFC 2782 (DNS SRV) and <http://www.iana.org/assignments/port-numbers>)
+ @param domain The domain in which to register the service (e.g. "apple.com.")
+ @param port The local port on which this service is being offered (in network byte order)
+ @param txtRecord Optional protocol-specific additional information
+ @param callBack The DNSServiceRegistrationReply function to be called
+ @param context A user specified context which will be passed to the callout function.
+ @result A dns_registration_t
+ */
+dns_service_discovery_ref DNSServiceRegistrationCreate
+(
+ const char *name,
+ const char *regtype,
+ const char *domain,
+ uint16_t port,
+ const char *txtRecord,
+ DNSServiceRegistrationReply callBack,
+ void *context
+) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/***************************************************************************/
+/* DNS Domain Enumeration */
+
+typedef enum
+{
+ DNSServiceDomainEnumerationReplyAddDomain, // Domain found
+ DNSServiceDomainEnumerationReplyAddDomainDefault, // Domain found (and should be selected by default)
+ DNSServiceDomainEnumerationReplyRemoveDomain, // Domain has been removed from network
+} DNSServiceDomainEnumerationReplyResultType;
+
+typedef enum
+{
+ DNSServiceDiscoverReplyFlagsFinished,
+ DNSServiceDiscoverReplyFlagsMoreComing,
+} DNSServiceDiscoveryReplyFlags;
+
+typedef void (*DNSServiceDomainEnumerationReply)(
+ DNSServiceDomainEnumerationReplyResultType resultType, // One of DNSServiceDomainEnumerationReplyResultType
+ const char *replyDomain,
+ DNSServiceDiscoveryReplyFlags flags, // DNS Service Discovery reply flags information
+ void *context
+ );
+
+/*!
+ @function DNSServiceDomainEnumerationCreate
+ @discussion Asynchronously create a DNS Domain Enumerator
+ @param registrationDomains A boolean indicating whether you are looking
+ for recommended registration domains
+ (e.g. equivalent to the AppleTalk zone list in the AppleTalk Control Panel)
+ or recommended browsing domains
+ (e.g. equivalent to the AppleTalk zone list in the Chooser).
+ @param callBack The function to be called when domains are found or removed
+ @param context A user specified context which will be passed to the callout function.
+ @result A dns_registration_t
+ */
+dns_service_discovery_ref DNSServiceDomainEnumerationCreate
+(
+ int registrationDomains,
+ DNSServiceDomainEnumerationReply callBack,
+ void *context
+) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/***************************************************************************/
+/* DNS Service Browser */
+
+typedef enum
+{
+ DNSServiceBrowserReplyAddInstance, // Instance of service found
+ DNSServiceBrowserReplyRemoveInstance // Instance has been removed from network
+} DNSServiceBrowserReplyResultType;
+
+typedef void (*DNSServiceBrowserReply)(
+ DNSServiceBrowserReplyResultType resultType, // One of DNSServiceBrowserReplyResultType
+ const char *replyName,
+ const char *replyType,
+ const char *replyDomain,
+ DNSServiceDiscoveryReplyFlags flags, // DNS Service Discovery reply flags information
+ void *context
+ );
+
+/*!
+ @function DNSServiceBrowserCreate
+ @discussion Asynchronously create a DNS Service browser
+ @param regtype The type of service
+ @param domain The domain in which to find the service
+ @param callBack The function to be called when service instances are found or removed
+ @param context A user specified context which will be passed to the callout function.
+ @result A dns_registration_t
+ */
+dns_service_discovery_ref DNSServiceBrowserCreate
+(
+ const char *regtype,
+ const char *domain,
+ DNSServiceBrowserReply callBack,
+ void *context
+) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/***************************************************************************/
+/* Resolver requests */
+
+typedef void (*DNSServiceResolverReply)(
+ struct sockaddr *interface, // Needed for scoped addresses like link-local
+ struct sockaddr *address,
+ const char *txtRecord,
+ DNSServiceDiscoveryReplyFlags flags, // DNS Service Discovery reply flags information
+ void *context
+ );
+
+/*!
+ @function DNSServiceResolverResolve
+ @discussion Resolved a named instance of a service to its address, port, and
+ (optionally) other demultiplexing information contained in the TXT record.
+ @param name The name of the service instance
+ @param regtype The type of service
+ @param domain The domain in which to find the service
+ @param callBack The DNSServiceResolverReply function to be called when the specified
+ address has been resolved.
+ @param context A user specified context which will be passed to the callout function.
+ @result A dns_registration_t
+ */
+
+dns_service_discovery_ref DNSServiceResolverResolve
+(
+ const char *name,
+ const char *regtype,
+ const char *domain,
+ DNSServiceResolverReply callBack,
+ void *context
+) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/***************************************************************************/
+/* Mach port accessor and deallocation */
+
+/*!
+ @function DNSServiceDiscoveryMachPort
+ @discussion Returns the mach port for a dns_service_discovery_ref
+ @param registration A dns_service_discovery_ref as returned from DNSServiceRegistrationCreate
+ @result A mach reply port which will be sent messages as appropriate.
+ These messages should be passed to the DNSServiceDiscovery_handleReply
+ function. A NULL value indicates that no address was
+ specified or some other error occurred which prevented the
+ resolution from being started.
+ */
+mach_port_t DNSServiceDiscoveryMachPort(dns_service_discovery_ref dnsServiceDiscovery) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/*!
+ @function DNSServiceDiscoveryDeallocate
+ @discussion Deallocates the DNS Service Discovery type / closes the connection to the server
+ @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a creation or enumeration call
+ @result void
+ */
+void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/***************************************************************************/
+/* Registration updating */
+
+
+/*!
+ @function DNSServiceRegistrationAddRecord
+ @discussion Request that the mDNS Responder add the DNS Record of a specific type
+ @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call
+ @param rrtype A standard DNS Resource Record Type, from http://www.iana.org/assignments/dns-parameters
+ @param rdlen Length of the data
+ @param rdata Opaque binary Resource Record data, up to 64 kB.
+ @param ttl time to live for the added record.
+ @result DNSRecordReference An opaque reference that can be passed to the update and remove record calls. If an error occurs, this value will be zero or negative
+ */
+DNSRecordReference DNSServiceRegistrationAddRecord(dns_service_discovery_ref dnsServiceDiscovery, uint16_t rrtype, uint16_t rdlen, const char *rdata, uint32_t ttl) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/*!
+ @function DNSServiceRegistrationUpdateRecord
+ @discussion Request that the mDNS Responder add the DNS Record of a specific type
+ @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call
+ @param dnsRecordReference A dnsRecordReference as returned from a DNSServiceRegistrationAddRecord call
+ @param rdlen Length of the data
+ @param rdata Opaque binary Resource Record data, up to 64 kB.
+ @param ttl time to live for the updated record.
+ @result DNSServiceRegistrationReplyErrorType If an error occurs, this value will be non zero
+ */
+DNSServiceRegistrationReplyErrorType DNSServiceRegistrationUpdateRecord(dns_service_discovery_ref ref, DNSRecordReference reference, uint16_t rdlen, const char *rdata, uint32_t ttl) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+/*!
+ @function DNSServiceRegistrationRemoveRecord
+ @discussion Request that the mDNS Responder remove the DNS Record(s) of a specific type
+ @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call
+ @param dnsRecordReference A dnsRecordReference as returned from a DNSServiceRegistrationAddRecord call
+ @result DNSServiceRegistrationReplyErrorType If an error occurs, this value will be non zero
+ */
+DNSServiceRegistrationReplyErrorType DNSServiceRegistrationRemoveRecord(dns_service_discovery_ref ref, DNSRecordReference reference) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3;
+
+
+__END_DECLS
+
+#endif /* __DNS_SERVICE_DISCOVERY_H */
diff --git a/mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryDefines.h b/mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryDefines.h
new file mode 100644
index 00000000..cfad0a41
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryDefines.h
@@ -0,0 +1,31 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002-2003 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.
+ */
+
+#ifndef __DNS_SERVICE_DISCOVERY_DEFINES_H
+#define __DNS_SERVICE_DISCOVERY_DEFINES_H
+
+#include <mach/mach_types.h>
+
+#define DNS_SERVICE_DISCOVERY_SERVER "com.apple.mDNSResponder"
+
+typedef char DNSCString[1024];
+typedef char sockaddr_t[128];
+
+typedef const char * record_data_t;
+typedef struct { char bytes[4]; } IPPort;
+
+#endif /* __DNS_SERVICE_DISCOVERY_DEFINES_H */
diff --git a/mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryReply.defs b/mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryReply.defs
new file mode 100644
index 00000000..b918bee4
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryReply.defs
@@ -0,0 +1,60 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002 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.
+ */
+
+subsystem
+ DNSServiceDiscoveryReply 7250;
+
+ServerPrefix internal_;
+
+#include <mach/std_types.defs>
+#include <mach/mach_types.defs>
+
+import "DNSServiceDiscoveryDefines.h";
+
+type DNSCString = c_string[*:1024];
+type sockaddr_t = array[128] of char;
+
+simpleroutine DNSServiceDomainEnumerationReply_rpc(
+ reply: mach_port_t;
+ in resultType: int;
+ in replyDomain: DNSCString;
+ in flags: int;
+ SendTime to: natural_t);
+
+simpleroutine DNSServiceBrowserReply_rpc(
+ reply: mach_port_t;
+ in resultType: int;
+ in replyName: DNSCString;
+ in replyType: DNSCString;
+ in replyDomain: DNSCString;
+ in flags: int;
+ SendTime to: natural_t);
+
+
+simpleroutine DNSServiceRegistrationReply_rpc(
+ reply: mach_port_t;
+ in resultType: int;
+ SendTime to: natural_t);
+
+
+simpleroutine DNSServiceResolverReply_rpc(
+ reply: mach_port_t;
+ in interface: sockaddr_t;
+ in address: sockaddr_t;
+ in txtRecord: DNSCString;
+ in flags: int;
+ SendTime to: natural_t);
diff --git a/mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryRequest.defs b/mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryRequest.defs
new file mode 100644
index 00000000..ad06bdb5
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DNSServiceDiscoveryRequest.defs
@@ -0,0 +1,80 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002 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.
+ */
+
+subsystem
+ DNSServiceDiscoveryRequest 7200;
+
+ServerPrefix provide_;
+
+#include <mach/std_types.defs>
+#include <mach/mach_types.defs>
+
+import "DNSServiceDiscoveryDefines.h";
+
+type DNSCString = c_string[*:1024];
+type record_data = ^ array [] of MACH_MSG_TYPE_BYTE
+ ctype: record_data_t;
+type IPPort = struct[4] of char ctype:IPPort;
+
+simpleroutine DNSServiceBrowserCreate_rpc(
+ server: mach_port_t;
+ in client: mach_port_t;
+ in regtype: DNSCString;
+ in domain: DNSCString);
+
+
+simpleroutine DNSServiceDomainEnumerationCreate_rpc(
+ server: mach_port_t;
+ in client: mach_port_t;
+ in registrationDomains: int);
+
+simpleroutine DNSServiceRegistrationCreate_rpc(
+ server: mach_port_t;
+ in client: mach_port_t;
+ in name: DNSCString;
+ in regtype: DNSCString;
+ in domain: DNSCString;
+ in port: IPPort;
+ in txtRecord: DNSCString);
+
+
+simpleroutine DNSServiceResolverResolve_rpc(
+ server: mach_port_t;
+ in client: mach_port_t;
+ in name: DNSCString;
+ in regtype: DNSCString;
+ in domain: DNSCString);
+
+routine DNSServiceRegistrationAddRecord_rpc(
+ server: mach_port_t;
+ in client: mach_port_t;
+ in record_type: int;
+ in record_data: record_data;
+ in ttl: uint32_t;
+ out record_reference: natural_t);
+
+simpleroutine DNSServiceRegistrationUpdateRecord_rpc(
+ server: mach_port_t;
+ in client: mach_port_t;
+ in record_reference: natural_t;
+ in record_data: record_data;
+ in ttl: uint32_t);
+
+simpleroutine DNSServiceRegistrationRemoveRecord_rpc(
+ server: mach_port_t;
+ in client: mach_port_t;
+ in record_reference: natural_t);
diff --git a/mDNSResponder/mDNSMacOSX/LaunchDaemonInfo-Tiger.helper.plist b/mDNSResponder/mDNSMacOSX/LaunchDaemonInfo-Tiger.helper.plist
new file mode 100644
index 00000000..895287c7
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/LaunchDaemonInfo-Tiger.helper.plist
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Label</key>
+ <string>com.apple.mDNSResponderHelper</string>
+ <key>OnDemand</key>
+ <false/>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/sbin/mDNSResponderHelper</string>
+ <string>-t</string>
+ <string>0</string>
+ </array>
+ <key>ServiceIPC</key>
+ <false/>
+</dict>
+</plist>
diff --git a/mDNSResponder/mDNSMacOSX/LaunchDaemonInfo-Tiger.plist b/mDNSResponder/mDNSMacOSX/LaunchDaemonInfo-Tiger.plist
new file mode 100644
index 00000000..e91b7751
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/LaunchDaemonInfo-Tiger.plist
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Label</key>
+ <string>com.apple.mDNSResponder</string>
+ <key>OnDemand</key>
+ <false/>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/sbin/mDNSResponder</string>
+ <string>-launchdaemon</string>
+ </array>
+ <key>ServiceIPC</key>
+ <false/>
+</dict>
+</plist>
diff --git a/mDNSResponder/mDNSMacOSX/LaunchDaemonInfo.dnsextd.plist b/mDNSResponder/mDNSMacOSX/LaunchDaemonInfo.dnsextd.plist
new file mode 100644
index 00000000..e31b391f
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/LaunchDaemonInfo.dnsextd.plist
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Disabled</key>
+ <true/>
+ <key>Label</key>
+ <string>com.apple.dnsextd</string>
+ <key>OnDemand</key>
+ <false/>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/sbin/dnsextd</string>
+ <string>-launchd</string>
+ </array>
+</dict>
+</plist>
diff --git a/mDNSResponder/mDNSMacOSX/LaunchDaemonInfo.helper.plist b/mDNSResponder/mDNSMacOSX/LaunchDaemonInfo.helper.plist
new file mode 100644
index 00000000..a21868c7
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/LaunchDaemonInfo.helper.plist
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Label</key>
+ <string>com.apple.mDNSResponderHelper</string>
+ <key>OnDemand</key>
+ <true/>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/sbin/mDNSResponderHelper</string>
+ </array>
+ <key>MachServices</key>
+ <dict>
+ <key>com.apple.mDNSResponderHelper</key>
+ <true/>
+ </dict>
+ <key>EnableTransactions</key>
+ <true/>
+ <key>BeginTransactionAtShutdown</key>
+ <true/>
+ <key>POSIXSpawnType</key>
+ <string>Interactive</string>
+</dict>
+</plist>
diff --git a/mDNSResponder/mDNSMacOSX/LaunchDaemonInfo.plist b/mDNSResponder/mDNSMacOSX/LaunchDaemonInfo.plist
new file mode 100644
index 00000000..ba99d15d
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/LaunchDaemonInfo.plist
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Label</key>
+ <string>com.apple.mDNSResponder</string>
+ <key>OnDemand</key>
+ <false/>
+ <key>InitGroups</key>
+ <false/>
+ <key>UserName</key>
+ <string>_mdnsresponder</string>
+ <key>GroupName</key>
+ <string>_mdnsresponder</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/sbin/mDNSResponder</string>
+ </array>
+ <key>MachServices</key>
+ <dict>
+ <key>com.apple.mDNSResponder</key>
+ <true/>
+ <key>com.apple.mDNSResponder.dnsproxy</key>
+ <true/>
+ </dict>
+ <key>Sockets</key>
+ <dict>
+ <key>Listeners</key>
+ <dict>
+ <key>SockFamily</key>
+ <string>Unix</string>
+ <key>SockPathName</key>
+ <string>/var/run/mDNSResponder</string>
+ <key>SockPathMode</key>
+ <integer>438</integer>
+ </dict>
+ </dict>
+ <key>EnableTransactions</key>
+ <true/>
+ <key>BeginTransactionAtShutdown</key>
+ <true/>
+ <key>POSIXSpawnType</key>
+ <string>Interactive</string>
+</dict>
+</plist>
diff --git a/mDNSResponder/mDNSMacOSX/LegacyNATTraversal.c b/mDNSResponder/mDNSMacOSX/LegacyNATTraversal.c
new file mode 100644
index 00000000..e7cd65f0
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/LegacyNATTraversal.c
@@ -0,0 +1,933 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2004-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.
+ */
+
+#ifdef _LEGACY_NAT_TRAVERSAL_
+
+#include "stdlib.h" // For strtol()
+#include "string.h" // For strlcpy(), For strncpy(), strncasecmp()
+#include "assert.h" // For assert()
+
+#if defined( WIN32 )
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# define strcasecmp _stricmp
+# define strncasecmp _strnicmp
+# define mDNSASLLog( UUID, SUBDOMAIN, RESULT, SIGNATURE, FORMAT, ... ) ;
+
+static int
+inet_pton( int family, const char * addr, void * dst )
+{
+ struct sockaddr_storage ss;
+ int sslen = sizeof( ss );
+
+ ZeroMemory( &ss, sizeof( ss ) );
+ ss.ss_family = (ADDRESS_FAMILY)family;
+
+ if ( WSAStringToAddressA( (LPSTR)addr, family, NULL, ( struct sockaddr* ) &ss, &sslen ) == 0 )
+ {
+ if ( family == AF_INET ) { memcpy( dst, &( ( struct sockaddr_in* ) &ss)->sin_addr, sizeof( IN_ADDR ) ); return 1; }
+ else if ( family == AF_INET6 ) { memcpy( dst, &( ( struct sockaddr_in6* ) &ss)->sin6_addr, sizeof( IN6_ADDR ) ); return 1; }
+ else return 0;
+ }
+ else return 0;
+}
+#else
+# include <arpa/inet.h> // For inet_pton()
+#endif
+
+#include "mDNSEmbeddedAPI.h"
+#include "uDNS.h" // For natTraversalHandleAddressReply() etc.
+
+// used to format SOAP port mapping arguments
+typedef struct Property_struct
+{
+ char *name;
+ char *type;
+ char *value;
+} Property;
+
+// All of the text parsing in this file is intentionally transparent so that we know exactly
+// what's being done to the text, with an eye towards preventing security problems.
+
+// This is an evolving list of useful acronyms to know. Please add to it at will.
+// ST Service Type
+// NT Notification Type
+// USN Unique Service Name
+// UDN Unique Device Name
+// UUID Universally Unique Identifier
+// URN/urn Universal Resource Name
+
+// Forward declaration because of circular reference:
+// SendPortMapRequest -> SendSOAPMsgControlAction -> MakeTCPConnection -> tcpConnectionCallback -> handleLNTPortMappingResponse
+// In the event of a port conflict, handleLNTPortMappingResponse then increments tcpInfo->retries and calls back to SendPortMapRequest to try again
+mDNSlocal mStatus SendPortMapRequest(mDNS *m, NATTraversalInfo *n);
+
+#define RequestedPortNum(n) (mDNSVal16(mDNSIPPortIsZero((n)->RequestedPort) ? (n)->IntPort : (n)->RequestedPort) + (mDNSu16)(n)->tcpInfo.retries)
+
+// Note that this function assumes src is already NULL terminated
+mDNSlocal void AllocAndCopy(mDNSu8 **const dst, const mDNSu8 *const src)
+{
+ if (src == mDNSNULL) return;
+ if ((*dst = mDNSPlatformMemAllocate((mDNSu32)strlen((char*)src) + 1)) == mDNSNULL)
+ { LogMsg("AllocAndCopy: can't allocate string"); return; }
+ strcpy((char*)*dst, (char*)src);
+}
+
+// This function does a simple parse of an HTTP URL that may include a hostname, port, and path
+// If found in the URL, addressAndPort and path out params will point to newly allocated space (and will leak if they were previously pointing at allocated space)
+mDNSlocal mStatus ParseHttpUrl(const mDNSu8 *ptr, const mDNSu8 *const end, mDNSu8 **const addressAndPort, mDNSIPPort *const port, mDNSu8 **const path)
+{
+ // if the data begins with "http://", we assume there is a hostname and possibly a port number
+ if (end - ptr >= 7 && strncasecmp((char*)ptr, "http://", 7) == 0)
+ {
+ int i;
+ const mDNSu8 *stop = end;
+ const mDNSu8 *addrPtr = mDNSNULL;
+
+ ptr += 7; //skip over "http://"
+ if (ptr >= end) { LogInfo("ParseHttpUrl: past end of buffer parsing host:port"); return mStatus_BadParamErr; }
+
+ // find the end of the host:port
+ addrPtr = ptr;
+ for (i = 0; addrPtr && addrPtr != end; i++, addrPtr++) if (*addrPtr == '/') break;
+
+ // allocate the buffer (len i+1 so we have space to terminate the string)
+ if ((*addressAndPort = mDNSPlatformMemAllocate(i+1)) == mDNSNULL)
+ { LogMsg("ParseHttpUrl: can't allocate address string"); return mStatus_NoMemoryErr; }
+ strncpy((char*)*addressAndPort, (char*)ptr, i);
+ (*addressAndPort)[i] = '\0';
+
+ // find the port number in the string, by looking backwards for the ':'
+ stop = ptr; // can't go back farther than the original start
+ ptr = addrPtr; // move ptr to the path part
+
+ for (addrPtr--; addrPtr>stop; addrPtr--)
+ {
+ if (*addrPtr == ':')
+ {
+ addrPtr++; // skip over ':'
+ *port = mDNSOpaque16fromIntVal((mDNSu16)strtol((char*)addrPtr, mDNSNULL, 10)); // store it properly converted
+ break;
+ }
+ }
+ }
+
+ // ptr should now point to the first character we haven't yet processed
+ // everything that remains is the path
+ if (path && ptr < end)
+ {
+ if ((*path = mDNSPlatformMemAllocate((mDNSu32)(end - ptr) + 1)) == mDNSNULL)
+ { LogMsg("ParseHttpUrl: can't mDNSPlatformMemAllocate path"); return mStatus_NoMemoryErr; }
+ strncpy((char*)*path, (char*)ptr, end - ptr);
+ (*path)[end - ptr] = '\0';
+ }
+
+ return mStatus_NoError;
+}
+
+enum
+{
+ HTTPCode_NeedMoreData = -1, // No code found in stream
+ HTTPCode_Other = -2, // Valid code other than those below found in stream
+ HTTPCode_Bad = -3,
+ HTTPCode_200 = 200,
+ HTTPCode_404 = 404,
+ HTTPCode_500 = 500,
+};
+
+mDNSlocal mDNSs16 ParseHTTPResponseCode(const mDNSu8 **const data, const mDNSu8 *const end)
+{
+ const mDNSu8 *ptr = *data;
+ const mDNSu8 *code;
+
+ if (end - ptr < 5) return HTTPCode_NeedMoreData;
+ if (strncasecmp((char*)ptr, "HTTP/", 5) != 0) return HTTPCode_Bad;
+ ptr += 5;
+ // should we care about the HTTP protocol version?
+
+ // look for first space, which must come before first LF
+ while (ptr && ptr != end)
+ {
+ if (*ptr == '\n') return HTTPCode_Bad;
+ if (*ptr == ' ') break;
+ ptr++;
+ }
+ if (ptr == end) return HTTPCode_NeedMoreData;
+ ptr++;
+
+ if (end - ptr < 3) return HTTPCode_NeedMoreData;
+
+ code = ptr;
+ ptr += 3;
+ while (ptr && ptr != end)
+ {
+ if (*ptr == '\n') break;
+ ptr++;
+ }
+ if (ptr == end) return HTTPCode_NeedMoreData;
+ *data = ++ptr;
+
+ if (memcmp((char*)code, "200", 3) == 0) return HTTPCode_200;
+ if (memcmp((char*)code, "404", 3) == 0) return HTTPCode_404;
+ if (memcmp((char*)code, "500", 3) == 0) return HTTPCode_500;
+
+ LogInfo("ParseHTTPResponseCode found unexpected result code: %c%c%c", code[0], code[1], code[2]);
+ return HTTPCode_Other;
+}
+
+// This function parses the xml body of the device description response from the router. Basically, we look to
+// make sure this is a response referencing a service we care about (WANIPConnection or WANPPPConnection),
+// look for the "controlURL" header immediately following, and copy the addressing and URL info we need
+mDNSlocal void handleLNTDeviceDescriptionResponse(tcpLNTInfo *tcpInfo)
+{
+ mDNS *m = tcpInfo->m;
+ const mDNSu8 *ptr = tcpInfo->Reply;
+ const mDNSu8 *end = tcpInfo->Reply + tcpInfo->nread;
+ const mDNSu8 *stop;
+ mDNSs16 http_result;
+
+ if (!mDNSIPPortIsZero(m->UPnPSOAPPort)) return; // already have the info we need
+
+ http_result = ParseHTTPResponseCode(&ptr, end); // Note: modifies ptr
+ if (http_result == HTTPCode_404) LNT_ClearState(m);
+ if (http_result != HTTPCode_200)
+ {
+ mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "noop", "HTTP Result", "HTTP code: %d", http_result);
+ return;
+ }
+
+ // Always reset our flag to use WANIPConnection. We'll use WANPPPConnection if we find it and don't find WANIPConnection.
+ m->UPnPWANPPPConnection = mDNSfalse;
+
+ // find either service we care about
+ while (ptr && ptr < end)
+ {
+ if ((*ptr & 0xDF) == 'W' && (strncasecmp((char*)ptr, "WANIPConnection:1", 17) == 0)) break;
+ ptr++;
+ }
+ if (ptr == end)
+ {
+ ptr = tcpInfo->Reply;
+ while (ptr && ptr < end)
+ {
+ if ((*ptr & 0xDF) == 'W' && (strncasecmp((char*)ptr, "WANPPPConnection:1", 18) == 0))
+ {
+ m->UPnPWANPPPConnection = mDNStrue;
+ break;
+ }
+ ptr++;
+ }
+ }
+ if (ptr == mDNSNULL || ptr == end) { LogInfo("handleLNTDeviceDescriptionResponse: didn't find WANIPConnection:1 or WANPPPConnection:1 string"); return; }
+
+ // find "controlURL", starting from where we left off
+ while (ptr && ptr < end)
+ {
+ if ((*ptr & 0xDF) == 'C' && (strncasecmp((char*)ptr, "controlURL", 10) == 0)) break; // find the first 'c'; is this controlURL? if not, keep looking
+ ptr++;
+ }
+ if (ptr == mDNSNULL || ptr == end) { LogInfo("handleLNTDeviceDescriptionResponse: didn't find controlURL string"); return; }
+ ptr += 11; // skip over "controlURL>"
+ if (ptr >= end) { LogInfo("handleLNTDeviceDescriptionResponse: past end of buffer and no body!"); return; } // check ptr again in case we skipped over the end of the buffer
+
+ // find the end of the controlURL element
+ for (stop = ptr; stop < end; stop++) { if (*stop == '<') { end = stop; break; } }
+
+ // fill in default port
+ m->UPnPSOAPPort = m->UPnPRouterPort;
+
+ // free string pointers and set to NULL
+ if (m->UPnPSOAPAddressString != mDNSNULL)
+ {
+ mDNSPlatformMemFree(m->UPnPSOAPAddressString);
+ m->UPnPSOAPAddressString = mDNSNULL;
+ }
+ if (m->UPnPSOAPURL != mDNSNULL)
+ {
+ mDNSPlatformMemFree(m->UPnPSOAPURL);
+ m->UPnPSOAPURL = mDNSNULL;
+ }
+
+ if (ParseHttpUrl(ptr, end, &m->UPnPSOAPAddressString, &m->UPnPSOAPPort, &m->UPnPSOAPURL) != mStatus_NoError) return;
+ // the SOAPURL should look something like "/uuid:0013-108c-4b3f0000f3dc"
+
+ if (m->UPnPSOAPAddressString == mDNSNULL)
+ {
+ ptr = tcpInfo->Reply;
+ while (ptr && ptr < end)
+ {
+ if ((*ptr & 0xDF) == 'U' && (strncasecmp((char*)ptr, "URLBase", 7) == 0)) break;
+ ptr++;
+ }
+
+ if (ptr < end) // found URLBase
+ {
+ LogInfo("handleLNTDeviceDescriptionResponse: found URLBase");
+ ptr += 8; // skip over "URLBase>"
+ // find the end of the URLBase element
+ for (stop = ptr; stop < end; stop++) { if (*stop == '<') { end = stop; break; } }
+ if (ParseHttpUrl(ptr, end, &m->UPnPSOAPAddressString, &m->UPnPSOAPPort, mDNSNULL) != mStatus_NoError)
+ {
+ LogInfo("handleLNTDeviceDescriptionResponse: failed to parse URLBase");
+ }
+ }
+
+ // if all else fails, use the router address string
+ if (m->UPnPSOAPAddressString == mDNSNULL) AllocAndCopy(&m->UPnPSOAPAddressString, m->UPnPRouterAddressString);
+ }
+ if (m->UPnPSOAPAddressString == mDNSNULL) LogMsg("handleLNTDeviceDescriptionResponse: UPnPSOAPAddressString is NULL");
+ else LogInfo("handleLNTDeviceDescriptionResponse: SOAP address string [%s]", m->UPnPSOAPAddressString);
+
+ if (m->UPnPSOAPURL == mDNSNULL) AllocAndCopy(&m->UPnPSOAPURL, m->UPnPRouterURL);
+ if (m->UPnPSOAPURL == mDNSNULL) LogMsg("handleLNTDeviceDescriptionResponse: UPnPSOAPURL is NULL");
+ else LogInfo("handleLNTDeviceDescriptionResponse: SOAP URL [%s]", m->UPnPSOAPURL);
+}
+
+mDNSlocal void handleLNTGetExternalAddressResponse(tcpLNTInfo *tcpInfo)
+{
+ mDNS *m = tcpInfo->m;
+ mDNSu16 err = NATErr_None;
+ mDNSv4Addr ExtAddr;
+ const mDNSu8 *ptr = tcpInfo->Reply;
+ const mDNSu8 *end = tcpInfo->Reply + tcpInfo->nread;
+ mDNSu8 *addrend;
+ static char tagname[20] = { 'N','e','w','E','x','t','e','r','n','a','l','I','P','A','d','d','r','e','s','s' };
+ // Array NOT including a terminating nul
+
+// LogInfo("handleLNTGetExternalAddressResponse: %s", ptr);
+
+ mDNSs16 http_result = ParseHTTPResponseCode(&ptr, end); // Note: modifies ptr
+ if (http_result == HTTPCode_404) LNT_ClearState(m);
+ if (http_result != HTTPCode_200)
+ {
+ mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.AddressRequest", "noop", "HTTP Result", "HTTP code: %d", http_result);
+ return;
+ }
+
+ while (ptr < end && strncasecmp((char*)ptr, tagname, sizeof(tagname))) ptr++;
+ ptr += sizeof(tagname); // Skip over "NewExternalIPAddress"
+ while (ptr < end && *ptr != '>') ptr++;
+ ptr += 1; // Skip over ">"
+
+ // Find the end of the address and terminate the string so inet_pton() can convert it
+ // (Might be better to copy this to a local string here -- this is overwriting tcpInfo->Reply in-place
+ addrend = (mDNSu8*)ptr;
+ while (addrend < end && (mDNSIsDigit(*addrend) || *addrend == '.')) addrend++;
+ if (addrend >= end) return;
+ *addrend = 0;
+
+ if (inet_pton(AF_INET, (char*)ptr, &ExtAddr) <= 0)
+ {
+ mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.AddressRequest", "noop", "inet_pton", "");
+ LogMsg("handleLNTGetExternalAddressResponse: Router returned bad address %s", ptr);
+ err = NATErr_NetFail;
+ ExtAddr = zerov4Addr;
+ }
+ if (!err) LogInfo("handleLNTGetExternalAddressResponse: External IP address is %.4a", &ExtAddr);
+
+ natTraversalHandleAddressReply(m, err, ExtAddr);
+}
+
+mDNSlocal void handleLNTPortMappingResponse(tcpLNTInfo *tcpInfo)
+{
+ mDNS *m = tcpInfo->m;
+ mDNSIPPort extport = zeroIPPort;
+ const mDNSu8 *ptr = tcpInfo->Reply;
+ const mDNSu8 *const end = tcpInfo->Reply + tcpInfo->nread;
+ NATTraversalInfo *natInfo;
+ mDNSs16 http_result;
+
+ for (natInfo = m->NATTraversals; natInfo; natInfo=natInfo->next) { if (natInfo == tcpInfo->parentNATInfo) break;}
+
+ if (!natInfo) { LogInfo("handleLNTPortMappingResponse: can't find matching tcpInfo in NATTraversals!"); return; }
+
+ http_result = ParseHTTPResponseCode(&ptr, end); // Note: modifies ptr
+ if (http_result == HTTPCode_200)
+ {
+ LogInfo("handleLNTPortMappingResponse: got a valid response, sending reply to natTraversalHandlePortMapReply(internal %d external %d retries %d)",
+ mDNSVal16(natInfo->IntPort), RequestedPortNum(natInfo), tcpInfo->retries);
+
+ // Make sure to compute extport *before* we zero tcpInfo->retries
+ extport = mDNSOpaque16fromIntVal(RequestedPortNum(natInfo));
+ tcpInfo->retries = 0;
+ natTraversalHandlePortMapReply(m, natInfo, m->UPnPInterfaceID, mStatus_NoError, extport, NATMAP_DEFAULT_LEASE, NATTProtocolUPNPIGD);
+ }
+ else if (http_result == HTTPCode_500)
+ {
+ while (ptr && ptr != end)
+ {
+ if (((*ptr & 0xDF) == 'C' && end - ptr >= 8 && strncasecmp((char*)ptr, "Conflict", 8) == 0) ||
+ (*ptr == '>' && end - ptr >= 15 && strncasecmp((char*)ptr, ">718</errorCode", 15) == 0))
+ {
+ if (tcpInfo->retries < 100)
+ {
+ tcpInfo->retries++; SendPortMapRequest(tcpInfo->m, natInfo);
+ mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", "noop", "Conflict", "Retry %d", tcpInfo->retries);
+ }
+ else
+ {
+ LogMsg("handleLNTPortMappingResponse too many conflict retries %d %d", mDNSVal16(natInfo->IntPort), mDNSVal16(natInfo->RequestedPort));
+ mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", "noop", "Conflict - too many retries", "Retries: %d", tcpInfo->retries);
+ natTraversalHandlePortMapReply(m, natInfo, m->UPnPInterfaceID, NATErr_Res, zeroIPPort, 0, NATTProtocolUPNPIGD);
+ }
+ return;
+ }
+ ptr++;
+ }
+ }
+ else if (http_result == HTTPCode_Bad) LogMsg("handleLNTPortMappingResponse got data that was not a valid HTTP response");
+ else if (http_result == HTTPCode_Other) LogMsg("handleLNTPortMappingResponse got unexpected response code");
+ else if (http_result == HTTPCode_404) LNT_ClearState(m);
+ if (http_result != HTTPCode_200 && http_result != HTTPCode_500)
+ mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", "noop", "HTTP Result", "HTTP code: %d", http_result);
+}
+
+mDNSlocal void DisposeInfoFromUnmapList(mDNS *m, tcpLNTInfo *tcpInfo)
+{
+ tcpLNTInfo **ptr = &m->tcpInfoUnmapList;
+ while (*ptr && *ptr != tcpInfo) ptr = &(*ptr)->next;
+ if (*ptr) { *ptr = (*ptr)->next; mDNSPlatformMemFree(tcpInfo); } // If we found it, cut it from our list and free the memory
+}
+
+mDNSlocal void tcpConnectionCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEstablished, mStatus err)
+{
+ mStatus status = mStatus_NoError;
+ tcpLNTInfo *tcpInfo = (tcpLNTInfo *)context;
+ mDNSBool closed = mDNSfalse;
+ long n = 0;
+ long nsent = 0;
+ static int LNTERRORcount = 0;
+
+ if (tcpInfo == mDNSNULL) { LogInfo("tcpConnectionCallback: no tcpInfo context"); status = mStatus_Invalid; goto exit; }
+
+ if (tcpInfo->sock != sock)
+ {
+ LogMsg("tcpConnectionCallback: WARNING- tcpInfo->sock(%p) != sock(%p) !!! Printing tcpInfo struct", tcpInfo->sock, sock);
+ LogMsg("tcpConnectionCallback: tcpInfo->Address:Port [%#a:%d] tcpInfo->op[%d] tcpInfo->retries[%d] tcpInfo->Request[%s] tcpInfo->Reply[%s]",
+ &tcpInfo->Address, mDNSVal16(tcpInfo->Port), tcpInfo->op, tcpInfo->retries, tcpInfo->Request, tcpInfo->Reply);
+ }
+
+ // The handlers below expect to be called with the lock held
+ mDNS_Lock(tcpInfo->m);
+
+ if (err) { LogInfo("tcpConnectionCallback: received error"); goto exit; }
+
+ if (ConnectionEstablished) // connection is established - send the message
+ {
+ LogInfo("tcpConnectionCallback: connection established, sending message");
+ nsent = mDNSPlatformWriteTCP(sock, (char*)tcpInfo->Request, tcpInfo->requestLen);
+ if (nsent != (long)tcpInfo->requestLen) { LogMsg("tcpConnectionCallback: error writing"); status = mStatus_UnknownErr; goto exit; }
+ }
+ else
+ {
+ n = mDNSPlatformReadTCP(sock, (char*)tcpInfo->Reply + tcpInfo->nread, tcpInfo->replyLen - tcpInfo->nread, &closed);
+ LogInfo("tcpConnectionCallback: mDNSPlatformReadTCP read %d bytes", n);
+
+ if (n < 0) { LogInfo("tcpConnectionCallback - read returned %d", n); status = mStatus_ConnFailed; goto exit; }
+ else if (closed) { LogInfo("tcpConnectionCallback: socket closed by remote end %d", tcpInfo->nread); status = mStatus_ConnFailed; goto exit; }
+
+ tcpInfo->nread += n;
+ LogInfo("tcpConnectionCallback tcpInfo->nread %d", tcpInfo->nread);
+ if (tcpInfo->nread > LNT_MAXBUFSIZE)
+ {
+ LogInfo("result truncated...");
+ tcpInfo->nread = LNT_MAXBUFSIZE;
+ }
+
+ switch (tcpInfo->op)
+ {
+ case LNTDiscoveryOp: handleLNTDeviceDescriptionResponse (tcpInfo); break;
+ case LNTExternalAddrOp: handleLNTGetExternalAddressResponse(tcpInfo); break;
+ case LNTPortMapOp: handleLNTPortMappingResponse (tcpInfo); break;
+ case LNTPortMapDeleteOp: status = mStatus_ConfigChanged; break;
+ default: LogMsg("tcpConnectionCallback: bad tcp operation! %d", tcpInfo->op); status = mStatus_Invalid; break;
+ }
+ }
+exit:
+ if (err || status)
+ {
+ mDNS *m = tcpInfo->m;
+ if ((++LNTERRORcount % 1000) == 0)
+ {
+ LogMsg("ERROR: tcpconnectioncallback -> got error status %d times", LNTERRORcount);
+ assert(LNTERRORcount < 1000);
+ // Recovery Mechanism to bail mDNSResponder out of trouble: It has been seen that we can get into
+ // this loop: [tcpKQSocketCallback()--> doTcpSocketCallback()-->tcpconnectionCallback()-->mDNSASLLog()],
+ // if mDNSPlatformTCPCloseConnection() does not close the TCPSocket. Instead of calling mDNSASLLog()
+ // repeatedly and logging the same error msg causing 100% CPU usage, we
+ // 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
+ }
+
+ switch (tcpInfo->op)
+ {
+ case LNTDiscoveryOp: if (m->UPnPSOAPAddressString == mDNSNULL)
+ mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "failure", "SOAP Address", "");
+ if (m->UPnPSOAPURL == mDNSNULL)
+ mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "failure", "SOAP path", "");
+ if (m->UPnPSOAPAddressString && m->UPnPSOAPURL)
+ mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "success", "success", "");
+ break;
+ case LNTExternalAddrOp: mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.AddressRequest",
+ mDNSIPv4AddressIsZero(m->ExtAddress) ? "failure" : "success",
+ mDNSIPv4AddressIsZero(m->ExtAddress) ? "failure" : "success", "");
+ break;
+ case LNTPortMapOp: if (tcpInfo->parentNATInfo)
+ mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", (tcpInfo->parentNATInfo->Result) ? "failure" : "success",
+ (tcpInfo->parentNATInfo->Result) ? "failure" : "success", "Result: %d", tcpInfo->parentNATInfo->Result);
+ break;
+ case LNTPortMapDeleteOp: break;
+ default: break;
+ }
+
+ mDNSPlatformTCPCloseConnection(sock);
+ tcpInfo->sock = mDNSNULL;
+ if (tcpInfo->Request) { mDNSPlatformMemFree(tcpInfo->Request); tcpInfo->Request = mDNSNULL; }
+ if (tcpInfo->Reply ) { mDNSPlatformMemFree(tcpInfo->Reply); tcpInfo->Reply = mDNSNULL; }
+ }
+ else
+ {
+ LNTERRORcount = 0; // clear LNTERRORcount
+ }
+
+ if (tcpInfo) mDNS_Unlock(tcpInfo->m);
+
+ if (status == mStatus_ConfigChanged) DisposeInfoFromUnmapList(tcpInfo->m, tcpInfo);
+}
+
+mDNSlocal mStatus MakeTCPConnection(mDNS *const m, tcpLNTInfo *info, const mDNSAddr *const Addr, const mDNSIPPort Port, LNTOp_t op)
+{
+ mStatus err = mStatus_NoError;
+ mDNSIPPort srcport = zeroIPPort;
+
+ if (mDNSIPv4AddressIsZero(Addr->ip.v4) || mDNSIPPortIsZero(Port))
+ { LogMsg("LNT MakeTCPConnection: bad address/port %#a:%d", Addr, mDNSVal16(Port)); return(mStatus_Invalid); }
+ info->m = m;
+ info->Address = *Addr;
+ info->Port = Port;
+ info->op = op;
+ info->nread = 0;
+ info->replyLen = LNT_MAXBUFSIZE;
+ if (info->Reply != mDNSNULL) mDNSPlatformMemZero(info->Reply, LNT_MAXBUFSIZE); // reuse previously allocated buffer
+ else if ((info->Reply = mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogInfo("can't allocate reply buffer"); return (mStatus_NoMemoryErr); }
+
+ if (info->sock) { LogInfo("MakeTCPConnection: closing previous open connection"); mDNSPlatformTCPCloseConnection(info->sock); info->sock = mDNSNULL; }
+ info->sock = mDNSPlatformTCPSocket(m, kTCPSocketFlags_Zero, &srcport, mDNSfalse);
+ if (!info->sock) { LogMsg("LNT MakeTCPConnection: unable to create TCP socket"); mDNSPlatformMemFree(info->Reply); info->Reply = mDNSNULL; return(mStatus_NoMemoryErr); }
+ LogInfo("MakeTCPConnection: connecting to %#a:%d", &info->Address, mDNSVal16(info->Port));
+ err = mDNSPlatformTCPConnect(info->sock, Addr, Port, mDNSNULL, 0, tcpConnectionCallback, info);
+
+ if (err == mStatus_ConnPending) err = mStatus_NoError;
+ else if (err == mStatus_ConnEstablished)
+ {
+ mDNS_DropLockBeforeCallback();
+ tcpConnectionCallback(info->sock, info, mDNStrue, mStatus_NoError);
+ mDNS_ReclaimLockAfterCallback();
+ err = mStatus_NoError;
+ }
+ else
+ {
+ // Don't need to log this in customer builds -- it happens quite often during sleep, wake, configuration changes, etc.
+ LogInfo("LNT MakeTCPConnection: connection failed");
+ mDNSPlatformTCPCloseConnection(info->sock); // Dispose the socket we created with mDNSPlatformTCPSocket() above
+ info->sock = mDNSNULL;
+ mDNSPlatformMemFree(info->Reply);
+ info->Reply = mDNSNULL;
+ }
+ return(err);
+}
+
+mDNSlocal unsigned int AddSOAPArguments(char *const buf, const unsigned int maxlen, const int numArgs, const Property *const a)
+{
+ static const char f1[] = "<%s>%s</%s>";
+ static const char f2[] = "<%s xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"%s\">%s</%s>";
+ int i, len = 0;
+ *buf = 0;
+ for (i = 0; i < numArgs; i++)
+ {
+ if (a[i].type) len += mDNS_snprintf(buf + len, maxlen - len, f2, a[i].name, a[i].type, a[i].value, a[i].name);
+ else len += mDNS_snprintf(buf + len, maxlen - len, f1, a[i].name, a[i].value, a[i].name);
+ }
+ return(len);
+}
+
+mDNSlocal mStatus SendSOAPMsgControlAction(mDNS *m, tcpLNTInfo *info, const char *const Action, const int numArgs, const Property *const Arguments, const LNTOp_t op)
+{
+ // SOAP message header format -
+ // - control URL
+ // - action (string)
+ // - router's host/port ("host:port")
+ // - content-length
+ static const char header[] =
+ "POST %s HTTP/1.1\r\n"
+ "Content-Type: text/xml; charset=\"utf-8\"\r\n"
+ "SOAPAction: \"urn:schemas-upnp-org:service:WAN%sConnection:1#%s\"\r\n"
+ "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)\r\n"
+ "Host: %s\r\n"
+ "Content-Length: %d\r\n"
+ "Connection: close\r\n"
+ "Pragma: no-cache\r\n"
+ "\r\n"
+ "%s\r\n";
+
+ static const char body1[] =
+ "<?xml version=\"1.0\"?>\r\n"
+ "<SOAP-ENV:Envelope"
+ " xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\""
+ " SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
+ "<SOAP-ENV:Body>"
+ "<m:%s xmlns:m=\"urn:schemas-upnp-org:service:WAN%sConnection:1\">";
+
+ static const char body2[] =
+ "</m:%s>"
+ "</SOAP-ENV:Body>"
+ "</SOAP-ENV:Envelope>\r\n";
+
+ mStatus err;
+ char *body = (char*)&m->omsg; // Typically requires 1110-1122 bytes; m->omsg is 8952 bytes, which is plenty
+ int bodyLen;
+
+ if (mDNSIPPortIsZero(m->UPnPSOAPPort) || m->UPnPSOAPURL == mDNSNULL || m->UPnPSOAPAddressString == mDNSNULL) // if no SOAP URL or address exists get out here
+ { LogInfo("SendSOAPMsgControlAction: no SOAP port, URL or address string"); return mStatus_Invalid; }
+
+ // Create body
+ bodyLen = mDNS_snprintf (body, sizeof(m->omsg), body1, Action, m->UPnPWANPPPConnection ? "PPP" : "IP");
+ bodyLen += AddSOAPArguments(body + bodyLen, sizeof(m->omsg) - bodyLen, numArgs, Arguments);
+ bodyLen += mDNS_snprintf (body + bodyLen, sizeof(m->omsg) - bodyLen, body2, Action);
+
+ // Create info->Request; the header needs to contain the bodyLen in the "Content-Length" field
+ if (!info->Request) info->Request = mDNSPlatformMemAllocate(LNT_MAXBUFSIZE);
+ if (!info->Request) { LogMsg("SendSOAPMsgControlAction: Can't allocate info->Request"); return mStatus_NoMemoryErr; }
+ info->requestLen = mDNS_snprintf((char*)info->Request, LNT_MAXBUFSIZE, header, m->UPnPSOAPURL, m->UPnPWANPPPConnection ? "PPP" : "IP", Action, m->UPnPSOAPAddressString, bodyLen, body);
+
+ err = MakeTCPConnection(m, info, &m->Router, m->UPnPSOAPPort, op);
+ if (err) { mDNSPlatformMemFree(info->Request); info->Request = mDNSNULL; }
+ return err;
+}
+
+// Build port mapping request with new port (up to max) and send it
+mDNSlocal mStatus SendPortMapRequest(mDNS *m, NATTraversalInfo *n)
+{
+ char externalPort[6];
+ char internalPort[6];
+ char localIPAddrString[30];
+ char publicPortString[40];
+ Property propArgs[8];
+ mDNSu16 ReqPortNum = RequestedPortNum(n);
+ NATTraversalInfo *n2 = m->NATTraversals;
+
+ // Scan our m->NATTraversals list to make sure the external port we're requesting is locally unique.
+ // UPnP gateways will report conflicts if different devices request the same external port, but if two
+ // clients on the same device request the same external port the second one just stomps over the first.
+ // One way this can happen is like this:
+ // 1. Client A binds local port 80
+ // 2. Client A requests external port 80 -> internal port 80
+ // 3. UPnP NAT gateway refuses external port 80 (some other client already has it)
+ // 4. Client A tries again, and successfully gets external port 80 -> internal port 81
+ // 5. Client B on same machine tries to bind local port 80, and fails
+ // 6. Client B tries again, and successfully binds local port 81
+ // 7. Client B now requests external port 81 -> internal port 81
+ // 8. UPnP NAT gateway allows this, stomping over Client A's existing mapping
+
+ while (n2)
+ {
+ if (n2 == n || RequestedPortNum(n2) != ReqPortNum) n2=n2->next;
+ else
+ {
+ if (n->tcpInfo.retries < 100)
+ {
+ n->tcpInfo.retries++;
+ ReqPortNum = RequestedPortNum(n); // Pick a new port number
+ n2 = m->NATTraversals; // And re-scan the list looking for conflicts
+ }
+ else
+ {
+ natTraversalHandlePortMapReply(m, n, m->UPnPInterfaceID, NATErr_Res, zeroIPPort, 0, NATTProtocolUPNPIGD);
+ return mStatus_NoError;
+ }
+ }
+ }
+
+ // create strings to use in the message
+ mDNS_snprintf(externalPort, sizeof(externalPort), "%u", ReqPortNum);
+ mDNS_snprintf(internalPort, sizeof(internalPort), "%u", mDNSVal16(n->IntPort));
+ mDNS_snprintf(publicPortString, sizeof(publicPortString), "iC%u", ReqPortNum);
+ mDNS_snprintf(localIPAddrString, sizeof(localIPAddrString), "%u.%u.%u.%u",
+ m->AdvertisedV4.ip.v4.b[0], m->AdvertisedV4.ip.v4.b[1], m->AdvertisedV4.ip.v4.b[2], m->AdvertisedV4.ip.v4.b[3]);
+
+ // build the message
+ mDNSPlatformMemZero(propArgs, sizeof(propArgs));
+ propArgs[0].name = "NewRemoteHost";
+ propArgs[0].type = "string";
+ propArgs[0].value = "";
+ propArgs[1].name = "NewExternalPort";
+ propArgs[1].type = "ui2";
+ propArgs[1].value = externalPort;
+ propArgs[2].name = "NewProtocol";
+ propArgs[2].type = "string";
+ propArgs[2].value = (n->Protocol == NATOp_MapUDP) ? "UDP" : "TCP";
+ propArgs[3].name = "NewInternalPort";
+ propArgs[3].type = "ui2";
+ propArgs[3].value = internalPort;
+ propArgs[4].name = "NewInternalClient";
+ propArgs[4].type = "string";
+ propArgs[4].value = localIPAddrString;
+ propArgs[5].name = "NewEnabled";
+ propArgs[5].type = "boolean";
+ propArgs[5].value = "1";
+ propArgs[6].name = "NewPortMappingDescription";
+ propArgs[6].type = "string";
+ propArgs[6].value = publicPortString;
+ propArgs[7].name = "NewLeaseDuration";
+ propArgs[7].type = "ui4";
+ propArgs[7].value = "0";
+
+ LogInfo("SendPortMapRequest: internal %u external %u", mDNSVal16(n->IntPort), ReqPortNum);
+ return SendSOAPMsgControlAction(m, &n->tcpInfo, "AddPortMapping", 8, propArgs, LNTPortMapOp);
+}
+
+mDNSexport mStatus LNT_MapPort(mDNS *m, NATTraversalInfo *const n)
+{
+ LogInfo("LNT_MapPort");
+ if (n->tcpInfo.sock) return(mStatus_NoError); // If we already have a connection up don't make another request for the same thing
+ n->tcpInfo.parentNATInfo = n;
+ n->tcpInfo.retries = 0;
+ return SendPortMapRequest(m, n);
+}
+
+mDNSexport mStatus LNT_UnmapPort(mDNS *m, NATTraversalInfo *const n)
+{
+ char externalPort[10];
+ Property propArgs[3];
+ tcpLNTInfo *info;
+ tcpLNTInfo **infoPtr = &m->tcpInfoUnmapList;
+ mStatus err;
+
+ // If no NAT gateway to talk to, no need to do all this work for nothing
+ if (mDNSIPPortIsZero(m->UPnPSOAPPort) || !m->UPnPSOAPURL || !m->UPnPSOAPAddressString) return mStatus_NoError;
+
+ mDNS_snprintf(externalPort, sizeof(externalPort), "%u", mDNSVal16(mDNSIPPortIsZero(n->RequestedPort) ? n->IntPort : n->RequestedPort));
+
+ mDNSPlatformMemZero(propArgs, sizeof(propArgs));
+ propArgs[0].name = "NewRemoteHost";
+ propArgs[0].type = "string";
+ propArgs[0].value = "";
+ propArgs[1].name = "NewExternalPort";
+ propArgs[1].type = "ui2";
+ propArgs[1].value = externalPort;
+ propArgs[2].name = "NewProtocol";
+ propArgs[2].type = "string";
+ propArgs[2].value = (n->Protocol == NATOp_MapUDP) ? "UDP" : "TCP";
+
+ n->tcpInfo.parentNATInfo = n;
+
+ // clean up previous port mapping requests and allocations
+ if (n->tcpInfo.sock) LogInfo("LNT_UnmapPort: closing previous open connection");
+ if (n->tcpInfo.sock ) { mDNSPlatformTCPCloseConnection(n->tcpInfo.sock); n->tcpInfo.sock = mDNSNULL; }
+ if (n->tcpInfo.Request) { mDNSPlatformMemFree(n->tcpInfo.Request); n->tcpInfo.Request = mDNSNULL; }
+ if (n->tcpInfo.Reply ) { mDNSPlatformMemFree(n->tcpInfo.Reply); n->tcpInfo.Reply = mDNSNULL; }
+
+ // make a copy of the tcpInfo that we can clean up later (the one passed in will be destroyed by the client as soon as this returns)
+ if ((info = mDNSPlatformMemAllocate(sizeof(tcpLNTInfo))) == mDNSNULL)
+ { LogInfo("LNT_UnmapPort: can't allocate tcpInfo"); return(mStatus_NoMemoryErr); }
+ *info = n->tcpInfo;
+
+ while (*infoPtr) infoPtr = &(*infoPtr)->next; // find the end of the list
+ *infoPtr = info; // append
+
+ err = SendSOAPMsgControlAction(m, info, "DeletePortMapping", 3, propArgs, LNTPortMapDeleteOp);
+ if (err) DisposeInfoFromUnmapList(m, info);
+ return err;
+}
+
+mDNSexport mStatus LNT_GetExternalAddress(mDNS *m)
+{
+ return SendSOAPMsgControlAction(m, &m->tcpAddrInfo, "GetExternalIPAddress", 0, mDNSNULL, LNTExternalAddrOp);
+}
+
+mDNSlocal mStatus GetDeviceDescription(mDNS *m, tcpLNTInfo *info)
+{
+ // Device description format -
+ // - device description URL
+ // - host/port
+ static const char szSSDPMsgDescribeDeviceFMT[] =
+ "GET %s HTTP/1.1\r\n"
+ "Accept: text/xml, application/xml\r\n"
+ "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n"
+ "Host: %s\r\n"
+ "Connection: close\r\n"
+ "\r\n";
+
+ if (!mDNSIPPortIsZero(m->UPnPSOAPPort)) return mStatus_NoError; // already have the info we need
+
+ if (m->UPnPRouterURL == mDNSNULL || m->UPnPRouterAddressString == mDNSNULL) { LogInfo("GetDeviceDescription: no router URL or address string!"); return (mStatus_Invalid); }
+
+ // build message
+ if (info->Request != mDNSNULL) mDNSPlatformMemZero(info->Request, LNT_MAXBUFSIZE); // reuse previously allocated buffer
+ else if ((info->Request = mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogInfo("can't allocate send buffer for discovery"); return (mStatus_NoMemoryErr); }
+ info->requestLen = mDNS_snprintf((char*)info->Request, LNT_MAXBUFSIZE, szSSDPMsgDescribeDeviceFMT, m->UPnPRouterURL, m->UPnPRouterAddressString);
+ LogInfo("Describe Device: [%s]", info->Request);
+ return MakeTCPConnection(m, info, &m->Router, m->UPnPRouterPort, LNTDiscoveryOp);
+}
+
+// This function parses the response to our SSDP discovery message. Basically, we look to make sure this is a response
+// referencing a service we care about (WANIPConnection or WANPPPConnection), then look for the "Location:" header and copy the addressing and
+// URL info we need.
+mDNSexport void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID InterfaceID, const mDNSu8 *const data, const mDNSu16 len)
+{
+ const mDNSu8 *ptr = data;
+ const mDNSu8 *end = data + len;
+ const mDNSu8 *stop = ptr;
+
+ if (!mDNSIPPortIsZero(m->UPnPRouterPort)) return; // already have the info we need
+
+ // The formatting of the HTTP header is not always the same when it comes to the placement of
+ // the service and location strings, so we just look for each of them from the beginning for every response
+
+ // figure out if this is a message from a service we care about
+ while (ptr && ptr != end)
+ {
+ if ((*ptr & 0xDF) == 'W' && (strncasecmp((char*)ptr, "WANIPConnection:1", 17) == 0)) break;
+ ptr++;
+ }
+ if (ptr == end)
+ {
+ ptr = data;
+ while (ptr && ptr != end)
+ {
+ if ((*ptr & 0xDF) == 'W' && (strncasecmp((char*)ptr, "WANPPPConnection:1", 18) == 0)) break;
+ ptr++;
+ }
+ }
+ if (ptr == mDNSNULL || ptr == end) return; // not a message we care about
+
+ // find "Location:", starting from the beginning
+ ptr = data;
+ while (ptr && ptr != end)
+ {
+ if ((*ptr & 0xDF) == 'L' && (strncasecmp((char*)ptr, "Location:", 9) == 0)) break; // find the first 'L'; is this Location? if not, keep looking
+ ptr++;
+ }
+ if (ptr == mDNSNULL || ptr == end)
+ {
+ mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Location", "");
+ return; // not a message we care about
+ }
+ ptr += 9; //Skip over 'Location:'
+ while (*ptr == ' ' && ptr < end) ptr++; // skip over spaces
+ if (ptr >= end) return;
+
+ // find the end of the line
+ for (stop = ptr; stop != end; stop++) { if (*stop == '\r') { end = stop; break; } }
+
+ // fill in default port
+ m->UPnPRouterPort = mDNSOpaque16fromIntVal(80);
+
+ // free string pointers and set to NULL
+ if (m->UPnPRouterAddressString != mDNSNULL)
+ {
+ mDNSPlatformMemFree(m->UPnPRouterAddressString);
+ m->UPnPRouterAddressString = mDNSNULL;
+ }
+ if (m->UPnPRouterURL != mDNSNULL)
+ {
+ mDNSPlatformMemFree(m->UPnPRouterURL);
+ m->UPnPRouterURL = mDNSNULL;
+ }
+
+ // the Router URL should look something like "/dyndev/uuid:0013-108c-4b3f0000f3dc"
+ if (ParseHttpUrl(ptr, end, &m->UPnPRouterAddressString, &m->UPnPRouterPort, &m->UPnPRouterURL) != mStatus_NoError)
+ {
+ mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Parse URL", "");
+ return;
+ }
+
+ m->UPnPInterfaceID = InterfaceID;
+
+ if (m->UPnPRouterAddressString == mDNSNULL)
+ {
+ mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Router address", "");
+ LogMsg("LNT_ConfigureRouterInfo: UPnPRouterAddressString is NULL");
+ }
+ else LogInfo("LNT_ConfigureRouterInfo: Router address string [%s]", m->UPnPRouterAddressString);
+
+ if (m->UPnPRouterURL == mDNSNULL)
+ {
+ mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Router path", "");
+ LogMsg("LNT_ConfigureRouterInfo: UPnPRouterURL is NULL");
+ }
+ else LogInfo("LNT_ConfigureRouterInfo: Router URL [%s]", m->UPnPRouterURL);
+
+ LogInfo("LNT_ConfigureRouterInfo: Router port %d", mDNSVal16(m->UPnPRouterPort));
+ LogInfo("LNT_ConfigureRouterInfo: Router interface %d", m->UPnPInterfaceID);
+
+ // Don't need the SSDP socket anymore
+ if (m->SSDPSocket) { debugf("LNT_ConfigureRouterInfo destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }
+
+ mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "success", "success", "");
+ // now send message to get the device description
+ GetDeviceDescription(m, &m->tcpDeviceInfo);
+}
+
+mDNSexport void LNT_SendDiscoveryMsg(mDNS *m)
+{
+ static const char msg[] =
+ "M-SEARCH * HTTP/1.1\r\n"
+ "Host:239.255.255.250:1900\r\n"
+ "ST:urn:schemas-upnp-org:service:WAN%sConnection:1\r\n"
+ "Man:\"ssdp:discover\"\r\n"
+ "MX:3\r\n\r\n";
+ static const mDNSAddr multicastDest = { mDNSAddrType_IPv4, { { { 239, 255, 255, 250 } } } };
+
+ mDNSu8 *buf = (mDNSu8*)&m->omsg; //m->omsg is 8952 bytes, which is plenty
+ unsigned int bufLen;
+
+ if (!mDNSIPPortIsZero(m->UPnPRouterPort))
+ {
+ if (m->SSDPSocket) { debugf("LNT_SendDiscoveryMsg destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }
+ if (mDNSIPPortIsZero(m->UPnPSOAPPort) && !m->tcpDeviceInfo.sock) GetDeviceDescription(m, &m->tcpDeviceInfo);
+ return;
+ }
+
+ // Always query for WANIPConnection in the first SSDP packet
+ if (m->retryIntervalGetAddr <= NATMAP_INIT_RETRY) m->SSDPWANPPPConnection = mDNSfalse;
+
+ // Create message
+ bufLen = mDNS_snprintf((char*)buf, sizeof(m->omsg), msg, m->SSDPWANPPPConnection ? "PPP" : "IP");
+
+ debugf("LNT_SendDiscoveryMsg Router %.4a Current External Address %.4a", &m->Router.ip.v4, &m->ExtAddress);
+
+ if (!mDNSIPv4AddressIsZero(m->Router.ip.v4))
+ {
+ if (!m->SSDPSocket) { m->SSDPSocket = mDNSPlatformUDPSocket(m, zeroIPPort); debugf("LNT_SendDiscoveryMsg created SSDPSocket %p", &m->SSDPSocket); }
+ mDNSPlatformSendUDP(m, buf, buf + bufLen, 0, m->SSDPSocket, &m->Router, SSDPPort, mDNSfalse);
+ mDNSPlatformSendUDP(m, buf, buf + bufLen, 0, m->SSDPSocket, &multicastDest, SSDPPort, mDNSfalse);
+ }
+
+ m->SSDPWANPPPConnection = !m->SSDPWANPPPConnection;
+}
+
+mDNSexport void LNT_ClearState(mDNS *const m)
+{
+ if (m->tcpAddrInfo.sock) { mDNSPlatformTCPCloseConnection(m->tcpAddrInfo.sock); m->tcpAddrInfo.sock = mDNSNULL; }
+ if (m->tcpDeviceInfo.sock) { mDNSPlatformTCPCloseConnection(m->tcpDeviceInfo.sock); m->tcpDeviceInfo.sock = mDNSNULL; }
+ m->UPnPSOAPPort = m->UPnPRouterPort = zeroIPPort; // Reset UPnP ports
+}
+
+#endif /* _LEGACY_NAT_TRAVERSAL_ */
diff --git a/mDNSResponder/mDNSMacOSX/P2PPacketFilter.c b/mDNSResponder/mDNSMacOSX/P2PPacketFilter.c
new file mode 100644
index 00000000..1ab8a02f
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/P2PPacketFilter.c
@@ -0,0 +1,298 @@
+/*
+ *
+ * Copyright (c) 2011 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 <net/if.h>
+#include <System/net/pfvar.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <AssertMacros.h>
+#include "P2PPacketFilter.h"
+
+#define AIRDROP_ANCHOR_PATH "com.apple/200.AirDrop"
+#define MDNS_ANCHOR_NAME "Bonjour"
+#define MDNS_ANCHOR_PATH AIRDROP_ANCHOR_PATH "/" MDNS_ANCHOR_NAME
+
+#define PF_DEV_PATH "/dev/pf"
+#define BONJOUR_PORT 5353
+
+static int openPFDevice( int * outFD )
+{
+ int err;
+ int fd = open( PF_DEV_PATH, O_RDWR );
+
+ if( fd >= 0 )
+ {
+ err = 0;
+ *outFD = fd;
+ }
+ else
+ {
+ err = errno;
+ }
+
+ return err;
+}
+
+static int getTicket( int devFD, u_int32_t * outTicket, char * anchorPath )
+{
+ struct pfioc_trans_e trans_e;
+
+ trans_e.rs_num = PF_RULESET_FILTER;
+ strlcpy( trans_e.anchor, anchorPath, sizeof( trans_e.anchor ) );
+
+ struct pfioc_trans trans;
+
+ trans.size = 1;
+ trans.esize = sizeof( trans_e );
+ trans.array = &trans_e;
+
+ int result, ioctlError;
+
+ ioctlError = ioctl( devFD, DIOCXBEGIN, &trans );
+ if( ioctlError )
+ {
+ result = errno;
+ }
+ else
+ {
+ result = 0;
+ *outTicket = trans_e.ticket;
+ }
+
+ return result;
+}
+
+static int commitChange( int devFD, u_int32_t ticket, char * anchorPath )
+{
+ struct pfioc_trans_e trans_e;
+
+ trans_e.rs_num = PF_RULESET_FILTER;
+ strlcpy( trans_e.anchor, anchorPath, sizeof( trans_e.anchor ) );
+ trans_e.ticket = ticket;
+
+ struct pfioc_trans trans;
+
+ trans.size = 1;
+ trans.esize = sizeof( trans_e );
+ trans.array = &trans_e;
+
+ int result, ioctlError;
+
+ ioctlError = ioctl( devFD, DIOCXCOMMIT, &trans );
+ if( ioctlError )
+ result = errno;
+ else
+ result = 0;
+
+ return result;
+}
+
+static int getPoolTicket( int devFD, u_int32_t * outPoolTicket )
+{
+ struct pfioc_pooladdr pp;
+
+ int result, ioctlError;
+
+ ioctlError = ioctl( devFD, DIOCBEGINADDRS, &pp );
+ if( ioctlError )
+ {
+ result = errno;
+ }
+ else
+ {
+ result = 0;
+ *outPoolTicket = pp.ticket;
+ }
+
+ return result;
+}
+
+static int addRule( int devFD, struct pfioc_rule * pr )
+{
+ int result, ioctlResult;
+
+ ioctlResult = ioctl( devFD, DIOCADDRULE, pr );
+ if( ioctlResult )
+ result = errno;
+ else
+ result = 0;
+
+ return result;
+}
+
+static void initRuleHeader( struct pfioc_rule * pr,
+ u_int32_t ticket,
+ u_int32_t poolTicket,
+ char * anchorPath )
+{
+ pr->action = PF_CHANGE_NONE;
+ pr->ticket = ticket;
+ pr->pool_ticket = poolTicket;
+ strlcpy( pr->anchor, anchorPath, sizeof( pr->anchor ) );
+}
+
+// allow inbound traffice on the Bonjour port (5353)
+static void initBonjourRule( struct pfioc_rule * pr,
+ const char * interfaceName,
+ u_int32_t ticket,
+ u_int32_t poolTicket,
+ char * anchorPath )
+{
+ memset( pr, 0, sizeof( *pr ) );
+
+ // Header
+ initRuleHeader( pr, ticket, poolTicket, anchorPath );
+
+ // Rule
+ pr->rule.dst.xport.range.port[0] = htons( BONJOUR_PORT );
+ pr->rule.dst.xport.range.op = PF_OP_EQ;
+
+ strlcpy( pr->rule.ifname, interfaceName, sizeof( pr->rule.ifname ) );
+
+ pr->rule.action = PF_PASS;
+ pr->rule.direction = PF_IN;
+ pr->rule.keep_state = 1;
+ pr->rule.af = AF_INET6;
+ pr->rule.proto = IPPROTO_UDP;
+ pr->rule.extfilter = PF_EXTFILTER_APD;
+}
+
+// allow outbound TCP connections and return traffic for those connections
+static void initOutboundTCPRule( struct pfioc_rule * pr,
+ const char * interfaceName,
+ u_int32_t ticket,
+ u_int32_t poolTicket,
+ char * anchorPath )
+{
+ memset( pr, 0, sizeof( *pr ) );
+
+ // Header
+ initRuleHeader( pr, ticket, poolTicket, anchorPath );
+
+ // Rule
+ strlcpy( pr->rule.ifname, interfaceName, sizeof( pr->rule.ifname ) );
+
+ pr->rule.action = PF_PASS;
+ pr->rule.direction = PF_OUT;
+ pr->rule.keep_state = 1;
+ pr->rule.proto = IPPROTO_TCP;
+}
+
+// allow inbound traffic on the specified port and protocol
+static void initPortRule( struct pfioc_rule * pr,
+ const char * interfaceName,
+ u_int32_t ticket,
+ u_int32_t poolTicket,
+ char * anchorPath,
+ u_int16_t port,
+ u_int16_t protocol )
+{
+ memset( pr, 0, sizeof( *pr ) );
+
+ // Header
+ initRuleHeader( pr, ticket, poolTicket, anchorPath );
+
+ // Rule
+ // mDNSResponder passes the port in Network Byte Order, so htons(port) is not required
+ pr->rule.dst.xport.range.port[0] = port;
+ pr->rule.dst.xport.range.op = PF_OP_EQ;
+
+ strlcpy( pr->rule.ifname, interfaceName, sizeof( pr->rule.ifname ) );
+
+ pr->rule.action = PF_PASS;
+ pr->rule.direction = PF_IN;
+ pr->rule.keep_state = 1;
+ pr->rule.af = AF_INET6;
+ pr->rule.proto = protocol;
+ pr->rule.extfilter = PF_EXTFILTER_APD;
+}
+
+// allow inbound traffic on the Bonjour port (5353) and the specified port and protocol sets
+int P2PPacketFilterAddBonjourRuleSet(const char * interfaceName, u_int32_t count, pfArray_t portArray, pfArray_t protocolArray )
+{
+ int result;
+ u_int32_t i, ticket, poolTicket;
+ int devFD = -1;
+ char * anchorPath = MDNS_ANCHOR_PATH;
+
+ result = openPFDevice( &devFD );
+ require( result == 0, exit );
+
+ result = getTicket( devFD, &ticket, anchorPath );
+ require( result == 0, exit );
+
+ result = getPoolTicket( devFD, &poolTicket );
+ require( result == 0, exit );
+
+ struct pfioc_rule pr;
+
+ // allow inbound Bonjour traffice to port 5353
+ initBonjourRule( &pr, interfaceName, ticket, poolTicket, anchorPath);
+
+ result = addRule( devFD, &pr );
+ require( result == 0, exit );
+
+ // open inbound port for each service
+ for (i = 0; i < count; i++) {
+ initPortRule( &pr, interfaceName, ticket, poolTicket, anchorPath, portArray[i], protocolArray[i] );
+ result = addRule( devFD, &pr );
+ require( result == 0, exit );
+ }
+
+ // allow outbound TCP connections and return traffic for those connections
+ initOutboundTCPRule( &pr, interfaceName, ticket, poolTicket, anchorPath);
+
+ result = addRule( devFD, &pr );
+ require( result == 0, exit );
+
+ result = commitChange( devFD, ticket, anchorPath );
+ require( result == 0, exit );
+
+exit:
+
+ if( devFD >= 0 )
+ close( devFD );
+
+ return result;
+}
+
+int P2PPacketFilterClearBonjourRules()
+{
+ int result;
+ int pfDev = -1;
+ u_int32_t ticket;
+ char * anchorPath = MDNS_ANCHOR_PATH;
+
+ result = openPFDevice( &pfDev );
+ require( result == 0, exit );
+
+ result = getTicket( pfDev, &ticket, anchorPath );
+ require( result == 0, exit );
+
+ result = commitChange( pfDev, ticket, anchorPath );
+
+exit:
+
+ if( pfDev >= 0 )
+ close( pfDev );
+
+ return result;
+}
+
diff --git a/mDNSResponder/mDNSMacOSX/P2PPacketFilter.h b/mDNSResponder/mDNSMacOSX/P2PPacketFilter.h
new file mode 100644
index 00000000..9c196577
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/P2PPacketFilter.h
@@ -0,0 +1,31 @@
+/*
+ *
+ * Copyright (c) 2011 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.
+ */
+
+#ifndef _P2P_PACKET_FILTER_H_
+#define _P2P_PACKET_FILTER_H_
+
+#include "helpermsg-types.h"
+
+enum {
+ PF_SET_RULES,
+ PF_CLEAR_RULES
+};
+
+int P2PPacketFilterAddBonjourRuleSet(const char * interfaceName, u_int32_t count, pfArray_t portArray, pfArray_t protocolArray );
+int P2PPacketFilterClearBonjourRules(void);
+
+#endif /* _P2P_PACKET_FILTER_H_ */
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_idle.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_idle.tiff
new file mode 100644
index 00000000..b78b0c2a
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_idle.tiff
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_pressed.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_pressed.tiff
new file mode 100644
index 00000000..b842e20c
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_pressed.tiff
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/failure.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/failure.tiff
new file mode 100644
index 00000000..89a10dfe
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/failure.tiff
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/inprogress.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/inprogress.tiff
new file mode 100644
index 00000000..340bb335
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/inprogress.tiff
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_disabled.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_disabled.tiff
new file mode 100644
index 00000000..70d3dd9c
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_disabled.tiff
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_idle.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_idle.tiff
new file mode 100644
index 00000000..dacc97c3
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_idle.tiff
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_pressed.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_pressed.tiff
new file mode 100644
index 00000000..de3f8779
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_pressed.tiff
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/success.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/success.tiff
new file mode 100644
index 00000000..21702a9a
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/success.tiff
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPref.icns b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPref.icns
new file mode 100644
index 00000000..5ba4674e
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPref.icns
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPref.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPref.tiff
new file mode 100644
index 00000000..55cb212c
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPref.tiff
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c b/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c
new file mode 100644
index 00000000..a2ab5464
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c
@@ -0,0 +1,180 @@
+/*
+ File: ConfigurationAuthority.c
+
+ Abstract: Interface to system security framework that manages access
+ to protected resources like system configuration preferences.
+
+ Copyright: (c) Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ConfigurationAuthority.h"
+#include "ConfigurationRights.h"
+
+#include <AssertMacros.h>
+
+
+static AuthorizationRef gAuthRef = 0;
+
+static AuthorizationItem gAuthorizations[] = { { UPDATE_SC_RIGHT, 0, NULL, 0 },
+ { EDIT_SYS_KEYCHAIN_RIGHT, 0, NULL, 0 }};
+static AuthorizationRights gAuthSet = { sizeof gAuthorizations / sizeof gAuthorizations[0], gAuthorizations };
+
+static CFDictionaryRef CreateRightsDict( CFStringRef prompt)
+/* Create a CFDictionary decribing an auth right. See /etc/authorization for examples. */
+/* Specifies that the right requires admin authentication, which persists for 5 minutes. */
+{
+ CFMutableDictionaryRef dict = NULL, tmpDict;
+ CFMutableArrayRef mechanisms;
+ CFNumberRef timeout;
+ int val;
+
+ tmpDict = CFDictionaryCreateMutable( (CFAllocatorRef) NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ require( tmpDict != NULL, MakeDictFailed);
+
+ CFDictionaryAddValue(tmpDict, CFSTR("class"), CFSTR("user"));
+ CFDictionaryAddValue(tmpDict, CFSTR("comment"), prompt);
+ CFDictionaryAddValue(tmpDict, CFSTR("group"), CFSTR("admin"));
+
+ mechanisms = CFArrayCreateMutable((CFAllocatorRef) NULL, 1, &kCFTypeArrayCallBacks);
+ require( mechanisms != NULL, MakeArrayFailed);
+ CFArrayAppendValue( mechanisms, CFSTR("builtin:authenticate"));
+ CFDictionaryAddValue( tmpDict, CFSTR("mechanisms"), mechanisms);
+
+ val = 300; // seconds
+ timeout = CFNumberCreate((CFAllocatorRef) NULL, kCFNumberIntType, &val);
+ require( timeout != NULL, MakeIntFailed);
+ CFDictionaryAddValue( tmpDict, CFSTR("timeout"), timeout);
+ CFDictionaryAddValue( tmpDict, CFSTR("shared"), kCFBooleanTrue);
+
+ dict = tmpDict;
+ tmpDict = NULL;
+
+ CFRelease( timeout);
+MakeIntFailed:
+ CFRelease( mechanisms);
+MakeArrayFailed:
+ if ( tmpDict)
+ CFRelease( tmpDict);
+MakeDictFailed:
+ return dict;
+}
+
+OSStatus InitConfigAuthority(void)
+/* Initialize the authorization record-keeping */
+{
+ OSStatus err;
+ CFDictionaryRef dict;
+ CFStringRef rightInfo;
+
+ err = AuthorizationCreate((AuthorizationRights*) NULL, (AuthorizationEnvironment*) NULL,
+ (AuthorizationFlags) 0, &gAuthRef);
+ require_noerr( err, NewAuthFailed);
+
+ err = AuthorizationRightGet( UPDATE_SC_RIGHT, (CFDictionaryRef*) NULL);
+ if (err == errAuthorizationDenied)
+ {
+ rightInfo = CFCopyLocalizedString(CFSTR("Authentication required to set Dynamic DNS preferences."),
+ CFSTR("Describes operation that requires user authorization"));
+ require_action( rightInfo != NULL, GetStrFailed, err=coreFoundationUnknownErr;);
+ dict = CreateRightsDict(rightInfo);
+ require_action( dict != NULL, GetStrFailed, err=coreFoundationUnknownErr;);
+
+ err = AuthorizationRightSet(gAuthRef, UPDATE_SC_RIGHT, dict, (CFStringRef) NULL,
+ (CFBundleRef) NULL, (CFStringRef) NULL);
+ CFRelease(rightInfo);
+ CFRelease(dict);
+ }
+ require_noerr( err, AuthSetFailed);
+
+ err = AuthorizationRightGet( EDIT_SYS_KEYCHAIN_RIGHT, (CFDictionaryRef*) NULL);
+ if (err == errAuthorizationDenied)
+ {
+ rightInfo = CFCopyLocalizedString( CFSTR("Authentication required to edit System Keychain."),
+ CFSTR("Describes operation that requires user authorization"));
+ require_action( rightInfo != NULL, GetStrFailed, err=coreFoundationUnknownErr;);
+ dict = CreateRightsDict( rightInfo);
+ require_action( dict != NULL, GetStrFailed, err=coreFoundationUnknownErr;);
+
+ err = AuthorizationRightSet(gAuthRef, EDIT_SYS_KEYCHAIN_RIGHT, dict, (CFStringRef) NULL,
+ (CFBundleRef) NULL, (CFStringRef) NULL);
+ CFRelease( rightInfo);
+ CFRelease( dict);
+ }
+ require_noerr( err, AuthSetFailed);
+
+AuthSetFailed:
+GetStrFailed:
+NewAuthFailed:
+ return err;
+}
+
+OSStatus AttemptAcquireAuthority( Boolean allowUI)
+/* Try to get permission for privileged ops, either implicitly or by asking the user for */
+/* authority to perform operations (if necessary) */
+{
+ AuthorizationFlags allowFlag = allowUI ? kAuthorizationFlagInteractionAllowed : 0;
+ OSStatus err;
+
+ err = AuthorizationCopyRights( gAuthRef, &gAuthSet, (AuthorizationEnvironment*) NULL,
+ kAuthorizationFlagExtendRights | kAuthorizationFlagPreAuthorize |
+ allowFlag,
+ (AuthorizationRights**) NULL);
+ return err;
+}
+
+OSStatus ReleaseAuthority(void)
+/* Discard authority to perform operations */
+{
+ (void) AuthorizationFree( gAuthRef, kAuthorizationFlagDefaults);
+ gAuthRef = 0;
+ return AuthorizationCreate( (AuthorizationRights*) NULL, (AuthorizationEnvironment*) NULL,
+ (AuthorizationFlags) 0, &gAuthRef);
+}
+
+Boolean CurrentlyAuthorized(void)
+{
+ OSStatus err = AttemptAcquireAuthority(true);
+ return err == noErr;
+}
+
+
+OSStatus ExternalizeAuthority(AuthorizationExternalForm *pAuth)
+/* Package up current authorizations for transfer to another process */
+{
+ return AuthorizationMakeExternalForm(gAuthRef, pAuth);
+}
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.h b/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.h
new file mode 100644
index 00000000..49da93d0
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.h
@@ -0,0 +1,52 @@
+/*
+ File: ConfigurationAuthority.h
+
+ Abstract: Interface to system security framework that manages access
+ to protected resources like system configuration preferences.
+
+ Copyright: (c) Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <CoreServices/CoreServices.h>
+#include <Security/Security.h>
+
+OSStatus InitConfigAuthority(void);
+Boolean CurrentlyAuthorized(void);
+OSStatus AttemptAcquireAuthority(Boolean allowUI);
+OSStatus ReleaseAuthority(void);
+OSStatus ExternalizeAuthority(AuthorizationExternalForm *pAuth);
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationRights.h b/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationRights.h
new file mode 100644
index 00000000..44379c67
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationRights.h
@@ -0,0 +1,49 @@
+/*
+ File: ConfigurationRights.h
+
+ Abstract: Defines the rights we need, namely, (i) the right to write to
+ the system configuration settings for Dynamic DNS and Wide-Area DNS-SD,
+ and (ii) the right to write to the system keychain to store Dynamic DNS
+ shared secrets used to perform authorized updates to DDNS servers.
+ Right now these are both actually the same right: "system.preferences"
+
+ Copyright: (c) Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define UPDATE_SC_RIGHT "system.preferences"
+#define EDIT_SYS_KEYCHAIN_RIGHT "system.preferences"
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.h b/mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.h
new file mode 100644
index 00000000..f0586591
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.h
@@ -0,0 +1,170 @@
+/*
+ File: DNSServiceDiscoveryPref.h
+
+ Abstract: System Preference Pane for Dynamic DNS and Wide-Area DNS Service Discovery
+
+ Copyright: (c) Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <Cocoa/Cocoa.h>
+#import <PreferencePanes/PreferencePanes.h>
+#import <CoreFoundation/CoreFoundation.h>
+#import <SecurityInterface/SFAuthorizationView.h>
+#import <SystemConfiguration/SystemConfiguration.h>
+#import <dns_sd.h>
+
+typedef struct MyDNSServiceState {
+ DNSServiceRef service;
+ CFRunLoopSourceRef source;
+ CFSocketRef socket;
+} MyDNSServiceState;
+
+
+@interface DNSServiceDiscoveryPref : NSPreferencePane
+{
+ IBOutlet NSTextField *hostName;
+ IBOutlet NSTextField *sharedSecretName;
+ IBOutlet NSSecureTextField *sharedSecretValue;
+ IBOutlet NSComboBox *browseDomainsComboBox;
+ IBOutlet NSComboBox *regDomainsComboBox;
+ IBOutlet NSButton *wideAreaCheckBox;
+ IBOutlet NSButton *hostNameSharedSecretButton;
+ IBOutlet NSButton *registrationSharedSecretButton;
+ IBOutlet NSButton *applyButton;
+ IBOutlet NSButton *revertButton;
+ IBOutlet NSWindow *sharedSecretWindow;
+ IBOutlet NSWindow *addBrowseDomainWindow;
+ IBOutlet NSButton *addBrowseDomainButton;
+ IBOutlet NSButton *removeBrowseDomainButton;
+ IBOutlet NSButton *browseOKButton;
+ IBOutlet NSButton *browseCancelButton;
+ IBOutlet NSButton *secretOKButton;
+ IBOutlet NSButton *secretCancelButton;
+ IBOutlet NSImageView *statusImageView;
+ IBOutlet NSTabView *tabView;
+ IBOutlet NSTableView *browseDomainList;
+ IBOutlet SFAuthorizationView *comboAuthButton;
+
+ NSWindow *mainWindow;
+ NSString *currentHostName;
+ NSString *currentRegDomain;
+ NSArray *currentBrowseDomainsArray;
+ NSMutableArray *browseDomainsArray;
+ NSMutableArray *defaultBrowseDomainsArray;
+ NSString *defaultRegDomain;
+
+ NSString *hostNameSharedSecretName;
+ NSString *hostNameSharedSecretValue;
+ NSString *regSharedSecretName;
+ NSString *regSharedSecretValue;
+ BOOL currentWideAreaState;
+ BOOL prefsNeedUpdating;
+ BOOL toolInstalled;
+ BOOL browseDomainListEnabled;
+ BOOL justStartedEditing;
+ NSImage *successImage;
+ NSImage *inprogressImage;
+ NSImage *failureImage;
+
+ MyDNSServiceState regQuery;
+ MyDNSServiceState browseQuery;
+ NSMutableArray *browseDataSource;
+ NSMutableArray *registrationDataSource;
+}
+
+-(IBAction)applyClicked : (id)sender;
+-(IBAction)enableBrowseDomainClicked : (id)sender;
+-(IBAction)addBrowseDomainClicked : (id)sender;
+-(IBAction)removeBrowseDomainClicked : (id)sender;
+-(IBAction)revertClicked : (id)sender;
+-(IBAction)changeButtonPressed : (id)sender;
+-(IBAction)closeMyCustomSheet : (id)sender;
+-(IBAction)comboAction : (id)sender;
+-(IBAction)wideAreaCheckBoxChanged : (id)sender;
+
+
+-(NSMutableArray *)browseDataSource;
+-(NSMutableArray *)registrationDataSource;
+-(NSComboBox *)browseDomainsComboBox;
+-(NSComboBox *)regDomainsComboBox;
+-(NSString *)currentRegDomain;
+-(NSMutableArray *)defaultBrowseDomainsArray;
+-(NSArray *)currentBrowseDomainsArray;
+-(NSString *)currentHostName;
+-(NSString *)defaultRegDomain;
+-(void)setDefaultRegDomain : (NSString *)domain;
+
+
+
+-(void)enableApplyButton;
+-(void)disableApplyButton;
+-(void)applyCurrentState;
+-(void)setBrowseDomainsComboBox;
+-(void)setupInitialValues;
+-(void)startDomainBrowsing;
+-(void)toggleWideAreaBonjour : (BOOL)state;
+-(void)updateApplyButtonState;
+-(void)enableControls;
+-(void)disableControls;
+-(void)validateTextFields;
+-(void)readPreferences;
+-(void)savePreferences;
+-(void)restorePreferences;
+-(void)watchForPreferenceChanges;
+-(void)updateStatusImageView;
+
+
+-(NSString *)sharedSecretKeyName : (NSString * )domain;
+-(NSString *)domainForHostName : (NSString *)hostNameString;
+-(int)statusForHostName : (NSString * )domain;
+-(NSData *)dataForDomainArray : (NSArray *)domainArray;
+-(NSData *)dataForDomain : (NSString *)domainName isEnabled : (BOOL)enabled;
+-(NSData *)dataForSharedSecret : (NSString *)secret domain : (NSString *)domainName key : (NSString *)keyName;
+-(BOOL)domainAlreadyInList : (NSString *)domainString;
+-(NSString *)trimCharactersFromDomain : (NSString *)domain;
+
+
+// Delegate methods
+-(void)authorizationViewDidAuthorize : (SFAuthorizationView *)view;
+-(void)authorizationViewDidDeauthorize : (SFAuthorizationView *)view;
+-(void)mainViewDidLoad;
+-(int)numberOfItemsInComboBox : (NSComboBox *)aComboBox;
+-(id)comboBox : (NSComboBox *)aComboBox objectValueForItemAtIndex : (int)index;
+-(void)controlTextDidChange : (NSNotification *) notification;
+
+@end
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m b/mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m
new file mode 100644
index 00000000..063bc724
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m
@@ -0,0 +1,1194 @@
+/*
+ File: DNSServiceDiscoveryPref.m
+
+ Abstract: System Preference Pane for Dynamic DNS and Wide-Area DNS Service Discovery
+
+ Copyright: (c) Copyright 2005-2011 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "DNSServiceDiscoveryPref.h"
+#import "ConfigurationAuthority.h"
+#import "PrivilegedOperations.h"
+#import <unistd.h>
+
+#include "../../Clients/ClientCommon.h"
+
+#ifndef NSINTEGER_DEFINED
+#define NSInteger int
+#endif
+
+@implementation DNSServiceDiscoveryPref
+
+static NSInteger
+MyArrayCompareFunction(id val1, id val2, void *context)
+{
+ (void)context; // Unused
+ return CFStringCompare((CFStringRef)val1, (CFStringRef)val2, kCFCompareCaseInsensitive);
+}
+
+static NSInteger
+MyDomainArrayCompareFunction(id val1, id val2, void *context)
+{
+ (void)context; // Unused
+ NSString *domain1 = [val1 objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
+ NSString *domain2 = [val2 objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
+ return CFStringCompare((CFStringRef)domain1, (CFStringRef)domain2, kCFCompareCaseInsensitive);
+}
+
+
+static void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
+{
+ (void)store; // Unused
+ (void)changedKeys; // Unused
+ DNSServiceDiscoveryPref * me = (DNSServiceDiscoveryPref *)context;
+ assert(me != NULL);
+
+ [me setupInitialValues];
+}
+
+
+static void ServiceDomainEnumReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode, const char *replyDomain, void *context, DNSServiceFlags enumType)
+{
+ (void)sdRef; // Unused
+ (void)interfaceIndex; // Unused
+ (void)errorCode; // Unused
+ if (strcmp(replyDomain, "local.") == 0) return; // local domain is not interesting
+
+ DNSServiceDiscoveryPref * me = (DNSServiceDiscoveryPref *)context;
+ BOOL moreComing = (BOOL)(flags & kDNSServiceFlagsMoreComing);
+ NSMutableArray * domainArray;
+ NSMutableArray * defaultBrowseDomainsArray = nil;
+ NSComboBox * domainComboBox;
+ NSString * domainString;
+ NSString * currentDomain = nil;
+ char decodedDomainString[kDNSServiceMaxDomainName] = "\0";
+ char nextLabel[256] = "\0";
+ char * buffer = (char *)replyDomain;
+
+ while (*buffer) {
+ buffer = (char *)GetNextLabel(buffer, nextLabel);
+ strcat(decodedDomainString, nextLabel);
+ strcat(decodedDomainString, ".");
+ }
+
+ // Remove trailing dot from domain name.
+ decodedDomainString[strlen(decodedDomainString)-1] = '\0';
+
+ domainString = [[[NSString alloc] initWithUTF8String:(const char *)decodedDomainString] autorelease];
+
+ if (enumType & kDNSServiceFlagsRegistrationDomains) {
+ domainArray = [me registrationDataSource];
+ domainComboBox = [me regDomainsComboBox];
+ currentDomain = [me currentRegDomain];
+ } else {
+ domainArray = [me browseDataSource];
+ domainComboBox = [me browseDomainsComboBox];
+ defaultBrowseDomainsArray = [me defaultBrowseDomainsArray];
+ }
+
+ if (flags & kDNSServiceFlagsAdd) {
+ [domainArray removeObject:domainString]; // How can I check if an object is in the array?
+ [domainArray addObject:domainString];
+ if ((flags & kDNSServiceFlagsDefault) && (enumType & kDNSServiceFlagsRegistrationDomains)) {
+ [me setDefaultRegDomain:domainString];
+ if ([[domainComboBox stringValue] length] == 0) [domainComboBox setStringValue:domainString];
+ } else if ((flags & kDNSServiceFlagsDefault) && !(enumType & kDNSServiceFlagsRegistrationDomains)) {
+ [defaultBrowseDomainsArray removeObject:domainString];
+ [defaultBrowseDomainsArray addObject:domainString];
+ }
+ }
+
+ if (moreComing == NO) {
+ [domainArray sortUsingFunction:MyArrayCompareFunction context:nil];
+ [domainComboBox reloadData];
+ }
+}
+
+
+static void
+browseDomainReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode, const char *replyDomain, void *context)
+{
+ ServiceDomainEnumReply(sdRef, flags, interfaceIndex, errorCode, replyDomain, context, kDNSServiceFlagsBrowseDomains);
+}
+
+
+static void
+registrationDomainReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode, const char *replyDomain, void *context)
+{
+ ServiceDomainEnumReply(sdRef, flags, interfaceIndex, errorCode, replyDomain, context, kDNSServiceFlagsRegistrationDomains);
+}
+
+
+
+static void
+MyDNSServiceCleanUp(MyDNSServiceState * query)
+{
+ /* Remove the CFRunLoopSource from the current run loop. */
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), query->source, kCFRunLoopCommonModes);
+ CFRelease(query->source);
+
+ /* Invalidate the CFSocket. */
+ CFSocketInvalidate(query->socket);
+ CFRelease(query->socket);
+
+ /* Workaround that gives time to CFSocket's select thread so it can remove the socket from its FD set
+ before we close the socket by calling DNSServiceRefDeallocate. <rdar://problem/3585273> */
+ usleep(1000);
+
+ /* Terminate the connection with the mDNSResponder daemon, which cancels the query. */
+ DNSServiceRefDeallocate(query->service);
+}
+
+
+
+static void
+MySocketReadCallback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void * data, void * info)
+{
+ #pragma unused(s)
+ #pragma unused(type)
+ #pragma unused(address)
+ #pragma unused(data)
+
+ DNSServiceErrorType err;
+
+ MyDNSServiceState * query = (MyDNSServiceState *)info; // context passed in to CFSocketCreateWithNative().
+ assert(query != NULL);
+
+ /* Read a reply from the mDNSResponder. */
+ err= DNSServiceProcessResult(query->service);
+ if (err != kDNSServiceErr_NoError) {
+ fprintf(stderr, "DNSServiceProcessResult returned %d\n", err);
+
+ /* Terminate the query operation and release the CFRunLoopSource and CFSocket. */
+ MyDNSServiceCleanUp(query);
+ }
+}
+
+
+
+static void
+MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
+{
+ CFSocketNativeHandle sock;
+ CFOptionFlags sockFlags;
+ CFSocketContext context = { 0, query, NULL, NULL, NULL }; // Use MyDNSServiceState as context data.
+
+ /* Access the underlying Unix domain socket to communicate with the mDNSResponder daemon. */
+ sock = DNSServiceRefSockFD(query->service);
+ assert(sock != -1);
+
+ /* Create a CFSocket using the Unix domain socket. */
+ query->socket = CFSocketCreateWithNative(NULL, sock, kCFSocketReadCallBack, MySocketReadCallback, &context);
+ assert(query->socket != NULL);
+
+ /* Prevent CFSocketInvalidate from closing DNSServiceRef's socket. */
+ sockFlags = CFSocketGetSocketFlags(query->socket);
+ CFSocketSetSocketFlags(query->socket, sockFlags & (~kCFSocketCloseOnInvalidate));
+
+ /* Create a CFRunLoopSource from the CFSocket. */
+ query->source = CFSocketCreateRunLoopSource(NULL, query->socket, 0);
+ assert(query->source != NULL);
+
+ /* Add the CFRunLoopSource to the current run loop. */
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), query->source, kCFRunLoopCommonModes);
+}
+
+
+
+-(void)updateStatusImageView
+{
+ int value = [self statusForHostName:currentHostName];
+ if (value == 0) [statusImageView setImage:successImage];
+ else if (value > 0) [statusImageView setImage:inprogressImage];
+ else [statusImageView setImage:failureImage];
+}
+
+
+- (void)watchForPreferenceChanges
+{
+ SCDynamicStoreContext context = { 0, self, NULL, NULL, NULL };
+ SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("watchForPreferenceChanges"), NetworkChanged, &context);
+ CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ CFRunLoopSourceRef rls;
+
+ assert(store != NULL);
+ assert(keys != NULL);
+
+ CFArrayAppendValue(keys, SC_DYNDNS_STATE_KEY);
+ CFArrayAppendValue(keys, SC_DYNDNS_SETUP_KEY);
+
+ (void)SCDynamicStoreSetNotificationKeys(store, keys, NULL);
+
+ rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
+ assert(rls != NULL);
+
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopCommonModes);
+
+ CFRelease(keys);
+ CFRelease(store);
+}
+
+
+-(int)statusForHostName:(NSString * )domain
+{
+ SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("statusForHostName"), NULL, NULL);
+ NSString *lowercaseDomain = [domain lowercaseString];
+ int status = 1;
+
+ assert(store != NULL);
+
+ NSDictionary *dynamicDNS = (NSDictionary *)SCDynamicStoreCopyValue(store, SC_DYNDNS_STATE_KEY);
+ if (dynamicDNS) {
+ NSDictionary *hostNames = [dynamicDNS objectForKey:(NSString *)SC_DYNDNS_HOSTNAMES_KEY];
+ NSDictionary *infoDict = [hostNames objectForKey:lowercaseDomain];
+ if (infoDict) status = [[infoDict objectForKey:(NSString*)SC_DYNDNS_STATUS_KEY] intValue];
+ CFRelease(dynamicDNS);
+ }
+ CFRelease(store);
+
+ return status;
+}
+
+
+- (void)startDomainBrowsing
+{
+ DNSServiceFlags flags;
+ OSStatus err = noErr;
+
+ flags = kDNSServiceFlagsRegistrationDomains;
+ err = DNSServiceEnumerateDomains(&regQuery.service, flags, 0, registrationDomainReply, (void *)self);
+ if (err == kDNSServiceErr_NoError) MyDNSServiceAddServiceToRunLoop(&regQuery);
+
+ flags = kDNSServiceFlagsBrowseDomains;
+ err = DNSServiceEnumerateDomains(&browseQuery.service, flags, 0, browseDomainReply, (void *)self);
+ if (err == kDNSServiceErr_NoError) MyDNSServiceAddServiceToRunLoop(&browseQuery);
+}
+
+
+-(void)readPreferences
+{
+ NSDictionary *origDict;
+ NSArray *regDomainArray;
+ NSArray *hostArray;
+
+ if (currentRegDomain) [currentRegDomain release];
+ if (currentBrowseDomainsArray) [currentBrowseDomainsArray release];
+ if (currentHostName) [currentHostName release];
+
+ SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("com.apple.preference.bonjour"), NULL, NULL);
+ origDict = (NSDictionary *)SCDynamicStoreCopyValue(store, SC_DYNDNS_SETUP_KEY);
+
+ regDomainArray = [origDict objectForKey:(NSString *)SC_DYNDNS_REGDOMAINS_KEY];
+ if (regDomainArray && [regDomainArray count] > 0) {
+ currentRegDomain = [[[regDomainArray objectAtIndex:0] objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY] copy];
+ currentWideAreaState = [[[regDomainArray objectAtIndex:0] objectForKey:(NSString *)SC_DYNDNS_ENABLED_KEY] intValue];
+ } else {
+ currentRegDomain = [[NSString alloc] initWithString:@""];
+ currentWideAreaState = NO;
+ }
+
+ currentBrowseDomainsArray = [[origDict objectForKey:(NSString *)SC_DYNDNS_BROWSEDOMAINS_KEY] retain];
+
+ hostArray = [origDict objectForKey:(NSString *)SC_DYNDNS_HOSTNAMES_KEY];
+ if (hostArray && [hostArray count] > 0) {
+ currentHostName = [[[hostArray objectAtIndex:0] objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY] copy];
+ } else {
+ currentHostName = [[NSString alloc] initWithString:@""];
+ }
+
+ [origDict release];
+ CFRelease(store);
+}
+
+
+- (void)tableViewSelectionDidChange:(NSNotification *)notification
+{
+ [removeBrowseDomainButton setEnabled:[[notification object] numberOfSelectedRows]];
+}
+
+
+- (void)setBrowseDomainsComboBox
+{
+ NSString * domain = nil;
+
+ if ([defaultBrowseDomainsArray count] > 0) {
+ NSEnumerator * arrayEnumerator = [defaultBrowseDomainsArray objectEnumerator];
+ while ((domain = [arrayEnumerator nextObject]) != NULL) {
+ if ([self domainAlreadyInList:domain] == NO) break;
+ }
+ }
+ if (domain) [browseDomainsComboBox setStringValue:domain];
+ else [browseDomainsComboBox setStringValue:@""];
+}
+
+
+- (IBAction)addBrowseDomainClicked:(id)sender
+{
+ [self setBrowseDomainsComboBox];
+
+ [NSApp beginSheet:addBrowseDomainWindow modalForWindow:mainWindow modalDelegate:self
+ didEndSelector:@selector(addBrowseDomainSheetDidEnd:returnCode:contextInfo:) contextInfo:sender];
+
+ [browseDomainList deselectAll:sender];
+ [self updateApplyButtonState];
+}
+
+
+- (IBAction)removeBrowseDomainClicked:(id)sender
+{
+ (void)sender; // Unused
+ int selectedBrowseDomain = [browseDomainList selectedRow];
+ [browseDomainsArray removeObjectAtIndex:selectedBrowseDomain];
+ [browseDomainList reloadData];
+ [self updateApplyButtonState];
+}
+
+
+- (IBAction)enableBrowseDomainClicked:(id)sender
+{
+ NSTableView *tableView = sender;
+ NSMutableDictionary *browseDomainDict;
+ int value;
+
+ browseDomainDict = [[browseDomainsArray objectAtIndex:[tableView clickedRow]] mutableCopy];
+ value = [[browseDomainDict objectForKey:(NSString *)SC_DYNDNS_ENABLED_KEY] intValue];
+ [browseDomainDict setObject:[[[NSNumber alloc] initWithInt:(!value)] autorelease] forKey:(NSString *)SC_DYNDNS_ENABLED_KEY];
+ [browseDomainsArray replaceObjectAtIndex:[tableView clickedRow] withObject:browseDomainDict];
+ [tableView reloadData];
+ [self updateApplyButtonState];
+}
+
+
+
+- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
+{
+ (void)tableView; // Unused
+ int numberOfRows = 0;
+
+ if (browseDomainsArray) {
+ numberOfRows = [browseDomainsArray count];
+ }
+ return numberOfRows;
+}
+
+
+- (void)tabView:(NSTabView *)xtabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem
+{
+ (void)xtabView; // Unused
+ (void)tabViewItem; // Unused
+ [browseDomainList deselectAll:self];
+ [mainWindow makeFirstResponder:nil];
+}
+
+
+- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
+{
+ (void)tableView; // Unused
+ NSDictionary *browseDomainDict;
+ id value = nil;
+
+ if (browseDomainsArray) {
+ browseDomainDict = [browseDomainsArray objectAtIndex:row];
+ if (browseDomainDict) {
+ if ([[tableColumn identifier] isEqualTo:(NSString *)SC_DYNDNS_ENABLED_KEY]) {
+ value = [browseDomainDict objectForKey:(NSString *)SC_DYNDNS_ENABLED_KEY];
+ } else if ([[tableColumn identifier] isEqualTo:(NSString *)SC_DYNDNS_DOMAIN_KEY]) {
+ value = [browseDomainDict objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
+ }
+ }
+ }
+ return value;
+}
+
+
+- (void)setupInitialValues
+{
+ [self readPreferences];
+
+ if (currentHostName) {
+ [hostName setStringValue:currentHostName];
+ [self updateStatusImageView];
+ }
+
+ if (browseDomainsArray) {
+ [browseDomainsArray release];
+ browseDomainsArray = nil;
+ }
+
+ if (currentBrowseDomainsArray) {
+ browseDomainsArray = [currentBrowseDomainsArray mutableCopy];
+ if (browseDomainsArray) {
+ [browseDomainsArray sortUsingFunction:MyDomainArrayCompareFunction context:nil];
+ if ([browseDomainsArray isEqualToArray:currentBrowseDomainsArray] == NO) {
+ OSStatus err = WriteBrowseDomain((CFDataRef)[self dataForDomainArray:browseDomainsArray]);
+ if (err != noErr) NSLog(@"WriteBrowseDomain returned %d\n", (int32_t)err);
+ [currentBrowseDomainsArray release];
+ currentBrowseDomainsArray = [browseDomainsArray copy];
+ }
+ }
+ } else {
+ browseDomainsArray = nil;
+ }
+ [browseDomainList reloadData];
+
+ if (currentRegDomain && ([currentRegDomain length] > 0)) {
+ [regDomainsComboBox setStringValue:currentRegDomain];
+ [registrationDataSource removeObject:currentRegDomain];
+ [registrationDataSource addObject:currentRegDomain];
+ [registrationDataSource sortUsingFunction:MyArrayCompareFunction context:nil];
+ [regDomainsComboBox reloadData];
+ }
+
+ if (currentWideAreaState) {
+ [self toggleWideAreaBonjour:YES];
+ } else {
+ [self toggleWideAreaBonjour:NO];
+ }
+
+ if (hostNameSharedSecretValue) {
+ [hostNameSharedSecretValue release];
+ hostNameSharedSecretValue = nil;
+ }
+
+ if (regSharedSecretValue) {
+ [regSharedSecretValue release];
+ regSharedSecretValue = nil;
+ }
+
+ [self updateApplyButtonState];
+ [mainWindow makeFirstResponder:nil];
+ [browseDomainList deselectAll:self];
+ [removeBrowseDomainButton setEnabled:NO];
+}
+
+
+
+- (void)awakeFromNib
+{
+ OSStatus err;
+
+ prefsNeedUpdating = NO;
+ toolInstalled = NO;
+ browseDomainListEnabled = NO;
+ defaultRegDomain = nil;
+ currentRegDomain = nil;
+ currentBrowseDomainsArray = nil;
+ currentHostName = nil;
+ hostNameSharedSecretValue = nil;
+ regSharedSecretValue = nil;
+ browseDomainsArray = nil;
+ justStartedEditing = YES;
+ currentWideAreaState = NO;
+ NSString *successPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"success" ofType:@"tiff"];
+ NSString *inprogressPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"inprogress" ofType:@"tiff"];
+ NSString *failurePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"failure" ofType:@"tiff"];
+
+ registrationDataSource = [[NSMutableArray alloc] init];
+ browseDataSource = [[NSMutableArray alloc] init];
+ defaultBrowseDomainsArray = [[NSMutableArray alloc] init];
+ successImage = [[NSImage alloc] initWithContentsOfFile:successPath];
+ inprogressImage = [[NSImage alloc] initWithContentsOfFile:inprogressPath];
+ failureImage = [[NSImage alloc] initWithContentsOfFile:failurePath];
+
+ [tabView selectFirstTabViewItem:self];
+ [self setupInitialValues];
+ [self startDomainBrowsing];
+ [self watchForPreferenceChanges];
+
+ InitConfigAuthority();
+ err = EnsureToolInstalled();
+ if (err == noErr) toolInstalled = YES;
+ else { long int tmp = err; fprintf(stderr, "EnsureToolInstalled returned %ld\n", tmp); }
+
+}
+
+
+- (IBAction)closeMyCustomSheet:(id)sender
+{
+ BOOL result = [sender isEqualTo:browseOKButton] || [sender isEqualTo:secretOKButton];
+
+ if (result) [NSApp endSheet:[sender window] returnCode:NSOKButton];
+ else [NSApp endSheet:[sender window] returnCode:NSCancelButton];
+}
+
+
+- (void)sharedSecretSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
+{
+ NSButton * button = (NSButton *)contextInfo;
+ [sheet orderOut:self];
+ [self enableControls];
+
+ if (returnCode == NSOKButton) {
+ if ([button isEqualTo:hostNameSharedSecretButton]) {
+ hostNameSharedSecretName = [[NSString alloc] initWithString:[sharedSecretName stringValue]];
+ hostNameSharedSecretValue = [[NSString alloc] initWithString:[sharedSecretValue stringValue]];
+ } else {
+ regSharedSecretName = [[NSString alloc] initWithString:[sharedSecretName stringValue]];
+ regSharedSecretValue = [[NSString alloc] initWithString:[sharedSecretValue stringValue]];
+ }
+ [self updateApplyButtonState];
+ }
+ [sharedSecretValue setStringValue:@""];
+}
+
+
+- (BOOL)domainAlreadyInList:(NSString *)domainString
+{
+ if (browseDomainsArray) {
+ NSDictionary *domainDict;
+ NSString *domainName;
+ NSEnumerator *arrayEnumerator = [browseDomainsArray objectEnumerator];
+ while ((domainDict = [arrayEnumerator nextObject]) != NULL) {
+ domainName = [domainDict objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
+ if ([domainString caseInsensitiveCompare:domainName] == NSOrderedSame) return YES;
+ }
+ }
+ return NO;
+}
+
+
+- (NSString *)trimCharactersFromDomain:(NSString *)domain
+{
+ NSMutableCharacterSet * trimSet = [[[NSCharacterSet whitespaceCharacterSet] mutableCopy] autorelease];
+ [trimSet formUnionWithCharacterSet:[NSCharacterSet punctuationCharacterSet]];
+ return [domain stringByTrimmingCharactersInSet:trimSet];
+}
+
+
+- (void)addBrowseDomainSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
+{
+ (void)contextInfo; // Unused
+ [sheet orderOut:self];
+ [self enableControls];
+
+ if (returnCode == NSOKButton) {
+ NSString * newBrowseDomainString = [self trimCharactersFromDomain:[browseDomainsComboBox stringValue]];
+ NSMutableDictionary *newBrowseDomainDict;
+
+ if (browseDomainsArray == nil) browseDomainsArray = [[NSMutableArray alloc] initWithCapacity:0];
+ if ([self domainAlreadyInList:newBrowseDomainString] == NO) {
+ newBrowseDomainDict = [[[NSMutableDictionary alloc] initWithCapacity:2] autorelease];
+
+ [newBrowseDomainDict setObject:newBrowseDomainString forKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
+ [newBrowseDomainDict setObject:[[[NSNumber alloc] initWithBool:YES] autorelease] forKey:(NSString *)SC_DYNDNS_ENABLED_KEY];
+
+ [browseDomainsArray addObject:newBrowseDomainDict];
+ [browseDomainsArray sortUsingFunction:MyDomainArrayCompareFunction context:nil];
+ [browseDomainList reloadData];
+ [self updateApplyButtonState];
+ }
+ }
+}
+
+
+-(void)validateTextFields
+{
+ [hostName validateEditing];
+ [browseDomainsComboBox validateEditing];
+ [regDomainsComboBox validateEditing];
+}
+
+
+- (IBAction)changeButtonPressed:(id)sender
+{
+ NSString * keyName;
+
+ [self disableControls];
+ [self validateTextFields];
+ [mainWindow makeFirstResponder:nil];
+ [browseDomainList deselectAll:sender];
+
+ if ([sender isEqualTo:hostNameSharedSecretButton]) {
+ if (hostNameSharedSecretValue) {
+ [sharedSecretValue setStringValue:hostNameSharedSecretValue];
+ } else if ((keyName = [self sharedSecretKeyName:[hostName stringValue]]) != NULL) {
+ [sharedSecretName setStringValue:keyName];
+ [sharedSecretValue setStringValue:@"****************"];
+ } else {
+ [sharedSecretName setStringValue:[hostName stringValue]];
+ [sharedSecretValue setStringValue:@""];
+ }
+
+ } else {
+ if (regSharedSecretValue) {
+ [sharedSecretValue setStringValue:regSharedSecretValue];
+ } else if ((keyName = [self sharedSecretKeyName:[regDomainsComboBox stringValue]]) != NULL) {
+ [sharedSecretName setStringValue:keyName];
+ [sharedSecretValue setStringValue:@"****************"];
+ } else {
+ [sharedSecretName setStringValue:[regDomainsComboBox stringValue]];
+ [sharedSecretValue setStringValue:@""];
+ }
+ }
+
+ [sharedSecretWindow resignFirstResponder];
+
+ if ([[sharedSecretName stringValue] length] > 0) [sharedSecretWindow makeFirstResponder:sharedSecretValue];
+ else [sharedSecretWindow makeFirstResponder:sharedSecretName];
+
+ [NSApp beginSheet:sharedSecretWindow modalForWindow:mainWindow modalDelegate:self
+ didEndSelector:@selector(sharedSecretSheetDidEnd:returnCode:contextInfo:) contextInfo:sender];
+}
+
+
+- (IBAction)wideAreaCheckBoxChanged:(id)sender
+{
+ [self toggleWideAreaBonjour:[sender state]];
+ [self updateApplyButtonState];
+ [mainWindow makeFirstResponder:nil];
+}
+
+
+- (void)updateApplyButtonState
+{
+ NSString *hostNameString = [hostName stringValue];
+ NSString *regDomainString = [regDomainsComboBox stringValue];
+
+ NSComparisonResult hostNameResult = [hostNameString compare:currentHostName];
+ NSComparisonResult regDomainResult = [regDomainString compare:currentRegDomain];
+
+ if ((currentHostName && (hostNameResult != NSOrderedSame)) ||
+ (currentRegDomain && (regDomainResult != NSOrderedSame) && ([wideAreaCheckBox state])) ||
+ (currentHostName == nil && ([hostNameString length]) > 0) ||
+ (currentRegDomain == nil && ([regDomainString length]) > 0) ||
+ (currentWideAreaState != [wideAreaCheckBox state]) ||
+ (hostNameSharedSecretValue != nil) ||
+ (regSharedSecretValue != nil) ||
+ (browseDomainsArray && [browseDomainsArray isEqualToArray:currentBrowseDomainsArray] == NO))
+ {
+ [self enableApplyButton];
+ } else {
+ [self disableApplyButton];
+ }
+}
+
+
+
+- (void)controlTextDidChange:(NSNotification *)notification
+{
+ (void)notification; // Unused
+ [self updateApplyButtonState];
+}
+
+
+
+- (IBAction)comboAction:(id)sender
+{
+ (void)sender; // Unused
+ [self updateApplyButtonState];
+}
+
+
+- (id)comboBox:(NSComboBox *)aComboBox objectValueForItemAtIndex:(int)ind
+{
+ NSString *domain = nil;
+ if ([aComboBox isEqualTo:browseDomainsComboBox]) domain = [browseDataSource objectAtIndex:ind];
+ else if ([aComboBox isEqualTo:regDomainsComboBox]) domain = [registrationDataSource objectAtIndex:ind];
+ return domain;
+}
+
+
+
+- (int)numberOfItemsInComboBox:(NSComboBox *)aComboBox
+{
+ int count = 0;
+ if ([aComboBox isEqualTo:browseDomainsComboBox]) count = [browseDataSource count];
+ else if ([aComboBox isEqualTo:regDomainsComboBox]) count = [registrationDataSource count];
+ return count;
+}
+
+
+- (NSMutableArray *)browseDataSource
+{
+ return browseDataSource;
+}
+
+
+- (NSMutableArray *)registrationDataSource
+{
+ return registrationDataSource;
+}
+
+
+- (NSComboBox *)browseDomainsComboBox
+{
+ return browseDomainsComboBox;
+}
+
+
+- (NSComboBox *)regDomainsComboBox
+{
+ return regDomainsComboBox;
+}
+
+
+- (NSString *)currentRegDomain
+{
+ return currentRegDomain;
+}
+
+
+- (NSMutableArray *)defaultBrowseDomainsArray
+{
+ return defaultBrowseDomainsArray;
+}
+
+
+- (NSArray *)currentBrowseDomainsArray
+{
+ return currentBrowseDomainsArray;
+}
+
+
+- (NSString *)currentHostName
+{
+ return currentHostName;
+}
+
+
+- (NSString *)defaultRegDomain
+{
+ return defaultRegDomain;
+}
+
+
+- (void)setDefaultRegDomain:(NSString *)domain
+{
+ [defaultRegDomain release];
+ defaultRegDomain = domain;
+ [defaultRegDomain retain];
+}
+
+
+- (void)didSelect
+{
+ [super didSelect];
+ mainWindow = [[self mainView] window];
+}
+
+
+- (void)mainViewDidLoad
+{
+ [comboAuthButton setString:"system.preferences"];
+ [comboAuthButton setDelegate:self];
+ [comboAuthButton updateStatus:nil];
+ [comboAuthButton setAutoupdate:YES];
+}
+
+
+
+- (IBAction)applyClicked:(id)sender
+{
+ (void)sender; // Unused
+ [self applyCurrentState];
+}
+
+
+- (void)applyCurrentState
+{
+ [self validateTextFields];
+
+ if (toolInstalled == YES) {
+ [self savePreferences];
+ [self disableApplyButton];
+ [mainWindow makeFirstResponder:nil];
+ }
+}
+
+
+- (void)enableApplyButton
+{
+ [applyButton setEnabled:YES];
+ [revertButton setEnabled:YES];
+ prefsNeedUpdating = YES;
+}
+
+
+- (void)disableApplyButton
+{
+ [applyButton setEnabled:NO];
+ [revertButton setEnabled:NO];
+ prefsNeedUpdating = NO;
+}
+
+
+- (void)toggleWideAreaBonjour:(BOOL)state
+{
+ [wideAreaCheckBox setState:state];
+ [regDomainsComboBox setEnabled:state];
+ [registrationSharedSecretButton setEnabled:state];
+}
+
+
+- (IBAction)revertClicked:(id)sender
+{
+ [self restorePreferences];
+ [browseDomainList deselectAll:sender];
+ [mainWindow makeFirstResponder:nil];
+}
+
+
+- (void)restorePreferences
+{
+ [self setupInitialValues];
+}
+
+
+- (void)savePanelWillClose:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
+{
+ (void)sheet; // Unused
+ DNSServiceDiscoveryPref * me = (DNSServiceDiscoveryPref *)contextInfo;
+
+ if (returnCode == NSAlertDefaultReturn) {
+ [me applyCurrentState];
+ } else if (returnCode == NSAlertAlternateReturn ) {
+ [me restorePreferences];
+ }
+
+ [me enableControls];
+ [me replyToShouldUnselect:(returnCode != NSAlertOtherReturn)];
+}
+
+
+-(SecKeychainItemRef)copyKeychainItemforDomain:(NSString *)domain
+{
+ const char * serviceName = [domain UTF8String];
+ UInt32 type = 'ddns';
+ UInt32 typeLength = sizeof(type);
+
+ SecKeychainAttribute attrs[] = { { kSecServiceItemAttr, strlen(serviceName), (char *)serviceName },
+ { kSecTypeItemAttr, typeLength, (UInt32 *)&type } };
+
+ SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
+ SecKeychainSearchRef searchRef;
+ SecKeychainItemRef itemRef = NULL;
+ OSStatus err;
+
+ err = SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attributes, &searchRef);
+ if (err == noErr) {
+ err = SecKeychainSearchCopyNext(searchRef, &itemRef);
+ if (err != noErr) itemRef = NULL;
+ }
+ return itemRef;
+}
+
+
+-(NSString *)sharedSecretKeyName:(NSString * )domain
+{
+ SecKeychainItemRef itemRef = NULL;
+ NSString *keyName = nil;
+ OSStatus err;
+
+ err = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
+ assert(err == noErr);
+
+ itemRef = [self copyKeychainItemforDomain:[domain lowercaseString]];
+ if (itemRef) {
+ UInt32 tags[1];
+ SecKeychainAttributeInfo attrInfo;
+ SecKeychainAttributeList *attrList = NULL;
+ SecKeychainAttribute attribute;
+ unsigned int i;
+
+ tags[0] = kSecAccountItemAttr;
+ attrInfo.count = 1;
+ attrInfo.tag = tags;
+ attrInfo.format = NULL;
+
+ err = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, &attrList, NULL, NULL);
+ if (err == noErr) {
+ for (i = 0; i < attrList->count; i++) {
+ attribute = attrList->attr[i];
+ if (attribute.tag == kSecAccountItemAttr) {
+ keyName = [[NSString alloc] initWithBytes:attribute.data length:attribute.length encoding:NSUTF8StringEncoding];
+ break;
+ }
+ }
+ if (attrList) (void)SecKeychainItemFreeAttributesAndData(attrList, NULL);
+ }
+ CFRelease(itemRef);
+ }
+ return keyName;
+}
+
+
+-(NSString *)domainForHostName:(NSString *)hostNameString
+{
+ NSString * domainName = nil;
+ char text[64];
+ char * ptr = NULL;
+
+ ptr = (char *)[hostNameString UTF8String];
+ if (ptr) {
+ ptr = (char *)GetNextLabel(ptr, text);
+ domainName = [[NSString alloc] initWithUTF8String:(const char *)ptr];
+ }
+ return ([domainName autorelease]);
+}
+
+
+- (NSData *)dataForDomain:(NSString *)domainName isEnabled:(BOOL)enabled
+{
+ NSMutableArray *domainsArray;
+ NSMutableDictionary *domainDict = nil;
+
+ if (domainName && [domainName length] > 0) {
+ domainDict= [[[NSMutableDictionary alloc] initWithCapacity:2] autorelease];
+ [domainDict setObject:domainName forKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
+ [domainDict setObject:[[[NSNumber alloc] initWithBool:enabled] autorelease] forKey:(NSString *)SC_DYNDNS_ENABLED_KEY];
+ }
+ domainsArray = [[[NSMutableArray alloc] initWithCapacity:1] autorelease];
+ if (domainDict) [domainsArray addObject:domainDict];
+ return [NSArchiver archivedDataWithRootObject:domainsArray];
+}
+
+
+- (NSData *)dataForDomainArray:(NSArray *)domainArray
+{
+ return [NSArchiver archivedDataWithRootObject:domainArray];
+}
+
+
+- (NSData *)dataForSharedSecret:(NSString *)secret domain:(NSString *)domainName key:(NSString *)keyName
+{
+ NSMutableDictionary *sharedSecretDict = [[[NSMutableDictionary alloc] initWithCapacity:3] autorelease];
+ [sharedSecretDict setObject:secret forKey:(NSString *)SC_DYNDNS_SECRET_KEY];
+ [sharedSecretDict setObject:[domainName lowercaseString] forKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
+ [sharedSecretDict setObject:keyName forKey:(NSString *)SC_DYNDNS_KEYNAME_KEY];
+ return [NSArchiver archivedDataWithRootObject:sharedSecretDict];
+}
+
+
+-(void)savePreferences
+{
+ NSString *hostNameString = [hostName stringValue];
+ NSString *browseDomainString = [browseDomainsComboBox stringValue];
+ NSString *regDomainString = [regDomainsComboBox stringValue];
+ NSString *tempHostNameSharedSecretName = hostNameSharedSecretName;
+ NSString *tempRegSharedSecretName = regSharedSecretName;
+ NSData *browseDomainData = nil;
+ BOOL regSecretWasSet = NO;
+ BOOL hostSecretWasSet = NO;
+ OSStatus err = noErr;
+
+ hostNameString = [self trimCharactersFromDomain:hostNameString];
+ browseDomainString = [self trimCharactersFromDomain:browseDomainString];
+ regDomainString = [self trimCharactersFromDomain:regDomainString];
+ tempHostNameSharedSecretName = [self trimCharactersFromDomain:tempHostNameSharedSecretName];
+ tempRegSharedSecretName = [self trimCharactersFromDomain:tempRegSharedSecretName];
+
+ [hostName setStringValue:hostNameString];
+ [regDomainsComboBox setStringValue:regDomainString];
+
+ // Convert Shared Secret account names to lowercase.
+ tempHostNameSharedSecretName = [tempHostNameSharedSecretName lowercaseString];
+ tempRegSharedSecretName = [tempRegSharedSecretName lowercaseString];
+
+ // Save hostname shared secret.
+ if ([hostNameSharedSecretName length] > 0 && ([hostNameSharedSecretValue length] > 0)) {
+ SetKeyForDomain((CFDataRef)[self dataForSharedSecret:hostNameSharedSecretValue domain:hostNameString key:tempHostNameSharedSecretName]);
+ [hostNameSharedSecretValue release];
+ hostNameSharedSecretValue = nil;
+ hostSecretWasSet = YES;
+ }
+
+ // Save registration domain shared secret.
+ if (([regSharedSecretName length] > 0) && ([regSharedSecretValue length] > 0)) {
+ SetKeyForDomain((CFDataRef)[self dataForSharedSecret:regSharedSecretValue domain:regDomainString key:tempRegSharedSecretName]);
+ [regSharedSecretValue release];
+ regSharedSecretValue = nil;
+ regSecretWasSet = YES;
+ }
+
+ // Save hostname.
+ if ((currentHostName == NULL) || [currentHostName compare:hostNameString] != NSOrderedSame) {
+ err = WriteHostname((CFDataRef)[self dataForDomain:hostNameString isEnabled:YES]);
+ if (err != noErr) NSLog(@"WriteHostname returned %d\n", (int32_t)err);
+ currentHostName = [hostNameString copy];
+ } else if (hostSecretWasSet) {
+ WriteHostname((CFDataRef)[self dataForDomain:@"" isEnabled:NO]);
+ usleep(200000); // Temporary hack
+ if ([currentHostName length] > 0) WriteHostname((CFDataRef)[self dataForDomain:(NSString *)currentHostName isEnabled:YES]);
+ }
+
+ // Save browse domain.
+ if (browseDomainsArray && [browseDomainsArray isEqualToArray:currentBrowseDomainsArray] == NO) {
+ browseDomainData = [self dataForDomainArray:browseDomainsArray];
+ err = WriteBrowseDomain((CFDataRef)browseDomainData);
+ if (err != noErr) NSLog(@"WriteBrowseDomain returned %d\n", (int32_t)err);
+ currentBrowseDomainsArray = [browseDomainsArray copy];
+ }
+
+ // Save registration domain.
+ if ((currentRegDomain == NULL) || ([currentRegDomain compare:regDomainString] != NSOrderedSame) || (currentWideAreaState != [wideAreaCheckBox state])) {
+
+ err = WriteRegistrationDomain((CFDataRef)[self dataForDomain:regDomainString isEnabled:[wideAreaCheckBox state]]);
+ if (err != noErr) NSLog(@"WriteRegistrationDomain returned %d\n", (int32_t)err);
+
+ if (currentRegDomain) CFRelease(currentRegDomain);
+ currentRegDomain = [regDomainString copy];
+
+ if ([currentRegDomain length] > 0) {
+ currentWideAreaState = [wideAreaCheckBox state];
+ [registrationDataSource removeObject:regDomainString];
+ [registrationDataSource addObject:currentRegDomain];
+ [registrationDataSource sortUsingFunction:MyArrayCompareFunction context:nil];
+ [regDomainsComboBox reloadData];
+ } else {
+ currentWideAreaState = NO;
+ [self toggleWideAreaBonjour:NO];
+ if (defaultRegDomain != nil) [regDomainsComboBox setStringValue:defaultRegDomain];
+ }
+ } else if (regSecretWasSet) {
+ WriteRegistrationDomain((CFDataRef)[self dataForDomain:@"" isEnabled:NO]);
+ usleep(200000); // Temporary hack
+ if ([currentRegDomain length] > 0) WriteRegistrationDomain((CFDataRef)[self dataForDomain:currentRegDomain isEnabled:currentWideAreaState]);
+ }
+}
+
+
+- (NSPreferencePaneUnselectReply)shouldUnselect
+{
+#if 1
+ if (prefsNeedUpdating == YES) {
+
+ [self disableControls];
+
+ NSBeginAlertSheet(
+ @"Apply Configuration Changes?",
+ @"Apply",
+ @"Don't Apply",
+ @"Cancel",
+ mainWindow,
+ self,
+ @selector( savePanelWillClose:returnCode:contextInfo: ),
+ NULL,
+ (void *) self, // sender,
+ @"" );
+ return NSUnselectLater;
+ }
+#endif
+
+ return NSUnselectNow;
+}
+
+
+-(void)disableControls
+{
+ [hostName setEnabled:NO];
+ [hostNameSharedSecretButton setEnabled:NO];
+ [browseDomainsComboBox setEnabled:NO];
+ [applyButton setEnabled:NO];
+ [revertButton setEnabled:NO];
+ [wideAreaCheckBox setEnabled:NO];
+ [regDomainsComboBox setEnabled:NO];
+ [registrationSharedSecretButton setEnabled:NO];
+ [statusImageView setEnabled:NO];
+
+ browseDomainListEnabled = NO;
+ [browseDomainList deselectAll:self];
+ [browseDomainList setEnabled:NO];
+
+ [addBrowseDomainButton setEnabled:NO];
+ [removeBrowseDomainButton setEnabled:NO];
+}
+
+
+- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row
+{
+ (void)row; // Unused
+ (void)tableView; // Unused
+ return browseDomainListEnabled;
+}
+
+
+-(void)enableControls
+{
+ [hostName setEnabled:YES];
+ [hostNameSharedSecretButton setEnabled:YES];
+ [browseDomainsComboBox setEnabled:YES];
+ [wideAreaCheckBox setEnabled:YES];
+ [registrationSharedSecretButton setEnabled:YES];
+ [self toggleWideAreaBonjour:[wideAreaCheckBox state]];
+ [statusImageView setEnabled:YES];
+ [addBrowseDomainButton setEnabled:YES];
+
+ [browseDomainList setEnabled:YES];
+ [browseDomainList deselectAll:self];
+ browseDomainListEnabled = YES;
+
+ [removeBrowseDomainButton setEnabled:[browseDomainList numberOfSelectedRows]];
+ [applyButton setEnabled:prefsNeedUpdating];
+ [revertButton setEnabled:prefsNeedUpdating];
+}
+
+
+- (void)authorizationViewDidAuthorize:(SFAuthorizationView *)view
+{
+ (void)view; // Unused
+ [self enableControls];
+}
+
+
+- (void)authorizationViewDidDeauthorize:(SFAuthorizationView *)view
+{
+ (void)view; // Unused
+ [self disableControls];
+}
+
+@end
+
+
+// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
+// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+// To expand "version" to its value before making the string, use STRINGIFY(version) instead
+#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
+#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
+
+// NOT static -- otherwise the compiler may optimize it out
+// The "@(#) " pattern is a special prefix the "what" command looks for
+const char VersionString_SCCS[] = "@(#) Bonjour Preference Pane " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
+
+#if _BUILDING_XCODE_PROJECT_
+// If the process crashes, then this string will be magically included in the automatically-generated crash log
+const char *__crashreporter_info__ = VersionString_SCCS + 5;
+asm(".desc ___crashreporter_info__, 0x10");
+#endif
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/classes.nib b/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/classes.nib
new file mode 100644
index 00000000..58c1f3e5
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/classes.nib
@@ -0,0 +1,59 @@
+{
+ IBClasses = (
+ {
+ ACTIONS = {
+ addBrowseDomainClicked = id;
+ applyClicked = id;
+ changeButtonPressed = id;
+ closeMyCustomSheet = id;
+ comboAction = id;
+ enableBrowseDomainClicked = id;
+ removeBrowseDomainClicked = id;
+ revertClicked = id;
+ wideAreaCheckBoxChanged = id;
+ };
+ CLASS = DNSServiceDiscoveryPref;
+ LANGUAGE = ObjC;
+ OUTLETS = {
+ addBrowseDomainButton = NSButton;
+ addBrowseDomainWindow = NSWindow;
+ applyButton = NSButton;
+ browseCancelButton = NSButton;
+ browseDomainList = NSTableView;
+ browseDomainsComboBox = NSComboBox;
+ browseOKButton = NSButton;
+ comboAuthButton = SFAuthorizationView;
+ hostName = NSTextField;
+ hostNameSharedSecretButton = NSButton;
+ regDomainsComboBox = NSComboBox;
+ registrationSharedSecretButton = NSButton;
+ removeBrowseDomainButton = NSButton;
+ revertButton = NSButton;
+ secretCancelButton = NSButton;
+ secretOKButton = NSButton;
+ sharedSecretName = NSTextField;
+ sharedSecretValue = NSSecureTextField;
+ sharedSecretWindow = NSWindow;
+ statusImageView = NSImageView;
+ tabView = NSTabView;
+ wideAreaCheckBox = NSButton;
+ };
+ SUPERCLASS = NSPreferencePane;
+ },
+ {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
+ {
+ CLASS = NSPreferencePane;
+ LANGUAGE = ObjC;
+ OUTLETS = {
+ "_firstKeyView" = id;
+ "_initialKeyView" = id;
+ "_lastKeyView" = id;
+ "_window" = id;
+ };
+ SUPERCLASS = NSObject;
+ },
+ {CLASS = NSSegmentedControl; LANGUAGE = ObjC; SUPERCLASS = NSControl; },
+ {CLASS = SFAuthorizationView; LANGUAGE = ObjC; SUPERCLASS = NSView; }
+ );
+ IBVersion = 1;
+} \ No newline at end of file
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/info.nib b/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/info.nib
new file mode 100644
index 00000000..e8dbd926
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/info.nib
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IBDocumentLocation</key>
+ <string>32 63 547 281 0 0 1024 746 </string>
+ <key>IBFramework Version</key>
+ <string>439.0</string>
+ <key>IBOpenObjects</key>
+ <array>
+ <integer>255</integer>
+ <integer>333</integer>
+ <integer>12</integer>
+ </array>
+ <key>IBSystem Version</key>
+ <string>8F23</string>
+</dict>
+</plist>
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/keyedobjects.nib b/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/keyedobjects.nib
new file mode 100644
index 00000000..eec01ee4
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/keyedobjects.nib
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/InfoPlist.strings b/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/InfoPlist.strings
new file mode 100644
index 00000000..e2dfa991
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/InfoPlist.strings
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Info-PreferencePane.plist b/mDNSResponder/mDNSMacOSX/PreferencePane/Info-PreferencePane.plist
new file mode 100644
index 00000000..e5cdb9f2
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Info-PreferencePane.plist
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>Bonjour</string>
+ <key>CFBundleGetInfoString</key>
+ <string></string>
+ <key>CFBundleIconFile</key>
+ <string>BonjourPref</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.apple.preference.bonjour</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string></string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>NSMainNibFile</key>
+ <string>DNSServiceDiscoveryPref</string>
+ <key>NSPrefPaneIconFile</key>
+ <string>BonjourPref.tiff</string>
+ <key>NSPrefPaneIconLabel</key>
+ <string>Bonjour</string>
+ <key>NSPrincipalClass</key>
+ <string>DNSServiceDiscoveryPref</string>
+</dict>
+</plist>
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.c b/mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.c
new file mode 100644
index 00000000..4c0ffa0e
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.c
@@ -0,0 +1,230 @@
+/*
+ File: PrivilegedOperations.c
+
+ Abstract: Interface to "ddnswriteconfig" setuid root tool.
+
+ Copyright: (c) Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "PrivilegedOperations.h"
+#include "ConfigurationAuthority.h"
+#include <CoreFoundation/CoreFoundation.h>
+#include <SystemConfiguration/SystemConfiguration.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <AssertMacros.h>
+#include <Security/Security.h>
+
+Boolean gToolApproved = false;
+
+static pid_t execTool(const char *args[])
+// fork/exec and return new pid
+{
+ pid_t child;
+
+ child = vfork();
+ if (child == 0)
+ {
+ execv(args[0], (char *const *)args);
+ printf("exec of %s failed; errno = %d\n", args[0], errno);
+ _exit(-1); // exec failed
+ }
+ else
+ return child;
+}
+
+OSStatus EnsureToolInstalled(void)
+// Make sure that the tool is installed in the right place, with the right privs, and the right version.
+{
+ CFURLRef bundleURL;
+ pid_t toolPID;
+ int status;
+ OSStatus err = noErr;
+ const char *args[] = { kToolPath, "0", "V", NULL };
+ char toolSourcePath[PATH_MAX] = {};
+ char toolInstallerPath[PATH_MAX] = {};
+
+ if (gToolApproved)
+ return noErr;
+
+ // Check version of installed tool
+ toolPID = execTool(args);
+ if (toolPID > 0)
+ {
+ waitpid(toolPID, &status, 0);
+ if (WIFEXITED(status) && WEXITSTATUS(status) == PRIV_OP_TOOL_VERS)
+ return noErr;
+ }
+
+ // Locate our in-bundle copy of privop tool
+ bundleURL = CFBundleCopyBundleURL(CFBundleGetBundleWithIdentifier(CFSTR("com.apple.preference.bonjour")) );
+ if (bundleURL != NULL)
+ {
+ CFURLGetFileSystemRepresentation(bundleURL, false, (UInt8*) toolSourcePath, sizeof toolSourcePath);
+ if (strlcat(toolSourcePath, "/Contents/Resources/" kToolName, sizeof toolSourcePath ) >= sizeof toolSourcePath ) return(-1);
+ CFURLGetFileSystemRepresentation(bundleURL, false, (UInt8*) toolInstallerPath, sizeof toolInstallerPath);
+ if (strlcat(toolInstallerPath, "/Contents/Resources/" kToolInstaller, sizeof toolInstallerPath) >= sizeof toolInstallerPath) return(-1);
+ }
+ else
+ return coreFoundationUnknownErr;
+
+ // Obtain authorization and run in-bundle copy as root to install it
+ {
+ AuthorizationItem aewpRight = { kAuthorizationRightExecute, strlen(toolInstallerPath), toolInstallerPath, 0 };
+ AuthorizationItemSet rights = { 1, &aewpRight };
+ AuthorizationRef authRef;
+
+ err = AuthorizationCreate(&rights, (AuthorizationEnvironment*) NULL,
+ kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights |
+ kAuthorizationFlagPreAuthorize, &authRef);
+ if (err == noErr)
+ {
+ char *installerargs[] = { toolSourcePath, NULL };
+ err = AuthorizationExecuteWithPrivileges(authRef, toolInstallerPath, 0, installerargs, (FILE**) NULL);
+ if (err == noErr) {
+ int pid = wait(&status);
+ if (pid > 0 && WIFEXITED(status)) {
+ err = WEXITSTATUS(status);
+ if (err == noErr) {
+ gToolApproved = true;
+ }
+ } else {
+ err = -1;
+ }
+ }
+ (void) AuthorizationFree(authRef, kAuthorizationFlagDefaults);
+ }
+ }
+
+ return err;
+}
+
+
+static OSStatus ExecWithCmdAndParam(const char *subCmd, CFDataRef paramData)
+// Execute our privop tool with the supplied subCmd and parameter
+{
+ OSStatus err = noErr;
+ int commFD, dataLen;
+ u_int32_t len;
+ pid_t child;
+ char fileNum[16];
+ UInt8 *buff;
+ const char *args[] = { kToolPath, NULL, "A", NULL, NULL };
+ AuthorizationExternalForm authExt;
+
+ err = ExternalizeAuthority(&authExt);
+ require_noerr(err, AuthFailed);
+
+ dataLen = CFDataGetLength(paramData);
+ buff = (UInt8*) malloc(dataLen * sizeof(UInt8));
+ require_action(buff != NULL, AllocBuffFailed, err=memFullErr;);
+ {
+ CFRange all = { 0, dataLen };
+ CFDataGetBytes(paramData, all, buff);
+ }
+
+ commFD = fileno(tmpfile());
+ sprintf(fileNum, "%d", commFD);
+ args[1] = fileNum;
+ args[3] = subCmd;
+
+ // write authority to pipe
+ len = 0; // tag, unused
+ write(commFD, &len, sizeof len);
+ len = sizeof authExt; // len
+ write(commFD, &len, sizeof len);
+ write(commFD, &authExt, len);
+
+ // write parameter to pipe
+ len = 0; // tag, unused
+ write(commFD, &len, sizeof len);
+ len = dataLen; // len
+ write(commFD, &len, sizeof len);
+ write(commFD, buff, len);
+
+ child = execTool(args);
+ if (child > 0) {
+ int status;
+ waitpid(child, &status, 0);
+ if (WIFEXITED(status))
+ err = WEXITSTATUS(status);
+ //fprintf(stderr, "child exited; status = %d (%ld)\n", status, err);
+ }
+
+ close(commFD);
+
+ free(buff);
+AllocBuffFailed:
+AuthFailed:
+ return err;
+}
+
+OSStatus
+WriteBrowseDomain(CFDataRef domainArrayData)
+{
+ if (!CurrentlyAuthorized())
+ return authFailErr;
+ return ExecWithCmdAndParam("Wb", domainArrayData);
+}
+
+OSStatus
+WriteRegistrationDomain(CFDataRef domainArrayData)
+{
+ if (!CurrentlyAuthorized())
+ return authFailErr;
+ return ExecWithCmdAndParam("Wd", domainArrayData);
+}
+
+OSStatus
+WriteHostname(CFDataRef domainArrayData)
+{
+ if (!CurrentlyAuthorized())
+ return authFailErr;
+ return ExecWithCmdAndParam("Wh", domainArrayData);
+}
+
+OSStatus
+SetKeyForDomain(CFDataRef secretData)
+{
+ if (!CurrentlyAuthorized())
+ return authFailErr;
+ return ExecWithCmdAndParam("Wk", secretData);
+}
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.h b/mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.h
new file mode 100644
index 00000000..91a60daf
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.h
@@ -0,0 +1,70 @@
+/*
+ File: PrivilegedOperations.h
+
+ Abstract: Interface to "ddnswriteconfig" setuid root tool.
+
+ Copyright: (c) Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <CoreServices/CoreServices.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+#define PRIV_OP_TOOL_VERS 4
+
+#define kToolName "ddnswriteconfig"
+#define kToolPath "/Library/Application Support/Bonjour/" kToolName
+#define kToolInstaller "installtool"
+
+#define SC_DYNDNS_SETUP_KEY CFSTR("Setup:/Network/DynamicDNS")
+#define SC_DYNDNS_STATE_KEY CFSTR("State:/Network/DynamicDNS")
+#define SC_DYNDNS_REGDOMAINS_KEY CFSTR("RegistrationDomains")
+#define SC_DYNDNS_BROWSEDOMAINS_KEY CFSTR("BrowseDomains")
+#define SC_DYNDNS_HOSTNAMES_KEY CFSTR("HostNames")
+#define SC_DYNDNS_DOMAIN_KEY CFSTR("Domain")
+#define SC_DYNDNS_KEYNAME_KEY CFSTR("KeyName")
+#define SC_DYNDNS_SECRET_KEY CFSTR("Secret")
+#define SC_DYNDNS_ENABLED_KEY CFSTR("Enabled")
+#define SC_DYNDNS_STATUS_KEY CFSTR("Status")
+#define DYNDNS_KEYCHAIN_DESCRIPTION "Dynamic DNS Key"
+
+
+OSStatus EnsureToolInstalled(void);
+OSStatus WriteRegistrationDomain(CFDataRef domainArrayData);
+OSStatus WriteBrowseDomain(CFDataRef domainArrayData);
+OSStatus WriteHostname(CFDataRef domainArrayData);
+OSStatus SetKeyForDomain(CFDataRef secretData);
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/ddnswriteconfig.m b/mDNSResponder/mDNSMacOSX/PreferencePane/ddnswriteconfig.m
new file mode 100644
index 00000000..437879bc
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/ddnswriteconfig.m
@@ -0,0 +1,442 @@
+/*
+ File: ddnswriteconfig.m
+
+ Abstract: Setuid root tool invoked by Preference Pane to perform
+ privileged accesses to system configuration preferences and the system keychain.
+ Invoked by PrivilegedOperations.c.
+
+ Copyright: (c) Copyright 2005 Apple Computer, Inc. All rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#import "PrivilegedOperations.h"
+#import "ConfigurationRights.h"
+
+#import <stdio.h>
+#import <stdint.h>
+#import <stdlib.h>
+#import <unistd.h>
+#import <fcntl.h>
+#import <errno.h>
+#import <sys/types.h>
+#import <sys/stat.h>
+#import <sys/mman.h>
+#import <mach-o/dyld.h>
+#import <dns_sd.h>
+#import <AssertMacros.h>
+#import <Security/Security.h>
+#import <CoreServices/CoreServices.h>
+#import <CoreFoundation/CoreFoundation.h>
+#import <SystemConfiguration/SystemConfiguration.h>
+#import <Foundation/Foundation.h>
+
+
+static AuthorizationRef gAuthRef = 0;
+
+static OSStatus
+WriteArrayToDynDNS(CFStringRef arrayKey, CFArrayRef domainArray)
+{
+ SCPreferencesRef store;
+ OSStatus err = noErr;
+ CFDictionaryRef origDict;
+ CFMutableDictionaryRef dict = NULL;
+ Boolean result;
+ CFStringRef scKey = CFSTR("/System/Network/DynamicDNS");
+
+
+ // Add domain to the array member ("arrayKey") of the DynamicDNS dictionary
+ // Will replace duplicate, at head of list
+ // At this point, we only support a single-item list
+ store = SCPreferencesCreate(NULL, CFSTR("com.apple.preference.bonjour"), NULL);
+ require_action(store != NULL, SysConfigErr, err=paramErr;);
+ require_action(true == SCPreferencesLock( store, true), LockFailed, err=coreFoundationUnknownErr;);
+
+ origDict = SCPreferencesPathGetValue(store, scKey);
+ if (origDict) {
+ dict = CFDictionaryCreateMutableCopy(NULL, 0, origDict);
+ }
+
+ if (!dict) {
+ dict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ }
+ require_action( dict != NULL, NoDict, err=memFullErr;);
+
+ if (CFArrayGetCount(domainArray) > 0) {
+ CFDictionarySetValue(dict, arrayKey, domainArray);
+ } else {
+ CFDictionaryRemoveValue(dict, arrayKey);
+ }
+
+ result = SCPreferencesPathSetValue(store, scKey, dict);
+ require_action(result, SCError, err=kernelPrivilegeErr;);
+
+ result = SCPreferencesCommitChanges(store);
+ require_action(result, SCError, err=kernelPrivilegeErr;);
+ result = SCPreferencesApplyChanges(store);
+ require_action(result, SCError, err=kernelPrivilegeErr;);
+
+SCError:
+ CFRelease(dict);
+NoDict:
+ SCPreferencesUnlock(store);
+LockFailed:
+ CFRelease(store);
+SysConfigErr:
+ return err;
+}
+
+
+static int
+readTaggedBlock(int fd, u_int32_t *pTag, u_int32_t *pLen, char **ppBuff)
+// Read tag, block len and block data from stream and return. Dealloc *ppBuff via free().
+{
+ ssize_t num;
+ u_int32_t tag, len; // Don't use ssize_t because that's different on 32- vs. 64-bit
+ int result = 0;
+
+ num = read(fd, &tag, sizeof tag);
+ require_action(num == sizeof tag, GetTagFailed, result = -1;);
+ num = read(fd, &len, sizeof len);
+ require_action(num == sizeof len, GetLenFailed, result = -1;);
+
+ *ppBuff = (char*) malloc( len);
+ require_action(*ppBuff != NULL, AllocFailed, result = -1;);
+
+ num = read(fd, *ppBuff, len);
+ if (num == (ssize_t)len) {
+ *pTag = tag;
+ *pLen = len;
+ } else {
+ free(*ppBuff);
+ result = -1;
+ }
+
+AllocFailed:
+GetLenFailed:
+GetTagFailed:
+ return result;
+}
+
+
+
+static int
+SetAuthInfo( int fd)
+{
+ int result = 0;
+ u_int32_t tag, len;
+ char *p;
+
+ result = readTaggedBlock( fd, &tag, &len, &p);
+ require( result == 0, ReadParamsFailed);
+ require( len == sizeof(AuthorizationExternalForm), ReadParamsFailed);
+ require( len == kAuthorizationExternalFormLength, ReadParamsFailed);
+
+ if (gAuthRef != 0) {
+ (void) AuthorizationFree(gAuthRef, kAuthorizationFlagDefaults);
+ gAuthRef = 0;
+ }
+
+ result = AuthorizationCreateFromExternalForm((AuthorizationExternalForm*) p, &gAuthRef);
+
+ free( p);
+ReadParamsFailed:
+ return result;
+}
+
+
+static int
+HandleWriteDomain(int fd, int domainType)
+{
+ CFArrayRef domainArray;
+ CFDataRef domainData;
+ int result = 0;
+ u_int32_t tag, len;
+ char *p;
+
+ AuthorizationItem scAuth = { UPDATE_SC_RIGHT, 0, NULL, 0 };
+ AuthorizationRights authSet = { 1, &scAuth };
+
+ if (noErr != (result = AuthorizationCopyRights(gAuthRef, &authSet, NULL, (AuthorizationFlags)0, NULL)))
+ return result;
+
+ result = readTaggedBlock(fd, &tag, &len, &p);
+ require(result == 0, ReadParamsFailed);
+
+ domainData = CFDataCreate(NULL, (UInt8 *)p, len);
+ domainArray = (CFArrayRef)[NSUnarchiver unarchiveObjectWithData:(NSData *)domainData];
+
+ if (domainType) {
+ result = WriteArrayToDynDNS(SC_DYNDNS_REGDOMAINS_KEY, domainArray);
+ } else {
+ result = WriteArrayToDynDNS(SC_DYNDNS_BROWSEDOMAINS_KEY, domainArray);
+ }
+
+ReadParamsFailed:
+ return result;
+}
+
+
+static int
+HandleWriteHostname(int fd)
+{
+ CFArrayRef domainArray;
+ CFDataRef domainData;
+ int result = 0;
+ u_int32_t tag, len;
+ char *p;
+
+ AuthorizationItem scAuth = { UPDATE_SC_RIGHT, 0, NULL, 0 };
+ AuthorizationRights authSet = { 1, &scAuth };
+
+ if (noErr != (result = AuthorizationCopyRights(gAuthRef, &authSet, NULL, (AuthorizationFlags) 0, NULL)))
+ return result;
+
+ result = readTaggedBlock(fd, &tag, &len, &p);
+ require(result == 0, ReadParamsFailed);
+
+ domainData = CFDataCreate(NULL, (const UInt8 *)p, len);
+ domainArray = (CFArrayRef)[NSUnarchiver unarchiveObjectWithData:(NSData *)domainData];
+ result = WriteArrayToDynDNS(SC_DYNDNS_HOSTNAMES_KEY, domainArray);
+
+ReadParamsFailed:
+ return result;
+}
+
+
+static SecAccessRef
+MyMakeUidAccess(uid_t uid)
+{
+ // make the "uid/gid" ACL subject
+ // this is a CSSM_LIST_ELEMENT chain
+ CSSM_ACL_PROCESS_SUBJECT_SELECTOR selector = {
+ CSSM_ACL_PROCESS_SELECTOR_CURRENT_VERSION, // selector version
+ CSSM_ACL_MATCH_UID, // set mask: match uids (only)
+ uid, // uid to match
+ 0 // gid (not matched here)
+ };
+ CSSM_LIST_ELEMENT subject2 = { NULL, 0, 0, {{0,0,0}} };
+ subject2.Element.Word.Data = (UInt8 *)&selector;
+ subject2.Element.Word.Length = sizeof(selector);
+ CSSM_LIST_ELEMENT subject1 = { &subject2, CSSM_ACL_SUBJECT_TYPE_PROCESS, CSSM_LIST_ELEMENT_WORDID, {{0,0,0}} };
+
+
+ // rights granted (replace with individual list if desired)
+ CSSM_ACL_AUTHORIZATION_TAG rights[] = {
+ CSSM_ACL_AUTHORIZATION_ANY // everything
+ };
+ // owner component (right to change ACL)
+ CSSM_ACL_OWNER_PROTOTYPE owner = {
+ // TypedSubject
+ { CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 },
+ // Delegate
+ false
+ };
+ // ACL entries (any number, just one here)
+ CSSM_ACL_ENTRY_INFO acls =
+ {
+ // CSSM_ACL_ENTRY_PROTOTYPE
+ {
+ { CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 }, // TypedSubject
+ false, // Delegate
+ { sizeof(rights) / sizeof(rights[0]), rights }, // Authorization rights for this entry
+ { { 0, 0 }, { 0, 0 } }, // CSSM_ACL_VALIDITY_PERIOD
+ "" // CSSM_STRING EntryTag
+ },
+ // CSSM_ACL_HANDLE
+ 0
+ };
+
+ SecAccessRef a = NULL;
+ (void) SecAccessCreateFromOwnerAndACL(&owner, 1, &acls, &a);
+ return a;
+}
+
+
+static OSStatus
+MyAddDynamicDNSPassword(SecKeychainRef keychain, SecAccessRef a, UInt32 serviceNameLength, const char *serviceName,
+ UInt32 accountNameLength, const char *accountName, UInt32 passwordLength, const void *passwordData)
+{
+ char * description = DYNDNS_KEYCHAIN_DESCRIPTION;
+ UInt32 descriptionLength = strlen(DYNDNS_KEYCHAIN_DESCRIPTION);
+ UInt32 type = 'ddns';
+ UInt32 creator = 'ddns';
+ UInt32 typeLength = sizeof(type);
+ UInt32 creatorLength = sizeof(creator);
+ OSStatus err;
+
+ // set up attribute vector (each attribute consists of {tag, length, pointer})
+ SecKeychainAttribute attrs[] = { { kSecLabelItemAttr, serviceNameLength, (char *)serviceName },
+ { kSecAccountItemAttr, accountNameLength, (char *)accountName },
+ { kSecServiceItemAttr, serviceNameLength, (char *)serviceName },
+ { kSecDescriptionItemAttr, descriptionLength, (char *)description },
+ { kSecTypeItemAttr, typeLength, (UInt32 *)&type },
+ { kSecCreatorItemAttr, creatorLength, (UInt32 *)&creator } };
+ SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
+
+ err = SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass, &attributes, passwordLength, passwordData, keychain, a, NULL);
+ return err;
+}
+
+
+static int
+SetKeychainEntry(int fd)
+// Create a new entry in system keychain, or replace existing
+{
+ CFDataRef secretData;
+ CFDictionaryRef secretDictionary;
+ CFStringRef keyNameString;
+ CFStringRef domainString;
+ CFStringRef secretString;
+ SecKeychainItemRef item = NULL;
+ int result = 0;
+ u_int32_t tag, len;
+ char *p;
+ char keyname[kDNSServiceMaxDomainName];
+ char domain[kDNSServiceMaxDomainName];
+ char secret[kDNSServiceMaxDomainName];
+
+ AuthorizationItem kcAuth = { EDIT_SYS_KEYCHAIN_RIGHT, 0, NULL, 0 };
+ AuthorizationRights authSet = { 1, &kcAuth };
+
+ if (noErr != (result = AuthorizationCopyRights(gAuthRef, &authSet, NULL, (AuthorizationFlags)0, NULL)))
+ return result;
+
+ result = readTaggedBlock(fd, &tag, &len, &p);
+ require_noerr(result, ReadParamsFailed);
+
+ secretData = CFDataCreate(NULL, (UInt8 *)p, len);
+ secretDictionary = (CFDictionaryRef)[NSUnarchiver unarchiveObjectWithData:(NSData *)secretData];
+
+ keyNameString = (CFStringRef)CFDictionaryGetValue(secretDictionary, SC_DYNDNS_KEYNAME_KEY);
+ assert(keyNameString != NULL);
+
+ domainString = (CFStringRef)CFDictionaryGetValue(secretDictionary, SC_DYNDNS_DOMAIN_KEY);
+ assert(domainString != NULL);
+
+ secretString = (CFStringRef)CFDictionaryGetValue(secretDictionary, SC_DYNDNS_SECRET_KEY);
+ assert(secretString != NULL);
+
+ CFStringGetCString(keyNameString, keyname, kDNSServiceMaxDomainName, kCFStringEncodingUTF8);
+ CFStringGetCString(domainString, domain, kDNSServiceMaxDomainName, kCFStringEncodingUTF8);
+ CFStringGetCString(secretString, secret, kDNSServiceMaxDomainName, kCFStringEncodingUTF8);
+
+ result = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
+ if (result == noErr) {
+ result = SecKeychainFindGenericPassword(NULL, strlen(domain), domain, 0, NULL, 0, NULL, &item);
+ if (result == noErr) {
+ result = SecKeychainItemDelete(item);
+ if (result != noErr) fprintf(stderr, "SecKeychainItemDelete returned %d\n", result);
+ }
+
+ result = MyAddDynamicDNSPassword(NULL, MyMakeUidAccess(0), strlen(domain), domain, strlen(keyname)+1, keyname, strlen(secret)+1, secret);
+ if (result != noErr) fprintf(stderr, "MyAddDynamicDNSPassword returned %d\n", result);
+ if (item) CFRelease(item);
+ }
+
+ReadParamsFailed:
+ return result;
+}
+
+
+int main( int argc, char **argv)
+/* argv[0] is the exec path; argv[1] is a fd for input data; argv[2]... are operation codes.
+ The tool supports the following operations:
+ V -- exit with status PRIV_OP_TOOL_VERS
+ A -- read AuthInfo from input pipe
+ Wd -- write registration domain to dynamic store
+ Wb -- write browse domain to dynamic store
+ Wh -- write hostname to dynamic store
+ Wk -- write keychain entry for given account name
+*/
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ int commFD = -1, iArg, result = 0;
+
+ if ( 0 != seteuid( 0))
+ return -1;
+
+ if ( argc == 3 && 0 == strcmp( argv[2], "V"))
+ return PRIV_OP_TOOL_VERS;
+
+ if ( argc > 1)
+ {
+ commFD = strtol( argv[1], NULL, 0);
+ lseek( commFD, 0, SEEK_SET);
+ }
+ for ( iArg = 2; iArg < argc && result == 0; iArg++)
+ {
+ if ( 0 == strcmp( "A", argv[ iArg])) // get auth info
+ {
+ result = SetAuthInfo( commFD);
+ }
+ else if ( 0 == strcmp( "Wd", argv[ iArg])) // Write registration domain
+ {
+ result = HandleWriteDomain( commFD, 1);
+ }
+ else if ( 0 == strcmp( "Wb", argv[ iArg])) // Write browse domain
+ {
+ result = HandleWriteDomain( commFD, 0);
+ }
+ else if ( 0 == strcmp( "Wh", argv[ iArg])) // Write hostname
+ {
+ result = HandleWriteHostname( commFD);
+ }
+ else if ( 0 == strcmp( "Wk", argv[ iArg])) // Write keychain entry
+ {
+ result = SetKeychainEntry( commFD);
+ }
+ }
+ [pool release];
+ return result;
+}
+
+// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
+// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+// To expand "version" to its value before making the string, use STRINGIFY(version) instead
+#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
+#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
+
+// NOT static -- otherwise the compiler may optimize it out
+// The "@(#) " pattern is a special prefix the "what" command looks for
+const char VersionString_SCCS[] = "@(#) ddnswriteconfig " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
+
+#if _BUILDING_XCODE_PROJECT_
+// If the process crashes, then this string will be magically included in the automatically-generated crash log
+const char *__crashreporter_info__ = VersionString_SCCS + 5;
+asm(".desc ___crashreporter_info__, 0x10");
+#endif
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/installtool b/mDNSResponder/mDNSMacOSX/PreferencePane/installtool
new file mode 100755
index 00000000..ce341c87
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/installtool
@@ -0,0 +1,94 @@
+#!/usr/bin/perl
+# Emacs settings: -*- tab-width: 4 -*-
+#
+# File: installtool
+#
+# Abstract: Copy "ddnswriteconfig" to Application Support and make it setuid root.
+#
+# Copyright: (c) Copyright 2005 Apple Computer, Inc. All rights reserved.
+#
+# Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+# ("Apple") in consideration of your agreement to the following terms, and your
+# use, installation, modification or redistribution of this Apple software
+# constitutes acceptance of these terms. If you do not agree with these terms,
+# please do not use, install, modify or redistribute this Apple software.
+#
+# In consideration of your agreement to abide by the following terms, and subject
+# to these terms, Apple grants you a personal, non-exclusive license, under Apple's
+# copyrights in this original Apple software (the "Apple Software"), to use,
+# reproduce, modify and redistribute the Apple Software, with or without
+# modifications, in source and/or binary forms; provided that if you redistribute
+# the Apple Software in its entirety and without modifications, you must retain
+# this notice and the following text and disclaimers in all such redistributions of
+# the Apple Software. Neither the name, trademarks, service marks or logos of
+# Apple Computer, Inc. may be used to endorse or promote products derived from the
+# Apple Software without specific prior written permission from Apple. Except as
+# expressly stated in this notice, no other rights or licenses, express or implied,
+# are granted by Apple herein, including but not limited to any patent rights that
+# may be infringed by your derivative works or by other works in which the Apple
+# Software may be incorporated.
+#
+# The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+# WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+# WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+# COMBINATION WITH YOUR PRODUCTS.
+#
+# IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+# OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+# (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Create the Bonjour subdirectory.
+# Copy ARGV[0] to $dest and set owner and suid permissions.
+#
+# This script will be run as root by the AEWP trampoline.
+#
+
+use File::Temp qw/ :mktemp /;
+
+$dest_dir = "/Library/Application Support/Bonjour";
+$dest = $dest_dir . "/ddnswriteconfig";
+
+$template = ".XXXXXX";
+
+# Perl seems to think this code is running setuid root, so it applies its security checks.
+# See <http://www.monster-submit.com/resources/docs/pod/perlsec.html>.
+# In fact this is NOT a setuid script. It is a normal unprivileged user-level script --
+# but it is run as root when properly authorized by a user with an admin password,
+# via the AuthorizationExecuteWithPrivileges() call.
+# We therefore have to do this trick pattern match to 'untaint' the source file specified in $ARGV[0].
+if ($ARGV[0] =~ /^(.+)$/) { $src = $1; }
+
+# Also clear $ENV{PATH} so we don't get "Insecure $ENV{PATH}" fatal errors
+$ENV{PATH} = "";
+
+if (! -d $dest_dir) {
+ $dest_tmp_dir = mkdtemp ($dest_dir . $template);
+ (chown 0, 80, $dest_tmp_dir) or cleanup_dir();
+ (chmod 0755, $dest_tmp_dir) or cleanup_dir();
+ (rename $dest_tmp_dir, $dest_dir) or cleanup_dir();
+}
+
+$dest_tmp = mktemp ($dest . $template);
+
+if ($src ne '') {
+ system ('/bin/cp', '-f', $src, $dest_tmp) and cleanup();
+ (chown 0, 80, $dest_tmp) or cleanup();
+ (chmod 04555, $dest_tmp) or cleanup();
+ (rename $dest_tmp, $dest) or cleanup();
+}
+exit (0);
+
+sub cleanup {
+ unlink $dest_tmp;
+ exit (1);
+}
+
+sub cleanup_dir {
+ unlink $dest_tmp_dir;
+ exit (1);
+}
diff --git a/mDNSResponder/mDNSMacOSX/Private/dns_services.c b/mDNSResponder/mDNSMacOSX/Private/dns_services.c
new file mode 100644
index 00000000..d0e9e6ca
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/Private/dns_services.c
@@ -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.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;
+}
+
diff --git a/mDNSResponder/mDNSMacOSX/Private/dns_services.h b/mDNSResponder/mDNSMacOSX/Private/dns_services.h
new file mode 100644
index 00000000..7b74e10d
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/Private/dns_services.h
@@ -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 */
diff --git a/mDNSResponder/mDNSMacOSX/Private/dns_xpc.h b/mDNSResponder/mDNSMacOSX/Private/dns_xpc.h
new file mode 100644
index 00000000..10ae01fa
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/Private/dns_xpc.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * Defines the common interface between mDNSResponder and the Private ClientLibrary(libdnsprivate.dylib)
+ * Uses XPC as the IPC Mechanism
+ *
+ */
+
+#ifndef DNS_XPC_H
+#define DNS_XPC_H
+
+#define kDNSProxyService "com.apple.mDNSResponder.dnsproxy"
+
+#define kDNSProxyParameters "DNSProxyParameters"
+
+#define kDNSInIfindex0 "InputArrayInterfaceIndex[0]"
+#define kDNSInIfindex1 "InputArrayInterfaceIndex[1]"
+#define kDNSInIfindex2 "InputArrayInterfaceIndex[2]"
+#define kDNSInIfindex3 "InputArrayInterfaceIndex[3]"
+#define kDNSInIfindex4 "InputArrayInterfaceIndex[4]"
+
+#define kDNSOutIfindex "OutputInterfaceIndex"
+
+#define kDNSDaemonReply "DaemonReplyStatusToClient"
+
+typedef enum
+{
+ kDNSMsgReceived = 0,
+ kDNSDaemonEngaged
+} DaemonReplyStatusCodes;
+
+#endif // DNS_XPC_H
diff --git a/mDNSResponder/mDNSMacOSX/Private/xpc_services.c b/mDNSResponder/mDNSMacOSX/Private/xpc_services.c
new file mode 100644
index 00000000..7a0e29fb
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/Private/xpc_services.c
@@ -0,0 +1,255 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * xpc_services.c
+ * mDNSResponder
+ *
+ * XPC as an IPC mechanism to communicate with Clients. Open only to Apple OSX/iOS clients
+ */
+
+#include "xpc_services.h"
+#include "dns_xpc.h"
+
+#ifndef UNICAST_DISABLED
+
+#include "dnsproxy.h" // DNSProxyInit/ProxyUDPCallback/ProxyTCPCallback
+#include "mDNSMacOSX.h" // KQueueLock/KQueueUnlock
+#include <xpc/xpc.h>
+#include <xpc/private.h> // xpc_connection_copy_entitlement_value
+
+// ***************************************************************************
+// Globals
+extern mDNS mDNSStorage;
+static int dps_client_pid; // To track current active client using DNS Proxy Service
+static dispatch_queue_t dps_queue = NULL;
+// ***************************************************************************
+
+// prints current XPC Server State
+mDNSexport void xpcserver_info(mDNS *const m)
+{
+
+ LogMsg("----- Active XPC Clients -----");
+ if (dps_client_pid)
+ LogMsg("DNSProxy->Client[%d]: InputIntfs[%d, %d, %d, %d, %d] Output[%d]", dps_client_pid, m->dp_ipintf[0],
+ m->dp_ipintf[1], m->dp_ipintf[2], m->dp_ipintf[3], m->dp_ipintf[4], m->dp_opintf);
+}
+
+
+mDNSlocal void ActivateDNSProxy(mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf, mDNSBool proxy_off)
+{
+
+ LogInfo("ActivateDNSProxy: InterfaceIndex List by Client: Input[%d, %d, %d, %d, %d] Output[%d] ", IpIfArr[0], IpIfArr[1],
+ IpIfArr[2], IpIfArr[3], IpIfArr[4], OpIf);
+
+ KQueueLock(&mDNSStorage);
+ DNSProxyInit(&mDNSStorage, IpIfArr, OpIf);
+ if (proxy_off) // Open skts only if proxy was OFF else we may end up opening extra skts
+ mDNSPlatformInitDNSProxySkts(&mDNSStorage, ProxyUDPCallback, ProxyTCPCallback);
+ KQueueUnlock(&mDNSStorage, "DNSProxy Activated");
+}
+
+mDNSlocal void handle_dps_terminate()
+{
+
+ LogInfo("handle_dps_terminate: Client PID[%d] terminated connection or crashed. Proceed to terminate DNSProxy", dps_client_pid);
+ // Clear the Client's PID, so that we can now accept new DPS requests
+ dps_client_pid = 0;
+
+ KQueueLock(&mDNSStorage);
+ mDNSPlatformCloseDNSProxySkts(&mDNSStorage);
+ // TBD: Close TCP Sockets
+ DNSProxyTerminate(&mDNSStorage);
+ KQueueUnlock(&mDNSStorage, "DNSProxy Deactivated");
+}
+
+mDNSlocal void handle_dps_request(xpc_object_t req)
+{
+ int dps_tmp_client;
+ mDNSBool proxy_off = mDNSfalse;
+ xpc_connection_t remote_conn = xpc_dictionary_get_remote_connection(req);
+ dps_tmp_client = (int) xpc_connection_get_pid(remote_conn);
+
+ LogInfo("handle_dps_request: Handler for DNS Proxy Requests");
+
+ if (dps_client_pid <= 0)
+ {
+ LogInfo("handle_dps_request: DNSProxy is not engaged (New Client)");
+ // No Active Client, save new Client's PID (also indicates DNS Proxy was OFF)
+ dps_client_pid = dps_tmp_client;
+ proxy_off = mDNStrue;
+ }
+ else
+ {
+ // We already have an active DNS Proxy Client and until that client does not terminate the connection
+ // or crashes, a new client cannot change/override the current DNS Proxy settings.
+ if (dps_client_pid != dps_tmp_client)
+ {
+ LogMsg("handle_dps_request: A Client is already using DNS Proxy and your request cannot be handled at this time");
+ // Return Engaged Status to the client
+ xpc_object_t reply = xpc_dictionary_create(NULL, NULL, 0);
+ if (reply)
+ {
+ xpc_dictionary_set_uint64(reply, kDNSDaemonReply, kDNSDaemonEngaged);
+ xpc_connection_send_message(remote_conn, reply);
+ xpc_release(reply);
+ }
+ else
+ {
+ LogMsg("handle_dps_request: Reply Dictionary could not be created");
+ return;
+ }
+ // We do not really need to terminate the connection with the client
+ // as it may try again later which is fine
+ return;
+ }
+ }
+
+ // Return Success Status to the client
+ xpc_object_t response = xpc_dictionary_create(NULL, NULL, 0);
+ if (response)
+ {
+ xpc_dictionary_set_uint64(response, kDNSDaemonReply, kDNSMsgReceived);
+ xpc_connection_send_message(remote_conn, response);
+ xpc_release(response);
+ }
+ else
+ {
+ LogMsg("handle_dps_request: Response Dictionary could not be created");
+ return;
+ }
+
+ // Proceed to get DNS Proxy Settings from the Client
+ if (xpc_dictionary_get_uint64(req, kDNSProxyParameters))
+ {
+ mDNSu32 inIf[MaxIp], outIf;
+
+ inIf[0] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex0);
+ inIf[1] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex1);
+ inIf[2] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex2);
+ inIf[3] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex3);
+ inIf[4] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex4);
+ outIf = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSOutIfindex);
+
+ ActivateDNSProxy(inIf, outIf, proxy_off);
+ }
+
+}
+
+// Verify Client's Entitlement
+mDNSlocal mDNSBool IsEntitled(xpc_connection_t conn, const char *password)
+{
+ mDNSBool entitled = mDNSfalse;
+ xpc_object_t ent = xpc_connection_copy_entitlement_value(conn, password);
+
+ if (ent)
+ {
+ if (xpc_get_type(ent) == XPC_TYPE_BOOL && xpc_bool_get_value(ent))
+ {
+ entitled = mDNStrue;
+ }
+ xpc_release(ent);
+ }
+ else
+ {
+ LogMsg("IsEntitled: Client Entitlement is NULL");
+ }
+
+ return entitled;
+}
+
+mDNSlocal void accept_dps_client(xpc_connection_t conn)
+{
+ uid_t euid;
+ euid = xpc_connection_get_euid(conn);
+
+ if (euid != 0 || !IsEntitled(conn, kDNSProxyService))
+ {
+ LogMsg("accept_dps_client: DNSProxyService Client Pid[%d] is missing Entitlement or is not root!", (int) xpc_connection_get_pid(conn));
+ xpc_connection_cancel(conn);
+ return;
+ }
+
+ xpc_retain(conn);
+ xpc_connection_set_target_queue(conn, dps_queue);
+ xpc_connection_set_event_handler(conn, ^(xpc_object_t req_msg)
+ {
+ xpc_type_t type = xpc_get_type(req_msg);
+
+ if (type == XPC_TYPE_DICTIONARY)
+ {
+ handle_dps_request(req_msg);
+ }
+ // We hit the case below only if Client Terminated DPS Connection OR Crashed
+ else
+ {
+ LogInfo("accept_dps_client: DPS Client %p teared down the connection or Crashed", (void *) conn);
+ // Only the Client that has activated DPS should be able to terminate it
+ if (((int)xpc_connection_get_pid(conn)) == dps_client_pid)
+ handle_dps_terminate();
+ xpc_release(conn);
+ }
+ });
+ xpc_connection_resume(conn);
+
+}
+
+mDNSlocal void init_dnsproxy_service(void)
+{
+
+ xpc_connection_t dps_listener = xpc_connection_create_mach_service(kDNSProxyService, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
+ if (!dps_listener || xpc_get_type(dps_listener) != XPC_TYPE_CONNECTION)
+ {
+ LogMsg("init_dnsproxy_service: Error Creating XPC Listener for DNSProxyService !!");
+ return;
+ }
+
+ dps_queue = dispatch_queue_create("com.apple.mDNSResponder.dnsproxyservice_queue", NULL);
+
+ xpc_connection_set_event_handler(dps_listener, ^(xpc_object_t eventmsg)
+ {
+ xpc_type_t type = xpc_get_type(eventmsg);
+
+ if (type == XPC_TYPE_CONNECTION)
+ {
+ LogInfo("init_dnsproxy_service: New DNSProxyService Client %p", eventmsg);
+ accept_dps_client(eventmsg);
+ }
+ // Ideally, we would never hit the cases below
+ else if (type == XPC_TYPE_ERROR)
+ {
+ LogMsg("init_dnsproxy_service: XPCError: %s", xpc_dictionary_get_string(eventmsg, XPC_ERROR_KEY_DESCRIPTION));
+ return;
+ }
+ else
+ {
+ LogMsg("init_dnsproxy_service: Unknown EventMsg type");
+ return;
+ }
+ });
+ xpc_connection_resume(dps_listener);
+
+}
+
+mDNSexport void xpc_server_init()
+{
+ // Add XPC Services here
+ init_dnsproxy_service();
+}
+
+#else // !UNICAST_DISABLED
+
+mDNSexport void xpc_server_init()
+{
+ return;
+}
+
+mDNSexport void xpcserver_info(mDNS *const m)
+{
+ (void) m;
+
+ return;
+}
+
+#endif // !UNICAST_DISABLED
+
diff --git a/mDNSResponder/mDNSMacOSX/Private/xpc_services.h b/mDNSResponder/mDNSMacOSX/Private/xpc_services.h
new file mode 100644
index 00000000..50081bed
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/Private/xpc_services.h
@@ -0,0 +1,21 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ *
+ *
+ * File: xpc_services.h
+ *
+ * Contains: Interfaces necessary to talk to xpc_services.c
+ *
+ */
+
+#ifndef XPC_SERVICES_H
+#define XPC_SERVICES_H
+
+#include "mDNSEmbeddedAPI.h"
+
+extern void xpc_server_init(void);
+extern void xpcserver_info(mDNS *const m);
+
+#endif // XPC_SERVICES_H
diff --git a/mDNSResponder/mDNSMacOSX/README.privsep b/mDNSResponder/mDNSMacOSX/README.privsep
new file mode 100644
index 00000000..130e3276
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/README.privsep
@@ -0,0 +1,40 @@
+On Mac OS X, mDNSResponder now runs with user-ID and group-ID
+"_mdnsresponder". In order to perform certain privileged operations, a
+helper (unimagintively called mDNSResponderHelper) runs as root when
+needed and handles requests from mDNSResponder.
+
+
+* A new LaunchD job com.apple.mDNSResponderHelper starts
+ mDNSResponderHelper on demand. The helper exits after approximately
+ 10 seconds of idle time.
+
+* The com.apple.mDNSResponder LaunchD job specifies the account under
+ which to run, so that mDNSResponder starts as _mdnsresponder.
+
+* A subdirectory named "mdns" and owned by _mdnsresponder has been
+ created in /var/run. The PID file and uDNS server socket has been
+ moved to that subdirectory.
+
+* There are currently six remote procedure calls handled by
+ mDNSResponderHelper: mDNSPreferencesSetName, mDNSKeychainGetSecrets,
+ mDNSConfigureServer, and mDNSAutoTunnelSetKeys
+
+* mDNSPreferencesSetName allows mDNSResponder to set the computer name
+ or local host name, and displays a notification if there was a
+ conflict.
+
+* mDNSKeychainGetSecrets causes mDNSResponderHelper to collect DNS
+ keys from the system keychain. SetDomainSecrets uses the result to
+ populate AuthInfoList. One could refactor this code further so that
+ mDNSResponderHelper performs all the cryptographic operations, with
+ the result that a compromise of mDNSResponder does not compromise
+ keys. But I think that may be more change than is advisable at this
+ point.
+
+* On the advice of the Security.framework team, I've used
+ SecKeychainSetPreferenceDomain to ensure that the system keychain is
+ references whenever a NULL SecKeychainRef is used. Wherever a
+ SecKeychainRef is needed, NULL is now specified.
+
+* mDNSConfigureServer, and mDNSAutoTunnelSetKeys do various setup and
+ teardown for BTMM.
diff --git a/mDNSResponder/mDNSMacOSX/VPNService.c b/mDNSResponder/mDNSMacOSX/VPNService.c
new file mode 100644
index 00000000..8c1bf1d0
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/VPNService.c
@@ -0,0 +1,35 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 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.
+ */
+#include "mDNSMacOSX.h"
+#include <SystemConfiguration/VPNAppLayerPrivate.h>
+
+mDNSexport mDNSs32 mDNSPlatformGetServiceID(mDNS *const m, DNSQuestion *q)
+{
+ (void) m;
+ int sid;
+
+ if (q->pid)
+ {
+ sid = VPNAppLayerGetMatchingServiceIdentifier(q->pid, NULL);
+ }
+ else
+ {
+ sid = VPNAppLayerGetMatchingServiceIdentifier(0, q->uuid);
+ }
+ LogInfo("mDNSPlatformGetServiceID: returning %d for %##s (%s)", sid, q->qname.c, DNSTypeName(q->qtype));
+ return sid;
+}
diff --git a/mDNSResponder/mDNSMacOSX/com.apple.networking.mDNSResponder b/mDNSResponder/mDNSMacOSX/com.apple.networking.mDNSResponder
new file mode 100644
index 00000000..d07c99d0
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/com.apple.networking.mDNSResponder
@@ -0,0 +1 @@
+? [= LoggerID com.apple.networking.mDNSResponder] file /Library/Logs/CrashReporter/com.apple.networking.mDNSResponder.log rotate file_max=1M compress
diff --git a/mDNSResponder/mDNSMacOSX/daemon.c b/mDNSResponder/mDNSMacOSX/daemon.c
new file mode 100644
index 00000000..3b3ed393
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/daemon.c
@@ -0,0 +1,3052 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002-2011 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 <mach/mach.h>
+#include <mach/mach_error.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+#include <paths.h>
+#include <fcntl.h>
+#include <launch.h>
+#include <launch_priv.h> // for launch_socket_service_check_in()
+#include <vproc.h>
+#include <pwd.h>
+#include <sys/event.h>
+#include <pthread.h>
+#include <sandbox.h>
+#include <SystemConfiguration/SCDynamicStoreCopyDHCPInfo.h>
+#include <asl.h>
+#include <syslog.h>
+#include <err.h>
+#include <sysexits.h>
+#include <bootstrap_priv.h> // for bootstrap_check_in()
+
+#include "DNSServiceDiscoveryRequestServer.h"
+#include "DNSServiceDiscoveryReply.h"
+
+#include "uDNS.h"
+#include "DNSCommon.h"
+#include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
+
+#include "uds_daemon.h" // Interface to the server side implementation of dns_sd.h
+#include "xpc_services.h" // Interface to XPC services
+
+#include "../mDNSMacOSX/DNSServiceDiscovery.h"
+#include "helper.h"
+
+static aslclient log_client = NULL;
+static aslmsg log_msg = NULL;
+
+// Used on Embedded Side for Reading mDNSResponder Managed Preferences Profile
+#if TARGET_OS_EMBEDDED
+#define kmDNSEnableLoggingStr CFSTR("EnableLogging")
+#define kmDNSResponderPrefIDStr "com.apple.mDNSResponder.plist"
+#define kmDNSResponderPrefID CFSTR(kmDNSResponderPrefIDStr)
+#endif
+
+//*************************************************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - Globals
+#endif
+
+static mDNS_PlatformSupport PlatformStorage;
+
+// Start off with a default cache of 16K (99 records)
+// Each time we grow the cache we add another 99 records
+// 99 * 164 = 16236 bytes.
+// This fits in four 4kB pages, with 148 bytes spare for memory block headers and similar overhead
+#define RR_CACHE_SIZE ((16*1024) / sizeof(CacheRecord))
+static CacheEntity rrcachestorage[RR_CACHE_SIZE];
+
+static mach_port_t m_port = MACH_PORT_NULL;
+
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+mDNSlocal void PrepareForIdle(void *m_param);
+#else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+static mach_port_t client_death_port = MACH_PORT_NULL;
+static mach_port_t signal_port = MACH_PORT_NULL;
+#endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+
+static dnssd_sock_t *launchd_fds = mDNSNULL;
+static mDNSu32 launchd_fds_count = 0;
+
+// mDNS Mach Message Timeout, in milliseconds.
+// We need this to be short enough that we don't deadlock the mDNSResponder if a client
+// fails to service its mach message queue, but long enough to give a well-written
+// client a chance to service its mach message queue without getting cut off.
+// Empirically, 50ms seems to work, so we set the timeout to 250ms to give
+// even extra-slow clients a fair chance before we cut them off.
+#define MDNS_MM_TIMEOUT 250
+
+static mDNSBool advertise = mDNS_Init_AdvertiseLocalAddresses; // By default, advertise addresses (& other records) via multicast
+
+extern mDNSBool StrictUnicastOrdering;
+extern mDNSBool AlwaysAppendSearchDomains;
+
+//*************************************************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Active client list structures
+#endif
+
+typedef struct DNSServiceDomainEnumeration_struct DNSServiceDomainEnumeration;
+struct DNSServiceDomainEnumeration_struct
+{
+ DNSServiceDomainEnumeration *next;
+ mach_port_t ClientMachPort;
+ DNSQuestion dom; // Question asking for domains
+ DNSQuestion def; // Question asking for default domain
+};
+
+typedef struct DNSServiceBrowserResult_struct DNSServiceBrowserResult;
+struct DNSServiceBrowserResult_struct
+{
+ DNSServiceBrowserResult *next;
+ int resultType;
+ domainname result;
+};
+
+typedef struct DNSServiceBrowser_struct DNSServiceBrowser;
+
+typedef struct DNSServiceBrowserQuestion
+{
+ struct DNSServiceBrowserQuestion *next;
+ DNSQuestion q;
+ domainname domain;
+} DNSServiceBrowserQuestion;
+
+struct DNSServiceBrowser_struct
+{
+ DNSServiceBrowser *next;
+ mach_port_t ClientMachPort;
+ DNSServiceBrowserQuestion *qlist;
+ DNSServiceBrowserResult *results;
+ mDNSs32 lastsuccess;
+ mDNSBool DefaultDomain; // was the browse started on an explicit domain?
+ domainname type; // registration type
+};
+
+typedef struct DNSServiceResolver_struct DNSServiceResolver;
+struct DNSServiceResolver_struct
+{
+ DNSServiceResolver *next;
+ mach_port_t ClientMachPort;
+ ServiceInfoQuery q;
+ ServiceInfo i;
+ mDNSs32 ReportTime;
+};
+
+// A single registered service: ServiceRecordSet + bookkeeping
+// Note that we duplicate some fields from parent DNSServiceRegistration object
+// to facilitate cleanup, when instances and parent may be deallocated at different times.
+typedef struct ServiceInstance
+{
+ struct ServiceInstance *next;
+ mach_port_t ClientMachPort;
+ mDNSBool autoname; // Set if this name is tied to the Computer Name
+ mDNSBool renameonmemfree; // Set if we just got a name conflict and now need to automatically pick a new name
+ domainlabel name;
+ domainname domain;
+ ServiceRecordSet srs;
+ // Don't add any fields after ServiceRecordSet.
+ // This is where the implicit extra space goes if we allocate an oversized ServiceRecordSet object
+} ServiceInstance;
+
+// A client-created service. May reference several ServiceInstance objects if default
+// settings cause registration in multiple domains.
+typedef struct DNSServiceRegistration
+{
+ struct DNSServiceRegistration *next;
+ mach_port_t ClientMachPort;
+ mDNSBool DefaultDomain;
+ mDNSBool autoname;
+ size_t rdsize;
+ int NumSubTypes;
+ char regtype[MAX_ESCAPED_DOMAIN_NAME]; // for use in AllocateSubtypes
+ domainlabel name; // used only if autoname is false
+ domainname type;
+ mDNSIPPort port;
+ unsigned char txtinfo[1024];
+ size_t txt_len;
+ uint32_t NextRef;
+ ServiceInstance *regs;
+} DNSServiceRegistration;
+
+static DNSServiceDomainEnumeration *DNSServiceDomainEnumerationList = NULL;
+static DNSServiceBrowser *DNSServiceBrowserList = NULL;
+static DNSServiceResolver *DNSServiceResolverList = NULL;
+static DNSServiceRegistration *DNSServiceRegistrationList = NULL;
+
+// We keep a list of client-supplied event sources in KQSocketEventSource records
+typedef struct KQSocketEventSource
+{
+ struct KQSocketEventSource *next;
+ int fd;
+ KQueueEntry kqs;
+} KQSocketEventSource;
+
+static KQSocketEventSource *gEventSources;
+
+//*************************************************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - General Utility Functions
+#endif
+
+#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
+
+char _malloc_options[] = "AXZ";
+
+mDNSexport void LogMemCorruption(const char *format, ...)
+{
+ char buffer[512];
+ va_list ptr;
+ va_start(ptr,format);
+ buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
+ va_end(ptr);
+ LogMsg("!!!! %s !!!!", buffer);
+ NotifyOfElusiveBug("Memory Corruption", buffer);
+#if ForceAlerts
+ *(long*)0 = 0; // Trick to crash and get a stack trace right here, if that's what we want
+#endif
+}
+
+mDNSlocal void validatelists(mDNS *const m)
+{
+ // Check local lists
+ KQSocketEventSource *k;
+ for (k = gEventSources; k; k=k->next)
+ if (k->next == (KQSocketEventSource *)~0 || k->fd < 0)
+ LogMemCorruption("gEventSources: %p is garbage (%d)", k, k->fd);
+
+ // Check Mach client lists
+ DNSServiceDomainEnumeration *e;
+ for (e = DNSServiceDomainEnumerationList; e; e=e->next)
+ if (e->next == (DNSServiceDomainEnumeration *)~0 || e->ClientMachPort == 0 || e->ClientMachPort == (mach_port_t) ~0)
+ LogMemCorruption("DNSServiceDomainEnumerationList: %p is garbage (%X)", e, e->ClientMachPort);
+
+ DNSServiceBrowser *b;
+ for (b = DNSServiceBrowserList; b; b=b->next)
+ if (b->next == (DNSServiceBrowser *)~0 || b->ClientMachPort == 0 || b->ClientMachPort == (mach_port_t) ~0)
+ LogMemCorruption("DNSServiceBrowserList: %p is garbage (%X)", b, b->ClientMachPort);
+
+ DNSServiceResolver *l;
+ for (l = DNSServiceResolverList; l; l=l->next)
+ if (l->next == (DNSServiceResolver *)~0 || l->ClientMachPort == 0 || l->ClientMachPort == (mach_port_t) ~0)
+ LogMemCorruption("DNSServiceResolverList: %p is garbage (%X)", l, l->ClientMachPort);
+
+ DNSServiceRegistration *r;
+ for (r = DNSServiceRegistrationList; r; r=r->next)
+ if (r->next == (DNSServiceRegistration *)~0 || r->ClientMachPort == 0 || r->ClientMachPort == (mach_port_t) ~0)
+ LogMemCorruption("DNSServiceRegistrationList: %p is garbage (%X)", r, r->ClientMachPort);
+
+ // Check Unix Domain Socket client lists (uds_daemon.c)
+ uds_validatelists();
+
+ // Check core mDNS lists
+ AuthRecord *rr;
+ for (rr = m->ResourceRecords; rr; rr=rr->next)
+ {
+ if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
+ LogMemCorruption("ResourceRecords list: %p is garbage (%X)", rr, rr->resrec.RecordType);
+ if (rr->resrec.name != &rr->namestorage)
+ LogMemCorruption("ResourceRecords list: %p name %p does not point to namestorage %p %##s",
+ rr, rr->resrec.name->c, rr->namestorage.c, rr->namestorage.c);
+ }
+
+ for (rr = m->DuplicateRecords; rr; rr=rr->next)
+ if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
+ LogMemCorruption("DuplicateRecords list: %p is garbage (%X)", rr, rr->resrec.RecordType);
+
+ rr = m->NewLocalRecords;
+ if (rr)
+ if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
+ LogMemCorruption("NewLocalRecords: %p is garbage (%X)", rr, rr->resrec.RecordType);
+
+ rr = m->CurrentRecord;
+ if (rr)
+ if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
+ LogMemCorruption("CurrentRecord: %p is garbage (%X)", rr, rr->resrec.RecordType);
+
+ DNSQuestion *q;
+ for (q = m->Questions; q; q=q->next)
+ if (q->next == (DNSQuestion*)~0 || q->ThisQInterval == (mDNSs32) ~0)
+ LogMemCorruption("Questions list: %p is garbage (%lX %p)", q, q->ThisQInterval, q->next);
+
+ CacheGroup *cg;
+ CacheRecord *cr;
+ mDNSu32 slot;
+ FORALL_CACHERECORDS(slot, cg, cr)
+ {
+ if (cr->resrec.RecordType == 0 || cr->resrec.RecordType == 0xFF)
+ LogMemCorruption("Cache slot %lu: %p is garbage (%X)", slot, cr, cr->resrec.RecordType);
+ if (cr->CRActiveQuestion)
+ {
+ for (q = m->Questions; q; q=q->next) if (q == cr->CRActiveQuestion) break;
+ if (!q) LogMemCorruption("Cache slot %lu: CRActiveQuestion %p not in m->Questions list %s", slot, cr->CRActiveQuestion, CRDisplayString(m, cr));
+ }
+ }
+
+ // Check core uDNS lists
+ udns_validatelists(m);
+
+ // Check platform-layer lists
+ NetworkInterfaceInfoOSX *i;
+ for (i = m->p->InterfaceList; i; i = i->next)
+ if (i->next == (NetworkInterfaceInfoOSX *)~0 || !i->m || i->m == (mDNS *)~0)
+ LogMemCorruption("m->p->InterfaceList: %p is garbage (%p)", i, i->ifinfo.ifname);
+
+ ClientTunnel *t;
+ for (t = m->TunnelClients; t; t=t->next)
+ if (t->next == (ClientTunnel *)~0 || t->dstname.c[0] > 63)
+ LogMemCorruption("m->TunnelClients: %p is garbage (%d)", t, t->dstname.c[0]);
+}
+
+mDNSexport void *mallocL(char *msg, unsigned int size)
+{
+ // Allocate space for two words of sanity checking data before the requested block
+ mDNSu32 *mem = malloc(sizeof(mDNSu32) * 2 + size);
+ if (!mem)
+ { LogMsg("malloc( %s : %d ) failed", msg, size); return(NULL); }
+ else
+ {
+ if (size > 24000) LogMsg("malloc( %s : %lu ) = %p suspiciously large", msg, size, &mem[2]);
+ else if (MACOSX_MDNS_MALLOC_DEBUGGING >= 2) LogMsg("malloc( %s : %lu ) = %p", msg, size, &mem[2]);
+ mem[0] = 0xDEAD1234;
+ mem[1] = size;
+ //mDNSPlatformMemZero(&mem[2], size);
+ memset(&mem[2], 0xFF, size);
+ validatelists(&mDNSStorage);
+ return(&mem[2]);
+ }
+}
+
+mDNSexport void freeL(char *msg, void *x)
+{
+ if (!x)
+ LogMsg("free( %s @ NULL )!", msg);
+ else
+ {
+ mDNSu32 *mem = ((mDNSu32 *)x) - 2;
+ if (mem[0] != 0xDEAD1234) { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg, &mem[2]); return; }
+ if (mem[1] > 24000) LogMsg("free( %s : %ld @ %p) suspiciously large", msg, mem[1], &mem[2]);
+ else if (MACOSX_MDNS_MALLOC_DEBUGGING >= 2) LogMsg("free( %s : %ld @ %p)", msg, mem[1], &mem[2]);
+ //mDNSPlatformMemZero(mem, sizeof(mDNSu32) * 2 + mem[1]);
+ memset(mem, 0xFF, sizeof(mDNSu32) * 2 + mem[1]);
+ validatelists(&mDNSStorage);
+ free(mem);
+ }
+}
+
+#endif
+
+//*************************************************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Mach client request handlers
+#endif
+
+//*************************************************************************************************************
+// Client Death Detection
+
+// This gets called after ALL constituent records of the Service Record Set have been deregistered
+mDNSlocal void FreeServiceInstance(ServiceInstance *x)
+{
+ ServiceRecordSet *s = &x->srs;
+ ExtraResourceRecord *e = x->srs.Extras, *tmp;
+
+ while (e)
+ {
+ e->r.RecordContext = e;
+ tmp = e;
+ e = e->next;
+ FreeExtraRR(&mDNSStorage, &tmp->r, mStatus_MemFree);
+ }
+
+ if (s->RR_TXT.resrec.rdata != &s->RR_TXT.rdatastorage)
+ freeL("TXT RData", s->RR_TXT.resrec.rdata);
+
+ if (s->SubTypes) freeL("ServiceSubTypes", s->SubTypes);
+ freeL("ServiceInstance", x);
+}
+
+// AbortClient finds whatever client is identified by the given Mach port,
+// stops whatever operation that client was doing, and frees its memory.
+// In the case of a service registration, the actual freeing may be deferred
+// until we get the mStatus_MemFree message, if necessary
+mDNSlocal void AbortClient(mach_port_t ClientMachPort, void *m)
+{
+ DNSServiceDomainEnumeration **e = &DNSServiceDomainEnumerationList;
+ DNSServiceBrowser **b = &DNSServiceBrowserList;
+ DNSServiceResolver **l = &DNSServiceResolverList;
+ DNSServiceRegistration **r = &DNSServiceRegistrationList;
+
+ while (*e && (*e)->ClientMachPort != ClientMachPort) e = &(*e)->next;
+ if (*e)
+ {
+ DNSServiceDomainEnumeration *x = *e;
+ *e = (*e)->next;
+ if (m && m != x)
+ LogMsg("%5d: DNSServiceDomainEnumeration(%##s) STOP; WARNING m %p != x %p", ClientMachPort, x->dom.qname.c, m, x);
+ else LogOperation("%5d: DNSServiceDomainEnumeration(%##s) STOP", ClientMachPort, x->dom.qname.c);
+ mDNS_StopGetDomains(&mDNSStorage, &x->dom);
+ mDNS_StopGetDomains(&mDNSStorage, &x->def);
+ freeL("DNSServiceDomainEnumeration", x);
+ return;
+ }
+
+ while (*b && (*b)->ClientMachPort != ClientMachPort) b = &(*b)->next;
+ if (*b)
+ {
+ DNSServiceBrowser *x = *b;
+ DNSServiceBrowserQuestion *freePtr, *qptr = x->qlist;
+ *b = (*b)->next;
+ while (qptr)
+ {
+ if (m && m != x)
+ LogMsg("%5d: DNSServiceBrowse(%##s) STOP; WARNING m %p != x %p", ClientMachPort, qptr->q.qname.c, m, x);
+ else LogOperation("%5d: DNSServiceBrowse(%##s) STOP", ClientMachPort, qptr->q.qname.c);
+ mDNS_StopBrowse(&mDNSStorage, &qptr->q);
+ freePtr = qptr;
+ qptr = qptr->next;
+ freeL("DNSServiceBrowserQuestion", freePtr);
+ }
+ while (x->results)
+ {
+ DNSServiceBrowserResult *t = x->results;
+ x->results = x->results->next;
+ freeL("DNSServiceBrowserResult", t);
+ }
+ freeL("DNSServiceBrowser", x);
+ return;
+ }
+
+ while (*l && (*l)->ClientMachPort != ClientMachPort) l = &(*l)->next;
+ if (*l)
+ {
+ DNSServiceResolver *x = *l;
+ *l = (*l)->next;
+ if (m && m != x)
+ LogMsg("%5d: DNSServiceResolve(%##s) STOP; WARNING m %p != x %p", ClientMachPort, x->i.name.c, m, x);
+ else LogOperation("%5d: DNSServiceResolve(%##s) STOP", ClientMachPort, x->i.name.c);
+ mDNS_StopResolveService(&mDNSStorage, &x->q);
+ freeL("DNSServiceResolver", x);
+ return;
+ }
+
+ while (*r && (*r)->ClientMachPort != ClientMachPort) r = &(*r)->next;
+ if (*r)
+ {
+ ServiceInstance *si = NULL;
+ DNSServiceRegistration *x = *r;
+ *r = (*r)->next;
+
+ si = x->regs;
+ while (si)
+ {
+ ServiceInstance *instance = si;
+ si = si->next;
+ instance->renameonmemfree = mDNSfalse;
+ if (m && m != x) LogMsg("%5d: DNSServiceRegistration(%##s, %u) STOP; WARNING m %p != x %p", ClientMachPort, instance->srs.RR_SRV.resrec.name->c, SRS_PORT(&instance->srs), m, x);
+ else LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort, instance->srs.RR_SRV.resrec.name->c, SRS_PORT(&instance->srs));
+
+ // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
+ // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory.
+ // If mDNS_DeregisterService() returns an error, it means that the service had already been removed from
+ // the list, so we should go ahead and free the memory right now
+ if (mDNS_DeregisterService(&mDNSStorage, &instance->srs)) FreeServiceInstance(instance); // FreeServiceInstance invalidates pointer
+ }
+ x->regs = NULL;
+ freeL("DNSServiceRegistration", x);
+ return;
+ }
+
+ LogMsg("%5d: died or deallocated, but no record of client can be found!", ClientMachPort);
+}
+
+#define AbortBlockedClient(C,MSG,M) AbortClientWithLogMessage((C), "stopped accepting Mach messages", " (" MSG ")", (M))
+
+mDNSlocal void AbortClientWithLogMessage(mach_port_t c, char *reason, char *msg, void *m)
+{
+ DNSServiceDomainEnumeration *e = DNSServiceDomainEnumerationList;
+ DNSServiceBrowser *b = DNSServiceBrowserList;
+ DNSServiceResolver *l = DNSServiceResolverList;
+ DNSServiceRegistration *r = DNSServiceRegistrationList;
+ DNSServiceBrowserQuestion *qptr;
+
+ while (e && e->ClientMachPort != c) e = e->next;
+ while (b && b->ClientMachPort != c) b = b->next;
+ while (l && l->ClientMachPort != c) l = l->next;
+ while (r && r->ClientMachPort != c) r = r->next;
+
+ if (e) LogMsg("%5d: DomainEnumeration(%##s) %s%s", c, e->dom.qname.c, reason, msg);
+ else if (b)
+ {
+ for (qptr = b->qlist; qptr; qptr = qptr->next)
+ LogMsg("%5d: Browser(%##s) %s%s", c, qptr->q.qname.c, reason, msg);
+ }
+ else if (l) LogMsg("%5d: Resolver(%##s) %s%s", c, l->i.name.c, reason, msg);
+ else if (r)
+ {
+ ServiceInstance *si;
+ for (si = r->regs; si; si = si->next)
+ LogMsg("%5d: Registration(%##s) %s%s", c, si->srs.RR_SRV.resrec.name->c, reason, msg);
+ }
+ else LogMsg("%5d: (%s) %s, but no record of client can be found!", c, reason, msg);
+
+ AbortClient(c, m);
+}
+
+mDNSlocal mDNSBool CheckForExistingClient(mach_port_t c)
+{
+ DNSServiceDomainEnumeration *e = DNSServiceDomainEnumerationList;
+ DNSServiceBrowser *b = DNSServiceBrowserList;
+ DNSServiceResolver *l = DNSServiceResolverList;
+ DNSServiceRegistration *r = DNSServiceRegistrationList;
+ DNSServiceBrowserQuestion *qptr;
+
+ while (e && e->ClientMachPort != c) e = e->next;
+ while (b && b->ClientMachPort != c) b = b->next;
+ while (l && l->ClientMachPort != c) l = l->next;
+ while (r && r->ClientMachPort != c) r = r->next;
+ if (e) LogMsg("%5d: DomainEnumeration(%##s) already exists!", c, e->dom.qname.c);
+ if (b)
+ {
+ for (qptr = b->qlist; qptr; qptr = qptr->next)
+ LogMsg("%5d: Browser(%##s) already exists!", c, qptr->q.qname.c);
+ }
+ if (l) LogMsg("%5d: Resolver(%##s) already exists!", c, l->i.name.c);
+ if (r) LogMsg("%5d: Registration(%##s) already exists!", c, r->regs ? r->regs->srs.RR_SRV.resrec.name->c : NULL);
+ return(e || b || l || r);
+}
+
+#ifndef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+
+mDNSlocal void ClientDeathCallback(CFMachPortRef unusedport, void *voidmsg, CFIndex size, void *info)
+{
+ KQueueLock(&mDNSStorage);
+ mach_msg_header_t *msg = (mach_msg_header_t *)voidmsg;
+ (void)unusedport; // Unused
+ (void)size; // Unused
+ (void)info; // Unused
+ if (msg->msgh_id == MACH_NOTIFY_DEAD_NAME)
+ {
+ const mach_dead_name_notification_t *const deathMessage = (mach_dead_name_notification_t *)msg;
+ AbortClient(deathMessage->not_port, NULL);
+
+ /* Deallocate the send right that came in the dead name notification */
+ mach_port_destroy(mach_task_self(), deathMessage->not_port);
+ }
+ KQueueUnlock(&mDNSStorage, "Mach AbortClient");
+}
+
+#endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+
+mDNSlocal void EnableDeathNotificationForClient(mach_port_t ClientMachPort, void *m)
+{
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+ dispatch_source_t mach_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, ClientMachPort, 0, dispatch_get_main_queue());
+ if (mach_source == mDNSNULL)
+ {
+ AbortClientWithLogMessage(ClientMachPort, "died/deallocated before we could enable death notification", "", m);
+ return;
+ }
+ dispatch_source_set_event_handler(mach_source, ^{
+ mach_port_destroy(mach_task_self(), ClientMachPort);
+ });
+ dispatch_resume(mach_source);
+#else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+ mach_port_t prev;
+ kern_return_t r = mach_port_request_notification(mach_task_self(), ClientMachPort, MACH_NOTIFY_DEAD_NAME, 0,
+ client_death_port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev);
+ // If the port already died while we were thinking about it, then abort the operation right away
+ if (r != KERN_SUCCESS)
+ AbortClientWithLogMessage(ClientMachPort, "died/deallocated before we could enable death notification", "", m);
+#endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+}
+
+//*************************************************************************************************************
+// Domain Enumeration
+
+mDNSlocal void DomainEnumFound(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
+{
+ kern_return_t status;
+ char buffer[MAX_ESCAPED_DOMAIN_NAME];
+ DNSServiceDomainEnumerationReplyResultType rt;
+ DNSServiceDomainEnumeration *x = (DNSServiceDomainEnumeration *)question->QuestionContext;
+ (void)m; // Unused
+
+ debugf("DomainEnumFound: %##s PTR %##s", answer->name->c, answer->rdata->u.name.c);
+ if (answer->rrtype != kDNSType_PTR) return;
+ if (!x) { debugf("DomainEnumFound: DNSServiceDomainEnumeration is NULL"); return; }
+
+ if (AddRecord)
+ {
+ if (question == &x->dom) rt = DNSServiceDomainEnumerationReplyAddDomain;
+ else rt = DNSServiceDomainEnumerationReplyAddDomainDefault;
+ }
+ else
+ {
+ if (question == &x->dom) rt = DNSServiceDomainEnumerationReplyRemoveDomain;
+ else return;
+ }
+
+ LogOperation("%5d: DNSServiceDomainEnumeration(%##s) %##s %s",
+ x->ClientMachPort, x->dom.qname.c, answer->rdata->u.name.c,
+ !AddRecord ? "RemoveDomain" :
+ question == &x->dom ? "AddDomain" : "AddDomainDefault");
+
+ ConvertDomainNameToCString(&answer->rdata->u.name, buffer);
+ status = DNSServiceDomainEnumerationReply_rpc(x->ClientMachPort, rt, buffer, 0, MDNS_MM_TIMEOUT);
+ if (status == MACH_SEND_TIMED_OUT)
+ AbortBlockedClient(x->ClientMachPort, "enumeration", x);
+}
+
+mDNSexport kern_return_t provide_DNSServiceDomainEnumerationCreate_rpc(mach_port_t unusedserver, mach_port_t client,
+ int regDom)
+{
+ // Check client parameter
+ (void)unusedserver; // Unused
+ mStatus err = mStatus_NoError;
+ const char *errormsg = "Unknown";
+ if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
+ if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; }
+
+ mDNS_DomainType dt1 = regDom ? mDNS_DomainTypeRegistration : mDNS_DomainTypeBrowse;
+ mDNS_DomainType dt2 = regDom ? mDNS_DomainTypeRegistrationDefault : mDNS_DomainTypeBrowseDefault;
+
+ // Allocate memory, and handle failure
+ DNSServiceDomainEnumeration *x = mallocL("DNSServiceDomainEnumeration", sizeof(*x));
+ if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
+
+ // Set up object, and link into list
+ x->ClientMachPort = client;
+ x->next = DNSServiceDomainEnumerationList;
+ DNSServiceDomainEnumerationList = x;
+
+ verbosedebugf("%5d: Enumerate %s Domains", client, regDom ? "Registration" : "Browsing");
+
+ // Do the operation
+ err = mDNS_GetDomains(&mDNSStorage, &x->dom, dt1, NULL, mDNSInterface_LocalOnly, DomainEnumFound, x);
+ if (!err) err = mDNS_GetDomains(&mDNSStorage, &x->def, dt2, NULL, mDNSInterface_LocalOnly, DomainEnumFound, x);
+ if (err) { AbortClient(client, x); errormsg = "mDNS_GetDomains"; goto fail; }
+
+ // Succeeded: Wrap up and return
+ LogOperation("%5d: DNSServiceDomainEnumeration(%##s) START", client, x->dom.qname.c);
+ EnableDeathNotificationForClient(client, x);
+ return(mStatus_NoError);
+
+fail:
+ LogMsg("%5d: DNSServiceDomainEnumeration(%d) failed: %s (%d)", client, regDom, errormsg, err);
+ return(err);
+}
+
+//*************************************************************************************************************
+// Browse for services
+
+mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
+{
+ (void)m; // Unused
+
+ if (answer->rrtype != kDNSType_PTR)
+ { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer->rrtype); return; }
+
+ domainlabel name;
+ domainname type, domain;
+ if (!DeconstructServiceName(&answer->rdata->u.name, &name, &type, &domain))
+ {
+ LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
+ answer->name->c, answer->rdata->u.name.c);
+ return;
+ }
+
+ DNSServiceBrowserResult *x = mallocL("DNSServiceBrowserResult", sizeof(*x));
+ if (!x) { LogMsg("FoundInstance: Failed to allocate memory for result %##s", answer->rdata->u.name.c); return; }
+
+ verbosedebugf("FoundInstance: %s %##s", AddRecord ? "Add" : "Rmv", answer->rdata->u.name.c);
+ AssignDomainName(&x->result, &answer->rdata->u.name);
+ if (AddRecord)
+ x->resultType = DNSServiceBrowserReplyAddInstance;
+ else x->resultType = DNSServiceBrowserReplyRemoveInstance;
+ x->next = NULL;
+
+ DNSServiceBrowser *browser = (DNSServiceBrowser *)question->QuestionContext;
+ DNSServiceBrowserResult **p = &browser->results;
+ while (*p) p = &(*p)->next;
+ *p = x;
+
+ LogOperation("%5d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
+ browser->ClientMachPort, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer));
+}
+
+mDNSlocal mStatus AddDomainToBrowser(DNSServiceBrowser *browser, const domainname *d)
+{
+ mStatus err = mStatus_NoError;
+ DNSServiceBrowserQuestion *ptr, *question = NULL;
+
+ for (ptr = browser->qlist; ptr; ptr = ptr->next)
+ {
+ if (SameDomainName(&ptr->q.qname, d))
+ { debugf("Domain %##s already contained in browser", d->c); return mStatus_AlreadyRegistered; }
+ }
+
+ question = mallocL("DNSServiceBrowserQuestion", sizeof(DNSServiceBrowserQuestion));
+ if (!question) { LogMsg("Error: malloc"); return mStatus_NoMemoryErr; }
+ AssignDomainName(&question->domain, d);
+ question->next = browser->qlist;
+ LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", browser->ClientMachPort, browser->type.c, d->c);
+ err = mDNS_StartBrowse(&mDNSStorage, &question->q, &browser->type, d, mDNSNULL, mDNSInterface_Any, 0, mDNSfalse, mDNSfalse, FoundInstance, browser);
+ if (!err)
+ browser->qlist = question;
+ else
+ {
+ LogMsg("Error: AddDomainToBrowser: mDNS_StartBrowse %d", err);
+ freeL("DNSServiceBrowserQuestion", question);
+ }
+ return err;
+}
+
+mDNSexport void machserver_automatic_browse_domain_changed(const domainname *d, mDNSBool add)
+{
+ DNSServiceBrowser *ptr;
+ for (ptr = DNSServiceBrowserList; ptr; ptr = ptr->next)
+ {
+ if (ptr->DefaultDomain)
+ {
+ if (add)
+ {
+ mStatus err = AddDomainToBrowser(ptr, d);
+ if (err && err != mStatus_AlreadyRegistered) LogMsg("Default browse in domain %##s for client %5d failed. Continuing", d, ptr->ClientMachPort);
+ }
+ else
+ {
+ DNSServiceBrowserQuestion **q = &ptr->qlist;
+ while (*q)
+ {
+ if (SameDomainName(&(*q)->domain, d))
+ {
+ DNSServiceBrowserQuestion *rem = *q;
+ *q = (*q)->next;
+ mDNS_StopQueryWithRemoves(&mDNSStorage, &rem->q);
+ freeL("DNSServiceBrowserQuestion", rem);
+ return;
+ }
+ q = &(*q)->next;
+ }
+ LogMsg("Requested removal of default domain %##s not in client %5d's list", d->c, ptr->ClientMachPort);
+ }
+ }
+ }
+}
+
+mDNSexport kern_return_t provide_DNSServiceBrowserCreate_rpc(mach_port_t unusedserver, mach_port_t client,
+ DNSCString regtype, DNSCString domain)
+{
+ // Check client parameter
+ (void)unusedserver; // Unused
+ mStatus err = mStatus_NoError;
+ const char *errormsg = "Unknown";
+
+ if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
+ if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; }
+
+ // Check other parameters
+ domainname t, d;
+ t.c[0] = 0;
+ mDNSs32 NumSubTypes = ChopSubTypes(regtype, mDNSNULL); // Note: Modifies regtype string to remove trailing subtypes
+ if (NumSubTypes < 0 || NumSubTypes > 1) { errormsg = "Bad Service SubType"; goto badparam; }
+ if (NumSubTypes == 1 && !AppendDNSNameString(&t, regtype + strlen(regtype) + 1))
+ { errormsg = "Bad Service SubType"; goto badparam; }
+ if (!regtype[0] || !AppendDNSNameString(&t, regtype)) { errormsg = "Illegal regtype"; goto badparam; }
+ domainname temp;
+ if (!MakeDomainNameFromDNSNameString(&temp, regtype)) { errormsg = "Illegal regtype"; goto badparam; }
+ if (temp.c[0] > 15 && (!domain || domain[0] == 0)) domain = "local."; // For over-long service types, we only allow domain "local"
+
+ // Allocate memory, and handle failure
+ DNSServiceBrowser *x = mallocL("DNSServiceBrowser", sizeof(*x));
+ if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
+
+ // Set up object, and link into list
+ AssignDomainName(&x->type, &t);
+ x->ClientMachPort = client;
+ x->results = NULL;
+ x->lastsuccess = 0;
+ x->qlist = NULL;
+ x->next = DNSServiceBrowserList;
+ DNSServiceBrowserList = x;
+
+ if (domain[0])
+ {
+ // Start browser for an explicit domain
+ x->DefaultDomain = mDNSfalse;
+ if (!MakeDomainNameFromDNSNameString(&d, domain)) { errormsg = "Illegal domain"; goto badparam; }
+ err = AddDomainToBrowser(x, &d);
+ if (err) { AbortClient(client, x); errormsg = "AddDomainToBrowser"; goto fail; }
+ }
+ else
+ {
+ DNameListElem *sdPtr;
+ // Start browser on all domains
+ x->DefaultDomain = mDNStrue;
+ if (!AutoBrowseDomains) { AbortClient(client, x); errormsg = "GetSearchDomainList"; goto fail; }
+ for (sdPtr = AutoBrowseDomains; sdPtr; sdPtr = sdPtr->next)
+ {
+ err = AddDomainToBrowser(x, &sdPtr->name);
+ if (err)
+ {
+ // only terminally bail if .local fails
+ if (!SameDomainName(&localdomain, &sdPtr->name))
+ LogMsg("Default browse in domain %##s failed. Continuing", sdPtr->name.c);
+ else { AbortClient(client, x); errormsg = "AddDomainToBrowser"; goto fail; }
+ }
+ }
+ }
+
+ // Succeeded: Wrap up and return
+ EnableDeathNotificationForClient(client, x);
+ return(mStatus_NoError);
+
+badparam:
+ err = mStatus_BadParamErr;
+fail:
+ LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%d)", client, regtype, domain, errormsg, err);
+ return(err);
+}
+
+//*************************************************************************************************************
+// Resolve Service Info
+
+mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
+{
+ kern_return_t status;
+ DNSServiceResolver *x = (DNSServiceResolver *)query->ServiceInfoQueryContext;
+ NetworkInterfaceInfoOSX *ifx = IfindexToInterfaceInfoOSX(m, query->info->InterfaceID);
+ if (query->info->InterfaceID == mDNSInterface_LocalOnly || query->info->InterfaceID == mDNSInterface_P2P) ifx = mDNSNULL;
+ struct sockaddr_storage interface;
+ struct sockaddr_storage address;
+ char cstring[1024];
+ int i, pstrlen = query->info->TXTinfo[0];
+ (void)m; // Unused
+
+ //debugf("FoundInstanceInfo %.4a %.4a %##s", &query->info->InterfaceAddr, &query->info->ip, &query->info->name);
+
+ if (query->info->TXTlen > sizeof(cstring)) return;
+
+ mDNSPlatformMemZero(&interface, sizeof(interface));
+ mDNSPlatformMemZero(&address, sizeof(address));
+
+ if (ifx && ifx->ifinfo.ip.type == mDNSAddrType_IPv4)
+ {
+ struct sockaddr_in *s = (struct sockaddr_in*)&interface;
+ s->sin_len = sizeof(*s);
+ s->sin_family = AF_INET;
+ s->sin_port = 0;
+ s->sin_addr.s_addr = ifx->ifinfo.ip.ip.v4.NotAnInteger;
+ }
+ else if (ifx && ifx->ifinfo.ip.type == mDNSAddrType_IPv6)
+ {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&interface;
+ sin6->sin6_len = sizeof(*sin6);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_flowinfo = 0;
+ sin6->sin6_port = 0;
+ sin6->sin6_addr = *(struct in6_addr*)&ifx->ifinfo.ip.ip.v6;
+ sin6->sin6_scope_id = ifx->scope_id;
+ }
+
+ if (query->info->ip.type == mDNSAddrType_IPv4)
+ {
+ struct sockaddr_in *s = (struct sockaddr_in*)&address;
+ s->sin_len = sizeof(*s);
+ s->sin_family = AF_INET;
+ s->sin_port = query->info->port.NotAnInteger;
+ s->sin_addr.s_addr = query->info->ip.ip.v4.NotAnInteger;
+ }
+ else
+ {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&address;
+ sin6->sin6_len = sizeof(*sin6);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = query->info->port.NotAnInteger;
+ sin6->sin6_flowinfo = 0;
+ sin6->sin6_addr = *(struct in6_addr*)&query->info->ip.ip.v6;
+ sin6->sin6_scope_id = ifx ? ifx->scope_id : 0;
+ }
+
+ // The OS X DNSServiceResolverResolve() API is defined using a C-string,
+ // but the mDNS_StartResolveService() call actually returns a packed block of P-strings.
+ // Hence we have to convert the P-string(s) to a C-string before returning the result to the client.
+ // ASCII-1 characters are used in the C-string as boundary markers,
+ // to indicate the boundaries between the original constituent P-strings.
+ for (i=1; i<query->info->TXTlen; i++)
+ {
+ if (--pstrlen >= 0)
+ cstring[i-1] = query->info->TXTinfo[i];
+ else
+ {
+ cstring[i-1] = 1;
+ pstrlen = query->info->TXTinfo[i];
+ }
+ }
+ cstring[i-1] = 0; // Put the terminating NULL on the end
+
+ LogOperation("%5d: DNSServiceResolver(%##s) -> %#a:%u", x->ClientMachPort,
+ x->i.name.c, &query->info->ip, mDNSVal16(query->info->port));
+ status = DNSServiceResolverReply_rpc(x->ClientMachPort,
+ (char*)&interface, (char*)&address, cstring, 0, MDNS_MM_TIMEOUT);
+ if (status == MACH_SEND_TIMED_OUT)
+ AbortBlockedClient(x->ClientMachPort, "resolve", x);
+}
+
+mDNSexport kern_return_t provide_DNSServiceResolverResolve_rpc(mach_port_t unusedserver, mach_port_t client,
+ DNSCString name, DNSCString regtype, DNSCString domain)
+{
+ // Check client parameter
+ (void)unusedserver; // Unused
+ mStatus err = mStatus_NoError;
+ const char *errormsg = "Unknown";
+ if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
+ if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; }
+
+ // Check other parameters
+ domainlabel n;
+ domainname t, d, srv;
+ if (!name[0] || !MakeDomainLabelFromLiteralString(&n, name)) { errormsg = "Bad Instance Name"; goto badparam; }
+ if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type"; goto badparam; }
+ if (!domain[0] || !MakeDomainNameFromDNSNameString(&d, domain)) { errormsg = "Bad Domain"; goto badparam; }
+ if (!ConstructServiceName(&srv, &n, &t, &d)) { errormsg = "Bad Name"; goto badparam; }
+
+ // Allocate memory, and handle failure
+ DNSServiceResolver *x = mallocL("DNSServiceResolver", sizeof(*x));
+ if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
+
+ // Set up object, and link into list
+ x->ClientMachPort = client;
+ x->i.InterfaceID = mDNSInterface_Any;
+ x->i.name = srv;
+ x->ReportTime = NonZeroTime(mDNS_TimeNow(&mDNSStorage) + 130 * mDNSPlatformOneSecond);
+ x->next = DNSServiceResolverList;
+ DNSServiceResolverList = x;
+
+ // Do the operation
+ LogOperation("%5d: DNSServiceResolve(%##s) START", client, x->i.name.c);
+ err = mDNS_StartResolveService(&mDNSStorage, &x->q, &x->i, FoundInstanceInfo, x);
+ if (err) { AbortClient(client, x); errormsg = "mDNS_StartResolveService"; goto fail; }
+
+ // Succeeded: Wrap up and return
+ EnableDeathNotificationForClient(client, x);
+ return(mStatus_NoError);
+
+badparam:
+ err = mStatus_BadParamErr;
+fail:
+ LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%d)", client, name, regtype, domain, errormsg, err);
+ return(err);
+}
+
+//*************************************************************************************************************
+// Registration
+
+mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
+{
+ m->p->NotifyUser = NonZeroTime(m->timenow + delay);
+}
+
+mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
+{
+ ServiceInstance *si = (ServiceInstance*)srs->ServiceContext;
+
+ if (result == mStatus_NoError)
+ {
+ kern_return_t status;
+ LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Registered", si->ClientMachPort, srs->RR_SRV.resrec.name->c, SRS_PORT(srs));
+ status = DNSServiceRegistrationReply_rpc(si->ClientMachPort, result, MDNS_MM_TIMEOUT);
+ if (status == MACH_SEND_TIMED_OUT)
+ AbortBlockedClient(si->ClientMachPort, "registration success", si);
+ if (si->autoname && CountPeerRegistrations(m, srs) == 0)
+ RecordUpdatedNiceLabel(m, 0); // Successfully got new name, tell user immediately
+ }
+
+ else if (result == mStatus_NameConflict)
+ {
+ LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Conflict", si->ClientMachPort, srs->RR_SRV.resrec.name->c, SRS_PORT(srs));
+ // Note: By the time we get the mStatus_NameConflict message, the service is already deregistered
+ // and the memory is free, so we don't have to wait for an mStatus_MemFree message as well.
+ if (si->autoname && CountPeerRegistrations(m, srs) == 0)
+ {
+ // On conflict for an autoname service, rename and reregister *all* autoname services
+ IncrementLabelSuffix(&m->nicelabel, mDNStrue);
+ mDNS_ConfigChanged(m);
+ }
+ else if (si->autoname)
+ {
+ mDNS_RenameAndReregisterService(m, srs, mDNSNULL);
+ return;
+ }
+ else
+ {
+ // If we get a name conflict, we tell the client about it, and then they are expected to dispose
+ // of their registration in the usual way (which we will catch via client death notification).
+ // If the Mach queue is full, we forcibly abort the client immediately.
+ kern_return_t status = DNSServiceRegistrationReply_rpc(si->ClientMachPort, result, MDNS_MM_TIMEOUT);
+ if (status == MACH_SEND_TIMED_OUT)
+ AbortBlockedClient(si->ClientMachPort, "registration conflict", NULL);
+ }
+ }
+
+ else if (result == mStatus_MemFree)
+ {
+ if (si->renameonmemfree) // We intentionally terminated registration so we could re-register with new name
+ {
+ debugf("RegCallback renaming %#s to %#s", si->name.c, m->nicelabel.c);
+ si->renameonmemfree = mDNSfalse;
+ si->name = m->nicelabel;
+ mDNS_RenameAndReregisterService(m, srs, &si->name);
+ }
+ else
+ {
+ // SANITY CHECK: make sure service instance is no longer in any ServiceRegistration's list
+ DNSServiceRegistration *r;
+ for (r = DNSServiceRegistrationList; r; r = r->next)
+ {
+ ServiceInstance **sp = &r->regs;
+ while (*sp)
+ {
+ if (*sp == si) { LogMsg("RegCallback: %##s Still in list; removing", srs->RR_SRV.resrec.name->c); *sp = (*sp)->next; break; }
+ sp = &(*sp)->next;
+ }
+ }
+ // END SANITY CHECK
+ FreeServiceInstance(si);
+ }
+ }
+
+ else if (result != mStatus_NATTraversal)
+ LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %d", si->ClientMachPort, srs->RR_SRV.resrec.name->c, SRS_PORT(srs), result);
+}
+
+mDNSlocal mStatus AddServiceInstance(DNSServiceRegistration *x, const domainname *domain)
+{
+ mStatus err = 0;
+ ServiceInstance *si = NULL;
+ AuthRecord *SubTypes = NULL;
+
+ for (si = x->regs; si; si = si->next)
+ {
+ if (SameDomainName(&si->domain, domain))
+ { LogMsg("Requested addition of domain %##s already in list", domain->c); return mStatus_AlreadyRegistered; }
+ }
+
+ SubTypes = AllocateSubTypes(x->NumSubTypes, x->regtype, mDNSNULL);
+ if (x->NumSubTypes && !SubTypes) return mStatus_NoMemoryErr;
+
+ si = mallocL("ServiceInstance", sizeof(*si) - sizeof(RDataBody) + x->rdsize);
+ if (!si) return mStatus_NoMemoryErr;
+
+ si->ClientMachPort = x->ClientMachPort;
+ si->renameonmemfree = mDNSfalse;
+ si->autoname = x->autoname;
+ si->name = x->autoname ? mDNSStorage.nicelabel : x->name;
+ si->domain = *domain;
+ si->srs.AnonData = mDNSNULL;
+
+ err = mDNS_RegisterService(&mDNSStorage, &si->srs, &si->name, &x->type, domain, NULL,
+ x->port, x->txtinfo, x->txt_len, SubTypes, x->NumSubTypes, mDNSInterface_Any, RegCallback, si, 0);
+ if (!err)
+ {
+ si->next = x->regs;
+ x->regs = si;
+ }
+ else
+ {
+ LogMsg("Error %d for registration of service in domain %##s", err, domain->c);
+ freeL("ServiceInstance", si);
+ }
+ return err;
+}
+
+mDNSexport void machserver_automatic_registration_domain_changed(const domainname *d, mDNSBool add)
+{
+ DNSServiceRegistration *reg;
+
+ for (reg = DNSServiceRegistrationList; reg; reg = reg->next)
+ {
+ if (reg->DefaultDomain)
+ {
+ if (add)
+ AddServiceInstance(reg, d);
+ else
+ {
+ ServiceInstance **si = &reg->regs;
+ while (*si)
+ {
+ if (SameDomainName(&(*si)->domain, d))
+ {
+ ServiceInstance *s = *si;
+ *si = (*si)->next;
+ if (mDNS_DeregisterService(&mDNSStorage, &s->srs)) FreeServiceInstance(s); // only free memory synchronously on error
+ break;
+ }
+ si = &(*si)->next;
+ }
+ if (!si) debugf("Requested removal of default domain %##s not in client %5d's list", d, reg->ClientMachPort); // normal if registration failed
+ }
+ }
+ }
+}
+
+mDNSexport kern_return_t provide_DNSServiceRegistrationCreate_rpc(mach_port_t unusedserver, mach_port_t client,
+ DNSCString name, DNSCString regtype, DNSCString domain, IPPort IpPort, DNSCString txtRecord)
+{
+ (void)unusedserver; // Unused
+ mStatus err = mStatus_NoError;
+ const char *errormsg = "Unknown";
+
+ // older versions of this code passed the port via mach IPC as an int.
+ // we continue to pass it as 4 bytes to maintain binary compatibility,
+ // but now ensure that the network byte order is preserved by using a struct
+ mDNSIPPort port;
+ port.b[0] = IpPort.bytes[2];
+ port.b[1] = IpPort.bytes[3];
+
+ if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
+ if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; }
+
+ // Check for sub-types after the service type
+ size_t reglen = strlen(regtype) + 1;
+ if (reglen > MAX_ESCAPED_DOMAIN_NAME) { errormsg = "reglen too long"; goto badparam; }
+ mDNSs32 NumSubTypes = ChopSubTypes(regtype, mDNSNULL); // Note: Modifies regtype string to remove trailing subtypes
+ if (NumSubTypes < 0) { errormsg = "Bad Service SubType"; goto badparam; }
+
+ // Check other parameters
+ domainlabel n;
+ domainname t, d;
+ domainname srv;
+ if (!name[0]) n = mDNSStorage.nicelabel;
+ else if (!MakeDomainLabelFromLiteralString(&n, name)) { errormsg = "Bad Instance Name"; goto badparam; }
+ if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type"; goto badparam; }
+ if (!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) { errormsg = "Bad Domain"; goto badparam; }
+ if (!ConstructServiceName(&srv, &n, &t, &d)) { errormsg = "Bad Name"; goto badparam; }
+
+ unsigned char txtinfo[1024] = "";
+ unsigned int data_len = 0;
+ unsigned int size = sizeof(RDataBody);
+ unsigned char *pstring = &txtinfo[data_len];
+ char *ptr = txtRecord;
+
+ // The OS X DNSServiceRegistrationCreate() API is defined using a C-string,
+ // but the mDNS_RegisterService() call actually requires a packed block of P-strings.
+ // Hence we have to convert the C-string to a P-string.
+ // ASCII-1 characters are allowed in the C-string as boundary markers,
+ // so that a single C-string can be used to represent one or more P-strings.
+ while (*ptr)
+ {
+ if (++data_len >= sizeof(txtinfo)) { errormsg = "TXT record too long"; goto badtxt; }
+ if (*ptr == 1) // If this is our boundary marker, start a new P-string
+ {
+ pstring = &txtinfo[data_len];
+ pstring[0] = 0;
+ ptr++;
+ }
+ else
+ {
+ if (pstring[0] == 255) { errormsg = "TXT record invalid (component longer than 255)"; goto badtxt; }
+ pstring[++pstring[0]] = *ptr++;
+ }
+ }
+
+ data_len++;
+ if (size < data_len)
+ size = data_len;
+
+ // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with
+ // a port number of zero. When two instances of the protected client are allowed to run on one
+ // machine, we don't want to see misleading "Bogus client" messages in syslog and the console.
+ if (!mDNSIPPortIsZero(port))
+ {
+ int count = CountExistingRegistrations(&srv, port);
+ if (count)
+ LogMsg("%5d: Client application registered %d identical instances of service %##s port %u.",
+ client, count+1, srv.c, mDNSVal16(port));
+ }
+
+ // Allocate memory, and handle failure
+ DNSServiceRegistration *x = mallocL("DNSServiceRegistration", sizeof(*x));
+ if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
+ mDNSPlatformMemZero(x, sizeof(*x));
+
+ // Set up object, and link into list
+ x->ClientMachPort = client;
+ x->DefaultDomain = !domain[0];
+ x->autoname = (!name[0]);
+ x->rdsize = size;
+ x->NumSubTypes = NumSubTypes;
+ memcpy(x->regtype, regtype, reglen);
+ x->name = n;
+ x->type = t;
+ x->port = port;
+ memcpy(x->txtinfo, txtinfo, 1024);
+ x->txt_len = data_len;
+ x->NextRef = 0;
+ x->regs = NULL;
+
+ x->next = DNSServiceRegistrationList;
+ DNSServiceRegistrationList = x;
+
+ LogOperation("%5d: DNSServiceRegistration(\"%s\", \"%s\", \"%s\", %u) START",
+ x->ClientMachPort, name, regtype, domain, mDNSVal16(port));
+
+ err = AddServiceInstance(x, &d);
+ if (err) { AbortClient(client, x); errormsg = "mDNS_RegisterService"; goto fail; } // bail if .local (or explicit domain) fails
+
+ if (x->DefaultDomain)
+ {
+ DNameListElem *p;
+ for (p = AutoRegistrationDomains; p; p = p->next)
+ AddServiceInstance(x, &p->name);
+ }
+
+ // Succeeded: Wrap up and return
+ EnableDeathNotificationForClient(client, x);
+ return(mStatus_NoError);
+
+badtxt:
+ LogMsg("%5d: TXT record: %.100s...", client, txtRecord);
+badparam:
+ err = mStatus_BadParamErr;
+fail:
+ LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%d)",
+ client, name, regtype, domain, mDNSVal16(port), errormsg, err);
+ return(err);
+}
+
+mDNSlocal void mDNSPreferencesSetNames(mDNS *const m, int key, domainlabel *old, domainlabel *new)
+{
+ domainlabel *prevold, *prevnew;
+ switch (key)
+ {
+ case kmDNSComputerName:
+ case kmDNSLocalHostName:
+ if (key == kmDNSComputerName)
+ {
+ prevold = &m->p->prevoldnicelabel;
+ prevnew = &m->p->prevnewnicelabel;
+ }
+ else
+ {
+ prevold = &m->p->prevoldhostlabel;
+ prevnew = &m->p->prevnewhostlabel;
+ }
+ // There are a few cases where we need to invoke the helper.
+ //
+ // 1. If the "old" label and "new" label are not same, it means there is a conflict. We need
+ // to invoke the helper so that it pops up a dialogue to inform the user about the
+ // conflict
+ //
+ // 2. If the "old" label and "new" label are same, it means the user has set the host/nice label
+ // through the preferences pane. We may have to inform the helper as it may have popped up
+ // a dialogue previously (due to a conflict) and it needs to suppress it now. We can avoid invoking
+ // the helper in this case if the previous values (old and new) that we told helper last time
+ // are same. If the previous old and new values are same, helper does not care.
+ //
+ // Note: "new" can be NULL when we have repeated conflicts and we are asking helper to give up. "old"
+ // is not called with NULL today, but this makes it future proof.
+ if (!old || !new || !SameDomainLabelCS(old->c, new->c) ||
+ !SameDomainLabelCS(old->c, prevold->c) ||
+ !SameDomainLabelCS(new->c, prevnew->c))
+ {
+ if (old)
+ *prevold = *old;
+ else
+ prevold->c[0] = 0;
+ if (new)
+ *prevnew = *new;
+ else
+ prevnew->c[0] = 0;
+ mDNSPreferencesSetName(key, old, new);
+ }
+ else
+ {
+ LogInfo("mDNSPreferencesSetNames not invoking helper %s %#s, %s %#s, old %#s, new %#s",
+ (key == kmDNSComputerName ? "prevoldnicelabel" : "prevoldhostlabel"), prevold->c,
+ (key == kmDNSComputerName ? "prevnewnicelabel" : "prevnewhostlabel"), prevnew->c,
+ old->c, new->c);
+ }
+ break;
+ default:
+ LogMsg("mDNSPreferencesSetNames: unrecognized key: %d", key);
+ return;
+ }
+}
+
+mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
+{
+ (void)m; // Unused
+ if (result == mStatus_NoError)
+ {
+ if (!SameDomainLabelCS(m->p->userhostlabel.c, m->hostlabel.c))
+ LogInfo("Local Hostname changed from \"%#s.local\" to \"%#s.local\"", m->p->userhostlabel.c, m->hostlabel.c);
+ // One second pause in case we get a Computer Name update too -- don't want to alert the user twice
+ RecordUpdatedNiceLabel(m, mDNSPlatformOneSecond);
+ }
+ else if (result == mStatus_NameConflict)
+ {
+ LogInfo("Local Hostname conflict for \"%#s.local\"", m->hostlabel.c);
+ if (!m->p->HostNameConflict) m->p->HostNameConflict = NonZeroTime(m->timenow);
+ else if (m->timenow - m->p->HostNameConflict > 60 * mDNSPlatformOneSecond)
+ {
+ // Tell the helper we've given up
+ mDNSPreferencesSetNames(m, kmDNSLocalHostName, &m->p->userhostlabel, NULL);
+ }
+ }
+ else if (result == mStatus_GrowCache)
+ {
+ // Allocate another chunk of cache storage
+ CacheEntity *storage = mallocL("mStatus_GrowCache", sizeof(CacheEntity) * RR_CACHE_SIZE);
+ //LogInfo("GrowCache %d * %d = %d", sizeof(CacheEntity), RR_CACHE_SIZE, sizeof(CacheEntity) * RR_CACHE_SIZE);
+ if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE);
+ }
+ else if (result == mStatus_ConfigChanged)
+ {
+ // Tell the helper we've seen a change in the labels. It will dismiss the name conflict alert if needed.
+ mDNSPreferencesSetNames(m, kmDNSComputerName, &m->p->usernicelabel, &m->nicelabel);
+ mDNSPreferencesSetNames(m, kmDNSLocalHostName, &m->p->userhostlabel, &m->hostlabel);
+
+ // First we check our list of old Mach-based registered services, to see if any need to be updated to a new name
+ DNSServiceRegistration *r;
+ for (r = DNSServiceRegistrationList; r; r=r->next)
+ if (r->autoname)
+ {
+ ServiceInstance *si;
+ for (si = r->regs; si; si = si->next)
+ {
+ if (!SameDomainLabelCS(si->name.c, m->nicelabel.c))
+ {
+ debugf("NetworkChanged renaming %##s to %#s", si->srs.RR_SRV.resrec.name->c, m->nicelabel.c);
+ si->renameonmemfree = mDNStrue;
+ if (mDNS_DeregisterService_drt(m, &si->srs, mDNS_Dereg_rapid))
+ RegCallback(m, &si->srs, mStatus_MemFree); // If service deregistered already, we can re-register immediately
+ }
+ }
+ }
+
+ // Then we call into the UDS daemon code, to let it do the same
+ udsserver_handle_configchange(m);
+ }
+}
+
+//*************************************************************************************************************
+// Add / Update / Remove records from existing Registration
+
+mDNSexport kern_return_t provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t unusedserver, mach_port_t client,
+ int type, const char *data, mach_msg_type_number_t data_len, uint32_t ttl, natural_t *reference)
+{
+ // Check client parameter
+ uint32_t id;
+ mStatus err = mStatus_NoError;
+ const char *errormsg = "Unknown";
+ DNSServiceRegistration *x = DNSServiceRegistrationList;
+ if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
+ ServiceInstance *si;
+ size_t size;
+ (void)unusedserver; // Unused
+ while (x && x->ClientMachPort != client) x = x->next;
+ if (!x) { err = mStatus_BadReferenceErr; errormsg = "No such client"; goto fail; }
+
+ // Check other parameters
+ if (data_len > 8192) { err = mStatus_BadParamErr; errormsg = "data_len > 8K"; goto fail; }
+ if (data_len > sizeof(RDataBody)) size = data_len;
+ else size = sizeof(RDataBody);
+
+ id = x->NextRef++;
+ *reference = (natural_t)id;
+ for (si = x->regs; si; si = si->next)
+ {
+ // Allocate memory, and handle failure
+ ExtraResourceRecord *extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
+ if (!extra) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
+
+ // Fill in type, length, and data of new record
+ extra->r.resrec.rrtype = type;
+ extra->r.rdatastorage.MaxRDLength = size;
+ extra->r.resrec.rdlength = data_len;
+ memcpy(&extra->r.rdatastorage.u.data, data, data_len);
+
+ // Do the operation
+ LogOperation("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) REF %p",
+ client, si->srs.RR_SRV.resrec.name->c, type, data_len, extra);
+ err = mDNS_AddRecordToService(&mDNSStorage, &si->srs, extra, &extra->r.rdatastorage, ttl, 0);
+
+ if (err)
+ {
+ freeL("Extra Resource Record", extra);
+ errormsg = "mDNS_AddRecordToService";
+ goto fail;
+ }
+
+ extra->ClientID = id;
+ }
+
+ return mStatus_NoError;
+
+fail:
+ LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%d)", client, x ? x->name.c : (mDNSu8*)"\x8" "«NULL»", type, data_len, errormsg, err);
+ return mStatus_UnknownErr;
+}
+
+mDNSlocal void UpdateCallback(mDNS *const m, AuthRecord *const rr, RData *OldRData, mDNSu16 OldRDLen)
+{
+ (void)m; // Unused
+ (void)OldRDLen; // Unused
+ if (OldRData != &rr->rdatastorage)
+ freeL("Old RData", OldRData);
+}
+
+mDNSlocal mStatus UpdateRecord(ServiceRecordSet *srs, mach_port_t client, AuthRecord *rr, const char *data, mach_msg_type_number_t data_len, uint32_t ttl)
+{
+ // Check client parameter
+ mStatus err = mStatus_NoError;
+ const char *errormsg = "Unknown";
+ const domainname *name = (const domainname *)"";
+
+ name = srs->RR_SRV.resrec.name;
+
+ unsigned int size = sizeof(RDataBody);
+ if (size < data_len)
+ size = data_len;
+
+ // Allocate memory, and handle failure
+ RData *newrdata = mallocL("RData", sizeof(*newrdata) - sizeof(RDataBody) + size);
+ if (!newrdata) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
+
+ // Fill in new length, and data
+ newrdata->MaxRDLength = size;
+ memcpy(&newrdata->u, data, data_len);
+
+ // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
+ // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
+ // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
+ if (rr->resrec.rrtype == kDNSType_TXT && data_len == 0) { data_len = 1; newrdata->u.txt.c[0] = 0; }
+
+ // Do the operation
+ LogOperation("%5d: DNSServiceRegistrationUpdateRecord(%##s, new length %d)",
+ client, srs->RR_SRV.resrec.name->c, data_len);
+
+ err = mDNS_Update(&mDNSStorage, rr, ttl, data_len, newrdata, UpdateCallback);
+ if (err)
+ {
+ errormsg = "mDNS_Update";
+ freeL("RData", newrdata);
+ return err;
+ }
+ return(mStatus_NoError);
+
+fail:
+ LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %d) failed: %s (%d)", client, name->c, data_len, errormsg, err);
+ return(err);
+}
+
+mDNSexport kern_return_t provide_DNSServiceRegistrationUpdateRecord_rpc(mach_port_t unusedserver, mach_port_t client,
+ natural_t reference, const char *data, mach_msg_type_number_t data_len, uint32_t ttl)
+{
+ // Check client parameter
+ mStatus err = mStatus_NoError;
+ const char *errormsg = "Unknown";
+ const domainname *name = (const domainname *)"";
+ ServiceInstance *si;
+
+ (void)unusedserver; // unused
+ if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
+ DNSServiceRegistration *x = DNSServiceRegistrationList;
+ while (x && x->ClientMachPort != client) x = x->next;
+ if (!x) { err = mStatus_BadReferenceErr; errormsg = "No such client"; goto fail; }
+
+ // Check other parameters
+ if (data_len > 8192) { err = mStatus_BadParamErr; errormsg = "data_len > 8K"; goto fail; }
+
+ for (si = x->regs; si; si = si->next)
+ {
+ AuthRecord *r = NULL;
+
+ // Find the record we're updating. NULL reference means update the primary TXT record
+ if (!reference) r = &si->srs.RR_TXT;
+ else
+ {
+ ExtraResourceRecord *ptr;
+ for (ptr = si->srs.Extras; ptr; ptr = ptr->next)
+ {
+ if ((natural_t)ptr->ClientID == reference)
+ { r = &ptr->r; break; }
+ }
+ if (!r) { err = mStatus_BadReferenceErr; errormsg = "No such record"; goto fail; }
+ }
+ err = UpdateRecord(&si->srs, client, r, data, data_len, ttl);
+ if (err) goto fail; //!!!KRS this will cause failures for non-local defaults!
+ }
+
+ return mStatus_NoError;
+
+fail:
+ LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%d)", client, name->c, reference, data_len, errormsg, err);
+ return(err);
+}
+
+mDNSlocal mStatus RemoveRecord(ServiceRecordSet *srs, ExtraResourceRecord *extra, mach_port_t client)
+{
+ const domainname *const name = srs->RR_SRV.resrec.name;
+ mStatus err = mStatus_NoError;
+
+ // Do the operation
+ LogOperation("%5d: DNSServiceRegistrationRemoveRecord(%##s)", client, srs->RR_SRV.resrec.name->c);
+
+ err = mDNS_RemoveRecordFromService(&mDNSStorage, srs, extra, FreeExtraRR, extra);
+ if (err) LogMsg("%5d: DNSServiceRegistrationRemoveRecord (%##s) failed: %d", client, name->c, err);
+
+ return err;
+}
+
+mDNSexport kern_return_t provide_DNSServiceRegistrationRemoveRecord_rpc(mach_port_t unusedserver, mach_port_t client,
+ natural_t reference)
+{
+ // Check client parameter
+ (void)unusedserver; // Unused
+ mStatus err = mStatus_NoError;
+ const char *errormsg = "Unknown";
+ if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; }
+ DNSServiceRegistration *x = DNSServiceRegistrationList;
+ ServiceInstance *si;
+
+ while (x && x->ClientMachPort != client) x = x->next;
+ if (!x) { err = mStatus_BadReferenceErr; errormsg = "No such client"; goto fail; }
+
+ for (si = x->regs; si; si = si->next)
+ {
+ ExtraResourceRecord *e;
+ for (e = si->srs.Extras; e; e = e->next)
+ {
+ if ((natural_t)e->ClientID == reference)
+ {
+ err = RemoveRecord(&si->srs, e, client);
+ break;
+ }
+ }
+ if (!e) { err = mStatus_BadReferenceErr; errormsg = "No such reference"; goto fail; }
+ }
+
+ return mStatus_NoError;
+
+fail:
+ LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%X) failed: %s (%d)", client, reference, errormsg, err);
+ return(err);
+}
+
+//*************************************************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Startup, shutdown, and supporting code
+#endif
+
+mDNSlocal void ExitCallback(int sig)
+{
+ (void)sig; // Unused
+ LogMsg("%s stopping", mDNSResponderVersionString);
+
+ debugf("ExitCallback: Aborting MIG clients");
+ while (DNSServiceDomainEnumerationList)
+ AbortClient(DNSServiceDomainEnumerationList->ClientMachPort, DNSServiceDomainEnumerationList);
+ while (DNSServiceBrowserList)
+ AbortClient(DNSServiceBrowserList->ClientMachPort, DNSServiceBrowserList);
+ while (DNSServiceResolverList)
+ AbortClient(DNSServiceResolverList->ClientMachPort, DNSServiceResolverList);
+ while (DNSServiceRegistrationList)
+ AbortClient(DNSServiceRegistrationList->ClientMachPort, DNSServiceRegistrationList);
+
+ if (udsserver_exit() < 0)
+ LogMsg("ExitCallback: udsserver_exit failed");
+
+ debugf("ExitCallback: mDNS_StartExit");
+ mDNS_StartExit(&mDNSStorage);
+}
+
+#ifndef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+
+mDNSlocal void DNSserverCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
+{
+ mig_reply_error_t *request = msg;
+ mig_reply_error_t *reply;
+ mach_msg_return_t mr;
+ int options;
+ (void)port; // Unused
+ (void)size; // Unused
+ (void)info; // Unused
+
+ KQueueLock(&mDNSStorage);
+
+ /* allocate a reply buffer */
+ reply = CFAllocatorAllocate(NULL, provide_DNSServiceDiscoveryRequest_subsystem.maxsize, 0);
+
+ /* call the MiG server routine */
+ (void) DNSServiceDiscoveryRequest_server(&request->Head, &reply->Head);
+
+ if (!(reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) && (reply->RetCode != KERN_SUCCESS))
+ {
+ if (reply->RetCode == MIG_NO_REPLY)
+ {
+ /*
+ * This return code is a little tricky -- it appears that the
+ * demux routine found an error of some sort, but since that
+ * error would not normally get returned either to the local
+ * user or the remote one, we pretend it's ok.
+ */
+ CFAllocatorDeallocate(NULL, reply);
+ goto done;
+ }
+
+ /*
+ * destroy any out-of-line data in the request buffer but don't destroy
+ * the reply port right (since we need that to send an error message).
+ */
+ request->Head.msgh_remote_port = MACH_PORT_NULL;
+ mach_msg_destroy(&request->Head);
+ }
+
+ if (reply->Head.msgh_remote_port == MACH_PORT_NULL)
+ {
+ /* no reply port, so destroy the reply */
+ if (reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)
+ mach_msg_destroy(&reply->Head);
+ CFAllocatorDeallocate(NULL, reply);
+ goto done;
+ }
+
+ /*
+ * send reply.
+ *
+ * We don't want to block indefinitely because the client
+ * isn't receiving messages from the reply port.
+ * If we have a send-once right for the reply port, then
+ * this isn't a concern because the send won't block.
+ * If we have a send right, we need to use MACH_SEND_TIMEOUT.
+ * To avoid falling off the kernel's fast RPC path unnecessarily,
+ * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
+ */
+
+ options = MACH_SEND_MSG;
+ if (MACH_MSGH_BITS_REMOTE(reply->Head.msgh_bits) == MACH_MSG_TYPE_MOVE_SEND_ONCE)
+ options |= MACH_SEND_TIMEOUT;
+
+ mr = mach_msg(&reply->Head, /* msg */
+ options, /* option */
+ reply->Head.msgh_size, /* send_size */
+ 0, /* rcv_size */
+ MACH_PORT_NULL, /* rcv_name */
+ MACH_MSG_TIMEOUT_NONE, /* timeout */
+ MACH_PORT_NULL); /* notify */
+
+ /* Has a message error occurred? */
+ switch (mr)
+ {
+ case MACH_SEND_INVALID_DEST:
+ case MACH_SEND_TIMED_OUT:
+ /* the reply can't be delivered, so destroy it */
+ mach_msg_destroy(&reply->Head);
+ break;
+
+ default:
+ /* Includes success case. */
+ break;
+ }
+
+ CFAllocatorDeallocate(NULL, reply);
+
+done:
+ KQueueUnlock(&mDNSStorage, "Mach client event");
+}
+
+// Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit
+mDNSlocal void HandleSIG(int sig)
+{
+ kern_return_t status;
+ mach_msg_header_t header;
+
+ // WARNING: can't call syslog or fprintf from signal handler
+ header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
+ header.msgh_remote_port = signal_port;
+ header.msgh_local_port = MACH_PORT_NULL;
+ header.msgh_size = sizeof(header);
+ header.msgh_id = sig;
+
+ status = mach_msg(&header, MACH_SEND_MSG | MACH_SEND_TIMEOUT, header.msgh_size,
+ 0, MACH_PORT_NULL, 0, MACH_PORT_NULL);
+
+ if (status != MACH_MSG_SUCCESS)
+ {
+ if (status == MACH_SEND_TIMED_OUT) mach_msg_destroy(&header);
+ if (sig == SIGTERM || sig == SIGINT) exit(-1);
+ }
+}
+
+#endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+
+mDNSlocal void INFOCallback(void)
+{
+ mDNSs32 utc = mDNSPlatformUTC();
+ NetworkInterfaceInfoOSX *i;
+ DNSServer *s;
+ McastResolver *mr;
+
+ // Create LoggerID(Key)->com.apple.networking.mDNSResponder(Value) pair when SIGINFO is received.
+ // This key-value pair is used as a condition by syslogd to Log to com.apple.networking.mDNSResponder.log file
+ // present in /etc/asl/com.apple.networking.mDNSResponder.
+ asl_set(log_msg, "LoggerID", "com.apple.networking.mDNSResponder");
+
+ LogMsg("---- BEGIN STATE LOG ---- %s %s %d", mDNSResponderVersionString, OSXVers ? "OSXVers" : "iOSVers", OSXVers ? OSXVers : iOSVers);
+
+ udsserver_info(&mDNSStorage);
+ xpcserver_info(&mDNSStorage);
+
+ LogMsgNoIdent("----- KQSocketEventSources -----");
+ if (!gEventSources) LogMsgNoIdent("<None>");
+ else
+ {
+ KQSocketEventSource *k;
+ for (k = gEventSources; k; k=k->next)
+ LogMsgNoIdent("%3d %s %s", k->fd, k->kqs.KQtask, k->fd == mDNSStorage.uds_listener_skt ? "Listener for incoming UDS clients" : " ");
+ }
+
+ LogMsgNoIdent("------ Network Interfaces ------");
+ if (!mDNSStorage.p->InterfaceList) LogMsgNoIdent("<None>");
+ else
+ {
+ for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
+ {
+ // Allow six characters for interface name, for names like "vmnet8"
+ if (!i->Exists)
+ LogMsgNoIdent("%p %2ld, Registered %p, %s %-6s(%lu) %.6a %.6a %#-14a dormant for %d seconds",
+ i, i->ifinfo.InterfaceID, i->Registered,
+ i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifinfo.ifname, i->scope_id, &i->ifinfo.MAC, &i->BSSID,
+ &i->ifinfo.ip, utc - i->LastSeen);
+ else
+ {
+ const CacheRecord *sps[3];
+ FindSPSInCache(&mDNSStorage, &i->ifinfo.NetWakeBrowse, sps);
+ LogMsgNoIdent("%p %2ld, Registered %p, %s %-6s(%lu) %.6a %.6a %s %s %-15.4a %s %s %s %s %#a",
+ i, i->ifinfo.InterfaceID, i->Registered,
+ i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifinfo.ifname, i->scope_id, &i->ifinfo.MAC, &i->BSSID,
+ i->ifinfo.InterfaceActive ? "Active" : " ",
+ i->ifinfo.IPv4Available ? "v4" : " ",
+ i->ifinfo.IPv4Available ? (mDNSv4Addr*)&i->ifa_v4addr : &zerov4Addr,
+ i->ifinfo.IPv6Available ? "v6" : " ",
+ i->ifinfo.Advertise ? "A" : " ",
+ i->ifinfo.McastTxRx ? "M" : " ",
+ !(i->ifinfo.InterfaceActive && i->ifinfo.NetWake) ? " " : !sps[0] ? "p" : "P",
+ &i->ifinfo.ip);
+
+ if (sps[0]) LogMsgNoIdent(" %13d %#s", SPSMetric(sps[0]->resrec.rdata->u.name.c), sps[0]->resrec.rdata->u.name.c);
+ if (sps[1]) LogMsgNoIdent(" %13d %#s", SPSMetric(sps[1]->resrec.rdata->u.name.c), sps[1]->resrec.rdata->u.name.c);
+ if (sps[2]) LogMsgNoIdent(" %13d %#s", SPSMetric(sps[2]->resrec.rdata->u.name.c), sps[2]->resrec.rdata->u.name.c);
+ }
+ }
+ }
+
+ LogMsgNoIdent("--------- DNS Servers(%d) ----------", NumUnicastDNSServers);
+ if (!mDNSStorage.DNSServers) LogMsgNoIdent("<None>");
+ else
+ {
+ for (s = mDNSStorage.DNSServers; s; s = s->next)
+ {
+ NetworkInterfaceInfoOSX *ifx = IfindexToInterfaceInfoOSX(&mDNSStorage, s->interface);
+ LogMsgNoIdent("DNS Server %##s %s%s%#a:%d %d %s %d %d %s %s %s %s %s",
+ s->domain.c, ifx ? ifx->ifinfo.ifname : "", ifx ? " " : "", &s->addr, mDNSVal16(s->port),
+ s->penaltyTime ? s->penaltyTime - mDNS_TimeNow(&mDNSStorage) : 0, DNSScopeToString(s->scoped),
+ s->timeout, s->resGroupID,
+ s->teststate == DNSServer_Untested ? "(Untested)" :
+ s->teststate == DNSServer_Passed ? "" :
+ s->teststate == DNSServer_Failed ? "(Failed)" :
+ s->teststate == DNSServer_Disabled ? "(Disabled)" : "(Unknown state)",
+ s->req_A ? "v4" : "!v4",
+ s->req_AAAA ? "v6" : "!v6",
+ s->cellIntf ? "cell" : "!cell",
+ s->DNSSECAware ? "DNSSECAware" : "!DNSSECAware");
+ }
+ }
+ mDNSs32 now = mDNS_TimeNow(&mDNSStorage);
+ LogMsgNoIdent("v4answers %d", mDNSStorage.p->v4answers);
+ LogMsgNoIdent("v6answers %d", mDNSStorage.p->v6answers);
+ LogMsgNoIdent("Last DNS Trigger: %d ms ago", (now - mDNSStorage.p->DNSTrigger));
+
+ LogMsgNoIdent("--------- Mcast Resolvers ----------");
+ if (!mDNSStorage.McastResolvers) LogMsgNoIdent("<None>");
+ else
+ {
+ for (mr = mDNSStorage.McastResolvers; mr; mr = mr->next)
+ LogMsgNoIdent("Mcast Resolver %##s timeout %u", mr->domain.c, mr->timeout);
+ }
+
+ LogMsgNoIdent("Timenow 0x%08lX (%d)", (mDNSu32)now, now);
+ LogMsg("---- END STATE LOG ---- %s %s %d", mDNSResponderVersionString, OSXVers ? "OSXVers" : "iOSVers", OSXVers ? OSXVers : iOSVers);
+
+ // If logging is disabled, only then clear the key we set at the top of this func
+ if (!mDNS_LoggingEnabled)
+ asl_unset(log_msg, "LoggerID");
+}
+
+mDNSlocal void DebugSetFilter()
+{
+ if (!log_client)
+ return;
+
+ // When USR1 is turned on, we log only the LOG_WARNING and LOG_NOTICE messages by default.
+ // The user has to manually do "syslog -c mDNSResponder -i" to get the LOG_INFO messages
+ // also to be logged. Most of the times, we need the INFO level messages for debugging.
+ // Hence, we set the filter to INFO level when USR1 logging is turned on to avoid
+ // having the user to do this extra step manually.
+
+ if (mDNS_LoggingEnabled)
+ {
+ asl_set_filter(log_client, ASL_FILTER_MASK_UPTO(ASL_LEVEL_INFO));
+ asl_set(log_msg, "LoggerID", "com.apple.networking.mDNSResponder");
+ // Create LoggerID(Key)->com.apple.networking.mDNSResponder(Value) pair when USR1 Logging is Enabled.
+ // This key-value pair is used as a condition by syslogd to Log to com.apple.networking.mDNSResponder.log file
+ // present in /etc/asl/com.apple.networking.mDNSResponder.
+ }
+ else
+ {
+ asl_set_filter(log_client, ASL_FILTER_MASK_UPTO(ASL_LEVEL_ERR));
+ asl_unset(log_msg, "LoggerID");
+ // Clear the key-value pair when USR1 Logging is Disabled, as we do not want to log to
+ // com.apple.networking.mDNSResponder.log file in this case.
+ }
+}
+
+mDNSexport void mDNSPlatformLogToFile(int log_level, const char *buffer)
+{
+ int asl_level = ASL_LEVEL_ERR;
+
+ if (!log_client)
+ {
+ syslog(log_level, "%s", buffer);
+ return;
+ }
+ switch (log_level)
+ {
+ case LOG_ERR:
+ asl_level = ASL_LEVEL_ERR;
+ break;
+ case LOG_WARNING:
+ asl_level = ASL_LEVEL_WARNING;
+ break;
+ case LOG_NOTICE:
+ asl_level = ASL_LEVEL_NOTICE;
+ break;
+ case LOG_INFO:
+ asl_level = ASL_LEVEL_INFO;
+ break;
+ case LOG_DEBUG:
+ asl_level = ASL_LEVEL_DEBUG;
+ break;
+ default:
+ break;
+ }
+ asl_log(log_client, log_msg, asl_level, "%s", buffer);
+}
+
+// Writes the state out to the dynamic store and also affects the ASL filter level
+mDNSexport void UpdateDebugState()
+{
+ mDNSu32 one = 1;
+ mDNSu32 zero = 0;
+
+ CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ if (!dict)
+ {
+ LogMsg("UpdateDebugState: Could not create dict");
+ return;
+ }
+
+ CFNumberRef numOne = CFNumberCreate(NULL, kCFNumberSInt32Type, &one);
+ if (!numOne)
+ {
+ LogMsg("UpdateDebugState: Could not create CFNumber one");
+ return;
+ }
+ CFNumberRef numZero = CFNumberCreate(NULL, kCFNumberSInt32Type, &zero);
+ if (!numZero)
+ {
+ LogMsg("UpdateDebugState: Could not create CFNumber zero");
+ CFRelease(numOne);
+ return;
+ }
+
+ if (mDNS_LoggingEnabled)
+ CFDictionarySetValue(dict, CFSTR("VerboseLogging"), numOne);
+ else
+ CFDictionarySetValue(dict, CFSTR("VerboseLogging"), numZero);
+
+ if (mDNS_PacketLoggingEnabled)
+ CFDictionarySetValue(dict, CFSTR("PacketLogging"), numOne);
+ else
+ CFDictionarySetValue(dict, CFSTR("PacketLogging"), numZero);
+
+ if (mDNS_McastLoggingEnabled)
+ CFDictionarySetValue(dict, CFSTR("McastLogging"), numOne);
+ else
+ CFDictionarySetValue(dict, CFSTR("McastLogging"), numZero);
+
+ if (mDNS_McastTracingEnabled)
+ CFDictionarySetValue(dict, CFSTR("McastTracing"), numOne);
+ else
+ CFDictionarySetValue(dict, CFSTR("McastTracing"), numZero);
+
+ CFRelease(numOne);
+ CFRelease(numZero);
+ mDNSDynamicStoreSetConfig(kmDNSDebugState, mDNSNULL, dict);
+ CFRelease(dict);
+ // If we turned off USR1 logging, we need to reset the filter
+ DebugSetFilter();
+}
+
+#if TARGET_OS_EMBEDDED
+mDNSlocal void Prefschanged()
+{
+ mDNSBool mDNSProf_installed;
+ LogMsg("Prefschanged: mDNSResponder Managed Preferences have changed");
+ mDNSProf_installed = GetmDNSManagedPref(kmDNSEnableLoggingStr);
+ dispatch_async(dispatch_get_main_queue(),
+ ^{
+ if (mDNSProf_installed)
+ {
+ mDNS_LoggingEnabled = mDNS_PacketLoggingEnabled = 1;
+ }
+ else
+ {
+ LogMsg("Prefschanged: mDNSDebugProfile is uninstalled -> Turning OFF USR1/USR2 Logging with SIGINFO o/p");
+ INFOCallback();
+ mDNS_LoggingEnabled = mDNS_PacketLoggingEnabled = 0;
+ }
+ UpdateDebugState();
+ // If Logging Enabled: Start Logging to com.apple.networking.mDNSResponder.log (has to be LogInfo)
+ LogInfo("Prefschanged: mDNSDebugProfile is installed -> Turned ON USR1/USR2 Logging");
+ });
+ return;
+}
+#endif //TARGET_OS_EMBEDDED
+
+#ifndef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+
+mDNSlocal void SignalCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
+{
+ (void)port; // Unused
+ (void)size; // Unused
+ (void)info; // Unused
+ mach_msg_header_t *msg_header = (mach_msg_header_t *)msg;
+ mDNS *const m = &mDNSStorage;
+
+ // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding
+ KQueueLock(m);
+ switch(msg_header->msgh_id)
+ {
+ case SIGURG:
+ m->mDNSOppCaching = m->mDNSOppCaching ? mDNSfalse : mDNStrue;
+ LogMsg("SIGURG: Opportunistic Caching %s", m->mDNSOppCaching ? "Enabled" : "Disabled");
+ // FALL THROUGH to purge the cache so that we re-do the caching based on the new setting
+ case SIGHUP: {
+ mDNSu32 slot;
+ CacheGroup *cg;
+ CacheRecord *rr;
+ LogMsg("SIGHUP: Purge cache");
+ mDNS_Lock(m);
+ FORALL_CACHERECORDS(slot, cg, rr)
+ {
+ mDNS_PurgeCacheResourceRecord(m, rr);
+ }
+ // Restart unicast and multicast queries
+ mDNSCoreRestartQueries(m);
+ mDNS_Unlock(m);
+ } break;
+ case SIGINT:
+ case SIGTERM: ExitCallback(msg_header->msgh_id); break;
+ case SIGINFO: INFOCallback(); break;
+ case SIGUSR1: mDNS_LoggingEnabled = mDNS_LoggingEnabled ? 0 : 1;
+ LogMsg("SIGUSR1: Logging %s", mDNS_LoggingEnabled ? "Enabled" : "Disabled");
+ WatchDogReportingThreshold = mDNS_LoggingEnabled ? 50 : 250;
+ UpdateDebugState();
+ // If Logging Enabled: Start Logging to com.apple.networking.mDNSResponder.log
+ LogInfo("USR1 Logging Enabled: Start Logging to mDNSResponder Log file");
+ break;
+ case SIGUSR2: mDNS_PacketLoggingEnabled = mDNS_PacketLoggingEnabled ? 0 : 1;
+ LogMsg("SIGUSR2: Packet Logging %s", mDNS_PacketLoggingEnabled ? "Enabled" : "Disabled");
+ mDNS_McastTracingEnabled = (mDNS_PacketLoggingEnabled && mDNS_McastLoggingEnabled) ? mDNStrue : mDNSfalse;
+ LogInfo("SIGUSR2: Multicast Tracing is %s", mDNS_McastTracingEnabled ? "Enabled" : "Disabled");
+ UpdateDebugState();
+ break;
+ case SIGPROF: mDNS_McastLoggingEnabled = mDNS_McastLoggingEnabled ? mDNSfalse : mDNStrue;
+ LogMsg("SIGPROF: Multicast Logging %s", mDNS_McastLoggingEnabled ? "Enabled" : "Disabled");
+ LogMcastStateInfo(m, mDNSfalse, mDNStrue, mDNStrue);
+ mDNS_McastTracingEnabled = (mDNS_PacketLoggingEnabled && mDNS_McastLoggingEnabled) ? mDNStrue : mDNSfalse;
+ LogMsg("SIGPROF: Multicast Tracing is %s", mDNS_McastTracingEnabled ? "Enabled" : "Disabled");
+ UpdateDebugState();
+ break;
+ case SIGTSTP: mDNS_LoggingEnabled = mDNS_PacketLoggingEnabled = mDNS_McastLoggingEnabled = mDNS_McastTracingEnabled = mDNSfalse;
+ LogMsg("All mDNSResponder Debug Logging/Tracing Disabled (USR1/USR2/PROF)");
+ UpdateDebugState();
+ break;
+
+ default: LogMsg("SignalCallback: Unknown signal %d", msg_header->msgh_id); break;
+ }
+ KQueueUnlock(m, "Unix Signal");
+}
+
+// MachServerName is com.apple.mDNSResponder (Supported only till 10.9.x)
+mDNSlocal kern_return_t mDNSDaemonInitialize(void)
+{
+ mStatus err;
+ CFMachPortRef s_port;
+ CFRunLoopSourceRef s_rls;
+ CFRunLoopSourceRef d_rls;
+
+ s_port = CFMachPortCreateWithPort(NULL, m_port, DNSserverCallback, NULL, NULL);
+ CFMachPortRef d_port = CFMachPortCreate(NULL, ClientDeathCallback, NULL, NULL);
+
+ err = mDNS_Init(&mDNSStorage, &PlatformStorage,
+ rrcachestorage, RR_CACHE_SIZE,
+ advertise,
+ mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext);
+
+ if (err) { LogMsg("Daemon start: mDNS_Init failed %d", err); return(err); }
+
+ client_death_port = CFMachPortGetPort(d_port);
+
+ s_rls = CFMachPortCreateRunLoopSource(NULL, s_port, 0);
+ CFRunLoopAddSource(PlatformStorage.CFRunLoop, s_rls, kCFRunLoopDefaultMode);
+ CFRelease(s_rls);
+
+ d_rls = CFMachPortCreateRunLoopSource(NULL, d_port, 0);
+ CFRunLoopAddSource(PlatformStorage.CFRunLoop, d_rls, kCFRunLoopDefaultMode);
+ CFRelease(d_rls);
+
+ CFMachPortRef i_port = CFMachPortCreate(NULL, SignalCallback, NULL, NULL);
+ CFRunLoopSourceRef i_rls = CFMachPortCreateRunLoopSource(NULL, i_port, 0);
+ signal_port = CFMachPortGetPort(i_port);
+ CFRunLoopAddSource(PlatformStorage.CFRunLoop, i_rls, kCFRunLoopDefaultMode);
+ CFRelease(i_rls);
+
+ if (mDNS_DebugMode) printf("Service registered with Mach Port %d\n", m_port);
+ return(err);
+}
+
+#else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+
+// SignalDispatch is mostly just a copy/paste of entire code block from SignalCallback above.
+// The common code should be a subroutine, or we end up having to fix bugs in two places all the time.
+// The same applies to mDNSDaemonInitialize, much of which is just a copy/paste of chunks
+// of code from above. Alternatively we could remove the duplicated source code by having
+// single routines, with the few differing parts bracketed with "#ifndef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM"
+
+mDNSlocal void SignalDispatch(dispatch_source_t source)
+{
+ int sig = (int)dispatch_source_get_handle(source);
+ mDNS *const m = &mDNSStorage;
+ KQueueLock(m);
+ switch(sig)
+ {
+ case SIGHUP: {
+ mDNSu32 slot;
+ CacheGroup *cg;
+ CacheRecord *rr;
+ LogMsg("SIGHUP: Purge cache");
+ mDNS_Lock(m);
+ FORALL_CACHERECORDS(slot, cg, rr)
+ {
+ mDNS_PurgeCacheResourceRecord(m, rr);
+ }
+ // Restart unicast and multicast queries
+ mDNSCoreRestartQueries(m);
+ mDNS_Unlock(m);
+ } break;
+ case SIGINT:
+ case SIGTERM: ExitCallback(sig); break;
+ case SIGINFO: INFOCallback(); break;
+ case SIGUSR1: mDNS_LoggingEnabled = mDNS_LoggingEnabled ? 0 : 1;
+ LogMsg("SIGUSR1: Logging %s", mDNS_LoggingEnabled ? "Enabled" : "Disabled");
+ WatchDogReportingThreshold = mDNS_LoggingEnabled ? 50 : 250;
+ UpdateDebugState();
+ break;
+ case SIGUSR2: mDNS_PacketLoggingEnabled = mDNS_PacketLoggingEnabled ? 0 : 1;
+ LogMsg("SIGUSR2: Packet Logging %s", mDNS_PacketLoggingEnabled ? "Enabled" : "Disabled");
+ UpdateDebugState();
+ break;
+ default: LogMsg("SignalCallback: Unknown signal %d", sig); break;
+ }
+ KQueueUnlock(m, "Unix Signal");
+}
+
+mDNSlocal void mDNSSetupSignal(dispatch_queue_t queue, int sig)
+{
+ signal(sig, SIG_IGN);
+ dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, sig, 0, queue);
+
+ if (source)
+ {
+ dispatch_source_set_event_handler(source, ^{SignalDispatch(source);});
+ // Start processing signals
+ dispatch_resume(source);
+ }
+ else
+ {
+ LogMsg("mDNSSetupSignal: Cannot setup signal %d", sig);
+ }
+}
+
+// On 10.2 the MachServerName is DNSServiceDiscoveryServer
+// On 10.3 and later, the MachServerName is com.apple.mDNSResponder
+mDNSlocal kern_return_t mDNSDaemonInitialize(void)
+{
+ mStatus err;
+ dispatch_source_t mach_source;
+ dispatch_queue_t queue = dispatch_get_main_queue();
+
+ err = mDNS_Init(&mDNSStorage, &PlatformStorage,
+ rrcachestorage, RR_CACHE_SIZE,
+ advertise,
+ mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext);
+
+ if (err) { LogMsg("Daemon start: mDNS_Init failed %d", err); return(err); }
+
+ mach_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, m_port, 0, queue);
+ if (mach_source == mDNSNULL) {LogMsg("mDNSDaemonInitialize: Error creating source for m_port"); return -1;}
+ dispatch_source_set_event_handler(mach_source, ^{
+ dispatch_mig_server(mach_source, sizeof(union __RequestUnion__DNSServiceDiscoveryReply_subsystem),
+ DNSServiceDiscoveryRequest_server);
+ });
+ dispatch_resume(mach_source);
+
+ mDNSSetupSignal(queue, SIGHUP);
+ mDNSSetupSignal(queue, SIGINT);
+ mDNSSetupSignal(queue, SIGTERM);
+ mDNSSetupSignal(queue, SIGINFO);
+ mDNSSetupSignal(queue, SIGUSR1);
+ mDNSSetupSignal(queue, SIGUSR2);
+ mDNSSetupSignal(queue, SIGURG);
+
+ // Create a custom handler for doing the housekeeping work. This is either triggered
+ // by the timer or an event source
+ PlatformStorage.custom = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, queue);
+ if (PlatformStorage.custom == mDNSNULL) {LogMsg("mDNSDaemonInitialize: Error creating custom source"); return -1;}
+ dispatch_source_set_event_handler(PlatformStorage.custom, ^{PrepareForIdle(&mDNSStorage);});
+ dispatch_resume(PlatformStorage.custom);
+
+ // Create a timer source to trigger housekeeping work. The houskeeping work itself
+ // is done in the custom handler that we set below.
+
+ PlatformStorage.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
+ if (PlatformStorage.timer == mDNSNULL) {LogMsg("mDNSDaemonInitialize: Error creating timer source"); return -1;}
+
+ // As the API does not support one shot timers, we pass zero for the interval. In the custom handler, we
+ // always reset the time to the new time computed. In effect, we ignore the interval
+ dispatch_source_set_timer(PlatformStorage.timer, DISPATCH_TIME_NOW, 1000ull * 1000000000, 0);
+ dispatch_source_set_event_handler(PlatformStorage.timer, ^{
+ dispatch_source_merge_data(PlatformStorage.custom, 1);
+ });
+ dispatch_resume(PlatformStorage.timer);
+
+ LogMsg("DaemonIntialize done successfully");
+
+ if (mDNS_DebugMode) printf("Service registered with Mach Port %d\n", m_port);
+ return(err);
+}
+
+#endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+
+mDNSlocal mDNSs32 mDNSDaemonIdle(mDNS *const m)
+{
+ mDNSs32 now = mDNS_TimeNow(m);
+
+ // 1. If we need to set domain secrets, do so before handling the network change
+ // Detailed reason:
+ // BTMM domains listed in DynStore Setup:/Network/BackToMyMac are added to the registration domains list,
+ // and we need to setup the associated AutoTunnel DomainAuthInfo entries before that happens.
+ if (m->p->KeyChainTimer && now - m->p->KeyChainTimer >= 0)
+ {
+ m->p->KeyChainTimer = 0;
+ mDNS_Lock(m);
+ SetDomainSecrets(m);
+ mDNS_Unlock(m);
+ }
+
+ // 2. If we have network change events to handle, do them before calling mDNS_Execute()
+ // Detailed reason:
+ // mDNSMacOSXNetworkChanged() currently closes and re-opens its sockets. If there are received packets waiting, they are lost.
+ // mDNS_Execute() generates packets, including multicasts that are looped back to ourself.
+ // If we call mDNS_Execute() first, and generate packets, and then call mDNSMacOSXNetworkChanged() immediately afterwards
+ // we then systematically lose our own looped-back packets.
+ if (m->p->NetworkChanged && now - m->p->NetworkChanged >= 0) mDNSMacOSXNetworkChanged(m);
+
+ if (m->p->RequestReSleep && now - m->p->RequestReSleep >= 0) { m->p->RequestReSleep = 0; mDNSPowerRequest(0, 0); }
+
+ // 3. Call mDNS_Execute() to let mDNSCore do what it needs to do
+ mDNSs32 nextevent = mDNS_Execute(m);
+
+ if (m->p->NetworkChanged)
+ if (nextevent - m->p->NetworkChanged > 0)
+ nextevent = m->p->NetworkChanged;
+
+ if (m->p->KeyChainTimer)
+ if (nextevent - m->p->KeyChainTimer > 0)
+ nextevent = m->p->KeyChainTimer;
+
+ if (m->p->RequestReSleep)
+ if (nextevent - m->p->RequestReSleep > 0)
+ nextevent = m->p->RequestReSleep;
+
+ // 4. Deliver any waiting browse messages to clients
+ DNSServiceBrowser *b = DNSServiceBrowserList;
+
+ while (b)
+ {
+ // Note: Need to advance b to the next element BEFORE we call DeliverInstance(), because in the
+ // event that the client Mach queue overflows, DeliverInstance() will call AbortBlockedClient()
+ // and that will cause the DNSServiceBrowser object's memory to be freed before it returns
+ DNSServiceBrowser *x = b;
+ b = b->next;
+ if (x->results) // Try to deliver the list of results
+ {
+ while (x->results)
+ {
+ DNSServiceBrowserResult *const r = x->results;
+ domainlabel name;
+ domainname type, domain;
+ DeconstructServiceName(&r->result, &name, &type, &domain); // Don't need to check result; already validated in FoundInstance()
+ char cname[MAX_DOMAIN_LABEL+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL.
+ char ctype[MAX_ESCAPED_DOMAIN_NAME];
+ char cdom [MAX_ESCAPED_DOMAIN_NAME];
+ ConvertDomainLabelToCString_unescaped(&name, cname);
+ ConvertDomainNameToCString(&type, ctype);
+ ConvertDomainNameToCString(&domain, cdom);
+ DNSServiceDiscoveryReplyFlags flags = (r->next) ? DNSServiceDiscoverReplyFlagsMoreComing : 0;
+ kern_return_t status = DNSServiceBrowserReply_rpc(x->ClientMachPort, r->resultType, cname, ctype, cdom, flags, 1);
+ // If we failed to send the mach message, try again in one second
+ if (status == MACH_SEND_TIMED_OUT)
+ {
+ if (nextevent - now > mDNSPlatformOneSecond)
+ nextevent = now + mDNSPlatformOneSecond;
+ break;
+ }
+ else
+ {
+ x->lastsuccess = now;
+ x->results = x->results->next;
+ freeL("DNSServiceBrowserResult", r);
+ }
+ }
+ // If this client hasn't read a single message in the last 60 seconds, abort it
+ if (now - x->lastsuccess >= 60 * mDNSPlatformOneSecond)
+ AbortBlockedClient(x->ClientMachPort, "browse", x);
+ }
+ }
+
+ DNSServiceResolver *l;
+ for (l = DNSServiceResolverList; l; l=l->next)
+ if (l->ReportTime && now - l->ReportTime >= 0)
+ {
+ l->ReportTime = 0;
+ LogMsgNoIdent("Client application bug: DNSServiceResolver(%##s) active for over two minutes. "
+ "This places considerable burden on the network.", l->i.name.c);
+ }
+
+ if (m->p->NotifyUser)
+ {
+ if (m->p->NotifyUser - now < 0)
+ {
+ if (!SameDomainLabelCS(m->p->usernicelabel.c, m->nicelabel.c))
+ {
+ LogMsg("Name Conflict: Updated Computer Name from \"%#s\" to \"%#s\"", m->p->usernicelabel.c, m->nicelabel.c);
+ mDNSPreferencesSetNames(m, kmDNSComputerName, &m->p->usernicelabel, &m->nicelabel);
+ m->p->usernicelabel = m->nicelabel;
+ }
+ if (!SameDomainLabelCS(m->p->userhostlabel.c, m->hostlabel.c))
+ {
+ LogMsg("Name Conflict: Updated Local Hostname from \"%#s.local\" to \"%#s.local\"", m->p->userhostlabel.c, m->hostlabel.c);
+ mDNSPreferencesSetNames(m, kmDNSLocalHostName, &m->p->userhostlabel, &m->hostlabel);
+ m->p->HostNameConflict = 0; // Clear our indicator, now name change has been successful
+ m->p->userhostlabel = m->hostlabel;
+ }
+ m->p->NotifyUser = 0;
+ }
+ else
+ if (nextevent - m->p->NotifyUser > 0)
+ nextevent = m->p->NotifyUser;
+ }
+
+ return(nextevent);
+}
+
+// Right now we consider *ALL* of our DHCP leases
+// It might make sense to be a bit more selective and only consider the leases on interfaces
+// (a) that are capable and enabled for wake-on-LAN, and
+// (b) where we have found (and successfully registered with) a Sleep Proxy
+// If we can't be woken for traffic on a given interface, then why keep waking to renew its lease?
+mDNSlocal mDNSu32 DHCPWakeTime(void)
+{
+ mDNSu32 e = 24 * 3600; // Maximum maintenance wake interval is 24 hours
+ const CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
+ if (!now) LogMsg("DHCPWakeTime: CFAbsoluteTimeGetCurrent failed");
+ else
+ {
+ int ic, j;
+
+ const void *pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetDHCP);
+ if (!pattern)
+ {
+ LogMsg("DHCPWakeTime: SCDynamicStoreKeyCreateNetworkServiceEntity failed\n");
+ return e;
+ }
+ CFArrayRef dhcpinfo = CFArrayCreate(NULL, (const void **)&pattern, 1, &kCFTypeArrayCallBacks);
+ CFRelease(pattern);
+ if (dhcpinfo)
+ {
+ SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("DHCP-LEASES"), NULL, NULL);
+ if (store)
+ {
+ CFDictionaryRef dict = SCDynamicStoreCopyMultiple(store, NULL, dhcpinfo);
+ if (dict)
+ {
+ ic = CFDictionaryGetCount(dict);
+ const void *vals[ic];
+ CFDictionaryGetKeysAndValues(dict, NULL, vals);
+
+ for (j = 0; j < ic; j++)
+ {
+ const CFDictionaryRef dhcp = (CFDictionaryRef)vals[j];
+ if (dhcp)
+ {
+ const CFDateRef start = DHCPInfoGetLeaseStartTime(dhcp);
+ const CFDataRef lease = DHCPInfoGetOptionData(dhcp, 51); // Option 51 = IP Address Lease Time
+ if (!start || !lease || CFDataGetLength(lease) < 4)
+ LogMsg("DHCPWakeTime: SCDynamicStoreCopyDHCPInfo index %d failed "
+ "CFDateRef start %p CFDataRef lease %p CFDataGetLength(lease) %d",
+ j, start, lease, lease ? CFDataGetLength(lease) : 0);
+ else
+ {
+ const UInt8 *d = CFDataGetBytePtr(lease);
+ if (!d) LogMsg("DHCPWakeTime: CFDataGetBytePtr %d failed", j);
+ else
+ {
+ const mDNSu32 elapsed = now - CFDateGetAbsoluteTime(start);
+ const mDNSu32 lifetime = (mDNSs32) ((mDNSs32)d[0] << 24 | (mDNSs32)d[1] << 16 | (mDNSs32)d[2] << 8 | d[3]);
+ const mDNSu32 remaining = lifetime - elapsed;
+ const mDNSu32 wake = remaining > 60 ? remaining - remaining/10 : 54; // Wake at 90% of the lease time
+ LogSPS("DHCP Address Lease Elapsed %6u Lifetime %6u Remaining %6u Wake %6u", elapsed, lifetime, remaining, wake);
+ if (e > wake) e = wake;
+ }
+ }
+ }
+ }
+ CFRelease(dict);
+ }
+ CFRelease(store);
+ }
+ CFRelease(dhcpinfo);
+ }
+ }
+ return(e);
+}
+
+// We deliberately schedule our wakeup for halfway between when we'd *like* it and when we *need* it.
+// For example, if our DHCP lease expires in two hours, we'll typically renew it at the halfway point, after one hour.
+// If we scheduled our wakeup for the one-hour renewal time, that might be just seconds from now, and sleeping
+// for a few seconds and then waking again is silly and annoying.
+// If we scheduled our wakeup for the two-hour expiry time, and we were slow to wake, we might lose our lease.
+// Scheduling our wakeup for halfway in between -- 90 minutes -- avoids short wakeups while still
+// allowing us an adequate safety margin to renew our lease before we lose it.
+
+mDNSlocal mDNSBool AllowSleepNow(mDNS *const m, mDNSs32 now)
+{
+ mDNSBool ready = mDNSCoreReadyForSleep(m, now);
+ if (m->SleepState && !ready && now - m->SleepLimit < 0) return(mDNSfalse);
+
+ m->p->WakeAtUTC = 0;
+ int result = kIOReturnSuccess;
+ CFDictionaryRef opts = NULL;
+
+ // If the sleep request was cancelled, and we're no longer planning to sleep, don't need to
+ // do the stuff below, but we *DO* still need to acknowledge the sleep message we received.
+ if (!m->SleepState)
+ LogMsg("AllowSleepNow: Sleep request was canceled with %d ticks remaining", m->SleepLimit - now);
+ else
+ {
+ if (!m->SystemWakeOnLANEnabled || !mDNSCoreHaveAdvertisedMulticastServices(m))
+ LogSPS("AllowSleepNow: Not scheduling wakeup: SystemWakeOnLAN %s enabled; %s advertised services",
+ m->SystemWakeOnLANEnabled ? "is" : "not",
+ mDNSCoreHaveAdvertisedMulticastServices(m) ? "have" : "no");
+ else
+ {
+ mDNSs32 dhcp = DHCPWakeTime();
+ LogSPS("ComputeWakeTime: DHCP Wake %d", dhcp);
+ mDNSs32 interval = mDNSCoreIntervalToNextWake(m, now) / mDNSPlatformOneSecond;
+ if (interval > dhcp) interval = dhcp;
+
+ // If we're not ready to sleep (failed to register with Sleep Proxy, maybe because of
+ // transient network problem) then schedule a wakeup in one hour to try again. Otherwise,
+ // a single SPS failure could result in a remote machine falling permanently asleep, requiring
+ // someone to go to the machine in person to wake it up again, which would be unacceptable.
+ if (!ready && interval > 3600) interval = 3600;
+
+ //interval = 48; // For testing
+
+#ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements
+ if (m->p->IOPMConnection) // If lightweight-wake capability is available, use that
+ {
+ const CFDateRef WakeDate = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent() + interval);
+ if (!WakeDate) LogMsg("ScheduleNextWake: CFDateCreate failed");
+ else
+ {
+ const mDNSs32 reqs = kIOPMSystemPowerStateCapabilityNetwork;
+ const CFNumberRef Requirements = CFNumberCreate(NULL, kCFNumberSInt32Type, &reqs);
+ if (!Requirements) LogMsg("ScheduleNextWake: CFNumberCreate failed");
+ else
+ {
+ const void *OptionKeys[2] = { CFSTR("WakeDate"), CFSTR("Requirements") };
+ const void *OptionVals[2] = { WakeDate, Requirements };
+ opts = CFDictionaryCreate(NULL, (void*)OptionKeys, (void*)OptionVals, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ if (!opts) LogMsg("ScheduleNextWake: CFDictionaryCreate failed");
+ CFRelease(Requirements);
+ }
+ CFRelease(WakeDate);
+ }
+ LogSPS("AllowSleepNow: Will request lightweight wakeup in %d seconds", interval);
+ }
+ else // else schedule the wakeup using the old API instead to
+#endif
+ {
+ // If we wake within +/- 30 seconds of our requested time we'll assume the system woke for us,
+ // so we should put it back to sleep. To avoid frustrating the user, we always request at least
+ // 60 seconds sleep, so if they immediately re-wake the system within seconds of it going to sleep,
+ // we then shouldn't hit our 30-second window, and we won't attempt to re-sleep the machine.
+ if (interval < 60) interval = 60;
+
+ result = mDNSPowerRequest(1, interval);
+
+ if (result == kIOReturnNotReady)
+ {
+ int r;
+ LogMsg("AllowSleepNow: Requested wakeup in %d seconds unsuccessful; retrying with longer intervals", interval);
+ // IOPMSchedulePowerEvent fails with kIOReturnNotReady (-536870184/0xe00002d8) if the
+ // requested wake time is "too soon", but there's no API to find out what constitutes
+ // "too soon" on any given OS/hardware combination, so if we get kIOReturnNotReady
+ // we just have to iterate with successively longer intervals until it doesn't fail.
+ // We preserve the value of "result" because if our original power request was deemed "too soon"
+ // for the machine to get to sleep and wake back up again, we attempt to cancel the sleep request,
+ // since the implication is that the system won't manage to be awake again at the time we need it.
+ do
+ {
+ interval += (interval < 20) ? 1 : ((interval+3) / 4);
+ r = mDNSPowerRequest(1, interval);
+ }
+ while (r == kIOReturnNotReady);
+ if (r) LogMsg("AllowSleepNow: Requested wakeup in %d seconds unsuccessful: %d %X", interval, r, r);
+ else LogSPS("AllowSleepNow: Requested later wakeup in %d seconds; will also attempt IOCancelPowerChange", interval);
+ }
+ else
+ {
+ if (result) LogMsg("AllowSleepNow: Requested wakeup in %d seconds unsuccessful: %d %X", interval, result, result);
+ else LogSPS("AllowSleepNow: Requested wakeup in %d seconds", interval);
+ }
+ m->p->WakeAtUTC = mDNSPlatformUTC() + interval;
+ }
+ }
+
+ m->SleepState = SleepState_Sleeping;
+ // We used to clear our interface list to empty state here before going to sleep.
+ // The applications that try to connect to an external server during maintenance wakes, saw
+ // DNS resolution errors as we don't have any interfaces (most queries use SuppressUnusable
+ // flag). Thus, we don't remove our interfaces anymore on sleep.
+ }
+
+ LogSPS("AllowSleepNow: %s(%lX) %s at %ld (%d ticks remaining)",
+#if !TARGET_OS_EMBEDDED && defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements)
+ (m->p->IOPMConnection) ? "IOPMConnectionAcknowledgeEventWithOptions" :
+#endif
+ (result == kIOReturnSuccess) ? "IOAllowPowerChange" : "IOCancelPowerChange",
+ m->p->SleepCookie, ready ? "ready for sleep" : "giving up", now, m->SleepLimit - now);
+
+ m->SleepLimit = 0; // Don't clear m->SleepLimit until after we've logged it above
+ m->TimeSlept = mDNSPlatformUTC();
+
+ // accumulate total time awake for this statistics gathering interval
+ if (m->StatStartTime)
+ {
+ m->ActiveStatTime += (m->TimeSlept - m->StatStartTime);
+
+ // indicate this value is invalid until reinitialzed on wakeup
+ m->StatStartTime = 0;
+ }
+
+#if !TARGET_OS_EMBEDDED && defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements)
+ if (m->p->IOPMConnection) IOPMConnectionAcknowledgeEventWithOptions(m->p->IOPMConnection, m->p->SleepCookie, opts);
+ else
+#endif
+ if (result == kIOReturnSuccess) IOAllowPowerChange (m->p->PowerConnection, m->p->SleepCookie);
+ else IOCancelPowerChange(m->p->PowerConnection, m->p->SleepCookie);
+
+ if (opts) CFRelease(opts);
+ return(mDNStrue);
+}
+
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+
+mDNSexport void TriggerEventCompletion()
+{
+ debugf("TriggerEventCompletion: Merge data");
+ dispatch_source_merge_data(PlatformStorage.custom, 1);
+}
+
+mDNSlocal void PrepareForIdle(void *m_param)
+{
+ mDNS *m = m_param;
+ int64_t time_offset;
+ dispatch_time_t dtime;
+
+ const int multiplier = 1000000000 / mDNSPlatformOneSecond;
+
+ // This is the main work loop:
+ // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time
+ // (2) Then we make sure we've delivered all waiting browse messages to our clients
+ // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner
+
+ debugf("PrepareForIdle: called");
+ // Run mDNS_Execute to find out the time we next need to wake up
+ mDNSs32 start = mDNSPlatformRawTime();
+ mDNSs32 nextTimerEvent = udsserver_idle(mDNSDaemonIdle(m));
+ mDNSs32 end = mDNSPlatformRawTime();
+ if (end - start >= WatchDogReportingThreshold)
+ LogInfo("CustomSourceHandler:WARNING: Idle task took %dms to complete", end - start);
+
+ mDNSs32 now = mDNS_TimeNow(m);
+
+ if (m->ShutdownTime)
+ {
+ if (mDNSStorage.ResourceRecords)
+ {
+ LogInfo("Cannot exit yet; Resource Record still exists: %s", ARDisplayString(m, mDNSStorage.ResourceRecords));
+ if (mDNS_LoggingEnabled) usleep(10000); // Sleep 10ms so that we don't flood syslog with too many messages
+ }
+ if (mDNS_ExitNow(m, now))
+ {
+ LogInfo("IdleLoop: mDNS_FinalExit");
+ mDNS_FinalExit(&mDNSStorage);
+ usleep(1000); // Little 1ms pause before exiting, so we don't lose our final syslog messages
+ exit(0);
+ }
+ if (nextTimerEvent - m->ShutdownTime >= 0)
+ nextTimerEvent = m->ShutdownTime;
+ }
+
+ if (m->SleepLimit)
+ if (!AllowSleepNow(m, now))
+ if (nextTimerEvent - m->SleepLimit >= 0)
+ nextTimerEvent = m->SleepLimit;
+
+ // Convert absolute wakeup time to a relative time from now
+ mDNSs32 ticks = nextTimerEvent - now;
+ if (ticks < 1) ticks = 1;
+
+ static mDNSs32 RepeatedBusy = 0; // Debugging sanity check, to guard against CPU spins
+ if (ticks > 1)
+ RepeatedBusy = 0;
+ else
+ {
+ ticks = 1;
+ if (++RepeatedBusy >= mDNSPlatformOneSecond) { ShowTaskSchedulingError(&mDNSStorage); RepeatedBusy = 0; }
+ }
+
+ time_offset = ((mDNSu32)ticks / mDNSPlatformOneSecond) * 1000000000 + (ticks % mDNSPlatformOneSecond) * multiplier;
+ dtime = dispatch_time(DISPATCH_TIME_NOW, time_offset);
+ dispatch_source_set_timer(PlatformStorage.timer, dtime, 1000ull*1000000000, 0);
+ debugf("PrepareForIdle: scheduling timer with ticks %d", ticks);
+ return;
+}
+
+#else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+
+mDNSlocal void KQWokenFlushBytes(int fd, __unused short filter, __unused void *context)
+{
+ // Read all of the bytes so we won't wake again.
+ char buffer[100];
+ while (recv(fd, buffer, sizeof(buffer), MSG_DONTWAIT) > 0) continue;
+}
+
+mDNSlocal void * KQueueLoop(void *m_param)
+{
+ mDNS *m = m_param;
+ int numevents = 0;
+
+#if USE_SELECT_WITH_KQUEUEFD
+ fd_set readfds;
+ FD_ZERO(&readfds);
+ const int multiplier = 1000000 / mDNSPlatformOneSecond;
+#else
+ const int multiplier = 1000000000 / mDNSPlatformOneSecond;
+#endif
+
+ pthread_mutex_lock(&PlatformStorage.BigMutex);
+ LogInfo("Starting time value 0x%08lX (%ld)", (mDNSu32)mDNSStorage.timenow_last, mDNSStorage.timenow_last);
+
+ // This is the main work loop:
+ // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time
+ // (2) Then we make sure we've delivered all waiting browse messages to our clients
+ // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner
+ // (4) On wakeup we first process *all* events
+ // (5) then when no more events remain, we go back to (1) to finish off any deferred work and do it all again
+ for ( ; ; )
+ {
+ #define kEventsToReadAtOnce 1
+ struct kevent new_events[kEventsToReadAtOnce];
+
+ // Run mDNS_Execute to find out the time we next need to wake up
+ mDNSs32 start = mDNSPlatformRawTime();
+ mDNSs32 nextTimerEvent = udsserver_idle(mDNSDaemonIdle(m));
+ mDNSs32 end = mDNSPlatformRawTime();
+ if (end - start >= WatchDogReportingThreshold)
+ LogInfo("WARNING: Idle task took %dms to complete", end - start);
+
+ mDNSs32 now = mDNS_TimeNow(m);
+
+ if (m->ShutdownTime)
+ {
+ if (mDNSStorage.ResourceRecords)
+ {
+ AuthRecord *rr;
+ for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
+ {
+ LogInfo("Cannot exit yet; Resource Record still exists: %s", ARDisplayString(m, rr));
+ if (mDNS_LoggingEnabled) usleep(10000); // Sleep 10ms so that we don't flood syslog with too many messages
+ }
+ }
+ if (mDNS_ExitNow(m, now))
+ {
+ LogInfo("mDNS_FinalExit");
+ mDNS_FinalExit(&mDNSStorage);
+ usleep(1000); // Little 1ms pause before exiting, so we don't lose our final syslog messages
+ exit(0);
+ }
+ if (nextTimerEvent - m->ShutdownTime >= 0)
+ nextTimerEvent = m->ShutdownTime;
+ }
+
+ if (m->SleepLimit)
+ if (!AllowSleepNow(m, now))
+ if (nextTimerEvent - m->SleepLimit >= 0)
+ nextTimerEvent = m->SleepLimit;
+
+ // Convert absolute wakeup time to a relative time from now
+ mDNSs32 ticks = nextTimerEvent - now;
+ if (ticks < 1) ticks = 1;
+
+ static mDNSs32 RepeatedBusy = 0; // Debugging sanity check, to guard against CPU spins
+ if (ticks > 1)
+ RepeatedBusy = 0;
+ else
+ {
+ ticks = 1;
+ if (++RepeatedBusy >= mDNSPlatformOneSecond) { ShowTaskSchedulingError(&mDNSStorage); RepeatedBusy = 0; }
+ }
+
+ verbosedebugf("KQueueLoop: Handled %d events; now sleeping for %d ticks", numevents, ticks);
+ numevents = 0;
+
+ // Release the lock, and sleep until:
+ // 1. Something interesting happens like a packet arriving, or
+ // 2. The other thread writes a byte to WakeKQueueLoopFD to poke us and make us wake up, or
+ // 3. The timeout expires
+ pthread_mutex_unlock(&PlatformStorage.BigMutex);
+
+#if USE_SELECT_WITH_KQUEUEFD
+ struct timeval timeout;
+ timeout.tv_sec = ticks / mDNSPlatformOneSecond;
+ timeout.tv_usec = (ticks % mDNSPlatformOneSecond) * multiplier;
+ FD_SET(KQueueFD, &readfds);
+ if (select(KQueueFD+1, &readfds, NULL, NULL, &timeout) < 0)
+ { LogMsg("select(%d) failed errno %d (%s)", KQueueFD, errno, strerror(errno)); sleep(1); }
+#else
+ struct timespec timeout;
+ timeout.tv_sec = ticks / mDNSPlatformOneSecond;
+ timeout.tv_nsec = (ticks % mDNSPlatformOneSecond) * multiplier;
+ // In my opinion, you ought to be able to call kevent() with nevents set to zero,
+ // and have it work similarly to the way it does with nevents non-zero --
+ // i.e. it waits until either an event happens or the timeout expires, and then wakes up.
+ // In fact, what happens if you do this is that it just returns immediately. So, we have
+ // to pass nevents set to one, and then we just ignore the event it gives back to us. -- SC
+ if (kevent(KQueueFD, NULL, 0, new_events, 1, &timeout) < 0)
+ { LogMsg("kevent(%d) failed errno %d (%s)", KQueueFD, errno, strerror(errno)); sleep(1); }
+#endif
+
+ pthread_mutex_lock(&PlatformStorage.BigMutex);
+ // We have to ignore the event we may have been told about above, because that
+ // was done without holding the lock, and between the time we woke up and the
+ // time we reclaimed the lock the other thread could have done something that
+ // makes the event no longer valid. Now we have the lock, we call kevent again
+ // and this time we can safely process the events it tells us about.
+
+ static const struct timespec zero_timeout = { 0, 0 };
+ int events_found;
+ while ((events_found = kevent(KQueueFD, NULL, 0, new_events, kEventsToReadAtOnce, &zero_timeout)) != 0)
+ {
+ if (events_found > kEventsToReadAtOnce || (events_found < 0 && errno != EINTR))
+ {
+ // Not sure what to do here, our kqueue has failed us - this isn't ideal
+ LogMsg("ERROR: KQueueLoop - kevent failed errno %d (%s)", errno, strerror(errno));
+ exit(errno);
+ }
+
+ numevents += events_found;
+
+ int i;
+ for (i = 0; i < events_found; i++)
+ {
+ const KQueueEntry *const kqentry = new_events[i].udata;
+ mDNSs32 stime = mDNSPlatformRawTime();
+ const char *const KQtask = kqentry->KQtask; // Grab a copy in case KQcallback deletes the task
+ kqentry->KQcallback(new_events[i].ident, new_events[i].filter, kqentry->KQcontext);
+ mDNSs32 etime = mDNSPlatformRawTime();
+ if (etime - stime >= WatchDogReportingThreshold)
+ LogInfo("WARNING: %s took %dms to complete", KQtask, etime - stime);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+#endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+
+mDNSlocal void LaunchdCheckin(void)
+{
+ // Ask launchd for our socket
+ launch_data_t resp_sd = launch_socket_service_check_in();
+ if (!resp_sd)
+ {
+ LogMsg("launch_socket_service_check_in returned NULL");
+ return;
+ }
+ else
+ {
+ launch_data_t skts = launch_data_dict_lookup(resp_sd, LAUNCH_JOBKEY_SOCKETS);
+ if (!skts) LogMsg("launch_data_dict_lookup LAUNCH_JOBKEY_SOCKETS returned NULL");
+ else
+ {
+ launch_data_t skt = launch_data_dict_lookup(skts, "Listeners");
+ if (!skt) LogMsg("launch_data_dict_lookup Listeners returned NULL");
+ else
+ {
+ launchd_fds_count = launch_data_array_get_count(skt);
+ if (launchd_fds_count == 0) LogMsg("launch_data_array_get_count(skt) returned 0");
+ else
+ {
+ launchd_fds = mallocL("LaunchdCheckin", sizeof(dnssd_sock_t) * launchd_fds_count);
+ if (!launchd_fds) LogMsg("LaunchdCheckin: malloc failed");
+ else
+ {
+ size_t i;
+ for(i = 0; i < launchd_fds_count; i++)
+ {
+ launch_data_t s = launch_data_array_get_index(skt, i);
+ if (!s)
+ {
+ launchd_fds[i] = dnssd_InvalidSocket;
+ LogMsg("launch_data_array_get_index(skt, %d) returned NULL", i);
+ }
+ else
+ {
+ launchd_fds[i] = launch_data_get_fd(s);
+ LogInfo("Launchd Unix Domain Socket [%d]: %d", i, launchd_fds[i]);
+ }
+ }
+ }
+ // In some early versions of 10.4.x, the permissions on the UDS were not set correctly, so we fix them here
+ chmod(MDNS_UDS_SERVERPATH, S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP | S_IROTH|S_IWOTH);
+ }
+ }
+ }
+ }
+ launch_data_free(resp_sd);
+}
+
+static mach_port_t RegisterMachService(const char *service_name)
+{
+ mach_port_t port = MACH_PORT_NULL;
+ kern_return_t kr;
+
+ if (KERN_SUCCESS != (kr = bootstrap_check_in(bootstrap_port, (char *)service_name, &port)))
+ {
+ LogMsg("RegisterMachService: %d %X %s", kr, kr, mach_error_string(kr));
+ return MACH_PORT_NULL;
+ }
+
+ if (KERN_SUCCESS != (kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND)))
+ {
+ LogMsg("RegisterMachService: %d %X %s", kr, kr, mach_error_string(kr));
+ mach_port_deallocate(mach_task_self(), port);
+ return MACH_PORT_NULL;
+ }
+
+ return port;
+}
+
+extern int sandbox_init(const char *profile, uint64_t flags, char **errorbuf) __attribute__((weak_import));
+
+mDNSexport int main(int argc, char **argv)
+{
+ int i;
+ kern_return_t status;
+
+ mDNSMacOSXSystemBuildNumber(NULL);
+ LogMsg("%s starting %s %d", mDNSResponderVersionString, OSXVers ? "OSXVers" : "iOSVers", OSXVers ? OSXVers : iOSVers);
+
+#if 0
+ LogMsg("CacheRecord %d", sizeof(CacheRecord));
+ LogMsg("CacheGroup %d", sizeof(CacheGroup));
+ LogMsg("ResourceRecord %d", sizeof(ResourceRecord));
+ LogMsg("RData_small %d", sizeof(RData_small));
+
+ LogMsg("sizeof(CacheEntity) %d", sizeof(CacheEntity));
+ LogMsg("RR_CACHE_SIZE %d", RR_CACHE_SIZE);
+ LogMsg("block usage %d", sizeof(CacheEntity) * RR_CACHE_SIZE);
+ LogMsg("block wastage %d", 16*1024 - sizeof(CacheEntity) * RR_CACHE_SIZE);
+#endif
+
+ if (0 == geteuid())
+ {
+ LogMsg("mDNSResponder cannot be run as root !! Exiting..");
+ return -1;
+ }
+
+ for (i=1; i<argc; i++)
+ {
+ if (!strcasecmp(argv[i], "-d" )) mDNS_DebugMode = mDNStrue;
+ if (!strcasecmp(argv[i], "-NoMulticastAdvertisements")) advertise = mDNS_Init_DontAdvertiseLocalAddresses;
+ if (!strcasecmp(argv[i], "-DisableSleepProxyClient" )) DisableSleepProxyClient = mDNStrue;
+ if (!strcasecmp(argv[i], "-DebugLogging" )) mDNS_LoggingEnabled = mDNStrue;
+ if (!strcasecmp(argv[i], "-UnicastPacketLogging" )) mDNS_PacketLoggingEnabled = mDNStrue;
+ if (!strcasecmp(argv[i], "-OfferSleepProxyService" ))
+ OfferSleepProxyService = (i+1 < argc && mDNSIsDigit(argv[i+1][0]) && mDNSIsDigit(argv[i+1][1]) && argv[i+1][2]==0) ? atoi(argv[++i]) : 100;
+ if (!strcasecmp(argv[i], "-UseInternalSleepProxy" ))
+ UseInternalSleepProxy = (i+1<argc && mDNSIsDigit(argv[i+1][0]) && argv[i+1][1]==0) ? atoi(argv[++i]) : 1;
+ if (!strcasecmp(argv[i], "-StrictUnicastOrdering" )) StrictUnicastOrdering = mDNStrue;
+ if (!strcasecmp(argv[i], "-AlwaysAppendSearchDomains")) AlwaysAppendSearchDomains = mDNStrue;
+ }
+
+ // Note that mDNSPlatformInit will set DivertMulticastAdvertisements in the mDNS structure
+ if (!advertise) LogMsg("Administratively prohibiting multicast advertisements");
+
+#ifndef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+
+ signal(SIGHUP, HandleSIG); // (Debugging) Purge the cache to check for cache handling bugs
+ signal(SIGINT, HandleSIG); // Ctrl-C: Detach from Mach BootstrapService and exit cleanly
+ signal(SIGPIPE, SIG_IGN); // Don't want SIGPIPE signals -- we'll handle EPIPE errors directly
+ signal(SIGTERM, HandleSIG); // Machine shutting down: Detach from and exit cleanly like Ctrl-C
+ signal(SIGINFO, HandleSIG); // (Debugging) Write state snapshot to syslog
+ signal(SIGUSR1, HandleSIG); // (Debugging) Enable Logging
+ signal(SIGUSR2, HandleSIG); // (Debugging) Enable Packet Logging
+ signal(SIGURG, HandleSIG); // (Debugging) Toggle Opportunistic Caching
+ signal(SIGPROF, HandleSIG); // (Debugging) Toggle Multicast Logging
+ signal(SIGTSTP, HandleSIG); // (Debugging) Disable all Debug Logging (USR1/USR2/PROF)
+
+#endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+
+ mDNSStorage.p = &PlatformStorage; // Make sure mDNSStorage.p is set up, because validatelists uses it
+ // Need to Start XPC Server Before LaunchdCheckin() (Reason: rdar11023750)
+ xpc_server_init();
+ LaunchdCheckin();
+
+#ifndef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+
+ // Create the kqueue, mutex and thread to support KQSockets
+ KQueueFD = kqueue();
+ if (KQueueFD == -1) { LogMsg("kqueue() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; }
+
+ i = pthread_mutex_init(&PlatformStorage.BigMutex, NULL);
+ if (i == -1) { LogMsg("pthread_mutex_init() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; }
+
+ int fdpair[2] = {0, 0};
+ i = socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair);
+ if (i == -1) { LogMsg("socketpair() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; }
+
+ // Socket pair returned us two identical sockets connected to each other
+ // We will use the first socket to send the second socket. The second socket
+ // will be added to the kqueue so it will wake when data is sent.
+ static const KQueueEntry wakeKQEntry = { KQWokenFlushBytes, NULL, "kqueue wakeup after CFRunLoop event" };
+
+ PlatformStorage.WakeKQueueLoopFD = fdpair[0];
+ KQueueSet(fdpair[1], EV_ADD, EVFILT_READ, &wakeKQEntry);
+
+#endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+
+ // Invoke sandbox profile /usr/share/sandbox/mDNSResponder.sb
+#if MDNS_NO_SANDBOX
+ LogMsg("Note: Compiled without Apple Sandbox support");
+#else // MDNS_NO_SANDBOX
+ if (!sandbox_init)
+ LogMsg("Note: Running without Apple Sandbox support (not available on this OS)");
+ else
+ {
+ char *sandbox_msg;
+ uint64_t sandbox_flags = SANDBOX_NAMED;
+
+ int sandbox_err = sandbox_init("mDNSResponder", sandbox_flags, &sandbox_msg);
+ if (sandbox_err)
+ {
+ LogMsg("WARNING: sandbox_init error %s", sandbox_msg);
+ // If we have errors in the sandbox during development, to prevent
+ // exiting, uncomment the following line.
+ //sandbox_free_error(sandbox_msg);
+
+ errx(EX_OSERR, "sandbox_init() failed: %s", sandbox_msg);
+ }
+ else LogInfo("Now running under Apple Sandbox restrictions");
+ }
+#endif // MDNS_NO_SANDBOX
+
+ // We use BeginTransactionAtShutdown in the plist that ensures that we will
+ // receive a SIGTERM during shutdown rather than a SIGKILL. But launchd (due to some
+ // limitation) currently requires us to still start and end the transaction for
+ // its proper initialization.
+ vproc_transaction_t vt = vproc_transaction_begin(NULL);
+ if (vt) vproc_transaction_end(NULL, vt);
+
+ m_port = RegisterMachService(kmDNSResponderServName);
+ // We should ALWAYS receive our Mach port from RegisterMachService() but sanity check before initializing daemon
+ if (m_port == MACH_PORT_NULL)
+ {
+ LogMsg("! MACH PORT IS NULL ! bootstrap_checkin failed to give a mach port");
+ return -1;
+ }
+
+ status = mDNSDaemonInitialize();
+ if (status) { LogMsg("Daemon start: mDNSDaemonInitialize failed"); goto exit; }
+
+ status = udsserver_init(launchd_fds, launchd_fds_count);
+ if (status) { LogMsg("Daemon start: udsserver_init failed"); goto exit; }
+
+ log_client = asl_open(NULL, "mDNSResponder", 0);
+ log_msg = asl_new(ASL_TYPE_MSG);
+
+#if TARGET_OS_EMBEDDED
+ _scprefs_observer_watch(scprefs_observer_type_global, kmDNSResponderPrefIDStr, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
+ ^{
+ Prefschanged();
+ });
+#endif
+
+ mDNSMacOSXNetworkChanged(&mDNSStorage);
+ UpdateDebugState();
+
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+ LogInfo("Daemon Start: Using LibDispatch");
+ // CFRunLoopRun runs both CFRunLoop sources and dispatch sources
+ CFRunLoopRun();
+#else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+ // Start the kqueue thread
+ pthread_t KQueueThread;
+ i = pthread_create(&KQueueThread, NULL, KQueueLoop, &mDNSStorage);
+ if (i == -1) { LogMsg("pthread_create() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; }
+ if (status == 0)
+ {
+ CFRunLoopRun();
+ LogMsg("ERROR: CFRunLoopRun Exiting.");
+ mDNS_Close(&mDNSStorage);
+ }
+#endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+
+ LogMsg("%s exiting", mDNSResponderVersionString);
+
+exit:
+ return(status);
+}
+
+// uds_daemon.c support routines /////////////////////////////////////////////
+
+// Arrange things so that when data appears on fd, callback is called with context
+mDNSexport mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context, void **platform_data)
+{
+ KQSocketEventSource **p = &gEventSources;
+ (void) platform_data;
+ while (*p && (*p)->fd != fd) p = &(*p)->next;
+ if (*p) { LogMsg("udsSupportAddFDToEventLoop: ERROR fd %d already has EventLoop source entry", fd); return mStatus_AlreadyRegistered; }
+
+ KQSocketEventSource *newSource = (KQSocketEventSource*) mallocL("KQSocketEventSource", sizeof *newSource);
+ if (!newSource) return mStatus_NoMemoryErr;
+
+ newSource->next = mDNSNULL;
+ newSource->fd = fd;
+ newSource->kqs.KQcallback = callback;
+ newSource->kqs.KQcontext = context;
+ newSource->kqs.KQtask = "UDS client";
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+ newSource->kqs.readSource = mDNSNULL;
+ newSource->kqs.writeSource = mDNSNULL;
+ newSource->kqs.fdClosed = mDNSfalse;
+#endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+
+ if (KQueueSet(fd, EV_ADD, EVFILT_READ, &newSource->kqs) == 0)
+ {
+ *p = newSource;
+ return mStatus_NoError;
+ }
+
+ LogMsg("KQueueSet failed for fd %d errno %d (%s)", fd, errno, strerror(errno));
+ freeL("KQSocketEventSource", newSource);
+ return mStatus_BadParamErr;
+}
+
+int udsSupportReadFD(dnssd_sock_t fd, char *buf, int len, int flags, void *platform_data)
+{
+ (void) platform_data;
+ return recv(fd, buf, len, flags);
+}
+
+mDNSexport mStatus udsSupportRemoveFDFromEventLoop(int fd, void *platform_data) // Note: This also CLOSES the file descriptor
+{
+ KQSocketEventSource **p = &gEventSources;
+ (void) platform_data;
+ while (*p && (*p)->fd != fd) p = &(*p)->next;
+ if (*p)
+ {
+ KQSocketEventSource *s = *p;
+ *p = (*p)->next;
+ // We don't have to explicitly do a kqueue EV_DELETE here because closing the fd
+ // causes the kernel to automatically remove any associated kevents
+ mDNSPlatformCloseFD(&s->kqs, s->fd);
+ freeL("KQSocketEventSource", s);
+ return mStatus_NoError;
+ }
+ LogMsg("udsSupportRemoveFDFromEventLoop: ERROR fd %d not found in EventLoop source list", fd);
+ return mStatus_NoSuchNameErr;
+}
+
+#if _BUILDING_XCODE_PROJECT_
+// If mDNSResponder crashes, then this string will be magically included in the automatically-generated crash log
+const char *__crashreporter_info__ = mDNSResponderVersionString;
+asm (".desc ___crashreporter_info__, 0x10");
+#endif
+
+// For convenience when using the "strings" command, this is the last thing in the file
+// The "@(#) " pattern is a special prefix the "what" command looks for
+mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
diff --git a/mDNSResponder/mDNSMacOSX/dnsctl-entitlements.plist b/mDNSResponder/mDNSMacOSX/dnsctl-entitlements.plist
new file mode 100644
index 00000000..fb9c3a30
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/dnsctl-entitlements.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.mDNSResponder.dnsproxy</key>
+ <true/>
+</dict>
+</plist>
diff --git a/mDNSResponder/mDNSMacOSX/helper-entitlements.plist b/mDNSResponder/mDNSMacOSX/helper-entitlements.plist
new file mode 100644
index 00000000..cf478cd9
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/helper-entitlements.plist
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.SystemConfiguration.SCDynamicStore-write-access</key>
+ <true/>
+ <key>com.apple.SystemConfiguration.SCPreferences-write-access</key>
+ <array>
+ <string>com.apple.AutoWake.xml</string>
+ </array>
+</dict>
+</plist>
diff --git a/mDNSResponder/mDNSMacOSX/helper-error.h b/mDNSResponder/mDNSMacOSX/helper-error.h
new file mode 100644
index 00000000..2e463b0a
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/helper-error.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 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.
+ */
+
+ERROR(kmDNSHelperCommunicationFailed, "Mach communication failed")
+ERROR(kmDNSHelperNotAuthorized, "Not authorized")
+ERROR(kmDNSHelperCreationFailed, "Object creation failed")
+ERROR(kmDNSHelperInvalidPList, "Invalid property list")
+ERROR(kmDNSHelperInvalidNameKey, "Invalid name key")
+ERROR(kmDNSHelperInvalidConfigKey, "Invalid configuration key")
+ERROR(kmDNSHelperTypeError, "Object was not of expected type")
+ERROR(kmDNSHelperPreferencesFailed, "Could not create preferences session")
+ERROR(kmDNSHelperPreferencesLockFailed, "Could not lock preferences")
+ERROR(kmDNSHelperPreferencesSetFailed, "Could not update preferences")
+ERROR(kmDNSHelperKeychainCopyDefaultFailed, "Could not copy keychain default")
+ERROR(kmDNSHelperKeychainSearchCreationFailed, "Could not create keychain search")
+ERROR(kmDNSHelperPListWriteFailed, "Could not write property list to stream")
+ERROR(kmDNSHelperResultTooLarge, "Result too large")
+ERROR(kmDNSHelperInterfaceCreationFailed, "Could not create auto-tunnel interface")
+ERROR(kmDNSHelperInterfaceDeletionFailed, "Could not delete auto-tunnel interface")
+ERROR(kmDNSHelperInvalidInterfaceState, "Invalid interface state requested")
+ERROR(kmDNSHelperInvalidServerState, "Invalid server state requested")
+ERROR(kmDNSHelperRacoonConfigCreationFailed, "Could not create racoon configuration file")
+ERROR(kmDNSHelperRacoonStartFailed, "Could not start racoon")
+ERROR(kmDNSHelperRacoonNotificationFailed, "Could not notify racoon")
+ERROR(kmDNSHelperInvalidTunnelSetKeysOperation, "Invalid tunnel setkey operation requested")
+ERROR(kmDNSHelperInvalidNetworkAddress, "Invalid network address")
+ERROR(kmDNSHelperRouteAdditionFailed, "Could not add route")
+ERROR(kmDNSHelperRouteDeletionFailed, "Could not remove route")
+ERROR(kmDNSHelperRoutingSocketCreationFailed, "Could not create routing socket")
+ERROR(kmDNSHelperDatagramSocketCreationFailed, "Could not create datagram socket")
+ERROR(kmDNSHelperIPsecPolicyCreationFailed, "Could not create IPsec policy")
+ERROR(kmDNSHelperIPsecPolicySetFailed, "Could not set IPsec policy")
+ERROR(kmDNSHelperIPsecRemoveSAFailed, "Could not remove IPsec SA")
+ERROR(kmDNSHelperIPsecPolicySocketCreationFailed, "Could not create IPsec policy socket")
+ERROR(kmDNSHelperIPsecDisabled, "IPSec support was not compiled in to the helper")
diff --git a/mDNSResponder/mDNSMacOSX/helper-main.c b/mDNSResponder/mDNSMacOSX/helper-main.c
new file mode 100644
index 00000000..52779e85
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/helper-main.c
@@ -0,0 +1,298 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 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.
+ */
+
+#define _FORTIFY_SOURCE 2
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <sys/cdefs.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <servers/bootstrap.h>
+#include <asl.h>
+#include <launch.h>
+#include <pwd.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <Security/Security.h>
+#include "helper.h"
+#include "helper-server.h"
+#include "helpermsg.h"
+#include "helpermsgServer.h"
+#include <vproc.h>
+
+#if TARGET_OS_EMBEDDED
+#define NO_SECURITYFRAMEWORK 1
+#endif
+
+#ifndef LAUNCH_JOBKEY_MACHSERVICES
+#define LAUNCH_JOBKEY_MACHSERVICES "MachServices"
+#define LAUNCH_DATA_MACHPORT 10
+#define launch_data_get_machport launch_data_get_fd
+#endif
+
+union max_msg_size
+{
+ union __RequestUnion__proxy_helper_subsystem req;
+ union __ReplyUnion__proxy_helper_subsystem rep;
+};
+
+static const mach_msg_size_t MAX_MSG_SIZE = sizeof(union max_msg_size) + MAX_TRAILER_SIZE;
+static aslclient logclient = NULL;
+static int opt_debug;
+static pthread_t idletimer_thread;
+
+unsigned long maxidle = 15;
+unsigned long actualidle = 3600;
+
+CFRunLoopRef gRunLoop = NULL;
+CFRunLoopTimerRef gTimer = NULL;
+
+mach_port_t gPort = MACH_PORT_NULL;
+
+static void helplogv(int level, const char *fmt, va_list ap)
+{
+ if (NULL == logclient) { vfprintf(stderr, fmt, ap); fflush(stderr); }
+ else asl_vlog(logclient, NULL, level, fmt, ap);
+}
+
+void helplog(int level, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ helplogv(level, fmt, ap);
+ va_end(ap);
+}
+
+// for safe_vproc
+void LogMsgWithLevel(mDNSLogLevel_t logLevel, const char *fmt, ...)
+{
+ (void)logLevel;
+ va_list ap;
+ va_start(ap, fmt);
+ // safe_vproc only calls LogMsg, so assume logLevel maps to ASL_LEVEL_ERR
+ helplog(ASL_LEVEL_ERR, fmt, ap);
+ va_end(ap);
+}
+
+static void handle_sigterm(int sig)
+{
+ // debug("entry sig=%d", sig); Can't use syslog from within a signal handler
+ assert(sig == SIGTERM);
+ (void)proxy_mDNSExit(gPort);
+}
+
+static void initialize_logging(void)
+{
+ logclient = asl_open(NULL, kmDNSHelperServiceName, (opt_debug ? ASL_OPT_STDERR : 0));
+ if (NULL == logclient) { fprintf(stderr, "Could not initialize ASL logging.\n"); fflush(stderr); return; }
+ if (opt_debug) asl_set_filter(logclient, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
+}
+
+static void initialize_id(void)
+{
+ static char login[] = "_mdnsresponder";
+ struct passwd hardcode;
+ struct passwd *pwd = &hardcode; // getpwnam(login);
+ hardcode.pw_uid = 65;
+ hardcode.pw_gid = 65;
+
+ if (!pwd) { helplog(ASL_LEVEL_ERR, "Could not find account name `%s'. I will only help root.", login); return; }
+ mDNSResponderUID = pwd->pw_uid;
+ mDNSResponderGID = pwd->pw_gid;
+}
+
+static void diediedie(CFRunLoopTimerRef timer, void *context)
+{
+ debug("entry %p %p %d", timer, context, maxidle);
+ assert(gTimer == timer);
+ if (maxidle)
+ (void)proxy_mDNSExit(gPort);
+}
+
+void pause_idle_timer(void)
+{
+ debug("entry");
+ assert(gTimer);
+ assert(gRunLoop);
+ CFRunLoopRemoveTimer(gRunLoop, gTimer, kCFRunLoopDefaultMode);
+}
+
+void unpause_idle_timer(void)
+{
+ debug("entry");
+ assert(gRunLoop);
+ assert(gTimer);
+ CFRunLoopAddTimer(gRunLoop, gTimer, kCFRunLoopDefaultMode);
+}
+
+void update_idle_timer(void)
+{
+ debug("entry");
+ assert(gTimer);
+ CFRunLoopTimerSetNextFireDate(gTimer, CFAbsoluteTimeGetCurrent() + actualidle);
+}
+
+static void *idletimer(void *context)
+{
+ debug("entry context=%p", context);
+ gRunLoop = CFRunLoopGetCurrent();
+
+ unpause_idle_timer();
+
+ for (;;)
+ {
+ debug("Running CFRunLoop");
+ CFRunLoopRun();
+ sleep(1);
+ }
+
+ return NULL;
+}
+
+static int initialize_timer()
+{
+ gTimer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + actualidle, actualidle, 0, 0, diediedie, NULL);
+ int err = 0;
+
+ debug("entry");
+ if (0 != (err = pthread_create(&idletimer_thread, NULL, idletimer, NULL)))
+ helplog(ASL_LEVEL_ERR, "Could not start idletimer thread: %s", strerror(err));
+
+ return err;
+}
+
+static mach_port_t register_service(const char *service_name)
+{
+ mach_port_t port = MACH_PORT_NULL;
+ kern_return_t kr;
+
+ if (KERN_SUCCESS != (kr = bootstrap_check_in(bootstrap_port, (char *)service_name, &port)))
+ {
+ helplog(ASL_LEVEL_ERR, "bootstrap_check_in: %d %X %s", kr, kr, mach_error_string(kr));
+ return MACH_PORT_NULL;
+ }
+
+ if (KERN_SUCCESS != (kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND)))
+ {
+ helplog(ASL_LEVEL_ERR, "mach_port_insert_right: %d %X %s", kr, kr, mach_error_string(kr));
+ mach_port_deallocate(mach_task_self(), port);
+ return MACH_PORT_NULL;
+ }
+
+ return port;
+}
+
+int main(int ac, char *av[])
+{
+ char *p = NULL;
+ kern_return_t kr = KERN_FAILURE;
+ long n;
+ int ch;
+ mach_msg_header_t hdr;
+
+ while ((ch = getopt(ac, av, "dt:")) != -1)
+ switch (ch)
+ {
+ case 'd': opt_debug = 1; break;
+ case 't':
+ n = strtol(optarg, &p, 0);
+ if ('\0' == optarg[0] || '\0' != *p || n > LONG_MAX || n < 0)
+ { fprintf(stderr, "Invalid idle timeout: %s\n", optarg); exit(EXIT_FAILURE); }
+ maxidle = n;
+ break;
+ case '?':
+ default:
+ fprintf(stderr, "Usage: mDNSResponderHelper [-d] [-t maxidle]\n");
+ exit(EXIT_FAILURE);
+ }
+ ac -= optind;
+ av += optind;
+
+ initialize_logging();
+ helplog(ASL_LEVEL_INFO, "Starting");
+ initialize_id();
+
+#ifndef NO_SECURITYFRAMEWORK
+ // We should normally be running as a system daemon. However, that might not be the case in some scenarios (e.g. debugging).
+ // Explicitly ensure that our Keychain operations utilize the system domain.
+ if (opt_debug) SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
+#endif
+ gPort = register_service(kmDNSHelperServiceName);
+ if (!gPort)
+ exit(EXIT_FAILURE);
+
+ if (maxidle) actualidle = maxidle;
+
+ signal(SIGTERM, handle_sigterm);
+
+ // We use BeginTransactionAtShutdown in the plist that ensures that we will
+ // receive a SIGTERM during shutdown rather than a SIGKILL. But launchd (due to some
+ // limitation) currently requires us to still start and end the transaction for
+ // its proper initialization.
+ vproc_transaction_t vt = vproc_transaction_begin(NULL);
+ if (vt) vproc_transaction_end(NULL, vt);
+
+ if (initialize_timer()) exit(EXIT_FAILURE);
+ for (n=0; n<100000; n++) if (!gRunLoop) usleep(100);
+ if (!gRunLoop)
+ {
+ helplog(ASL_LEVEL_ERR, "gRunLoop not set after waiting");
+ exit(EXIT_FAILURE);
+ }
+
+ for(;;)
+ {
+ hdr.msgh_bits = 0;
+ hdr.msgh_local_port = gPort;
+ hdr.msgh_remote_port = MACH_PORT_NULL;
+ hdr.msgh_size = sizeof(hdr);
+ hdr.msgh_id = 0;
+ kr = mach_msg(&hdr, MACH_RCV_LARGE | MACH_RCV_MSG, 0, hdr.msgh_size, gPort, 0, 0);
+ if (MACH_RCV_TOO_LARGE != kr)
+ helplog(ASL_LEVEL_ERR, "main MACH_RCV_MSG error: %d %X %s", kr, kr, mach_error_string(kr));
+
+ kr = mach_msg_server_once(helper_server, MAX_MSG_SIZE, gPort,
+ MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0));
+ if (KERN_SUCCESS != kr)
+ { helplog(ASL_LEVEL_ERR, "mach_msg_server: %d %X %s", kr, kr, mach_error_string(kr)); exit(EXIT_FAILURE); }
+
+ }
+ exit(EXIT_SUCCESS);
+}
+
+// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
+// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+// To expand "version" to its value before making the string, use STRINGIFY(version) instead
+#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) # s
+#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
+
+// For convenience when using the "strings" command, this is the last thing in the file
+// The "@(#) " pattern is a special prefix the "what" command looks for
+const char VersionString_SCCS[] = "@(#) mDNSResponderHelper " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
+
+#if _BUILDING_XCODE_PROJECT_
+// If the process crashes, then this string will be magically included in the automatically-generated crash log
+const char *__crashreporter_info__ = VersionString_SCCS + 5;
+asm (".desc ___crashreporter_info__, 0x10");
+#endif
diff --git a/mDNSResponder/mDNSMacOSX/helper-server.h b/mDNSResponder/mDNSMacOSX/helper-server.h
new file mode 100644
index 00000000..1c391a01
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/helper-server.h
@@ -0,0 +1,31 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 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.
+ */
+
+#ifndef H_HELPER_SERVER_H
+#define H_HELPER_SERVER_H
+
+extern void helplog(int, const char *, ...);
+extern void pause_idle_timer(void);
+extern void unpause_idle_timer(void);
+extern void update_idle_timer(void);
+extern uid_t mDNSResponderUID;
+extern uid_t mDNSResponderGID;
+extern CFRunLoopRef gRunLoop;
+#define debug(...) debug_(__func__, __VA_ARGS__)
+extern void debug_(const char *func, const char *fmt, ...);
+
+#endif /* H_HELPER_SERVER_H */
diff --git a/mDNSResponder/mDNSMacOSX/helper-stubs.c b/mDNSResponder/mDNSMacOSX/helper-stubs.c
new file mode 100644
index 00000000..29fd9aed
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/helper-stubs.c
@@ -0,0 +1,496 @@
+/*
+ * 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 <mach/mach.h>
+#include <mach/mach_error.h>
+#include <mach/vm_map.h>
+#include <servers/bootstrap.h>
+#include <IOKit/IOReturn.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include "mDNSDebug.h"
+#include "helper.h"
+#include "helpermsg.h"
+#include <dispatch/dispatch.h>
+#include <arpa/inet.h>
+
+//
+// Implementation Notes about the HelperQueue:
+//
+// To prevent blocking the main queue, all communications with mDNSResponderHelper should happen on
+// HelperQueue. There are a few calls which are still synchronous and needs to be handled separately
+// case by case.
+//
+// When spawning off the work to the HelperQueue, any arguments that are pointers need to be copied
+// explicitly as they may cease to exist after the call returns. From within the block that is scheduled,
+// arrays defined on the stack can't be referenced and hence it is enclosed them in a struct. If the array is
+// an argument to the function, the blocks can reference them as they are passed in as pointers. But care should
+// be taken to copy them locally as they may cease to exist when the function returns.
+//
+static dispatch_queue_t HelperQueue;
+
+#define ERROR(x, y) y,
+static const char *errorstring[] =
+{
+ #include "helper-error.h"
+ NULL
+};
+#undef ERROR
+
+mDNSexport mStatus mDNSHelperInit()
+{
+ HelperQueue = dispatch_queue_create("com.apple.mDNSResponder.HelperQueue", NULL);
+ if (HelperQueue == NULL)
+ {
+ LogMsg("dispatch_queue_create: Helper queue NULL");
+ return mStatus_NoMemoryErr;
+ }
+ return mStatus_NoError;
+}
+
+static mach_port_t getHelperPort(int retry)
+{
+ static mach_port_t port = MACH_PORT_NULL;
+ if (retry) port = MACH_PORT_NULL;
+ if (port == MACH_PORT_NULL && BOOTSTRAP_SUCCESS != bootstrap_look_up(bootstrap_port, kmDNSHelperServiceName, &port))
+ LogMsg("%s: cannot contact helper", __func__);
+ return port;
+}
+
+const char *mDNSHelperError(int err)
+{
+ static const char *p = "<unknown error>";
+ if (mDNSHelperErrorBase < err && mDNSHelperErrorEnd > err)
+ p = errorstring[err - mDNSHelperErrorBase - 1];
+ return p;
+}
+
+/* Ugly but handy. */
+// We don't bother reporting kIOReturnNotReady because that error code occurs in "normal" operation
+// and doesn't indicate anything unexpected that needs to be investigated
+
+#define MACHRETRYLOOP_BEGIN(kr, retry, err, fin) \
+ for (;;) \
+ {
+#define MACHRETRYLOOP_END(kr, retry, err, fin) \
+ if (KERN_SUCCESS == (kr)) break; \
+ else if (MACH_SEND_INVALID_DEST == (kr) && 0 == (retry)++) continue; \
+ else \
+ { \
+ (err) = kmDNSHelperCommunicationFailed; \
+ LogMsg("%s: Mach communication failed: %d %X %s", __func__, kr, kr, mach_error_string(kr)); \
+ goto fin; \
+ } \
+ } \
+ if (0 != (err) && kIOReturnNotReady != (err)) \
+ { LogMsg("%s: %d 0x%X (%s)", __func__, (err), (err), mDNSHelperError(err)); goto fin; }
+
+void mDNSPreferencesSetName(int key, domainlabel *old, domainlabel *new)
+{
+ struct {
+ char oldname[MAX_DOMAIN_LABEL+1];
+ char newname[MAX_DOMAIN_LABEL+1];
+ } names;
+
+ mDNSPlatformMemZero(names.oldname, MAX_DOMAIN_LABEL + 1);
+ mDNSPlatformMemZero(names.newname, MAX_DOMAIN_LABEL + 1);
+
+ ConvertDomainLabelToCString_unescaped(old, names.oldname);
+ if (new) ConvertDomainLabelToCString_unescaped(new, names.newname);
+ dispatch_async(HelperQueue, ^{
+
+ kern_return_t kr = KERN_FAILURE;
+ int retry = 0;
+ int err = 0;
+
+ LogInfo("%s: oldname %s newname %s", __func__, names.oldname, names.newname);
+ MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+ kr = proxy_mDNSPreferencesSetName(getHelperPort(retry), key, names.oldname, names.newname);
+ MACHRETRYLOOP_END(kr, retry, err, fin);
+
+fin:
+ (void)err;
+ });
+}
+
+void mDNSRequestBPF(void)
+{
+ dispatch_async(HelperQueue, ^{
+
+ kern_return_t kr = KERN_FAILURE;
+ int retry = 0, err = 0;
+ LogInfo("%s: BPF", __func__);
+ MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+ kr = proxy_mDNSRequestBPF(getHelperPort(retry));
+ MACHRETRYLOOP_END(kr, retry, err, fin);
+fin:
+ (void)err;
+ });
+}
+
+int mDNSPowerRequest(int key, int interval)
+{
+ kern_return_t kr = KERN_FAILURE;
+ int retry = 0, err = 0;
+ MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+ kr = proxy_mDNSPowerRequest(getHelperPort(retry), key, interval, &err);
+ MACHRETRYLOOP_END(kr, retry, err, fin);
+fin:
+ return err;
+}
+
+int mDNSSetLocalAddressCacheEntry(int ifindex, int family, const v6addr_t ip, const ethaddr_t eth)
+{
+ kern_return_t kr = KERN_FAILURE;
+ int retry = 0, err = 0;
+ MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+ kr = proxy_mDNSSetLocalAddressCacheEntry(getHelperPort(retry), ifindex, family, (uint8_t*)ip, (uint8_t*)eth, &err);
+ MACHRETRYLOOP_END(kr, retry, err, fin);
+fin:
+ return err;
+}
+
+void mDNSNotify(const char *title, const char *msg) // Both strings are UTF-8 text
+{
+ char *titleCopy = NULL;
+ char *msgCopy = NULL;
+
+ if (title)
+ {
+ int len = strlen(title);
+ titleCopy = mDNSPlatformMemAllocate(len + 1);
+ if (!titleCopy)
+ {
+ LogMsg("mDNSNotify: titleCopy NULL for %s", msg);
+ return;
+ }
+ mDNSPlatformMemCopy(titleCopy, title, len);
+ titleCopy[len] = 0;
+ }
+ if (msg)
+ {
+ int len = strlen(msg);
+ msgCopy = mDNSPlatformMemAllocate(len + 1);
+ if (!msgCopy)
+ {
+ LogMsg("mDNSNotify: msgCopy NULL for %s", msg);
+ return;
+ }
+ mDNSPlatformMemCopy(msgCopy, msg, len);
+ msgCopy[len] = 0;
+ }
+
+ dispatch_async(HelperQueue, ^{
+
+ kern_return_t kr = KERN_FAILURE;
+ int retry = 0, err = 0;
+
+ LogInfo("%s: title %s, msg %s", __func__, titleCopy, msgCopy);
+
+ MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+ kr = proxy_mDNSNotify(getHelperPort(retry), titleCopy, msgCopy);
+ MACHRETRYLOOP_END(kr, retry, err, fin);
+fin:
+ if (titleCopy)
+ mDNSPlatformMemFree(titleCopy);
+ if (msgCopy)
+ mDNSPlatformMemFree(msgCopy);
+ (void)err;
+ });
+}
+
+int mDNSKeychainGetSecrets(CFArrayRef *result)
+{
+ CFPropertyListRef plist = NULL;
+ CFDataRef bytes = NULL;
+ kern_return_t kr = KERN_FAILURE;
+ unsigned int numsecrets = 0;
+ vm_offset_t secrets = 0;
+ mach_msg_type_number_t secretsCnt = 0;
+ int retry = 0, err = 0;
+
+ MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+ kr = proxy_mDNSKeychainGetSecrets(getHelperPort(retry), &numsecrets, &secrets, &secretsCnt, &err);
+ MACHRETRYLOOP_END(kr, retry, err, fin);
+
+ if (NULL == (bytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (void*)secrets, secretsCnt, kCFAllocatorNull)))
+ {
+ err = kmDNSHelperCreationFailed;
+ LogMsg("%s: CFDataCreateWithBytesNoCopy failed", __func__);
+ goto fin;
+ }
+ if (NULL == (plist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, bytes, kCFPropertyListImmutable, NULL)))
+ {
+ err = kmDNSHelperInvalidPList;
+ LogMsg("%s: CFPropertyListCreateFromXMLData failed", __func__);
+ goto fin;
+ }
+ if (CFArrayGetTypeID() != CFGetTypeID(plist))
+ {
+ err = kmDNSHelperTypeError;
+ LogMsg("%s: Unexpected result type", __func__);
+ CFRelease(plist);
+ plist = NULL;
+ goto fin;
+ }
+ *result = (CFArrayRef)plist;
+
+fin:
+ if (bytes) CFRelease(bytes);
+ if (secrets) vm_deallocate(mach_task_self(), secrets, secretsCnt);
+ return err;
+}
+
+void mDNSConfigureServer(int updown, const char *const prefix, const domainname *const fqdn)
+{
+ struct
+ {
+ // Assume the prefix is no larger than 10 chars
+ char fqdnStr[MAX_ESCAPED_DOMAIN_NAME + 10];
+ } name;
+
+ mDNSPlatformMemZero(name.fqdnStr, MAX_DOMAIN_LABEL + 10);
+
+ if (fqdn)
+ {
+ mDNSPlatformStrCopy(name.fqdnStr, prefix);
+ ConvertDomainNameToCString(fqdn, name.fqdnStr + mDNSPlatformStrLen(prefix));
+ }
+
+ dispatch_async(HelperQueue, ^{
+
+ kern_return_t kr = KERN_SUCCESS;
+ int retry = 0, err = 0;
+
+ LogInfo("%s: fqdnStr %s", __func__, name.fqdnStr);
+
+ MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+ kr = proxy_mDNSConfigureServer(getHelperPort(retry), updown, name.fqdnStr);
+ MACHRETRYLOOP_END(kr, retry, err, fin);
+fin:
+ (void)err;
+
+ });
+}
+
+int mDNSAutoTunnelSetKeys(int replacedelete, v6addr_t local_inner,
+ v6addr_t local_outer, short local_port, v6addr_t remote_inner,
+ v6addr_t remote_outer, short remote_port, const char* const prefix, const domainname *const fqdn)
+{
+ kern_return_t kr = KERN_SUCCESS;
+ int retry = 0, err = 0;
+ char fqdnStr[MAX_ESCAPED_DOMAIN_NAME + 10] = { 0 }; // Assume the prefix is no larger than 10 chars
+ if (fqdn)
+ {
+ mDNSPlatformStrCopy(fqdnStr, prefix);
+ ConvertDomainNameToCString(fqdn, fqdnStr + mDNSPlatformStrLen(prefix));
+ }
+ MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+ kr = proxy_mDNSAutoTunnelSetKeys(getHelperPort(retry), replacedelete, local_inner, local_outer, local_port, remote_inner, remote_outer, remote_port, fqdnStr, &err);
+ MACHRETRYLOOP_END(kr, retry, err, fin);
+fin:
+ return err;
+}
+
+void mDNSSendWakeupPacket(unsigned ifid, char *eth_addr, char *ip_addr, int iteration)
+{
+ char *ip_addr_copy = NULL;
+ char *eth_addr_copy = NULL;
+
+ if (eth_addr)
+ {
+ int len = strlen(eth_addr);
+ eth_addr_copy = mDNSPlatformMemAllocate(len + 1);
+ if (!eth_addr_copy)
+ {
+ LogMsg("mDNSSendWakeupPacket: eth_addr_copy NULL for %s", eth_addr);
+ return;
+ }
+ mDNSPlatformMemCopy(eth_addr_copy, eth_addr, len);
+ eth_addr_copy[len] = 0;
+ }
+ if (ip_addr)
+ {
+ int len = strlen(ip_addr);
+ ip_addr_copy = mDNSPlatformMemAllocate(len + 1);
+ if (!ip_addr_copy)
+ {
+ LogMsg("mDNSSendWakeupPacket: ip_addr_copy NULL for %s", ip_addr);
+ return;
+ }
+ mDNSPlatformMemCopy(ip_addr_copy, ip_addr, len);
+ ip_addr_copy[len] = 0;
+ }
+ dispatch_async(HelperQueue, ^{
+
+ kern_return_t kr = KERN_SUCCESS;
+ int retry = 0, err = 0;
+
+ LogInfo("%s: Entered ethernet address %s, ip address %s", __func__, eth_addr_copy, ip_addr_copy);
+
+ MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+ kr = proxy_mDNSSendWakeupPacket(getHelperPort(retry), ifid, eth_addr_copy, ip_addr_copy, iteration);
+ MACHRETRYLOOP_END(kr, retry, err, fin);
+fin:
+ if (eth_addr_copy)
+ mDNSPlatformMemFree(eth_addr_copy);
+ if (ip_addr_copy)
+ mDNSPlatformMemFree(ip_addr_copy);
+ (void) err;
+ });
+}
+
+void mDNSPacketFilterControl(uint32_t command, char * ifname, uint32_t count, pfArray_t portArray, pfArray_t protocolArray)
+{
+ struct
+ {
+ pfArray_t portArray;
+ pfArray_t protocolArray;
+ } pfa;
+ char *ifnameCopy = NULL;
+
+ mDNSPlatformMemCopy(pfa.portArray, portArray, sizeof(pfArray_t));
+ mDNSPlatformMemCopy(pfa.protocolArray, protocolArray, sizeof(pfArray_t));
+ if (ifname)
+ {
+ int len = strlen(ifname);
+ ifnameCopy = mDNSPlatformMemAllocate(len + 1);
+ if (!ifnameCopy)
+ {
+ LogMsg("mDNSPacketFilterControl: ifnameCopy NULL");
+ return;
+ }
+ mDNSPlatformMemCopy(ifnameCopy, ifname, len);
+ ifnameCopy[len] = 0;
+ }
+ dispatch_async(HelperQueue, ^{
+
+ kern_return_t kr = KERN_SUCCESS;
+ int retry = 0, err = 0;
+
+ LogInfo("%s, ifname %s", __func__, ifnameCopy);
+
+ MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+ kr = proxy_mDNSPacketFilterControl(getHelperPort(retry), command, ifnameCopy, count, (uint16_t *)pfa.portArray, (uint16_t *)pfa.protocolArray);
+ MACHRETRYLOOP_END(kr, retry, err, fin);
+fin:
+ if (ifnameCopy)
+ mDNSPlatformMemFree(ifnameCopy);
+ (void) err;
+ });
+}
+
+void mDNSSendKeepalive(v6addr_t sadd, v6addr_t dadd, uint16_t lport, uint16_t rport, unsigned seq, unsigned ack, uint16_t win)
+{
+ struct
+ {
+ v6addr_t sadd;
+ v6addr_t dadd;
+ } addr;
+
+ mDNSPlatformMemCopy(addr.sadd, sadd, sizeof(v6addr_t));
+ mDNSPlatformMemCopy(addr.dadd, dadd, sizeof(v6addr_t));
+
+ dispatch_async(HelperQueue, ^{
+
+ kern_return_t kr = KERN_FAILURE;
+ int retry = 0, err = 0;
+ char buf1[INET6_ADDRSTRLEN];
+ char buf2[INET6_ADDRSTRLEN];
+
+ buf1[0] = 0;
+ buf2[0] = 0;
+
+ inet_ntop(AF_INET6, addr.sadd, buf1, sizeof(buf1));
+ inet_ntop(AF_INET6, addr.dadd, buf2, sizeof(buf2));
+ LogInfo("%s: sadd is %s, dadd is %s", __func__, buf1, buf2);
+
+ MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+ kr = proxy_mDNSSendKeepalive(getHelperPort(retry), (uint8_t *)addr.sadd, (uint8_t *)addr.dadd, lport, rport, seq, ack, win);
+ MACHRETRYLOOP_END(kr, retry, err, fin);
+fin:
+ (void) err;
+ });
+}
+
+int mDNSRetrieveTCPInfo(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)
+{
+ kern_return_t kr = KERN_FAILURE;
+ int retry = 0, err = 0;
+ MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+ kr = proxy_mDNSRetrieveTCPInfo(getHelperPort(retry), family, (uint8_t *)laddr, lport, (uint8_t *)raddr, rport, seq, ack, win, intfid);
+ MACHRETRYLOOP_END(kr, retry, err, fin);
+fin:
+ return err;
+}
+
+void mDNSGetRemoteMAC(mDNS *const m, int family, v6addr_t raddr)
+{
+ struct {
+ v6addr_t addr;
+ } dst;
+
+ mDNSPlatformMemCopy(dst.addr, raddr, sizeof(v6addr_t));
+ dispatch_async(HelperQueue, ^{
+ kern_return_t kr = KERN_FAILURE;
+ int retry = 0, err = 0;
+ ethaddr_t eth;
+ IPAddressMACMapping *addrMapping;
+
+ MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+ kr = proxy_mDNSGetRemoteMAC(getHelperPort(retry), family, (uint8_t *)dst.addr, eth);
+ MACHRETRYLOOP_END(kr, retry, err, fin);
+ // If the call to get the remote MAC address succeeds, allocate and copy
+ // the values and schedule a task to update the MAC address in the TCP Keepalive record.
+ if (kr == KERN_SUCCESS)
+ {
+ addrMapping = (IPAddressMACMapping *)malloc(sizeof(IPAddressMACMapping));
+ snprintf(addrMapping->ethaddr, sizeof(addrMapping->ethaddr), "%02x:%02x:%02x:%02x:%02x:%02x",
+ eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
+ if (family == AF_INET)
+ {
+ addrMapping->ipaddr.type = mDNSAddrType_IPv4;
+ mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v4.b, dst.addr, sizeof(v6addr_t));
+ }
+ else
+ {
+ addrMapping->ipaddr.type = mDNSAddrType_IPv6;
+ mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v6.b, dst.addr, sizeof(v6addr_t));
+ }
+ mDNSPlatformDispatchAsync(m, addrMapping, UpdateRMACCallback);
+ }
+fin:
+ (void) err;
+ });
+
+}
+
+void mDNSStoreSPSMACAddress(int family, v6addr_t spsaddr, char *ifname)
+{
+ struct {
+ v6addr_t saddr;
+ } addr;
+ mDNSPlatformMemCopy(addr.saddr, spsaddr, sizeof(v6addr_t));
+
+ dispatch_async(HelperQueue, ^{
+ kern_return_t kr = KERN_FAILURE;
+ int retry = 0, err = 0;
+ MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
+ kr = proxy_mDNSStoreSPSMACAddress(getHelperPort(retry), family, (uint8_t *)addr.saddr, ifname);
+ MACHRETRYLOOP_END(kr, retry, err, fin);
+fin:
+ (void)err;
+ });
+}
diff --git a/mDNSResponder/mDNSMacOSX/helper.c b/mDNSResponder/mDNSMacOSX/helper.c
new file mode 100644
index 00000000..0251e709
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/helper.c
@@ -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;
+}
diff --git a/mDNSResponder/mDNSMacOSX/helper.h b/mDNSResponder/mDNSMacOSX/helper.h
new file mode 100644
index 00000000..a2982372
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/helper.h
@@ -0,0 +1,84 @@
+/* -*- 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.
+ */
+
+#ifndef H_HELPER_H
+#define H_HELPER_H
+
+#define kmDNSHelperServiceName "com.apple.mDNSResponderHelper"
+
+enum mDNSPreferencesSetNameKey
+{
+ kmDNSComputerName = 1,
+ kmDNSLocalHostName
+};
+
+enum mDNSUpDown
+{
+ kmDNSUp = 1,
+ kmDNSDown
+};
+
+enum mDNSAutoTunnelSetKeysReplaceDelete
+{
+ kmDNSAutoTunnelSetKeysReplace = 1,
+ kmDNSAutoTunnelSetKeysDelete
+};
+
+// helper parses the system keychain and returns the information to mDNSResponder.
+// It returns four attributes. Attributes are defined after how they show up in
+// keychain access utility (the actual attribute name to retrieve these are different).
+enum mDNSKeyChainAttributes
+{
+ kmDNSKcWhere, // Where
+ kmDNSKcAccount, // Account
+ kmDNSKcKey, // Key
+ kmDNSKcName // Name
+};
+
+#define ERROR(x, y) x,
+enum mDNSHelperErrors
+{
+ mDNSHelperErrorBase = 2300,
+ #include "helper-error.h"
+ mDNSHelperErrorEnd
+};
+#undef ERROR
+
+#include "mDNSEmbeddedAPI.h"
+#include "helpermsg-types.h"
+
+extern const char *mDNSHelperError(int errornum);
+
+extern mStatus mDNSHelperInit(void);
+extern void mDNSRequestBPF(void);
+extern int mDNSPowerRequest(int key, int interval);
+extern int mDNSSetLocalAddressCacheEntry(int ifindex, int family, const v6addr_t ip, const ethaddr_t eth);
+extern void mDNSNotify(const char *title, const char *msg); // Both strings are UTF-8 text
+extern void mDNSPreferencesSetName(int key, domainlabel *old, domainlabel *new);
+extern int mDNSKeychainGetSecrets(CFArrayRef *secrets);
+extern void mDNSConfigureServer(int updown, const char *const prefix, const domainname *const fqdn);
+extern int mDNSAutoTunnelSetKeys(int replacedelete, v6addr_t local_inner,
+ v6addr_t local_outer, short local_port, v6addr_t remote_inner,
+ v6addr_t remote_outer, short remote_port, const char *const prefix, const domainname *const fqdn);
+extern void mDNSSendWakeupPacket(unsigned ifid, char *eth_addr, char *ip_addr, int iteration);
+extern void mDNSPacketFilterControl(uint32_t command, char * ifname, uint32_t count, pfArray_t portArray, pfArray_t protocolArray);
+extern void mDNSSendKeepalive(v6addr_t sadd, v6addr_t dadd, uint16_t lport, uint16_t rport, unsigned seq, unsigned ack, uint16_t win);
+extern int mDNSRetrieveTCPInfo(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);
+extern void mDNSGetRemoteMAC(mDNS *const m, int family, v6addr_t raddr);
+extern void mDNSStoreSPSMACAddress(int family, v6addr_t spsaddr, char *ifname);
+
+#endif /* H_HELPER_H */
diff --git a/mDNSResponder/mDNSMacOSX/helpermsg-types.h b/mDNSResponder/mDNSMacOSX/helpermsg-types.h
new file mode 100644
index 00000000..ca5b140a
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/helpermsg-types.h
@@ -0,0 +1,30 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2007 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.
+ */
+
+#ifndef H_HELPERMSG_TYPES_H
+#define H_HELPERMSG_TYPES_H
+
+#include <stdint.h>
+typedef uint8_t v4addr_t [ 4];
+typedef uint8_t ethaddr_t[ 6];
+typedef uint8_t v6addr_t [16];
+typedef const char *string_t;
+
+#define PFPortArraySize 16
+typedef uint16_t pfArray_t [PFPortArraySize];
+
+#endif /* H_HELPERMSG_TYPES_H */
diff --git a/mDNSResponder/mDNSMacOSX/helpermsg.defs b/mDNSResponder/mDNSMacOSX/helpermsg.defs
new file mode 100644
index 00000000..58363082
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/helpermsg.defs
@@ -0,0 +1,143 @@
+/* -*- 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 <mach/std_types.defs>
+#include <mach/mach_types.defs>
+
+import "helpermsg-types.h";
+
+type v4addr_t = array [ 4] of uint8_t;
+type ethaddr_t = array [ 6] of uint8_t;
+type v6addr_t = array [16] of uint8_t;
+type string_t = c_string[*:1024];
+
+// Mig doesn't generate the output file if I use the constant PFPortArraySize below
+type pfArray_t = array [16] of uint16_t;
+
+subsystem helper 1833193043;
+serverprefix do_;
+userprefix proxy_;
+
+simpleroutine mDNSExit( port : mach_port_t;
+ ServerAuditToken token : audit_token_t);
+
+simpleroutine mDNSRequestBPF( port : mach_port_t;
+ ServerAuditToken token : audit_token_t);
+
+routine mDNSPowerRequest( port : mach_port_t;
+ key : int;
+ interval : int;
+ out err : int;
+ ServerAuditToken token : audit_token_t);
+
+routine mDNSSetLocalAddressCacheEntry(
+ port : mach_port_t;
+ ifindex : int;
+ family : int;
+ ip : v6addr_t;
+ eth : ethaddr_t;
+ out err : int;
+ ServerAuditToken token : audit_token_t);
+
+simpleroutine mDNSNotify( port : mach_port_t;
+ title : string_t;
+ msg : string_t;
+ ServerAuditToken token : audit_token_t);
+
+simpleroutine mDNSPreferencesSetName(
+ port : mach_port_t;
+ key : int;
+ old : string_t;
+ new : string_t;
+ ServerAuditToken token : audit_token_t);
+
+routine mDNSKeychainGetSecrets( port : mach_port_t;
+ out numsecrets : unsigned;
+ out secrets : pointer_t;
+ out err : int;
+ ServerAuditToken token : audit_token_t);
+
+simpleroutine mDNSConfigureServer(
+ port : mach_port_t;
+ updown : int;
+ id : string_t;
+ ServerAuditToken token : audit_token_t);
+
+routine mDNSAutoTunnelSetKeys( port : mach_port_t;
+ replacedelete : int;
+ local_inner : v6addr_t;
+ local_outer : v6addr_t;
+ local_port : uint16_t; /* Port expressed as a numeric integer value */
+ remote_inner : v6addr_t;
+ remote_outer : v6addr_t;
+ remote_port : uint16_t; /* Port expressed as a numeric integer value */
+ id : string_t;
+ out err : int;
+ ServerAuditToken token : audit_token_t);
+
+simpleroutine mDNSSendWakeupPacket(
+ port : mach_port_t;
+ ifid : unsigned;
+ eth_addr : string_t;
+ ip_addr : string_t;
+ iteration : int;
+ ServerAuditToken token : audit_token_t);
+
+simpleroutine mDNSPacketFilterControl(
+ port : mach_port_t;
+ command : uint32_t;
+ ifname : string_t;
+ arraySize : uint32_t;
+ portArray : pfArray_t;
+ protocolArray : pfArray_t;
+ ServerAuditToken token : audit_token_t);
+
+
+simpleroutine mDNSSendKeepalive( port : mach_port_t;
+ sadd : v6addr_t;
+ dadd : v6addr_t;
+ lport : uint16_t;
+ rport : uint16_t;
+ seq : unsigned;
+ ack : unsigned;
+ win : uint16_t;
+ ServerAuditToken token : audit_token_t);
+
+routine mDNSRetrieveTCPInfo(
+ port : mach_port_t;
+ family : int;
+ laddr : v6addr_t;
+ lport : uint16_t;
+ raddr : v6addr_t;
+ rport : uint16_t;
+ out seq : uint32_t;
+ out ack : uint32_t;
+ out win : uint16_t;
+ out intfid : int32_t;
+ ServerAuditToken token : audit_token_t);
+
+routine mDNSGetRemoteMAC( port : mach_port_t;
+ family : int;
+ raddr : v6addr_t;
+ out eth : ethaddr_t;
+ ServerAuditToken token : audit_token_t);
+
+simpleroutine mDNSStoreSPSMACAddress( port : mach_port_t;
+ family : int;
+ spsaddr : v6addr_t;
+ ifname : string_t;
+ ServerAuditToken token : audit_token_t);
diff --git a/mDNSResponder/mDNSMacOSX/ipsec_strerror.h b/mDNSResponder/mDNSMacOSX/ipsec_strerror.h
new file mode 100644
index 00000000..ecacf3b2
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/ipsec_strerror.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2003-2007 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.
+ */
+/* $FreeBSD: src/lib/libipsec/ipsec_strerror.h,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $ */
+/* $KAME: ipsec_strerror.h,v 1.8 2000/07/30 00:45:12 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * 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 the project 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 THE PROJECT AND 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 THE PROJECT OR 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.
+ */
+
+extern int __ipsec_errcode;
+extern void __ipsec_set_strerror __P((const char *));
+
+#define EIPSEC_NO_ERROR 0 /*success*/
+#define EIPSEC_NOT_SUPPORTED 1 /*not supported*/
+#define EIPSEC_INVAL_ARGUMENT 2 /*invalid argument*/
+#define EIPSEC_INVAL_SADBMSG 3 /*invalid sadb message*/
+#define EIPSEC_INVAL_VERSION 4 /*invalid version*/
+#define EIPSEC_INVAL_POLICY 5 /*invalid security policy*/
+#define EIPSEC_INVAL_ADDRESS 6 /*invalid address specification*/
+#define EIPSEC_INVAL_PROTO 7 /*invalid ipsec protocol*/
+#define EIPSEC_INVAL_MODE 8 /*Invalid ipsec mode*/
+#define EIPSEC_INVAL_LEVEL 9 /*invalid ipsec level*/
+#define EIPSEC_INVAL_SATYPE 10 /*invalid SA type*/
+#define EIPSEC_INVAL_MSGTYPE 11 /*invalid message type*/
+#define EIPSEC_INVAL_EXTTYPE 12 /*invalid extension type*/
+#define EIPSEC_INVAL_ALGS 13 /*Invalid algorithm type*/
+#define EIPSEC_INVAL_KEYLEN 14 /*invalid key length*/
+#define EIPSEC_INVAL_FAMILY 15 /*invalid address family*/
+#define EIPSEC_INVAL_PREFIXLEN 16 /*SPI range violation*/
+#define EIPSEC_INVAL_DIR 17 /*Invalid direciton*/
+#define EIPSEC_INVAL_SPI 18 /*invalid prefixlen*/
+#define EIPSEC_NO_PROTO 19 /*no protocol specified*/
+#define EIPSEC_NO_ALGS 20 /*No algorithm specified*/
+#define EIPSEC_NO_BUFS 21 /*no buffers available*/
+#define EIPSEC_DO_GET_SUPP_LIST 22 /*must get supported algorithm first*/
+#define EIPSEC_PROTO_MISMATCH 23 /*protocol mismatch*/
+#define EIPSEC_FAMILY_MISMATCH 24 /*family mismatch*/
+#define EIPSEC_FEW_ARGUMENTS 25 /*Too few arguments*/
+#define EIPSEC_SYSTEM_ERROR 26 /*system error*/
+#define EIPSEC_MAX 27 /*unknown error*/
diff --git a/mDNSResponder/mDNSMacOSX/libpfkey.h b/mDNSResponder/mDNSMacOSX/libpfkey.h
new file mode 100644
index 00000000..98d192d8
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/libpfkey.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2003-2007 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.
+ */
+/* $FreeBSD: src/lib/libipsec/libpfkey.h,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $ */
+/* $KAME: libpfkey.h,v 1.6 2001/03/05 18:22:17 thorpej Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * 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 the project 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 THE PROJECT AND 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 THE PROJECT OR 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.
+ */
+
+struct sadb_msg;
+extern void pfkey_sadump __P((struct sadb_msg *));
+extern void pfkey_spdump __P((struct sadb_msg *));
+
+struct sockaddr;
+struct sadb_alg;
+int ipsec_check_keylen __P((u_int, u_int, u_int));
+int ipsec_check_keylen2 __P((u_int, u_int, u_int));
+int ipsec_get_keylen __P((u_int, u_int, struct sadb_alg *));
+u_int pfkey_set_softrate __P((u_int, u_int));
+u_int pfkey_get_softrate __P((u_int));
+int pfkey_send_getspi __P((int, u_int, u_int, struct sockaddr *,
+ struct sockaddr *, u_int32_t, u_int32_t, u_int32_t, u_int32_t));
+int pfkey_send_update __P((int, u_int, u_int, struct sockaddr *,
+ struct sockaddr *, u_int32_t, u_int32_t, u_int,
+ caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t,
+ u_int64_t, u_int64_t, u_int32_t));
+int pfkey_send_add __P((int, u_int, u_int, struct sockaddr *,
+ struct sockaddr *, u_int32_t, u_int32_t, u_int,
+ caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t,
+ u_int64_t, u_int64_t, u_int32_t));
+int pfkey_send_delete __P((int, u_int, u_int,
+ struct sockaddr *, struct sockaddr *, u_int32_t));
+int pfkey_send_delete_all __P((int, u_int, u_int,
+ struct sockaddr *, struct sockaddr *));
+int pfkey_send_get __P((int, u_int, u_int,
+ struct sockaddr *, struct sockaddr *, u_int32_t));
+int pfkey_send_register __P((int, u_int));
+int pfkey_recv_register __P((int));
+int pfkey_set_supported __P((struct sadb_msg *, int));
+int pfkey_send_flush __P((int, u_int));
+int pfkey_send_dump __P((int, u_int));
+int pfkey_send_promisc_toggle __P((int, int));
+int pfkey_send_spdadd __P((int, struct sockaddr *, u_int,
+ struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
+int pfkey_send_spdadd2 __P((int, struct sockaddr *, u_int,
+ struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t,
+ caddr_t, int, u_int32_t));
+int pfkey_send_spdupdate __P((int, struct sockaddr *, u_int,
+ struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
+int pfkey_send_spdupdate2 __P((int, struct sockaddr *, u_int,
+ struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t,
+ caddr_t, int, u_int32_t));
+int pfkey_send_spddelete __P((int, struct sockaddr *, u_int,
+ struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
+int pfkey_send_spddelete2 __P((int, u_int32_t));
+int pfkey_send_spdget __P((int, u_int32_t));
+int pfkey_send_spdsetidx __P((int, struct sockaddr *, u_int,
+ struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
+int pfkey_send_spdflush __P((int));
+int pfkey_send_spddump __P((int));
+
+int pfkey_open __P((void));
+void pfkey_close __P((int));
+struct sadb_msg *pfkey_recv __P((int));
+int pfkey_send __P((int, struct sadb_msg *, int));
+int pfkey_align __P((struct sadb_msg *, caddr_t *));
+int pfkey_check __P((caddr_t *));
diff --git a/mDNSResponder/mDNSMacOSX/mDNSMacOSX.c b/mDNSResponder/mDNSMacOSX/mDNSMacOSX.c
new file mode 100644
index 00000000..fda595c9
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/mDNSMacOSX.c
@@ -0,0 +1,10442 @@
+/* -*- 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;
+ // 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@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@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@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);
+}
diff --git a/mDNSResponder/mDNSMacOSX/mDNSMacOSX.h b/mDNSResponder/mDNSMacOSX/mDNSMacOSX.h
new file mode 100644
index 00000000..00bfb87c
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/mDNSMacOSX.h
@@ -0,0 +1,295 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002-2003 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.
+ */
+
+#ifndef __mDNSMacOSX_h
+#define __mDNSMacOSX_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <SystemConfiguration/SystemConfiguration.h>
+#include <IOKit/pwr_mgt/IOPM.h>
+#include <IOKit/pwr_mgt/IOPMLib.h>
+#include <IOKit/pwr_mgt/IOPMLibPrivate.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include "mDNSEmbeddedAPI.h" // for domain name structure
+
+#include <net/if.h>
+
+//#define MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+#include <dispatch/dispatch.h>
+#include <dispatch/private.h>
+#endif
+
+#if TARGET_OS_EMBEDDED
+#define NO_SECURITYFRAMEWORK 1
+#define NO_CFUSERNOTIFICATION 1
+#include <MobileGestalt.h> // for IsAppleTV()
+#include <SystemConfiguration/scprefs_observer.h> // for _scprefs_observer_watch()
+extern mDNSBool GetmDNSManagedPref(CFStringRef key);
+#endif
+
+#ifndef NO_SECURITYFRAMEWORK
+#include <Security/SecureTransport.h>
+#include <Security/Security.h>
+#endif /* NO_SECURITYFRAMEWORK */
+
+#if TARGET_OS_IPHONE
+#include "cellular_usage_policy.h"
+#endif
+
+#define kmDNSResponderServName "com.apple.mDNSResponder"
+
+enum mDNSDynamicStoreSetConfigKey
+{
+ kmDNSMulticastConfig = 1,
+ kmDNSDynamicConfig,
+ kmDNSPrivateConfig,
+ kmDNSBackToMyMacConfig,
+ kmDNSSleepProxyServersState,
+ kmDNSDebugState,
+};
+
+typedef struct NetworkInterfaceInfoOSX_struct NetworkInterfaceInfoOSX;
+
+typedef void (*KQueueEventCallback)(int fd, short filter, void *context);
+typedef struct
+{
+ KQueueEventCallback KQcallback;
+ void *KQcontext;
+ const char *KQtask; // For debugging messages
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+ dispatch_source_t readSource;
+ dispatch_source_t writeSource;
+ mDNSBool fdClosed;
+#endif
+} KQueueEntry;
+
+typedef struct
+{
+ mDNSIPPort port; // MUST BE FIRST FIELD -- UDPSocket_struct begins with a KQSocketSet,
+ // and mDNSCore requires every UDPSocket_struct to begin with a mDNSIPPort port
+ mDNS *m;
+ int sktv4;
+ KQueueEntry kqsv4;
+ int sktv6;
+ KQueueEntry kqsv6;
+ int *closeFlag;
+ mDNSBool proxy;
+} KQSocketSet;
+
+struct UDPSocket_struct
+{
+ KQSocketSet ss; // First field of KQSocketSet has to be mDNSIPPort -- mDNSCore requires every UDPSocket_struct to begin with mDNSIPPort port
+};
+
+// TCP socket support
+
+typedef enum
+{
+ handshake_required,
+ handshake_in_progress,
+ handshake_completed,
+ handshake_to_be_closed
+} handshakeStatus;
+
+struct TCPSocket_struct
+{
+ TCPSocketFlags flags; // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
+ TCPConnectionCallback callback;
+ int fd;
+ KQueueEntry *kqEntry;
+ KQSocketSet ss;
+#ifndef NO_SECURITYFRAMEWORK
+ SSLContextRef tlsContext;
+ pthread_t handshake_thread;
+#endif /* NO_SECURITYFRAMEWORK */
+ domainname hostname;
+ void *context;
+ mDNSBool setup;
+ mDNSBool connected;
+ handshakeStatus handshake;
+ mDNS *m; // So we can call KQueueLock from the SSLHandshake thread
+ mStatus err;
+};
+
+struct NetworkInterfaceInfoOSX_struct
+{
+ NetworkInterfaceInfo ifinfo; // MUST be the first element in this structure
+ NetworkInterfaceInfoOSX *next;
+ mDNS *m;
+ mDNSu8 Exists; // 1 = currently exists in getifaddrs list; 0 = doesn't
+ // 2 = exists, but McastTxRx state changed
+ mDNSu8 Flashing; // Set if interface appeared for less than 60 seconds and then vanished
+ mDNSu8 Occulting; // Set if interface vanished for less than 60 seconds and then came back
+ mDNSu8 D2DInterface; // IFEF_LOCALNET_PRIVATE flag indicates we should call
+ // D2D plugin for operations over this interface
+ mDNSu8 DirectLink; // IFEF_DIRECTLINK flag is set for interface
+
+ mDNSs32 AppearanceTime; // Time this interface appeared most recently in getifaddrs list
+ // i.e. the first time an interface is seen, AppearanceTime is set.
+ // If an interface goes away temporarily and then comes back then
+ // AppearanceTime is updated to the time of the most recent appearance.
+ mDNSs32 LastSeen; // If Exists==0, last time this interface appeared in getifaddrs list
+ unsigned int ifa_flags;
+ struct in_addr ifa_v4addr;
+ mDNSu32 scope_id; // interface index / IPv6 scope ID
+ mDNSEthAddr BSSID; // BSSID of 802.11 base station, if applicable
+ u_short sa_family;
+ int BPF_fd; // -1 uninitialized; -2 requested BPF; -3 failed
+ int BPF_mcfd; // Socket for our IPv6 ND group membership
+ u_int BPF_len;
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+ dispatch_source_t BPF_source;
+#else
+ CFSocketRef BPF_cfs;
+ CFRunLoopSourceRef BPF_rls;
+#endif
+ NetworkInterfaceInfoOSX *Registered; // non-NULL means registered with mDNS Core
+};
+
+struct mDNS_PlatformSupport_struct
+{
+ NetworkInterfaceInfoOSX *InterfaceList;
+ KQSocketSet permanentsockets;
+ domainlabel userhostlabel; // The hostlabel as it was set in System Preferences the last time we looked
+ domainlabel usernicelabel; // The nicelabel as it was set in System Preferences the last time we looked
+ // Following four variables are used for optimization where the helper is not
+ // invoked when not needed. It records the state of what we told helper the
+ // last time we invoked mDNSPreferencesSetName
+ domainlabel prevoldhostlabel; // Previous m->p->userhostlabel
+ domainlabel prevnewhostlabel; // Previous m->hostlabel
+ domainlabel prevoldnicelabel; // Previous m->p->usernicelabel
+ domainlabel prevnewnicelabel; // Previous m->nicelabel
+ mDNSs32 NotifyUser;
+ mDNSs32 HostNameConflict; // Time we experienced conflict on our link-local host name
+ mDNSs32 NetworkChanged;
+ mDNSs32 KeyChainTimer;
+
+ CFRunLoopRef CFRunLoop;
+ SCDynamicStoreRef Store;
+ CFRunLoopSourceRef StoreRLS;
+ CFRunLoopSourceRef PMRLS;
+ int SysEventNotifier;
+ KQueueEntry SysEventKQueue;
+ IONotificationPortRef PowerPortRef;
+ io_connect_t PowerConnection;
+ io_object_t PowerNotifier;
+#ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements
+ IOPMConnection IOPMConnection;
+#endif
+ IOPMAssertionID IOPMAssertion;
+ long SleepCookie; // Cookie we need to pass to IOAllowPowerChange()
+ long WakeAtUTC;
+ mDNSs32 RequestReSleep;
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+ dispatch_source_t timer;
+ dispatch_source_t custom;
+#else
+ pthread_mutex_t BigMutex;
+#endif
+ mDNSs32 BigMutexStartTime;
+ int WakeKQueueLoopFD;
+ mDNSu8 v4answers; // non-zero if we are receiving answers
+ mDNSu8 v6answers; // for A/AAAA from external DNS servers
+ mDNSs32 DNSTrigger; // Time the DNSTrigger was given
+ uint64_t LastConfigGeneration; // DNS configuration generation number
+ UDPSocket UDPProxy;
+ TCPSocket TCPProxy;
+ ProxyCallback *UDPProxyCallback;
+ ProxyCallback *TCPProxyCallback;
+#if TARGET_OS_IPHONE
+ cellular_usage_policy_client_t handle;
+#endif
+};
+
+extern int OfferSleepProxyService;
+extern int DisableSleepProxyClient;
+extern int UseInternalSleepProxy;
+extern int OSXVers, iOSVers;
+
+extern int KQueueFD;
+
+extern void NotifyOfElusiveBug(const char *title, const char *msg); // Both strings are UTF-8 text
+extern void SetDomainSecrets(mDNS *m);
+extern void mDNSMacOSXNetworkChanged(mDNS *const m);
+extern void mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring);
+extern NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(const mDNS *const m, mDNSInterfaceID ifindex);
+extern void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord);
+extern void myKQSocketCallBack(int s1, short filter, void *context);
+extern void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropertyListRef value);
+extern void UpdateDebugState(void);
+
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+extern int KQueueSet(int fd, u_short flags, short filter, KQueueEntry *const entryRef);
+mDNSexport void TriggerEventCompletion(void);
+#else
+extern int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef);
+#endif
+
+// When events are processed on the non-kqueue thread (i.e. CFRunLoop notifications like Sleep/Wake,
+// Interface changes, Keychain changes, etc.) they must use KQueueLock/KQueueUnlock to lock out the kqueue thread
+extern void KQueueLock(mDNS *const m);
+extern void KQueueUnlock(mDNS *const m, const char* task);
+extern void mDNSPlatformCloseFD(KQueueEntry *kq, int fd);
+extern 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, mDNSu8 *ttl);
+
+extern mDNSBool DictionaryIsEnabled(CFDictionaryRef dict);
+
+extern void CUPInit(mDNS *const m);
+extern const char *DNSScopeToString(mDNSu32 scope);
+
+// If any event takes more than WatchDogReportingThreshold milliseconds to be processed, we log a warning message
+// General event categories are:
+// o Mach client request initiated / terminated
+// o UDS client request
+// o Handling UDP packets received from the network
+// o Environmental change events:
+// - network interface changes
+// - sleep/wake
+// - keychain changes
+// o Name conflict dialog dismissal
+// o Reception of Unix signal (e.g. SIGINFO)
+// o Idle task processing
+// If we find that we're getting warnings for any of these categories, and it's not evident
+// what's causing the problem, we may need to subdivide some categories into finer-grained
+// sub-categories (e.g. "Idle task processing" covers a pretty broad range of sub-tasks).
+
+extern int WatchDogReportingThreshold;
+
+struct CompileTimeAssertionChecks_mDNSMacOSX
+{
+ // Check our structures are reasonable sizes. Including overly-large buffers, or embedding
+ // other overly-large structures instead of having a pointer to them, can inadvertently
+ // cause structure sizes (and therefore memory usage) to balloon unreasonably.
+
+ // Checks commented out when sizeof(DNSQuestion) change cascaded into having to change yet another
+ // set of hardcoded size values because these structures contain one or more DNSQuestion
+ // instances.
+// char sizecheck_NetworkInterfaceInfoOSX[(sizeof(NetworkInterfaceInfoOSX) <= 7084) ? 1 : -1];
+ char sizecheck_mDNS_PlatformSupport [(sizeof(mDNS_PlatformSupport) <= 1378) ? 1 : -1];
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mDNSResponder/mDNSMacOSX/mDNSResponder-bundle/Resources/English.lproj/Localizable.strings b/mDNSResponder/mDNSMacOSX/mDNSResponder-bundle/Resources/English.lproj/Localizable.strings
new file mode 100644
index 00000000..7b88ff90
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/mDNSResponder-bundle/Resources/English.lproj/Localizable.strings
@@ -0,0 +1,13 @@
+"The name of your computer " = "The name of your computer ";
+"This computer’s local hostname " = "This computer’s local hostname ";
+"“" = "“";
+"”" = "”";
+" is already in use on this network. " = " is already in use on this network. ";
+"The name has been changed to " = "The name has been changed to ";
+"." = ".";
+
+"To change the name of your computer, open System Preferences and click Sharing, then type the name in the Computer Name field." = "To change the name of your computer, open System Preferences and click Sharing, then type the name in the Computer Name field.";
+"To change the local hostname, open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field." = "To change the local hostname, open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field.";
+
+"All attempts to find an available name by adding a number to the name were also unsuccessful." = "All attempts to find an available name by adding a number to the name were also unsuccessful.";
+"This may indicate a problem with the local network. Please inform your network administrator." = "This may indicate a problem with the local network. Please inform your network administrator.";
diff --git a/mDNSResponder/mDNSMacOSX/mDNSResponder-bundle/Resources/French.lproj/Localizable.strings b/mDNSResponder/mDNSMacOSX/mDNSResponder-bundle/Resources/French.lproj/Localizable.strings
new file mode 100644
index 00000000..453d5560
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/mDNSResponder-bundle/Resources/French.lproj/Localizable.strings
@@ -0,0 +1,13 @@
+"The name of your computer " = "Le nom de l’ordinateur ";
+"This computer’s local hostname " = "Le nom d’hôte local de cet ordinateur ";
+"“" = "“";
+"”" = "”";
+" is already in use on this network. " = " est déjà utilié sur ce réseau. ";
+"The name has been changed to " = "Le nom a été changé pa ";
+"." = ".";
+
+"To change the name of your computer, open System Preferences and click Sharing, then type the name in the Computer Name field." = "Pour changer le nom de votre ordinateur, ouvrez Préférences Systèmes et cliquer Partage. Ensuite entrez le nom dans le champ Nom de l’ordinateur.";
+"To change the local hostname, open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field." = "Pour changer le nom d’hôte local, ouvrez Préférences Systèmes et cliquer Partage. Ensuite cliquer Modifier et entrez le nom dans le champ Nom local de l’ordinateur.";
+
+"All attempts to find an available name by adding a number to the name were also unsuccessful." = "Toutes les tentatives de trouver un nom disponible en ajoutant un nombre au nom étaient également non réussies.";
+"This may indicate a problem with the local network. Please inform your network administrator." = "Ceci peut indiquer un problème avec le réseau local. Veuillez informer votre administrateur de réseau.";
diff --git a/mDNSResponder/mDNSMacOSX/mDNSResponder-entitlements.plist b/mDNSResponder/mDNSMacOSX/mDNSResponder-entitlements.plist
new file mode 100644
index 00000000..bb3f05e8
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/mDNSResponder-entitlements.plist
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.wifi.manager-access</key>
+ <true/>
+ <key>com.apple.SystemConfiguration.trailing-edge-agent</key>
+ <true/>
+ <key>com.apple.private.network.socket-delegate</key>
+ <true/>
+ <key>com.apple.networkd.cellular_blocked.notify</key>
+ <true/>
+ <key>com.apple.private.SCNetworkConnection-proxy-user</key>
+ <true/>
+ <key>com.apple.private.network.reserved-port</key>
+ <true/>
+ <key>com.apple.SystemConfiguration.SCDynamicStore-write-access</key>
+ <true/>
+ <key>com.apple.private.snhelper</key>
+ <true/>
+ <key>com.apple.telephony.cupolicy-monitor-access</key>
+ <true/>
+</dict>
+</plist>
diff --git a/mDNSResponder/mDNSMacOSX/mDNSResponder.order b/mDNSResponder/mDNSMacOSX/mDNSResponder.order
new file mode 100644
index 00000000..55cfd6fe
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/mDNSResponder.order
@@ -0,0 +1,314 @@
+_start
+__start
+_dyld_stub_binding_helper
+__dyld_func_lookup
+_main
+_LogMsgWithLevel
+_mDNS_vsnprintf
+_mDNSPlatformWriteLogMsg
+_KQueueSet
+_mDNSMacOSXSystemBuildNumber
+_mDNSDaemonInitialize
+_mDNS_Init
+_mDNSPlatformTimeInit
+_mDNSRandom
+_mDNSPlatformRandomNumber
+_mDNSPlatformRawTime
+_mDNSPlatformInit
+_mDNS_snprintf
+_GetUserSpecifiedLocalHostName
+_SetupSocket
+_SystemWakeForNetworkAccess
+_UpdateInterfaceList
+_myGetIfAddrs
+_AddInterfaceToList
+_SetupAddr
+_NetWakeInterface
+_mDNS_SetFQDN
+_AppendDomainLabel
+_AppendLiteralLabelString
+_mDNS_Lock_
+_mDNSPlatformLock
+_SameDomainNameCS
+_DomainNameLengthLimit
+_mDNSPlatformMemCopy
+_mDNS_Unlock_
+_mDNSPlatformUnlock
+_SetupActiveInterfaces
+_SearchForInterfaceByName
+_mDNS_RegisterInterface
+_AdvertiseInterface
+_mDNS_SetupResourceRecord
+_MakeDomainNameFromDNSNameString
+_AppendDNSNameString
+_mDNS_Register_internal
+_InitializeLastAPTime
+_SetNextAnnounceProbeTime
+_GetRDLength
+_ValidateRData
+_DomainNameHashValue
+_RDataHashValue
+_SetTargetToHostName
+_SameDomainName
+_SetNewRData
+_CompressedDomainNameLength
+_AcknowledgeRecord
+_mDNS_StartBrowse_internal
+_ConstructServiceName
+_AppendDomainName
+_mDNS_StartQuery_internal
+_IsLocalDomain
+_CheckForSoonToExpireRecords
+_GetAuthInfoForQuestion
+_GetAuthInfoForName_internal
+_FindDuplicateQuestion
+_SetNextQueryTime
+_SetDomainSecrets
+_mDNSKeychainGetSecrets
+_getHelperPort
+_proxy_mDNSKeychainGetSecrets
+_mDNS_SetSecretForDomain
+_DNSDigest_ConstructHMACKeyfromBase64
+_mDNSPlatformMemZero
+_UpdateAutoTunnelDomainStatus
+_ConvertDomainLabelToCString_withescape
+_mDNSASLLog
+_mDNSDynamicStoreSetConfig
+_proxy_mDNSDynamicStoreSetConfig
+_ConvertDomainNameToCString_withescape
+_UpdateConfigureServer
+_TunnelServers
+_mDNSCoreInitComplete
+_mDNS_StatusCallback
+_mDNSPlatformMemSame
+_uDNS_SetupDNSConfig
+_mDNSPlatformSetDNSConfig
+_dns_configuration_copy
+___dns_initialize
+__dns_configuration_server_port
+_shared_dns_infoGet
+_CountLabels
+_SkipLeadingLabels
+_dns_configuration_free
+_mDNSPlatformGetPrimaryInterface
+_mDNS_SetPrimaryInterfaceInfo
+_udsserver_init
+_udsSupportAddFDToEventLoop
+_mDNS_GetDomains
+_mDNS_StartQuery
+_RegisterLocalOnlyDomainEnumPTR
+_mDNSPlatformMemAllocate
+_mDNS_Register
+_AddAutoBrowseDomain
+_udsserver_automatic_browse_domain_changed
+_machserver_automatic_browse_domain_changed
+_udsserver_handle_configchange
+_UpdateDeviceInfoRecord
+_AppendDNameListElem
+_SetPrefsBrowseDomains
+_udsserver_default_reg_domain_changed
+_machserver_automatic_registration_domain_changed
+_mDNSMacOSXNetworkChanged
+_mDNSSameAddress
+_ClearInactiveInterfaces
+_mDNSCoreBeSleepProxyServer
+_mDNS_ConfigChanged
+_mDNSPreferencesSetName
+_proxy_mDNSPreferencesSetName
+_SameRDataBody
+_DeregisterLocalOnlyDomainEnumPTR
+_mDNS_Deregister
+_mDNS_Deregister_internal
+_mDNSPlatformMemFree
+_RmvAutoBrowseDomain
+_KQueueLoop
+_mDNS_TimeNow
+_mDNS_Execute
+_SendQueries
+_GetFirstActiveInterface
+_InitializeDNSMessage
+_uDNS_Execute
+_mDNSv4AddrIsRFC1918
+_udsserver_idle
+_connect_callback
+_NewRequest
+_request_callback
+_ConvertHeaderBytes
+_handle_regservice_request
+_get_uint32
+_mDNSPlatformInterfaceIDfromInterfaceIndex
+_get_string
+_mDNSPlatformStrCopy
+_get_uint16
+_ChopSubTypes
+_AuthorizedDomain
+_register_service_instance
+_AllocateSubTypes
+_mDNS_RegisterService
+_ServiceCallback
+_GetServiceTarget
+_SetupLocalAutoTunnelInterface_internal
+_NetworkChanged
+_KQueueLock
+_AbortDeregistration
+_mDNS_StartNATOperation_internal
+_put_uint32
+_send_all
+_uDNS_SendNATMsg
+_KQueueUnlock
+_KQWokenFlushBytes
+_handle_queryrecord_request
+_mDNS_NewMessageID
+_GetServerForName
+_ActivateUnicastQuery
+_LastLabel
+_SameDomainLabel
+_uDNS_CheckCurrentQuestion
+_CacheGroupForName
+_MakeNegativeCacheRecord
+_CreateNewCacheEntry
+_GetCacheEntity
+_ResourceRecordAnswersQuestion
+_SetNextCacheCheckTime
+_SameNameRecordAnswersQuestion
+_CheckCacheExpiration
+_CacheRecordDeferredAdd
+_AnswerCurrentQuestionWithResourceRecord
+_queryrecord_result_callback
+_create_reply
+_mDNSPlatformInterfaceIndexfromInterfaceID
+_put_string
+_put_uint16
+_abort_request
+_queryrecord_termination_callback
+_mDNS_StopQuery
+_mDNS_StopQuery_internal
+_putQuestion
+_putDomainNameAsLabels
+_FindCompressionPointer
+_GetNextActiveInterfaceID
+_PutResourceRecordTTLWithLimit
+_putRData
+_mDNSSendDNSMessage
+_putHINFO
+_mDNSPlatformSendUDP
+_mDNSAddrIsDNSMulticast
+_myKQSocketCallBack
+_mDNSCoreReceive
+_mDNSCoreReceiveQuery
+_AddressIsLocalSubnet
+_LocateOptRR
+_LocateAdditionals
+_LocateAuthorities
+_LocateAnswers
+_skipResourceRecord
+_getQuestion
+_getDomainName
+_GetLargeResourceRecord
+_PacketRRConflict
+_AddAdditionalsToResponseList
+_mDNS_HostNameCallback
+_regservice_callback
+_GenerateNTDResponse
+_DeconstructServiceName
+_CountPeerRegistrations
+_RecordUpdatedNiceLabel
+_ClearProxyRecords
+_SendResponses
+_uDNS_recvLLQResponse
+_AnswerAllLocalQuestionsWithLocalAuthRecord
+_handle_regrecord_request
+_read_rr_from_ipc_msg
+_get_rdata
+_regrecord_callback
+_StartGetZoneData
+_GetZoneData_StartQuery
+_SetRecordRetry
+_GetZoneData_QuestionCallback
+_RecordRegistrationGotZoneData
+_SameResourceRecordSignature
+_FindIdenticalRecordInCache
+_mDNS_GrowCache
+_ShouldSuppressKnownAnswer
+_AutoTunnelNATCallback
+_RegisterAutoTunnelRecords
+_SysEventCallBack
+_UpdateSRVRecords
+_UpdateSRV
+_mDNS_DeregisterInterface
+_mDNS_PurgeCacheResourceRecord
+_DeadvertiseInterface
+_NumCacheRecordsForInterfaceID
+_AddrRequiresPPPConnection
+_mDNS_AddDNSServer
+_PurgeOrReconfirmCacheRecord
+_LNT_ClearState
+_UpdateAutoTunnelDomainStatuses
+_ReleaseCacheGroup
+_mDNS_AddDynDNSHostName
+_AdvertiseHostname
+_mDNSConfigureServer
+_mDNSPlatformStrLen
+_proxy_mDNSConfigureServer
+_CancelGetZoneData
+_mDNSPlatformUDPSocket
+_uDNS_ReceiveMsg
+_GetLLQOptData
+_ExpectingUnicastResponseForQuestion
+_UpdateSPSStatus
+_SPSStatusPutNumber
+_mDNSPlatformUDPClose
+_CloseSocketSet
+_SendRecordRegistration
+_putZone
+_putUpdateLease
+_MakeTCPConn
+_mDNSPlatformTCPSocket
+_mDNSPlatformTCPConnect
+_putDeleteRRSet
+_ServiceRegistrationGotZoneData
+_SendServiceRegistration
+_tcpKQSocketCallback
+_tlsSetupSock
+_doSSLHandshake
+_tlsWriteSock
+_tlsReadSock
+_tcpCallback
+_GetAuthInfoForName
+_DNSDigest_SignMessage
+_MD5_Update
+_md5_block_data_order
+_md5_block_host_order
+_mDNSPlatformUTC
+_MD5_Final
+_mDNSPlatformWriteTCP
+_mDNSPlatformReadTCP
+_DisposeTCPConn
+_mDNSPlatformTCPCloseConnection
+_GetPktLease
+_checkUpdateResult
+_HostnameCallback
+_AutoTunnelRecordCallback
+_handle_getproperty_request
+_AbortUnlinkAndFree
+_udsSupportRemoveFDFromEventLoop
+_handle_browse_request
+_add_domain_to_browser
+_mDNS_StartBrowse
+_ReconfirmAntecedents
+_FoundInstance
+_connection_termination
+_startLLQHandshake
+_LLQNATCallback
+_uDNS_RegisterSearchDomains
+_mDNS_AddSearchDomain
+_AnswerLocalQuestionWithLocalAuthRecord
+_enum_result_callback
+_LLQGotZoneData
+_GetLLQEventPort
+_mDNSPlatformSourceAddrForDest
+_putLLQ
+_SetLLQTimer
+_sendLLQRefresh
+_SendDelayedUnicastResponse
+_mDNS_Reconfirm_internal
diff --git a/mDNSResponder/mDNSMacOSX/mDNSResponder.pbproj/project.pbxproj b/mDNSResponder/mDNSMacOSX/mDNSResponder.pbproj/project.pbxproj
new file mode 100644
index 00000000..3e7df115
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/mDNSResponder.pbproj/project.pbxproj
@@ -0,0 +1,2338 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 38;
+ objects = {
+ 000753D303367C1C0CCA2C71 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ path = mDNSMacOSX.h;
+ refType = 4;
+ };
+ 00AD62A3032D799A0CCA2C71 = {
+ buildPhases = (
+ FFF7174A07614A8600E10551,
+ 00AD62A4032D799A0CCA2C71,
+ 00AD62AC032D799A0CCA2C71,
+ 00AD62B3032D799A0CCA2C71,
+ 00AD62B7032D799A0CCA2C71,
+ );
+ buildSettings = {
+ FRAMEWORK_SEARCH_PATHS = "";
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = "../mDNSShared \"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers\" \"${CONFIGURATION_TEMP_DIR}\"";
+ LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
+ MACOSX_DEPLOYMENT_TARGET = 10.2;
+ OPTIMIZATION_CFLAGS = "-O0";
+ OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -DmDNSResponderVersion=${MVERS} -DAPPLE_OSX_mDNSResponder=1 -D_LEGACY_NAT_TRAVERSAL_ -DMDNS_DEBUGMSGS=1";
+ OTHER_LDFLAGS = "-ldnsinfo";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = mDNSResponder.debug;
+ REZ_EXECUTABLE = YES;
+ SECTORDER_FLAGS = "-sectorder __TEXT __text mDNSResponder.order";
+ STRIPFLAGS = "-S";
+ WARNING_CFLAGS = "-W -Wall -Wmissing-prototypes -Wno-four-char-constants -Wno-unknown-pragmas";
+ };
+ dependencies = (
+ );
+ isa = PBXToolTarget;
+ name = "mDNSResponder debug";
+ productName = mDNSResponder;
+ productReference = 00AD62B8032D799A0CCA2C71;
+ };
+ 00AD62A4032D799A0CCA2C71 = {
+ buildActionMask = 2147483647;
+ files = (
+ 00AD62A5032D799A0CCA2C71,
+ F5E11B5F04A28126019798ED,
+ F515E29604A37BB701CA296C,
+ F515E29704A37BB801CA296C,
+ F515E29904A37BBB01CA296C,
+ );
+ isa = PBXHeadersBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 00AD62A5032D799A0CCA2C71 = {
+ fileRef = 6575FBFF022EAFBA00000109;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 00AD62AC032D799A0CCA2C71 = {
+ buildActionMask = 2147483647;
+ files = (
+ 00AD62AD032D799A0CCA2C71,
+ 00AD62AE032D799A0CCA2C71,
+ 00AD62AF032D799A0CCA2C71,
+ 7F18A9FB0587CEF6001880B3,
+ 7F18A9FA0587CEF6001880B3,
+ 7F461DB7062DBF2900672BF3,
+ DBAAFE2E057E8F660085CAD0,
+ DBAAFE2B057E8F4D0085CAD0,
+ F525E72B04AA167A01F1CF4D,
+ F5E11B5E04A28126019798ED,
+ FFCB6D75075D595E00B8AF62,
+ 00AD62B0032D799A0CCA2C71,
+ 7FC8F9D606D14E66007E879D,
+ 00AD62B1032D799A0CCA2C71,
+ );
+ isa = PBXSourcesBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 00AD62AD032D799A0CCA2C71 = {
+ fileRef = 6575FC00022EAFBA00000109;
+ isa = PBXBuildFile;
+ settings = {
+ ATTRIBUTES = (
+ Client,
+ );
+ };
+ };
+ 00AD62AE032D799A0CCA2C71 = {
+ fileRef = 6575FC01022EAFBA00000109;
+ isa = PBXBuildFile;
+ settings = {
+ ATTRIBUTES = (
+ Server,
+ Client,
+ );
+ };
+ };
+ 00AD62AF032D799A0CCA2C71 = {
+ fileRef = 6575FBE9022EAF5A00000109;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 00AD62B0032D799A0CCA2C71 = {
+ fileRef = 6575FBEB022EAF7200000109;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 00AD62B1032D799A0CCA2C71 = {
+ fileRef = 6575FBEC022EAF7200000109;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 00AD62B3032D799A0CCA2C71 = {
+ buildActionMask = 2147483647;
+ files = (
+ 00AD62B4032D799A0CCA2C71,
+ 00AD62B5032D799A0CCA2C71,
+ 00AD62B6032D799A0CCA2C71,
+ 7F869687066EE02400D2A2DC,
+ );
+ isa = PBXFrameworksBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 00AD62B4032D799A0CCA2C71 = {
+ fileRef = 09AB6884FE841BABC02AAC07;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 00AD62B5032D799A0CCA2C71 = {
+ fileRef = 65713D46025A293200000109;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 00AD62B6032D799A0CCA2C71 = {
+ fileRef = 00CA213D02786FC30CCA2C71;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 00AD62B7032D799A0CCA2C71 = {
+ buildActionMask = 2147483647;
+ files = (
+ );
+ isa = PBXRezBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 00AD62B8032D799A0CCA2C71 = {
+ isa = PBXExecutableFileReference;
+ path = mDNSResponder.debug;
+ refType = 3;
+ };
+ 00AD62BB032D7A0C0CCA2C71 = {
+ buildPhases = (
+ );
+ buildSettings = {
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = "Build All";
+ SECTORDER_FLAGS = "";
+ };
+ dependencies = (
+ FF25795106C9AB1D00376F7B,
+ 00AD62BC032D7A160CCA2C71,
+ 00AD62BD032D7A1B0CCA2C71,
+ 00AD62BE032D7A1D0CCA2C71,
+ FF16238F07023BD2001AB7D7,
+ FFD41DDB0664169900F0C438,
+ FFD41DDC0664169B00F0C438,
+ FF2A870707B4481500B14068,
+ );
+ isa = PBXAggregateTarget;
+ name = "Build All";
+ productName = "Build All";
+ };
+ 00AD62BC032D7A160CCA2C71 = {
+ isa = PBXTargetDependency;
+ target = 08FB779FFE84155DC02AAC07;
+ };
+ 00AD62BD032D7A1B0CCA2C71 = {
+ isa = PBXTargetDependency;
+ target = 00AD62A3032D799A0CCA2C71;
+ };
+ 00AD62BE032D7A1D0CCA2C71 = {
+ isa = PBXTargetDependency;
+ target = 6575FC1C022EB76000000109;
+ };
+ 00B2AB0C032D7B220CCA2C71 = {
+ buildRules = (
+ );
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
+ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
+ MVERS = "\"mDNSResponder (Engineering Build)\"";
+ };
+ isa = PBXBuildStyle;
+ name = Development;
+ };
+ 00CA213D02786FC30CCA2C71 = {
+ isa = PBXFrameworkReference;
+ name = IOKit.framework;
+ path = /System/Library/Frameworks/IOKit.framework;
+ refType = 0;
+ };
+//000
+//001
+//002
+//003
+//004
+//030
+//031
+//032
+//033
+//034
+ 034768E2FF38A6DC11DB9C8B = {
+ isa = PBXExecutableFileReference;
+ path = mDNSResponder;
+ refType = 3;
+ };
+//030
+//031
+//032
+//033
+//034
+//080
+//081
+//082
+//083
+//084
+ 08FB7793FE84155DC02AAC07 = {
+ buildStyles = (
+ 00B2AB0C032D7B220CCA2C71,
+ );
+ hasScannedForEncodings = 1;
+ isa = PBXProject;
+ mainGroup = 08FB7794FE84155DC02AAC07;
+ projectDirPath = "";
+ targets = (
+ 00AD62BB032D7A0C0CCA2C71,
+ 08FB779FFE84155DC02AAC07,
+ 00AD62A3032D799A0CCA2C71,
+ 6575FC1C022EB76000000109,
+ FF1C919207021C84001048AB,
+ DB2CC4530662DD6800335AB3,
+ DB2CC4660662DF5C00335AB3,
+ FF25792906C9A70800376F7B,
+ FFFB0DA907B43C9100B88D48,
+ FF2609E107B440DD00CE10E5,
+ );
+ };
+ 08FB7794FE84155DC02AAC07 = {
+ children = (
+ 08FB7795FE84155DC02AAC07,
+ 6575FC1F022EB78C00000109,
+ 6575FBFE022EAFA800000109,
+ DB2CC4420662DCE500335AB3,
+ FFFB0DA407B43BED00B88D48,
+ 08FB779DFE84155DC02AAC07,
+ 19C28FBDFE9D53C911CA2CBB,
+ );
+ isa = PBXGroup;
+ name = mDNSResponder;
+ refType = 4;
+ };
+ 08FB7795FE84155DC02AAC07 = {
+ children = (
+ 7FC8F9D406D14E66007E879D,
+ 7F461DB5062DBF2900672BF3,
+ F525E72804AA167501F1CF4D,
+ F5E11B5A04A28126019798ED,
+ F5E11B5B04A28126019798ED,
+ 6575FBEC022EAF7200000109,
+ 6575FBE9022EAF5A00000109,
+ 6575FBEB022EAF7200000109,
+ 654BE64F02B63B93000001D1,
+ 654BE65002B63B93000001D1,
+ DBAAFE29057E8F4D0085CAD0,
+ 000753D303367C1C0CCA2C71,
+ DBAAFE2C057E8F660085CAD0,
+ FFCB6D73075D539900B8AF62,
+ FF0E0B5D065ADC7600FE4D9C,
+ FF1C919D07021D77001048AB,
+ FF485D5105632E0000130380,
+ FFF4F63A06CFE4DD00459EFD,
+ 7F18A9F60587CEF6001880B3,
+ 7F18A9F70587CEF6001880B3,
+ FF25794606C9A8BF00376F7B,
+ FF13FFEA0A5DA44A00897C81,
+ FF13FFEC0A5DA45500897C81,
+ );
+ isa = PBXGroup;
+ name = "mDNS Server Sources";
+ path = "";
+ refType = 4;
+ };
+ 08FB779DFE84155DC02AAC07 = {
+ children = (
+ 7F869685066EE02400D2A2DC,
+ FFFB0DB407B43D2700B88D48,
+ 09AB6884FE841BABC02AAC07,
+ 65713D46025A293200000109,
+ 00CA213D02786FC30CCA2C71,
+ DB2CC4680662DFF500335AB3,
+ FF2609FA07B4433800CE10E5,
+ FF260A1F07B4436900CE10E5,
+ );
+ isa = PBXGroup;
+ name = "External Frameworks and Libraries";
+ refType = 4;
+ };
+ 08FB779FFE84155DC02AAC07 = {
+ buildPhases = (
+ FF37BE9207614059003C0420,
+ 08FB77A0FE84155DC02AAC07,
+ 08FB77A1FE84155DC02AAC07,
+ 08FB77A3FE84155DC02AAC07,
+ 08FB77A5FE84155DC02AAC07,
+ FF5A0AE705632EA600743C27,
+ FF5585E507790732008D1C14,
+ );
+ buildSettings = {
+ FRAMEWORK_SEARCH_PATHS = "";
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = "../mDNSShared \"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers\" \"${CONFIGURATION_TEMP_DIR}\"";
+ INSTALL_PATH = /usr/sbin;
+ LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
+ MACOSX_DEPLOYMENT_TARGET = 10.2;
+ OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -DmDNSResponderVersion=${MVERS} -DAPPLE_OSX_mDNSResponder=1 -D_LEGACY_NAT_TRAVERSAL_ -D__MigTypeCheck=1";
+ OTHER_LDFLAGS = "-ldnsinfo";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = mDNSResponder;
+ REZ_EXECUTABLE = YES;
+ SECTORDER_FLAGS = "-sectorder __TEXT __text mDNSResponder.order";
+ STRIPFLAGS = "-S";
+ WARNING_CFLAGS = "-W -Wall -Wmissing-prototypes -Wno-four-char-constants -Wno-unknown-pragmas";
+ };
+ dependencies = (
+ );
+ isa = PBXToolTarget;
+ name = mDNSResponder;
+ productInstallPath = "${HOME}/bin";
+ productName = mDNSResponder;
+ productReference = 034768E2FF38A6DC11DB9C8B;
+ };
+ 08FB77A0FE84155DC02AAC07 = {
+ buildActionMask = 2147483647;
+ files = (
+ 6575FC02022EAFBA00000109,
+ F5E11B5D04A28126019798ED,
+ );
+ isa = PBXHeadersBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 08FB77A1FE84155DC02AAC07 = {
+ buildActionMask = 2147483647;
+ files = (
+ 6575FC0D022EB18700000109,
+ 6575FC0E022EB18700000109,
+ 6575FBEA022EAF5A00000109,
+ 7F18A9F90587CEF6001880B3,
+ 7F18A9F80587CEF6001880B3,
+ 7F461DB6062DBF2900672BF3,
+ DBAAFE2D057E8F660085CAD0,
+ DBAAFE2A057E8F4D0085CAD0,
+ F525E72904AA167501F1CF4D,
+ F5E11B5C04A28126019798ED,
+ FFCB6D74075D539900B8AF62,
+ 6575FBED022EAF7200000109,
+ 7FC8F9D506D14E66007E879D,
+ 6575FBEE022EAF7200000109,
+ );
+ isa = PBXSourcesBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 08FB77A3FE84155DC02AAC07 = {
+ buildActionMask = 2147483647;
+ files = (
+ 09AB6885FE841BABC02AAC07,
+ 65713D66025A293200000109,
+ 6585DD640279A3B7000001D1,
+ 7F869686066EE02400D2A2DC,
+ );
+ isa = PBXFrameworksBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 08FB77A5FE84155DC02AAC07 = {
+ buildActionMask = 2147483647;
+ files = (
+ );
+ isa = PBXRezBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+//080
+//081
+//082
+//083
+//084
+//090
+//091
+//092
+//093
+//094
+ 09AB6884FE841BABC02AAC07 = {
+ isa = PBXFrameworkReference;
+ name = CoreFoundation.framework;
+ path = /System/Library/Frameworks/CoreFoundation.framework;
+ refType = 0;
+ };
+ 09AB6885FE841BABC02AAC07 = {
+ fileRef = 09AB6884FE841BABC02AAC07;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+//090
+//091
+//092
+//093
+//094
+//190
+//191
+//192
+//193
+//194
+ 19C28FBDFE9D53C911CA2CBB = {
+ children = (
+ 034768E2FF38A6DC11DB9C8B,
+ 6575FC1D022EB76000000109,
+ 00AD62B8032D799A0CCA2C71,
+ DB2CC4670662DF5C00335AB3,
+ FFD41DDA0664157900F0C438,
+ FF25794406C9A70800376F7B,
+ FF1C919B07021C84001048AB,
+ FFFB0DAA07B43C9100B88D48,
+ FF2609E207B440DD00CE10E5,
+ );
+ isa = PBXGroup;
+ name = Products;
+ refType = 4;
+ };
+//190
+//191
+//192
+//193
+//194
+//650
+//651
+//652
+//653
+//654
+ 654BE64F02B63B93000001D1 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = mDNSEmbeddedAPI.h;
+ path = ../mDNSCore/mDNSEmbeddedAPI.h;
+ refType = 4;
+ };
+ 654BE65002B63B93000001D1 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = mDNSDebug.h;
+ path = ../mDNSCore/mDNSDebug.h;
+ refType = 4;
+ };
+ 65713D46025A293200000109 = {
+ isa = PBXFrameworkReference;
+ name = SystemConfiguration.framework;
+ path = /System/Library/Frameworks/SystemConfiguration.framework;
+ refType = 0;
+ };
+ 65713D66025A293200000109 = {
+ fileRef = 65713D46025A293200000109;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 6575FBE9022EAF5A00000109 = {
+ fileEncoding = 4;
+ indentWidth = 4;
+ isa = PBXFileReference;
+ name = mDNS.c;
+ path = ../mDNSCore/mDNS.c;
+ refType = 4;
+ tabWidth = 4;
+ usesTabs = 1;
+ };
+ 6575FBEA022EAF5A00000109 = {
+ fileRef = 6575FBE9022EAF5A00000109;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 6575FBEB022EAF7200000109 = {
+ fileEncoding = 4;
+ indentWidth = 4;
+ isa = PBXFileReference;
+ path = mDNSMacOSX.c;
+ refType = 4;
+ tabWidth = 4;
+ usesTabs = 1;
+ };
+ 6575FBEC022EAF7200000109 = {
+ fileEncoding = 4;
+ indentWidth = 4;
+ isa = PBXFileReference;
+ path = daemon.c;
+ refType = 4;
+ tabWidth = 4;
+ usesTabs = 1;
+ };
+ 6575FBED022EAF7200000109 = {
+ fileRef = 6575FBEB022EAF7200000109;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 6575FBEE022EAF7200000109 = {
+ fileRef = 6575FBEC022EAF7200000109;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 6575FBFE022EAFA800000109 = {
+ children = (
+ 6575FBFF022EAFBA00000109,
+ 6575FC00022EAFBA00000109,
+ 6575FC01022EAFBA00000109,
+ );
+ isa = PBXGroup;
+ name = "DNS Service Discovery MIG files";
+ refType = 4;
+ };
+ 6575FBFF022EAFBA00000109 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ path = DNSServiceDiscoveryDefines.h;
+ refType = 4;
+ };
+ 6575FC00022EAFBA00000109 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ path = DNSServiceDiscoveryReply.defs;
+ refType = 4;
+ };
+ 6575FC01022EAFBA00000109 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ path = DNSServiceDiscoveryRequest.defs;
+ refType = 4;
+ };
+ 6575FC02022EAFBA00000109 = {
+ fileRef = 6575FBFF022EAFBA00000109;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 6575FC0D022EB18700000109 = {
+ fileRef = 6575FC00022EAFBA00000109;
+ isa = PBXBuildFile;
+ settings = {
+ ATTRIBUTES = (
+ Client,
+ );
+ };
+ };
+ 6575FC0E022EB18700000109 = {
+ fileRef = 6575FC01022EAFBA00000109;
+ isa = PBXBuildFile;
+ settings = {
+ ATTRIBUTES = (
+ Server,
+ Client,
+ );
+ };
+ };
+ 6575FC18022EB76000000109 = {
+ buildActionMask = 2147483647;
+ files = (
+ );
+ isa = PBXHeadersBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 6575FC19022EB76000000109 = {
+ buildActionMask = 2147483647;
+ files = (
+ 6575FC21022EB7AA00000109,
+ );
+ isa = PBXSourcesBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 6575FC1A022EB76000000109 = {
+ buildActionMask = 2147483647;
+ files = (
+ 6575FC24022EBA5D00000109,
+ );
+ isa = PBXFrameworksBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 6575FC1B022EB76000000109 = {
+ buildActionMask = 2147483647;
+ files = (
+ );
+ isa = PBXRezBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 6575FC1C022EB76000000109 = {
+ buildPhases = (
+ 6575FC18022EB76000000109,
+ 6575FC19022EB76000000109,
+ 6575FC1A022EB76000000109,
+ 6575FC1B022EB76000000109,
+ FFF4F63C06CFE53300459EFD,
+ );
+ buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ INSTALL_PATH = /usr/bin;
+ MACOSX_DEPLOYMENT_TARGET = 10.2;
+ OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic";
+ OTHER_LDFLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = mDNS;
+ REZ_EXECUTABLE = YES;
+ SECTORDER_FLAGS = "";
+ STRIPFLAGS = "-S";
+ WARNING_CFLAGS = "-W -Wall -Wmissing-prototypes -Wno-four-char-constants -Wno-unknown-pragmas";
+ };
+ dependencies = (
+ );
+ isa = PBXToolTarget;
+ name = "mDNS command-line tool";
+ productInstallPath = /usr/bin;
+ productName = "mDNS command-line tool";
+ productReference = 6575FC1D022EB76000000109;
+ };
+ 6575FC1D022EB76000000109 = {
+ isa = PBXExecutableFileReference;
+ path = mDNS;
+ refType = 3;
+ };
+ 6575FC1F022EB78C00000109 = {
+ children = (
+ 6575FC20022EB7AA00000109,
+ FF1C919F07021E3F001048AB,
+ );
+ isa = PBXGroup;
+ name = "Command-Line Clients";
+ refType = 4;
+ };
+ 6575FC20022EB7AA00000109 = {
+ fileEncoding = 4;
+ indentWidth = 4;
+ isa = PBXFileReference;
+ path = SamplemDNSClient.c;
+ refType = 2;
+ tabWidth = 4;
+ usesTabs = 0;
+ };
+ 6575FC21022EB7AA00000109 = {
+ fileRef = 6575FC20022EB7AA00000109;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 6575FC24022EBA5D00000109 = {
+ fileRef = 09AB6884FE841BABC02AAC07;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 6585DD640279A3B7000001D1 = {
+ fileRef = 00CA213D02786FC30CCA2C71;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+//650
+//651
+//652
+//653
+//654
+//7F0
+//7F1
+//7F2
+//7F3
+//7F4
+ 7F18A9F60587CEF6001880B3 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = DNSCommon.c;
+ path = ../mDNSCore/DNSCommon.c;
+ refType = 2;
+ };
+ 7F18A9F70587CEF6001880B3 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = uDNS.c;
+ path = ../mDNSCore/uDNS.c;
+ refType = 2;
+ };
+ 7F18A9F80587CEF6001880B3 = {
+ fileRef = 7F18A9F60587CEF6001880B3;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 7F18A9F90587CEF6001880B3 = {
+ fileRef = 7F18A9F70587CEF6001880B3;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 7F18A9FA0587CEF6001880B3 = {
+ fileRef = 7F18A9F60587CEF6001880B3;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 7F18A9FB0587CEF6001880B3 = {
+ fileRef = 7F18A9F70587CEF6001880B3;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 7F461DB5062DBF2900672BF3 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = DNSDigest.c;
+ path = ../mDNSCore/DNSDigest.c;
+ refType = 2;
+ };
+ 7F461DB6062DBF2900672BF3 = {
+ fileRef = 7F461DB5062DBF2900672BF3;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 7F461DB7062DBF2900672BF3 = {
+ fileRef = 7F461DB5062DBF2900672BF3;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 7F869685066EE02400D2A2DC = {
+ isa = PBXFrameworkReference;
+ name = Security.framework;
+ path = /System/Library/Frameworks/Security.framework;
+ refType = 0;
+ };
+ 7F869686066EE02400D2A2DC = {
+ fileRef = 7F869685066EE02400D2A2DC;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 7F869687066EE02400D2A2DC = {
+ fileRef = 7F869685066EE02400D2A2DC;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 7FC8F9D406D14E66007E879D = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ path = LegacyNATTraversal.c;
+ refType = 2;
+ };
+ 7FC8F9D506D14E66007E879D = {
+ fileRef = 7FC8F9D406D14E66007E879D;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ 7FC8F9D606D14E66007E879D = {
+ fileRef = 7FC8F9D406D14E66007E879D;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+//7F0
+//7F1
+//7F2
+//7F3
+//7F4
+//DB0
+//DB1
+//DB2
+//DB3
+//DB4
+ DB2CC4420662DCE500335AB3 = {
+ children = (
+ DB2CC4430662DD1100335AB3,
+ DB2CC4440662DD1100335AB3,
+ DB2CC4450662DD1100335AB3,
+ DB2CC4460662DD1100335AB3,
+ DB2CC4470662DD1100335AB3,
+ DB2CC4480662DD1100335AB3,
+ DB2CC4490662DD1100335AB3,
+ DB2CC44A0662DD1100335AB3,
+ DB2CC44B0662DD1100335AB3,
+ DB2CC44C0662DD1100335AB3,
+ DB2CC44D0662DD1100335AB3,
+ DB2CC44E0662DD1100335AB3,
+ DB2CC44F0662DD1100335AB3,
+ FF2C5FB00A48B8680066DA11,
+ FF2C5FB20A48B86E0066DA11,
+ );
+ isa = PBXGroup;
+ name = "Java Support";
+ refType = 4;
+ };
+ DB2CC4430662DD1100335AB3 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = BaseListener.java;
+ path = ../mDNSShared/Java/BaseListener.java;
+ refType = 2;
+ };
+ DB2CC4440662DD1100335AB3 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = BrowseListener.java;
+ path = ../mDNSShared/Java/BrowseListener.java;
+ refType = 2;
+ };
+ DB2CC4450662DD1100335AB3 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = DNSRecord.java;
+ path = ../mDNSShared/Java/DNSRecord.java;
+ refType = 2;
+ };
+ DB2CC4460662DD1100335AB3 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = DNSSD.java;
+ path = ../mDNSShared/Java/DNSSD.java;
+ refType = 2;
+ };
+ DB2CC4470662DD1100335AB3 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = DNSSDException.java;
+ path = ../mDNSShared/Java/DNSSDException.java;
+ refType = 2;
+ };
+ DB2CC4480662DD1100335AB3 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = DNSSDRegistration.java;
+ path = ../mDNSShared/Java/DNSSDRegistration.java;
+ refType = 2;
+ };
+ DB2CC4490662DD1100335AB3 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = DNSSDService.java;
+ path = ../mDNSShared/Java/DNSSDService.java;
+ refType = 2;
+ };
+ DB2CC44A0662DD1100335AB3 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = DomainListener.java;
+ path = ../mDNSShared/Java/DomainListener.java;
+ refType = 2;
+ };
+ DB2CC44B0662DD1100335AB3 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = JNISupport.c;
+ path = ../mDNSShared/Java/JNISupport.c;
+ refType = 2;
+ };
+ DB2CC44C0662DD1100335AB3 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = QueryListener.java;
+ path = ../mDNSShared/Java/QueryListener.java;
+ refType = 2;
+ };
+ DB2CC44D0662DD1100335AB3 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = RegisterListener.java;
+ path = ../mDNSShared/Java/RegisterListener.java;
+ refType = 2;
+ };
+ DB2CC44E0662DD1100335AB3 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = ResolveListener.java;
+ path = ../mDNSShared/Java/ResolveListener.java;
+ refType = 2;
+ };
+ DB2CC44F0662DD1100335AB3 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = TXTRecord.java;
+ path = ../mDNSShared/Java/TXTRecord.java;
+ refType = 2;
+ };
+ DB2CC4500662DD6800335AB3 = {
+ buildActionMask = 2147483647;
+ files = (
+ DB2CC4560662DE4500335AB3,
+ DB2CC4570662DE4600335AB3,
+ DB2CC4580662DE4700335AB3,
+ DB2CC4590662DE4700335AB3,
+ DB2CC45A0662DE4800335AB3,
+ DB2CC45B0662DE4900335AB3,
+ DB2CC45C0662DE4900335AB3,
+ DB2CC45D0662DE4A00335AB3,
+ DB2CC45E0662DE4B00335AB3,
+ DB2CC45F0662DE4C00335AB3,
+ DB2CC4600662DE4C00335AB3,
+ DB2CC4610662DE4D00335AB3,
+ FF2C5FB10A48B8680066DA11,
+ FF2C5FB30A48B86E0066DA11,
+ );
+ isa = PBXSourcesBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DB2CC4510662DD6800335AB3 = {
+ buildActionMask = 2147483647;
+ files = (
+ );
+ isa = PBXJavaArchiveBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DB2CC4520662DD6800335AB3 = {
+ buildActionMask = 2147483647;
+ files = (
+ );
+ isa = PBXFrameworksBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DB2CC4530662DD6800335AB3 = {
+ buildPhases = (
+ DB2CC4500662DD6800335AB3,
+ DB2CC4510662DD6800335AB3,
+ DB2CC4520662DD6800335AB3,
+ DB2CC4550662DE1700335AB3,
+ FFD41DDD06641B4200F0C438,
+ );
+ buildSettings = {
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ INSTALL_PATH = "${SYSTEM_LIBRARY_DIR}/Java/Extensions";
+ JAVA_ARCHIVE_CLASSES = YES;
+ JAVA_ARCHIVE_COMPRESSION = YES;
+ JAVA_ARCHIVE_TYPE = JAR;
+ JAVA_COMPILER_DEBUGGING_SYMBOLS = NO;
+ JAVA_COMPILER_SOURCE_VERSION = 1.4;
+ JAVA_COMPILER_TARGET_VM_VERSION = 1.4;
+ JAVA_SOURCE_SUBDIR = .;
+ LIBRARY_STYLE = STATIC;
+ MACOSX_DEPLOYMENT_TARGET = 10.2;
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = "";
+ OTHER_LIBTOOL_FLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = dns_sd;
+ PURE_JAVA = YES;
+ REZ_EXECUTABLE = YES;
+ SECTORDER_FLAGS = "";
+ STRIPFLAGS = "-S";
+ WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+ };
+ comments = "Multiplatform .jar file that implements Java interface to DNS-SD";
+ dependencies = (
+ );
+ isa = PBXLibraryTarget;
+ name = dns_sd.jar;
+ productInstallPath = /System/Library/Java/Extensions;
+ productName = dns_sd.jar;
+ productReference = FFD41DDA0664157900F0C438;
+ };
+ DB2CC4550662DE1700335AB3 = {
+ buildActionMask = 12;
+ files = (
+ );
+ generatedFileNames = (
+ );
+ isa = PBXShellScriptBuildPhase;
+ neededFileNames = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "javah -force -J-Xbootclasspath/p:${CONFIGURATION_TEMP_DIR}/dns_sd.jar.build/JavaClasses -o ${CONFIGURATION_TEMP_DIR}/dns_sd.jar.build/DNSSD.java.h com.apple.dnssd.AppleDNSSD com.apple.dnssd.AppleBrowser com.apple.dnssd.AppleResolver com.apple.dnssd.AppleRegistration com.apple.dnssd.AppleQuery com.apple.dnssd.AppleDomainEnum com.apple.dnssd.AppleService";
+ };
+ DB2CC4560662DE4500335AB3 = {
+ fileRef = DB2CC4430662DD1100335AB3;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ DB2CC4570662DE4600335AB3 = {
+ fileRef = DB2CC4440662DD1100335AB3;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ DB2CC4580662DE4700335AB3 = {
+ fileRef = DB2CC4450662DD1100335AB3;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ DB2CC4590662DE4700335AB3 = {
+ fileRef = DB2CC4460662DD1100335AB3;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ DB2CC45A0662DE4800335AB3 = {
+ fileRef = DB2CC4470662DD1100335AB3;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ DB2CC45B0662DE4900335AB3 = {
+ fileRef = DB2CC4480662DD1100335AB3;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ DB2CC45C0662DE4900335AB3 = {
+ fileRef = DB2CC4490662DD1100335AB3;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ DB2CC45D0662DE4A00335AB3 = {
+ fileRef = DB2CC44A0662DD1100335AB3;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ DB2CC45E0662DE4B00335AB3 = {
+ fileRef = DB2CC44C0662DD1100335AB3;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ DB2CC45F0662DE4C00335AB3 = {
+ fileRef = DB2CC44D0662DD1100335AB3;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ DB2CC4600662DE4C00335AB3 = {
+ fileRef = DB2CC44E0662DD1100335AB3;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ DB2CC4610662DE4D00335AB3 = {
+ fileRef = DB2CC44F0662DD1100335AB3;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ DB2CC4620662DF5C00335AB3 = {
+ buildActionMask = 2147483647;
+ files = (
+ );
+ isa = PBXHeadersBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DB2CC4630662DF5C00335AB3 = {
+ buildActionMask = 2147483647;
+ files = (
+ DB2CC46A0662E00700335AB3,
+ );
+ isa = PBXSourcesBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DB2CC4640662DF5C00335AB3 = {
+ buildActionMask = 2147483647;
+ files = (
+ DB2CC4690662DFF500335AB3,
+ );
+ isa = PBXFrameworksBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DB2CC4650662DF5C00335AB3 = {
+ buildActionMask = 2147483647;
+ files = (
+ );
+ isa = PBXRezBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ DB2CC4660662DF5C00335AB3 = {
+ buildPhases = (
+ DB2CC4620662DF5C00335AB3,
+ DB2CC4630662DF5C00335AB3,
+ DB2CC4640662DF5C00335AB3,
+ DB2CC4650662DF5C00335AB3,
+ );
+ buildSettings = {
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ HEADER_SEARCH_PATHS = "../mDNSShared \"${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/A/Headers\" \"${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/1.3.1/Headers\" \"${CONFIGURATION_TEMP_DIR}/dns_sd.jar.build\"";
+ INSTALL_PATH = /usr/lib/java;
+ LIBRARY_STYLE = DYNAMIC;
+ MACOSX_DEPLOYMENT_TARGET = 10.2;
+ OTHER_CFLAGS = "";
+ OTHER_LIBTOOL_FLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = libjdns_sd.jnilib;
+ REZ_EXECUTABLE = YES;
+ SECTORDER_FLAGS = "";
+ STRIPFLAGS = "-S";
+ WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+ };
+ comments = "Platform-specific JNI library that bridges dns_sd.jar to <dns_sd.h>.";
+ dependencies = (
+ FFD41DDF06641BBB00F0C438,
+ );
+ isa = PBXLibraryTarget;
+ name = libjdns_sd.jnilib;
+ productInstallPath = /usr/lib/java;
+ productName = libjdns_sd.jnilib;
+ productReference = DB2CC4670662DF5C00335AB3;
+ };
+ DB2CC4670662DF5C00335AB3 = {
+ isa = PBXLibraryReference;
+ path = libjdns_sd.jnilib;
+ refType = 3;
+ };
+ DB2CC4680662DFF500335AB3 = {
+ isa = PBXFrameworkReference;
+ name = JavaVM.framework;
+ path = /System/Library/Frameworks/JavaVM.framework;
+ refType = 0;
+ };
+ DB2CC4690662DFF500335AB3 = {
+ fileRef = DB2CC4680662DFF500335AB3;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ DB2CC46A0662E00700335AB3 = {
+ fileRef = DB2CC44B0662DD1100335AB3;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ DBAAFE29057E8F4D0085CAD0 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = mDNSDebug.c;
+ path = ../mDNSShared/mDNSDebug.c;
+ refType = 2;
+ };
+ DBAAFE2A057E8F4D0085CAD0 = {
+ fileRef = DBAAFE29057E8F4D0085CAD0;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ DBAAFE2B057E8F4D0085CAD0 = {
+ fileRef = DBAAFE29057E8F4D0085CAD0;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ DBAAFE2C057E8F660085CAD0 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = GenLinkedList.c;
+ path = ../mDNSShared/GenLinkedList.c;
+ refType = 2;
+ };
+ DBAAFE2D057E8F660085CAD0 = {
+ fileRef = DBAAFE2C057E8F660085CAD0;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ DBAAFE2E057E8F660085CAD0 = {
+ fileRef = DBAAFE2C057E8F660085CAD0;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+//DB0
+//DB1
+//DB2
+//DB3
+//DB4
+//F50
+//F51
+//F52
+//F53
+//F54
+ F515E29604A37BB701CA296C = {
+ fileRef = 654BE64F02B63B93000001D1;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ F515E29704A37BB801CA296C = {
+ fileRef = 654BE65002B63B93000001D1;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ F515E29904A37BBB01CA296C = {
+ fileRef = 000753D303367C1C0CCA2C71;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ F525E72804AA167501F1CF4D = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = uds_daemon.c;
+ path = ../mDNSShared/uds_daemon.c;
+ refType = 2;
+ };
+ F525E72904AA167501F1CF4D = {
+ fileRef = F525E72804AA167501F1CF4D;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ F525E72B04AA167A01F1CF4D = {
+ fileRef = F525E72804AA167501F1CF4D;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ F5E11B5A04A28126019798ED = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = dnssd_ipc.c;
+ path = ../mDNSShared/dnssd_ipc.c;
+ refType = 2;
+ };
+ F5E11B5B04A28126019798ED = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = dnssd_ipc.h;
+ path = ../mDNSShared/dnssd_ipc.h;
+ refType = 2;
+ };
+ F5E11B5C04A28126019798ED = {
+ fileRef = F5E11B5A04A28126019798ED;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ F5E11B5D04A28126019798ED = {
+ fileRef = F5E11B5B04A28126019798ED;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ F5E11B5E04A28126019798ED = {
+ fileRef = F5E11B5A04A28126019798ED;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ F5E11B5F04A28126019798ED = {
+ fileRef = F5E11B5B04A28126019798ED;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+//F50
+//F51
+//F52
+//F53
+//F54
+//FF0
+//FF1
+//FF2
+//FF3
+//FF4
+ FF08480607CEB8E800AE6769 = {
+ isa = PBXFileReference;
+ name = inprogress.tiff;
+ path = PreferencePane/Artwork/inprogress.tiff;
+ refType = 2;
+ };
+ FF08480707CEB8E800AE6769 = {
+ fileRef = FF08480607CEB8E800AE6769;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF0E0B5D065ADC7600FE4D9C = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = mDNS.1;
+ path = ../mDNSShared/mDNS.1;
+ refType = 2;
+ };
+ FF13FFE90A5DA40200897C81 = {
+ fileRef = 6575FBEB022EAF7200000109;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF13FFEA0A5DA44A00897C81 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = dnsextd_lexer.l;
+ path = ../mDNSShared/dnsextd_lexer.l;
+ refType = 2;
+ };
+ FF13FFEB0A5DA44A00897C81 = {
+ fileRef = FF13FFEA0A5DA44A00897C81;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF13FFEC0A5DA45500897C81 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = dnsextd_parser.y;
+ path = ../mDNSShared/dnsextd_parser.y;
+ refType = 2;
+ };
+ FF13FFED0A5DA45500897C81 = {
+ fileRef = FF13FFEC0A5DA45500897C81;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF13FFEE0A5DA52700897C81 = {
+ isa = PBXTargetDependency;
+ target = 08FB779FFE84155DC02AAC07;
+ };
+ FF13FFEF0A5DA6FD00897C81 = {
+ fileRef = FFCB6D73075D539900B8AF62;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF16238F07023BD2001AB7D7 = {
+ isa = PBXTargetDependency;
+ target = FF1C919207021C84001048AB;
+ };
+ FF1C919207021C84001048AB = {
+ buildPhases = (
+ FF1C919307021C84001048AB,
+ FF1C919407021C84001048AB,
+ FF1C919607021C84001048AB,
+ FF1C919807021C84001048AB,
+ FF1C919907021C84001048AB,
+ );
+ buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ INSTALL_PATH = /usr/bin;
+ MACOSX_DEPLOYMENT_TARGET = 10.2;
+ OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -I../mDNSShared";
+ OTHER_LDFLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = "dns-sd";
+ REZ_EXECUTABLE = YES;
+ SECTORDER_FLAGS = "";
+ STRIPFLAGS = "-S";
+ WARNING_CFLAGS = "-W -Wall -Wmissing-prototypes -Wno-four-char-constants -Wno-unknown-pragmas";
+ };
+ dependencies = (
+ );
+ isa = PBXToolTarget;
+ name = "dns-sd command-line tool";
+ productInstallPath = /usr/bin;
+ productName = "dns-sd command-line tool";
+ productReference = FF1C919B07021C84001048AB;
+ };
+ FF1C919307021C84001048AB = {
+ buildActionMask = 2147483647;
+ files = (
+ );
+ isa = PBXHeadersBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FF1C919407021C84001048AB = {
+ buildActionMask = 2147483647;
+ files = (
+ FF1C91A007021E40001048AB,
+ );
+ isa = PBXSourcesBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FF1C919607021C84001048AB = {
+ buildActionMask = 2147483647;
+ files = (
+ );
+ isa = PBXFrameworksBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FF1C919807021C84001048AB = {
+ buildActionMask = 2147483647;
+ files = (
+ );
+ isa = PBXRezBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FF1C919907021C84001048AB = {
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FF1C919E07021D78001048AB,
+ );
+ isa = PBXCopyFilesBuildPhase;
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FF1C919B07021C84001048AB = {
+ isa = PBXExecutableFileReference;
+ path = "dns-sd";
+ refType = 3;
+ };
+ FF1C919D07021D77001048AB = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = "dns-sd.1";
+ path = "../mDNSShared/dns-sd.1";
+ refType = 2;
+ };
+ FF1C919E07021D78001048AB = {
+ fileRef = FF1C919D07021D77001048AB;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF1C919F07021E3F001048AB = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = "dns-sd.c";
+ path = "../Clients/dns-sd.c";
+ refType = 2;
+ };
+ FF1C91A007021E40001048AB = {
+ fileRef = FF1C919F07021E3F001048AB;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF25792906C9A70800376F7B = {
+ buildPhases = (
+ FF25792A06C9A70800376F7B,
+ FF25792D06C9A70800376F7B,
+ FF25793A06C9A70800376F7B,
+ FF25793F06C9A70800376F7B,
+ FF25794006C9A70800376F7B,
+ );
+ buildSettings = {
+ FRAMEWORK_SEARCH_PATHS = "";
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = "\"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers\" \"${CONFIGURATION_TEMP_DIR}\"";
+ INSTALL_PATH = /usr/sbin;
+ LEX = /usr/bin/flex;
+ LEXFLAGS = "-i";
+ LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
+ MACOSX_DEPLOYMENT_TARGET = 10.2;
+ OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic";
+ OTHER_LDFLAGS = "-ldnsinfo";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = dnsextd;
+ REZ_EXECUTABLE = YES;
+ SECTORDER_FLAGS = "";
+ STRIPFLAGS = "-S";
+ WARNING_CFLAGS = "-W -Wall -Wmissing-prototypes -Wno-four-char-constants -Wno-unknown-pragmas";
+ YACC = "/usr/bin/bison -y";
+ };
+ dependencies = (
+ FF13FFEE0A5DA52700897C81,
+ );
+ isa = PBXToolTarget;
+ name = dnsextd;
+ productInstallPath = /usr/sbin;
+ productName = mDNSResponder;
+ productReference = FF25794406C9A70800376F7B;
+ };
+ FF25792A06C9A70800376F7B = {
+ buildActionMask = 2147483647;
+ files = (
+ FF25792B06C9A70800376F7B,
+ );
+ isa = PBXHeadersBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FF25792B06C9A70800376F7B = {
+ fileRef = 6575FBFF022EAFBA00000109;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF25792D06C9A70800376F7B = {
+ buildActionMask = 2147483647;
+ files = (
+ FF25793606C9A70800376F7B,
+ FF25793806C9A70800376F7B,
+ FF25794706C9A8BF00376F7B,
+ FF25794A06C9A98700376F7B,
+ FF25794E06C9AA3000376F7B,
+ FF13FFE90A5DA40200897C81,
+ FF13FFEB0A5DA44A00897C81,
+ FF13FFED0A5DA45500897C81,
+ FF13FFEF0A5DA6FD00897C81,
+ );
+ isa = PBXSourcesBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FF25793606C9A70800376F7B = {
+ fileRef = 7F18A9F60587CEF6001880B3;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF25793806C9A70800376F7B = {
+ fileRef = 7F461DB5062DBF2900672BF3;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF25793A06C9A70800376F7B = {
+ buildActionMask = 2147483647;
+ files = (
+ FF25793B06C9A70800376F7B,
+ FF25793C06C9A70800376F7B,
+ FF25793D06C9A70800376F7B,
+ FF25793E06C9A70800376F7B,
+ );
+ isa = PBXFrameworksBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FF25793B06C9A70800376F7B = {
+ fileRef = 09AB6884FE841BABC02AAC07;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF25793C06C9A70800376F7B = {
+ fileRef = 65713D46025A293200000109;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF25793D06C9A70800376F7B = {
+ fileRef = 00CA213D02786FC30CCA2C71;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF25793E06C9A70800376F7B = {
+ fileRef = 7F869685066EE02400D2A2DC;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF25793F06C9A70800376F7B = {
+ buildActionMask = 2147483647;
+ files = (
+ );
+ isa = PBXRezBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FF25794006C9A70800376F7B = {
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ FFF4F63B06CFE4DD00459EFD,
+ );
+ isa = PBXCopyFilesBuildPhase;
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FF25794406C9A70800376F7B = {
+ isa = PBXExecutableFileReference;
+ path = dnsextd;
+ refType = 3;
+ };
+ FF25794606C9A8BF00376F7B = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = dnsextd.c;
+ path = ../mDNSShared/dnsextd.c;
+ refType = 2;
+ };
+ FF25794706C9A8BF00376F7B = {
+ fileRef = FF25794606C9A8BF00376F7B;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF25794A06C9A98700376F7B = {
+ fileRef = DBAAFE29057E8F4D0085CAD0;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF25794E06C9AA3000376F7B = {
+ fileRef = DBAAFE2C057E8F660085CAD0;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF25795106C9AB1D00376F7B = {
+ isa = PBXTargetDependency;
+ target = FF25792906C9A70800376F7B;
+ };
+ FF2609DC07B440DD00CE10E5 = {
+ buildActionMask = 2147483647;
+ files = (
+ );
+ isa = PBXHeadersBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FF2609DD07B440DD00CE10E5 = {
+ buildActionMask = 2147483647;
+ files = (
+ FF260A2B07B4464B00CE10E5,
+ FF260A2C07B4464B00CE10E5,
+ FF260A2D07B4464B00CE10E5,
+ FF260A2E07B4464B00CE10E5,
+ FF260A2F07B4464B00CE10E5,
+ FF260A3007B4464B00CE10E5,
+ FF260A3107B4464B00CE10E5,
+ FF260A3407B4466900CE10E5,
+ FF260A3507B4466900CE10E5,
+ FF260A4A07B4475600CE10E5,
+ FF260A4D07B4477F00CE10E5,
+ FF2A870607B447EF00B14068,
+ FF08480707CEB8E800AE6769,
+ FF354EB208516C63007C00E1,
+ );
+ isa = PBXResourcesBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FF2609DE07B440DD00CE10E5 = {
+ buildActionMask = 2147483647;
+ files = (
+ FF2609E407B441D400CE10E5,
+ FF2609E507B441D700CE10E5,
+ FF2609E607B441DB00CE10E5,
+ );
+ isa = PBXSourcesBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FF2609DF07B440DD00CE10E5 = {
+ buildActionMask = 2147483647;
+ files = (
+ FF2609F607B442BA00CE10E5,
+ FF2609F707B442C000CE10E5,
+ FF2609FB07B4433800CE10E5,
+ FF260A2007B4436900CE10E5,
+ FF260A2107B443B500CE10E5,
+ );
+ isa = PBXFrameworksBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FF2609E007B440DD00CE10E5 = {
+ buildActionMask = 2147483647;
+ files = (
+ );
+ isa = PBXRezBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FF2609E107B440DD00CE10E5 = {
+ buildPhases = (
+ FF2609DC07B440DD00CE10E5,
+ FF2609DD07B440DD00CE10E5,
+ FF2609DE07B440DD00CE10E5,
+ FF2609DF07B440DD00CE10E5,
+ FF2609E007B440DD00CE10E5,
+ );
+ buildSettings = {
+ EXPORTED_SYMBOLS_FILE = "";
+ INSTALL_PATH = "${SYSTEM_LIBRARY_DIR}/PreferencePanes";
+ MACOSX_DEPLOYMENT_TARGET = 10.2;
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = "-twolevel_namespace";
+ OTHER_REZFLAGS = "";
+ PREBINDING = NO;
+ PRODUCT_NAME = Bonjour;
+ SECTORDER_FLAGS = "";
+ STRIPFLAGS = "-S";
+ WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+ WRAPPER_EXTENSION = prefPane;
+ };
+ dependencies = (
+ FF2609E307B440EC00CE10E5,
+ );
+ isa = PBXBundleTarget;
+ name = PreferencePane;
+ productInstallPath = "${SYSTEM_LIBRARY_DIR}/PreferencePanes";
+ productName = PreferencePane;
+ productReference = FF2609E207B440DD00CE10E5;
+ productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
+<plist version=\"1.0\">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>Bonjour</string>
+ <key>CFBundleGetInfoString</key>
+ <string></string>
+ <key>CFBundleIconFile</key>
+ <string>BonjourPref</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.apple.preference.bonjour</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string></string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleShortVersionString</key>
+ <string></string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>NSMainNibFile</key>
+ <string>DNSServiceDiscoveryPref</string>
+ <key>NSPrefPaneIconFile</key>
+ <string>BonjourPref.tiff</string>
+ <key>NSPrefPaneIconLabel</key>
+ <string>Bonjour</string>
+ <key>NSPrincipalClass</key>
+ <string>DNSServiceDiscoveryPref</string>
+</dict>
+</plist>
+";
+ };
+ FF2609E207B440DD00CE10E5 = {
+ isa = PBXBundleReference;
+ path = Bonjour.prefPane;
+ refType = 3;
+ };
+ FF2609E307B440EC00CE10E5 = {
+ isa = PBXTargetDependency;
+ target = FFFB0DA907B43C9100B88D48;
+ };
+ FF2609E407B441D400CE10E5 = {
+ fileRef = FFFB0DAC07B43CBA00B88D48;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF2609E507B441D700CE10E5 = {
+ fileRef = FFFB0DAD07B43CBA00B88D48;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF2609E607B441DB00CE10E5 = {
+ fileRef = FFFB0DAE07B43CBA00B88D48;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF2609F607B442BA00CE10E5 = {
+ fileRef = 65713D46025A293200000109;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF2609F707B442C000CE10E5 = {
+ fileRef = 7F869685066EE02400D2A2DC;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF2609FA07B4433800CE10E5 = {
+ isa = PBXFrameworkReference;
+ name = Cocoa.framework;
+ path = /System/Library/Frameworks/Cocoa.framework;
+ refType = 0;
+ };
+ FF2609FB07B4433800CE10E5 = {
+ fileRef = FF2609FA07B4433800CE10E5;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF260A1F07B4436900CE10E5 = {
+ isa = PBXFrameworkReference;
+ name = PreferencePanes.framework;
+ path = /System/Library/Frameworks/PreferencePanes.framework;
+ refType = 0;
+ };
+ FF260A2007B4436900CE10E5 = {
+ fileRef = FF260A1F07B4436900CE10E5;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF260A2107B443B500CE10E5 = {
+ fileRef = 09AB6884FE841BABC02AAC07;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF260A2207B443C500CE10E5 = {
+ fileRef = 09AB6884FE841BABC02AAC07;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF260A2307B4463400CE10E5 = {
+ children = (
+ FF260A2407B4464B00CE10E5,
+ FF260A2507B4464B00CE10E5,
+ FF260A2607B4464B00CE10E5,
+ FF260A2707B4464B00CE10E5,
+ FF260A2907B4464B00CE10E5,
+ FF260A2807B4464B00CE10E5,
+ FF08480607CEB8E800AE6769,
+ FF260A2A07B4464B00CE10E5,
+ FF260A3207B4466900CE10E5,
+ FF260A3307B4466900CE10E5,
+ FF354EB108516C63007C00E1,
+ FF260A4807B4475600CE10E5,
+ FF260A4B07B4477F00CE10E5,
+ );
+ isa = PBXGroup;
+ name = Resources;
+ refType = 4;
+ };
+ FF260A2407B4464B00CE10E5 = {
+ isa = PBXFileReference;
+ name = remove_idle.tiff;
+ path = PreferencePane/Artwork/remove_idle.tiff;
+ refType = 2;
+ };
+ FF260A2507B4464B00CE10E5 = {
+ isa = PBXFileReference;
+ name = add_pressed.tiff;
+ path = PreferencePane/Artwork/add_pressed.tiff;
+ refType = 2;
+ };
+ FF260A2607B4464B00CE10E5 = {
+ isa = PBXFileReference;
+ name = remove_disabled.tiff;
+ path = PreferencePane/Artwork/remove_disabled.tiff;
+ refType = 2;
+ };
+ FF260A2707B4464B00CE10E5 = {
+ isa = PBXFileReference;
+ name = add_idle.tiff;
+ path = PreferencePane/Artwork/add_idle.tiff;
+ refType = 2;
+ };
+ FF260A2807B4464B00CE10E5 = {
+ isa = PBXFileReference;
+ name = success.tiff;
+ path = PreferencePane/Artwork/success.tiff;
+ refType = 2;
+ };
+ FF260A2907B4464B00CE10E5 = {
+ isa = PBXFileReference;
+ name = remove_pressed.tiff;
+ path = PreferencePane/Artwork/remove_pressed.tiff;
+ refType = 2;
+ };
+ FF260A2A07B4464B00CE10E5 = {
+ isa = PBXFileReference;
+ name = failure.tiff;
+ path = PreferencePane/Artwork/failure.tiff;
+ refType = 2;
+ };
+ FF260A2B07B4464B00CE10E5 = {
+ fileRef = FF260A2407B4464B00CE10E5;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF260A2C07B4464B00CE10E5 = {
+ fileRef = FF260A2507B4464B00CE10E5;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF260A2D07B4464B00CE10E5 = {
+ fileRef = FF260A2607B4464B00CE10E5;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF260A2E07B4464B00CE10E5 = {
+ fileRef = FF260A2707B4464B00CE10E5;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF260A2F07B4464B00CE10E5 = {
+ fileRef = FF260A2807B4464B00CE10E5;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF260A3007B4464B00CE10E5 = {
+ fileRef = FF260A2907B4464B00CE10E5;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF260A3107B4464B00CE10E5 = {
+ fileRef = FF260A2A07B4464B00CE10E5;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF260A3207B4466900CE10E5 = {
+ isa = PBXFileReference;
+ name = BonjourPref.icns;
+ path = PreferencePane/BonjourPref.icns;
+ refType = 2;
+ };
+ FF260A3307B4466900CE10E5 = {
+ isa = PBXFileReference;
+ name = BonjourPref.tiff;
+ path = PreferencePane/BonjourPref.tiff;
+ refType = 2;
+ };
+ FF260A3407B4466900CE10E5 = {
+ fileRef = FF260A3207B4466900CE10E5;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF260A3507B4466900CE10E5 = {
+ fileRef = FF260A3307B4466900CE10E5;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF260A4807B4475600CE10E5 = {
+ children = (
+ FF260A4907B4475600CE10E5,
+ );
+ isa = PBXVariantGroup;
+ name = DNSServiceDiscoveryPref.nib;
+ path = PreferencePane;
+ refType = 2;
+ };
+ FF260A4907B4475600CE10E5 = {
+ isa = PBXFileReference;
+ name = English;
+ path = PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib;
+ refType = 2;
+ };
+ FF260A4A07B4475600CE10E5 = {
+ fileRef = FF260A4807B4475600CE10E5;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF260A4B07B4477F00CE10E5 = {
+ children = (
+ FF260A4C07B4477F00CE10E5,
+ );
+ isa = PBXVariantGroup;
+ name = InfoPlist.strings;
+ path = PreferencePane;
+ refType = 2;
+ };
+ FF260A4C07B4477F00CE10E5 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = English;
+ path = PreferencePane/English.lproj/InfoPlist.strings;
+ refType = 2;
+ };
+ FF260A4D07B4477F00CE10E5 = {
+ fileRef = FF260A4B07B4477F00CE10E5;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF2A870607B447EF00B14068 = {
+ fileRef = FFFB0DAA07B43C9100B88D48;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF2A870707B4481500B14068 = {
+ isa = PBXTargetDependency;
+ target = FF2609E107B440DD00CE10E5;
+ };
+ FF2C5FB00A48B8680066DA11 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = DNSSDRecordRegistrar.java;
+ path = ../mDNSShared/Java/DNSSDRecordRegistrar.java;
+ refType = 2;
+ };
+ FF2C5FB10A48B8680066DA11 = {
+ fileRef = FF2C5FB00A48B8680066DA11;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF2C5FB20A48B86E0066DA11 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = RegisterRecordListener.java;
+ path = ../mDNSShared/Java/RegisterRecordListener.java;
+ refType = 2;
+ };
+ FF2C5FB30A48B86E0066DA11 = {
+ fileRef = FF2C5FB20A48B86E0066DA11;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF354EB108516C63007C00E1 = {
+ fileEncoding = 4;
+ isa = PBXExecutableFileReference;
+ name = installtool;
+ path = PreferencePane/installtool;
+ refType = 2;
+ };
+ FF354EB208516C63007C00E1 = {
+ fileRef = FF354EB108516C63007C00E1;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FF37BE9207614059003C0420 = {
+ buildActionMask = 2147483647;
+ files = (
+ );
+ generatedFileNames = (
+ );
+ isa = PBXShellScriptBuildPhase;
+ neededFileNames = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "if [ -e /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\ncc ${CONFIGURATION_TEMP_DIR}/empty.c -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f ${CONFIGURATION_TEMP_DIR}/empty.c\nfi";
+ };
+ FF485D5105632E0000130380 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = mDNSResponder.8;
+ path = ../mDNSShared/mDNSResponder.8;
+ refType = 2;
+ };
+ FF5585E507790732008D1C14 = {
+ buildActionMask = 8;
+ files = (
+ );
+ generatedFileNames = (
+ );
+ isa = PBXShellScriptBuildPhase;
+ neededFileNames = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/tcsh;
+ shellScript = "# Install plist to tell launchd to start mDNSResponder\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons\ncp ${SRCROOT}/LaunchDaemonInfo.plist ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponder.plist\n\n# 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 (not necessary, but required by B&I policy)\nforeach file (`find ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -name Localizable.strings`)\niconv -f utf-8 -t utf-16 ${file} > ${file}.new\nmv -f ${file}.new ${file}\nend\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";
+ };
+ FF5A0AE705632EA600743C27 = {
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ FF5A0AE805632EAE00743C27,
+ );
+ isa = PBXCopyFilesBuildPhase;
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FF5A0AE805632EAE00743C27 = {
+ fileRef = FF485D5105632E0000130380;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FFCB6D73075D539900B8AF62 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = PlatformCommon.c;
+ path = ../mDNSShared/PlatformCommon.c;
+ refType = 2;
+ };
+ FFCB6D74075D539900B8AF62 = {
+ fileRef = FFCB6D73075D539900B8AF62;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FFCB6D75075D595E00B8AF62 = {
+ fileRef = FFCB6D73075D539900B8AF62;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FFD41DDA0664157900F0C438 = {
+ includeInIndex = 0;
+ isa = PBXZipArchiveReference;
+ path = dns_sd.jar;
+ refType = 3;
+ };
+ FFD41DDB0664169900F0C438 = {
+ isa = PBXTargetDependency;
+ target = DB2CC4530662DD6800335AB3;
+ };
+ FFD41DDC0664169B00F0C438 = {
+ isa = PBXTargetDependency;
+ target = DB2CC4660662DF5C00335AB3;
+ };
+ FFD41DDD06641B4200F0C438 = {
+ buildActionMask = 2147483647;
+ files = (
+ );
+ generatedFileNames = (
+ );
+ isa = PBXShellScriptBuildPhase;
+ neededFileNames = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "rm -f ${CONFIGURATION_BUILD_DIR}/dns_sd";
+ };
+ FFD41DDF06641BBB00F0C438 = {
+ isa = PBXTargetDependency;
+ target = DB2CC4530662DD6800335AB3;
+ };
+ FFE6935007C2CA7F00283007 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = ConfigurationAuthority.h;
+ path = PreferencePane/ConfigurationAuthority.h;
+ refType = 2;
+ };
+ FFE6935207C2CAA400283007 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = DNSServiceDiscoveryPref.h;
+ path = PreferencePane/DNSServiceDiscoveryPref.h;
+ refType = 2;
+ };
+ FFE6935407C2CABD00283007 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = PrivilegedOperations.h;
+ path = PreferencePane/PrivilegedOperations.h;
+ refType = 2;
+ };
+ FFF4F63A06CFE4DD00459EFD = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ name = dnsextd.8;
+ path = ../mDNSShared/dnsextd.8;
+ refType = 2;
+ };
+ FFF4F63B06CFE4DD00459EFD = {
+ fileRef = FFF4F63A06CFE4DD00459EFD;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FFF4F63C06CFE53300459EFD = {
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FFF4F63D06CFE54300459EFD,
+ );
+ isa = PBXCopyFilesBuildPhase;
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FFF4F63D06CFE54300459EFD = {
+ fileRef = FF0E0B5D065ADC7600FE4D9C;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FFF7174A07614A8600E10551 = {
+ buildActionMask = 2147483647;
+ files = (
+ );
+ generatedFileNames = (
+ );
+ isa = PBXShellScriptBuildPhase;
+ neededFileNames = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "if [ -e /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\ncc ${CONFIGURATION_TEMP_DIR}/empty.c -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f ${CONFIGURATION_TEMP_DIR}/empty.c\nfi";
+ };
+ FFFB0DA407B43BED00B88D48 = {
+ children = (
+ FFE6935007C2CA7F00283007,
+ FFFB0DAE07B43CBA00B88D48,
+ FFE6935207C2CAA400283007,
+ FFFB0DAC07B43CBA00B88D48,
+ FFE6935407C2CABD00283007,
+ FFFB0DAD07B43CBA00B88D48,
+ FFFB0DAF07B43CBA00B88D48,
+ FF260A2307B4463400CE10E5,
+ );
+ isa = PBXGroup;
+ path = PreferencePane;
+ refType = 2;
+ };
+ FFFB0DA507B43C9100B88D48 = {
+ buildActionMask = 2147483647;
+ files = (
+ );
+ isa = PBXHeadersBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FFFB0DA607B43C9100B88D48 = {
+ buildActionMask = 2147483647;
+ files = (
+ FFFB0DB307B43CBA00B88D48,
+ );
+ isa = PBXSourcesBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FFFB0DA707B43C9100B88D48 = {
+ buildActionMask = 2147483647;
+ files = (
+ FFFB0DB507B43D2700B88D48,
+ FFFB0DB907B43D5F00B88D48,
+ FFFB0DBD07B43D7400B88D48,
+ FF260A2207B443C500CE10E5,
+ );
+ isa = PBXFrameworksBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FFFB0DA807B43C9100B88D48 = {
+ buildActionMask = 2147483647;
+ files = (
+ );
+ isa = PBXRezBuildPhase;
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FFFB0DA907B43C9100B88D48 = {
+ buildPhases = (
+ FFFB0DA507B43C9100B88D48,
+ FFFB0DA607B43C9100B88D48,
+ FFFB0DA707B43C9100B88D48,
+ FFFB0DA807B43C9100B88D48,
+ );
+ buildSettings = {
+ INSTALL_PATH = "/Library/Application Support/Bonjour";
+ MACOSX_DEPLOYMENT_TARGET = 10.2;
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = "";
+ OTHER_REZFLAGS = "";
+ PRODUCT_NAME = ddnswriteconfig;
+ REZ_EXECUTABLE = YES;
+ SECTORDER_FLAGS = "";
+ STRIPFLAGS = "-S";
+ WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas";
+ };
+ dependencies = (
+ );
+ isa = PBXToolTarget;
+ name = ddnswriteconfig;
+ productInstallPath = "/Library/Application Support/Bonjour";
+ productName = ddnswriteconfig;
+ productReference = FFFB0DAA07B43C9100B88D48;
+ };
+ FFFB0DAA07B43C9100B88D48 = {
+ isa = PBXExecutableFileReference;
+ path = ddnswriteconfig;
+ refType = 3;
+ };
+ FFFB0DAC07B43CBA00B88D48 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ path = DNSServiceDiscoveryPref.m;
+ refType = 4;
+ };
+ FFFB0DAD07B43CBA00B88D48 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ path = PrivilegedOperations.c;
+ refType = 4;
+ };
+ FFFB0DAE07B43CBA00B88D48 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ path = ConfigurationAuthority.c;
+ refType = 4;
+ };
+ FFFB0DAF07B43CBA00B88D48 = {
+ fileEncoding = 4;
+ isa = PBXFileReference;
+ path = ddnswriteconfig.m;
+ refType = 4;
+ };
+ FFFB0DB307B43CBA00B88D48 = {
+ fileRef = FFFB0DAF07B43CBA00B88D48;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FFFB0DB407B43D2700B88D48 = {
+ isa = PBXFrameworkReference;
+ name = Foundation.framework;
+ path = /System/Library/Frameworks/Foundation.framework;
+ refType = 0;
+ };
+ FFFB0DB507B43D2700B88D48 = {
+ fileRef = FFFB0DB407B43D2700B88D48;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FFFB0DB907B43D5F00B88D48 = {
+ fileRef = 7F869685066EE02400D2A2DC;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ FFFB0DBD07B43D7400B88D48 = {
+ fileRef = 65713D46025A293200000109;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
+ };
+ rootObject = 08FB7793FE84155DC02AAC07;
+}
diff --git a/mDNSResponder/mDNSMacOSX/mDNSResponder.plist b/mDNSResponder/mDNSMacOSX/mDNSResponder.plist
new file mode 100644
index 00000000..6150bc37
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/mDNSResponder.plist
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<array>
+<dict>
+ <key>OpenSourceProject</key>
+ <string>libipsec</string>
+ <key>OpenSourceVersion</key>
+ <string>Original version number unavailable, possibly RELENG_4_9_0_RELEASE</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org</string>
+ <key>OpenSourceSCM</key>
+ <string>svn export http://svn.freebsd.org/base/release/4.9.0/lib/libipsec</string>
+ <key>OpenSourceImportDate</key>
+ <string>2007-07-31</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>Removed all files except ipsec_strerror.h libpfkey.h pfkey.c</string>
+ <string>Added Apple Computer copyright and Apache license</string>
+ <string>Removed unused include netkey/key_var.h</string>
+ <string>Fixed compiler warnings such as "unused function parameter" and "signed/unsigned comparison"</string>
+ <string>Added code to conditionally compile only on OSX</string>
+ <string>Whitespace changes</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>bsd</string>
+ <key>OpenSourceLicenseFile</key>
+ <string>mDNSResponder.txt</string>
+</dict>
+</array>
+</plist>
diff --git a/mDNSResponder/mDNSMacOSX/mDNSResponder.sb b/mDNSResponder/mDNSMacOSX/mDNSResponder.sb
new file mode 100644
index 00000000..eee623c8
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/mDNSResponder.sb
@@ -0,0 +1,151 @@
+; -*- Mode: Scheme; tab-width: 4 -*-
+;
+; Copyright (c) 2012 Apple 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.
+;
+;############################################################################
+
+
+; WARNING: The sandbox rule capabilities and syntax used in this file are currently an
+; Apple SPI (System Private Interface) and are subject to change at any time without notice.
+
+(version 1)
+; When mDNSResponder is denied access, we want to avoid symoblification of mDNSResponder
+; to get the stack trace as that can get into deadlock. no-callout will prevent
+; symbolification.
+(deny default (with no-callout))
+
+(import "system.sb")
+
+; Baseline
+(allow file-read-metadata ipc-posix-shm)
+
+; Mach communications
+; These are needed for things like getpwnam, hostname changes, & keychain
+(allow mach-lookup
+ (global-name "com.apple.bsd.dirhelper")
+ (global-name "com.apple.distributed_notifications.2")
+ (global-name "com.apple.ocspd")
+ (global-name "com.apple.PowerManagement.control")
+ (global-name "com.apple.mDNSResponderHelper")
+ (global-name "com.apple.SecurityServer")
+ (global-name "com.apple.SystemConfiguration.configd")
+ (global-name "com.apple.SystemConfiguration.SCNetworkReachability")
+ (global-name "com.apple.SystemConfiguration.DNSConfiguration")
+ (global-name "com.apple.SystemConfiguration.NetworkInformation")
+ (global-name "com.apple.system.notification_center")
+ (global-name "com.apple.system.logger")
+ (global-name "com.apple.webcontentfilter.dns")
+ (global-name "com.apple.server.bluetooth")
+ (global-name "com.apple.awacs")
+ (global-name "com.apple.networkd")
+ (global-name "com.apple.securityd")
+ (global-name "com.apple.wifi.manager")
+ (global-name "com.apple.commcenter.cupolicy.xpc")
+ (global-name "com.apple.blued")
+ (global-name "com.apple.mobilegestalt.xpc")
+ (global-name "com.apple.snhelper"))
+
+(allow mach-register
+ (global-name "com.apple.d2d.ipc"))
+
+; Networking, including Unix Domain Sockets
+(allow network*)
+
+; Raw sockets
+(if (defined? 'system-socket)
+ (allow system-socket))
+
+; Hardware model information
+(allow sysctl-read)
+
+; Syslog early in the boot process
+(allow file-read-data file-write-data (literal "/dev/console"))
+
+(allow file-read-data
+ ; /etc/hosts support
+ (literal "/private/etc/hosts")
+ (literal "/private/etc"))
+
+; Our socket
+(allow file-read* file-write* (literal "/private/var/run/mDNSResponder"))
+
+; System version, settings, and other miscellaneous necessary file system accesses
+(allow file-read-data
+ ; Needed for CFCopyVersionDictionary()
+ (literal "/usr/sbin")
+ (literal "/usr/sbin/mDNSResponder")
+
+ (literal "/Library/Preferences/SystemConfiguration/preferences.plist")
+ (literal "/Library/Preferences/SystemConfiguration/com.apple.nat.plist")
+ (regex #"^/Library/Preferences/(ByHost/)?\.GlobalPreferences\.")
+ (literal "/Library/Preferences/com.apple.crypto.plist")
+ (literal "/Library/Security/Trust Settings/Admin.plist")
+ (regex #"^/Library/Preferences/com\.apple\.security\.")
+ (literal "/Library/Preferences/SystemConfiguration/com.apple.PowerManagement.plist")
+ (literal "/private/var/preferences/SystemConfiguration/preferences.plist"))
+
+; For MAC Address
+(allow system-info (info-type "net.link.addr"))
+
+; We just need access to System.keychain. But we don't want errors logged if other keychains are
+; accessed under /Library/Keychains. Other keychains may be accessed as part of setting up an SSL
+; connection. Instead of adding access to it here (to things which we don't need), we disable any
+; logging that might happen during the access
+(deny file-read-data (regex #"^/Library/Keychains/") (with no-log))
+(allow file-read-data (literal "/Library/Keychains/System.keychain"))
+
+; Access to mDNSResponder Managed Preferences profile
+; instead of using (mobile-preferences-read "com.apple.mDNSResponder") we use the lines below for OSX compatibility
+(allow file-read* (literal "/private/var/Managed Preferences/mobile"))
+(allow file-read* (literal "/private/var/Library/Preferences/"))
+(allow file-read* (literal "/Library/Managed Preferences"))
+(allow file-read* (literal "/private/var/Managed Preferences/mobile/com.apple.mDNSResponder.plist"))
+
+; Our Module Directory Services cache
+(allow file-read-data
+ (subpath "/private/var/tmp/mds")
+ (subpath "/private/var/db/mds"))
+
+(allow file-read* file-write*
+ (regex #"^/private/var/tmp/mds/[0-9]+(/|$)")
+ (regex #"^/private/var/db/mds/[0-9]+(/|$)")
+ (regex #"^/private/var/folders/[^/]+/[^/]+/C/mds(/|$)")
+
+ ; Required on 10.5 and 10.6
+ (regex #"^/private/var/folders/[^/]+/[^/]+/-Caches-/mds(/|$)"))
+
+; CRL Cache for SSL/TLS connections
+(allow file-read-data (literal "/private/var/db/crls/crlcache.db"))
+
+; For mDNS sleep proxy offload and IOPMConnectionCreate
+(if (defined? 'iokit-open)
+ (begin
+ (allow iokit-open
+ (iokit-user-client-class "NVEthernetUserClientMDNS")
+ (iokit-user-client-class "mDNSOffloadUserClient")
+ (iokit-user-client-class "wlDNSOffloadUserClient")
+ (iokit-user-client-class "RootDomainUserClient")
+ (iokit-user-client-class "AppleMobileFileIntegrityUserClient"))))
diff --git a/mDNSResponder/mDNSMacOSX/mDNSResponder.txt b/mDNSResponder/mDNSMacOSX/mDNSResponder.txt
new file mode 100644
index 00000000..f798e565
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/mDNSResponder.txt
@@ -0,0 +1,55 @@
+1)
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * 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 the project 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 THE PROJECT AND 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 THE PROJECT OR 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.
+
+2)
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * 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 the project 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 THE PROJECT AND 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 THE PROJECT OR 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.
diff --git a/mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj b/mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
new file mode 100644
index 00000000..a5c44ef3
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
@@ -0,0 +1,3137 @@
+// !$*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_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/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_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 [ \"${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 */;
+}
diff --git a/mDNSResponder/mDNSMacOSX/mDNSResponderHelper.8 b/mDNSResponder/mDNSMacOSX/mDNSResponderHelper.8
new file mode 100644
index 00000000..6e959dbd
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/mDNSResponderHelper.8
@@ -0,0 +1,54 @@
+.\" -*- tab-width: 4 -*-
+.\"
+.\" Copyright (c) 2007 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.
+.\"
+.Dd August 2007 \" Date
+.Dt mDNSResponderHelper 8 \" Document Title
+.Os Darwin \" Operating System
+.\"
+.Sh NAME
+.Nm mDNSResponderHelper
+.Nd mDNS privilege separation helper \" Name Description for whatis database
+.\"
+.Sh SYNOPSIS
+.Nm
+.\"
+.Sh DESCRIPTION
+.Nm
+is an executable invoked by
+.Nm launchd
+to provide privilege separation
+to the
+.Nm mDNSResponder
+daemon.
+.Pp
+.Nm
+has no user-specifiable command-line arguments, and users should not run
+.Nm
+manually.
+.Sh FILES
+.Pa /usr/sbin/mDNSResponderHelper \" Pathname
+.\"
+.Sh SEE ALSO
+.Xr mDNSResponder 8
+.\"
+.Sh BUGS
+.Nm
+bugs are tracked in Apple Radar component "mDNSResponder".
+.\"
+.Sh HISTORY
+The
+.Nm
+first appeared in Mac OS X 10.5 (Leopard).
diff --git a/mDNSResponder/mDNSMacOSX/mDNSResponderHelper.plist b/mDNSResponder/mDNSMacOSX/mDNSResponderHelper.plist
new file mode 100644
index 00000000..22286d2e
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/mDNSResponderHelper.plist
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<!-- To run mDNSResponderHelper on Tiger, place this file into /etc/mach_init.d -->
+<plist version="1.0">
+<dict>
+ <key>ServiceName</key>
+ <string>com.apple.mDNSResponderHelper</string>
+ <key>Command</key>
+ <string>/usr/sbin/mDNSResponderHelper</string>
+ <key>OnDemand</key>
+ <true/>
+</dict>
+</plist>
diff --git a/mDNSResponder/mDNSMacOSX/mDNSResponderLogging.mobileconfig b/mDNSResponder/mDNSMacOSX/mDNSResponderLogging.mobileconfig
new file mode 100644
index 00000000..34ec0d9a
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/mDNSResponderLogging.mobileconfig
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>PayloadIdentifier</key>
+ <string>com.apple.mDNSResponder</string>
+ <key>PayloadUUID</key>
+ <string>6D0962E1-558A-44FB-8FE0-1F4F0BD157F4</string>
+ <key>PayloadDescription</key>
+ <string>Turns on mDNSResponder Debug Logging</string>
+ <key>PayloadDisplayName</key>
+ <string>mDNSResponder Debug Logging</string>
+ <key>PayloadOrganization</key>
+ <string>Apple, Inc</string>
+ <key>PayloadType</key>
+ <string>Configuration</string>
+ <key>PayloadVersion</key>
+ <integer>2</integer>
+
+ <key>ConsentText</key>
+ <dict>
+ <key>en</key>
+ <string>English consent text</string>
+ <key>jp</key>
+ <string>Japanese consent text</string>
+ <key>default</key>
+ <string>Default consent text - used if none of the other languages match</string>
+ </dict>
+
+ <key>PayloadContent</key>
+ <array>
+ <dict>
+ <key>PayloadUUID</key>
+ <string>6D0962E1-558A-44FB-8FE0-1F4F0BD157F4</string>
+ <key>PayloadIdentifier</key>
+ <string>com.apple.defaults.1</string>
+ <key>PayloadType</key>
+ <string>com.apple.defaults.managed</string>
+ <key>PayloadVersion</key>
+ <integer>1</integer>
+ <key>PayloadContent</key>
+ <array>
+ <dict>
+ <key>DefaultsDomainName</key>
+ <string>com.apple.mDNSResponder</string>
+ <key>DefaultsData</key>
+ <dict>
+ <key>EnableLogging</key>
+ <true/>
+ </dict>
+ </dict>
+ </array>
+ </dict>
+ </array>
+</dict>
+</plist>
+
diff --git a/mDNSResponder/mDNSMacOSX/pfkey.c b/mDNSResponder/mDNSMacOSX/pfkey.c
new file mode 100644
index 00000000..839c8d71
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/pfkey.c
@@ -0,0 +1,2138 @@
+/*
+ * Copyright (c) 2003-2007 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.
+ */
+/* $FreeBSD: src/lib/libipsec/pfkey.c,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $ */
+/* $KAME: pfkey.c,v 1.39 2001/03/05 18:22:17 thorpej Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * 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 the project 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 THE PROJECT AND 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 THE PROJECT OR 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <net/pfkeyv2.h>
+#include <netinet/in.h>
+#include <netinet6/ipsec.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <TargetConditionals.h>
+
+#include "ipsec_strerror.h"
+#include "libpfkey.h"
+#include "ipsec_options.h"
+
+#if TARGET_OS_EMBEDDED
+#ifndef MDNS_NO_IPSEC
+#define MDNS_NO_IPSEC 1
+#endif
+#endif
+
+#ifndef MDNS_NO_IPSEC
+
+#define CALLOC(size, cast) (cast)calloc(1, (size))
+
+static int findsupportedmap __P((int));
+static int setsupportedmap __P((struct sadb_supported *));
+static struct sadb_alg *findsupportedalg __P((u_int, u_int));
+static int pfkey_send_x1 __P((int, u_int, u_int, u_int, struct sockaddr *,
+ struct sockaddr *, u_int32_t, u_int32_t, u_int, caddr_t,
+ u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int32_t,
+ u_int32_t, u_int32_t, u_int32_t));
+static int pfkey_send_x2 __P((int, u_int, u_int, u_int,
+ struct sockaddr *, struct sockaddr *, u_int32_t));
+static int pfkey_send_x3 __P((int, u_int, u_int));
+static int pfkey_send_x4 __P((int, u_int, struct sockaddr *, u_int,
+ struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t,
+ char *, int, u_int32_t));
+static int pfkey_send_x5 __P((int, u_int, u_int32_t));
+
+static caddr_t pfkey_setsadbmsg __P((caddr_t, caddr_t, u_int, u_int,
+ u_int, u_int32_t, pid_t));
+static caddr_t pfkey_setsadbsa __P((caddr_t, caddr_t, u_int32_t, u_int,
+ u_int, u_int, u_int32_t));
+static caddr_t pfkey_setsadbaddr __P((caddr_t, caddr_t, u_int,
+ struct sockaddr *, u_int, u_int));
+static caddr_t pfkey_setsadbkey __P((caddr_t, caddr_t, u_int, caddr_t, u_int));
+static caddr_t pfkey_setsadblifetime __P((caddr_t, caddr_t, u_int, u_int32_t,
+ u_int32_t, u_int32_t, u_int32_t));
+static caddr_t pfkey_setsadbxsa2 __P((caddr_t, caddr_t, u_int32_t, u_int32_t));
+
+/*
+ * make and search supported algorithm structure.
+ */
+static struct sadb_supported *ipsec_supported[] = { NULL, NULL, NULL, };
+
+static int supported_map[] = {
+ SADB_SATYPE_AH,
+ SADB_SATYPE_ESP,
+ SADB_X_SATYPE_IPCOMP,
+};
+
+static int
+findsupportedmap(satype)
+int satype;
+{
+ int i;
+
+ for (i = 0; (unsigned int)i < sizeof(supported_map)/sizeof(supported_map[0]); i++)
+ if (supported_map[i] == satype)
+ return i;
+ return -1;
+}
+
+static struct sadb_alg *
+findsupportedalg(satype, alg_id)
+u_int satype, alg_id;
+{
+ int algno;
+ int tlen;
+ caddr_t p;
+
+ /* validity check */
+ algno = findsupportedmap(satype);
+ if (algno == -1) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return NULL;
+ }
+ if (ipsec_supported[algno] == NULL) {
+ __ipsec_errcode = EIPSEC_DO_GET_SUPP_LIST;
+ return NULL;
+ }
+
+ tlen = ipsec_supported[algno]->sadb_supported_len
+ - sizeof(struct sadb_supported);
+ p = (caddr_t)(ipsec_supported[algno] + 1);
+ while (tlen > 0) {
+ if ((unsigned int)tlen < sizeof(struct sadb_alg)) {
+ /* invalid format */
+ break;
+ }
+ if (((struct sadb_alg *)p)->sadb_alg_id == alg_id)
+ return (struct sadb_alg *)p;
+
+ tlen -= sizeof(struct sadb_alg);
+ p += sizeof(struct sadb_alg);
+ }
+
+ __ipsec_errcode = EIPSEC_NOT_SUPPORTED;
+ return NULL;
+}
+
+static int
+setsupportedmap(sup)
+struct sadb_supported *sup;
+{
+ struct sadb_supported **ipsup;
+
+ switch (sup->sadb_supported_exttype) {
+ case SADB_EXT_SUPPORTED_AUTH:
+ ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_AH)];
+ break;
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_ESP)];
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+
+ if (*ipsup)
+ free(*ipsup);
+
+ *ipsup = malloc(sup->sadb_supported_len);
+ if (!*ipsup) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ memcpy(*ipsup, sup, sup->sadb_supported_len);
+
+ return 0;
+}
+
+/*
+ * check key length against algorithm specified.
+ * This function is called with SADB_EXT_SUPPORTED_{AUTH,ENCRYPT} as the
+ * augument, and only calls to ipsec_check_keylen2();
+ * keylen is the unit of bit.
+ * OUT:
+ * -1: invalid.
+ * 0: valid.
+ */
+int
+ipsec_check_keylen(supported, alg_id, keylen)
+u_int supported;
+u_int alg_id;
+u_int keylen;
+{
+ int satype;
+
+ /* validity check */
+ switch (supported) {
+ case SADB_EXT_SUPPORTED_AUTH:
+ satype = SADB_SATYPE_AH;
+ break;
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ satype = SADB_SATYPE_ESP;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ return ipsec_check_keylen2(satype, alg_id, keylen);
+}
+
+/*
+ * check key length against algorithm specified.
+ * satype is one of satype defined at pfkeyv2.h.
+ * keylen is the unit of bit.
+ * OUT:
+ * -1: invalid.
+ * 0: valid.
+ */
+int
+ipsec_check_keylen2(satype, alg_id, keylen)
+u_int satype;
+u_int alg_id;
+u_int keylen;
+{
+ struct sadb_alg *alg;
+
+ alg = findsupportedalg(satype, alg_id);
+ if (!alg)
+ return -1;
+
+ if (keylen < alg->sadb_alg_minbits || keylen > alg->sadb_alg_maxbits) {
+ __ipsec_errcode = EIPSEC_INVAL_KEYLEN;
+ return -1;
+ }
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+/*
+ * get max/min key length against algorithm specified.
+ * satype is one of satype defined at pfkeyv2.h.
+ * keylen is the unit of bit.
+ * OUT:
+ * -1: invalid.
+ * 0: valid.
+ */
+int
+ipsec_get_keylen(supported, alg_id, alg0)
+u_int supported, alg_id;
+struct sadb_alg *alg0;
+{
+ struct sadb_alg *alg;
+ u_int satype;
+
+ /* validity check */
+ if (!alg0) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ switch (supported) {
+ case SADB_EXT_SUPPORTED_AUTH:
+ satype = SADB_SATYPE_AH;
+ break;
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ satype = SADB_SATYPE_ESP;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ alg = findsupportedalg(satype, alg_id);
+ if (!alg)
+ return -1;
+
+ memcpy(alg0, alg, sizeof(*alg0));
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+/*
+ * set the rate for SOFT lifetime against HARD one.
+ * If rate is more than 100 or equal to zero, then set to 100.
+ */
+static u_int soft_lifetime_allocations_rate = PFKEY_SOFT_LIFETIME_RATE;
+static u_int soft_lifetime_bytes_rate = PFKEY_SOFT_LIFETIME_RATE;
+static u_int soft_lifetime_addtime_rate = PFKEY_SOFT_LIFETIME_RATE;
+static u_int soft_lifetime_usetime_rate = PFKEY_SOFT_LIFETIME_RATE;
+
+u_int
+pfkey_set_softrate(type, rate)
+u_int type, rate;
+{
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+
+ if (rate > 100 || rate == 0)
+ rate = 100;
+
+ switch (type) {
+ case SADB_X_LIFETIME_ALLOCATIONS:
+ soft_lifetime_allocations_rate = rate;
+ return 0;
+ case SADB_X_LIFETIME_BYTES:
+ soft_lifetime_bytes_rate = rate;
+ return 0;
+ case SADB_X_LIFETIME_ADDTIME:
+ soft_lifetime_addtime_rate = rate;
+ return 0;
+ case SADB_X_LIFETIME_USETIME:
+ soft_lifetime_usetime_rate = rate;
+ return 0;
+ }
+
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return 1;
+}
+
+/*
+ * get current rate for SOFT lifetime against HARD one.
+ * ATTENTION: ~0 is returned if invalid type was passed.
+ */
+u_int
+pfkey_get_softrate(type)
+u_int type;
+{
+ switch (type) {
+ case SADB_X_LIFETIME_ALLOCATIONS:
+ return soft_lifetime_allocations_rate;
+ case SADB_X_LIFETIME_BYTES:
+ return soft_lifetime_bytes_rate;
+ case SADB_X_LIFETIME_ADDTIME:
+ return soft_lifetime_addtime_rate;
+ case SADB_X_LIFETIME_USETIME:
+ return soft_lifetime_usetime_rate;
+ }
+
+ return ~0;
+}
+
+/*
+ * sending SADB_GETSPI message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq)
+int so;
+u_int satype, mode;
+struct sockaddr *src, *dst;
+u_int32_t min, max, reqid, seq;
+{
+ struct sadb_msg *newmsg;
+ caddr_t ep;
+ int len;
+ int need_spirange = 0;
+ caddr_t p;
+ int plen;
+
+ /* validity check */
+ if (src == NULL || dst == NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+ if (src->sa_family != dst->sa_family) {
+ __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+ if (min > max || (min > 0 && min <= 255)) {
+ __ipsec_errcode = EIPSEC_INVAL_SPI;
+ return -1;
+ }
+ switch (src->sa_family) {
+ case AF_INET:
+ plen = sizeof(struct in_addr) << 3;
+ break;
+ case AF_INET6:
+ plen = sizeof(struct in6_addr) << 3;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+ return -1;
+ }
+
+ /* create new sadb_msg to send. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(struct sadb_x_sa2)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(src->sa_len)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(dst->sa_len);
+
+ if (min > (u_int32_t)255 && max < (u_int32_t) ~0) {
+ need_spirange++;
+ len += sizeof(struct sadb_spirange);
+ }
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ ep = ((caddr_t)newmsg) + len;
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_GETSPI,
+ len, satype, seq, getpid());
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+
+ p = pfkey_setsadbxsa2(p, ep, mode, reqid);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* set sadb_address for source */
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* set sadb_address for destination */
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* proccessing spi range */
+ if (need_spirange) {
+ struct sadb_spirange spirange;
+
+ if (p + sizeof(spirange) > ep) {
+ free(newmsg);
+ return -1;
+ }
+
+ memset(&spirange, 0, sizeof(spirange));
+ spirange.sadb_spirange_len = PFKEY_UNIT64(sizeof(spirange));
+ spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE;
+ spirange.sadb_spirange_min = min;
+ spirange.sadb_spirange_max = max;
+
+ memcpy(p, &spirange, sizeof(spirange));
+
+ p += sizeof(spirange);
+ }
+ if (p != ep) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/*
+ * sending SADB_UPDATE message to the kernel.
+ * The length of key material is a_keylen + e_keylen.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_update(so, satype, mode, src, dst, spi, reqid, wsize,
+ keymat, e_type, e_keylen, a_type, a_keylen, flags,
+ l_alloc, l_bytes, l_addtime, l_usetime, seq)
+int so;
+u_int satype, mode, wsize;
+struct sockaddr *src, *dst;
+u_int32_t spi, reqid;
+caddr_t keymat;
+u_int e_type, e_keylen, a_type, a_keylen, flags;
+u_int32_t l_alloc;
+u_int64_t l_bytes, l_addtime, l_usetime;
+u_int32_t seq;
+{
+ int len;
+ if ((len = pfkey_send_x1(so, SADB_UPDATE, satype, mode, src, dst, spi,
+ reqid, wsize,
+ keymat, e_type, e_keylen, a_type, a_keylen, flags,
+ l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_ADD message to the kernel.
+ * The length of key material is a_keylen + e_keylen.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_add(so, satype, mode, src, dst, spi, reqid, wsize,
+ keymat, e_type, e_keylen, a_type, a_keylen, flags,
+ l_alloc, l_bytes, l_addtime, l_usetime, seq)
+int so;
+u_int satype, mode, wsize;
+struct sockaddr *src, *dst;
+u_int32_t spi, reqid;
+caddr_t keymat;
+u_int e_type, e_keylen, a_type, a_keylen, flags;
+u_int32_t l_alloc;
+u_int64_t l_bytes, l_addtime, l_usetime;
+u_int32_t seq;
+{
+ int len;
+ if ((len = pfkey_send_x1(so, SADB_ADD, satype, mode, src, dst, spi,
+ reqid, wsize,
+ keymat, e_type, e_keylen, a_type, a_keylen, flags,
+ l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_DELETE message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_delete(so, satype, mode, src, dst, spi)
+int so;
+u_int satype, mode;
+struct sockaddr *src, *dst;
+u_int32_t spi;
+{
+ int len;
+ if ((len = pfkey_send_x2(so, SADB_DELETE, satype, mode, src, dst, spi)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_DELETE without spi to the kernel. This is
+ * the "delete all" request (an extension also present in
+ * Solaris).
+ *
+ * OUT:
+ * positive: success and return length sent
+ * -1 : error occured, and set errno
+ */
+int
+pfkey_send_delete_all(so, satype, mode, src, dst)
+int so;
+u_int satype, mode;
+struct sockaddr *src, *dst;
+{
+ struct sadb_msg *newmsg;
+ int len;
+ caddr_t p;
+ int plen;
+ caddr_t ep;
+
+ (void)mode;
+
+ /* validity check */
+ if (src == NULL || dst == NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+ if (src->sa_family != dst->sa_family) {
+ __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+ switch (src->sa_family) {
+ case AF_INET:
+ plen = sizeof(struct in_addr) << 3;
+ break;
+ case AF_INET6:
+ plen = sizeof(struct in6_addr) << 3;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+ return -1;
+ }
+
+ /* create new sadb_msg to reply. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(src->sa_len)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(dst->sa_len);
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ ep = ((caddr_t)newmsg) + len;
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_DELETE, len, satype, 0,
+ getpid());
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p || p != ep) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/*
+ * sending SADB_GET message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_get(so, satype, mode, src, dst, spi)
+int so;
+u_int satype, mode;
+struct sockaddr *src, *dst;
+u_int32_t spi;
+{
+ int len;
+ if ((len = pfkey_send_x2(so, SADB_GET, satype, mode, src, dst, spi)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_REGISTER message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_register(so, satype)
+int so;
+u_int satype;
+{
+ int len, algno;
+
+ if (satype == PF_UNSPEC) {
+ for (algno = 0;
+ (unsigned int)algno < sizeof(supported_map)/sizeof(supported_map[0]);
+ algno++) {
+ if (ipsec_supported[algno]) {
+ free(ipsec_supported[algno]);
+ ipsec_supported[algno] = NULL;
+ }
+ }
+ } else {
+ algno = findsupportedmap(satype);
+ if (algno == -1) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ if (ipsec_supported[algno]) {
+ free(ipsec_supported[algno]);
+ ipsec_supported[algno] = NULL;
+ }
+ }
+
+ if ((len = pfkey_send_x3(so, SADB_REGISTER, satype)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * receiving SADB_REGISTER message from the kernel, and copy buffer for
+ * sadb_supported returned into ipsec_supported.
+ * OUT:
+ * 0: success and return length sent.
+ * -1: error occured, and set errno.
+ */
+int
+pfkey_recv_register(so)
+int so;
+{
+ pid_t pid = getpid();
+ struct sadb_msg *newmsg;
+ int error = -1;
+
+ /* receive message */
+ do {
+ if ((newmsg = pfkey_recv(so)) == NULL)
+ return -1;
+ } while (newmsg->sadb_msg_type != SADB_REGISTER
+ || (pid_t)newmsg->sadb_msg_pid != pid);
+
+ /* check and fix */
+ newmsg->sadb_msg_len = PFKEY_UNUNIT64(newmsg->sadb_msg_len);
+
+ error = pfkey_set_supported(newmsg, newmsg->sadb_msg_len);
+ free(newmsg);
+
+ if (error == 0)
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+
+ return error;
+}
+
+/*
+ * receiving SADB_REGISTER message from the kernel, and copy buffer for
+ * sadb_supported returned into ipsec_supported.
+ * NOTE: sadb_msg_len must be host order.
+ * IN:
+ * tlen: msg length, it's to makeing sure.
+ * OUT:
+ * 0: success and return length sent.
+ * -1: error occured, and set errno.
+ */
+int
+pfkey_set_supported(msg, tlen)
+struct sadb_msg *msg;
+int tlen;
+{
+ struct sadb_supported *sup;
+ caddr_t p;
+ caddr_t ep;
+
+ /* validity */
+ if (msg->sadb_msg_len != tlen) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ p = (caddr_t)msg;
+ ep = p + tlen;
+
+ p += sizeof(struct sadb_msg);
+
+ while (p < ep) {
+ sup = (struct sadb_supported *)p;
+ if (ep < p + sizeof(*sup) ||
+ (size_t)PFKEY_EXTLEN(sup) < sizeof(*sup) ||
+ ep < p + sup->sadb_supported_len) {
+ /* invalid format */
+ break;
+ }
+
+ switch (sup->sadb_supported_exttype) {
+ case SADB_EXT_SUPPORTED_AUTH:
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+
+ /* fixed length */
+ sup->sadb_supported_len = PFKEY_EXTLEN(sup);
+
+ /* set supported map */
+ if (setsupportedmap(sup) != 0)
+ return -1;
+
+ p += sup->sadb_supported_len;
+ }
+
+ if (p != ep) {
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+
+ return 0;
+}
+
+/*
+ * sending SADB_FLUSH message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_flush(so, satype)
+int so;
+u_int satype;
+{
+ int len;
+
+ if ((len = pfkey_send_x3(so, SADB_FLUSH, satype)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_DUMP message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_dump(so, satype)
+int so;
+u_int satype;
+{
+ int len;
+
+ if ((len = pfkey_send_x3(so, SADB_DUMP, satype)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_PROMISC message to the kernel.
+ * NOTE that this function handles promisc mode toggle only.
+ * IN:
+ * flag: set promisc off if zero, set promisc on if non-zero.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ * 0 : error occured, and set errno.
+ * others: a pointer to new allocated buffer in which supported
+ * algorithms is.
+ */
+int
+pfkey_send_promisc_toggle(so, flag)
+int so;
+int flag;
+{
+ int len;
+
+ if ((len = pfkey_send_x3(so, SADB_X_PROMISC, (flag ? 1 : 0))) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDADD message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdadd(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
+int so;
+struct sockaddr *src, *dst;
+u_int prefs, prefd, proto;
+caddr_t policy;
+int policylen;
+u_int32_t seq;
+{
+ int len;
+
+ if ((len = pfkey_send_x4(so, SADB_X_SPDADD,
+ src, prefs, dst, prefd, proto,
+ 0, 0,
+ policy, policylen, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDADD message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdadd2(so, src, prefs, dst, prefd, proto, ltime, vtime,
+ policy, policylen, seq)
+int so;
+struct sockaddr *src, *dst;
+u_int prefs, prefd, proto;
+u_int64_t ltime, vtime;
+caddr_t policy;
+int policylen;
+u_int32_t seq;
+{
+ int len;
+
+ if ((len = pfkey_send_x4(so, SADB_X_SPDADD,
+ src, prefs, dst, prefd, proto,
+ ltime, vtime,
+ policy, policylen, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDUPDATE message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdupdate(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
+int so;
+struct sockaddr *src, *dst;
+u_int prefs, prefd, proto;
+caddr_t policy;
+int policylen;
+u_int32_t seq;
+{
+ int len;
+
+ if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE,
+ src, prefs, dst, prefd, proto,
+ 0, 0,
+ policy, policylen, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDUPDATE message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdupdate2(so, src, prefs, dst, prefd, proto, ltime, vtime,
+ policy, policylen, seq)
+int so;
+struct sockaddr *src, *dst;
+u_int prefs, prefd, proto;
+u_int64_t ltime, vtime;
+caddr_t policy;
+int policylen;
+u_int32_t seq;
+{
+ int len;
+
+ if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE,
+ src, prefs, dst, prefd, proto,
+ ltime, vtime,
+ policy, policylen, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDDELETE message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spddelete(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
+int so;
+struct sockaddr *src, *dst;
+u_int prefs, prefd, proto;
+caddr_t policy;
+int policylen;
+u_int32_t seq;
+{
+ int len;
+
+ if (policylen != sizeof(struct sadb_x_policy)) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ if ((len = pfkey_send_x4(so, SADB_X_SPDDELETE,
+ src, prefs, dst, prefd, proto,
+ 0, 0,
+ policy, policylen, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDDELETE message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spddelete2(so, spid)
+int so;
+u_int32_t spid;
+{
+ int len;
+
+ if ((len = pfkey_send_x5(so, SADB_X_SPDDELETE2, spid)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDGET message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdget(so, spid)
+int so;
+u_int32_t spid;
+{
+ int len;
+
+ if ((len = pfkey_send_x5(so, SADB_X_SPDGET, spid)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_X_SPDSETIDX message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdsetidx(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
+int so;
+struct sockaddr *src, *dst;
+u_int prefs, prefd, proto;
+caddr_t policy;
+int policylen;
+u_int32_t seq;
+{
+ int len;
+
+ if (policylen != sizeof(struct sadb_x_policy)) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ if ((len = pfkey_send_x4(so, SADB_X_SPDSETIDX,
+ src, prefs, dst, prefd, proto,
+ 0, 0,
+ policy, policylen, seq)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_SPDFLUSH message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spdflush(so)
+int so;
+{
+ int len;
+
+ if ((len = pfkey_send_x3(so, SADB_X_SPDFLUSH, SADB_SATYPE_UNSPEC)) < 0)
+ return -1;
+
+ return len;
+}
+
+/*
+ * sending SADB_SPDDUMP message to the kernel.
+ * OUT:
+ * positive: success and return length sent.
+ * -1 : error occured, and set errno.
+ */
+int
+pfkey_send_spddump(so)
+int so;
+{
+ int len;
+
+ if ((len = pfkey_send_x3(so, SADB_X_SPDDUMP, SADB_SATYPE_UNSPEC)) < 0)
+ return -1;
+
+ return len;
+}
+
+/* sending SADB_ADD or SADB_UPDATE message to the kernel */
+static int
+pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize,
+ keymat, e_type, e_keylen, a_type, a_keylen, flags,
+ l_alloc, l_bytes, l_addtime, l_usetime, seq)
+int so;
+u_int type, satype, mode;
+struct sockaddr *src, *dst;
+u_int32_t spi, reqid;
+u_int wsize;
+caddr_t keymat;
+u_int e_type, e_keylen, a_type, a_keylen, flags;
+u_int32_t l_alloc, l_bytes, l_addtime, l_usetime, seq;
+{
+ struct sadb_msg *newmsg;
+ int len;
+ caddr_t p;
+ int plen;
+ caddr_t ep;
+
+ /* validity check */
+ if (src == NULL || dst == NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+ if (src->sa_family != dst->sa_family) {
+ __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+ switch (src->sa_family) {
+ case AF_INET:
+ plen = sizeof(struct in_addr) << 3;
+ break;
+ case AF_INET6:
+ plen = sizeof(struct in6_addr) << 3;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+ return -1;
+ }
+
+ switch (satype) {
+ case SADB_SATYPE_ESP:
+ if (e_type == SADB_EALG_NONE) {
+ __ipsec_errcode = EIPSEC_NO_ALGS;
+ return -1;
+ }
+ break;
+ case SADB_SATYPE_AH:
+ if (e_type != SADB_EALG_NONE) {
+ __ipsec_errcode = EIPSEC_INVAL_ALGS;
+ return -1;
+ }
+ if (a_type == SADB_AALG_NONE) {
+ __ipsec_errcode = EIPSEC_NO_ALGS;
+ return -1;
+ }
+ break;
+ case SADB_X_SATYPE_IPCOMP:
+ if (e_type == SADB_X_CALG_NONE) {
+ __ipsec_errcode = EIPSEC_INVAL_ALGS;
+ return -1;
+ }
+ if (a_type != SADB_AALG_NONE) {
+ __ipsec_errcode = EIPSEC_NO_ALGS;
+ return -1;
+ }
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+
+ /* create new sadb_msg to reply. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(struct sadb_sa)
+ + sizeof(struct sadb_x_sa2)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(src->sa_len)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(dst->sa_len)
+ + sizeof(struct sadb_lifetime)
+ + sizeof(struct sadb_lifetime);
+
+ if (e_type != SADB_EALG_NONE)
+ len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(e_keylen));
+ if (a_type != SADB_AALG_NONE)
+ len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(a_keylen));
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ ep = ((caddr_t)newmsg) + len;
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len,
+ satype, seq, getpid());
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbsa(p, ep, spi, wsize, a_type, e_type, flags);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbxsa2(p, ep, mode, reqid);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+
+ if (e_type != SADB_EALG_NONE) {
+ p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_ENCRYPT,
+ keymat, e_keylen);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ }
+ if (a_type != SADB_AALG_NONE) {
+ p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_AUTH,
+ keymat + e_keylen, a_keylen);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ }
+
+ /* set sadb_lifetime for destination */
+ p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD,
+ l_alloc, l_bytes, l_addtime, l_usetime);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_SOFT,
+ l_alloc, l_bytes, l_addtime, l_usetime);
+ if (!p || p != ep) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/* sending SADB_DELETE or SADB_GET message to the kernel */
+static int
+pfkey_send_x2(so, type, satype, mode, src, dst, spi)
+int so;
+u_int type, satype, mode;
+struct sockaddr *src, *dst;
+u_int32_t spi;
+{
+ struct sadb_msg *newmsg;
+ int len;
+ caddr_t p;
+ int plen;
+ caddr_t ep;
+
+ (void)mode;
+
+ /* validity check */
+ if (src == NULL || dst == NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+ if (src->sa_family != dst->sa_family) {
+ __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+ switch (src->sa_family) {
+ case AF_INET:
+ plen = sizeof(struct in_addr) << 3;
+ break;
+ case AF_INET6:
+ plen = sizeof(struct in6_addr) << 3;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+ return -1;
+ }
+
+ /* create new sadb_msg to reply. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(struct sadb_sa)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(src->sa_len)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(dst->sa_len);
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ ep = ((caddr_t)newmsg) + len;
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0,
+ getpid());
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbsa(p, ep, spi, 0, 0, 0, 0);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
+ IPSEC_ULPROTO_ANY);
+ if (!p || p != ep) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/*
+ * sending SADB_REGISTER, SADB_FLUSH, SADB_DUMP or SADB_X_PROMISC message
+ * to the kernel
+ */
+static int
+pfkey_send_x3(so, type, satype)
+int so;
+u_int type, satype;
+{
+ struct sadb_msg *newmsg;
+ int len;
+ caddr_t p;
+ caddr_t ep;
+
+ /* validity check */
+ switch (type) {
+ case SADB_X_PROMISC:
+ if (satype != 0 && satype != 1) {
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+ break;
+ default:
+ switch (satype) {
+ case SADB_SATYPE_UNSPEC:
+ case SADB_SATYPE_AH:
+ case SADB_SATYPE_ESP:
+ case SADB_X_SATYPE_IPCOMP:
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+ }
+
+ /* create new sadb_msg to send. */
+ len = sizeof(struct sadb_msg);
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ ep = ((caddr_t)newmsg) + len;
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0,
+ getpid());
+ if (!p || p != ep) {
+ free(newmsg);
+ return -1;
+ }
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/* sending SADB_X_SPDADD message to the kernel */
+static int
+pfkey_send_x4(so, type, src, prefs, dst, prefd, proto,
+ ltime, vtime, policy, policylen, seq)
+int so;
+struct sockaddr *src, *dst;
+u_int type, prefs, prefd, proto;
+u_int64_t ltime, vtime;
+char *policy;
+int policylen;
+u_int32_t seq;
+{
+ struct sadb_msg *newmsg;
+ int len;
+ caddr_t p;
+ int plen;
+ caddr_t ep;
+
+ /* validity check */
+ if (src == NULL || dst == NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+ if (src->sa_family != dst->sa_family) {
+ __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+
+ switch (src->sa_family) {
+ case AF_INET:
+ plen = sizeof(struct in_addr) << 3;
+ break;
+ case AF_INET6:
+ plen = sizeof(struct in6_addr) << 3;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+ return -1;
+ }
+ if (prefs > (u_int)plen || prefd > (u_int)plen) {
+ __ipsec_errcode = EIPSEC_INVAL_PREFIXLEN;
+ return -1;
+ }
+
+ /* create new sadb_msg to reply. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(src->sa_len)
+ + sizeof(struct sadb_address)
+ + PFKEY_ALIGN8(src->sa_len)
+ + sizeof(struct sadb_lifetime)
+ + policylen;
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ ep = ((caddr_t)newmsg) + len;
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len,
+ SADB_SATYPE_UNSPEC, seq, getpid());
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, prefs, proto);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, prefd, proto);
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+ p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD,
+ 0, 0, ltime, vtime);
+ if (!p || p + policylen != ep) {
+ free(newmsg);
+ return -1;
+ }
+ memcpy(p, policy, policylen);
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/* sending SADB_X_SPDGET or SADB_X_SPDDELETE message to the kernel */
+static int
+pfkey_send_x5(so, type, spid)
+int so;
+u_int type;
+u_int32_t spid;
+{
+ struct sadb_msg *newmsg;
+ struct sadb_x_policy xpl;
+ int len;
+ caddr_t p;
+ caddr_t ep;
+
+ /* create new sadb_msg to reply. */
+ len = sizeof(struct sadb_msg)
+ + sizeof(xpl);
+
+ if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+ ep = ((caddr_t)newmsg) + len;
+
+ p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len,
+ SADB_SATYPE_UNSPEC, 0, getpid());
+ if (!p) {
+ free(newmsg);
+ return -1;
+ }
+
+ if (p + sizeof(xpl) != ep) {
+ free(newmsg);
+ return -1;
+ }
+ memset(&xpl, 0, sizeof(xpl));
+ xpl.sadb_x_policy_len = PFKEY_UNUNIT64(sizeof(xpl));
+ xpl.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+ xpl.sadb_x_policy_id = spid;
+ memcpy(p, &xpl, sizeof(xpl));
+
+ /* send message */
+ len = pfkey_send(so, newmsg, len);
+ free(newmsg);
+
+ if (len < 0)
+ return -1;
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/*
+ * open a socket.
+ * OUT:
+ * -1: fail.
+ * others : success and return value of socket.
+ */
+int
+pfkey_open()
+{
+ int so;
+ const int bufsiz = 128 * 1024; /*is 128K enough?*/
+
+ if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+
+ /*
+ * This is a temporary workaround for KAME PR 154.
+ * Don't really care even if it fails.
+ */
+ (void)setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsiz, sizeof(bufsiz));
+ (void)setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsiz, sizeof(bufsiz));
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return so;
+}
+
+/*
+ * close a socket.
+ * OUT:
+ * 0: success.
+ * -1: fail.
+ */
+void
+pfkey_close(so)
+int so;
+{
+ (void)close(so);
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return;
+}
+
+/*
+ * receive sadb_msg data, and return pointer to new buffer allocated.
+ * Must free this buffer later.
+ * OUT:
+ * NULL : error occured.
+ * others : a pointer to sadb_msg structure.
+ *
+ * XXX should be rewritten to pass length explicitly
+ */
+struct sadb_msg *
+pfkey_recv(so)
+int so;
+{
+ struct sadb_msg buf, *newmsg;
+ int len, reallen;
+
+ while ((len = recv(so, (caddr_t)&buf, sizeof(buf), MSG_PEEK)) < 0) {
+ if (errno == EINTR)
+ continue;
+ __ipsec_set_strerror(strerror(errno));
+ return NULL;
+ }
+
+ if ((size_t)len < sizeof(buf)) {
+ recv(so, (caddr_t)&buf, sizeof(buf), 0);
+ __ipsec_errcode = EIPSEC_MAX;
+ return NULL;
+ }
+
+ /* read real message */
+ reallen = PFKEY_UNUNIT64(buf.sadb_msg_len);
+ if ((newmsg = CALLOC(reallen, struct sadb_msg *)) == 0) {
+ __ipsec_set_strerror(strerror(errno));
+ return NULL;
+ }
+
+ while ((len = recv(so, (caddr_t)newmsg, reallen, 0)) < 0) {
+ if (errno == EINTR)
+ continue;
+ __ipsec_set_strerror(strerror(errno));
+ free(newmsg);
+ return NULL;
+ }
+
+ if (len != reallen) {
+ __ipsec_errcode = EIPSEC_SYSTEM_ERROR;
+ free(newmsg);
+ return NULL;
+ }
+
+ /* don't trust what the kernel says, validate! */
+ if (PFKEY_UNUNIT64(newmsg->sadb_msg_len) != len) {
+ __ipsec_errcode = EIPSEC_SYSTEM_ERROR;
+ free(newmsg);
+ return NULL;
+ }
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return newmsg;
+}
+
+/*
+ * send message to a socket.
+ * OUT:
+ * others: success and return length sent.
+ * -1 : fail.
+ */
+int
+pfkey_send(so, msg, len)
+int so;
+struct sadb_msg *msg;
+int len;
+{
+ if ((len = send(so, (caddr_t)msg, len, 0)) < 0) {
+ __ipsec_set_strerror(strerror(errno));
+ return -1;
+ }
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return len;
+}
+
+/*
+ * %%% Utilities
+ * NOTE: These functions are derived from netkey/key.c in KAME.
+ */
+/*
+ * set the pointer to each header in this message buffer.
+ * IN: msg: pointer to message buffer.
+ * mhp: pointer to the buffer initialized like below:
+ * caddr_t mhp[SADB_EXT_MAX + 1];
+ * OUT: -1: invalid.
+ * 0: valid.
+ *
+ * XXX should be rewritten to obtain length explicitly
+ */
+int
+pfkey_align(msg, mhp)
+struct sadb_msg *msg;
+caddr_t *mhp;
+{
+ struct sadb_ext *ext;
+ int i;
+ caddr_t p;
+ caddr_t ep; /* XXX should be passed from upper layer */
+
+ /* validity check */
+ if (msg == NULL || mhp == NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ /* initialize */
+ for (i = 0; i < SADB_EXT_MAX + 1; i++)
+ mhp[i] = NULL;
+
+ mhp[0] = (caddr_t)msg;
+
+ /* initialize */
+ p = (caddr_t) msg;
+ ep = p + PFKEY_UNUNIT64(msg->sadb_msg_len);
+
+ /* skip base header */
+ p += sizeof(struct sadb_msg);
+
+ while (p < ep) {
+ ext = (struct sadb_ext *)p;
+ if (ep < p + sizeof(*ext) || (size_t)PFKEY_EXTLEN(ext) < sizeof(*ext) ||
+ ep < p + PFKEY_EXTLEN(ext)) {
+ /* invalid format */
+ break;
+ }
+
+ /* duplicate check */
+ /* XXX Are there duplication either KEY_AUTH or KEY_ENCRYPT ?*/
+ if (mhp[ext->sadb_ext_type] != NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_EXTTYPE;
+ return -1;
+ }
+
+ /* set pointer */
+ switch (ext->sadb_ext_type) {
+ case SADB_EXT_SA:
+ case SADB_EXT_LIFETIME_CURRENT:
+ case SADB_EXT_LIFETIME_HARD:
+ case SADB_EXT_LIFETIME_SOFT:
+ case SADB_EXT_ADDRESS_SRC:
+ case SADB_EXT_ADDRESS_DST:
+ case SADB_EXT_ADDRESS_PROXY:
+ case SADB_EXT_KEY_AUTH:
+ /* XXX should to be check weak keys. */
+ case SADB_EXT_KEY_ENCRYPT:
+ /* XXX should to be check weak keys. */
+ case SADB_EXT_IDENTITY_SRC:
+ case SADB_EXT_IDENTITY_DST:
+ case SADB_EXT_SENSITIVITY:
+ case SADB_EXT_PROPOSAL:
+ case SADB_EXT_SUPPORTED_AUTH:
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ case SADB_EXT_SPIRANGE:
+ case SADB_X_EXT_POLICY:
+ case SADB_X_EXT_SA2:
+ mhp[ext->sadb_ext_type] = (caddr_t)ext;
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_EXTTYPE;
+ return -1;
+ }
+
+ p += PFKEY_EXTLEN(ext);
+ }
+
+ if (p != ep) {
+ __ipsec_errcode = EIPSEC_INVAL_SADBMSG;
+ return -1;
+ }
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+/*
+ * check basic usage for sadb_msg,
+ * NOTE: This routine is derived from netkey/key.c in KAME.
+ * IN: msg: pointer to message buffer.
+ * mhp: pointer to the buffer initialized like below:
+ *
+ * caddr_t mhp[SADB_EXT_MAX + 1];
+ *
+ * OUT: -1: invalid.
+ * 0: valid.
+ */
+int
+pfkey_check(mhp)
+caddr_t *mhp;
+{
+ struct sadb_msg *msg;
+
+ /* validity check */
+ if (mhp == NULL || mhp[0] == NULL) {
+ __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
+ return -1;
+ }
+
+ msg = (struct sadb_msg *)mhp[0];
+
+ /* check version */
+ if (msg->sadb_msg_version != PF_KEY_V2) {
+ __ipsec_errcode = EIPSEC_INVAL_VERSION;
+ return -1;
+ }
+
+ /* check type */
+ if (msg->sadb_msg_type > SADB_MAX) {
+ __ipsec_errcode = EIPSEC_INVAL_MSGTYPE;
+ return -1;
+ }
+
+ /* check SA type */
+ switch (msg->sadb_msg_satype) {
+ case SADB_SATYPE_UNSPEC:
+ switch (msg->sadb_msg_type) {
+ case SADB_GETSPI:
+ case SADB_UPDATE:
+ case SADB_ADD:
+ case SADB_DELETE:
+ case SADB_GET:
+ case SADB_ACQUIRE:
+ case SADB_EXPIRE:
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+ break;
+ case SADB_SATYPE_ESP:
+ case SADB_SATYPE_AH:
+ case SADB_X_SATYPE_IPCOMP:
+ switch (msg->sadb_msg_type) {
+ case SADB_X_SPDADD:
+ case SADB_X_SPDDELETE:
+ case SADB_X_SPDGET:
+ case SADB_X_SPDDUMP:
+ case SADB_X_SPDFLUSH:
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+ break;
+ case SADB_SATYPE_RSVP:
+ case SADB_SATYPE_OSPFV2:
+ case SADB_SATYPE_RIPV2:
+ case SADB_SATYPE_MIP:
+ __ipsec_errcode = EIPSEC_NOT_SUPPORTED;
+ return -1;
+ case 1: /* XXX: What does it do ? */
+ if (msg->sadb_msg_type == SADB_X_PROMISC)
+ break;
+ /*FALLTHROUGH*/
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_SATYPE;
+ return -1;
+ }
+
+ /* check field of upper layer protocol and address family */
+ if (mhp[SADB_EXT_ADDRESS_SRC] != NULL
+ && mhp[SADB_EXT_ADDRESS_DST] != NULL) {
+ struct sadb_address *src0, *dst0;
+
+ src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]);
+ dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]);
+
+ if (src0->sadb_address_proto != dst0->sadb_address_proto) {
+ __ipsec_errcode = EIPSEC_PROTO_MISMATCH;
+ return -1;
+ }
+
+ if (PFKEY_ADDR_SADDR(src0)->sa_family
+ != PFKEY_ADDR_SADDR(dst0)->sa_family) {
+ __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
+ return -1;
+ }
+
+ switch (PFKEY_ADDR_SADDR(src0)->sa_family) {
+ case AF_INET:
+ case AF_INET6:
+ break;
+ default:
+ __ipsec_errcode = EIPSEC_INVAL_FAMILY;
+ return -1;
+ }
+
+ /*
+ * prefixlen == 0 is valid because there must be the case
+ * all addresses are matched.
+ */
+ }
+
+ __ipsec_errcode = EIPSEC_NO_ERROR;
+ return 0;
+}
+
+/*
+ * set data into sadb_msg.
+ * `buf' must has been allocated sufficiently.
+ */
+static caddr_t
+pfkey_setsadbmsg(buf, lim, type, tlen, satype, seq, pid)
+caddr_t buf;
+caddr_t lim;
+u_int type, satype;
+u_int tlen;
+u_int32_t seq;
+pid_t pid;
+{
+ struct sadb_msg *p;
+ u_int len;
+
+ p = (struct sadb_msg *)buf;
+ len = sizeof(struct sadb_msg);
+
+ if (buf + len > lim)
+ return NULL;
+
+ memset(p, 0, len);
+ p->sadb_msg_version = PF_KEY_V2;
+ p->sadb_msg_type = type;
+ p->sadb_msg_errno = 0;
+ p->sadb_msg_satype = satype;
+ p->sadb_msg_len = PFKEY_UNIT64(tlen);
+ p->sadb_msg_reserved = 0;
+ p->sadb_msg_seq = seq;
+ p->sadb_msg_pid = (u_int32_t)pid;
+
+ return(buf + len);
+}
+
+/*
+ * copy secasvar data into sadb_address.
+ * `buf' must has been allocated sufficiently.
+ */
+static caddr_t
+pfkey_setsadbsa(buf, lim, spi, wsize, auth, enc, flags)
+caddr_t buf;
+caddr_t lim;
+u_int32_t spi, flags;
+u_int wsize, auth, enc;
+{
+ struct sadb_sa *p;
+ u_int len;
+
+ p = (struct sadb_sa *)buf;
+ len = sizeof(struct sadb_sa);
+
+ if (buf + len > lim)
+ return NULL;
+
+ memset(p, 0, len);
+ p->sadb_sa_len = PFKEY_UNIT64(len);
+ p->sadb_sa_exttype = SADB_EXT_SA;
+ p->sadb_sa_spi = spi;
+ p->sadb_sa_replay = wsize;
+ p->sadb_sa_state = SADB_SASTATE_LARVAL;
+ p->sadb_sa_auth = auth;
+ p->sadb_sa_encrypt = enc;
+ p->sadb_sa_flags = flags;
+
+ return(buf + len);
+}
+
+/*
+ * set data into sadb_address.
+ * `buf' must has been allocated sufficiently.
+ * prefixlen is in bits.
+ */
+static caddr_t
+pfkey_setsadbaddr(buf, lim, exttype, saddr, prefixlen, ul_proto)
+caddr_t buf;
+caddr_t lim;
+u_int exttype;
+struct sockaddr *saddr;
+u_int prefixlen;
+u_int ul_proto;
+{
+ struct sadb_address *p;
+ u_int len;
+
+ p = (struct sadb_address *)buf;
+ len = sizeof(struct sadb_address) + PFKEY_ALIGN8(saddr->sa_len);
+
+ if (buf + len > lim)
+ return NULL;
+
+ memset(p, 0, len);
+ p->sadb_address_len = PFKEY_UNIT64(len);
+ p->sadb_address_exttype = exttype & 0xffff;
+ p->sadb_address_proto = ul_proto & 0xff;
+ p->sadb_address_prefixlen = prefixlen;
+ p->sadb_address_reserved = 0;
+
+ memcpy(p + 1, saddr, saddr->sa_len);
+
+ return(buf + len);
+}
+
+/*
+ * set sadb_key structure after clearing buffer with zero.
+ * OUT: the pointer of buf + len.
+ */
+static caddr_t
+pfkey_setsadbkey(buf, lim, type, key, keylen)
+caddr_t buf;
+caddr_t lim;
+caddr_t key;
+u_int type, keylen;
+{
+ struct sadb_key *p;
+ u_int len;
+
+ p = (struct sadb_key *)buf;
+ len = sizeof(struct sadb_key) + PFKEY_ALIGN8(keylen);
+
+ if (buf + len > lim)
+ return NULL;
+
+ memset(p, 0, len);
+ p->sadb_key_len = PFKEY_UNIT64(len);
+ p->sadb_key_exttype = type;
+ p->sadb_key_bits = keylen << 3;
+ p->sadb_key_reserved = 0;
+
+ memcpy(p + 1, key, keylen);
+
+ return buf + len;
+}
+
+/*
+ * set sadb_lifetime structure after clearing buffer with zero.
+ * OUT: the pointer of buf + len.
+ */
+static caddr_t
+pfkey_setsadblifetime(buf, lim, type, l_alloc, l_bytes, l_addtime, l_usetime)
+caddr_t buf;
+caddr_t lim;
+u_int type;
+u_int32_t l_alloc, l_bytes, l_addtime, l_usetime;
+{
+ struct sadb_lifetime *p;
+ u_int len;
+
+ p = (struct sadb_lifetime *)buf;
+ len = sizeof(struct sadb_lifetime);
+
+ if (buf + len > lim)
+ return NULL;
+
+ memset(p, 0, len);
+ p->sadb_lifetime_len = PFKEY_UNIT64(len);
+ p->sadb_lifetime_exttype = type;
+
+ switch (type) {
+ case SADB_EXT_LIFETIME_SOFT:
+ p->sadb_lifetime_allocations
+ = (l_alloc * soft_lifetime_allocations_rate) /100;
+ p->sadb_lifetime_bytes
+ = (l_bytes * soft_lifetime_bytes_rate) /100;
+ p->sadb_lifetime_addtime
+ = (l_addtime * soft_lifetime_addtime_rate) /100;
+ p->sadb_lifetime_usetime
+ = (l_usetime * soft_lifetime_usetime_rate) /100;
+ break;
+ case SADB_EXT_LIFETIME_HARD:
+ p->sadb_lifetime_allocations = l_alloc;
+ p->sadb_lifetime_bytes = l_bytes;
+ p->sadb_lifetime_addtime = l_addtime;
+ p->sadb_lifetime_usetime = l_usetime;
+ break;
+ }
+
+ return buf + len;
+}
+
+/*
+ * copy secasvar data into sadb_address.
+ * `buf' must has been allocated sufficiently.
+ */
+static caddr_t
+pfkey_setsadbxsa2(buf, lim, mode0, reqid)
+caddr_t buf;
+caddr_t lim;
+u_int32_t mode0;
+u_int32_t reqid;
+{
+ struct sadb_x_sa2 *p;
+ u_int8_t mode = mode0 & 0xff;
+ u_int len;
+
+ p = (struct sadb_x_sa2 *)buf;
+ len = sizeof(struct sadb_x_sa2);
+
+ if (buf + len > lim)
+ return NULL;
+
+ memset(p, 0, len);
+ p->sadb_x_sa2_len = PFKEY_UNIT64(len);
+ p->sadb_x_sa2_exttype = SADB_X_EXT_SA2;
+ p->sadb_x_sa2_mode = mode;
+ p->sadb_x_sa2_reqid = reqid;
+
+ return(buf + len);
+}
+
+#endif /* ndef MDNS_NO_IPSEC */