summaryrefslogtreecommitdiffstats
path: root/mDNSResponder
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-09-19 08:56:09 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-09-20 11:23:33 +0200
commit4c086a244624bf36865edcfa4309c333d7d7200d (patch)
treee566ffc50a6b6fdb46702ac57c8e7c4088b60b42 /mDNSResponder
parentmDNSResponder: Update to v765.50.9 (diff)
downloadrtems-libbsd-4c086a244624bf36865edcfa4309c333d7d7200d.tar.bz2
mDNSResponder: Update to v878.1.1
The sources can be obtained via: https://opensource.apple.com/tarballs/mDNSResponder/mDNSResponder-878.1.1.tar.gz Update #3522.
Diffstat (limited to 'mDNSResponder')
-rw-r--r--mDNSResponder/Clients/dns-sd.c345
-rw-r--r--mDNSResponder/Clients/dnssdutil.c7899
-rw-r--r--mDNSResponder/Documents/Start mDNSResponder in Xcode.rtfd/TXT.rtf5
-rw-r--r--mDNSResponder/Makefile13
-rw-r--r--mDNSResponder/mDNSCore/DNSCommon.c75
-rw-r--r--mDNSResponder/mDNSCore/DNSCommon.h5
-rw-r--r--mDNSResponder/mDNSCore/anonymous.c12
-rw-r--r--mDNSResponder/mDNSCore/dnsproxy.c89
-rw-r--r--mDNSResponder/mDNSCore/dnsproxy.h8
-rw-r--r--mDNSResponder/mDNSCore/dnssec.c37
-rwxr-xr-xmDNSResponder/mDNSCore/mDNS.c801
-rwxr-xr-xmDNSResponder/mDNSCore/mDNSEmbeddedAPI.h179
-rw-r--r--mDNSResponder/mDNSCore/nsec.c9
-rw-r--r--mDNSResponder/mDNSCore/nsec3.c5
-rwxr-xr-xmDNSResponder/mDNSCore/uDNS.c146
-rwxr-xr-xmDNSResponder/mDNSCore/uDNS.h2
-rw-r--r--mDNSResponder/mDNSMacOSX/BLE.c1369
-rw-r--r--mDNSResponder/mDNSMacOSX/BLE.h44
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourEvents.c50
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/BonjourTop.xcodeproj/project.pbxproj297
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/BonjourTop.xcodeproj/project.xcworkspace/contents.xcworkspacedata7
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/BonjourTop.179
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/BonjourTop.cpp2049
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/BonjourTop.h577
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/CaptureFile.cpp141
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/CaptureFile.h55
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/CollectBy.cpp314
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/CollectBy.h155
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/DNSFrame.cpp384
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/DNSFrame.h132
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/Frame.cpp201
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/Frame.h66
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/LLRBTree.cpp157
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/LLRBTree.h460
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/bjIPAddr.cpp312
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/bjIPAddr.h56
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/bjMACAddr.cpp11
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/bjMACAddr.h54
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/bjStringtoStringMap.cpp40
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/bjStringtoStringMap.h42
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/bjsocket.cpp384
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/bjsocket.h88
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/bjstring.cpp238
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/bjstring.h63
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/bjtypes.h64
-rw-r--r--mDNSResponder/mDNSMacOSX/BonjourTop/source/main.cpp179
-rw-r--r--mDNSResponder/mDNSMacOSX/D2D.c995
-rw-r--r--mDNSResponder/mDNSMacOSX/D2D.h48
-rw-r--r--mDNSResponder/mDNSMacOSX/DNS64.c559
-rw-r--r--mDNSResponder/mDNSMacOSX/DNS64.h39
-rw-r--r--mDNSResponder/mDNSMacOSX/DNS64State.h41
-rw-r--r--mDNSResponder/mDNSMacOSX/DNSProxySupport.c37
-rw-r--r--mDNSResponder/mDNSMacOSX/DNSSECSupport.c2
-rw-r--r--mDNSResponder/mDNSMacOSX/DomainBrowser/Shared/CNDomainBrowserPathUtils.h22
-rw-r--r--mDNSResponder/mDNSMacOSX/DomainBrowser/Shared/CNDomainBrowserPathUtils.m114
-rw-r--r--mDNSResponder/mDNSMacOSX/DomainBrowser/Shared/_CNDomainBrowser.h49
-rw-r--r--mDNSResponder/mDNSMacOSX/DomainBrowser/Shared/_CNDomainBrowser.m190
-rw-r--r--mDNSResponder/mDNSMacOSX/DomainBrowser/iOS/CNDomainBrowserViewController.h51
-rw-r--r--mDNSResponder/mDNSMacOSX/DomainBrowser/iOS/CNDomainBrowserViewController.m350
-rw-r--r--mDNSResponder/mDNSMacOSX/DomainBrowser/iOS/DomainBrowser.h30
-rw-r--r--mDNSResponder/mDNSMacOSX/DomainBrowser/iOS/DomainBrowser.strings18
-rw-r--r--mDNSResponder/mDNSMacOSX/DomainBrowser/iOS/Info.plist26
-rw-r--r--mDNSResponder/mDNSMacOSX/DomainBrowser/macOS/CNDomainBrowserView.h58
-rw-r--r--mDNSResponder/mDNSMacOSX/DomainBrowser/macOS/CNDomainBrowserView.m474
-rw-r--r--mDNSResponder/mDNSMacOSX/DomainBrowser/macOS/DomainBrowser.h30
-rw-r--r--mDNSResponder/mDNSMacOSX/DomainBrowser/macOS/Info.plist26
-rw-r--r--mDNSResponder/mDNSMacOSX/LegacyNATTraversal.c47
-rw-r--r--mDNSResponder/mDNSMacOSX/Metrics.m14
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_idle.tiffbin728 -> 0 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_pressed.tiffbin688 -> 0 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_disabled.tiffbin698 -> 0 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_idle.tiffbin694 -> 0 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_pressed.tiffbin656 -> 0 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Base.lproj/DNSServiceDiscoveryPref.nib/designable.nib821
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Base.lproj/DNSServiceDiscoveryPref.nib/keyedobjects.nibbin0 -> 45019 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/BonjourPrefTool-Info.plist37
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/BonjourPrefTool.h24
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/BonjourPrefTool.m158
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/BonjourPrefToolProtocol.h27
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/entitlements.plist8
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/main.m62
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c180
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.h52
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.h118
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m514
-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.nibbin21082 -> 0 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/Info-PreferencePane.plist4
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.c235
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.h70
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/RemoteViewService/BonjourPrefRemoteViewService-Info.plist41
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/RemoteViewService/BonjourPrefRemoteViewService.h22
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/RemoteViewService/BonjourPrefRemoteViewService.m21
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/RemoteViewService/InfoPlist.strings3
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/RemoteViewService/entitlements.plist10
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/RemoteViewService/main.m40
-rw-r--r--mDNSResponder/mDNSMacOSX/PreferencePane/ddnswriteconfig.m462
-rwxr-xr-xmDNSResponder/mDNSMacOSX/PreferencePane/installtool94
-rw-r--r--mDNSResponder/mDNSMacOSX/Private/dnsctl_server.c12
-rw-r--r--mDNSResponder/mDNSMacOSX/Private/xpc_services.c14
-rw-r--r--mDNSResponder/mDNSMacOSX/SettingsBundle/Assets.xcassets/Contents.json6
-rw-r--r--mDNSResponder/mDNSMacOSX/SettingsBundle/Assets.xcassets/UIPreferencesBlueCheck.imageset/Contents.json22
-rw-r--r--mDNSResponder/mDNSMacOSX/SettingsBundle/Assets.xcassets/UIPreferencesBlueCheck.imageset/UIPreferencesBlueCheck.pngbin0 -> 341 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/SettingsBundle/Assets.xcassets/UIPreferencesBlueCheck.imageset/UIPreferencesBlueCheck@2x.pngbin0 -> 506 bytes
-rw-r--r--mDNSResponder/mDNSMacOSX/SettingsBundle/BonjourConstants.h15
-rw-r--r--mDNSResponder/mDNSMacOSX/SettingsBundle/BonjourSCStore.h40
-rw-r--r--mDNSResponder/mDNSMacOSX/SettingsBundle/BonjourSCStore.m84
-rw-r--r--mDNSResponder/mDNSMacOSX/SettingsBundle/BonjourSettingsController.h24
-rw-r--r--mDNSResponder/mDNSMacOSX/SettingsBundle/BonjourSettingsController.m143
-rw-r--r--mDNSResponder/mDNSMacOSX/SettingsBundle/CNBrowseDomainsController.h37
-rw-r--r--mDNSResponder/mDNSMacOSX/SettingsBundle/CNBrowseDomainsController.m710
-rw-r--r--mDNSResponder/mDNSMacOSX/SettingsBundle/HostnameController.h25
-rw-r--r--mDNSResponder/mDNSMacOSX/SettingsBundle/HostnameController.m125
-rw-r--r--mDNSResponder/mDNSMacOSX/SettingsBundle/Info.plist26
-rw-r--r--mDNSResponder/mDNSMacOSX/SettingsBundle/Localizable.strings34
-rw-r--r--mDNSResponder/mDNSMacOSX/com.apple.mDNSResponderHelper.plist30
-rw-r--r--mDNSResponder/mDNSMacOSX/coreBLE.h11
-rw-r--r--mDNSResponder/mDNSMacOSX/coreBLE.m332
-rw-r--r--mDNSResponder/mDNSMacOSX/daemon.c175
-rw-r--r--mDNSResponder/mDNSMacOSX/mDNSMacOSX.c2900
-rw-r--r--mDNSResponder/mDNSMacOSX/mDNSMacOSX.h29
-rw-r--r--mDNSResponder/mDNSMacOSX/mDNSNetMonitor/mDNSNetMonitor.840
-rw-r--r--mDNSResponder/mDNSMacOSX/mDNSResponder-entitlements.plist10
-rw-r--r--mDNSResponder/mDNSMacOSX/mDNSResponder-xcodeproj-explanation.txt40
-rw-r--r--mDNSResponder/mDNSMacOSX/mDNSResponder.sb25
-rw-r--r--mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj2279
-rw-r--r--mDNSResponder/mDNSMacOSX/uDNSPathEvalulation.c5
-rw-r--r--mDNSResponder/mDNSPosix/ExampleClientApp.c2
-rw-r--r--mDNSResponder/mDNSPosix/NetMonitor.c32
-rw-r--r--mDNSResponder/mDNSPosix/PosixDaemon.c11
-rw-r--r--mDNSResponder/mDNSPosix/ProxyResponder.c2
-rwxr-xr-xmDNSResponder/mDNSPosix/Responder.c2
-rwxr-xr-xmDNSResponder/mDNSPosix/mDNSPosix.c50
-rwxr-xr-xmDNSResponder/mDNSPosix/mDNSPosix.h2
-rw-r--r--mDNSResponder/mDNSShared/dns_sd.h47
-rw-r--r--mDNSResponder/mDNSShared/dns_sd_internal.h15
-rw-r--r--mDNSResponder/mDNSShared/dns_sd_private.h (renamed from mDNSResponder/mDNSMacOSX/Private/dns_sd_private.h)32
-rw-r--r--mDNSResponder/mDNSShared/dnsextd.c21
-rw-r--r--mDNSResponder/mDNSShared/dnssd_clientstub.c42
-rw-r--r--mDNSResponder/mDNSShared/uds_daemon.c630
-rw-r--r--mDNSResponder/mDNSShared/uds_daemon.h210
-rw-r--r--mDNSResponder/mDNSVxWorks/mDNSVxWorks.c4
-rw-r--r--mDNSResponder/mDNSVxWorks/mDNSVxWorksIPv4Only.c4
-rw-r--r--mDNSResponder/mDNSWindows/BonjourQuickLooks.sln81
-rw-r--r--mDNSResponder/mDNSWindows/BonjourQuickLooksInstaller/BonjourQuickLooksInstaller.wixproj85
-rw-r--r--mDNSResponder/mDNSWindows/BonjourQuickLooksInstaller/Product.wxs176
-rw-r--r--mDNSResponder/mDNSWindows/WinVersRes.h8
-rwxr-xr-xmDNSResponder/mDNSWindows/mDNSWin32.c6
-rw-r--r--mDNSResponder/unittests/CNameRecordTests.c400
-rw-r--r--mDNSResponder/unittests/CNameRecordTests.h9
-rw-r--r--mDNSResponder/unittests/LocalOnlyTimeoutTests.c378
-rw-r--r--mDNSResponder/unittests/LocalOnlyTimeoutTests.h9
-rw-r--r--mDNSResponder/unittests/ResourceRecordTest.c5
-rw-r--r--mDNSResponder/unittests/daemon_ut.c35
-rw-r--r--mDNSResponder/unittests/mDNSCoreReceiveTest.c151
-rw-r--r--mDNSResponder/unittests/mDNSCoreReceiveTest.h9
-rw-r--r--mDNSResponder/unittests/main.c13
-rw-r--r--mDNSResponder/unittests/mdns_macosx_ut.c66
-rw-r--r--mDNSResponder/unittests/mdns_ut.c17
-rw-r--r--mDNSResponder/unittests/uds_daemon_ut.c43
-rw-r--r--mDNSResponder/unittests/unittest.h44
-rw-r--r--mDNSResponder/unittests/unittest_common.c157
-rw-r--r--mDNSResponder/unittests/unittest_common.h57
164 files changed, 28521 insertions, 5525 deletions
diff --git a/mDNSResponder/Clients/dns-sd.c b/mDNSResponder/Clients/dns-sd.c
index f36211e5..78c8f29f 100644
--- a/mDNSResponder/Clients/dns-sd.c
+++ b/mDNSResponder/Clients/dns-sd.c
@@ -165,6 +165,7 @@ static const char kFilePathSep = '/';
#undef _DNS_SD_LIBDISPATCH
#endif
#include "dns_sd.h"
+#include "dns_sd_internal.h"
#include "ClientCommon.h"
#if TEST_NEW_CLIENTSTUB
@@ -1520,138 +1521,321 @@ DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *
static int API_NULL_input_test()
{
- printf("Running basic API input range tests with all parameters set to 0:\n");
+ printf("Running basic API input range tests with various pointer parameters set to NULL:\n");
// Test that API's handle NULL pointers by returning an error when appropriate.
- printf("DNSServiceRefSockFD()\n");
+
+ // DNSServiceRefSockFD()
if (DNSServiceRefSockFD(0) != -1)
{
printf("DNSServiceRefSockFD(): expected dnssd_InvalidSocket return\n");
return 1;
- };
+ }
- printf("DNSServiceProcessResult()\n");
+ // DNSServiceProcessResult()
if (DNSServiceProcessResult(0) == 0)
{
printf("DNSServiceProcessResult(): expected error return\n");
return 1;
- };
+ }
- // no return value, just verify it doesn't crash
- printf("DNSServiceRefDeallocate()\n");
+ // DNSServiceRefDeallocate(): no return value, just verify it doesn't crash
DNSServiceRefDeallocate(0);
- printf("DNSServiceGetProperty()\n");
- if (DNSServiceGetProperty(0, 0, 0) == 0)
+ // DNSServiceGetProperty()
{
- printf("DNSServiceGetProperty(): expected error return\n");
- return 1;
- };
+ uint32_t result;
+ uint32_t size;
- printf("DNSServiceResolve()\n");
- if (DNSServiceResolve(0, 0, 0, 0, 0, 0, 0, 0) == 0)
+ if ( (DNSServiceGetProperty( 0, &result, &size) == 0)
+ || (DNSServiceGetProperty(kDNSServiceProperty_DaemonVersion, 0, &size) == 0)
+ || (DNSServiceGetProperty(kDNSServiceProperty_DaemonVersion, &result, 0) == 0)
+ )
+ {
+ printf("DNSServiceGetProperty(): expected error return\n");
+ return 1;
+ }
+ }
+
+ // DNSServiceResolve()
{
- printf("DNSServiceResolve(): expected error return\n");
- return 1;
- };
+ DNSServiceRef sdRef;
+ DNSServiceFlags flags = 0;
+ uint32_t interfaceIndex = 0;
+ const char *name = "name";
+ const char *regtype = "_test._tcp";
+ const char *domain = "local";
+ DNSServiceResolveReply callBack = 0;
+ void *context = 0; // can be a NULL pointer
+
+ if ( (DNSServiceResolve( 0, flags, interfaceIndex, name, regtype, domain, callBack, context) == 0)
+ || (DNSServiceResolve(&sdRef, flags, interfaceIndex, 0, regtype, domain, callBack, context) == 0)
+ || (DNSServiceResolve(&sdRef, flags, interfaceIndex, name, 0, domain, callBack, context) == 0)
+ || (DNSServiceResolve(&sdRef, flags, interfaceIndex, name, regtype, 0, callBack, context) == 0)
+ || (DNSServiceResolve(&sdRef, flags, interfaceIndex, name, regtype, domain, callBack, context) == 0)
+ )
+ {
+ printf("DNSServiceResolve(): expected error return\n");
+ return 1;
+ }
+ }
- printf("DNSServiceQueryRecord()\n");
- if (DNSServiceQueryRecord(0, 0, 0, 0, 0, 0, 0, 0) == 0)
+ // DNSServiceQueryRecord()
{
- printf("DNSServiceQueryRecord(): expected error return\n");
- return 1;
- };
+ DNSServiceRef sdRef;
+ DNSServiceFlags flags = 0;
+ uint32_t interfaceIndex = 0;
+ const char *fullname = "fullname";
+ uint16_t rrtype = 0;
+ uint16_t rrclass = 0;
+ DNSServiceQueryRecordReply callBack = 0;
+ void *context = 0; /* may be NULL */
+
+ if ( (DNSServiceQueryRecord( 0, flags, interfaceIndex, fullname, rrtype, rrclass, callBack, context) == 0)
+ || (DNSServiceQueryRecord(&sdRef, flags, interfaceIndex, 0, rrtype, rrclass, callBack, context) == 0)
+ || (DNSServiceQueryRecord(&sdRef, flags, interfaceIndex, fullname, rrtype, rrclass, 0, context) == 0)
+ )
+ {
+ printf("DNSServiceQueryRecord(): expected error return\n");
+ return 1;
+ }
+ }
- printf("DNSServiceGetAddrInfo()\n");
- if (DNSServiceGetAddrInfo(0, 0, 0, 0, 0, 0, 0) == 0)
+ // DNSServiceGetAddrInfo()
{
- printf("DNSServiceGetAddrInfo(): expected error return\n");
- return 1;
- };
+ DNSServiceRef sdRef;
+ DNSServiceFlags flags = 0;
+ uint32_t interfaceIndex = 0;
+ DNSServiceProtocol protocol = kDNSServiceProtocol_IPv4|kDNSServiceProtocol_IPv6;
+ const char *hostname = "host.local";
+ DNSServiceGetAddrInfoReply callBack = 0;
+ void *context = 0; // may be NULL
+
+ if ( (DNSServiceGetAddrInfo( 0, flags, interfaceIndex, protocol, hostname, callBack, context) == 0)
+ || (DNSServiceGetAddrInfo(&sdRef, flags, interfaceIndex, protocol, 0, callBack, context) == 0)
+ || (DNSServiceGetAddrInfo(&sdRef, flags, interfaceIndex, protocol, hostname, 0, context) == 0)
+ )
+ {
+ printf("DNSServiceGetAddrInfo(): expected error return\n");
+ return 1;
+ }
+ }
- printf("DNSServiceBrowse()\n");
- if (DNSServiceBrowse(0, 0, 0, 0, 0, 0, 0) == 0)
+ // DNSServiceBrowse()
{
- printf("DNSServiceBrowse(): expected error return\n");
- return 1;
- };
+ DNSServiceRef sdRef;
+ DNSServiceFlags flags = 0;
+ uint32_t interfaceIndex = 0;
+ const char *regtype = "_test._tcp";
+ const char *domain = 0; /* may be NULL */
+ DNSServiceBrowseReply callBack = 0;
+ void *context = 0; /* may be NULL */
+
+ if ( (DNSServiceBrowse( 0, flags, interfaceIndex, regtype, domain, callBack, context) == 0)
+ || (DNSServiceBrowse(&sdRef, flags, interfaceIndex, 0, domain, callBack, context) == 0)
+ || (DNSServiceBrowse(&sdRef, flags, interfaceIndex, regtype, domain, 0, context) == 0)
+ )
+ {
+ printf("DNSServiceBrowse(): expected error return\n");
+ return 1;
+ }
+ }
#if APPLE_OSX_mDNSResponder
- printf("DNSServiceSetDefaultDomainForUser()\n");
+ // DNSServiceSetDefaultDomainForUser()
if (DNSServiceSetDefaultDomainForUser(0, 0) == 0)
{
printf("DNSServiceSetDefaultDomainForUser(): expected error return\n");
return 1;
- };
+ }
#endif
- printf("DNSServiceRegister()\n");
- if (DNSServiceRegister(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) == 0)
+ // DNSServiceRegister()
{
- printf("DNSServiceRegister(): expected error return\n");
- return 1;
- };
+ DNSServiceRef sdRef;
+ DNSServiceFlags flags = 0;
+ uint32_t interfaceIndex = 0;
+ const char *name = 0; /* may be NULL */
+ const char *regtype = "_test._tcp";
+ const char *domain = 0; /* may be NULL */
+ const char *host = 0; /* may be NULL */
+ uint16_t port = 0x2211; /* In network byte order */
+ uint16_t txtLen = 1;
+ const void *txtRecord = "\0"; /* may be NULL */
+ DNSServiceRegisterReply callBack = 0; /* may be NULL */
+ void *context = 0; /* may be NULL */
+
+ if ( (DNSServiceRegister( 0, flags, interfaceIndex, name, regtype, domain, host, port, txtLen, txtRecord, callBack, context) == 0)
+ || (DNSServiceRegister(&sdRef, flags, interfaceIndex, name, 0, domain, host, port, txtLen, txtRecord, callBack, context) == 0)
+ )
+ {
+ printf("DNSServiceRegister(): expected error return\n");
+ return 1;
+ }
+ }
- printf("DNSServiceEnumerateDomains()\n");
- if (DNSServiceEnumerateDomains(0, 0, 0, 0, 0) == 0)
+ // DNSServiceEnumerateDomains()
{
- printf("DNSServiceEnumerateDomains(): expected error return\n");
- return 1;
- };
+ DNSServiceRef sdRef;
+ DNSServiceFlags flags = 0;
+ uint32_t interfaceIndex = 0;
+ DNSServiceDomainEnumReply callBack = 0;
+ void *context = 0; /* may be NULL */
+
+ if ( (DNSServiceEnumerateDomains( 0, flags, interfaceIndex, callBack, context) == 0)
+ || (DNSServiceEnumerateDomains(&sdRef, flags, interfaceIndex, 0, context) == 0)
+ )
+ {
+ printf("DNSServiceEnumerateDomains(): expected error return\n");
+ return 1;
+ }
+ }
- printf("DNSServiceCreateConnection()\n");
+ // DNSServiceCreateConnection()
if (DNSServiceCreateConnection(0) == 0)
{
printf("DNSServiceCreateConnection(): expected error return\n");
return 1;
- };
+ }
#if APPLE_OSX_mDNSResponder
- printf("DNSServiceCreateDelegateConnection()\n");
+ // DNSServiceCreateDelegateConnection()
if (DNSServiceCreateDelegateConnection(0, 0, 0) == 0)
{
printf("DNSServiceCreateDelegateConnection(): expected error return\n");
return 1;
- };
+ }
#endif
- printf("DNSServiceRegisterRecord()\n");
- if (DNSServiceRegisterRecord(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) == 0)
+ // DNSServiceRegisterRecord()
{
- printf("DNSServiceRegisterRecord(): expected error return\n");
- return 1;
- };
+ DNSServiceRef sdRef;
+ DNSRecordRef RecordRef;
+ DNSServiceFlags flags = 0;
+ uint32_t interfaceIndex = 0;
+ const char *fullname = "test1._test._tcp.local";
+ uint16_t rrtype = kDNSServiceType_TXT;
+ uint16_t rrclass = kDNSServiceClass_IN;
+ uint16_t rdlen = 1;
+ const void *rdata = "\0";
+ uint32_t ttl = 0;
+ DNSServiceRegisterRecordReply callBack = 0;
+ void *context = 0; /* may be NULL */
+
+ // Need an initialize sdRef
+ if (DNSServiceCreateConnection(&sdRef))
+ {
+ printf("DNSServiceCreateConnection(): failed\n");
+ return 1;
+ }
- printf("DNSServiceAddRecord()\n");
- if (DNSServiceAddRecord(0, 0, 0, 0, 0, 0, 0) == 0)
- {
- printf("DNSServiceAddRecord(): expected error return\n");
- return 1;
- };
+ if ( (DNSServiceRegisterRecord( 0, &RecordRef, flags, interfaceIndex, fullname, rrtype, rrclass, rdlen, rdata, ttl, callBack, context) == 0)
+ || (DNSServiceRegisterRecord(sdRef, &RecordRef, flags, interfaceIndex, 0, rrtype, rrclass, rdlen, rdata, ttl, callBack, context) == 0)
+ || (DNSServiceRegisterRecord(sdRef, &RecordRef, flags, interfaceIndex, fullname, rrtype, rrclass, rdlen, 0, ttl, callBack, context) == 0)
+ || (DNSServiceRegisterRecord(sdRef, &RecordRef, flags, interfaceIndex, fullname, rrtype, rrclass, rdlen, rdata, ttl, 0, context) == 0)
+ )
+ {
+ printf("DNSServiceRegisterRecord(): expected error return\n");
+ return 1;
+ }
+ }
- printf("DNSServiceUpdateRecord()\n");
- if (DNSServiceUpdateRecord(0, 0, 0, 0, 0, 0) == 0)
+ // DNSServiceAddRecord(), DNSServiceUpdateRecord(), and DNSServiceRemoveRecord() verify that they
+ // get a valid DNSServiceRef returned from DNSServiceRegister()
{
- printf("DNSServiceUpdateRecord(): expected error return\n");
- return 1;
- };
+ DNSServiceErrorType err;
+ Opaque16 registerPort = { { 0x12, 0x34 } };
+ static const char TXT[] = "\xC" "First String";
+ DNSServiceRef sdRef;
+
+ DNSRecordRef RecordRef;
+ DNSServiceFlags flags = 0;
+ uint16_t rrtype = kDNSServiceType_TXT;
+ uint16_t rdlen = 1;
+ const void *rdata = "\0";
+ uint32_t ttl = 100;
+
+ err = DNSServiceRegister(&sdRef, 0, 0, "Test", "_test._tcp.", "", NULL, registerPort.NotAnInteger, sizeof(TXT)-1, TXT, reg_reply, NULL);
+ if (err)
+ {
+ printf("DNSServiceRegister() failed with: %d\n", err);
+ return 1;
+ }
+
+ // DNSServiceAddRecord()
+ if ( (DNSServiceAddRecord( 0, &RecordRef, flags, rrtype, rdlen, rdata, ttl) == 0)
+ || (DNSServiceAddRecord(sdRef, 0, flags, rrtype, rdlen, rdata, ttl) == 0)
+ || (DNSServiceAddRecord(sdRef, &RecordRef, flags, rrtype, rdlen, 0, ttl) == 0)
+ )
- printf("DNSServiceRemoveRecord()\n");
- if (DNSServiceRemoveRecord(0, 0, 0) == 0)
- {
- printf("DNSServiceRemoveRecord(): expected error return\n");
- return 1;
- };
+ {
+ printf("DNSServiceAddRecord(): expected error return\n");
+ return 1;
+ }
+
+ // (rdlen == 0 && rdata == 0) should indicate a TXT with rdata containing only a 0 length byte.
+ if (DNSServiceAddRecord(sdRef, &RecordRef, flags, rrtype, 0, 0, ttl) == kDNSServiceErr_BadParam)
+ {
+ printf("DNSServiceAddRecord(): with (rdlen == 0 && rdata == 0) returned kDNSServiceErr_BadParam\n");
+ return 1;
+ }
+
+ // DNSServiceUpdateRecord()
+ // Note, RecordRef can be NULL per explanation with declaration in dns_sd.h
+ if ( (DNSServiceUpdateRecord( 0, RecordRef, flags, rdlen, rdata, ttl) == 0)
+ || (DNSServiceUpdateRecord(sdRef, RecordRef, flags, rdlen, 0, ttl) == 0)
+ )
+ {
+ printf("DNSServiceUpdateRecord(): expected error return\n");
+ return 1;
+ }
+
+ // (rdlen == 0 && rdata == 0) should indicate a TXT with rdata containing only a 0 length byte.
+ if (DNSServiceUpdateRecord(sdRef, RecordRef, flags, 0, 0, ttl) == kDNSServiceErr_BadParam)
+ {
+ printf("DNSServiceUpdateRecord(): with (rdlen == 0 && rdata == 0) returned kDNSServiceErr_BadParam\n");
+ return 1;
+ }
+
+ // DNSServiceRemoveRecord()
+ if ( (DNSServiceRemoveRecord( 0, RecordRef, flags) == 0)
+ || (DNSServiceRemoveRecord(sdRef, 0, flags) == 0)
+ )
+ {
+ printf("DNSServiceRemoveRecord(): expected error return\n");
+ return 1;
+ }
+
+ DNSServiceRefDeallocate(sdRef);
+ }
- printf("DNSServiceReconfirmRecord()\n");
- if (DNSServiceReconfirmRecord(0, 0, 0, 0, 0, 0, 0) == 0)
+ // DNSServiceReconfirmRecord()
{
- printf("DNSServiceReconfirmRecord(): expected error return\n");
- return 1;
- };
+ DNSServiceFlags flags = 0;
+ uint32_t interfaceIndex = 0;
+ const char *fullname = "aaa._test._tcp.local";
+ uint16_t rrtype = kDNSServiceType_TXT;
+ uint16_t rrclass = kDNSServiceClass_IN;
+ uint16_t rdlen = 1;
+ const void *rdata = "\0";
+
+ if ( (DNSServiceReconfirmRecord(flags, interfaceIndex, 0, rrtype, rrclass, rdlen, rdata) == 0)
+ || (DNSServiceReconfirmRecord(flags, interfaceIndex, fullname, rrtype, rrclass, rdlen, 0) == 0)
+ )
+ {
+ printf("DNSServiceReconfirmRecord(): expected error return\n");
+ return 1;
+ }
+ // (rdlen == 0 && rdata == 0) should indicate a TXT with rdata containing only a 0 length byte.
+ if (DNSServiceReconfirmRecord(flags, interfaceIndex, fullname, rrtype, rrclass, 0, 0) == kDNSServiceErr_BadParam)
+ {
+ printf("DNSServiceReconfirmRecord(): with (rdlen == 0 && rdata == 0) returned kDNSServiceErr_BadParam\n");
+ return 1;
+ }
+ }
- printf("Basic API input range tests with all parameters set to 0: PASSED\n");
+ printf("Basic API input range tests: PASSED\n");
return 0;
}
@@ -1739,6 +1923,14 @@ int main(int argc, char **argv)
flags |= kDNSServiceFlagsIncludeP2P;
printf("Setting kDNSServiceFlagsIncludeP2P\n");
}
+
+ if (argc > 1 && !strcasecmp(argv[1], "-fmc"))
+ {
+ argc--;
+ argv++;
+ flags |= kDNSServiceFlagsForceMulticast;
+ printf("Setting kDNSServiceFlagsForceMulticast flag for this request\n");
+ }
if (argc > 1 && !strcasecmp(argv[1], "-includeAWDL"))
{
@@ -2002,6 +2194,7 @@ int main(int argc, char **argv)
case 'g':
case 'G': {
flags |= kDNSServiceFlagsReturnIntermediates;
+
if (operation == 'g')
{
flags |= kDNSServiceFlagsSuppressUnusable;
diff --git a/mDNSResponder/Clients/dnssdutil.c b/mDNSResponder/Clients/dnssdutil.c
new file mode 100644
index 00000000..068f05a6
--- /dev/null
+++ b/mDNSResponder/Clients/dnssdutil.c
@@ -0,0 +1,7899 @@
+/*
+ Copyright (c) 2016-2017 Apple Inc. All rights reserved.
+
+ dnssdutil is a command-line utility for testing the DNS-SD API.
+*/
+
+#include <CoreUtils/CommonServices.h> // Include early.
+#include <CoreUtils/AsyncConnection.h>
+#include <CoreUtils/CommandLineUtils.h>
+#include <CoreUtils/DataBufferUtils.h>
+#include <CoreUtils/DebugServices.h>
+#include <CoreUtils/MiscUtils.h>
+#include <CoreUtils/NetUtils.h>
+#include <CoreUtils/PrintFUtils.h>
+#include <CoreUtils/RandomNumberUtils.h>
+#include <CoreUtils/StringUtils.h>
+#include <CoreUtils/TickUtils.h>
+#include <dns_sd.h>
+#include <dns_sd_private.h>
+
+#if( TARGET_OS_DARWIN )
+ #include <libproc.h>
+ #include <sys/proc_info.h>
+#endif
+
+#if( TARGET_OS_POSIX )
+ #include <sys/resource.h>
+#endif
+
+#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
+ #include "tweetnacl.h" // TweetNaCl from <https://tweetnacl.cr.yp.to/software.html>.
+#endif
+
+//===========================================================================================================================
+// Global Constants
+//===========================================================================================================================
+
+// Versioning
+
+#define kDNSSDUtilNumVersion NumVersionBuild( 2, 0, 0, kVersionStageBeta, 0 )
+
+#if( !MDNSRESPONDER_PROJECT && !defined( DNSSDUTIL_SOURCE_VERSION ) )
+ #define DNSSDUTIL_SOURCE_VERSION "0.0.0"
+#endif
+
+// DNS-SD API flag descriptors
+
+#define kDNSServiceFlagsDescriptors \
+ "\x00" "AutoTrigger\0" \
+ "\x01" "Add\0" \
+ "\x02" "Default\0" \
+ "\x03" "NoAutoRename\0" \
+ "\x04" "Shared\0" \
+ "\x05" "Unique\0" \
+ "\x06" "BrowseDomains\0" \
+ "\x07" "RegistrationDomains\0" \
+ "\x08" "LongLivedQuery\0" \
+ "\x09" "AllowRemoteQuery\0" \
+ "\x0A" "ForceMulticast\0" \
+ "\x0B" "KnownUnique\0" \
+ "\x0C" "ReturnIntermediates\0" \
+ "\x0D" "NonBrowsable\0" \
+ "\x0E" "ShareConnection\0" \
+ "\x0F" "SuppressUnusable\0" \
+ "\x10" "Timeout\0" \
+ "\x11" "IncludeP2P\0" \
+ "\x12" "WakeOnResolve\0" \
+ "\x13" "BackgroundTrafficClass\0" \
+ "\x14" "IncludeAWDL\0" \
+ "\x15" "Validate\0" \
+ "\x16" "UnicastResponse\0" \
+ "\x17" "ValidateOptional\0" \
+ "\x18" "WakeOnlyService\0" \
+ "\x19" "ThresholdOne\0" \
+ "\x1A" "ThresholdFinder\0" \
+ "\x1B" "DenyCellular\0" \
+ "\x1C" "ServiceIndex\0" \
+ "\x1D" "DenyExpensive\0" \
+ "\x1E" "PathEvaluationDone\0" \
+ "\x00"
+
+#define kDNSServiceProtocolDescriptors \
+ "\x00" "IPv4\0" \
+ "\x01" "IPv6\0" \
+ "\x00"
+
+// (m)DNS
+
+#define kDNSHeaderFlag_Response ( 1 << 15 )
+#define kDNSHeaderFlag_AuthAnswer ( 1 << 10 )
+#define kDNSHeaderFlag_Truncation ( 1 << 9 )
+#define kDNSHeaderFlag_RecursionDesired ( 1 << 8 )
+#define kDNSHeaderFlag_RecursionAvailable ( 1 << 7 )
+
+#define kDNSOpCode_Query 0
+#define kDNSOpCode_InverseQuery 1
+#define kDNSOpCode_Status 2
+#define kDNSOpCode_Notify 4
+#define kDNSOpCode_Update 5
+
+#define kDNSRCode_NoError 0
+#define kDNSRCode_FormatError 1
+#define kDNSRCode_ServerFailure 2
+#define kDNSRCode_NXDomain 3
+#define kDNSRCode_NotImplemented 4
+#define kDNSRCode_Refused 5
+
+#define kQClassUnicastResponseBit ( 1U << 15 )
+#define kRRClassCacheFlushBit ( 1U << 15 )
+
+#define kDomainLabelLengthMax 63
+#define kDomainNameLengthMax 256
+
+//===========================================================================================================================
+// Gerneral Command Options
+//===========================================================================================================================
+
+// Command option macros
+
+#define Command( NAME, CALLBACK, SUB_OPTIONS, SHORT_HELP, IS_NOTCOMMON ) \
+ CLI_COMMAND_EX( NAME, CALLBACK, SUB_OPTIONS, (IS_NOTCOMMON) ? kCLIOptionFlags_NotCommon : kCLIOptionFlags_None, \
+ (SHORT_HELP), NULL )
+
+#define kRequiredOptionSuffix " [REQUIRED]"
+
+#define MultiStringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, VAL_COUNT_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED, LONG_HELP ) \
+ CLI_OPTION_MULTI_STRING_EX( SHORT_CHAR, LONG_NAME, VAL_PTR, VAL_COUNT_PTR, ARG_HELP, \
+ (IS_REQUIRED) ? SHORT_HELP kRequiredOptionSuffix : SHORT_HELP, \
+ (IS_REQUIRED) ? kCLIOptionFlags_Required : kCLIOptionFlags_None, LONG_HELP )
+
+#define MultiStringOption( SHORT_CHAR, LONG_NAME, VAL_PTR, VAL_COUNT_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED ) \
+ MultiStringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, VAL_COUNT_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED, NULL )
+
+#define IntegerOption( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED ) \
+ CLI_OPTION_INTEGER_EX( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, \
+ (IS_REQUIRED) ? SHORT_HELP kRequiredOptionSuffix : SHORT_HELP, \
+ (IS_REQUIRED) ? kCLIOptionFlags_Required : kCLIOptionFlags_None, NULL )
+
+#define BooleanOption( SHORT_CHAR, LONG_NAME, VAL_PTR, SHORT_HELP ) \
+ CLI_OPTION_BOOLEAN( (SHORT_CHAR), (LONG_NAME), (VAL_PTR), (SHORT_HELP), NULL )
+
+#define StringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED, LONG_HELP ) \
+ CLI_OPTION_STRING_EX( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, \
+ (IS_REQUIRED) ? SHORT_HELP kRequiredOptionSuffix : SHORT_HELP, \
+ (IS_REQUIRED) ? kCLIOptionFlags_Required : kCLIOptionFlags_None, LONG_HELP )
+
+#define StringOption( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED ) \
+ StringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED, NULL )
+
+// DNS-SD API flag options
+
+static int gDNSSDFlags = 0;
+static int gDNSSDFlag_BrowseDomains = false;
+static int gDNSSDFlag_DenyCellular = false;
+static int gDNSSDFlag_DenyExpensive = false;
+static int gDNSSDFlag_ForceMulticast = false;
+static int gDNSSDFlag_IncludeAWDL = false;
+static int gDNSSDFlag_NoAutoRename = false;
+static int gDNSSDFlag_PathEvaluationDone = false;
+static int gDNSSDFlag_RegistrationDomains = false;
+static int gDNSSDFlag_ReturnIntermediates = false;
+static int gDNSSDFlag_Shared = false;
+static int gDNSSDFlag_SuppressUnusable = false;
+static int gDNSSDFlag_Timeout = false;
+static int gDNSSDFlag_UnicastResponse = false;
+static int gDNSSDFlag_Unique = false;
+
+#define DNSSDFlagsOption() \
+ IntegerOption( 'f', "flags", &gDNSSDFlags, "flags", \
+ "DNSServiceFlags to use. This value is bitwise ORed with other single flag options.", false )
+
+#define DNSSDFlagOption( SHORT_CHAR, FLAG_NAME ) \
+ BooleanOption( SHORT_CHAR, Stringify( FLAG_NAME ), &gDNSSDFlag_ ## FLAG_NAME, \
+ "Use kDNSServiceFlags" Stringify( FLAG_NAME ) "." )
+
+#define DNSSDFlagsOption_DenyCellular() DNSSDFlagOption( 'C', DenyCellular )
+#define DNSSDFlagsOption_DenyExpensive() DNSSDFlagOption( 'E', DenyExpensive )
+#define DNSSDFlagsOption_ForceMulticast() DNSSDFlagOption( 'M', ForceMulticast )
+#define DNSSDFlagsOption_IncludeAWDL() DNSSDFlagOption( 'A', IncludeAWDL )
+#define DNSSDFlagsOption_NoAutoRename() DNSSDFlagOption( 'N', NoAutoRename )
+#define DNSSDFlagsOption_PathEvalDone() DNSSDFlagOption( 'P', PathEvaluationDone )
+#define DNSSDFlagsOption_ReturnIntermediates() DNSSDFlagOption( 'I', ReturnIntermediates )
+#define DNSSDFlagsOption_Shared() DNSSDFlagOption( 'S', Shared )
+#define DNSSDFlagsOption_SuppressUnusable() DNSSDFlagOption( 'S', SuppressUnusable )
+#define DNSSDFlagsOption_Timeout() DNSSDFlagOption( 'T', Timeout )
+#define DNSSDFlagsOption_UnicastResponse() DNSSDFlagOption( 'U', UnicastResponse )
+#define DNSSDFlagsOption_Unique() DNSSDFlagOption( 'U', Unique )
+
+// Interface option
+
+static const char * gInterface = NULL;
+
+#define InterfaceOption() \
+ StringOption( 'i', "interface", &gInterface, "interface", \
+ "Network interface by name or index. Use index -1 for local-only.", false )
+
+// Connection options
+
+#define kConnectionArg_Normal ""
+#define kConnectionArgPrefix_PID "pid:"
+#define kConnectionArgPrefix_UUID "uuid:"
+
+static const char * gConnectionOpt = kConnectionArg_Normal;
+
+#define ConnectionOptions() \
+ { kCLIOptionType_String, 0, "connection", &gConnectionOpt, NULL, (intptr_t) kConnectionArg_Normal, "type", \
+ kCLIOptionFlags_OptionalArgument, NULL, NULL, NULL, NULL, \
+ "Specifies the type of main connection to use. See " kConnectionSection_Name " below.", NULL }
+
+#define kConnectionSection_Name "Connection Option"
+#define kConnectionSection_Text \
+ "The default behavior is to create a main connection with DNSServiceCreateConnection() and perform operations on\n" \
+ "the main connection using the kDNSServiceFlagsShareConnection flag. This behavior can be explicitly invoked by\n" \
+ "specifying the connection option without an argument, i.e.,\n" \
+ "\n" \
+ " --connection\n" \
+ "\n" \
+ "To instead use a delegate connection created with DNSServiceCreateDelegateConnection(), use\n" \
+ "\n" \
+ " --connection=pid:<PID>\n" \
+ "\n" \
+ "to specify the delegator by PID, or use\n" \
+ "\n" \
+ " --connection=uuid:<UUID>\n" \
+ "\n" \
+ "to specify the delegator by UUID.\n" \
+ "\n" \
+ "To not use a main connection at all, but instead perform operations on their own connections, use\n" \
+ "\n" \
+ " --no-connection\n"
+
+#define ConnectionSection() CLI_SECTION( kConnectionSection_Name, kConnectionSection_Text )
+
+// Help text for record data options
+
+#define kRDataArgPrefix_File "file:"
+#define kRDataArgPrefix_HexString "hex:"
+#define kRDataArgPrefix_String "string:"
+#define kRDataArgPrefix_TXT "txt:"
+
+#define kRecordDataSection_Name "Record Data Arguments"
+#define kRecordDataSection_Text \
+ "A record data argument is specified in one of the following formats:\n" \
+ "\n" \
+ "Format Syntax Example\n" \
+ "String string:<string> string:'\\x09color=red'\n" \
+ "Hexadecimal string hex:<hex string> hex:c0a80101 or hex:'C0 A8 01 01'\n" \
+ "TXT record keys and values txt:<comma-delimited keys and values> txt:'key1=x,key2=y\\,z,key3'\n" \
+ "File containing raw record data file:<file path> file:dir/record_data.bin\n"
+
+#define RecordDataSection() CLI_SECTION( kRecordDataSection_Name, kRecordDataSection_Text )
+
+//===========================================================================================================================
+// Browse Command Options
+//===========================================================================================================================
+
+static char ** gBrowse_ServiceTypes = NULL;
+static size_t gBrowse_ServiceTypesCount = 0;
+static const char * gBrowse_Domain = NULL;
+static int gBrowse_DoResolve = false;
+static int gBrowse_QueryTXT = false;
+static int gBrowse_TimeLimitSecs = 0;
+
+static CLIOption kBrowseOpts[] =
+{
+ InterfaceOption(),
+ MultiStringOption( 't', "type", &gBrowse_ServiceTypes, &gBrowse_ServiceTypesCount, "service type", "Service type(s), e.g., \"_ssh._tcp\".", true ),
+ StringOption( 'd', "domain", &gBrowse_Domain, "domain", "Domain in which to browse for the service type(s).", false ),
+
+ CLI_OPTION_GROUP( "Flags" ),
+ DNSSDFlagsOption(),
+ DNSSDFlagsOption_IncludeAWDL(),
+
+ CLI_OPTION_GROUP( "Operation" ),
+ ConnectionOptions(),
+ BooleanOption( 0 , "resolve", &gBrowse_DoResolve, "Resolve service instances." ),
+ BooleanOption( 0 , "queryTXT", &gBrowse_QueryTXT, "Query TXT records of service instances." ),
+ IntegerOption( 'l', "timeLimit", &gBrowse_TimeLimitSecs, "seconds", "Specifies the max duration of the browse operation. Use '0' for no time limit.", false ),
+
+ ConnectionSection(),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// GetAddrInfo Command Options
+//===========================================================================================================================
+
+static const char * gGetAddrInfo_Name = NULL;
+static int gGetAddrInfo_ProtocolIPv4 = false;
+static int gGetAddrInfo_ProtocolIPv6 = false;
+static int gGetAddrInfo_OneShot = false;
+static int gGetAddrInfo_TimeLimitSecs = 0;
+
+static CLIOption kGetAddrInfoOpts[] =
+{
+ InterfaceOption(),
+ StringOption( 'n', "name", &gGetAddrInfo_Name, "domain name", "Domain name to resolve.", true ),
+ BooleanOption( 0 , "ipv4", &gGetAddrInfo_ProtocolIPv4, "Use kDNSServiceProtocol_IPv4." ),
+ BooleanOption( 0 , "ipv6", &gGetAddrInfo_ProtocolIPv6, "Use kDNSServiceProtocol_IPv6." ),
+
+ CLI_OPTION_GROUP( "Flags" ),
+ DNSSDFlagsOption(),
+ DNSSDFlagsOption_DenyCellular(),
+ DNSSDFlagsOption_DenyExpensive(),
+ DNSSDFlagsOption_PathEvalDone(),
+ DNSSDFlagsOption_ReturnIntermediates(),
+ DNSSDFlagsOption_SuppressUnusable(),
+ DNSSDFlagsOption_Timeout(),
+
+ CLI_OPTION_GROUP( "Operation" ),
+ ConnectionOptions(),
+ BooleanOption( 'o', "oneshot", &gGetAddrInfo_OneShot, "Finish after first set of results." ),
+ IntegerOption( 'l', "timeLimit", &gGetAddrInfo_TimeLimitSecs, "seconds", "Maximum duration of the GetAddrInfo operation. Use '0' for no time limit.", false ),
+
+ ConnectionSection(),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// QueryRecord Command Options
+//===========================================================================================================================
+
+static const char * gQueryRecord_Name = NULL;
+static const char * gQueryRecord_Type = NULL;
+static int gQueryRecord_OneShot = false;
+static int gQueryRecord_TimeLimitSecs = 0;
+static int gQueryRecord_RawRData = false;
+
+static CLIOption kQueryRecordOpts[] =
+{
+ InterfaceOption(),
+ StringOption( 'n', "name", &gQueryRecord_Name, "domain name", "Full domain name of record to query.", true ),
+ StringOption( 't', "type", &gQueryRecord_Type, "record type", "Record type by name (e.g., TXT, SRV, etc.) or number.", true ),
+
+ CLI_OPTION_GROUP( "Flags" ),
+ DNSSDFlagsOption(),
+ DNSSDFlagsOption_IncludeAWDL(),
+ DNSSDFlagsOption_ForceMulticast(),
+ DNSSDFlagsOption_Timeout(),
+ DNSSDFlagsOption_ReturnIntermediates(),
+ DNSSDFlagsOption_SuppressUnusable(),
+ DNSSDFlagsOption_UnicastResponse(),
+ DNSSDFlagsOption_DenyCellular(),
+ DNSSDFlagsOption_DenyExpensive(),
+ DNSSDFlagsOption_PathEvalDone(),
+
+ CLI_OPTION_GROUP( "Operation" ),
+ ConnectionOptions(),
+ BooleanOption( 'o', "oneshot", &gQueryRecord_OneShot, "Finish after first set of results." ),
+ IntegerOption( 'l', "timeLimit", &gQueryRecord_TimeLimitSecs, "seconds", "Maximum duration of the query record operation. Use '0' for no time limit.", false ),
+ BooleanOption( 'r', "raw", &gQueryRecord_RawRData, "Show record data as a hexdump." ),
+
+ ConnectionSection(),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// Register Command Options
+//===========================================================================================================================
+
+static const char * gRegister_Name = NULL;
+static const char * gRegister_Type = NULL;
+static const char * gRegister_Domain = NULL;
+static int gRegister_Port = 0;
+static const char * gRegister_TXT = NULL;
+static int gRegister_LifetimeMs = -1;
+static const char ** gAddRecord_Types = NULL;
+static size_t gAddRecord_TypesCount = 0;
+static const char ** gAddRecord_Data = NULL;
+static size_t gAddRecord_DataCount = 0;
+static const char ** gAddRecord_TTLs = NULL;
+static size_t gAddRecord_TTLsCount = 0;
+static const char * gUpdateRecord_Data = NULL;
+static int gUpdateRecord_DelayMs = 0;
+static int gUpdateRecord_TTL = 0;
+
+static CLIOption kRegisterOpts[] =
+{
+ InterfaceOption(),
+ StringOption( 'n', "name", &gRegister_Name, "service name", "Name of service.", false ),
+ StringOption( 't', "type", &gRegister_Type, "service type", "Service type, e.g., \"_ssh._tcp\".", true ),
+ StringOption( 'd', "domain", &gRegister_Domain, "domain", "Domain in which to advertise the service.", false ),
+ IntegerOption( 'p', "port", &gRegister_Port, "port number", "Service's port number.", true ),
+ StringOption( 0 , "txt", &gRegister_TXT, "record data", "The TXT record data. See " kRecordDataSection_Name " below.", false ),
+
+ CLI_OPTION_GROUP( "Flags" ),
+ DNSSDFlagsOption(),
+ DNSSDFlagsOption_IncludeAWDL(),
+ DNSSDFlagsOption_NoAutoRename(),
+
+ CLI_OPTION_GROUP( "Operation" ),
+ IntegerOption( 'l', "lifetime", &gRegister_LifetimeMs, "ms", "Lifetime of the service registration in milliseconds.", false ),
+
+ CLI_OPTION_GROUP( "Options for updating the registered service's primary TXT record with DNSServiceUpdateRecord()\n" ),
+ StringOption( 0 , "updateData", &gUpdateRecord_Data, "record data", "Record data for the record update. See " kRecordDataSection_Name " below.", false ),
+ IntegerOption( 0 , "updateDelay", &gUpdateRecord_DelayMs, "ms", "Number of milliseconds after registration to wait before record update.", false ),
+ IntegerOption( 0 , "updateTTL", &gUpdateRecord_TTL, "seconds", "Time-to-live of the updated record.", false ),
+
+ CLI_OPTION_GROUP( "Options for adding extra record(s) to the registered service with DNSServiceAddRecord()\n" ),
+ MultiStringOption( 0 , "addType", &gAddRecord_Types, &gAddRecord_TypesCount, "record type", "Type of additional record by name (e.g., TXT, SRV, etc.) or number.", false ),
+ MultiStringOptionEx( 0 , "addData", &gAddRecord_Data, &gAddRecord_DataCount, "record data", "Additional record's data. See " kRecordDataSection_Name " below.", false, NULL ),
+ MultiStringOption( 0 , "addTTL", &gAddRecord_TTLs, &gAddRecord_TTLsCount, "seconds", "Time-to-live of additional record in seconds. Use '0' for default.", false ),
+
+ RecordDataSection(),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// RegisterRecord Command Options
+//===========================================================================================================================
+
+static const char * gRegisterRecord_Name = NULL;
+static const char * gRegisterRecord_Type = NULL;
+static const char * gRegisterRecord_Data = NULL;
+static int gRegisterRecord_TTL = 0;
+static int gRegisterRecord_LifetimeMs = -1;
+static const char * gRegisterRecord_UpdateData = NULL;
+static int gRegisterRecord_UpdateDelayMs = 0;
+static int gRegisterRecord_UpdateTTL = 0;
+
+static CLIOption kRegisterRecordOpts[] =
+{
+ InterfaceOption(),
+ StringOption( 'n', "name", &gRegisterRecord_Name, "record name", "Fully qualified domain name of record.", true ),
+ StringOption( 't', "type", &gRegisterRecord_Type, "record type", "Record type by name (e.g., TXT, PTR, A) or number.", true ),
+ StringOption( 'd', "data", &gRegisterRecord_Data, "record data", "The record data. See " kRecordDataSection_Name " below.", false ),
+ IntegerOption( 0 , "ttl", &gRegisterRecord_TTL, "seconds", "Time-to-live in seconds. Use '0' for default.", false ),
+
+ CLI_OPTION_GROUP( "Flags" ),
+ DNSSDFlagsOption(),
+ DNSSDFlagsOption_IncludeAWDL(),
+ DNSSDFlagsOption_Shared(),
+ DNSSDFlagsOption_Unique(),
+
+ CLI_OPTION_GROUP( "Operation" ),
+ IntegerOption( 'l', "lifetime", &gRegisterRecord_LifetimeMs, "ms", "Lifetime of the service registration in milliseconds.", false ),
+
+ CLI_OPTION_GROUP( "Options for updating the registered record with DNSServiceUpdateRecord()\n" ),
+ StringOption( 0 , "updateData", &gRegisterRecord_UpdateData, "record data", "Record data for the record update.", false ),
+ IntegerOption( 0 , "updateDelay", &gRegisterRecord_UpdateDelayMs, "ms", "Number of milliseconds after registration to wait before record update.", false ),
+ IntegerOption( 0 , "updateTTL", &gRegisterRecord_UpdateTTL, "seconds", "Time-to-live of the updated record.", false ),
+
+ RecordDataSection(),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// Resolve Command Options
+//===========================================================================================================================
+
+static char * gResolve_Name = NULL;
+static char * gResolve_Type = NULL;
+static char * gResolve_Domain = NULL;
+static int gResolve_TimeLimitSecs = 0;
+
+static CLIOption kResolveOpts[] =
+{
+ InterfaceOption(),
+ StringOption( 'n', "name", &gResolve_Name, "service name", "Name of the service instance to resolve.", true ),
+ StringOption( 't', "type", &gResolve_Type, "service type", "Type of the service instance to resolve.", true ),
+ StringOption( 'd', "domain", &gResolve_Domain, "domain", "Domain of the service instance to resolve.", true ),
+
+ CLI_OPTION_GROUP( "Flags" ),
+ DNSSDFlagsOption(),
+ DNSSDFlagsOption_ForceMulticast(),
+ DNSSDFlagsOption_IncludeAWDL(),
+ DNSSDFlagsOption_ReturnIntermediates(),
+
+ CLI_OPTION_GROUP( "Operation" ),
+ ConnectionOptions(),
+ IntegerOption( 'l', "timeLimit", &gResolve_TimeLimitSecs, "seconds", "Maximum duration of the resolve operation. Use '0' for no time limit.", false ),
+
+ ConnectionSection(),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// Reconfirm Command Options
+//===========================================================================================================================
+
+static const char * gReconfirmRecord_Name = NULL;
+static const char * gReconfirmRecord_Type = NULL;
+static const char * gReconfirmRecord_Class = NULL;
+static const char * gReconfirmRecord_Data = NULL;
+
+static CLIOption kReconfirmOpts[] =
+{
+ InterfaceOption(),
+ StringOption( 'n', "name", &gReconfirmRecord_Name, "record name", "Full name of the record to reconfirm.", true ),
+ StringOption( 't', "type", &gReconfirmRecord_Type, "record type", "Type of the record to reconfirm.", true ),
+ StringOption( 'c', "class", &gReconfirmRecord_Class, "record class", "Class of the record to reconfirm. Default class is IN.", false ),
+ StringOption( 'd', "data", &gReconfirmRecord_Data, "record data", "The record data. See " kRecordDataSection_Name " below.", false ),
+
+ CLI_OPTION_GROUP( "Flags" ),
+ DNSSDFlagsOption(),
+
+ RecordDataSection(),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// getaddrinfo-POSIX Command Options
+//===========================================================================================================================
+
+static const char * gGAIPOSIX_Name = NULL;
+static const char * gGAIPOSIX_Family = NULL;
+
+static CLIOption kGetAddrInfoPOSIXOpts[] =
+{
+ StringOption( 'n', "name", &gGAIPOSIX_Name, "domain name", "Domain name to resolve.", true ),
+ StringOptionEx( 'f', "family", &gGAIPOSIX_Family, "address family", "Address family to pass to getaddrinfo().", false,
+ "The address family value determines which value to use for the ai_family element of the hints struct addrinfo\n"
+ "argument used when calling getaddrinfo().\n"
+ "\n"
+ "Possible address family values are 'inet' for AF_INET, 'inet6' for AF_INET6, or 'unspec' for AF_UNSPEC. If no\n"
+ "address family is specified, then AF_UNSPEC is used.\n" ),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// ReverseLookup Command Options
+//===========================================================================================================================
+
+static const char * gReverseLookup_IPAddr = NULL;
+static int gReverseLookup_OneShot = false;
+static int gReverseLookup_TimeLimitSecs = 0;
+
+static CLIOption kReverseLookupOpts[] =
+{
+ InterfaceOption(),
+ StringOption( 'a', "address", &gReverseLookup_IPAddr, "IP address", "IPv4 or IPv6 address for which to perform a reverse IP lookup.", true ),
+
+ CLI_OPTION_GROUP( "Flags" ),
+ DNSSDFlagsOption(),
+ DNSSDFlagsOption_ForceMulticast(),
+ DNSSDFlagsOption_ReturnIntermediates(),
+ DNSSDFlagsOption_SuppressUnusable(),
+
+ CLI_OPTION_GROUP( "Operation" ),
+ ConnectionOptions(),
+ BooleanOption( 'o', "oneshot", &gReverseLookup_OneShot, "Finish after first set of results." ),
+ IntegerOption( 'l', "timeLimit", &gReverseLookup_TimeLimitSecs, "seconds", "Specifies the max duration of the query record operation. Use '0' for no time limit.", false ),
+
+ ConnectionSection(),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// BrowseAll Command Options
+//===========================================================================================================================
+
+static const char * gBrowseAll_Domain = NULL;
+static char ** gBrowseAll_ServiceTypes = NULL;
+static size_t gBrowseAll_ServiceTypesCount = 0;
+static int gBrowseAll_IncludeAWDL = false;
+static int gBrowseAll_BrowseTimeSecs = 5;
+static int gBrowseAll_ConnectTimeLimitSecs = 5;
+
+static CLIOption kBrowseAllOpts[] =
+{
+ InterfaceOption(),
+ StringOption( 'd', "domain", &gBrowseAll_Domain, "domain", "Domain in which to browse for the service.", false ),
+ MultiStringOption( 't', "type", &gBrowseAll_ServiceTypes, &gBrowseAll_ServiceTypesCount, "service type", "Service type(s), e.g., \"_ssh._tcp\".", false ),
+
+ CLI_OPTION_GROUP( "Flags" ),
+ DNSSDFlagsOption_IncludeAWDL(),
+
+ CLI_OPTION_GROUP( "Operation" ),
+ IntegerOption( 'b', "browseTime", &gBrowseAll_BrowseTimeSecs, "seconds", "Specifies the duration of the browse.", false ),
+ IntegerOption( 'c', "connectTimeLimit", &gBrowseAll_ConnectTimeLimitSecs, "seconds", "Specifies the max duration of the connect operations.", false ),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// GetAddrInfoStress Command Options
+//===========================================================================================================================
+
+static int gGAIStress_TestDurationSecs = 0;
+static int gGAIStress_ConnectionCount = 0;
+static int gGAIStress_DurationMinMs = 0;
+static int gGAIStress_DurationMaxMs = 0;
+static int gGAIStress_RequestCountMax = 0;
+
+static CLIOption kGetAddrInfoStressOpts[] =
+{
+ InterfaceOption(),
+
+ CLI_OPTION_GROUP( "Flags" ),
+ DNSSDFlagsOption_ReturnIntermediates(),
+ DNSSDFlagsOption_SuppressUnusable(),
+
+ CLI_OPTION_GROUP( "Operation" ),
+ IntegerOption( 0, "testDuration", &gGAIStress_TestDurationSecs, "seconds", "Stress test duration in seconds. Use '0' for forever.", false ),
+ IntegerOption( 0, "connectionCount", &gGAIStress_ConnectionCount, "integer", "Number of simultaneous DNS-SD connections.", true ),
+ IntegerOption( 0, "requestDurationMin", &gGAIStress_DurationMinMs, "ms", "Minimum duration of DNSServiceGetAddrInfo() request in milliseconds.", true ),
+ IntegerOption( 0, "requestDurationMax", &gGAIStress_DurationMaxMs, "ms", "Maximum duration of DNSServiceGetAddrInfo() request in milliseconds.", true ),
+ IntegerOption( 0, "consecutiveRequestMax", &gGAIStress_RequestCountMax, "integer", "Maximum number of requests on a connection before restarting it.", true ),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// DNSQuery Command Options
+//===========================================================================================================================
+
+static char * gDNSQuery_Name = NULL;
+static char * gDNSQuery_Type = "A";
+static char * gDNSQuery_Server = NULL;
+static int gDNSQuery_TimeLimitSecs = 5;
+static int gDNSQuery_UseTCP = false;
+static int gDNSQuery_Flags = kDNSHeaderFlag_RecursionDesired;
+static int gDNSQuery_RawRData = false;
+static int gDNSQuery_Verbose = false;
+
+static CLIOption kDNSQueryOpts[] =
+{
+ StringOption( 'n', "name", &gDNSQuery_Name, "name", "Question name (QNAME) to put in DNS query message.", true ),
+ StringOption( 't', "type", &gDNSQuery_Type, "type", "Question type (QTYPE) to put in DNS query message. Default value is 'A'.", false ),
+ StringOption( 's', "server", &gDNSQuery_Server, "IP address", "DNS server's IPv4 or IPv6 address.", true ),
+ IntegerOption( 'l', "timeLimit", &gDNSQuery_TimeLimitSecs, "seconds", "Specifies query time limit. Use '-1' for no limit and '0' to exit immediately after sending.", false ),
+ BooleanOption( 0 , "tcp", &gDNSQuery_UseTCP, "Send the DNS query via TCP instead of UDP." ),
+ IntegerOption( 'f', "flags", &gDNSQuery_Flags, "flags", "16-bit value for DNS header flags/codes field. Default value is 0x0100 (Recursion Desired).", false ),
+ BooleanOption( 'r', "raw", &gDNSQuery_RawRData, "Present record data as a hexdump." ),
+ BooleanOption( 'v', "verbose", &gDNSQuery_Verbose, "Prints the DNS message to be sent to the server." ),
+ CLI_OPTION_END()
+};
+
+#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
+//===========================================================================================================================
+// DNSCrypt Command Options
+//===========================================================================================================================
+
+static char * gDNSCrypt_ProviderName = NULL;
+static char * gDNSCrypt_ProviderKey = NULL;
+static char * gDNSCrypt_Name = NULL;
+static char * gDNSCrypt_Type = NULL;
+static char * gDNSCrypt_Server = NULL;
+static int gDNSCrypt_TimeLimitSecs = 5;
+static int gDNSCrypt_RawRData = false;
+static int gDNSCrypt_Verbose = false;
+
+static CLIOption kDNSCryptOpts[] =
+{
+ StringOption( 'p', "providerName", &gDNSCrypt_ProviderName, "name", "The DNSCrypt provider name.", true ),
+ StringOption( 'k', "providerKey", &gDNSCrypt_ProviderKey, "hex string", "The DNSCrypt provider's public signing key.", true ),
+ StringOption( 'n', "name", &gDNSCrypt_Name, "name", "Question name (QNAME) to put in DNS query message.", true ),
+ StringOption( 't', "type", &gDNSCrypt_Type, "type", "Question type (QTYPE) to put in DNS query message.", true ),
+ StringOption( 's', "server", &gDNSCrypt_Server, "IP address", "DNS server's IPv4 or IPv6 address.", true ),
+ IntegerOption( 'l', "timeLimit", &gDNSCrypt_TimeLimitSecs, "seconds", "Specifies query time limit. Use '-1' for no time limit and '0' to exit immediately after sending.", false ),
+ BooleanOption( 'r', "raw", &gDNSCrypt_RawRData, "Present record data as a hexdump." ),
+ BooleanOption( 'v', "verbose", &gDNSCrypt_Verbose, "Prints the DNS message to be sent to the server." ),
+ CLI_OPTION_END()
+};
+#endif
+
+//===========================================================================================================================
+// MDNSQuery Command Options
+//===========================================================================================================================
+
+static char * gMDNSQuery_Name = NULL;
+static char * gMDNSQuery_Type = NULL;
+static int gMDNSQuery_SourcePort = 0;
+static int gMDNSQuery_IsQU = false;
+static int gMDNSQuery_RawRData = false;
+static int gMDNSQuery_UseIPv4 = false;
+static int gMDNSQuery_UseIPv6 = false;
+static int gMDNSQuery_AllResponses = false;
+
+static CLIOption kMDNSQueryOpts[] =
+{
+ StringOption( 'i', "interface", &gInterface, "name or index", "Network interface by name or index.", true ),
+ StringOption( 'n', "name", &gMDNSQuery_Name, "name", "Question name (QNAME) to put in mDNS message.", true ),
+ StringOption( 't', "type", &gMDNSQuery_Type, "type", "Question type (QTYPE) to put in mDNS message.", true ),
+ IntegerOption( 'p', "sourcePort", &gMDNSQuery_SourcePort, "port number", "UDP source port to use when sending mDNS messages. Default is 5353 for QM questions.", false ),
+ BooleanOption( 'u', "QU", &gMDNSQuery_IsQU, "Set the unicast-response bit, i.e., send a QU question." ),
+ BooleanOption( 'r', "raw", &gMDNSQuery_RawRData, "Present record data as a hexdump." ),
+ BooleanOption( 0 , "ipv4", &gMDNSQuery_UseIPv4, "Use IPv4." ),
+ BooleanOption( 0 , "ipv6", &gMDNSQuery_UseIPv6, "Use IPv6." ),
+ BooleanOption( 'a', "allResponses", &gMDNSQuery_AllResponses, "Print all responses." ),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// PIDToUUID Command Options
+//===========================================================================================================================
+
+static int gPIDToUUID_PID = 0;
+
+static CLIOption kPIDToUUIDOpts[] =
+{
+ IntegerOption( 'p', "pid", &gPIDToUUID_PID, "PID", "Process ID.", true ),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// Command Table
+//===========================================================================================================================
+
+static OSStatus VersionOptionCallback( CLIOption *inOption, const char *inArg, int inUnset );
+
+static void BrowseCmd( void );
+static void GetAddrInfoCmd( void );
+static void QueryRecordCmd( void );
+static void RegisterCmd( void );
+static void RegisterRecordCmd( void );
+static void ResolveCmd( void );
+static void ReconfirmCmd( void );
+static void GetAddrInfoPOSIXCmd( void );
+static void ReverseLookupCmd( void );
+static void BrowseAllCmd( void );
+static void GetAddrInfoStressCmd( void );
+static void DNSQueryCmd( void );
+#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
+static void DNSCryptCmd( void );
+#endif
+static void MDNSQueryCmd( void );
+static void PIDToUUIDCmd( void );
+static void DaemonVersionCmd( void );
+
+static CLIOption kGlobalOpts[] =
+{
+ CLI_OPTION_CALLBACK_EX( 'V', "version", VersionOptionCallback, NULL, NULL,
+ kCLIOptionFlags_NoArgument | kCLIOptionFlags_GlobalOnly, "Displays the version of this tool.", NULL ),
+ CLI_OPTION_HELP(),
+
+ // Common commands.
+
+ Command( "browse", BrowseCmd, kBrowseOpts, "Uses DNSServiceBrowse() to browse for one or more service types.", false ),
+ Command( "getAddrInfo", GetAddrInfoCmd, kGetAddrInfoOpts, "Uses DNSServiceGetAddrInfo() to resolve a hostname to IP addresses.", false ),
+ Command( "queryRecord", QueryRecordCmd, kQueryRecordOpts, "Uses DNSServiceQueryRecord() to query for an arbitrary DNS record.", false ),
+ Command( "register", RegisterCmd, kRegisterOpts, "Uses DNSServiceRegister() to register a service.", false ),
+ Command( "registerRecord", RegisterRecordCmd, kRegisterRecordOpts, "Uses DNSServiceRegisterRecord() to register a record.", false ),
+ Command( "resolve", ResolveCmd, kResolveOpts, "Uses DNSServiceResolve() to resolve a service.", false ),
+ Command( "reconfirm", ReconfirmCmd, kReconfirmOpts, "Uses DNSServiceReconfirmRecord() to reconfirm a record.", false ),
+ Command( "getaddrinfo-posix", GetAddrInfoPOSIXCmd, kGetAddrInfoPOSIXOpts, "Uses getaddrinfo() to resolve a hostname to IP addresses.", false ),
+ Command( "reverseLookup", ReverseLookupCmd, kReverseLookupOpts, "Uses DNSServiceQueryRecord() to perform a reverse IP address lookup.", false ),
+ Command( "browseAll", BrowseAllCmd, kBrowseAllOpts, "Browse and resolve all, or just some, services.", false ),
+
+ // Uncommon commands.
+
+ Command( "getAddrInfoStress", GetAddrInfoStressCmd, kGetAddrInfoStressOpts, "Runs DNSServiceGetAddrInfo() stress testing.", true ),
+ Command( "DNSQuery", DNSQueryCmd, kDNSQueryOpts, "Crafts and sends a DNS query.", true ),
+#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
+ Command( "DNSCrypt", DNSCryptCmd, kDNSCryptOpts, "Crafts and sends a DNSCrypt query.", true ),
+#endif
+ Command( "mDNSQuery", MDNSQueryCmd, kMDNSQueryOpts, "Crafts and sends an mDNS query over the specified interface.", true ),
+ Command( "pid2uuid", PIDToUUIDCmd, kPIDToUUIDOpts, "Prints the UUID of a process.", true ),
+ Command( "daemonVersion", DaemonVersionCmd, NULL, "Prints the version of the DNS-SD daemon.", true ),
+
+ CLI_COMMAND_HELP(),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// Helper Prototypes
+//===========================================================================================================================
+
+#define kExitReason_OneShotDone "one-shot done"
+#define kExitReason_ReceivedResponse "received response"
+#define kExitReason_SIGINT "interrupt signal"
+#define kExitReason_Timeout "timeout"
+#define kExitReason_TimeLimit "time limit"
+
+static void Exit( void *inContext ) ATTRIBUTE_NORETURN;
+
+#define kTimestampBufLen 27
+
+static char * GetTimestampStr( char inBuffer[ kTimestampBufLen ] );
+static DNSServiceFlags GetDNSSDFlagsFromOpts( void );
+
+typedef enum
+{
+ kConnectionType_None = 0,
+ kConnectionType_Normal = 1,
+ kConnectionType_DelegatePID = 2,
+ kConnectionType_DelegateUUID = 3
+
+} ConnectionType;
+
+typedef struct
+{
+ ConnectionType type;
+ union
+ {
+ int32_t pid;
+ uint8_t uuid[ 16 ];
+
+ } delegate;
+
+} ConnectionDesc;
+
+static OSStatus
+ CreateConnectionFromArgString(
+ const char * inString,
+ dispatch_queue_t inQueue,
+ DNSServiceRef * outSDRef,
+ ConnectionDesc * outDesc );
+static OSStatus InterfaceIndexFromArgString( const char *inString, uint32_t *outIndex );
+static OSStatus RecordDataFromArgString( const char *inString, uint8_t **outDataPtr, size_t *outDataLen );
+static OSStatus RecordTypeFromArgString( const char *inString, uint16_t *outValue );
+static OSStatus RecordClassFromArgString( const char *inString, uint16_t *outValue );
+
+#define kInterfaceNameBufLen ( Max( IF_NAMESIZE, 16 ) + 1 )
+
+static char * InterfaceIndexToName( uint32_t inIfIndex, char inNameBuf[ kInterfaceNameBufLen ] );
+static const char * RecordTypeToString( unsigned int inValue );
+
+// DNS message helpers
+
+typedef struct
+{
+ uint8_t id[ 2 ];
+ uint8_t flags[ 2 ];
+ uint8_t questionCount[ 2 ];
+ uint8_t answerCount[ 2 ];
+ uint8_t authorityCount[ 2 ];
+ uint8_t additionalCount[ 2 ];
+
+} DNSHeader;
+
+#define kDNSHeaderLength 12
+check_compile_time( sizeof( DNSHeader ) == kDNSHeaderLength );
+
+#define DNSHeaderGetID( HDR ) ReadBig16( ( HDR )->id )
+#define DNSHeaderGetFlags( HDR ) ReadBig16( ( HDR )->flags )
+#define DNSHeaderGetQuestionCount( HDR ) ReadBig16( ( HDR )->questionCount )
+#define DNSHeaderGetAnswerCount( HDR ) ReadBig16( ( HDR )->answerCount )
+#define DNSHeaderGetAuthorityCount( HDR ) ReadBig16( ( HDR )->authorityCount )
+#define DNSHeaderGetAdditionalCount( HDR ) ReadBig16( ( HDR )->additionalCount )
+
+static OSStatus
+ DNSMessageExtractDomainName(
+ const uint8_t * inMsgPtr,
+ size_t inMsgLen,
+ const uint8_t * inNamePtr,
+ uint8_t inBuf[ kDomainNameLengthMax ],
+ const uint8_t ** outNextPtr );
+static OSStatus
+ DNSMessageExtractDomainNameString(
+ const void * inMsgPtr,
+ size_t inMsgLen,
+ const void * inNamePtr,
+ char inBuf[ kDNSServiceMaxDomainName ],
+ const uint8_t ** outNextPtr );
+static OSStatus
+ DNSMessageExtractRecord(
+ const uint8_t * inMsgPtr,
+ size_t inMsgLen,
+ const uint8_t * inPtr,
+ uint8_t inNameBuf[ kDomainNameLengthMax ],
+ uint16_t * outType,
+ uint16_t * outClass,
+ uint32_t * outTTL,
+ const uint8_t ** outRDataPtr,
+ size_t * outRDataLen,
+ const uint8_t ** outPtr );
+static OSStatus DNSMessageGetAnswerSection( const uint8_t *inMsgPtr, size_t inMsgLen, const uint8_t **outPtr );
+static OSStatus
+ DNSRecordDataToString(
+ const void * inRDataPtr,
+ size_t inRDataLen,
+ unsigned int inRDataType,
+ const void * inMsgPtr,
+ size_t inMsgLen,
+ char ** outString );
+static OSStatus
+ DomainNameAppendString(
+ uint8_t inDomainName[ kDomainNameLengthMax ],
+ const char * inString,
+ uint8_t ** outEndPtr );
+static Boolean DomainNameEqual( const uint8_t *inName1, const uint8_t *inName2 );
+static OSStatus
+ DomainNameToString(
+ const uint8_t * inDomainName,
+ const uint8_t * inEnd,
+ char inBuf[ kDNSServiceMaxDomainName ],
+ const uint8_t ** outNextPtr );
+
+static OSStatus PrintDNSMessage( const uint8_t *inMsgPtr, size_t inMsgLen, Boolean inIsMDNS, Boolean inPrintRaw );
+
+#define PrintMDNSMessage( MSGPTR, MSGLEN, RAW ) PrintDNSMessage( MSGPTR, MSGLEN, true, RAW )
+#define PrintUDNSMessage( MSGPTR, MSGLEN, RAW ) PrintDNSMessage( MSGPTR, MSGLEN, false, RAW )
+
+#define kDNSQueryMessageMaxLen ( kDNSHeaderLength + kDomainNameLengthMax + 4 )
+
+static OSStatus
+ WriteDNSQueryMessage(
+ uint8_t inMsg[ kDNSQueryMessageMaxLen ],
+ uint16_t inMsgID,
+ uint16_t inFlags,
+ const char * inQName,
+ uint16_t inQType,
+ uint16_t inQClass,
+ size_t * outMsgLen );
+
+// Dispatch helpers
+
+typedef void ( *DispatchHandler )( void *inContext );
+
+static OSStatus
+ DispatchSignalSourceCreate(
+ int inSignal,
+ DispatchHandler inEventHandler,
+ void * inContext,
+ dispatch_source_t * outSource );
+static OSStatus
+ DispatchReadSourceCreate(
+ SocketRef inSock,
+ DispatchHandler inEventHandler,
+ DispatchHandler inCancelHandler,
+ void * inContext,
+ dispatch_source_t * outSource );
+static OSStatus
+ DispatchTimerCreate(
+ dispatch_time_t inStart,
+ uint64_t inIntervalNs,
+ uint64_t inLeewayNs,
+ DispatchHandler inEventHandler,
+ DispatchHandler inCancelHandler,
+ void * inContext,
+ dispatch_source_t * outTimer );
+
+static const char * ServiceTypeDescription( const char *inName );
+
+typedef struct
+{
+ SocketRef sock;
+ void * context;
+
+} SocketContext;
+
+static void SocketContextCancelHandler( void *inContext );
+static OSStatus StringToInt32( const char *inString, int32_t *outValue );
+static OSStatus StringToUInt32( const char *inString, uint32_t *outValue );
+
+#define AddRmvString( X ) ( ( (X) & kDNSServiceFlagsAdd ) ? "Add" : "Rmv" )
+#define Unused( X ) (void)(X)
+
+//===========================================================================================================================
+// main
+//===========================================================================================================================
+
+int main( int argc, const char **argv )
+{
+ // Route DebugServices logging output to stderr.
+
+ dlog_control( "DebugServices:output=file;stderr" );
+
+ CLIInit( argc, argv );
+ CLIParse( kGlobalOpts, kCLIFlags_None );
+
+ return( gExitCode );
+}
+
+//===========================================================================================================================
+// VersionOptionCallback
+//===========================================================================================================================
+
+static OSStatus VersionOptionCallback( CLIOption *inOption, const char *inArg, int inUnset )
+{
+ const char * srcVers;
+#if( MDNSRESPONDER_PROJECT )
+ char srcStr[ 16 ];
+#endif
+
+ Unused( inOption );
+ Unused( inArg );
+ Unused( inUnset );
+
+#if( MDNSRESPONDER_PROJECT )
+ srcVers = SourceVersionToCString( _DNS_SD_H, srcStr );
+#else
+ srcVers = DNSSDUTIL_SOURCE_VERSION;
+#endif
+ FPrintF( stdout, "%s version %v (%s)\n", gProgramName, kDNSSDUtilNumVersion, srcVers );
+
+ return( kEndingErr );
+}
+
+//===========================================================================================================================
+// BrowseCmd
+//===========================================================================================================================
+
+typedef struct BrowseResolveOp BrowseResolveOp;
+
+struct BrowseResolveOp
+{
+ BrowseResolveOp * next; // Next resolve operation in list.
+ DNSServiceRef sdRef; // sdRef of the DNSServiceResolve or DNSServiceQueryRecord operation.
+ char * fullName; // Full name of the service to resolve.
+ uint32_t interfaceIndex; // Interface index of the DNSServiceResolve or DNSServiceQueryRecord operation.
+};
+
+typedef struct
+{
+ DNSServiceRef mainRef; // Main sdRef for shared connection.
+ DNSServiceRef * opRefs; // Array of sdRefs for individual Browse operarions.
+ size_t opRefsCount; // Count of array of sdRefs for non-shared connections.
+ const char * domain; // Domain for DNSServiceBrowse operation(s).
+ DNSServiceFlags flags; // Flags for DNSServiceBrowse operation(s).
+ char ** serviceTypes; // Array of service types to browse for.
+ size_t serviceTypesCount; // Count of array of service types to browse for.
+ int timeLimitSecs; // Time limit of DNSServiceBrowse operation in seconds.
+ BrowseResolveOp * resolveList; // List of resolve and/or TXT record query operations.
+ uint32_t ifIndex; // Interface index of DNSServiceBrowse operation(s).
+ Boolean printedHeader; // True if results header has been printed.
+ Boolean doResolve; // True if service instances are to be resolved.
+ Boolean doResolveTXTOnly; // True if TXT records of service instances are to be queried.
+
+} BrowseContext;
+
+static void BrowsePrintPrologue( const BrowseContext *inContext );
+static void BrowseContextFree( BrowseContext *inContext );
+static OSStatus BrowseResolveOpCreate( const char *inFullName, uint32_t inInterfaceIndex, BrowseResolveOp **outOp );
+static void BrowseResolveOpFree( BrowseResolveOp *inOp );
+static void DNSSD_API
+ BrowseCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inName,
+ const char * inRegType,
+ const char * inDomain,
+ void * inContext );
+static void DNSSD_API
+ BrowseResolveCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ const char * inHostname,
+ uint16_t inPort,
+ uint16_t inTXTLen,
+ const unsigned char * inTXTPtr,
+ void * inContext );
+static void DNSSD_API
+ BrowseQueryRecordCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext );
+
+static void BrowseCmd( void )
+{
+ OSStatus err;
+ size_t i;
+ BrowseContext * context = NULL;
+ dispatch_source_t signalSource = NULL;
+ int useMainConnection;
+
+ // Set up SIGINT handler.
+
+ signal( SIGINT, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+ require_noerr( err, exit );
+ dispatch_resume( signalSource );
+
+ // Create context.
+
+ context = (BrowseContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ context->opRefs = (DNSServiceRef *) calloc( gBrowse_ServiceTypesCount, sizeof( DNSServiceRef ) );
+ require_action( context->opRefs, exit, err = kNoMemoryErr );
+ context->opRefsCount = gBrowse_ServiceTypesCount;
+
+ // Check command parameters.
+
+ if( gBrowse_TimeLimitSecs < 0 )
+ {
+ FPrintF( stderr, "Invalid time limit: %d seconds.\n", gBrowse_TimeLimitSecs );
+ err = kParamErr;
+ goto exit;
+ }
+
+ // Create main connection.
+
+ if( gConnectionOpt )
+ {
+ err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
+ require_noerr_quiet( err, exit );
+ useMainConnection = true;
+ }
+ else
+ {
+ useMainConnection = false;
+ }
+
+ // Get flags.
+
+ context->flags = GetDNSSDFlagsFromOpts();
+ if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
+
+ // Get interface.
+
+ err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+
+ // Set remaining parameters.
+
+ context->serviceTypes = gBrowse_ServiceTypes;
+ context->serviceTypesCount = gBrowse_ServiceTypesCount;
+ context->domain = gBrowse_Domain;
+ context->doResolve = gBrowse_DoResolve ? true : false;
+ context->timeLimitSecs = gBrowse_TimeLimitSecs;
+ context->doResolveTXTOnly = gBrowse_QueryTXT ? true : false;
+
+ // Print prologue.
+
+ BrowsePrintPrologue( context );
+
+ // Start operation(s).
+
+ for( i = 0; i < context->serviceTypesCount; ++i )
+ {
+ DNSServiceRef sdRef;
+
+ if( useMainConnection ) sdRef = context->mainRef;
+ err = DNSServiceBrowse( &sdRef, context->flags, context->ifIndex, context->serviceTypes[ i ], context->domain,
+ BrowseCallback, context );
+ require_noerr( err, exit );
+
+ context->opRefs[ i ] = sdRef;
+ if( !useMainConnection )
+ {
+ err = DNSServiceSetDispatchQueue( context->opRefs[ i ], dispatch_get_main_queue() );
+ require_noerr( err, exit );
+ }
+ }
+
+ // Set time limit.
+
+ if( context->timeLimitSecs > 0 )
+ {
+ dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(),
+ kExitReason_TimeLimit, Exit );
+ }
+ dispatch_main();
+
+exit:
+ dispatch_source_forget( &signalSource );
+ if( context ) BrowseContextFree( context );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// BrowsePrintPrologue
+//===========================================================================================================================
+
+static void BrowsePrintPrologue( const BrowseContext *inContext )
+{
+ const int timeLimitSecs = inContext->timeLimitSecs;
+ const char * const * serviceType = (const char **) inContext->serviceTypes;
+ const char * const * const end = (const char **) inContext->serviceTypes + inContext->serviceTypesCount;
+ char time[ kTimestampBufLen ];
+ char ifName[ kInterfaceNameBufLen ];
+
+ InterfaceIndexToName( inContext->ifIndex, ifName );
+
+ FPrintF( stdout, "Flags: %#{flags}\n", inContext->flags, kDNSServiceFlagsDescriptors );
+ FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, ifName );
+ FPrintF( stdout, "Service types: %s", *serviceType++ );
+ while( serviceType < end ) FPrintF( stdout, ", %s", *serviceType++ );
+ FPrintF( stdout, "\n" );
+ FPrintF( stdout, "Domain: %s\n", inContext->domain ? inContext->domain : "<NULL> (default domains)" );
+ FPrintF( stdout, "Time limit: " );
+ if( timeLimitSecs > 0 ) FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
+ else FPrintF( stdout, "∞\n" );
+ FPrintF( stdout, "Start time: %s\n", GetTimestampStr( time ) );
+ FPrintF( stdout, "---\n" );
+}
+
+//===========================================================================================================================
+// BrowseContextFree
+//===========================================================================================================================
+
+static void BrowseContextFree( BrowseContext *inContext )
+{
+ size_t i;
+
+ for( i = 0; i < inContext->opRefsCount; ++i )
+ {
+ DNSServiceForget( &inContext->opRefs[ i ] );
+ }
+ if( inContext->serviceTypes )
+ {
+ StringArray_Free( inContext->serviceTypes, inContext->serviceTypesCount );
+ inContext->serviceTypes = NULL;
+ inContext->serviceTypesCount = 0;
+ }
+ DNSServiceForget( &inContext->mainRef );
+ free( inContext );
+}
+
+//===========================================================================================================================
+// BrowseResolveOpCreate
+//===========================================================================================================================
+
+static OSStatus BrowseResolveOpCreate( const char *inFullName, uint32_t inInterfaceIndex, BrowseResolveOp **outOp )
+{
+ OSStatus err;
+ BrowseResolveOp * resolveOp;
+
+ resolveOp = (BrowseResolveOp *) calloc( 1, sizeof( *resolveOp ) );
+ require_action( resolveOp, exit, err = kNoMemoryErr );
+
+ resolveOp->fullName = strdup( inFullName );
+ require_action( resolveOp->fullName, exit, err = kNoMemoryErr );
+
+ resolveOp->interfaceIndex = inInterfaceIndex;
+
+ *outOp = resolveOp;
+ resolveOp = NULL;
+ err = kNoErr;
+
+exit:
+ if( resolveOp ) BrowseResolveOpFree( resolveOp );
+ return( err );
+}
+
+//===========================================================================================================================
+// BrowseResolveOpFree
+//===========================================================================================================================
+
+static void BrowseResolveOpFree( BrowseResolveOp *inOp )
+{
+ DNSServiceForget( &inOp->sdRef );
+ ForgetMem( &inOp->fullName );
+ free( inOp );
+}
+
+//===========================================================================================================================
+// BrowseCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ BrowseCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inName,
+ const char * inRegType,
+ const char * inDomain,
+ void * inContext )
+{
+ BrowseContext * const context = (BrowseContext *) inContext;
+ OSStatus err;
+ BrowseResolveOp * newOp = NULL;
+ BrowseResolveOp ** p;
+ char fullName[ kDNSServiceMaxDomainName ];
+ char time[ kTimestampBufLen ];
+
+ Unused( inSDRef );
+
+ GetTimestampStr( time );
+
+ err = inError;
+ require_noerr( err, exit );
+
+ if( !context->printedHeader )
+ {
+ FPrintF( stdout, "%-26s A/R Flags IF %-20s %-20s Instance Name\n", "Timestamp", "Domain", "Service Type" );
+ context->printedHeader = true;
+ }
+ FPrintF( stdout, "%-26s %-3s %5X %2d %-20s %-20s %s\n",
+ time, AddRmvString( inFlags ), inFlags, (int32_t) inInterfaceIndex, inDomain, inRegType, inName );
+
+ if( !context->doResolve && !context->doResolveTXTOnly ) goto exit;
+
+ err = DNSServiceConstructFullName( fullName, inName, inRegType, inDomain );
+ require_noerr( err, exit );
+
+ if( inFlags & kDNSServiceFlagsAdd )
+ {
+ DNSServiceRef sdRef;
+ DNSServiceFlags flags;
+
+ err = BrowseResolveOpCreate( fullName, inInterfaceIndex, &newOp );
+ require_noerr( err, exit );
+
+ if( context->mainRef )
+ {
+ sdRef = context->mainRef;
+ flags = kDNSServiceFlagsShareConnection;
+ }
+ else
+ {
+ flags = 0;
+ }
+ if( context->doResolve )
+ {
+ err = DNSServiceResolve( &sdRef, flags, inInterfaceIndex, inName, inRegType, inDomain, BrowseResolveCallback,
+ NULL );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ err = DNSServiceQueryRecord( &sdRef, flags, inInterfaceIndex, fullName, kDNSServiceType_TXT, kDNSServiceClass_IN,
+ BrowseQueryRecordCallback, NULL );
+ require_noerr( err, exit );
+ }
+
+ newOp->sdRef = sdRef;
+ if( !context->mainRef )
+ {
+ err = DNSServiceSetDispatchQueue( newOp->sdRef, dispatch_get_main_queue() );
+ require_noerr( err, exit );
+ }
+ for( p = &context->resolveList; *p; p = &( *p )->next ) {}
+ *p = newOp;
+ newOp = NULL;
+ }
+ else
+ {
+ BrowseResolveOp * resolveOp;
+
+ for( p = &context->resolveList; ( resolveOp = *p ) != NULL; p = &resolveOp->next )
+ {
+ if( ( resolveOp->interfaceIndex == inInterfaceIndex ) && ( strcasecmp( resolveOp->fullName, fullName ) == 0 ) )
+ {
+ break;
+ }
+ }
+ if( resolveOp )
+ {
+ *p = resolveOp->next;
+ BrowseResolveOpFree( resolveOp );
+ }
+ }
+
+exit:
+ if( newOp ) BrowseResolveOpFree( newOp );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// BrowseQueryRecordCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ BrowseQueryRecordCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext )
+{
+ OSStatus err;
+ char time[ kTimestampBufLen ];
+
+ Unused( inSDRef );
+ Unused( inClass );
+ Unused( inTTL );
+ Unused( inContext );
+
+ GetTimestampStr( time );
+
+ err = inError;
+ require_noerr( err, exit );
+ require_action( inType == kDNSServiceType_TXT, exit, err = kTypeErr );
+
+ FPrintF( stdout, "%s %s %s TXT on interface %d\n TXT: %#{txt}\n",
+ time, AddRmvString( inFlags ), inFullName, (int32_t) inInterfaceIndex, inRDataPtr, (size_t) inRDataLen );
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// BrowseResolveCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ BrowseResolveCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ const char * inHostname,
+ uint16_t inPort,
+ uint16_t inTXTLen,
+ const unsigned char * inTXTPtr,
+ void * inContext )
+{
+ char time[ kTimestampBufLen ];
+ char errorStr[ 64 ];
+
+ Unused( inSDRef );
+ Unused( inFlags );
+ Unused( inContext );
+
+ GetTimestampStr( time );
+
+ if( inError ) SNPrintF( errorStr, sizeof( errorStr ), " error %#m", inError );
+
+ FPrintF( stdout, "%s %s can be reached at %s:%u (interface %d)%?s\n",
+ time, inFullName, inHostname, ntohs( inPort ), (int32_t) inInterfaceIndex, inError, errorStr );
+ if( inTXTLen == 1 )
+ {
+ FPrintF( stdout, " TXT record: %#H\n", inTXTPtr, (int) inTXTLen, INT_MAX );
+ }
+ else
+ {
+ FPrintF( stdout, " TXT record: %#{txt}\n", inTXTPtr, (size_t) inTXTLen );
+ }
+}
+
+//===========================================================================================================================
+// GetAddrInfoCmd
+//===========================================================================================================================
+
+typedef struct
+{
+ DNSServiceRef mainRef; // Main sdRef for shared connection.
+ DNSServiceRef opRef; // sdRef for the DNSServiceGetAddrInfo operation.
+ const char * name; // Hostname to resolve.
+ DNSServiceFlags flags; // Flags argument for DNSServiceGetAddrInfo().
+ DNSServiceProtocol protocols; // Protocols argument for DNSServiceGetAddrInfo().
+ uint32_t ifIndex; // Interface index argument for DNSServiceGetAddrInfo().
+ int timeLimitSecs; // Time limit for the DNSServiceGetAddrInfo() operation in seconds.
+ Boolean printedHeader; // True if the results header has been printed.
+ Boolean oneShotMode; // True if command is done after the first set of results (one-shot mode).
+ Boolean needIPv4; // True if in one-shot mode and an IPv4 result is needed.
+ Boolean needIPv6; // True if in one-shot mode and an IPv6 result is needed.
+
+} GetAddrInfoContext;
+
+static void GetAddrInfoPrintPrologue( const GetAddrInfoContext *inContext );
+static void GetAddrInfoContextFree( GetAddrInfoContext *inContext );
+static void DNSSD_API
+ GetAddrInfoCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inHostname,
+ const struct sockaddr * inSockAddr,
+ uint32_t inTTL,
+ void * inContext );
+
+static void GetAddrInfoCmd( void )
+{
+ OSStatus err;
+ DNSServiceRef sdRef;
+ GetAddrInfoContext * context = NULL;
+ dispatch_source_t signalSource = NULL;
+ int useMainConnection;
+
+ // Set up SIGINT handler.
+
+ signal( SIGINT, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+ require_noerr( err, exit );
+ dispatch_resume( signalSource );
+
+ // Check command parameters.
+
+ if( gGetAddrInfo_TimeLimitSecs < 0 )
+ {
+ FPrintF( stderr, "Invalid time limit: %d s.\n", gGetAddrInfo_TimeLimitSecs );
+ err = kParamErr;
+ goto exit;
+ }
+
+ // Create context.
+
+ context = (GetAddrInfoContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ // Create main connection.
+
+ if( gConnectionOpt )
+ {
+ err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
+ require_noerr_quiet( err, exit );
+ useMainConnection = true;
+ }
+ else
+ {
+ useMainConnection = false;
+ }
+
+ // Get flags.
+
+ context->flags = GetDNSSDFlagsFromOpts();
+ if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
+
+ // Get interface.
+
+ err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+
+ // Set remaining parameters.
+
+ context->name = gGetAddrInfo_Name;
+ context->timeLimitSecs = gGetAddrInfo_TimeLimitSecs;
+ if( gGetAddrInfo_ProtocolIPv4 ) context->protocols |= kDNSServiceProtocol_IPv4;
+ if( gGetAddrInfo_ProtocolIPv6 ) context->protocols |= kDNSServiceProtocol_IPv6;
+ if( gGetAddrInfo_OneShot )
+ {
+ context->oneShotMode = true;
+ context->needIPv4 = ( gGetAddrInfo_ProtocolIPv4 || !gGetAddrInfo_ProtocolIPv6 ) ? true : false;
+ context->needIPv6 = ( gGetAddrInfo_ProtocolIPv6 || !gGetAddrInfo_ProtocolIPv4 ) ? true : false;
+ }
+
+ // Print prologue.
+
+ GetAddrInfoPrintPrologue( context );
+
+ // Start operation.
+
+ if( useMainConnection ) sdRef = context->mainRef;
+ err = DNSServiceGetAddrInfo( &sdRef, context->flags, context->ifIndex, context->protocols, context->name,
+ GetAddrInfoCallback, context );
+ require_noerr( err, exit );
+
+ context->opRef = sdRef;
+ if( !useMainConnection )
+ {
+ err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
+ require_noerr( err, exit );
+ }
+
+ // Set time limit.
+
+ if( context->timeLimitSecs > 0 )
+ {
+ dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(),
+ kExitReason_TimeLimit, Exit );
+ }
+ dispatch_main();
+
+exit:
+ dispatch_source_forget( &signalSource );
+ if( context ) GetAddrInfoContextFree( context );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// GetAddrInfoPrintPrologue
+//===========================================================================================================================
+
+static void GetAddrInfoPrintPrologue( const GetAddrInfoContext *inContext )
+{
+ const int timeLimitSecs = inContext->timeLimitSecs;
+ char ifName[ kInterfaceNameBufLen ];
+ char time[ kTimestampBufLen ];
+
+ InterfaceIndexToName( inContext->ifIndex, ifName );
+
+ FPrintF( stdout, "Flags: %#{flags}\n", inContext->flags, kDNSServiceFlagsDescriptors );
+ FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, ifName );
+ FPrintF( stdout, "Protocols: %#{flags}\n", inContext->protocols, kDNSServiceProtocolDescriptors );
+ FPrintF( stdout, "Name: %s\n", inContext->name );
+ FPrintF( stdout, "Mode: %s\n", inContext->oneShotMode ? "one-shot" : "continuous" );
+ FPrintF( stdout, "Time limit: " );
+ if( timeLimitSecs > 0 ) FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
+ else FPrintF( stdout, "∞\n" );
+ FPrintF( stdout, "Start time: %s\n", GetTimestampStr( time ) );
+ FPrintF( stdout, "---\n" );
+}
+
+//===========================================================================================================================
+// GetAddrInfoContextFree
+//===========================================================================================================================
+
+static void GetAddrInfoContextFree( GetAddrInfoContext *inContext )
+{
+ DNSServiceForget( &inContext->opRef );
+ DNSServiceForget( &inContext->mainRef );
+ free( inContext );
+}
+
+//===========================================================================================================================
+// GetAddrInfoCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ GetAddrInfoCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inHostname,
+ const struct sockaddr * inSockAddr,
+ uint32_t inTTL,
+ void * inContext )
+{
+ GetAddrInfoContext * const context = (GetAddrInfoContext *) inContext;
+ OSStatus err;
+ const char * addrStr;
+ char addrStrBuf[ kSockAddrStringMaxSize ];
+ char time[ kTimestampBufLen ];
+
+ Unused( inSDRef );
+
+ GetTimestampStr( time );
+
+ switch( inError )
+ {
+ case kDNSServiceErr_NoError:
+ case kDNSServiceErr_NoSuchRecord:
+ err = kNoErr;
+ break;
+
+ case kDNSServiceErr_Timeout:
+ Exit( kExitReason_Timeout );
+
+ default:
+ err = inError;
+ goto exit;
+ }
+
+ if( ( inSockAddr->sa_family != AF_INET ) && ( inSockAddr->sa_family != AF_INET6 ) )
+ {
+ dlogassert( "Unexpected address family: %d", inSockAddr->sa_family );
+ err = kTypeErr;
+ goto exit;
+ }
+
+ if( !inError )
+ {
+ err = SockAddrToString( inSockAddr, kSockAddrStringFlagsNone, addrStrBuf );
+ require_noerr( err, exit );
+ addrStr = addrStrBuf;
+ }
+ else
+ {
+ addrStr = ( inSockAddr->sa_family == AF_INET ) ? "No Such Record (A)" : "No Such Record (AAAA)";
+ }
+
+ if( !context->printedHeader )
+ {
+ FPrintF( stdout, "%-26s A/R Flags IF %-32s %-38s %6s\n", "Timestamp", "Hostname", "Address", "TTL" );
+ context->printedHeader = true;
+ }
+ FPrintF( stdout, "%-26s %s %5X %2d %-32s %-38s %6u\n",
+ time, AddRmvString( inFlags ), inFlags, (int32_t) inInterfaceIndex, inHostname, addrStr, inTTL );
+
+ if( context->oneShotMode )
+ {
+ if( inFlags & kDNSServiceFlagsAdd )
+ {
+ if( inSockAddr->sa_family == AF_INET ) context->needIPv4 = false;
+ else context->needIPv6 = false;
+ }
+ if( !( inFlags & kDNSServiceFlagsMoreComing ) && !context->needIPv4 && !context->needIPv6 )
+ {
+ Exit( kExitReason_OneShotDone );
+ }
+ }
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// QueryRecordCmd
+//===========================================================================================================================
+
+typedef struct
+{
+ DNSServiceRef mainRef; // Main sdRef for shared connection.
+ DNSServiceRef opRef; // sdRef for the DNSServiceQueryRecord operation.
+ const char * recordName; // Resource record name argument for DNSServiceQueryRecord().
+ DNSServiceFlags flags; // Flags argument for DNSServiceQueryRecord().
+ uint32_t ifIndex; // Interface index argument for DNSServiceQueryRecord().
+ int timeLimitSecs; // Time limit for the DNSServiceQueryRecord() operation in seconds.
+ uint16_t recordType; // Resource record type argument for DNSServiceQueryRecord().
+ Boolean printedHeader; // True if the results header was printed.
+ Boolean oneShotMode; // True if command is done after the first set of results (one-shot mode).
+ Boolean gotRecord; // True if in one-shot mode and received at least one record of the desired type.
+ Boolean printRawRData; // True if RDATA results are not to be formatted.
+
+} QueryRecordContext;
+
+static void QueryRecordPrintPrologue( const QueryRecordContext *inContext );
+static void QueryRecordContextFree( QueryRecordContext *inContext );
+static void DNSSD_API
+ QueryRecordCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext );
+
+static void QueryRecordCmd( void )
+{
+ OSStatus err;
+ DNSServiceRef sdRef;
+ QueryRecordContext * context = NULL;
+ dispatch_source_t signalSource = NULL;
+ int useMainConnection;
+
+ // Set up SIGINT handler.
+
+ signal( SIGINT, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+ require_noerr( err, exit );
+ dispatch_resume( signalSource );
+
+ // Create context.
+
+ context = (QueryRecordContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ // Check command parameters.
+
+ if( gQueryRecord_TimeLimitSecs < 0 )
+ {
+ FPrintF( stderr, "Invalid time limit: %d seconds.\n", gQueryRecord_TimeLimitSecs );
+ err = kParamErr;
+ goto exit;
+ }
+
+ // Create main connection.
+
+ if( gConnectionOpt )
+ {
+ err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
+ require_noerr_quiet( err, exit );
+ useMainConnection = true;
+ }
+ else
+ {
+ useMainConnection = false;
+ }
+
+ // Get flags.
+
+ context->flags = GetDNSSDFlagsFromOpts();
+ if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
+
+ // Get interface.
+
+ err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+
+ // Get record type.
+
+ err = RecordTypeFromArgString( gQueryRecord_Type, &context->recordType );
+ require_noerr( err, exit );
+
+ // Set remaining parameters.
+
+ context->recordName = gQueryRecord_Name;
+ context->timeLimitSecs = gQueryRecord_TimeLimitSecs;
+ context->oneShotMode = gQueryRecord_OneShot ? true : false;
+ context->printRawRData = gQueryRecord_RawRData ? true : false;
+
+ // Print prologue.
+
+ QueryRecordPrintPrologue( context );
+
+ // Start operation.
+
+ if( useMainConnection ) sdRef = context->mainRef;
+ err = DNSServiceQueryRecord( &sdRef, context->flags, context->ifIndex, context->recordName, context->recordType,
+ kDNSServiceClass_IN, QueryRecordCallback, context );
+ require_noerr( err, exit );
+
+ context->opRef = sdRef;
+ if( !useMainConnection )
+ {
+ err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
+ require_noerr( err, exit );
+ }
+
+ // Set time limit.
+
+ if( context->timeLimitSecs > 0 )
+ {
+ dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(), kExitReason_TimeLimit,
+ Exit );
+ }
+ dispatch_main();
+
+exit:
+ dispatch_source_forget( &signalSource );
+ if( context ) QueryRecordContextFree( context );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// QueryRecordContextFree
+//===========================================================================================================================
+
+static void QueryRecordContextFree( QueryRecordContext *inContext )
+{
+ DNSServiceForget( &inContext->opRef );
+ DNSServiceForget( &inContext->mainRef );
+ free( inContext );
+}
+
+//===========================================================================================================================
+// QueryRecordPrintPrologue
+//===========================================================================================================================
+
+static void QueryRecordPrintPrologue( const QueryRecordContext *inContext )
+{
+ const int timeLimitSecs = inContext->timeLimitSecs;
+ char ifName[ kInterfaceNameBufLen ];
+ char time[ kTimestampBufLen ];
+
+ InterfaceIndexToName( inContext->ifIndex, ifName );
+
+ FPrintF( stdout, "Flags: %#{flags}\n", inContext->flags, kDNSServiceFlagsDescriptors );
+ FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, ifName );
+ FPrintF( stdout, "Name: %s\n", inContext->recordName );
+ FPrintF( stdout, "Type: %s (%u)\n", RecordTypeToString( inContext->recordType ), inContext->recordType );
+ FPrintF( stdout, "Mode: %s\n", inContext->oneShotMode ? "one-shot" : "continuous" );
+ FPrintF( stdout, "Time limit: " );
+ if( timeLimitSecs > 0 ) FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
+ else FPrintF( stdout, "∞\n" );
+ FPrintF( stdout, "Start time: %s\n", GetTimestampStr( time ) );
+ FPrintF( stdout, "---\n" );
+
+}
+
+//===========================================================================================================================
+// QueryRecordCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ QueryRecordCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext )
+{
+ QueryRecordContext * const context = (QueryRecordContext *) inContext;
+ OSStatus err;
+ char * rdataStr = NULL;
+ char time[ kTimestampBufLen ];
+
+ Unused( inSDRef );
+
+ GetTimestampStr( time );
+
+ switch( inError )
+ {
+ case kDNSServiceErr_NoError:
+ case kDNSServiceErr_NoSuchRecord:
+ err = kNoErr;
+ break;
+
+ case kDNSServiceErr_Timeout:
+ Exit( kExitReason_Timeout );
+
+ default:
+ err = inError;
+ goto exit;
+ }
+
+ if( inError == kDNSServiceErr_NoSuchRecord )
+ {
+ ASPrintF( &rdataStr, "No Such Record" );
+ }
+ else
+ {
+ if( !context->printRawRData ) DNSRecordDataToString( inRDataPtr, inRDataLen, inType, NULL, 0, &rdataStr );
+ if( !rdataStr )
+ {
+ ASPrintF( &rdataStr, "%#H", inRDataPtr, inRDataLen, INT_MAX );
+ require_action( rdataStr, exit, err = kNoMemoryErr );
+ }
+ }
+
+ if( !context->printedHeader )
+ {
+ FPrintF( stdout, "%-26s A/R Flags IF %-32s %-5s %-5s %6s RData\n", "Timestamp", "Name", "Type", "Class", "TTL" );
+ context->printedHeader = true;
+ }
+ FPrintF( stdout, "%-26s %-3s %5X %2d %-32s %-5s %?-5s%?5u %6u %s\n",
+ time, AddRmvString( inFlags ), inFlags, (int32_t) inInterfaceIndex, inFullName, RecordTypeToString( inType ),
+ ( inClass == kDNSServiceClass_IN ), "IN", ( inClass != kDNSServiceClass_IN ), inClass, inTTL, rdataStr );
+
+ if( context->oneShotMode )
+ {
+ if( ( inFlags & kDNSServiceFlagsAdd ) &&
+ ( ( context->recordType == kDNSServiceType_ANY ) || ( context->recordType == inType ) ) )
+ {
+ context->gotRecord = true;
+ }
+ if( !( inFlags & kDNSServiceFlagsMoreComing ) && context->gotRecord ) Exit( kExitReason_OneShotDone );
+ }
+
+exit:
+ FreeNullSafe( rdataStr );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// RegisterCmd
+//===========================================================================================================================
+
+typedef struct
+{
+ DNSRecordRef recordRef; // Reference returned by DNSServiceAddRecord().
+ uint8_t * dataPtr; // Record data.
+ size_t dataLen; // Record data length.
+ uint32_t ttl; // Record TTL value.
+ uint16_t type; // Record type.
+
+} ExtraRecord;
+
+typedef struct
+{
+ DNSServiceRef opRef; // sdRef for DNSServiceRegister operation.
+ const char * name; // Service name argument for DNSServiceRegister().
+ const char * type; // Service type argument for DNSServiceRegister().
+ const char * domain; // Domain in which advertise the service.
+ uint8_t * txtPtr; // Service TXT record data. (malloc'd)
+ size_t txtLen; // Service TXT record data len.
+ ExtraRecord * extraRecords; // Array of extra records to add to registered service.
+ size_t extraRecordsCount; // Number of extra records.
+ uint8_t * updateTXTPtr; // Pointer to record data for TXT record update. (malloc'd)
+ size_t updateTXTLen; // Length of record data for TXT record update.
+ uint32_t updateTTL; // TTL of updated TXT record.
+ int updateDelayMs; // Post-registration TXT record update delay in milliseconds.
+ DNSServiceFlags flags; // Flags argument for DNSServiceRegister().
+ uint32_t ifIndex; // Interface index argument for DNSServiceRegister().
+ int lifetimeMs; // Lifetime of the record registration in milliseconds.
+ uint16_t port; // Service instance's port number.
+ Boolean printedHeader; // True if results header was printed.
+ Boolean didRegister; // True if service was registered.
+
+} RegisterContext;
+
+static void RegisterPrintPrologue( const RegisterContext *inContext );
+static void RegisterContextFree( RegisterContext *inContext );
+static void DNSSD_API
+ RegisterCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ DNSServiceErrorType inError,
+ const char * inName,
+ const char * inType,
+ const char * inDomain,
+ void * inContext );
+static void RegisterUpdate( void *inContext );
+
+static void RegisterCmd( void )
+{
+ OSStatus err;
+ RegisterContext * context = NULL;
+ dispatch_source_t signalSource = NULL;
+
+ // Set up SIGINT handler.
+
+ signal( SIGINT, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+ require_noerr( err, exit );
+ dispatch_resume( signalSource );
+
+ // Create context.
+
+ context = (RegisterContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ // Check command parameters.
+
+ if( ( gRegister_Port < 0 ) || ( gRegister_Port > UINT16_MAX ) )
+ {
+ FPrintF( stderr, "Port number %d is out-of-range.\n", gRegister_Port );
+ err = kParamErr;
+ goto exit;
+ }
+
+ if( ( gAddRecord_DataCount != gAddRecord_TypesCount ) || ( gAddRecord_TTLsCount != gAddRecord_TypesCount ) )
+ {
+ FPrintF( stderr, "There are missing additional record parameters.\n" );
+ err = kParamErr;
+ goto exit;
+ }
+
+ // Get flags.
+
+ context->flags = GetDNSSDFlagsFromOpts();
+
+ // Get interface index.
+
+ err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+
+ // Get TXT record data.
+
+ if( gRegister_TXT )
+ {
+ err = RecordDataFromArgString( gRegister_TXT, &context->txtPtr, &context->txtLen );
+ require_noerr_quiet( err, exit );
+ }
+
+ // Set remaining parameters.
+
+ context->name = gRegister_Name;
+ context->type = gRegister_Type;
+ context->domain = gRegister_Domain;
+ context->port = (uint16_t) gRegister_Port;
+ context->lifetimeMs = gRegister_LifetimeMs;
+
+ if( gAddRecord_TypesCount > 0 )
+ {
+ size_t i;
+
+ context->extraRecords = (ExtraRecord *) calloc( gAddRecord_TypesCount, sizeof( ExtraRecord ) );
+ require_action( context, exit, err = kNoMemoryErr );
+ context->extraRecordsCount = gAddRecord_TypesCount;
+
+ for( i = 0; i < gAddRecord_TypesCount; ++i )
+ {
+ ExtraRecord * const extraRecord = &context->extraRecords[ i ];
+
+ err = RecordTypeFromArgString( gAddRecord_Types[ i ], &extraRecord->type );
+ require_noerr( err, exit );
+
+ err = StringToUInt32( gAddRecord_TTLs[ i ], &extraRecord->ttl );
+ if( err )
+ {
+ FPrintF( stderr, "Invalid TTL value: %s\n", gAddRecord_TTLs[ i ] );
+ err = kParamErr;
+ goto exit;
+ }
+
+ err = RecordDataFromArgString( gAddRecord_Data[ i ], &extraRecord->dataPtr, &extraRecord->dataLen );
+ require_noerr_quiet( err, exit );
+ }
+ }
+
+ if( gUpdateRecord_Data )
+ {
+ err = RecordDataFromArgString( gUpdateRecord_Data, &context->updateTXTPtr, &context->updateTXTLen );
+ require_noerr_quiet( err, exit );
+
+ context->updateTTL = (uint32_t) gUpdateRecord_TTL;
+ context->updateDelayMs = gUpdateRecord_DelayMs;
+ }
+
+ // Print prologue.
+
+ RegisterPrintPrologue( context );
+
+ // Start operation.
+
+ err = DNSServiceRegister( &context->opRef, context->flags, context->ifIndex, context->name, context->type,
+ context->domain, NULL, ntohs( context->port ), (uint16_t) context->txtLen, context->txtPtr,
+ RegisterCallback, context );
+ ForgetMem( &context->txtPtr );
+ require_noerr( err, exit );
+
+ err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
+ require_noerr( err, exit );
+
+ dispatch_main();
+
+exit:
+ dispatch_source_forget( &signalSource );
+ if( context ) RegisterContextFree( context );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// RegisterPrintPrologue
+//===========================================================================================================================
+
+static void RegisterPrintPrologue( const RegisterContext *inContext )
+{
+ size_t i;
+ int infinite;
+ char ifName[ kInterfaceNameBufLen ];
+ char time[ kTimestampBufLen ];
+
+ InterfaceIndexToName( inContext->ifIndex, ifName );
+
+ FPrintF( stdout, "Flags: %#{flags}\n", inContext->flags, kDNSServiceFlagsDescriptors );
+ FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, ifName );
+ FPrintF( stdout, "Name: %s\n", inContext->name ? inContext->name : "<NULL>" );
+ FPrintF( stdout, "Type: %s\n", inContext->type );
+ FPrintF( stdout, "Domain: %s\n", inContext->domain ? inContext->domain : "<NULL> (default domains)" );
+ FPrintF( stdout, "Port: %u\n", inContext->port );
+ FPrintF( stdout, "TXT data: %#{txt}\n", inContext->txtPtr, inContext->txtLen );
+ infinite = ( inContext->lifetimeMs < 0 ) ? true : false;
+ FPrintF( stdout, "Lifetime: %?s%?d ms\n", infinite, "∞", !infinite, inContext->lifetimeMs );
+ if( inContext->updateTXTPtr )
+ {
+ FPrintF( stdout, "\nUpdate record:\n" );
+ FPrintF( stdout, " Delay: %d ms\n", ( inContext->updateDelayMs > 0 ) ? inContext->updateDelayMs : 0 );
+ FPrintF( stdout, " TTL: %u%?s\n",
+ inContext->updateTTL, inContext->updateTTL == 0, " (system will use a default value.)" );
+ FPrintF( stdout, " TXT data: %#{txt}\n", inContext->updateTXTPtr, inContext->updateTXTLen );
+ }
+ if( inContext->extraRecordsCount > 0 ) FPrintF( stdout, "\n" );
+ for( i = 0; i < inContext->extraRecordsCount; ++i )
+ {
+ const ExtraRecord * record = &inContext->extraRecords[ i ];
+
+ FPrintF( stdout, "Extra record %zu:\n", i + 1 );
+ FPrintF( stdout, " Type: %s (%u)\n", RecordTypeToString( record->type ), record->type );
+ FPrintF( stdout, " TTL: %u%?s\n", record->ttl, record->ttl == 0, " (system will use a default value.)" );
+ FPrintF( stdout, " RData: %#H\n\n", record->dataPtr, (int) record->dataLen, INT_MAX );
+ }
+ FPrintF( stdout, "Start time: %s\n", GetTimestampStr( time ) );
+ FPrintF( stdout, "---\n" );
+}
+
+//===========================================================================================================================
+// RegisterContextFree
+//===========================================================================================================================
+
+static void RegisterContextFree( RegisterContext *inContext )
+{
+ ExtraRecord * record;
+ const ExtraRecord * const end = inContext->extraRecords + inContext->extraRecordsCount;
+
+ DNSServiceForget( &inContext->opRef );
+ ForgetMem( &inContext->txtPtr );
+ for( record = inContext->extraRecords; record < end; ++record )
+ {
+ check( !record->recordRef );
+ ForgetMem( &record->dataPtr );
+ }
+ ForgetMem( &inContext->extraRecords );
+ ForgetMem( &inContext->updateTXTPtr );
+ free( inContext );
+}
+
+//===========================================================================================================================
+// RegisterCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ RegisterCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ DNSServiceErrorType inError,
+ const char * inName,
+ const char * inType,
+ const char * inDomain,
+ void * inContext )
+{
+ RegisterContext * const context = (RegisterContext *) inContext;
+ OSStatus err;
+ char time[ kTimestampBufLen ];
+
+ Unused( inSDRef );
+
+ GetTimestampStr( time );
+
+ if( !context->printedHeader )
+ {
+ FPrintF( stdout, "%-26s A/R Flags Service\n", "Timestamp" );
+ context->printedHeader = true;
+ }
+ FPrintF( stdout, "%-26s %-3s %5X %s.%s%s %?#m\n",
+ time, AddRmvString( inFlags ), inFlags, inName, inType, inDomain, inError, inError );
+
+ require_noerr_action_quiet( inError, exit, err = inError );
+
+ if( !context->didRegister && ( inFlags & kDNSServiceFlagsAdd ) )
+ {
+ context->didRegister = true;
+ if( context->updateTXTPtr )
+ {
+ if( context->updateDelayMs > 0 )
+ {
+ dispatch_after_f( dispatch_time_milliseconds( context->updateDelayMs ), dispatch_get_main_queue(),
+ context, RegisterUpdate );
+ }
+ else
+ {
+ RegisterUpdate( context );
+ }
+ }
+ if( context->extraRecordsCount > 0 )
+ {
+ ExtraRecord * record;
+ const ExtraRecord * const end = context->extraRecords + context->extraRecordsCount;
+
+ for( record = context->extraRecords; record < end; ++record )
+ {
+ err = DNSServiceAddRecord( context->opRef, &record->recordRef, 0, record->type,
+ (uint16_t) record->dataLen, record->dataPtr, record->ttl );
+ require_noerr( err, exit );
+ }
+ }
+ if( context->lifetimeMs == 0 )
+ {
+ Exit( kExitReason_TimeLimit );
+ }
+ else if( context->lifetimeMs > 0 )
+ {
+ dispatch_after_f( dispatch_time_milliseconds( context->lifetimeMs ), dispatch_get_main_queue(),
+ kExitReason_TimeLimit, Exit );
+ }
+ }
+ err = kNoErr;
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// RegisterUpdate
+//===========================================================================================================================
+
+static void RegisterUpdate( void *inContext )
+{
+ OSStatus err;
+ RegisterContext * const context = (RegisterContext *) inContext;
+
+ err = DNSServiceUpdateRecord( context->opRef, NULL, 0, (uint16_t) context->updateTXTLen, context->updateTXTPtr,
+ context->updateTTL );
+ require_noerr( err, exit );
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// RegisterRecordCmd
+//===========================================================================================================================
+
+typedef struct
+{
+ DNSServiceRef conRef; // sdRef to be initialized by DNSServiceCreateConnection().
+ DNSRecordRef recordRef; // Registered record reference.
+ const char * recordName; // Name of resource record.
+ uint8_t * dataPtr; // Pointer to resource record data.
+ size_t dataLen; // Length of resource record data.
+ uint32_t ttl; // TTL value of resource record in seconds.
+ uint32_t ifIndex; // Interface index argument for DNSServiceRegisterRecord().
+ DNSServiceFlags flags; // Flags argument for DNSServiceRegisterRecord().
+ int lifetimeMs; // Lifetime of the record registration in milliseconds.
+ uint16_t recordType; // Resource record type.
+ uint8_t * updateDataPtr; // Pointer to data for record update. (malloc'd)
+ size_t updateDataLen; // Length of data for record update.
+ uint32_t updateTTL; // TTL for updated record.
+ int updateDelayMs; // Post-registration record update delay in milliseconds.
+ Boolean didRegister; // True if the record was registered.
+
+} RegisterRecordContext;
+
+static void RegisterRecordPrintPrologue( const RegisterRecordContext *inContext );
+static void RegisterRecordContextFree( RegisterRecordContext *inContext );
+static void DNSSD_API
+ RegisterRecordCallback(
+ DNSServiceRef inSDRef,
+ DNSRecordRef inRecordRef,
+ DNSServiceFlags inFlags,
+ DNSServiceErrorType inError,
+ void * inContext );
+static void RegisterRecordUpdate( void *inContext );
+
+static void RegisterRecordCmd( void )
+{
+ OSStatus err;
+ RegisterRecordContext * context = NULL;
+ dispatch_source_t signalSource = NULL;
+
+ // Set up SIGINT handler.
+
+ signal( SIGINT, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+ require_noerr( err, exit );
+ dispatch_resume( signalSource );
+
+ // Create context.
+
+ context = (RegisterRecordContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ // Create connection.
+
+ err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->conRef, NULL );
+ require_noerr_quiet( err, exit );
+
+ // Get flags.
+
+ context->flags = GetDNSSDFlagsFromOpts();
+
+ // Get interface.
+
+ err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+
+ // Get record type.
+
+ err = RecordTypeFromArgString( gRegisterRecord_Type, &context->recordType );
+ require_noerr( err, exit );
+
+ // Get record data.
+
+ if( gRegisterRecord_Data )
+ {
+ err = RecordDataFromArgString( gRegisterRecord_Data, &context->dataPtr, &context->dataLen );
+ require_noerr_quiet( err, exit );
+ }
+
+ // Set remaining parameters.
+
+ context->recordName = gRegisterRecord_Name;
+ context->ttl = (uint32_t) gRegisterRecord_TTL;
+ context->lifetimeMs = gRegisterRecord_LifetimeMs;
+
+ // Get update data.
+
+ if( gRegisterRecord_UpdateData )
+ {
+ err = RecordDataFromArgString( gRegisterRecord_UpdateData, &context->updateDataPtr, &context->updateDataLen );
+ require_noerr_quiet( err, exit );
+
+ context->updateTTL = (uint32_t) gRegisterRecord_UpdateTTL;
+ context->updateDelayMs = gRegisterRecord_UpdateDelayMs;
+ }
+
+ // Print prologue.
+
+ RegisterRecordPrintPrologue( context );
+
+ // Start operation.
+
+ err = DNSServiceRegisterRecord( context->conRef, &context->recordRef, context->flags, context->ifIndex,
+ context->recordName, context->recordType, kDNSServiceClass_IN, (uint16_t) context->dataLen, context->dataPtr,
+ context->ttl, RegisterRecordCallback, context );
+ if( err )
+ {
+ FPrintF( stderr, "DNSServiceRegisterRecord() returned %#m\n", err );
+ goto exit;
+ }
+
+ dispatch_main();
+
+exit:
+ dispatch_source_forget( &signalSource );
+ if( context ) RegisterRecordContextFree( context );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// RegisterRecordPrintPrologue
+//===========================================================================================================================
+
+static void RegisterRecordPrintPrologue( const RegisterRecordContext *inContext )
+{
+ int infinite;
+ char time[ kTimestampBufLen ];
+ char ifName[ kInterfaceNameBufLen ];
+
+ InterfaceIndexToName( inContext->ifIndex, ifName );
+
+ FPrintF( stdout, "Flags: %#{flags}\n", inContext->flags, kDNSServiceFlagsDescriptors );
+ FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, ifName );
+ FPrintF( stdout, "Name: %s\n", inContext->recordName );
+ FPrintF( stdout, "Type: %s (%u)\n", RecordTypeToString( inContext->recordType ), inContext->recordType );
+ FPrintF( stdout, "TTL: %u\n", inContext->ttl );
+ FPrintF( stdout, "Data: %#H\n", inContext->dataPtr, (int) inContext->dataLen, INT_MAX );
+ infinite = ( inContext->lifetimeMs < 0 ) ? true : false;
+ FPrintF( stdout, "Lifetime: %?s%?d ms\n", infinite, "∞", !infinite, inContext->lifetimeMs );
+ if( inContext->updateDataPtr )
+ {
+ FPrintF( stdout, "\nUpdate record:\n" );
+ FPrintF( stdout, " Delay: %d ms\n", ( inContext->updateDelayMs >= 0 ) ? inContext->updateDelayMs : 0 );
+ FPrintF( stdout, " TTL: %u%?s\n",
+ inContext->updateTTL, inContext->updateTTL == 0, " (system will use a default value.)" );
+ FPrintF( stdout, " RData: %#H\n", inContext->updateDataPtr, (int) inContext->updateDataLen, INT_MAX );
+ }
+ FPrintF( stdout, "Start time: %s\n", GetTimestampStr( time ) );
+ FPrintF( stdout, "---\n" );
+}
+
+//===========================================================================================================================
+// RegisterRecordContextFree
+//===========================================================================================================================
+
+static void RegisterRecordContextFree( RegisterRecordContext *inContext )
+{
+ DNSServiceForget( &inContext->conRef );
+ ForgetMem( &inContext->dataPtr );
+ ForgetMem( &inContext->updateDataPtr );
+ free( inContext );
+}
+
+//===========================================================================================================================
+// RegisterRecordCallback
+//===========================================================================================================================
+
+static void
+ RegisterRecordCallback(
+ DNSServiceRef inSDRef,
+ DNSRecordRef inRecordRef,
+ DNSServiceFlags inFlags,
+ DNSServiceErrorType inError,
+ void * inContext )
+{
+ RegisterRecordContext * context = (RegisterRecordContext *) inContext;
+ char time[ kTimestampBufLen ];
+
+ Unused( inSDRef );
+ Unused( inRecordRef );
+ Unused( inFlags );
+ Unused( context );
+
+ GetTimestampStr( time );
+ FPrintF( stdout, "%s Record registration result (error %#m)\n", time, inError );
+
+ if( !context->didRegister && !inError )
+ {
+ context->didRegister = true;
+ if( context->updateDataPtr )
+ {
+ if( context->updateDelayMs > 0 )
+ {
+ dispatch_after_f( dispatch_time_milliseconds( context->updateDelayMs ), dispatch_get_main_queue(),
+ context, RegisterRecordUpdate );
+ }
+ else
+ {
+ RegisterRecordUpdate( context );
+ }
+ }
+ if( context->lifetimeMs == 0 )
+ {
+ Exit( kExitReason_TimeLimit );
+ }
+ else if( context->lifetimeMs > 0 )
+ {
+ dispatch_after_f( dispatch_time_milliseconds( context->lifetimeMs ), dispatch_get_main_queue(),
+ kExitReason_TimeLimit, Exit );
+ }
+ }
+}
+
+//===========================================================================================================================
+// RegisterRecordUpdate
+//===========================================================================================================================
+
+static void RegisterRecordUpdate( void *inContext )
+{
+ OSStatus err;
+ RegisterRecordContext * const context = (RegisterRecordContext *) inContext;
+
+ err = DNSServiceUpdateRecord( context->conRef, context->recordRef, 0, (uint16_t) context->updateDataLen,
+ context->updateDataPtr, context->updateTTL );
+ require_noerr( err, exit );
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// ResolveCmd
+//===========================================================================================================================
+
+typedef struct
+{
+ DNSServiceRef mainRef; // Main sdRef for shared connections.
+ DNSServiceRef opRef; // sdRef for the DNSServiceResolve operation.
+ DNSServiceFlags flags; // Flags argument for DNSServiceResolve().
+ const char * name; // Service name argument for DNSServiceResolve().
+ const char * type; // Service type argument for DNSServiceResolve().
+ const char * domain; // Domain argument for DNSServiceResolve().
+ uint32_t ifIndex; // Interface index argument for DNSServiceResolve().
+ int timeLimitSecs; // Time limit for the DNSServiceResolve operation in seconds.
+
+} ResolveContext;
+
+static void ResolvePrintPrologue( const ResolveContext *inContext );
+static void ResolveContextFree( ResolveContext *inContext );
+static void DNSSD_API
+ ResolveCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ const char * inHostname,
+ uint16_t inPort,
+ uint16_t inTXTLen,
+ const unsigned char * inTXTPtr,
+ void * inContext );
+
+static void ResolveCmd( void )
+{
+ OSStatus err;
+ DNSServiceRef sdRef;
+ ResolveContext * context = NULL;
+ dispatch_source_t signalSource = NULL;
+ int useMainConnection;
+
+ // Set up SIGINT handler.
+
+ signal( SIGINT, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+ require_noerr( err, exit );
+ dispatch_resume( signalSource );
+
+ // Create context.
+
+ context = (ResolveContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ // Check command parameters.
+
+ if( gResolve_TimeLimitSecs < 0 )
+ {
+ FPrintF( stderr, "Invalid time limit: %d seconds.\n", gResolve_TimeLimitSecs );
+ err = kParamErr;
+ goto exit;
+ }
+
+ // Create main connection.
+
+ if( gConnectionOpt )
+ {
+ err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
+ require_noerr_quiet( err, exit );
+ useMainConnection = true;
+ }
+ else
+ {
+ useMainConnection = false;
+ }
+
+ // Get flags.
+
+ context->flags = GetDNSSDFlagsFromOpts();
+ if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
+
+ // Get interface index.
+
+ err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+
+ // Set remaining parameters.
+
+ context->name = gResolve_Name;
+ context->type = gResolve_Type;
+ context->domain = gResolve_Domain;
+ context->timeLimitSecs = gResolve_TimeLimitSecs;
+
+ // Print prologue.
+
+ ResolvePrintPrologue( context );
+
+ // Start operation.
+
+ if( useMainConnection ) sdRef = context->mainRef;
+ err = DNSServiceResolve( &sdRef, context->flags, context->ifIndex, context->name, context->type, context->domain,
+ ResolveCallback, NULL );
+ require_noerr( err, exit );
+
+ context->opRef = sdRef;
+ if( !useMainConnection )
+ {
+ err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
+ require_noerr( err, exit );
+ }
+
+ // Set time limit.
+
+ if( context->timeLimitSecs > 0 )
+ {
+ dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(),
+ kExitReason_TimeLimit, Exit );
+ }
+ dispatch_main();
+
+exit:
+ dispatch_source_forget( &signalSource );
+ if( context ) ResolveContextFree( context );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// ReconfirmCmd
+//===========================================================================================================================
+
+static void ReconfirmCmd( void )
+{
+ OSStatus err;
+ uint8_t * rdataPtr = NULL;
+ size_t rdataLen = 0;
+ DNSServiceFlags flags;
+ uint32_t ifIndex;
+ uint16_t type, class;
+ char ifName[ kInterfaceNameBufLen ];
+
+ // Get flags.
+
+ flags = GetDNSSDFlagsFromOpts();
+
+ // Get interface index.
+
+ err = InterfaceIndexFromArgString( gInterface, &ifIndex );
+ require_noerr_quiet( err, exit );
+
+ // Get record type.
+
+ err = RecordTypeFromArgString( gReconfirmRecord_Type, &type );
+ require_noerr( err, exit );
+
+ // Get record data.
+
+ if( gReconfirmRecord_Data )
+ {
+ err = RecordDataFromArgString( gReconfirmRecord_Data, &rdataPtr, &rdataLen );
+ require_noerr_quiet( err, exit );
+ }
+
+ // Get record data.
+
+ if( gReconfirmRecord_Class )
+ {
+ err = RecordClassFromArgString( gReconfirmRecord_Class, &class );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ class = kDNSServiceClass_IN;
+ }
+
+ // Print prologue.
+
+ FPrintF( stdout, "Flags: %#{flags}\n", flags, kDNSServiceFlagsDescriptors );
+ FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) ifIndex, InterfaceIndexToName( ifIndex, ifName ) );
+ FPrintF( stdout, "Name: %s\n", gReconfirmRecord_Name );
+ FPrintF( stdout, "Type: %s (%u)\n", RecordTypeToString( type ), type );
+ FPrintF( stdout, "Class: %s (%u)\n", ( class == kDNSServiceClass_IN ) ? "IN" : "???", class );
+ FPrintF( stdout, "Data: %#H\n", rdataPtr, (int) rdataLen, INT_MAX );
+ FPrintF( stdout, "---\n" );
+
+ err = DNSServiceReconfirmRecord( flags, ifIndex, gReconfirmRecord_Name, type, class, (uint16_t) rdataLen, rdataPtr );
+ FPrintF( stdout, "Error: %#m\n", err );
+
+exit:
+ FreeNullSafe( rdataPtr );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// ResolvePrintPrologue
+//===========================================================================================================================
+
+static void ResolvePrintPrologue( const ResolveContext *inContext )
+{
+ const int timeLimitSecs = inContext->timeLimitSecs;
+ char ifName[ kInterfaceNameBufLen ];
+ char time[ kTimestampBufLen ];
+
+ InterfaceIndexToName( inContext->ifIndex, ifName );
+
+ FPrintF( stdout, "Flags: %#{flags}\n", inContext->flags, kDNSServiceFlagsDescriptors );
+ FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, ifName );
+ FPrintF( stdout, "Name: %s\n", inContext->name );
+ FPrintF( stdout, "Type: %s\n", inContext->type );
+ FPrintF( stdout, "Domain: %s\n", inContext->domain );
+ FPrintF( stdout, "Time limit: " );
+ if( timeLimitSecs > 0 ) FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
+ else FPrintF( stdout, "∞\n" );
+ FPrintF( stdout, "Start time: %s\n", GetTimestampStr( time ) );
+ FPrintF( stdout, "---\n" );
+}
+
+//===========================================================================================================================
+// ResolveContextFree
+//===========================================================================================================================
+
+static void ResolveContextFree( ResolveContext *inContext )
+{
+ DNSServiceForget( &inContext->opRef );
+ DNSServiceForget( &inContext->mainRef );
+ free( inContext );
+}
+
+//===========================================================================================================================
+// ResolveCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ ResolveCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ const char * inHostname,
+ uint16_t inPort,
+ uint16_t inTXTLen,
+ const unsigned char * inTXTPtr,
+ void * inContext )
+{
+ char time[ kTimestampBufLen ];
+ char errorStr[ 64 ];
+
+ Unused( inSDRef );
+ Unused( inFlags );
+ Unused( inContext );
+
+ GetTimestampStr( time );
+
+ if( inError ) SNPrintF( errorStr, sizeof( errorStr ), " error %#m", inError );
+
+ FPrintF( stdout, "%s: %s can be reached at %s:%u (interface %d)%?s\n",
+ time, inFullName, inHostname, ntohs( inPort ), (int32_t) inInterfaceIndex, inError, errorStr );
+ if( inTXTLen == 1 )
+ {
+ FPrintF( stdout, " TXT record: %#H\n", inTXTPtr, (int) inTXTLen, INT_MAX );
+ }
+ else
+ {
+ FPrintF( stdout, " TXT record: %#{txt}\n", inTXTPtr, (size_t) inTXTLen );
+ }
+}
+
+//===========================================================================================================================
+// GetAddrInfoPOSIXCmd
+//===========================================================================================================================
+
+#define AddressFamilyStr( X ) ( \
+ ( (X) == AF_INET ) ? "inet" : \
+ ( (X) == AF_INET6 ) ? "inet6" : \
+ ( (X) == AF_UNSPEC ) ? "unspec" : \
+ "???" )
+
+static void GetAddrInfoPOSIXCmd( void )
+{
+ OSStatus err;
+ struct addrinfo hints;
+ struct addrinfo * addrInfo;
+ struct addrinfo * addrInfoList = NULL;
+ int addrCount;
+ char time[ kTimestampBufLen ];
+
+ memset( &hints, 0, sizeof( hints ) );
+ hints.ai_socktype = SOCK_STREAM;
+ if( !gGAIPOSIX_Family ) hints.ai_family = AF_UNSPEC;
+ else if( strcasecmp( gGAIPOSIX_Family, "inet" ) == 0 ) hints.ai_family = AF_INET;
+ else if( strcasecmp( gGAIPOSIX_Family, "inet6" ) == 0 ) hints.ai_family = AF_INET6;
+ else if( strcasecmp( gGAIPOSIX_Family, "unspec" ) == 0 ) hints.ai_family = AF_UNSPEC;
+ else
+ {
+ FPrintF( stderr, "Invalid address family: %s.\n", gGAIPOSIX_Family );
+ err = kParamErr;
+ goto exit;
+ }
+
+ FPrintF( stdout, "Name: %s\n", gGAIPOSIX_Name );
+ FPrintF( stdout, "Address family: %s\n", AddressFamilyStr( hints.ai_family ) );
+ FPrintF( stdout, "Start time: %s\n", GetTimestampStr( time ) );
+ FPrintF( stdout, "---\n" );
+
+ err = getaddrinfo( gGAIPOSIX_Name, NULL, &hints, &addrInfoList );
+ FPrintF( stdout, "%s:\n", GetTimestampStr( time ) );
+ if( err )
+ {
+ FPrintF( stderr, "getaddrinfo() error %#m: %s.\n", err, gai_strerror( err ) );
+ goto exit;
+ }
+
+ addrCount = 0;
+ for( addrInfo = addrInfoList; addrInfo; addrInfo = addrInfo->ai_next ) { ++addrCount; }
+
+ FPrintF( stdout, "Addresses (%d total):\n", addrCount );
+ for( addrInfo = addrInfoList; addrInfo; addrInfo = addrInfo->ai_next )
+ {
+ FPrintF( stdout, "%##a\n", addrInfo->ai_addr );
+ }
+
+exit:
+ FPrintF( stdout, "---\n" );
+ FPrintF( stdout, "End time: %s\n", GetTimestampStr( time ) );
+
+ if( addrInfoList ) freeaddrinfo( addrInfoList );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// ReverseLookupCmd
+//===========================================================================================================================
+
+static void ReverseLookupCmd( void )
+{
+ OSStatus err;
+ QueryRecordContext * context = NULL;
+ DNSServiceRef sdRef;
+ dispatch_source_t signalSource = NULL;
+ uint32_t ipv4Addr;
+ uint8_t ipv6Addr[ 16 ];
+ char recordName[ ( 16 * 4 ) + 9 + 1 ];
+ int useMainConnection;
+
+ // Set up SIGINT handler.
+
+ signal( SIGINT, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+ require_noerr( err, exit );
+ dispatch_resume( signalSource );
+
+ // Create context.
+
+ context = (QueryRecordContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ // Check command parameters.
+
+ if( gReverseLookup_TimeLimitSecs < 0 )
+ {
+ FPrintF( stderr, "Invalid time limit: %d s.\n", gReverseLookup_TimeLimitSecs );
+ err = kParamErr;
+ goto exit;
+ }
+
+ // Create main connection.
+
+ if( gConnectionOpt )
+ {
+ err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
+ require_noerr_quiet( err, exit );
+ useMainConnection = true;
+ }
+ else
+ {
+ useMainConnection = false;
+ }
+
+ // Get flags.
+
+ context->flags = GetDNSSDFlagsFromOpts();
+ if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
+
+ // Get interface index.
+
+ err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+
+ // Create reverse lookup record name.
+
+ err = StringToIPv4Address( gReverseLookup_IPAddr, kStringToIPAddressFlagsNoPort | kStringToIPAddressFlagsNoPrefix,
+ &ipv4Addr, NULL, NULL, NULL, NULL );
+ if( err )
+ {
+ char * dst;
+ int i;
+
+ err = StringToIPv6Address( gReverseLookup_IPAddr,
+ kStringToIPAddressFlagsNoPort | kStringToIPAddressFlagsNoPrefix | kStringToIPAddressFlagsNoScope,
+ ipv6Addr, NULL, NULL, NULL, NULL );
+ if( err )
+ {
+ FPrintF( stderr, "Invalid IP address: \"%s\".\n", gReverseLookup_IPAddr );
+ err = kParamErr;
+ goto exit;
+ }
+ dst = recordName;
+ for( i = 15; i >= 0; --i )
+ {
+ *dst++ = kHexDigitsLowercase[ ipv6Addr[ i ] & 0x0F ];
+ *dst++ = '.';
+ *dst++ = kHexDigitsLowercase[ ipv6Addr[ i ] >> 4 ];
+ *dst++ = '.';
+ }
+ strcpy( dst, "ip6.arpa." );
+ check( ( strlen( recordName ) + 1 ) <= sizeof( recordName ) );
+ }
+ else
+ {
+ SNPrintF( recordName, sizeof( recordName ), "%u.%u.%u.%u.in-addr.arpa.",
+ ipv4Addr & 0xFF,
+ ( ipv4Addr >> 8 ) & 0xFF,
+ ( ipv4Addr >> 16 ) & 0xFF,
+ ( ipv4Addr >> 24 ) & 0xFF );
+ }
+
+ // Set remaining parameters.
+
+ context->recordName = recordName;
+ context->recordType = kDNSServiceType_PTR;
+ context->timeLimitSecs = gReverseLookup_TimeLimitSecs;
+ context->oneShotMode = gReverseLookup_OneShot ? true : false;
+
+ // Print prologue.
+
+ QueryRecordPrintPrologue( context );
+
+ // Start operation.
+
+ if( useMainConnection ) sdRef = context->mainRef;
+ err = DNSServiceQueryRecord( &sdRef, context->flags, context->ifIndex, context->recordName, context->recordType,
+ kDNSServiceClass_IN, QueryRecordCallback, context );
+ require_noerr( err, exit );
+
+ context->opRef = sdRef;
+ if( !useMainConnection )
+ {
+ err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
+ require_noerr( err, exit );
+ }
+
+ // Set time limit.
+
+ if( context->timeLimitSecs > 0 )
+ {
+ dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(),
+ kExitReason_TimeLimit, Exit );
+ }
+ dispatch_main();
+
+exit:
+ dispatch_source_forget( &signalSource );
+ if( context ) QueryRecordContextFree( context );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// BrowseAllCmd
+//===========================================================================================================================
+
+typedef struct BrowseDomain BrowseDomain;
+typedef struct BrowseType BrowseType;
+typedef struct BrowseOp BrowseOp;
+typedef struct BrowseInstance BrowseInstance;
+typedef struct BrowseIPAddr BrowseIPAddr;
+
+typedef struct
+{
+ int refCount;
+ DNSServiceRef mainRef;
+ DNSServiceRef domainsQuery;
+ const char * domain;
+ BrowseDomain * domainList;
+ char ** serviceTypes;
+ size_t serviceTypesCount;
+ dispatch_source_t exitTimer;
+ uint32_t ifIndex;
+ int pendingConnectCount;
+ int browseTimeSecs;
+ int connectTimeLimitSecs;
+ Boolean includeAWDL;
+ Boolean useColoredText;
+
+} BrowseAllContext;
+
+struct BrowseDomain
+{
+ BrowseDomain * next;
+ char * name;
+ DNSServiceRef servicesQuery;
+ BrowseAllContext * context;
+ BrowseType * typeList;
+};
+
+struct BrowseType
+{
+ BrowseType * next;
+ char * name;
+ BrowseOp * browseList;
+};
+
+struct BrowseOp
+{
+ BrowseOp * next;
+ BrowseAllContext * context;
+ DNSServiceRef browse;
+ uint64_t startTicks;
+ BrowseInstance * instanceList;
+ uint32_t ifIndex;
+ Boolean isTCP;
+};
+
+struct BrowseInstance
+{
+ BrowseInstance * next;
+ BrowseAllContext * context;
+ char * name;
+ uint64_t foundTicks;
+ DNSServiceRef resolve;
+ uint64_t resolveStartTicks;
+ uint64_t resolveDoneTicks;
+ DNSServiceRef getAddr;
+ uint64_t getAddrStartTicks;
+ BrowseIPAddr * addrList;
+ uint8_t * txtPtr;
+ size_t txtLen;
+ char * hostname;
+ uint32_t ifIndex;
+ uint16_t port;
+ Boolean isTCP;
+};
+
+typedef enum
+{
+ kConnectStatus_None = 0,
+ kConnectStatus_Pending = 1,
+ kConnectStatus_Succeeded = 2,
+ kConnectStatus_Failed = 3
+
+} ConnectStatus;
+
+struct BrowseIPAddr
+{
+ BrowseIPAddr * next;
+ sockaddr_ip sip;
+ int refCount;
+ BrowseAllContext * context;
+ uint64_t foundTicks;
+ AsyncConnectionRef connection;
+ ConnectStatus connectStatus;
+ CFTimeInterval connectTimeSecs;
+ OSStatus connectError;
+};
+
+static void BrowseAllPrintPrologue( const BrowseAllContext *inContext );
+static void DNSSD_API
+ BrowseAllQueryDomainsCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext );
+static void DNSSD_API
+ BrowseAllQueryCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext );
+static void DNSSD_API
+ BrowseAllBrowseCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inName,
+ const char * inRegType,
+ const char * inDomain,
+ void * inContext );
+static void DNSSD_API
+ BrowseAllResolveCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ const char * inHostname,
+ uint16_t inPort,
+ uint16_t inTXTLen,
+ const unsigned char * inTXTPtr,
+ void * inContext );
+static void DNSSD_API
+ BrowseAllGAICallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inHostname,
+ const struct sockaddr * inSockAddr,
+ uint32_t inTTL,
+ void * inContext );
+static void BrowseAllConnectionProgress( int inPhase, const void *inDetails, void *inArg );
+static void BrowseAllConnectionHandler( SocketRef inSock, OSStatus inError, void *inArg );
+static void BrowseAllStop( void *inContext );
+static void BrowseAllExit( void *inContext );
+static OSStatus BrowseAllAddDomain( BrowseAllContext *inContext, const char *inName );
+static OSStatus BrowseAllRemoveDomain( BrowseAllContext *inContext, const char *inName );
+static void BrowseAllContextRelease( BrowseAllContext *inContext );
+static OSStatus
+ BrowseAllAddServiceType(
+ BrowseAllContext * inContext,
+ BrowseDomain * inDomain,
+ const char * inName,
+ uint32_t inIfIndex,
+ Boolean inIncludeAWDL );
+static OSStatus
+ BrowseAllRemoveServiceType(
+ BrowseAllContext * inContext,
+ BrowseDomain * inDomain,
+ const char * inName,
+ uint32_t inIfIndex );
+static OSStatus
+ BrowseAllAddServiceInstance(
+ BrowseAllContext * inContext,
+ BrowseOp * inBrowse,
+ const char * inName,
+ const char * inRegType,
+ const char * inDomain,
+ uint32_t inIfIndex );
+static OSStatus
+ BrowseAllRemoveServiceInstance(
+ BrowseAllContext * inContext,
+ BrowseOp * inBrowse,
+ const char * inName,
+ uint32_t inIfIndex );
+static OSStatus
+ BrowseAllAddIPAddress(
+ BrowseAllContext * inContext,
+ BrowseInstance * inInstance,
+ const struct sockaddr * inSockAddr );
+static OSStatus
+ BrowseAllRemoveIPAddress(
+ BrowseAllContext * inContext,
+ BrowseInstance * inInstance,
+ const struct sockaddr * inSockAddr );
+static void BrowseDomainFree( BrowseDomain *inDomain );
+static void BrowseTypeFree( BrowseType *inType );
+static void BrowseOpFree( BrowseOp *inBrowse );
+static void BrowseInstanceFree( BrowseInstance *inInstance );
+static void BrowseIPAddrRelease( BrowseIPAddr *inAddr );
+static void BrowseIPAddrReleaseList( BrowseIPAddr *inList );
+
+#define ForgetIPAddressList( X ) ForgetCustom( X, BrowseIPAddrReleaseList )
+#define ForgetBrowseAllContext( X ) ForgetCustom( X, BrowseAllContextRelease )
+
+#define kBrowseAllOpenFileMin 4096
+
+static void BrowseAllCmd( void )
+{
+ OSStatus err;
+ BrowseAllContext * context = NULL;
+
+ // Check command parameters.
+
+ if( gBrowseAll_BrowseTimeSecs <= 0 )
+ {
+ FPrintF( stdout, "Invalid browse time: %d seconds.\n", gBrowseAll_BrowseTimeSecs );
+ err = kParamErr;
+ goto exit;
+ }
+
+#if( TARGET_OS_POSIX )
+ // Set open file minimum.
+
+ {
+ struct rlimit fdLimits;
+
+ err = getrlimit( RLIMIT_NOFILE, &fdLimits );
+ err = map_global_noerr_errno( err );
+ require_noerr( err, exit );
+
+ if( fdLimits.rlim_cur < kBrowseAllOpenFileMin )
+ {
+ fdLimits.rlim_cur = kBrowseAllOpenFileMin;
+ err = setrlimit( RLIMIT_NOFILE, &fdLimits );
+ err = map_global_noerr_errno( err );
+ require_noerr( err, exit );
+ }
+ }
+#endif
+
+ context = (BrowseAllContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ context->refCount = 1;
+ context->domain = gBrowseAll_Domain;
+ context->serviceTypes = gBrowseAll_ServiceTypes;
+ context->serviceTypesCount = gBrowseAll_ServiceTypesCount;
+ gBrowseAll_ServiceTypes = NULL;
+ gBrowseAll_ServiceTypesCount = 0;
+ context->browseTimeSecs = gBrowseAll_BrowseTimeSecs;
+ context->connectTimeLimitSecs = gBrowseAll_ConnectTimeLimitSecs;
+ context->includeAWDL = gBrowseAll_IncludeAWDL ? true : false;
+#if( TARGET_OS_POSIX )
+ context->useColoredText = isatty( STDOUT_FILENO ) ? true : false;
+#endif
+
+ err = DNSServiceCreateConnection( &context->mainRef );
+ require_noerr( err, exit );
+
+ err = DNSServiceSetDispatchQueue( context->mainRef, dispatch_get_main_queue() );
+ require_noerr( err, exit );
+
+ // Set interface index.
+
+ err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+
+ BrowseAllPrintPrologue( context );
+
+ if( context->domain )
+ {
+ err = BrowseAllAddDomain( context, context->domain );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ DNSServiceRef sdRef;
+
+ sdRef = context->mainRef;
+ err = DNSServiceQueryRecord( &sdRef, kDNSServiceFlagsShareConnection, kDNSServiceInterfaceIndexLocalOnly,
+ "b._dns-sd._udp.local.", kDNSServiceType_PTR, kDNSServiceClass_IN, BrowseAllQueryDomainsCallback, context );
+ require_noerr( err, exit );
+
+ context->domainsQuery = sdRef;
+ }
+
+ dispatch_after_f( dispatch_time_seconds( context->browseTimeSecs ), dispatch_get_main_queue(), context, BrowseAllStop );
+ dispatch_main();
+
+exit:
+ if( context ) BrowseAllContextRelease( context );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// BrowseAllPrintPrologue
+//===========================================================================================================================
+
+static void BrowseAllPrintPrologue( const BrowseAllContext *inContext )
+{
+ size_t i;
+ char ifName[ kInterfaceNameBufLen ];
+ char time[ kTimestampBufLen ];
+
+ InterfaceIndexToName( inContext->ifIndex, ifName );
+
+ FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, ifName );
+ FPrintF( stdout, "Service types: ");
+ if( inContext->serviceTypesCount > 0 )
+ {
+ FPrintF( stdout, "%s", inContext->serviceTypes[ 0 ] );
+ for( i = 1; i < inContext->serviceTypesCount; ++i ) FPrintF( stdout, ", %s", inContext->serviceTypes[ i ] );
+ FPrintF( stdout, "\n" );
+ }
+ else
+ {
+ FPrintF( stdout, "all services\n" );
+ }
+ FPrintF( stdout, "Domain: %s\n", inContext->domain ? inContext->domain : "default domains" );
+ FPrintF( stdout, "Browse time: %d second%?c\n", inContext->browseTimeSecs, inContext->browseTimeSecs != 1, 's' );
+ FPrintF( stdout, "Connect time limit: %d second%?c\n",
+ inContext->connectTimeLimitSecs, inContext->connectTimeLimitSecs != 1, 's' );
+ FPrintF( stdout, "Start time: %s\n", GetTimestampStr( time ) );
+ FPrintF( stdout, "---\n" );
+}
+
+//===========================================================================================================================
+// BrowseAllQueryDomainsCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ BrowseAllQueryDomainsCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext )
+{
+ OSStatus err;
+ BrowseAllContext * const context = (BrowseAllContext *) inContext;
+ char domainStr[ kDNSServiceMaxDomainName ];
+
+ Unused( inSDRef );
+ Unused( inInterfaceIndex );
+ Unused( inFullName );
+ Unused( inType );
+ Unused( inClass );
+ Unused( inTTL );
+
+ err = inError;
+ require_noerr( err, exit );
+
+ err = DomainNameToString( inRDataPtr, ( (const uint8_t *) inRDataPtr ) + inRDataLen, domainStr, NULL );
+ require_noerr( err, exit );
+
+ if( inFlags & kDNSServiceFlagsAdd )
+ {
+ err = BrowseAllAddDomain( context, domainStr );
+ if( err == kDuplicateErr ) err = kNoErr;
+ require_noerr( err, exit );
+ }
+ else
+ {
+ err = BrowseAllRemoveDomain( context, domainStr );
+ if( err == kNotFoundErr ) err = kNoErr;
+ require_noerr( err, exit );
+ }
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// BrowseAllQueryCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ BrowseAllQueryCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext )
+{
+ OSStatus err;
+ BrowseDomain * const domain = (BrowseDomain *) inContext;
+ const uint8_t * firstLabel;
+ const uint8_t * secondLabel;
+ char * serviceTypeStr = NULL;
+ const uint8_t * const end = ( (uint8_t * ) inRDataPtr ) + inRDataLen;
+
+ Unused( inSDRef );
+ Unused( inFullName );
+ Unused( inTTL );
+ Unused( inType );
+ Unused( inClass );
+
+ err = inError;
+ require_noerr( err, exit );
+
+ check( inType == kDNSServiceType_PTR );
+ check( inClass == kDNSServiceClass_IN );
+ require_action( inRDataLen > 0, exit, err = kSizeErr );
+
+ firstLabel = inRDataPtr;
+ require_action_quiet( ( firstLabel + 1 + firstLabel[ 0 ] ) < end , exit, err = kUnderrunErr );
+
+ secondLabel = firstLabel + 1 + firstLabel[ 0 ];
+ require_action_quiet( ( secondLabel + 1 + secondLabel[ 0 ] ) < end , exit, err = kUnderrunErr );
+
+ ASPrintF( &serviceTypeStr, "%#s.%#s", firstLabel, secondLabel );
+ require_action( serviceTypeStr, exit, err = kNoMemoryErr );
+
+ if( inFlags & kDNSServiceFlagsAdd )
+ {
+ err = BrowseAllAddServiceType( domain->context, domain, serviceTypeStr, inInterfaceIndex, false );
+ if( err == kDuplicateErr ) err = kNoErr;
+ require_noerr( err, exit );
+ }
+ else
+ {
+ err = BrowseAllRemoveServiceType( domain->context, domain, serviceTypeStr, inInterfaceIndex );
+ if( err == kNotFoundErr ) err = kNoErr;
+ require_noerr( err, exit );
+ }
+
+exit:
+ FreeNullSafe( serviceTypeStr );
+}
+
+//===========================================================================================================================
+// BrowseAllBrowseCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ BrowseAllBrowseCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inName,
+ const char * inRegType,
+ const char * inDomain,
+ void * inContext )
+{
+ OSStatus err;
+ BrowseOp * const browse = (BrowseOp *) inContext;
+
+ Unused( inSDRef );
+
+ err = inError;
+ require_noerr( err, exit );
+
+ if( inFlags & kDNSServiceFlagsAdd )
+ {
+ err = BrowseAllAddServiceInstance( browse->context, browse, inName, inRegType, inDomain, inInterfaceIndex );
+ if( err == kDuplicateErr ) err = kNoErr;
+ require_noerr( err, exit );
+ }
+ else
+ {
+ err = BrowseAllRemoveServiceInstance( browse->context, browse, inName, inInterfaceIndex );
+ if( err == kNotFoundErr ) err = kNoErr;
+ require_noerr( err, exit );
+ }
+
+exit:
+ return;
+}
+
+//===========================================================================================================================
+// BrowseAllResolveCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ BrowseAllResolveCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ const char * inHostname,
+ uint16_t inPort,
+ uint16_t inTXTLen,
+ const unsigned char * inTXTPtr,
+ void * inContext )
+{
+ OSStatus err;
+ const uint64_t nowTicks = UpTicks();
+ BrowseInstance * const instance = (BrowseInstance *) inContext;
+
+ Unused( inSDRef );
+ Unused( inFlags );
+ Unused( inInterfaceIndex );
+ Unused( inFullName );
+
+ err = inError;
+ require_noerr( err, exit );
+
+ if( !MemEqual( instance->txtPtr, instance->txtLen, inTXTPtr, inTXTLen ) )
+ {
+ FreeNullSafe( instance->txtPtr );
+ instance->txtPtr = malloc( inTXTLen );
+ require_action( instance->txtPtr, exit, err = kNoMemoryErr );
+
+ memcpy( instance->txtPtr, inTXTPtr, inTXTLen );
+ instance->txtLen = inTXTLen;
+ }
+
+ instance->port = ntohs( inPort );
+
+ if( !instance->hostname || ( strcasecmp( instance->hostname, inHostname ) != 0 ) )
+ {
+ DNSServiceRef sdRef;
+
+ if( !instance->hostname ) instance->resolveDoneTicks = nowTicks;
+ FreeNullSafe( instance->hostname );
+ instance->hostname = strdup( inHostname );
+ require_action( instance->hostname, exit, err = kNoMemoryErr );
+
+ DNSServiceForget( &instance->getAddr );
+ ForgetIPAddressList( &instance->addrList );
+
+ sdRef = instance->context->mainRef;
+ instance->getAddrStartTicks = UpTicks();
+ err = DNSServiceGetAddrInfo( &sdRef, kDNSServiceFlagsShareConnection, instance->ifIndex,
+ kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6, instance->hostname, BrowseAllGAICallback, instance );
+ require_noerr( err, exit );
+
+ instance->getAddr = sdRef;
+ }
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// BrowseAllGAICallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ BrowseAllGAICallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inHostname,
+ const struct sockaddr * inSockAddr,
+ uint32_t inTTL,
+ void * inContext )
+{
+ OSStatus err;
+ BrowseInstance * const instance = (BrowseInstance *) inContext;
+
+ Unused( inSDRef );
+ Unused( inInterfaceIndex );
+ Unused( inHostname );
+ Unused( inTTL );
+
+ err = inError;
+ require_noerr( err, exit );
+
+ if( ( inSockAddr->sa_family != AF_INET ) && ( inSockAddr->sa_family != AF_INET6 ) )
+ {
+ dlogassert( "Unexpected address family: %d", inSockAddr->sa_family );
+ goto exit;
+ }
+
+ if( inFlags & kDNSServiceFlagsAdd )
+ {
+ err = BrowseAllAddIPAddress( instance->context, instance, inSockAddr );
+ if( err == kDuplicateErr ) err = kNoErr;
+ require_noerr( err, exit );
+ }
+ else
+ {
+ err = BrowseAllRemoveIPAddress( instance->context, instance, inSockAddr );
+ if( err == kNotFoundErr ) err = kNoErr;
+ require_noerr( err, exit );
+ }
+
+exit:
+ return;
+}
+
+//===========================================================================================================================
+// BrowseAllConnectionProgress
+//===========================================================================================================================
+
+static void BrowseAllConnectionProgress( int inPhase, const void *inDetails, void *inArg )
+{
+ BrowseIPAddr * const addr = (BrowseIPAddr *) inArg;
+
+ if( inPhase == kAsyncConnectionPhase_Connected )
+ {
+ const AsyncConnectedInfo * const info = (AsyncConnectedInfo *) inDetails;
+
+ addr->connectTimeSecs = info->connectSecs;
+ }
+}
+
+//===========================================================================================================================
+// BrowseAllConnectionHandler
+//===========================================================================================================================
+
+static void BrowseAllConnectionHandler( SocketRef inSock, OSStatus inError, void *inArg )
+{
+ BrowseIPAddr * const addr = (BrowseIPAddr *) inArg;
+ BrowseAllContext * const context = addr->context;
+
+ if( inError )
+ {
+ addr->connectStatus = kConnectStatus_Failed;
+ addr->connectError = inError;
+ }
+ else
+ {
+ addr->connectStatus = kConnectStatus_Succeeded;
+ }
+
+ check( context->pendingConnectCount > 0 );
+ if( --context->pendingConnectCount == 0 )
+ {
+ if( context->exitTimer )
+ {
+ dispatch_source_forget( &context->exitTimer );
+ dispatch_async_f( dispatch_get_main_queue(), context, BrowseAllExit );
+ }
+ }
+
+ ForgetSocket( &inSock );
+ BrowseIPAddrRelease( addr );
+}
+
+//===========================================================================================================================
+// BrowseAllStop
+//===========================================================================================================================
+
+static void BrowseAllStop( void *inContext )
+{
+ OSStatus err;
+ BrowseAllContext * const context = (BrowseAllContext *) inContext;
+ BrowseDomain * domain;
+ BrowseType * type;
+ BrowseOp * browse;
+ BrowseInstance * instance;
+
+ DNSServiceForget( &context->domainsQuery );
+ for( domain = context->domainList; domain; domain = domain->next )
+ {
+ DNSServiceForget( &domain->servicesQuery );
+ for( type = domain->typeList; type; type = type->next )
+ {
+ for( browse = type->browseList; browse; browse = browse->next )
+ {
+ DNSServiceForget( &browse->browse );
+ for( instance = browse->instanceList; instance; instance = instance->next )
+ {
+ DNSServiceForget( &instance->resolve );
+ DNSServiceForget( &instance->getAddr );
+ }
+ }
+ }
+ }
+ DNSServiceForget( &context->mainRef );
+
+ if( ( context->pendingConnectCount > 0 ) && ( context->connectTimeLimitSecs > 0 ) )
+ {
+ check( !context->exitTimer );
+ err = DispatchTimerCreate( dispatch_time_seconds( context->connectTimeLimitSecs ), DISPATCH_TIME_FOREVER,
+ 100 * kNanosecondsPerMillisecond, BrowseAllExit, NULL, context, &context->exitTimer );
+ require_noerr( err, exit );
+ dispatch_resume( context->exitTimer );
+ }
+ else
+ {
+ dispatch_async_f( dispatch_get_main_queue(), context, BrowseAllExit );
+ }
+ err = kNoErr;
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// BrowseAllExit
+//===========================================================================================================================
+
+#define kStatusStr_CouldConnect "connected"
+#define kStatusStr_CouldConnectColored kANSIGreen kStatusStr_CouldConnect kANSINormal
+#define kStatusStr_CouldNotConnect "could not connect"
+#define kStatusStr_CouldNotConnectColored kANSIRed kStatusStr_CouldNotConnect kANSINormal
+#define kStatusStr_NoConnectionAttempted "no connection attempted"
+#define kStatusStr_Unknown "unknown"
+
+#define Indent( X ) ( (X) * 4 ), ""
+
+static void BrowseAllExit( void *inContext )
+{
+ BrowseAllContext * const context = (BrowseAllContext *) inContext;
+ BrowseDomain * domain;
+ BrowseType * type;
+ BrowseOp * browse;
+ BrowseInstance * instance;
+ BrowseIPAddr * addr;
+
+ dispatch_source_forget( &context->exitTimer );
+
+ for( domain = context->domainList; domain; domain = domain->next )
+ {
+ FPrintF( stdout, "%s\n\n", domain->name );
+
+ for( type = domain->typeList; type; type = type->next )
+ {
+ const char * desc;
+
+ desc = ServiceTypeDescription( type->name );
+ if( desc ) FPrintF( stdout, "%*s" "%s (%s)\n\n", Indent( 1 ), desc, type->name );
+ else FPrintF( stdout, "%*s" "%s\n\n", Indent( 1 ), type->name );
+
+ for( browse = type->browseList; browse; browse = browse->next )
+ {
+ for( instance = browse->instanceList; instance; instance = instance->next )
+ {
+ char ifname[ IF_NAMESIZE + 1 ];
+
+ FPrintF( stdout, "%*s" "%s via ", Indent( 2 ), instance->name );
+ FPrintF( stdout, "%*s" "%s via ", Indent( 2 ), instance->name );
+ if( instance->ifIndex == 0 )
+ {
+ FPrintF( stdout, "the Internet" );
+ }
+ else if( if_indextoname( instance->ifIndex, ifname ) )
+ {
+ NetTransportType netType;
+
+ SocketGetInterfaceInfo( kInvalidSocketRef, ifname, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ &netType );
+ FPrintF( stdout, "%s (%s)",
+ ( netType == kNetTransportType_Ethernet ) ? "ethernet" : NetTransportTypeToString( netType ),
+ ifname );
+ }
+ else
+ {
+ FPrintF( stdout, "interface index %u", instance->ifIndex );
+ }
+ FPrintF( stdout, "\n\n" );
+
+ if( instance->hostname )
+ {
+ char buffer[ 256 ];
+
+ SNPrintF( buffer, sizeof( buffer ), "%s:%u", instance->hostname, instance->port );
+ FPrintF( stdout, "%*s" "%-51s %4llu ms\n", Indent( 3 ), buffer,
+ UpTicksToMilliseconds( instance->resolveDoneTicks - instance->resolveStartTicks ) );
+ }
+ else
+ {
+ FPrintF( stdout, "%*s" "%s:%u\n", Indent( 3 ), instance->hostname, instance->port );
+ }
+
+ for( addr = instance->addrList; addr; addr = addr->next )
+ {
+ AsyncConnection_Forget( &addr->connection );
+
+ if( addr->connectStatus == kConnectStatus_Pending )
+ {
+ addr->connectStatus = kConnectStatus_Failed;
+ addr->connectError = kTimeoutErr;
+ }
+
+ FPrintF( stdout, "%*s" "%-##47a %4llu ms (", Indent( 4 ),
+ &addr->sip.sa, UpTicksToMilliseconds( addr->foundTicks - instance->getAddrStartTicks ) );
+ switch( addr->connectStatus )
+ {
+ case kConnectStatus_None:
+ FPrintF( stdout, "%s", kStatusStr_NoConnectionAttempted );
+ break;
+
+ case kConnectStatus_Succeeded:
+ FPrintF( stdout, "%s in %.2f ms",
+ context->useColoredText ? kStatusStr_CouldConnectColored : kStatusStr_CouldConnect,
+ addr->connectTimeSecs * 1000 );
+ break;
+
+ case kConnectStatus_Failed:
+ FPrintF( stdout, "%s: %m",
+ context->useColoredText ? kStatusStr_CouldNotConnectColored : kStatusStr_CouldNotConnect,
+ addr->connectError );
+ break;
+
+ default:
+ FPrintF( stdout, "%s", kStatusStr_Unknown );
+ break;
+ }
+ FPrintF( stdout, ")\n" );
+ }
+
+ FPrintF( stdout, "\n" );
+ if( instance->txtLen == 0 ) continue;
+
+ FPrintF( stdout, "%*s" "TXT record:\n", Indent( 3 ) );
+ if( instance->txtLen > 1 )
+ {
+ FPrintF( stdout, "%3{txt}", instance->txtPtr, instance->txtLen );
+ }
+ else
+ {
+ FPrintF( stdout, "%*s" "%#H\n", Indent( 3 ), instance->txtPtr, (int) instance->txtLen, INT_MAX );
+ }
+ FPrintF( stdout, "\n" );
+ }
+ }
+ FPrintF( stdout, "\n" );
+ }
+ }
+
+ while( ( domain = context->domainList ) != NULL )
+ {
+ context->domainList = domain->next;
+ BrowseDomainFree( domain );
+ }
+
+ BrowseAllContextRelease( context );
+ Exit( NULL );
+}
+
+//===========================================================================================================================
+// BrowseAllAddDomain
+//===========================================================================================================================
+
+static OSStatus BrowseAllAddDomain( BrowseAllContext *inContext, const char *inName )
+{
+ OSStatus err;
+ BrowseDomain * domain;
+ BrowseDomain ** p;
+ BrowseDomain * newDomain = NULL;
+
+ for( p = &inContext->domainList; ( domain = *p ) != NULL; p = &domain->next )
+ {
+ if( strcasecmp( domain->name, inName ) == 0 ) break;
+ }
+ require_action_quiet( !domain, exit, err = kDuplicateErr );
+
+ newDomain = (BrowseDomain *) calloc( 1, sizeof( *newDomain ) );
+ require_action( newDomain, exit, err = kNoMemoryErr );
+
+ ++inContext->refCount;
+ newDomain->context = inContext;
+
+ newDomain->name = strdup( inName );
+ require_action( newDomain->name, exit, err = kNoMemoryErr );
+
+ if( inContext->serviceTypesCount > 0 )
+ {
+ size_t i;
+
+ for( i = 0; i < inContext->serviceTypesCount; ++i )
+ {
+ err = BrowseAllAddServiceType( inContext, newDomain, inContext->serviceTypes[ i ], inContext->ifIndex,
+ inContext->includeAWDL );
+ if( err == kDuplicateErr ) err = kNoErr;
+ require_noerr( err, exit );
+ }
+ }
+ else
+ {
+ char * recordName;
+ DNSServiceFlags flags;
+ DNSServiceRef sdRef;
+
+ ASPrintF( &recordName, "_services._dns-sd._udp.%s", newDomain->name );
+ require_action( recordName, exit, err = kNoMemoryErr );
+
+ flags = kDNSServiceFlagsShareConnection;
+ if( inContext->includeAWDL ) flags |= kDNSServiceFlagsIncludeAWDL;
+
+ sdRef = newDomain->context->mainRef;
+ err = DNSServiceQueryRecord( &sdRef, flags, inContext->ifIndex, recordName, kDNSServiceType_PTR, kDNSServiceClass_IN,
+ BrowseAllQueryCallback, newDomain );
+ free( recordName );
+ require_noerr( err, exit );
+
+ newDomain->servicesQuery = sdRef;
+ }
+
+ *p = newDomain;
+ newDomain = NULL;
+ err = kNoErr;
+
+exit:
+ if( newDomain ) BrowseDomainFree( newDomain );
+ return( err );
+}
+
+//===========================================================================================================================
+// BrowseAllRemoveDomain
+//===========================================================================================================================
+
+static OSStatus BrowseAllRemoveDomain( BrowseAllContext *inContext, const char *inName )
+{
+ OSStatus err;
+ BrowseDomain * domain;
+ BrowseDomain ** p;
+
+ for( p = &inContext->domainList; ( domain = *p ) != NULL; p = &domain->next )
+ {
+ if( strcasecmp( domain->name, inName ) == 0 ) break;
+ }
+
+ if( domain )
+ {
+ *p = domain->next;
+ BrowseDomainFree( domain );
+ err = kNoErr;
+ }
+ else
+ {
+ err = kNotFoundErr;
+ }
+
+ return( err );
+}
+
+//===========================================================================================================================
+// BrowseAllContextRelease
+//===========================================================================================================================
+
+static void BrowseAllContextRelease( BrowseAllContext *inContext )
+{
+ if( --inContext->refCount == 0 )
+ {
+ check( !inContext->domainsQuery );
+ check( !inContext->domainList );
+ check( !inContext->exitTimer );
+ check( !inContext->pendingConnectCount );
+ DNSServiceForget( &inContext->mainRef );
+ if( inContext->serviceTypes )
+ {
+ StringArray_Free( inContext->serviceTypes, inContext->serviceTypesCount );
+ inContext->serviceTypes = NULL;
+ inContext->serviceTypesCount = 0;
+ }
+ free( inContext );
+ }
+}
+
+//===========================================================================================================================
+// BrowseAllAddServiceType
+//===========================================================================================================================
+
+static OSStatus
+ BrowseAllAddServiceType(
+ BrowseAllContext * inContext,
+ BrowseDomain * inDomain,
+ const char * inName,
+ uint32_t inIfIndex,
+ Boolean inIncludeAWDL )
+{
+ OSStatus err;
+ DNSServiceRef sdRef;
+ DNSServiceFlags flags;
+ BrowseType * type;
+ BrowseType ** typePtr;
+ BrowseType * newType = NULL;
+ BrowseOp * browse;
+ BrowseOp ** browsePtr;
+ BrowseOp * newBrowse = NULL;
+
+ for( typePtr = &inDomain->typeList; ( type = *typePtr ) != NULL; typePtr = &type->next )
+ {
+ if( strcasecmp( type->name, inName ) == 0 ) break;
+ }
+ if( !type )
+ {
+ newType = (BrowseType *) calloc( 1, sizeof( *newType ) );
+ require_action( newType, exit, err = kNoMemoryErr );
+
+ newType->name = strdup( inName );
+ require_action( newType->name, exit, err = kNoMemoryErr );
+
+ type = newType;
+ }
+
+ for( browsePtr = &type->browseList; ( browse = *browsePtr ) != NULL; browsePtr = &browse->next )
+ {
+ if( browse->ifIndex == inIfIndex ) break;
+ }
+ require_action_quiet( !browse, exit, err = kDuplicateErr );
+
+ newBrowse = (BrowseOp *) calloc( 1, sizeof( *newBrowse ) );
+ require_action( newBrowse, exit, err = kNoMemoryErr );
+
+ ++inContext->refCount;
+ newBrowse->context = inContext;
+ newBrowse->ifIndex = inIfIndex;
+ if( stricmp_suffix( inName, "._tcp" ) == 0 ) newBrowse->isTCP = true;
+
+ flags = kDNSServiceFlagsShareConnection;
+ if( inIncludeAWDL ) flags |= kDNSServiceFlagsIncludeAWDL;
+
+ newBrowse->startTicks = UpTicks();
+
+ sdRef = inContext->mainRef;
+ err = DNSServiceBrowse( &sdRef, flags, newBrowse->ifIndex, type->name, inDomain->name, BrowseAllBrowseCallback,
+ newBrowse );
+ require_noerr( err, exit );
+
+ newBrowse->browse = sdRef;
+ *browsePtr = newBrowse;
+ newBrowse = NULL;
+
+ if( newType )
+ {
+ *typePtr = newType;
+ newType = NULL;
+ }
+
+exit:
+ if( newBrowse ) BrowseOpFree( newBrowse );
+ if( newType ) BrowseTypeFree( newType );
+ return( err );
+}
+
+//===========================================================================================================================
+// BrowseAllRemoveServiceType
+//===========================================================================================================================
+
+static OSStatus
+ BrowseAllRemoveServiceType(
+ BrowseAllContext * inContext,
+ BrowseDomain * inDomain,
+ const char * inName,
+ uint32_t inIfIndex )
+{
+ OSStatus err;
+ BrowseType * type;
+ BrowseType ** typePtr;
+ BrowseOp * browse;
+ BrowseOp ** browsePtr;
+
+ Unused( inContext );
+
+ for( typePtr = &inDomain->typeList; ( type = *typePtr ) != NULL; typePtr = &type->next )
+ {
+ if( strcasecmp( type->name, inName ) == 0 ) break;
+ }
+ require_action_quiet( type, exit, err = kNotFoundErr );
+
+ for( browsePtr = &type->browseList; ( browse = *browsePtr ) != NULL; browsePtr = &browse->next )
+ {
+ if( browse->ifIndex == inIfIndex ) break;
+ }
+ require_action_quiet( browse, exit, err = kNotFoundErr );
+
+ *browsePtr = browse->next;
+ BrowseOpFree( browse );
+ if( !type->browseList )
+ {
+ *typePtr = type->next;
+ BrowseTypeFree( type );
+ }
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// BrowseAllAddServiceInstance
+//===========================================================================================================================
+
+static OSStatus
+ BrowseAllAddServiceInstance(
+ BrowseAllContext * inContext,
+ BrowseOp * inBrowse,
+ const char * inName,
+ const char * inRegType,
+ const char * inDomain,
+ uint32_t inIfIndex )
+{
+ OSStatus err;
+ DNSServiceRef sdRef;
+ BrowseInstance * instance;
+ BrowseInstance ** p;
+ const uint64_t nowTicks = UpTicks();
+ BrowseInstance * newInstance = NULL;
+
+ for( p = &inBrowse->instanceList; ( instance = *p ) != NULL; p = &instance->next )
+ {
+ if( ( instance->ifIndex == inIfIndex ) && ( strcasecmp( instance->name, inName ) == 0 ) ) break;
+ }
+ require_action_quiet( !instance, exit, err = kDuplicateErr );
+
+ newInstance = (BrowseInstance *) calloc( 1, sizeof( *newInstance ) );
+ require_action( newInstance, exit, err = kNoMemoryErr );
+
+ ++inContext->refCount;
+ newInstance->context = inContext;
+ newInstance->foundTicks = nowTicks;
+ newInstance->ifIndex = inIfIndex;
+ newInstance->isTCP = inBrowse->isTCP;
+
+ newInstance->name = strdup( inName );
+ require_action( newInstance->name, exit, err = kNoMemoryErr );
+
+ sdRef = inContext->mainRef;
+ newInstance->resolveStartTicks = UpTicks();
+ err = DNSServiceResolve( &sdRef, kDNSServiceFlagsShareConnection, newInstance->ifIndex, inName, inRegType, inDomain,
+ BrowseAllResolveCallback, newInstance );
+ require_noerr( err, exit );
+
+ newInstance->resolve = sdRef;
+ *p = newInstance;
+ newInstance = NULL;
+
+exit:
+ if( newInstance ) BrowseInstanceFree( newInstance );
+ return( err );
+}
+
+//===========================================================================================================================
+// BrowseAllRemoveServiceInstance
+//===========================================================================================================================
+
+static OSStatus
+ BrowseAllRemoveServiceInstance(
+ BrowseAllContext * inContext,
+ BrowseOp * inBrowse,
+ const char * inName,
+ uint32_t inIfIndex )
+{
+ OSStatus err;
+ BrowseInstance * instance;
+ BrowseInstance ** p;
+
+ Unused( inContext );
+
+ for( p = &inBrowse->instanceList; ( instance = *p ) != NULL; p = &instance->next )
+ {
+ if( ( instance->ifIndex == inIfIndex ) && ( strcasecmp( instance->name, inName ) == 0 ) ) break;
+ }
+ require_action_quiet( instance, exit, err = kNotFoundErr );
+
+ *p = instance->next;
+ BrowseInstanceFree( instance );
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// BrowseAllAddIPAddress
+//===========================================================================================================================
+
+#define kDiscardProtocolPort 9
+
+static OSStatus
+ BrowseAllAddIPAddress(
+ BrowseAllContext * inContext,
+ BrowseInstance * inInstance,
+ const struct sockaddr * inSockAddr )
+{
+ OSStatus err;
+ BrowseIPAddr * addr;
+ BrowseIPAddr ** p;
+ const uint64_t nowTicks = UpTicks();
+ BrowseIPAddr * newAddr = NULL;
+
+ if( ( inSockAddr->sa_family != AF_INET ) && ( inSockAddr->sa_family != AF_INET6 ) )
+ {
+ dlogassert( "Unexpected address family: %d", inSockAddr->sa_family );
+ err = kTypeErr;
+ goto exit;
+ }
+
+ for( p = &inInstance->addrList; ( addr = *p ) != NULL; p = &addr->next )
+ {
+ if( SockAddrCompareAddr( &addr->sip, inSockAddr ) == 0 ) break;
+ }
+ require_action_quiet( !addr, exit, err = kDuplicateErr );
+
+ newAddr = (BrowseIPAddr *) calloc( 1, sizeof( *newAddr ) );
+ require_action( newAddr, exit, err = kNoMemoryErr );
+
+ ++inContext->refCount;
+ newAddr->refCount = 1;
+ newAddr->context = inContext;
+ newAddr->foundTicks = nowTicks;
+ SockAddrCopy( inSockAddr, &newAddr->sip.sa );
+
+ if( inInstance->isTCP && ( inInstance->port != kDiscardProtocolPort ) )
+ {
+ char destination[ kSockAddrStringMaxSize ];
+
+ err = SockAddrToString( &newAddr->sip, kSockAddrStringFlagsNoPort, destination );
+ require_noerr( err, exit );
+
+ err = AsyncConnection_Connect( &newAddr->connection, destination, -inInstance->port, kAsyncConnectionFlag_P2P,
+ kAsyncConnectionNoTimeout, kSocketBufferSize_DontSet, kSocketBufferSize_DontSet,
+ BrowseAllConnectionProgress, newAddr, BrowseAllConnectionHandler, newAddr, dispatch_get_main_queue() );
+ require_noerr( err, exit );
+
+ ++newAddr->refCount;
+ newAddr->connectStatus = kConnectStatus_Pending;
+ ++inContext->pendingConnectCount;
+ }
+
+ *p = newAddr;
+ newAddr = NULL;
+ err = kNoErr;
+
+exit:
+ if( newAddr ) BrowseIPAddrRelease( newAddr );
+ return( err );
+}
+
+//===========================================================================================================================
+// BrowseAllRemoveIPAddress
+//===========================================================================================================================
+
+static OSStatus
+ BrowseAllRemoveIPAddress(
+ BrowseAllContext * inContext,
+ BrowseInstance * inInstance,
+ const struct sockaddr * inSockAddr )
+{
+ OSStatus err;
+ BrowseIPAddr * addr;
+ BrowseIPAddr ** p;
+
+ Unused( inContext );
+
+ for( p = &inInstance->addrList; ( addr = *p ) != NULL; p = &addr->next )
+ {
+ if( SockAddrCompareAddr( &addr->sip.sa, inSockAddr ) == 0 ) break;
+ }
+ require_action_quiet( addr, exit, err = kNotFoundErr );
+
+ *p = addr->next;
+ BrowseIPAddrRelease( addr );
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// BrowseDomainFree
+//===========================================================================================================================
+
+static void BrowseDomainFree( BrowseDomain *inDomain )
+{
+ BrowseType * type;
+
+ ForgetBrowseAllContext( &inDomain->context );
+ ForgetMem( &inDomain->name );
+ DNSServiceForget( &inDomain->servicesQuery );
+ while( ( type = inDomain->typeList ) != NULL )
+ {
+ inDomain->typeList = type->next;
+ BrowseTypeFree( type );
+ }
+ free( inDomain );
+}
+
+//===========================================================================================================================
+// BrowseTypeFree
+//===========================================================================================================================
+
+static void BrowseTypeFree( BrowseType *inType )
+{
+ BrowseOp * browse;
+
+ ForgetMem( &inType->name );
+ while( ( browse = inType->browseList ) != NULL )
+ {
+ inType->browseList = browse->next;
+ BrowseOpFree( browse );
+ }
+ free( inType );
+}
+
+//===========================================================================================================================
+// BrowseOpFree
+//===========================================================================================================================
+
+static void BrowseOpFree( BrowseOp *inBrowse )
+{
+ BrowseInstance * instance;
+
+ ForgetBrowseAllContext( &inBrowse->context );
+ DNSServiceForget( &inBrowse->browse );
+ while( ( instance = inBrowse->instanceList ) != NULL )
+ {
+ inBrowse->instanceList = instance->next;
+ BrowseInstanceFree( instance );
+ }
+ free( inBrowse );
+}
+
+//===========================================================================================================================
+// BrowseInstanceFree
+//===========================================================================================================================
+
+static void BrowseInstanceFree( BrowseInstance *inInstance )
+{
+ ForgetBrowseAllContext( &inInstance->context );
+ ForgetMem( &inInstance->name );
+ DNSServiceForget( &inInstance->resolve );
+ DNSServiceForget( &inInstance->getAddr );
+ ForgetMem( &inInstance->txtPtr );
+ ForgetMem( &inInstance->hostname );
+ ForgetIPAddressList( &inInstance->addrList );
+ free( inInstance );
+}
+
+//===========================================================================================================================
+// BrowseIPAddrRelease
+//===========================================================================================================================
+
+static void BrowseIPAddrRelease( BrowseIPAddr *inAddr )
+{
+ AsyncConnection_Forget( &inAddr->connection );
+ if( --inAddr->refCount == 0 )
+ {
+ ForgetBrowseAllContext( &inAddr->context );
+ free( inAddr );
+ }
+}
+
+//===========================================================================================================================
+// BrowseIPAddrReleaseList
+//===========================================================================================================================
+
+static void BrowseIPAddrReleaseList( BrowseIPAddr *inList )
+{
+ BrowseIPAddr * addr;
+
+ while( ( addr = inList ) != NULL )
+ {
+ inList = addr->next;
+ BrowseIPAddrRelease( addr );
+ }
+}
+
+//===========================================================================================================================
+// GetAddrInfoStressCmd
+//===========================================================================================================================
+
+typedef struct
+{
+ DNSServiceRef mainRef;
+ DNSServiceRef sdRef;
+ DNSServiceFlags flags;
+ unsigned int interfaceIndex;
+ unsigned int connectionNumber;
+ unsigned int requestCount;
+ unsigned int requestCountMax;
+ unsigned int requestCountLimit;
+ unsigned int durationMinMs;
+ unsigned int durationMaxMs;
+
+} GAIStressContext;
+
+static void GetAddrInfoStressEvent( void *inContext );
+static void DNSSD_API
+ GetAddrInfoStressCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inHostname,
+ const struct sockaddr * inSockAddr,
+ uint32_t inTTL,
+ void * inContext );
+
+static void GetAddrInfoStressCmd( void )
+{
+ OSStatus err;
+ GAIStressContext * context = NULL;
+ int i;
+ DNSServiceFlags flags;
+ uint32_t ifIndex;
+ char ifName[ kInterfaceNameBufLen ];
+ char time[ kTimestampBufLen ];
+
+ if( gGAIStress_TestDurationSecs < 0 )
+ {
+ FPrintF( stdout, "Invalid test duration: %d s.\n", gGAIStress_TestDurationSecs );
+ err = kParamErr;
+ goto exit;
+ }
+ if( gGAIStress_ConnectionCount <= 0 )
+ {
+ FPrintF( stdout, "Invalid simultaneous connection count: %d.\n", gGAIStress_ConnectionCount );
+ err = kParamErr;
+ goto exit;
+ }
+ if( gGAIStress_DurationMinMs <= 0 )
+ {
+ FPrintF( stdout, "Invalid minimum DNSServiceGetAddrInfo() duration: %d ms.\n", gGAIStress_DurationMinMs );
+ err = kParamErr;
+ goto exit;
+ }
+ if( gGAIStress_DurationMaxMs <= 0 )
+ {
+ FPrintF( stdout, "Invalid maximum DNSServiceGetAddrInfo() duration: %d ms.\n", gGAIStress_DurationMaxMs );
+ err = kParamErr;
+ goto exit;
+ }
+ if( gGAIStress_DurationMinMs > gGAIStress_DurationMaxMs )
+ {
+ FPrintF( stdout, "Invalid minimum and maximum DNSServiceGetAddrInfo() durations: %d ms and %d ms.\n",
+ gGAIStress_DurationMinMs, gGAIStress_DurationMaxMs );
+ err = kParamErr;
+ goto exit;
+ }
+ if( gGAIStress_RequestCountMax <= 0 )
+ {
+ FPrintF( stdout, "Invalid maximum request count: %d.\n", gGAIStress_RequestCountMax );
+ err = kParamErr;
+ goto exit;
+ }
+
+ // Set flags.
+
+ flags = GetDNSSDFlagsFromOpts();
+
+ // Set interface index.
+
+ err = InterfaceIndexFromArgString( gInterface, &ifIndex );
+ require_noerr_quiet( err, exit );
+
+ for( i = 0; i < gGAIStress_ConnectionCount; ++i )
+ {
+ context = (GAIStressContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ context->flags = flags;
+ context->interfaceIndex = ifIndex;
+ context->connectionNumber = (unsigned int)( i + 1 );
+ context->requestCountMax = (unsigned int) gGAIStress_RequestCountMax;
+ context->durationMinMs = (unsigned int) gGAIStress_DurationMinMs;
+ context->durationMaxMs = (unsigned int) gGAIStress_DurationMaxMs;
+
+ dispatch_async_f( dispatch_get_main_queue(), context, GetAddrInfoStressEvent );
+ context = NULL;
+ }
+
+ if( gGAIStress_TestDurationSecs > 0 )
+ {
+ dispatch_after_f( dispatch_time_seconds( gGAIStress_TestDurationSecs ), dispatch_get_main_queue(), NULL, Exit );
+ }
+
+ FPrintF( stdout, "Flags: %#{flags}\n", flags, kDNSServiceFlagsDescriptors );
+ FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) ifIndex, InterfaceIndexToName( ifIndex, ifName ) );
+ FPrintF( stdout, "Test duration: " );
+ if( gGAIStress_TestDurationSecs == 0 )
+ {
+ FPrintF( stdout, "∞\n" );
+ }
+ else
+ {
+ FPrintF( stdout, "%d s\n", gGAIStress_TestDurationSecs );
+ }
+ FPrintF( stdout, "Connection count: %d\n", gGAIStress_ConnectionCount );
+ FPrintF( stdout, "Request duration min: %d ms\n", gGAIStress_DurationMinMs );
+ FPrintF( stdout, "Request duration max: %d ms\n", gGAIStress_DurationMaxMs );
+ FPrintF( stdout, "Request count max: %d\n", gGAIStress_RequestCountMax );
+ FPrintF( stdout, "Start time: %s\n", GetTimestampStr( time ) );
+ FPrintF( stdout, "---\n" );
+
+ dispatch_main();
+
+exit:
+ FreeNullSafe( context );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// GetAddrInfoStressEvent
+//===========================================================================================================================
+
+#define kStressRandStrLen 5
+
+#define kLowercaseAlphaCharSet "abcdefghijklmnopqrstuvwxyz"
+
+static void GetAddrInfoStressEvent( void *inContext )
+{
+ GAIStressContext * const context = (GAIStressContext *) inContext;
+ OSStatus err;
+ DNSServiceRef sdRef;
+ unsigned int nextMs;
+ char randomStr[ kStressRandStrLen + 1 ];
+ char hostname[ kStressRandStrLen + 4 + 1 ];
+ char time[ kTimestampBufLen ];
+ Boolean isConnectionNew = false;
+ static Boolean printedHeader = false;
+
+ if( !context->mainRef || ( context->requestCount >= context->requestCountLimit ) )
+ {
+ DNSServiceForget( &context->mainRef );
+ context->sdRef = NULL;
+ context->requestCount = 0;
+ context->requestCountLimit = RandomRange( 1, context->requestCountMax );
+
+ err = DNSServiceCreateConnection( &context->mainRef );
+ require_noerr( err, exit );
+
+ err = DNSServiceSetDispatchQueue( context->mainRef, dispatch_get_main_queue() );
+ require_noerr( err, exit );
+
+ isConnectionNew = true;
+ }
+
+ RandomString( kLowercaseAlphaCharSet, sizeof_string( kLowercaseAlphaCharSet ), 2, kStressRandStrLen, randomStr );
+ SNPrintF( hostname, sizeof( hostname ), "%s.com", randomStr );
+
+ nextMs = RandomRange( context->durationMinMs, context->durationMaxMs );
+
+ if( !printedHeader )
+ {
+ FPrintF( stdout, "%-26s Conn Hostname Dur (ms)\n", "Timestamp" );
+ printedHeader = true;
+ }
+ FPrintF( stdout, "%-26s %3u%c %9s %8u\n",
+ GetTimestampStr( time ), context->connectionNumber, isConnectionNew ? '*': ' ', hostname, nextMs );
+
+ DNSServiceForget( &context->sdRef );
+ sdRef = context->mainRef;
+ err = DNSServiceGetAddrInfo( &sdRef, context->flags | kDNSServiceFlagsShareConnection, context->interfaceIndex,
+ kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6, hostname, GetAddrInfoStressCallback, NULL );
+ require_noerr( err, exit );
+ context->sdRef = sdRef;
+
+ context->requestCount++;
+
+ dispatch_after_f( dispatch_time_milliseconds( nextMs ), dispatch_get_main_queue(), context, GetAddrInfoStressEvent );
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// GetAddrInfoStressCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ GetAddrInfoStressCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inHostname,
+ const struct sockaddr * inSockAddr,
+ uint32_t inTTL,
+ void * inContext )
+{
+ Unused( inSDRef );
+ Unused( inFlags );
+ Unused( inInterfaceIndex );
+ Unused( inError );
+ Unused( inHostname );
+ Unused( inSockAddr );
+ Unused( inTTL );
+ Unused( inContext );
+}
+
+//===========================================================================================================================
+// DNSQueryCmd
+//===========================================================================================================================
+
+#define kDNSPort 53
+
+typedef struct
+{
+ sockaddr_ip serverAddr;
+ uint64_t sendTicks;
+ uint8_t * msgPtr;
+ size_t msgLen;
+ size_t msgOffset;
+ const char * name;
+ dispatch_source_t readSource;
+ SocketRef sock;
+ int timeLimitSecs;
+ uint16_t queryID;
+ uint16_t type;
+ Boolean haveTCPLen;
+ Boolean useTCP;
+ Boolean printRawRData; // True if RDATA results are not to be formatted.
+ uint8_t msgBuf[ 512 ];
+
+} DNSQueryContext;
+
+static void DNSQueryPrintPrologue( const DNSQueryContext *inContext );
+static void DNSQueryReadHandler( void *inContext );
+static void DNSQueryCancelHandler( void *inContext );
+
+static void DNSQueryCmd( void )
+{
+ OSStatus err;
+ DNSQueryContext * context = NULL;
+ uint8_t * msgPtr;
+ size_t msgLen, sendLen;
+
+ // Check command parameters.
+
+ if( gDNSQuery_TimeLimitSecs < -1 )
+ {
+ FPrintF( stdout, "Invalid wait period: %d seconds.\n", gDNSQuery_TimeLimitSecs );
+ err = kParamErr;
+ goto exit;
+ }
+ if( ( gDNSQuery_Flags < INT16_MIN ) || ( gDNSQuery_Flags > UINT16_MAX ) )
+ {
+ FPrintF( stdout, "DNS flags-and-codes value is out of the unsigned 16-bit range: 0x%08X.\n", gDNSQuery_Flags );
+ err = kParamErr;
+ goto exit;
+ }
+
+ // Create context.
+
+ context = (DNSQueryContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ context->name = gDNSQuery_Name;
+ context->sock = kInvalidSocketRef;
+ context->timeLimitSecs = gDNSQuery_TimeLimitSecs;
+ context->queryID = (uint16_t) Random32();
+ context->useTCP = gDNSQuery_UseTCP ? true : false;
+ context->printRawRData = gDNSQuery_RawRData ? true : false;
+
+ err = StringToSockAddr( gDNSQuery_Server, &context->serverAddr, sizeof( context->serverAddr ), NULL );
+ require_noerr( err, exit );
+ if( SockAddrGetPort( &context->serverAddr ) == 0 ) SockAddrSetPort( &context->serverAddr, kDNSPort );
+
+ err = RecordTypeFromArgString( gDNSQuery_Type, &context->type );
+ require_noerr( err, exit );
+
+ // Write query message.
+
+ check_compile_time_code( sizeof( context->msgBuf ) >= ( kDNSQueryMessageMaxLen + 2 ) );
+
+ msgPtr = context->useTCP ? &context->msgBuf[ 2 ] : context->msgBuf;
+ err = WriteDNSQueryMessage( msgPtr, context->queryID, (uint16_t) gDNSQuery_Flags, context->name, context->type,
+ kDNSServiceClass_IN, &msgLen );
+ require_noerr( err, exit );
+ check( msgLen <= UINT16_MAX );
+
+ if( context->useTCP )
+ {
+ WriteBig16( context->msgBuf, msgLen );
+ sendLen = 2 + msgLen;
+ }
+ else
+ {
+ sendLen = msgLen;
+ }
+
+ DNSQueryPrintPrologue( context );
+
+ if( gDNSQuery_Verbose )
+ {
+ FPrintF( stdout, "DNS message to send:\n\n" );
+ PrintUDNSMessage( msgPtr, msgLen, false );
+ FPrintF( stdout, "---\n" );
+ }
+
+ if( context->useTCP )
+ {
+ // Create TCP socket.
+
+ context->sock = socket( context->serverAddr.sa.sa_family, SOCK_STREAM, IPPROTO_TCP );
+ err = map_socket_creation_errno( context->sock );
+ require_noerr( err, exit );
+
+ err = SocketConnect( context->sock, &context->serverAddr, 5 );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ // Create UDP socket.
+
+ err = UDPClientSocketOpen( AF_UNSPEC, &context->serverAddr, 0, -1, NULL, &context->sock );
+ require_noerr( err, exit );
+ }
+
+ context->sendTicks = UpTicks();
+ err = SocketWriteAll( context->sock, context->msgBuf, sendLen, 5 );
+ require_noerr( err, exit );
+
+ if( context->timeLimitSecs == 0 ) goto exit;
+
+ err = DispatchReadSourceCreate( context->sock, DNSQueryReadHandler, DNSQueryCancelHandler, context,
+ &context->readSource );
+ require_noerr( err, exit );
+ dispatch_resume( context->readSource );
+
+ if( context->timeLimitSecs > 0 )
+ {
+ dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(), kExitReason_Timeout,
+ Exit );
+ }
+ dispatch_main();
+
+exit:
+ if( context )
+ {
+ dispatch_source_forget( &context->readSource );
+ ForgetSocket( &context->sock );
+ free( context );
+ }
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// DNSQueryPrintPrologue
+//===========================================================================================================================
+
+static void DNSQueryPrintPrologue( const DNSQueryContext *inContext )
+{
+ const int timeLimitSecs = inContext->timeLimitSecs;
+ char time[ kTimestampBufLen ];
+
+ FPrintF( stdout, "Name: %s\n", inContext->name );
+ FPrintF( stdout, "Type: %s (%u)\n", RecordTypeToString( inContext->type ), inContext->type );
+ FPrintF( stdout, "Server: %##a\n", &inContext->serverAddr );
+ FPrintF( stdout, "Transport: %s\n", inContext->useTCP ? "TCP" : "UDP" );
+ FPrintF( stdout, "Time limit: " );
+ if( timeLimitSecs >= 0 ) FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
+ else FPrintF( stdout, "∞\n" );
+ FPrintF( stdout, "Start time: %s\n", GetTimestampStr( time ) );
+ FPrintF( stdout, "---\n" );
+}
+
+//===========================================================================================================================
+// DNSQueryReadHandler
+//===========================================================================================================================
+
+static void DNSQueryReadHandler( void *inContext )
+{
+ OSStatus err;
+ const uint64_t nowTicks = UpTicks();
+ DNSQueryContext * const context = (DNSQueryContext *) inContext;
+ char time[ kTimestampBufLen ];
+
+ GetTimestampStr( time );
+
+ if( context->useTCP )
+ {
+ if( !context->haveTCPLen )
+ {
+ err = SocketReadData( context->sock, &context->msgBuf, 2, &context->msgOffset );
+ if( err == EWOULDBLOCK ) { err = kNoErr; goto exit; }
+ require_noerr( err, exit );
+
+ context->msgOffset = 0;
+ context->msgLen = ReadBig16( context->msgBuf );
+ context->haveTCPLen = true;
+ if( context->msgLen <= sizeof( context->msgBuf ) )
+ {
+ context->msgPtr = context->msgBuf;
+ }
+ else
+ {
+ context->msgPtr = (uint8_t *) malloc( context->msgLen );
+ require_action( context->msgPtr, exit, err = kNoMemoryErr );
+ }
+ }
+
+ err = SocketReadData( context->sock, context->msgPtr, context->msgLen, &context->msgOffset );
+ if( err == EWOULDBLOCK ) { err = kNoErr; goto exit; }
+ require_noerr( err, exit );
+ context->msgOffset = 0;
+ context->haveTCPLen = false;
+ }
+ else
+ {
+ sockaddr_ip fromAddr;
+
+ context->msgPtr = context->msgBuf;
+ err = SocketRecvFrom( context->sock, context->msgPtr, sizeof( context->msgBuf ), &context->msgLen, &fromAddr,
+ sizeof( fromAddr ), NULL, NULL, NULL, NULL );
+ require_noerr( err, exit );
+
+ check( SockAddrCompareAddr( &fromAddr, &context->serverAddr ) == 0 );
+ }
+
+ FPrintF( stdout, "Receive time: %s\n", time );
+ FPrintF( stdout, "Source: %##a\n", &context->serverAddr );
+ FPrintF( stdout, "Message size: %zu\n", context->msgLen );
+ FPrintF( stdout, "RTT: %llu ms\n\n", UpTicksToMilliseconds( nowTicks - context->sendTicks ) );
+ PrintUDNSMessage( context->msgPtr, context->msgLen, context->printRawRData );
+
+ if( ( context->msgLen >= kDNSHeaderLength ) && ( DNSHeaderGetID( (DNSHeader *) context->msgPtr ) == context->queryID ) )
+ {
+ Exit( kExitReason_ReceivedResponse );
+ }
+
+exit:
+ if( err ) dispatch_source_forget( &context->readSource );
+}
+
+//===========================================================================================================================
+// DNSQueryCancelHandler
+//===========================================================================================================================
+
+static void DNSQueryCancelHandler( void *inContext )
+{
+ DNSQueryContext * const context = (DNSQueryContext *) inContext;
+
+ check( !context->readSource );
+ ForgetSocket( &context->sock );
+ if( context->msgPtr != context->msgBuf ) ForgetMem( &context->msgPtr );
+ free( context );
+ dispatch_async_f( dispatch_get_main_queue(), NULL, Exit );
+}
+
+#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
+//===========================================================================================================================
+// DNSCryptCmd
+//===========================================================================================================================
+
+#define kDNSCryptPort 443
+
+#define kDNSCryptMinPadLength 8
+#define kDNSCryptMaxPadLength 256
+#define kDNSCryptBlockSize 64
+#define kDNSCryptCertMinimumLength 124
+#define kDNSCryptClientMagicLength 8
+#define kDNSCryptResolverMagicLength 8
+#define kDNSCryptHalfNonceLength 12
+#define kDNSCryptCertMagicLength 4
+
+check_compile_time( ( kDNSCryptHalfNonceLength * 2 ) == crypto_box_NONCEBYTES );
+
+static const uint8_t kDNSCryptCertMagic[ kDNSCryptCertMagicLength ] = { 'D', 'N', 'S', 'C' };
+static const uint8_t kDNSCryptResolverMagic[ kDNSCryptResolverMagicLength ] =
+{
+ 0x72, 0x36, 0x66, 0x6e, 0x76, 0x57, 0x6a, 0x38
+};
+
+typedef struct
+{
+ uint8_t certMagic[ kDNSCryptCertMagicLength ];
+ uint8_t esVersion[ 2 ];
+ uint8_t minorVersion[ 2 ];
+ uint8_t signature[ crypto_sign_BYTES ];
+ uint8_t publicKey[ crypto_box_PUBLICKEYBYTES ];
+ uint8_t clientMagic[ kDNSCryptClientMagicLength ];
+ uint8_t serial[ 4 ];
+ uint8_t startTime[ 4 ];
+ uint8_t endTime[ 4 ];
+ uint8_t extensions[ 1 ]; // Variably-sized extension data.
+
+} DNSCryptCert;
+
+check_compile_time( offsetof( DNSCryptCert, extensions ) == kDNSCryptCertMinimumLength );
+
+typedef struct
+{
+ uint8_t clientMagic[ kDNSCryptClientMagicLength ];
+ uint8_t clientPublicKey[ crypto_box_PUBLICKEYBYTES ];
+ uint8_t clientNonce[ kDNSCryptHalfNonceLength ];
+ uint8_t poly1305MAC[ 16 ];
+
+} DNSCryptQueryHeader;
+
+check_compile_time( sizeof( DNSCryptQueryHeader ) == 68 );
+check_compile_time( sizeof( DNSCryptQueryHeader ) >= crypto_box_ZEROBYTES );
+check_compile_time( ( sizeof( DNSCryptQueryHeader ) - crypto_box_ZEROBYTES + crypto_box_BOXZEROBYTES ) ==
+ offsetof( DNSCryptQueryHeader, poly1305MAC ) );
+
+typedef struct
+{
+ uint8_t resolverMagic[ kDNSCryptResolverMagicLength ];
+ uint8_t clientNonce[ kDNSCryptHalfNonceLength ];
+ uint8_t resolverNonce[ kDNSCryptHalfNonceLength ];
+ uint8_t poly1305MAC[ 16 ];
+
+} DNSCryptResponseHeader;
+
+check_compile_time( sizeof( DNSCryptResponseHeader ) == 48 );
+check_compile_time( offsetof( DNSCryptResponseHeader, poly1305MAC ) >= crypto_box_BOXZEROBYTES );
+check_compile_time( ( offsetof( DNSCryptResponseHeader, poly1305MAC ) - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES ) ==
+ sizeof( DNSCryptResponseHeader ) );
+
+typedef struct
+{
+ sockaddr_ip serverAddr;
+ uint64_t sendTicks;
+ const char * providerName;
+ const char * qname;
+ const uint8_t * certPtr;
+ size_t certLen;
+ dispatch_source_t readSource;
+ size_t msgLen;
+ int timeLimitSecs;
+ uint16_t queryID;
+ uint16_t qtype;
+ Boolean printRawRData;
+ uint8_t serverPublicSignKey[ crypto_sign_PUBLICKEYBYTES ];
+ uint8_t serverPublicKey[ crypto_box_PUBLICKEYBYTES ];
+ uint8_t clientPublicKey[ crypto_box_PUBLICKEYBYTES ];
+ uint8_t clientSecretKey[ crypto_box_SECRETKEYBYTES ];
+ uint8_t clientMagic[ kDNSCryptClientMagicLength ];
+ uint8_t clientNonce[ kDNSCryptHalfNonceLength ];
+ uint8_t nmKey[ crypto_box_BEFORENMBYTES ];
+ uint8_t msgBuf[ 512 ];
+
+} DNSCryptContext;
+
+static void DNSCryptReceiveCertHandler( void *inContext );
+static void DNSCryptReceiveResponseHandler( void *inContext );
+static void DNSCryptProceed( void *inContext );
+static OSStatus DNSCryptProcessCert( DNSCryptContext *inContext );
+static OSStatus DNSCryptBuildQuery( DNSCryptContext *inContext );
+static OSStatus DNSCryptSendQuery( DNSCryptContext *inContext );
+static void DNSCryptPrintCertificate( const DNSCryptCert *inCert, size_t inLen );
+
+static void DNSCryptCmd( void )
+{
+ OSStatus err;
+ DNSCryptContext * context = NULL;
+ size_t writtenBytes;
+ size_t totalBytes;
+ SocketContext * sockContext;
+ SocketRef sock = kInvalidSocketRef;
+ const char * ptr;
+
+ // Check command parameters.
+
+ if( gDNSQuery_TimeLimitSecs < -1 )
+ {
+ FPrintF( stdout, "Invalid wait period: %d seconds.\n", gDNSQuery_TimeLimitSecs );
+ err = kParamErr;
+ goto exit;
+ }
+
+ // Create context.
+
+ context = (DNSCryptContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ context->providerName = gDNSCrypt_ProviderName;
+ context->qname = gDNSCrypt_Name;
+ context->timeLimitSecs = gDNSCrypt_TimeLimitSecs;
+ context->printRawRData = gDNSCrypt_RawRData ? true : false;
+
+ err = crypto_box_keypair( context->clientPublicKey, context->clientSecretKey );
+ require_noerr( err, exit );
+
+ err = HexToData( gDNSCrypt_ProviderKey, kSizeCString, kHexToData_DefaultFlags,
+ context->serverPublicSignKey, sizeof( context->serverPublicSignKey ), &writtenBytes, &totalBytes, &ptr );
+ if( err || ( *ptr != '\0' ) )
+ {
+ FPrintF( stderr, "Failed to parse public signing key hex string (%s).\n", gDNSCrypt_ProviderKey );
+ goto exit;
+ }
+ else if( totalBytes != sizeof( context->serverPublicSignKey ) )
+ {
+ FPrintF( stderr, "Public signing key contains incorrect number of hex bytes (%zu != %zu)\n",
+ totalBytes, sizeof( context->serverPublicSignKey ) );
+ err = kSizeErr;
+ goto exit;
+ }
+ check( writtenBytes == totalBytes );
+
+ err = StringToSockAddr( gDNSCrypt_Server, &context->serverAddr, sizeof( context->serverAddr ), NULL );
+ require_noerr( err, exit );
+ if( SockAddrGetPort( &context->serverAddr ) == 0 ) SockAddrSetPort( &context->serverAddr, kDNSCryptPort );
+
+ err = RecordTypeFromArgString( gDNSCrypt_Type, &context->qtype );
+ require_noerr( err, exit );
+
+ // Write query message.
+
+ context->queryID = (uint16_t) Random32();
+ err = WriteDNSQueryMessage( context->msgBuf, context->queryID, kDNSHeaderFlag_RecursionDesired, context->providerName,
+ kDNSServiceType_TXT, kDNSServiceClass_IN, &context->msgLen );
+ require_noerr( err, exit );
+
+ // Create UDP socket.
+
+ err = UDPClientSocketOpen( AF_UNSPEC, &context->serverAddr, 0, -1, NULL, &sock );
+ require_noerr( err, exit );
+
+ // Send DNS query.
+
+ context->sendTicks = UpTicks();
+ err = SocketWriteAll( sock, context->msgBuf, context->msgLen, 5 );
+ require_noerr( err, exit );
+
+ sockContext = (SocketContext *) calloc( 1, sizeof( *sockContext ) );
+ require_action( sockContext, exit, err = kNoMemoryErr );
+
+ err = DispatchReadSourceCreate( sock, DNSCryptReceiveCertHandler, SocketContextCancelHandler, sockContext,
+ &context->readSource );
+ if( err ) ForgetMem( &sockContext );
+ require_noerr( err, exit );
+
+ sockContext->context = context;
+ sockContext->sock = sock;
+ sock = kInvalidSocketRef;
+ dispatch_resume( context->readSource );
+
+ if( context->timeLimitSecs > 0 )
+ {
+ dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(), kExitReason_Timeout,
+ Exit );
+ }
+ dispatch_main();
+
+exit:
+ if( context ) free( context );
+ ForgetSocket( &sock );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// DNSCryptReceiveCertHandler
+//===========================================================================================================================
+
+static void DNSCryptReceiveCertHandler( void *inContext )
+{
+ OSStatus err;
+ const uint64_t nowTicks = UpTicks();
+ SocketContext * const sockContext = (SocketContext *) inContext;
+ DNSCryptContext * const context = (DNSCryptContext *) sockContext->context;
+ const DNSHeader * hdr;
+ sockaddr_ip fromAddr;
+ const uint8_t * ptr;
+ const uint8_t * txtPtr;
+ size_t txtLen;
+ unsigned int answerCount, i;
+ uint8_t targetName[ kDomainNameLengthMax ];
+ char time[ kTimestampBufLen ];
+
+ GetTimestampStr( time );
+
+ dispatch_source_forget( &context->readSource );
+
+ err = SocketRecvFrom( sockContext->sock, context->msgBuf, sizeof( context->msgBuf ), &context->msgLen,
+ &fromAddr, sizeof( fromAddr ), NULL, NULL, NULL, NULL );
+ require_noerr( err, exit );
+ check( SockAddrCompareAddr( &fromAddr, &context->serverAddr ) == 0 );
+
+ FPrintF( stdout, "Receive time: %s\n", time );
+ FPrintF( stdout, "Source: %##a\n", &context->serverAddr );
+ FPrintF( stdout, "Message size: %zu\n", context->msgLen );
+ FPrintF( stdout, "RTT: %llu ms\n\n", UpTicksToMilliseconds( nowTicks - context->sendTicks ) );
+
+ PrintUDNSMessage( context->msgBuf, context->msgLen, context->printRawRData );
+
+ require_action_quiet( context->msgLen >= kDNSHeaderLength, exit, err = kSizeErr );
+
+ hdr = (DNSHeader *) context->msgBuf;
+ require_action_quiet( DNSHeaderGetID( hdr ) == context->queryID, exit, err = kMismatchErr );
+
+ err = DNSMessageGetAnswerSection( context->msgBuf, context->msgLen, &ptr );
+ require_noerr( err, exit );
+
+ targetName[ 0 ] = 0;
+ err = DomainNameAppendString( targetName, context->providerName, NULL );
+ require_noerr( err, exit );
+
+ answerCount = DNSHeaderGetAnswerCount( hdr );
+ for( i = 0; i < answerCount; ++i )
+ {
+ uint16_t type;
+ uint16_t class;
+ uint8_t name[ kDomainNameLengthMax ];
+
+ err = DNSMessageExtractRecord( context->msgBuf, context->msgLen, ptr, name, &type, &class, NULL, &txtPtr, &txtLen,
+ &ptr );
+ require_noerr( err, exit );
+
+ if( ( type == kDNSServiceType_TXT ) && ( class == kDNSServiceClass_IN ) && DomainNameEqual( name, targetName ) )
+ {
+ break;
+ }
+ }
+
+ if( txtLen < ( 1 + kDNSCryptCertMinimumLength ) )
+ {
+ FPrintF( stderr, "TXT record length is too short (%u < %u)\n", txtLen, kDNSCryptCertMinimumLength + 1 );
+ err = kSizeErr;
+ goto exit;
+ }
+ if( txtPtr[ 0 ] < kDNSCryptCertMinimumLength )
+ {
+ FPrintF( stderr, "TXT record value length is too short (%u < %u)\n", txtPtr[ 0 ], kDNSCryptCertMinimumLength );
+ err = kSizeErr;
+ goto exit;
+ }
+
+ context->certLen = txtPtr[ 0 ];
+ context->certPtr = &txtPtr[ 1 ];
+
+ dispatch_async_f( dispatch_get_main_queue(), context, DNSCryptProceed );
+
+exit:
+ if( err ) Exit( NULL );
+}
+
+//===========================================================================================================================
+// DNSCryptReceiveResponseHandler
+//===========================================================================================================================
+
+static void DNSCryptReceiveResponseHandler( void *inContext )
+{
+ OSStatus err;
+ const uint64_t nowTicks = UpTicks();
+ SocketContext * const sockContext = (SocketContext *) inContext;
+ DNSCryptContext * const context = (DNSCryptContext *) sockContext->context;
+ sockaddr_ip fromAddr;
+ DNSCryptResponseHeader * hdr;
+ const uint8_t * end;
+ uint8_t * ciphertext;
+ uint8_t * plaintext;
+ const uint8_t * response;
+ char time[ kTimestampBufLen ];
+ uint8_t nonce[ crypto_box_NONCEBYTES ];
+
+ GetTimestampStr( time );
+
+ dispatch_source_forget( &context->readSource );
+
+ err = SocketRecvFrom( sockContext->sock, context->msgBuf, sizeof( context->msgBuf ), &context->msgLen,
+ &fromAddr, sizeof( fromAddr ), NULL, NULL, NULL, NULL );
+ require_noerr( err, exit );
+ check( SockAddrCompareAddr( &fromAddr, &context->serverAddr ) == 0 );
+
+ FPrintF( stdout, "Receive time: %s\n", time );
+ FPrintF( stdout, "Source: %##a\n", &context->serverAddr );
+ FPrintF( stdout, "Message size: %zu\n", context->msgLen );
+ FPrintF( stdout, "RTT: %llu ms\n\n", UpTicksToMilliseconds( nowTicks - context->sendTicks ) );
+
+ if( context->msgLen < sizeof( DNSCryptResponseHeader ) )
+ {
+ FPrintF( stderr, "DNSCrypt response is too short.\n" );
+ err = kSizeErr;
+ goto exit;
+ }
+
+ hdr = (DNSCryptResponseHeader *) context->msgBuf;
+
+ if( memcmp( hdr->resolverMagic, kDNSCryptResolverMagic, kDNSCryptResolverMagicLength ) != 0 )
+ {
+ FPrintF( stderr, "DNSCrypt response resolver magic %#H != %#H\n",
+ hdr->resolverMagic, kDNSCryptResolverMagicLength, INT_MAX,
+ kDNSCryptResolverMagic, kDNSCryptResolverMagicLength, INT_MAX );
+ err = kValueErr;
+ goto exit;
+ }
+
+ if( memcmp( hdr->clientNonce, context->clientNonce, kDNSCryptHalfNonceLength ) != 0 )
+ {
+ FPrintF( stderr, "DNSCrypt response client nonce mismatch.\n" );
+ err = kValueErr;
+ goto exit;
+ }
+
+ memcpy( nonce, hdr->clientNonce, crypto_box_NONCEBYTES );
+
+ ciphertext = hdr->poly1305MAC - crypto_box_BOXZEROBYTES;
+ memset( ciphertext, 0, crypto_box_BOXZEROBYTES );
+
+ plaintext = (uint8_t *)( hdr + 1 ) - crypto_box_ZEROBYTES;
+ check( plaintext == ciphertext );
+
+ end = context->msgBuf + context->msgLen;
+
+ err = crypto_box_open_afternm( plaintext, ciphertext, (size_t)( end - ciphertext ), nonce, context->nmKey );
+ require_noerr( err, exit );
+
+ response = plaintext + crypto_box_ZEROBYTES;
+ PrintUDNSMessage( response, (size_t)( end - response ), context->printRawRData );
+ Exit( kExitReason_ReceivedResponse );
+
+exit:
+ if( err ) Exit( NULL );
+}
+
+//===========================================================================================================================
+// DNSCryptProceed
+//===========================================================================================================================
+
+static void DNSCryptProceed( void *inContext )
+{
+ OSStatus err;
+ DNSCryptContext * const context = (DNSCryptContext *) inContext;
+
+ err = DNSCryptProcessCert( context );
+ require_noerr_quiet( err, exit );
+
+ err = DNSCryptBuildQuery( context );
+ require_noerr_quiet( err, exit );
+
+ err = DNSCryptSendQuery( context );
+ require_noerr_quiet( err, exit );
+
+exit:
+ if( err ) Exit( NULL );
+}
+
+//===========================================================================================================================
+// DNSCryptProcessCert
+//===========================================================================================================================
+
+static OSStatus DNSCryptProcessCert( DNSCryptContext *inContext )
+{
+ OSStatus err;
+ const DNSCryptCert * const cert = (DNSCryptCert *) inContext->certPtr;
+ const uint8_t * const certEnd = inContext->certPtr + inContext->certLen;
+ struct timeval now;
+ time_t startTimeSecs, endTimeSecs;
+ size_t signedLen;
+ uint8_t * tempBuf;
+ unsigned long long tempLen;
+
+ DNSCryptPrintCertificate( cert, inContext->certLen );
+
+ if( memcmp( cert->certMagic, kDNSCryptCertMagic, kDNSCryptCertMagicLength ) != 0 )
+ {
+ FPrintF( stderr, "DNSCrypt certificate magic %#H != %#H\n",
+ cert->certMagic, kDNSCryptCertMagicLength, INT_MAX,
+ kDNSCryptCertMagic, kDNSCryptCertMagicLength, INT_MAX );
+ err = kValueErr;
+ goto exit;
+ }
+
+ startTimeSecs = (time_t) ReadBig32( cert->startTime );
+ endTimeSecs = (time_t) ReadBig32( cert->endTime );
+
+ gettimeofday( &now, NULL );
+ if( now.tv_sec < startTimeSecs )
+ {
+ FPrintF( stderr, "DNSCrypt certificate start time is in the future.\n" );
+ err = kDateErr;
+ goto exit;
+ }
+ if( now.tv_sec >= endTimeSecs )
+ {
+ FPrintF( stderr, "DNSCrypt certificate has expired.\n" );
+ err = kDateErr;
+ goto exit;
+ }
+
+ signedLen = (size_t)( certEnd - cert->signature );
+ tempBuf = (uint8_t *) malloc( signedLen );
+ require_action( tempBuf, exit, err = kNoMemoryErr );
+ err = crypto_sign_open( tempBuf, &tempLen, cert->signature, signedLen, inContext->serverPublicSignKey );
+ free( tempBuf );
+ if( err )
+ {
+ FPrintF( stderr, "DNSCrypt certificate failed verification.\n" );
+ err = kAuthenticationErr;
+ goto exit;
+ }
+
+ memcpy( inContext->serverPublicKey, cert->publicKey, crypto_box_PUBLICKEYBYTES );
+ memcpy( inContext->clientMagic, cert->clientMagic, kDNSCryptClientMagicLength );
+
+ err = crypto_box_beforenm( inContext->nmKey, inContext->serverPublicKey, inContext->clientSecretKey );
+ require_noerr( err, exit );
+
+ inContext->certPtr = NULL;
+ inContext->certLen = 0;
+ inContext->msgLen = 0;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// DNSCryptBuildQuery
+//===========================================================================================================================
+
+static OSStatus DNSCryptPadQuery( uint8_t *inMsgPtr, size_t inMsgLen, size_t inMaxLen, size_t *outPaddedLen );
+
+static OSStatus DNSCryptBuildQuery( DNSCryptContext *inContext )
+{
+ OSStatus err;
+ DNSCryptQueryHeader * const hdr = (DNSCryptQueryHeader *) inContext->msgBuf;
+ uint8_t * const queryPtr = (uint8_t *)( hdr + 1 );
+ size_t queryLen;
+ size_t paddedQueryLen;
+ const uint8_t * const msgLimit = inContext->msgBuf + sizeof( inContext->msgBuf );
+ const uint8_t * padLimit;
+ uint8_t nonce[ crypto_box_NONCEBYTES ];
+
+ check_compile_time_code( sizeof( inContext->msgBuf ) >= ( sizeof( DNSCryptQueryHeader ) + kDNSQueryMessageMaxLen ) );
+
+ inContext->queryID = (uint16_t) Random32();
+ err = WriteDNSQueryMessage( queryPtr, inContext->queryID, kDNSHeaderFlag_RecursionDesired, inContext->qname,
+ inContext->qtype, kDNSServiceClass_IN, &queryLen );
+ require_noerr( err, exit );
+
+ padLimit = &queryPtr[ queryLen + kDNSCryptMaxPadLength ];
+ if( padLimit > msgLimit ) padLimit = msgLimit;
+
+ err = DNSCryptPadQuery( queryPtr, queryLen, (size_t)( padLimit - queryPtr ), &paddedQueryLen );
+ require_noerr( err, exit );
+
+ memset( queryPtr - crypto_box_ZEROBYTES, 0, crypto_box_ZEROBYTES );
+ RandomBytes( inContext->clientNonce, kDNSCryptHalfNonceLength );
+ memcpy( nonce, inContext->clientNonce, kDNSCryptHalfNonceLength );
+ memset( &nonce[ kDNSCryptHalfNonceLength ], 0, kDNSCryptHalfNonceLength );
+
+ err = crypto_box_afternm( queryPtr - crypto_box_ZEROBYTES, queryPtr - crypto_box_ZEROBYTES,
+ paddedQueryLen + crypto_box_ZEROBYTES, nonce, inContext->nmKey );
+ require_noerr( err, exit );
+
+ memcpy( hdr->clientMagic, inContext->clientMagic, kDNSCryptClientMagicLength );
+ memcpy( hdr->clientPublicKey, inContext->clientPublicKey, crypto_box_PUBLICKEYBYTES );
+ memcpy( hdr->clientNonce, nonce, kDNSCryptHalfNonceLength );
+
+ inContext->msgLen = (size_t)( &queryPtr[ paddedQueryLen ] - inContext->msgBuf );
+
+exit:
+ return( err );
+}
+
+static OSStatus DNSCryptPadQuery( uint8_t *inMsgPtr, size_t inMsgLen, size_t inMaxLen, size_t *outPaddedLen )
+{
+ OSStatus err;
+ size_t paddedLen;
+
+ require_action_quiet( ( inMsgLen + kDNSCryptMinPadLength ) <= inMaxLen, exit, err = kSizeErr );
+
+ paddedLen = inMsgLen + kDNSCryptMinPadLength +
+ arc4random_uniform( (uint32_t)( inMaxLen - ( inMsgLen + kDNSCryptMinPadLength ) + 1 ) );
+ paddedLen += ( kDNSCryptBlockSize - ( paddedLen % kDNSCryptBlockSize ) );
+ if( paddedLen > inMaxLen ) paddedLen = inMaxLen;
+
+ inMsgPtr[ inMsgLen ] = 0x80;
+ memset( &inMsgPtr[ inMsgLen + 1 ], 0, paddedLen - ( inMsgLen + 1 ) );
+
+ if( outPaddedLen ) *outPaddedLen = paddedLen;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// DNSCryptSendQuery
+//===========================================================================================================================
+
+static OSStatus DNSCryptSendQuery( DNSCryptContext *inContext )
+{
+ OSStatus err;
+ SocketContext * sockContext;
+ SocketRef sock = kInvalidSocketRef;
+
+ check( inContext->msgLen > 0 );
+ check( !inContext->readSource );
+
+ err = UDPClientSocketOpen( AF_UNSPEC, &inContext->serverAddr, 0, -1, NULL, &sock );
+ require_noerr( err, exit );
+
+ inContext->sendTicks = UpTicks();
+ err = SocketWriteAll( sock, inContext->msgBuf, inContext->msgLen, 5 );
+ require_noerr( err, exit );
+
+ sockContext = (SocketContext *) calloc( 1, sizeof( *sockContext ) );
+ require_action( sockContext, exit, err = kNoMemoryErr );
+
+ err = DispatchReadSourceCreate( sock, DNSCryptReceiveResponseHandler, SocketContextCancelHandler, sockContext,
+ &inContext->readSource );
+ if( err ) ForgetMem( &sockContext );
+ require_noerr( err, exit );
+
+ sockContext->context = inContext;
+ sockContext->sock = sock;
+ sock = kInvalidSocketRef;
+
+ dispatch_resume( inContext->readSource );
+
+exit:
+ ForgetSocket( &sock );
+ return( err );
+}
+
+//===========================================================================================================================
+// DNSCryptPrintCertificate
+//===========================================================================================================================
+
+#define kCertTimeStrBufLen 32
+
+static char * CertTimeStr( time_t inTime, char inBuffer[ kCertTimeStrBufLen ] );
+
+static void DNSCryptPrintCertificate( const DNSCryptCert *inCert, size_t inLen )
+{
+ time_t startTime, endTime;
+ int extLen;
+ char timeBuf[ kCertTimeStrBufLen ];
+
+ check( inLen >= kDNSCryptCertMinimumLength );
+
+ startTime = (time_t) ReadBig32( inCert->startTime );
+ endTime = (time_t) ReadBig32( inCert->endTime );
+
+ FPrintF( stdout, "DNSCrypt certificate (%zu bytes):\n", inLen );
+ FPrintF( stdout, "Cert Magic: %#H\n", inCert->certMagic, kDNSCryptCertMagicLength, INT_MAX );
+ FPrintF( stdout, "ES Version: %u\n", ReadBig16( inCert->esVersion ) );
+ FPrintF( stdout, "Minor Version: %u\n", ReadBig16( inCert->minorVersion ) );
+ FPrintF( stdout, "Signature: %H\n", inCert->signature, crypto_sign_BYTES / 2, INT_MAX );
+ FPrintF( stdout, " %H\n", &inCert->signature[ crypto_sign_BYTES / 2 ], crypto_sign_BYTES / 2, INT_MAX );
+ FPrintF( stdout, "Public Key: %H\n", inCert->publicKey, sizeof( inCert->publicKey ), INT_MAX );
+ FPrintF( stdout, "Client Magic: %H\n", inCert->clientMagic, kDNSCryptClientMagicLength, INT_MAX );
+ FPrintF( stdout, "Serial: %u\n", ReadBig32( inCert->serial ) );
+ FPrintF( stdout, "Start Time: %u (%s)\n", (uint32_t) startTime, CertTimeStr( startTime, timeBuf ) );
+ FPrintF( stdout, "End Time: %u (%s)\n", (uint32_t) endTime, CertTimeStr( endTime, timeBuf ) );
+
+ if( inLen > kDNSCryptCertMinimumLength )
+ {
+ extLen = (int)( inLen - kDNSCryptCertMinimumLength );
+ FPrintF( stdout, "Extensions: %.1H\n", inCert->extensions, extLen, extLen );
+ }
+ FPrintF( stdout, "\n" );
+}
+
+static char * CertTimeStr( time_t inTime, char inBuffer[ kCertTimeStrBufLen ] )
+{
+ struct tm * tm;
+
+ tm = localtime( &inTime );
+ if( !tm )
+ {
+ dlogassert( "localtime() returned a NULL pointer.\n" );
+ *inBuffer = '\0';
+ }
+ else
+ {
+ strftime( inBuffer, kCertTimeStrBufLen, "%a %b %d %H:%M:%S %Z %Y", tm );
+ }
+
+ return( inBuffer );
+}
+
+#endif // DNSSDUTIL_INCLUDE_DNSCRYPT
+
+//===========================================================================================================================
+// MDNSQueryCmd
+//===========================================================================================================================
+
+#define kMDNSMulticastAddressIPv4 0xE00000FB // 224.0.0.251
+#define kMDNSPort 5353
+
+#define kDefaultMDNSMessageID 0
+#define kDefaultMDNSQueryFlags 0
+
+typedef struct
+{
+ const char * qname;
+ dispatch_source_t readSourceV4;
+ dispatch_source_t readSourceV6;
+ int receivedMsgCount;
+ int localPort;
+ uint32_t ifIndex;
+ uint16_t type;
+ Boolean isQU;
+ Boolean printRawRData;
+ Boolean useIPv4;
+ Boolean useIPv6;
+ Boolean allResponses;
+ char ifName[ IF_NAMESIZE + 1 ];
+ uint8_t domainName[ kDomainNameLengthMax ];
+ uint8_t msgBuf[ 8940 ];
+
+} MDNSQueryContext;
+
+static void MDNSQueryPrintPrologue( const MDNSQueryContext *inContext );
+static void MDNSQueryReadHandler( void *inContext );
+
+static void MDNSQueryCmd( void )
+{
+ OSStatus err;
+ MDNSQueryContext * context;
+ struct sockaddr_in mcastAddr4;
+ struct sockaddr_in6 mcastAddr6;
+ SocketRef sockV4 = kInvalidSocketRef;
+ SocketRef sockV6 = kInvalidSocketRef;
+ ssize_t n;
+ const char * ifNamePtr;
+ SocketContext * sockContext;
+ size_t msgLen;
+
+ context = (MDNSQueryContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ context->qname = gMDNSQuery_Name;
+ context->isQU = gMDNSQuery_IsQU ? true : false;
+ context->printRawRData = gMDNSQuery_RawRData ? true : false;
+ context->allResponses = gMDNSQuery_AllResponses ? true : false;
+ context->useIPv4 = ( gMDNSQuery_UseIPv4 || !gMDNSQuery_UseIPv6 ) ? true : false;
+ context->useIPv6 = ( gMDNSQuery_UseIPv6 || !gMDNSQuery_UseIPv4 ) ? true : false;
+
+ err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+
+ ifNamePtr = if_indextoname( context->ifIndex, context->ifName );
+ require_action( ifNamePtr, exit, err = kNameErr );
+
+ err = RecordTypeFromArgString( gMDNSQuery_Type, &context->type );
+ require_noerr( err, exit );
+
+ // Set up IPv4 socket.
+
+ if( context->useIPv4 )
+ {
+ err = ServerSocketOpen( AF_INET, SOCK_DGRAM, IPPROTO_UDP,
+ gMDNSQuery_SourcePort ? gMDNSQuery_SourcePort : ( context->isQU ? context->localPort : kMDNSPort ),
+ &context->localPort, kSocketBufferSize_DontSet, &sockV4 );
+ require_noerr( err, exit );
+
+ err = SocketSetMulticastInterface( sockV4, ifNamePtr, context->ifIndex );
+ require_noerr( err, exit );
+
+ err = setsockopt( sockV4, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &(uint8_t){ 1 }, (socklen_t) sizeof( uint8_t ) );
+ err = map_socket_noerr_errno( sockV4, err );
+ require_noerr( err, exit );
+
+ memset( &mcastAddr4, 0, sizeof( mcastAddr4 ) );
+ SIN_LEN_SET( &mcastAddr4 );
+ mcastAddr4.sin_family = AF_INET;
+ mcastAddr4.sin_port = htons( kMDNSPort );
+ mcastAddr4.sin_addr.s_addr = htonl( kMDNSMulticastAddressIPv4 );
+
+ if( !context->isQU && ( context->localPort == kMDNSPort ) )
+ {
+ SocketJoinMulticast( sockV4, &mcastAddr4, ifNamePtr, context->ifIndex );
+ require_noerr( err, exit );
+ }
+ }
+
+ // Set up IPv6 socket.
+
+ if( context->useIPv6 )
+ {
+ err = ServerSocketOpen( AF_INET6, SOCK_DGRAM, IPPROTO_UDP,
+ gMDNSQuery_SourcePort ? gMDNSQuery_SourcePort : ( context->isQU ? context->localPort : kMDNSPort ),
+ &context->localPort, kSocketBufferSize_DontSet, &sockV6 );
+ require_noerr( err, exit );
+
+ err = SocketSetMulticastInterface( sockV6, ifNamePtr, context->ifIndex );
+ require_noerr( err, exit );
+
+ err = setsockopt( sockV6, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &(int){ 1 }, (socklen_t) sizeof( int ) );
+ err = map_socket_noerr_errno( sockV6, err );
+ require_noerr( err, exit );
+
+ memset( &mcastAddr6, 0, sizeof( mcastAddr6 ) );
+ SIN6_LEN_SET( &mcastAddr6 );
+ mcastAddr6.sin6_family = AF_INET6;
+ mcastAddr6.sin6_port = htons( kMDNSPort );
+ mcastAddr6.sin6_addr.s6_addr[ 0 ] = 0xFF; // mDNS IPv6 multicast address FF02::FB
+ mcastAddr6.sin6_addr.s6_addr[ 1 ] = 0x02;
+ mcastAddr6.sin6_addr.s6_addr[ 15 ] = 0xFB;
+
+ if( !context->isQU && ( context->localPort == kMDNSPort ) )
+ {
+ SocketJoinMulticast( sockV6, &mcastAddr6, ifNamePtr, context->ifIndex );
+ require_noerr( err, exit );
+ }
+ }
+
+ // Write mDNS query message.
+
+ check_compile_time_code( sizeof( context->msgBuf ) >= kDNSQueryMessageMaxLen );
+ err = WriteDNSQueryMessage( context->msgBuf, kDefaultMDNSMessageID, kDefaultMDNSQueryFlags, context->qname,
+ context->type,
+ context->isQU ? ( kDNSServiceClass_IN | kQClassUnicastResponseBit ) : kDNSServiceClass_IN, &msgLen );
+ require_noerr( err, exit );
+
+ // Print prologue.
+
+ MDNSQueryPrintPrologue( context );
+
+ if( context->useIPv4 )
+ {
+ n = sendto( sockV4, context->msgBuf, msgLen, 0, (struct sockaddr *) &mcastAddr4, (socklen_t) sizeof( mcastAddr4 ) );
+ err = map_socket_value_errno( sockV4, n == (ssize_t) msgLen, n );
+ require_noerr_quiet( err, exit );
+
+ sockContext = (SocketContext *) calloc( 1, sizeof( *sockContext ) );
+ require_action( sockContext, exit, err = kNoMemoryErr );
+
+ err = DispatchReadSourceCreate( sockV4, MDNSQueryReadHandler, SocketContextCancelHandler, sockContext,
+ &context->readSourceV4 );
+ if( err ) ForgetMem( &sockContext );
+ require_noerr( err, exit );
+
+ sockContext->context = context;
+ sockContext->sock = sockV4;
+ sockV4 = kInvalidSocketRef;
+ dispatch_resume( context->readSourceV4 );
+ }
+
+ if( context->useIPv6 )
+ {
+ n = sendto( sockV6, context->msgBuf, msgLen, 0, (struct sockaddr *) &mcastAddr6, (socklen_t) sizeof( mcastAddr6 ) );
+ err = map_socket_value_errno( sockV6, n == (ssize_t) msgLen, n );
+ require_noerr_quiet( err, exit );
+
+ sockContext = (SocketContext *) calloc( 1, sizeof( *sockContext ) );
+ require_action( sockContext, exit, err = kNoMemoryErr );
+
+ err = DispatchReadSourceCreate( sockV6, MDNSQueryReadHandler, SocketContextCancelHandler, sockContext,
+ &context->readSourceV6 );
+ if( err ) ForgetMem( &sockContext );
+ require_noerr( err, exit );
+
+ sockContext->context = context;
+ sockContext->sock = sockV6;
+ sockV6 = kInvalidSocketRef;
+ dispatch_resume( context->readSourceV6 );
+ }
+
+ dispatch_main();
+
+exit:
+ ForgetSocket( &sockV4 );
+ ForgetSocket( &sockV6 );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// MDNSQueryPrintPrologue
+//===========================================================================================================================
+
+static void MDNSQueryPrintPrologue( const MDNSQueryContext *inContext )
+{
+ char time[ kTimestampBufLen ];
+
+ FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, inContext->ifName );
+ FPrintF( stdout, "Name: %s\n", inContext->qname );
+ FPrintF( stdout, "Type: %s (%u)\n", RecordTypeToString( inContext->type ), inContext->type );
+ FPrintF( stdout, "Class: IN (%s)\n", inContext->isQU ? "QU" : "QM" );
+ FPrintF( stdout, "Local port: %d\n", inContext->localPort );
+ FPrintF( stdout, "Start time: %s\n", GetTimestampStr( time ) );
+}
+
+//===========================================================================================================================
+// MDNSQueryReadHandler
+//===========================================================================================================================
+
+static void MDNSQueryReadHandler( void *inContext )
+{
+ OSStatus err;
+ SocketContext * const sockContext = (SocketContext *) inContext;
+ MDNSQueryContext * const context = (MDNSQueryContext *) sockContext->context;
+ size_t msgLen;
+ sockaddr_ip fromAddr;
+ char time[ kTimestampBufLen ];
+ Boolean foundAnswer = false;
+
+ GetTimestampStr( time );
+
+ err = SocketRecvFrom( sockContext->sock, context->msgBuf, sizeof( context->msgBuf ), &msgLen, &fromAddr,
+ sizeof( fromAddr ), NULL, NULL, NULL, NULL );
+ require_noerr( err, exit );
+
+ if( !context->allResponses && ( msgLen >= kDNSHeaderLength ) )
+ {
+ const uint8_t * ptr;
+ const DNSHeader * const hdr = (DNSHeader *) context->msgBuf;
+ unsigned int rrCount, i;
+ uint16_t type, class;
+ uint8_t domainName[ kDomainNameLengthMax ];
+
+ err = DNSMessageGetAnswerSection( context->msgBuf, msgLen, &ptr );
+ require_noerr( err, exit );
+
+ if( context->domainName[ 0 ] == 0 )
+ {
+ err = DomainNameAppendString( context->domainName, context->qname, NULL );
+ require_noerr( err, exit );
+ }
+
+ rrCount = DNSHeaderGetAnswerCount( hdr ) + DNSHeaderGetAuthorityCount( hdr ) + DNSHeaderGetAdditionalCount( hdr );
+ for( i = 0; i < rrCount; ++i )
+ {
+ err = DNSMessageExtractRecord( context->msgBuf, msgLen, ptr, domainName, &type, &class, NULL, NULL, NULL, &ptr );
+ require_noerr( err, exit );
+
+ if( ( type == context->type ) && DomainNameEqual( domainName, context->domainName ) )
+ {
+ foundAnswer = true;
+ break;
+ }
+ }
+ }
+ if( context->allResponses || foundAnswer )
+ {
+ FPrintF( stdout, "---\n" );
+ FPrintF( stdout, "Receive time: %s\n", time );
+ FPrintF( stdout, "Source: %##a\n", &fromAddr );
+ FPrintF( stdout, "Message size: %zu\n\n", msgLen );
+
+ PrintMDNSMessage( context->msgBuf, msgLen, context->printRawRData );
+ }
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// PIDToUUIDCmd
+//===========================================================================================================================
+
+static void PIDToUUIDCmd( void )
+{
+ OSStatus err;
+ int n;
+ struct proc_uniqidentifierinfo info;
+
+ n = proc_pidinfo( gPIDToUUID_PID, PROC_PIDUNIQIDENTIFIERINFO, 1, &info, sizeof( info ) );
+ require_action_quiet( n == (int) sizeof( info ), exit, err = kUnknownErr );
+
+ FPrintF( stdout, "%#U\n", info.p_uuid );
+ err = kNoErr;
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// DaemonVersionCmd
+//===========================================================================================================================
+
+static void DaemonVersionCmd( void )
+{
+ OSStatus err;
+ uint32_t size, version;
+ char strBuf[ 16 ];
+
+ size = (uint32_t) sizeof( version );
+ err = DNSServiceGetProperty( kDNSServiceProperty_DaemonVersion, &version, &size );
+ require_noerr( err, exit );
+
+ FPrintF( stdout, "Daemon version: %s\n", SourceVersionToCString( version, strBuf ) );
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// Exit
+//===========================================================================================================================
+
+static void Exit( void *inContext )
+{
+ const char * const reason = (const char *) inContext;
+ char time[ kTimestampBufLen ];
+
+ FPrintF( stdout, "---\n" );
+ FPrintF( stdout, "End time: %s\n", GetTimestampStr( time ) );
+ if( reason ) FPrintF( stdout, "End reason: %s\n", reason );
+ exit( gExitCode );
+}
+
+//===========================================================================================================================
+// GetTimestampStr
+//===========================================================================================================================
+
+static char * GetTimestampStr( char inBuffer[ kTimestampBufLen ] )
+{
+ struct timeval now;
+ struct tm * tm;
+ size_t len;
+
+ gettimeofday( &now, NULL );
+ tm = localtime( &now.tv_sec );
+ require_action( tm, exit, *inBuffer = '\0' );
+
+ len = strftime( inBuffer, kTimestampBufLen, "%Y-%m-%d %H:%M:%S", tm );
+ SNPrintF( &inBuffer[ len ], kTimestampBufLen - len, ".%06u", (unsigned int) now.tv_usec );
+
+exit:
+ return( inBuffer );
+}
+
+//===========================================================================================================================
+// GetDNSSDFlagsFromOpts
+//===========================================================================================================================
+
+static DNSServiceFlags GetDNSSDFlagsFromOpts( void )
+{
+ DNSServiceFlags flags;
+
+ flags = (DNSServiceFlags) gDNSSDFlags;
+ if( flags & kDNSServiceFlagsShareConnection )
+ {
+ FPrintF( stderr, "*** Warning: kDNSServiceFlagsShareConnection (0x%X) is explicitly set in flag parameters.\n",
+ kDNSServiceFlagsShareConnection );
+ }
+
+ if( gDNSSDFlag_BrowseDomains ) flags |= kDNSServiceFlagsBrowseDomains;
+ if( gDNSSDFlag_DenyCellular ) flags |= kDNSServiceFlagsDenyCellular;
+ if( gDNSSDFlag_DenyExpensive ) flags |= kDNSServiceFlagsDenyExpensive;
+ if( gDNSSDFlag_ForceMulticast ) flags |= kDNSServiceFlagsForceMulticast;
+ if( gDNSSDFlag_IncludeAWDL ) flags |= kDNSServiceFlagsIncludeAWDL;
+ if( gDNSSDFlag_NoAutoRename ) flags |= kDNSServiceFlagsNoAutoRename;
+ if( gDNSSDFlag_PathEvaluationDone ) flags |= kDNSServiceFlagsPathEvaluationDone;
+ if( gDNSSDFlag_RegistrationDomains ) flags |= kDNSServiceFlagsRegistrationDomains;
+ if( gDNSSDFlag_ReturnIntermediates ) flags |= kDNSServiceFlagsReturnIntermediates;
+ if( gDNSSDFlag_Shared ) flags |= kDNSServiceFlagsShared;
+ if( gDNSSDFlag_SuppressUnusable ) flags |= kDNSServiceFlagsSuppressUnusable;
+ if( gDNSSDFlag_Timeout ) flags |= kDNSServiceFlagsTimeout;
+ if( gDNSSDFlag_UnicastResponse ) flags |= kDNSServiceFlagsUnicastResponse;
+ if( gDNSSDFlag_Unique ) flags |= kDNSServiceFlagsUnique;
+
+ return( flags );
+}
+
+//===========================================================================================================================
+// CreateConnectionFromArgString
+//===========================================================================================================================
+
+static OSStatus
+ CreateConnectionFromArgString(
+ const char * inString,
+ dispatch_queue_t inQueue,
+ DNSServiceRef * outSDRef,
+ ConnectionDesc * outDesc )
+{
+ OSStatus err;
+ DNSServiceRef sdRef = NULL;
+ ConnectionType type;
+ int32_t pid = -1; // Initializing because the analyzer claims pid may be used uninitialized.
+ uint8_t uuid[ 16 ];
+
+ if( strcasecmp( inString, kConnectionArg_Normal ) == 0 )
+ {
+ err = DNSServiceCreateConnection( &sdRef );
+ require_noerr( err, exit );
+ type = kConnectionType_Normal;
+ }
+ else if( stricmp_prefix( inString, kConnectionArgPrefix_PID ) == 0 )
+ {
+ const char * const pidStr = inString + sizeof_string( kConnectionArgPrefix_PID );
+
+ err = StringToInt32( pidStr, &pid );
+ if( err )
+ {
+ FPrintF( stderr, "Invalid delegate connection PID value: %s\n", pidStr );
+ err = kParamErr;
+ goto exit;
+ }
+
+ memset( uuid, 0, sizeof( uuid ) );
+ err = DNSServiceCreateDelegateConnection( &sdRef, pid, uuid );
+ if( err )
+ {
+ FPrintF( stderr, "DNSServiceCreateDelegateConnection() returned %#m for PID %d\n", err, pid );
+ goto exit;
+ }
+ type = kConnectionType_DelegatePID;
+ }
+ else if( stricmp_prefix( inString, kConnectionArgPrefix_UUID ) == 0 )
+ {
+ const char * const uuidStr = inString + sizeof_string( kConnectionArgPrefix_UUID );
+
+ check_compile_time_code( sizeof( uuid ) == sizeof( uuid_t ) );
+
+ err = StringToUUID( uuidStr, kSizeCString, false, uuid );
+ if( err )
+ {
+ FPrintF( stderr, "Invalid delegate connection UUID value: %s\n", uuidStr );
+ err = kParamErr;
+ goto exit;
+ }
+
+ err = DNSServiceCreateDelegateConnection( &sdRef, 0, uuid );
+ if( err )
+ {
+ FPrintF( stderr, "DNSServiceCreateDelegateConnection() returned %#m for UUID %#U\n", err, uuid );
+ goto exit;
+ }
+ type = kConnectionType_DelegateUUID;
+ }
+ else
+ {
+ FPrintF( stderr, "Unrecognized connection string \"%s\".\n", inString );
+ err = kParamErr;
+ goto exit;
+ }
+
+ err = DNSServiceSetDispatchQueue( sdRef, inQueue );
+ require_noerr( err, exit );
+
+ *outSDRef = sdRef;
+ if( outDesc )
+ {
+ outDesc->type = type;
+ if( type == kConnectionType_DelegatePID ) outDesc->delegate.pid = pid;
+ else if( type == kConnectionType_DelegateUUID ) memcpy( outDesc->delegate.uuid, uuid, 16 );
+ }
+ sdRef = NULL;
+
+exit:
+ if( sdRef ) DNSServiceRefDeallocate( sdRef );
+ return( err );
+}
+
+//===========================================================================================================================
+// InterfaceIndexFromArgString
+//===========================================================================================================================
+
+static OSStatus InterfaceIndexFromArgString( const char *inString, uint32_t *outIndex )
+{
+ OSStatus err;
+ uint32_t ifIndex;
+
+ if( inString )
+ {
+ ifIndex = if_nametoindex( inString );
+ if( ifIndex == 0 )
+ {
+ err = StringToUInt32( inString, &ifIndex );
+ if( err )
+ {
+ FPrintF( stderr, "Invalid interface value: %s\n", inString );
+ err = kParamErr;
+ goto exit;
+ }
+ }
+ }
+ else
+ {
+ ifIndex = 0;
+ }
+
+ *outIndex = ifIndex;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// RecordDataFromArgString
+//===========================================================================================================================
+
+#define kRDataMaxLen UINT16_C( 0xFFFF )
+
+static OSStatus RecordDataFromArgString( const char *inString, uint8_t **outDataPtr, size_t *outDataLen )
+{
+ OSStatus err;
+ uint8_t * dataPtr = NULL;
+ size_t dataLen;
+ DataBuffer dataBuf;
+
+ DataBuffer_Init( &dataBuf, NULL, 0, kRDataMaxLen );
+
+ if( stricmp_prefix( inString, kRDataArgPrefix_String ) == 0 )
+ {
+ const char * const strPtr = inString + sizeof_string( kRDataArgPrefix_String );
+ const size_t strLen = strlen( strPtr );
+ size_t copiedLen;
+ size_t totalLen;
+
+ if( strLen > 0 )
+ {
+ require_action( strLen <= kRDataMaxLen, exit, err = kSizeErr );
+ dataPtr = (uint8_t *) malloc( strLen );
+ require_action( dataPtr, exit, err = kNoMemoryErr );
+
+ copiedLen = 0;
+ ParseQuotedEscapedString( strPtr, strPtr + strLen, "", (char *) dataPtr, strLen, &copiedLen, &totalLen, NULL );
+ check( copiedLen == totalLen );
+ dataLen = copiedLen;
+ }
+ else
+ {
+ dataPtr = NULL;
+ dataLen = 0;
+ }
+ }
+ else if( stricmp_prefix( inString, kRDataArgPrefix_HexString ) == 0 )
+ {
+ const char * const strPtr = inString + sizeof_string( kRDataArgPrefix_HexString );
+
+ err = HexToDataCopy( strPtr, kSizeCString, kHexToData_DefaultFlags, &dataPtr, &dataLen, NULL );
+ require_noerr( err, exit );
+ require_action( dataLen <= kRDataMaxLen, exit, err = kSizeErr );
+ }
+ else if( stricmp_prefix( inString, kRDataArgPrefix_File ) == 0 )
+ {
+ const char * const path = inString + sizeof_string( kRDataArgPrefix_File );
+
+ err = CopyFileDataByPath( path, (char **) &dataPtr, &dataLen );
+ require_noerr( err, exit );
+ require_action( dataLen <= kRDataMaxLen, exit, err = kSizeErr );
+ }
+ else if( stricmp_prefix( inString, kRDataArgPrefix_TXT ) == 0 )
+ {
+ const char * strPtr = inString + sizeof_string( kRDataArgPrefix_TXT );
+ const char * const strEnd = strPtr + strlen( strPtr );
+
+ while( strPtr < strEnd )
+ {
+ size_t copiedLen, totalLen;
+ uint8_t kvBuf[ 1 + 255 + 1 ]; // Length byte + max key-value length + 1 for NUL terminator.
+
+ err = ParseEscapedString( strPtr, strEnd, ',', (char *) &kvBuf[ 1 ], sizeof( kvBuf ) - 1,
+ &copiedLen, &totalLen, &strPtr );
+ require_noerr_quiet( err, exit );
+ check( copiedLen == totalLen );
+ if( totalLen > 255 )
+ {
+ FPrintF( stderr, "TXT key-value pair length %zu is too long (> 255 bytes).\n", totalLen );
+ err = kParamErr;
+ goto exit;
+ }
+
+ kvBuf[ 0 ] = (uint8_t) copiedLen;
+ err = DataBuffer_Append( &dataBuf, kvBuf, 1 + kvBuf[ 0 ] );
+ require_noerr( err, exit );
+ }
+
+ err = DataBuffer_Commit( &dataBuf, NULL, NULL );
+ require_noerr( err, exit );
+
+ err = DataBuffer_Detach( &dataBuf, &dataPtr, &dataLen );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ FPrintF( stderr, "Unrecognized record data string \"%s\".\n", inString );
+ err = kParamErr;
+ goto exit;
+ }
+ err = kNoErr;
+
+ *outDataLen = dataLen;
+ *outDataPtr = dataPtr;
+ dataPtr = NULL;
+
+exit:
+ DataBuffer_Free( &dataBuf );
+ FreeNullSafe( dataPtr );
+ return( err );
+}
+
+//===========================================================================================================================
+// RecordTypeFromArgString
+//===========================================================================================================================
+
+typedef struct
+{
+ uint16_t value; // Record type's numeric value.
+ const char * name; // Record type's name as a string (e.g., "A", "PTR", "SRV").
+
+} RecordType;
+
+static const RecordType kRecordTypes[] =
+{
+ // Common types.
+
+ { kDNSServiceType_A, "A" },
+ { kDNSServiceType_AAAA, "AAAA" },
+ { kDNSServiceType_PTR, "PTR" },
+ { kDNSServiceType_SRV, "SRV" },
+ { kDNSServiceType_TXT, "TXT" },
+ { kDNSServiceType_CNAME, "CNAME" },
+ { kDNSServiceType_SOA, "SOA" },
+ { kDNSServiceType_NSEC, "NSEC" },
+ { kDNSServiceType_NS, "NS" },
+ { kDNSServiceType_MX, "MX" },
+ { kDNSServiceType_ANY, "ANY" },
+ { kDNSServiceType_OPT, "OPT" },
+
+ // Less common types.
+
+ { kDNSServiceType_MD, "MD" },
+ { kDNSServiceType_NS, "NS" },
+ { kDNSServiceType_MD, "MD" },
+ { kDNSServiceType_MF, "MF" },
+ { kDNSServiceType_MB, "MB" },
+ { kDNSServiceType_MG, "MG" },
+ { kDNSServiceType_MR, "MR" },
+ { kDNSServiceType_NULL, "NULL" },
+ { kDNSServiceType_WKS, "WKS" },
+ { kDNSServiceType_HINFO, "HINFO" },
+ { kDNSServiceType_MINFO, "MINFO" },
+ { kDNSServiceType_RP, "RP" },
+ { kDNSServiceType_AFSDB, "AFSDB" },
+ { kDNSServiceType_X25, "X25" },
+ { kDNSServiceType_ISDN, "ISDN" },
+ { kDNSServiceType_RT, "RT" },
+ { kDNSServiceType_NSAP, "NSAP" },
+ { kDNSServiceType_NSAP_PTR, "NSAP_PTR" },
+ { kDNSServiceType_SIG, "SIG" },
+ { kDNSServiceType_KEY, "KEY" },
+ { kDNSServiceType_PX, "PX" },
+ { kDNSServiceType_GPOS, "GPOS" },
+ { kDNSServiceType_LOC, "LOC" },
+ { kDNSServiceType_NXT, "NXT" },
+ { kDNSServiceType_EID, "EID" },
+ { kDNSServiceType_NIMLOC, "NIMLOC" },
+ { kDNSServiceType_ATMA, "ATMA" },
+ { kDNSServiceType_NAPTR, "NAPTR" },
+ { kDNSServiceType_KX, "KX" },
+ { kDNSServiceType_CERT, "CERT" },
+ { kDNSServiceType_A6, "A6" },
+ { kDNSServiceType_DNAME, "DNAME" },
+ { kDNSServiceType_SINK, "SINK" },
+ { kDNSServiceType_APL, "APL" },
+ { kDNSServiceType_DS, "DS" },
+ { kDNSServiceType_SSHFP, "SSHFP" },
+ { kDNSServiceType_IPSECKEY, "IPSECKEY" },
+ { kDNSServiceType_RRSIG, "RRSIG" },
+ { kDNSServiceType_DNSKEY, "DNSKEY" },
+ { kDNSServiceType_DHCID, "DHCID" },
+ { kDNSServiceType_NSEC3, "NSEC3" },
+ { kDNSServiceType_NSEC3PARAM, "NSEC3PARAM" },
+ { kDNSServiceType_HIP, "HIP" },
+ { kDNSServiceType_SPF, "SPF" },
+ { kDNSServiceType_UINFO, "UINFO" },
+ { kDNSServiceType_UID, "UID" },
+ { kDNSServiceType_GID, "GID" },
+ { kDNSServiceType_UNSPEC, "UNSPEC" },
+ { kDNSServiceType_TKEY, "TKEY" },
+ { kDNSServiceType_TSIG, "TSIG" },
+ { kDNSServiceType_IXFR, "IXFR" },
+ { kDNSServiceType_AXFR, "AXFR" },
+ { kDNSServiceType_MAILB, "MAILB" },
+ { kDNSServiceType_MAILA, "MAILA" }
+};
+
+static OSStatus RecordTypeFromArgString( const char *inString, uint16_t *outValue )
+{
+ OSStatus err;
+ int32_t i32;
+ const RecordType * type;
+ const RecordType * const end = kRecordTypes + countof( kRecordTypes );
+
+ for( type = kRecordTypes; type < end; ++type )
+ {
+ if( strcasecmp( type->name, inString ) == 0 )
+ {
+ *outValue = type->value;
+ return( kNoErr );
+ }
+ }
+
+ err = StringToInt32( inString, &i32 );
+ require_noerr_quiet( err, exit );
+ require_action_quiet( ( i32 >= 0 ) && ( i32 <= UINT16_MAX ), exit, err = kParamErr );
+
+ *outValue = (uint16_t) i32;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// RecordClassFromArgString
+//===========================================================================================================================
+
+static OSStatus RecordClassFromArgString( const char *inString, uint16_t *outValue )
+{
+ OSStatus err;
+ int32_t i32;
+
+ if( strcasecmp( inString, "IN" ) == 0 )
+ {
+ *outValue = kDNSServiceClass_IN;
+ err = kNoErr;
+ goto exit;
+ }
+
+ err = StringToInt32( inString, &i32 );
+ require_noerr_quiet( err, exit );
+ require_action_quiet( ( i32 >= 0 ) && ( i32 <= UINT16_MAX ), exit, err = kParamErr );
+
+ *outValue = (uint16_t) i32;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// InterfaceIndexToName
+//===========================================================================================================================
+
+static char * InterfaceIndexToName( uint32_t inIfIndex, char inNameBuf[ kInterfaceNameBufLen ] )
+{
+ switch( inIfIndex )
+ {
+ case kDNSServiceInterfaceIndexAny:
+ strlcpy( inNameBuf, "Any", kInterfaceNameBufLen );
+ break;
+
+ case kDNSServiceInterfaceIndexLocalOnly:
+ strlcpy( inNameBuf, "LocalOnly", kInterfaceNameBufLen );
+ break;
+
+ case kDNSServiceInterfaceIndexUnicast:
+ strlcpy( inNameBuf, "Unicast", kInterfaceNameBufLen );
+ break;
+
+ case kDNSServiceInterfaceIndexP2P:
+ strlcpy( inNameBuf, "P2P", kInterfaceNameBufLen );
+ break;
+
+ #if( defined( kDNSServiceInterfaceIndexBLE ) )
+ case kDNSServiceInterfaceIndexBLE:
+ strlcpy( inNameBuf, "BLE", kInterfaceNameBufLen );
+ break;
+ #endif
+
+ default:
+ {
+ const char * name;
+
+ name = if_indextoname( inIfIndex, inNameBuf );
+ if( !name ) strlcpy( inNameBuf, "NO NAME", kInterfaceNameBufLen );
+ break;
+ }
+ }
+
+ return( inNameBuf );
+}
+
+//===========================================================================================================================
+// RecordTypeToString
+//===========================================================================================================================
+
+static const char * RecordTypeToString( unsigned int inValue )
+{
+ const RecordType * type;
+ const RecordType * const end = kRecordTypes + countof( kRecordTypes );
+
+ for( type = kRecordTypes; type < end; ++type )
+ {
+ if( type->value == inValue ) return( type->name );
+ }
+ return( "???" );
+}
+
+//===========================================================================================================================
+// DNSMessageExtractDomainName
+//===========================================================================================================================
+
+#define IsCompressionByte( X ) ( ( ( X ) & 0xC0 ) == 0xC0 )
+
+static OSStatus
+ DNSMessageExtractDomainName(
+ const uint8_t * inMsgPtr,
+ size_t inMsgLen,
+ const uint8_t * inNamePtr,
+ uint8_t inBuf[ kDomainNameLengthMax ],
+ const uint8_t ** outNextPtr )
+{
+ OSStatus err;
+ const uint8_t * label;
+ uint8_t labelLen;
+ const uint8_t * nextLabel;
+ const uint8_t * const msgEnd = inMsgPtr + inMsgLen;
+ uint8_t * dst = inBuf;
+ const uint8_t * const dstLim = inBuf ? ( inBuf + kDomainNameLengthMax ) : NULL;
+ const uint8_t * nameEnd = NULL;
+
+ require_action( ( inNamePtr >= inMsgPtr ) && ( inNamePtr < msgEnd ), exit, err = kRangeErr );
+
+ for( label = inNamePtr; ( labelLen = label[ 0 ] ) != 0; label = nextLabel )
+ {
+ if( labelLen <= kDomainLabelLengthMax )
+ {
+ nextLabel = label + 1 + labelLen;
+ require_action( nextLabel < msgEnd, exit, err = kUnderrunErr );
+ if( dst )
+ {
+ require_action( ( dstLim - dst ) > ( 1 + labelLen ), exit, err = kOverrunErr );
+ memcpy( dst, label, 1 + labelLen );
+ dst += ( 1 + labelLen );
+ }
+ }
+ else if( IsCompressionByte( labelLen ) )
+ {
+ uint16_t offset;
+
+ require_action( ( msgEnd - label ) >= 2, exit, err = kUnderrunErr );
+ if( !nameEnd )
+ {
+ nameEnd = label + 2;
+ if( !dst ) break;
+ }
+ offset = (uint16_t)( ( ( label[ 0 ] & 0x3F ) << 8 ) | label[ 1 ] );
+ nextLabel = inMsgPtr + offset;
+ require_action( nextLabel < msgEnd, exit, err = kUnderrunErr );
+ require_action( !IsCompressionByte( nextLabel[ 0 ] ), exit, err = kMalformedErr );
+ }
+ else
+ {
+ dlogassert( "Unhandled label length 0x%02X\n", labelLen );
+ err = kMalformedErr;
+ goto exit;
+ }
+ }
+
+ if( dst ) *dst = 0;
+ if( !nameEnd ) nameEnd = label + 1;
+
+ if( outNextPtr ) *outNextPtr = nameEnd;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// DNSMessageExtractDomainNameString
+//===========================================================================================================================
+
+static OSStatus
+ DNSMessageExtractDomainNameString(
+ const void * inMsgPtr,
+ size_t inMsgLen,
+ const void * inNamePtr,
+ char inBuf[ kDNSServiceMaxDomainName ],
+ const uint8_t ** outNextPtr )
+{
+ OSStatus err;
+ const uint8_t * nextPtr;
+ uint8_t domainName[ kDomainNameLengthMax ];
+
+ err = DNSMessageExtractDomainName( inMsgPtr, inMsgLen, inNamePtr, domainName, &nextPtr );
+ require_noerr( err, exit );
+
+ err = DomainNameToString( domainName, NULL, inBuf, NULL );
+ require_noerr( err, exit );
+
+ if( outNextPtr ) *outNextPtr = nextPtr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// DNSMessageExtractRecord
+//===========================================================================================================================
+
+typedef struct
+{
+ uint8_t type[ 2 ];
+ uint8_t class[ 2 ];
+ uint8_t ttl[ 4 ];
+ uint8_t rdLength[ 2 ];
+ uint8_t rdata[ 1 ];
+
+} DNSRecordFields;
+
+check_compile_time( offsetof( DNSRecordFields, rdata ) == 10 );
+
+static OSStatus
+ DNSMessageExtractRecord(
+ const uint8_t * inMsgPtr,
+ size_t inMsgLen,
+ const uint8_t * inPtr,
+ uint8_t inNameBuf[ kDomainNameLengthMax ],
+ uint16_t * outType,
+ uint16_t * outClass,
+ uint32_t * outTTL,
+ const uint8_t ** outRDataPtr,
+ size_t * outRDataLen,
+ const uint8_t ** outPtr )
+{
+ OSStatus err;
+ const uint8_t * const msgEnd = inMsgPtr + inMsgLen;
+ const uint8_t * ptr;
+ const DNSRecordFields * record;
+ size_t rdLength;
+
+ err = DNSMessageExtractDomainName( inMsgPtr, inMsgLen, inPtr, inNameBuf, &ptr );
+ require_noerr_quiet( err, exit );
+ require_action_quiet( (size_t)( msgEnd - ptr ) >= offsetof( DNSRecordFields, rdata ), exit, err = kUnderrunErr );
+
+ record = (DNSRecordFields *) ptr;
+ rdLength = ReadBig16( record->rdLength );
+ require_action_quiet( (size_t)( msgEnd - record->rdata ) >= rdLength , exit, err = kUnderrunErr );
+
+ if( outType ) *outType = ReadBig16( record->type );
+ if( outClass ) *outClass = ReadBig16( record->class );
+ if( outTTL ) *outTTL = ReadBig32( record->ttl );
+ if( outRDataPtr ) *outRDataPtr = record->rdata;
+ if( outRDataLen ) *outRDataLen = rdLength;
+ if( outPtr ) *outPtr = record->rdata + rdLength;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// DNSMessageGetAnswerSection
+//===========================================================================================================================
+
+static OSStatus DNSMessageGetAnswerSection( const uint8_t *inMsgPtr, size_t inMsgLen, const uint8_t **outPtr )
+{
+ OSStatus err;
+ const uint8_t * const msgEnd = inMsgPtr + inMsgLen;
+ unsigned int questionCount, i;
+ const DNSHeader * hdr;
+ const uint8_t * ptr;
+
+ require_action_quiet( inMsgLen >= kDNSHeaderLength, exit, err = kSizeErr );
+
+ hdr = (DNSHeader *) inMsgPtr;
+ questionCount = DNSHeaderGetQuestionCount( hdr );
+
+ ptr = (uint8_t *)( hdr + 1 );
+ for( i = 0; i < questionCount; ++i )
+ {
+ err = DNSMessageExtractDomainName( inMsgPtr, inMsgLen, ptr, NULL, &ptr );
+ require_noerr( err, exit );
+ require_action_quiet( ( msgEnd - ptr ) >= 4, exit, err = kUnderrunErr );
+ ptr += 4;
+ }
+
+ if( outPtr ) *outPtr = ptr;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// DNSRecordDataToString
+//===========================================================================================================================
+
+static OSStatus
+ DNSRecordDataToString(
+ const void * inRDataPtr,
+ size_t inRDataLen,
+ unsigned int inRDataType,
+ const void * inMsgPtr,
+ size_t inMsgLen,
+ char ** outString )
+{
+ OSStatus err;
+ const uint8_t * const rdataPtr = (uint8_t *) inRDataPtr;
+ const uint8_t * const rdataEnd = rdataPtr + inRDataLen;
+ char * rdataStr;
+ const uint8_t * ptr;
+ int n;
+ char domainNameStr[ kDNSServiceMaxDomainName ];
+
+ rdataStr = NULL;
+ if( inRDataType == kDNSServiceType_A )
+ {
+ require_action_quiet( inRDataLen == 4, exit, err = kMalformedErr );
+
+ ASPrintF( &rdataStr, "%.4a", rdataPtr );
+ require_action( rdataStr, exit, err = kNoMemoryErr );
+ }
+ else if( inRDataType == kDNSServiceType_AAAA )
+ {
+ require_action_quiet( inRDataLen == 16, exit, err = kMalformedErr );
+
+ ASPrintF( &rdataStr, "%.16a", rdataPtr );
+ require_action( rdataStr, exit, err = kNoMemoryErr );
+ }
+ else if( ( inRDataType == kDNSServiceType_PTR ) || ( inRDataType == kDNSServiceType_CNAME ) ||
+ ( inRDataType == kDNSServiceType_NS ) )
+ {
+ if( inMsgPtr )
+ {
+ err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, rdataPtr, domainNameStr, NULL );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ err = DomainNameToString( rdataPtr, rdataEnd, domainNameStr, NULL );
+ require_noerr( err, exit );
+ }
+
+ rdataStr = strdup( domainNameStr );
+ require_action( rdataStr, exit, err = kNoMemoryErr );
+ }
+ else if( inRDataType == kDNSServiceType_SRV )
+ {
+ uint16_t priority, weight, port;
+ const uint8_t * target;
+
+ require_action_quiet( ( rdataPtr + 6 ) < rdataEnd, exit, err = kMalformedErr );
+
+ priority = ReadBig16( rdataPtr );
+ weight = ReadBig16( rdataPtr + 2 );
+ port = ReadBig16( rdataPtr + 4 );
+ target = rdataPtr + 6;
+
+ if( inMsgPtr )
+ {
+ err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, target, domainNameStr, NULL );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ err = DomainNameToString( target, rdataEnd, domainNameStr, NULL );
+ require_noerr( err, exit );
+ }
+
+ ASPrintF( &rdataStr, "%u %u %u %s", priority, weight, port, domainNameStr );
+ require_action( rdataStr, exit, err = kNoMemoryErr );
+ }
+ else if( inRDataType == kDNSServiceType_TXT )
+ {
+ require_action_quiet( inRDataLen > 0, exit, err = kMalformedErr );
+
+ if( inRDataLen == 1 )
+ {
+ ASPrintF( &rdataStr, "%#H", rdataPtr, (int) inRDataLen, INT_MAX );
+ require_action( rdataStr, exit, err = kNoMemoryErr );
+ }
+ else
+ {
+ ASPrintF( &rdataStr, "%#{txt}", rdataPtr, inRDataLen );
+ require_action( rdataStr, exit, err = kNoMemoryErr );
+ }
+ }
+ else if( inRDataType == kDNSServiceType_SOA )
+ {
+ uint32_t serial, refresh, retry, expire, minimum;
+
+ if( inMsgPtr )
+ {
+ err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, rdataPtr, domainNameStr, &ptr );
+ require_noerr( err, exit );
+
+ require_action_quiet( ptr < rdataEnd, exit, err = kMalformedErr );
+
+ rdataStr = strdup( domainNameStr );
+ require_action( rdataStr, exit, err = kNoMemoryErr );
+
+ err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, ptr, domainNameStr, &ptr );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ err = DomainNameToString( rdataPtr, rdataEnd, domainNameStr, &ptr );
+ require_noerr( err, exit );
+
+ rdataStr = strdup( domainNameStr );
+ require_action( rdataStr, exit, err = kNoMemoryErr );
+
+ err = DomainNameToString( ptr, rdataEnd, domainNameStr, &ptr );
+ require_noerr( err, exit );
+ }
+
+ require_action_quiet( ( ptr + 20 ) == rdataEnd, exit, err = kMalformedErr );
+
+ serial = ReadBig32( ptr );
+ refresh = ReadBig32( ptr + 4 );
+ retry = ReadBig32( ptr + 8 );
+ expire = ReadBig32( ptr + 12 );
+ minimum = ReadBig32( ptr + 16 );
+
+ n = AppendPrintF( &rdataStr, " %s %u %u %u %u %u\n", domainNameStr, serial, refresh, retry, expire, minimum );
+ require_action( n > 0, exit, err = kUnknownErr );
+ }
+ else if( inRDataType == kDNSServiceType_NSEC )
+ {
+ unsigned int windowBlock, bitmapLen, i, recordType;
+ const uint8_t * bitmapPtr;
+
+ if( inMsgPtr )
+ {
+ err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, rdataPtr, domainNameStr, &ptr );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ err = DomainNameToString( rdataPtr, rdataEnd, domainNameStr, &ptr );
+ require_noerr( err, exit );
+ }
+
+ require_action_quiet( ptr < rdataEnd, exit, err = kMalformedErr );
+
+ rdataStr = strdup( domainNameStr );
+ require_action( rdataStr, exit, err = kNoMemoryErr );
+
+ for( ; ptr < rdataEnd; ptr += ( 2 + bitmapLen ) )
+ {
+ require_action_quiet( ( ptr + 2 ) < rdataEnd, exit, err = kMalformedErr );
+
+ windowBlock = ptr[ 0 ];
+ bitmapLen = ptr[ 1 ];
+ bitmapPtr = &ptr[ 2 ];
+
+ require_action_quiet( ( bitmapLen >= 1 ) && ( bitmapLen <= 32 ) , exit, err = kMalformedErr );
+ require_action_quiet( ( bitmapPtr + bitmapLen ) <= rdataEnd, exit, err = kMalformedErr );
+
+ for( i = 0; i < BitArray_MaxBits( bitmapLen ); ++i )
+ {
+ if( BitArray_GetBit( bitmapPtr, bitmapLen, i ) )
+ {
+ recordType = ( windowBlock * 256 ) + i;
+ n = AppendPrintF( &rdataStr, " %s", RecordTypeToString( recordType ) );
+ require_action( n > 0, exit, err = kUnknownErr );
+ }
+ }
+ }
+ }
+ else if( inRDataType == kDNSServiceType_MX )
+ {
+ uint16_t preference;
+ const uint8_t * exchange;
+
+ require_action_quiet( ( rdataPtr + 2 ) < rdataEnd, exit, err = kMalformedErr );
+
+ preference = ReadBig16( rdataPtr );
+ exchange = &rdataPtr[ 2 ];
+
+ if( inMsgPtr )
+ {
+ err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, exchange, domainNameStr, NULL );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ err = DomainNameToString( exchange, rdataEnd, domainNameStr, NULL );
+ require_noerr( err, exit );
+ }
+
+ n = ASPrintF( &rdataStr, "%u %s", preference, domainNameStr );
+ require_action( n > 0, exit, err = kUnknownErr );
+ }
+ else
+ {
+ err = kNotHandledErr;
+ goto exit;
+ }
+
+ check( rdataStr );
+ *outString = rdataStr;
+ rdataStr = NULL;
+ err = kNoErr;
+
+exit:
+ FreeNullSafe( rdataStr );
+ return( err );
+}
+
+//===========================================================================================================================
+// DomainNameAppendString
+//===========================================================================================================================
+
+static OSStatus
+ DomainNameAppendString(
+ uint8_t inDomainName[ kDomainNameLengthMax ],
+ const char * inString,
+ uint8_t ** outEndPtr )
+{
+ OSStatus err;
+ const char * src;
+ uint8_t * dst;
+ const uint8_t * const nameLimit = inDomainName + kDomainNameLengthMax;
+
+ // Find the root label.
+
+ for( dst = inDomainName; ( dst < nameLimit ) && *dst; dst += ( 1 + *dst ) ) {}
+ require_action_quiet( dst < nameLimit, exit, err = kMalformedErr );
+
+ // Append the string's labels one label at a time.
+
+ src = inString;
+ while( *src )
+ {
+ uint8_t * const label = dst++;
+ const uint8_t * const labelLimit = Min( dst + kDomainLabelLengthMax, nameLimit - 1 );
+
+ // If the first character is a label separator, then the label is empty. Empty non-root labels are not allowed.
+
+ require_action_quiet( *src != '.', exit, err = kMalformedErr );
+
+ // Write the label characters until the end of the label, a separator or NUL character, is encountered, or until no
+ // more space is available.
+
+ while( ( *src != '.' ) && ( *src != '\0' ) && ( dst < labelLimit ) )
+ {
+ uint8_t value;
+
+ value = (uint8_t) *src++;
+ if( value == '\\' )
+ {
+ if( *src == '\0' ) break;
+ value = (uint8_t) *src++;
+ if( isdigit_safe( value ) && isdigit_safe( src[ 0 ] ) && isdigit_safe( src[ 1 ] ) )
+ {
+ int decimalValue;
+
+ decimalValue = ( ( value - '0' ) * 100 ) + ( ( src[ 0 ] - '0' ) * 10 ) + ( src[ 1 ] - '0' );
+ if( decimalValue <= 255 )
+ {
+ value = (uint8_t) decimalValue;
+ src += 2;
+ }
+ }
+ }
+ *dst++ = value;
+ }
+ if( ( *src == '.' ) || ( *src == '\0' ) )
+ {
+ label[ 0 ] = (uint8_t)( dst - &label[ 1 ] ); // Write the label length.
+ if( *src == '.' ) ++src; // Advance the pointer past the label separator.
+ }
+ else
+ {
+ label[ 0 ] = 0;
+ err = kOverrunErr;
+ goto exit;
+ }
+ }
+
+ *dst++ = 0; // Write the empty root label.
+ if( outEndPtr ) *outEndPtr = dst;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// DomainNameEqual
+//===========================================================================================================================
+
+static Boolean DomainNameEqual( const uint8_t *inName1, const uint8_t *inName2 )
+{
+ const uint8_t * p1 = inName1;
+ const uint8_t * p2 = inName2;
+ unsigned int len;
+
+ for( ;; )
+ {
+ if( ( len = *p1++ ) != *p2++ ) return( false );
+ if( len == 0 ) break;
+ for( ; len > 0; ++p1, ++p2, --len )
+ {
+ if( tolower_safe( *p1 ) != tolower_safe( *p2 ) ) return( false );
+ }
+ }
+ return( true );
+}
+
+//===========================================================================================================================
+// DomainNameToString
+//===========================================================================================================================
+
+static OSStatus
+ DomainNameToString(
+ const uint8_t * inDomainName,
+ const uint8_t * inEnd,
+ char inBuf[ kDNSServiceMaxDomainName ],
+ const uint8_t ** outNextPtr )
+{
+ OSStatus err;
+ const uint8_t * label;
+ uint8_t labelLen;
+ const uint8_t * nextLabel;
+ char * dst;
+ const uint8_t * src;
+
+ require_action( !inEnd || ( inDomainName < inEnd ), exit, err = kUnderrunErr );
+
+ // Convert each label up until the root label, i.e., the zero-length label.
+
+ dst = inBuf;
+ for( label = inDomainName; ( labelLen = label[ 0 ] ) != 0; label = nextLabel )
+ {
+ require_action( labelLen <= kDomainLabelLengthMax, exit, err = kMalformedErr );
+
+ nextLabel = &label[ 1 ] + labelLen;
+ require_action( ( nextLabel - inDomainName ) < kDomainNameLengthMax, exit, err = kMalformedErr );
+ require_action( !inEnd || ( nextLabel < inEnd ), exit, err = kUnderrunErr );
+
+ for( src = &label[ 1 ]; src < nextLabel; ++src )
+ {
+ if( isprint_safe( *src ) )
+ {
+ if( ( *src == '.' ) || ( *src == '\\' ) || ( *src == ' ' ) ) *dst++ = '\\';
+ *dst++ = (char) *src;
+ }
+ else
+ {
+ *dst++ = '\\';
+ *dst++ = '0' + ( *src / 100 );
+ *dst++ = '0' + ( ( *src / 10 ) % 10 );
+ *dst++ = '0' + ( *src % 10 );
+ }
+ }
+ *dst++ = '.';
+ }
+
+ // At this point, label points to the root label.
+ // If the root label was the only label, then write a dot for it.
+
+ if( label == inDomainName ) *dst++ = '.';
+ *dst = '\0';
+ if( outNextPtr ) *outNextPtr = label + 1;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// PrintDNSMessage
+//===========================================================================================================================
+
+#define DNSFlagsOpCodeToString( X ) ( \
+ ( (X) == kDNSOpCode_Query ) ? "Query" : \
+ ( (X) == kDNSOpCode_InverseQuery ) ? "IQuery" : \
+ ( (X) == kDNSOpCode_Status ) ? "Status" : \
+ ( (X) == kDNSOpCode_Notify ) ? "Notify" : \
+ ( (X) == kDNSOpCode_Update ) ? "Update" : \
+ "Unassigned" )
+
+#define DNSFlagsRCodeToString( X ) ( \
+ ( (X) == kDNSRCode_NoError ) ? "NoError" : \
+ ( (X) == kDNSRCode_FormatError ) ? "FormErr" : \
+ ( (X) == kDNSRCode_ServerFailure ) ? "ServFail" : \
+ ( (X) == kDNSRCode_NXDomain ) ? "NXDomain" : \
+ ( (X) == kDNSRCode_NotImplemented ) ? "NotImp" : \
+ ( (X) == kDNSRCode_Refused ) ? "Refused" : \
+ "???" )
+
+#define DNSFlagsGetOpCode( X ) ( ( (X) >> 11 ) & 0x0F )
+#define DNSFlagsGetRCode( X ) ( (X) & 0x0F )
+
+static OSStatus PrintDNSMessage( const uint8_t *inMsgPtr, size_t inMsgLen, const Boolean inIsMDNS, const Boolean inPrintRaw )
+{
+ OSStatus err;
+ const DNSHeader * hdr;
+ const uint8_t * const msgEnd = inMsgPtr + inMsgLen;
+ const uint8_t * ptr;
+ unsigned int id, flags, opcode, rcode;
+ unsigned int questionCount, answerCount, authorityCount, additionalCount, i, totalRRCount;
+ char nameStr[ kDNSServiceMaxDomainName ];
+
+ require_action_quiet( inMsgLen >= kDNSHeaderLength, exit, err = kSizeErr );
+
+ hdr = (DNSHeader *) inMsgPtr;
+ id = DNSHeaderGetID( hdr );
+ flags = DNSHeaderGetFlags( hdr );
+ questionCount = DNSHeaderGetQuestionCount( hdr );
+ answerCount = DNSHeaderGetAnswerCount( hdr );
+ authorityCount = DNSHeaderGetAuthorityCount( hdr );
+ additionalCount = DNSHeaderGetAdditionalCount( hdr );
+ opcode = DNSFlagsGetOpCode( flags );
+ rcode = DNSFlagsGetRCode( flags );
+
+ FPrintF( stdout, "ID: 0x%04X\n", id );
+ FPrintF( stdout, "Flags: 0x%04X %c/%s %cAA%cTC%cRD%cRA %s\n",
+ flags,
+ ( flags & kDNSHeaderFlag_Response ) ? 'R' : 'Q', DNSFlagsOpCodeToString( opcode ),
+ ( flags & kDNSHeaderFlag_AuthAnswer ) ? ' ' : '!',
+ ( flags & kDNSHeaderFlag_Truncation ) ? ' ' : '!',
+ ( flags & kDNSHeaderFlag_RecursionDesired ) ? ' ' : '!',
+ ( flags & kDNSHeaderFlag_RecursionAvailable ) ? ' ' : '!',
+ DNSFlagsRCodeToString( rcode ) );
+ FPrintF( stdout, "Question count: %u\n", questionCount );
+ FPrintF( stdout, "Answer count: %u\n", answerCount );
+ FPrintF( stdout, "Authority count: %u\n", authorityCount );
+ FPrintF( stdout, "Additional count: %u\n", additionalCount );
+
+ ptr = (uint8_t *)( hdr + 1 );
+ for( i = 0; i < questionCount; ++i )
+ {
+ unsigned int qType, qClass;
+ Boolean isQU;
+
+ err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, ptr, nameStr, &ptr );
+ require_noerr( err, exit );
+
+ if( ( msgEnd - ptr ) < 4 )
+ {
+ err = kUnderrunErr;
+ goto exit;
+ }
+
+ qType = ReadBig16( ptr );
+ ptr += 2;
+ qClass = ReadBig16( ptr );
+ ptr += 2;
+
+ isQU = ( inIsMDNS && ( qClass & kQClassUnicastResponseBit ) ) ? true : false;
+ if( inIsMDNS ) qClass &= ~kQClassUnicastResponseBit;
+
+ if( i == 0 ) FPrintF( stdout, "\nQUESTION SECTION\n" );
+
+ FPrintF( stdout, "%s %2s %?2s%?2u %-5s\n",
+ nameStr, inIsMDNS ? ( isQU ? "QU" : "QM" ) : "",
+ ( qClass == kDNSServiceClass_IN ), "IN", ( qClass != kDNSServiceClass_IN ), qClass,
+ RecordTypeToString( qType ) );
+ }
+
+ totalRRCount = answerCount + authorityCount + additionalCount;
+ for( i = 0; i < totalRRCount; ++i )
+ {
+ uint16_t type;
+ uint16_t class;
+ uint32_t ttl;
+ const uint8_t * rdataPtr;
+ size_t rdataLen;
+ char * rdataStr;
+ Boolean cacheFlush;
+ uint8_t name[ kDomainNameLengthMax ];
+
+ err = DNSMessageExtractRecord( inMsgPtr, inMsgLen, ptr, name, &type, &class, &ttl, &rdataPtr, &rdataLen, &ptr );
+ require_noerr( err, exit );
+
+ err = DomainNameToString( name, NULL, nameStr, NULL );
+ require_noerr( err, exit );
+
+ cacheFlush = ( inIsMDNS && ( class & kRRClassCacheFlushBit ) ) ? true : false;
+ if( inIsMDNS ) class &= ~kRRClassCacheFlushBit;
+
+ rdataStr = NULL;
+ if( !inPrintRaw ) DNSRecordDataToString( rdataPtr, rdataLen, type, inMsgPtr, inMsgLen, &rdataStr );
+ if( !rdataStr )
+ {
+ ASPrintF( &rdataStr, "%#H", rdataPtr, (int) rdataLen, INT_MAX );
+ require_action( rdataStr, exit, err = kNoMemoryErr );
+ }
+
+ if( answerCount && ( i == 0 ) ) FPrintF( stdout, "\nANSWER SECTION\n" );
+ else if( authorityCount && ( i == answerCount ) ) FPrintF( stdout, "\nAUTHORITY SECTION\n" );
+ else if( additionalCount && ( i == ( answerCount + authorityCount ) ) ) FPrintF( stdout, "\nADDITIONAL SECTION\n" );
+
+ FPrintF( stdout, "%-42s %6u %2s %?2s%?2u %-5s %s\n",
+ nameStr, ttl, cacheFlush ? "CF" : "",
+ ( class == kDNSServiceClass_IN ), "IN", ( class != kDNSServiceClass_IN ), class,
+ RecordTypeToString( type ), rdataStr );
+ free( rdataStr );
+ }
+ FPrintF( stdout, "\n" );
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// WriteDNSQueryMessage
+//===========================================================================================================================
+
+static OSStatus
+ WriteDNSQueryMessage(
+ uint8_t inMsg[ kDNSQueryMessageMaxLen ],
+ uint16_t inMsgID,
+ uint16_t inFlags,
+ const char * inQName,
+ uint16_t inQType,
+ uint16_t inQClass,
+ size_t * outMsgLen )
+{
+ OSStatus err;
+ DNSHeader * const hdr = (DNSHeader *) inMsg;
+ uint8_t * ptr;
+ size_t msgLen;
+
+ WriteBig16( hdr->id, inMsgID );
+ WriteBig16( hdr->flags, inFlags );
+ WriteBig16( hdr->questionCount, 1 );
+ WriteBig16( hdr->answerCount, 0 );
+ WriteBig16( hdr->authorityCount, 0 );
+ WriteBig16( hdr->additionalCount, 0 );
+
+ ptr = (uint8_t *)( hdr + 1 );
+ ptr[ 0 ] = 0;
+ err = DomainNameAppendString( ptr, inQName, &ptr );
+ require_noerr_quiet( err, exit );
+
+ WriteBig16( ptr, inQType );
+ ptr += 2;
+ WriteBig16( ptr, inQClass );
+ ptr += 2;
+ msgLen = (size_t)( ptr - inMsg );
+ check( msgLen <= kDNSQueryMessageMaxLen );
+
+ if( outMsgLen ) *outMsgLen = msgLen;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// DispatchSignalSourceCreate
+//===========================================================================================================================
+
+static OSStatus
+ DispatchSignalSourceCreate(
+ int inSignal,
+ DispatchHandler inEventHandler,
+ void * inContext,
+ dispatch_source_t * outSource )
+{
+ OSStatus err;
+ dispatch_source_t source;
+
+ source = dispatch_source_create( DISPATCH_SOURCE_TYPE_SIGNAL, (uintptr_t) inSignal, 0, dispatch_get_main_queue() );
+ require_action( source, exit, err = kUnknownErr );
+
+ dispatch_set_context( source, inContext );
+ dispatch_source_set_event_handler_f( source, inEventHandler );
+
+ *outSource = source;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// DispatchReadSourceCreate
+//===========================================================================================================================
+
+static OSStatus
+ DispatchReadSourceCreate(
+ SocketRef inSock,
+ DispatchHandler inEventHandler,
+ DispatchHandler inCancelHandler,
+ void * inContext,
+ dispatch_source_t * outSource )
+{
+ OSStatus err;
+ dispatch_source_t source;
+
+ source = dispatch_source_create( DISPATCH_SOURCE_TYPE_READ, (uintptr_t) inSock, 0, dispatch_get_main_queue() );
+ require_action( source, exit, err = kUnknownErr );
+
+ dispatch_set_context( source, inContext );
+ dispatch_source_set_event_handler_f( source, inEventHandler );
+ dispatch_source_set_cancel_handler_f( source, inCancelHandler );
+
+ *outSource = source;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// DispatchTimerCreate
+//===========================================================================================================================
+
+static OSStatus
+ DispatchTimerCreate(
+ dispatch_time_t inStart,
+ uint64_t inIntervalNs,
+ uint64_t inLeewayNs,
+ DispatchHandler inEventHandler,
+ DispatchHandler inCancelHandler,
+ void * inContext,
+ dispatch_source_t * outTimer )
+{
+ OSStatus err;
+ dispatch_source_t timer;
+
+ timer = dispatch_source_create( DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue() );
+ require_action( timer, exit, err = kUnknownErr );
+
+ dispatch_source_set_timer( timer, inStart, inIntervalNs, inLeewayNs );
+ dispatch_set_context( timer, inContext );
+ dispatch_source_set_event_handler_f( timer, inEventHandler );
+ dispatch_source_set_cancel_handler_f( timer, inCancelHandler );
+
+ *outTimer = timer;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// ServiceTypeDescription
+//===========================================================================================================================
+
+typedef struct
+{
+ const char * name; // Name of the service type in two-label "_service._proto" format.
+ const char * description; // Description of the service type.
+
+} ServiceType;
+
+// A Non-comprehensive table of DNS-SD service types
+
+static const ServiceType kServiceTypes[] =
+{
+ { "_acp-sync._tcp", "AirPort Base Station Sync" },
+ { "_adisk._tcp", "Automatic Disk Discovery" },
+ { "_afpovertcp._tcp", "Apple File Sharing" },
+ { "_airdrop._tcp", "AirDrop" },
+ { "_airplay._tcp", "AirPlay" },
+ { "_airport._tcp", "AirPort Base Station" },
+ { "_daap._tcp", "Digital Audio Access Protocol (iTunes)" },
+ { "_eppc._tcp", "Remote AppleEvents" },
+ { "_ftp._tcp", "File Transfer Protocol" },
+ { "_home-sharing._tcp", "Home Sharing" },
+ { "_homekit._tcp", "HomeKit" },
+ { "_http._tcp", "World Wide Web HTML-over-HTTP" },
+ { "_https._tcp", "HTTP over SSL/TLS" },
+ { "_ipp._tcp", "Internet Printing Protocol" },
+ { "_ldap._tcp", "Lightweight Directory Access Protocol" },
+ { "_mediaremotetv._tcp", "Media Remote" },
+ { "_net-assistant._tcp", "Apple Remote Desktop" },
+ { "_od-master._tcp", "OpenDirectory Master" },
+ { "_nfs._tcp", "Network File System" },
+ { "_presence._tcp", "Peer-to-peer messaging / Link-Local Messaging" },
+ { "_pdl-datastream._tcp", "Printer Page Description Language Data Stream" },
+ { "_raop._tcp", "Remote Audio Output Protocol" },
+ { "_rfb._tcp", "Remote Frame Buffer" },
+ { "_scanner._tcp", "Bonjour Scanning" },
+ { "_smb._tcp", "Server Message Block over TCP/IP" },
+ { "_sftp-ssh._tcp", "Secure File Transfer Protocol over SSH" },
+ { "_sleep-proxy._udp", "Sleep Proxy Server" },
+ { "_ssh._tcp", "SSH Remote Login Protocol" },
+ { "_teleport._tcp", "teleport" },
+ { "_tftp._tcp", "Trivial File Transfer Protocol" },
+ { "_workstation._tcp", "Workgroup Manager" },
+ { "_webdav._tcp", "World Wide Web Distributed Authoring and Versioning (WebDAV)" },
+ { "_webdavs._tcp", "WebDAV over SSL/TLS" }
+};
+
+static const char * ServiceTypeDescription( const char *inName )
+{
+ const ServiceType * serviceType;
+ const ServiceType * const end = kServiceTypes + countof( kServiceTypes );
+
+ for( serviceType = kServiceTypes; serviceType < end; ++serviceType )
+ {
+ if( strcasecmp( inName, serviceType->name ) == 0 ) return( serviceType->description );
+ }
+ return( NULL );
+}
+
+//===========================================================================================================================
+// SocketContextCancelHandler
+//===========================================================================================================================
+
+static void SocketContextCancelHandler( void *inContext )
+{
+ SocketContext * const context = (SocketContext *) inContext;
+
+ ForgetSocket( &context->sock );
+ free( context );
+}
+
+//===========================================================================================================================
+// StringToInt32
+//===========================================================================================================================
+
+static OSStatus StringToInt32( const char *inString, int32_t *outValue )
+{
+ OSStatus err;
+ long value;
+ char * endPtr;
+
+ value = strtol( inString, &endPtr, 0 );
+ require_action_quiet( ( *endPtr == '\0' ) && ( endPtr != inString ), exit, err = kParamErr );
+ require_action_quiet( ( value >= INT32_MIN ) && ( value <= INT32_MAX ), exit, err = kRangeErr );
+
+ *outValue = (int32_t) value;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// StringToUInt32
+//===========================================================================================================================
+
+static OSStatus StringToUInt32( const char *inString, uint32_t *outValue )
+{
+ OSStatus err;
+ uint32_t value;
+ char * endPtr;
+
+ value = (uint32_t) strtol( inString, &endPtr, 0 );
+ require_action_quiet( ( *endPtr == '\0' ) && ( endPtr != inString ), exit, err = kParamErr );
+
+ *outValue = value;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// SocketWriteAll
+//
+// Note: This was copied from CoreUtils because the SocketWriteAll function is currently not exported in the framework.
+//===========================================================================================================================
+
+OSStatus SocketWriteAll( SocketRef inSock, const void *inData, size_t inSize, int32_t inTimeoutSecs )
+{
+ OSStatus err;
+ const uint8_t * src;
+ const uint8_t * end;
+ fd_set writeSet;
+ struct timeval timeout;
+ ssize_t n;
+
+ FD_ZERO( &writeSet );
+ src = (const uint8_t *) inData;
+ end = src + inSize;
+ while( src < end )
+ {
+ FD_SET( inSock, &writeSet );
+ timeout.tv_sec = inTimeoutSecs;
+ timeout.tv_usec = 0;
+ n = select( (int)( inSock + 1 ), NULL, &writeSet, NULL, &timeout );
+ if( n == 0 ) { err = kTimeoutErr; goto exit; }
+ err = map_socket_value_errno( inSock, n > 0, n );
+ require_noerr( err, exit );
+
+ n = send( inSock, (char *) src, (size_t)( end - src ), 0 );
+ err = map_socket_value_errno( inSock, n >= 0, n );
+ if( err == EINTR ) continue;
+ require_noerr( err, exit );
+
+ src += n;
+ }
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// ParseEscapedString
+//
+// Note: This was copied from CoreUtils because the ParseEscapedString function is currently not exported in the framework.
+//===========================================================================================================================
+
+OSStatus
+ ParseEscapedString(
+ const char * inSrc,
+ const char * inEnd,
+ char inDelimiter,
+ char * inBuf,
+ size_t inMaxLen,
+ size_t * outCopiedLen,
+ size_t * outTotalLen,
+ const char ** outSrc )
+{
+ OSStatus err;
+ char c;
+ char * dst;
+ char * lim;
+ size_t len;
+
+ dst = inBuf;
+ lim = dst + ( ( inMaxLen > 0 ) ? ( inMaxLen - 1 ) : 0 ); // Leave room for null terminator.
+ len = 0;
+ while( ( inSrc < inEnd ) && ( ( c = *inSrc++ ) != inDelimiter ) )
+ {
+ if( c == '\\' )
+ {
+ require_action_quiet( inSrc < inEnd, exit, err = kUnderrunErr );
+ c = *inSrc++;
+ }
+ if( dst < lim )
+ {
+ if( inBuf ) *dst = c;
+ ++dst;
+ }
+ ++len;
+ }
+ if( inBuf && ( inMaxLen > 0 ) ) *dst = '\0';
+ err = kNoErr;
+
+exit:
+ if( outCopiedLen ) *outCopiedLen = (size_t)( dst - inBuf );
+ if( outTotalLen ) *outTotalLen = len;
+ if( outSrc ) *outSrc = inSrc;
+ return( err );
+}
+
+//===========================================================================================================================
+// ParseIPv4Address
+//
+// Warning: "inBuffer" may be modified even in error cases.
+//
+// Note: This was copied from CoreUtils because the StringToIPv4Address function is currently not exported in the framework.
+//===========================================================================================================================
+
+static OSStatus ParseIPv4Address( const char *inStr, uint8_t inBuffer[ 4 ], const char **outStr )
+{
+ OSStatus err;
+ uint8_t * dst;
+ int segments;
+ int sawDigit;
+ int c;
+ int v;
+
+ check( inBuffer );
+ check( outStr );
+
+ dst = inBuffer;
+ *dst = 0;
+ sawDigit = 0;
+ segments = 0;
+ for( ; ( c = *inStr ) != '\0'; ++inStr )
+ {
+ if( isdigit_safe( c ) )
+ {
+ v = ( *dst * 10 ) + ( c - '0' );
+ require_action_quiet( v <= 255, exit, err = kRangeErr );
+ *dst = (uint8_t) v;
+ if( !sawDigit )
+ {
+ ++segments;
+ require_action_quiet( segments <= 4, exit, err = kOverrunErr );
+ sawDigit = 1;
+ }
+ }
+ else if( ( c == '.' ) && sawDigit )
+ {
+ require_action_quiet( segments < 4, exit, err = kMalformedErr );
+ *++dst = 0;
+ sawDigit = 0;
+ }
+ else
+ {
+ break;
+ }
+ }
+ require_action_quiet( segments == 4, exit, err = kUnderrunErr );
+
+ *outStr = inStr;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// StringToIPv4Address
+//
+// Note: This was copied from CoreUtils because the StringToIPv4Address function is currently not exported in the framework.
+//===========================================================================================================================
+
+OSStatus
+ StringToIPv4Address(
+ const char * inStr,
+ StringToIPAddressFlags inFlags,
+ uint32_t * outIP,
+ int * outPort,
+ uint32_t * outSubnet,
+ uint32_t * outRouter,
+ const char ** outStr )
+{
+ OSStatus err;
+ uint8_t buf[ 4 ];
+ int c;
+ uint32_t ip;
+ int hasPort;
+ int port;
+ int hasPrefix;
+ int prefix;
+ uint32_t subnetMask;
+ uint32_t router;
+
+ require_action( inStr, exit, err = kParamErr );
+
+ // Parse the address-only part of the address (e.g. "1.2.3.4").
+
+ err = ParseIPv4Address( inStr, buf, &inStr );
+ require_noerr_quiet( err, exit );
+ ip = (uint32_t)( ( buf[ 0 ] << 24 ) | ( buf[ 1 ] << 16 ) | ( buf[ 2 ] << 8 ) | buf[ 3 ] );
+ c = *inStr;
+
+ // Parse the port (if any).
+
+ hasPort = 0;
+ port = 0;
+ if( c == ':' )
+ {
+ require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoPort ), exit, err = kUnexpectedErr );
+ while( ( ( c = *( ++inStr ) ) != '\0' ) && ( ( c >= '0' ) && ( c <= '9' ) ) ) port = ( port * 10 ) + ( c - '0' );
+ require_action_quiet( port <= 65535, exit, err = kRangeErr );
+ hasPort = 1;
+ }
+
+ // Parse the prefix length (if any).
+
+ hasPrefix = 0;
+ prefix = 0;
+ subnetMask = 0;
+ router = 0;
+ if( c == '/' )
+ {
+ require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoPrefix ), exit, err = kUnexpectedErr );
+ while( ( ( c = *( ++inStr ) ) != '\0' ) && ( ( c >= '0' ) && ( c <= '9' ) ) ) prefix = ( prefix * 10 ) + ( c - '0' );
+ require_action_quiet( ( prefix >= 0 ) && ( prefix <= 32 ), exit, err = kRangeErr );
+ hasPrefix = 1;
+
+ subnetMask = ( prefix > 0 ) ? ( UINT32_C( 0xFFFFFFFF ) << ( 32 - prefix ) ) : 0;
+ router = ( ip & subnetMask ) | 1;
+ }
+
+ // Return the results. Only fill in port/prefix/router results if the info was found to allow for defaults.
+
+ if( outIP ) *outIP = ip;
+ if( outPort && hasPort ) *outPort = port;
+ if( outSubnet && hasPrefix ) *outSubnet = subnetMask;
+ if( outRouter && hasPrefix ) *outRouter = router;
+ if( outStr ) *outStr = inStr;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// ParseIPv6Address
+//
+// Note: Parsed according to the rules specified in RFC 3513.
+// Warning: "inBuffer" may be modified even in error cases.
+//
+// Note: This was copied from CoreUtils because the StringToIPv6Address function is currently not exported in the framework.
+//===========================================================================================================================
+
+static OSStatus ParseIPv6Address( const char *inStr, int inAllowV4Mapped, uint8_t inBuffer[ 16 ], const char **outStr )
+{
+ // Table to map uppercase hex characters - '0' to their numeric values.
+ // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F
+ static const uint8_t kASCIItoHexTable[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15 };
+ OSStatus err;
+ const char * ptr;
+ uint8_t * dst;
+ uint8_t * lim;
+ uint8_t * colonPtr;
+ int c;
+ int sawDigit;
+ unsigned int v;
+ int i;
+ int n;
+
+ // Pre-zero the address to simplify handling of compressed addresses (e.g. "::1").
+
+ for( i = 0; i < 16; ++i ) inBuffer[ i ] = 0;
+
+ // Special case leading :: (e.g. "::1") to simplify processing later.
+
+ if( *inStr == ':' )
+ {
+ ++inStr;
+ require_action_quiet( *inStr == ':', exit, err = kMalformedErr );
+ }
+
+ // Parse the address.
+
+ ptr = inStr;
+ dst = inBuffer;
+ lim = dst + 16;
+ colonPtr = NULL;
+ sawDigit = 0;
+ v = 0;
+ while( ( ( c = *inStr++ ) != '\0' ) && ( c != '%' ) && ( c != '/' ) && ( c != ']' ) )
+ {
+ if( ( c >= 'a' ) && ( c <= 'f' ) ) c -= ( 'a' - 'A' );
+ if( ( ( c >= '0' ) && ( c <= '9' ) ) || ( ( c >= 'A' ) && ( c <= 'F' ) ) )
+ {
+ c -= '0';
+ check( c < (int) countof( kASCIItoHexTable ) );
+ v = ( v << 4 ) | kASCIItoHexTable[ c ];
+ require_action_quiet( v <= 0xFFFF, exit, err = kRangeErr );
+ sawDigit = 1;
+ continue;
+ }
+ if( c == ':' )
+ {
+ ptr = inStr;
+ if( !sawDigit )
+ {
+ require_action_quiet( !colonPtr, exit, err = kMalformedErr );
+ colonPtr = dst;
+ continue;
+ }
+ require_action_quiet( *inStr != '\0', exit, err = kUnderrunErr );
+ require_action_quiet( ( dst + 2 ) <= lim, exit, err = kOverrunErr );
+ *dst++ = (uint8_t)( ( v >> 8 ) & 0xFF );
+ *dst++ = (uint8_t)( v & 0xFF );
+ sawDigit = 0;
+ v = 0;
+ continue;
+ }
+
+ // Handle IPv4-mapped/compatible addresses (e.g. ::FFFF:1.2.3.4).
+
+ if( inAllowV4Mapped && ( c == '.' ) && ( ( dst + 4 ) <= lim ) )
+ {
+ err = ParseIPv4Address( ptr, dst, &inStr );
+ require_noerr_quiet( err, exit );
+ dst += 4;
+ sawDigit = 0;
+ ++inStr; // Increment because the code below expects the end to be at "inStr - 1".
+ }
+ break;
+ }
+ if( sawDigit )
+ {
+ require_action_quiet( ( dst + 2 ) <= lim, exit, err = kOverrunErr );
+ *dst++ = (uint8_t)( ( v >> 8 ) & 0xFF );
+ *dst++ = (uint8_t)( v & 0xFF );
+ }
+ check( dst <= lim );
+ if( colonPtr )
+ {
+ require_action_quiet( dst < lim, exit, err = kOverrunErr );
+ n = (int)( dst - colonPtr );
+ for( i = 1; i <= n; ++i )
+ {
+ lim[ -i ] = colonPtr[ n - i ];
+ colonPtr[ n - i ] = 0;
+ }
+ dst = lim;
+ }
+ require_action_quiet( dst == lim, exit, err = kUnderrunErr );
+
+ *outStr = inStr - 1;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// ParseIPv6Scope
+//
+// Note: This was copied from CoreUtils because the StringToIPv6Address function is currently not exported in the framework.
+//===========================================================================================================================
+
+static OSStatus ParseIPv6Scope( const char *inStr, uint32_t *outScope, const char **outStr )
+{
+#if( TARGET_OS_POSIX )
+ OSStatus err;
+ char scopeStr[ 64 ];
+ char * dst;
+ char * lim;
+ int c;
+ uint32_t scope;
+ const char * ptr;
+
+ // Copy into a local NULL-terminated string since that is what if_nametoindex expects.
+
+ dst = scopeStr;
+ lim = dst + ( countof( scopeStr ) - 1 );
+ while( ( ( c = *inStr ) != '\0' ) && ( c != ':' ) && ( c != '/' ) && ( c != ']' ) && ( dst < lim ) )
+ {
+ *dst++ = *inStr++;
+ }
+ *dst = '\0';
+ check( dst <= lim );
+
+ // First try to map as a name and if that fails, treat it as a numeric scope.
+
+ scope = if_nametoindex( scopeStr );
+ if( scope == 0 )
+ {
+ for( ptr = scopeStr; ( ( c = *ptr ) >= '0' ) && ( c <= '9' ); ++ptr )
+ {
+ scope = ( scope * 10 ) + ( ( (uint8_t) c ) - '0' );
+ }
+ require_action_quiet( c == '\0', exit, err = kMalformedErr );
+ require_action_quiet( ( ptr != scopeStr ) && ( ( (int)( ptr - scopeStr ) ) <= 10 ), exit, err = kMalformedErr );
+ }
+
+ *outScope = scope;
+ *outStr = inStr;
+ err = kNoErr;
+
+exit:
+ return( err );
+#else
+ OSStatus err;
+ uint32_t scope;
+ const char * start;
+ int c;
+
+ scope = 0;
+ for( start = inStr; ( ( c = *inStr ) >= '0' ) && ( c <= '9' ); ++inStr )
+ {
+ scope = ( scope * 10 ) + ( c - '0' );
+ }
+ require_action_quiet( ( inStr != start ) && ( ( (int)( inStr - start ) ) <= 10 ), exit, err = kMalformedErr );
+
+ *outScope = scope;
+ *outStr = inStr;
+ err = kNoErr;
+
+exit:
+ return( err );
+#endif
+}
+
+//===========================================================================================================================
+// StringToIPv6Address
+//
+// Note: This was copied from CoreUtils because the StringToIPv6Address function is currently not exported in the framework.
+//===========================================================================================================================
+
+OSStatus
+ StringToIPv6Address(
+ const char * inStr,
+ StringToIPAddressFlags inFlags,
+ uint8_t outIPv6[ 16 ],
+ uint32_t * outScope,
+ int * outPort,
+ int * outPrefix,
+ const char ** outStr )
+{
+ OSStatus err;
+ uint8_t ipv6[ 16 ];
+ int c;
+ int hasScope;
+ uint32_t scope;
+ int hasPort;
+ int port;
+ int hasPrefix;
+ int prefix;
+ int hasBracket;
+ int i;
+
+ require_action( inStr, exit, err = kParamErr );
+
+ if( *inStr == '[' ) ++inStr; // Skip a leading bracket for []-wrapped addresses (e.g. "[::1]:80").
+
+ // Parse the address-only part of the address (e.g. "1::1").
+
+ err = ParseIPv6Address( inStr, !( inFlags & kStringToIPAddressFlagsNoIPv4Mapped ), ipv6, &inStr );
+ require_noerr_quiet( err, exit );
+ c = *inStr;
+
+ // Parse the scope, port, or prefix length.
+
+ hasScope = 0;
+ scope = 0;
+ hasPort = 0;
+ port = 0;
+ hasPrefix = 0;
+ prefix = 0;
+ hasBracket = 0;
+ for( ;; )
+ {
+ if( c == '%' ) // Scope (e.g. "%en0" or "%5")
+ {
+ require_action_quiet( !hasScope, exit, err = kMalformedErr );
+ require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoScope ), exit, err = kUnexpectedErr );
+ ++inStr;
+ err = ParseIPv6Scope( inStr, &scope, &inStr );
+ require_noerr_quiet( err, exit );
+ hasScope = 1;
+ c = *inStr;
+ }
+ else if( c == ':' ) // Port (e.g. ":80")
+ {
+ require_action_quiet( !hasPort, exit, err = kMalformedErr );
+ require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoPort ), exit, err = kUnexpectedErr );
+ while( ( ( c = *( ++inStr ) ) != '\0' ) && ( ( c >= '0' ) && ( c <= '9' ) ) ) port = ( port * 10 ) + ( c - '0' );
+ require_action_quiet( port <= 65535, exit, err = kRangeErr );
+ hasPort = 1;
+ }
+ else if( c == '/' ) // Prefix Length (e.g. "/64")
+ {
+ require_action_quiet( !hasPrefix, exit, err = kMalformedErr );
+ require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoPrefix ), exit, err = kUnexpectedErr );
+ while( ( ( c = *( ++inStr ) ) != '\0' ) && ( ( c >= '0' ) && ( c <= '9' ) ) ) prefix = ( prefix * 10 ) + ( c - '0' );
+ require_action_quiet( ( prefix >= 0 ) && ( prefix <= 128 ), exit, err = kRangeErr );
+ hasPrefix = 1;
+ }
+ else if( c == ']' )
+ {
+ require_action_quiet( !hasBracket, exit, err = kMalformedErr );
+ hasBracket = 1;
+ c = *( ++inStr );
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ // Return the results. Only fill in scope/port/prefix results if the info was found to allow for defaults.
+
+ if( outIPv6 ) for( i = 0; i < 16; ++i ) outIPv6[ i ] = ipv6[ i ];
+ if( outScope && hasScope ) *outScope = scope;
+ if( outPort && hasPort ) *outPort = port;
+ if( outPrefix && hasPrefix ) *outPrefix = prefix;
+ if( outStr ) *outStr = inStr;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// StringArray_Append
+//
+// Note: This was copied from CoreUtils because the StringArray_Append function is currently not exported in the framework.
+//===========================================================================================================================
+
+OSStatus StringArray_Append( char ***ioArray, size_t *ioCount, const char *inStr )
+{
+ OSStatus err;
+ char * newStr;
+ size_t oldCount;
+ size_t newCount;
+ char ** oldArray;
+ char ** newArray;
+
+ newStr = strdup( inStr );
+ require_action( newStr, exit, err = kNoMemoryErr );
+
+ oldCount = *ioCount;
+ newCount = oldCount + 1;
+ newArray = (char **) malloc( newCount * sizeof( *newArray ) );
+ require_action( newArray, exit, err = kNoMemoryErr );
+
+ if( oldCount > 0 )
+ {
+ oldArray = *ioArray;
+ memcpy( newArray, oldArray, oldCount * sizeof( *oldArray ) );
+ free( oldArray );
+ }
+ newArray[ oldCount ] = newStr;
+ newStr = NULL;
+
+ *ioArray = newArray;
+ *ioCount = newCount;
+ err = kNoErr;
+
+exit:
+ if( newStr ) free( newStr );
+ return( err );
+}
+
+//===========================================================================================================================
+// StringArray_Free
+//
+// Note: This was copied from CoreUtils because the StringArray_Free function is currently not exported in the framework.
+//===========================================================================================================================
+
+void StringArray_Free( char **inArray, size_t inCount )
+{
+ size_t i;
+
+ for( i = 0; i < inCount; ++i )
+ {
+ free( inArray[ i ] );
+ }
+ if( inCount > 0 ) free( inArray );
+}
+
+//===========================================================================================================================
+// ParseQuotedEscapedString
+//
+// Note: This was copied from CoreUtils because it's currently not exported in the framework.
+//===========================================================================================================================
+
+Boolean
+ ParseQuotedEscapedString(
+ const char * inSrc,
+ const char * inEnd,
+ const char * inDelimiters,
+ char * inBuf,
+ size_t inMaxLen,
+ size_t * outCopiedLen,
+ size_t * outTotalLen,
+ const char ** outSrc )
+{
+ const unsigned char * src;
+ const unsigned char * end;
+ unsigned char * dst;
+ unsigned char * lim;
+ unsigned char c;
+ unsigned char c2;
+ size_t totalLen;
+ Boolean singleQuote;
+ Boolean doubleQuote;
+
+ if( inEnd == NULL ) inEnd = inSrc + strlen( inSrc );
+ src = (const unsigned char *) inSrc;
+ end = (const unsigned char *) inEnd;
+ dst = (unsigned char *) inBuf;
+ lim = dst + inMaxLen;
+ while( ( src < end ) && isspace_safe( *src ) ) ++src; // Skip leading spaces.
+ if( src >= end ) return( false );
+
+ // Parse each argument from the string.
+ //
+ // See <http://resources.mpi-inf.mpg.de/departments/rg1/teaching/unixffb-ss98/quoting-guide.html> for details.
+
+ totalLen = 0;
+ singleQuote = false;
+ doubleQuote = false;
+ while( src < end )
+ {
+ c = *src++;
+ if( singleQuote )
+ {
+ // Single quotes protect everything (even backslashes, newlines, etc.) except single quotes.
+
+ if( c == '\'' )
+ {
+ singleQuote = false;
+ continue;
+ }
+ }
+ else if( doubleQuote )
+ {
+ // Double quotes protect everything except double quotes and backslashes. A backslash can be
+ // used to protect " or \ within double quotes. A backslash-newline pair disappears completely.
+ // A backslash followed by x or X and 2 hex digits (e.g. "\x1f") is stored as that hex byte.
+ // A backslash followed by 3 octal digits (e.g. "\377") is stored as that octal byte.
+ // A backslash that does not precede ", \, x, X, or a newline is taken literally.
+
+ if( c == '"' )
+ {
+ doubleQuote = false;
+ continue;
+ }
+ else if( c == '\\' )
+ {
+ if( src < end )
+ {
+ c2 = *src;
+ if( ( c2 == '"' ) || ( c2 == '\\' ) )
+ {
+ ++src;
+ c = c2;
+ }
+ else if( c2 == '\n' )
+ {
+ ++src;
+ continue;
+ }
+ else if( ( c2 == 'x' ) || ( c2 == 'X' ) )
+ {
+ ++src;
+ c = c2;
+ if( ( ( end - src ) >= 2 ) && IsHexPair( src ) )
+ {
+ c = HexPairToByte( src );
+ src += 2;
+ }
+ }
+ else if( isoctal_safe( c2 ) )
+ {
+ if( ( ( end - src ) >= 3 ) && IsOctalTriple( src ) )
+ {
+ c = OctalTripleToByte( src );
+ src += 3;
+ }
+ }
+ }
+ }
+ }
+ else if( strchr( inDelimiters, c ) )
+ {
+ break;
+ }
+ else if( c == '\\' )
+ {
+ // A backslash protects the next character, except a newline, x, X and 2 hex bytes or 3 octal bytes.
+ // A backslash followed by a newline disappears completely.
+ // A backslash followed by x or X and 2 hex digits (e.g. "\x1f") is stored as that hex byte.
+ // A backslash followed by 3 octal digits (e.g. "\377") is stored as that octal byte.
+
+ if( src < end )
+ {
+ c = *src;
+ if( c == '\n' )
+ {
+ ++src;
+ continue;
+ }
+ else if( ( c == 'x' ) || ( c == 'X' ) )
+ {
+ ++src;
+ if( ( ( end - src ) >= 2 ) && IsHexPair( src ) )
+ {
+ c = HexPairToByte( src );
+ src += 2;
+ }
+ }
+ else if( isoctal_safe( c ) )
+ {
+ if( ( ( end - src ) >= 3 ) && IsOctalTriple( src ) )
+ {
+ c = OctalTripleToByte( src );
+ src += 3;
+ }
+ else
+ {
+ ++src;
+ }
+ }
+ else
+ {
+ ++src;
+ }
+ }
+ }
+ else if( c == '\'' )
+ {
+ singleQuote = true;
+ continue;
+ }
+ else if( c == '"' )
+ {
+ doubleQuote = true;
+ continue;
+ }
+
+ if( dst < lim )
+ {
+ if( inBuf ) *dst = c;
+ ++dst;
+ }
+ ++totalLen;
+ }
+
+ if( outCopiedLen ) *outCopiedLen = (size_t)( dst - ( (unsigned char *) inBuf ) );
+ if( outTotalLen ) *outTotalLen = totalLen;
+ if( outSrc ) *outSrc = (const char *) src;
+ return( true );
+}
diff --git a/mDNSResponder/Documents/Start mDNSResponder in Xcode.rtfd/TXT.rtf b/mDNSResponder/Documents/Start mDNSResponder in Xcode.rtfd/TXT.rtf
index 13e14d4a..340c2dc9 100644
--- a/mDNSResponder/Documents/Start mDNSResponder in Xcode.rtfd/TXT.rtf
+++ b/mDNSResponder/Documents/Start mDNSResponder in Xcode.rtfd/TXT.rtf
@@ -1,12 +1,13 @@
-{\rtf1\ansi\ansicpg1252\cocoartf1404\cocoasubrtf460
+{\rtf1\ansi\ansicpg1252\cocoartf1504\cocoasubrtf150
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
{\colortbl;\red255\green255\blue255;}
+{\*\expandedcolortbl;\csgray\c100000;}
\margl1440\margr1440\vieww51000\viewh25780\viewkind0
\deftab720
\pard\pardeftab720\partightenfactor0
\f0\fs24 \cf0 \expnd0\expndtw0\kerning0
-Instructions on how to run a secondary mDNSResponder in the Xcode debugger. (Two known issues, the secondary mDNSResponder will not send unicast mDNS packets and it does not support BTMM.)\
+Instructions on how to run a secondary mDNSResponder in the Xcode debugger. (Two known issues, the secondary mDNSResponder will not receive unicast mDNS packets and it does not support BTMM.)\
\
1.) From Terminal shell, open mDNSResponder Xcode project. \'a0\
\
diff --git a/mDNSResponder/Makefile b/mDNSResponder/Makefile
index 2b528d03..8a15f95e 100644
--- a/mDNSResponder/Makefile
+++ b/mDNSResponder/Makefile
@@ -16,25 +16,26 @@
include $(MAKEFILEPATH)/pb_makefiles/platform.make
-MVERS = "mDNSResponder-765.50.9"
+MVERS = "mDNSResponder-878.1.1"
-DDNSWRITECONFIG = "$(DSTROOT)/Library/Application Support/Bonjour/ddnswriteconfig"
-VER =
+VER =
ifneq ($(strip $(GCC_VERSION)),)
VER = -- GCC_VERSION=$(GCC_VERSION)
endif
echo "VER = $(VER)"
installSome:
- cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target Build\ Some $(VER)
+ifneq ($(findstring iphoneos, $(shell echo '$(SDKROOT)' | tr '[:upper:]' '[:lower:]')),)
+ cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target Build\ Some\ iOS $(VER)
+else
+ cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target Build\ Some $(VER)
+endif
SystemLibraries:
cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target SystemLibraries $(VER)
install:
cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) $(VER)
- # Make sure ddnswriteconfig is owned by root:wheel, then make it setuid root executable
- if test -e $(DDNSWRITECONFIG) ; then chown 0:80 $(DDNSWRITECONFIG) ; chmod 4555 $(DDNSWRITECONFIG) ; fi
installsrc:
ditto . "$(SRCROOT)"
diff --git a/mDNSResponder/mDNSCore/DNSCommon.c b/mDNSResponder/mDNSCore/DNSCommon.c
index 3ea9a307..be8e1065 100644
--- a/mDNSResponder/mDNSCore/DNSCommon.c
+++ b/mDNSResponder/mDNSCore/DNSCommon.c
@@ -21,6 +21,10 @@
#include "CryptoAlg.h"
#include "anonymous.h"
+#ifdef UNIT_TEST
+#include "unittest.h"
+#endif
+
// Disable certain benign warnings with Microsoft compilers
#if (defined(_MSC_VER))
// Disable "conditional expression is constant" warning for debug macros.
@@ -111,7 +115,8 @@ mDNSexport const mDNSOpaque16 UpdateRespFlags = { { kDNSFlag0_QR_Response | kDNS
mDNSexport const mDNSOpaque16 SubscribeFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_Subscribe, 0 } };
mDNSexport const mDNSOpaque16 UnSubscribeFlags= { { kDNSFlag0_QR_Query | kDNSFlag0_OP_UnSubscribe, 0 } };
-mDNSexport const mDNSOpaque64 zeroOpaque64 = { { 0 } };
+mDNSexport const mDNSOpaque64 zeroOpaque64 = { { 0 } };
+mDNSexport const mDNSOpaque128 zeroOpaque128 = { { 0 } };
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
@@ -622,6 +627,8 @@ mDNSexport mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip)
#pragma mark - Domain Name Utility Functions
#endif
+#if !APPLE_OSX_mDNSResponder
+
mDNSexport mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
{
int i;
@@ -642,6 +649,8 @@ mDNSexport mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
return(mDNStrue);
}
+#endif // !APPLE_OSX_mDNSResponder
+
mDNSexport mDNSBool SameDomainName(const domainname *const d1, const domainname *const d2)
{
const mDNSu8 * a = d1->c;
@@ -971,10 +980,6 @@ mDNSexport void ConvertUTF8PstringToRFC1034HostLabel(const mDNSu8 UTF8Name[], do
hostlabel->c[0] = (mDNSu8)(ptr - &hostlabel->c[1]);
}
-#define ValidTransportProtocol(X) ( (X)[0] == 4 && (X)[1] == '_' && \
- ((((X)[2] | 0x20) == 'u' && ((X)[3] | 0x20) == 'd') || (((X)[2] | 0x20) == 't' && ((X)[3] | 0x20) == 'c')) && \
- ((X)[4] | 0x20) == 'p')
-
mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn,
const domainlabel *name, const domainname *type, const domainname *const domain)
{
@@ -1033,10 +1038,6 @@ mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn,
{
LogMsg("Bad service type in %#s.%##s%##s Application protocol name must be underscore plus 1-15 characters. "
"See <http://www.dns-sd.org/ServiceTypes.html>", name->c, type->c, domain->c);
-#if APPLE_OSX_mDNSResponder
- ConvertDomainNameToCString(type, typeBuf);
- mDNSASLLog(mDNSNULL, "serviceType.nameTooLong", "noop", typeBuf, "");
-#endif
}
if (len < 2 || len >= 0x40 || (len > 16 && !SameDomainName(domain, &localdomain))) return(mDNSNULL);
if (src[1] != '_') { errormsg = "Application protocol name must begin with underscore"; goto fail; }
@@ -1053,19 +1054,13 @@ mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn,
if (src[i] == '_' && loggedUnderscore == mDNSfalse)
{
ConvertDomainNameToCString(type, typeBuf);
- mDNSASLLog(mDNSNULL, "serviceType.nameWithUnderscore", "noop", typeBuf, "");
+ LogInfo("ConstructServiceName: Service type with non-leading underscore %s", typeBuf);
loggedUnderscore = mDNStrue;
}
#endif
continue;
}
errormsg = "Application protocol name must contain only letters, digits, and hyphens";
-#if APPLE_OSX_mDNSResponder
- {
- ConvertDomainNameToCString(type, typeBuf);
- mDNSASLLog(mDNSNULL, "serviceType.nameWithIllegalCharacters", "noop", typeBuf, "");
- }
-#endif
goto fail;
}
for (i=0; i<=len; i++) *dst++ = *src++;
@@ -2754,12 +2749,12 @@ mDNSexport const mDNSu8 *getDomainName(const DNSMessage *const msg, const mDNSu8
while (1) // Read sequence of labels
{
+ int i;
+ mDNSu16 offset;
const mDNSu8 len = *ptr++; // Read length of this label
if (len == 0) break; // If length is zero, that means this name is complete
switch (len & 0xC0)
{
- int i;
- mDNSu16 offset;
case 0x00: if (ptr + len >= end) // Remember: expect at least one more byte for the root label
{ debugf("getDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL); }
@@ -3457,12 +3452,6 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
rr->CRActiveQuestion = mDNSNULL;
rr->UnansweredQueries = 0;
rr->LastUnansweredTime= 0;
-#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
- rr->MPUnansweredQ = 0;
- rr->MPLastUnansweredQT= 0;
- rr->MPUnansweredKA = 0;
- rr->MPExpectingKA = mDNSfalse;
-#endif
rr->NextInCFList = mDNSNULL;
rr->resrec.InterfaceID = InterfaceID;
@@ -3617,16 +3606,27 @@ mDNSexport const rdataOPT *GetLLQOptData(mDNS *const m, const DNSMessage *const
}
// Get the lease life of records in a dynamic update
-// returns 0 on error or if no lease present
-mDNSexport mDNSu32 GetPktLease(mDNS *m, DNSMessage *msg, const mDNSu8 *end)
+mDNSexport mDNSBool GetPktLease(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, mDNSu32 *const lease)
{
- mDNSu32 result = 0;
const mDNSu8 *ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space);
- if (ptr) ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
- if (ptr && m->rec.r.resrec.rdlength >= DNSOpt_LeaseData_Space && m->rec.r.resrec.rdata->u.opt[0].opt == kDNSOpt_Lease)
- result = m->rec.r.resrec.rdata->u.opt[0].u.updatelease;
- m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
- return(result);
+ if (ptr)
+ {
+ ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
+ if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && m->rec.r.resrec.rrtype == kDNSType_OPT)
+ {
+ const rdataOPT *o;
+ const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength];
+ for (o = &m->rec.r.resrec.rdata->u.opt[0]; o < e; o++)
+ if (o->opt == kDNSOpt_Lease)
+ {
+ *lease = o->u.updatelease;
+ m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
+ return mDNStrue;
+ }
+ }
+ m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
+ }
+ return mDNSfalse;
}
mDNSlocal const mDNSu8 *DumpRecords(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end, int count, char *label)
@@ -3725,6 +3725,10 @@ mDNSexport void DumpPacket(mDNS *const m, mStatus status, mDNSBool sent, char *t
#pragma mark - Packet Sending Functions
#endif
+#ifdef UNIT_TEST
+// Run the unit test of mDNSSendDNSMessage
+UNITTEST_SENDDNSMESSAGE
+#else
// Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.)
struct TCPSocket_struct { TCPSocketFlags flags; /* ... */ };
// Stub definition of UDPSocket_struct so we can access port field. (Rest of UDPSocket_struct is platform-dependent.)
@@ -3826,6 +3830,7 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS
return(status);
}
+#endif // UNIT_TEST
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
@@ -3883,7 +3888,7 @@ mDNSlocal AuthRecord *AnyLocalRecordReady(const mDNS *const m)
mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m)
{
- mDNSs32 e = m->timenow + 0x78000000;
+ mDNSs32 e = m->timenow + FutureTime;
if (m->mDNSPlatformStatus != mStatus_NoError) return(e);
if (m->NewQuestions)
{
@@ -4057,7 +4062,8 @@ mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt
for (c = *fmt; c != 0; c = *++fmt)
{
- if (c != '%')
+ unsigned long n;
+ if (c != '%')
{
*sbuffer++ = (char)c;
if (++nwritten >= buflen) goto exit;
@@ -4113,7 +4119,6 @@ mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt
conv:
switch (c) // perform appropriate conversion
{
- unsigned long n;
case 'h': F.hSize = 1; c = *++fmt; goto conv;
case 'l': // fall through
case 'L': F.lSize = 1; c = *++fmt; goto conv;
diff --git a/mDNSResponder/mDNSCore/DNSCommon.h b/mDNSResponder/mDNSCore/DNSCommon.h
index 2da19700..e1ef261e 100644
--- a/mDNSResponder/mDNSCore/DNSCommon.h
+++ b/mDNSResponder/mDNSCore/DNSCommon.h
@@ -240,8 +240,7 @@ extern const mDNSu8 *NSEC3HashName(const domainname *name, rdataNSEC3 *nsec3, co
#pragma mark - DNS Message Parsing Functions
#endif
-#define AuthHashSlot(X) (DomainNameHashValue(X) % AUTH_HASH_SLOTS)
-#define HashSlot(X) (DomainNameHashValue(X) % CACHE_HASH_SLOTS)
+#define HashSlotFromNameHash(X) ((X) % CACHE_HASH_SLOTS)
extern mDNSu32 DomainNameHashValue(const domainname *const name);
extern void SetNewRData(ResourceRecord *const rr, RData *NewRData, mDNSu16 rdlength);
extern const mDNSu8 *skipDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end);
@@ -260,7 +259,7 @@ extern const mDNSu8 *LocateAuthorities(const DNSMessage *const msg, const mDNSu8
extern const mDNSu8 *LocateAdditionals(const DNSMessage *const msg, const mDNSu8 *const end);
extern const mDNSu8 *LocateOptRR(const DNSMessage *const msg, const mDNSu8 *const end, int minsize);
extern const rdataOPT *GetLLQOptData(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end);
-extern mDNSu32 GetPktLease(mDNS *m, DNSMessage *msg, const mDNSu8 *end);
+extern mDNSBool GetPktLease(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, mDNSu32 *const lease);
extern void DumpPacket(mDNS *const m, mStatus status, mDNSBool sent, char *transport,
const mDNSAddr *srcaddr, mDNSIPPort srcport,
const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end);
diff --git a/mDNSResponder/mDNSCore/anonymous.c b/mDNSResponder/mDNSCore/anonymous.c
index aaaebc27..fde3ed80 100644
--- a/mDNSResponder/mDNSCore/anonymous.c
+++ b/mDNSResponder/mDNSCore/anonymous.c
@@ -240,6 +240,12 @@ mDNSexport void SetAnonData(DNSQuestion *q, ResourceRecord *rr, mDNSBool ForQues
debugf("SetAnonData: question %##s(%p), rr %##s(%p)", q->qname.c, q->AnonInfo, rr->name->c, rr->AnonInfo);
if (ForQuestion)
{
+ if (q->AnonInfo->AnonDataLen < rr->AnonInfo->AnonDataLen)
+ {
+ mDNSPlatformMemFree(q->AnonInfo->AnonData);
+ q->AnonInfo->AnonData = mDNSNULL;
+ }
+
if (!q->AnonInfo->AnonData)
{
q->AnonInfo->AnonData = mDNSPlatformMemAllocate(rr->AnonInfo->AnonDataLen);
@@ -251,6 +257,12 @@ mDNSexport void SetAnonData(DNSQuestion *q, ResourceRecord *rr, mDNSBool ForQues
}
else
{
+ if (rr->AnonInfo->AnonDataLen < q->AnonInfo->AnonDataLen)
+ {
+ mDNSPlatformMemFree(rr->AnonInfo->AnonData);
+ rr->AnonInfo->AnonData = mDNSNULL;
+ }
+
if (!rr->AnonInfo->AnonData)
{
rr->AnonInfo->AnonData = mDNSPlatformMemAllocate(q->AnonInfo->AnonDataLen);
diff --git a/mDNSResponder/mDNSCore/dnsproxy.c b/mDNSResponder/mDNSCore/dnsproxy.c
index 2afb59d1..a94c005e 100644
--- a/mDNSResponder/mDNSCore/dnsproxy.c
+++ b/mDNSResponder/mDNSCore/dnsproxy.c
@@ -19,6 +19,8 @@
#ifndef UNICAST_DISABLED
+mDNSexport mDNS mDNSStorage;
+
// Implementation Notes
//
// DNS Proxy listens on port 53 (UDPv4v6 & TCPv4v6) for DNS queries. It handles only
@@ -72,7 +74,7 @@ struct DNSProxyClient_struct {
};
#define MIN_DNS_MESSAGE_SIZE 512
-DNSProxyClient *DNSProxyClients;
+static DNSProxyClient *DNSProxyClients;
mDNSlocal void FreeDNSProxyClient(DNSProxyClient *pc)
{
@@ -130,7 +132,7 @@ mDNSexport mDNSu8 *DNSProxySetAttributes(DNSQuestion *q, DNSMessageHeader *h, DN
return ptr;
}
-mDNSlocal mDNSu8 *AddEDNS0Option(mDNS *const m, mDNSu8 *ptr, mDNSu8 *limit)
+mDNSlocal mDNSu8 *AddEDNS0Option(mDNSu8 *ptr, mDNSu8 *limit)
{
int len = 4096;
@@ -139,7 +141,7 @@ mDNSlocal mDNSu8 *AddEDNS0Option(mDNS *const m, mDNSu8 *ptr, mDNSu8 *limit)
LogInfo("AddEDNS0Option: not enough space");
return mDNSNULL;
}
- m->omsg.h.numAdditionals++;
+ mDNSStorage.omsg.h.numAdditionals++;
ptr[0] = 0;
ptr[1] = (mDNSu8) (kDNSType_OPT >> 8);
ptr[2] = (mDNSu8) (kDNSType_OPT & 0xFF);
@@ -180,9 +182,9 @@ mDNSlocal mDNSOpaque16 SetResponseFlags(DNSProxyClient *pc, const mDNSOpaque16 r
return rFlags;
}
-mDNSlocal mDNSu8 *AddResourceRecords(mDNS *const m, DNSProxyClient *pc, mDNSu8 **prevptr, mStatus *error)
+mDNSlocal mDNSu8 *AddResourceRecords(DNSProxyClient *pc, mDNSu8 **prevptr, mStatus *error)
{
- mDNSu32 slot;
+ mDNS *const m = &mDNSStorage;
CacheGroup *cg;
CacheRecord *cr;
int len = sizeof(DNSMessageHeader);
@@ -229,9 +231,8 @@ mDNSlocal mDNSu8 *AddResourceRecords(mDNS *const m, DNSProxyClient *pc, mDNSu8 *
again:
nsec = soa = cname = mDNSNULL;
- slot = HashSlot(&tempQName);
- cg = CacheGroupForName(m, slot, tempQNameHash, &tempQName);
+ cg = CacheGroupForName(m, tempQNameHash, &tempQName);
if (!cg)
{
LogInfo("AddResourceRecords: CacheGroup not found for %##s", tempQName.c);
@@ -355,7 +356,7 @@ again:
}
if (pc->rcvBufSize)
{
- ptr = AddEDNS0Option(m, ptr, limit);
+ ptr = AddEDNS0Option(ptr, limit);
if (!ptr)
{
*prevptr = orig;
@@ -408,7 +409,7 @@ mDNSlocal void ProxyClientCallback(mDNS *const m, DNSQuestion *question, const R
return;
}
}
- ptr = AddResourceRecords(m, pc, &prevptr, &error);
+ ptr = AddResourceRecords(pc, &prevptr, &error);
if (!ptr)
{
LogInfo("ProxyClientCallback: AddResourceRecords NULL for %##s (%s)", &pc->qname.c, DNSTypeName(pc->q.qtype));
@@ -494,9 +495,10 @@ done:
FreeDNSProxyClient(pc);
}
-mDNSlocal void SendError(mDNS *const m, void *socket, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *dstaddr,
+mDNSlocal void SendError(void *socket, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *dstaddr,
const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, mDNSBool tcp, void *context, mDNSu8 rcode)
{
+ mDNS *const m = &mDNSStorage;
int pktlen = (int)(end - (mDNSu8 *)msg);
// RFC 1035 requires that we copy the question back and RFC 2136 is okay with sending nothing
@@ -509,7 +511,8 @@ mDNSlocal void SendError(mDNS *const m, void *socket, DNSMessage *const msg, con
mDNSPlatformMemCopy(&m->omsg.h, &msg->h, sizeof(DNSMessageHeader));
m->omsg.h.flags.b[0] |= kDNSFlag0_QR_Response;
m->omsg.h.flags.b[1] = rcode;
- mDNSPlatformMemCopy(m->omsg.data, (mDNSu8 *)&msg->h.numQuestions, pktlen);
+ mDNSPlatformMemCopy(m->omsg.data, (mDNSu8 *)&msg->data, (pktlen - sizeof(DNSMessageHeader)));
+
if (!tcp)
{
mDNSSendDNSMessage(m, &m->omsg, (mDNSu8 *)&m->omsg + pktlen, InterfaceID, socket, dstaddr, dstport, mDNSNULL, mDNSNULL,
@@ -523,14 +526,12 @@ mDNSlocal void SendError(mDNS *const m, void *socket, DNSMessage *const msg, con
mDNSPlatformDisposeProxyContext(context);
}
-mDNSlocal DNSQuestion *IsDuplicateClient(const mDNS *const m, const mDNSAddr *const addr, const mDNSIPPort port, const mDNSOpaque16 id,
+mDNSlocal DNSQuestion *IsDuplicateClient(const mDNSAddr *const addr, const mDNSIPPort port, const mDNSOpaque16 id,
const DNSQuestion *const question)
{
DNSProxyClient *pc;
- (void) m; // unused
-
- for (pc = DNSProxyClients; pc; pc = pc->next)
+ for (pc = DNSProxyClients; pc; pc = pc->next)
{
if (mDNSSameAddress(&pc->addr, addr) &&
mDNSSameIPPort(pc->port, port) &&
@@ -546,8 +547,9 @@ mDNSlocal DNSQuestion *IsDuplicateClient(const mDNS *const m, const mDNSAddr *co
return(mDNSNULL);
}
-mDNSlocal mDNSBool CheckDNSProxyIpIntf(const mDNS *const m, mDNSInterfaceID InterfaceID)
+mDNSlocal mDNSBool CheckDNSProxyIpIntf(mDNSInterfaceID InterfaceID)
{
+ mDNS *const m = &mDNSStorage;
int i;
mDNSu32 ip_ifindex = (mDNSu32)(unsigned long)InterfaceID;
@@ -570,9 +572,10 @@ mDNSlocal mDNSBool CheckDNSProxyIpIntf(const mDNS *const m, mDNSInterfaceID Inte
}
-mDNSlocal void ProxyCallbackCommon(mDNS *const m, void *socket, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr,
+mDNSlocal void ProxyCallbackCommon(void *socket, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr,
const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, mDNSBool tcp, void *context)
{
+ mDNS *const m = &mDNSStorage;
mDNSu8 QR_OP;
const mDNSu8 *ptr;
DNSQuestion q, *qptr;
@@ -586,7 +589,7 @@ mDNSlocal void ProxyCallbackCommon(mDNS *const m, void *socket, DNSMessage *cons
debugf("ProxyCallbackCommon: DNS Query coming from InterfaceID %p", InterfaceID);
// Ignore if the DNS Query is not from a Valid Input InterfaceID
- if (!CheckDNSProxyIpIntf(m, InterfaceID))
+ if (!CheckDNSProxyIpIntf(InterfaceID))
{
LogMsg("ProxyCallbackCommon: Rejecting DNS Query coming from InterfaceID %p", InterfaceID);
return;
@@ -598,14 +601,6 @@ mDNSlocal void ProxyCallbackCommon(mDNS *const m, void *socket, DNSMessage *cons
return;
}
- QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
- if (QR_OP != kDNSFlag0_QR_Query)
- {
- LogInfo("ProxyCallbackCommon: Not a query(%d) for pkt from %#a:%d", QR_OP, srcaddr, mDNSVal16(srcport));
- SendError(m, socket, msg, end, srcaddr, srcport, InterfaceID, tcp, context, kDNSFlag1_RC_NotImpl);
- return;
- }
-
// Read the integer parts which are in IETF byte-order (MSB first, LSB second)
ptr = (mDNSu8 *)&msg->h.numQuestions;
msg->h.numQuestions = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
@@ -613,11 +608,19 @@ mDNSlocal void ProxyCallbackCommon(mDNS *const m, void *socket, DNSMessage *cons
msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]);
msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]);
+ QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
+ if (QR_OP != kDNSFlag0_QR_Query)
+ {
+ LogInfo("ProxyCallbackCommon: Not a query(%d) for pkt from %#a:%d", QR_OP, srcaddr, mDNSVal16(srcport));
+ SendError(socket, msg, end, srcaddr, srcport, InterfaceID, tcp, context, kDNSFlag1_RC_NotImpl);
+ return;
+ }
+
if (msg->h.numQuestions != 1 || msg->h.numAnswers || msg->h.numAuthorities)
{
LogInfo("ProxyCallbackCommon: Malformed pkt from %#a:%d, Q:%d, An:%d, Au:%d", srcaddr, mDNSVal16(srcport),
msg->h.numQuestions, msg->h.numAnswers, msg->h.numAuthorities);
- SendError(m, socket, msg, end, srcaddr, srcport, InterfaceID, tcp, context, kDNSFlag1_RC_FormErr);
+ SendError(socket, msg, end, srcaddr, srcport, InterfaceID, tcp, context, kDNSFlag1_RC_FormErr);
return;
}
ptr = msg->data;
@@ -625,7 +628,7 @@ mDNSlocal void ProxyCallbackCommon(mDNS *const m, void *socket, DNSMessage *cons
if (!ptr)
{
LogInfo("ProxyCallbackCommon: Question cannot be parsed for pkt from %#a:%d", srcaddr, mDNSVal16(srcport));
- SendError(m, socket, msg, end, srcaddr, srcport, InterfaceID, tcp, context, kDNSFlag1_RC_FormErr);
+ SendError(socket, msg, end, srcaddr, srcport, InterfaceID, tcp, context, kDNSFlag1_RC_FormErr);
return;
}
else
@@ -653,7 +656,7 @@ mDNSlocal void ProxyCallbackCommon(mDNS *const m, void *socket, DNSMessage *cons
LogInfo("ProxyCallbackCommon: EDNS0 opt not present in Question %##s (%s), ptr %p", q.qname.c, DNSTypeName(q.qtype), ptr);
}
- qptr = IsDuplicateClient(m, srcaddr, srcport, msg->h.id, &q);
+ qptr = IsDuplicateClient(srcaddr, srcport, msg->h.id, &q);
if (qptr)
{
LogInfo("ProxyCallbackCommon: Found a duplicate for pkt from %#a:%d, ignoring this", srcaddr, mDNSVal16(srcport));
@@ -730,21 +733,21 @@ mDNSlocal void ProxyCallbackCommon(mDNS *const m, void *socket, DNSMessage *cons
mDNS_StartQuery(m, &pc->q);
}
-mDNSexport void ProxyUDPCallback(mDNS *const m, void *socket, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr,
+mDNSexport void ProxyUDPCallback(void *socket, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr,
const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context)
{
LogInfo("ProxyUDPCallback: DNS Message from %#a:%d to %#a:%d length %d", srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), (int)(end - (mDNSu8 *)msg));
- ProxyCallbackCommon(m, socket, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID, mDNSfalse, context);
+ ProxyCallbackCommon(socket, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID, mDNSfalse, context);
}
-mDNSexport void ProxyTCPCallback(mDNS *const m, void *socket, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr,
+mDNSexport void ProxyTCPCallback(void *socket, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr,
const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context)
{
LogInfo("ProxyTCPCallback: DNS Message from %#a:%d to %#a:%d length %d", srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), (int)(end - (mDNSu8 *)msg));
// If the connection was closed from the other side or incoming packet does not match stored input interface list, locate the client
// state and free it.
- if (((end - (mDNSu8 *)msg) == 0) || (!CheckDNSProxyIpIntf(m, InterfaceID)))
+ if (((end - (mDNSu8 *)msg) == 0) || (!CheckDNSProxyIpIntf(InterfaceID)))
{
DNSProxyClient **ppc = &DNSProxyClients;
DNSProxyClient **prevpc;
@@ -767,11 +770,12 @@ mDNSexport void ProxyTCPCallback(mDNS *const m, void *socket, DNSMessage *const
FreeDNSProxyClient(*ppc);
return;
}
- ProxyCallbackCommon(m, socket, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID, mDNStrue, context);
+ ProxyCallbackCommon(socket, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID, mDNStrue, context);
}
-mDNSexport void DNSProxyInit(mDNS *const m, mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf)
+mDNSexport void DNSProxyInit(mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf)
{
+ mDNS *const m = &mDNSStorage;
int i;
// Store DNSProxy Interface fields in mDNS struct
@@ -783,8 +787,9 @@ mDNSexport void DNSProxyInit(mDNS *const m, mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf
m->dp_ipintf[1], m->dp_ipintf[2], m->dp_ipintf[3], m->dp_ipintf[4], m->dp_opintf);
}
-mDNSexport void DNSProxyTerminate(mDNS *const m)
+mDNSexport void DNSProxyTerminate(void)
{
+ mDNS *const m = &mDNSStorage;
int i;
// Clear DNSProxy Interface fields from mDNS struct
@@ -797,9 +802,8 @@ mDNSexport void DNSProxyTerminate(mDNS *const m)
}
#else // UNICAST_DISABLED
-mDNSexport void ProxyUDPCallback(mDNS *const m, void *socket, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context)
+mDNSexport void ProxyUDPCallback(void *socket, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context)
{
- (void) m;
(void) socket;
(void) msg;
(void) end;
@@ -811,9 +815,8 @@ mDNSexport void ProxyUDPCallback(mDNS *const m, void *socket, DNSMessage *const
(void) context;
}
-mDNSexport void ProxyTCPCallback(mDNS *const m, void *socket, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context)
+mDNSexport void ProxyTCPCallback(void *socket, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context)
{
- (void) m;
(void) socket;
(void) msg;
(void) end;
@@ -825,15 +828,13 @@ mDNSexport void ProxyTCPCallback(mDNS *const m, void *socket, DNSMessage *const
(void) context;
}
-mDNSexport void DNSProxyInit(mDNS *const m, mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf)
+mDNSexport void DNSProxyInit(mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf)
{
- (void) m;
(void) IpIfArr;
(void) OpIf;
}
-extern void DNSProxyTerminate(mDNS *const m)
+extern void DNSProxyTerminate(void)
{
- (void) m;
}
diff --git a/mDNSResponder/mDNSCore/dnsproxy.h b/mDNSResponder/mDNSCore/dnsproxy.h
index a2abdfbf..6889e73a 100644
--- a/mDNSResponder/mDNSCore/dnsproxy.h
+++ b/mDNSResponder/mDNSCore/dnsproxy.h
@@ -21,11 +21,11 @@
#include "mDNSEmbeddedAPI.h"
#include "DNSCommon.h"
-extern void ProxyUDPCallback(mDNS *const m, void *socket, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr,
+extern void ProxyUDPCallback(void *socket, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr,
const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context);
-extern void ProxyTCPCallback(mDNS *const m, void *socket, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr,
+extern void ProxyTCPCallback(void *socket, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr,
const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context);
-extern void DNSProxyInit(mDNS *const m, mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf);
-extern void DNSProxyTerminate(mDNS *const m);
+extern void DNSProxyInit(mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf);
+extern void DNSProxyTerminate(void);
#endif // __DNS_PROXY_H
diff --git a/mDNSResponder/mDNSCore/dnssec.c b/mDNSResponder/mDNSCore/dnssec.c
index 514a488c..9525655f 100644
--- a/mDNSResponder/mDNSCore/dnssec.c
+++ b/mDNSResponder/mDNSCore/dnssec.c
@@ -707,7 +707,6 @@ mDNSexport void ValidateRRSIG(DNSSECVerifier *dv, RRVerifierSet type, const Reso
mDNSlocal mStatus CheckRRSIGForRRSet(mDNS *const m, DNSSECVerifier *dv, CacheRecord **negcr)
{
- mDNSu32 slot;
CacheGroup *cg;
CacheRecord *cr;
RRVerifier *rv;
@@ -722,8 +721,7 @@ mDNSlocal mStatus CheckRRSIGForRRSet(mDNS *const m, DNSSECVerifier *dv, CacheRec
}
rv = dv->rrset;
- slot = HashSlot(&rv->name);
- cg = CacheGroupForName(m, slot, rv->namehash, &rv->name);
+ cg = CacheGroupForName(m, rv->namehash, &rv->name);
if (!cg)
{
debugdnssec("CheckRRSIGForRRSet: cg null");
@@ -807,7 +805,6 @@ mDNSlocal void CheckOneKeyForRRSIG(DNSSECVerifier *dv, const ResourceRecord *con
mDNSlocal mStatus CheckKeyForRRSIG(mDNS *const m, DNSSECVerifier *dv, CacheRecord **negcr)
{
- mDNSu32 slot;
mDNSu32 namehash;
CacheGroup *cg;
CacheRecord *cr;
@@ -825,9 +822,8 @@ mDNSlocal mStatus CheckKeyForRRSIG(mDNS *const m, DNSSECVerifier *dv, CacheRecor
rrsig = (rdataRRSig *)dv->rrsig->rdata;
name = (domainname *)&rrsig->signerName;
- slot = HashSlot(name);
namehash = DomainNameHashValue(name);
- cg = CacheGroupForName(m, slot, namehash, name);
+ cg = CacheGroupForName(m, namehash, name);
if (!cg)
{
debugdnssec("CheckKeyForRRSIG: cg null for %##s", name->c);
@@ -887,7 +883,6 @@ mDNSlocal void CheckOneRRSIGForKey(DNSSECVerifier *dv, const ResourceRecord *con
mDNSlocal mStatus CheckRRSIGForKey(mDNS *const m, DNSSECVerifier *dv, CacheRecord **negcr)
{
- mDNSu32 slot;
mDNSu32 namehash;
CacheGroup *cg;
CacheRecord *cr;
@@ -909,9 +904,8 @@ mDNSlocal mStatus CheckRRSIGForKey(mDNS *const m, DNSSECVerifier *dv, CacheRecor
rrsig = (rdataRRSig *)dv->rrsig->rdata;
name = (domainname *)&rrsig->signerName;
- slot = HashSlot(name);
namehash = DomainNameHashValue(name);
- cg = CacheGroupForName(m, slot, namehash, name);
+ cg = CacheGroupForName(m, namehash, name);
if (!cg)
{
debugdnssec("CheckRRSIGForKey: cg null %##s", name->c);
@@ -1010,7 +1004,6 @@ mDNSlocal void CheckOneDSForKey(DNSSECVerifier *dv, const ResourceRecord *const
mDNSlocal mStatus CheckDSForKey(mDNS *const m, DNSSECVerifier *dv, CacheRecord **negcr)
{
- mDNSu32 slot;
mDNSu32 namehash;
CacheGroup *cg;
CacheRecord *cr;
@@ -1030,9 +1023,8 @@ mDNSlocal mStatus CheckDSForKey(mDNS *const m, DNSSECVerifier *dv, CacheRecord *
}
rrsig = (rdataRRSig *)dv->rrsig->rdata;
name = (domainname *)&rrsig->signerName;
- slot = HashSlot(name);
namehash = DomainNameHashValue(name);
- cg = CacheGroupForName(m, slot, namehash, name);
+ cg = CacheGroupForName(m, namehash, name);
if (!cg)
{
debugdnssec("CheckDSForKey: cg null for %s", name->c);
@@ -2336,7 +2328,6 @@ mDNSlocal void SetTTLRRSet(mDNS *const m, DNSSECVerifier *dv, DNSSECStatus statu
CacheRecord *rr;
RRVerifier *rrsigv;
rdataRRSig *rrsig;
- mDNSu32 slot;
CacheGroup *cg;
mDNSu32 rrTTL, rrsigTTL, rrsigOrigTTL, rrsigTimeTTL;
domainname *qname;
@@ -2368,8 +2359,7 @@ mDNSlocal void SetTTLRRSet(mDNS *const m, DNSSECVerifier *dv, DNSSECStatus statu
question.ThisQInterval = -1;
InitializeQuestion(m, &question, dv->InterfaceID, qname, qtype, mDNSNULL, mDNSNULL);
- slot = HashSlot(&question.qname);
- cg = CacheGroupForName(m, slot, question.qnamehash, &question.qname);
+ cg = CacheGroupForName(m, question.qnamehash, &question.qname);
if (!cg)
{
@@ -2691,7 +2681,7 @@ mDNSlocal void DNSSECNoResponse(mDNS *const m, DNSSECVerifier *dv)
{
CacheGroup *cg;
CacheRecord *cr;
- mDNSu32 slot, namehash;
+ mDNSu32 namehash;
ResourceRecord *answer = mDNSNULL;
LogDNSSEC("DNSSECNoResponse: called");
@@ -2704,10 +2694,9 @@ mDNSlocal void DNSSECNoResponse(mDNS *const m, DNSSECVerifier *dv)
BumpDNSSECStats(m, kStatsActionSet, kStatsTypeStatus, DNSSEC_NoResponse);
- slot = HashSlot(&dv->origName);
namehash = DomainNameHashValue(&dv->origName);
- cg = CacheGroupForName(m, (const mDNSu32)slot, namehash, &dv->origName);
+ cg = CacheGroupForName(m, namehash, &dv->origName);
if (!cg)
{
LogDNSSEC("DNSSECNoResponse: cg NULL for %##s (%s)", dv->origName.c, DNSTypeName(dv->origType));
@@ -3033,7 +3022,7 @@ done:
mDNSlocal void DNSSECValidationCB(mDNS *const m, DNSSECVerifier *dv, DNSSECStatus status)
{
- mDNSu32 slot, namehash;
+ mDNSu32 namehash;
CacheGroup *cg;
CacheRecord *cr;
@@ -3053,10 +3042,9 @@ mDNSlocal void DNSSECValidationCB(mDNS *const m, DNSSECVerifier *dv, DNSSECStatu
ProveInsecure(m, dv, mDNSNULL, mDNSNULL);
return;
}
- slot = HashSlot(&dv->origName);
namehash = DomainNameHashValue(&dv->origName);
- cg = CacheGroupForName(m, (const mDNSu32)slot, namehash, &dv->origName);
+ cg = CacheGroupForName(m, namehash, &dv->origName);
if (!cg)
{
LogDNSSEC("DNSSECValidationCB: cg NULL for %##s (%s)", dv->origName.c, DNSTypeName(dv->origType));
@@ -3082,8 +3070,7 @@ mDNSlocal void DNSSECValidationCB(mDNS *const m, DNSSECVerifier *dv, DNSSECStatu
mDNSexport void VerifySignature(mDNS *const m, DNSSECVerifier *dv, DNSQuestion *q)
{
- mDNSu32 slot = HashSlot(&q->qname);
- CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+ CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
CacheRecord *rr;
mDNSBool first = mDNSfalse;
static mDNSBool TrustAnchorsUpdated = mDNSfalse;
@@ -3319,14 +3306,12 @@ mDNSlocal mStatus TrustedKey(mDNS *const m, DNSSECVerifier *dv)
mDNSlocal CacheRecord* NegativeCacheRecordForRR(mDNS *const m, const ResourceRecord *const rr)
{
- mDNSu32 slot;
mDNSu32 namehash;
CacheGroup *cg;
CacheRecord *cr;
- slot = HashSlot(rr->name);
namehash = DomainNameHashValue(rr->name);
- cg = CacheGroupForName(m, slot, namehash, rr->name);
+ cg = CacheGroupForName(m, namehash, rr->name);
if (!cg)
{
LogMsg("NegativeCacheRecordForRR: cg null %##s", rr->name->c);
diff --git a/mDNSResponder/mDNSCore/mDNS.c b/mDNSResponder/mDNSCore/mDNS.c
index a58a6c1a..0d4d8ae4 100755
--- a/mDNSResponder/mDNSCore/mDNS.c
+++ b/mDNSResponder/mDNSCore/mDNS.c
@@ -45,6 +45,7 @@
#endif
#include "dns_sd.h" // for kDNSServiceFlags* definitions
+#include "dns_sd_internal.h"
#if APPLE_OSX_mDNSResponder
#include <WebFilterDNS/WebFilterDNS.h>
@@ -65,15 +66,22 @@ void WCFConnectionDealloc(WCFConnection* c) __attribute__((weak_import));
#define NO_WCF 1
#endif // APPLE_OSX_mDNSResponder
-#if TARGET_OS_EMBEDDED
+#if AWD_METRICS
#include "Metrics.h"
#endif
+#if USE_DNS64
+#include "DNS64.h"
+#endif
+
+#ifdef UNIT_TEST
+#include "unittest.h"
+#endif
+
// Forward declarations
mDNSlocal void BeginSleepProcessing(mDNS *const m);
mDNSlocal void RetrySPSRegistrations(mDNS *const m);
mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password, mDNSBool unicastOnly);
-mDNSlocal mDNSBool CacheRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q);
mDNSlocal mDNSBool LocalRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q);
mDNSlocal void mDNS_PurgeForQuestion(mDNS *const m, DNSQuestion *q);
mDNSlocal void CheckForDNSSECRecords(mDNS *const m, DNSQuestion *q);
@@ -109,6 +117,10 @@ mDNSlocal mDNSu8 *GetValueForMACAddr(mDNSu8 *ptr, mDNSu8 *limit, mDNSEthAddr *et
#define NR_AnswerMulticast (mDNSu8*)~0
#define NR_AnswerUnicast (mDNSu8*)~1
+// Question default timeout values
+#define DEFAULT_MCAST_TIMEOUT 5
+#define DEFAULT_LO_OR_P2P_TIMEOUT 5
+
// The code (see SendQueries() and BuildQuestion()) needs to have the
// RequestUnicast value set to a value one greater than the number of times you want the query
// sent with the "request unicast response" (QU) bit set.
@@ -274,24 +286,27 @@ mDNSlocal AuthEntity *GetAuthEntity(AuthHash *r, const AuthGroup *const Preserve
return(e);
}
-mDNSexport AuthGroup *AuthGroupForName(AuthHash *r, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name)
+mDNSexport AuthGroup *AuthGroupForName(AuthHash *r, const mDNSu32 namehash, const domainname *const name)
{
AuthGroup *ag;
+ const mDNSu32 slot = namehash % AUTH_HASH_SLOTS;
+
for (ag = r->rrauth_hash[slot]; ag; ag=ag->next)
if (ag->namehash == namehash && SameDomainName(ag->name, name))
break;
return(ag);
}
-mDNSexport AuthGroup *AuthGroupForRecord(AuthHash *r, const mDNSu32 slot, const ResourceRecord *const rr)
+mDNSexport AuthGroup *AuthGroupForRecord(AuthHash *r, const ResourceRecord *const rr)
{
- return(AuthGroupForName(r, slot, rr->namehash, rr->name));
+ return(AuthGroupForName(r, rr->namehash, rr->name));
}
-mDNSlocal AuthGroup *GetAuthGroup(AuthHash *r, const mDNSu32 slot, const ResourceRecord *const rr)
+mDNSlocal AuthGroup *GetAuthGroup(AuthHash *r, const ResourceRecord *const rr)
{
mDNSu16 namelen = DomainNameLength(rr->name);
AuthGroup *ag = (AuthGroup*)GetAuthEntity(r, mDNSNULL);
+ const mDNSu32 slot = rr->namehash % AUTH_HASH_SLOTS;
if (!ag) { LogMsg("GetAuthGroup: Failed to allocate memory for %##s", rr->name->c); return(mDNSNULL); }
ag->next = r->rrauth_hash[slot];
ag->namehash = rr->namehash;
@@ -310,9 +325,9 @@ mDNSlocal AuthGroup *GetAuthGroup(AuthHash *r, const mDNSu32 slot, const Resourc
}
AssignDomainName(ag->name, rr->name);
- if (AuthGroupForRecord(r, slot, rr)) LogMsg("GetAuthGroup: Already have AuthGroup for %##s", rr->name->c);
+ if (AuthGroupForRecord(r, rr)) LogMsg("GetAuthGroup: Already have AuthGroup for %##s", rr->name->c);
r->rrauth_hash[slot] = ag;
- if (AuthGroupForRecord(r, slot, rr) != ag) LogMsg("GetAuthGroup: Not finding AuthGroup for %##s", rr->name->c);
+ if (AuthGroupForRecord(r, rr) != ag) LogMsg("GetAuthGroup: Not finding AuthGroup for %##s", rr->name->c);
return(ag);
}
@@ -320,11 +335,11 @@ mDNSlocal AuthGroup *GetAuthGroup(AuthHash *r, const mDNSu32 slot, const Resourc
// Returns the AuthGroup in which the AuthRecord was inserted
mDNSexport AuthGroup *InsertAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr)
{
- (void)m;
AuthGroup *ag;
- const mDNSu32 slot = AuthHashSlot(rr->resrec.name);
- ag = AuthGroupForRecord(r, slot, &rr->resrec);
- if (!ag) ag = GetAuthGroup(r, slot, &rr->resrec); // If we don't have a AuthGroup for this name, make one now
+
+ (void)m;
+ ag = AuthGroupForRecord(r, &rr->resrec);
+ if (!ag) ag = GetAuthGroup(r, &rr->resrec); // If we don't have a AuthGroup for this name, make one now
if (ag)
{
*(ag->rrauth_tail) = rr; // Append this record to tail of cache slot list
@@ -337,9 +352,8 @@ mDNSexport AuthGroup *RemoveAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *r
{
AuthGroup *a;
AuthRecord **rp;
- const mDNSu32 slot = AuthHashSlot(rr->resrec.name);
- a = AuthGroupForRecord(r, slot, &rr->resrec);
+ a = AuthGroupForRecord(r, &rr->resrec);
if (!a) { LogMsg("RemoveAuthRecord: ERROR!! AuthGroup not found for %s", ARDisplayString(m, rr)); return mDNSNULL; }
rp = &a->members;
while (*rp)
@@ -359,18 +373,19 @@ mDNSexport AuthGroup *RemoveAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *r
return a;
}
-mDNSexport CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name)
+mDNSexport CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 namehash, const domainname *const name)
{
CacheGroup *cg;
+ mDNSu32 slot = HashSlotFromNameHash(namehash);
for (cg = m->rrcache_hash[slot]; cg; cg=cg->next)
if (cg->namehash == namehash && SameDomainName(cg->name, name))
break;
return(cg);
}
-mDNSlocal CacheGroup *CacheGroupForRecord(const mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr)
+mDNSlocal CacheGroup *CacheGroupForRecord(const mDNS *const m, const ResourceRecord *const rr)
{
- return(CacheGroupForName(m, slot, rr->namehash, rr->name));
+ return(CacheGroupForName(m, rr->namehash, rr->name));
}
mDNSexport mDNSBool mDNS_AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr)
@@ -472,7 +487,7 @@ mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, Re
const mDNSu32 c = q->CNAMEReferrals + 1; // Stash a copy of the new q->CNAMEReferrals value
UDPSocket *sock = q->LocalSocket;
mDNSOpaque16 id = q->TargetQID;
-#if TARGET_OS_EMBEDDED
+#if AWD_METRICS
uDNSMetrics metrics;
#endif
@@ -496,7 +511,7 @@ mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, Re
LogInfo("AnswerQuestionByFollowingCNAME: %p %##s (%s) following CNAME referral %d for %s",
q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, RRDisplayString(m, rr));
-#if TARGET_OS_EMBEDDED
+#if AWD_METRICS
if ((q->CNAMEReferrals == 0) && !q->metrics.originalQName)
{
domainname * qName;
@@ -532,7 +547,7 @@ mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, Re
// Record how many times we've done this. We need to do this *after* mDNS_StartQuery_internal,
// because mDNS_StartQuery_internal re-initializes CNAMEReferrals to zero
q->CNAMEReferrals = c;
-#if TARGET_OS_EMBEDDED
+#if AWD_METRICS
q->metrics = metrics;
#endif
if (sock)
@@ -787,7 +802,6 @@ mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRec
(X) &kDNSRecordTypeActiveUniqueMask ? DefaultAnnounceIntervalForTypeUnique : 0)
#define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0)
-#define TimeToSendThisRecord(RR,time) ((TimeToAnnounceThisRecord(RR,time) || (RR)->ImmedAnswer) && ResourceRecordIsValidAnswer(RR))
#define TicksTTL(RR) ((mDNSs32)(RR)->resrec.rroriginalttl * mDNSPlatformOneSecond)
#define RRExpireTime(RR) ((RR)->TimeRcvd + TicksTTL(RR))
@@ -962,9 +976,9 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
}
rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval;
}
- // Skip kDNSRecordTypeKnownUnique records here and set their LastAPTime in the "else" block below so that they get announced immediately,
- // otherwise, their announcement would be delayed until all other record probes complete.
- else if ((rr->resrec.RecordType != kDNSRecordTypeKnownUnique) && m->SuppressProbes && m->SuppressProbes - m->timenow >= 0)
+ // Skip kDNSRecordTypeKnownUnique and kDNSRecordTypeShared records here and set their LastAPTime in the "else" block below so
+ // that they get announced immediately, otherwise, their announcement would be delayed until the based on the SuppressProbes value.
+ else if ((rr->resrec.RecordType != kDNSRecordTypeKnownUnique) && (rr->resrec.RecordType != kDNSRecordTypeShared) && m->SuppressProbes && (m->SuppressProbes - m->timenow >= 0))
rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval + DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2;
else
rr->LastAPTime = m->timenow - rr->ThisAPInterval;
@@ -1155,9 +1169,8 @@ mDNSlocal AuthRecord *CheckAuthIdenticalRecord(AuthHash *r, AuthRecord *rr)
{
const AuthGroup *a;
AuthRecord *rp;
- const mDNSu32 slot = AuthHashSlot(rr->resrec.name);
- a = AuthGroupForRecord(r, slot, &rr->resrec);
+ a = AuthGroupForRecord(r, &rr->resrec);
if (!a) return mDNSNULL;
rp = a->members;
while (rp)
@@ -1181,9 +1194,8 @@ mDNSlocal mDNSBool CheckAuthRecordConflict(AuthHash *r, AuthRecord *rr)
{
const AuthGroup *a;
const AuthRecord *rp;
- const mDNSu32 slot = AuthHashSlot(rr->resrec.name);
- a = AuthGroupForRecord(r, slot, &rr->resrec);
+ a = AuthGroupForRecord(r, &rr->resrec);
if (!a) return mDNSfalse;
rp = a->members;
while (rp)
@@ -1203,9 +1215,8 @@ mDNSlocal AuthRecord *CheckAuthSameRecord(AuthHash *r, AuthRecord *rr)
{
const AuthGroup *a;
AuthRecord *rp;
- const mDNSu32 slot = AuthHashSlot(rr->resrec.name);
- a = AuthGroupForRecord(r, slot, &rr->resrec);
+ a = AuthGroupForRecord(r, &rr->resrec);
if (!a) return mDNSNULL;
rp = a->members;
while (rp)
@@ -1386,9 +1397,9 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
{
if (rr->resrec.RecordType == kDNSRecordTypeUnique)
rr->resrec.RecordType = kDNSRecordTypeVerified;
- else
+ else if (rr->resrec.RecordType != kDNSRecordTypeKnownUnique)
{
- LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn && RecordType != kDNSRecordTypeUnique",
+ LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn && RecordType != kDNSRecordTypeUnique or kDNSRecordTypeKnownUnique",
rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
return(mStatus_Invalid);
}
@@ -1630,7 +1641,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
getKeepaliveRaddr(m, rr, &raddr);
// This is an asynchronous call. Once the remote MAC address is available, helper will schedule an
// asynchronous task to update the resource record
- mDNSPlatformGetRemoteMacAddr(m, &raddr);
+ mDNSPlatformGetRemoteMacAddr(&raddr);
}
return(mStatus_NoError);
@@ -1679,9 +1690,8 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
{
AuthGroup *a;
AuthRecord **rp;
- const mDNSu32 slot = AuthHashSlot(rr->resrec.name);
- a = AuthGroupForRecord(&m->rrauth, slot, &rr->resrec);
+ a = AuthGroupForRecord(&m->rrauth, &rr->resrec);
if (!a) return mDNSfalse;
rp = &a->members;
while (*rp && *rp != rr) rp=&(*rp)->next;
@@ -1954,6 +1964,27 @@ mDNSlocal void AddRecordToResponseList(AuthRecord ***nrpp, AuthRecord *rr, AuthR
debugf("AddRecordToResponseList: %##s (%s) already in list", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
}
+mDNSlocal void AddRRSetAdditionalsToResponseList(mDNS *const m, AuthRecord ***nrpp, AuthRecord *rr, AuthRecord *additional, const mDNSInterfaceID InterfaceID)
+{
+ AuthRecord *rr2;
+ if (additional->resrec.RecordType & kDNSRecordTypeUniqueMask)
+ {
+ for (rr2 = m->ResourceRecords; rr2; rr2 = rr2->next)
+ {
+ if ((rr2->resrec.namehash == additional->resrec.namehash) &&
+ (rr2->resrec.rrtype == additional->resrec.rrtype) &&
+ (rr2 != additional) &&
+ (rr2->resrec.RecordType & kDNSRecordTypeUniqueMask) &&
+ (rr2->resrec.rrclass == additional->resrec.rrclass) &&
+ ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) &&
+ SameDomainName(rr2->resrec.name, additional->resrec.name))
+ {
+ AddRecordToResponseList(nrpp, rr2, rr);
+ }
+ }
+ }
+}
+
mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseRecords, AuthRecord ***nrpp, const mDNSInterfaceID InterfaceID)
{
AuthRecord *rr, *rr2;
@@ -1962,10 +1993,16 @@ mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseR
// (Note: This is an "if", not a "while". If we add a record, we'll find it again
// later in the "for" loop, and we will follow further "additional" links then.)
if (rr->Additional1 && ResourceRecordIsValidInterfaceAnswer(rr->Additional1, InterfaceID))
+ {
AddRecordToResponseList(nrpp, rr->Additional1, rr);
+ AddRRSetAdditionalsToResponseList(m, nrpp, rr, rr->Additional1, InterfaceID);
+ }
if (rr->Additional2 && ResourceRecordIsValidInterfaceAnswer(rr->Additional2, InterfaceID))
+ {
AddRecordToResponseList(nrpp, rr->Additional2, rr);
+ AddRRSetAdditionalsToResponseList(m, nrpp, rr, rr->Additional2, InterfaceID);
+ }
// For SRV records, automatically add the Address record(s) for the target host
if (rr->resrec.rrtype == kDNSType_SRV)
@@ -2485,7 +2522,7 @@ mDNSlocal void SendResponses(mDNS *const m)
mDNSs32 maxExistingAnnounceInterval = 0;
const NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces);
- m->NextScheduledResponse = m->timenow + 0x78000000;
+ m->NextScheduledResponse = m->timenow + FutureTime;
if (m->SleepState == SleepState_Transferring) RetrySPSRegistrations(m);
@@ -3059,13 +3096,18 @@ mDNSexport void SetNextCacheCheckTimeForRecord(mDNS *const m, CacheRecord *const
verbosedebugf("SetNextCacheCheckTimeForRecord: NextRequiredQuery in %ld sec CacheCheckGracePeriod %d ticks for %s",
(rr->NextRequiredQuery - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m,rr));
}
- ScheduleNextCacheCheckTime(m, HashSlot(rr->resrec.name), NextCacheCheckEvent(rr));
+ ScheduleNextCacheCheckTime(m, HashSlotFromNameHash(rr->resrec.namehash), NextCacheCheckEvent(rr));
}
#define kMinimumReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 5)
#define kDefaultReconfirmTimeForWake ((mDNSu32)mDNSPlatformOneSecond * 5)
#define kDefaultReconfirmTimeForNoAnswer ((mDNSu32)mDNSPlatformOneSecond * 5)
-#define kDefaultReconfirmTimeForFlappingInterface ((mDNSu32)mDNSPlatformOneSecond * 5)
+
+// Delay before restarting questions on a flapping interface.
+#define kDefaultQueryDelayTimeForFlappingInterface ((mDNSu32)mDNSPlatformOneSecond * 3)
+// After kDefaultQueryDelayTimeForFlappingInterface seconds, allow enough time for up to three queries (0, 1, and 4 seconds)
+// plus three seconds for "response delay" before removing the reconfirmed records from the cache.
+#define kDefaultReconfirmTimeForFlappingInterface (kDefaultQueryDelayTimeForFlappingInterface + ((mDNSu32)mDNSPlatformOneSecond * 7))
mDNSexport mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr, mDNSu32 interval)
{
@@ -3080,7 +3122,7 @@ mDNSexport mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr,
// Add a 33% random amount to the interval, to avoid synchronization between multiple hosts
// For all the reconfirmations in a given batch, we want to use the same random value
// so that the reconfirmation questions can be grouped into a single query packet
- if (!m->RandomReconfirmDelay) m->RandomReconfirmDelay = 1 + mDNSRandom(0x3FFFFFFF);
+ if (!m->RandomReconfirmDelay) m->RandomReconfirmDelay = 1 + mDNSRandom(FutureTime);
interval += m->RandomReconfirmDelay % ((interval/3) + 1);
rr->TimeRcvd = m->timenow - (mDNSs32)interval * 3;
rr->resrec.rroriginalttl = (interval * 4 + mDNSPlatformOneSecond - 1) / mDNSPlatformOneSecond;
@@ -3110,8 +3152,7 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, const NetworkInterfaceInfo *intf
else
{
mDNSu32 forecast = *answerforecast + anoninfo_space;
- const mDNSu32 slot = HashSlot(&q->qname);
- const CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+ const CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
CacheRecord *rr;
CacheRecord **ka = *kalistptrptr; // Make a working copy of the pointer we're going to update
@@ -3204,7 +3245,7 @@ mDNSlocal void ReconfirmAntecedents(mDNS *const m, const domainname *const name,
// to get a AAAA response is not grounds to doubt the PTR/SRV chain that lead us to that name.
mDNSlocal const CacheRecord *CacheHasAddressTypeForName(mDNS *const m, const domainname *const name, const mDNSu32 namehash)
{
- CacheGroup *const cg = CacheGroupForName(m, HashSlot(name), namehash, name);
+ CacheGroup *const cg = CacheGroupForName(m, namehash, name);
const CacheRecord *cr = cg ? cg->members : mDNSNULL;
while (cr && !RRTypeIsAddressType(cr->resrec.rrtype)) cr=cr->next;
return(cr);
@@ -3214,7 +3255,7 @@ mDNSlocal const CacheRecord *CacheHasAddressTypeForName(mDNS *const m, const dom
mDNSlocal const CacheRecord *FindSPSInCache1(mDNS *const m, const DNSQuestion *const q, const CacheRecord *const c0, const CacheRecord *const c1)
{
#ifndef SPC_DISABLED
- CacheGroup *const cg = CacheGroupForName(m, HashSlot(&q->qname), q->qnamehash, &q->qname);
+ CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
const CacheRecord *cr, *bestcr = mDNSNULL;
mDNSu32 bestmetric = 1000000;
for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
@@ -3365,7 +3406,7 @@ mDNSlocal void mDNSSendWakeOnResolve(mDNS *const m, DNSQuestion *q)
mDNSPlatformMemCopy(IPAddr, &d->c[i + 1], len - i);
IPAddr[len - i] = 0;
m->mDNSStats.WakeOnResolves++;
- mDNSPlatformSendWakeupPacket(m, InterfaceID, EthAddr, IPAddr, InitialWakeOnResolveCount - q->WakeOnResolveCount);
+ mDNSPlatformSendWakeupPacket(InterfaceID, EthAddr, IPAddr, InitialWakeOnResolveCount - q->WakeOnResolveCount);
return;
}
else if (d->c[i] == ':')
@@ -3386,8 +3427,7 @@ mDNSlocal mDNSBool AccelerateThisQuery(mDNS *const m, DNSQuestion *q)
{
// We forecast: qname (n) type (2) class (2)
mDNSu32 forecast = (mDNSu32)DomainNameLength(&q->qname) + 4;
- const mDNSu32 slot = HashSlot(&q->qname);
- const CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+ const CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
const CacheRecord *rr;
for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // If we have a resource record in our cache,
if (rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet
@@ -3490,7 +3530,7 @@ mDNSlocal void SendQueries(mDNS *const m)
const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data);
// If we fail to get a new on-demand socket (should only happen cases of the most extreme resource exhaustion), we'll try again next time
- if (!q->LocalSocket) q->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort);
+ if (!q->LocalSocket) q->LocalSocket = mDNSPlatformUDPSocket(zeroIPPort);
if (q->LocalSocket)
{
InitializeDNSMessage(&m->omsg.h, q->TargetQID, QueryFlags);
@@ -3531,7 +3571,7 @@ mDNSlocal void SendQueries(mDNS *const m)
// Note: Don't set NextScheduledQuery until here, because uDNS_CheckCurrentQuestion in the loop above can add new questions to the list,
// which causes NextScheduledQuery to get (incorrectly) set to m->timenow. Setting it here is the right place, because the very
// next thing we do is scan the list and call SetNextQueryTime() for every question we find, so we know we end up with the right value.
- m->NextScheduledQuery = m->timenow + 0x78000000;
+ m->NextScheduledQuery = m->timenow + FutureTime;
for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
{
if (mDNSOpaque16IsZero(q->TargetQID)
@@ -3610,7 +3650,7 @@ mDNSlocal void SendQueries(mDNS *const m)
// 2. Scan our authoritative RR list to see what probes we might need to send
- m->NextScheduledProbe = m->timenow + 0x78000000;
+ m->NextScheduledProbe = m->timenow + FutureTime;
if (m->CurrentRecord)
LogMsg("SendQueries ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
@@ -4110,7 +4150,7 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
return;
}
-#if TARGET_OS_EMBEDDED
+#if AWD_METRICS
if ((AddRecord == QC_add) && Question_uDNS(q) && !followcname)
{
const domainname * queryName;
@@ -4169,6 +4209,11 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
if (rr->DelayDelivery) return; // We'll come back later when CacheRecordDeferredAdd() calls us
+#if USE_DNS64
+ // If DNS64StateMachine() returns true, then the question was restarted as a different question, so return.
+ if (!mDNSOpaque16IsZero(q->TargetQID) && DNS64StateMachine(m, q, &rr->resrec, AddRecord)) return;
+#endif
+
#ifdef USE_LIBIDN
if (rr->resrec.RecordType == kDNSRecordTypePacketNegative) // If negative answer, check if we need to try Punycode conversion
{
@@ -4209,7 +4254,18 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
q->QuestionCallback(m, q, &neg.resrec, AddRecord);
}
else
- q->QuestionCallback(m, q, &rr->resrec, AddRecord);
+ {
+#if USE_DNS64
+ if (DNS64ShouldAnswerQuestion(q, &rr->resrec))
+ {
+ DNS64AnswerQuestion(m, q, &rr->resrec, AddRecord);
+ }
+ else
+#endif
+ {
+ q->QuestionCallback(m, q, &rr->resrec, AddRecord);
+ }
+ }
mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
}
// If this is an "Add" operation and this question needs validation, validate the response.
@@ -4265,12 +4321,12 @@ mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr)
m->CurrentQuestion = mDNSNULL;
}
-mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const mDNSu32 slot, mDNSBool *purge)
+mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *const name, const mDNSu32 namehash, mDNSBool *purge)
{
const mDNSs32 threshhold = m->timenow + mDNSPlatformOneSecond; // See if there are any records expiring within one second
const mDNSs32 start = m->timenow - 0x10000000;
mDNSs32 delay = start;
- CacheGroup *cg = CacheGroupForName(m, slot, namehash, name);
+ CacheGroup *cg = CacheGroupForName(m, namehash, name);
const CacheRecord *rr;
if (purge)
@@ -4559,13 +4615,12 @@ mDNSlocal void ReleaseAdditionalCacheRecords(mDNS *const m, CacheRecord **rp)
mDNSexport void ReleaseCacheRecord(mDNS *const m, CacheRecord *r)
{
CacheGroup *cg;
- const mDNSu32 slot = HashSlot(r->resrec.name);
//LogMsg("ReleaseCacheRecord: Releasing %s", CRDisplayString(m, r));
if (r->resrec.rdata && r->resrec.rdata != (RData*)&r->smallrdatastorage) mDNSPlatformMemFree(r->resrec.rdata);
r->resrec.rdata = mDNSNULL;
- cg = CacheGroupForRecord(m, slot, &r->resrec);
+ cg = CacheGroupForRecord(m, &r->resrec);
if (!cg)
{
@@ -4662,7 +4717,7 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, const mDNSu32 slot, CacheGrou
m->NextScheduledQuery = m->timenow;
// After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTimeForRecord(),
// which will correctly update m->NextCacheCheck for us.
- event = m->timenow + 0x3FFFFFFF;
+ event = m->timenow + FutureTime;
}
}
}
@@ -4687,15 +4742,13 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, const mDNSu32 slot, CacheGrou
// returns true to indicate the same.
mDNSlocal mDNSBool AnswerQuestionWithLORecord(mDNS *const m, DNSQuestion *q, mDNSBool checkOnly)
{
- mDNSu32 slot;
AuthRecord *lr;
AuthGroup *ag;
if (m->CurrentRecord)
LogMsg("AnswerQuestionWithLORecord ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
- slot = AuthHashSlot(&q->qname);
- ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname);
+ ag = AuthGroupForName(&m->rrauth, q->qnamehash, &q->qname);
if (ag)
{
m->CurrentRecord = ag->members;
@@ -4772,8 +4825,19 @@ mDNSlocal mDNSBool AnswerQuestionWithLORecord(mDNS *const m, DNSQuestion *q, mDN
// reasons for suppressing the query, this function should be updated.
mDNSlocal void AnswerSuppressedQuestion(mDNS *const m, DNSQuestion *q)
{
- mDNSBool SuppressQuery = q->SuppressQuery;
- mDNSBool DisallowPID = q->DisallowPID;
+ mDNSBool SuppressQuery;
+ mDNSBool DisallowPID;
+
+ // If the client did not set the kDNSServiceFlagsReturnIntermediates flag, then don't generate a negative response, just
+ // deactivate the DNSQuestion.
+ if (!q->ReturnIntermed)
+ {
+ q->ThisQInterval = 0;
+ return;
+ }
+
+ SuppressQuery = q->SuppressQuery;
+ DisallowPID = q->DisallowPID;
// make sure that QuerySuppressed() returns false
q->SuppressQuery = mDNSfalse;
@@ -4789,13 +4853,15 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
{
mDNSBool ShouldQueryImmediately = mDNStrue;
DNSQuestion *const q = m->NewQuestions; // Grab the question we're going to answer
- mDNSu32 slot = HashSlot(&q->qname);
- CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+#if USE_DNS64
+ if (!mDNSOpaque16IsZero(q->TargetQID)) DNS64HandleNewQuestion(m, q);
+#endif
+ CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
mDNSBool AnsweredFromCache = mDNSfalse;
verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- if (cg) CheckCacheExpiration(m, slot, cg);
+ if (cg) CheckCacheExpiration(m, HashSlotFromNameHash(q->qnamehash), cg);
if (m->NewQuestions != q) { LogInfo("AnswerNewQuestion: Question deleted while doing CheckCacheExpiration"); goto exit; }
m->NewQuestions = q->next;
// Advance NewQuestions to the next *after* calling CheckCacheExpiration, because if we advance it first
@@ -4935,11 +5001,10 @@ exit:
// appropriate answers, stopping if it reaches a NewLocalOnlyRecord -- these will be handled by AnswerAllLocalQuestionsWithLocalAuthRecord
mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
{
- mDNSu32 slot;
AuthGroup *ag;
DNSQuestion *q = m->NewLocalOnlyQuestions; // Grab the question we're going to answer
- m->NewLocalOnlyQuestions = q->next; // Advance NewLocalOnlyQuestions to the next (if any)
mDNSBool retEv = mDNSfalse;
+ m->NewLocalOnlyQuestions = q->next; // Advance NewLocalOnlyQuestions to the next (if any)
debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
@@ -4954,8 +5019,7 @@ mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
// 1. First walk the LocalOnly records answering the LocalOnly question
// 2. As LocalOnly questions should also be answered by any other Auth records local to the machine,
// walk the ResourceRecords list delivering the answers
- slot = AuthHashSlot(&q->qname);
- ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname);
+ ag = AuthGroupForName(&m->rrauth, q->qnamehash, &q->qname);
if (ag)
{
m->CurrentRecord = ag->members;
@@ -5120,9 +5184,9 @@ mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const Res
}
AssignDomainName(cg->name, rr->name);
- if (CacheGroupForRecord(m, slot, rr)) LogMsg("GetCacheGroup: Already have CacheGroup for %##s", rr->name->c);
+ if (CacheGroupForRecord(m, rr)) LogMsg("GetCacheGroup: Already have CacheGroup for %##s", rr->name->c);
m->rrcache_hash[slot] = cg;
- if (CacheGroupForRecord(m, slot, rr) != cg) LogMsg("GetCacheGroup: Not finding CacheGroup for %##s", rr->name->c);
+ if (CacheGroupForRecord(m, rr) != cg) LogMsg("GetCacheGroup: Not finding CacheGroup for %##s", rr->name->c);
return(cg);
}
@@ -5162,7 +5226,7 @@ mDNSexport mDNSs32 mDNS_TimeNow(const mDNS *const m)
// had its Sleep Proxy client list change, and defer to actual BPF reconfiguration to mDNS_Execute().
// (GetNextScheduledEvent() returns "now" when m->SPSProxyListChanged is set)
#define SetSPSProxyListChanged(X) do { \
- if (m->SPSProxyListChanged && m->SPSProxyListChanged != (X)) mDNSPlatformUpdateProxyList(m, m->SPSProxyListChanged); \
+ if (m->SPSProxyListChanged && m->SPSProxyListChanged != (X)) mDNSPlatformUpdateProxyList(m->SPSProxyListChanged); \
m->SPSProxyListChanged = (X); } while(0)
// Called from mDNS_Execute() to expire stale proxy records
@@ -5221,13 +5285,12 @@ mDNSlocal void CheckRmvEventsForLocalRecords(mDNS *const m)
}
}
-mDNSlocal void TimeoutQuestions(mDNS *const m)
+mDNSlocal void TimeoutQuestions_internal(mDNS *const m, DNSQuestion* questions, mDNSInterfaceID InterfaceID)
{
- m->NextScheduledStopTime = m->timenow + 0x3FFFFFFF;
if (m->CurrentQuestion)
LogMsg("TimeoutQuestions ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c,
DNSTypeName(m->CurrentQuestion->qtype));
- m->CurrentQuestion = m->Questions;
+ m->CurrentQuestion = questions;
while (m->CurrentQuestion)
{
DNSQuestion *const q = m->CurrentQuestion;
@@ -5239,7 +5302,8 @@ mDNSlocal void TimeoutQuestions(mDNS *const m)
if (m->timenow - q->StopTime >= 0)
{
LogInfo("TimeoutQuestions: question %p %##s timed out, time %d", q, q->qname.c, m->timenow - q->StopTime);
- GenerateNegativeResponse(m, mDNSInterface_Any, QC_forceresponse);
+ q->LOAddressAnswers = 0; // unset since timing out the question
+ GenerateNegativeResponse(m, InterfaceID, QC_forceresponse);
if (m->CurrentQuestion == q) q->StopTime = 0;
}
else
@@ -5257,6 +5321,13 @@ mDNSlocal void TimeoutQuestions(mDNS *const m)
m->CurrentQuestion = mDNSNULL;
}
+mDNSlocal void TimeoutQuestions(mDNS *const m)
+{
+ m->NextScheduledStopTime = m->timenow + FutureTime; // push reschedule of TimeoutQuestions to way off into the future
+ TimeoutQuestions_internal(m, m->Questions, mDNSInterface_Any);
+ TimeoutQuestions_internal(m, m->LocalOnlyQuestions, mDNSInterface_LocalOnly);
+}
+
mDNSlocal void mDNSCoreFreeProxyRR(mDNS *const m)
{
AuthRecord *rrPtr = m->SPSRRSet, *rrNext = mDNSNULL;
@@ -5274,10 +5345,6 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
{
mDNS_Lock(m); // Must grab lock before trying to read m->timenow
-#if APPLE_OSX_mDNSResponder
- mDNSLogStatistics(m);
-#endif // APPLE_OSX_mDNSResponder
-
if (m->timenow - m->NextScheduledEvent >= 0)
{
int i;
@@ -5304,13 +5371,13 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
if (m->rrcache_size && m->timenow - m->NextCacheCheck >= 0)
{
mDNSu32 numchecked = 0;
- m->NextCacheCheck = m->timenow + 0x3FFFFFFF;
+ m->NextCacheCheck = m->timenow + FutureTime;
for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
{
if (m->timenow - m->rrcache_nextcheck[slot] >= 0)
{
CacheGroup **cp = &m->rrcache_hash[slot];
- m->rrcache_nextcheck[slot] = m->timenow + 0x3FFFFFFF;
+ m->rrcache_nextcheck[slot] = m->timenow + FutureTime;
while (*cp)
{
debugf("m->NextCacheCheck %4d Slot %3d %##s", numchecked, slot, *cp ? (*cp)->name : (domainname*)"\x04NULL");
@@ -5330,7 +5397,7 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
if (m->timenow - m->NextScheduledSPS >= 0)
{
- m->NextScheduledSPS = m->timenow + 0x3FFFFFFF;
+ m->NextScheduledSPS = m->timenow + FutureTime;
CheckProxyRecords(m, m->DuplicateRecords); // Clear m->DuplicateRecords first, then m->ResourceRecords
CheckProxyRecords(m, m->ResourceRecords);
}
@@ -5341,7 +5408,7 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
// as records could have expired during that check
if (m->timenow - m->NextScheduledKA >= 0)
{
- m->NextScheduledKA = m->timenow + 0x3FFFFFFF;
+ m->NextScheduledKA = m->timenow + FutureTime;
mDNS_SendKeepalives(m);
}
@@ -5525,16 +5592,17 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
m->RandomQueryDelay = 0;
m->RandomReconfirmDelay = 0;
+ // See if any questions (or local-only questions) have timed out
if (m->NextScheduledStopTime && m->timenow - m->NextScheduledStopTime >= 0) TimeoutQuestions(m);
#ifndef UNICAST_DISABLED
if (m->NextSRVUpdate && m->timenow - m->NextSRVUpdate >= 0) UpdateAllSRVRecords(m);
if (m->timenow - m->NextScheduledNATOp >= 0) CheckNATMappings(m);
if (m->timenow - m->NextuDNSEvent >= 0) uDNS_Tasks(m);
#endif
-#if APPLE_OSX_mDNSResponder
+#if APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
extern void serviceBLE();
if (m->NextBLEServiceTime && (m->timenow - m->NextBLEServiceTime >= 0)) serviceBLE();
-#endif // APPLE_OSX_mDNSResponder
+#endif // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
}
// Note about multi-threaded systems:
@@ -5574,11 +5642,9 @@ mDNSlocal void SuspendLLQs(mDNS *m)
mDNSlocal mDNSBool QuestionHasLocalAnswers(mDNS *const m, DNSQuestion *q)
{
AuthRecord *rr;
- mDNSu32 slot;
AuthGroup *ag;
- slot = AuthHashSlot(&q->qname);
- ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname);
+ ag = AuthGroupForName(&m->rrauth, q->qnamehash, &q->qname);
if (ag)
{
for (rr = ag->members; rr; rr=rr->next)
@@ -5614,7 +5680,7 @@ mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question,
!SameDomainLabel(question->qname.c, (const mDNSu8 *)"\x0c_autotunnel6")&& question->QuestionCallback != AutoTunnelCallback)
{
question->NoAnswer = NoAnswer_Suspended;
- AddNewClientTunnel(m, question);
+ AddNewClientTunnel(question);
return;
}
#endif // APPLE_OSX_mDNSResponder
@@ -5890,7 +5956,7 @@ mDNSexport void mDNS_UpdateAllowSleep(mDNS *const m)
}
// Call the platform code to enable/disable sleep
- mDNSPlatformSetAllowSleep(m, allowSleep, reason);
+ mDNSPlatformSetAllowSleep(allowSleep, reason);
#else
(void) m;
#endif /* !defined(IDLESLEEPCONTROL_DISABLED) */
@@ -6001,7 +6067,7 @@ mDNSexport mStatus UpdateKeepaliveRData(mDNS *const m, AuthRecord *rr, NetworkIn
// now, then we don't update the DNS NULL record. But we do not prevent it from registering with the SPS. When SPS sees
// this DNS NULL record, it does not send any keepalives as it does not have all the information
mDNSPlatformMemZero(&mti, sizeof (mDNSTCPInfo));
- ret = mDNSPlatformRetrieveTCPInfo(m, &laddr, &lport, &raddr, &rport, &mti);
+ ret = mDNSPlatformRetrieveTCPInfo(&laddr, &lport, &raddr, &rport, &mti);
if (ret != mStatus_NoError)
{
LogMsg("mDNSPlatformRetrieveTCPInfo: mDNSPlatformRetrieveTCPInfo failed %d", ret);
@@ -6568,15 +6634,14 @@ mDNSlocal void BeginSleepProcessing(mDNS *const m)
m->NextScheduledSPRetry = m->timenow;
+ // Clear out the SCDynamic entry that stores the external SPS information
+ mDNSPlatformClearSPSData();
+
if (!m->SystemWakeOnLANEnabled) LogSPS("BeginSleepProcessing: m->SystemWakeOnLANEnabled is false");
else if (!mDNSCoreHaveAdvertisedMulticastServices(m)) LogSPS("BeginSleepProcessing: No advertised services");
else // If we have at least one advertised service
{
NetworkInterfaceInfo *intf;
-
- // Clear out the SCDynamic entry that stores the external SPS information
- mDNSPlatformClearSPSData();
-
for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
{
// Intialize it to false. These values make sense only when SleepState is set to Sleeping.
@@ -6616,7 +6681,7 @@ mDNSlocal void BeginSleepProcessing(mDNS *const m)
else if (SupportsInNICProxy(intf))
{
mDNSBool keepaliveOnly = mDNSfalse;
- if (ActivateLocalProxy(m, intf, &keepaliveOnly) == mStatus_NoError)
+ if (ActivateLocalProxy(intf, &keepaliveOnly) == mStatus_NoError)
{
SendGoodbyesForWakeOnlyService(m, &WakeOnlyService);
@@ -6833,11 +6898,6 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
// 2. Re-validate our cache records
currtime = mDNSPlatformUTC();
-#if APPLE_OSX_mDNSResponder
- // start time of this statistics gathering interval
- m->StatStartTime = currtime;
-#endif // APPLE_OSX_mDNSResponder
-
diff = currtime - m->TimeSlept;
FORALL_CACHERECORDS(slot, cg, cr)
{
@@ -6984,7 +7044,7 @@ mDNSexport mDNSBool mDNSCoreReadyForSleep(mDNS *m, mDNSs32 now)
if (rr->state == regState_Refresh && rr->tcp)
{ LogSPS("mDNSCoreReadyForSleep: waiting for Record updateIntID 0x%x 0x%x (updateid %d) %s", rr->updateIntID.l[1], rr->updateIntID.l[0], mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto notready; }
#if APPLE_OSX_mDNSResponder
- if (!RecordReadyForSleep(m, rr)) { LogSPS("mDNSCoreReadyForSleep: waiting for %s", ARDisplayString(m, rr)); goto notready; }
+ if (!RecordReadyForSleep(rr)) { LogSPS("mDNSCoreReadyForSleep: waiting for %s", ARDisplayString(m, rr)); goto notready; }
#endif
}
@@ -7315,8 +7375,7 @@ exit:
mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, const ResourceRecord *const pktrr)
{
- mDNSu32 slot = HashSlot(pktrr->name);
- CacheGroup *cg = CacheGroupForRecord(m, slot, pktrr);
+ CacheGroup *cg = CacheGroupForRecord(m, pktrr);
CacheRecord *rr;
mDNSBool match;
for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
@@ -7563,7 +7622,7 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
// We only mark this question for sending if it is at least one second since the last time we multicast it
// on this interface. If it is more than a second, or LastMCInterface is different, then we may multicast it.
// This is to guard against the case where someone blasts us with queries as fast as they can.
- if (m->timenow - (rr->LastMCTime + mDNSPlatformOneSecond) >= 0 ||
+ if ((mDNSu32)(m->timenow - rr->LastMCTime) >= (mDNSu32)mDNSPlatformOneSecond ||
(rr->LastMCInterface != mDNSInterfaceMark && rr->LastMCInterface != InterfaceID))
rr->NR_AnswerTo = NR_AnswerMulticast;
}
@@ -7592,44 +7651,25 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
if (query->h.flags.b[0] & kDNSFlag0_TC)
m->mDNSStats.KnownAnswerMultiplePkts++;
-#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
- if (QuestionNeedsMulticastResponse)
-#else
// We only do the following accelerated cache expiration and duplicate question suppression processing
// for non-truncated multicast queries with multicast responses.
// For any query generating a unicast response we don't do this because we can't assume we will see the response.
// For truncated queries we don't do this because a response we're expecting might be suppressed by a subsequent
// known-answer packet, and when there's packet loss we can't safely assume we'll receive *all* known-answer packets.
if (QuestionNeedsMulticastResponse && !(query->h.flags.b[0] & kDNSFlag0_TC))
-#endif
{
#if POOF_ENABLED
- const mDNSu32 slot = HashSlot(&pktq.qname);
- CacheGroup *cg = CacheGroupForName(m, slot, pktq.qnamehash, &pktq.qname);
+ CacheGroup *cg = CacheGroupForName(m, pktq.qnamehash, &pktq.qname);
CacheRecord *cr;
// Make a list indicating which of our own cache records we expect to see updated as a result of this query
// Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated
-#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
- if (!(query->h.flags.b[0] & kDNSFlag0_TC))
-#endif // ENABLE_MULTI_PACKET_QUERY_SNOOPING
for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
if (SameNameRecordAnswersQuestion(&cr->resrec, &pktq) && cr->resrec.rdlength <= SmallRecordLimit)
if (!cr->NextInKAList && eap != &cr->NextInKAList)
{
*eap = cr;
eap = &cr->NextInKAList;
-#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
- if (cr->MPUnansweredQ == 0 || m->timenow - cr->MPLastUnansweredQT >= mDNSPlatformOneSecond)
- {
- // Although MPUnansweredQ is only really used for multi-packet query processing,
- // we increment it for both single-packet and multi-packet queries, so that it stays in sync
- // with the MPUnansweredKA value, which by necessity is incremented for both query types.
- cr->MPUnansweredQ++;
- cr->MPLastUnansweredQT = m->timenow;
- cr->MPExpectingKA = mDNStrue;
- }
-#endif // ENABLE_MULTI_PACKET_QUERY_SNOOPING
}
#endif // POOF_ENABLED
@@ -7637,9 +7677,6 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
// We only do this for non-truncated queries. Right now it would be too complicated to try
// to keep track of duplicate suppression state between multiple packets, especially when we
// can't guarantee to receive all of the Known Answer packets that go with a particular query.
-#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
- if (!(query->h.flags.b[0] & kDNSFlag0_TC))
-#endif
// For anonymous question, the duplicate suppressesion should happen if the
// question belongs in the same group. As the group is expected to be
// small, we don't do the optimization for now.
@@ -7723,16 +7760,6 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
ourcacherr = FindIdenticalRecordInCache(m, &m->rec.r.resrec);
- #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
- // See if this Known-Answer suppresses any answers we were expecting for our cache records. We do this always,
- // even if the TC bit is not set (the TC bit will *not* be set in the *last* packet of a multi-packet KA list).
- if (ourcacherr && ourcacherr->MPExpectingKA && m->timenow - ourcacherr->MPLastUnansweredQT < mDNSPlatformOneSecond)
- {
- ourcacherr->MPUnansweredKA++;
- ourcacherr->MPExpectingKA = mDNSfalse;
- }
- #endif
-
#if POOF_ENABLED
// Having built our ExpectedAnswers list from the questions in this packet, we then remove
// any records that are suppressed by the Known Answer list in this packet.
@@ -7779,13 +7806,9 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
mDNSBool SendMulticastResponse = mDNSfalse; // Send modern multicast response
mDNSBool SendUnicastResponse = mDNSfalse; // Send modern unicast response (not legacy unicast response)
-#if !TARGET_OS_EMBEDDED
- // always honor kDNSQClass_UnicastResponse in embedded environment to increase reliability
- // in high multicast packet loss environments.
-
// If it's been one TTL/4 since we multicast this, then send a multicast response
// for conflict detection, etc.
- if (m->timenow - (rr->LastMCTime + TicksTTL(rr)/4) >= 0)
+ if ((mDNSu32)(m->timenow - rr->LastMCTime) >= (mDNSu32)TicksTTL(rr)/4)
{
SendMulticastResponse = mDNStrue;
// If this record was marked for modern (delayed) unicast response, then mark it as promoted to
@@ -7797,7 +7820,6 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
rr->NR_AnswerTo = NR_AnswerMulticast;
}
}
-#endif // !TARGET_OS_EMBEDDED
// If the client insists on a multicast response, then we'd better send one
if (rr->NR_AnswerTo == NR_AnswerMulticast)
@@ -7925,12 +7947,7 @@ exit:
cr->UnansweredQueries++;
cr->LastUnansweredTime = m->timenow;
if (cr->UnansweredQueries > 1)
- #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
- debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s",
- cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr));
- #else
debugf("ProcessQuery: UnansweredQueries %lu %s", cr->UnansweredQueries, CRDisplayString(m, cr));
- #endif // ENABLE_MULTI_PACKET_QUERY_SNOOPING
SetNextCacheCheckTimeForRecord(m, cr);
}
@@ -7940,49 +7957,12 @@ exit:
{
// Only show debugging message if this record was not about to expire anyway
if (RRExpireTime(cr) - m->timenow > (mDNSs32) kDefaultReconfirmTimeForNoAnswer * 4 / 3 + mDNSPlatformOneSecond)
- #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
- debugf("ProcessQuery: (Max) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
- cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr));
- #else
- LogInfo("ProcessQuery: UnansweredQueries %lu TTL %lu mDNS_Reconfirm() for %s",
- cr->UnansweredQueries, (RRExpireTime(cr) - m->timenow + mDNSPlatformOneSecond-1) / mDNSPlatformOneSecond, CRDisplayString(m, cr));
- #endif // ENABLE_MULTI_PACKET_QUERY_SNOOPING
+ LogInfo("ProcessQuery: UnansweredQueries %lu interface %lu TTL %lu mDNS_Reconfirm() for %s",
+ cr->UnansweredQueries, InterfaceID, (RRExpireTime(cr) - m->timenow + mDNSPlatformOneSecond-1) / mDNSPlatformOneSecond, CRDisplayString(m, cr));
m->mDNSStats.PoofCacheDeletions++;
mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
}
-#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
- // Make a guess, based on the multi-packet query / known answer counts, whether we think we
- // should have seen an answer for this. (We multiply MPQ by 4 and MPKA by 5, to allow for
- // possible packet loss of up to 20% of the additional KA packets.)
- else if (cr->MPUnansweredQ * 4 > cr->MPUnansweredKA * 5 + 8)
- {
- // We want to do this conservatively.
- // If there are so many machines on the network that they have to use multi-packet known-answer lists,
- // then we don't want them to all hit the network simultaneously with their final expiration queries.
- // By setting the record to expire in four minutes, we achieve two things:
- // (a) the 90-95% final expiration queries will be less bunched together
- // (b) we allow some time for us to witness enough other failed queries that we don't have to do our own
- mDNSu32 remain = (mDNSu32)(RRExpireTime(cr) - m->timenow) / 4;
- if (remain > 240 * (mDNSu32)mDNSPlatformOneSecond)
- remain = 240 * (mDNSu32)mDNSPlatformOneSecond;
-
- // Only show debugging message if this record was not about to expire anyway
- if (RRExpireTime(cr) - m->timenow > 4 * mDNSPlatformOneSecond)
- debugf("ProcessQuery: (MPQ) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s",
- cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr));
-
- if (remain <= 60 * (mDNSu32)mDNSPlatformOneSecond)
- cr->UnansweredQueries++; // Treat this as equivalent to one definite unanswered query
- cr->MPUnansweredQ = 0; // Clear MPQ/MPKA statistics
- cr->MPUnansweredKA = 0;
- cr->MPExpectingKA = mDNSfalse;
-
- if (remain < kDefaultReconfirmTimeForNoAnswer)
- remain = kDefaultReconfirmTimeForNoAnswer;
- mDNS_Reconfirm_internal(m, cr, remain);
- }
-#endif // ENABLE_MULTI_PACKET_QUERY_SNOOPING
}
#endif // POOF_ENABLED
@@ -8229,19 +8209,13 @@ mDNSlocal void RefreshCacheRecord(mDNS *const m, CacheRecord *rr, mDNSu32 ttl)
rr->TimeRcvd = m->timenow;
rr->resrec.rroriginalttl = ttl;
rr->UnansweredQueries = 0;
-#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
- rr->MPUnansweredQ = 0;
- rr->MPUnansweredKA = 0;
- rr->MPExpectingKA = mDNSfalse;
-#endif
SetNextCacheCheckTimeForRecord(m, rr);
}
mDNSexport void GrantCacheExtensions(mDNS *const m, DNSQuestion *q, mDNSu32 lease)
{
CacheRecord *rr;
- const mDNSu32 slot = HashSlot(&q->qname);
- CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+ CacheGroup *cg = CacheGroupForName(m, q->qnamehash, &q->qname);
for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
if (rr->CRActiveQuestion == q)
{
@@ -8454,8 +8428,7 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage *
if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q, !dstaddr)))
{
CacheRecord *rr, *neg = mDNSNULL;
- mDNSu32 slot = HashSlot(&q.qname);
- CacheGroup *cg = CacheGroupForName(m, slot, q.qnamehash, &q.qname);
+ CacheGroup *cg = CacheGroupForName(m, q.qnamehash, &q.qname);
for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
if (SameNameRecordAnswersQuestion(&rr->resrec, qptr))
{
@@ -8524,8 +8497,7 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage *
ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && m->rec.r.resrec.rrtype == kDNSType_SOA)
{
- const mDNSu32 s = HashSlot(m->rec.r.resrec.name);
- CacheGroup *cgSOA = CacheGroupForRecord(m, s, &m->rec.r.resrec);
+ CacheGroup *cgSOA = CacheGroupForRecord(m, &m->rec.r.resrec);
const rdataSOA *const soa = (const rdataSOA *)m->rec.r.resrec.rdata->u.data;
mDNSu32 ttl_s = soa->min;
// We use the lesser of the SOA.MIN field and the SOA record's TTL, *except*
@@ -8537,7 +8509,7 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage *
// Create the SOA record as we may have to return this to the questions
// that we are acting as a proxy for currently or in the future.
- SOARecord = CreateNewCacheEntry(m, s, cgSOA, 1, mDNSfalse, mDNSNULL);
+ SOARecord = CreateNewCacheEntry(m, HashSlotFromNameHash(m->rec.r.resrec.namehash), cgSOA, 1, mDNSfalse, mDNSNULL);
// Special check for SOA queries: If we queried for a.b.c.d.com, and got no answer,
// with an Authority Section SOA record for d.com, then this is a hint that the authority
@@ -8620,12 +8592,12 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage *
// been NULL. If we pass NULL cg to new cache entries that we create below,
// it will create additional cache groups for the same name. To avoid that,
// look up the cache group again to re-initialize cg again.
- cg = CacheGroupForName(m, slot, hash, name);
+ cg = CacheGroupForName(m, hash, name);
if (NSECRecords && DNSSECQuestion(qptr))
{
// Create the cache entry with delay and then add the NSEC records
// to it and add it immediately.
- negcr = CreateNewCacheEntry(m, slot, cg, 1, mDNStrue, mDNSNULL);
+ negcr = CreateNewCacheEntry(m, HashSlotFromNameHash(hash), cg, 1, mDNStrue, mDNSNULL);
if (negcr)
{
negcr->CRDNSSECQuestion = 0;
@@ -8650,7 +8622,7 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage *
else
{
// Need to add with a delay so that we can tag the SOA record
- negcr = CreateNewCacheEntry(m, slot, cg, 1, mDNStrue, mDNSNULL);
+ negcr = CreateNewCacheEntry(m, HashSlotFromNameHash(hash), cg, 1, mDNStrue, mDNSNULL);
if (negcr)
{
negcr->CRDNSSECQuestion = 0;
@@ -8674,9 +8646,6 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage *
repeat--;
name = (const domainname *)(name->c + 1 + name->c[0]);
hash = DomainNameHashValue(name);
- slot = HashSlot(name);
- // For now, we don't need to update cg here, because we'll do it again immediately, back up at the start of this loop
- //cg = CacheGroupForName(m, slot, hash, name);
}
}
}
@@ -8891,7 +8860,6 @@ mDNSlocal void mDNSParseNSEC3Records(mDNS *const m, const DNSMessage *const resp
}
for (i = 0; i < response->h.numAuthorities && ptr && ptr < end; i++)
{
- mDNSu32 slot;
CacheGroup *cg;
ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
@@ -8901,11 +8869,10 @@ mDNSlocal void mDNSParseNSEC3Records(mDNS *const m, const DNSMessage *const resp
m->rec.r.resrec.RecordType = 0;
continue;
}
- slot = HashSlot(m->rec.r.resrec.name);
- cg = CacheGroupForRecord(m, slot, &m->rec.r.resrec);
+ cg = CacheGroupForRecord(m, &m->rec.r.resrec);
// Create the cache entry but don't add it to the cache it. We need
// to cache this along with the main cache record.
- rr = CreateNewCacheEntry(m, slot, cg, 0, mDNSfalse, mDNSNULL);
+ rr = CreateNewCacheEntry(m, HashSlotFromNameHash(m->rec.r.resrec.namehash), cg, 0, mDNSfalse, mDNSNULL);
if (rr)
{
debugf("mDNSParseNSEC3Records: %s", CRDisplayString(m, rr));
@@ -9027,8 +8994,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
CacheRecord *rr;
// Remember the unicast question that we found, which we use to make caching
// decisions later on in this function
- const mDNSu32 slot = HashSlot(&q.qname);
- CacheGroup *cg = CacheGroupForName(m, slot, q.qnamehash, &q.qname);
+ CacheGroup *cg = CacheGroupForName(m, q.qnamehash, &q.qname);
if (!mDNSOpaque16IsZero(response->h.id))
{
unicastQuestion = qptr;
@@ -9401,7 +9367,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
// have any record(s) of the same type that we should re-assert to rescue them
// (see note about "multi-homing and bridged networks" at the end of this function).
else if (m->rec.r.resrec.rrtype == rr->resrec.rrtype)
- if ((m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) && m->timenow - rr->LastMCTime > mDNSPlatformOneSecond/2)
+ if ((m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) && (mDNSu32)(m->timenow - rr->LastMCTime) > (mDNSu32)mDNSPlatformOneSecond/2)
{ rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; }
}
}
@@ -9420,8 +9386,8 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
if (!AcceptableResponse) LogInfo("mDNSCoreReceiveResponse ignoring %s", CRDisplayString(m, &m->rec.r));
if (m->rrcache_size && AcceptableResponse)
{
- const mDNSu32 slot = HashSlot(m->rec.r.resrec.name);
- CacheGroup *cg = CacheGroupForRecord(m, slot, &m->rec.r.resrec);
+ const mDNSu32 slot = HashSlotFromNameHash(m->rec.r.resrec.namehash);
+ CacheGroup *cg = CacheGroupForRecord(m, &m->rec.r.resrec);
CacheRecord *rr = mDNSNULL;
if (McastNSEC3Records)
@@ -9447,7 +9413,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
if (AddToCFList)
delay = NonZeroTime(m->timenow + mDNSPlatformOneSecond);
else
- delay = CheckForSoonToExpireRecords(m, m->rec.r.resrec.name, m->rec.r.resrec.namehash, slot, mDNSNULL);
+ delay = CheckForSoonToExpireRecords(m, m->rec.r.resrec.name, m->rec.r.resrec.namehash, mDNSNULL);
// If unique, assume we may have to delay delivery of this 'add' event.
// Below, where we walk the CacheFlushRecords list, we either call CacheRecordDeferredAdd()
@@ -9513,8 +9479,8 @@ exit:
while (CacheFlushRecords != (CacheRecord*)1)
{
CacheRecord *r1 = CacheFlushRecords, *r2;
- const mDNSu32 slot = HashSlot(r1->resrec.name);
- const CacheGroup *cg = CacheGroupForRecord(m, slot, &r1->resrec);
+ const mDNSu32 slot = HashSlotFromNameHash(r1->resrec.namehash);
+ const CacheGroup *cg = CacheGroupForRecord(m, &r1->resrec);
CacheFlushRecords = CacheFlushRecords->NextInCFList;
r1->NextInCFList = mDNSNULL;
@@ -9664,7 +9630,7 @@ exit:
NSECRecords = mDNSNULL;
NSECCachePtr = mDNSNULL;
}
- r1->DelayDelivery = CheckForSoonToExpireRecords(m, r1->resrec.name, r1->resrec.namehash, slot, mDNSNULL);
+ r1->DelayDelivery = CheckForSoonToExpireRecords(m, r1->resrec.name, r1->resrec.namehash, mDNSNULL);
// If no longer delaying, deliver answer now, else schedule delivery for the appropriate time
if (!r1->DelayDelivery) CacheRecordDeferredAdd(m, r1);
else ScheduleNextCacheCheckTime(m, slot, r1->DelayDelivery);
@@ -10382,13 +10348,14 @@ mDNSlocal mDNSu32 mDNSGenerateOwnerOptForInterface(mDNS *const m, const mDNSInte
mDNSu8 *end = mDNSNULL;
mDNSu32 length = 0;
AuthRecord opt;
+ NetworkInterfaceInfo *intf;
mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
opt.resrec.rrclass = NormalMaxDNSMessageData;
opt.resrec.rdlength = sizeof(rdataOPT);
opt.resrec.rdestimate = sizeof(rdataOPT);
- NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
+ intf = FirstInterfaceForID(m, InterfaceID);
SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[0]);
LogSPS("Generated OPT record : %s", ARDisplayString(m, &opt));
@@ -10405,30 +10372,18 @@ mDNSlocal mDNSu32 mDNSGenerateOwnerOptForInterface(mDNS *const m, const mDNSInte
return length;
}
+// Note that this routine is called both for Sleep Proxy Registrations, and for Standard Dynamic
+// DNS registrations, but (currently) only has to handle the Sleep Proxy Registration reply case,
+// and should ignore Standard Dynamic DNS registration replies, because those are handled elsewhere.
+// Really, both should be unified and handled in one place.
mDNSlocal void mDNSCoreReceiveUpdateR(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *end, const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID)
{
if (InterfaceID)
{
- mDNSu32 updatelease = 60 * 60; // If SPS fails to indicate lease time, assume one hour
- const mDNSu8 *ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space);
- mDNSAddr spsaddr;
- char *ifname;
- if (ptr)
- {
- ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
- if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && m->rec.r.resrec.rrtype == kDNSType_OPT)
- {
- const rdataOPT *o;
- const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength];
- for (o = &m->rec.r.resrec.rdata->u.opt[0]; o < e; o++)
- if (o->opt == kDNSOpt_Lease)
- {
- updatelease = o->u.updatelease;
- LogSPS("Sleep Proxy granted lease time %4d seconds, updateid %d, InterfaceID %p", updatelease, mDNSVal16(msg->h.id), InterfaceID);
- }
- }
- m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
- }
+ mDNSu32 pktlease = 0, spsupdates = 0;
+ const mDNSBool gotlease = GetPktLease(m, msg, end, &pktlease);
+ const mDNSu32 updatelease = gotlease ? pktlease : 60 * 60; // If SPS fails to indicate lease time, assume one hour
+ if (gotlease) LogSPS("DNS Update response contains lease option granting %4d seconds, updateid %d, InterfaceID %p", updatelease, mDNSVal16(msg->h.id), InterfaceID);
if (m->CurrentRecord)
LogMsg("mDNSCoreReceiveUpdateR ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
@@ -10447,7 +10402,8 @@ mDNSlocal void mDNSCoreReceiveUpdateR(mDNS *const m, const DNSMessage *const msg
if (mDNSOpaque64IsZero(&rr->updateIntID))
rr->updateid = zeroID;
rr->expire = NonZeroTime(m->timenow + updatelease * mDNSPlatformOneSecond);
- LogSPS("Sleep Proxy %s record %5d 0x%x 0x%x (%d) %s", rr->WakeUp.HMAC.l[0] ? "transferred" : "registered", updatelease, rr->updateIntID.l[1], rr->updateIntID.l[0], mDNSVal16(rr->updateid), ARDisplayString(m,rr));
+ spsupdates++;
+ LogSPS("Sleep Proxy %s record %2d %5d 0x%x 0x%x (%d) %s", rr->WakeUp.HMAC.l[0] ? "transferred" : "registered", spsupdates, updatelease, rr->updateIntID.l[1], rr->updateIntID.l[0], mDNSVal16(rr->updateid), ARDisplayString(m,rr));
if (rr->WakeUp.HMAC.l[0])
{
rr->WakeUp.HMAC = zeroEthAddr; // Clear HMAC so that mDNS_Deregister_internal doesn't waste packets trying to wake this host
@@ -10460,22 +10416,26 @@ mDNSlocal void mDNSCoreReceiveUpdateR(mDNS *const m, const DNSMessage *const msg
if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now
m->CurrentRecord = rr->next;
}
-
- // Update the dynamic store with the IP Address and MAC address of the sleep proxy
- ifname = InterfaceNameForID(m, InterfaceID);
- mDNSPlatformMemCopy(&spsaddr, srcaddr, sizeof (mDNSAddr));
- mDNSPlatformStoreSPSMACAddr(&spsaddr, ifname);
-
- // Store the Owner OPT record for this interface.
- // Configd may use the OPT record if it detects a conflict with the BSP when the system wakes up
- DNSMessage optMsg;
- int length = 0;
- InitializeDNSMessage(&optMsg.h, zeroID, ResponseFlags);
- length = mDNSGenerateOwnerOptForInterface(m, InterfaceID, &optMsg);
- if (length != 0)
+ if (spsupdates) // Only do this dynamic store stuff if this was, in fact, a Sleep Proxy Update response
{
- length += sizeof(DNSMessageHeader);
- mDNSPlatformStoreOwnerOptRecord(ifname, &optMsg, length);
+ char *ifname;
+ mDNSAddr spsaddr;
+ DNSMessage optMsg;
+ int length;
+ // Update the dynamic store with the IP Address and MAC address of the sleep proxy
+ ifname = InterfaceNameForID(m, InterfaceID);
+ mDNSPlatformMemCopy(&spsaddr, srcaddr, sizeof (mDNSAddr));
+ mDNSPlatformStoreSPSMACAddr(&spsaddr, ifname);
+
+ // Store the Owner OPT record for this interface.
+ // Configd may use the OPT record if it detects a conflict with the BSP when the system wakes up
+ InitializeDNSMessage(&optMsg.h, zeroID, ResponseFlags);
+ length = mDNSGenerateOwnerOptForInterface(m, InterfaceID, &optMsg);
+ if (length != 0)
+ {
+ length += sizeof(DNSMessageHeader);
+ mDNSPlatformStoreOwnerOptRecord(ifname, &optMsg, length);
+ }
}
}
// If we were waiting to go to sleep, then this SPS registration or wide-area record deletion
@@ -10512,12 +10472,6 @@ mDNSexport void MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr,
cr->CRActiveQuestion = mDNSNULL;
cr->UnansweredQueries = 0;
cr->LastUnansweredTime = 0;
-#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
- cr->MPUnansweredQ = 0;
- cr->MPLastUnansweredQT = 0;
- cr->MPUnansweredKA = 0;
- cr->MPExpectingKA = mDNSfalse;
-#endif
cr->NextInCFList = mDNSNULL;
cr->nsec = mDNSNULL;
cr->soa = mDNSNULL;
@@ -10595,7 +10549,7 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS
// Track the number of multicast packets received from a source outside our subnet.
// Check the destination address to avoid accounting for spurious packets that
// comes in with message id zero.
- if (!mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr) &&
+ if (!mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr) && dstaddr &&
mDNSAddressIsAllDNSLinkGroup(dstaddr))
{
m->RemoteSubnet++;
@@ -10624,8 +10578,8 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS
{
static int msgCount = 0;
if (msgCount < 1000) {
- msgCount++;
int i = 0;
+ msgCount++;
LogInfo("Unknown DNS packet type %02X%02X from %#-15a:%-5d to %#-15a:%-5d length %d on %p (ignored)",
msg->h.flags.b[0], msg->h.flags.b[1], srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), (int)(end - pkt), InterfaceID);
while (i < (int)(end - pkt))
@@ -10658,6 +10612,11 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS
#define SameQTarget(A,B) (((A)->Target.type == mDNSAddrType_None && (B)->Target.type == mDNSAddrType_None) || \
(mDNSSameAddress(& (A)->Target, & (B)->Target) && mDNSSameIPPort((A)->TargetPort, (B)->TargetPort)))
+// SameQuestionKind is true if *both* questions are either multicast or unicast
+// TargetQID is used for this determination.
+#define SameQuestionKind(A,B) ((mDNSOpaque16IsZero(A) && mDNSOpaque16IsZero(B)) || \
+ ((!mDNSOpaque16IsZero(A)) && (!mDNSOpaque16IsZero(B))))
+
// Note: We explicitly disallow making a public query be a duplicate of a private one. This is to avoid the
// circular deadlock where a client does a query for something like "dns-sd -Q _dns-query-tls._tcp.company.com SRV"
// and we have a key for company.com, so we try to locate the private query server for company.com, which necessarily entails
@@ -10701,8 +10660,9 @@ mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuest
(q->DisallowPID == question->DisallowPID) && // Disallowing a PID should not affect a PID that is allowed
(q->BrowseThreshold == question->BrowseThreshold) && // browse thresholds must match
q->qnamehash == question->qnamehash &&
- (IsAWDLIncluded(q) == IsAWDLIncluded(question)) && // Inclusion of AWDL interface must match
- SameDomainName(&q->qname, &question->qname)) // and name
+ (IsAWDLIncluded(q) == IsAWDLIncluded(question)) && // Inclusion of AWDL interface must match
+ SameQuestionKind(q->TargetQID, question->TargetQID) && // mDNS or uDNS must match
+ SameDomainName(&q->qname, &question->qname)) // and name
return(q);
return(mDNSNULL);
}
@@ -11007,7 +10967,7 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question)
mDNSu32 timeout = 0;
mDNSBool DEQuery;
- question->validDNSServers = zeroOpaque64;
+ question->validDNSServers = zeroOpaque128;
DEQuery = DomainEnumQuery(&question->qname);
for (curr = m->DNSServers; curr; curr = curr->next)
{
@@ -11036,6 +10996,7 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question)
currcount = CountLabels(&curr->domain);
if ((!curr->cellIntf || (!DEQuery && !(question->flags & kDNSServiceFlagsDenyCellular))) &&
+ (!curr->isExpensive || !(question->flags & kDNSServiceFlagsDenyExpensive)) &&
DNSServerMatch(curr, question->InterfaceID, question->ServiceID))
{
bettermatch = BetterMatchForName(&question->qname, namecount, &curr->domain, currcount, bestmatchlen);
@@ -11050,7 +11011,7 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question)
if (bettermatch)
{
debugf("SetValidDNSServers: Resetting all the bits");
- question->validDNSServers = zeroOpaque64;
+ question->validDNSServers = zeroOpaque128;
timeout = 0;
}
debugf("SetValidDNSServers: question %##s Setting the bit for DNS server Address %#a (Domain %##s), Scoped:%d index %d,"
@@ -11059,15 +11020,15 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question)
timeout += curr->timeout;
if (DEQuery)
debugf("DomainEnumQuery: Question %##s, DNSServer %#a, cell %d", question->qname.c, &curr->addr, curr->cellIntf);
- bit_set_opaque64(question->validDNSServers, index);
+ bit_set_opaque128(question->validDNSServers, index);
}
}
index++;
}
question->noServerResponse = 0;
- debugf("SetValidDNSServers: ValidDNSServer bits 0x%x%x for question %p %##s (%s)",
- question->validDNSServers.l[1], question->validDNSServers.l[0], question, question->qname.c, DNSTypeName(question->qtype));
+ debugf("SetValidDNSServers: ValidDNSServer bits 0x%x%x%x%x for question %p %##s (%s)",
+ question->validDNSServers.l[3], question->validDNSServers.l[2], question->validDNSServers.l[1], question->validDNSServers.l[0], question, question->qname.c, DNSTypeName(question->qtype));
// If there are no matching resolvers, then use the default timeout value.
// For ProxyQuestion, shorten the timeout so that dig does not timeout on us in case of no response.
return ((question->ProxyQuestion || question->ValidatingResponse) ? DEFAULT_UDNSSEC_TIMEOUT : timeout ? timeout : DEFAULT_UDNS_TIMEOUT);
@@ -11075,7 +11036,7 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question)
// Get the Best server that matches a name. If you find penalized servers, look for the one
// that will come out of the penalty box soon
-mDNSlocal DNSServer *GetBestServer(mDNS *m, const domainname *name, mDNSInterfaceID InterfaceID, mDNSs32 ServiceID, mDNSOpaque64 validBits,
+mDNSlocal DNSServer *GetBestServer(mDNS *m, const domainname *name, mDNSInterfaceID InterfaceID, mDNSs32 ServiceID, mDNSOpaque128 validBits,
int *selected, mDNSBool nameMatch)
{
DNSServer *curmatch = mDNSNULL;
@@ -11154,7 +11115,7 @@ mDNSlocal DNSServer *GetServerForName(mDNS *m, const domainname *name, mDNSInter
{
DNSServer *curmatch = mDNSNULL;
char *ifname = mDNSNULL; // for logging purposes only
- mDNSOpaque64 allValid;
+ mDNSOpaque128 allValid;
if ((InterfaceID == mDNSInterface_Unicast) || (InterfaceID == mDNSInterface_LocalOnly))
InterfaceID = mDNSNULL;
@@ -11162,7 +11123,7 @@ mDNSlocal DNSServer *GetServerForName(mDNS *m, const domainname *name, mDNSInter
if (InterfaceID) ifname = InterfaceNameForID(m, InterfaceID);
// By passing in all ones, we make sure that every DNS server is considered
- allValid.l[0] = allValid.l[1] = 0xFFFFFFFF;
+ allValid.l[0] = allValid.l[1] = allValid.l[2] = allValid.l[3] = 0xFFFFFFFF;
curmatch = GetBestServer(m, name, InterfaceID, ServiceID, allValid, mDNSNULL, mDNStrue);
@@ -11191,11 +11152,11 @@ mDNSexport DNSServer *GetServerForQuestion(mDNS *m, DNSQuestion *question)
if (InterfaceID)
ifname = InterfaceNameForID(m, InterfaceID);
- if (!mDNSOpaque64IsZero(&question->validDNSServers))
+ if (!mDNSOpaque128IsZero(&question->validDNSServers))
{
curmatch = GetBestServer(m, name, InterfaceID, question->ServiceID, question->validDNSServers, &currindex, mDNSfalse);
if (currindex != -1)
- bit_clr_opaque64(question->validDNSServers, currindex);
+ bit_clr_opaque128(question->validDNSServers, currindex);
}
if (curmatch != mDNSNULL)
@@ -11289,6 +11250,13 @@ mDNSlocal mDNSBool ShouldSuppressUnicastQuery(mDNS *const m, DNSQuestion *q, DNS
DNSTypeName(q->qtype), d->domain.c, &d->addr, mDNSVal16(d->port));
return mDNSfalse;
}
+#if USE_DNS64
+ if (DNS64IsQueryingARecord(q->dns64.state))
+ {
+ LogInfo("ShouldSuppressUnicastQuery: DNS64 query not suppressed for %##s, qtype %s", q->qname.c, DNSTypeName(q->qtype));
+ return mDNSfalse;
+ }
+#endif
LogInfo("ShouldSuppressUnicastQuery: Query suppressed for %##s, qtype %s, since DNS Configuration does not allow (req_A is %s and req_AAAA is %s)",
q->qname.c, DNSTypeName(q->qtype), d->req_A ? "true" : "false", d->req_AAAA ? "true" : "false");
@@ -11384,11 +11352,9 @@ mDNSlocal mDNSBool ShouldSuppressQuery(mDNS *const m, DNSQuestion *q)
mDNSlocal void CacheRecordRmvEventsForCurrentQuestion(mDNS *const m, DNSQuestion *q)
{
CacheRecord *rr;
- mDNSu32 slot;
CacheGroup *cg;
- slot = HashSlot(&q->qname);
- cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+ cg = CacheGroupForName(m, q->qnamehash, &q->qname);
for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
{
// Don't deliver RMV events for negative records
@@ -11445,7 +11411,6 @@ mDNSlocal mDNSBool IsQuestionNew(mDNS *const m, DNSQuestion *question)
mDNSlocal mDNSBool LocalRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q)
{
AuthRecord *rr;
- mDNSu32 slot;
AuthGroup *ag;
if (m->CurrentQuestion)
@@ -11458,8 +11423,7 @@ mDNSlocal mDNSBool LocalRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q
return mDNStrue;
}
m->CurrentQuestion = q;
- slot = AuthHashSlot(&q->qname);
- ag = AuthGroupForName(&m->rrauth, slot, q->qnamehash, &q->qname);
+ ag = AuthGroupForName(&m->rrauth, q->qnamehash, &q->qname);
if (ag)
{
for (rr = ag->members; rr; rr=rr->next)
@@ -11485,7 +11449,7 @@ mDNSlocal mDNSBool LocalRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q
// Returns false if the question got deleted while delivering the RMV events
// The caller should handle the case
-mDNSlocal mDNSBool CacheRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q)
+mDNSexport mDNSBool CacheRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q)
{
if (m->CurrentQuestion)
LogMsg("CacheRecordRmvEventsForQuestion: ERROR m->CurrentQuestion already set: %##s (%s)",
@@ -11684,33 +11648,29 @@ mDNSlocal void InitDNSConfig(mDNS *const m, DNSQuestion *const question)
{
// First reset all DNS Configuration
question->qDNSServer = mDNSNULL;
- question->validDNSServers = zeroOpaque64;
+ question->validDNSServers = zeroOpaque128;
question->triedAllServersOnce = 0;
question->noServerResponse = 0;
- question->StopTime = 0;
-#if TARGET_OS_EMBEDDED
+ question->StopTime = (question->TimeoutQuestion) ? question->StopTime : 0;
+#if AWD_METRICS
mDNSPlatformMemZero(&question->metrics, sizeof(question->metrics));
#endif
- // Need not initialize the DNS Configuration for Local Only OR P2P Questions
- if (LocalOnlyOrP2PInterface(question->InterfaceID))
+ // Need not initialize the DNS Configuration for Local Only OR P2P Questions when timeout not specified
+ if (LocalOnlyOrP2PInterface(question->InterfaceID) && !question->TimeoutQuestion)
return;
// Proceed to initialize DNS Configuration (some are set in SetValidDNSServers())
if (!mDNSOpaque16IsZero(question->TargetQID))
{
mDNSu32 timeout = SetValidDNSServers(m, question);
- // We set the timeout whenever mDNS_StartQuery_internal is called. This means if we have
- // a networking change/search domain change that calls this function again we keep
- // reinitializing the timeout value which means it may never timeout. If this becomes
- // a common case in the future, we can easily fix this by adding extra state that
- // indicates that we have already set the StopTime.
- //
- // Note that we set the timeout for all questions. If this turns out to be a duplicate,
+ // We set the timeout value the first time mDNS_StartQuery_internal is called for a question.
+ // So if a question is restarted when a network change occurs, the StopTime is not reset.
+ // Note that we set the timeout for all questions. If this turns out to be a duplicate,
// it gets a full timeout value even if the original question times out earlier.
- if (question->TimeoutQuestion)
+ if (question->TimeoutQuestion && !question->StopTime)
{
question->StopTime = NonZeroTime(m->timenow + timeout * mDNSPlatformOneSecond);
- LogInfo("InitDNSConfig: Setting StopTime on question %p %##s (%s)", question, question->qname.c, DNSTypeName(question->qtype));
+ LogInfo("InitDNSConfig: Setting StopTime on the uDNS question %p %##s (%s)", question, question->qname.c, DNSTypeName(question->qtype));
}
question->qDNSServer = GetServerForQuestion(m, question);
@@ -11719,17 +11679,22 @@ mDNSlocal void InitDNSConfig(mDNS *const m, DNSQuestion *const question)
question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort));
}
- else
+ else if (question->TimeoutQuestion && !question->StopTime)
{
- if (question->TimeoutQuestion)
- question->StopTime = NonZeroTime(m->timenow + GetTimeoutForMcastQuestion(m, question) * mDNSPlatformOneSecond);
+ // If the question is to be timed out and its a multicast, local-only or P2P case,
+ // then set it's stop time.
+ mDNSu32 timeout = LocalOnlyOrP2PInterface(question->InterfaceID) ?
+ DEFAULT_LO_OR_P2P_TIMEOUT : GetTimeoutForMcastQuestion(m, question);
+ question->StopTime = NonZeroTime(m->timenow + timeout * mDNSPlatformOneSecond);
+ LogInfo("InitDNSConfig: Setting StopTime on question %p %##s (%s)", question, question->qname.c, DNSTypeName(question->qtype));
}
// Set StopTime here since it is a part of DNS Configuration
if (question->StopTime)
SetNextQueryStopTime(m, question);
- // SetNextQueryTime() need not be initialized for LocalOnly OR P2P Questions since those questions
- // will never be transmitted on the wire. Hence we call SetNextQueryTime() here.
- SetNextQueryTime(m,question);
+ // Don't call SetNextQueryTime() if a LocalOnly OR P2P Question since those questions
+ // will never be transmitted on the wire.
+ if (!(LocalOnlyOrP2PInterface(question->InterfaceID)))
+ SetNextQueryTime(m,question);
}
// InitCommonState() is called by mDNS_StartQuery_internal() to initialize the common(uDNS/mDNS) internal
@@ -11755,7 +11720,7 @@ mDNSlocal mDNSBool InitCommonState(mDNS *const m, DNSQuestion *const question)
// turned ON which can allocate memory e.g., base64 encoding, in the case of DNSSEC.
question->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question
question->qnamehash = DomainNameHashValue(&question->qname);
- question->DelayAnswering = CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash, HashSlot(&question->qname), &purge);
+ question->DelayAnswering = CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash, &purge);
question->LastQTime = m->timenow;
question->ExpectUnicastResp = 0;
question->LastAnswerPktNum = m->PktNum;
@@ -11792,7 +11757,7 @@ mDNSlocal mDNSBool InitCommonState(mDNS *const m, DNSQuestion *const question)
if (!(question->flags & kDNSServiceFlagsServiceIndex))
{
#if APPLE_OSX_mDNSResponder
- mDNSPlatformGetDNSRoutePolicy(m, question, &isBlocked);
+ mDNSPlatformGetDNSRoutePolicy(question, &isBlocked);
#else
question->ServiceID = -1;
#endif
@@ -11897,10 +11862,12 @@ mDNSlocal void InitLLQState(DNSQuestion *const question)
question->id = zeroOpaque64;
}
+#ifdef DNS_PUSH_ENABLED
mDNSlocal void InitDNSPNState(DNSQuestion *const question)
{
question->dnsPushState = DNSPUSH_INIT;
}
+#endif // DNS_PUSH_ENABLED
// InitDNSSECProxyState() is called by mDNS_StartQuery_internal() to initialize
// DNSSEC & DNS Proxy fields of the DNS Question.
@@ -11941,6 +11908,16 @@ mDNSlocal void FinalizeUnicastQuestion(mDNS *const m, DNSQuestion *question, mDN
if (question->DuplicateOf)
{
question->validDNSServers = question->DuplicateOf->validDNSServers;
+ // If current(dup) question has DNS Server assigned but the original question has no DNS Server assigned to it,
+ // then we log a line as it could indicate an issue
+ if (question->DuplicateOf->qDNSServer == mDNSNULL)
+ {
+ if (question->qDNSServer)
+ LogInfo("FinalizeUnicastQuestion: Current(dup) question %p has DNSServer(%#a:%d) but original question(%p) has no DNS Server! %##s (%s)",
+ question, question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
+ mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort),
+ question->DuplicateOf, question->qname.c, DNSTypeName(question->qtype));
+ }
question->qDNSServer = question->DuplicateOf->qDNSServer;
LogInfo("FinalizeUnicastQuestion: Duplicate question %p (%p) %##s (%s), DNS Server %#a:%d",
question, question->DuplicateOf, question->qname.c, DNSTypeName(question->qtype),
@@ -12031,7 +12008,9 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
purge = InitCommonState(m, question);
InitWABState(question);
InitLLQState(question);
+#ifdef DNS_PUSH_ENABLED
InitDNSPNState(question);
+#endif // DNS_PUSH_ENABLED
InitDNSSECProxyState(m, question);
// FindDuplicateQuestion should be called last after all the intialization
@@ -12108,8 +12087,7 @@ mDNSexport void CancelGetZoneData(mDNS *const m, ZoneData *nta)
mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question)
{
- const mDNSu32 slot = HashSlot(&question->qname);
- CacheGroup *cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname);
+ CacheGroup *cg = CacheGroupForName(m, question->qnamehash, &question->qname);
CacheRecord *rr;
DNSQuestion **qp = &m->Questions;
@@ -12139,24 +12117,16 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
}
#endif // BONJOUR_ON_DEMAND
-#if TARGET_OS_EMBEDDED
+#if AWD_METRICS
if (Question_uDNS(question) && !question->metrics.answered && (question->metrics.querySendCount > 0))
{
const domainname * queryName;
mDNSBool isForCell;
mDNSu32 durationMs;
- queryName = question->metrics.originalQName ? question->metrics.originalQName : &question->qname;
- isForCell = (question->qDNSServer && question->qDNSServer->cellIntf);
-
- if (question->metrics.querySendCount > 0)
- {
- durationMs = ((m->timenow - question->metrics.firstQueryTime) * 1000) / mDNSPlatformOneSecond;
- }
- else
- {
- durationMs = 0;
- }
+ queryName = question->metrics.originalQName ? question->metrics.originalQName : &question->qname;
+ isForCell = (question->qDNSServer && question->qDNSServer->cellIntf);
+ durationMs = ((m->timenow - question->metrics.firstQueryTime) * 1000) / mDNSPlatformOneSecond;
MetricsUpdateUDNSQueryStats(queryName, question->qtype, mDNSNULL, question->metrics.querySendCount, durationMs, isForCell);
}
#endif
@@ -12279,6 +12249,7 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
question->tcp = mDNSNULL;
}
}
+#ifdef DNS_PUSH_ENABLED
else if (question->dnsPushState == DNSPUSH_ESTABLISHED)
{
if (question->tcp)
@@ -12288,6 +12259,7 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
question->tcp = mDNSNULL;
}
}
+#endif // DNS_PUSH_ENABLED
#if APPLE_OSX_mDNSResponder
UpdateAutoTunnelDomainStatuses(m);
#endif
@@ -12306,7 +12278,7 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
FreeAnonInfo(question->AnonInfo);
question->AnonInfo = mDNSNULL;
}
-#if TARGET_OS_EMBEDDED
+#if AWD_METRICS
if (question->metrics.originalQName)
{
mDNSPlatformMemFree(question->metrics.originalQName);
@@ -12314,6 +12286,10 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
}
#endif
+#if USE_DNS64
+ DNS64ResetState(question);
+#endif
+
return(mStatus_NoError);
}
@@ -12352,8 +12328,7 @@ mDNSexport mStatus mDNS_StopQueryWithRemoves(mDNS *const m, DNSQuestion *const q
if (status == mStatus_NoError && !qq)
{
const CacheRecord *rr;
- const mDNSu32 slot = HashSlot(&question->qname);
- CacheGroup *const cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname);
+ CacheGroup *const cg = CacheGroupForName(m, question->qnamehash, &question->qname);
LogInfo("Generating terminal removes for %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
if (rr->resrec.RecordType != kDNSRecordTypePacketNegative && SameNameRecordAnswersQuestion(&rr->resrec, question))
@@ -12585,6 +12560,8 @@ mDNSlocal NetworkInterfaceInfo *FindFirstAdvertisedInterface(mDNS *const m)
return(intf);
}
+// The parameter "set" here refers to the set of AuthRecords used to advertise this interface.
+// (It's a set of records, not a set of interfaces.)
mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
{
char buffer[MAX_REVERSE_MAPPING_NAME];
@@ -12599,6 +12576,8 @@ mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
primary = FindFirstAdvertisedInterface(m);
if (!primary) primary = set; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary
+ // We should never have primary be NULL, because even if there is
+ // no other interface yet, we should always find ourself in the list.
// If interface is marked as a direct link, we can assume the address record is unique
// and does not need to go through the probe phase of the probe/announce packet sequence.
@@ -12608,9 +12587,9 @@ mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
LogInfo("AdvertiseInterface: Marking address record as kDNSRecordTypeKnownUnique for %s", set->ifname);
// Send dynamic update for non-linklocal IPv4 Addresses
- mDNS_SetupResourceRecord(&set->RR_A, mDNSNULL, set->InterfaceID, kDNSType_A, kHostNameTTL, recordType, AuthRecordAny, mDNS_HostNameCallback, set);
- mDNS_SetupResourceRecord(&set->RR_PTR, mDNSNULL, set->InterfaceID, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
- mDNS_SetupResourceRecord(&set->RR_HINFO, mDNSNULL, set->InterfaceID, kDNSType_HINFO, kHostNameTTL, kDNSRecordTypeUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
+ mDNS_SetupResourceRecord(&set->RR_A, mDNSNULL, set->InterfaceID, kDNSType_A, kHostNameTTL, recordType, AuthRecordAny, mDNS_HostNameCallback, set);
+ mDNS_SetupResourceRecord(&set->RR_PTR, mDNSNULL, set->InterfaceID, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
+ mDNS_SetupResourceRecord(&set->RR_HINFO, mDNSNULL, set->InterfaceID, kDNSType_HINFO, kHostNameTTL, kDNSRecordTypeUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
#if ANSWER_REMOTE_HOSTNAME_QUERIES
set->RR_A.AllowRemoteQuery = mDNStrue;
@@ -12907,7 +12886,7 @@ mDNSexport void mDNS_DeactivateNetWake_internal(mDNS *const m, NetworkInterfaceI
}
}
-mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
+mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, InterfaceActivationSpeed activationSpeed)
{
AuthRecord *rr;
mDNSBool FirstOfType = mDNStrue;
@@ -12978,32 +12957,56 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
// We don't want to do a probe, and then see a stale echo of an announcement we ourselves sent,
// and think it's a conflicting answer to our probe.
// In the case of a flapping interface, we pause for five seconds, and reduce the announcement count to one packet.
- const mDNSs32 probedelay = flapping ? mDNSPlatformOneSecond * 5 : mDNSPlatformOneSecond / 2;
- const mDNSu8 numannounce = flapping ? (mDNSu8)1 : InitialAnnounceCount;
+ mDNSs32 probedelay;
+ mDNSu8 numannounce;
+ switch (activationSpeed)
+ {
+ case FastActivation:
+ probedelay = (mDNSs32)0;
+ numannounce = InitialAnnounceCount;
+ LogMsg("mDNS_RegisterInterface: Using fast activation for DirectLink interface %s (%#a)", set->ifname, &set->ip);
+ break;
- // Use a small amount of randomness:
- // In the case of a network administrator turning on an Ethernet hub so that all the
- // connected machines establish link at exactly the same time, we don't want them all
- // to go and hit the network with identical queries at exactly the same moment.
- // We set a random delay of up to InitialQuestionInterval (1/3 second).
- // We must *never* set m->SuppressSending to more than that (or set it repeatedly in a way
- // that causes mDNSResponder to remain in a prolonged state of SuppressSending, because
- // suppressing packet sending for more than about 1/3 second can cause protocol correctness
- // to start to break down (e.g. we don't answer probes fast enough, and get name conflicts).
- // See <rdar://problem/4073853> mDNS: m->SuppressSending set too enthusiastically
- if (!m->SuppressSending) m->SuppressSending = m->timenow + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval);
+ case SlowActivation:
+ probedelay = mDNSPlatformOneSecond * 5;
+ numannounce = (mDNSu8)1;
+ LogMsg("mDNS_RegisterInterface: Frequent transitions for interface %s (%#a), doing slow activation", set->ifname, &set->ip);
+ m->mDNSStats.InterfaceUpFlap++;
+ break;
- if (flapping)
- {
- LogMsg("mDNS_RegisterInterface: Frequent transitions for interface %s (%#a)", set->ifname, &set->ip);
- m->mDNSStats.InterfaceUpFlap++;
+ case NormalActivation:
+ default:
+ probedelay = mDNSPlatformOneSecond / 2;
+ numannounce = InitialAnnounceCount;
+ break;
}
LogInfo("mDNS_RegisterInterface: %s (%#a) probedelay %d", set->ifname, &set->ip, probedelay);
- if (m->SuppressProbes == 0 ||
- m->SuppressProbes - NonZeroTime(m->timenow + probedelay) < 0)
- m->SuppressProbes = NonZeroTime(m->timenow + probedelay);
+ // No probe or sending suppression on DirectLink type interfaces.
+ if (activationSpeed == FastActivation)
+ {
+ m->SuppressSending = 0;
+ m->SuppressProbes = 0;
+ }
+ else
+ {
+ // Use a small amount of randomness:
+ // In the case of a network administrator turning on an Ethernet hub so that all the
+ // connected machines establish link at exactly the same time, we don't want them all
+ // to go and hit the network with identical queries at exactly the same moment.
+ // We set a random delay of up to InitialQuestionInterval (1/3 second).
+ // We must *never* set m->SuppressSending to more than that (or set it repeatedly in a way
+ // that causes mDNSResponder to remain in a prolonged state of SuppressSending, because
+ // suppressing packet sending for more than about 1/3 second can cause protocol correctness
+ // to start to break down (e.g. we don't answer probes fast enough, and get name conflicts).
+ // See <rdar://problem/4073853> mDNS: m->SuppressSending set too enthusiastically
+ if (!m->SuppressSending) m->SuppressSending = m->timenow + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval);
+
+ if (m->SuppressProbes == 0 ||
+ m->SuppressProbes - NonZeroTime(m->timenow + probedelay) < 0)
+ m->SuppressProbes = NonZeroTime(m->timenow + probedelay);
+ }
// Include OWNER option in packets for 60 seconds after connecting to the network. Setting
// it here also handles the wake up case as the network link comes UP after waking causing
@@ -13020,10 +13023,10 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
if (!q->InterfaceID || q->InterfaceID == set->InterfaceID) // If non-specific Q, or Q on this specific interface,
{ // then reactivate this question
// If flapping, delay between first and second queries is nine seconds instead of one second
- mDNSBool dodelay = flapping && (q->FlappingInterface1 == set->InterfaceID || q->FlappingInterface2 == set->InterfaceID);
+ mDNSBool dodelay = (activationSpeed == SlowActivation) && (q->FlappingInterface1 == set->InterfaceID || q->FlappingInterface2 == set->InterfaceID);
mDNSs32 initial = dodelay ? InitialQuestionInterval * QuestionIntervalStep2 : InitialQuestionInterval;
- mDNSs32 qdelay = dodelay ? mDNSPlatformOneSecond * 5 : 0;
- if (dodelay) LogInfo("No cache records expired for %##s (%s); okay to delay questions a little", q->qname.c, DNSTypeName(q->qtype));
+ mDNSs32 qdelay = dodelay ? kDefaultQueryDelayTimeForFlappingInterface : 0;
+ if (dodelay) LogInfo("No cache records expired for %##s (%s); delaying questions by %d seconds", q->qname.c, DNSTypeName(q->qtype), qdelay);
if (!q->ThisQInterval || q->ThisQInterval > initial)
{
@@ -13066,7 +13069,7 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
// Note: mDNS_DeregisterInterface calls mDNS_Deregister_internal which can call a user callback, which may change
// the record list and/or question list.
// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
-mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
+mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, InterfaceActivationSpeed activationSpeed)
{
NetworkInterfaceInfo **p = &m->HostInterfaces;
mDNSBool revalidate = mDNSfalse;
@@ -13126,7 +13129,7 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
m->mDNSStats.InterfaceDown++;
- if (set->McastTxRx && flapping)
+ if (set->McastTxRx && (activationSpeed == SlowActivation))
{
LogMsg("mDNS_DeregisterInterface: Frequent transitions for interface %s (%#a)", set->ifname, &set->ip);
m->mDNSStats.InterfaceDownFlap++;
@@ -13152,9 +13155,10 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
{
// If this interface is deemed flapping,
// postpone deleting the cache records in case the interface comes back again
- if (set->McastTxRx && flapping)
+ if (set->McastTxRx && (activationSpeed == SlowActivation))
{
- // For a flapping interface we want these record to go away after 30 seconds
+ // For a flapping interface we want these records to go away after
+ // kDefaultReconfirmTimeForFlappingInterface seconds if they are not reconfirmed.
mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface);
// We set UnansweredQueries = MaxUnansweredQueries so we don't waste time doing any queries for them --
// if the interface does come back, any relevant questions will be reactivated anyway
@@ -13314,10 +13318,7 @@ mDNSlocal void NSSCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
}
-// Derive AuthRecType from the coreFlag* values.
-// Note, this is not using the external flags values, kDNSServiceFlags*, defined in dns_sd.h.
-// It should be changed to do so once the use of coreFlag* is completely replaced with
-// the use the kDNSServiceFlags* definitions within mDNSResponder.
+// Derive AuthRecType from the kDNSServiceFlags* values.
mDNSlocal AuthRecType setAuthRecType(mDNSInterfaceID InterfaceID, mDNSu32 flags)
{
AuthRecType artype;
@@ -13326,12 +13327,12 @@ mDNSlocal AuthRecType setAuthRecType(mDNSInterfaceID InterfaceID, mDNSu32 flags)
artype = AuthRecordLocalOnly;
else if (InterfaceID == mDNSInterface_P2P || InterfaceID == mDNSInterface_BLE)
artype = AuthRecordP2P;
- else if ((InterfaceID == mDNSInterface_Any) && (flags & coreFlagIncludeP2P)
- && (flags & coreFlagIncludeAWDL))
+ else if ((InterfaceID == mDNSInterface_Any) && (flags & kDNSServiceFlagsIncludeP2P)
+ && (flags & kDNSServiceFlagsIncludeAWDL))
artype = AuthRecordAnyIncludeAWDLandP2P;
- else if ((InterfaceID == mDNSInterface_Any) && (flags & coreFlagIncludeP2P))
+ else if ((InterfaceID == mDNSInterface_Any) && (flags & kDNSServiceFlagsIncludeP2P))
artype = AuthRecordAnyIncludeP2P;
- else if ((InterfaceID == mDNSInterface_Any) && (flags & coreFlagIncludeAWDL))
+ else if ((InterfaceID == mDNSInterface_Any) && (flags & kDNSServiceFlagsIncludeAWDL))
artype = AuthRecordAnyIncludeAWDL;
else
artype = AuthRecordAny;
@@ -13370,7 +13371,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
mDNSu32 i;
mDNSu32 hostTTL;
AuthRecType artype;
- mDNSu8 recordType = (flags & coreFlagKnownUnique) ? kDNSRecordTypeKnownUnique : kDNSRecordTypeUnique;
+ mDNSu8 recordType = (flags & kDNSServiceFlagsKnownUnique) ? kDNSRecordTypeKnownUnique : kDNSRecordTypeUnique;
sr->ServiceCallback = Callback;
sr->ServiceContext = Context;
@@ -13388,7 +13389,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
mDNS_SetupResourceRecord(&sr->RR_ADV, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeAdvisory, artype, ServiceCallback, sr);
mDNS_SetupResourceRecord(&sr->RR_PTR, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, artype, ServiceCallback, sr);
- if (flags & coreFlagWakeOnly)
+ if (flags & kDNSServiceFlagsWakeOnlyService)
{
sr->RR_PTR.AuthFlags = AuthFlagsWakeOnly;
}
@@ -13399,7 +13400,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
hostTTL = kHostNameTTL;
mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, InterfaceID, kDNSType_SRV, hostTTL, recordType, artype, ServiceCallback, sr);
- mDNS_SetupResourceRecord(&sr->RR_TXT, mDNSNULL, InterfaceID, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnique, artype, ServiceCallback, sr);
+ mDNS_SetupResourceRecord(&sr->RR_TXT, mDNSNULL, InterfaceID, kDNSType_TXT, kStandardTTL, recordType, artype, ServiceCallback, sr);
// If port number is zero, that means the client is really trying to do a RegisterNoSuchService
if (mDNSIPPortIsZero(port))
@@ -13841,7 +13842,7 @@ mDNSlocal void mDNSCoreReceiveRawARP(mDNS *const m, const ARP_EthIP *const arp,
}
else if (msg == msg3)
{
- mDNSPlatformSetLocalAddressCacheEntry(m, &rr->AddressProxy, &rr->WakeUp.IMAC, InterfaceID);
+ mDNSPlatformSetLocalAddressCacheEntry(&rr->AddressProxy, &rr->WakeUp.IMAC, InterfaceID);
}
else if (msg == msg4)
{
@@ -13947,7 +13948,7 @@ mDNSlocal void mDNSCoreReceiveRawND(mDNS *const m, const mDNSEthAddr *const sha,
LogSPS("Reached maximum number of restarts for probing - %s", ARDisplayString(m,rr));
}
else if (msg == msg3)
- mDNSPlatformSetLocalAddressCacheEntry(m, &rr->AddressProxy, &rr->WakeUp.IMAC, InterfaceID);
+ mDNSPlatformSetLocalAddressCacheEntry(&rr->AddressProxy, &rr->WakeUp.IMAC, InterfaceID);
else if (msg == msg4)
SendNDP(m, NDP_Adv, NDP_Solicited, rr, &ndp->target, mDNSNULL, spa, sha);
else if (msg == msg5)
@@ -14286,7 +14287,7 @@ mDNSexport void mDNSCoreBeSleepProxyServer_internal(mDNS *const m, mDNSu8 sps, m
{
if (!m->SPSSocket)
{
- m->SPSSocket = mDNSPlatformUDPSocket(m, zeroIPPort);
+ m->SPSSocket = mDNSPlatformUDPSocket(zeroIPPort);
if (!m->SPSSocket) { LogMsg("mDNSCoreBeSleepProxyServer: Failed to allocate SPSSocket"); goto fail; }
}
#ifndef SPC_DISABLED
@@ -14328,9 +14329,9 @@ mDNSexport void mDNS_GrowCache(mDNS *const m, CacheEntity *storage, mDNSu32 numr
mDNS_Unlock(m);
}
-mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
- CacheEntity *rrcachestorage, mDNSu32 rrcachesize,
- mDNSBool AdvertiseLocalAddresses, mDNSCallback *Callback, void *Context)
+mDNSlocal mStatus mDNS_InitStorage(mDNS *const m, mDNS_PlatformSupport *const p,
+ CacheEntity *rrcachestorage, mDNSu32 rrcachesize,
+ mDNSBool AdvertiseLocalAddresses, mDNSCallback *Callback, void *Context)
{
mDNSu32 slot;
mDNSs32 timenow;
@@ -14370,14 +14371,14 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
m->timenow_last = timenow;
m->NextScheduledEvent = timenow;
m->SuppressSending = timenow;
- m->NextCacheCheck = timenow + 0x78000000;
- m->NextScheduledQuery = timenow + 0x78000000;
- m->NextScheduledProbe = timenow + 0x78000000;
- m->NextScheduledResponse = timenow + 0x78000000;
- m->NextScheduledNATOp = timenow + 0x78000000;
- m->NextScheduledSPS = timenow + 0x78000000;
- m->NextScheduledKA = timenow + 0x78000000;
- m->NextScheduledStopTime = timenow + 0x78000000;
+ m->NextCacheCheck = timenow + FutureTime;
+ m->NextScheduledQuery = timenow + FutureTime;
+ m->NextScheduledProbe = timenow + FutureTime;
+ m->NextScheduledResponse = timenow + FutureTime;
+ m->NextScheduledNATOp = timenow + FutureTime;
+ m->NextScheduledSPS = timenow + FutureTime;
+ m->NextScheduledKA = timenow + FutureTime;
+ m->NextScheduledStopTime = timenow + FutureTime;
m->NextBLEServiceTime = 0; // zero indicates inactive
#if BONJOUR_ON_DEMAND
@@ -14399,9 +14400,6 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
m->SleepLimit = 0;
#if APPLE_OSX_mDNSResponder
- m->StatStartTime = mDNSPlatformUTC();
- m->NextStatLogTime = m->StatStartTime + kDefaultNextStatsticsLogTime;
- m->ActiveStatTime = 0;
m->UnicastPacketsSent = 0;
m->MulticastPacketsSent = 0;
m->RemoteSubnet = 0;
@@ -14424,7 +14422,7 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
{
m->rrcache_hash[slot] = mDNSNULL;
- m->rrcache_nextcheck[slot] = timenow + 0x78000000;;
+ m->rrcache_nextcheck[slot] = timenow + FutureTime;;
}
mDNS_GrowCache_internal(m, rrcachestorage, rrcachesize);
@@ -14450,8 +14448,8 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
m->SuppressProbes = 0;
#ifndef UNICAST_DISABLED
- m->NextuDNSEvent = timenow + 0x78000000;
- m->NextSRVUpdate = timenow + 0x78000000;
+ m->NextuDNSEvent = timenow + FutureTime;
+ m->NextSRVUpdate = timenow + FutureTime;
m->DNSServers = mDNSNULL;
@@ -14482,7 +14480,7 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
m->NATTraversals = mDNSNULL;
m->CurrentNATTraversal = mDNSNULL;
m->retryIntervalGetAddr = 0; // delta between time sent and retry
- m->retryGetAddr = timenow + 0x78000000; // absolute time when we retry
+ m->retryGetAddr = timenow + FutureTime; // absolute time when we retry
m->ExtAddress = zerov4Addr;
m->PCPNonce[0] = mDNSRandom(-1);
m->PCPNonce[1] = mDNSRandom(-1);
@@ -14531,6 +14529,17 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
#endif
+ return(result);
+}
+
+mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
+ CacheEntity *rrcachestorage, mDNSu32 rrcachesize,
+ mDNSBool AdvertiseLocalAddresses, mDNSCallback *Callback, void *Context)
+{
+ mStatus result = mDNS_InitStorage(m, p, rrcachestorage, rrcachesize, AdvertiseLocalAddresses, Callback, Context);
+ if (result != mStatus_NoError)
+ return(result);
+
result = mDNSPlatformInit(m);
#ifndef UNICAST_DISABLED
@@ -14604,8 +14613,7 @@ mDNSlocal void PurgeOrReconfirmCacheRecord(mDNS *const m, CacheRecord *cr, const
mDNSlocal void mDNS_PurgeForQuestion(mDNS *const m, DNSQuestion *q)
{
- const mDNSu32 slot = HashSlot(&q->qname);
- CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+ CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
CacheRecord *rp;
mDNSu8 validatingResponse = 0;
@@ -14640,8 +14648,7 @@ mDNSlocal void mDNS_PurgeForQuestion(mDNS *const m, DNSQuestion *q)
// them.
mDNSlocal void CheckForDNSSECRecords(mDNS *const m, DNSQuestion *q)
{
- const mDNSu32 slot = HashSlot(&q->qname);
- CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+ CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
CacheRecord *rp;
for (rp = cg ? cg->members : mDNSNULL; rp; rp = rp->next)
@@ -14664,8 +14671,7 @@ mDNSlocal void CheckForDNSSECRecords(mDNS *const m, DNSQuestion *q)
mDNSexport mDNSBool mDNS_CheckForCacheRecord(mDNS *const m, DNSQuestion *q, mDNSu16 qtype)
{
DNSQuestion question;
- const mDNSu32 slot = HashSlot(&q->qname);
- CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+ CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
CacheRecord *rp;
// Create an identical question but with qtype
@@ -14788,7 +14794,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
// hence we are ready to ack the configuration as this is the last call to mDNSPlatformSetConfig
// for the dns configuration change notification.
SetConfigState(m, mDNStrue);
- if (!mDNSPlatformSetDNSConfig(m, mDNStrue, mDNSfalse, &fqdn, mDNSNULL, mDNSNULL, mDNStrue))
+ if (!mDNSPlatformSetDNSConfig(mDNStrue, mDNSfalse, &fqdn, mDNSNULL, mDNSNULL, mDNStrue))
{
SetDynDNSHostNameIfChanged(m, &fqdn);
SetConfigState(m, mDNSfalse);
@@ -14844,6 +14850,9 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
// cache records and as the resGroupID is different, you can't use the cache record from the scoped DNSServer to answer the
// non-scoped question and vice versa.
//
+#if USE_DNS64
+ DNS64RestartQuestions(m);
+#endif
for (q = m->Questions; q; q=q->next)
{
if (!mDNSOpaque16IsZero(q->TargetQID))
@@ -15007,7 +15016,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
{
LogMsg("uDNS_SetupDNSConfig: ERROR!! Cache Record %s Active question %##s (%s) (scope:%p) pointing to DNSServer Address %#a"
" to be freed", CRDisplayString(m, cr), qptr->qname.c, DNSTypeName(qptr->qtype), qptr->InterfaceID, &ptr->addr);
- qptr->validDNSServers = zeroOpaque64;
+ qptr->validDNSServers = zeroOpaque128;
qptr->qDNSServer = mDNSNULL;
cr->resrec.rDNSServer = mDNSNULL;
}
@@ -15070,7 +15079,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
v4 = v6 = r = zeroAddr;
v4.type = r.type = mDNSAddrType_IPv4;
- if (mDNSPlatformGetPrimaryInterface(m, &v4, &v6, &r) == mStatus_NoError && !mDNSv4AddressIsLinkLocal(&v4.ip.v4))
+ if (mDNSPlatformGetPrimaryInterface(&v4, &v6, &r) == mStatus_NoError && !mDNSv4AddressIsLinkLocal(&v4.ip.v4))
{
mDNS_SetPrimaryInterfaceInfo(m,
!mDNSIPv4AddressIsZero(v4.ip.v4) ? &v4 : mDNSNULL,
@@ -15256,3 +15265,7 @@ mDNSexport void mDNS_FinalExit(mDNS *const m)
LogInfo("mDNS_FinalExit: done");
}
+
+#ifdef UNIT_TEST
+#include "../unittests/mdns_ut.c"
+#endif
diff --git a/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h b/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h
index 81ade5c5..0e96058d 100755
--- a/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h
+++ b/mDNSResponder/mDNSCore/mDNSEmbeddedAPI.h
@@ -296,6 +296,11 @@ typedef mDNSOpaque48 mDNSEthAddr; // An Ethernet address is a six-byte opa
#define bit_set_opaque64(op64, index) (op64.l[((index))/(sizeof(mDNSu32) * mDNSNBBY)] |= (1 << ((index) % (sizeof(mDNSu32) * mDNSNBBY))))
#define bit_clr_opaque64(op64, index) (op64.l[((index))/(sizeof(mDNSu32) * mDNSNBBY)] &= ~(1 << ((index) % (sizeof(mDNSu32) * mDNSNBBY))))
#define bit_get_opaque64(op64, index) (op64.l[((index))/(sizeof(mDNSu32) * mDNSNBBY)] & (1 << ((index) % (sizeof(mDNSu32) * mDNSNBBY))))
+
+// Bit operations for opaque 128 bit quantity. Uses the 32 bit quantity(l[4]) to set and clear bits
+#define bit_set_opaque128(op128, index) (op128.l[((index))/(sizeof(mDNSu32) * mDNSNBBY)] |= (1 << ((index) % (sizeof(mDNSu32) * mDNSNBBY))))
+#define bit_clr_opaque128(op128, index) (op128.l[((index))/(sizeof(mDNSu32) * mDNSNBBY)] &= ~(1 << ((index) % (sizeof(mDNSu32) * mDNSNBBY))))
+#define bit_get_opaque128(op128, index) (op128.l[((index))/(sizeof(mDNSu32) * mDNSNBBY)] & (1 << ((index) % (sizeof(mDNSu32) * mDNSNBBY))))
typedef enum
{
@@ -722,7 +727,7 @@ typedef packedstruct
// Bit 6 (value 0x40) is set for answer records; clear for authority/additional records
// Bit 5 (value 0x20) is set for records received with the kDNSClass_UniqueRRSet
-enum
+typedef enum
{
kDNSRecordTypeUnregistered = 0x00, // Not currently in any list
kDNSRecordTypeDeregistering = 0x01, // Shared record about to announce its departure and leave the list
@@ -750,7 +755,7 @@ enum
kDNSRecordTypePacketNegative = 0xF0, // Pseudo-RR generated to cache non-existence results like NXDomain
kDNSRecordTypePacketUniqueMask = 0x10 // True for PacketAddUnique, PacketAnsUnique, PacketAuthUnique, kDNSRecordTypePacketNegative
-};
+} kDNSRecordTypes;
typedef packedstruct { mDNSu16 priority; mDNSu16 weight; mDNSIPPort port; domainname target; } rdataSRV;
typedef packedstruct { mDNSu16 preference; domainname exchange; } rdataMX;
@@ -1359,14 +1364,14 @@ typedef struct DNSServer
mDNSs32 penaltyTime; // amount of time this server is penalized
mDNSu32 scoped; // See the scoped enum above
mDNSu32 timeout; // timeout value for questions
- mDNSBool cellIntf; // Resolver from Cellular Interface ?
mDNSu16 resGroupID; // ID of the resolver group that contains this DNSServer
+ mDNSu8 retransDO; // Total Retransmissions for queries sent with DO option
+ mDNSBool cellIntf; // Resolver from Cellular Interface?
mDNSBool req_A; // If set, send v4 query (DNSConfig allows A queries)
mDNSBool req_AAAA; // If set, send v6 query (DNSConfig allows AAAA queries)
mDNSBool req_DO; // If set, okay to send DNSSEC queries (EDNS DO bit is supported)
- mDNSBool retransDO; // Total Retransmissions for queries sent with DO option
- mDNSBool DNSSECAware; // set if we are able to receive a response to a request
- // sent with DO option.
+ mDNSBool DNSSECAware; // Set if we are able to receive a response to a request sent with DO option.
+ mDNSBool isExpensive; // True if the interface to this server is expensive.
} DNSServer;
typedef struct
@@ -1380,9 +1385,9 @@ typedef struct
struct ResourceRecord_struct
{
- mDNSu8 RecordType; // See enum above
- mDNSu16 rrtype;
- mDNSu16 rrclass;
+ mDNSu8 RecordType; // See kDNSRecordTypes enum.
+ mDNSu16 rrtype; // See DNS_TypeValues enum.
+ mDNSu16 rrclass; // See DNS_ClassValues enum.
mDNSu32 rroriginalttl; // In seconds
mDNSu16 rdlength; // Size of the raw rdata, in bytes, in the on-the-wire format
// (In-memory storage may be larger, for structures containing 'holes', like SOA)
@@ -1595,7 +1600,7 @@ struct AuthRecord_struct
// Everywhere else in the code, the determination of whether a question is unicast is made by checking to see if TargetQID is nonzero.
#define AuthRecord_uDNS(R) ((R)->resrec.InterfaceID == mDNSInterface_Any && !(R)->ForceMCast && !IsLocalDomain((R)->resrec.name))
#define Question_uDNS(Q) ((Q)->InterfaceID == mDNSInterface_Unicast || (Q)->ProxyQuestion || \
- ((Q)->InterfaceID != mDNSInterface_LocalOnly && (Q)->InterfaceID != mDNSInterface_P2P && !(Q)->ForceMCast && !IsLocalDomain(&(Q)->qname)))
+ ((Q)->InterfaceID != mDNSInterface_LocalOnly && (Q)->InterfaceID != mDNSInterface_P2P && (Q)->InterfaceID != mDNSInterface_BLE && !(Q)->ForceMCast && !IsLocalDomain(&(Q)->qname)))
// AuthRecordLocalOnly records are registered using mDNSInterface_LocalOnly and
// AuthRecordP2P records are created by D2DServiceFound events. Both record types are kept on the same list.
@@ -1639,12 +1644,6 @@ struct CacheRecord_struct
mDNSu8 UnansweredQueries; // Number of times we've issued a query for this record without getting an answer
mDNSu8 CRDNSSECQuestion; // Set to 1 if this was created in response to a DNSSEC question
mDNSOpaque16 responseFlags; // Second 16 bit in the DNS response
-#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
- mDNSu32 MPUnansweredQ; // Multi-packet query handling: Number of times we've seen a query for this record
- mDNSs32 MPLastUnansweredQT; // Multi-packet query handling: Last time we incremented MPUnansweredQ
- mDNSu32 MPUnansweredKA; // Multi-packet query handling: Number of times we've seen this record in a KA list
- mDNSBool MPExpectingKA; // Multi-packet query handling: Set when we increment MPUnansweredQ; allows one KA
-#endif
CacheRecord *NextInCFList; // Set if this is in the list of records we just received with the cache flush bit set
CacheRecord *nsec; // NSEC records needed for non-existence proofs
CacheRecord *soa; // SOA record to return for proxy questions
@@ -1897,7 +1896,9 @@ typedef enum { DNSSECValNotRequired = 0, DNSSECValRequired, DNSSECValInProgress,
// RFC 4122 defines it to be 16 bytes
#define UUID_SIZE 16
-#if TARGET_OS_EMBEDDED
+#define AWD_METRICS (USE_AWD && TARGET_OS_EMBEDDED)
+
+#if AWD_METRICS
typedef struct
{
domainname * originalQName; // Name of original A/AAAA record if this question is for a CNAME record.
@@ -1906,10 +1907,18 @@ typedef struct
mDNSBool answered; // Has this question been answered?
} uDNSMetrics;
-
+#endif
+
+// DNS64 code is only for iOS, which is currently the only Apple OS that supports DNS proxy network extensions.
+#define USE_DNS64 (HAVE_DNS64 && TARGET_OS_IOS)
+
+#if USE_DNS64
+#include "DNS64State.h"
+#endif
+
+#if TARGET_OS_EMBEDDED
extern mDNSu32 curr_num_regservices; // tracks the current number of services registered
extern mDNSu32 max_num_regservices; // tracks the max number of simultaneous services registered by the device
-
#endif
struct DNSQuestion_struct
@@ -1964,7 +1973,7 @@ struct DNSQuestion_struct
// |-> DNS Configuration related fields used in uDNS (Subset of Wide Area/Unicast fields)
DNSServer *qDNSServer; // Caching server for this query (in the absence of an SRV saying otherwise)
- mDNSOpaque64 validDNSServers; // Valid DNSServers for this question
+ mDNSOpaque128 validDNSServers; // Valid DNSServers for this question
mDNSu16 noServerResponse; // At least one server did not respond.
mDNSu16 triedAllServersOnce; // Tried all DNS servers once
mDNSu8 unansweredQueries; // The number of unanswered queries to this server
@@ -2033,6 +2042,9 @@ struct DNSQuestion_struct
#if TARGET_OS_EMBEDDED
uDNSMetrics metrics; // Data used for collecting unicast DNS query metrics.
#endif
+#if USE_DNS64
+ DNS64 dns64; // DNS64 state for performing IPv6 address synthesis on networks with NAT64.
+#endif
};
typedef enum { ZoneServiceUpdate, ZoneServiceQuery, ZoneServiceLLQ, ZoneServiceDNSPush } ZoneService;
@@ -2281,6 +2293,10 @@ struct mDNS_DNSPushNotificationZone
} ;
+// Time constant (~= 260 hours ~= 10 days and 21 hours) used to set
+// various time values to a point well into the future.
+#define FutureTime 0x38000000
+
struct mDNS_struct
{
// Internal state fields. These hold the main internal state of mDNSCore;
@@ -2346,9 +2362,6 @@ struct mDNS_struct
// during which underying platform layer should inhibit system sleep
mDNSs32 TimeSlept; // Time we went to sleep.
- mDNSs32 StatStartTime; // Time we started gathering statistics during this interval.
- mDNSs32 NextStatLogTime; // Next time to log statistics.
- mDNSs32 ActiveStatTime; // Total time awake/gathering statistics for this log period.
mDNSs32 UnicastPacketsSent; // Number of unicast packets sent.
mDNSs32 MulticastPacketsSent; // Number of multicast packets sent.
mDNSs32 RemoteSubnet; // Multicast packets received from outside our subnet.
@@ -2445,11 +2458,11 @@ struct mDNS_struct
mDNSBool SSDPWANPPPConnection; // whether we should send the SSDP query for WANIPConnection or WANPPPConnection
mDNSIPPort UPnPRouterPort; // port we send discovery messages to
mDNSIPPort UPnPSOAPPort; // port we send SOAP messages to
- mDNSu8 *UPnPRouterURL; // router's URL string
+ char *UPnPRouterURL; // router's URL string
mDNSBool UPnPWANPPPConnection; // whether we're using WANIPConnection or WANPPPConnection
- mDNSu8 *UPnPSOAPURL; // router's SOAP control URL string
- mDNSu8 *UPnPRouterAddressString; // holds both the router's address and port
- mDNSu8 *UPnPSOAPAddressString; // holds both address and port for SOAP messages
+ char *UPnPSOAPURL; // router's SOAP control URL string
+ char *UPnPRouterAddressString; // holds both the router's address and port
+ char *UPnPSOAPAddressString; // holds both address and port for SOAP messages
// DNS Push Notification fields
DNSPushNotificationServer *DNSPushServers; // DNS Push Notification Servers
@@ -2476,7 +2489,6 @@ struct mDNS_struct
#if APPLE_OSX_mDNSResponder
ClientTunnel *TunnelClients;
- uuid_t asl_uuid; // uuid for ASL logging
void *WCF;
#endif
// DNS Proxy fields
@@ -2569,7 +2581,8 @@ extern const mDNSOpaque16 SubscribeFlags;
extern const mDNSOpaque16 UnSubscribeFlags;
extern const mDNSOpaque64 zeroOpaque64;
-
+extern const mDNSOpaque128 zeroOpaque128;
+
extern mDNSBool StrictUnicastOrdering;
extern mDNSu8 NumUnicastDNSServers;
#if APPLE_OSX_mDNSResponder
@@ -2762,17 +2775,6 @@ typedef enum { mDNS_Dereg_normal, mDNS_Dereg_rapid, mDNS_Dereg_conflict, mDNS_De
extern void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID,
mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, AuthRecType artype, mDNSRecordCallback Callback, void *Context);
-// mDNS_RegisterService() flags parameter bit definitions.
-// Note these are only defined to transfer the corresponding DNSServiceFlags settings into mDNSCore routines,
-// since code in mDNSCore does not include the DNSServiceFlags definitions in dns_sd.h.
-enum
-{
- coreFlagIncludeP2P = 0x1, // include P2P interfaces when using mDNSInterface_Any
- coreFlagIncludeAWDL = 0x2, // include AWDL interface when using mDNSInterface_Any
- coreFlagKnownUnique = 0x4, // client guarantees that SRV and TXT record names are unique
- coreFlagWakeOnly = 0x8 // Service won't be registered with sleep proxy
-};
-
extern mDNSu32 deriveD2DFlagsFromAuthRecType(AuthRecType authRecType);
extern mStatus mDNS_RegisterService (mDNS *const m, ServiceRecordSet *sr,
const domainlabel *const name, const domainname *const type, const domainname *const domain,
@@ -2900,6 +2902,10 @@ extern char *ConvertDomainNameToCString_withescape(const domainname *const na
extern void ConvertUTF8PstringToRFC1034HostLabel(const mDNSu8 UTF8Name[], domainlabel *const hostlabel);
+#define ValidTransportProtocol(X) ( (X)[0] == 4 && (X)[1] == '_' && \
+ ((((X)[2] | 0x20) == 'u' && ((X)[3] | 0x20) == 'd') || (((X)[2] | 0x20) == 't' && ((X)[3] | 0x20) == 'c')) && \
+ ((X)[4] | 0x20) == 'p')
+
extern mDNSu8 *ConstructServiceName(domainname *const fqdn, const domainlabel *name, const domainname *type, const domainname *const domain);
extern mDNSBool DeconstructServiceName(const domainname *const fqdn, domainlabel *const name, domainname *const type, domainname *const domain);
@@ -2955,6 +2961,7 @@ extern mDNSBool mDNSAddrIPv4FromMappedIPv6(mDNSv6Addr *in, mDNSv4Addr *out);
#define mDNSIPPortIsZero(A) ((A).NotAnInteger == 0)
#define mDNSOpaque16IsZero(A) ((A).NotAnInteger == 0)
#define mDNSOpaque64IsZero(A) (((A)->l[0] | (A)->l[1] ) == 0)
+#define mDNSOpaque128IsZero(A) (((A)->l[0] | (A)->l[1] | (A)->l[2] | (A)->l[3]) == 0)
#define mDNSIPv4AddressIsZero(A) ((A).NotAnInteger == 0)
#define mDNSIPv6AddressIsZero(A) (((A).l[0] | (A).l[1] | (A).l[2] | (A).l[3]) == 0)
#define mDNSEthAddressIsZero(A) (((A).w[0] | (A).w[1] | (A).w[2] ) == 0)
@@ -2989,12 +2996,6 @@ extern mDNSBool mDNSAddrIPv4FromMappedIPv6(mDNSv6Addr *in, mDNSv4Addr *out);
((X)->type == mDNSAddrType_IPv4) ? mDNSv4AddressIsLinkLocal(&(X)->ip.v4) : \
((X)->type == mDNSAddrType_IPv6) ? mDNSv6AddressIsLinkLocal(&(X)->ip.v6) : mDNSfalse)
-#define mDNSv4AddressIsLoopback(X) ((X)->b[0] == 127 && (X)->b[1] == 0 && (X)->b[2] == 0 && (X)->b[3] == 1)
-#define mDNSv6AddressIsLoopback(X) ((((X)->l[0] | (X)->l[1] | (X)->l[2]) == 0) && ((X)->b[12] == 0 && (X)->b[13] == 0 && (X)->b[14] == 0 && (X)->b[15] == 1))
-
-#define mDNSAddressIsLoopback(X) ( \
- ((X)->type == mDNSAddrType_IPv4) ? mDNSv4AddressIsLoopback(&(X)->ip.v4) : \
- ((X)->type == mDNSAddrType_IPv6) ? mDNSv6AddressIsLoopback(&(X)->ip.v6) : mDNSfalse)
// ***************************************************************************
#if 0
@@ -3038,8 +3039,8 @@ extern void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCa
extern void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn);
extern void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router);
extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, mDNSs32 serviceID, const mDNSAddr *addr,
- const mDNSIPPort port, mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSu16 resGroupID, mDNSBool reqA,
- mDNSBool reqAAAA, mDNSBool reqDO);
+ const mDNSIPPort port, mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSu16 resGroupID,
+ mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO);
extern void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSOpaque16 responseFlags);
extern void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID);
@@ -3157,17 +3158,6 @@ extern void mDNSPlatformWriteDebugMsg(const char *msg);
#endif
extern void mDNSPlatformWriteLogMsg(const char *ident, const char *msg, mDNSLogLevel_t loglevel);
-#if APPLE_OSX_mDNSResponder
-// Utility function for ASL logging
-mDNSexport void mDNSASLLog(uuid_t *uuid, const char *subdomain, const char *result, const char *signature, const char *fmt, ...);
-
-// Log unicast and multicast traffic statistics once a day. Also used for DNSSEC statistics.
-#define kDefaultNextStatsticsLogTime (24 * 60 * 60)
-
-extern void mDNSLogStatistics(mDNS *const m);
-
-#endif // APPLE_OSX_mDNSResponder
-
// Platform support modules should provide the following functions to map between opaque interface IDs
// and interface indexes in order to support the DNS-SD API. If your target platform does not support
// multiple interfaces and/or does not support the DNS-SD API, these functions can be empty.
@@ -3198,7 +3188,7 @@ typedef enum
} TCPSocketFlags;
typedef void (*TCPConnectionCallback)(TCPSocket *sock, void *context, mDNSBool ConnectionEstablished, mStatus err);
-extern TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass); // creates a TCP socket
+extern TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass); // creates a TCP socket
extern TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int sd);
extern int mDNSPlatformTCPGetFD(TCPSocket *sock);
extern mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname,
@@ -3206,17 +3196,18 @@ extern mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, m
extern void mDNSPlatformTCPCloseConnection(TCPSocket *sock);
extern long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed);
extern long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len);
-extern UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport);
+extern UDPSocket *mDNSPlatformUDPSocket(const mDNSIPPort requestedport);
extern mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock);
extern void mDNSPlatformUDPClose(UDPSocket *sock);
-extern void mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd);
-extern void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID);
+extern mDNSBool mDNSPlatformUDPSocketEncounteredEOF(const UDPSocket *sock);
+extern void mDNSPlatformReceiveBPF_fd(int fd);
+extern void mDNSPlatformUpdateProxyList(const mDNSInterfaceID InterfaceID);
extern void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID);
-extern void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID);
+extern void mDNSPlatformSetLocalAddressCacheEntry(const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID);
extern void mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst);
extern void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win);
-extern mStatus mDNSPlatformRetrieveTCPInfo(mDNS *const m, mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti);
-extern mStatus mDNSPlatformGetRemoteMacAddr(mDNS *const m, mDNSAddr *raddr);
+extern mStatus mDNSPlatformRetrieveTCPInfo(mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti);
+extern mStatus mDNSPlatformGetRemoteMacAddr(mDNSAddr *raddr);
extern mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname);
extern mStatus mDNSPlatformClearSPSData(void);
extern mStatus mDNSPlatformStoreOwnerOptRecord(char *ifname, DNSMessage *msg, int length);
@@ -3228,14 +3219,14 @@ extern void mDNSPlatformTLSTearDownCerts(void);
// Platforms that support unicast browsing and dynamic update registration for clients who do not specify a domain
// in browse/registration calls must implement these routines to get the "default" browse/registration list.
-extern mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains,
+extern mDNSBool mDNSPlatformSetDNSConfig(mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains,
DNameListElem **BrowseDomains, mDNSBool ackConfig);
-extern mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *router);
+extern mStatus mDNSPlatformGetPrimaryInterface(mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *router);
extern void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status);
-extern void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason);
-extern void mDNSPlatformPreventSleep(mDNS *const m, mDNSu32 timeout, const char *reason);
-extern void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration);
+extern void mDNSPlatformSetAllowSleep(mDNSBool allowSleep, const char *reason);
+extern void mDNSPlatformPreventSleep(mDNSu32 timeout, const char *reason);
+extern void mDNSPlatformSendWakeupPacket(mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration);
extern mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID);
extern mDNSBool mDNSPlatformInterfaceIsAWDL(const NetworkInterfaceInfo *intf);
@@ -3293,8 +3284,17 @@ extern void LNT_ClearState(mDNS *const m);
extern void mDNS_SetFQDN(mDNS *const m);
extern void mDNS_ActivateNetWake_internal (mDNS *const m, NetworkInterfaceInfo *set);
extern void mDNS_DeactivateNetWake_internal(mDNS *const m, NetworkInterfaceInfo *set);
-extern mStatus mDNS_RegisterInterface (mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping);
-extern void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping);
+
+// Attributes that controls the Bonjour operation initiation and response speed for an interface.
+typedef enum
+{
+ FastActivation, // For p2p* and DirectLink type interfaces
+ NormalActivation, // For standard interface timing
+ SlowActivation // For flapping interfaces
+} InterfaceActivationSpeed;
+
+extern mStatus mDNS_RegisterInterface (mDNS *const m, NetworkInterfaceInfo *set, InterfaceActivationSpeed probeDelay);
+extern void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, InterfaceActivationSpeed probeDelay);
extern void mDNSCoreInitComplete(mDNS *const m, mStatus result);
extern void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
const mDNSAddr *const srcaddr, const mDNSIPPort srcport,
@@ -3316,7 +3316,7 @@ extern void mDNSCoreReceiveRawPacket (mDNS *const m, const mDNSu8 *const p,
extern mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip);
extern CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, CacheGroup *cg, mDNSs32 delay, mDNSBool Add, const mDNSAddr *sourceAddress);
-extern CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name);
+extern CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 namehash, const domainname *const name);
extern void ReleaseCacheRecord(mDNS *const m, CacheRecord *r);
extern void ScheduleNextCacheCheckTime(mDNS *const m, const mDNSu32 slot, const mDNSs32 event);
extern void SetNextCacheCheckTimeForRecord(mDNS *const m, CacheRecord *const rr);
@@ -3340,8 +3340,8 @@ extern void UpdateRMAC(mDNS *const m, void *context);
// Used only in logging to restrict the number of /etc/hosts entries printed
extern void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result);
// exported for using the hash for /etc/hosts AuthRecords
-extern AuthGroup *AuthGroupForName(AuthHash *r, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name);
-extern AuthGroup *AuthGroupForRecord(AuthHash *r, const mDNSu32 slot, const ResourceRecord *const rr);
+extern AuthGroup *AuthGroupForName(AuthHash *r, const mDNSu32 namehash, const domainname *const name);
+extern AuthGroup *AuthGroupForRecord(AuthHash *r, const ResourceRecord *const rr);
extern AuthGroup *InsertAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr);
extern AuthGroup *RemoveAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr);
extern mDNSBool mDNS_CheckForCacheRecord(mDNS *const m, DNSQuestion *q, mDNSu16 qtype);
@@ -3350,35 +3350,36 @@ extern mDNSBool mDNS_CheckForCacheRecord(mDNS *const m, DNSQuestion *q, mDNSu16
// In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
#if APPLE_OSX_mDNSResponder
extern void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord);
-extern void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q);
-extern void StartServerTunnel(mDNS *const m, DomainAuthInfo *const info);
+extern void AddNewClientTunnel(DNSQuestion *const q);
+extern void StartServerTunnel(DomainAuthInfo *const info);
extern void UpdateAutoTunnelDomainStatuses(const mDNS *const m);
extern void RemoveAutoTunnel6Record(mDNS *const m);
-extern mDNSBool RecordReadyForSleep(mDNS *const m, AuthRecord *rr);
+extern mDNSBool RecordReadyForSleep(AuthRecord *rr);
// For now this LocalSleepProxy stuff is specific to Mac OS X.
// In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
-extern mStatus ActivateLocalProxy(mDNS *const m, NetworkInterfaceInfo *const intf, mDNSBool *keepaliveOnly);
-extern void mDNSPlatformUpdateDNSStatus(mDNS *const m, DNSQuestion *q);
-extern void mDNSPlatformTriggerDNSRetry(mDNS *const m, DNSQuestion *v4q, DNSQuestion *v6q);
+extern mStatus ActivateLocalProxy(NetworkInterfaceInfo *const intf, mDNSBool *keepaliveOnly);
+extern void mDNSPlatformUpdateDNSStatus(DNSQuestion *q);
+extern void mDNSPlatformTriggerDNSRetry(DNSQuestion *v4q, DNSQuestion *v6q);
extern void mDNSPlatformLogToFile(int log_level, const char *buffer);
extern mDNSBool SupportsInNICProxy(NetworkInterfaceInfo *const intf);
extern mStatus SymptomReporterDNSServerReachable(mDNS *const m, const mDNSAddr *addr);
extern mStatus SymptomReporterDNSServerUnreachable(DNSServer *s);
#endif
-typedef void ProxyCallback (mDNS *const m, void *socket, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr,
+typedef void ProxyCallback (void *socket, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr,
const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context);
-extern void mDNSPlatformInitDNSProxySkts(mDNS *const m, ProxyCallback *UDPCallback, ProxyCallback *TCPCallback);
+extern void mDNSPlatformInitDNSProxySkts(ProxyCallback *UDPCallback, ProxyCallback *TCPCallback);
extern void mDNSPlatformCloseDNSProxySkts(mDNS *const m);
extern void mDNSPlatformDisposeProxyContext(void *context);
extern mDNSu8 *DNSProxySetAttributes(DNSQuestion *q, DNSMessageHeader *h, DNSMessage *msg, mDNSu8 *start, mDNSu8 *limit);
#if APPLE_OSX_mDNSResponder
-extern void mDNSPlatformGetDNSRoutePolicy(mDNS *const m, DNSQuestion *q, mDNSBool *isBlocked);
+extern void mDNSPlatformGetDNSRoutePolicy(DNSQuestion *q, mDNSBool *isBlocked);
#endif
extern void mDNSPlatformSetSocktOpt(void *sock, mDNSTransport_Type transType, mDNSAddr_Type addrType, const DNSQuestion *q);
extern mDNSs32 mDNSPlatformGetPID(void);
extern mDNSBool mDNSValidKeepAliveRecord(AuthRecord *rr);
+extern mDNSBool CacheRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q);
// ***************************************************************************
#if 0
@@ -3600,17 +3601,17 @@ struct CompileTimeAssertionChecks_mDNS
char sizecheck_AuthRecord [(sizeof(AuthRecord) <= 1208) ? 1 : -1];
char sizecheck_CacheRecord [(sizeof(CacheRecord) <= 232) ? 1 : -1];
char sizecheck_CacheGroup [(sizeof(CacheGroup) <= 232) ? 1 : -1];
- char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 894) ? 1 : -1];
+ char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 912) ? 1 : -1];
- char sizecheck_ZoneData [(sizeof(ZoneData) <= 1730) ? 1 : -1];
+ char sizecheck_ZoneData [(sizeof(ZoneData) <= 1744) ? 1 : -1];
char sizecheck_NATTraversalInfo [(sizeof(NATTraversalInfo) <= 200) ? 1 : -1];
char sizecheck_HostnameInfo [(sizeof(HostnameInfo) <= 3050) ? 1 : -1];
char sizecheck_DNSServer [(sizeof(DNSServer) <= 330) ? 1 : -1];
- char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 7272) ? 1 : -1];
+ char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 7376) ? 1 : -1];
char sizecheck_ServiceRecordSet [(sizeof(ServiceRecordSet) <= 5540) ? 1 : -1];
char sizecheck_DomainAuthInfo [(sizeof(DomainAuthInfo) <= 7888) ? 1 : -1];
#if APPLE_OSX_mDNSResponder
- char sizecheck_ClientTunnel [(sizeof(ClientTunnel) <= 1230) ? 1 : -1];
+ char sizecheck_ClientTunnel [(sizeof(ClientTunnel) <= 1256) ? 1 : -1];
#endif
};
diff --git a/mDNSResponder/mDNSCore/nsec.c b/mDNSResponder/mDNSCore/nsec.c
index 09d27356..31cf1e95 100644
--- a/mDNSResponder/mDNSCore/nsec.c
+++ b/mDNSResponder/mDNSCore/nsec.c
@@ -56,12 +56,10 @@ mDNSlocal CacheRecord *NSECParentForQuestion(mDNS *const m, DNSQuestion *q)
{
CacheGroup *cg;
CacheRecord *cr;
- mDNSu32 slot;
mDNSu32 namehash;
- slot = HashSlot(&q->qname);
namehash = DomainNameHashValue(&q->qname);
- cg = CacheGroupForName(m, slot, namehash, &q->qname);
+ cg = CacheGroupForName(m, namehash, &q->qname);
if (!cg)
{
LogDNSSEC("NSECParentForQuestion: Cannot find cg for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
@@ -1050,12 +1048,11 @@ mDNSexport CacheRecord *NSECRecordIsDelegation(mDNS *const m, domainname *name,
{
CacheGroup *cg;
CacheRecord *cr;
- mDNSu32 slot, namehash;
+ mDNSu32 namehash;
- slot = HashSlot(name);
namehash = DomainNameHashValue(name);
- cg = CacheGroupForName(m, (const mDNSu32)slot, namehash, name);
+ cg = CacheGroupForName(m, namehash, name);
if (!cg)
{
LogDNSSEC("NSECRecordForName: cg NULL for %##s", name);
diff --git a/mDNSResponder/mDNSCore/nsec3.c b/mDNSResponder/mDNSCore/nsec3.c
index 4e9e8c82..43cd37a8 100644
--- a/mDNSResponder/mDNSCore/nsec3.c
+++ b/mDNSResponder/mDNSCore/nsec3.c
@@ -675,12 +675,11 @@ mDNSexport CacheRecord *NSEC3RecordIsDelegation(mDNS *const m, domainname *name,
CacheGroup *cg;
CacheRecord *cr;
CacheRecord *ncr;
- mDNSu32 slot, namehash;
+ mDNSu32 namehash;
- slot = HashSlot(name);
namehash = DomainNameHashValue(name);
- cg = CacheGroupForName(m, (const mDNSu32)slot, namehash, name);
+ cg = CacheGroupForName(m, namehash, name);
if (!cg)
{
LogDNSSEC("NSEC3RecordForName: cg NULL for %##s", name);
diff --git a/mDNSResponder/mDNSCore/uDNS.c b/mDNSResponder/mDNSCore/uDNS.c
index 3677b9f7..dc87724c 100755
--- a/mDNSResponder/mDNSCore/uDNS.c
+++ b/mDNSResponder/mDNSCore/uDNS.c
@@ -45,12 +45,12 @@ mDNSexport SearchListElem *SearchList = mDNSNULL;
mDNSBool StrictUnicastOrdering = mDNSfalse;
// We keep track of the number of unicast DNS servers and log a message when we exceed 64.
-// Currently the unicast queries maintain a 64 bit map to track the valid DNS servers for that
+// Currently the unicast queries maintain a 128 bit map to track the valid DNS servers for that
// question. Bit position is the index into the DNS server list. This is done so to try all
// the servers exactly once before giving up. If we could allocate memory in the core, then
-// arbitrary limitation of 64 DNSServers can be removed.
+// arbitrary limitation of 128 DNSServers can be removed.
mDNSu8 NumUnicastDNSServers = 0;
-#define MAX_UNICAST_DNS_SERVERS 64
+#define MAX_UNICAST_DNS_SERVERS 128
#if APPLE_OSX_mDNSResponder
mDNSu8 NumUnreachableDNSServers = 0;
#endif
@@ -112,8 +112,8 @@ mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mDNSu32 random)
#endif
mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSs32 serviceID, const mDNSAddr *addr,
- const mDNSIPPort port, mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSu16 resGroupID, mDNSBool reqA,
- mDNSBool reqAAAA, mDNSBool reqDO)
+ const mDNSIPPort port, mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSu16 resGroupID,
+ mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
{
DNSServer **p = &m->DNSServers;
DNSServer *tmp = mDNSNULL;
@@ -127,9 +127,9 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
if (!d)
d = (const domainname *)"";
- LogInfo("mDNS_AddDNSServer(%d): Adding %#a for %##s, InterfaceID %p, serviceID %u, scoped %d, resGroupID %d req_A is %s req_AAAA is %s cell %s req_DO is %s",
+ LogInfo("mDNS_AddDNSServer(%d): Adding %#a for %##s, InterfaceID %p, serviceID %u, scoped %d, resGroupID %d req_A is %s req_AAAA is %s cell %s isExpensive %s req_DO is %s",
NumUnicastDNSServers, addr, d->c, interface, serviceID, scoped, resGroupID, reqA ? "True" : "False", reqAAAA ? "True" : "False",
- cellIntf ? "True" : "False", reqDO ? "True" : "False");
+ cellIntf ? "True" : "False", isExpensive ? "True" : "False", reqDO ? "True" : "False");
mDNS_CheckLock(m);
@@ -186,17 +186,18 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
}
else
{
- (*p)->scoped = scoped;
- (*p)->interface = interface;
- (*p)->serviceID = serviceID;
- (*p)->addr = *addr;
- (*p)->port = port;
- (*p)->flags = DNSServer_FlagNew;
- (*p)->timeout = timeout;
- (*p)->cellIntf = cellIntf;
- (*p)->req_A = reqA;
- (*p)->req_AAAA = reqAAAA;
- (*p)->req_DO = reqDO;
+ (*p)->scoped = scoped;
+ (*p)->interface = interface;
+ (*p)->serviceID = serviceID;
+ (*p)->addr = *addr;
+ (*p)->port = port;
+ (*p)->flags = DNSServer_FlagNew;
+ (*p)->timeout = timeout;
+ (*p)->cellIntf = cellIntf;
+ (*p)->isExpensive = isExpensive;
+ (*p)->req_A = reqA;
+ (*p)->req_AAAA = reqAAAA;
+ (*p)->req_DO = reqDO;
// We start off assuming that the DNS server is not DNSSEC aware and
// when we receive the first response to a DNSSEC question, we set
// it to true.
@@ -485,7 +486,7 @@ mDNSlocal mStatus uDNS_RequestAddress(mDNS *m)
if (!m->NATTraversals)
{
- m->retryGetAddr = NonZeroTime(m->timenow + 0x78000000);
+ m->retryGetAddr = NonZeroTime(m->timenow + FutureTime);
LogInfo("uDNS_RequestAddress: Setting retryGetAddr to future");
}
else if (m->timenow - m->retryGetAddr >= 0)
@@ -1554,7 +1555,7 @@ mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, con
mDNSPlatformMemZero(info, sizeof(tcpInfo_t));
info->m = m;
- info->sock = mDNSPlatformTCPSocket(m, flags, &srcport, useBackgroundTrafficClass);
+ info->sock = mDNSPlatformTCPSocket(flags, &srcport, useBackgroundTrafficClass);
info->requestLen = 0;
info->question = question;
info->rr = rr;
@@ -1720,7 +1721,7 @@ mDNSexport const domainname *GetServiceTarget(mDNS *m, AuthRecord *const rr)
DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name);
if (AuthInfo && AuthInfo->AutoTunnel)
{
- StartServerTunnel(m, AuthInfo);
+ StartServerTunnel(AuthInfo);
if (AuthInfo->AutoTunnelHostRecord.namestorage.c[0] == 0) return(mDNSNULL);
debugf("GetServiceTarget: Returning %##s", AuthInfo->AutoTunnelHostRecord.namestorage.c);
return(&AuthInfo->AutoTunnelHostRecord.namestorage);
@@ -2759,7 +2760,6 @@ mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, co
m->NextSRVUpdate = NonZeroTime(m->timenow);
#if APPLE_OSX_mDNSResponder
- if (RouterChanged) uuid_generate(m->asl_uuid);
UpdateAutoTunnelDomainStatuses(m);
#endif
}
@@ -3034,7 +3034,6 @@ exit:
mDNSlocal mDNSBool IsRecordMergeable(mDNS *const m, AuthRecord *rr, mDNSs32 time)
{
DomainAuthInfo *info;
- (void) m; //unused
// A record is eligible for merge, if the following properties are met.
//
// 1. uDNS Resource Record
@@ -3697,9 +3696,7 @@ mDNSlocal void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID Interface
if (AddrReply->opcode == NATOp_AddrResponse)
{
#if APPLE_OSX_mDNSResponder
- static char msgbuf[16];
- mDNS_snprintf(msgbuf, sizeof(msgbuf), "%d", AddrReply->err);
- mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.natpmp.AddressRequest", AddrReply->err ? "failure" : "success", msgbuf, "");
+ LogInfo("uDNS_ReceiveNATPMPPacket: AddressRequest %s error %d", AddrReply->err ? "failure" : "success", AddrReply->err);
#endif
if (!AddrReply->err && len < sizeof(NATAddrReply)) { LogMsg("NAT-PMP AddrResponse message too short (%d bytes)", len); return; }
natTraversalHandleAddressReply(m, AddrReply->err, AddrReply->ExtAddr);
@@ -3708,9 +3705,8 @@ mDNSlocal void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID Interface
{
mDNSu8 Protocol = AddrReply->opcode & 0x7F;
#if APPLE_OSX_mDNSResponder
- static char msgbuf[16];
- mDNS_snprintf(msgbuf, sizeof(msgbuf), "%s - %d", AddrReply->opcode == NATOp_MapUDPResponse ? "UDP" : "TCP", PortMapReply->err);
- mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.natpmp.PortMapRequest", PortMapReply->err ? "failure" : "success", msgbuf, "");
+ LogInfo("uDNS_ReceiveNATPMPPacket: PortMapRequest %s %s - error %d",
+ PortMapReply->err ? "failure" : "success", (AddrReply->opcode == NATOp_MapUDPResponse) ? "UDP" : "TCP", PortMapReply->err);
#endif
if (!PortMapReply->err)
{
@@ -3921,7 +3917,9 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS
if (QR_OP == UpdateR)
{
- mDNSu32 lease = GetPktLease(m, msg, end);
+ mDNSu32 pktlease = 0;
+ mDNSBool gotlease = GetPktLease(m, msg, end, &pktlease);
+ mDNSu32 lease = gotlease ? pktlease : 60 * 60; // If lease option missing, assume one hour
mDNSs32 expire = m->timenow + (mDNSs32)lease * mDNSPlatformOneSecond;
mDNSu32 random = mDNSRandom((mDNSs32)lease * mDNSPlatformOneSecond/10);
@@ -4088,6 +4086,7 @@ mDNSexport void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneI
mDNS_Unlock(m);
}
+#ifdef DNS_PUSH_ENABLED
mDNSexport void DNSPushNotificationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo)
{
DNSQuestion *q = (DNSQuestion *)zoneInfo->ZoneDataContext;
@@ -4120,7 +4119,7 @@ mDNSexport void DNSPushNotificationGotZoneData(mDNS *const m, mStatus err, const
}
mDNS_Unlock(m);
}
-
+#endif // DNS_PUSH_ENABLED
// Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
mDNSlocal void PrivateQueryGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo)
@@ -4625,9 +4624,11 @@ mDNSlocal void handle_unanswered_query(mDNS *const m)
mDNSlocal void uDNS_HandleLLQState(mDNS *const m, DNSQuestion *q)
{
+#ifdef DNS_PUSH_ENABLED
// First attempt to use DNS Push Notification.
if (q->dnsPushState == DNSPUSH_INIT)
DiscoverDNSPushNotificationServer(m, q);
+#endif // DNS_PUSH_ENABLED
switch (q->state)
{
case LLQ_InitialRequest: startLLQHandshake(m, q); break;
@@ -4733,9 +4734,20 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
debugf("uDNS_CheckCurrentQuestion sending %p %##s (%s) %#a:%d UnansweredQueries %d",
q, q->qname.c, DNSTypeName(q->qtype),
q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort), q->unansweredQueries);
+#if APPLE_OSX_mDNSResponder
+ // When a DNS proxy network extension initiates the close of a UDP flow (this usually happens when a DNS
+ // proxy gets disabled or crashes), mDNSResponder's corresponding UDP socket will be marked with the
+ // SS_CANTRCVMORE state flag. Reading from such a socket is no longer possible, so close the current
+ // socket pair so that we can create a new pair.
+ if (q->LocalSocket && mDNSPlatformUDPSocketEncounteredEOF(q->LocalSocket))
+ {
+ mDNSPlatformUDPClose(q->LocalSocket);
+ q->LocalSocket = mDNSNULL;
+ }
+#endif
if (!q->LocalSocket)
{
- q->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort);
+ q->LocalSocket = mDNSPlatformUDPSocket(zeroIPPort);
if (q->LocalSocket)
{
mDNSPlatformSetSocktOpt(q->LocalSocket, mDNSTransport_UDP, mDNSAddrType_IPv4, q);
@@ -4777,8 +4789,18 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
}
newServer = GetServerForQuestion(m, q);
- DNSServerChangeForQuestion(m, q, newServer);
-
+ if (!newServer)
+ {
+ q->triedAllServersOnce = 1;
+ SetValidDNSServers(m, q);
+ newServer = GetServerForQuestion(m, q);
+ }
+ if (newServer)
+ {
+ LogInfo("uDNS_checkCurrentQuestion: Retrying question %p %##s (%s) DNS Server %#a:%u ThisQInterval %d",
+ q, q->qname.c, DNSTypeName(q->qtype), newServer ? &newServer->addr : mDNSNULL, mDNSVal16(newServer ? newServer->port : zeroIPPort), q->ThisQInterval);
+ DNSServerChangeForQuestion(m, q, newServer);
+ }
if (q->triedAllServersOnce)
{
q->LastQTime = m->timenow;
@@ -4789,7 +4811,6 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
q->LastQTime = m->timenow - q->ThisQInterval;
}
q->unansweredQueries = 0;
- q->noServerResponse = 1;
}
else
{
@@ -4839,20 +4860,20 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
// passed to uDNS_CheckCurrentQuestion -- we only want one set of query packets hitting the wire --
// but we want *all* of the questions to get answer callbacks.)
CacheRecord *rr;
- const mDNSu32 slot = HashSlot(&q->qname);
- CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+ const mDNSu32 slot = HashSlotFromNameHash(q->qnamehash);
+ CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
if (!q->qDNSServer)
{
- if (!mDNSOpaque64IsZero(&q->validDNSServers))
- LogMsg("uDNS_CheckCurrentQuestion: ERROR!!: valid DNSServer bits not zero 0x%x, 0x%x for question %##s (%s)",
- q->validDNSServers.l[1], q->validDNSServers.l[0], q->qname.c, DNSTypeName(q->qtype));
+ if (!mDNSOpaque128IsZero(&q->validDNSServers))
+ LogMsg("uDNS_CheckCurrentQuestion: ERROR!!: valid DNSServer bits not zero 0x%x, 0x%x 0x%x 0x%x for question %##s (%s)",
+ q->validDNSServers.l[3], q->validDNSServers.l[2], q->validDNSServers.l[1], q->validDNSServers.l[0], q->qname.c, DNSTypeName(q->qtype));
// If we reached the end of list while picking DNS servers, then we don't want to deactivate the
// question. Try after 60 seconds. We find this by looking for valid DNSServers for this question,
// if we find any, then we must have tried them before we came here. This avoids maintaining
// another state variable to see if we had valid DNS servers for this question.
SetValidDNSServers(m, q);
- if (mDNSOpaque64IsZero(&q->validDNSServers))
+ if (mDNSOpaque128IsZero(&q->validDNSServers))
{
LogInfo("uDNS_CheckCurrentQuestion: no DNS server for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
q->ThisQInterval = 0;
@@ -4916,7 +4937,7 @@ mDNSexport void CheckNATMappings(mDNS *m)
{
mDNSBool rfc1918 = mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4);
mDNSBool HaveRoutable = !rfc1918 && !mDNSIPv4AddressIsZero(m->AdvertisedV4.ip.v4);
- m->NextScheduledNATOp = m->timenow + 0x3FFFFFFF;
+ m->NextScheduledNATOp = m->timenow + FutureTime;
if (HaveRoutable) m->ExtAddress = m->AdvertisedV4.ip.v4;
@@ -4926,7 +4947,7 @@ mDNSexport void CheckNATMappings(mDNS *m)
{
// we need to log a message if we can't get our socket, but only the first time (after success)
static mDNSBool needLog = mDNStrue;
- m->NATMcastRecvskt = mDNSPlatformUDPSocket(m, NATPMPAnnouncementPort);
+ m->NATMcastRecvskt = mDNSPlatformUDPSocket(NATPMPAnnouncementPort);
if (!m->NATMcastRecvskt)
{
if (needLog)
@@ -5047,7 +5068,7 @@ mDNSexport void CheckNATMappings(mDNS *m)
mDNSlocal mDNSs32 CheckRecordUpdates(mDNS *m)
{
AuthRecord *rr;
- mDNSs32 nextevent = m->timenow + 0x3FFFFFFF;
+ mDNSs32 nextevent = m->timenow + FutureTime;
CheckGroupRecordUpdates(m);
@@ -5105,7 +5126,7 @@ mDNSexport void uDNS_Tasks(mDNS *const m)
mDNSs32 nexte;
DNSServer *d;
- m->NextuDNSEvent = m->timenow + 0x3FFFFFFF;
+ m->NextuDNSEvent = m->timenow + FutureTime;
nexte = CheckRecordUpdates(m);
if (m->NextuDNSEvent - nexte > 0)
@@ -5400,7 +5421,7 @@ mDNSexport void uDNS_SetupWABQueries(mDNS *const m)
// Make sure we have the search domains from the platform layer so that if we start the WAB
// queries below, we have the latest information.
mDNS_Lock(m);
- if (!mDNSPlatformSetDNSConfig(m, mDNSfalse, mDNStrue, mDNSNULL, mDNSNULL, mDNSNULL, mDNSfalse))
+ if (!mDNSPlatformSetDNSConfig(mDNSfalse, mDNStrue, mDNSNULL, mDNSNULL, mDNSNULL, mDNSfalse))
{
// If the configuration did not change, clear the flag so that we don't free the searchlist.
// We still have to start the domain enumeration queries as we may not have started them
@@ -5648,11 +5669,10 @@ mDNSexport void uDNS_StopWABQueries(mDNS *const m, int queryType)
uDNS_SetupWABQueries(m);
}
-mDNSexport domainname *uDNS_GetNextSearchDomain(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSs8 *searchIndex, mDNSBool ignoreDotLocal)
+mDNSexport domainname *uDNS_GetNextSearchDomain(mDNSInterfaceID InterfaceID, mDNSs8 *searchIndex, mDNSBool ignoreDotLocal)
{
SearchListElem *p = SearchList;
int count = *searchIndex;
- (void) m; // unused
if (count < 0) { LogMsg("uDNS_GetNextSearchDomain: count %d less than zero", count); return mDNSNULL; }
@@ -5775,10 +5795,15 @@ struct CompileTimeAssertionChecks_uDNS
#pragma mark - DNS Push Notification functions
#endif
+#ifdef DNS_PUSH_ENABLED
mDNSlocal tcpInfo_t * GetTCPConnectionToPushServer(mDNS *m, DNSQuestion *q)
{
+ DNSPushNotificationZone *zone;
+ DNSPushNotificationServer *server;
+ DNSPushNotificationZone *newZone;
+ DNSPushNotificationServer *newServer;
+
// If we already have a question for this zone and if the server is the same, reuse it
- DNSPushNotificationZone *zone = mDNSNULL;
for (zone = m->DNSPushZones; zone != mDNSNULL; zone = zone->next)
{
if (SameDomainName(&q->nta->ChildName, &zone->zoneName))
@@ -5797,12 +5822,11 @@ mDNSlocal tcpInfo_t * GetTCPConnectionToPushServer(mDNS *m, DNSQuestion *q)
}
// If we have a connection to this server but it is for a differnt zone, create a new zone entry and reuse the connection
- DNSPushNotificationServer *server = mDNSNULL;
for (server = m->DNSPushServers; server != mDNSNULL; server = server->next)
{
if (mDNSSameAddress(&q->dnsPushServerAddr, &server->serverAddr))
{
- DNSPushNotificationZone *newZone = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationZone));
+ newZone = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationZone));
newZone->numberOfQuestions = 1;
newZone->zoneName = q->nta->ChildName;
newZone->servers = server;
@@ -5817,8 +5841,8 @@ mDNSlocal tcpInfo_t * GetTCPConnectionToPushServer(mDNS *m, DNSQuestion *q)
}
// If we do not have any existing connections, create a new connection
- DNSPushNotificationServer *newServer = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationServer));
- DNSPushNotificationZone *newZone = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationZone));
+ newServer = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationServer));
+ newZone = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationZone));
newServer->numberOfQuestions = 1;
newServer->serverAddr = q->dnsPushServerAddr;
@@ -5930,6 +5954,9 @@ mDNSlocal void reconcileDNSPushConnection(mDNS *m, DNSQuestion *q)
{
DNSPushNotificationZone *zone;
DNSPushNotificationServer *server;
+ DNSPushNotificationServer *nextServer;
+ DNSPushNotificationZone *nextZone;
+
// Update the counts
for (zone = m->DNSPushZones; zone != mDNSNULL; zone = zone->next)
{
@@ -5946,7 +5973,7 @@ mDNSlocal void reconcileDNSPushConnection(mDNS *m, DNSQuestion *q)
// Now prune the lists
server = m->DNSPushServers;
- DNSPushNotificationServer *nextServer = mDNSNULL;
+ nextServer = mDNSNULL;
while(server != mDNSNULL)
{
nextServer = server->next;
@@ -5962,7 +5989,7 @@ mDNSlocal void reconcileDNSPushConnection(mDNS *m, DNSQuestion *q)
}
zone = m->DNSPushZones;
- DNSPushNotificationZone *nextZone = mDNSNULL;
+ nextZone = mDNSNULL;
while(zone != mDNSNULL)
{
nextZone = zone->next;
@@ -5994,6 +6021,7 @@ mDNSexport void UnSubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
reconcileDNSPushConnection(m, q);
}
+#endif // DNS_PUSH_ENABLED
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
#endif
@@ -6119,9 +6147,8 @@ mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info, const
return mStatus_UnsupportedErr;
}
-mDNSexport domainname *uDNS_GetNextSearchDomain(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSs8 *searchIndex, mDNSBool ignoreDotLocal)
+mDNSexport domainname *uDNS_GetNextSearchDomain(mDNSInterfaceID InterfaceID, mDNSs8 *searchIndex, mDNSBool ignoreDotLocal)
{
- (void) m;
(void) InterfaceID;
(void) searchIndex;
(void) ignoreDotLocal;
@@ -6154,8 +6181,8 @@ mDNSexport mStatus mDNS_StopNATOperation(mDNS *const m, NATTraversalInfo *traver
}
mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSs32 serviceID, const mDNSAddr *addr,
- const mDNSIPPort port, mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSu16 resGroupID, mDNSBool reqA,
- mDNSBool reqAAAA, mDNSBool reqDO)
+ const mDNSIPPort port, mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSu16 resGroupID,
+ mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
{
(void) m;
(void) d;
@@ -6166,6 +6193,7 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
(void) scoped;
(void) timeout;
(void) cellIntf;
+ (void) isExpensive;
(void) resGroupID;
(void) reqA;
(void) reqAAAA;
diff --git a/mDNSResponder/mDNSCore/uDNS.h b/mDNSResponder/mDNSCore/uDNS.h
index 910449f1..27b7acee 100755
--- a/mDNSResponder/mDNSCore/uDNS.h
+++ b/mDNSResponder/mDNSCore/uDNS.h
@@ -128,7 +128,7 @@ extern mStatus uDNS_SetupDNSConfig(mDNS *const m);
extern void uDNS_SetupWABQueries(mDNS *const m);
extern void uDNS_StartWABQueries(mDNS *const m, int queryType);
extern void uDNS_StopWABQueries(mDNS *const m, int queryType);
-extern domainname *uDNS_GetNextSearchDomain(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSs8 *searchIndex, mDNSBool ignoreDotLocal);
+extern domainname *uDNS_GetNextSearchDomain(mDNSInterfaceID InterfaceID, mDNSs8 *searchIndex, mDNSBool ignoreDotLocal);
typedef enum
{
diff --git a/mDNSResponder/mDNSMacOSX/BLE.c b/mDNSResponder/mDNSMacOSX/BLE.c
index 85fb810c..4a35ff0b 100644
--- a/mDNSResponder/mDNSMacOSX/BLE.c
+++ b/mDNSResponder/mDNSMacOSX/BLE.c
@@ -15,23 +15,134 @@
* limitations under the License.
*/
+#if ENABLE_BLE_TRIGGERED_BONJOUR
+
#include "mDNSEmbeddedAPI.h"
#include "DNSCommon.h"
#include "mDNSMacOSX.h"
#include "BLE.h"
-#include <pthread.h>
+#include "D2D.h"
+
+#include <dlfcn.h>
#pragma mark - Browse and Registration Request Handling
-// Disable use of BLE discovery APIs by default.
+// When set, enables BLE triggered discovery APIs.
mDNSBool EnableBLEBasedDiscovery = mDNSfalse;
+// When set, the default mode is to promote all client requests made with
+// kDNSServiceInterfaceIndexAny to BLE Triggered Discovery.
+// Requests to promote will be filtered by either a service type whitelist or
+// blacklist as noted below.
+mDNSBool DefaultToBLETriggered = mDNSfalse;
+
+#define USE_WHITELIST 1
+
+#if USE_WHITELIST
+
+// Current list of service types that will have BLE triggers applied by default
+// when DefaultToBLETriggered is set to true.
+
+const char * defaultServiceWhitelist[] = {
+ "\x04_ssh",
+ "\x04_smb",
+ "\x04_rfb",
+ "\x04_ipp",
+ "\x05_ipps",
+ "\x08_printer",
+ 0
+};
+
+// Return true if DefaultToBLETriggered is set and the operation should be
+// promoted to use BLE triggered discovery by default.
+bool shouldUseBLE(mDNSInterfaceID interfaceID, DNS_TypeValues rrtype, domainname *serviceType, domainname *domain)
+{
+ const mDNSu8 ** ptr;
+
+ if (!DefaultToBLETriggered || (interfaceID != mDNSInterface_Any) || !IsLocalDomain(domain))
+ return mDNSfalse;
+
+ // Address records don't have a service type to match on, but we'll trigger them
+ // here to support the case were the DNSServiceQueryRecord() was done using mDNSInterface_Any instead
+ // of the interface that the corresponding SRV record was returned over.
+ if ((rrtype == kDNSType_A) || (rrtype == kDNSType_AAAA))
+ return mDNStrue;
+
+ ptr = (const mDNSu8 **) defaultServiceWhitelist;
+ while (*ptr)
+ {
+ if (SameDomainLabel(*ptr, serviceType->c))
+ return mDNStrue;
+ ptr++;
+ }
+
+ return mDNSfalse;
+}
+
+#else // USE_WHITELIST
+
+// Current list of service types that will NOT have BLE triggers applied by default
+// when DefaultToBLETriggered is set to true.
+
+// _airplay and _airdrop discovery already employ BLE based triggering using Apple service specific
+// BLE beacons. The rest of the entries here are default browses run in a standard OSX install
+// that we don't want to have cluttering up the Bloom filter when using the service blacklist approach.
+
+const char * defaultServiceBlacklist[] = {
+ "\x08_airplay",
+ "\x08_airdrop",
+ "\x05_raop",
+ "\x08_airport",
+ "\x0d_apple-mobdev",
+ "\x06_uscan",
+ "\x07_uscans",
+ "\x08_scanner",
+ "\x0e_apple-mobdev2",
+ "\x04_ipp",
+ "\x05_ipps",
+ "\x07_ippusb",
+ "\x08_printer",
+ "\x0f_pdl-datastream",
+ "\x04_ptp",
+ 0
+};
+
+// Return true if DefaultToBLETriggered is set and the operation should be
+// promoted to use BLE triggered discovery by default.
+bool shouldUseBLE(mDNSInterfaceID interfaceID, DNS_TypeValues rrtype, domainname *serviceType, domainname *domain)
+{
+ (void) rrtype;
+ const mDNSu8 ** ptr;
+
+ if (!DefaultToBLETriggered || (interfaceID != mDNSInterface_Any) || !IsLocalDomain(domain))
+ return mDNSfalse;
+
+ ptr = (const mDNSu8 **) defaultServiceBlacklist;
+ while (*ptr)
+ {
+ if (SameDomainLabel(*ptr, serviceType->c))
+ return mDNSfalse;
+ ptr++;
+ }
+
+ return mDNStrue;
+}
+
+#endif // USE_WHITELIST
+
+// Structure for linked list of BLE responses received that match
+// a given client request.
typedef struct matchingResponses
{
struct matchingResponses * next;
void * response;
} matchingResponses_t;
+// Max size of input key generated by DNSNameCompressionBuildLHS() is MAX_DOMAIN_NAME + 3
+// where the three additional bytes are:
+// two bytes for DNS_TypeValues and one byte for "compression_packet_v1", the D2D compression version number.
+#define MAX_KEY_SIZE MAX_DOMAIN_NAME + 3
+
// Initially used for both the browse and registration lists.
typedef struct requestList
{
@@ -41,22 +152,17 @@ typedef struct requestList
mDNSu16 type;
DNSServiceFlags flags;
mDNSInterfaceID InterfaceID;
-
-// TODO: Possibly restructure the following browse and registration specific
-// members as a union to save a bit of space.
+ serviceHash_t browseHash;
+ serviceHash_t registeredHash;
+ matchingResponses_t * ourResponses;
+ bool triggeredOnAWDL;
// The following fields are only used for browse requests currently
- serviceHash_t browseHash;
- DNSQuestion * question;
- mDNSu8 key[MAX_DOMAIN_LABEL];
+ mDNSu8 key[MAX_KEY_SIZE];
size_t keySize;
- matchingResponses_t * ourResponses;
// The following fields are only used for registration requests currently
- serviceHash_t registeredHash;
- ServiceRecordSet * serviceRecordSet; // service record set in the original request
- AuthRecType savedARType;
- bool triggeredOnAWDL;
+ const ResourceRecord * resourceRecord;
} requestList_t;
// Lists for all DNSServiceBrowse() and DNSServiceRegister() requests using
@@ -64,10 +170,27 @@ typedef struct requestList
static requestList_t* BLEBrowseListHead = NULL;
static requestList_t* BLERegistrationListHead = NULL;
-#define isAutoTriggerRequest(ptr) ((ptr->InterfaceID == kDNSServiceInterfaceIndexAny) && (ptr->flags & kDNSServiceFlagsAutoTrigger))
+// The kDNSServiceFlagsAutoTrigger should only be set for a request that would normally apply to AWDL.
+#define isAutoTriggerRequest(INTERFACE_INDEX, FLAGS) ( (FLAGS & kDNSServiceFlagsAutoTrigger) \
+ && ( (AWDLInterfaceID && (INTERFACE_INDEX == AWDLInterfaceID)) \
+ || ((INTERFACE_INDEX == kDNSServiceInterfaceIndexAny) && (FLAGS & kDNSServiceFlagsIncludeAWDL))))
#pragma mark - Manage list of responses that match this request.
+// Return true if any response matches one of our current registrations.
+mDNSlocal bool responseMatchesRegistrations(void)
+{
+ requestList_t *ptr;
+
+ for (ptr = BLERegistrationListHead; ptr; ptr = ptr->next)
+ {
+ if (ptr->ourResponses)
+ return true;
+ }
+ return false;
+}
+
+// Return true if the response is already in the list of responses for this client request.
mDNSlocal bool inResponseListForRequest(requestList_t *request, void * response)
{
matchingResponses_t * rp;
@@ -130,10 +253,13 @@ mDNSlocal void freeResponseListEntriesForRequest(requestList_t *request)
ptr = ptr->next;
free(tmp);
}
+ request->ourResponses = 0;
}
#pragma mark - Manage request lists
+// Return the address of the pointer to the entry, which can either be the address of "listHead"
+// or the address of the prior entry on the lists "next" pointer.
mDNSlocal requestList_t ** findInRequestList(requestList_t ** listHead, const domainname *const name, mDNSu16 type)
{
requestList_t **ptr = listHead;
@@ -185,332 +311,383 @@ mDNSlocal void removeFromRequestList(requestList_t ** listHead, const domainname
#pragma mark - Hashing and beacon state
-// Simple string hash based on the Bernstein hash.
-
-#define PRIME 31 // small prime number
-#define MODULO (sizeof(serviceHash_t) * 8)
-#define CONVERT_TO_LOWER_CASE(x) (((x) <= 'Z' && (x) >= 'A') ? ((x) | 0x20) : (x))
-
-mDNSlocal serviceHash_t BLELabelHash(const unsigned char *str, unsigned int length)
+// These SipHash routines were copied from CoreUtils-500.9.
+// We use these when running an mDNSRespnder root on a system that does not
+// have the SipHash() routine available and exported in CoreUtils.
+// TODO: This local copy should be removed once we are no longer running mDNSResponder roots
+// on systems that do no include CoreUtils-500.9 or newer.
+
+// Start of code copied from: CoreUtils-500.9
+
+/*! @group BitRotates
+ @abstract Rotates X COUNT bits to the left or right.
+*/
+#define ROTL( X, N, SIZE ) ( ( (X) << (N) ) | ( (X) >> ( (SIZE) - N ) ) )
+#define ROTR( X, N, SIZE ) ( ( (X) >> (N) ) | ( (X) << ( (SIZE) - N ) ) )
+
+#define ROTL64( X, N ) ROTL( (X), (N), 64 )
+#define ROTR64( X, N ) ROTR( (X), (N), 64 )
+
+ #define ReadLittle64( PTR ) \
+ ( (uint64_t)( \
+ ( (uint64_t)( (uint8_t *)(PTR) )[ 0 ] ) | \
+ ( ( (uint64_t)( (uint8_t *)(PTR) )[ 1 ] ) << 8 ) | \
+ ( ( (uint64_t)( (uint8_t *)(PTR) )[ 2 ] ) << 16 ) | \
+ ( ( (uint64_t)( (uint8_t *)(PTR) )[ 3 ] ) << 24 ) | \
+ ( ( (uint64_t)( (uint8_t *)(PTR) )[ 4 ] ) << 32 ) | \
+ ( ( (uint64_t)( (uint8_t *)(PTR) )[ 5 ] ) << 40 ) | \
+ ( ( (uint64_t)( (uint8_t *)(PTR) )[ 6 ] ) << 48 ) | \
+ ( ( (uint64_t)( (uint8_t *)(PTR) )[ 7 ] ) << 56 ) ) )
+
+// Based on <https://131002.net/siphash/>.
+
+#define SipRound() \
+ do \
+ { \
+ v0 += v1; v1 = ROTL64( v1, 13 ); v1 ^= v0; v0 = ROTL64( v0, 32 ); \
+ v2 += v3; v3 = ROTL64( v3, 16 ); v3 ^= v2; \
+ v0 += v3; v3 = ROTL64( v3, 21 ); v3 ^= v0; \
+ v2 += v1; v1 = ROTL64( v1, 17 ); v1 ^= v2; v2 = ROTL64( v2, 32 ); \
+ \
+ } while( 0 )
+
+mDNSlocal uint64_t local_SipHash( const uint8_t inKey[ 16 ], const void *inSrc, size_t inLen )
{
- serviceHash_t hash = 0;
-
- for (unsigned int i = 0; i < length; i++) {
- hash = PRIME * hash + CONVERT_TO_LOWER_CASE(*str);
- str++;
- }
-
- hash %= MODULO;
- LogInfo("BLELabelHash: %d characters hashed to %d", length, hash);
-
- return ((serviceHash_t)1 << hash);
+ const uint8_t * src = (const uint8_t *) inSrc;
+ size_t const left = inLen % 8;
+ const uint8_t * const end = src + ( inLen - left );
+ uint64_t k0, k1, v0, v1, v2, v3, tmp;
+
+ k0 = ReadLittle64( &inKey[ 0 ] );
+ k1 = ReadLittle64( &inKey[ 8 ] );
+ v0 = k0 ^ UINT64_C( 0x736f6d6570736575 ); // 'somepseu'
+ v1 = k1 ^ UINT64_C( 0x646f72616e646f6d ); // 'dorandom'
+ v2 = k0 ^ UINT64_C( 0x6c7967656e657261 ); // 'lygenera'
+ v3 = k1 ^ UINT64_C( 0x7465646279746573 ); // 'tedbytes'
+
+ for( ; src != end; src += 8 )
+ {
+ tmp = ReadLittle64( src );
+ v3 ^= tmp;
+ SipRound();
+ SipRound();
+ v0 ^= tmp;
+ }
+
+ tmp = ( (uint64_t)( inLen & 0xFF ) ) << 56;
+ switch( left )
+ {
+ case 7: tmp |= ( ( (uint64_t) src[ 6 ] ) << 48 );
+ case 6: tmp |= ( ( (uint64_t) src[ 5 ] ) << 40 );
+ case 5: tmp |= ( ( (uint64_t) src[ 4 ] ) << 32 );
+ case 4: tmp |= ( ( (uint64_t) src[ 3 ] ) << 24 );
+ case 3: tmp |= ( ( (uint64_t) src[ 2 ] ) << 16 );
+ case 2: tmp |= ( ( (uint64_t) src[ 1 ] ) << 8 );
+ case 1: tmp |= ( (uint64_t) src[ 0 ] );
+ default: break;
+ }
+ v3 ^= tmp;
+ SipRound();
+ SipRound();
+ v0 ^= tmp;
+ v2 ^= 0xFF;
+ SipRound();
+ SipRound();
+ SipRound();
+ SipRound();
+ return( v0 ^ v1 ^ v2 ^ v3 );
}
-// Hash just the service type not including the protocol or first "_" character initially.
-mDNSlocal serviceHash_t BLEServiceHash(const domainname *const domain)
-{
- const unsigned char *p = domain->c;
- unsigned int length = (unsigned int) *p;
-
- p++;
- if (*p != '_')
- {
- LogInfo("BLEServiceHash: browse type does not begin with a _");
- return 0;
- }
- p++; // skip the '-"
- length--;
+// See <https://spc.apple.com/AppleBLEInfo.html#_wifi_tds> for details.
- if (length > MAX_DOMAIN_LABEL || length == 0)
- {
- LogInfo("BLEServiceHash: invalid browse type length: %d characters", length);
- return 0;
- }
+#define kTDSSipHashKey ( (const uint8_t *) "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" )
+#define kTDSSipHashCount 5
- return BLELabelHash(p, length);
-}
+#define kSizeCString ( (size_t) -1 )
-// Storage for the current Bonjour BLE beacon data;
-typedef struct BLEBeacon
-{
- serviceHash_t browseHash;
- serviceHash_t registeredHash;
-} BLEBeacon_t;
+// End of code copied from: CoreUtils-500.9
-BLEBeacon_t BLEBeacon;
+// Must link symbol from CoreUtils at runtime to avoid cyclic dependency cycles in the build process.
+static uint64_t (*SipHash_p)( const uint8_t inKey[ 16 ], const void *inSrc, size_t inLen ) = NULL;
-mDNSlocal void addServiceToBeacon(serviceHash_t browseHash, serviceHash_t registeredHash)
+mDNSlocal uint64_t local_TDSBloomFilterMake( uint32_t inBloomCount, const void *inStr, size_t inLen )
{
- bool beaconUpdated = false;
+ uint64_t bloomFilter = 0, hash;
+ uint8_t i;
- if (BLEBeacon.browseHash & browseHash)
- {
- LogInfo("addServiceToBeacon: Bit 0x%x already set in browsing services hash", browseHash);
- }
+ if( inLen == kSizeCString ) inLen = strlen( (const char *) inStr );
+ if (SipHash_p)
+ hash = SipHash_p( kTDSSipHashKey, inStr, inLen );
else
- {
- BLEBeacon.browseHash |= browseHash;
- beaconUpdated = true;
- }
+ hash = local_SipHash( kTDSSipHashKey, inStr, inLen );
- if (BLEBeacon.registeredHash & registeredHash)
- {
- LogInfo("addServiceToBeacon: Bit 0x%x already set in advertising services hash", registeredHash);
- }
- else
+ for( i = 0; i < kTDSSipHashCount; ++i )
{
- BLEBeacon.registeredHash |= registeredHash;
- beaconUpdated = true;
+ bloomFilter |= ( UINT64_C( 1 ) << ( hash % inBloomCount ) );
+ hash /= inBloomCount;
}
-
- if (beaconUpdated)
- updateBLEBeaconAndScan(BLEBeacon.browseHash, BLEBeacon.registeredHash);
+ return( bloomFilter );
}
-// Go through all the existing browses and registrations to get the
-// current hash values for the corresponding BLE beacon.
-// We must do this when any hash bits are removed do accurately generate
-// the correct combination of all currently set hash bits.
-mDNSlocal void updateBeacon()
+mDNSlocal void loadCoreUtils()
{
- requestList_t *ptr;
+ static mDNSBool runOnce = mDNSfalse;
+ static void *CoreUtils_p = mDNSNULL;
+ static const char path[] = "/System/Library/PrivateFrameworks/CoreUtils.framework/CoreUtils";
- BLEBeacon.browseHash = 0;
- BLEBeacon.registeredHash = 0;
-
- for (ptr = BLEBrowseListHead; ptr; ptr = ptr->next)
+ if (!runOnce)
{
- BLEBeacon.browseHash |= ptr->browseHash;
- }
+ runOnce = mDNStrue;
+ if (!CoreUtils_p)
+ {
+ CoreUtils_p = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
+ if (!CoreUtils_p)
+ {
+ LogInfo("loadCoreUtils: dlopen() failed.");
+ return;
+ }
+ }
- for (ptr = BLERegistrationListHead; ptr; ptr = ptr->next)
- {
- BLEBeacon.registeredHash |= ptr->registeredHash;
+ if (!SipHash_p)
+ {
+ SipHash_p = dlsym(CoreUtils_p, "SipHash");
+ if (!SipHash_p)
+ {
+ LogInfo("loadCoreUtils: load of SipHash symbol failed.");
+ return;
+ }
+ }
+ LogInfo("loadCoreUtils: found SipHash symbol.");
}
+}
+
+#define HASH_SIZE 64
+
+mDNSlocal serviceHash_t BLELabelHash(unsigned char *str, unsigned int length)
+{
+ loadCoreUtils();
- updateBLEBeaconAndScan(BLEBeacon.browseHash, BLEBeacon.registeredHash);
+ return local_TDSBloomFilterMake(HASH_SIZE, (const void *) str, (size_t) length);
}
-#pragma mark - Request start/stop
-// Forward declarations for mDNSLocal functions that are called before they are defined.
-mDNSlocal void checkForMatchingResponses(requestList_t *bp);
-mDNSlocal void clearResponseLists();
+// Maximum number of characters in string to hash should be:
+// 2 for initial "s:" or "p:"
+// 16 for "_" followed by up to 15 characters of service type
+// 1 for separating "."
+// 4 for "_udp" or "_tcp"
+// 1 for the terminating NULL byte
+#define MAX_HASH_STRING (2 + 16 + 1 + 4 + 1)
+
+// Maximum service name length, including the initial "_"
+#define MAX_SERVICE_NAME 16
-void start_BLE_browse(DNSQuestion * q, const domainname *const domain, DNS_TypeValues type, DNSServiceFlags flags, mDNSu8 *key, size_t keySize)
+// Convert the service name and transport protocol to a NULL terminated C string.
+// stringBuf must point to least (MAX_HASH_STRING - 2) bytes of available space.
+mDNSlocal bool serviceNameStringFromDomain(const domainname *const domain, mDNSu8 * stringBuf)
{
- requestList_t * ptr;
+ mDNSu8 * dst = stringBuf;
+ const mDNSu8 * src = domain->c;
+ mDNSu8 len = *src++;
- if (!EnableBLEBasedDiscovery)
+ if (len == 0 || len > MAX_SERVICE_NAME)
{
- LogMsg("start_BLE_browse: EnableBLEBasedDiscovery disabled");
- return;
+ LogInfo("serviceNameStringFromDomain: Invalid name lenght: %d", len);
+ return false;
}
-
- LogInfo("start_BLE_browse: Starting BLE browse for: %##s %s", domain->c, DNSTypeName(type));
-
- ptr = addToRequestList(&BLEBrowseListHead, domain, type, flags);
-
- // If equivalent BLE browse is already running, just return.
- if (ptr->refCount > 1)
+ if (*src != '_')
{
- LogInfo("start_BLE_browse: Dup of existing BLE browse.");
- return;
+ LogInfo("serviceNameStringFromDomain: service name does not begin with a _");
+ return false;
}
+ // Copy the service type
+ while (len--)
+ *dst++ = *src++;
- ptr->browseHash = BLEServiceHash(domain);
- ptr->question = q;
+ *dst++ = '.';
- if (ptr->browseHash == 0)
+ if (!ValidTransportProtocol(src))
{
- LogInfo("BLEServiceHash failed!");
- removeFromRequestList(&BLEBrowseListHead, domain, type);
- return;
+ LogInfo("serviceNameStringFromDomain: Transport protocol name must be _udp or _tcp");
+ return false;
}
+ // copy the transport protocol
+ len = *src++;
+ while (len--)
+ *dst++ = *src++;
- // Save these for use in D2D plugin callback logic.
- memcpy(ptr->key, key, keySize);
- ptr->keySize = keySize;
- // Extract the interface ID for easier access in the requestList_t structure
- ptr->InterfaceID = q->InterfaceID;
-
- addServiceToBeacon(ptr->browseHash, 0);
-
- checkForMatchingResponses(ptr);
+ *dst = 0;
+ return true;
}
-// Stop the browse.
-// Return true if this is the last reference to the browse, false otherwise.
-bool stop_BLE_browse(const domainname *const domain, DNS_TypeValues type, DNSServiceFlags flags)
+mDNSlocal bool setBLEServiceHash(const domainname *const domain, requestList_t * ptr)
{
- (void) flags; // not used initially
- requestList_t * ptr;
- bool lastReference = false;
+ // Initialize the string with the "s:" for the browser/seeker hash calculation.
+ mDNSu8 stringBuf[MAX_HASH_STRING] = { 's', ':', '\0' };
- if (!EnableBLEBasedDiscovery)
+ // Append the service name and protocol strings to the initial "s:" string.
+ if (!serviceNameStringFromDomain(domain, &stringBuf[2]))
{
- LogMsg("stop_BLE_browse: EnableBLEBasedDiscovery disabled");
- return lastReference;
+ LogInfo("setBLEServiceHash: serviceNameStringFromDomain() failed!");
+ return false;
}
- LogInfo("stop_BLE_browse: Stopping BLE browse for: %##s %s", domain->c, DNSTypeName(type));
-
- ptr = *(findInRequestList(&BLEBrowseListHead, domain, type));
- if (ptr == 0)
- {
- LogInfo("stop_BLE_browse: No matching browse found.");
- return lastReference;
- }
-
- // If this is the last reference for this browse, update advertising and browsing bits set in
- // the beacon after removing this browse from the list.
- if (ptr->refCount == 1)
- lastReference = true;
+ ptr->browseHash = BLELabelHash(stringBuf, strlen((const char *)stringBuf));
+ LogInfo("setBLEServiceHash: seeker string %s, hashed to 0x%lx", stringBuf, ptr->browseHash);
- removeFromRequestList(&BLEBrowseListHead, domain, type);
+ // Update string to start with "p:" for registration/provider hash calculation.
+ stringBuf[0] = 'p';
- if (lastReference)
- updateBeacon();
+ ptr->registeredHash = BLELabelHash(stringBuf, strlen((const char *)stringBuf));
+ LogInfo("setBLEServiceHash: provider string %s, hashed to 0x%lx", stringBuf, ptr->registeredHash);
+ if (ptr->browseHash && ptr->registeredHash)
+ return true;
+ else
+ return false;
+}
- // If there are no active browse or registration requests, BLE scanning will be disabled.
- // Clear the list of responses received to remove any stale response state.
- if (BLEBrowseListHead == NULL && BLERegistrationListHead == 0)
- clearResponseLists();
+// Indicates we are sending the final beacon with zeroed Bloom filter to let
+// peers know we are no longer actively seeking or providing any services.
+bool finalBeacon = false;
- return lastReference;
-}
+// The last time we walked our response list looking for stale entries.
+mDNSs32 lastScanForStaleResponses;
-extern void internal_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags, DNSQuestion * q);
-extern void internal_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags);
+// Forward declaration.
+mDNSlocal void removeStaleResponses(mDNSs32 currentTime);
-extern void internal_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags);
-extern void internal_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags);
+// Interval at which we scan the response lists to remove any stale entries.
+#define StaleResponseScanInterval 30
-void start_BLE_advertise(ServiceRecordSet * serviceRecordSet, const domainname *const domain, DNS_TypeValues type, DNSServiceFlags flags)
+// Called from mDNS_Execute() when NextBLEServiceTime is reached.
+void serviceBLE(void)
{
- requestList_t * ptr;
- const domainname * instanceRemoved;
+ // Note, we can access mDNSStorage.timenow since we are called from mDNS_Execute,
+ // which initializes that value by calling mDNS_Lock().
+ mDNSs32 currentTime = mDNSStorage.timenow;
- if (!EnableBLEBasedDiscovery)
- {
- LogMsg("start_BLE_advertise: EnableBLEBasedDiscovery disabled");
- return;
- }
-
- // Just process the SRV record for each service registration. The PTR
- // record already has the service type at the beginning of the domain, but
- // we want to filter out reverse address PTR records at this point in time, so using
- // the SRV record instead.
- if (type != kDNSServiceType_SRV)
- return;
+ // Initialize if zero.
+ if (!lastScanForStaleResponses)
+ lastScanForStaleResponses = NonZeroTime(currentTime - (StaleResponseScanInterval * mDNSPlatformOneSecond));
- if (serviceRecordSet == NULL)
+ if (finalBeacon)
{
- LogInfo("start_BLE_advertise: NULL service record set for: %##s %s, returning", domain->c, DNSTypeName(type));
- return;
- }
- LogInfo("start_BLE_advertise: Starting BLE advertisement for: %##s %s", domain->c, DNSTypeName(type));
+ // We don't expect to do the finalBeacon processing if there are active browse requests,
+ if (BLEBrowseListHead)
+ LogInfo("serviceBLE: finalBeacon set and called with active browse BLE requests ??");
- instanceRemoved = SkipLeadingLabels(domain, 1);
+ // or active registrations but we are not in suppress beacons state.
+ if (BLERegistrationListHead && !suppressBeacons)
+ LogInfo("serviceBLE: finalBeacon set and called with active registrations requests, but not in suppress beacons state ??");
- ptr = addToRequestList(&BLERegistrationListHead, instanceRemoved, type, flags);
+ finalBeacon = false;
+ stopBLEBeacon();
+ }
- // If equivalent BLE registration is already running, just return.
- if (ptr->refCount > 1)
+ if (!BLEBrowseListHead && !BLERegistrationListHead)
{
- LogInfo("start_BLE_advertise: Dup of existing BLE advertisement.");
- return;
+ LogInfo("serviceBLE: no active client requests, disabling service timer");
+ mDNSStorage.NextBLEServiceTime = 0;
}
-
- ptr->registeredHash = BLEServiceHash(instanceRemoved);
- if (ptr->registeredHash == 0)
+ else if ((currentTime - lastScanForStaleResponses) >= (StaleResponseScanInterval * mDNSPlatformOneSecond))
{
- LogInfo("BLEServiceHash failed!");
- removeFromRequestList(&BLERegistrationListHead, instanceRemoved, type);
- return;
+ removeStaleResponses(currentTime);
+ lastScanForStaleResponses = currentTime;
+ mDNSStorage.NextBLEServiceTime = NonZeroTime(currentTime + (StaleResponseScanInterval * mDNSPlatformOneSecond));
}
- ptr->serviceRecordSet = serviceRecordSet;
- // Extract the interface ID for easier access in the requestList_t structure
- ptr->InterfaceID = serviceRecordSet->RR_SRV.resrec.InterfaceID;
-
- addServiceToBeacon(0, ptr->registeredHash);
}
-void stop_BLE_advertise(const domainname *const domain, DNS_TypeValues type, DNSServiceFlags flags)
+// Initialize the periodic service timer if we have active requests.
+// The timer is disabled in the next call to serviceBLE() when no requests are active.
+mDNSlocal void updateServiceTimer()
{
- (void) flags; // not used initially
- requestList_t * ptr;
- bool lastReference = false;
- const domainname * instanceRemoved;
-
- if (!EnableBLEBasedDiscovery)
- {
- LogMsg("stop_BLE_advertise: EnableBLEBasedDiscovery disabled");
- return;
- }
+ if (!mDNSStorage.NextBLEServiceTime && (BLEBrowseListHead || BLERegistrationListHead))
+ mDNSStorage.NextBLEServiceTime = NonZeroTime(mDNSStorage.timenow + (StaleResponseScanInterval * mDNSPlatformOneSecond));
+}
- // Just process the SRV record for each service registration. The PTR
- // record already has the service type at the beginning of the domain, but
- // we want to filter out reverse address PTR records at this point in time, so using
- // the SRV record instead.
- if (type != kDNSServiceType_SRV)
- return;
+// Set true when suppressing beacon transmissions for our registrations until we see
+// a peer beacon indicating a browse for one of our services.
+bool suppressBeacons = false;
- LogInfo("stop_BLE_advertise: Stopping BLE advertisement for: %##s %s", domain->c, DNSTypeName(type));
+// Go through all the existing browses and registrations to create the
+// current Bloom filter value for the BLE beacon.
+// Update the current scan and beaconing state appropriately.
+mDNSlocal void updateBeaconAndScanState()
+{
+ requestList_t *ptr;
+ serviceHash_t beaconBloomFilter = 0;
- instanceRemoved = SkipLeadingLabels(domain, 1);
+ updateServiceTimer();
- // Get the request pointer from the indirect pointer returned.
- ptr = *(findInRequestList(&BLERegistrationListHead, instanceRemoved, type));
-
- if (ptr == 0)
+ for (ptr = BLEBrowseListHead; ptr; ptr = ptr->next)
{
- LogInfo("stop_BLE_advertise: No matching advertisement found.");
- return;
+ beaconBloomFilter |= ptr->browseHash;
}
-
- // If this is the last reference for this registration, update advertising and browsing bits set in
- // the beacon before removing this registration from the request list.
- if (ptr->refCount == 1)
+
+ for (ptr = BLERegistrationListHead; ptr; ptr = ptr->next)
{
- lastReference = true;
+ beaconBloomFilter |= ptr->registeredHash;
+ }
- if (isAutoTriggerRequest(ptr) && ptr->triggeredOnAWDL)
+ // If only advertising registered services and not browsing, we don't start the beacon transmission
+ // until we receive a beacon from a peer matching one of our registrations.
+ if (BLERegistrationListHead && !BLEBrowseListHead && !responseMatchesRegistrations())
+ {
+ // If beacons are already suppressed, then no further action to take.
+ if (suppressBeacons)
+ LogInfo("updateBeaconAndScanState: continuing to suppressing beacons");
+ else
{
- // And remove the corresponding advertisements from the AWDL D2D plugin.
- // Do it directly here, since we do not set the kDNSServiceFlagsIncludeAWDL bit in the original client request structure
- // when we trigger the registration over AWDL, we just update the record ARType field, so our caller, external_stop_browsing_for_service()
- // would not call into the D2D plugin to remove the advertisements in this case.
- internal_stop_advertising_service(& ptr->serviceRecordSet->RR_PTR.resrec, (ptr->flags | kDNSServiceFlagsIncludeAWDL));
- internal_stop_advertising_service(& ptr->serviceRecordSet->RR_SRV.resrec, (ptr->flags | kDNSServiceFlagsIncludeAWDL));
- internal_stop_advertising_service(& ptr->serviceRecordSet->RR_TXT.resrec, (ptr->flags | kDNSServiceFlagsIncludeAWDL));
+ LogInfo("updateBeaconAndScanState: suppressing beacons, no peers currently seeking our services");
+ suppressBeacons = true;
+
+ // If currently beaconing, send a beacon for two seconds with a zeroed Bloom filter indicating we are
+ // no longer browsing for any services so that any matching auto triggered peer registrations have a
+ // chance to see our state change.
+ if (currentlyBeaconing())
+ updateBLEBeacon(0);
+ startBLEScan();
}
}
- removeFromRequestList(&BLERegistrationListHead, instanceRemoved, type);
-
- if (lastReference)
- updateBeacon();
-
- // If there are no active browse or registration requests, BLE scanning will be disabled.
- // Clear the list of responses received to remove any stale response state.
- if (BLEBrowseListHead == NULL && BLERegistrationListHead == 0)
- clearResponseLists();
+ // If beacons had been suppressed and we no longer have services to advertise, no
+ // need to send a beacon with a zeroed Bloom filter for two seconds, just stop
+ // the scan.
+ else if (suppressBeacons == true && beaconBloomFilter == 0)
+ {
+ suppressBeacons = false;
+ stopBLEScan();
+ }
+ // Update the beacon with the current Bloom filter values.
+ else
+ {
+ suppressBeacons = false;
+ updateBLEBeacon(beaconBloomFilter);
+ // Scan unless the Bloom filter is zero, indicating we are not currently
+ // seeking or providing any services.
+ if (beaconBloomFilter)
+ startBLEScan();
+ else
+ stopBLEScan();
+ }
}
-#pragma mark - Response Handling
+#pragma mark - Peer response handling
// Structure used to track the beacons received from various peers.
typedef struct responseList
{
struct responseList * next;
- serviceHash_t browseHash;
- serviceHash_t registeredHash;
- mDNSEthAddr senderMAC;
+ serviceHash_t peerBloomFilter;
+ mDNSs32 recievedTime;
+ mDNSEthAddr peerMac;
} responseList_t;
#define RESPONSE_LIST_NUMBER 8
static responseList_t* BLEResponseListHeads[RESPONSE_LIST_NUMBER];
+// Return the address of the pointer to the entry, which can either be the address of the
+// corresponding BLEResponseListHeads[] entry, or the address of the prior responseList_t entry
+// on the lists "next" pointer.
mDNSlocal responseList_t ** findInResponseList(mDNSEthAddr * ptrToMAC)
{
// Use the least significant byte of the MAC address as our hash index to find the list.
@@ -518,7 +695,7 @@ mDNSlocal responseList_t ** findInResponseList(mDNSEthAddr * ptrToMAC)
for ( ; *ptr; ptr = &(*ptr)->next)
{
- if (memcmp(&(*ptr)->senderMAC, ptrToMAC, sizeof(mDNSEthAddr)) == 0)
+ if (memcmp(&(*ptr)->peerMac, ptrToMAC, sizeof(mDNSEthAddr)) == 0)
break;
}
@@ -526,7 +703,7 @@ mDNSlocal responseList_t ** findInResponseList(mDNSEthAddr * ptrToMAC)
}
-mDNSlocal responseList_t ** addToResponseList(serviceHash_t browseHash, serviceHash_t registeredHash, mDNSEthAddr * ptrToMAC)
+mDNSlocal responseList_t * addToResponseList(serviceHash_t peerBloomFilter, mDNSEthAddr * ptrToMAC)
{
responseList_t **ptr = findInResponseList(ptrToMAC);
@@ -534,12 +711,11 @@ mDNSlocal responseList_t ** addToResponseList(serviceHash_t browseHash, serviceH
{
*ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
mDNSPlatformMemZero(*ptr, sizeof(**ptr));
- (*ptr)->browseHash = browseHash;
- (*ptr)->registeredHash = registeredHash;
- memcpy(& (*ptr)->senderMAC, ptrToMAC, sizeof(mDNSEthAddr));
+ (*ptr)->peerBloomFilter = peerBloomFilter;
+ memcpy(& (*ptr)->peerMac, ptrToMAC, sizeof(mDNSEthAddr));
}
- return ptr;
+ return *ptr;
}
mDNSlocal void removeFromResponseList(mDNSEthAddr * ptrToMAC)
@@ -581,25 +757,8 @@ mDNSlocal void clearResponseLists()
}
}
-// Called from mDNS_Execute() when NextBLEServiceTime is reached
-// to stop the BLE beacon a few seconds after the last request has
-// been stopped. This gives peers a chance to see that this device
-// is no longer browsing for or advertising any services via the
-// BLE beacon.
-void serviceBLE(void)
-{
- mDNSStorage.NextBLEServiceTime = 0;
- if (BLEBrowseListHead || BLERegistrationListHead)
- {
- // We don't expect to be called if there are active requests.
- LogInfo("serviceBLE: called with active BLE requests ??");
- return;
- }
- stopBLEBeacon();
-}
-
-// Called from start_BLE_browse() on the mDNSResonder kqueue thread
-mDNSlocal void checkForMatchingResponses(requestList_t *bp)
+// Check to see if we have cached a response that matches a service for which we just started a browse or registration.
+mDNSlocal void checkCachedResponses(requestList_t *browse, requestList_t *registration)
{
responseList_t *ptr;
@@ -607,28 +766,28 @@ mDNSlocal void checkForMatchingResponses(requestList_t *bp)
{
for (ptr = BLEResponseListHeads[i]; ptr; ptr = ptr->next)
{
- if ((bp->browseHash & ptr->registeredHash) == bp->browseHash)
+ // For browses, we are looking for responses that have a matching registration
+ // and for registrations we are looking for responses that have a matching browse.
+ if ( (browse && (browse->registeredHash & ptr->peerBloomFilter) == browse->registeredHash)
+ || (registration && (registration->browseHash & ptr->peerBloomFilter) == registration->browseHash))
{
- // Clear the registered services hash for the response.
- // The next beacon from this peer will update the hash and our
- // newly started browse will get an add event if there is a match.
- ptr->registeredHash = 0;
+ // Clear the Bloom filter for the response.
+ // The next beacon from this peer will update the filter then autoTrigger
+ // any newly started client requests as appropriate.
+ ptr->peerBloomFilter = 0;
}
}
}
}
// Define a fixed name to use for the instance name denoting that one or more instances
-// of a service are being advetised by peers in their BLE beacons.
+// of a service are being advertised by peers in their BLE beacons.
// Name format is: length byte + bytes of name string + two byte pointer to the PTR record name.
-// See compression_lhs definition in the D2D plugin code for backgound on 0xc027 DNS name compression pointer value.
+// See compression_lhs definition in the D2D plugin code for background on 0xc027 DNS name compression pointer value.
static Byte *BLEinstanceValue = (Byte *) "\x11ThresholdInstance\xc0\x27";
#define BLEValueSize strlen((const char *)BLEinstanceValue)
-void xD2DAddToCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize);
-void xD2DRemoveFromCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize);
-
-// Find each unique browse that matches the registered service hash in the BLE response.
+// Find each local browse that matches the registered service hash in the BLE response.
// Called on the CFRunLoop thread while handling a callback from CoreBluetooth.
// Caller should hold KQueueLock().
mDNSlocal void findMatchingBrowse(responseList_t *response)
@@ -638,7 +797,9 @@ mDNSlocal void findMatchingBrowse(responseList_t *response)
ptr = BLEBrowseListHead;
for ( ; ptr; ptr = ptr->next)
{
- if ((ptr->browseHash & response->registeredHash) == ptr->browseHash)
+ // See if we potentially match a corresponding registration in the beacon.
+ // thus, compare using the "registeredHash" of our browse..
+ if ((ptr->registeredHash & response->peerBloomFilter) == ptr->registeredHash)
{
LogInfo("findMatchingBrowse: Registration in response matched browse for: %##s", ptr->name.c);
@@ -655,20 +816,19 @@ mDNSlocal void findMatchingBrowse(responseList_t *response)
if (ptr->ourResponses == 0)
{
- if (isAutoTriggerRequest(ptr))
+ if (isAutoTriggerRequest(ptr->InterfaceID, ptr->flags))
{
LogInfo("findMatchingBrowse: First BLE response, triggering browse for %##s on AWDL", ptr->name.c);
- ptr->question->flags |= kDNSServiceFlagsIncludeAWDL;
- mDNSCoreRestartQuestion(& mDNSStorage, ptr->question);
// register with the AWDL D2D plugin,
- internal_start_browsing_for_service(ptr->question->InterfaceID, & ptr->name, ptr->type, ptr->question->flags, ptr->question);
+ internal_start_browsing_for_service(ptr->InterfaceID, & ptr->name, ptr->type, ptr->flags);
+ ptr->triggeredOnAWDL = true;
}
// Browse on mDNSInterface_BLE is used to determine if there are one or more instances of the
// service type discoveryed over BLE. If this is the first instance, add the psuedo instance defined by BLEinstanceValue.
- if (ptr->question->InterfaceID == mDNSInterface_BLE)
+ if (ptr->InterfaceID == mDNSInterface_BLE)
{
- xD2DAddToCache(& mDNSStorage, kD2DSuccess, 0, D2DBLETransport, ptr->key, ptr->keySize, BLEinstanceValue, BLEValueSize);
+ xD2DAddToCache(kD2DSuccess, 0, D2DBLETransport, ptr->key, ptr->keySize, BLEinstanceValue, BLEValueSize);
}
}
addToResponseListForRequest(ptr, response);
@@ -680,34 +840,37 @@ mDNSlocal void findMatchingBrowse(responseList_t *response)
// list now. If this is the last matching response, remove the corresponding key from the AWDL D2D plugin
if (removeFromResponseListForRequest(ptr, response) && (ptr->ourResponses == 0))
{
- if (ptr->question->InterfaceID == mDNSInterface_BLE)
+ if (ptr->InterfaceID == mDNSInterface_BLE)
{
- xD2DRemoveFromCache(& mDNSStorage, kD2DSuccess, 0, D2DBLETransport, ptr->key, ptr->keySize, BLEinstanceValue, BLEValueSize);
+ xD2DRemoveFromCache(kD2DSuccess, 0, D2DBLETransport, ptr->key, ptr->keySize, BLEinstanceValue, BLEValueSize);
}
- if (isAutoTriggerRequest(ptr))
+ if (isAutoTriggerRequest(ptr->InterfaceID, ptr->flags))
{
LogInfo("findMatchingBrowse: Last BLE response, disabling browse for %##s on AWDL", ptr->name.c);
- internal_stop_browsing_for_service(ptr->question->InterfaceID, & ptr->name, ptr->type, ptr->question->flags);
+ internal_stop_browsing_for_service(ptr->InterfaceID, & ptr->name, ptr->type, ptr->flags);
+ ptr->triggeredOnAWDL = false;
}
}
}
}
}
-// Find each local registration that matches the service browse hash in the BLE response.
+// Find each local registration that matches the service browse hash BLE response Bloom filter.
// Called on the CFRunLoop thread while handling a callback from CoreBluetooth.
// Caller should hold KQueueLock().
mDNSlocal void findMatchingRegistration(responseList_t *response)
{
- requestList_t *ptr;
+ requestList_t *ptr;
+ bool matchingPeer;
ptr = BLERegistrationListHead;
for ( ; ptr; ptr = ptr->next)
{
- if ((ptr->registeredHash & response->browseHash) == ptr->registeredHash)
+ // See if we potentially match a corresponding browse in the beacon,
+ // thus, compare using the "browseHash" of our registration.
+ if ((ptr->browseHash & response->peerBloomFilter) == ptr->browseHash)
{
-
LogInfo("findMatchingRegistration: Incoming browse matched registration for: %##s", ptr->name.c);
if (inResponseListForRequest(ptr, response))
@@ -722,44 +885,16 @@ mDNSlocal void findMatchingRegistration(responseList_t *response)
// Also pass the registration to the AWDL D2D plugin if this is the first matching peer browse for
// an auto triggered local registration.
- if ((ptr->ourResponses == 0) && isAutoTriggerRequest(ptr))
+ if ((ptr->ourResponses == 0) && isAutoTriggerRequest(ptr->InterfaceID, ptr->flags))
{
- AuthRecType newARType;
-
LogInfo("findMatchingRegistration: First BLE response, triggering registration for %##s on AWDL", ptr->name.c);
- if (ptr->serviceRecordSet == 0)
- {
- LogInfo("findMatchingRegistration: serviceRecordSet pointer is NULL ??");
- continue;
- }
- // Modify the PTR, TXT, and SRV records so that they now apply to AWDL and restart the registration.
- // RR_ADV is not passed to the D2D plugins froma internal_start_advertising_helper(), so we don't do it here either.
-
- if (ptr->flags & kDNSServiceFlagsIncludeAWDL)
+ if (ptr->resourceRecord == 0)
{
- LogInfo("findMatchingRegistration: registration for %##s already applies to AWDL, skipping", ptr->name.c);
+ LogInfo("findMatchingRegistration: resourceRecord pointer is NULL ??");
continue;
}
- // Save the current ARType value to restore when the promotion to use AWDL is stopped.
- ptr->savedARType = ptr->serviceRecordSet->RR_PTR.ARType;
-
- // Preserve P2P attribute if original registration was applied to P2P.
- if (ptr->serviceRecordSet->RR_PTR.ARType == AuthRecordAnyIncludeP2P)
- newARType = AuthRecordAnyIncludeAWDLandP2P;
- else
- newARType = AuthRecordAnyIncludeAWDL;
-
- ptr->serviceRecordSet->RR_PTR.ARType = newARType;
- ptr->serviceRecordSet->RR_SRV.ARType = newARType;
- ptr->serviceRecordSet->RR_TXT.ARType = newARType;
- mDNSCoreRestartRegistration(& mDNSStorage, & ptr->serviceRecordSet->RR_PTR, -1);
- mDNSCoreRestartRegistration(& mDNSStorage, & ptr->serviceRecordSet->RR_SRV, -1);
- mDNSCoreRestartRegistration(& mDNSStorage, & ptr->serviceRecordSet->RR_TXT, -1);
-
- internal_start_advertising_service(& ptr->serviceRecordSet->RR_PTR.resrec, (ptr->flags | kDNSServiceFlagsIncludeAWDL));
- internal_start_advertising_service(& ptr->serviceRecordSet->RR_SRV.resrec, (ptr->flags | kDNSServiceFlagsIncludeAWDL));
- internal_start_advertising_service(& ptr->serviceRecordSet->RR_TXT.resrec, (ptr->flags | kDNSServiceFlagsIncludeAWDL));
+ internal_start_advertising_service(ptr->resourceRecord, (ptr->flags | kDNSServiceFlagsIncludeAWDL));
// indicate the registration has been applied to the AWDL interface
ptr->triggeredOnAWDL = true;
}
@@ -772,51 +907,113 @@ mDNSlocal void findMatchingRegistration(responseList_t *response)
// If a previous response from this peer had matched the browse, remove that response from the
// list now. If this is the last matching response for a local auto triggered registration,
// remove the advertised key/value pairs from the AWDL D2D plugin.
- if (removeFromResponseListForRequest(ptr, response) && (ptr->ourResponses == 0) && isAutoTriggerRequest(ptr))
+ if (removeFromResponseListForRequest(ptr, response) && (ptr->ourResponses == 0) && isAutoTriggerRequest(ptr->InterfaceID, ptr->flags))
{
LogInfo("findMatchingRegistration: Last BLE response, disabling registration for %##s on AWDL", ptr->name.c);
// Restore the saved ARType and call into the AWDL D2D plugin to stop the corresponding record advertisements over AWDL.
- ptr->serviceRecordSet->RR_PTR.ARType = ptr->savedARType;
- ptr->serviceRecordSet->RR_SRV.ARType = ptr->savedARType;
- ptr->serviceRecordSet->RR_TXT.ARType = ptr->savedARType;
- internal_stop_advertising_service(& ptr->serviceRecordSet->RR_PTR.resrec, (ptr->flags | kDNSServiceFlagsIncludeAWDL));
- internal_stop_advertising_service(& ptr->serviceRecordSet->RR_SRV.resrec, (ptr->flags | kDNSServiceFlagsIncludeAWDL));
- internal_stop_advertising_service(& ptr->serviceRecordSet->RR_TXT.resrec, (ptr->flags | kDNSServiceFlagsIncludeAWDL));
+ internal_stop_advertising_service(ptr->resourceRecord, (ptr->flags | kDNSServiceFlagsIncludeAWDL));
+ ptr->triggeredOnAWDL = false;
}
}
}
+
+ // If beacons for our registrations had been suppressed, see if we now have a match and need to restart them.
+ matchingPeer = responseMatchesRegistrations();
+ if (suppressBeacons && matchingPeer)
+ {
+ LogInfo("findMatchingRegistration: peer searching for our service, starting beacon transmission");
+ updateBeaconAndScanState();
+
+ if (suppressBeacons == true)
+ LogInfo("findMatchingRegistration: NOTE: suppressBeacons is true after updateBeaconAndScanState() call ??");
+ }
+ // If we have only registrations, but no matching peers, we can suppress beacons until we get a matching peer beacon.
+ else if (!suppressBeacons && !matchingPeer && BLERegistrationListHead && !BLEBrowseListHead)
+ {
+ LogInfo("findMatchingRegistration: no peer beacons match our registrations, suppressing beacon transmission");
+ suppressBeacons = true;
+ stopBLEBeacon();
+ }
+}
+
+
+// Time limit before a beacon is aged out of our received list.
+#define MAX_RESPONSE_AGE 10
+
+// If we have responses from peers that are more than MAX_RESPONSE_AGE seconds
+// old, remove them since a peer with active requests should be beaconing multiple
+// times per second if still within BLE range.
+mDNSlocal void removeStaleResponses(mDNSs32 currentTime)
+{
+ responseList_t **ptr;
+
+ for (unsigned int i = 0; i < RESPONSE_LIST_NUMBER; i++)
+ {
+ ptr = & BLEResponseListHeads[i];
+ while (*ptr)
+ {
+ if ((currentTime - (*ptr)->recievedTime) > (MAX_RESPONSE_AGE * mDNSPlatformOneSecond))
+ {
+ responseList_t * tmp;
+
+ // Clear the Bloom filter so that it will be removed from any matching response list
+ // by the following calls.
+ (*ptr)->peerBloomFilter = 0;
+
+ LogInfo("removeStaleResponses: clearing stale response from peer MAC = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
+ (*ptr)->peerMac.b[0], (*ptr)->peerMac.b[1], (*ptr)->peerMac.b[2], (*ptr)->peerMac.b[3], (*ptr)->peerMac.b[4], (*ptr)->peerMac.b[5]);
+
+ findMatchingBrowse(*ptr);
+ findMatchingRegistration(*ptr);
+
+ // Unlink and free the response structure
+ tmp = *ptr;
+ *ptr = (*ptr)->next;
+ mDNSPlatformMemFree(tmp);
+ }
+ // Move to the next response on this linked list.
+ else
+ ptr = & (*ptr)->next;
+ }
+ }
}
// Called on CFRunLoop thread during CoreBluetooth beacon response processing.
// Thus, must call KQueueLock() prior to calling any core mDNSResponder routines to register records, etc.
-void responseReceived(serviceHash_t browseHash, serviceHash_t registeredHash, mDNSEthAddr * ptrToMAC)
+void responseReceived(serviceHash_t peerBloomFilter, mDNSEthAddr * ptrToMAC)
{
- responseList_t ** ptr;
+ responseList_t * ptr;
- KQueueLock(& mDNSStorage);
- ptr = findInResponseList(ptrToMAC);
- if (*ptr == 0)
+ KQueueLock();
+ mDNS_Lock(& mDNSStorage); // Must lock to initialize mDNSStorage.timenow
+
+ ptr = *(findInResponseList(ptrToMAC));
+ if (ptr == 0)
{
// Only add to list if peer is actively browsing or advertising.
- if (browseHash || registeredHash)
+ if (peerBloomFilter)
{
LogInfo("responseReceived: First beacon of this type, adding to list");
- LogInfo("responseReceived: browseHash = 0x%x, registeredHash = 0x%x",
- browseHash, registeredHash);
- LogInfo("responseReceived: sender MAC = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
+ LogInfo("responseReceived: peerBloomFilter = 0x%lx", peerBloomFilter);
+ LogInfo("responseReceived: peer MAC = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
ptrToMAC->b[0], ptrToMAC->b[1], ptrToMAC->b[2], ptrToMAC->b[3], ptrToMAC->b[4], ptrToMAC->b[5]);
- ptr = addToResponseList(browseHash, registeredHash, ptrToMAC);
+ ptr = addToResponseList(peerBloomFilter, ptrToMAC);
+ // Update the received time.
+ ptr->recievedTime = mDNSStorage.timenow;
// See if we are browsing for any of the peers advertised services.
- findMatchingBrowse(*ptr);
+ findMatchingBrowse(ptr);
// See if we have a registration that matches the peer's browse.
- findMatchingRegistration(*ptr);
+ findMatchingRegistration(ptr);
}
}
- else // have entry from this MAC in the list
+ else // Have an entry from this MAC in the list.
{
- if (((*ptr)->browseHash == browseHash) && ((*ptr)->registeredHash == registeredHash))
+ // Update the received time.
+ ptr->recievedTime = mDNSStorage.timenow;
+
+ if (ptr->peerBloomFilter == peerBloomFilter)
{
// A duplicate of a current entry.
#if VERBOSE_BLE_DEBUG
@@ -828,20 +1025,17 @@ void responseReceived(serviceHash_t browseHash, serviceHash_t registeredHash, mD
else
{
LogInfo("responseReceived: Update of previous beacon");
- LogInfo("responseReceived: browseHash = 0x%x, registeredHash = 0x%x",
- browseHash, registeredHash);
+ LogInfo("responseReceived: peerBloomFilter = 0x%lx", peerBloomFilter);
LogInfo("responseReceived: sender MAC = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
ptrToMAC->b[0], ptrToMAC->b[1], ptrToMAC->b[2], ptrToMAC->b[3], ptrToMAC->b[4], ptrToMAC->b[5]);
- (*ptr)->browseHash = browseHash;
- (*ptr)->registeredHash = registeredHash;
-
- findMatchingBrowse(*ptr);
- findMatchingRegistration(*ptr);
+ ptr->peerBloomFilter = peerBloomFilter;
+ findMatchingBrowse(ptr);
+ findMatchingRegistration(ptr);
}
// If peer is no longer browsing or advertising, remove from list.
- if ((browseHash == 0) && (registeredHash == 0))
+ if (peerBloomFilter == 0)
{
LogInfo("responseReceived: Removing peer entry from the list");
@@ -849,5 +1043,450 @@ void responseReceived(serviceHash_t browseHash, serviceHash_t registeredHash, mD
}
}
- KQueueUnlock(& mDNSStorage, "BLE responseReceived");
+ mDNS_Unlock(& mDNSStorage); // Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value
+ KQueueUnlock("BLE responseReceived");
+}
+
+#pragma mark - Client request handling
+
+void start_BLE_browse(mDNSInterfaceID InterfaceID, const domainname *const domain, DNS_TypeValues type, DNSServiceFlags flags, mDNSu8 *key, size_t keySize)
+{
+ requestList_t * ptr;
+ const domainname *serviceType = domain;
+
+ if (!EnableBLEBasedDiscovery)
+ {
+ LogMsg("start_BLE_browse: EnableBLEBasedDiscovery disabled");
+ return;
+ }
+
+ if (keySize > MAX_KEY_SIZE)
+ {
+ LogMsg("start_BLE_browse: keySize = %d, maximum allowable is %d", keySize, MAX_KEY_SIZE);
+ return;
+ }
+
+ // Verify that the request to be auto triggered applies to AWDL, or is using the pseudo interface for
+ // BLE threshold browsing.
+ if (!isAutoTriggerRequest(InterfaceID, flags) && (InterfaceID != mDNSInterface_BLE))
+ {
+ LogMsg("start_BLE_browse: invalid request: InterfaceID = %d, flags = 0x%x", InterfaceID, flags);
+ return;
+ }
+
+ // Address records don't have a service type to hash and match on, so pass them directly to the D2D plugin.
+ if ((type == kDNSType_A) || (type == kDNSType_AAAA))
+ {
+ LogInfo("start_BLE_browse: Passing directly to D2D layer: %##s %s", domain->c, DNSTypeName(type));
+ internal_start_browsing_for_service(InterfaceID, domain, type, flags);
+ return;
+ }
+
+ // Skip the instance to get to the service type for non PTR records
+ if (type != kDNSType_PTR)
+ serviceType = SkipLeadingLabels(domain, 1);
+
+ LogInfo("start_BLE_browse: Starting BLE service type browse for: %##s %s", domain->c, DNSTypeName(type));
+
+ ptr = addToRequestList(&BLEBrowseListHead, domain, type, flags);
+
+ // If equivalent BLE browse is already running, just return.
+ if (ptr->refCount > 1)
+ {
+ LogInfo("start_BLE_browse: Dup of existing BLE browse.");
+ return;
+ }
+
+ if (!setBLEServiceHash(serviceType, ptr))
+ {
+ LogInfo("setBLEServiceHash failed!");
+ removeFromRequestList(&BLEBrowseListHead, domain, type);
+ return;
+ }
+
+ // Save these for use in D2D plugin callback logic.
+ memcpy(ptr->key, key, keySize);
+ ptr->keySize = keySize;
+ ptr->InterfaceID = InterfaceID;
+
+ mDNS_Lock(& mDNSStorage); // Must lock to initialize mDNSStorage.timenow.
+ updateBeaconAndScanState();
+ mDNS_Unlock(& mDNSStorage); // Updates mDNSStorage.NextScheduledEvent.
+ checkCachedResponses(ptr, NULL);
+}
+
+// Stop the browse.
+// Return true if this is the last reference to the browse, false otherwise.
+bool stop_BLE_browse(mDNSInterfaceID InterfaceID, const domainname *const domain, DNS_TypeValues type, DNSServiceFlags flags)
+{
+ (void) flags; // not used initially
+ requestList_t * ptr;
+ bool lastReference = false;
+
+ if (!EnableBLEBasedDiscovery)
+ {
+ LogMsg("stop_BLE_browse: EnableBLEBasedDiscovery disabled");
+ return lastReference;
+ }
+
+ // Address records don't have a service type to hash and match on, so pass them directly to the D2D plugin.
+ if ((type == kDNSType_A) || (type == kDNSType_AAAA))
+ {
+ LogInfo("stop_BLE_browse: Passing directly to D2D layer: %##s %s", domain->c, DNSTypeName(type));
+ internal_stop_browsing_for_service(InterfaceID, domain, type, flags);
+ return lastReference;
+ }
+
+ LogInfo("stop_BLE_browse: Stopping BLE service type browse for: %##s %s", domain->c, DNSTypeName(type));
+
+ ptr = *(findInRequestList(&BLEBrowseListHead, domain, type));
+ if (ptr == 0)
+ {
+ LogInfo("stop_BLE_browse: No matching browse found.");
+ return lastReference;
+ }
+
+ // If this is the last reference for this browse, and it was autoTriggered on AWDL,
+ // remove the request from the AWDL pluggin.
+ if (ptr->refCount == 1)
+ {
+ lastReference = true;
+
+ if (isAutoTriggerRequest(ptr->InterfaceID, ptr->flags) && ptr->triggeredOnAWDL)
+ {
+ internal_stop_browsing_for_service(ptr->InterfaceID, & ptr->name, ptr->type, ptr->flags);
+ ptr->triggeredOnAWDL = false;
+ }
+ }
+
+ removeFromRequestList(&BLEBrowseListHead, domain, type);
+
+ mDNS_Lock(& mDNSStorage); // Must lock to initialize mDNSStorage.timenow.
+ if (lastReference)
+ updateBeaconAndScanState();
+ mDNS_Unlock(& mDNSStorage); // Updates mDNSStorage.NextScheduledEvent.
+
+ // If there are no active browse or registration requests, BLE scanning will be disabled.
+ // Clear the list of responses received to remove any stale response state.
+ if (BLEBrowseListHead == NULL && BLERegistrationListHead == 0)
+ clearResponseLists();
+
+ return lastReference;
+}
+
+void start_BLE_advertise(const ResourceRecord *const resourceRecord, const domainname *const domain, DNS_TypeValues type, DNSServiceFlags flags)
+{
+ requestList_t * ptr;
+ const domainname * serviceType = domain;
+
+ if (!EnableBLEBasedDiscovery)
+ {
+ LogMsg("start_BLE_advertise: EnableBLEBasedDiscovery disabled");
+ return;
+ }
+
+ if (resourceRecord == NULL)
+ {
+ LogInfo("start_BLE_advertise: NULL resourceRecord for: %##s %s, returning", domain->c, DNSTypeName(type));
+ return;
+ }
+
+ // Verify that the request to be auto triggered applies to AWDL, or is using the pseudo interface for
+ // BLE threshold browsing.
+ if (!isAutoTriggerRequest(resourceRecord->InterfaceID, flags) && (resourceRecord->InterfaceID != mDNSInterface_BLE))
+ {
+ LogMsg("start_BLE_advertise: invalid request: InterfaceID = %d, flags = 0x%x", resourceRecord->InterfaceID, flags);
+ return;
+ }
+
+ LogInfo("start_BLE_advertise: Starting BLE service type advertisement for: %##s %s", domain->c, DNSTypeName(type));
+
+ // Skip the instance to get to the service type for non PTR records
+ if (type != kDNSType_PTR)
+ serviceType = SkipLeadingLabels(domain, 1);
+
+ ptr = addToRequestList(&BLERegistrationListHead, domain, type, flags);
+
+ // If equivalent BLE registration is already running, just return.
+ if (ptr->refCount > 1)
+ {
+ LogInfo("start_BLE_advertise: Dup of existing BLE advertisement.");
+ return;
+ }
+
+ if (!setBLEServiceHash(serviceType, ptr))
+ {
+ LogInfo("setBLEServiceHash failed!");
+ removeFromRequestList(&BLERegistrationListHead, domain, type);
+ return;
+ }
+ ptr->resourceRecord = resourceRecord;
+ ptr->InterfaceID = resourceRecord->InterfaceID;
+
+ mDNS_Lock(& mDNSStorage); // Must lock to initialize mDNSStorage.timenow.
+ updateBeaconAndScanState();
+ mDNS_Unlock(& mDNSStorage); // Updates mDNSStorage.NextScheduledEvent.
+ checkCachedResponses(NULL, ptr);
+}
+
+void stop_BLE_advertise(const domainname *const domain, DNS_TypeValues type, DNSServiceFlags flags)
+{
+ (void) flags; // not used initially
+ requestList_t * ptr;
+ bool lastReference = false;
+
+ LogInfo("stop_BLE_advertise: Stopping BLE service type advertisement for: %##s %s", domain->c, DNSTypeName(type));
+
+ // Get the request pointer from the indirect pointer returned.
+ ptr = *(findInRequestList(&BLERegistrationListHead, domain, type));
+
+ if (ptr == 0)
+ {
+ LogInfo("stop_BLE_advertise: No matching advertisement found.");
+ return;
+ }
+
+ // If this is the last reference for this registration, and it was autoTriggered on AWDL,
+ // remove the request from the AWDL pluggin.
+ if (ptr->refCount == 1)
+ {
+ lastReference = true;
+
+ if (isAutoTriggerRequest(ptr->InterfaceID, ptr->flags) && ptr->triggeredOnAWDL)
+ {
+ // And remove the corresponding advertisements from the AWDL D2D plugin if we had previously
+ // passed this advertisement request to the plugin.
+ internal_stop_advertising_service(ptr->resourceRecord, (ptr->flags | kDNSServiceFlagsIncludeAWDL));
+ ptr->triggeredOnAWDL = false;
+ }
+ }
+ removeFromRequestList(&BLERegistrationListHead, domain, type);
+
+ mDNS_Lock(& mDNSStorage); // Must lock to initialize mDNSStorage.timenow.
+ // If this is the last reference for this registration, update advertising and browsing bits set in the beacon.
+ if (lastReference)
+ updateBeaconAndScanState();
+ mDNS_Unlock(& mDNSStorage); // Updates mDNSStorage.NextScheduledEvent.
+
+ // If there are no active browse or registration requests, BLE scanning will be disabled.
+ // Clear the list of responses received to remove any stale response state.
+ if (BLEBrowseListHead == NULL && BLERegistrationListHead == 0)
+ clearResponseLists();
}
+
+#ifdef UNIT_TEST
+#pragma mark - Unit test support routines
+
+// These unit test support routines are called from unittests/ framework
+// and are not compiled for the mDNSResponder runtime code paths.
+
+#define MAX_ENTRIES 42
+#define FAILED exit(1)
+
+mDNSlocal void BLE_requestListTests(void)
+{
+ const domainname *domainArray[] = { (const domainname*)"\x6" "_test0" "\x4" "_tcp" "\x5" "local",
+ (const domainname*)"\x6" "_test1" "\x4" "_tcp" "\x5" "local",
+ (const domainname*)"\x6" "_test2" "\x4" "_tcp" "\x5" "local",
+ (const domainname*)"\x6" "_test3" "\x4" "_tcp" "\x5" "local",
+ (const domainname*)"\x6" "_test4" "\x4" "_tcp" "\x5" "local",
+ };
+
+ mDNSu16 type = kDNSServiceType_PTR;
+ DNSServiceFlags flags = 0;
+ requestList_t * ptr;
+ void * response = 0;
+ int i;
+ int numOfdomains = sizeof(domainArray)/sizeof(domainArray[0]);
+
+ printf("BLE_requestListTests() entry:\n");
+
+ // Basic request list unit tests.
+ for (i = 0; i < numOfdomains; i++)
+ {
+ ptr = addToRequestList(&BLEBrowseListHead, domainArray[i], type, flags);
+
+ if (ptr == NULL)
+ {
+ printf("addToRequestList() FAILED:\n");
+ FAILED;
+ }
+ }
+ for (i = 0; i < numOfdomains; i++)
+ {
+ // should now find the entry
+ if (*(findInRequestList(&BLEBrowseListHead, domainArray[i], type)) == 0)
+ {
+ printf("findInRequestList() did not find valid entry FAILED:\n");
+ FAILED;
+ }
+ // but not find an entry with the same domain, but different type
+ if (*(findInRequestList(&BLEBrowseListHead, domainArray[i], kDNSServiceType_NULL)) != 0)
+ {
+ printf("findInRequestList() invalid entry matched FAILED:\n");
+ FAILED;
+ }
+ }
+ // remove all the entries
+ for (i = 0; i < numOfdomains; i++)
+ {
+ removeFromRequestList(&BLEBrowseListHead, domainArray[i], type);
+ }
+ // and sanity check the list is now empty
+ if (BLEBrowseListHead)
+ {
+ printf("BLEBrowseListHead not empty after all entries removed.\n");
+ FAILED;
+ }
+
+ // Identical request reference count management tests.
+ // Add identical requests to the list and verify the corresponding refCount is managed correctly
+ for (i = 0; i < MAX_ENTRIES; i++)
+ {
+ ptr = addToRequestList(&BLEBrowseListHead, domainArray[0], type, flags);
+
+ if (ptr == NULL)
+ {
+ printf("addToRequestList() of duplicate request FAILED:\n");
+ FAILED;
+ }
+ }
+
+ if (ptr->refCount != MAX_ENTRIES)
+ {
+ printf("refCount = %d, should be %d\n", ptr->refCount, MAX_ENTRIES);
+ FAILED;
+ }
+
+ // Remove all but one entry
+ for (i = 0; i < (MAX_ENTRIES - 1); i++)
+ {
+ removeFromRequestList(&BLEBrowseListHead, domainArray[0], type);
+ }
+ if (ptr->refCount != 1)
+ {
+ printf("refCount = %d, should be %d\n", ptr->refCount, 1);
+ FAILED;
+ }
+
+ // Basic response list unit tests.
+ // Note that responses per request are not checked for duplicates at this level, so
+ // we can unit test with the same (NULL) response pointer to add multiple responses.
+
+ // add MAX_ENTRIES responses
+ for (i = 0; i < MAX_ENTRIES; i++)
+ addToResponseListForRequest(ptr, response);
+
+ // remove the responses, counting that MAX_ENTRIES were removed
+ i = 0;
+ while (inResponseListForRequest(ptr, response) && removeFromResponseListForRequest(ptr, response))
+ {
+ i++;
+ }
+ if (i != MAX_ENTRIES)
+ {
+ printf("removed %d responses, should have been %d\n", i, MAX_ENTRIES);
+ FAILED;
+ }
+
+ // response list should be empty at this point
+ if (ptr->ourResponses)
+ {
+ printf("response list should be empty\n");
+ FAILED;
+ }
+
+ // add MAX_ENTRIES responses
+ for (i = 0; i < MAX_ENTRIES; i++)
+ addToResponseListForRequest(ptr, response);
+
+ // free them all
+ freeResponseListEntriesForRequest(ptr);
+
+ if (ptr->ourResponses)
+ {
+ printf("freeResponseListEntriesForRequest() should have removed all responses\n");
+ FAILED;
+ }
+}
+
+mDNSlocal mDNSEthAddr etherAddress[] = {
+ { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } },
+ { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } },
+ { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 } },
+ { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x04 } },
+ { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x05 } },
+ { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x06 } },
+ { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x07 } },
+ { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x08 } },
+ { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x09 } },
+ { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a } },
+ { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b } },
+ { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c } },
+ { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d } },
+ { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e } },
+ { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f } },
+};
+
+mDNSlocal void BLE_responseListTests(void)
+{
+ int numOfEtherAddresses = sizeof(etherAddress)/sizeof(etherAddress[0]);
+ int i;
+
+ printf("BLE_responseListTests() entry:\n");
+
+ // Just use the index as to generate the peerBloomFilter value to vary it per entry.
+ for (i = 0; i < numOfEtherAddresses; i++)
+ (void)addToResponseList(1 << i, &etherAddress[i]);
+
+ // Verify all entries are found.
+ for (i = 0; i < numOfEtherAddresses; i++)
+ {
+ if (*(findInResponseList(&etherAddress[i])) == 0)
+ {
+ printf("findInResponseList() did not find entry in list\n");
+ FAILED;
+ }
+ }
+
+ // Remove all entries.
+ for (i = 0; i < numOfEtherAddresses; i++)
+ removeFromResponseList(&etherAddress[i]);
+
+ // Sanity check that all response lists are empty
+ for (i = 0; i < RESPONSE_LIST_NUMBER; i++)
+ {
+ if (BLEResponseListHeads[i])
+ {
+ printf("BLEResponseListHeads[%d] not empty after removeFromResponseList() calls \n", i);
+ FAILED;
+ }
+ }
+
+ // Add them back again.
+ for (i = 0; i < numOfEtherAddresses; i++)
+ (void)addToResponseList(1 << i, &etherAddress[i]);
+
+ // And verify that clearResponseLists() clears all entries.
+ clearResponseLists();
+ for (i = 0; i < RESPONSE_LIST_NUMBER; i++)
+ {
+ if (BLEResponseListHeads[i])
+ {
+ printf("BLEResponseListHeads[%d] not empty after clearResponseLists() call\n", i);
+ FAILED;
+ }
+ }
+}
+
+void BLE_unitTest(void)
+{
+ BLE_requestListTests();
+ BLE_responseListTests();
+ printf("All BLE.c unit tests PASSED.\n");
+}
+
+#endif // UNIT_TEST
+
+#endif // ENABLE_BLE_TRIGGERED_BONJOUR
diff --git a/mDNSResponder/mDNSMacOSX/BLE.h b/mDNSResponder/mDNSMacOSX/BLE.h
index 970c8faf..1b91e6c2 100644
--- a/mDNSResponder/mDNSMacOSX/BLE.h
+++ b/mDNSResponder/mDNSMacOSX/BLE.h
@@ -18,37 +18,51 @@
#ifndef _BLE_H_
#define _BLE_H_
+#if ENABLE_BLE_TRIGGERED_BONJOUR
+
#include "dns_sd.h"
-#include "dns_sd_private.h"
+#include "dns_sd_internal.h"
+
+typedef unsigned long serviceHash_t;
-typedef unsigned int serviceHash_t;
+bool shouldUseBLE(mDNSInterfaceID interfaceID, DNS_TypeValues rrtype, domainname *serviceType, domainname *domain);
-void start_BLE_browse(DNSQuestion * q, const domainname *const typeDomain, DNS_TypeValues type, DNSServiceFlags flags,
+void start_BLE_browse(mDNSInterfaceID InterfaceID, const domainname *const domain, DNS_TypeValues type, DNSServiceFlags flags,
mDNSu8 *key, size_t keySize);
-bool stop_BLE_browse(const domainname *const typeDomain, DNS_TypeValues type, DNSServiceFlags flags);
+bool stop_BLE_browse(mDNSInterfaceID InterfaceID, const domainname *const domain, DNS_TypeValues type, DNSServiceFlags flags);
-void start_BLE_advertise(ServiceRecordSet * serviceRecordSet, const domainname *const domain, DNS_TypeValues type, DNSServiceFlags flags);
-void stop_BLE_advertise(const domainname *const typeDomain, DNS_TypeValues type, DNSServiceFlags flags);
+void start_BLE_advertise(const ResourceRecord *const resourceRecord, const domainname *const domain, DNS_TypeValues type, DNSServiceFlags flags);
+void stop_BLE_advertise(const domainname *const domain, DNS_TypeValues type, DNSServiceFlags flags);
-void responseReceived(serviceHash_t browseHash, serviceHash_t registeredHash, mDNSEthAddr *ptrToMAC);
+void responseReceived(serviceHash_t peerBloomFilter, mDNSEthAddr *ptrToMAC);
void serviceBLE(void);
// C interfaces to Objective-C beacon management code.
-void updateBLEBeaconAndScan(serviceHash_t browseHash, serviceHash_t registeredHash);
+void updateBLEBeacon(serviceHash_t bloomFilter);
void stopBLEBeacon(void);
+void startBLEScan(void);
+void stopBLEScan(void);
+bool currentlyBeaconing(void);
+
+extern bool suppressBeacons;
+extern bool finalBeacon;
extern mDNS mDNSStorage;
extern mDNSBool EnableBLEBasedDiscovery;
+extern mDNSBool DefaultToBLETriggered;
+
+extern mDNSInterfaceID AWDLInterfaceID;
+#define applyToBLE(interface, flags) ((interface == mDNSInterface_BLE) || (((interface == mDNSInterface_Any) || (interface == AWDLInterfaceID)) && (flags & kDNSServiceFlagsAutoTrigger)))
+
+#ifdef UNIT_TEST
+#pragma mark - Unit test declarations
-// TODO: Add the following to a local D2D.h file
-#include <DeviceToDeviceManager/DeviceToDeviceManager.h>
+// Unit test entry points, which are not used in the mDNSResponder runtime code paths.
+void BLE_unitTest(void);
-// Just define as the current max value for now.
-// TODO: Will need to define in DeviceToDeviceManager.framework if we convert this
-// BLE discovery code to a D2D plugin.
-#define D2DBLETransport D2DTransportMax
+#endif // UNIT_TEST
-#define applyToBLE(interface, flags) ((interface == mDNSInterface_BLE) || ((interface == mDNSInterface_Any) && (flags & kDNSServiceFlagsAutoTrigger)))
+#endif // ENABLE_BLE_TRIGGERED_BONJOUR
#endif /* _BLE_H_ */
diff --git a/mDNSResponder/mDNSMacOSX/BonjourEvents.c b/mDNSResponder/mDNSMacOSX/BonjourEvents.c
index e06106e8..9456ab1c 100644
--- a/mDNSResponder/mDNSMacOSX/BonjourEvents.c
+++ b/mDNSResponder/mDNSMacOSX/BonjourEvents.c
@@ -21,7 +21,7 @@
#include <UserEventAgentInterface.h>
#include <stdio.h>
#include <stdlib.h>
-#include <asl.h>
+#include <os/log.h>
#include <xpc/xpc.h>
@@ -344,19 +344,19 @@ static void ManageEventsCallback(UserEventAgentLaunchdAction action, CFNumberRef
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__);
+ os_log_info(OS_LOG_DEFAULT, "%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__);
+ os_log_info(OS_LOG_DEFAULT, "%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__);
+ os_log_info(OS_LOG_DEFAULT, "%s:%s unknown callback event\n", sPluginIdentifier, __FUNCTION__);
}
}
@@ -443,13 +443,13 @@ void AddEventToPlugin(BonjourUserEventsPlugin* plugin, CFNumberRef launchdToken,
// Add to the correct dictionary.
if (onAdd)
{
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Adding browser to AddEvents", sPluginIdentifier, __FUNCTION__);
+ os_log_info(OS_LOG_DEFAULT, "%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__);
+ os_log_info(OS_LOG_DEFAULT, "%s:%s: Adding browser to RemoveEvents", sPluginIdentifier, __FUNCTION__);
AddEventDictionary(eventDictionary, plugin->_onRemoveEvents, browser);
}
@@ -484,26 +484,26 @@ void RemoveEventFromPlugin(BonjourUserEventsPlugin* plugin, CFNumberRef launchdT
if (onAddEvents)
{
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: Calling RemoveEventFromArray for OnAddEvents", sPluginIdentifier, __FUNCTION__);
+ os_log_info(OS_LOG_DEFAULT, "%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__);
+ os_log_info(OS_LOG_DEFAULT, "%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__);
+ os_log_info(OS_LOG_DEFAULT, "%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__);
+ os_log_info(OS_LOG_DEFAULT, "%s:%s: Removing the browser from RemoveEvents", sPluginIdentifier, __FUNCTION__);
CFDictionaryRemoveValue(plugin->_onRemoveEvents, browser);
}
}
@@ -531,12 +531,12 @@ void RemoveEventFromPlugin(BonjourUserEventsPlugin* plugin, CFNumberRef launchdT
// 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);
+ os_log_info(OS_LOG_DEFAULT, "%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);
+ os_log_info(OS_LOG_DEFAULT, "%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);
}
@@ -575,7 +575,7 @@ NetBrowserInfo* CreateBrowser(BonjourUserEventsPlugin* plugin, CFStringRef type,
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__);
+ os_log_info(OS_LOG_DEFAULT, "%s:%s: found a duplicate browser\n", sPluginIdentifier, __FUNCTION__);
browser = browsers[i];
NetBrowserInfoRetain(NULL, browser);
break;
@@ -663,11 +663,11 @@ void AddEventDictionary(CFDictionaryRef eventDict, CFMutableDictionaryRef allEve
{
eventsForBrowser = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFDictionarySetValue(allEventsDictionary, key, eventsForBrowser);
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s creating a new array", sPluginIdentifier, __FUNCTION__);
+ os_log_info(OS_LOG_DEFAULT, "%s:%s creating a new array", sPluginIdentifier, __FUNCTION__);
}
else
{
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s Incrementing refcount", sPluginIdentifier, __FUNCTION__);
+ os_log_info(OS_LOG_DEFAULT, "%s:%s Incrementing refcount", sPluginIdentifier, __FUNCTION__);
CFRetain(eventsForBrowser);
}
@@ -695,7 +695,7 @@ void RemoveEventFromArray(CFMutableArrayRef array, CFNumberRef launchdToken)
if (CFEqual(token, launchdToken)) // This is the same event?
{
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s found token", sPluginIdentifier, __FUNCTION__);
+ os_log_info(OS_LOG_DEFAULT, "%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.
}
@@ -704,7 +704,7 @@ void RemoveEventFromArray(CFMutableArrayRef array, CFNumberRef launchdToken)
++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__);
+ if (i == count) os_log_info(OS_LOG_DEFAULT, "%s:%s did not find token", sPluginIdentifier, __FUNCTION__);
}
#pragma mark -
@@ -751,7 +751,7 @@ void ServiceBrowserCallback (DNSServiceRef sdRef,
static int msgCount = 0;
if (msgCount < 1000)
{
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s Can not create CFString for serviceName %s", sPluginIdentifier, __FUNCTION__, serviceName);
+ os_log_info(OS_LOG_DEFAULT, "%s:%s Can not create CFString for serviceName %s", sPluginIdentifier, __FUNCTION__, serviceName);
msgCount++;
}
return;
@@ -759,12 +759,12 @@ void ServiceBrowserCallback (DNSServiceRef sdRef,
if (flags & kDNSServiceFlagsAdd)
{
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s calling HandleTemporaryEventsForService Add\n", sPluginIdentifier, __FUNCTION__);
+ os_log_info(OS_LOG_DEFAULT, "%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__);
+ os_log_info(OS_LOG_DEFAULT, "%s:%s calling HandleTemporaryEventsForService Remove\n", sPluginIdentifier, __FUNCTION__);
HandleTemporaryEventsForService(plugin, browser, cfServiceName, plugin->_onRemoveEvents);
}
@@ -804,7 +804,7 @@ void HandleTemporaryEventsForService(BonjourUserEventsPlugin* plugin, NetBrowser
// 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__);
+ os_log_info(OS_LOG_DEFAULT, "%s:%s HandleTemporaryEventsForService signal\n", sPluginIdentifier, __FUNCTION__);
CFNumberGetValue(token, kCFNumberLongLongType, &tokenUint64);
xpc_object_t jobRequest = _CFXPCCreateXPCObjectFromCFObject(dict);
@@ -903,7 +903,7 @@ NetBrowserInfo* NetBrowserInfoCreate(CFStringRef serviceType, CFStringRef domain
outObj->refCount = 1;
outObj->browserRef = browserRef;
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: created new object %p", sPluginIdentifier, __FUNCTION__, outObj);
+ os_log_info(OS_LOG_DEFAULT, "%s:%s: created new object %p", sPluginIdentifier, __FUNCTION__, outObj);
free(cServiceType);
@@ -927,7 +927,7 @@ const void* NetBrowserInfoRetain(CFAllocatorRef allocator, const void* info)
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);
+ os_log_info(OS_LOG_DEFAULT, "%s:%s: Incremented ref count on %p, count %d", sPluginIdentifier, __FUNCTION__, obj->browserRef, (int)obj->refCount);
return obj;
}
@@ -947,14 +947,14 @@ void NetBrowserInfoRelease(CFAllocatorRef allocator, const void* info)
if (obj->refCount == 1)
{
- asl_log(NULL, NULL, ASL_LEVEL_INFO, "%s:%s: DNSServiceRefDeallocate %p", sPluginIdentifier, __FUNCTION__, obj->browserRef);
+ os_log_info(OS_LOG_DEFAULT, "%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);
+ os_log_info(OS_LOG_DEFAULT, "%s:%s: Decremented ref count on %p, count %d", sPluginIdentifier, __FUNCTION__, obj->browserRef, (int)obj->refCount);
}
}
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/BonjourTop.xcodeproj/project.pbxproj b/mDNSResponder/mDNSMacOSX/BonjourTop/BonjourTop.xcodeproj/project.pbxproj
new file mode 100644
index 00000000..9f313d5f
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/BonjourTop.xcodeproj/project.pbxproj
@@ -0,0 +1,297 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ F22E4EBF1728621600876C2D /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F22E4EBE1728621600876C2D /* main.cpp */; };
+ F22E4EC11728621600876C2D /* BonjourTop.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = F22E4EC01728621600876C2D /* BonjourTop.1 */; };
+ F22E4EDF172863F100876C2D /* bjIPAddr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F22E4EDC1728635200876C2D /* bjIPAddr.cpp */; };
+ F22E4EE0172863FB00876C2D /* bjMACAddr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F22E4EC91728635200876C2D /* bjMACAddr.cpp */; };
+ F22E4EE1172863FE00876C2D /* bjsocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F22E4ED71728635200876C2D /* bjsocket.cpp */; };
+ F22E4EE21728640500876C2D /* bjstring.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F22E4EDB1728635200876C2D /* bjstring.cpp */; };
+ F22E4EE31728640800876C2D /* bjStringtoStringMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F22E4ED01728635200876C2D /* bjStringtoStringMap.cpp */; };
+ F22E4EE41728640C00876C2D /* BonjourTop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F22E4EDE1728635200876C2D /* BonjourTop.cpp */; };
+ F22E4EE51728640E00876C2D /* CaptureFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F22E4ECA1728635200876C2D /* CaptureFile.cpp */; };
+ F22E4EE61728641100876C2D /* CollectBy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F22E4ECC1728635200876C2D /* CollectBy.cpp */; };
+ F22E4EE71728641400876C2D /* DNSFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F22E4ED91728635200876C2D /* DNSFrame.cpp */; };
+ F22E4EE81728641800876C2D /* LLRBTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F22E4EC81728635200876C2D /* LLRBTree.cpp */; };
+ F22E4EE91728653E00876C2D /* Frame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F22E4ED51728635200876C2D /* Frame.cpp */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ F22E4EB91728621500876C2D /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ F22E4EC11728621600876C2D /* BonjourTop.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ F22E4EBB1728621500876C2D /* bonjourtop */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = bonjourtop; sourceTree = BUILT_PRODUCTS_DIR; };
+ F22E4EBE1728621600876C2D /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
+ F22E4EC01728621600876C2D /* BonjourTop.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = BonjourTop.1; sourceTree = "<group>"; };
+ F22E4EC71728635200876C2D /* bjtypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bjtypes.h; sourceTree = "<group>"; };
+ F22E4EC81728635200876C2D /* LLRBTree.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = LLRBTree.cpp; sourceTree = "<group>"; };
+ F22E4EC91728635200876C2D /* bjMACAddr.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = bjMACAddr.cpp; sourceTree = "<group>"; };
+ F22E4ECA1728635200876C2D /* CaptureFile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CaptureFile.cpp; sourceTree = "<group>"; };
+ F22E4ECB1728635200876C2D /* CollectBy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CollectBy.h; sourceTree = "<group>"; };
+ F22E4ECC1728635200876C2D /* CollectBy.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CollectBy.cpp; sourceTree = "<group>"; };
+ F22E4ECD1728635200876C2D /* bjstring.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bjstring.h; sourceTree = "<group>"; };
+ F22E4ECF1728635200876C2D /* bjMACAddr.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bjMACAddr.h; sourceTree = "<group>"; };
+ F22E4ED01728635200876C2D /* bjStringtoStringMap.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = bjStringtoStringMap.cpp; sourceTree = "<group>"; };
+ F22E4ED11728635200876C2D /* bjStringtoStringMap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bjStringtoStringMap.h; sourceTree = "<group>"; };
+ F22E4ED21728635200876C2D /* LLRBTree.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LLRBTree.h; sourceTree = "<group>"; };
+ F22E4ED31728635200876C2D /* Frame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Frame.h; sourceTree = "<group>"; };
+ F22E4ED41728635200876C2D /* CaptureFile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CaptureFile.h; sourceTree = "<group>"; };
+ F22E4ED51728635200876C2D /* Frame.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Frame.cpp; sourceTree = "<group>"; };
+ F22E4ED61728635200876C2D /* bjsocket.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bjsocket.h; sourceTree = "<group>"; };
+ F22E4ED71728635200876C2D /* bjsocket.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = bjsocket.cpp; sourceTree = "<group>"; };
+ F22E4ED81728635200876C2D /* DNSFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DNSFrame.h; sourceTree = "<group>"; };
+ F22E4ED91728635200876C2D /* DNSFrame.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DNSFrame.cpp; sourceTree = "<group>"; };
+ F22E4EDA1728635200876C2D /* BonjourTop.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BonjourTop.h; sourceTree = "<group>"; };
+ F22E4EDB1728635200876C2D /* bjstring.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = bjstring.cpp; sourceTree = "<group>"; };
+ F22E4EDC1728635200876C2D /* bjIPAddr.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = bjIPAddr.cpp; sourceTree = "<group>"; };
+ F22E4EDD1728635200876C2D /* bjIPAddr.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bjIPAddr.h; sourceTree = "<group>"; };
+ F22E4EDE1728635200876C2D /* BonjourTop.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = BonjourTop.cpp; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ F22E4EB81728621500876C2D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ F22E4EB21728621500876C2D = {
+ isa = PBXGroup;
+ children = (
+ F22E4EBD1728621500876C2D /* source */,
+ F22E4EBC1728621500876C2D /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ F22E4EBC1728621500876C2D /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ F22E4EBB1728621500876C2D /* bonjourtop */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ F22E4EBD1728621500876C2D /* source */ = {
+ isa = PBXGroup;
+ children = (
+ F22E4EDC1728635200876C2D /* bjIPAddr.cpp */,
+ F22E4EDD1728635200876C2D /* bjIPAddr.h */,
+ F22E4EC91728635200876C2D /* bjMACAddr.cpp */,
+ F22E4ECF1728635200876C2D /* bjMACAddr.h */,
+ F22E4ED71728635200876C2D /* bjsocket.cpp */,
+ F22E4ED61728635200876C2D /* bjsocket.h */,
+ F22E4EDB1728635200876C2D /* bjstring.cpp */,
+ F22E4ECD1728635200876C2D /* bjstring.h */,
+ F22E4ED01728635200876C2D /* bjStringtoStringMap.cpp */,
+ F22E4ED11728635200876C2D /* bjStringtoStringMap.h */,
+ F22E4EC71728635200876C2D /* bjtypes.h */,
+ F22E4EC01728621600876C2D /* BonjourTop.1 */,
+ F22E4EDE1728635200876C2D /* BonjourTop.cpp */,
+ F22E4EDA1728635200876C2D /* BonjourTop.h */,
+ F22E4ECA1728635200876C2D /* CaptureFile.cpp */,
+ F22E4ED41728635200876C2D /* CaptureFile.h */,
+ F22E4ECC1728635200876C2D /* CollectBy.cpp */,
+ F22E4ECB1728635200876C2D /* CollectBy.h */,
+ F22E4ED91728635200876C2D /* DNSFrame.cpp */,
+ F22E4ED81728635200876C2D /* DNSFrame.h */,
+ F22E4ED51728635200876C2D /* Frame.cpp */,
+ F22E4ED31728635200876C2D /* Frame.h */,
+ F22E4EC81728635200876C2D /* LLRBTree.cpp */,
+ F22E4ED21728635200876C2D /* LLRBTree.h */,
+ F22E4EBE1728621600876C2D /* main.cpp */,
+ );
+ path = source;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ F22E4EBA1728621500876C2D /* BonjourTop */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F22E4EC41728621600876C2D /* Build configuration list for PBXNativeTarget "BonjourTop" */;
+ buildPhases = (
+ F22E4EB71728621500876C2D /* Sources */,
+ F22E4EB81728621500876C2D /* Frameworks */,
+ F22E4EB91728621500876C2D /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = BonjourTop;
+ productName = BonjourTop;
+ productReference = F22E4EBB1728621500876C2D /* bonjourtop */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ F22E4EB31728621500876C2D /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0500;
+ ORGANIZATIONNAME = Apple;
+ };
+ buildConfigurationList = F22E4EB61728621500876C2D /* Build configuration list for PBXProject "BonjourTop" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = F22E4EB21728621500876C2D;
+ productRefGroup = F22E4EBC1728621500876C2D /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ F22E4EBA1728621500876C2D /* BonjourTop */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ F22E4EB71728621500876C2D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F22E4EE0172863FB00876C2D /* bjMACAddr.cpp in Sources */,
+ F22E4EE61728641100876C2D /* CollectBy.cpp in Sources */,
+ F22E4EE21728640500876C2D /* bjstring.cpp in Sources */,
+ F22E4EE41728640C00876C2D /* BonjourTop.cpp in Sources */,
+ F22E4EBF1728621600876C2D /* main.cpp in Sources */,
+ F22E4EE51728640E00876C2D /* CaptureFile.cpp in Sources */,
+ F22E4EE31728640800876C2D /* bjStringtoStringMap.cpp in Sources */,
+ F22E4EE1172863FE00876C2D /* bjsocket.cpp in Sources */,
+ F22E4EE81728641800876C2D /* LLRBTree.cpp in Sources */,
+ F22E4EE91728653E00876C2D /* Frame.cpp in Sources */,
+ F22E4EDF172863F100876C2D /* bjIPAddr.cpp in Sources */,
+ F22E4EE71728641400876C2D /* DNSFrame.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ F22E4EC21728621600876C2D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.9;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = macosx;
+ };
+ name = Debug;
+ };
+ F22E4EC31728621600876C2D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.9;
+ SDKROOT = macosx;
+ };
+ name = Release;
+ };
+ F22E4EC51728621600876C2D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ "OTHER_LDFLAGS[arch=*]" = "-lncurses";
+ PRODUCT_NAME = bonjourtop;
+ };
+ name = Debug;
+ };
+ F22E4EC61728621600876C2D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ "OTHER_LDFLAGS[arch=*]" = "-lncurses";
+ PRODUCT_NAME = bonjourtop;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ F22E4EB61728621500876C2D /* Build configuration list for PBXProject "BonjourTop" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F22E4EC21728621600876C2D /* Debug */,
+ F22E4EC31728621600876C2D /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ F22E4EC41728621600876C2D /* Build configuration list for PBXNativeTarget "BonjourTop" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F22E4EC51728621600876C2D /* Debug */,
+ F22E4EC61728621600876C2D /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = F22E4EB31728621500876C2D /* Project object */;
+}
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/BonjourTop.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/mDNSResponder/mDNSMacOSX/BonjourTop/BonjourTop.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 00000000..919434a6
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/BonjourTop.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:">
+ </FileRef>
+</Workspace>
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/BonjourTop.1 b/mDNSResponder/mDNSMacOSX/BonjourTop/source/BonjourTop.1
new file mode 100644
index 00000000..6836139c
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/BonjourTop.1
@@ -0,0 +1,79 @@
+.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples.
+.\"See Also:
+.\"man mdoc.samples for a complete listing of options
+.\"man mdoc for the short list of editing options
+.\"/usr/share/misc/mdoc.template
+.Dd 4/24/13 \" DATE
+.Dt BonjourTop 1 \" Program name and manual section number
+.Os Darwin
+.Sh NAME \" Section Header - required - don't modify
+.Nm BonjourTop,
+.\" The following lines are read in generating the apropos(man -k) database. Use only key
+.\" words here as the database is built based on the words here and in the .ND line.
+.Nm Other_name_for_same_program(),
+.Nm Yet another name for the same program.
+.\" Use .Nm macro to designate other names for the documented program.
+.Nd This line parsed for whatis database.
+.Sh SYNOPSIS \" Section Header - required - don't modify
+.Nm
+.Op Fl abcd \" [-abcd]
+.Op Fl a Ar path \" [-a path]
+.Op Ar file \" [file]
+.Op Ar \" [file ...]
+.Ar arg0 \" Underlined argument - use .Ar anywhere to underline
+arg2 ... \" Arguments
+.Sh DESCRIPTION \" Section Header - required - don't modify
+Use the .Nm macro to refer to your program throughout the man page like such:
+.Nm
+Underlining is accomplished with the .Ar macro like this:
+.Ar underlined text .
+.Pp \" Inserts a space
+A list of items with descriptions:
+.Bl -tag -width -indent \" Begins a tagged list
+.It item a \" Each item preceded by .It macro
+Description of item a
+.It item b
+Description of item b
+.El \" Ends the list
+.Pp
+A list of flags and their descriptions:
+.Bl -tag -width -indent \" Differs from above in tag removed
+.It Fl a \"-a flag as a list item
+Description of -a flag
+.It Fl b
+Description of -b flag
+.El \" Ends the list
+.Pp
+.\" .Sh ENVIRONMENT \" May not be needed
+.\" .Bl -tag -width "ENV_VAR_1" -indent \" ENV_VAR_1 is width of the string ENV_VAR_1
+.\" .It Ev ENV_VAR_1
+.\" Description of ENV_VAR_1
+.\" .It Ev ENV_VAR_2
+.\" Description of ENV_VAR_2
+.\" .El
+.Sh FILES \" File used or created by the topic of the man page
+.Bl -tag -width "/Users/joeuser/Library/really_long_file_name" -compact
+.It Pa /usr/share/file_name
+FILE_1 description
+.It Pa /Users/joeuser/Library/really_long_file_name
+FILE_2 description
+.El \" Ends the list
+.\" .Sh DIAGNOSTICS \" May not be needed
+.\" .Bl -diag
+.\" .It Diagnostic Tag
+.\" Diagnostic informtion here.
+.\" .It Diagnostic Tag
+.\" Diagnostic informtion here.
+.\" .El
+.Sh SEE ALSO
+.\" List links in ascending order by section, alphabetically within a section.
+.\" Please do not reference files that do not exist without filing a bug report
+.Xr a 1 ,
+.Xr b 1 ,
+.Xr c 1 ,
+.Xr a 2 ,
+.Xr b 2 ,
+.Xr a 3 ,
+.Xr b 3
+.\" .Sh BUGS \" Document known, unremedied bugs
+.\" .Sh HISTORY \" Document history if command behaves in a unique manner \ No newline at end of file
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/BonjourTop.cpp b/mDNSResponder/mDNSMacOSX/BonjourTop/source/BonjourTop.cpp
new file mode 100644
index 00000000..ff201c9f
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/BonjourTop.cpp
@@ -0,0 +1,2049 @@
+//
+// BonjourTop.cpp
+// TestTB
+//
+// Created by Terrin Eager on 9/26/12.
+//
+//
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <ncurses.h>
+
+#include "BonjourTop.h"
+#include "DNSFrame.h"
+#include "CaptureFile.h"
+#include "bjsocket.h"
+#include "bjstring.h"
+
+#include <sys/sysctl.h>
+#include <mach/mach.h>
+
+#define SERVICE_IPV4 0
+#define SERVICE_IPV6 1
+#define APP_IPV4 2
+#define APP_IPV6 3
+
+#define TRACE_PLATFORM_UNKNOWN 0
+#define TRACE_PLATFORM_OSX 1
+#define TRACE_PLATFORM_iOS 2
+#define TRACE_PLATFORM_APPLE_TV 3
+#define TRACE_PLATFORM_NON_APPLE_PLATFORM 4
+#define DISCOVERYD_TRACE_PLATFORM_OSX (1 | 0x80)
+#define DISCOVERYD_TRACE_PLATFORM_iOS (2 | 0x80)
+#define DISCOVERYD_TRACE_PLATFORM_APPLE_TV (3 | 0x80)
+#define DISCOVERYD_TRACE_PLATFORM_NON_APPLE_PLATFORM (4 | 0x80)
+
+int CDeviceNode::nCreateCount = 0;
+static integer_t Usage(void);
+
+char CVSFileNameExample[] ="BonjourTop";
+char DeviceNameExample[] ="BonjourTopDevice.csv";
+
+char Service2App[][50] = {
+ // Service_Name, Application_Name, Browse_OS_Type, Register_OS_Type
+ "_device-info._tcp.local.", "Device-Info", "?" , "?",
+ "_rfb._tcp.local.", "Finder", "X" , "?",
+ "_afpovertcp._tcp.local.", "Finder", "?" , "X",
+ "_adisk._tcp.local.", "Finder", "?" , "X",
+ "_odisk._tcp.local.", "Finder", "?" , "X",
+ "_smb._tcp.local.", "Finder", "X" , "X",
+ "_smb2._tcp.local.", "Finder", "X" , "X",
+ "_workstation._tcp.local.", "Finder", "X" , "X",
+ "_kerberos.", "Finder", "X" , "X",
+ "_nfs._tcp.local.", "Finder", "X" , "X",
+ "_ftp._tcp.local.", "Finder", "X" , "X",
+
+ "_appletv._tcp.local.", "AppleTV", "?" , "t",
+ "_appletv-v2._tcp.local.", "AppleTV", "?" , "?",
+ "_appletv-pair._tcp.local.", "AppleTV", "?" , "?",
+
+ "A", "LinkLocal", "?" , "?",
+ "AAAA", "LinkLocal", "?" , "?",
+ "*.ip6.arpa.", "LinkLocal", "?" , "?",
+ "*.arpa.", "LinkLocal", "?" , "?",
+
+ "_airplay._tcp.local.", "AirPlay", "?" , "t",
+ "_airplayTXT", "AirPlay","?" , "t",
+ "_raop._tcp.local.", "AirPlay","?" , "?",
+
+ "_ubd._tcp.local.", "Ubiquity", "?" , "?",
+ "_ubiquity._tcp.local.", "Ubiquity", "?" , "?",
+ "_ubiquityV1._tcp.local.", "Ubiquity", "?" , "?",
+ "_ubiquityV2._tcp.local.", "Ubiquity", "?" , "?",
+
+ " _ipps._tcp.local.", "Printing", "?" , "?",
+ "_ipp._tcp.local.", "Printing", "?" , "?",
+ "_ipps._tcp.local.", "Printing", "?" , "?",
+ "_ipp-tls._tcp.local.", "Printing", "?" , "?",
+ "_printer._tcp.local.", "Printing", "?" , "?",
+ "_scanner._tcp.local.", "Printing", "?" , "?",
+ "_pdl-datastream._tcp.local.", "Printing", "?" , "?",
+ "_fax-ipp._tcp.local.", "Printing", "?" , "?",
+
+ "_apple-mobdev._tcp.local.", "iTunes-WiFiSync","?" , "i",
+ "_daap._tcp.local.", "iTunes", "?" , "?",
+
+ "_sftp-ssh._tcp.local.", "Terminal", "?" , "X",
+ "_ssh._tcp.local.", "Terminal", "?" , "X",
+
+ "_sleep-proxy._udp.local.", "Sleep Proxy", "?" , "?",
+ "_keepalive._dns-sd._udp.local.","Sleep Proxy", "X" , "?",
+ "_services._dns-sd._udp.local.", "Services", "?" , "?",
+ "ANY *.ip6.arpa.", "Sleep Proxy", "?" , "?",
+ "ANY *.arpa.", "Sleep Proxy", "?" , "?",
+
+ "AirPort_presence._tcp.local.", "AirPort", "?" , "?",
+ "_airport._tcp.local.", "AirPort", "?" , "?",
+ "_presence._tcp.local.", "iChat", "X" , "X",
+ "_home-sharing._tcp.local.", "HomeSharing", "?" , "X",
+
+ "_ptp._tcp.local.", "iPhoto", "?" , "X",
+ "_ica-networking2._tcp.local.", "iPhoto", "X" , "X",
+ "_mobileiphoto._udp.local.", "iPhoto", "?" , "?",
+ "_mobileiphoto2._udp.local.", "iPhoto", "?" , "?",
+ "_dpap._tcp.local.", "iPhoto", "?" , "X",
+ "_airdrop._tcp.local.", "AirDrop", "?" , "?",
+ "_http._tcp.local.", "Safari", "X" , "X",
+ "_net-assistant._udp.local.","Apple Remote Desktop","X" , "X",
+ "_servermgr._tcp.local.", "OSX Server", "X" , "X",
+ ""
+};
+
+char DeviceInfo2DeviceOS[][50] = {
+ // deviceModel, deviceType
+ "MacBookAir", "X",
+ "MacBookPro", "X",
+ "Macmini", "X",
+ "iMac", "X",
+ "MacPro", "X",
+ "MacBook", "X",
+ "AAPLJ15", "X",
+ "AAPLJ41", "X",
+ "AAPLJ43", "X",
+ "AAPLJ45", "X",
+ "AAPLJ90", "X",
+ "AAPLJ17", "X",
+ "PowerMac", "X",
+
+
+ "J33AP", "t",
+ "J33iAP", "t",
+ "J71AP", "i",
+ "J72AP", "i",
+ "J75AP", "i",
+ "J85DEV", "i",
+ "K66AP", "t",
+ "N41AP", "i",
+ "N42AP", "i",
+ "N48AP", "i",
+ "N51AP", "i",
+ "N53AP", "i",
+ "N78AP", "i",
+ "P101AP", "i",
+ "P102AP", "i",
+ "P103AP", "i",
+ "P105AP", "i",
+ "P106AP", "i",
+ "P107AP", "i",
+ "AirPort", "b",
+ "TimeCapsule", "b",
+ ""
+};
+
+char Name2DeviceOS[][50] = {
+ // Name contains, osType
+ "iPhone", "i",
+ "phone", "i",
+ "Phone", "i",
+ "iPod", "i",
+ "iPad", "i",
+ "ipad", "i",
+ "Apple-TV", "t",
+ "AppleTV", "t",
+ "MacBook", "X",
+ "macbook", "X",
+ "iMac", "X",
+ "macmini", "X",
+ ""
+};
+
+BJ_UINT64 Hash(const char* pStr);
+BJ_UINT64 Hash2(char* pStr);
+
+
+CSocketStats::CSocketStats()
+{
+ Init();
+
+}
+void CSocketStats::Init()
+{
+ m_nFrameCount = 0;
+
+ m_nQuestionOnlyFrames = 0;
+ m_nAnswerOnlyFrames = 0;
+ m_nQandAFrames = 0;
+
+ m_SampleDay = 0;
+}
+
+void CSocketStats::Clear()
+{
+ Init();
+}
+
+CBonjourTop::CBonjourTop()
+{
+
+ m_bCursers = true;
+ m_pTcpDumpFileName = NULL;
+ m_pExportFileName = CVSFileNameExample;
+ m_DeviceFileName = DeviceNameExample;
+
+ m_nFrameCount = 0;
+ m_nTotalBytes = 0;
+
+ m_StartTime = m_EndTime = time(NULL);
+
+ m_SnapshotSeconds = 0;
+
+ m_MinAnswerCountForTruncatedFrames = 0;
+ m_AvgAnswerCountForTruncatedFrames = 0;
+ m_MaxAnswerCountForTruncatedFrames = 0;
+
+ window_size_changed = false;
+ m_bImportExportDeviceMap = false;
+
+ // loadup application mapping
+ for(int i=0; Service2App[i][0] != 0;)
+ {
+ BJString a(Service2App[i++]);
+
+ m_Service2AppMap.FindwithAddRecord(&a)->value = Service2App[i++];
+ m_Service2osBrowseMap.FindwithAddRecord(&a)->value = Service2App[i++];
+ m_Service2osRegisterMap.FindwithAddRecord(&a)->value = Service2App[i++];
+
+ }
+
+
+ m_CurrentDisplay = CBonjourTop::BJ_DISPLAY_APP;
+ // m_CurrentDisplay = CBonjourTop::BJ_DISPLAY_SERVICE;
+
+ Usage();
+
+}
+
+static int CbClearDataDevice(const void* pNode, const void*)
+{
+ CDeviceNode* pDeviceRecord = (CDeviceNode*)pNode;
+
+ pDeviceRecord->ClearData();
+ return 0;
+}
+
+void CBonjourTop::Reset()
+{
+ m_nFrameCount = 0;
+ m_nTotalBytes = 0;
+
+ m_MinAnswerCountForTruncatedFrames = 0;
+ m_AvgAnswerCountForTruncatedFrames = 0;
+ m_MaxAnswerCountForTruncatedFrames = 0;
+
+ m_StartTime = m_EndTime = time(NULL);
+
+ m_ServicePtrCache.ClearAll();
+ m_ApplPtrCache.ClearAll();
+
+ m_ServicePtrCacheIPv6.ClearAll();
+ m_ApplPtrCacheIPv6.ClearAll();
+
+ // Clear all data in the map
+ m_AppBreakdownIPv4OSX.clear();
+ m_AppBreakdownIPv4iOS.clear();
+ m_AppBreakdownIPv6OSX.clear();
+ m_AppBreakdownIPv6iOS.clear();
+
+ m_ServiceBreakdownIPv4OSX.clear();
+ m_ServiceBreakdownIPv4iOS.clear();
+ m_ServiceBreakdownIPv6OSX.clear();
+ m_ServiceBreakdownIPv6iOS.clear();
+
+ // Clear Socket Status
+ for (int i = 0; i < NUM_SOCKET_STATUS; i++)
+ {
+ m_SocketStatus[i].Clear();
+ }
+
+ for (int i = 0; i < HOURS_IN_DAY; i++)
+ {
+ for (int j = 0; j < MINUTES_IN_HOUR; j++)
+ {
+ m_MinSnapshot[i][j].Clear();
+ }
+ }
+
+ CDeviceNode* pDeviceNode = m_DeviceMap.GetRoot();
+ if (pDeviceNode)
+ {
+ pDeviceNode->CallBack(&CbClearDataDevice,NULL);
+ }
+
+}
+
+void CBonjourTop::SetIPAddr(const char* pStr)
+{
+ m_IPv4Addr.Set(pStr);
+
+}
+
+void CBonjourTop::UpdateRecord(CStringTree& Cache,CDNSRecord* pDNSRecord,BJString& RecordName,BJString& ServiceName,BJ_UINT32 nBytes,bool bGoodbye)
+{
+ BJ_UINT64 nHashValue = 0;
+ char deviceOS = '?';
+
+ nHashValue = Hash(RecordName.GetBuffer());
+ CStringNode* pRecord = Cache.Find(&nHashValue);
+ if (pRecord == NULL)
+ {
+ pRecord = (CStringNode*) Cache.FindwithAddRecord(&nHashValue);
+ strcpy(pRecord->m_Value, RecordName.GetBuffer());
+ }
+
+ if (pRecord == NULL)
+ return;
+ CDeviceNode dummyDevice;
+ CDeviceNode *device = &dummyDevice;
+ CIPDeviceNode *pipNode = m_IPtoNameMap.Find(&m_Frame.m_SourceIPAddress);
+
+ device = (pipNode)? pipNode->pDeviceNode : &dummyDevice;
+ pRecord->m_nBytes += 10 + nBytes;
+ deviceOS = device->GetDeviceOS();
+ device->frameTotal.Increment(m_nFrameCount);
+
+ if (pRecord->m_nLastFrameIndex != m_nFrameCount)
+ {
+ pRecord->m_nLastFrameIndex = m_nFrameCount;
+
+ pRecord->m_nFrames++;
+ if (deviceOS == 't' || deviceOS == 'i')
+ {
+ pRecord->m_nFramesiOS++;
+ }
+ else if (deviceOS == 'X')
+ {
+ pRecord->m_nFramesOSX++;
+ }
+ }
+
+ // Update Total Device Count
+ if (pRecord->m_DeviceTotalTree.Find(&m_Frame.m_SourceIPAddress) == NULL)
+ {
+ pRecord->m_nDeviceTotalCount++;
+ pRecord->m_DeviceTotalTree.FindwithAddRecord(&m_Frame.m_SourceIPAddress);
+ }
+
+ if (m_Frame.IsQueryFrame())
+ {
+ GetOSTypeFromQuery(pDNSRecord, ServiceName);
+ device->questionFrame.Increment(m_nFrameCount);
+ if (pRecord->m_nLastQueryFrameIndex != m_nFrameCount)
+ {
+ pRecord->m_nLastQueryFrameIndex = m_nFrameCount;
+
+ pRecord->m_nQuestionFrames++;
+
+ if (deviceOS == 't' || deviceOS == 'i')
+ {
+ pRecord->m_nQuestionFramesiOS++;
+ }
+ else if (deviceOS == 'X')
+ {
+ pRecord->m_nQuestionFramesOSX++;
+ }
+
+ if (pRecord->m_DeviceAskingTree.Find(&m_Frame.m_SourceIPAddress) == NULL)
+ {
+ pRecord->m_nDeviceAskingCount++;
+ pRecord->m_DeviceAskingTree.FindwithAddRecord(&m_Frame.m_SourceIPAddress);
+ }
+ }
+ }
+ else
+ {
+ GetOSTypeFromRegistration(pDNSRecord,ServiceName);
+
+ device->answerFrame.Increment(m_nFrameCount);
+ if (pRecord->m_nLastRespondsFrameIndex != m_nFrameCount)
+ {
+ pRecord->m_nLastRespondsFrameIndex = m_nFrameCount;
+
+ pRecord->m_nAnswerFrames++;
+ if (deviceOS == 't' || deviceOS == 'i')
+ {
+ pRecord->m_nAnswerFramesiOS++;
+ }
+ else if (deviceOS == 'X')
+ {
+ pRecord->m_nAnswerFramesOSX++;
+ }
+
+ if (bGoodbye)
+ {
+ pRecord->m_nGoodbyeFrames++;
+ }
+
+ if (pRecord->m_DeviceAnsweringTree.Find(&m_Frame.m_SourceIPAddress) == NULL)
+ {
+ pRecord->m_nDeviceAnsweringCount++;
+ pRecord->m_DeviceAnsweringTree.FindwithAddRecord(&m_Frame.m_SourceIPAddress);
+ }
+ }
+ }
+
+ if (m_Frame.IsWakeFrame())
+ {
+ if (pRecord->m_nLastWakeFrameIndex != m_nFrameCount)
+ {
+ pRecord->m_nLastWakeFrameIndex = m_nFrameCount;
+ if (pRecord->m_lastQUFrameTime +1000000ll < m_Frame.GetTime() || pRecord->m_lastQUFrameTime == 0) // last qu frame has been over 1 sec
+ {
+ pRecord->m_nWakeFrames++;
+ pRecord->m_lastQUFrameTime = m_Frame.GetTime();
+ device->QUFrame.Increment(m_nFrameCount);
+ }
+ pRecord->m_lastQUFrameTime = m_Frame.GetTime();
+ }
+ }
+
+
+}
+
+void CBonjourTop::UpdateShortRecordHelper(BJ_UINT32 cacheType, BJ_UINT32 tracePlatform, BJ_UINT32 traceVersion, char deviceOS, CDNSRecord* pDNSRecord,BJString& RecordName,BJString& ServiceName,BJ_UINT32 nBytes,bool bGoodbye)
+{
+ bool isOSX = false;
+ BJString versionNumber = "mDNSResponder-";
+ const int version_max_length = 11; // largest number is 0xffffffff = 4294967295
+ char versionChar[version_max_length];
+
+ CStringShortTree *cache;
+ map<BJString, CStringShortTree*>* myMap;
+
+ if ((tracePlatform | 0x80) == tracePlatform)
+ {
+ versionNumber = "Discoveryd-";
+ }
+
+ snprintf(versionChar, sizeof(versionChar), "%u", 0); // Set versionChar to "0" by default
+ if (tracePlatform == TRACE_PLATFORM_UNKNOWN) // Pre iOS 7 or Pre OSX 10.9
+ {
+ if (deviceOS == 'i' || deviceOS == 't') // Pre iOS 7
+ {
+ isOSX = false;
+ }
+ else if (deviceOS == 'X') // Pre OSX 10.9
+ {
+ isOSX = true;
+ }
+ }
+ else if ((tracePlatform == TRACE_PLATFORM_OSX) || (tracePlatform == DISCOVERYD_TRACE_PLATFORM_OSX)) // >= OSX 10.9
+ {
+ isOSX = true;
+ snprintf(versionChar, sizeof(versionChar), "%u", traceVersion);
+ }
+ else if ((tracePlatform == TRACE_PLATFORM_iOS) || (tracePlatform == DISCOVERYD_TRACE_PLATFORM_iOS)) // >= iOS 7.x
+ {
+ isOSX = false;
+ snprintf(versionChar, sizeof(versionChar), "%u", traceVersion);
+ }
+ else if ((tracePlatform == TRACE_PLATFORM_APPLE_TV) || (tracePlatform == DISCOVERYD_TRACE_PLATFORM_APPLE_TV))
+ {
+ snprintf(versionChar, sizeof(versionChar), "%u", traceVersion);
+ }
+
+ versionNumber += (const char*)versionChar;
+
+ switch (cacheType) {
+ case SERVICE_IPV4:
+ if (isOSX)
+ {
+ myMap = &m_ServiceBreakdownIPv4OSX;
+ }
+ else
+ {
+ myMap = &m_ServiceBreakdownIPv4iOS;
+ }
+ break;
+ case SERVICE_IPV6:
+ if (isOSX)
+ {
+ myMap = &m_ServiceBreakdownIPv6OSX;
+ }
+ else
+ {
+ myMap = &m_ServiceBreakdownIPv6iOS;
+ }
+ break;
+ case APP_IPV4:
+ if (isOSX)
+ {
+ myMap = &m_AppBreakdownIPv4OSX;
+ }
+ else
+ {
+ myMap = &m_AppBreakdownIPv4iOS;
+ }
+ break;
+ case APP_IPV6:
+ if (isOSX)
+ {
+ myMap = &m_AppBreakdownIPv6OSX;
+ }
+ else
+ {
+ myMap = &m_AppBreakdownIPv6iOS;
+ }
+ break;
+
+ default:
+ return;
+ break;
+ }
+
+ if (myMap->find(versionNumber) == myMap->end()) // Version number not found. Create new record
+ {
+ myMap->insert(std::pair<BJString, CStringShortTree*>(versionNumber, new CStringShortTree()));
+ }
+ cache = (*myMap)[versionNumber];
+ UpdateShortRecord(cache, pDNSRecord, RecordName, ServiceName, nBytes, bGoodbye);
+}
+
+void CBonjourTop::UpdateShortRecord(CStringShortTree* Cache,CDNSRecord* pDNSRecord,BJString& RecordName,BJString& ServiceName,BJ_UINT32 nBytes,bool bGoodbye)
+{
+ if (Cache == NULL)
+ {
+ return;
+ }
+
+ BJ_UINT64 nHashValue = 0;
+ char deviceOS = '?';
+
+ nHashValue = Hash(RecordName.GetBuffer());
+ CStringShortNode* pRecord = Cache->Find(&nHashValue);
+ if (pRecord == NULL)
+ {
+ pRecord = (CStringShortNode*) Cache->FindwithAddRecord(&nHashValue);
+ strcpy(pRecord->m_Value, RecordName.GetBuffer());
+ }
+
+ if (pRecord == NULL)
+ {
+ return;
+ }
+
+ CDeviceNode dummyDevice;
+ CDeviceNode *device = &dummyDevice;
+ CIPDeviceNode *pipNode = m_IPtoNameMap.Find(&m_Frame.m_SourceIPAddress);
+
+ device = (pipNode)? pipNode->pDeviceNode : &dummyDevice;
+ pRecord->m_nBytes += 10 + nBytes;
+ deviceOS = device->GetDeviceOS();
+ device->frameTotal.Increment(m_nFrameCount);
+
+ if (pRecord->m_nLastFrameIndex != m_nFrameCount)
+ {
+ pRecord->m_nLastFrameIndex = m_nFrameCount;
+ pRecord->m_nFrames++;
+ }
+
+ // Update Total Device Count
+ if (pRecord->m_DeviceTotalTree.Find(&m_Frame.m_SourceIPAddress) == NULL)
+ {
+ pRecord->m_nDeviceTotalCount++;
+ pRecord->m_DeviceTotalTree.FindwithAddRecord(&m_Frame.m_SourceIPAddress);
+ }
+
+ if (m_Frame.IsQueryFrame())
+ {
+ GetOSTypeFromQuery(pDNSRecord, ServiceName);
+ device->questionFrame.Increment(m_nFrameCount);
+ if (pRecord->m_nLastQueryFrameIndex != m_nFrameCount)
+ {
+ pRecord->m_nLastQueryFrameIndex = m_nFrameCount;
+
+ pRecord->m_nQuestionFrames++;
+
+ if (pRecord->m_DeviceAskingTree.Find(&m_Frame.m_SourceIPAddress) == NULL)
+ {
+ pRecord->m_nDeviceAskingCount++;
+ pRecord->m_DeviceAskingTree.FindwithAddRecord(&m_Frame.m_SourceIPAddress);
+ }
+
+ }
+ }
+ else
+ {
+ GetOSTypeFromRegistration(pDNSRecord,ServiceName);
+
+ device->answerFrame.Increment(m_nFrameCount);
+ if (pRecord->m_nLastRespondsFrameIndex != m_nFrameCount)
+ {
+ pRecord->m_nLastRespondsFrameIndex = m_nFrameCount;
+
+ pRecord->m_nAnswerFrames++;
+
+ if (bGoodbye)
+ {
+ pRecord->m_nGoodbyeFrames++;
+ }
+
+ if (pRecord->m_DeviceAnsweringTree.Find(&m_Frame.m_SourceIPAddress) == NULL)
+ {
+ pRecord->m_nDeviceAnsweringCount++;
+ pRecord->m_DeviceAnsweringTree.FindwithAddRecord(&m_Frame.m_SourceIPAddress);
+ }
+ }
+ }
+
+ if (m_Frame.IsWakeFrame())
+ {
+ if (pRecord->m_nLastWakeFrameIndex != m_nFrameCount)
+ {
+ pRecord->m_nLastWakeFrameIndex = m_nFrameCount;
+ if (pRecord->m_lastQUFrameTime +1000000ll < m_Frame.GetTime() || pRecord->m_lastQUFrameTime == 0) // last qu frame has been over 1 sec
+ {
+ pRecord->m_nWakeFrames++;
+ pRecord->m_lastQUFrameTime = m_Frame.GetTime();
+ device->QUFrame.Increment(m_nFrameCount);
+ }
+ pRecord->m_lastQUFrameTime = m_Frame.GetTime();
+ }
+ }
+
+
+}
+
+void CBonjourTop::GetOSTypeFromQuery(CDNSRecord *pDNSRecord,BJString& ServiceName)
+{
+ if (pDNSRecord->m_RecType == DNS_TYPE_PTR)
+ {
+ StringMapNode* pStringNode = m_Service2osBrowseMap.Find(&ServiceName);
+ if (pStringNode && *pStringNode->value.GetBuffer() != '?')
+ {
+ CIPDeviceNode *ipNode = m_IPtoNameMap.FindwithAddRecord(&m_Frame.m_SourceIPAddress);
+ if (ipNode->pDeviceNode)
+ {
+ StringMapNode* pStringNode_temp = m_Service2osBrowseMap.Find(&ServiceName);
+ ipNode->pDeviceNode->SetDeviceOS(*pStringNode_temp->value.GetBuffer(),ServiceName.GetBuffer());
+ }
+ }
+ }
+}
+
+void CBonjourTop::GetOSTypeFromRegistration(CDNSRecord *pDNSRecord,BJString& ServiceName)
+{
+ CDeviceNode* deviceNode = NULL;
+ BJString sDeviceName;
+
+ if (pDNSRecord->m_RecType == DNS_TYPE_PTR)
+ {
+ BJString sInstanceName;
+ pDNSRecord->GetRdata(sInstanceName,0,99);
+ CDNSRecord* pSRVRecord = m_Frame.FindAdditionRecord(sInstanceName, DNS_TYPE_SRV);
+ if (pSRVRecord)
+ {
+ pSRVRecord->GetRdata(sDeviceName,0,1);
+ }
+ else
+ {
+ sDeviceName = sInstanceName;
+ }
+ deviceNode = m_DeviceMap.Find(&sDeviceName);
+ }
+
+ // Name guess
+ if (Name2OSType(sDeviceName,deviceNode))
+ return;
+
+ StringMapNode* pStringNode = m_Service2osRegisterMap.Find(&ServiceName);
+
+ if (pStringNode == NULL || *pStringNode->value.GetBuffer() == '?')
+ return;
+
+
+
+ if (sDeviceName.GetLength() > 0)
+ {
+ // update global device table with os type
+ if (deviceNode)
+ {
+ deviceNode->SetDeviceOS(*pStringNode->value.GetBuffer(),ServiceName.GetBuffer());
+ }
+ }
+}
+bool CBonjourTop::Name2OSType(BJString name,CDeviceNode* device)
+{
+ if (device == NULL)
+ return false;
+ // try to set device type from common names
+ for (int i=0; Name2DeviceOS[i][0] != 0; i +=2)
+ {
+ if (name.Contains(Name2DeviceOS[i]))
+ {
+ device->SetDeviceOS(Name2DeviceOS[i+1][0], "Name Mapping");
+ return true;
+ }
+ }
+ return false;
+}
+void CBonjourTop::ProcessFrame(BJ_UINT8* pBuffer,BJ_INT32 nLength,BJ_UINT64 nFrameTime)
+{
+
+ m_Frame.ParseDNSFrame(pBuffer, nLength, nFrameTime);
+
+ if (m_Collection.IsValid())
+ {
+ // setup static collectby
+ CollectByPacketCount::nFrameIndex = m_nFrameCount;
+ CollectBySameSubnetDiffSubnet::bSameSubnet = m_Frame.m_SourceIPAddress.IsIPv6()? true: m_IPv4Addr.IsSameSubNet(&m_Frame.m_SourceIPAddress);
+ m_Collection.ProcessFrame(&m_Frame);
+ return;
+ }
+
+ if (m_Frame.IsTruncatedFrame())
+ {
+ if (m_Frame.GetAnswerCount() > 0)
+ {
+ if (m_AvgAnswerCountForTruncatedFrames)
+ {
+ m_AvgAnswerCountForTruncatedFrames += m_Frame.GetAnswerCount();
+ m_AvgAnswerCountForTruncatedFrames /=2;
+ }
+ else
+ m_AvgAnswerCountForTruncatedFrames += m_Frame.GetAnswerCount();
+
+ if (m_MinAnswerCountForTruncatedFrames > m_Frame.GetAnswerCount() || m_MinAnswerCountForTruncatedFrames == 0)
+ m_MinAnswerCountForTruncatedFrames = m_Frame.GetAnswerCount();
+ if (m_MaxAnswerCountForTruncatedFrames < m_Frame.GetAnswerCount())
+ m_MaxAnswerCountForTruncatedFrames = m_Frame.GetAnswerCount();
+
+ }
+ }
+
+ // find min snapshot bucket
+ time_t now = time(NULL);
+ struct tm* timeStruct = localtime(&now);
+ if (m_MinSnapshot[timeStruct->tm_hour][timeStruct->tm_min].m_SampleDay != timeStruct->tm_mday)
+ {
+ //Reset Snapshot 24 hour wrap around
+ m_MinSnapshot[timeStruct->tm_hour][timeStruct->tm_min].Init();
+ m_MinSnapshot[timeStruct->tm_hour][timeStruct->tm_min].m_SampleDay = timeStruct->tm_mday;
+
+ }
+ m_MinSnapshot[timeStruct->tm_hour][timeStruct->tm_min].m_nFrameCount++;
+
+ if (m_Frame.GetQuestionCount() == 0 && m_Frame.GetAnswerCount() > 0)
+ m_SocketStatus[0].m_nAnswerOnlyFrames++;
+ else if (m_Frame.GetQuestionCount() > 0 && m_Frame.GetAnswerCount() == 0)
+ m_SocketStatus[0].m_nQuestionOnlyFrames++;
+ else
+ m_SocketStatus[0].m_nQandAFrames++;
+
+ BJString InstanceName;
+ BJString RecordName;
+ BJString ApplRecordName;
+
+ /// first get the name to address
+ for (int dnsItemsIndex =m_Frame.GetQuestionCount(); dnsItemsIndex < m_Frame.GetMaxRecords();dnsItemsIndex++)
+ {
+ CDNSRecord* pDNSRecord = m_Frame.GetDnsRecord(dnsItemsIndex);
+ if (pDNSRecord == NULL)
+ continue;
+
+ if (pDNSRecord->m_RecType == DNS_TYPE_A)
+ {
+ BJString sName;
+ pDNSRecord->GetDnsRecordName(sName, 0, 1);
+ BJIPAddr ip;
+ ip.Setv4Raw(pDNSRecord->GetStartofRdata());
+
+ CDeviceNode* device = m_DeviceMap.FindwithAddRecord(&sName);
+ device->ipAddressv4 = ip;
+
+ // create ip to name mapping
+ CIPDeviceNode* pipNode = m_IPtoNameMap.FindwithAddRecord(&ip);
+
+ if (pipNode->pDeviceNode && pipNode->pDeviceNode->bIPName && pipNode->pDeviceNode->m_Key != device->m_Key)
+ {
+ pipNode->pDeviceNode->bDuplicate = true;
+ device->MergeData(pipNode->pDeviceNode);
+ pipNode->pDeviceNode->ClearData();
+ // remap IPv6
+ if (!pipNode->pDeviceNode->ipAddressv6.IsEmpty())
+ {
+ CIPDeviceNode* ipv6Node = m_IPtoNameMap.Find(&pipNode->pDeviceNode->ipAddressv6);
+ if (ipv6Node)
+ ipv6Node->pDeviceNode = device;
+ }
+ }
+
+ pipNode->pDeviceNode = device;
+ Name2OSType(sName,device);
+ }
+
+ if (pDNSRecord->m_RecType == DNS_TYPE_AAAA)
+ {
+ BJString sName;
+ pDNSRecord->GetDnsRecordName(sName, 0, 1);
+ BJIPAddr ip;
+ ip.Setv6Raw(pDNSRecord->GetStartofRdata());
+
+ if (ip.IsIPv6LinkLocal())
+ {
+ CDeviceNode* device = m_DeviceMap.FindwithAddRecord(&sName);
+ device->ipAddressv6 = ip;
+
+ // create ip to name mapping
+ CIPDeviceNode* pipNode = m_IPtoNameMap.FindwithAddRecord(&ip);
+
+ if (pipNode->pDeviceNode && pipNode->pDeviceNode->bIPName && pipNode->pDeviceNode->m_Key != device->m_Key)
+ {
+ pipNode->pDeviceNode->bDuplicate = true;
+ device->MergeData(pipNode->pDeviceNode);
+ pipNode->pDeviceNode->ClearData();
+ // remap IPv4
+ if (!pipNode->pDeviceNode->ipAddressv4.IsEmpty())
+ {
+ CIPDeviceNode* ipv4Node = m_IPtoNameMap.Find(&pipNode->pDeviceNode->ipAddressv4);
+ if (ipv4Node)
+ ipv4Node->pDeviceNode = device;
+ }
+ }
+
+ pipNode->pDeviceNode = device;
+ Name2OSType(sName,device);
+ }
+ }
+ if (pDNSRecord->m_RecType == DNS_TYPE_SRV)
+ { // Save SVR to Target
+ BJString sName;
+ pDNSRecord->GetDnsRecordName(sName, 0, 1);
+ StringMapNode *node = SVRtoDeviceName.FindwithAddRecord(&sName);
+ pDNSRecord->GetRdata(node->value, 0, 1);
+ }
+ }
+
+ CIPDeviceNode* pipNode = m_IPtoNameMap.FindwithAddRecord(&m_Frame.m_SourceIPAddress);
+ CDeviceNode* device = pipNode->pDeviceNode;
+ if (device == NULL)
+ {
+ // find the device by mac address
+ CMACAddrDeviceNode *macDevice = m_MACtoDevice.FindwithAddRecord(&m_Frame.m_SourceMACAddress);
+ device = macDevice->device;
+ if (device == NULL)
+ {
+ // auto create a device record
+ BJString name = m_Frame.m_SourceIPAddress.GetString();
+ device = m_DeviceMap.FindwithAddRecord(&name);
+ device->bIPName = true;
+ macDevice->device = device;
+ }
+
+ if (m_Frame.m_SourceIPAddress.IsIPv4())
+ device->ipAddressv4 = m_Frame.m_SourceIPAddress;
+ else
+ device->ipAddressv6 = m_Frame.m_SourceIPAddress;
+ if (device->macAddress.IsEmpty())
+ device->macAddress = m_Frame.m_SourceMACAddress;
+
+ pipNode->pDeviceNode = device;
+ }
+ device->bHasFrames = true;
+ // update mac address
+ if (m_Frame.IsQueryFrame() || device->GetDeviceOS() == 'i' ) // iOS don't use BSP so we can use SourceIP
+ {
+ if (m_Frame.m_SourceIPAddress.IsIPv4())
+ device->ipAddressv4 = m_Frame.m_SourceIPAddress;
+ if (m_Frame.m_SourceIPAddress.IsIPv6())
+ device->ipAddressv6 =m_Frame.m_SourceIPAddress;
+ device->macAddress = m_Frame.m_SourceMACAddress;
+ }
+
+ BJ_UINT8 traceplatform = TRACE_PLATFORM_UNKNOWN;
+ BJ_UINT32 traceversion = 0;
+ BJMACAddr traceMac;
+ if (device /*&& device->GetDeviceOS() == '?' */&& m_Frame.GetTracingInfo(traceplatform, traceversion, traceMac))
+ {
+ // printf("Tracing Data found platform=%d traceversion=%d\n",traceplatform,traceversion);
+ char platformMap[]= "?Xitw";
+ device->SetDeviceOS((traceplatform < 5) ? platformMap[traceplatform] : '?', "EDNS0 Trace");
+ if ((traceplatform == TRACE_PLATFORM_OSX) || (traceplatform == DISCOVERYD_TRACE_PLATFORM_OSX))
+ {
+ device->bOSXWithEDNSField = true;
+ }
+ else if ((traceplatform == TRACE_PLATFORM_iOS) || (traceplatform == DISCOVERYD_TRACE_PLATFORM_iOS))
+ {
+ device->biOSWithEDNSField = true;
+ }
+ }
+
+ for (int dnsItemsIndex =0; dnsItemsIndex < m_Frame.GetQuestionCount()+m_Frame.GetAnswerCount();dnsItemsIndex++)
+ {
+ RecordName = "";
+ ApplRecordName = "";
+ InstanceName = "";
+ // printf("Name = %s\n", GetDnsRecordName(&Frame,dnsItemsIndex,tempBuffer,sizeof(tempBuffer),0));
+
+ CDNSRecord* pDNSRecord = m_Frame.GetDnsRecord(dnsItemsIndex);
+ if (pDNSRecord == NULL)
+ continue;
+
+ pDNSRecord->GetDnsRecordName(RecordName,0,99);
+ InstanceName = RecordName;
+
+ if (RecordName.Contains("_kerberos."))
+ {
+ RecordName = "_kerberos.";
+ }
+ else
+ pDNSRecord->GetDnsRecordName(RecordName, (pDNSRecord->m_RecType == DNS_TYPE_PTR)?0:1,99);
+
+ if (pDNSRecord->m_RecType == DNS_TYPE_PTR)
+ {
+ if (RecordName.Contains(".ip6.arpa."))
+ RecordName = "*.ip6.arpa.";
+ else if (RecordName.Contains(".arpa."))
+ RecordName = "*.arpa.";
+ }
+ if (pDNSRecord->m_RecType == DNS_TYPE_A)
+ RecordName = "A";
+ if (pDNSRecord->m_RecType == DNS_TYPE_AAAA)
+ RecordName = "AAAA";
+ if (pDNSRecord->m_RecType == 255)
+ {
+ if (RecordName.Contains(".ip6.arpa."))
+ RecordName = "ANY *.ip6.arpa.";
+ else if (RecordName.Contains(".arpa."))
+ RecordName = "ANY *.arpa.";
+ else
+ RecordName = "Any";
+ }
+ if (RecordName.Contains("_sub."))
+ {
+ pDNSRecord->GetDnsRecordName(RecordName,2,99); /// skip first label and _sub. label
+ }
+
+ BJ_UINT32 nBytes = pDNSRecord->m_nNameLength + pDNSRecord->m_nRdataLen;
+
+ m_nTotalBytes += 10 + nBytes;
+
+ if (m_Frame.m_SourceIPAddress.IsIPv4())
+ {
+ UpdateRecord(m_ServicePtrCache,pDNSRecord,RecordName,RecordName, nBytes, (pDNSRecord->m_nTTL == 0));
+ UpdateShortRecordHelper(SERVICE_IPV4, traceplatform, traceversion, device->GetDeviceOS(), pDNSRecord, RecordName, RecordName, nBytes, (pDNSRecord->m_nTTL == 0));
+ }
+ else
+ {
+ UpdateRecord(m_ServicePtrCacheIPv6,pDNSRecord,RecordName,RecordName, nBytes, (pDNSRecord->m_nTTL == 0));
+ UpdateShortRecordHelper(SERVICE_IPV6, traceplatform, traceversion, device->GetDeviceOS(), pDNSRecord, RecordName, RecordName, nBytes, (pDNSRecord->m_nTTL == 0));
+ }
+
+ // Add application to cache
+ if (RecordName.GetLength() != 0)
+ {
+
+ ApplRecordName = RecordName;
+ StringMapNode* pNode;
+ pNode = m_Service2AppMap.Find(&ApplRecordName);
+ if (pNode && ApplRecordName.GetBuffer() != NULL)
+ {
+ ApplRecordName = pNode->value.GetBuffer();
+ if ( ApplRecordName == "Device-Info")
+ {
+ // find device record
+ BJString svrName;
+ pDNSRecord->GetDnsRecordName(svrName, 0, 1);
+ StringMapNode *nodeName = SVRtoDeviceName.Find(&svrName);
+
+ CDeviceNode* pDeviceNode = nodeName ? m_DeviceMap.Find(&nodeName->value) : NULL;
+
+ if (pDeviceNode)
+ {
+ BJString DeviceInfo;
+ DeviceInfo.Set((char*)pDNSRecord->GetStartofRdata(),MIN(pDNSRecord->m_nRdataLen,50));
+ char osType = '?';
+
+ for (int i=0; DeviceInfo2DeviceOS[i][0] != 0; i+=2)
+ {
+ if (DeviceInfo.Contains(DeviceInfo2DeviceOS[i]))
+ {
+ osType = *DeviceInfo2DeviceOS[i+1];
+ if (pDeviceNode->GetDeviceOS() != *DeviceInfo2DeviceOS[i])
+ {
+ pDeviceNode->SetDeviceOS(osType,"_device-info._tcp.local.");
+ pDeviceNode->SetModel(DeviceInfo2DeviceOS[i]);
+ }
+ break;
+ }
+ }
+
+
+ if (osType == 'X' || (pDeviceNode && pDeviceNode->GetDeviceOS() == 'X'))
+ ApplRecordName = "Finder";
+ if (osType == 't' || (pDeviceNode && pDeviceNode->GetDeviceOS() == 't'))
+ ApplRecordName = "AirPlay";
+
+ if (pDeviceNode && pDeviceNode->GetDeviceOS() == '?' && pDNSRecord->m_nRdataLen > 0)
+ {
+ BJString DeviceInfo_temp;
+ DeviceInfo_temp.Set((char*)pDNSRecord->GetStartofRdata(),MIN(pDNSRecord->m_nRdataLen,25));
+ }
+ }
+ }
+ }
+ else
+ {
+ ApplRecordName = "Other";
+ }
+
+ if (m_Frame.m_SourceIPAddress.IsIPv4())
+ {
+ UpdateRecord(m_ApplPtrCache,pDNSRecord,ApplRecordName,RecordName, nBytes, (pDNSRecord->m_nTTL == 0));
+ UpdateShortRecordHelper(APP_IPV4, traceplatform, traceversion, device->GetDeviceOS(), pDNSRecord, ApplRecordName, RecordName, nBytes, (pDNSRecord->m_nTTL == 0));
+
+ }
+ else
+ {
+ UpdateRecord(m_ApplPtrCacheIPv6,pDNSRecord,ApplRecordName,RecordName, nBytes, (pDNSRecord->m_nTTL == 0));
+ UpdateShortRecordHelper(APP_IPV6, traceplatform, traceversion, device->GetDeviceOS(), pDNSRecord, ApplRecordName, RecordName, nBytes, (pDNSRecord->m_nTTL == 0));
+ }
+
+ }
+
+ }
+}
+
+
+class CSortOptions
+{
+
+public:
+ CStringTree m_SortedCache;
+ int m_nSortCol;
+
+};
+static int CbPrintResults(const void* pNode, const void* pParam)
+{
+ CStringNode* pRecord = (CStringNode*)pNode;
+ CSortOptions* pSortedOption = (CSortOptions*)pParam;
+
+ CStringNode* pNewRecord;
+
+ BJ_UINT64 SortKey =0;
+ switch (pSortedOption->m_nSortCol) {
+ case 0:
+ SortKey = Hash2(pRecord->m_Value); // cheat the sort to the first 8 char
+ break;
+ case 1:
+ SortKey = pRecord->m_nBytes;
+ break;
+ case 2:
+ SortKey = pRecord->m_nFrames;
+ break;
+ case 3:
+ SortKey = pRecord->m_nQuestionFrames;
+ break;
+ case 4:
+ SortKey = pRecord->m_nAnswerFrames;
+ break;
+ default:
+ break;
+ }
+
+
+ pNewRecord = pSortedOption->m_SortedCache.AddRecord(&SortKey);
+
+ if (pNewRecord)
+ {
+ pNewRecord->CopyNode(pRecord);
+
+ }
+
+ return 0;
+}
+
+#if 0 // Not used
+static int CbPrintUnknownDevice(const void* pNode, const void*)
+{
+ CDeviceNode* pDeviceRecord = (CDeviceNode*)pNode;
+
+ if (pDeviceRecord->GetDeviceOS() != '?')
+ return 0;
+
+ // printf("%s %s\n",pDeviceRecord->m_Key.GetBuffer(), pDeviceRecord->macAddress.GetString());
+ return 0;
+
+}
+#endif
+
+static int CbBuildMacMap(const void* pNode, const void* pParam)
+{
+ CDeviceNode* pDeviceNode = (CDeviceNode*)pNode;
+ CMACAddrTree* pMacMap = (CMACAddrTree*)pParam;
+
+
+ BJMACAddr vendorMac;
+ vendorMac.CopyVendor(pDeviceNode->macAddress);
+ if (vendorMac.IsEmpty())
+ return 0;
+
+
+
+ if (pDeviceNode->GetDeviceOS() == '?')
+ {
+ // try to set device type from MAC address
+ CMACAddrNode* pMacRecord = pMacMap->Find(&vendorMac);
+ if (pMacRecord != NULL && pDeviceNode->GetDeviceOS() == '?')
+ {
+ pDeviceNode->SetDeviceOS(pMacRecord->deviceOS, "MAC Mapping");
+// printf("update device %s %c\n",vendorMac.GetStringVendor(),pMacRecord->deviceOS);
+ }
+
+ if (pDeviceNode->GetDeviceOS() == '?')
+ return 0;
+ }
+
+
+ CMACAddrNode* pMacRecord = pMacMap->Find(&vendorMac);
+ if (pMacRecord == NULL)
+ {
+ pMacRecord = pMacMap->FindwithAddRecord(&vendorMac);
+ pMacRecord->deviceOS = pDeviceNode->GetDeviceOS();
+ pMacRecord->model = pDeviceNode->model;
+ pMacRecord->method = pDeviceNode->settingService;
+ }
+ else
+ {
+ // Check mapping
+ /// if (pMacRecord && pMacRecord->deviceOS != pDeviceNode->GetDeviceOS())
+ // printf("Mac Mapping Bad deviceOS %c != %c %s %s %s\n", pMacRecord->deviceOS, pDeviceNode->GetDeviceOS(),pMacRecord->method.GetBuffer(), pDeviceNode->settingService.GetBuffer(),vendorMac.GetStringVendor());
+ // if (pMacRecord && !(pMacRecord->model == pDeviceNode->model) && pMacRecord->model.GetLength() > 0 && pDeviceNode->model.GetLength() > 0)
+ // printf("Mac Mapping Bad model %s != %s\n", pMacRecord->model.GetBuffer(), pDeviceNode->model.GetBuffer());
+
+ }
+ return 0;
+
+}
+
+CStringNode* CBonjourTop::GetCurrentDisplayRoot(BJString &sTitle)
+{
+ CStringNode* pRecord = NULL;
+
+ switch(m_CurrentDisplay)
+ {
+ case BJ_DISPLAY_APP:
+ pRecord = m_ApplPtrCache.GetRoot();
+ sTitle = "Application (IPv4)";
+ break;
+ case BJ_DISPLAY_APPv6:
+ pRecord = m_ApplPtrCacheIPv6.GetRoot();
+ sTitle = "Application (IPv6)";
+ break;
+ case BJ_DISPLAY_SERVICE:
+ pRecord = m_ServicePtrCache.GetRoot();
+ sTitle = "Services (IPv4)";
+ break;
+ case BJ_DISPLAY_SERVICEv6:
+ pRecord = m_ServicePtrCacheIPv6.GetRoot();
+ sTitle = "Services (IPv6)";
+ break;
+ case BJ_DISPLAY_24_MIN:
+ printf("Error");
+ break;
+ }
+ return pRecord;
+}
+void CBonjourTop::UpdateOSCounts()
+{
+
+
+ CDeviceNode* pDeviceNode = m_DeviceMap.GetRoot();
+ if (pDeviceNode)
+ {
+ pDeviceNode->CallBack(&CbBuildMacMap,&m_MacMap);
+ // pDeviceNode->CallBack(&CbPrintUnknownDevice,NULL);
+ }
+
+
+ // Update Application Caches
+ CStringNode* pCacheRoot = m_ApplPtrCache.GetRoot();
+
+ if (pCacheRoot)
+ {
+ pCacheRoot->UpdateOSTypeCounts(&m_DeviceMap,&m_IPtoNameMap);
+ }
+ pCacheRoot = m_ApplPtrCacheIPv6.GetRoot();
+
+ if (pCacheRoot)
+ {
+ pCacheRoot->UpdateOSTypeCounts(&m_DeviceMap,&m_IPtoNameMap);
+ }
+
+ // Update Service caches
+ pCacheRoot = m_ServicePtrCache.GetRoot();
+
+ if (pCacheRoot)
+ {
+ pCacheRoot->UpdateOSTypeCounts(&m_DeviceMap,&m_IPtoNameMap);
+ }
+ pCacheRoot = m_ServicePtrCacheIPv6.GetRoot();
+
+ if (pCacheRoot)
+ {
+ pCacheRoot->UpdateOSTypeCounts(&m_DeviceMap,&m_IPtoNameMap);
+ }
+
+
+}
+void CBonjourTop::PrintResults(int nSortCol, bool bSortAsc)
+{
+
+ BJString sTitle;
+ GetCurrentDisplayRoot(sTitle);
+ device_count devCount;
+ BJString sTableTitle;
+
+ UpdateOSCounts();
+
+ /////
+ BJ_UINT64 nRate = 0;
+ BJ_UINT64 nElapsedTime = m_EndTime-m_StartTime;
+ if (nElapsedTime > 0)
+ {
+ nRate = (m_nFrameCount *3600) /nElapsedTime;
+ }
+ if (m_bCursers)
+ {
+ resizeterm(0,0);
+ clear();
+
+ printw("While running the follow keys may be used:\n");
+ printw("[p = sort by Packets (default)], [b = sort by Bytes], [n = sort by Name]\n");
+ printw("[a = Display Application Names (default)], [s = Display Services Names], [t = Display 24 hour packet per min]\n");
+ printw("[o = flip sort order], [e = export to BonjourTop.csv], [q = quit]\n\n");
+
+ printw("Total Packets: %llu, Total Bytes: %llu, Elapse Time: %lld sec, Rate: %llu packet/hr\n",m_nFrameCount,m_nTotalBytes,nElapsedTime,nRate);
+ printw("IPv4 multicast: %llu, IPv6 multicast: %llu, IPv4 Unicast: %lld, IPv6 Unicast: %llu\n",m_SocketStatus[0].m_nFrameCount,m_SocketStatus[1].m_nFrameCount,m_SocketStatus[2].m_nFrameCount,m_SocketStatus[3].m_nFrameCount);
+ printw("IPv4 Wrong subnet: %llu, IPv6 Wrong subnet: %llu\n",m_SocketStatus[4].m_nFrameCount,m_SocketStatus[5].m_nFrameCount);
+ printw("QuestionOnly Packets: %llu, AnswerOnly Packets: %llu, Q&A Packets %llu\n",m_SocketStatus[0].m_nQuestionOnlyFrames,m_SocketStatus[0].m_nAnswerOnlyFrames,m_SocketStatus[0].m_nQandAFrames);
+ printw("AnswerCount for truncated frames(min,avg,max): %llu,%llu,%llu\n\n",m_MinAnswerCountForTruncatedFrames,m_AvgAnswerCountForTruncatedFrames,m_MaxAnswerCountForTruncatedFrames);
+
+ bzero(&devCount, sizeof(devCount));
+ m_DeviceMap.GetDeviceOSTypes(m_DeviceMap.GetRoot(),NULL, devCount);
+ printw("Total Devices: %llu, iOS Devices: %llu(>= iOS7: %llu), OSX Devices %llu(>= OSX 10.9: %llu)\n",devCount.iOS+devCount.OSX+devCount.unknownOS,devCount.iOS, devCount.iOSWithEDNSField, devCount.OSX,devCount.OSXWithEDNSField);
+ }
+ else
+ {
+ printf("\nTotal Packets: %llu, Total Bytes: %llu, Elapse Time: %lld sec, Rate: %llu packet/hr\n",m_nFrameCount,m_nTotalBytes,nElapsedTime,nRate);
+ printf("IPv4 multicast: %llu, IPv6 multicast: %llu, IPv4 Unicast: %lld, IPv6 Unicast: %llu\n",m_SocketStatus[0].m_nFrameCount,m_SocketStatus[1].m_nFrameCount,m_SocketStatus[2].m_nFrameCount,m_SocketStatus[3].m_nFrameCount);
+ printf("IPv4 Wrong subnet: %llu, IPv6 Wrong subnet: %llu\n",m_SocketStatus[4].m_nFrameCount,m_SocketStatus[5].m_nFrameCount);
+ printf("QuestionOnly Packets: %llu, AnswerOnly Packets: %llu, Q&A Packets %llu\n",m_SocketStatus[0].m_nQuestionOnlyFrames,m_SocketStatus[0].m_nAnswerOnlyFrames,m_SocketStatus[0].m_nQandAFrames);
+
+ bzero(&devCount, sizeof(devCount));
+ m_DeviceMap.GetDeviceOSTypes(m_DeviceMap.GetRoot(),NULL, devCount);
+
+ printf("Total Devices: %llu, iOS Devices: %llu(>= iOS7: %llu), OSX Devices %llu(>= OSX 10.9: %llu), unknown Devices %llu\n",devCount.iOS+devCount.OSX+devCount.unknownOS,devCount.iOS, devCount.iOSWithEDNSField,devCount.OSX,devCount.OSXWithEDNSField,devCount.unknownOS);
+ printf("AnswerCount for truncated frames(min,avg,max): %llu,%llu,%llu\n\n",m_MinAnswerCountForTruncatedFrames,m_AvgAnswerCountForTruncatedFrames,m_MaxAnswerCountForTruncatedFrames);
+ }
+ PrintDetailResults(nSortCol, bSortAsc);
+ if (m_bCursers)
+ refresh();
+}
+void CBonjourTop::PrintDetailResults(int nSortCol, bool bSortAsc)
+{
+ BJString sTitle;
+ CStringNode* pCacheRoot = GetCurrentDisplayRoot(sTitle);
+
+ if (m_bCursers)
+ {
+ if(m_CurrentDisplay == CBonjourTop::BJ_DISPLAY_24_MIN)
+ {
+ printw(" ");
+ for(int i=0;i<24;i++)
+ printw(" %02d ",i);
+ printw("\n");
+ }
+ else
+ {
+ printw("\n%s\n",sTitle.GetBuffer());
+ printw(" %- 30s %10s %10s%24s%24s%24s%24s%24s\n","","","Total","Question","Answer","Asking","Answering", "Total");
+ printw(" %- 30s %10s%24s%24s%24s %23s%24s%24s %11s %10s\n","Name","Bytes","Packets( iOS/ OSX)","Packets( iOS/ OSX)","Packets( iOS/ OSX)","Devices( iOS/ OSX)","Devices( iOS/ OSX)","Devices( iOS/ OSX)", "QU Bit","Goodbye");
+ }
+ }
+ else
+ {
+ if(m_CurrentDisplay == CBonjourTop::BJ_DISPLAY_24_MIN)
+ {
+
+ }
+ else
+ {
+ printf("\n%s\n",sTitle.GetBuffer());
+ printf(" %-30s %10s %10s%24s%24s%24s%24s%24s\n","","","Total","Question","Answer","Asking","Answering", "Total");
+ printf(" %-30s %10s%24s%24s%24s %23s%24s%24s %11s %10s\n","Name","Bytes","Packets( iOS/ OSX)","Packets( iOS/ OSX)","Packets( iOS/ OSX)","Devices( iOS/ OSX)","Devices( iOS/ OSX)","Devices( iOS/ OSX)", "QU Bit","Goodbye");
+ }
+ }
+ if (m_CurrentDisplay == CBonjourTop::BJ_DISPLAY_24_MIN)
+ {
+
+ for(int m=0;m<60;m++)
+ {
+ printw(" %02d ",m);
+ for (int h=0;h<24;h++)
+ printw("%5d ",m_MinSnapshot[h][m].m_nFrameCount);
+ printw("\n");
+ }
+ }
+ else
+ {
+ // sort list
+ CSortOptions SortOptions;
+ SortOptions.m_nSortCol = nSortCol;
+
+ if (pCacheRoot)
+ pCacheRoot->UpdateOSTypeCounts(&m_DeviceMap,&m_IPtoNameMap);
+
+ if (pCacheRoot)
+ pCacheRoot->CallBack(&CbPrintResults,&SortOptions);
+
+ // print list
+
+ CStringNode* pRecord = SortOptions.m_SortedCache.GetRoot();
+ BJ_UINT32 nIndex = 1;
+
+ if (pRecord)
+ pRecord->Print(m_bCursers,bSortAsc, nIndex,0,40);
+ }
+
+
+}
+
+void CBonjourTop::LiveCapture()
+{
+ /// Live Capture
+ const BJ_UINT16 BonjourPort = 5353;
+ BJSocket Sockv4;
+ BJSocket Sockv6;
+ BJSelect SockSelect;
+
+ Sockv4.CreateListenerIPv4(interfaceName);
+ Sockv6.CreateListenerIPv6(interfaceName);
+
+ SockSelect.Add(Sockv4);
+ SockSelect.Add(Sockv6);
+
+
+ m_StartTime = time(NULL);
+
+ bool bSortAsc = false;
+ int nSortCol = 1;
+
+ while (1)
+ {
+ SockSelect.Add(Sockv4);
+ SockSelect.Add(Sockv6);
+
+ int result = SockSelect.Wait(1);
+ if (result < 0)
+ {
+ // if SockSelect.Wait failed due to an interrupt, then we want to continue processing the packets
+ if (errno == EINTR)
+ {
+ continue;
+ }
+ printf("Error in Select\n");
+ break;
+ }
+
+ if (SockSelect.IsReady(Sockv4))
+ {
+
+ int recvsize = Sockv4.Read();
+
+ if ((recvsize != 0) &&
+ (Sockv4.GetSrcAddr()->GetPortNumber() == BonjourPort))
+ {
+ m_nFrameCount++;
+ m_SocketStatus[Sockv4.IsMulticastPacket()? 0:2].m_nFrameCount++;
+
+ if (!m_IPv4Addr.IsSameSubNet(Sockv4.GetSrcAddr()))
+ {
+ m_SocketStatus[4].m_nFrameCount++;
+ }
+ m_Frame.m_SourceIPAddress = *Sockv4.GetSrcAddr();
+ ProcessFrame(Sockv4.GetBuffer(),recvsize,Sockv4.m_CurrentFrame.GetTime());
+ }
+ }
+
+ if (SockSelect.IsReady(Sockv6))
+ {
+ int recvsize = Sockv6.Read();
+ if ((recvsize != 0) &&
+ (Sockv6.GetSrcAddr()->GetPortNumber() == BonjourPort))
+ {
+ m_nFrameCount++;
+ m_SocketStatus[Sockv6.IsMulticastPacket()? 1:3].m_nFrameCount++;
+ m_Frame.m_SourceIPAddress = *Sockv6.GetSrcAddr();
+
+ ProcessFrame(Sockv6.GetBuffer(),recvsize,Sockv6.m_CurrentFrame.GetTime());
+ }
+ }
+
+ if (m_bCursers)
+ {
+ int ch = getch();
+ switch (ch)
+ {
+ case 'o':
+ bSortAsc = !bSortAsc;
+ result = 0; // force an update
+ break;
+ case 'n':
+ nSortCol = 0;
+ result = 0; // force an update
+ break;
+ case 'b':
+ nSortCol = 1;
+ result = 0; // force an update
+ break;
+ case 'p':
+ if (nSortCol == 2)
+ nSortCol = 3;
+ else if (nSortCol == 3)
+ nSortCol = 4;
+ else
+ nSortCol = 2;
+ result = 0; // force an update
+ break;
+ case 'a':
+ case 'A':
+ if (m_CurrentDisplay == CBonjourTop::BJ_DISPLAY_APP)
+ m_CurrentDisplay = CBonjourTop::BJ_DISPLAY_APPv6;
+ else
+ m_CurrentDisplay = CBonjourTop::BJ_DISPLAY_APP;
+
+ result = 0;
+ break;
+ case 's':
+ case 'S':
+ if (m_CurrentDisplay == CBonjourTop::BJ_DISPLAY_SERVICE)
+ m_CurrentDisplay = CBonjourTop::BJ_DISPLAY_SERVICEv6;
+ else
+ m_CurrentDisplay = CBonjourTop::BJ_DISPLAY_SERVICE;
+ result = 0;
+ break;
+ case 't':
+ case 'T':
+ m_CurrentDisplay = CBonjourTop::BJ_DISPLAY_24_MIN;
+ result = 0;
+ break;
+ case 'q':
+ return;
+ case 'e':
+ ExportResults();
+ printf("\a");
+ break;
+ case KEY_RESIZE:
+ endwin();
+ initscr();
+ result = 0; // force an update
+ break;
+ case KEY_DOWN:
+ result = 0; // force an update
+ break;
+ }
+ if (window_size_changed)
+ {
+ endwin();
+ initscr();
+ window_size_changed = false;
+ }
+ }
+ if (m_EndTime != time(NULL) || result == 0)
+ {
+ m_EndTime = time(NULL);
+ PrintResults(nSortCol,bSortAsc);
+ if (m_SnapshotSeconds && (time(NULL) - m_StartTime) > m_SnapshotSeconds)
+ {
+ ExportResults();
+ if (m_bImportExportDeviceMap)
+ {
+ WriteDeviceFile();
+ WriteVendorFile();
+ }
+ Reset();
+ }
+ }
+ }
+}
+
+
+
+void CBonjourTop::CaptureFile()
+{
+ CCaptureFile CaptureFile;
+ BJIPAddr* pIPSrcAddr;
+ BJIPAddr* pIPDestAddr;
+
+ CIPAddrMap LocalSubnetIPv6;
+
+
+ CaptureFile.Open(m_pTcpDumpFileName);
+
+ m_StartTime = 0;
+ int nFrameIndex = 0;
+
+ while (CaptureFile.NextFrame())
+ {
+ nFrameIndex++;
+
+ BJ_UINT8* pBonjourBuffer = (BJ_UINT8*)CaptureFile.m_CurrentFrame.GetBonjourStart();
+ if (!pBonjourBuffer)
+ continue;
+
+ m_nFrameCount++;
+ m_nTotalBytes += CaptureFile.GetWiredLength();
+
+ pIPSrcAddr = CaptureFile.m_CurrentFrame.GetSrcIPAddr();
+ pIPDestAddr = CaptureFile.m_CurrentFrame.GetDestIPAddr();
+ m_Frame.m_SourceIPAddress = *CaptureFile.m_CurrentFrame.GetSrcIPAddr();;
+ m_Frame.m_SourceMACAddress = *CaptureFile.m_CurrentFrame.GetSrcMACAddr();
+
+ if (pIPSrcAddr->IsIPv4())
+ {
+ // check fragment flag
+ BJ_UINT8* pIP = CaptureFile.m_CurrentFrame.GetIPStart();
+ BJ_UINT16 flags = * ((BJ_UINT16*)(pIP+6));
+ if (flags)
+ continue;
+
+ if (!m_IPv4Addr.IsEmptySubnet())
+ {
+ if (m_IPv4Addr.IsSameSubNet(pIPSrcAddr))
+ {
+ BJ_UINT8* pSourceMac = CaptureFile.m_CurrentFrame.GetEthernetStart()+6;
+ BJIPAddr IPv6Addr;
+ IPv6Addr.CreateLinkLocalIPv6(pSourceMac);
+ LocalSubnetIPv6.FindwithAddRecord(&IPv6Addr);
+
+ }
+ else
+ {
+ m_SocketStatus[4].m_nFrameCount++;
+
+ if (!m_Collection.IsValid())
+ continue;
+ }
+ }
+ m_SocketStatus[(pIPDestAddr->IsBonjourMulticast())?0:2].m_nFrameCount++;
+ }
+ if (pIPSrcAddr->IsIPv6())
+ {
+ if (!LocalSubnetIPv6.Find(pIPSrcAddr) && !m_IPv4Addr.IsEmptySubnet())
+ {
+ m_SocketStatus[5].m_nFrameCount++;
+ if (!m_Collection.IsValid())
+ continue;
+ }
+ m_SocketStatus[(pIPDestAddr->IsBonjourMulticast())?1:3].m_nFrameCount++;
+ }
+
+ ProcessFrame(pBonjourBuffer,CaptureFile.GetBufferLen((pBonjourBuffer)),CaptureFile.m_CurrentFrame.GetTime());
+
+ }
+ m_EndTime = CaptureFile.GetDeltaTime();
+
+ PrintResults(2,false);
+ if ( m_CurrentDisplay == BJ_DISPLAY_APP)
+ m_CurrentDisplay = BJ_DISPLAY_APPv6;
+ else
+ m_CurrentDisplay = BJ_DISPLAY_SERVICEv6;
+
+ PrintDetailResults(2,false);
+
+}
+
+void CBonjourTop::ExportPtrCache(FILE* hFile, BJString sTitle,CStringNode* pRoot)
+{
+ fprintf(hFile,"%s\n",sTitle.GetBuffer());
+ fprintf(hFile,"Name,Bytes,Total Packets,Total Packets iOS,Total Packets OSX,Question Packets,Question Packets iOS,Question Packets OSX,Answer Packets,Answer Packets iOS,Answer Packets OSX,Asking Devices, Asking Devices iOS,Asking Devices OSX,Answering Devices,Answering Devices iOS,Answering Devices OSX,Total Devices,Total Devices iOS, Total Devices OSX,QU Bit,Goodbye\n");
+
+ if (pRoot)
+ pRoot->Export(hFile);
+}
+
+void CBonjourTop::ExportShortCacheHelper(FILE* hFile, BJString sTitle, CStringShortNode* pRoot)
+{
+ fprintf(hFile,"%s\n",sTitle.GetBuffer());
+ fprintf(hFile,"Name,Bytes,Total Packets,Question Packets,Answer Packets,Asking Devices,Answering Devices,Total Devices,QU Bit,Goodbye\n");
+
+ if (pRoot)
+ {
+ pRoot->Export(hFile);
+ }
+
+}
+
+void CBonjourTop::ExportShortCache(FILE* hFile, BJString sTitle, map<BJString, CStringShortTree*>* myMap)
+{
+ CStringShortTree* cache;
+ BJString versionNumber;
+
+ fprintf(hFile,"%s\n",sTitle.GetBuffer());
+
+ for (map<BJString, CStringShortTree*>::iterator it = myMap->begin(); it != myMap->end(); ++it)
+ {
+ versionNumber = (*it).first;
+ cache = (*it).second;
+
+ ExportShortCacheHelper(hFile, versionNumber, cache->GetRoot());
+ }
+}
+
+void CBonjourTop::ExportResults()
+{
+
+ BJString sTempFileName;
+ device_count devCount;
+ sTempFileName = m_pExportFileName;
+
+ if (m_SnapshotSeconds)
+ {
+ BJString sTimeStamp;
+ sTimeStamp.Format(time(NULL), BJString::BJSS_TIME);
+ sTempFileName += "_";
+ sTempFileName += sTimeStamp;
+ }
+ sTempFileName += ".csv";
+
+ if (m_Collection.IsValid())
+ {
+ m_Collection.ExportCollection(sTempFileName);
+ return;
+ }
+
+ FILE* hFile = fopen(sTempFileName.GetBuffer(),"w");
+
+ if (hFile == NULL)
+ {
+ printf("file open failed %s\n",m_pExportFileName);
+ return;
+ }
+
+ fprintf(hFile,"Total Number of Frames, %llu\n",m_nFrameCount);
+ fprintf(hFile,"Total Number of Bytes, %llu\n",m_nTotalBytes);
+ fprintf(hFile,"Total Number of Sec, %llu\n",m_EndTime-m_StartTime);
+
+ bzero(&devCount, sizeof(devCount));
+ m_DeviceMap.GetDeviceOSTypes(m_DeviceMap.GetRoot(),NULL, devCount);
+ fprintf(hFile,"Total Number of Devices, %llu\n\n",devCount.iOS+devCount.OSX+devCount.unknownOS);
+ fprintf(hFile,"Total Number of iOS Devices, %llu\n",devCount.iOS);
+ fprintf(hFile,"Total Number of iOS Devices (>= iOS7), %llu\n", devCount.iOSWithEDNSField);
+ fprintf(hFile,"Total Number of OSX Devices, %llu\n",devCount.OSX);
+ fprintf(hFile,"Total Number of OSX Devices (>= OSX 10.9), %llu\n",devCount.OSXWithEDNSField);
+
+ fprintf(hFile,"IPv4 multicast, %llu\n",m_SocketStatus[0].m_nFrameCount);
+ fprintf(hFile,"IPv6 multicast, %llu\n",m_SocketStatus[1].m_nFrameCount);
+ fprintf(hFile,"IPv4 Unicast, %llu\n",m_SocketStatus[2].m_nFrameCount);
+ fprintf(hFile,"IPv6 Unicast, %llu\n",m_SocketStatus[3].m_nFrameCount);
+ fprintf(hFile,"IPv4 Wrong subnet, %llu\n",m_SocketStatus[4].m_nFrameCount);
+ fprintf(hFile,"IPv6 Wrong subnet, %llu\n\n",m_SocketStatus[5].m_nFrameCount);
+
+ fprintf(hFile,"QuestionOnly Packets, %llu\n", m_SocketStatus[0].m_nQuestionOnlyFrames);
+ fprintf(hFile,"AnswerOnly Packets, %llu\n", m_SocketStatus[0].m_nAnswerOnlyFrames);
+ fprintf(hFile,"Q&A Packets, %llu\n\n", m_SocketStatus[0].m_nQandAFrames);
+
+ fprintf(hFile,"AnswerCount for truncated frames min, %llu\n", m_MinAnswerCountForTruncatedFrames);
+ fprintf(hFile,"AnswerCount for truncated frames avg, %llu\n", m_AvgAnswerCountForTruncatedFrames);
+ fprintf(hFile,"AnswerCount for truncated frames max, %llu\n\n", m_MaxAnswerCountForTruncatedFrames);
+
+ // Export Cache
+ UpdateOSCounts();
+ ExportPtrCache(hFile,"Application IPv4 Cache",m_ApplPtrCache.GetRoot());
+ ExportShortCache(hFile, "OSX", &m_AppBreakdownIPv4OSX);
+ ExportShortCache(hFile, "iOS", &m_AppBreakdownIPv4iOS);
+
+ ExportPtrCache(hFile,"Application IPv6 Cache",m_ApplPtrCacheIPv6.GetRoot());
+ ExportShortCache(hFile, "OSX", &m_AppBreakdownIPv6OSX);
+ ExportShortCache(hFile, "iOS", &m_AppBreakdownIPv6iOS);
+
+ ExportPtrCache(hFile,"Service IPv4 Cache",m_ServicePtrCache.GetRoot());
+ ExportShortCache(hFile, "OSX", &m_ServiceBreakdownIPv4OSX);
+ ExportShortCache(hFile, "iOS", &m_ServiceBreakdownIPv4iOS);
+
+ ExportPtrCache(hFile,"Service IPv6 Cache",m_ServicePtrCacheIPv6.GetRoot());
+ ExportShortCache(hFile, "OSX", &m_ServiceBreakdownIPv6OSX);
+ ExportShortCache(hFile, "iOS", &m_ServiceBreakdownIPv6iOS);
+
+ /// min snapshot table
+
+ fprintf(hFile,"Min Snapshot table\n");
+
+ for (int h=0;h<24;h++)
+ {
+ for(int m=0;m<60;m++)
+ {
+ if (m_MinSnapshot[h][m].m_nFrameCount)
+ {
+ fprintf(hFile,"%02d:%02d,%llu\n",h,m,m_MinSnapshot[h][m].m_nFrameCount);
+ }
+ }
+
+ }
+
+ fclose(hFile);
+
+}
+
+void CBonjourTop::WriteDeviceFile()
+{
+ BJString sTempFileName;
+ BJString sTimeStamp;
+
+ sTempFileName = m_DeviceFileName;
+ sTimeStamp.Format(time(NULL), BJString::BJSS_TIME);
+ sTempFileName += "_";
+ sTempFileName += sTimeStamp;
+ sTempFileName += ".csv";
+
+ FILE* hFile = fopen(sTempFileName.GetBuffer(),"w");
+
+ if (hFile == NULL)
+ {
+ printf("file open failed %s\n",sTempFileName.GetBuffer());
+ return;
+ }
+
+ fprintf(hFile,"\"Name\",\"IPv4Address\",\"IPv6Address\",\"MACAddress\",O,\"Model\",\"Method\",\"total frames\",\"question frames\",\"QU frames\",\"answer frames\"\n");
+
+ CDeviceNode *pDeviceNode = m_DeviceMap.GetRoot();
+
+ if (pDeviceNode)
+ pDeviceNode->Export(hFile);
+
+ fclose(hFile);
+
+ printf("devicemap count %llu %d\n",m_DeviceMap.GetCount(),CDeviceNode::nCreateCount);
+
+}
+
+void CBonjourTop::WriteVendorFile()
+{
+ BJString sTempFileName = "BonjourTopVendor";
+ BJString sTimeStamp;
+
+ sTimeStamp.Format(time(NULL), BJString::BJSS_TIME);
+ sTempFileName += "_";
+ sTempFileName += sTimeStamp;
+ sTempFileName += ".csv";
+
+ FILE* hFile = fopen(sTempFileName.GetBuffer(),"w");
+
+ if (hFile == NULL)
+ {
+ printf("file open failed %s\n",sTempFileName.GetBuffer());
+ return;
+ }
+ fprintf(hFile,"\"MACAddress\",O,\"Model\",\"Method\"\n");
+
+ CMACAddrNode *node = m_MacMap.GetRoot();
+
+ if (node)
+ node->Export(hFile);
+
+ fclose(hFile);
+}
+
+void CBonjourTop::WindowSizeChanged()
+{
+ window_size_changed = true;
+}
+
+BJ_UINT64 Hash(const char* pStr)
+{
+ // to fix
+ BJ_UINT64 hash = 0;
+ int c;
+
+ while ((c = *pStr++))
+ hash += c;
+
+ return hash;
+
+
+}
+
+BJ_UINT64 Hash2(char* pStr)
+{
+ // to fix
+ BJ_UINT64 hash = 0;
+ int c;
+ int i = 0;
+
+ while ((c = *pStr++) && i++ < 8)
+ {
+ hash = hash << 8;
+ hash |= c;
+ }
+
+ return hash;
+
+
+}
+
+static integer_t Usage(void)
+{
+ task_t targetTask = mach_task_self();
+ struct task_basic_info ti;
+ mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT;
+
+ kern_return_t kr = task_info(targetTask, TASK_BASIC_INFO_64,
+ (task_info_t) &ti, &count);
+ if (kr != KERN_SUCCESS)
+ {
+ printf("Kernel returned error during memory usage query");
+ return 0;
+ }
+
+ // On Mac OS X, the resident_size is in bytes, not pages!
+ // (This differs from the GNU Mach kernel)
+ // return ti.resident_size;
+ return ti.user_time.seconds;
+}
+
+///////////////
+
+
+/* CStringNode */
+
+void CStringNode::UpdateOSTypeCounts(CDeviceMap* pGlobalDeviceMap,CIPAddrMap *pIp2NameMap)
+{
+ if (m_rbLeft)
+ ((CStringNode*)m_rbLeft)->UpdateOSTypeCounts(pGlobalDeviceMap,pIp2NameMap);
+ if (m_rbRight)
+ ((CStringNode*)m_rbRight)->UpdateOSTypeCounts(pGlobalDeviceMap,pIp2NameMap);
+
+ BJ_UINT64 nDeviceUnknown = 0;
+ m_nDeviceAskingiOSCount = 0;
+ m_nDeviceAskingOSXCount = 0;
+ m_nDeviceAnsweringiOSCount = 0;
+ m_nDeviceAnsweringOSXCount = 0;
+ m_nDeviceTotaliOSCount = 0;
+ m_nDeviceTotalOSXCount = 0;
+ m_DeviceAskingTree.GetDeviceOSTypes(m_DeviceAskingTree.GetRoot(),pIp2NameMap,m_nDeviceAskingiOSCount,m_nDeviceAskingOSXCount,nDeviceUnknown);
+ if (m_DeviceAskingTree.GetCount() != m_nDeviceAskingiOSCount + m_nDeviceAskingOSXCount+nDeviceUnknown)
+ {
+ nDeviceUnknown = 0;
+ }
+ nDeviceUnknown = 0;
+ m_DeviceAnsweringTree.GetDeviceOSTypes(m_DeviceAnsweringTree.GetRoot(),pIp2NameMap,m_nDeviceAnsweringiOSCount,m_nDeviceAnsweringOSXCount,nDeviceUnknown);
+ if (m_DeviceAnsweringTree.GetCount() != m_nDeviceAnsweringiOSCount + m_nDeviceAnsweringOSXCount+nDeviceUnknown)
+ {
+ nDeviceUnknown = 0;
+ }
+ nDeviceUnknown = 0;
+ m_DeviceTotalTree.GetDeviceOSTypes(m_DeviceTotalTree.GetRoot(), pIp2NameMap, m_nDeviceTotaliOSCount, m_nDeviceTotalOSXCount, nDeviceUnknown);
+ if (m_DeviceTotalTree.GetCount() != m_nDeviceTotaliOSCount + m_nDeviceTotalOSXCount + nDeviceUnknown)
+ {
+ nDeviceUnknown = 0;
+ }
+}
+
+void CStringNode::Print(bool bCursers,bool bDescendingSort,BJ_UINT32 &nIndex, BJ_UINT32 nStartIndex,BJ_UINT32 nEndIndex)
+{
+ if (bDescendingSort)
+ {
+ if (m_rbLeft)
+ ((CStringNode*)m_rbLeft)->Print(bCursers,bDescendingSort,nIndex,nStartIndex,nEndIndex);
+
+ if (nIndex >= nStartIndex && nIndex <= nEndIndex)
+ {
+ if (bCursers)
+ {
+ printw("%3d. %-30s %10llu %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu %10llu\n",nIndex,(char*)&(m_Value),m_nBytes,m_nFrames, m_nFramesiOS, m_nFramesOSX, m_nQuestionFrames, m_nQuestionFramesiOS, m_nQuestionFramesOSX, m_nAnswerFrames,m_nAnswerFramesiOS, m_nAnswerFramesOSX, m_nDeviceAskingCount,m_nDeviceAskingiOSCount,m_nDeviceAskingOSXCount, m_nDeviceAnsweringCount,m_nDeviceAnsweringiOSCount,m_nDeviceAnsweringOSXCount, m_nDeviceTotalCount, m_nDeviceTotaliOSCount, m_nDeviceTotalOSXCount, m_nWakeFrames,m_nGoodbyeFrames);
+
+ }
+ else
+ {
+ printf("%3d. %-30s %10llu %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu %10llu\n",nIndex,(char*)&(m_Value),m_nBytes,m_nFrames, m_nFramesiOS, m_nFramesOSX, m_nQuestionFrames, m_nQuestionFramesiOS, m_nQuestionFramesOSX, m_nAnswerFrames,m_nAnswerFramesiOS, m_nAnswerFramesOSX, m_nDeviceAskingCount,m_nDeviceAskingiOSCount,m_nDeviceAskingOSXCount, m_nDeviceAnsweringCount,m_nDeviceAnsweringiOSCount,m_nDeviceAnsweringOSXCount, m_nDeviceTotalCount, m_nDeviceTotaliOSCount, m_nDeviceTotalOSXCount, m_nWakeFrames,m_nGoodbyeFrames);
+
+ }
+ }
+ nIndex++;
+ if (m_rbRight)
+ ((CStringNode*)m_rbRight)->Print(bCursers,bDescendingSort,nIndex,nStartIndex,nEndIndex);
+ }
+ else
+ {
+ if (m_rbRight)
+ ((CStringNode*)m_rbRight)->Print(bCursers,bDescendingSort,nIndex,nStartIndex,nEndIndex);
+
+ if (nIndex >= nStartIndex && nIndex <= nEndIndex)
+ {
+ if (bCursers)
+ {
+ printw("%3d. %-30s %10llu %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu %10llu\n",nIndex,(char*)&(m_Value),m_nBytes,m_nFrames, m_nFramesiOS, m_nFramesOSX, m_nQuestionFrames, m_nQuestionFramesiOS, m_nQuestionFramesOSX, m_nAnswerFrames,m_nAnswerFramesiOS, m_nAnswerFramesOSX, m_nDeviceAskingCount,m_nDeviceAskingiOSCount,m_nDeviceAskingOSXCount, m_nDeviceAnsweringCount,m_nDeviceAnsweringiOSCount,m_nDeviceAnsweringOSXCount, m_nDeviceTotalCount, m_nDeviceTotaliOSCount, m_nDeviceTotalOSXCount, m_nWakeFrames,m_nGoodbyeFrames);
+ }
+ else
+ {
+ printf("%3d. %-30s %10llu %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu(%5llu/%5llu) %10llu %10llu\n",nIndex,(char*)&(m_Value),m_nBytes,m_nFrames, m_nFramesiOS, m_nFramesOSX, m_nQuestionFrames, m_nQuestionFramesiOS, m_nQuestionFramesOSX, m_nAnswerFrames,m_nAnswerFramesiOS, m_nAnswerFramesOSX, m_nDeviceAskingCount,m_nDeviceAskingiOSCount,m_nDeviceAskingOSXCount, m_nDeviceAnsweringCount,m_nDeviceAnsweringiOSCount,m_nDeviceAnsweringOSXCount, m_nDeviceTotalCount, m_nDeviceTotaliOSCount, m_nDeviceTotalOSXCount, m_nWakeFrames,m_nGoodbyeFrames);
+ }
+ }
+ nIndex++;
+ if (m_rbLeft)
+ ((CStringNode*)m_rbLeft)->Print(bCursers,bDescendingSort,nIndex,nStartIndex,nEndIndex);
+ }
+
+}
+void CStringNode::Export(FILE* hFile)
+{
+ fprintf(hFile, "%s,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu\n",
+ (char*)&(m_Value),m_nBytes,
+ m_nFrames, m_nFramesiOS, m_nFramesOSX,
+ m_nQuestionFrames, m_nQuestionFramesiOS, m_nQuestionFramesOSX,
+ m_nAnswerFrames, m_nAnswerFramesiOS, m_nAnswerFramesOSX,
+ m_nDeviceAskingCount, m_nDeviceAskingiOSCount,m_nDeviceAskingOSXCount,
+ m_nDeviceAnsweringCount,m_nDeviceAnsweringiOSCount,m_nDeviceAnsweringOSXCount,
+ m_nDeviceTotalCount, m_nDeviceTotaliOSCount, m_nDeviceTotalOSXCount,
+ m_nWakeFrames,m_nGoodbyeFrames);
+
+ if (m_rbLeft)
+ ((CStringNode*)m_rbLeft)->Export(hFile);
+ if (m_rbRight)
+ ((CStringNode*)m_rbRight)->Export(hFile);
+
+}
+
+/* CStringShortNode */
+
+void CStringShortNode::Export(FILE *hFile)
+{
+ fprintf(hFile, "%s,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu\n",
+ (char*)&(m_Value),m_nBytes,
+ m_nFrames, m_nQuestionFrames, m_nAnswerFrames,
+ m_nDeviceAskingCount, m_nDeviceAnsweringCount, m_nDeviceTotalCount,
+ m_nWakeFrames,m_nGoodbyeFrames);
+
+
+ if (m_rbLeft)
+ {
+ ((CStringShortNode*)m_rbLeft)->Export(hFile);
+ }
+ if (m_rbRight)
+ {
+ ((CStringShortNode*)m_rbRight)->Export(hFile);
+ }
+}
+
+/* CDeviceMap */
+
+void CDeviceMap::GetDeviceOSTypes(CDeviceNode *node, CDeviceMap *pGlobalDeviceMap, device_count& dev_cnt)
+{
+ if (node == NULL)
+ return;
+
+ GetDeviceOSTypes(dynamic_cast<CDeviceNode*>(node->m_rbLeft),pGlobalDeviceMap, dev_cnt);
+ GetDeviceOSTypes(dynamic_cast<CDeviceNode*>(node->m_rbRight),pGlobalDeviceMap, dev_cnt);
+
+ if (node->bDuplicate || !node->bHasFrames)
+ return;
+
+ char deviceType = '?';
+ if (pGlobalDeviceMap)
+ {
+ CDeviceNode* globalDevice = pGlobalDeviceMap->Find(&node->m_Key);
+ if (globalDevice)
+ {
+ deviceType = globalDevice->GetDeviceOS();
+
+ if (globalDevice->bOSXWithEDNSField && deviceType == 'X')
+ {
+ dev_cnt.OSXWithEDNSField++;
+ }
+ else if (globalDevice->biOSWithEDNSField && (deviceType == 't' || deviceType == 'i'))
+ {
+ dev_cnt.iOSWithEDNSField++;
+ }
+ }
+ }
+ else
+ {
+ deviceType = node->GetDeviceOS();
+ if (node->bOSXWithEDNSField && deviceType == 'X')
+ {
+ dev_cnt.OSXWithEDNSField++;
+ }
+ else if (node->biOSWithEDNSField && (deviceType == 't' || deviceType == 'i'))
+ {
+ dev_cnt.iOSWithEDNSField++;
+ }
+ }
+ switch (deviceType)
+ {
+ case 'i':
+ case 't':
+ dev_cnt.iOS++;
+ break;
+ case 'X':
+ dev_cnt.OSX++;
+ break;
+ default:
+ dev_cnt.unknownOS++;
+ break;
+ }
+}
+
+void CIPAddrMap::GetDeviceOSTypes(CIPDeviceNode* node, CIPAddrMap* pGobalMap, BJ_UINT64& iOS,BJ_UINT64& OSX,BJ_UINT64& unknowOS)
+{
+ if (node == NULL)
+ return;
+
+ GetDeviceOSTypes(dynamic_cast<CIPDeviceNode*>(node->m_rbLeft),pGobalMap, iOS, OSX, unknowOS);
+ GetDeviceOSTypes(dynamic_cast<CIPDeviceNode*>(node->m_rbRight),pGobalMap,iOS, OSX, unknowOS);
+
+ char deviceType = '?';
+ if (pGobalMap)
+ {
+ CIPDeviceNode *ipDevice = pGobalMap->Find(&node->m_Key);
+
+ if (ipDevice && ipDevice->pDeviceNode )
+ deviceType = ipDevice->pDeviceNode->GetDeviceOS();
+
+ }
+
+ switch (deviceType)
+ {
+ case 'i':
+ case 't':
+ iOS++;
+ break;
+ case 'X':
+ OSX++;
+ break;
+ default:
+ unknowOS++;
+ }
+
+}
+
+
+///////////
+
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/BonjourTop.h b/mDNSResponder/mDNSMacOSX/BonjourTop/source/BonjourTop.h
new file mode 100644
index 00000000..9a678c0d
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/BonjourTop.h
@@ -0,0 +1,577 @@
+//
+// BonjourTop.h
+// TestTB
+//
+// Created by Terrin Eager on 9/26/12.
+//
+//
+
+#ifndef __TestTB__BonjourTop__
+#define __TestTB__BonjourTop__
+
+#include <iostream>
+#include <stdio.h>
+#include <map>
+#include <utility>
+
+#include "bjtypes.h"
+#include "bjsocket.h"
+#include "LLRBTree.h"
+#include "DNSFrame.h"
+#include "bjStringtoStringMap.h"
+#include "bjstring.h"
+
+#include "CollectBy.h"
+
+using namespace std;
+
+typedef struct device_count {
+ BJ_UINT64 iOS = 0;
+ BJ_UINT64 OSX = 0;
+ BJ_UINT64 unknownOS = 0;
+ BJ_UINT64 OSXWithEDNSField = 0;
+ BJ_UINT64 iOSWithEDNSField = 0;
+} device_count;
+
+class CSocketStats
+{
+public:
+ CSocketStats();
+ void Init();
+ void Clear();
+ BJ_UINT64 m_nFrameCount;
+
+ BJ_UINT64 m_nQuestionOnlyFrames;
+ BJ_UINT64 m_nAnswerOnlyFrames;
+ BJ_UINT64 m_nQandAFrames;
+
+ BJ_INT32 m_SampleDay;
+
+};
+
+class FrameCount
+{
+public:
+ FrameCount() { count = 0;lastFrameNumber = -1;};
+ void Increment(BJ_UINT64 frameNumber)
+ {
+ if (frameNumber != lastFrameNumber)
+ count++;
+ lastFrameNumber = frameNumber;
+
+ };
+ BJ_UINT64 GetValue() const {return count;};
+ void Reset() { count = 0;lastFrameNumber = -1;};
+ FrameCount &operator+=(const FrameCount &src) { count += src.count; return *this;};
+
+private:
+ BJ_UINT64 count;
+ BJ_UINT64 lastFrameNumber;
+};
+
+////////////////
+class CDeviceMap;
+class CDeviceNode;
+
+class CIPDeviceNode : public CRBNode<BJIPAddr>
+{
+public:
+ CIPDeviceNode(BJIPAddr* pSrc) {m_Key = *pSrc; /* temp deviceOS = '?';lastQUFrame = 0;*/pDeviceNode=NULL;};
+ CIPDeviceNode(){ /*deviceOS = '?';lastQUFrame = 0; */pDeviceNode=NULL;};
+ ~CIPDeviceNode(){};
+ inline virtual BJ_COMPARE Compare(BJIPAddr* pKey) {return m_Key.Compare(pKey);};
+ inline virtual void CopyNode(CRBNode* pSrc)
+ {
+ m_Key.Set(((BJIPAddr*)pSrc)->Getin6_addr());
+ pDeviceNode = ((CIPDeviceNode*)pSrc)->pDeviceNode;
+ };
+ void Init() {};
+ void Clear() {};
+
+
+ CDeviceNode* pDeviceNode;
+
+};
+
+class CIPAddrMap: public CLLRBTree<BJIPAddr,CIPDeviceNode>
+{
+public:
+ void GetDeviceOSTypes(CIPDeviceNode* node, CIPAddrMap* pGobalMap, BJ_UINT64& iOS,BJ_UINT64& OSX,BJ_UINT64& unknowOS);
+};
+
+////////////////////
+class CDeviceNode : public CRBNode<BJString>
+{
+public:
+ CDeviceNode(BJString* pSrc) {m_Key = *pSrc; deviceOS = '?'; bOSXWithEDNSField = false; biOSWithEDNSField = false; bDuplicate = false; bIPName = false; bHasFrames = false; nCreateCount++;};
+ CDeviceNode(){deviceOS = '?'; bDuplicate = false; bIPName = false; bHasFrames = false; nCreateCount++;};
+ ~CDeviceNode(){nCreateCount--;};
+ inline virtual BJ_COMPARE Compare(BJString* pKey) {return m_Key.Compare(*pKey);};
+ inline virtual void CopyNode(CRBNode* pSource)
+ {
+ m_Key = pSource->m_Key;
+ deviceOS = dynamic_cast<CDeviceNode*>(pSource)->deviceOS;
+ model = dynamic_cast<CDeviceNode*>(pSource)->model;
+ settingService = dynamic_cast<CDeviceNode*>(pSource)->settingService;
+ macAddress = dynamic_cast<CDeviceNode*>(pSource)->macAddress;
+ ipAddressv4 = dynamic_cast<CDeviceNode*>(pSource)->ipAddressv4;
+ ipAddressv6 = dynamic_cast<CDeviceNode*>(pSource)->ipAddressv6;
+ bOSXWithEDNSField = dynamic_cast<CDeviceNode*>(pSource)->bOSXWithEDNSField;
+ biOSWithEDNSField = dynamic_cast<CDeviceNode*>(pSource)->biOSWithEDNSField;
+ bHasFrames = dynamic_cast<CDeviceNode*>(pSource)->bHasFrames;
+ };
+ inline virtual void MergeData(CDeviceNode* src)
+ {
+ deviceOS = src->deviceOS;
+ model = src->model;
+ settingService = src->settingService;
+ macAddress = src->macAddress;
+ bOSXWithEDNSField = src->bOSXWithEDNSField;
+ biOSWithEDNSField = src->biOSWithEDNSField;
+
+ frameTotal += src->frameTotal;
+ questionFrame += src->questionFrame;
+ QUFrame += src->QUFrame;
+ answerFrame += src->answerFrame;
+ bHasFrames |= src->bHasFrames;
+ };
+ void ClearData()
+ {
+ frameTotal.Reset();
+ questionFrame.Reset();
+ QUFrame.Reset();
+ answerFrame.Reset();
+ bHasFrames = false;
+ }
+ void Init() {deviceOS = '?';};
+
+ void Clear() {};
+ char GetDeviceOS() {return deviceOS;};
+ void SetDeviceOS(char t,const char* pSettingService)
+ {
+ BJString EDNS0 = "EDNS0 Trace";
+ if (pSettingService == NULL)
+ printf("SetDeviceOS: pSettingService is NULL\n");
+
+ if (settingService != EDNS0 || EDNS0 == pSettingService)
+ {
+ settingService = pSettingService;;
+ deviceOS = t;
+ }
+ // if ( t != deviceOS && deviceOS != '?' && (deviceOS != 'b' ))
+ // printf("SetDeviceOS: %s deviceOS not equal %c by %s != %c by %s\n", m_Key.GetBuffer(),deviceOS,settingService.GetBuffer(),t,pSettingService);
+ };
+ void SetModel(char* pModel) {model = pModel;};
+ void Export(FILE* file)
+ {
+ // fprintf(hFile,"Name,IPAddress,MACAddress,OSType,Model,Method\n");
+ if (m_rbRight)
+ dynamic_cast<CDeviceNode*>(m_rbRight)->Export(file);
+
+ if (!bDuplicate || frameTotal.GetValue() > 0)
+ {
+ fprintf(file,"\"%s\",\"%s\",\"%s\",\"%s\",%c,\"%s\",\"%s\",%llu,%llu,%llu,%llu\n",
+ m_Key.GetBuffer(),
+ ipAddressv4.GetString(),
+ ipAddressv6.GetString(),
+ macAddress.GetString(),
+ deviceOS,
+ model.GetBuffer()?model.GetBuffer():" ",
+ (bDuplicate)?"dup":settingService.GetBuffer()?settingService.GetBuffer():" ",
+ frameTotal.GetValue(),
+ questionFrame.GetValue(),
+ QUFrame.GetValue(),
+ answerFrame.GetValue());
+ }
+
+ if (m_rbLeft)
+ dynamic_cast<CDeviceNode*>(m_rbLeft)->Export(file);
+ };
+
+ BJMACAddr macAddress;
+ BJIPAddr ipAddressv4;
+ BJIPAddr ipAddressv6;
+ BJString model;
+ BJString settingService;
+ bool biOSWithEDNSField;
+ bool bOSXWithEDNSField;
+ bool bDuplicate;
+ bool bIPName;
+ bool bHasFrames;
+
+ FrameCount frameTotal;
+ FrameCount questionFrame;
+ FrameCount QUFrame;
+ FrameCount answerFrame;
+ static int nCreateCount;
+
+private:
+ char deviceOS;
+};
+
+class CDeviceMap: public CLLRBTree<BJString,CDeviceNode>
+{
+public:
+ void GetDeviceOSTypes(CDeviceNode *node, CDeviceMap *pGobalMap, device_count& dev_cnt);
+};
+
+//////////////
+class CMACAddrNode: public CRBNode<BJMACAddr>
+{
+public:
+ CMACAddrNode(BJMACAddr* pSrc) {m_Key.Set(pSrc->Get()); deviceOS = '?'; };
+ CMACAddrNode(){deviceOS = '?';};
+ ~CMACAddrNode(){};
+ inline virtual BJ_COMPARE Compare(BJMACAddr* pKey) {return m_Key.Compare(pKey);};
+ inline virtual void CopyNode(CRBNode* pSource)
+ {
+ m_Key.Set( pSource->m_Key.Get());
+ deviceOS = dynamic_cast<CMACAddrNode*>(pSource)->deviceOS;
+ model = dynamic_cast<CMACAddrNode*>(pSource)->model;
+ method = dynamic_cast<CMACAddrNode*>(pSource)->method;
+ };
+ void Export(FILE* file)
+ {
+ if (m_rbRight)
+ dynamic_cast<CMACAddrNode*>(m_rbRight)->Export(file);
+
+
+ fprintf(file,"\"%s\",%c,\"%s\",\"%s\"\n",
+ m_Key.GetString(),
+ deviceOS,
+ model.GetBuffer()?model.GetBuffer():" ",
+ method.GetBuffer()?method.GetBuffer():" ");
+
+
+ if (m_rbLeft)
+ dynamic_cast<CMACAddrNode*>(m_rbLeft)->Export(file);
+ };
+
+ void Init() {deviceOS = '?';};
+ void Clear(){};
+ char deviceOS;
+ BJString model;
+ BJString method;
+
+};
+
+class CMACAddrTree: public CLLRBTree<BJMACAddr,CMACAddrNode>
+{
+public:
+
+};
+class CMACAddrDeviceNode: public CRBNode<BJMACAddr>
+{
+public:
+ CMACAddrDeviceNode(BJMACAddr* pSrc) {m_Key.Set(pSrc->Get()); device = NULL; };
+ CMACAddrDeviceNode(){device = NULL;};
+ ~CMACAddrDeviceNode(){};
+ inline virtual BJ_COMPARE Compare(BJMACAddr* pKey) {return m_Key.Compare(pKey);};
+ inline virtual void CopyNode(CRBNode* pSource)
+ {
+ m_Key.Set( pSource->m_Key.Get());
+ device = dynamic_cast<CMACAddrDeviceNode*>(pSource)->device;
+ };
+ void Init() {device = NULL;};
+ void Clear(){};
+ CDeviceNode *device;
+
+};
+
+class CMACDeviceMap: public CLLRBTree<BJMACAddr,CMACAddrDeviceNode>
+{
+
+};
+
+/////////////
+
+class CStringNode : public CRBNode<BJ_UINT64>
+{
+public:
+ CStringNode(){Init();};
+ CStringNode ( BJ_UINT64* Key) { Init(); m_Key = *Key;};
+ inline virtual BJ_COMPARE Compare(BJ_UINT64* pKey)
+ {
+
+ if (m_Key < *pKey)
+ return (BJ_GT);
+ else if (m_Key > *pKey)
+ return (BJ_LT);
+ else
+ return (BJ_EQUAL);
+ }
+ inline virtual void CopyNode(CRBNode* pSource)
+ {
+ CStringNode* pSrc = (CStringNode*) pSource;
+
+ // m_Key = pSrc->m_Key;
+ m_nBytes = pSrc->m_nBytes;
+ m_nFrames = pSrc->m_nFrames;
+ m_nFramesiOS = pSrc->m_nFramesiOS;
+ m_nFramesOSX = pSrc->m_nFramesOSX;
+ m_nQuestionFrames = pSrc->m_nQuestionFrames;
+ m_nQuestionFramesiOS = pSrc->m_nQuestionFramesiOS;
+ m_nQuestionFramesOSX = pSrc->m_nQuestionFramesOSX;
+ m_nAnswerFrames = pSrc->m_nAnswerFrames;
+ m_nAnswerFramesiOS = pSrc->m_nAnswerFramesiOS;
+ m_nAnswerFramesOSX = pSrc->m_nAnswerFramesOSX;
+ strcpy(m_Value,pSrc->m_Value);
+ m_nDeviceAskingCount = pSrc->m_nDeviceAskingCount;
+ m_nDeviceAskingiOSCount = pSrc->m_nDeviceAskingiOSCount;
+ m_nDeviceAskingOSXCount = pSrc->m_nDeviceAskingOSXCount;
+ m_nDeviceAnsweringCount = pSrc->m_nDeviceAnsweringCount;
+ m_nDeviceAnsweringiOSCount = pSrc->m_nDeviceAnsweringiOSCount;
+ m_nDeviceAnsweringOSXCount = pSrc->m_nDeviceAnsweringOSXCount;
+ m_nDeviceTotalCount = pSrc->m_nDeviceTotalCount;
+ m_nDeviceTotaliOSCount = pSrc->m_nDeviceTotaliOSCount;
+ m_nDeviceTotalOSXCount = pSrc->m_nDeviceTotalOSXCount;
+ m_nWakeFrames = pSrc->m_nWakeFrames;
+ m_nLastWakeFrameIndex = pSrc->m_nLastWakeFrameIndex;
+ m_nGoodbyeFrames = pSrc->m_nGoodbyeFrames;
+ }
+
+ inline void Init() {
+ m_nBytes = 0;
+ m_nFrames = m_nFramesiOS = m_nFramesOSX = m_nQuestionFrames = m_nQuestionFramesiOS = m_nQuestionFramesOSX = m_nAnswerFrames = m_nAnswerFramesiOS = m_nAnswerFramesOSX = 0;
+ m_nLastFrameIndex = 0;
+ m_nLastQueryFrameIndex = 0;
+ m_nLastRespondsFrameIndex = 0;
+ m_nDeviceAskingCount = m_nDeviceAskingiOSCount = m_nDeviceAskingOSXCount = 0;
+ m_nDeviceAnsweringCount = m_nDeviceAnsweringiOSCount = m_nDeviceAnsweringOSXCount = 0;
+ m_nDeviceTotalCount = m_nDeviceTotaliOSCount = m_nDeviceTotalOSXCount = 0;
+ m_nWakeFrames = 0;
+ m_nGoodbyeFrames = 0;
+ m_lastQUFrameTime = 0;
+ };
+ inline void Clear() {};
+
+ void UpdateOSTypeCounts(CDeviceMap* pGobalMap,CIPAddrMap *pIp2NameMap);
+
+ void Print(bool bCursers,bool bDescendingSort,BJ_UINT32 &nIndex,BJ_UINT32 nStartIndex,BJ_UINT32 nEndIndex);
+ void Export(FILE* hFile);
+
+ // BJ_UINT64 m_Key;
+ char m_Value[255];
+ BJ_UINT64 m_nBytes;
+ BJ_UINT64 m_nFrames;
+ BJ_UINT64 m_nFramesiOS;
+ BJ_UINT64 m_nFramesOSX;
+ BJ_UINT64 m_nQuestionFrames;
+ BJ_UINT64 m_nQuestionFramesiOS;
+ BJ_UINT64 m_nQuestionFramesOSX;
+ BJ_UINT64 m_nAnswerFrames;
+ BJ_UINT64 m_nAnswerFramesiOS;
+ BJ_UINT64 m_nAnswerFramesOSX;
+ BJ_UINT64 m_nLastFrameIndex;
+ BJ_UINT64 m_nLastQueryFrameIndex;
+ BJ_UINT64 m_nLastRespondsFrameIndex;
+ BJ_UINT64 m_nLastWakeFrameIndex;
+ CIPAddrMap m_DeviceAskingTree;
+ BJ_UINT64 m_nDeviceAskingCount;
+ BJ_UINT64 m_nDeviceAskingiOSCount;
+ BJ_UINT64 m_nDeviceAskingOSXCount;
+ CIPAddrMap m_DeviceAnsweringTree;
+ BJ_UINT64 m_nDeviceAnsweringCount;
+ BJ_UINT64 m_nDeviceAnsweringiOSCount;
+ BJ_UINT64 m_nDeviceAnsweringOSXCount;
+ CIPAddrMap m_DeviceTotalTree;
+ BJ_UINT64 m_nDeviceTotalCount;
+ BJ_UINT64 m_nDeviceTotaliOSCount;
+ BJ_UINT64 m_nDeviceTotalOSXCount;
+ BJ_UINT64 m_nWakeFrames;
+ BJ_UINT64 m_lastQUFrameTime;
+ BJ_UINT64 m_nGoodbyeFrames;
+};
+
+class CStringTree: public CLLRBTree<BJ_UINT64,CStringNode>
+{
+public:
+
+};
+
+///////////
+
+class CStringShortNode: public CRBNode<BJ_UINT64>
+{
+public:
+ CStringShortNode(BJ_UINT64* key) {Init(); m_Key = *key;};
+ inline virtual BJ_COMPARE Compare(BJ_UINT64* pKey)
+ {
+
+ if (m_Key < *pKey)
+ return (BJ_GT);
+ else if (m_Key > *pKey)
+ return (BJ_LT);
+ else
+ return (BJ_EQUAL);
+ }
+
+ inline virtual void CopyNode(CRBNode* pSource)
+ {
+ CStringShortNode* pSrc = (CStringShortNode*) pSource;
+
+ // m_Key = pSrc->m_Key;
+ m_nBytes = pSrc->m_nBytes;
+ m_nFrames = pSrc->m_nFrames;
+ m_nQuestionFrames = pSrc->m_nQuestionFrames;
+ m_nAnswerFrames = pSrc->m_nAnswerFrames;
+ strcpy(m_Value,pSrc->m_Value);
+ m_nDeviceAskingCount = pSrc->m_nDeviceAskingCount;
+ m_nDeviceAnsweringCount = pSrc->m_nDeviceAnsweringCount;
+ m_nDeviceTotalCount = pSrc->m_nDeviceTotalCount;
+ m_nWakeFrames = pSrc->m_nWakeFrames;
+ m_nLastWakeFrameIndex = pSrc->m_nLastWakeFrameIndex;
+ m_nGoodbyeFrames = pSrc->m_nGoodbyeFrames;
+ }
+
+ inline void Init() {
+ m_nBytes = 0;
+ m_nFrames = m_nQuestionFrames = m_nAnswerFrames = 0;
+ m_nLastFrameIndex = m_nLastQueryFrameIndex = m_nLastRespondsFrameIndex = m_nLastWakeFrameIndex = 0;
+ m_nDeviceAskingCount = m_nDeviceAnsweringCount = m_nDeviceTotalCount = 0;
+ m_nWakeFrames = m_lastQUFrameTime = m_nGoodbyeFrames = 0;
+ };
+ inline void Clear(){};
+
+ void Export(FILE* hFile);
+
+ // BJ_UINT64 m_Key;
+ char m_Value[255];
+ BJ_UINT64 m_nBytes;
+ BJ_UINT64 m_nFrames;
+ BJ_UINT64 m_nQuestionFrames;
+ BJ_UINT64 m_nAnswerFrames;
+ BJ_UINT64 m_nLastFrameIndex;
+ BJ_UINT64 m_nLastQueryFrameIndex;
+ BJ_UINT64 m_nLastRespondsFrameIndex;
+ BJ_UINT64 m_nLastWakeFrameIndex;
+ CIPAddrMap m_DeviceAskingTree;
+ BJ_UINT64 m_nDeviceAskingCount;
+ CIPAddrMap m_DeviceAnsweringTree;
+ BJ_UINT64 m_nDeviceAnsweringCount;
+ CIPAddrMap m_DeviceTotalTree;
+ BJ_UINT64 m_nDeviceTotalCount;
+ BJ_UINT64 m_nWakeFrames;
+ BJ_UINT64 m_lastQUFrameTime;
+ BJ_UINT64 m_nGoodbyeFrames;
+};
+
+class CStringShortTree: public CLLRBTree<BJ_UINT64, CStringShortNode>
+{
+public:
+};
+
+///////////
+
+
+class CBonjourTop
+{
+public:
+ CBonjourTop();
+
+ void SetIPAddr(const char*);
+ void LiveCapture();
+ void CaptureFile();
+
+ void PrintResults(int nSortCol, bool bSortAsc);
+ void UpdateOSCounts();
+ void PrintDetailResults(int nSortCol, bool bSortAsc);
+ void ExportResults();
+ void Reset();
+
+ void WriteDeviceFile();
+ void WriteVendorFile();
+
+ void ProcessFrame(BJ_UINT8* pBuffer,BJ_INT32 nLength, BJ_UINT64 frameTime);
+ bool Name2OSType(BJString name,CDeviceNode* device);
+
+ void UpdateRecord(CStringTree &Cache,CDNSRecord* pDNSRecord,BJString& RecordName,BJString& ServiceName,BJ_UINT32 nBytes,bool bGoodbye);
+
+ void UpdateShortRecordHelper(BJ_UINT32 cacheType, BJ_UINT32 tracePlatform, BJ_UINT32 traceVersion, char deviceOS, CDNSRecord* pDNSRecord,BJString& RecordName,BJString& ServiceName,BJ_UINT32 nBytes,bool bGoodbye);
+
+ void UpdateShortRecord(CStringShortTree* Cache,CDNSRecord* pDNSRecord,BJString& RecordName,BJString& ServiceName,BJ_UINT32 nBytes,bool bGoodbye);
+
+ void GetOSTypeFromQuery(CDNSRecord *pDNSRecord,BJString& ServiceName);
+ void GetOSTypeFromRegistration(CDNSRecord *pDNSRecord,BJString& ServiceName);
+
+ CStringNode* GetCurrentDisplayRoot(BJString &sTitle);
+ void ExportPtrCache(FILE* hFile, BJString sTitle, CStringNode* pRoot);
+ void ExportShortCache(FILE* hFile, BJString sTitle, map<BJString, CStringShortTree*>* myMap);
+ void ExportShortCacheHelper(FILE* hFile, BJString sTitle, CStringShortNode* pRoot);
+
+ void WindowSizeChanged();
+
+ bool m_bCursers;
+ const char* m_pTcpDumpFileName;
+ const char* m_pExportFileName;
+ bool window_size_changed;
+ bool m_bImportExportDeviceMap;
+ BJString m_DeviceFileName;
+
+ CDNSFrame m_Frame;
+
+#define NUM_SOCKET_STATUS 6
+#define HOURS_IN_DAY 24
+#define MINUTES_IN_HOUR 60
+
+ CSocketStats m_SocketStatus[NUM_SOCKET_STATUS];
+
+ CSocketStats m_MinSnapshot[HOURS_IN_DAY][MINUTES_IN_HOUR];
+
+ BJ_UINT64 m_nFrameCount;
+ BJ_UINT64 m_nTotalBytes;
+ long m_StartTime;
+ long m_EndTime;
+ BJ_UINT64 m_MinAnswerCountForTruncatedFrames;
+ BJ_UINT64 m_AvgAnswerCountForTruncatedFrames;
+ BJ_UINT64 m_MaxAnswerCountForTruncatedFrames;
+
+ BJIPAddr m_IPv4Addr;
+
+ BJStringtoStringMap m_Service2AppMap;
+
+ BJStringtoStringMap m_Service2osRegisterMap;
+ BJStringtoStringMap m_Service2osBrowseMap;
+
+ enum BJ_DISPLAY_MODE_ENUM {
+ BJ_DISPLAY_APP,
+ BJ_DISPLAY_APPv6,
+ BJ_DISPLAY_SERVICE,
+ BJ_DISPLAY_SERVICEv6,
+ BJ_DISPLAY_24_MIN
+ } m_CurrentDisplay ;
+
+ BJ_INT32 m_SnapshotSeconds;
+
+ CStringTree m_ServicePtrCache;
+ CStringTree m_ApplPtrCache;
+
+ CStringTree m_ServicePtrCacheIPv6;
+ CStringTree m_ApplPtrCacheIPv6;
+
+ map<BJString, CStringShortTree*> m_ServiceBreakdownIPv4OSX;
+ map<BJString, CStringShortTree*> m_ServiceBreakdownIPv4iOS;
+ map<BJString, CStringShortTree*> m_ServiceBreakdownIPv6OSX;
+ map<BJString, CStringShortTree*> m_ServiceBreakdownIPv6iOS;
+
+ map<BJString, CStringShortTree*> m_AppBreakdownIPv4OSX;
+ map<BJString, CStringShortTree*> m_AppBreakdownIPv4iOS;
+ map<BJString, CStringShortTree*> m_AppBreakdownIPv6OSX;
+ map<BJString, CStringShortTree*> m_AppBreakdownIPv6iOS;
+
+ CDeviceMap m_DeviceMap;
+
+ CMACAddrTree m_MacMap;
+ CIPAddrMap m_IPtoNameMap;
+ CMACDeviceMap m_MACtoDevice;
+ BJStringtoStringMap SVRtoDeviceName;
+
+ Collection m_Collection;
+
+ BJString interfaceName;
+ BJString filterApplicationName;
+
+
+};
+
+#endif /* defined(__TestTB__BonjourTop__) */
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/CaptureFile.cpp b/mDNSResponder/mDNSMacOSX/BonjourTop/source/CaptureFile.cpp
new file mode 100644
index 00000000..5dc33497
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/CaptureFile.cpp
@@ -0,0 +1,141 @@
+//
+// CaptureFile.cpp
+// TestTB
+//
+// Created by Terrin Eager on 9/14/12.
+//
+//
+
+#include "CaptureFile.h"
+#include <stdio.h>
+#include <pcap.h>
+#include <sys/types.h>
+
+#define BJ_MAX_PACKET (1024*20)
+
+struct packetheader
+{
+ __uint32_t sec;
+ __uint32_t usec;
+ __uint32_t captureLen;
+ __uint32_t origLen;
+
+};
+
+
+CCaptureFile::CCaptureFile()
+{
+ m_pFileHeader = NULL;
+ m_pFrameData = NULL;
+ m_pFrameHeader = NULL;
+ m_hFile = NULL;
+
+ m_nFirstFrameTime = 0;
+
+ if (!Init())
+ Clear();
+}
+CCaptureFile::~CCaptureFile()
+{
+ Clear();
+}
+
+bool CCaptureFile::Init()
+{
+ m_pFileHeader = new BJ_UINT8[sizeof(pcap_file_header)];
+ m_pFrameHeader = new BJ_UINT8[sizeof(packetheader)];
+ m_pFrameData = new BJ_UINT8[BJ_MAX_PACKET];
+
+ return (m_pFrameHeader && m_pFrameData && m_pFileHeader);
+}
+
+bool CCaptureFile::Clear()
+{
+ delete m_pFileHeader; m_pFileHeader = NULL;
+ delete m_pFrameData; m_pFrameData = NULL;
+ delete m_pFrameHeader; m_pFrameHeader = NULL;
+
+ fclose(m_hFile); m_hFile = NULL;
+ return true;
+}
+
+bool CCaptureFile::Open(const char* pFileName)
+{
+ m_hFile = fopen(pFileName, "r");
+
+ if (!m_hFile)
+ {
+ printf("Failed to open %s\n",pFileName);
+ return false;
+ }
+
+
+ fread(m_pFileHeader, sizeof(pcap_file_header), 1,m_hFile);
+
+ // pcap_file_header* pHeader = (pcap_file_header*)m_pFileHeader;
+ // int magic = pHeader->magic;
+ // int nType = pHeader->linktype;
+
+ pcap_file_header* pHeader = (pcap_file_header*)m_pFileHeader;
+ m_datalinkType = (Frame::BJ_DATALINKTYPE) pHeader->linktype;
+ m_CurrentFrame.SetDatalinkType(m_datalinkType);
+ return true;
+}
+
+bool CCaptureFile::NextFrame()
+{
+ packetheader* pFrameHeader = NULL;
+
+ if(!m_hFile)
+ return false;
+
+ if (fread(m_pFrameHeader,1,sizeof(packetheader),m_hFile)< sizeof(packetheader))
+ return false;
+
+ pFrameHeader = (packetheader*) m_pFrameHeader;
+
+ m_nWireLen = pFrameHeader->origLen;
+ m_TimeSec = pFrameHeader->sec;
+ if (m_nFirstFrameTime == 0)
+ m_nFirstFrameTime = m_TimeSec;
+ m_nCaptureLen = pFrameHeader->captureLen; // to do handle frames bigger than buffer
+
+ long nSkip = 0;
+ if (m_nCaptureLen > BJ_MAX_PACKET)
+ { // force truncate the packet ...
+ nSkip = m_nCaptureLen - BJ_MAX_PACKET;
+ m_nCaptureLen = BJ_MAX_PACKET;
+ }
+
+ if (fread(m_pFrameData,1,m_nCaptureLen,m_hFile) < m_nCaptureLen)
+ return false;
+
+ if (nSkip)
+ fseek(m_hFile, nSkip, SEEK_CUR);
+
+ m_CurrentFrame.Set(m_pFrameData, m_nCaptureLen,pFrameHeader->sec*1000000ll + pFrameHeader->usec);
+
+
+ return true;
+}
+
+bool CCaptureFile::Close()
+{
+
+ return true;
+}
+
+__uint32_t CCaptureFile::GetDeltaTime()
+{
+ return m_TimeSec-m_nFirstFrameTime;
+}
+
+__uint32_t CCaptureFile::GetBufferLen(BJ_UINT8* pStart)
+{
+ return m_nCaptureLen - (__uint32_t) (pStart - m_pFrameData);
+}
+
+
+
+
+
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/CaptureFile.h b/mDNSResponder/mDNSMacOSX/BonjourTop/source/CaptureFile.h
new file mode 100644
index 00000000..ea625bac
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/CaptureFile.h
@@ -0,0 +1,55 @@
+//
+// CaptureFile.h
+// TestTB
+//
+// Created by Terrin Eager on 9/14/12.
+//
+//
+
+#ifndef __TestTB__CaptureFile__
+#define __TestTB__CaptureFile__
+
+#include <iostream>
+#include "bjtypes.h"
+#include "bjsocket.h"
+#include "Frame.h"
+
+class CCaptureFile
+{
+public:
+ CCaptureFile();
+ virtual ~CCaptureFile();
+ bool Open(const char* pFileName);
+ bool NextFrame();
+ bool Close();
+
+ Frame m_CurrentFrame;
+
+
+
+ __uint32_t GetDeltaTime();
+
+ __uint32_t GetBufferLen(BJ_UINT8* pStart);
+
+ __uint32_t GetWiredLength(){ return m_nWireLen;};
+
+
+private:
+ bool Init();
+ bool Clear();
+
+ FILE* m_hFile;
+ BJ_UINT8* m_pFrameHeader;
+ BJ_UINT8* m_pFrameData;
+ BJ_UINT8* m_pFileHeader;
+ __uint32_t m_nCaptureLen;
+ __uint32_t m_nWireLen;
+ __uint32_t m_TimeSec;
+
+ __uint32_t m_nFirstFrameTime;
+
+ Frame::BJ_DATALINKTYPE m_datalinkType;
+
+};
+
+#endif /* defined(__TestTB__CaptureFile__) */
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/CollectBy.cpp b/mDNSResponder/mDNSMacOSX/BonjourTop/source/CollectBy.cpp
new file mode 100644
index 00000000..9387fcab
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/CollectBy.cpp
@@ -0,0 +1,314 @@
+//
+// CollectBy.cpp
+// TestTB
+//
+// Created by Terrin Eager on 3/17/13.
+//
+//
+
+#include <iostream>
+#include "bjtypes.h"
+#include "DNSFrame.h"
+#include "bjstring.h"
+#include "LLRBTree.h"
+
+#include "CollectBy.h"
+
+
+//////////////////////
+// Collection
+void Collection::Init(BJ_COLLECTBY_TYPE collectByList[])
+{
+ CollectByAbstract* pLastCollectBy = nullptr;
+
+ for (int i=0; i<20 && collectByList[i] != CBT_NOT_SET;i++)
+ {
+ m_CollectByList[i] = collectByList[i];
+ if (i==0)
+ {
+ m_pHeaderCollectBy = Factory(m_CollectByList[i]);
+ pLastCollectBy = m_pHeaderCollectBy;
+ m_pFirstCollectBy = pLastCollectBy->Factory();
+ }
+ else
+ {
+ pLastCollectBy->pNext = Factory(m_CollectByList[i]);
+ pLastCollectBy = pLastCollectBy->pNext;
+ }
+ }
+}
+
+void Collection::ProcessFrame(CDNSFrame* pFrame)
+{
+ m_pFirstCollectBy->Collect(pFrame,m_pHeaderCollectBy->pNext);
+}
+
+void Collection::ExportCollection(BJString sFileName)
+{
+ FILE* hFile = fopen(sFileName.GetBuffer(),"w");
+
+ if (hFile == NULL)
+ {
+ printf("file open failed %s\n",sFileName.GetBuffer());
+ return;
+ }
+
+ // Export Header Line
+ CollectByAbstract *collectBy = m_pHeaderCollectBy;
+ BJString sHeader;
+ while (collectBy)
+ {
+ if (sHeader.GetBufferLength() != 0)
+ sHeader += ",";
+ sHeader += collectBy->GetTitle();
+ collectBy = collectBy->pNext;
+ }
+ fprintf(hFile, "%s\n",sHeader.GetBuffer());
+
+ m_pFirstCollectBy->Export(hFile,"");
+
+ fclose(hFile);
+}
+
+CollectByAbstract* Collection::Factory(BJ_COLLECTBY_TYPE type)
+{
+ switch (type)
+ {
+ case CBT_NOT_SET:
+ return NULL;
+ case CBT_SERVICE:
+ return new CollectByService();
+ case CBT_REQUEST_RESPONDS:
+ return new CollectByRequestResponds();
+ case CBT_SAME_DIFF_SUBNET:
+ return new CollectBySameSubnetDiffSubnet();
+ case CBT_IP_ADDRESS_TYPE:
+ return new CollectByIPAddressType();
+ case CBT_PACKET:
+ return new CollectByPacketCount();
+ default:
+ return NULL;
+ }
+
+}
+
+/////////////
+// CollectByService
+
+void CServiceNode::Export(FILE* hFile,BJString sPrevColumns)
+{
+ if (pNext)
+ {
+ BJString sTemp = sPrevColumns;
+ if (sPrevColumns.GetBufferLength())
+ sTemp += ",";
+ sTemp += m_Key;
+ pNext->Export(hFile,sTemp);
+ }
+ if (m_rbLeft)
+ dynamic_cast<CServiceNode*>(m_rbLeft)->Export(hFile,sPrevColumns);
+ if (m_rbRight)
+ dynamic_cast<CServiceNode*>(m_rbRight)->Export(hFile,sPrevColumns);
+}
+
+void CollectByService::Collect(CDNSFrame* pFrame,CollectByAbstract* nextCollectBy)
+{
+ for (int dnsItemsIndex =0; dnsItemsIndex < pFrame->GetQuestionCount()+pFrame->GetAnswerCount();dnsItemsIndex++)
+ {
+ BJString RecordName;
+ CDNSRecord* pDNSRecord = pFrame->GetDnsRecord(dnsItemsIndex);
+ if (pDNSRecord == NULL)
+ continue;
+
+ pDNSRecord->GetDnsRecordName(RecordName,0,99);
+
+ if (RecordName.Contains("_kerberos."))
+ {
+ RecordName = "_kerberos.";
+ }
+ else
+ pDNSRecord->GetDnsRecordName(RecordName, (pDNSRecord->m_RecType == 12)?0:1,99);
+
+ if (pDNSRecord->m_RecType == 12)
+ {
+ if (RecordName.Contains(".ip6.arpa."))
+ RecordName = "*.ip6.arpa.";
+ else if (RecordName.Contains(".arpa."))
+ RecordName = "*.arpa.";
+ }
+ if (pDNSRecord->m_RecType == 1)
+ RecordName = "A";
+ if (pDNSRecord->m_RecType == 28)
+ RecordName = "AAAA";
+ if (pDNSRecord->m_RecType == 255)
+ {
+ if (RecordName.Contains(".ip6.arpa."))
+ RecordName = "ANY *.ip6.arpa.";
+ else if (RecordName.Contains(".arpa."))
+ RecordName = "ANY *.arpa.";
+ else
+ RecordName = "Any";
+ }
+ if (RecordName.Contains("_sub."))
+ {
+ pDNSRecord->GetDnsRecordName(RecordName,2,99); /// skip first label and _sub. label
+ }
+
+
+ CServiceNode *pNode= m_Cache.FindwithAddRecord(&RecordName);
+ if (pNode->pNext == NULL)
+ pNode->pNext = nextCollectBy->Factory();
+ pNode->pNext->Collect(pFrame,nextCollectBy?nextCollectBy->pNext:NULL);
+
+ }
+
+}
+
+
+
+
+void CollectByService::Export(FILE* hFile,BJString sPrevColumns)
+{
+
+ // loop thur list
+ CServiceNode *pNode = m_Cache.GetRoot();
+
+ if (pNode)
+ pNode->Export(hFile,sPrevColumns);
+}
+
+/////////////
+// CollectByRequestResponds
+void CollectByRequestResponds::Collect(CDNSFrame* pFrame,CollectByAbstract* nextCollectBy)
+{
+ if (pFrame->IsQueryFrame())
+ {
+ if (pRequestNext == NULL)
+ pRequestNext = nextCollectBy->Factory();
+ pRequestNext->Collect(pFrame, nextCollectBy?nextCollectBy->pNext:NULL);
+ }
+ else
+ {
+ if (pRespondsNext == NULL)
+ pRespondsNext = nextCollectBy->Factory();
+ pRespondsNext->Collect(pFrame, nextCollectBy?nextCollectBy->pNext:NULL);
+ }
+}
+
+void CollectByRequestResponds::Export(FILE* hFile,BJString sPrevColumns)
+{
+ if (pRequestNext)
+ {
+ BJString sTemp = sPrevColumns;
+ if (sPrevColumns.GetBufferLength())
+ sTemp += ",";
+ sTemp += "Request";
+ pRequestNext->Export(hFile,sTemp);
+ }
+ if (pRespondsNext)
+ {
+ BJString sTemp = sPrevColumns;
+ if (sPrevColumns.GetBufferLength())
+ sTemp += ",";
+ sTemp += "Responds";
+ pRespondsNext->Export(hFile,sTemp);
+ }
+}
+/////////////
+// CollectByIPAddressType
+void CollectByIPAddressType::Collect(CDNSFrame* pFrame,CollectByAbstract* nextCollectBy)
+{
+ if (pFrame->m_SourceIPAddress.IsIPv4())
+ {
+ if (pIPv4Next == NULL)
+ pIPv4Next = nextCollectBy->Factory();
+ pIPv4Next->Collect(pFrame, nextCollectBy?nextCollectBy->pNext:NULL);
+ }
+ if (pFrame->m_SourceIPAddress.IsIPv6())
+ {
+ if (pIPv6Next == NULL)
+ pIPv6Next = nextCollectBy->Factory();
+ pIPv6Next->Collect(pFrame, nextCollectBy?nextCollectBy->pNext:NULL);
+ }
+}
+void CollectByIPAddressType::Export(FILE* hFile,BJString sPrevColumns)
+{
+ if (pIPv4Next)
+ {
+ BJString sTemp = sPrevColumns;
+ if (sPrevColumns.GetBufferLength())
+ sTemp += ",";
+ sTemp += "IPv4";
+ pIPv4Next->Export(hFile,sTemp);
+ }
+ if (pIPv6Next)
+ {
+ BJString sTemp = sPrevColumns;
+ if (sPrevColumns.GetBufferLength())
+ sTemp += ",";
+ sTemp += "IPv6";
+ pIPv6Next->Export(hFile,sTemp);
+ }
+}
+/////////////
+// CollectBySameSubnetDiffSubnet:
+
+// static
+bool CollectBySameSubnetDiffSubnet::bSameSubnet = true;
+
+void CollectBySameSubnetDiffSubnet::Collect(CDNSFrame* pFrame,CollectByAbstract* nextCollectBy)
+{
+ if (bSameSubnet)
+ {
+ if (pSameSubnetNext == NULL)
+ pSameSubnetNext = nextCollectBy->Factory();
+ pSameSubnetNext->Collect(pFrame, nextCollectBy?nextCollectBy->pNext:NULL);
+ }
+ else
+ {
+ if (pDiffSubnetNext == NULL)
+ pDiffSubnetNext = nextCollectBy->Factory();
+ pDiffSubnetNext->Collect(pFrame, nextCollectBy?nextCollectBy->pNext:NULL);
+ }
+
+}
+void CollectBySameSubnetDiffSubnet::Export(FILE* hFile,BJString sPrevColumns)
+{
+ if (pSameSubnetNext)
+ {
+ BJString sTemp = sPrevColumns;
+ if (sPrevColumns.GetBufferLength())
+ sTemp += ",";
+ sTemp += "SameSubnet";
+ pSameSubnetNext->Export(hFile,sTemp);
+ }
+ if (pDiffSubnetNext)
+ {
+ BJString sTemp = sPrevColumns;
+ if (sPrevColumns.GetBufferLength())
+ sTemp += ",";
+ sTemp += "WrongSubnet";
+ pDiffSubnetNext->Export(hFile,sTemp);
+ }
+}
+/////////////
+// CollectByPacketCount
+
+// staticCollectByPacketCount
+BJ_INT64 CollectByPacketCount::nFrameIndex = 0;
+
+void CollectByPacketCount::Collect(CDNSFrame* ,CollectByAbstract* )
+{
+ if (nFrameIndex != nLastFrameIndex)
+ {
+ nFrameCount++;
+ nLastFrameIndex = nFrameIndex;
+ }
+}
+void CollectByPacketCount::Export(FILE* hFile,BJString sPrevColumns)
+{
+
+ fprintf(hFile,"%s,%llu\n",sPrevColumns.GetBuffer(),nFrameCount);
+}
+
+
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/CollectBy.h b/mDNSResponder/mDNSMacOSX/BonjourTop/source/CollectBy.h
new file mode 100644
index 00000000..80ff0d58
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/CollectBy.h
@@ -0,0 +1,155 @@
+//
+// CollectBy.h
+// TestTB
+//
+// Created by Terrin Eager on 3/17/13.
+//
+//
+
+#ifndef __TestTB__CollectBy__
+#define __TestTB__CollectBy__
+
+#include <iostream>
+#include "bjtypes.h"
+#include "DNSFrame.h"
+#include "bjstring.h"
+#include "LLRBTree.h"
+
+
+// Service request/Respond v4/v6 sameSubnet/DifferentSubnet
+
+enum BJ_COLLECTBY_TYPE
+{
+ CBT_NOT_SET,
+ CBT_SERVICE,
+ CBT_REQUEST_RESPONDS,
+ CBT_SAME_DIFF_SUBNET,
+ CBT_IP_ADDRESS_TYPE,
+ CBT_PACKET
+};
+
+class CollectByAbstract;
+class Collection
+{
+public:
+ Collection() {m_pHeaderCollectBy = NULL;m_pFirstCollectBy = NULL;};
+
+ void Init(BJ_COLLECTBY_TYPE collectByList[]);
+ void ProcessFrame(CDNSFrame* pFrame);
+
+ void ExportCollection(BJString sFileName);
+ bool IsValid() { return (m_pFirstCollectBy != NULL);};
+private:
+ CollectByAbstract* Factory(BJ_COLLECTBY_TYPE type);
+
+ BJ_COLLECTBY_TYPE m_CollectByList[20];
+ CollectByAbstract* m_pHeaderCollectBy;
+ CollectByAbstract* m_pFirstCollectBy;
+
+};
+
+class CollectByAbstract
+{
+public:
+ CollectByAbstract()
+ {
+ pNext = NULL;
+ }
+
+ virtual void Collect(CDNSFrame* pFrame,CollectByAbstract* nextCollectBy)=0;
+ virtual const char* GetTitle()=0;
+ virtual CollectByAbstract* Factory()=0;
+ virtual void Export(FILE* hFile,BJString sPrevColumns)=0;
+
+ CollectByAbstract* pNext;
+};
+/////////////
+// Service
+class CServiceNode : public CRBNode<BJString>
+{
+public:
+ CServiceNode() {pNext = NULL;};
+ CServiceNode(BJString* pKey){ m_Key = *pKey;};
+ ~CServiceNode(){};
+ inline virtual BJ_COMPARE Compare(BJString* pKey) { return m_Key.Compare(*pKey);};
+ inline virtual void CopyNode(CRBNode* pSource) {pNext = dynamic_cast<CServiceNode*>(pSource)->pNext;} ;
+ inline virtual void Init(){};
+ inline virtual void Clear() {};
+ void Export(FILE* hFile,BJString sPrevColumns);
+ CollectByAbstract* pNext;
+
+};
+
+class CServiceToCollectByMap : public CLLRBTree<BJString, CServiceNode>
+{
+public:
+
+
+};
+
+class CollectByService:public CollectByAbstract
+{
+public:
+ virtual void Collect(CDNSFrame* pFrame,CollectByAbstract* nextCollectBy);
+ virtual const char* GetTitle() {return "Service";};
+ virtual CollectByAbstract* Factory(){ return new CollectByService();};
+ virtual void Export(FILE* hFile,BJString sPrevColumns);
+private:
+ CServiceToCollectByMap m_Cache;
+};
+
+class CollectByRequestResponds:public CollectByAbstract
+{
+public:
+ virtual void Collect(CDNSFrame* pFrame,CollectByAbstract* nextCollectBy);
+ virtual const char* GetTitle() {return "Request/Responds";};
+ virtual CollectByAbstract* Factory(){ return new CollectByRequestResponds();};
+ virtual void Export(FILE* hFile,BJString sPrevColumns);
+
+private:
+ CollectByAbstract* pRequestNext;
+ CollectByAbstract* pRespondsNext;
+};
+
+class CollectByIPAddressType:public CollectByAbstract
+{
+public:
+ virtual void Collect(CDNSFrame* pFrame,CollectByAbstract* nextCollectBy);
+ virtual const char* GetTitle() {return "V4/V6";};
+ virtual CollectByAbstract* Factory(){ return new CollectByIPAddressType();};
+ virtual void Export(FILE* hFile,BJString sPrevColumns);
+private:
+ CollectByAbstract* pIPv4Next;
+ CollectByAbstract* pIPv6Next;
+};
+
+class CollectBySameSubnetDiffSubnet:public CollectByAbstract
+{
+public:
+ virtual void Collect(CDNSFrame* pFrame,CollectByAbstract* nextCollectBy);
+ virtual const char* GetTitle() {return "SameSubnet/DiffSubnet";};
+ virtual CollectByAbstract* Factory(){ return new CollectBySameSubnetDiffSubnet();};
+ virtual void Export(FILE* hFile,BJString sPrevColumns);
+
+ static bool bSameSubnet;
+private:
+ CollectByAbstract* pSameSubnetNext;
+ CollectByAbstract* pDiffSubnetNext;
+};
+
+class CollectByPacketCount:public CollectByAbstract
+{
+
+public:
+ virtual void Collect(CDNSFrame* pFrame,CollectByAbstract* nextCollectBy);
+ virtual const char* GetTitle() {return "Packets";};
+ virtual CollectByAbstract* Factory(){ return new CollectByPacketCount();};
+ virtual void Export(FILE* hFile,BJString sPrevColumns);
+
+ BJ_INT64 nFrameCount;
+ BJ_INT64 nLastFrameIndex;
+ static BJ_INT64 nFrameIndex;
+};
+
+
+#endif /* defined(__TestTB__CollectBy__) */
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/DNSFrame.cpp b/mDNSResponder/mDNSMacOSX/BonjourTop/source/DNSFrame.cpp
new file mode 100644
index 00000000..1e8586a0
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/DNSFrame.cpp
@@ -0,0 +1,384 @@
+//
+// DNSFrame.cpp
+// TestTB
+//
+// Created by Terrin Eager on 9/26/12.
+//
+//
+
+#include "DNSFrame.h"
+
+#define DNS_LABEL_MAX_LENGTH 63
+#define DNS_NAME_MAX_LENGTH 255
+
+void CDNSRecord::GetDnsRecordName(BJString& ReturnString,int nLabelToSkip,int nMaxLabel)
+{
+ GetDnsRecordNameFromBuffer(m_pStartofRec, ReturnString, nLabelToSkip, nMaxLabel);
+}
+
+void CDNSRecord::GetDnsRecordNameFromBuffer(BJ_UINT8* pBuffer,BJString& ReturnString,int nLabelToSkip,int nMaxLabel)
+{
+ BJ_UINT8* pNameBuffer = NULL;
+ int nOffset = 0;
+ // char* pTemp = pReturnBuffer;
+ int nCharCount = 0;
+ int nSkippedLabels = 0;
+ int nLabelProcessed = 0;
+ ReturnString.Set(NULL,255);
+
+ if (ReturnString.GetBuffer() == NULL)
+ return;
+
+ pNameBuffer = pBuffer;
+ if (pNameBuffer == NULL)
+ {
+ return;
+ }
+
+ while (ReturnString.GetBufferLength() < 1024)
+ {
+ nCharCount = *pNameBuffer++;
+ if (nCharCount == 0)
+ break;
+
+ if ((nCharCount&(DNS_NAME_OFFSET_MASK)) == DNS_NAME_OFFSET_MASK)
+ {
+ nOffset = *pNameBuffer++;
+ nOffset |= (nCharCount&(~DNS_NAME_OFFSET_MASK)) << 8;
+ pNameBuffer = m_pDNSFrame->GetBuffer() + nOffset;
+ continue;
+ }
+
+ if (nCharCount > DNS_LABEL_MAX_LENGTH)
+ {
+ printf("label too long %d\n",nCharCount);
+ break;
+ }
+
+ if (ReturnString.GetLength() + nCharCount + 1 > DNS_NAME_MAX_LENGTH) // + 1 is for the '.' added later on
+ {
+ printf("Name exceeded limit allowed for DNS: %d\n", ReturnString.GetLength() + nCharCount + 1);
+ break;
+ }
+
+ if (nLabelToSkip > nSkippedLabels)
+ {
+ nSkippedLabels++;
+ pNameBuffer += nCharCount;
+ continue;
+ }
+ ReturnString.Append((char*)pNameBuffer, nCharCount);
+ pNameBuffer+= nCharCount;
+ nLabelProcessed++;
+
+ if (nLabelProcessed >= nMaxLabel)
+ return;
+
+ ReturnString += ".";
+ }
+}
+
+
+
+
+CDNSFrame::CDNSFrame()
+{
+
+ for(int nIndex=0; nIndex < MAX_DNS_RECORDS_PER_FRAME; nIndex++)
+ m_dnsItems[nIndex].m_pDNSFrame = this;
+
+}
+
+CDNSRecord* CDNSFrame::GetDnsRecord(int nIndex)
+{
+ if (nIndex > m_nMaxItems)
+ return NULL;
+ return &m_dnsItems[nIndex];
+}
+
+bool CDNSFrame::ParseDNSFrame(BJ_UINT8* pBuffer,BJ_INT32 nLength, BJ_UINT64 frameTime)
+{
+ if (pBuffer == NULL)
+ return false;
+
+ int nIndex = 0;
+
+ m_Servicev4Address.Empty();
+ m_Servicev6Address.Empty();
+
+ m_pStartBuffer = pBuffer;
+ m_nFrameLen = (BJ_UINT32) nLength;
+
+ m_pCurrentBuffer = m_pStartBuffer;
+ m_pEndBuffer = m_pStartBuffer + m_nFrameLen;
+ m_Time = frameTime;
+
+ m_nId = PF_GET_UINT16(m_pStartBuffer,0);
+ m_nFlags = PF_GET_UINT16(m_pStartBuffer,2);
+ m_nQuestionCount = PF_GET_UINT16(m_pStartBuffer,4);
+ m_nAnswersCount = PF_GET_UINT16(m_pStartBuffer,6);
+ m_NSCOUNT = PF_GET_UINT16(m_pStartBuffer,8);
+ m_ARCOUNT = PF_GET_UINT16(m_pStartBuffer,10);
+
+ m_nMaxItems = 0;
+
+
+
+ // printf("FrameNum= %d,nQuestionCount= %d nAnswersCount= %d NSCOUNT= %d ARCOUNT= %d\n",nFrameCount++,m_nQuestionCount, m_nAnswersCount,m_NSCOUNT, m_ARCOUNT);
+
+ m_pCurrentBuffer = m_pStartBuffer + 12;
+
+
+ for (nIndex =0; nIndex < m_nQuestionCount;nIndex++)
+ {
+ // printf("FramePosition= %ld ",m_pCurrentBuffer);
+ ParseDnsRecord(CDNSRecord::Question);
+
+ }
+ for (nIndex =0; nIndex < m_nAnswersCount;nIndex++)
+ {
+ // printf("FramePosition= %ld ",m_pCurrentBuffer);
+ ParseDnsRecord(CDNSRecord::Answer);
+ }
+ for (nIndex =0; nIndex < m_NSCOUNT;nIndex++)
+ {
+ // printf("FramePosition= %ld ",m_pCurrentBuffer);
+ ParseDnsRecord(CDNSRecord::Answer);
+ }
+ for (nIndex =0; nIndex < m_ARCOUNT;nIndex++)
+ {
+ // printf("FramePosition= %ld ",m_pCurrentBuffer);
+ ParseDnsRecord(CDNSRecord::Answer);
+ CDNSRecord* pRecord = &m_dnsItems[m_nMaxItems-1];
+ if (pRecord->m_RecType == DNS_TYPE_AAAA && m_Servicev6Address.IsEmpty())
+ {
+ m_Servicev6Address.Setv6Raw(pRecord->GetStartofRdata());
+ }
+ if (pRecord->m_RecType == DNS_TYPE_A && m_Servicev4Address.IsEmpty())
+ {
+ m_Servicev4Address.Setv4Raw(pRecord->GetStartofRdata());
+ }
+ }
+ //
+ /// for (dnsItemsIndex =0; dnsItemsIndex < m_nQuestionCount+m_nAnswersCount;dnsItemsIndex++)
+ /// {
+ /// printf("Name = %s\n", GetDnsRecordName(&Frame,dnsItemsIndex,tempBuffer,sizeof(tempBuffer)));
+ // }
+ return true;
+}
+
+BJ_BOOL CDNSFrame::ParseDnsRecord(CDNSRecord::dnsItemType eItemType)
+{
+ unsigned char nCharCount = 0;
+ BJ_UINT8* pTemp = m_pCurrentBuffer;
+ CDNSRecord* pRecord = &m_dnsItems[m_nMaxItems++];
+
+ //temp
+ BJ_UINT16 nRdataLen = 0;
+ BJ_UINT16 nRdataLen2 = 0;
+
+ if (pTemp > m_pEndBuffer)
+ {
+ printf("Error in ParseDnsRecord pBuffer > pEndBuffer\n");
+ pRecord->m_pStartofRec = NULL;
+ pRecord->m_nNameLength = 0;
+ return false;
+ }
+
+
+ pRecord->m_pStartofRec = pTemp;
+ pRecord->m_nNameLength = 0;
+ pRecord->m_nRdataLen = 0;
+
+
+ // Skip over Name;
+ while (pTemp < m_pEndBuffer)
+ {
+ nCharCount = *pTemp;
+ pTemp++;
+
+ if (nCharCount == 0)
+ break;
+
+ if ((nCharCount&(DNS_NAME_OFFSET_MASK)) == DNS_NAME_OFFSET_MASK)
+ { // offset string
+ pTemp++;
+ break;
+ }
+
+ if (nCharCount > DNS_LABEL_MAX_LENGTH)
+ {
+ printf("%d. label too long %d\n",m_nMaxItems-1,nCharCount);
+ }
+
+ if (pTemp + nCharCount < m_pEndBuffer)
+ pTemp += nCharCount;
+ else
+ pTemp = m_pEndBuffer;
+ }
+
+ pRecord->m_nNameLength = (BJ_UINT32)(pTemp - pRecord->m_pStartofRec);
+
+ if (eItemType == CDNSRecord::Question)
+ {
+ pRecord->m_RecType = PF_GET_UINT16(pTemp,0);
+ pRecord->m_RecClass = PF_GET_UINT16(pTemp,2);
+ pRecord->m_nTTL = PF_GET_UINT16(pTemp,4);
+
+ // printf("Namelen=%u, Type=%u, class=%u, TTL=%u, RDLength=%u\n", m_dnsItems[ndnsIndex].nNameLength,nType,nClass,nTTL,nRdataLen);
+
+ pTemp += 4;
+ }
+ else
+ {
+
+ pRecord->m_RecType = PF_GET_UINT16(pTemp,0);
+ pRecord->m_RecClass = PF_GET_UINT16(pTemp,2);
+
+ pRecord->m_nTTL = PF_GET_UINT32(pTemp,4);
+ pRecord->m_nRdataLen = PF_GET_UINT16(pTemp,8);
+ if (nRdataLen > 1024*10)
+ {
+ printf("large Rdata ??");
+ nRdataLen2 = (pTemp[8] << 8) | pTemp[9];
+
+ }
+ // printf("Namelen=%u, Type=%u, class=%u, TTL=%u, RDLength=%u\n", m_dnsItems[ndnsIndex].nNameLength,m_dnsItems[ndnsIndex].RecType,nClass,nTTL,m_dnsItems[ndnsIndex].nRdataLen);
+ pTemp += 10 + pRecord->m_nRdataLen;
+ }
+
+ m_pCurrentBuffer = pTemp;
+
+ return true;
+}
+
+BJ_BOOL CDNSFrame::IsQueryFrame()
+{
+ return !(m_nFlags&0x8000);
+}
+
+#define UNICAST_RESPONDS_REQUESTED 0x8000
+BJ_BOOL CDNSFrame::IsWakeFrame()
+{
+
+ for (int i=0; i < m_nQuestionCount; i++)
+ {
+ if (m_dnsItems[i].m_RecType == DNS_TYPE_PTR && m_dnsItems[i].m_RecClass & UNICAST_RESPONDS_REQUESTED)
+ return true;
+ }
+
+ return false;
+}
+#define DNS_HEADER_TRUNCATEED 0x0200
+BJ_BOOL CDNSFrame::IsTruncatedFrame()
+{
+ return (m_nFlags&DNS_HEADER_TRUNCATEED);
+}
+
+
+BJ_BOOL CDNSFrame::HasOnlyService(BJString sName, BJ_INT16 nRecType)
+{
+ /* if (IsQueryFrame())
+ {
+ for (int i=0; i < m_nQuestionCount; i++)
+ {
+ CBJString sRecordName;
+ m_dnsItems[i].GetDnsRecordName(sRecordName, 0);
+ if (m_dnsItems[i].m_RecType != nRecType && nRecType != -1)
+ return false;
+
+ if (!sRecordName.Contains(sName.GetBuffer()))
+ return false;
+ }
+ }
+ else*/
+ {
+ for (int i=0; i < m_nQuestionCount+m_nAnswersCount; i++)
+ {
+ BJString sRecordName;
+ m_dnsItems[i].GetDnsRecordName(sRecordName, 0,99);
+ if (m_dnsItems[i].m_RecType != nRecType && nRecType != -1)
+ return false;
+
+ if (!sRecordName.Contains(sName.GetBuffer()))
+ return false;
+ }
+
+
+ }
+
+
+ return true;
+}
+
+CDNSRecord* CDNSFrame::FindAdditionRecord(BJString& sName,BJ_INT16 nRecType)
+{
+ for (int i = 0; i < m_nMaxItems; i++)
+ {
+ if (m_dnsItems[i].m_RecType != nRecType && nRecType != -1)
+ continue;
+ BJString sRecordName;
+ m_dnsItems[i].GetDnsRecordName(sRecordName, 0,99);
+ if (sRecordName == sName)
+ return &m_dnsItems[i];
+ }
+ return NULL;
+}
+
+void CDNSFrame::SetAddress(BJIPAddr *pSourceIPAddress,BJMACAddr *pSourceMACAddress)
+{
+ m_SourceIPAddress = *pSourceIPAddress;
+ m_SourceMACAddress = *pSourceMACAddress;
+
+
+}
+
+
+bool CDNSFrame::GetTracingInfo(BJ_UINT8 &platform, BJ_UINT32 &version, BJMACAddr &)
+{
+ // Find OPT record
+ for (int i = m_nQuestionCount + m_nAnswersCount + m_NSCOUNT; i < m_nMaxItems; i++)
+ {
+ if (m_dnsItems[i].m_RecType == DNS_TYPE_OPT)
+ {
+ BJ_UINT8* rdata = m_dnsItems[i].GetStartofRdata();
+
+ BJ_UINT8* rdataEnd = rdata + m_dnsItems[i].m_nRdataLen;
+
+ while (rdata < rdataEnd)
+ {
+ BJ_UINT16 type = PF_GET_UINT16(rdata,0);
+ BJ_UINT16 len = PF_GET_UINT16(rdata,2);
+
+ if (type == DNS_EDNS0_TRACE)
+ {
+ platform = PF_GET_UINT8(rdata,4);
+ if (len == 3) // EDNS field of length 3 <rdar://15101783>
+ {
+ version = static_cast<BJ_UINT32>(PF_GET_UINT16(rdata,5));
+ }
+ else if (len == 5) // EDNS field of length 5 <rdar://15235603>
+ {
+ version = static_cast<BJ_UINT32>(PF_GET_UINT32(rdata, 5));
+ }
+ else
+ {
+ return false;
+ }
+ return true;
+ }
+
+
+ rdata += sizeof(BJ_UINT16)*2 + len;
+ }
+
+ }
+ }
+ return false;
+
+}
+
+
+
+
+
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/DNSFrame.h b/mDNSResponder/mDNSMacOSX/BonjourTop/source/DNSFrame.h
new file mode 100644
index 00000000..8e7ded7c
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/DNSFrame.h
@@ -0,0 +1,132 @@
+//
+// DNSFrame.h
+// TestTB
+//
+// Created by Terrin Eager on 9/26/12.
+//
+//
+
+#ifndef __TestTB__DNSFrame__
+#define __TestTB__DNSFrame__
+
+#include <iostream>
+#include "bjtypes.h"
+#include "bjstring.h"
+#include "bjIPAddr.h"
+#include "bjMACAddr.h"
+
+#define MAX_DNS_RECORDS_PER_FRAME 500
+
+#define DNS_TYPE_PTR 12
+#define DNS_TYPE_SRV 33
+#define DNS_TYPE_TXT 16
+#define DNS_TYPE_A 1
+#define DNS_TYPE_AAAA 28
+#define DNS_TYPE_OPT 41
+
+#define DNS_EDNS0_TRACE 65001
+
+class CDNSFrame;
+
+
+
+
+class CDNSRecord
+{
+public:
+ typedef enum {Question,Answer,ns,ar} dnsItemType;
+
+ void GetDnsRecordName(BJString& ReturnString,int nLabelToSkip,int nMaxLabel);
+ void GetDnsRecordNameFromBuffer(BJ_UINT8* pBuffer,BJString& ReturnString,int nLabelToSkip,int nMaxLabel);
+
+ BJ_UINT8* GetStartofRdata() {return m_pStartofRec+m_nNameLength+10;}; // 10 = type(2) +class(2) + ttl(4) + datalen(2)
+ void GetRdata(BJString& ReturnString,int nLabelToSkip,int nMaxLabel)
+ {
+ if (m_RecType == DNS_TYPE_SRV)
+ GetDnsRecordNameFromBuffer(GetStartofRdata()+6, ReturnString, nLabelToSkip, nMaxLabel); // 6 = Priority + Weight + Port
+ else
+ GetDnsRecordNameFromBuffer(GetStartofRdata(), ReturnString, nLabelToSkip, nMaxLabel);
+ }
+ dnsItemType m_dnsType;
+ BJ_UINT8* m_pStartofRec;
+ BJ_UINT32 m_nNameLength;
+ BJ_INT16 m_RecType;
+ BJ_INT16 m_RecClass;
+ BJ_UINT32 m_nTTL;
+ BJ_UINT32 m_nRdataLen;
+
+ CDNSFrame* m_pDNSFrame;
+};
+
+
+
+class CDNSFrame
+{
+public:
+
+ CDNSFrame();
+ bool ParseDNSFrame(BJ_UINT8* pBuffer,BJ_INT32 nLength,BJ_UINT64 frameTime);
+
+
+ CDNSRecord* GetDnsRecord(int nIndex);
+ CDNSRecord* FindAdditionRecord(BJString& sName, BJ_INT16 nType);
+
+ BJ_UINT16 GetQuestionCount() {return m_nQuestionCount;};
+ BJ_UINT16 GetAnswerCount(){return m_nAnswersCount;};
+ BJ_UINT16 GetMaxRecords(){return m_nMaxItems;};
+ BJ_UINT8* GetBuffer() { return m_pStartBuffer;};
+
+ BJ_BOOL ParseDnsRecord(CDNSRecord::dnsItemType eItemType);
+
+ BJ_BOOL IsQueryFrame();
+ BJ_BOOL IsWakeFrame();
+ BJ_BOOL IsTruncatedFrame();
+
+ BJ_BOOL HasOnlyService(BJString sName, BJ_INT16 nRecType);
+
+ void SetAddress(BJIPAddr *SourceIPAddress,BJMACAddr *SourceMACAddress);
+
+ bool GetTracingInfo(BJ_UINT8 &platform, BJ_UINT32 &version, BJMACAddr &mac);
+
+ BJ_UINT64 GetTime() {return m_Time;};
+
+
+ BJIPAddr m_Servicev4Address;
+ BJIPAddr m_Servicev6Address;
+
+ BJIPAddr m_SourceIPAddress;
+ BJMACAddr m_SourceMACAddress;
+
+protected:
+
+
+ BJ_UINT8* m_pStartBuffer;
+ BJ_UINT8* m_pEndBuffer;
+ BJ_UINT8* m_pCurrentBuffer;
+ BJ_INT32 m_nBufferLen;
+
+ BJ_INT32 m_nFrameLen;
+
+ // Header
+ BJ_UINT16 m_nId;
+ BJ_UINT16 m_nFlags;
+
+ BJ_UINT16 m_nQuestionCount;
+ BJ_UINT16 m_nAnswersCount;
+ BJ_UINT16 m_NSCOUNT;
+ BJ_UINT16 m_ARCOUNT;
+
+
+ CDNSRecord m_dnsItems[MAX_DNS_RECORDS_PER_FRAME];
+
+ int m_nMaxItems;
+
+ BJ_UINT64 m_Time;
+
+};
+
+
+
+
+
+#endif /* defined(__TestTB__DNSFrame__) */
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/Frame.cpp b/mDNSResponder/mDNSMacOSX/BonjourTop/source/Frame.cpp
new file mode 100644
index 00000000..bbc1d821
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/Frame.cpp
@@ -0,0 +1,201 @@
+//
+// Frame.cpp
+// TestTB
+//
+// Created by Terrin Eager on 1/19/13.
+//
+//
+
+#include "Frame.h"
+
+#define EthernetHeaderStart 14
+
+void Frame::Set(BJ_UINT8* data,BJ_UINT32 len,BJ_UINT64 t)
+{
+ frameData = data;
+ length = len;
+ frameTime = t;
+}
+
+BJ_UINT8* Frame::GetEthernetStart()
+{
+ //todo Support other media types
+ return frameData;
+}
+BJ_UINT8* Frame::GetIPStart()
+{
+ BJ_UINT8* ether = GetEthernetStart();
+
+ return ether + 14;
+
+}
+BJ_UINT8* Frame::GetUDPStart()
+{
+ BJ_UINT8* ip = GetIPStart();
+
+ BJ_UINT16 nSize = *((__uint16_t*) (ip));
+ BJ_UINT16 nVerison = (nSize&0xf0) >> 4;
+ if (nVerison == 0x4)
+ {
+ m_bCurrentFrameIPversion = 4;
+
+ nSize &= 0x0f;
+ nSize *= 4;
+
+
+ BJ_UINT8 nProtocol = *(ip+9);
+
+ if (nProtocol != 17) // Not UDP
+ return NULL;
+ }
+ else if (nVerison == 0x6)
+ {
+ m_bCurrentFrameIPversion = 6;
+ BJ_UINT8 nProtocol = *(ip+6);
+
+ if (nProtocol != 17) // Not UDP
+ return NULL;
+ nSize = 40;
+
+ }
+
+ return ip+nSize;
+}
+
+BJ_UINT8* Frame::GetBonjourStart()
+{
+ BJ_UINT8* udp = GetUDPStart();
+
+
+ if (udp == NULL)
+ return NULL;
+
+ BJ_UINT16 nSourcePort = *((__uint16_t*)(udp));
+ BJ_UINT16 nDestPort = *((__uint16_t*)(udp+2));
+ BJ_UINT16 nBonjourPort = htons(5353);
+
+ if (nSourcePort == nBonjourPort && nDestPort == nBonjourPort)
+ return (udp+8);
+ else
+ return NULL;
+
+}
+
+
+
+BJIPAddr* Frame::GetSrcIPAddr()
+{
+ BJ_UINT8* ip = GetIPStart();
+
+ BJ_UINT16 nSize = (__uint16_t) (*ip);
+ BJ_UINT16 nVerison = (nSize&0xf0) >> 4;
+ if (nVerison == 0x4)
+ {
+ m_bCurrentFrameIPversion = 4;
+
+ struct in_addr* ipi_addr;
+
+ ipi_addr = (in_addr*)(ip+12);
+
+ sourceIPAddr.Set(ipi_addr);
+
+ }
+ else if (nVerison == 0x6)
+ {
+ m_bCurrentFrameIPversion = 6;
+ BJ_UINT8* ipi_addr;
+
+ ipi_addr = (ip+8);
+
+ sourceIPAddr.Setv6Raw(ipi_addr);
+
+ }
+
+ return &sourceIPAddr;
+}
+
+BJIPAddr* Frame::GetDestIPAddr()
+{
+ BJ_UINT8* ip = GetIPStart();
+
+ BJ_UINT16 nSize = *((__uint16_t*) (ip));
+ BJ_UINT16 nVerison = (nSize&0xf0) >> 4;
+ if (nVerison == 0x4)
+ {
+ m_bCurrentFrameIPversion = 4;
+
+ struct in_addr* ipi_addr;
+
+ ipi_addr = (in_addr*)(ip+16);
+
+ destIPAddr.Set(ipi_addr);
+
+ }
+ else if (nVerison == 0x6)
+ {
+ m_bCurrentFrameIPversion = 6;
+ struct in6_addr* ipi_addr;
+
+ ipi_addr = (in6_addr*)(ip+24);
+
+ destIPAddr.Set(ipi_addr);
+
+ }
+ return &destIPAddr;
+}
+
+BJMACAddr* Frame::GetSrcMACAddr()
+{
+ sourceMACAddr.Set(GetEthernetStart()+6);
+
+ return &sourceMACAddr;
+}
+
+BJMACAddr* Frame::GetDestMACAddr()
+{
+ destMACAddr.Set(GetEthernetStart());
+
+ return &destMACAddr;
+}
+
+void Frame::SetDatalinkType(BJ_DATALINKTYPE datalinkType)
+{
+ m_datalinkType = datalinkType;
+}
+
+BJ_UINT32 Frame::GetLinklayerHeaderLength()
+{
+ switch (m_datalinkType)
+ {
+ case (BJ_DLT_EN10MB):
+ return EthernetHeaderStart;
+ case (BJ_DLT_IEEE802_11):
+ return Get80211HeaderLength();
+ default:
+ // Default to Ethernet
+ return EthernetHeaderStart;
+ }
+}
+
+BJ_UINT32 Frame::Get80211HeaderLength()
+{
+ // XXX: 802.11 header is tricky since it has no "length" field.
+ // We should look at "FrameControl" and derive the length manually for each frame.
+ BJ_UINT16 * frameControl = (BJ_UINT16*)GetEthernetStart();
+
+ // [SubType] [Type - Ver]
+
+ bool isFrameData = (0x0C & *frameControl) == 0x08;
+ bool isQosData = ((0xF0 & *frameControl) == 0x80) && isFrameData;
+
+ if (isQosData)
+ {
+ //Standard (24) + QoS (2) + LLC (3) + SNAP (5)
+ return 24 + 2 + 3 + 5;
+ }
+ else
+ {
+ //Standard (24) + LLC (3) + SNAP (5)
+ return 24 + 3 + 5;
+ }
+}
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/Frame.h b/mDNSResponder/mDNSMacOSX/BonjourTop/source/Frame.h
new file mode 100644
index 00000000..f8e3ade6
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/Frame.h
@@ -0,0 +1,66 @@
+//
+// Frame.h
+// TestTB
+//
+// Created by Terrin Eager on 1/19/13.
+//
+//
+
+#ifndef __TestTB__Frame__
+#define __TestTB__Frame__
+
+#include "bjtypes.h"
+#include "bjIPAddr.h"
+#include "bjMACAddr.h"
+
+class Frame
+{
+public:
+ void Set(BJ_UINT8* data,BJ_UINT32 len,BJ_UINT64 t);
+ BJ_UINT8* GetEthernetStart();
+ BJ_UINT8* GetIPStart();
+ BJ_UINT8* GetUDPStart();
+ BJ_UINT8* GetBonjourStart();
+
+ BJIPAddr* GetSrcIPAddr();
+ BJIPAddr* GetDestIPAddr();
+
+ BJMACAddr* GetSrcMACAddr();
+ BJMACAddr* GetDestMACAddr();
+
+ int m_bCurrentFrameIPversion;
+
+ BJ_UINT64 GetTime(){ return frameTime; };
+
+ enum BJ_DATALINKTYPE {
+ BJ_DLT_EN10MB = 1,
+ BJ_DLT_IEEE802_11=105
+ };
+
+ void SetDatalinkType (BJ_DATALINKTYPE datalinkType);
+private:
+
+ BJ_UINT32 GetLinklayerHeaderLength();
+
+ //Get the header length of the current 802.11 frame.
+ BJ_UINT32 Get80211HeaderLength();
+
+ BJ_UINT8* frameData;
+ BJ_UINT32 length;
+
+ BJIPAddr sourceIPAddr;
+ BJIPAddr destIPAddr;
+
+ BJMACAddr sourceMACAddr;
+ BJMACAddr destMACAddr;
+
+ BJ_UINT64 frameTime; // in microseconds
+
+
+ BJ_DATALINKTYPE m_datalinkType = BJ_DLT_EN10MB;
+
+
+};
+
+
+#endif /* defined(__TestTB__Frame__) */
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/LLRBTree.cpp b/mDNSResponder/mDNSMacOSX/BonjourTop/source/LLRBTree.cpp
new file mode 100644
index 00000000..37ce9d76
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/LLRBTree.cpp
@@ -0,0 +1,157 @@
+//
+// LLRBTree.cpp
+// TestTB
+//
+// Created by Terrin Eager on 7/9/12.
+//
+//
+
+#include "LLRBTree.h"
+
+
+
+#include <stdio.h>
+#import <stdlib.h>
+#include <string.h>
+#include <curses.h>
+
+#include "bjtypes.h"
+
+#include <time.h>
+
+void test3();
+
+
+
+
+
+
+////////////////////
+
+////////////////
+// test case
+// Integrity checks
+
+/*********************
+BJ_BOOL isBST(CRBNode* pRecord, BJ_UINT64 min, BJ_UINT64 max);
+BJ_BOOL is234(CRBNode* pRecord);
+BJ_BOOL isBalanced(CLLRBTree* pCache);
+BJ_BOOL isBalancedNode(CRBNode* pRecord, int black);
+
+BJ_BOOL check(CLLRBTree* pCache)
+{ // Is this tree a red-black tree?
+ BJ_BOOL bBST = isBST(pCache->GetRoot(),pCache->minRecord(pCache->GetRoot())->nKey,pCache->maxRecord(pCache->GetRoot())->nKey);
+ BJ_BOOL b234 = is234(pCache->GetRoot());
+ BJ_BOOL bisBalanced = isBalanced(pCache);
+
+ printf("Bst=%d,234=%d, Balanced=%d",bBST,b234,bisBalanced);
+
+ return bBST && b234 && bisBalanced;
+}
+
+
+BJ_BOOL isBST(CRBNode* pRecord, BJ_UINT64 min, BJ_UINT64 max)
+{ // Are all the values in the BST rooted at x between min and max,
+ // and does the same property hold for both subtrees?
+ if (pRecord == NULL) return 1;
+ if ((pRecord->nKey > min) || (max > pRecord->nKey)) return 0;
+ return isBST(pRecord->m_rbLeft, min, pRecord->nKey) && isBST(pRecord->m_rbRight, pRecord->nKey, max);
+}
+BJ_BOOL is234(CRBNode* pRecord)
+{ // Does the tree have no red right links, and at most two (left)
+ // red links in a row on any path?
+ if (pRecord == NULL) return 1;
+ if (IsRed(pRecord->m_rbRight)) return 0;
+ if (IsRed(pRecord))
+ if (IsRed(pRecord->m_rbLeft))
+ if (IsRed(pRecord->m_rbLeft->m_rbLeft)) return 0;
+ return is234(pRecord->m_rbLeft) && is234(pRecord->m_rbRight);
+}
+
+BJ_BOOL isBalanced(CLLRBTree* pCache)
+{ // Do all paths from root to leaf have same number of black edges?
+ int black = 0; // number of black links on path from root to min
+ CRBNode* pRecord = pCache->m_Root;
+ while (pRecord != NULL)
+ {
+ if (!IsRed(pRecord)) black++;
+ pRecord = pRecord->m_rbLeft;
+ }
+ return isBalancedNode(pCache->root, black);
+}
+
+BJ_BOOL isBalancedNode(CRBNode* pRecord, int black)
+{ // Does every path from the root to a leaf have the given number
+ // of black links?
+ if (pRecord == NULL && black == 0) return 1;
+ else if (pRecord == NULL && black != 0) return 0;
+ if (!IsRed(pRecord)) black--;
+ return isBalancedNode(pRecord->m_rbLeft, black) && isBalancedNode(pRecord->m_rbRight, black);
+}
+****************/
+
+/**
+// sample code for testing
+void CStringNode_test()
+{
+ CStringTree Cache;
+
+
+ char DummyData[] = {'a','b','d','x'};
+ BJ_UINT64 i = 0;
+ CStringNode* pRecord;
+
+ while (i++ < sizeof(DummyData))
+ {
+
+ pRecord = (CStringNode*)Cache.FindwithAddRecord(&i);
+ if (pRecord)
+ pRecord->m_Value[0] = DummyData[i];
+ }
+
+ i = 2;
+ pRecord = (CStringNode*)Cache.Find(&i);
+
+
+ test3();
+
+}
+
+void test3()
+{
+ // float nSaveCPU =0;
+
+ CStringTree Cache;
+
+ CStringNode test;
+
+
+ BJ_UINT64 i = 0;
+ long starttime = clock();
+ float elapsedtime = 0;
+ CStringNode* pRecord;
+
+ // nSaveCPU = getCPUtime();
+ while (i++ < 1000000)
+ {
+ pRecord = (CStringNode*) Cache.FindwithAddRecord(&i);
+ if (pRecord)
+ memccpy(pRecord->m_Value, "test",4, 1);
+
+ // snprintf(pRecord->m_Value,sizeof(pRecord->m_Value),"%llx",key.m_nKey);
+ }
+ elapsedtime = clock() - starttime;
+ elapsedtime /= CLOCKS_PER_SEC;
+
+ // elapsedtime = getCPUtime() - nSaveCPU;
+
+ printf("Test elapsed time %f, check = %d\n",elapsedtime,0);
+
+
+
+
+}
+
+*****/
+///////////////
+
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/LLRBTree.h b/mDNSResponder/mDNSMacOSX/BonjourTop/source/LLRBTree.h
new file mode 100644
index 00000000..7b7ea0f9
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/LLRBTree.h
@@ -0,0 +1,460 @@
+//
+// LLRBTree.h
+// TestTB
+//
+// Created by Terrin Eager on 7/9/12.
+//
+// based on rbtree.h but converted to C++
+// ll from http://www.cs.princeton.edu/~rs/talks/LLRB/RedBlack.pdf
+
+#ifndef __TestTB__LLRBTree__
+#define __TestTB__LLRBTree__
+
+#include <iostream>
+#include "bjtypes.h"
+#include <sys/socket.h>
+#include "bjstring.h"
+#include "bjIPAddr.h"
+
+template <class KeyType>
+class CRBNode
+{
+public:
+ CRBNode() {m_bIsRed = true; m_rbLeft = m_rbRight = NULL;};
+ virtual ~CRBNode();
+
+ inline virtual BJ_COMPARE Compare(KeyType* pKey) = 0; // Key values are equal
+
+ inline virtual void CopyNode(CRBNode* pSource) = 0;
+ inline virtual void Init()=0;
+ inline virtual void Clear()=0;
+
+ CRBNode* GetMinNode();
+ CRBNode* GetMaxNode();
+
+
+ inline CRBNode* RotateNodeLeft();
+ inline CRBNode* RotateNodeRight();
+
+
+ CRBNode* AddRecord(CRBNode* pNewRecord);
+
+ void FlipColor();
+
+ BJ_UINT64 GetCount();
+
+ CRBNode* Fixup();
+
+ CRBNode* MoveRedLeft();
+ CRBNode* MoveRedRight();
+
+ void CallBack(int(*callback)(const void*, const void*),void* pParam);
+
+
+ bool m_bIsRed;
+
+//protected:
+ KeyType m_Key;
+ CRBNode* m_rbLeft;
+ CRBNode* m_rbRight;
+
+
+};
+
+template <class KeyType, class NodeType>
+class CLLRBTree
+{
+
+public:
+ CLLRBTree();
+ virtual ~CLLRBTree() { if (m_Root) delete m_Root;};
+
+ NodeType* Find(KeyType* pKey);
+
+ NodeType* FindwithAddRecord(KeyType* pKey);
+ NodeType* AddRecord(KeyType* pKey);
+ void RemoveRecord(KeyType* pKey);
+
+ NodeType* GetRoot() { return m_Root;};
+ void ClearAll() { delete m_Root; m_Root = NULL;};
+
+ BJ_UINT64 GetCount();
+
+
+ NodeType* GetMinNode();
+ NodeType* GetMaxNode();
+
+ NodeType* deleteMin(NodeType* pRecord);
+
+
+private:
+ NodeType* RemoveRecord(NodeType* pRecord,KeyType* pKey);
+
+ virtual NodeType* newNode(KeyType* pKey) { return new NodeType(pKey);}
+ virtual void freeNode(NodeType * pNode){ delete pNode;};
+
+
+ NodeType* m_Root;
+
+
+};
+/////////////////
+
+
+template<class KeyType>
+CRBNode<KeyType>::~CRBNode()
+{
+ if (m_rbLeft)
+ delete m_rbLeft;
+ if (m_rbRight)
+ delete m_rbRight;
+
+}
+
+
+
+
+template<class KeyType>
+CRBNode<KeyType>* CRBNode<KeyType>::RotateNodeLeft()
+{
+ CRBNode<KeyType>* pTemp = m_rbRight;
+ m_rbRight = pTemp->m_rbLeft;
+ pTemp->m_rbLeft = this;
+ pTemp->m_bIsRed = pTemp->m_rbLeft->m_bIsRed;
+ pTemp->m_rbLeft->m_bIsRed = 1;
+
+ return pTemp;
+}
+
+
+template<class KeyType>
+CRBNode<KeyType>* CRBNode<KeyType>::RotateNodeRight()
+{
+ CRBNode<KeyType>* pTemp = m_rbLeft;
+ m_rbLeft = pTemp->m_rbRight;
+ pTemp->m_rbRight = this;
+ pTemp->m_bIsRed = pTemp->m_rbRight->m_bIsRed;
+ pTemp->m_rbRight->m_bIsRed = 1;
+
+ return pTemp;
+}
+
+template<class KeyType>
+BJ_UINT64 CRBNode<KeyType>::GetCount()
+{
+ BJ_UINT64 Num = 1;
+ if (m_rbLeft)
+ Num += m_rbLeft->GetCount();
+ if (m_rbRight)
+ Num += m_rbRight->GetCount();
+
+ return Num;
+
+}
+
+template<class KeyType>
+void CRBNode<KeyType>::FlipColor()
+{
+ m_bIsRed = !m_bIsRed;
+ if (m_rbLeft)
+ m_rbLeft->m_bIsRed = !m_rbLeft->m_bIsRed;
+ if (m_rbRight)
+ m_rbRight->m_bIsRed = !m_rbRight->m_bIsRed;
+
+}
+
+template<class KeyType>
+CRBNode<KeyType>* CRBNode<KeyType>::Fixup()
+{
+ // fix the tree balance
+ CRBNode<KeyType>* pNode = this;
+
+ if (m_rbRight && m_rbRight->m_bIsRed) // fix right leaning reds on the way up
+ pNode = RotateNodeLeft();
+
+ if (pNode && pNode->m_rbLeft && pNode->m_rbLeft->m_bIsRed && pNode->m_rbLeft->m_rbLeft && pNode->m_rbLeft->m_rbLeft->m_bIsRed) // fix two reds in a row on the way up
+ pNode = RotateNodeRight();
+
+ if (pNode && pNode->m_rbRight && pNode->m_rbRight->m_bIsRed && pNode->m_rbLeft && pNode->m_rbLeft->m_bIsRed) //split 4-nodes on the way up
+ pNode->FlipColor();
+
+ return pNode;
+}
+
+template<class KeyType>
+CRBNode<KeyType>* CRBNode<KeyType>::MoveRedLeft()
+{
+ CRBNode* pNode = this;
+ FlipColor();
+
+ if (m_rbRight && m_rbRight->m_rbLeft && m_rbRight->m_rbLeft->m_bIsRed)
+ {
+ m_rbRight = m_rbRight->RotateNodeRight();
+ pNode = RotateNodeLeft();
+ if (pNode)
+ pNode->FlipColor();
+ }
+ return pNode;
+}
+
+template<class KeyType>
+CRBNode<KeyType>* CRBNode<KeyType>::MoveRedRight()
+{
+ CRBNode* pNode = this;
+ FlipColor();
+
+ if (m_rbLeft && m_rbLeft->m_rbLeft && m_rbLeft->m_rbLeft->m_bIsRed)
+ {
+ pNode = RotateNodeRight();
+ if (pNode)
+ pNode->FlipColor();
+ }
+
+ return pNode;
+}
+template<class KeyType>
+CRBNode<KeyType>* CRBNode<KeyType>::AddRecord(CRBNode* pNewRecord)
+{
+
+ switch (Compare(&pNewRecord->m_Key))
+ {
+ case BJ_GT:
+ if (m_rbRight)
+ m_rbRight = m_rbRight->AddRecord(pNewRecord);
+ else
+ m_rbRight = pNewRecord;
+
+ break;
+ case BJ_LT:
+ if (m_rbLeft)
+ m_rbLeft = m_rbLeft->AddRecord(pNewRecord);
+ else
+ m_rbLeft = pNewRecord;
+
+ break;
+ default: // equal
+ pNewRecord->m_bIsRed = false;
+ pNewRecord->m_rbLeft = m_rbLeft;
+ m_rbLeft = pNewRecord;
+ return this;
+ };
+
+ // fix the tree balance
+ CRBNode* pRecord = this;
+
+ // fix the tree balance
+
+ if (pRecord && pRecord->m_rbRight && pRecord->m_rbRight->m_bIsRed) // fix right leaning reds on the way up
+ pRecord = pRecord->RotateNodeLeft();
+
+ if (pRecord && pRecord->m_rbLeft && pRecord->m_rbLeft->m_bIsRed && pRecord->m_rbLeft->m_rbLeft && pRecord->m_rbLeft->m_rbLeft->m_bIsRed) // fix two reds in a row on the way up
+ pRecord = pRecord->RotateNodeRight();
+
+ if (pRecord && pRecord->m_rbRight && pRecord->m_rbRight->m_bIsRed && pRecord->m_rbLeft && pRecord->m_rbLeft->m_bIsRed) //split 4-nodes on the way up
+ pRecord->FlipColor();
+
+
+ return pRecord;
+}
+
+
+
+template<class KeyType>
+CRBNode<KeyType>* CRBNode<KeyType>::GetMinNode()
+{
+ CRBNode* pRecord = this;
+ while (pRecord && pRecord->m_rbLeft)
+ pRecord = pRecord->m_rbLeft;
+
+ return pRecord;
+}
+template<class KeyType>
+CRBNode<KeyType>* CRBNode<KeyType>::GetMaxNode()
+{
+ CRBNode* pRecord = this;
+ while (pRecord && pRecord->m_rbRight)
+ pRecord = pRecord->m_rbRight;
+
+ return pRecord;
+}
+
+template<class KeyType>
+void CRBNode<KeyType>::CallBack(int(*callback)(const void*, const void*),void* pParam)
+{
+
+ if (m_rbLeft)
+ m_rbLeft->CallBack(callback,pParam);
+
+ callback(this,pParam);
+
+ if (m_rbRight)
+ m_rbRight->CallBack(callback,pParam);
+
+
+}
+
+
+
+///////////
+template<class KeyType,class NodeType>
+CLLRBTree<KeyType,NodeType>::CLLRBTree()
+{
+ m_Root = NULL;
+}
+
+template<class KeyType,class NodeType>
+NodeType* CLLRBTree<KeyType,NodeType>::Find(KeyType* pKey)
+{
+
+ CRBNode<KeyType>* pNode = m_Root;
+
+ while (pNode)
+ {
+ switch (pNode->Compare(pKey))
+ {
+ case BJ_GT:
+ pNode = pNode->m_rbRight;
+ break;
+ case BJ_LT:
+ pNode = pNode->m_rbLeft;
+ break;
+ default:
+ return (NodeType*)pNode;
+ break;
+ }
+ }
+
+ return NULL;
+
+}
+
+template<class KeyType,class NodeType>
+NodeType* CLLRBTree<KeyType,NodeType>::AddRecord(KeyType* pKey)
+{
+ NodeType* pRecord = newNode(pKey);
+ if (m_Root)
+ m_Root = (NodeType*) m_Root->AddRecord(pRecord);
+ else
+ m_Root = pRecord;
+
+ if (m_Root)
+ m_Root->m_bIsRed = false;
+
+ return pRecord;
+}
+
+template<class KeyType,class NodeType>
+NodeType* CLLRBTree<KeyType,NodeType>::FindwithAddRecord(KeyType* pKey)
+{
+ NodeType* pRecord = NULL;
+
+ pRecord = Find(pKey);
+
+ if (pRecord == NULL)
+ pRecord = AddRecord(pKey);
+
+ return pRecord;
+}
+
+template<class KeyType,class NodeType>
+void CLLRBTree<KeyType,NodeType>::RemoveRecord(KeyType* pKey)
+{
+ m_Root = RemoveRecord(m_Root,pKey);
+}
+
+template<class KeyType,class NodeType>
+NodeType* CLLRBTree<KeyType,NodeType>::deleteMin(NodeType* pRecord)
+{
+ if (pRecord->m_rbLeft == NULL)
+ {
+ freeNode(pRecord);
+ return NULL;
+ }
+
+ if (!(pRecord->m_rbLeft && pRecord->m_rbLeft->m_bIsRed) && !(pRecord->m_rbLeft && pRecord->m_rbLeft->m_rbLeft &&pRecord->m_rbLeft->m_rbLeft->m_bIsRed))
+ pRecord = (NodeType*)pRecord->MoveRedLeft();
+
+ pRecord->m_rbLeft = deleteMin((NodeType*)pRecord->m_rbLeft);
+
+ return (NodeType*)pRecord->Fixup();
+}
+
+template<class KeyType,class NodeType>
+NodeType* CLLRBTree<KeyType,NodeType>::RemoveRecord(NodeType* pRecord,KeyType* pKey)
+{
+ NodeType* pTempRecord = NULL;
+
+ if (pRecord == NULL)
+ return NULL;
+
+ if (pRecord->Compare(pKey) == BJ_LT)
+ {
+ if (!(pRecord->m_rbLeft &&pRecord->m_rbLeft->m_bIsRed) && !(pRecord->m_rbLeft && pRecord->m_rbLeft->m_rbLeft &&pRecord->m_rbLeft->m_rbLeft->m_bIsRed))
+ pRecord->MoveRedLeft();
+ pRecord = RemoveRecord((NodeType*)pRecord->m_rbLeft, pKey);
+ }
+ else
+ {
+ if (pRecord->m_rbLeft &&pRecord->m_rbLeft->m_bIsRed)
+ pRecord->RotateNodeRight();
+
+ if(pRecord->Compare(pKey) == BJ_EQUAL && pRecord->m_rbRight == NULL)
+ {
+ freeNode(pRecord);
+ return NULL;
+ }
+
+ if (!(pRecord->m_rbRight && pRecord->m_rbRight->m_bIsRed) && !(pRecord->m_rbRight && pRecord->m_rbRight->m_rbLeft && pRecord->m_rbRight->m_rbLeft->m_bIsRed))
+ pRecord = (NodeType*)pRecord->MoveRedRight();
+
+ if (pRecord->Compare(pKey) == BJ_EQUAL)
+ {
+ pTempRecord = (NodeType*)pRecord->GetMinNode();
+ pRecord->CopyNode(pTempRecord);
+ pRecord->m_rbRight = deleteMin((NodeType*)pRecord->m_rbRight);
+ }
+ else
+ {
+ pRecord->m_rbRight = RemoveRecord((NodeType*)pRecord->m_rbRight, pKey);
+ }
+ }
+ return pRecord?(NodeType*)pRecord->Fixup():NULL;
+}
+
+
+
+
+template<class KeyType,class NodeType>
+BJ_UINT64 CLLRBTree<KeyType,NodeType>::GetCount()
+{
+ if (m_Root)
+ return m_Root->GetCount();
+ else
+ return 0;
+}
+
+template<class KeyType,class NodeType>
+NodeType* CLLRBTree<KeyType,NodeType>::GetMinNode()
+{
+ if (m_Root)
+ return m_Root->GetMinNode();
+ else
+ return NULL;
+
+}
+
+template<class KeyType,class NodeType>
+NodeType* CLLRBTree<KeyType,NodeType>::GetMaxNode()
+{
+ if (m_Root)
+ return m_Root->GetMaxNode();
+ else
+ return NULL;
+
+}
+
+
+
+
+
+#endif /* defined(__TestTB__LLRBTree__) */
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjIPAddr.cpp b/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjIPAddr.cpp
new file mode 100644
index 00000000..188f962e
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjIPAddr.cpp
@@ -0,0 +1,312 @@
+//
+// bjIPAddr.cpp
+// TestTB
+//
+// Created by Terrin Eager on 1/19/13.
+//
+//
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "bjIPAddr.h"
+#include "bjstring.h"
+
+
+// static
+sockaddr_storage BJIPAddr::emptySockAddrStorage;
+
+
+
+BJIPAddr::BJIPAddr()
+{
+ memset(&emptySockAddrStorage,0,sizeof(emptySockAddrStorage));
+ Empty();
+}
+
+BJIPAddr::BJIPAddr(const BJIPAddr& src)
+{
+ memcpy(&sockAddrStorage,&src.sockAddrStorage,sizeof(sockAddrStorage));
+ IPv4SubNet = src.IPv4SubNet;
+}
+void BJIPAddr::Empty()
+{
+ memset(&sockAddrStorage,0,sizeof(sockAddrStorage));
+ IPv4SubNet = 0;
+
+}
+
+bool BJIPAddr::IsBonjourMulticast()
+{
+ bool bResult = false;
+
+ struct in_addr BonjourMulicastAddrIPv4= {0xFB0000E0};
+
+ struct in6_addr BonjourMulicastAddrIPv6 = {{{ 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB }}};
+
+
+ if (sockAddrStorage.ss_family == AF_INET)
+ {
+ struct sockaddr_in* pAddrIn = (sockaddr_in*) &sockAddrStorage;
+ return (pAddrIn->sin_addr.s_addr == BonjourMulicastAddrIPv4.s_addr);
+ }
+
+ if (sockAddrStorage.ss_family == AF_INET6)
+ {
+ struct sockaddr_in6* pAddrIn = (sockaddr_in6*) &sockAddrStorage;
+ return (memcmp(&pAddrIn->sin6_addr,&BonjourMulicastAddrIPv6,sizeof(in6_addr)) == 0);
+ }
+
+
+ return bResult;
+
+}
+
+bool BJIPAddr::IsSameSubNet(BJIPAddr* pCheckAddr)
+{
+
+ if (IPv4SubNet == 0)
+ return true;
+
+ if (!pCheckAddr->IsIPv4())
+ return true;
+
+ in_addr_t Mask = 0xFFFFFFFF;
+
+ Mask = Mask << (32-IPv4SubNet);
+
+ endian_swap(Mask);
+
+ struct sockaddr_in* pMyAddrIn = (sockaddr_in*) &sockAddrStorage;
+ in_addr_t myNetworkAddress = pMyAddrIn->sin_addr.s_addr & Mask;
+
+ struct sockaddr_in* pCheckAddrIn = (sockaddr_in*) pCheckAddr->GetRawValue();
+ in_addr_t CheckNetworkAddress = pCheckAddrIn->sin_addr.s_addr & Mask;
+
+
+ return (myNetworkAddress == CheckNetworkAddress);
+}
+
+
+bool BJIPAddr::IsIPv4()
+{
+ return (sockAddrStorage.ss_family == AF_INET);
+}
+
+bool BJIPAddr::IsIPv6()
+{
+ return (sockAddrStorage.ss_family == AF_INET6);
+}
+
+bool BJIPAddr::IsIPv6LinkLocal()
+{
+ struct sockaddr_in6* pAddrIn = (sockaddr_in6*) &sockAddrStorage;
+ return (pAddrIn->sin6_addr.__u6_addr.__u6_addr8[0] == 0xfe &&
+ pAddrIn->sin6_addr.__u6_addr.__u6_addr8[1] == 0x80);
+}
+bool BJIPAddr::IsEmpty()
+{
+ return (memcmp(&sockAddrStorage,&emptySockAddrStorage,sizeof(sockAddrStorage)) == 0);
+}
+
+bool BJIPAddr::IsEmptySubnet()
+{
+ return (IPv4SubNet == 0);
+}
+
+void BJIPAddr::Setv6(const char* pIPaddr)
+{
+ memset(&sockAddrStorage,0,sizeof(sockAddrStorage));
+ struct sockaddr_in6* pAddrIn = (sockaddr_in6*) &sockAddrStorage;
+
+ if (inet_pton(AF_INET6, pIPaddr, &pAddrIn->sin6_addr) && memcmp(&sockAddrStorage,&emptySockAddrStorage,sizeof(sockAddrStorage)) == 0)
+ pAddrIn->sin6_family = AF_INET6;
+}
+
+void BJIPAddr::Set(const char* pIPaddr)
+{
+ memset(&sockAddrStorage,0,sizeof(sockAddrStorage));
+
+ if (pIPaddr == NULL || strlen(pIPaddr) == 0)
+ return;
+
+ BJString sIPAddr;
+ BJString sMask;
+
+ const char* pSeperator = strstr(pIPaddr,"/");
+ if (pSeperator)
+ {
+ sIPAddr.Set(pIPaddr, (BJ_UINT32)(pSeperator - pIPaddr));
+ sMask.Set(pSeperator+1);
+ }
+ else
+ {
+ sIPAddr.Set(pIPaddr);
+ }
+
+ struct sockaddr_in* pAddrIn = (sockaddr_in*) &sockAddrStorage;
+ pAddrIn->sin_family = AF_INET;
+ pAddrIn->sin_addr.s_addr = inet_addr(sIPAddr.GetBuffer());
+
+ IPv4SubNet = sMask.GetUINT32();
+
+}
+void BJIPAddr::Setv4Raw(BJ_UINT8* ipi4_addr)
+{
+
+ memset(&sockAddrStorage,0,sizeof(sockAddrStorage));
+ struct sockaddr_in* pAddrIn = (sockaddr_in*) &sockAddrStorage;
+ pAddrIn->sin_family = AF_INET;
+ memcpy(&pAddrIn->sin_addr, ipi4_addr, sizeof(pAddrIn->sin_addr));
+
+}
+void BJIPAddr::Setv6Raw(BJ_UINT8* ipi6_addr)
+{
+
+ memset(&sockAddrStorage,0,sizeof(sockAddrStorage));
+ struct sockaddr_in6* pAddrIn = (sockaddr_in6*) &sockAddrStorage;
+
+ pAddrIn->sin6_family = AF_INET6;
+ memcpy(&pAddrIn->sin6_addr, ipi6_addr, sizeof(pAddrIn->sin6_addr));
+}
+
+void BJIPAddr::Set(struct in6_addr* ipi6_addr)
+{
+
+ memset(&sockAddrStorage,0,sizeof(sockAddrStorage));
+ struct sockaddr_in6* pAddrIn = (sockaddr_in6*) &sockAddrStorage;
+
+ pAddrIn->sin6_family = AF_INET6;
+ memcpy(&pAddrIn->sin6_addr, ipi6_addr, sizeof(pAddrIn->sin6_addr));
+}
+
+void BJIPAddr::Set(struct in_addr* ip_addr)
+{
+
+ memset(&sockAddrStorage,0,sizeof(sockAddrStorage));
+ struct sockaddr_in* pAddrIn = (sockaddr_in*) &sockAddrStorage;
+ pAddrIn->sin_family = AF_INET;
+ pAddrIn->sin_addr = *ip_addr;
+}
+
+void BJIPAddr::Set(struct sockaddr_storage* pStorage)
+{
+ memcpy(&sockAddrStorage,pStorage,sizeof(sockAddrStorage));
+}
+
+sockaddr_storage* BJIPAddr::GetRawValue()
+{
+ return &sockAddrStorage;
+}
+
+struct in6_addr* BJIPAddr::Getin6_addr()
+{
+ struct sockaddr_in6* pAddrIn = (sockaddr_in6*) &sockAddrStorage;
+ return &pAddrIn->sin6_addr;
+}
+
+BJ_UINT16 BJIPAddr::GetPortNumber()
+{
+ BJ_UINT16 port = 0;
+ if (sockAddrStorage.ss_family == AF_INET)
+ {
+ struct sockaddr_in* pAddrIn = (struct sockaddr_in*)&sockAddrStorage;
+ port = ntohs(pAddrIn->sin_port);
+ }
+ else if (sockAddrStorage.ss_family == AF_INET6)
+ {
+ struct sockaddr_in6* pAddrIn = (struct sockaddr_in6*)&sockAddrStorage;
+ port = ntohs(pAddrIn->sin6_port);
+ }
+ return port;
+}
+
+BJ_COMPARE BJIPAddr::Compare(BJIPAddr* pIPAddr)
+{
+ if (sockAddrStorage.ss_family > pIPAddr->sockAddrStorage.ss_family)
+ return BJ_GT;
+ if (sockAddrStorage.ss_family < pIPAddr->sockAddrStorage.ss_family)
+ return BJ_LT;
+
+ if (sockAddrStorage.ss_family == AF_INET)
+ {
+ struct sockaddr_in* pMyAddrIn = (sockaddr_in*) &sockAddrStorage;
+ struct sockaddr_in* pAddrIn = (sockaddr_in*) &pIPAddr->sockAddrStorage;
+ if (pMyAddrIn->sin_addr.s_addr > pAddrIn->sin_addr.s_addr)
+ return BJ_GT;
+ if (pMyAddrIn->sin_addr.s_addr < pAddrIn->sin_addr.s_addr)
+ return BJ_LT;
+ return BJ_EQUAL;
+
+ }
+ else
+ {
+ struct sockaddr_in6* pMyAddrIn = (sockaddr_in6*) &sockAddrStorage;
+ struct sockaddr_in6* pAddrIn = (sockaddr_in6*) &pIPAddr->sockAddrStorage;
+
+ int result = memcmp(&pMyAddrIn->sin6_addr, &pAddrIn->sin6_addr, sizeof(sockaddr_in6));
+
+ if (result > 0)
+ return BJ_GT;
+ if (result < 0)
+ return BJ_LT;
+ return BJ_EQUAL;
+ }
+
+
+}
+
+/*
+
+ take the mac address: for example 52:74:f2:b1:a8:7f
+ throw ff:fe in the middle: 52:74:f2:ff:fe:b1:a8:7f
+ reformat to IPv6 notation 5274:f2ff:feb1:a87f
+ convert the first octet from hexadecimal to binary: 52 -> 01010010
+ invert the bit at position 6 (counting from 0): 01010010 -> 01010000
+ convert octet back to hexadecimal: 01010000 -> 50
+ replace first octet with newly calculated one: 5074:f2ff:feb1:a87f
+ prepend the link-local prefix: fe80::5074:f2ff:feb1:a87f
+ */
+
+void BJIPAddr::CreateLinkLocalIPv6(BJ_UINT8* pmac)
+{
+ memset(&sockAddrStorage,0,sizeof(sockAddrStorage));
+ struct sockaddr_in6* pAddrIn = (sockaddr_in6*) &sockAddrStorage;
+
+ pAddrIn->sin6_family = AF_INET6;
+
+ pAddrIn->sin6_addr.__u6_addr.__u6_addr8[0] = 0xfe;
+ pAddrIn->sin6_addr.__u6_addr.__u6_addr8[1] = 0x80;
+
+ pAddrIn->sin6_addr.__u6_addr.__u6_addr8[8] = *pmac;
+ pAddrIn->sin6_addr.__u6_addr.__u6_addr8[8] ^= 1 << 1; // invert 6 bit
+ pAddrIn->sin6_addr.__u6_addr.__u6_addr8[9] = *(pmac+1);
+ pAddrIn->sin6_addr.__u6_addr.__u6_addr8[10] = *(pmac+2);
+
+ pAddrIn->sin6_addr.__u6_addr.__u6_addr8[11] = 0xff;
+ pAddrIn->sin6_addr.__u6_addr.__u6_addr8[12] = 0xfe;
+
+
+ pAddrIn->sin6_addr.__u6_addr.__u6_addr8[13] = *(pmac+3);
+ pAddrIn->sin6_addr.__u6_addr.__u6_addr8[14] = *(pmac+4);
+ pAddrIn->sin6_addr.__u6_addr.__u6_addr8[15] = *(pmac+5);
+
+
+}
+
+char* BJIPAddr::GetString()
+{
+ memset(stringbuffer,0,sizeof(stringbuffer));
+ if (IsIPv6())
+ {
+ struct sockaddr_in6* pAddrIn = (sockaddr_in6*) &sockAddrStorage;
+ inet_ntop(AF_INET6, &pAddrIn->sin6_addr, stringbuffer, sizeof(stringbuffer));
+ }
+ else
+ {
+ struct sockaddr_in* pAddrIn = (sockaddr_in*) &sockAddrStorage;
+ inet_ntop(AF_INET, &pAddrIn->sin_addr, stringbuffer, sizeof(stringbuffer));
+ }
+ return stringbuffer;
+}
+
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjIPAddr.h b/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjIPAddr.h
new file mode 100644
index 00000000..579355a6
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjIPAddr.h
@@ -0,0 +1,56 @@
+//
+// bjIPAddr.h
+// TestTB
+//
+// Created by Terrin Eager on 1/19/13.
+//
+//
+
+#ifndef __TestTB__bjIPAddr__
+#define __TestTB__bjIPAddr__
+
+#include <iostream>
+#include <sys/socket.h>
+#include "bjtypes.h"
+
+class BJIPAddr
+{
+public:
+ BJIPAddr();
+ BJIPAddr(const BJIPAddr& src);
+
+ void Empty();
+
+ bool IsBonjourMulticast();
+ bool IsSameSubNet(BJIPAddr* addr);
+
+ bool IsIPv4();
+ bool IsIPv6();
+ bool IsIPv6LinkLocal();
+ bool IsEmpty();
+ bool IsEmptySubnet();
+
+ void Set(const char* addr);
+ void Setv6(const char* addr);
+ void Set(struct in6_addr* ipi6_addr);
+ void Set(struct in_addr* ip_addr);
+ void Set(struct sockaddr_storage* sockStorage);
+ void Setv4Raw(BJ_UINT8* ipi4_addr);
+ void Setv6Raw(BJ_UINT8* ipi6_addr);
+
+ sockaddr_storage* GetRawValue();
+ struct in6_addr* Getin6_addr();
+
+ void CreateLinkLocalIPv6(BJ_UINT8* mac);
+ BJ_COMPARE Compare(BJIPAddr* addr);
+ BJ_UINT16 GetPortNumber();
+ char* GetString();
+private:
+ sockaddr_storage sockAddrStorage;
+ BJ_INT32 IPv4SubNet;
+ char stringbuffer[100];
+ static sockaddr_storage emptySockAddrStorage;
+};
+
+
+#endif /* defined(__TestTB__bjIPAddr__) */
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjMACAddr.cpp b/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjMACAddr.cpp
new file mode 100644
index 00000000..78d2a8db
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjMACAddr.cpp
@@ -0,0 +1,11 @@
+//
+// bjMACAddr.cpp
+// TestTB
+//
+// Created by Terrin Eager on 3/23/13.
+//
+//
+
+
+#include "bjMACAddr.h"
+
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjMACAddr.h b/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjMACAddr.h
new file mode 100644
index 00000000..ced95507
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjMACAddr.h
@@ -0,0 +1,54 @@
+//
+// bjMACAddr.h
+// TestTB
+//
+// Created by Terrin Eager on 3/23/13.
+//
+//
+
+#ifndef __TestTB__bjMACAddr__
+#define __TestTB__bjMACAddr__
+
+#include <iostream>
+#include <sys/socket.h>
+#include "bjtypes.h"
+
+class BJMACAddr
+{
+public:
+ BJMACAddr() { memset(addr,0,sizeof(addr));};
+ BJMACAddr(const BJMACAddr& Src) { memcpy(addr,Src.addr,sizeof(addr)); };
+
+ void operator=(const BJMACAddr& Src) { memcpy(addr,Src.addr,sizeof(addr)); };
+
+ void Set(unsigned char* newAddr) {memcpy(addr,newAddr,sizeof(addr));};
+ void SetString(char* newAddrString)
+ {
+ int newAddr[6] = {0,0,0,0,0,0};
+ sscanf(newAddrString, "%02X:%02X:%02X:%02X:%02X:%02X", &newAddr[0],&newAddr[1],&newAddr[2],&newAddr[3],&newAddr[4],&newAddr[5]);
+ for (int i=0; i< 6; i++)
+ addr[i] = newAddr[i];
+ };
+ unsigned char* Get() {return addr;};
+
+ void CopyVendor(BJMACAddr& src) { memset(addr,0,sizeof(addr)); memcpy(addr,src.addr,4);}; // 3 is standar vendor But 4 is better with apple products
+
+ char* GetString() {sprintf(buffer,"%02X:%02X:%02X:%02X:%02X:%02X", addr[0],addr[1],addr[2],addr[3],addr[4],addr[5]); return buffer;};
+ char* GetStringVendor() {sprintf(buffer,"%02X:%02X:%02X", addr[0],addr[1],addr[2]); return buffer;};
+ BJ_COMPARE Compare(BJMACAddr* compareAddr)
+ {
+ int result = memcmp(addr, compareAddr->addr, sizeof(addr));
+ if (result > 0)
+ return BJ_GT;
+ if (result < 0)
+ return BJ_LT;
+ return BJ_EQUAL;
+ };
+ bool IsEmpty() { return (addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]) == 0;};
+
+private:
+ unsigned char addr[6];
+ char buffer[25];
+};
+
+#endif /* defined(__TestTB__bjMACAddr__) */
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjStringtoStringMap.cpp b/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjStringtoStringMap.cpp
new file mode 100644
index 00000000..3c5db739
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjStringtoStringMap.cpp
@@ -0,0 +1,40 @@
+//
+// bjStringtoStringMap.cpp
+// TestTB
+//
+// Created by Terrin Eager on 12/21/12.
+//
+//
+
+#include "bjStringtoStringMap.h"
+
+/////////////////////
+
+StringMapNode::StringMapNode()
+{
+
+
+}
+
+StringMapNode::StringMapNode(BJString* pKey)
+{
+ m_Key = *pKey;
+}
+
+StringMapNode::~StringMapNode()
+{
+
+}
+
+void StringMapNode::CopyNode(CRBNode* pSource)
+{
+ m_Key = ((StringMapNode*)pSource)->m_Key;
+}
+
+BJ_COMPARE StringMapNode::Compare(BJString* pKey)
+{
+
+ return m_Key.Compare(*pKey);
+
+}
+
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjStringtoStringMap.h b/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjStringtoStringMap.h
new file mode 100644
index 00000000..4e44d9d5
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjStringtoStringMap.h
@@ -0,0 +1,42 @@
+//
+// bjStringtoStringMap.h
+// TestTB
+//
+// Created by Terrin Eager on 12/21/12.
+//
+//
+
+#ifndef __TestTB__bjStringtoStringMap__
+#define __TestTB__bjStringtoStringMap__
+
+#include <iostream>
+#include "bjstring.h"
+#include "LLRBTree.h"
+
+class StringMapNode : public CRBNode<BJString>
+{
+public:
+ StringMapNode();
+ StringMapNode(BJString* pKey);
+ ~StringMapNode();
+ inline virtual BJ_COMPARE Compare(BJString* pKey);
+ inline virtual void CopyNode(CRBNode* pSource);
+ inline virtual void Init(){};
+ inline virtual void Clear() {};
+
+
+ BJString value;
+
+};
+
+class BJStringtoStringMap : public CLLRBTree<BJString, StringMapNode>
+{
+public:
+
+
+};
+
+
+
+
+#endif /* defined(__TestTB__bjStringtoStringMap__) */
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjsocket.cpp b/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjsocket.cpp
new file mode 100644
index 00000000..da3ce4ad
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjsocket.cpp
@@ -0,0 +1,384 @@
+//
+// bjsocket.cpp
+// TestTB
+//
+// Created by Terrin Eager on 10/24/12.
+//
+//
+#define __APPLE_USE_RFC_2292
+
+#include <unistd.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+#include <ifaddrs.h>
+#include <net/if.h>
+
+#include "bjsocket.h"
+#include "bjstring.h"
+
+
+////////////////////////////
+/// BJSocket
+///////////////////////////
+const BJ_UINT16 BonjourPort = 5353;
+
+BJSocket::BJSocket()
+{
+ socketHandle = 0;
+ buffer = NULL;
+ IPVersion = 0;
+ interfaceID = 0;
+}
+
+BJSocket::~BJSocket()
+{
+
+}
+
+bool BJSocket::Init()
+{
+
+ socketHandle = 0;
+ buffer = (BJ_UINT8*)malloc(MAX_FRAME_SIZE);
+
+ if (buffer == NULL)
+ return false;
+
+ //Setup msghdr;
+ memset(&socketMsghdr, '\0', sizeof(socketMsghdr));
+ socketMsghdr.msg_name = &peerAddr;
+ socketMsghdr.msg_namelen = sizeof(peerAddr);
+ socketMsghdr.msg_iov = socketIovec;
+ socketMsghdr.msg_iovlen = 1;
+ socketIovec[0].iov_base = (char *) buffer;
+ socketIovec[0].iov_len = MAX_FRAME_SIZE;
+
+
+ socketMsghdr.msg_control = socketCmsghdr;
+ socketMsghdr.msg_controllen = sizeof(socketCmsghdr);
+
+ return true;
+
+}
+
+bool BJSocket::CreateListenerIPv4(BJString interfaceName)
+{
+ bool bResult = true;
+ const int onoptval = 1;
+
+ if (socketHandle)
+ Close();
+
+ Init();
+
+
+ if (interfaceName.GetLength() > 0)
+ interfaceID = if_nametoindex(interfaceName.GetBuffer());
+
+
+ socketHandle = socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
+// socketHandle = socket(PF_INET,SOCK_DGRAM,IPPROTO_RAW);
+
+ if (-1 == setsockopt(socketHandle,SOL_SOCKET,SO_REUSEPORT,&onoptval,sizeof(onoptval)))
+ {
+ printf("setsockopt for SO_REUSEPORT failed");
+ Close();
+ return false;
+ }
+
+ JoinMulticastv4(interfaceName);
+
+ // set PktInfo to get dest address
+
+ if (-1 == setsockopt(socketHandle, IPPROTO_IP, IP_PKTINFO, &onoptval, sizeof(onoptval)))
+ {
+ printf("setsockopt for IP_PKTINFO failed");
+ Close();
+ return false;
+ }
+
+ // bind to socket
+
+ struct sockaddr_in sa;
+ memset(&sa,0,sizeof(sockaddr_in));
+ sa.sin_len = sizeof(sockaddr_in);
+ sa.sin_family = AF_INET;
+ sa.sin_addr.s_addr = INADDR_ANY;
+ sa.sin_port = htons(BonjourPort);
+
+ if (-1 == bind(socketHandle,(struct sockaddr*)&sa,sizeof(sa)))
+ {
+ printf("error in bind: %s\n",strerror(errno));
+ Close();
+ return false;
+ }
+ IPVersion = 4;
+
+ return bResult;
+}
+
+bool BJSocket::CreateListenerIPv6(BJString interfaceName)
+{
+ bool bResult = true;
+ const int onoptval=1;
+
+ if (socketHandle)
+ Close();
+
+ Init();
+
+ if (interfaceName.GetLength() > 0)
+ interfaceID = if_nametoindex(interfaceName.GetBuffer());
+
+ socketHandle = socket(PF_INET6,SOCK_DGRAM,IPPROTO_UDP);
+
+ if (-1 == setsockopt(socketHandle,SOL_SOCKET,SO_REUSEPORT,&onoptval,sizeof(onoptval)))
+ {
+ printf("setsockopt for SO_REUSEPORT failed");
+ Close();
+ return false;
+ }
+
+ JoinMulticastv6(interfaceName);
+
+ // set PktInfo to get dest address
+ if (-1 == setsockopt(socketHandle, IPPROTO_IPV6, IPV6_PKTINFO, &onoptval, sizeof(onoptval)))
+ {
+ printf("setsockopt for IP_PKTINFO failed");
+ Close();
+ return false;
+ }
+
+ // bind to socket
+ struct sockaddr_in6 sa6;
+ memset(&sa6,0,sizeof(sockaddr_in6));
+ sa6.sin6_len = sizeof(sockaddr_in6);
+ sa6.sin6_family = AF_INET6;
+ sa6.sin6_addr = in6addr_any;
+ sa6.sin6_port = htons(BonjourPort);
+
+ if (-1 == bind(socketHandle,(struct sockaddr*)&sa6,sizeof(sa6)))
+ {
+ printf("error in bind: %s\n",strerror(errno));
+ Close();
+ return false;
+ }
+ IPVersion = 6;
+
+ return bResult;
+}
+
+bool BJSocket::Close()
+{
+ bool bResult = true;
+
+ if (socketHandle)
+ close(socketHandle);
+
+ socketHandle = 0;
+
+ return bResult;
+}
+
+int BJSocket::Read()
+{
+ int nLength = (int) recvmsg(socketHandle, &socketMsghdr,0);
+ if (!CheckInterface())
+ return 0;
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ m_CurrentFrame.Set(buffer-14-40-8,nLength,tv.tv_sec*1000000ll + tv.tv_usec);
+ return nLength;
+}
+
+BJIPAddr* BJSocket::GetSrcAddr()
+{
+ sourceAddr.Set(&peerAddr);
+ return &sourceAddr;
+}
+
+BJIPAddr* BJSocket::GetDestAddr()
+{
+
+ struct cmsghdr *cmsg;
+
+ for(cmsg = CMSG_FIRSTHDR(&socketMsghdr); cmsg != NULL; cmsg = CMSG_NXTHDR(&socketMsghdr, cmsg))
+ {
+
+ if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO)
+ {
+ struct in_pktinfo* pPktInfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
+
+ destAddr.Set(&pPktInfo->ipi_addr);
+ }
+ if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO)
+ {
+ struct in6_pktinfo* pPktInfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
+ destAddr.Set(&pPktInfo->ipi6_addr);
+ }
+ }
+ return &destAddr;
+}
+
+bool BJSocket::CheckInterface()
+{
+ if (interfaceID ==0)
+ return true;
+ struct cmsghdr *cmsg;
+
+ bool bFound = false;
+
+ for(cmsg = CMSG_FIRSTHDR(&socketMsghdr); cmsg != NULL; cmsg = CMSG_NXTHDR(&socketMsghdr, cmsg))
+ {
+
+ if ((cmsg->cmsg_level == IPPROTO_IP) && cmsg->cmsg_type == IP_PKTINFO)
+ {
+ bFound = true;
+ struct in_pktinfo* pPktInfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
+ if (pPktInfo->ipi_ifindex == interfaceID)
+ return true;
+ else
+ {
+ if (pPktInfo->ipi_ifindex != 4)
+ {
+ sourceAddr.Set(&peerAddr);
+ printf("address:%d %s \n",pPktInfo->ipi_ifindex,sourceAddr.GetString());
+ }
+ }
+ }
+ if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO)
+ {
+ bFound = true;
+ struct in6_pktinfo* pPktInfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
+ if (pPktInfo->ipi6_ifindex == interfaceID)
+ return true;
+ }
+ }
+ if (!bFound)
+ printf("PKTINFO not found \n");
+ return false;
+}
+
+bool BJSocket::IsMulticastPacket()
+{
+ return GetDestAddr()->IsBonjourMulticast();
+
+}
+
+int BJSocket::GetSockectHandle()
+{
+ return socketHandle;
+}
+
+BJ_UINT8* BJSocket::GetBuffer()
+{
+ return buffer;
+}
+
+void BJSocket::JoinMulticastv4(BJString interfaceName)
+{
+ if (interfaceName.GetLength() == 0)
+ {
+ // join Multicast group
+ struct ip_mreq imr;
+ imr.imr_multiaddr.s_addr = inet_addr( "224.0.0.251");
+ imr.imr_interface.s_addr = INADDR_ANY;
+ if (-1 == setsockopt(socketHandle, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr)))
+ {
+ printf("setsockopt for IP_ADD_MEMBERSHIP failed");
+ }
+ return;
+ }
+
+ struct ifaddrs *ifa, *orig;
+
+ getifaddrs(&ifa);
+
+ orig = ifa;
+
+ for ( ; ifa; ifa = ifa->ifa_next)
+ {
+ if (interfaceName == ifa->ifa_name && ifa->ifa_addr->sa_family == AF_INET)
+ {
+ struct sockaddr_in *ifa_addr = (struct sockaddr_in *)ifa->ifa_addr;
+ struct ip_mreq imr;
+ imr.imr_multiaddr.s_addr = inet_addr( "224.0.0.251");
+ imr.imr_interface.s_addr = ifa_addr->sin_addr.s_addr;
+ if (-1 == setsockopt(socketHandle, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr)))
+ {
+ printf("setsockopt for IP_ADD_MEMBERSHIP failed");
+ }
+ }
+ }
+
+ freeifaddrs(orig);
+
+}
+
+void BJSocket::JoinMulticastv6(BJString interfaceName)
+{
+
+ if (interfaceName.GetLength() == 0)
+ return;
+
+ // join Multicast group
+ struct in6_addr BonjourMultiaddr = {{{ 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB }}};
+ struct ipv6_mreq i6mr;
+ memset(&i6mr,0,sizeof(i6mr));
+ memcpy(&i6mr.ipv6mr_multiaddr, &BonjourMultiaddr, sizeof(BonjourMultiaddr));
+ if (interfaceName.GetLength() > 0)
+ i6mr.ipv6mr_interface = interfaceID;
+ else
+ i6mr.ipv6mr_interface = __IPV6_ADDR_SCOPE_SITELOCAL;
+ int err = setsockopt(socketHandle, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
+ if (err < 0 && (errno != EADDRINUSE))
+ {
+ printf("setsockopt for IPV6_JOIN_GROUP failed %d",errno);
+ }
+}
+
+////////////////////////////////////////
+// BJSelect
+///////////////////////////////////////
+
+
+BJSelect::BJSelect()
+{
+ FD_ZERO(&socketSet);
+ maxSocket = 0;
+
+}
+
+bool BJSelect::Add(BJSocket& s)
+{
+ int sock = s.GetSockectHandle();
+ FD_SET(sock, &socketSet);
+ if (sock > maxSocket)
+ maxSocket = sock;
+
+ return true;
+
+}
+
+int BJSelect::Wait(int sec)
+{
+ struct timeval tv;
+ memset(&tv, 0, sizeof(tv));
+ tv.tv_sec = sec;
+
+ int result = select(maxSocket+1, &socketSet, NULL, NULL, &tv);
+ return result;
+
+}
+
+bool BJSelect::IsReady(BJSocket& Socket)
+{
+ int bIsSet = FD_ISSET(Socket.GetSockectHandle(), &socketSet);
+ return (bIsSet != 0);
+}
+
+
+
+
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjsocket.h b/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjsocket.h
new file mode 100644
index 00000000..c85e3841
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjsocket.h
@@ -0,0 +1,88 @@
+//
+// bjsocket.h
+// TestTB
+//
+// Created by Terrin Eager on 10/24/12.
+//
+//
+
+#ifndef __TestTB__bjsocket__
+#define __TestTB__bjsocket__
+
+#include <iostream>
+
+#include <sys/socket.h>
+
+#include "bjtypes.h"
+#include "bjIPAddr.h"
+#include "bjstring.h"
+
+#include "Frame.h"
+
+
+class BJSocket
+{
+public:
+
+ BJSocket();
+ virtual ~BJSocket();
+
+ bool Init();
+
+ bool CreateListenerIPv4(BJString interfaceName);
+ bool CreateListenerIPv6(BJString interfaceName);
+
+ bool Close();
+
+ int Read();
+
+ Frame m_CurrentFrame;
+
+ bool IsMulticastPacket();
+
+ int GetSockectHandle();
+
+ BJ_UINT8* GetBuffer();
+ BJIPAddr* GetSrcAddr();
+ BJIPAddr* GetDestAddr();
+
+private:
+ void JoinMulticastv4(BJString interfaceName);
+ void JoinMulticastv6(BJString interfaceName);
+
+ bool CheckInterface();
+
+ BJ_UINT32 interfaceID;
+
+ int socketHandle;
+ BJ_UINT8* buffer;
+
+
+ int IPVersion;
+ BJIPAddr sourceAddr;
+ BJIPAddr destAddr;
+
+ struct msghdr socketMsghdr;
+ sockaddr_storage peerAddr;
+ struct iovec socketIovec[1];
+ struct cmsghdr socketCmsghdr[10];
+
+};
+
+class BJSelect
+{
+public:
+ BJSelect();
+
+ bool Add(BJSocket& s);
+ int Wait(int sec);
+
+ bool IsReady(BJSocket& s);
+
+private:
+ fd_set socketSet;
+ int maxSocket;
+
+};
+
+#endif /* defined(__TestTB__bjsocket__) */
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjstring.cpp b/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjstring.cpp
new file mode 100644
index 00000000..5a6fcdf1
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjstring.cpp
@@ -0,0 +1,238 @@
+//
+// bjstring.cpp
+// TestTB
+//
+// Created by Terrin Eager on 9/26/12.
+//
+//
+
+#include "bjstring.h"
+#include <time.h>
+
+
+BJString::BJString()
+{
+ buffer = NULL;
+ length = 0;
+}
+
+BJString::BJString(const BJString& scr)
+{
+ buffer = NULL;
+ length = 0;
+ Set(scr.GetBuffer());
+}
+BJString::BJString(const char* str)
+{
+ buffer = NULL;
+ length = 0;
+ Set(str);
+}
+
+BJString::~BJString()
+{
+ delete[] buffer;
+ buffer = NULL;
+}
+
+
+BJString& BJString::operator=(const char* str)
+{
+ Set(str);
+ return *this;
+}
+
+BJString& BJString::operator=(const BJString& str)
+{
+ Set(str.GetBuffer());
+ return *this;
+}
+bool BJString::operator==(const char* str)
+{
+ if (buffer == NULL && str == NULL)
+ return true;
+ if (buffer == NULL || str == NULL)
+ return false;
+
+ return (strcmp(str,buffer) == 0);
+}
+bool BJString::operator==(const BJString& str)
+{
+ if (buffer == NULL && str.GetBuffer() == NULL)
+ return true;
+ if (buffer == NULL || str.GetBuffer() == NULL)
+ return false;
+ return (strcmp(str.GetBuffer(),buffer) == 0);
+}
+
+bool BJString::operator<(const BJString& str) const
+{
+ const char* myBuff = GetBuffer();
+ const char* otherBuff = str.GetBuffer();
+
+ if (myBuff == NULL && otherBuff == NULL)
+ return false;
+ if (myBuff != NULL && otherBuff == NULL)
+ return false;
+ if (myBuff == NULL && otherBuff != NULL)
+ return true;
+
+ int cmp = strcmp(myBuff, otherBuff);
+
+ if (cmp < 0)
+ return true;
+ else
+ return false;
+
+}
+
+BJ_COMPARE BJString::Compare(const BJString& str)
+{
+ const char* myBuff = GetBuffer();
+ const char* otherBuff = str.GetBuffer();
+
+ if (myBuff == NULL && otherBuff == NULL)
+ return BJ_EQUAL;
+ if (myBuff != NULL && otherBuff == NULL)
+ return BJ_GT;
+ if (myBuff == NULL && otherBuff != NULL)
+ return BJ_LT;
+
+ int cmp = strcmp(myBuff, otherBuff);
+
+ if (cmp > 0)
+ return (BJ_GT);
+ else if (cmp < 0)
+ return (BJ_LT);
+ else
+ return (BJ_EQUAL);
+
+}
+
+BJString& BJString::operator+=(const char* str)
+{
+ if (buffer == NULL)
+ return operator=(str);
+ if (str == NULL)
+ return *this;
+
+ BJString temp = buffer;
+ Create((BJ_UINT32)(strlen(buffer) + strlen(str)));
+ strcpy(buffer,temp.GetBuffer());
+ strcat(buffer,str);
+ return *this;
+}
+BJString& BJString::operator+=(const BJString&str)
+{
+ operator+=(str.GetBuffer());
+ return *this;
+}
+
+
+const char* BJString::GetBuffer() const
+{
+ return buffer;
+}
+
+void BJString::Set(const char* str)
+{
+
+ BJ_UINT32 len = str?(BJ_UINT32)strlen(str):0;
+ if (len > 255)
+ len = 250;
+ Create(len);
+ if (buffer && str)
+ strcpy(buffer, str);
+
+}
+void BJString::Set(const char* str, BJ_UINT32 len)
+{
+ Create(len);
+ if (buffer)
+ {
+ if (str)
+ strncpy(buffer, str, len);
+ else
+ memset(buffer, 0, length);
+ }
+}
+
+void BJString::Append(const char* str, BJ_UINT32 len)
+{
+ if (length < (strlen(buffer) + strlen(str)))
+ {
+ BJString temp = buffer;
+ Create((BJ_UINT32)(strlen(buffer) + strlen(str)));
+ if (buffer && temp.buffer)
+ strcpy(buffer,temp.GetBuffer());
+ }
+ strncat(buffer,str,len);
+}
+
+bool BJString::Contains(const char* str)
+{
+ if (buffer == NULL && str == NULL)
+ return true;
+ if (buffer == NULL || str == NULL)
+ return false;
+ return (strstr(buffer,str) != NULL);
+}
+
+BJ_UINT32 BJString::GetUINT32()
+{
+ if (buffer == NULL)
+ return 0;
+
+ return atoi(buffer);
+}
+
+void BJString::Format(BJ_UINT64 number,BJ_FORMAT_STYLE style)
+{
+ switch (style) {
+ case BJSS_BYTE:
+ Create(32);
+ sprintf(buffer,"%llu",number);
+ break;
+ case BJSS_TIME:
+ {
+ char formatedTime[24];
+ time_t timeValue = number;
+ struct tm* timeStruct = localtime(&timeValue);
+ strftime(formatedTime, sizeof(formatedTime), "%Y-%m-%d_%T_%a", timeStruct);
+ Set(formatedTime);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+
+void BJString::Create(BJ_UINT32 len)
+{
+ if (length >= len)
+ {
+ if (length > 0)
+ memset(buffer, 0, len+1);
+ return;
+ }
+
+ if (buffer)
+ {
+ delete buffer;
+ buffer = NULL;
+ length = 0;
+ }
+
+ buffer = new char[len+1];
+ if (buffer)
+ {
+ memset(buffer, 0, len+1);
+ length = len;
+ }
+}
+
+BJ_UINT32 BJString::GetLength()
+{
+ return buffer?(BJ_UINT32)strlen(buffer):0;
+}
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjstring.h b/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjstring.h
new file mode 100644
index 00000000..67a78f89
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjstring.h
@@ -0,0 +1,63 @@
+//
+// bjstring.h
+// TestTB
+//
+// Created by Terrin Eager on 9/26/12.
+//
+//
+
+#ifndef __TestTB__bjstring__
+#define __TestTB__bjstring__
+
+#include <iostream>
+#include "bjtypes.h"
+
+class BJString
+{
+
+public:
+ BJString();
+ BJString(const BJString& scr);
+ BJString(const char* str);
+ virtual ~BJString();
+
+ BJString& operator=(const char* str);
+ BJString& operator=(const BJString& str);
+ bool operator==(const char* str);
+ bool operator!=(const char* str){return !operator==(str);};
+ bool operator==(const BJString& str);
+ bool operator!=(const BJString& str) {return !operator==(str);};
+ bool operator<(const BJString& str) const;
+
+ BJ_COMPARE Compare(const BJString& str);
+
+
+ BJString& operator+=(const char* str);
+ BJString& operator+=(const BJString& str);
+
+ const char* GetBuffer() const;
+
+ void Set(const char* str);
+ void Set(const char* str,BJ_UINT32 len);
+
+ void Append(const char* str, BJ_UINT32 len);
+
+ bool Contains(const char* str);
+
+ BJ_UINT32 GetUINT32();
+
+ enum BJ_FORMAT_STYLE {BJSS_BYTE,BJSS_TIME} ;
+ void Format(BJ_UINT64 number,BJ_FORMAT_STYLE style);
+
+ BJ_UINT32 GetLength();
+
+ BJ_UINT32 GetBufferLength(){return length;};
+
+private:
+
+ void Create(BJ_UINT32 len);
+ char* buffer;
+ BJ_UINT32 length;
+};
+
+#endif /* defined(__TestTB__bjstring__) */
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjtypes.h b/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjtypes.h
new file mode 100644
index 00000000..59de2732
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/bjtypes.h
@@ -0,0 +1,64 @@
+//
+// bjtypes.h
+// TestTB
+//
+// Created by Terrin Eager on 4/24/12.
+//
+//
+
+
+#ifndef TestTB_bjtypes_h
+#define TestTB_bjtypes_h
+typedef bool BJ_BOOL;
+
+typedef char BJ_INT8;
+typedef unsigned char BJ_UINT8;
+
+typedef short int BJ_INT16;
+typedef unsigned short int BJ_UINT16;
+
+typedef int BJ_INT32;
+typedef unsigned int BJ_UINT32;
+
+typedef long long BJ_INT64;
+typedef unsigned long long BJ_UINT64;
+
+#define DNS_NAME_OFFSET_MASK 0xc0
+
+#define MAX_FRAME_SIZE 0x2800
+
+
+enum BJ_COMPARE {BJ_GT,BJ_LT,BJ_EQUAL};
+
+#define PF_GET_UINT8(pBuffer,offset) ( (BJ_UINT8)pBuffer[offset] )
+#define PF_GET_UINT16(pBuffer,offset) ((((BJ_UINT16)pBuffer[offset]) << 8) | ((BJ_UINT16)pBuffer[offset+1]))
+#define PF_GET_UINT32(pBuffer,offset) ((pBuffer[offset] << 24) | (pBuffer[offset+1] << 16) | (pBuffer[offset+2] << 8) | (pBuffer[offset+3]))
+
+
+inline void endian_swap(BJ_UINT8& x)
+{
+ x = (x>>8) |(x<<8);
+}
+
+inline void endian_swap(BJ_UINT32& x)
+{
+ x = (x>>24) |
+ ((x<<8) & 0x00FF0000) |
+ ((x>>8) & 0x0000FF00) |
+ (x<<24);
+}
+
+
+inline void endian_swap(BJ_UINT64& x)
+{
+ x = (x>>56) |
+ ((x<<40) & 0x00FF000000000000) |
+ ((x<<24) & 0x0000FF0000000000) |
+ ((x<<8) & 0x000000FF00000000) |
+ ((x>>8) & 0x00000000FF000000) |
+ ((x>>24) & 0x0000000000FF0000) |
+ ((x>>40) & 0x000000000000FF00) |
+ (x<<56);
+}
+
+#endif
diff --git a/mDNSResponder/mDNSMacOSX/BonjourTop/source/main.cpp b/mDNSResponder/mDNSMacOSX/BonjourTop/source/main.cpp
new file mode 100644
index 00000000..52107bbe
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/BonjourTop/source/main.cpp
@@ -0,0 +1,179 @@
+//
+// main.cpp
+// BonjourTop
+//
+// Created by Terrin Eager on 4/24/13.
+// Copyright (c) 2013-2014 Apple Inc. All rights reserved.
+//
+
+#include <stdio.h>
+#include <curses.h>
+
+#include "bjtypes.h"
+#include "BonjourTop.h"
+
+#include <signal.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+
+#define BJ_VERSION_MAJOR 0
+#define BJ_VERSION_MINOR 23
+CBonjourTop BjTop;
+
+static void
+usage()
+{
+ printf("bonjourtop usage: bonjourTop (Version: %d.%d)\n",BJ_VERSION_MAJOR,BJ_VERSION_MINOR);
+ printf("\t\t\t [-t tcptrace_filename ]\n");
+ printf("\t\t\t [-i interfaceName]\n");
+ printf("\t\t\t [-m ipaddress/subnetmask] ie 17.255.45.12/17\n");
+ printf("\t\t\t [-e export_filename] \n");
+ printf("\t\t\t [-x seconds] 'Snapshot export every x seconds'\n");
+ printf("\t\t\t [-s] 'service information'\n");
+ printf("\t\t\t [-v] 'report the version number' \n");
+ printf("\t\t\t [-d] filename 'export device map. Adds timestamp and csv extension to the filename' \n");
+ printf("\t\t\t [-f application] 'filter application for device map (only available with -t -d options)' \n");
+ printf("While running the follow keys may be used:\n");
+ printf("\t b - sort by Bytes\n");
+ printf("\t p - sort by Packets (default)\n");
+ printf("\t n - sort by Name\n");
+ printf("\t a - Display Application Names (default) \n");
+ printf("\t s - Display Services Names \n");
+ printf("\t t - Display 24 hour packet per min \n");
+
+ printf("\t o - flip sort order\n");
+ printf("\t e - export to BonjourTop.csv\n");
+ printf("\t q - quit\n\n");
+}
+
+static void
+handle_window_change(int signal) {
+ switch (signal) {
+ case SIGWINCH:
+ BjTop.WindowSizeChanged();
+ break;
+ default:
+ break;
+ }
+}
+
+int main(int argc, char * const *argv)
+{
+
+ sigset_t sset, oldsset;
+ int c;
+
+ static struct option longopts[] = {
+ { "trace", required_argument, NULL, 't' },
+ { "interface", required_argument, NULL, 'i' },
+ { "ipaddr_subnet", required_argument, NULL, 'm' },
+ { "export", required_argument, NULL, 'e' },
+ { "snapshot", required_argument, NULL, 'x' },
+ { "service", no_argument, NULL, 's' },
+ { "version", no_argument, NULL, 'v' },
+ { "devicemap", required_argument, NULL, 'd' },
+ { "filter", required_argument, NULL, 'f' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ sigemptyset(&sset);
+
+ /* Block SIGWINCH signals while we are in a relayout. */
+ if(-1 == sigprocmask(SIG_BLOCK, &sset, &oldsset)) {
+ perror("sigprocmask");
+ exit(EXIT_FAILURE);
+ }
+
+ BJ_COLLECTBY_TYPE TypeList[] = {CBT_SERVICE,CBT_REQUEST_RESPONDS,CBT_SAME_DIFF_SUBNET,CBT_IP_ADDRESS_TYPE,CBT_PACKET};
+ BJString sTemp;
+
+ bool bLiveCapture = true;
+ bool bExport = false;
+
+ while ((c = getopt_long(argc, argv, "t:i:m:e:x:svd:f:phb", longopts, NULL)) != -1) {
+ switch (c) {
+ case 't':
+ BjTop.m_pTcpDumpFileName = optarg; // TCP Dump Filename
+ bLiveCapture = false;
+ BjTop.m_bCursers = false;
+ break;
+ case 'p':
+ BjTop.m_bCursers = false;
+ break;
+ case 'e':
+ bExport = true;
+ BjTop.m_pExportFileName = optarg; // Export filename
+ break;
+ case 'i':
+ BjTop.interfaceName = optarg; // Interface name
+ break;
+ case 'm':
+ BjTop.SetIPAddr(optarg); // TODO: verify that the argument is an ip address
+ break;
+ case 'x':
+ sTemp = optarg; // time in seconds for snapshots
+ BjTop.m_SnapshotSeconds = sTemp.GetUINT32();
+ break;
+ case 'd':
+ BjTop.m_bImportExportDeviceMap = true;
+ BjTop.m_DeviceFileName = optarg;
+ break;
+ case 'f':
+ BjTop.filterApplicationName = optarg;
+ break;
+ case 's':
+ BjTop.m_CurrentDisplay = CBonjourTop::BJ_DISPLAY_SERVICE;
+ break;
+ case 'v':
+ printf("\nbonjourtop Version: %d.%d\n\n",BJ_VERSION_MAJOR,BJ_VERSION_MINOR);
+ exit(0);
+ break;
+ case 'b':
+ BjTop.m_Collection.Init(TypeList);
+ bExport = true;
+ break;
+ case 'h':
+ usage();
+ exit(0);
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if (BjTop.m_bCursers)
+ {
+ signal(SIGWINCH, handle_window_change);
+ initscr();
+ timeout(0);
+ BjTop.PrintResults(1,false);
+ }
+
+ if (bLiveCapture)
+ BjTop.LiveCapture();
+ else
+ BjTop.CaptureFile();
+
+
+ if (bExport)
+ {
+ BjTop.ExportResults();
+ return 0;
+ }
+
+ if (BjTop.m_bCursers)
+ endwin();
+
+ if (BjTop.m_bImportExportDeviceMap)
+ {
+ BjTop.WriteDeviceFile();
+ BjTop.WriteVendorFile();
+ }
+
+ return 0;
+}
+
+
diff --git a/mDNSResponder/mDNSMacOSX/D2D.c b/mDNSResponder/mDNSMacOSX/D2D.c
new file mode 100644
index 00000000..2848cdab
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/D2D.c
@@ -0,0 +1,995 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002-2016 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 "D2D.h"
+#include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
+#include "DNSCommon.h"
+#include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
+#include "dns_sd.h" // For mDNSInterface_LocalOnly etc.
+#include "dns_sd_internal.h"
+#include "uds_daemon.h"
+#include "BLE.h"
+
+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));
+
+#pragma mark - D2D Support
+
+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, 0);
+ if (interface->RR_PTR.resrec.RecordType)
+ external_start_advertising_service(&interface->RR_PTR.resrec, 0);
+ }
+}
+
+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, 0);
+ if (interface->RR_PTR.resrec.RecordType)
+ external_stop_advertising_service(&interface->RR_PTR.resrec, 0);
+ }
+}
+
+// If record would have been advertised to the D2D plugin layer, stop that advertisement.
+mDNSexport void D2D_stop_advertising_record(AuthRecord *ar)
+{
+ DNSServiceFlags flags = deriveD2DFlagsFromAuthRecType(ar->ARType);
+ if (callExternalHelpers(ar->resrec.InterfaceID, ar->resrec.name, flags))
+ {
+ external_stop_advertising_service(&ar->resrec, flags);
+ }
+}
+
+// If record should be advertised to the D2D plugin layer, start that advertisement.
+mDNSexport void D2D_start_advertising_record(AuthRecord *ar)
+{
+ DNSServiceFlags flags = deriveD2DFlagsFromAuthRecType(ar->ARType);
+ if (callExternalHelpers(ar->resrec.InterfaceID, ar->resrec.name, flags))
+ {
+ external_start_advertising_service(&ar->resrec, flags);
+ }
+}
+
+// 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 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))
+ {
+ LogInfo("xD2DClearCache: Clearing cache record and deregistering %s", ARDisplayString(&mDNSStorage, &ptr->ar));
+ mDNS_Deregister(&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);
+}
+
+// Returns true if found in list, false otherwise
+mDNSlocal bool 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 false; }
+
+ (*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);
+ }
+ return true;
+}
+
+mDNSlocal mStatus xD2DParse(const mDNSu8 * const lhs, const mDNSu16 lhs_len, const mDNSu8 * const rhs, const mDNSu16 rhs_len, D2DRecordListElem **D2DListp)
+{
+ mDNS *const m = &mDNSStorage;
+
+ // Sanity check that key array (lhs) has one domain name, followed by the record type and single byte D2D
+ // plugin protocol version number.
+ // Note, we don't have a DNSMessage pointer at this point, so just pass in the lhs value as the lower bound
+ // of the input bytes we are processing. skipDomainName() does not try to follow name compression pointers,
+ // so it is safe to pass it the key byte array since it will stop parsing the DNS name and return a pointer
+ // to the byte after the first name compression pointer it encounters.
+ const mDNSu8 *keyp = skipDomainName((const DNSMessage *const) lhs, lhs, lhs + lhs_len);
+
+ // There should be 3 bytes remaining in a valid key,
+ // two for the DNS record type, and one for the D2D protocol version number.
+ if (keyp == NULL || (keyp + 3 != (lhs + lhs_len)))
+ {
+ LogInfo("xD2DParse: Could not parse DNS name in key");
+ return mStatus_Incompatible;
+ }
+ keyp += 2; // point to D2D compression packet format version byte
+ if (*keyp != compression_packet_v1)
+ {
+ LogInfo("xD2DParse: Invalid D2D packet version: %d", *keyp);
+ return mStatus_Incompatible;
+ }
+
+ 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("xD2DParse: failed to get large RR");
+ m->rec.r.resrec.RecordType = 0;
+ return mStatus_UnknownErr;
+ }
+ else
+ {
+ LogInfo("xD2DParse: got rr: %s", CRDisplayString(m, &m->rec.r));
+ }
+
+ *D2DListp = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (m->rec.r.resrec.rdlength <= sizeof(RDataBody) ? 0 : m->rec.r.resrec.rdlength - sizeof(RDataBody)));
+ if (!*D2DListp) return mStatus_NoMemoryErr;
+
+ AuthRecord *rr = &(*D2DListp)->ar;
+ 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;
+}
+
+mDNSexport void xD2DAddToCache(D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
+{
+ mDNS *const m = &mDNSStorage;
+ 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 = NULL;
+
+ err = xD2DParse((const mDNSu8 * const)key, (const mDNSu16)keySize, (const mDNSu8 * const)value, (const mDNSu16)valueSize, &ptr);
+ if (err)
+ {
+ LogMsg("xD2DAddToCache: xD2DParse returned error: %d", err);
+ PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
+ if (ptr)
+ mDNSPlatformMemFree(ptr);
+ return;
+ }
+
+#if ENABLE_BLE_TRIGGERED_BONJOUR
+ // If the record was created based on a BLE beacon, update the interface index to indicate
+ // this and thus match BLE specific queries.
+ if (transportType == D2DBLETransport)
+ ptr->ar.resrec.InterfaceID = mDNSInterface_BLE;
+#endif // ENABLE_BLE_TRIGGERED_BONJOUR
+
+ 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(const Byte *const key, const size_t keySize, const Byte *const value, const size_t valueSize)
+{
+ D2DRecordListElem *ptr = D2DRecords;
+ D2DRecordListElem *arptr = NULL;
+
+ if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DFindInList: NULL Byte * passed in or length == 0"); return NULL; }
+
+ mStatus err = xD2DParse((const mDNSu8 *const)key, (const mDNSu16)keySize, (const mDNSu8 *const)value, (const mDNSu16)valueSize, &arptr);
+ if (err)
+ {
+ LogMsg("xD2DFindInList: xD2DParse returned error: %d", err);
+ PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
+ if (arptr)
+ 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(&mDNSStorage, &arptr->ar));
+ mDNSPlatformMemFree(arptr);
+ return ptr;
+}
+
+mDNSexport void xD2DRemoveFromCache(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(key, keySize, value, valueSize);
+ if (ptr)
+ {
+ LogInfo("xD2DRemoveFromCache: Remove from cache: %s", ARDisplayString(&mDNSStorage, &ptr->ar));
+ mDNS_Deregister(&mDNSStorage, &ptr->ar);
+ }
+ }
+ else
+ LogMsg("xD2DRemoveFromCache: Unexpected result %d", result);
+}
+
+mDNSlocal void xD2DServiceResolved(D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
+{
+ (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(D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
+{
+ (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(D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
+{
+ (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)
+{
+ const char *eventString = "unknown";
+
+ KQueueLock();
+
+ 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(result, instanceHandle, transportType, key, keySize, value, valueSize);
+ break;
+ case D2DServiceLost:
+ xD2DRemoveFromCache(result, instanceHandle, transportType, key, keySize, value, valueSize);
+ break;
+ case D2DServiceResolved:
+ xD2DServiceResolved(result, instanceHandle, transportType, key, keySize, value, valueSize);
+ break;
+ case D2DServiceRetained:
+ xD2DRetainHappened(result, instanceHandle, transportType, key, keySize, value, valueSize);
+ break;
+ case D2DServiceReleased:
+ xD2DReleaseHappened(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("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(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)
+{
+#if ENABLE_BLE_TRIGGERED_BONJOUR
+ // BLE support currently not handled by a D2D plugin
+ if (applyToBLE(InterfaceID, flags))
+ {
+ domainname lower;
+
+ DomainnameToLower(typeDomain, &lower);
+ // pass in the key and keySize
+ mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype);
+ start_BLE_browse(InterfaceID, &lower, qtype, flags, compression_lhs, end - compression_lhs);
+ }
+ else
+#endif // ENABLE_BLE_TRIGGERED_BONJOUR
+ internal_start_browsing_for_service(InterfaceID, typeDomain, qtype, flags);
+}
+
+mDNSexport void internal_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags)
+{
+ domainname lower;
+
+ DomainnameToLower(typeDomain, &lower);
+
+ if (!D2DBrowseListRefCount(&lower, qtype))
+ {
+ D2DTransportType transportType, excludedTransport;
+
+ LogInfo("%s: Starting browse for: %##s %s", __func__, 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)
+{
+#if ENABLE_BLE_TRIGGERED_BONJOUR
+ // BLE support currently not handled by a D2D plugin
+ if (applyToBLE(InterfaceID, flags))
+ {
+ domainname lower;
+
+ // If this is the last instance of this browse, clear any cached records recieved for it.
+ // We are not guaranteed to get a D2DServiceLost event for all key, value pairs cached over BLE.
+ DomainnameToLower(typeDomain, &lower);
+ if (stop_BLE_browse(InterfaceID, &lower, qtype, flags))
+ xD2DClearCache(&lower, qtype);
+ }
+ else
+#endif // ENABLE_BLE_TRIGGERED_BONJOUR
+ internal_stop_browsing_for_service(InterfaceID, typeDomain, qtype, flags);
+}
+
+mDNSexport void internal_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags)
+{
+ domainname lower;
+
+ DomainnameToLower(typeDomain, &lower);
+
+ // If found in list and this is the last reference to this browse, remove the key from the D2D plugins.
+ if (D2DBrowseListRelease(&lower, qtype) && !D2DBrowseListRefCount(&lower, qtype))
+ {
+ D2DTransportType transportType, excludedTransport;
+
+ LogInfo("%s: Stopping browse for: %##s %s", __func__, 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)
+{
+#if ENABLE_BLE_TRIGGERED_BONJOUR
+ if (applyToBLE(resourceRecord->InterfaceID, flags))
+ {
+ domainname lower;
+
+ DomainnameToLower(resourceRecord->name, &lower);
+ start_BLE_advertise(resourceRecord, &lower, resourceRecord->rrtype, flags);
+ }
+ else
+#endif // ENABLE_BLE_TRIGGERED_BONJOUR
+ internal_start_advertising_service(resourceRecord, flags);
+}
+
+mDNSexport void internal_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("%s: %s", __func__, 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)
+{
+#if ENABLE_BLE_TRIGGERED_BONJOUR
+ // BLE support currently not handled by a D2D plugin
+ if (applyToBLE(resourceRecord->InterfaceID, flags))
+ {
+ domainname lower;
+
+ DomainnameToLower(resourceRecord->name, &lower);
+ stop_BLE_advertise(&lower, resourceRecord->rrtype, flags);
+ }
+ else
+#endif // ENABLE_BLE_TRIGGERED_BONJOUR
+ internal_stop_advertising_service(resourceRecord, flags);
+}
+
+mDNSexport void internal_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("%s: %s", __func__, RRDisplayString(&mDNSStorage, resourceRecord));
+
+ // For SRV records, update packet filter if p2p interface already exists, otherwise,
+ // 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, 0);
+ external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, 0);
+ }
+}
+
+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, 0);
+ external_stop_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, 0);
+ }
+}
+
+void initializeD2DPlugins(mDNS *const m)
+{
+ // We only initialize if mDNSCore successfully initialized.
+ if (D2DInitialize)
+ {
+ D2DStatus ds = D2DInitialize(CFRunLoopGetMain(), xD2DServiceCallback, m);
+ if (ds != kD2DSuccess)
+ LogMsg("D2DInitialiize failed: %d", ds);
+ else
+ LogMsg("D2DInitialize succeeded");
+ }
+}
+
+void terminateD2DPlugins(void)
+{
+ if (D2DTerminate)
+ {
+ D2DStatus ds = D2DTerminate();
+ if (ds != kD2DSuccess)
+ LogMsg("D2DTerminate failed: %d", ds);
+ else
+ LogMsg("D2DTerminate succeeded");
+ }
+}
+
+#ifdef UNIT_TEST
+#pragma mark - Unit test support routines
+
+// These unit test support routines are called from unittests/ framework
+// and are not compiled for the mDNSResponder runtime code paths.
+
+void D2D_unitTest(void)
+{
+}
+
+#endif // UNIT_TEST
diff --git a/mDNSResponder/mDNSMacOSX/D2D.h b/mDNSResponder/mDNSMacOSX/D2D.h
new file mode 100644
index 00000000..a9850728
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/D2D.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2015-2016 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 _D2D_H_
+#define _D2D_H_
+
+#include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
+#include "dnssd_ipc.h"
+#include <DeviceToDeviceManager/DeviceToDeviceManager.h>
+
+extern void internal_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags);
+extern void internal_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags);
+extern void internal_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags);
+extern void internal_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags);
+
+void xD2DAddToCache(D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize);
+void xD2DRemoveFromCache(D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize);
+
+#if ENABLE_BLE_TRIGGERED_BONJOUR
+// Just define as the current max value for now for BLE.c prototype.
+// TODO: Will need to define in DeviceToDeviceManager.framework if we convert the
+// BLE discovery code to a D2D plugin.
+#define D2DBLETransport D2DTransportMax
+#endif // ENABLE_BLE_TRIGGERED_BONJOUR
+
+#ifdef UNIT_TEST
+#pragma mark - Unit test declarations
+
+// Unit test entry points, which are not used in the mDNSResponder runtime code paths.
+void D2D_unitTest(void);
+
+#endif // UNIT_TEST
+
+#endif /* _D2D_H_ */
diff --git a/mDNSResponder/mDNSMacOSX/DNS64.c b/mDNSResponder/mDNSMacOSX/DNS64.c
new file mode 100644
index 00000000..1f4e0ec2
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DNS64.c
@@ -0,0 +1,559 @@
+/*
+ * Copyright (c) 2017 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 <TargetConditionals.h>
+
+// DNS64 code is only for iOS, which is currently the only Apple OS that supports DNS proxy network extensions.
+
+#if TARGET_OS_IOS
+#include "DNS64.h"
+
+#include <AssertMacros.h>
+#include <network/nat64.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "dns_sd.h"
+#include "dns_sd_internal.h"
+#include "uDNS.h"
+
+//===========================================================================================================================
+// Constants
+//===========================================================================================================================
+
+#define kDNS64IPv4OnlyFQDNString "\x8" "ipv4only" "\x4" "arpa"
+#define kDNS64IPv4OnlyFQDN ((const domainname *) kDNS64IPv4OnlyFQDNString)
+#define kDNS64IPv4OnlyFQDNLength 15 // 9 bytes for first label, 5 bytes for second label, and 1 byte for the root label.
+
+#define sizeof_field(TYPE, FIELD) sizeof(((TYPE *)0)->FIELD) // From CoreUtils.h
+
+check_compile_time(sizeof(kDNS64IPv4OnlyFQDNString) == kDNS64IPv4OnlyFQDNLength);
+check_compile_time(sizeof_field(DNSQuestion, qname) >= kDNS64IPv4OnlyFQDNLength);
+check_compile_time(sizeof_field(DNS64, qnameStash) == kDNS64IPv4OnlyFQDNLength);
+
+//===========================================================================================================================
+// Local Prototypes
+//===========================================================================================================================
+
+mDNSlocal mStatus DNS64GetIPv6Addrs(mDNS *m, mDNSu16 inResGroupID, struct in6_addr **outAddrs, uint32_t *outAddrCount);
+mDNSlocal mStatus DNS64GetPrefixes(mDNS *m, mDNSu16 inResGroupID, nw_nat64_prefix_t **outPrefixes, uint32_t *outPrefixCount);
+mDNSlocal mDNSBool DNS64GetReverseIPv6Addr(const domainname *inQName, struct in6_addr *outAddr);
+mDNSlocal mDNSu32 DNS64IPv4OnlyFQDNHash(void);
+mDNSlocal void DNS64RestartQuestion(mDNS *m, DNSQuestion *q, DNS64State newState);
+mDNSlocal mDNSBool DNS64TestIPv6Synthesis(mDNS *m, mDNSu16 inResGroupID, const mDNSv4Addr *inV4Addr);
+
+//===========================================================================================================================
+// DNS64StateMachine
+//===========================================================================================================================
+
+mDNSexport mDNSBool DNS64StateMachine(mDNS *m, DNSQuestion *inQ, const ResourceRecord *inRR, QC_result inResult)
+{
+ // If this is an mDNS question, then exit early. DNS64 is only for unicast DNS questions.
+
+ if (mDNSOpaque16IsZero(inQ->TargetQID)) return (mDNSfalse);
+
+ switch (inQ->dns64.state)
+ {
+ // If this question is going to be answered with a negative AAAA record and the question is not for "ipv4only.arpa." and
+ // the question's DNS server's interface supports NAT64, then restart the question as an "ipv4only.arpa." AAAA question.
+ // Otherwise, do nothing.
+
+ case kDNS64State_Initial:
+ if ((inRR->RecordType == kDNSRecordTypePacketNegative) && (inResult == QC_add))
+ {
+ if ((inQ->qtype == kDNSType_AAAA) &&
+ (inRR->rrtype == kDNSType_AAAA) &&
+ (inRR->rrclass == kDNSClass_IN) &&
+ ((inQ->qnamehash != DNS64IPv4OnlyFQDNHash()) || !SameDomainName(&inQ->qname, kDNS64IPv4OnlyFQDN)) &&
+ inQ->qDNSServer &&
+ nw_nat64_does_interface_index_support_nat64((uint32_t)(uintptr_t)inQ->qDNSServer->interface))
+ {
+ DNS64RestartQuestion(m, inQ, kDNS64State_PrefixDiscovery);
+ return (mDNStrue);
+ }
+ else if ((inQ->qtype == kDNSType_PTR) &&
+ (inRR->rrtype == kDNSType_PTR) &&
+ (inRR->rrclass == kDNSClass_IN) &&
+ inQ->qDNSServer &&
+ nw_nat64_does_interface_index_support_nat64((uint32_t)(uintptr_t)inQ->qDNSServer->interface) &&
+ DNS64GetReverseIPv6Addr(&inQ->qname, NULL))
+ {
+ DNS64RestartQuestion(m, inQ, kDNS64State_PrefixDiscoveryPTR);
+ return (mDNStrue);
+ }
+ }
+ break;
+
+ // If the "ipv4only.arpa." question is going to be answered with a positive AAAA record, then restart it as a question
+ // for an A record with the original AAAA qname.
+ // Otherwise, restart the question for the original AAAA record.
+
+ case kDNS64State_PrefixDiscovery:
+ if ((inRR->RecordType != kDNSRecordTypePacketNegative) &&
+ (inResult == QC_add) &&
+ (inRR->rrtype == kDNSType_AAAA) &&
+ (inRR->rrclass == kDNSClass_IN))
+ {
+ DNS64RestartQuestion(m, inQ, kDNS64State_QueryA);
+ return (mDNStrue);
+ }
+ else
+ {
+ DNS64RestartQuestion(m, inQ, kDNS64State_QueryAAAA);
+ return (mDNStrue);
+ }
+ break;
+
+ // The "ipv4only.arpa." question is going to be answered. Restart the question now. DNS64HandleNewQuestion() will decide
+ // whether or not to change it to a reverse IPv4 question.
+
+ case kDNS64State_PrefixDiscoveryPTR:
+ DNS64RestartQuestion(m, inQ, kDNS64State_QueryPTR);
+ return (mDNStrue);
+ break;
+
+ // If this question is going to be answered with a CNAME, then do nothing.
+ // If this question is going to be answered with a positive A record that's synthesizable, then set the state to
+ // QueryARecord2.
+ // Otherwise, restart the question for the original AAAA record.
+
+ case kDNS64State_QueryA:
+ if (inRR->rrtype != kDNSType_CNAME)
+ {
+ if ((inRR->RecordType != kDNSRecordTypePacketNegative) &&
+ (inResult == QC_add) &&
+ (inRR->rrtype == kDNSType_A) &&
+ (inRR->rrclass == kDNSClass_IN) &&
+ inQ->qDNSServer &&
+ DNS64TestIPv6Synthesis(m, inQ->qDNSServer->resGroupID, &inRR->rdata->u.ipv4))
+ {
+ inQ->dns64.state = kDNS64State_QueryA2;
+ }
+ else
+ {
+ DNS64RestartQuestion(m, inQ, kDNS64State_QueryAAAA);
+ return (mDNStrue);
+ }
+ }
+ break;
+
+ // For all other states, do nothing.
+
+ case kDNS64State_QueryA2:
+ case kDNS64State_QueryAAAA:
+ case kDNS64State_QueryPTR:
+ case kDNS64State_ReverseIPv4:
+ case kDNS64State_ReverseIPv6:
+ break;
+
+ default:
+ LogMsg("DNS64StateMachine: unrecognized DNS64 state %d", inQ->dns64.state);
+ break;
+ }
+
+ return (mDNSfalse);
+}
+
+//===========================================================================================================================
+// DNS64AnswerQuestion
+//===========================================================================================================================
+
+mDNSexport mStatus DNS64AnswerQuestion(mDNS *m, DNSQuestion *inQ, const ResourceRecord *inRR, QC_result inResult)
+{
+ mStatus err;
+ ResourceRecord newRR;
+ RData rdata;
+ nw_nat64_prefix_t * prefixes = NULL;
+ uint32_t prefixCount;
+ uint32_t i;
+ struct in_addr v4Addr;
+ struct in6_addr synthV6;
+
+ require_action_quiet(inQ->qDNSServer, exit, err = mStatus_BadParamErr);
+
+ err = DNS64GetPrefixes(m, inQ->qDNSServer->resGroupID, &prefixes, &prefixCount);
+ require_noerr_quiet(err, exit);
+
+ newRR = *inRR;
+ newRR.rrtype = kDNSType_AAAA;
+ newRR.rdlength = 16;
+ rdata.MaxRDLength = newRR.rdlength;
+ newRR.rdata = &rdata;
+
+ memcpy(&v4Addr.s_addr, inRR->rdata->u.ipv4.b, 4);
+ for (i = 0; i < prefixCount; i++)
+ {
+ if (nw_nat64_synthesize_v6(&prefixes[i], &v4Addr, &synthV6))
+ {
+ memcpy(rdata.u.ipv6.b, synthV6.s6_addr, 16);
+ inQ->QuestionCallback(m, inQ, &newRR, inResult);
+ }
+ }
+ err = mStatus_NoError;
+
+exit:
+ if (prefixes) free(prefixes);
+ return (err);
+}
+
+//===========================================================================================================================
+// DNS64HandleNewQuestion
+//===========================================================================================================================
+
+mDNSexport void DNS64HandleNewQuestion(mDNS *m, DNSQuestion *inQ)
+{
+ if (inQ->dns64.state == kDNS64State_QueryPTR)
+ {
+ struct in6_addr v6Addr;
+
+ inQ->dns64.state = kDNS64State_ReverseIPv6;
+ if (inQ->qDNSServer && DNS64GetReverseIPv6Addr(&inQ->qname, &v6Addr))
+ {
+ mStatus err;
+ nw_nat64_prefix_t * prefixes;
+ uint32_t prefixCount;
+ uint32_t i;
+ struct in_addr v4Addr;
+ char qnameStr[MAX_REVERSE_MAPPING_NAME_V4];
+
+ err = DNS64GetPrefixes(m, inQ->qDNSServer->resGroupID, &prefixes, &prefixCount);
+ require_noerr_quiet(err, exit);
+
+ for (i = 0; i < prefixCount; i++)
+ {
+ if (nw_nat64_extract_v4(&prefixes[i], &v6Addr, &v4Addr))
+ {
+ const mDNSu8 * const a = (const mDNSu8 *)&v4Addr.s_addr;
+
+ snprintf(qnameStr, sizeof(qnameStr), "%u.%u.%u.%u.in-addr.arpa.", a[3], a[2], a[1], a[0]);
+ MakeDomainNameFromDNSNameString(&inQ->qname, qnameStr);
+ inQ->qnamehash = DomainNameHashValue(&inQ->qname);
+ inQ->dns64.state = kDNS64State_ReverseIPv4;
+ break;
+ }
+ }
+ free(prefixes);
+ }
+ }
+
+exit:
+ return;
+}
+
+//===========================================================================================================================
+// DNS64ResetState
+//===========================================================================================================================
+
+// Called from mDNS_StopQuery_internal().
+
+mDNSexport void DNS64ResetState(DNSQuestion *inQ)
+{
+ switch (inQ->dns64.state)
+ {
+ case kDNS64State_PrefixDiscoveryPTR:
+ inQ->qtype = kDNSType_PTR; // Restore qtype to PTR and fall through.
+
+ case kDNS64State_PrefixDiscovery:
+ memcpy(&inQ->qname, inQ->dns64.qnameStash, sizeof(inQ->dns64.qnameStash)); // Restore the previous qname.
+ inQ->qnamehash = DomainNameHashValue(&inQ->qname);
+ break;
+
+ case kDNS64State_QueryA:
+ case kDNS64State_QueryA2:
+ inQ->qtype = kDNSType_AAAA; // Restore qtype to AAAA.
+ break;
+
+ // Do nothing for the other states.
+
+ case kDNS64State_Initial:
+ case kDNS64State_QueryAAAA:
+ case kDNS64State_QueryPTR:
+ case kDNS64State_ReverseIPv4:
+ case kDNS64State_ReverseIPv6:
+ break;
+
+ default:
+ LogMsg("DNS64ResetState: unrecognized DNS64 state %d", inQ->dns64.state);
+ break;
+ }
+ inQ->dns64.state = kDNS64State_Initial;
+}
+
+//===========================================================================================================================
+// DNS64RestartQuestions
+//===========================================================================================================================
+
+mDNSexport void DNS64RestartQuestions(mDNS *m)
+{
+ DNSQuestion * q;
+ DNSQuestion * restartList = NULL;
+ DNSServer * newServer;
+
+ m->RestartQuestion = m->Questions;
+ while (m->RestartQuestion)
+ {
+ q = m->RestartQuestion;
+ m->RestartQuestion = q->next;
+ if (q->dns64.state != kDNS64State_Initial)
+ {
+ SetValidDNSServers(m, q);
+ q->triedAllServersOnce = 0;
+ newServer = GetServerForQuestion(m, q);
+ if (q->qDNSServer != newServer)
+ {
+ if (!CacheRecordRmvEventsForQuestion(m, q))
+ {
+ LogInfo("DNS64RestartQuestions: Question deleted while delivering RMV events from cache");
+ }
+ else
+ {
+ LogInfo("DNS64RestartQuestions: Stop question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+ mDNS_StopQuery_internal(m, q);
+ q->next = restartList;
+ restartList = q;
+ }
+ }
+ }
+ }
+ while ((q = restartList) != NULL)
+ {
+ restartList = restartList->next;
+ q->next = NULL;
+ LogInfo("DNS64RestartQuestions: Start question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+ mDNS_StartQuery_internal(m, q);
+ }
+}
+
+//===========================================================================================================================
+// DNS64GetIPv6Addrs
+//===========================================================================================================================
+
+#define IsPositiveAAAAFromResGroup(RR, RES_GROUP_ID) \
+ ((RR)->rDNSServer && \
+ ((RR)->rDNSServer->resGroupID == RES_GROUP_ID) && \
+ ((RR)->rrtype == kDNSType_AAAA) && \
+ ((RR)->RecordType != kDNSRecordTypePacketNegative) && \
+ !(RR)->InterfaceID)
+
+mDNSlocal mStatus DNS64GetIPv6Addrs(mDNS *m, const mDNSu16 inResGroupID, struct in6_addr **outAddrs, uint32_t *outAddrCount)
+{
+ mStatus err;
+ const CacheGroup * cg;
+ const CacheRecord * cr;
+ struct in6_addr * addrs = NULL;
+ uint32_t addrCount;
+ uint32_t recordCount;
+
+ cg = CacheGroupForName(m, DNS64IPv4OnlyFQDNHash(), kDNS64IPv4OnlyFQDN);
+ require_action_quiet(cg, exit, err = mStatus_NoSuchRecord);
+
+ recordCount = 0;
+ for (cr = cg->members; cr; cr = cr->next)
+ {
+ if (IsPositiveAAAAFromResGroup(&cr->resrec, inResGroupID))
+ {
+ recordCount++;
+ }
+ }
+ require_action_quiet(recordCount > 0, exit, err = mStatus_NoSuchRecord);
+
+ addrs = (struct in6_addr *)calloc(recordCount, sizeof(*addrs));
+ require_action_quiet(addrs, exit, err = mStatus_NoMemoryErr);
+
+ addrCount = 0;
+ for (cr = cg->members; cr && (addrCount < recordCount); cr = cr->next)
+ {
+ if (IsPositiveAAAAFromResGroup(&cr->resrec, inResGroupID))
+ {
+ memcpy(addrs[addrCount].s6_addr, cr->resrec.rdata->u.ipv6.b, 16);
+ addrCount++;
+ }
+ }
+
+ *outAddrs = addrs;
+ addrs = NULL;
+ *outAddrCount = addrCount;
+ err = mStatus_NoError;
+
+exit:
+ if (addrs) free(addrs);
+ return (err);
+}
+
+//===========================================================================================================================
+// DNS64GetPrefixes
+//===========================================================================================================================
+
+mDNSlocal mStatus DNS64GetPrefixes(mDNS *m, mDNSu16 inResGroupID, nw_nat64_prefix_t **outPrefixes, uint32_t *outPrefixCount)
+{
+ mStatus err;
+ struct in6_addr * v6Addrs;
+ uint32_t v6AddrCount;
+ nw_nat64_prefix_t * prefixes;
+ int32_t prefixCount;
+
+ err = DNS64GetIPv6Addrs(m, inResGroupID, &v6Addrs, &v6AddrCount);
+ require_noerr_quiet(err, exit);
+
+ prefixCount = nw_nat64_copy_prefixes_from_ipv4only_records(v6Addrs, v6AddrCount, &prefixes);
+ free(v6Addrs);
+ require_action_quiet(prefixCount > 0, exit, err = mStatus_UnknownErr);
+
+ *outPrefixes = prefixes;
+ *outPrefixCount = prefixCount;
+
+exit:
+ return (err);
+}
+
+//===========================================================================================================================
+// DNS64GetReverseIPv6Addr
+//===========================================================================================================================
+
+#define kReverseIPv6Domain ((const domainname *) "\x3" "ip6" "\x4" "arpa")
+
+mDNSlocal mDNSBool DNS64GetReverseIPv6Addr(const domainname *inQName, struct in6_addr *outAddr)
+{
+ const mDNSu8 * ptr;
+ int i;
+ unsigned int c;
+ unsigned int nl;
+ unsigned int nu;
+
+ // If the name is of the form "x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.ip6.arpa.", where each x
+ // is a hex digit, then the sequence of 32 hex digit labels represents the nibbles of an IPv6 address in reverse order.
+ // See <https://tools.ietf.org/html/rfc3596#section-2.5>.
+
+ ptr = (const mDNSu8 *)inQName;
+ for (i = 0; i < 16; i++)
+ {
+ if (*ptr++ != 1) return (mDNSfalse); // If this label's length is not 1, then fail.
+ c = *ptr++; // Get label byte.
+ if ( (c >= '0') && (c <= '9')) nl = c - '0'; // If it's a hex digit, get its numeric value.
+ else if ((c >= 'a') && (c <= 'f')) nl = (c - 'a') + 10;
+ else if ((c >= 'A') && (c <= 'F')) nl = (c - 'A') + 10;
+ else return (mDNSfalse); // Otherwise, fail.
+
+ if (*ptr++ != 1) return (mDNSfalse); // If this label's length is not 1, then fail.
+ c = *ptr++; // Get label byte.
+ if ( (c >= '0') && (c <= '9')) nu = c - '0'; // If it's a hex digit, get its numeric value.
+ else if ((c >= 'a') && (c <= 'f')) nu = (c - 'a') + 10;
+ else if ((c >= 'A') && (c <= 'F')) nu = (c - 'A') + 10;
+ else return (mDNSfalse); // Otherwise, fail.
+
+ if (outAddr) outAddr->s6_addr[15 - i] = (mDNSu8)((nu << 4) | nl);
+ }
+
+ // The rest of the name needs to be "ip6.arpa.". If it isn't, fail.
+
+ if (!SameDomainName((const domainname *)ptr, kReverseIPv6Domain)) return (mDNSfalse);
+
+ return (mDNStrue);
+}
+
+//===========================================================================================================================
+// DNS64IPv4OnlyFQDNHash
+//===========================================================================================================================
+
+mDNSlocal mDNSu32 DNS64IPv4OnlyFQDNHash(void)
+{
+ static dispatch_once_t sHashOnce;
+ static mDNSu32 sHash;
+
+ dispatch_once(&sHashOnce, ^{ sHash = DomainNameHashValue(kDNS64IPv4OnlyFQDN); });
+
+ return (sHash);
+}
+
+//===========================================================================================================================
+// DNS64RestartQuestion
+//===========================================================================================================================
+
+mDNSlocal void DNS64RestartQuestion(mDNS *const m, DNSQuestion *inQ, DNS64State inNewState)
+{
+ mDNS_StopQuery_internal(m, inQ);
+
+ inQ->dns64.state = inNewState;
+ switch (inQ->dns64.state)
+ {
+ case kDNS64State_Initial:
+ break;
+
+ case kDNS64State_PrefixDiscovery:
+ case kDNS64State_PrefixDiscoveryPTR:
+ // Save the first 15 bytes from the original qname that are displaced by setting qname to "ipv4only.arpa.".
+
+ memcpy(inQ->dns64.qnameStash, &inQ->qname, sizeof(inQ->dns64.qnameStash));
+ AssignDomainName(&inQ->qname, kDNS64IPv4OnlyFQDN);
+ inQ->qnamehash = DNS64IPv4OnlyFQDNHash();
+ inQ->qtype = kDNSType_AAAA;
+ break;
+
+ case kDNS64State_QueryA:
+ case kDNS64State_QueryA2:
+ inQ->qtype = kDNSType_A;
+ break;
+
+ case kDNS64State_QueryPTR:
+ case kDNS64State_ReverseIPv4:
+ case kDNS64State_ReverseIPv6:
+ inQ->qtype = kDNSType_PTR;
+ break;
+
+ case kDNS64State_QueryAAAA:
+ inQ->qtype = kDNSType_AAAA;
+ break;
+
+ default:
+ LogMsg("DNS64RestartQuestion: unrecognized DNS64 state %d", inQ->dns64.state);
+ break;
+ }
+
+ mDNS_StartQuery_internal(m, inQ);
+}
+
+//===========================================================================================================================
+// DNS64TestIPv6Synthesis
+//===========================================================================================================================
+
+mDNSlocal mDNSBool DNS64TestIPv6Synthesis(mDNS *m, mDNSu16 inResGroupID, const mDNSv4Addr *inV4Addr)
+{
+ mStatus err;
+ nw_nat64_prefix_t * prefixes = NULL;
+ uint32_t prefixCount;
+ uint32_t i;
+ struct in_addr v4Addr;
+ struct in6_addr synthV6;
+ mDNSBool result = mDNSfalse;
+
+ err = DNS64GetPrefixes(m, inResGroupID, &prefixes, &prefixCount);
+ require_noerr_quiet(err, exit);
+
+ memcpy(&v4Addr.s_addr, inV4Addr->b, 4);
+ for (i = 0; i < prefixCount; i++)
+ {
+ if (nw_nat64_synthesize_v6(&prefixes[i], &v4Addr, &synthV6))
+ {
+ result = mDNStrue;
+ break;
+ }
+ }
+
+exit:
+ if (prefixes) free(prefixes);
+ return (result);
+}
+#endif // TARGET_OS_IOS
diff --git a/mDNSResponder/mDNSMacOSX/DNS64.h b/mDNSResponder/mDNSMacOSX/DNS64.h
new file mode 100644
index 00000000..80eb7feb
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DNS64.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2017 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 __DNS64_h
+#define __DNS64_h
+
+#include "mDNSEmbeddedAPI.h"
+
+#define DNS64IsQueryingARecord(STATE) (((STATE) == kDNS64State_QueryA) || ((STATE) == kDNS64State_QueryA2))
+#define DNS64ShouldAnswerQuestion(Q, RR) (DNS64IsQueryingARecord((Q)->dns64.state) && ((RR)->rrtype == kDNSType_A))
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+mDNSexport mDNSBool DNS64StateMachine(mDNS *m, DNSQuestion *inQ, const ResourceRecord *inRR, QC_result inResult);
+mDNSexport mStatus DNS64AnswerQuestion(mDNS *m, DNSQuestion *inQ, const ResourceRecord *inRR, QC_result inResult);
+mDNSexport void DNS64HandleNewQuestion(mDNS *m, DNSQuestion *inQ);
+mDNSexport void DNS64ResetState(DNSQuestion *inQ);
+mDNSexport void DNS64RestartQuestions(mDNS *m);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __DNS64_h
diff --git a/mDNSResponder/mDNSMacOSX/DNS64State.h b/mDNSResponder/mDNSMacOSX/DNS64State.h
new file mode 100644
index 00000000..1a847900
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DNS64State.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2017 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 __DNS64State_h
+#define __DNS64State_h
+
+typedef enum
+{
+ kDNS64State_Initial = 0, // Initial state.
+ kDNS64State_PrefixDiscovery = 1, // Querying for "ipv4only.arpa." AAAA records to discover NAT64 IPv6 prefix(es).
+ kDNS64State_PrefixDiscoveryPTR = 2, // Same as PrefixDiscovery, but discoverying for "ip6.arpa." PTR record queries.
+ kDNS64State_QueryA = 3, // Querying for A record with same QNAME as AAAA record query.
+ kDNS64State_QueryA2 = 4, // Continuing A record query after being answered with a synthesizable A record.
+ kDNS64State_QueryAAAA = 5, // Querying for original AAAA record.
+ kDNS64State_QueryPTR = 6, // Determining whether to query for reverse IPV4 or reverse IPv6 PTR record.
+ kDNS64State_ReverseIPv4 = 7, // Querying for reverse IPV4 (in-addr.arpa.) PTR record.
+ kDNS64State_ReverseIPv6 = 8 // Querying for the original reverse IPv6 (ip6.arpa.) PTR record.
+
+} DNS64State;
+
+typedef struct
+{
+ DNS64State state; // Current state.
+ mDNSu8 qnameStash[15]; // Temporary space to hold the up to 15 bytes that are displaced in a DNSQuestion's qname
+ // when it's set to "ipv4only.arpa." during prefix discovery.
+} DNS64;
+
+#endif // __DNS64State_h
diff --git a/mDNSResponder/mDNSMacOSX/DNSProxySupport.c b/mDNSResponder/mDNSMacOSX/DNSProxySupport.c
index 7666cbc4..8a2e70b9 100644
--- a/mDNSResponder/mDNSMacOSX/DNSProxySupport.c
+++ b/mDNSResponder/mDNSMacOSX/DNSProxySupport.c
@@ -23,6 +23,8 @@
#include <sys/event.h>
#include <netinet/tcp.h>
+mDNSexport mDNS mDNSStorage;
+
#define ValidSocket(s) ((s) >= 0)
// Global to store the 4 DNS Proxy Listeners (UDPv4/6, TCPv4/6)
@@ -92,7 +94,7 @@ mDNSlocal int ProxyTCPRead(ProxyTCPInfo_t *tcpInfo)
return 1;
}
-mDNSlocal void ProxyTCPSocketCallBack(int s1, short filter, void *context)
+mDNSlocal void ProxyTCPSocketCallBack(int s1, short filter, void *context, __unused mDNSBool encounteredEOF)
{
int ret;
struct sockaddr_storage from;
@@ -185,11 +187,11 @@ mDNSlocal void ProxyTCPSocketCallBack(int s1, short filter, void *context)
// 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,
+ kq->m->p->TCPProxyCallback(sock, ti->reply, (mDNSu8 *)ti->reply + ti->replyLen, &senderAddr, senderPort, &destAddr,
UnicastDNSPort, (mDNSInterfaceID)(uintptr_t)intf_id, ti);
}
-mDNSlocal void ProxyTCPAccept(int s1, short filter, void *context)
+mDNSlocal void ProxyTCPAccept(int s1, short filter, void *context, __unused mDNSBool encounteredEOF)
{
int newfd;
struct sockaddr_storage ss;
@@ -271,14 +273,14 @@ mDNSlocal void ProxyTCPAccept(int s1, short filter, void *context)
}
}
-mDNSlocal mStatus SetupUDPProxySocket(mDNS *const m, int skt, KQSocketSet *cp, u_short sa_family, mDNSBool useBackgroundTrafficClass)
+mDNSlocal mStatus SetupUDPProxySocket(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;
mStatus err = mStatus_NoError;
- cp->m = m;
+ cp->m = &mDNSStorage;
cp->closeFlag = mDNSNULL;
// set default traffic class
@@ -348,13 +350,13 @@ mDNSlocal mStatus SetupUDPProxySocket(mDNS *const m, int skt, KQSocketSet *cp, u
return(err);
}
-mDNSlocal mStatus SetupTCPProxySocket(mDNS *const m, int skt, KQSocketSet *cp, u_short sa_family, mDNSBool useBackgroundTrafficClass)
+mDNSlocal mStatus SetupTCPProxySocket(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;
mStatus err;
- cp->m = m;
+ cp->m = &mDNSStorage;
// XXX may not be used by the TCP codepath
cp->closeFlag = mDNSNULL;
@@ -438,9 +440,10 @@ mDNSlocal void BindDPSocket(int fd, int sa_family)
}
// Setup DNS Proxy Skts in main kevent loop and set the skt options
-mDNSlocal void SetupDNSProxySkts(mDNS *const m, int fd[4])
+mDNSlocal void SetupDNSProxySkts(int fd[4])
{
- int i;
+ mDNS *const m = &mDNSStorage;
+ int i;
mStatus err;
KQSocketSet *udpSS;
KQSocketSet *tcpSS;
@@ -454,19 +457,19 @@ mDNSlocal void SetupDNSProxySkts(mDNS *const m, int fd[4])
// 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);
+ err = SetupUDPProxySocket(fd[0], udpSS, AF_INET, mDNSfalse);
if (err)
LogMsg("SetupDNSProxySkts: ERROR!! UDPv4 Socket");
- err = SetupUDPProxySocket(m, fd[1], udpSS, AF_INET6, mDNSfalse);
+ err = SetupUDPProxySocket(fd[1], udpSS, AF_INET6, mDNSfalse);
if (err)
LogMsg("SetupDNSProxySkts: ERROR!! UDPv6 Socket");
- err = SetupTCPProxySocket(m, fd[2], tcpSS, AF_INET, mDNSfalse);
+ err = SetupTCPProxySocket(fd[2], tcpSS, AF_INET, mDNSfalse);
if (err)
LogMsg("SetupDNSProxySkts: ERROR!! TCPv4 Socket");
- err = SetupTCPProxySocket(m, fd[3], tcpSS, AF_INET6, mDNSfalse);
+ err = SetupTCPProxySocket(fd[3], tcpSS, AF_INET6, mDNSfalse);
if (err)
LogMsg("SetupDNSProxySkts: ERROR!! TCPv6 Socket");
@@ -475,7 +478,7 @@ mDNSlocal void SetupDNSProxySkts(mDNS *const m, int fd[4])
}
// Create and bind the DNS Proxy Skts for use
-mDNSexport void mDNSPlatformInitDNSProxySkts(mDNS *const m, ProxyCallback UDPCallback, ProxyCallback TCPCallback)
+mDNSexport void mDNSPlatformInitDNSProxySkts(ProxyCallback UDPCallback, ProxyCallback TCPCallback)
{
int dpskt[4];
@@ -506,10 +509,10 @@ mDNSexport void mDNSPlatformInitDNSProxySkts(mDNS *const m, ProxyCallback UDPCal
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;
+ mDNSStorage.p->UDPProxyCallback = UDPCallback;
+ mDNSStorage.p->TCPProxyCallback = TCPCallback;
- SetupDNSProxySkts(m, dpskt);
+ SetupDNSProxySkts(dpskt);
}
mDNSexport void mDNSPlatformCloseDNSProxySkts(mDNS *const m)
diff --git a/mDNSResponder/mDNSMacOSX/DNSSECSupport.c b/mDNSResponder/mDNSMacOSX/DNSSECSupport.c
index b87f0d44..6db54b1c 100644
--- a/mDNSResponder/mDNSMacOSX/DNSSECSupport.c
+++ b/mDNSResponder/mDNSMacOSX/DNSSECSupport.c
@@ -561,7 +561,7 @@ mDNSexport void DNSSECProbe(mDNS *const m)
if (DNSSECProbeQuestion.ThisQInterval != -1)
return;
- rand = mDNSRandom(0x3FFFFFFF) % 100;
+ rand = mDNSRandom(FutureTime) % 100;
// Probe 1% of the time
if (rand >= DNSSECProbePercentage)
return;
diff --git a/mDNSResponder/mDNSMacOSX/DomainBrowser/Shared/CNDomainBrowserPathUtils.h b/mDNSResponder/mDNSMacOSX/DomainBrowser/Shared/CNDomainBrowserPathUtils.h
new file mode 100644
index 00000000..682b9721
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DomainBrowser/Shared/CNDomainBrowserPathUtils.h
@@ -0,0 +1,22 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+NSString * DomainPathToDNSDomain(NSArray * domainPath);
+NSArray * DNSDomainToDomainPath(NSString * domain);
+NSString * TrimCharactersFromDNSDomain(NSString * domain);
diff --git a/mDNSResponder/mDNSMacOSX/DomainBrowser/Shared/CNDomainBrowserPathUtils.m b/mDNSResponder/mDNSMacOSX/DomainBrowser/Shared/CNDomainBrowserPathUtils.m
new file mode 100644
index 00000000..baa7702e
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DomainBrowser/Shared/CNDomainBrowserPathUtils.m
@@ -0,0 +1,114 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import "CNDomainBrowserPathUtils.h"
+#import <CFNetwork/CFHostPriv.h>
+#include "../../../Clients/ClientCommon.h"
+
+static const char *EscapeLabel(const char *cstr, char label[64])
+{
+ // Based on code on clownfish from: DNSName::GetEscapedDNSName
+ char *ptr = label;
+ while (*cstr) // While we have characters in the label...
+ {
+ char c = *cstr++;
+ if (c == '\\' || c == '.') // escape '\' and '.'
+ {
+ if (ptr >= label+64-2) return(NULL);
+ *ptr++ = '\\';
+ *ptr++ = c;
+ }
+ else if (c <= ' ') // escape ' ' and lower
+ {
+ if (ptr >= label+64-4) return(NULL);
+ *ptr++ = '\\';
+ *ptr++ = '0' + (c / 100);
+ *ptr++ = '0' + ((c / 10) % 10);
+ *ptr++ = '0' + (c % 10);
+ }
+ else
+ {
+ if (ptr >= label+64-1) return(NULL);
+ *ptr++ = c;
+ }
+ }
+ *ptr = 0;
+ return(label);
+}
+
+NSString * DomainPathToDNSDomain(NSArray * domainPath)
+{
+ NSMutableString * dnsStr = [NSMutableString string];
+
+ char label[64];
+ for (NSString * next in domainPath)
+ {
+ NSString * nextLabel;
+ if (dnsStr.length) nextLabel = [NSString stringWithUTF8String: EscapeLabel([next UTF8String], label)];
+ else nextLabel = next;
+ [dnsStr insertString: [NSString stringWithFormat: @"%@.", nextLabel] atIndex: 0];
+ }
+
+ return(dnsStr);
+}
+
+NSArray * DNSDomainToDomainPath(NSString * domain)
+{
+ int labels = 0, depth = 0;
+ char text[64];
+ const char * domainStr = domain.UTF8String;
+ const char *label[128];
+ NSString * undottedStr;
+ NSMutableArray *a = [NSMutableArray array];
+
+ while (*domainStr)
+ {
+ label[labels] = domainStr;
+ domainStr = GetNextLabel(domainStr, text);
+
+ undottedStr = [[NSString stringWithUTF8String: label[labels]]
+ stringByTrimmingCharactersInSet: [NSCharacterSet punctuationCharacterSet]];
+ if (!*domainStr || _CFHostIsDomainTopLevel((__bridge CFStringRef)undottedStr))
+ {
+ if (labels)
+ {
+ labels--; // If not first level then back up one level
+ undottedStr = [[NSString stringWithUTF8String: label[labels]]
+ stringByTrimmingCharactersInSet: [NSCharacterSet punctuationCharacterSet]];
+ }
+ [a addObject: undottedStr];
+ break;
+ }
+ labels++;
+ }
+
+ // Process the remainder of the hierarchy
+ for (depth = 0 ; depth < labels ; depth++)
+ {
+ GetNextLabel(label[labels-1-depth], text);
+ [a addObject: [NSString stringWithUTF8String: text]];
+ }
+
+ return(a);
+}
+
+NSString * TrimCharactersFromDNSDomain(NSString * domain)
+{
+ NSMutableCharacterSet * trimSet = [NSMutableCharacterSet whitespaceCharacterSet];
+ [trimSet formUnionWithCharacterSet:[NSCharacterSet punctuationCharacterSet]];
+ return([domain stringByTrimmingCharactersInSet:trimSet]);
+}
diff --git a/mDNSResponder/mDNSMacOSX/DomainBrowser/Shared/_CNDomainBrowser.h b/mDNSResponder/mDNSMacOSX/DomainBrowser/Shared/_CNDomainBrowser.h
new file mode 100644
index 00000000..b80c2bf2
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DomainBrowser/Shared/_CNDomainBrowser.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import <Foundation/Foundation.h>
+#import <dispatch/queue.h>
+
+extern const NSString * _CNSubDomainKey_defaultFlag;
+extern const NSString * _CNSubDomainKey_subPath;
+
+@protocol _CNDomainBrowserDelegate;
+
+@interface _CNDomainBrowser : NSObject
+
+@property (nonatomic) BOOL browseRegistration;
+@property (nonatomic) BOOL ignoreLocal;
+@property (nonatomic) BOOL ignoreBTMM;
+@property (strong) dispatch_queue_t callbackQueue;
+@property (readonly) BOOL isBrowsing;
+
+- (instancetype)initWithDelegate:(id<_CNDomainBrowserDelegate>)delegate;
+- (void)startBrowser;
+- (void)stopBrowser;
+
+@property (readonly) NSArray * defaultDomainPath;
+@property (readonly) NSArray * flattenedDNSDomains;
+
+- (NSArray *)subDomainsAtDomainPath:(NSArray *)domainPath;
+
+@end
+
+@protocol _CNDomainBrowserDelegate <NSObject>
+
+- (void)bonjourBrowserDomainUpdate:(NSArray *)defaultDomainPath;
+
+@end
diff --git a/mDNSResponder/mDNSMacOSX/DomainBrowser/Shared/_CNDomainBrowser.m b/mDNSResponder/mDNSMacOSX/DomainBrowser/Shared/_CNDomainBrowser.m
new file mode 100644
index 00000000..37983772
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DomainBrowser/Shared/_CNDomainBrowser.m
@@ -0,0 +1,190 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import "_CNDomainBrowser.h"
+#import "CNDomainBrowserPathUtils.h"
+#include <dns_sd.h>
+
+const NSString * _CNSubDomainKey_defaultFlag = @"defaultFlag";
+const NSString * _CNSubDomainKey_subPath = @"subPath";
+const NSString * _CNSubDomainKey_reverseDomainPath = @"reverseDomainPath";
+
+@interface _CNDomainBrowser ()
+
+@property (assign) DNSServiceRef browseDomainR;
+@property (strong) NSMutableDictionary * browseDomainD;
+
+@property (weak) id<_CNDomainBrowserDelegate> delegate;
+
+@end
+
+@implementation _CNDomainBrowser
+
+void enumReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *replyDomain, void *context);
+
+- (instancetype)initWithDelegate:(id<_CNDomainBrowserDelegate>)delegate
+{
+ if (self = [super init])
+ {
+ _delegate = delegate;
+ [self _commonInit];
+ }
+ return(self);
+}
+
+- (void)_commonInit
+{
+ self.browseDomainD = [NSMutableDictionary dictionary];
+ self.callbackQueue = dispatch_get_main_queue();
+}
+
+- (void)dealloc
+{
+ [self stopBrowser];
+}
+
+- (void)startBrowser
+{
+ if (!_browseDomainR)
+ {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ dispatch_queue_t queue = dispatch_queue_create("DNSServiceEnumerateDomains", DISPATCH_QUEUE_PRIORITY_DEFAULT);
+ dispatch_set_context(queue, (void *)CFBridgingRetain(self));
+ dispatch_set_finalizer_f(queue, finalizer);
+
+ DNSServiceRef ref;
+ if (DNSServiceEnumerateDomains(&ref, _browseRegistration ? kDNSServiceFlagsRegistrationDomains : kDNSServiceFlagsBrowseDomains, 0, enumReply, (__bridge void *)self))
+ NSLog(@"DNSServiceEnumerateDomains failed");
+ else
+ {
+ _browseDomainR = ref;
+ (void)DNSServiceSetDispatchQueue(_browseDomainR, queue);
+ }
+ });
+ }
+}
+
+- (void)stopBrowser
+{
+ if (_browseDomainR)
+ {
+ DNSServiceRefDeallocate(_browseDomainR);
+ _browseDomainR = nil;
+ }
+}
+
+- (NSArray *)defaultDomainPath
+{
+ NSArray * revDomainArray = nil;
+
+ NSArray *defaults = [[self.browseDomainD allValues] filteredArrayUsingPredicate: [NSPredicate predicateWithFormat: @"(%K == %@)", _CNSubDomainKey_defaultFlag, @YES]];
+ if (defaults.count) revDomainArray = defaults[0][_CNSubDomainKey_reverseDomainPath];
+ if (!revDomainArray) revDomainArray = [NSArray arrayWithObject: @"local"]; // If no defaults found
+
+ return(revDomainArray);
+}
+
+- (NSArray *)flattenedDNSDomains
+{
+ return([self.browseDomainD allKeys]);
+}
+
+- (NSArray *)subDomainsAtDomainPath:(NSArray *)domainPath
+{
+ NSMutableDictionary * subs = [NSMutableDictionary dictionary];
+ for (NSDictionary * next in [self.browseDomainD allValues])
+ {
+ NSArray * bdomain = next[_CNSubDomainKey_reverseDomainPath];
+ if (bdomain.count > domainPath.count)
+ {
+ BOOL match = YES;
+ for (NSUInteger i = 0 ; i < domainPath.count ; i++)
+ {
+ if (![bdomain[i] isEqualToString: domainPath[i]]) { match = NO; break; }
+ }
+ if (match)
+ {
+ NSString * key = bdomain[domainPath.count];
+ [subs setObject: @{ _CNSubDomainKey_subPath: key, _CNSubDomainKey_defaultFlag: next[_CNSubDomainKey_defaultFlag] } forKey: key];
+ }
+ }
+ }
+ return([subs allValues]);
+}
+
+- (void) reloadBrowser
+{
+ if ([_delegate respondsToSelector: @selector(bonjourBrowserDomainUpdate:)])
+ {
+ dispatch_async(self.callbackQueue, ^{
+ [_delegate bonjourBrowserDomainUpdate: [self defaultDomainPath]];
+ });
+ }
+}
+
+- (BOOL)isBrowsing
+{
+ return(_browseDomainR != nil);
+}
+
+#pragma mark - Dispatch
+
+static void finalizer(void * context)
+{
+ _CNDomainBrowser *self = (__bridge _CNDomainBrowser *)context;
+ NSLog(@"finalizer: %@", self);
+ (void)CFBridgingRelease((__bridge void *)self);
+}
+
+#pragma mark - Commands
+
+#pragma mark - Static Callbacks
+
+void enumReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
+ const char *replyDomain, void *context)
+{
+ (void)sdRef;
+ (void)interfaceIndex;
+ (void)errorCode;
+
+ if (!*replyDomain) return;
+
+ _CNDomainBrowser *self = (__bridge _CNDomainBrowser *)context;
+ NSString *key = [NSString stringWithUTF8String: replyDomain];
+
+ if (self.ignoreLocal && [key isEqualToString: @"local."]) return;
+ if (self.ignoreBTMM && [key hasSuffix: @".members.btmm.icloud.com."]) return;
+
+ if (!(flags & kDNSServiceFlagsAdd))
+ {
+ [self.browseDomainD removeObjectForKey:key];
+ }
+ else
+ {
+ NSArray * pathArray = DNSDomainToDomainPath(key);
+ [self.browseDomainD setObject: @{ _CNSubDomainKey_reverseDomainPath: pathArray,
+ _CNSubDomainKey_defaultFlag: (flags & kDNSServiceFlagsDefault) ? @YES : @NO }
+ forKey: key];
+ }
+
+ if (!(flags & kDNSServiceFlagsMoreComing))
+ {
+ [self reloadBrowser];
+ }
+}
+
+@end
diff --git a/mDNSResponder/mDNSMacOSX/DomainBrowser/iOS/CNDomainBrowserViewController.h b/mDNSResponder/mDNSMacOSX/DomainBrowser/iOS/CNDomainBrowserViewController.h
new file mode 100644
index 00000000..bf70f88c
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DomainBrowser/iOS/CNDomainBrowserViewController.h
@@ -0,0 +1,51 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import <UIKit/UIKit.h>
+
+IB_DESIGNABLE
+
+@protocol CNDomainBrowserViewControllerDelegate;
+
+@interface CNTableViewController : UITableViewController
+@end
+
+@interface CNDomainBrowserViewController : CNTableViewController
+
+@property (nonatomic) IBInspectable BOOL browseRegistration;
+@property (nonatomic) IBInspectable BOOL ignoreLocal;
+@property (weak) IBOutlet id<CNDomainBrowserViewControllerDelegate> delegate;
+
+@property (readonly) NSString * selectedDNSDomain;
+@property (readonly) NSString * defaultDNSDomain;
+@property (readonly) NSArray * flattenedDNSDomains;
+
+@property (readonly) BOOL isBrowsing;
+
+- (void)startBrowse;
+- (void)stopBrowse;
+
+@end
+
+@protocol CNDomainBrowserViewControllerDelegate <NSObject>
+
+@optional
+
+- (void)domainBrowserDomainSelected:(NSString *)domain;
+- (void)bonjourBrowserDomainUpdate:(NSString *)defaultDomain;
+
+@end
diff --git a/mDNSResponder/mDNSMacOSX/DomainBrowser/iOS/CNDomainBrowserViewController.m b/mDNSResponder/mDNSMacOSX/DomainBrowser/iOS/CNDomainBrowserViewController.m
new file mode 100644
index 00000000..b8c9e65c
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DomainBrowser/iOS/CNDomainBrowserViewController.m
@@ -0,0 +1,350 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import "CNDomainBrowserViewController.h"
+#import "_CNDomainBrowser.h"
+#import "CNDomainBrowserPathUtils.h"
+#import <AssertMacros.h>
+
+#define LocalizedStringFromTableInMyBundle(key, table, comment) \
+ NSLocalizedStringFromTableInBundle(key, table, [NSBundle bundleForClass: [self class]], comment)
+
+
+@interface CNTableViewController()
+@property (copy) NSArray * pathArray;
+@property (assign) NSInteger selectionIndex;
+@end
+
+@implementation CNTableViewController
+
+- (instancetype)initWithStyle:(UITableViewStyle)style
+{
+ if (self = [super initWithStyle: style])
+ {
+ _selectionIndex = NSNotFound;
+ _pathArray = [NSArray array];
+ }
+ return self;
+}
+
+@end
+
+@interface CNDomainBrowserViewController ()
+
+@property _CNDomainBrowser * bonjour;
+
+@property (strong) NSMutableDictionary * instanceInfoStrings;
+@property (strong) NSMutableDictionary * instanceStatusViews;
+
+@end
+
+@implementation CNDomainBrowserViewController
+
+- (instancetype)initWithStyle:(UITableViewStyle)style
+{
+ if (self = [super initWithStyle: style])
+ {
+ [self commonInit];
+ }
+ return(self);
+}
+
+- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
+{
+ if (self = [super initWithNibName: nibNameOrNil bundle: nibBundleOrNil])
+ {
+ [self commonInit];
+ }
+ return(self);
+}
+
+- (nullable instancetype)initWithCoder:(NSCoder *)coder
+{
+ if (self = [super initWithCoder: coder])
+ {
+ [self commonInit];
+ }
+ return(self);
+}
+
+- (void)commonInit
+{
+ self.bonjour = [[_CNDomainBrowser alloc] initWithDelegate: (id<_CNDomainBrowserDelegate>)self];
+ self.bonjour.browseRegistration = _browseRegistration;
+ self.bonjour.ignoreLocal = _ignoreLocal;
+ self.instanceInfoStrings = [NSMutableDictionary dictionary];
+ self.instanceStatusViews = [NSMutableDictionary dictionary];
+}
+
+- (void)viewWillAppear:(BOOL)animated
+{
+ [super viewWillAppear: animated];
+ NSArray * pathArray = DNSDomainToDomainPath(_selectedDNSDomain);
+ if ((self.isMovingToParentViewController || self.isBeingPresented) && (pathArray.count > 1))
+ {
+ [self updateUIToDomainPathArray: pathArray];
+ }
+}
+
+- (void)viewDidLoad
+{
+ [super viewDidLoad];
+
+ self.tableView.allowsMultipleSelectionDuringEditing = NO;
+ self.tableView.dataSource = (id<UITableViewDataSource>)self;
+ self.tableView.delegate = (id<UITableViewDelegate>)self;
+
+ self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle: LocalizedStringFromTableInMyBundle(@"_dnsBrowser.browsedomains.cancel", @"DomainBrowser", nil)
+ style: UIBarButtonItemStylePlain
+ target: self
+ action: @selector(cancelAction:)];
+
+}
+
+- (void)updateUIToDomainPathArray:(NSArray *)newPathArray
+{
+ if (newPathArray.count > 1)
+ {
+ CNTableViewController * controller = nil;
+ NSMutableArray * newSubPathArray = [NSMutableArray array];
+ for (NSString * nextPathComponent in newPathArray)
+ {
+ BOOL animate = NO;//(newPathArray.count == ++count);
+ controller = [self pushNewBrowseController: newSubPathArray.lastObject animated: animate];
+ controller.pathArray = newSubPathArray;
+ [newSubPathArray addObject: nextPathComponent];
+ }
+ }
+}
+
+- (IBAction)cancelAction:(id)sender
+{
+ (void)sender; // Unused
+ [self.navigationController dismissViewControllerAnimated: YES completion: nil];
+}
+
+- (CNTableViewController *)pushNewBrowseController:(NSString *)title animated:(BOOL)animated
+{
+ CNTableViewController *tvc = [[CNTableViewController alloc] initWithStyle: self.tableView.style];
+ tvc.title = title;
+ tvc.clearsSelectionOnViewWillAppear = NO;
+ tvc.tableView.dataSource = (id<UITableViewDataSource>)self;
+ tvc.tableView.delegate = (id<UITableViewDelegate>)self;
+ [self.navigationController pushViewController: tvc animated: animated];
+ return(tvc);
+}
+
+- (CNTableViewController *)controllerForTableView:(UITableView *)tableView
+{
+ CNTableViewController * result = nil;
+
+ for (CNTableViewController * next in self.navigationController.viewControllers)
+ {
+ if ([next isKindOfClass: [CNTableViewController class]] && next.tableView == tableView)
+ {
+ result = next;
+ break;
+ }
+ }
+
+ return(result);
+}
+
+- (NSArray *)selectedPathArrayForTableView:(UITableView *)tableView includeSelectedRow:(BOOL)includeSelection
+{
+ NSMutableArray * pathArray = [NSMutableArray array];
+ CNTableViewController * controller = [self controllerForTableView: tableView];
+
+ [pathArray addObjectsFromArray: controller.pathArray];
+
+ if (includeSelection && controller.selectionIndex != NSNotFound)
+ {
+ NSArray * rowArray = [[self.bonjour subDomainsAtDomainPath: pathArray] sortedArrayUsingComparator: ^(id obj1, id obj2) {
+ return (NSComparisonResult)[ obj1[_CNSubDomainKey_subPath] compare: obj2[_CNSubDomainKey_subPath]];
+ }];
+ if (controller.selectionIndex < (NSInteger)rowArray.count)
+ {
+ [pathArray addObject: rowArray[controller.selectionIndex][_CNSubDomainKey_subPath]];
+ }
+ }
+
+ return(pathArray);
+}
+
+- (void)plusButtonPressed:(UIControl *)button withEvent:(UIEvent *)event
+{
+ UITableView * tableView = ((UITableViewController *)self.navigationController.topViewController).tableView;
+ NSIndexPath * indexPath = [tableView indexPathForRowAtPoint: [[[event touchesForView: button] anyObject] locationInView: tableView]];
+ if (indexPath != nil && self.delegate)
+ {
+ [self controllerForTableView: tableView].selectionIndex = indexPath.row;
+ NSArray * pathArray = [self selectedPathArrayForTableView: ((CNTableViewController *)self.navigationController.topViewController).tableView includeSelectedRow: YES];
+ _selectedDNSDomain = DomainPathToDNSDomain(pathArray);
+ [self.navigationController dismissViewControllerAnimated: YES completion: ^{
+ if ([self.delegate respondsToSelector: @selector(domainBrowserDomainSelected:)])
+ {
+ [self.delegate domainBrowserDomainSelected: _selectedDNSDomain];
+ }
+ }];
+ }
+}
+
+#pragma mark - Public Methods
+
+- (void)setIgnoreLocal:(BOOL)ignoreLocal
+{
+ _ignoreLocal = ignoreLocal;
+ self.bonjour.ignoreLocal = _ignoreLocal;
+}
+
+- (void)setBrowseRegistration:(BOOL)browseRegistration
+{
+ _browseRegistration = browseRegistration;
+ self.bonjour.browseRegistration = _browseRegistration;
+}
+
+- (NSString *)defaultDNSDomain
+{
+ return(DomainPathToDNSDomain(self.bonjour.defaultDomainPath));
+}
+
+- (NSArray *)flattenedDNSDomains
+{
+ return(self.bonjour.flattenedDNSDomains);
+}
+
+- (void)startBrowse
+{
+ [self.bonjour startBrowser];
+}
+
+- (void)stopBrowse
+{
+ [self.bonjour stopBrowser];
+}
+
+- (BOOL)isBrowsing
+{
+ return(self.bonjour.isBrowsing);
+}
+
+#pragma mark - TableView Delegates
+
+- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
+{
+ (void)tableView; // Unused
+ (void)indexPath; // Unused
+ return UITableViewAutomaticDimension;
+}
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
+{
+ (void)tableView; // Unused
+ return(1);
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
+{
+ (void)section; // Unused
+ return([self.bonjour subDomainsAtDomainPath: [self selectedPathArrayForTableView: tableView includeSelectedRow: NO]].count);
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
+{
+ UITableViewCell *cell = nil;
+
+ static NSString *MyIdentifier = @"browse_cell_id";
+ cell = [tableView dequeueReusableCellWithIdentifier: MyIdentifier];
+ if (!cell)
+ {
+ cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: MyIdentifier];
+ }
+
+ // Get the name
+ NSMutableArray * pathArray = [NSMutableArray arrayWithArray: [self selectedPathArrayForTableView: tableView includeSelectedRow: NO]];
+ NSArray * rowArray = [[self.bonjour subDomainsAtDomainPath: pathArray] sortedArrayUsingComparator: ^(id obj1, id obj2) {
+ return (NSComparisonResult)[ obj1[_CNSubDomainKey_subPath] compare: obj2[_CNSubDomainKey_subPath]];
+ }];
+ if (indexPath.row < (NSInteger)rowArray.count)
+ {
+ NSDictionary * item = [rowArray objectAtIndex: indexPath.row];
+ NSString *val = item[_CNSubDomainKey_subPath];
+ cell.textLabel.text = val;
+
+ // Set selection
+ BOOL selected = ([self controllerForTableView: tableView].selectionIndex == indexPath.row);
+ if (selected) [tableView selectRowAtIndexPath: indexPath animated: NO scrollPosition: UITableViewScrollPositionNone];
+
+ // Make Default domain bold
+ if ([item[_CNSubDomainKey_defaultFlag] boolValue]) cell.textLabel.font = [UIFont boldSystemFontOfSize: [UIFont labelFontSize]];
+ else cell.textLabel.font = nil;
+
+ // See if it's a leaf
+ [pathArray addObject: val];
+ cell.accessoryType = [self.bonjour subDomainsAtDomainPath: pathArray].count ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone;
+
+ // Add the "+" button
+ UIButton * plus = [UIButton buttonWithType: UIButtonTypeContactAdd];
+ [plus addTarget: self action: @selector(plusButtonPressed:withEvent:) forControlEvents: UIControlEventTouchUpInside];
+ plus.userInteractionEnabled = YES;
+ [cell.contentView addSubview: plus];
+
+ plus.translatesAutoresizingMaskIntoConstraints = NO;
+ [plus.widthAnchor constraintEqualToConstant: plus.frame.size.width].active = YES;
+ [plus.heightAnchor constraintEqualToConstant: plus.frame.size.height].active = YES;
+ [plus.centerYAnchor constraintEqualToAnchor: cell.layoutMarginsGuide.centerYAnchor].active = YES;
+ [plus.trailingAnchor constraintEqualToAnchor: cell.layoutMarginsGuide.trailingAnchor constant: -20].active = YES;
+ }
+
+ return(cell);
+}
+
+- (nullable NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
+{
+ UITableViewCell * cell = [tableView cellForRowAtIndexPath: indexPath];
+ return((cell.accessoryType == UITableViewCellAccessoryNone) ? nil : indexPath);
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
+{
+ UITableViewCell * cell = [tableView cellForRowAtIndexPath: indexPath];
+ if (cell.accessoryType != UITableViewCellAccessoryNone)
+ {
+ // Push next
+ CNTableViewController * controller = [self controllerForTableView: tableView];
+ NSArray * lastpathArray = controller.pathArray;
+ controller.selectionIndex = indexPath.row;
+ NSString * title = cell.textLabel.text;
+ controller = [self pushNewBrowseController: title animated: YES];
+ controller.pathArray = [lastpathArray arrayByAddingObject: title];
+ }
+ [tableView deselectRowAtIndexPath: indexPath animated: YES];
+}
+
+#pragma mark - _CNDomainBrowser Delegates
+
+- (void)bonjourBrowserDomainUpdate:(NSArray *)defaultDomainPath
+{
+ _selectedDNSDomain = DomainPathToDNSDomain(defaultDomainPath);
+ [((UITableViewController *)self.navigationController.topViewController).tableView reloadData];
+ if ([self.delegate respondsToSelector: @selector(bonjourBrowserDomainUpdate:)])
+ {
+ [self.delegate bonjourBrowserDomainUpdate: _selectedDNSDomain];
+ }
+}
+
+@end
diff --git a/mDNSResponder/mDNSMacOSX/DomainBrowser/iOS/DomainBrowser.h b/mDNSResponder/mDNSMacOSX/DomainBrowser/iOS/DomainBrowser.h
new file mode 100644
index 00000000..4a740bfe
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DomainBrowser/iOS/DomainBrowser.h
@@ -0,0 +1,30 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import <UIKit/UIKit.h>
+
+//! Project version number for DomainBrowser.
+FOUNDATION_EXPORT double DomainBrowserVersionNumber;
+
+//! Project version string for DomainBrowser.
+FOUNDATION_EXPORT const unsigned char DomainBrowserVersionString[];
+
+// In this header, you should import all the public headers of your framework using statements like #import <DomainBrowser/PublicHeader.h>
+
+
+#import <DomainBrowser/CNDomainBrowserViewController.h>
+#import <DomainBrowser/CNDomainBrowserPathUtils.h>
diff --git a/mDNSResponder/mDNSMacOSX/DomainBrowser/iOS/DomainBrowser.strings b/mDNSResponder/mDNSMacOSX/DomainBrowser/iOS/DomainBrowser.strings
new file mode 100644
index 00000000..27956d73
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DomainBrowser/iOS/DomainBrowser.strings
@@ -0,0 +1,18 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+"_dnsBrowser.browsedomains.cancel" = "Cancel";
diff --git a/mDNSResponder/mDNSMacOSX/DomainBrowser/iOS/Info.plist b/mDNSResponder/mDNSMacOSX/DomainBrowser/iOS/Info.plist
new file mode 100644
index 00000000..d3de8eef
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DomainBrowser/iOS/Info.plist
@@ -0,0 +1,26 @@
+<?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>en</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>$(CURRENT_PROJECT_VERSION)</string>
+ <key>NSPrincipalClass</key>
+ <string></string>
+</dict>
+</plist>
diff --git a/mDNSResponder/mDNSMacOSX/DomainBrowser/macOS/CNDomainBrowserView.h b/mDNSResponder/mDNSMacOSX/DomainBrowser/macOS/CNDomainBrowserView.h
new file mode 100644
index 00000000..ccc381b3
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DomainBrowser/macOS/CNDomainBrowserView.h
@@ -0,0 +1,58 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@protocol CNDomainBrowserViewDelegate;
+
+IB_DESIGNABLE
+
+@interface CNDomainBrowserView : NSView
+
+@property (nonatomic) IBInspectable BOOL browseRegistration;
+@property (nonatomic) IBInspectable BOOL ignoreLocal;
+@property (nonatomic) IBInspectable BOOL ignoreBTMM;
+@property (weak) IBOutlet id<CNDomainBrowserViewDelegate> delegate;
+
+@property (readonly) NSString * selectedDNSDomain;
+@property (readonly) NSString * defaultDNSDomain;
+@property (readonly) NSArray * flattenedDNSDomains;
+
+@property (readonly) BOOL isBrowsing;
+
+- (void)startBrowse;
+- (void)stopBrowse;
+
+@end
+
+@protocol CNDomainBrowserViewDelegate <NSObject>
+
+@optional
+
+- (void)bonjourBrowserDomainSelected:(NSString *)domain;
+- (void)bonjourBrowserDomainUpdate:(NSString *)defaultDomain;
+
+@end
+
+@interface CNBonjourDomainCell : NSCell
+@end
+
+@interface CNBonjourDomainView : NSView
+
+@property(strong, nonatomic) NSString * domain;
+
+@end
diff --git a/mDNSResponder/mDNSMacOSX/DomainBrowser/macOS/CNDomainBrowserView.m b/mDNSResponder/mDNSMacOSX/DomainBrowser/macOS/CNDomainBrowserView.m
new file mode 100644
index 00000000..1bb52602
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DomainBrowser/macOS/CNDomainBrowserView.m
@@ -0,0 +1,474 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import "CNDomainBrowserView.h"
+#import "_CNDomainBrowser.h"
+#import "CNDomainBrowserPathUtils.h"
+
+#define DEBUG_POPUP_CELLS 0
+#define SHOW_SERVICETYPE_IF_SEARCH_COUNT 0
+#define TEST_LEGACYBROWSE 0
+
+#define BROWSER_CELL_SPACING 4
+
+@protocol CNServiceTypeLocalizerDelegate <NSObject>
+@property (strong) NSDictionary * localizedServiceTypesDictionary;
+@end
+
+@interface CNServiceTypeLocalizer : NSValueTransformer
+{
+ id<CNServiceTypeLocalizerDelegate> _delegate;
+}
+- (instancetype)initWithDelegate:(id<CNServiceTypeLocalizerDelegate>)delegate;
+
+@end
+
+@implementation CNServiceTypeLocalizer
+
+- (instancetype)initWithDelegate:(id<CNServiceTypeLocalizerDelegate>)delegate
+{
+ if (self = [super init])
+ {
+ _delegate = delegate;
+ }
+ return(self);
+}
+
++ (Class)transformedValueClass
+{
+ return [NSString class];
+}
+
++ (BOOL)allowsReverseTransformation
+{
+ return NO;
+}
+
+- (nullable id)transformedValue:(nullable id)value
+{
+ id result = value;
+
+ if (value && _delegate && [_delegate respondsToSelector: @selector(localizedServiceTypesDictionary)])
+ {
+ NSString * localizedValue = [_delegate.localizedServiceTypesDictionary objectForKey: value];
+ if (localizedValue) result = localizedValue;
+ }
+
+ return(result);
+}
+
+@end
+
+@implementation NSBrowser(PathArray)
+
+- (NSArray *)pathArrayToColumn:(NSInteger)column includeSelectedRow:(BOOL)includeSelection
+{
+ NSMutableArray * pathArray = [NSMutableArray array];
+ if (!includeSelection) column--;
+ for (NSInteger c = 0 ; c <= column ; c++)
+ {
+ NSBrowserCell *cell = [self selectedCellInColumn: c];
+ if (cell) [pathArray addObject: [cell stringValue]];
+ }
+
+ return(pathArray);
+}
+
+@end
+
+@interface CNDomainBrowserView ()
+
+@property (strong) _CNDomainBrowser * bonjour;
+@property (strong) NSSplitView * mainSplitView;
+
+@property (strong) NSTableView * instanceTable;
+@property (strong) NSArrayController * instanceC;
+@property (strong) NSTableColumn * instanceNameColumn;
+@property (strong) NSTableColumn * instanceServiceTypeColumn;
+@property (strong) NSTableColumn * instancePathPopupColumn;
+
+@property (strong) NSBrowser * browser;
+
+@property (strong) CNServiceTypeLocalizer * serviceTypeLocalizer;
+
+@end
+
+@implementation CNDomainBrowserView
+
+- (instancetype)initWithFrame:(NSRect)frameRect
+{
+ if (self = [super initWithFrame: frameRect])
+ {
+ [self commonInit];
+ }
+ return(self);
+}
+
+- (nullable instancetype)initWithCoder:(NSCoder *)coder
+{
+ if (self = [super initWithCoder: coder])
+ {
+ [self commonInit];
+ }
+ return(self);
+}
+
+- (void)awakeFromNib
+{
+ [super awakeFromNib];
+
+ self.bonjour = [[_CNDomainBrowser alloc] initWithDelegate:(id<_CNDomainBrowserDelegate>)self];
+ _bonjour.browseRegistration = _browseRegistration;
+ _bonjour.ignoreLocal = _ignoreLocal;
+ _bonjour.ignoreBTMM = _ignoreBTMM;
+}
+
+
+- (void)contentViewsInit
+{
+ NSRect frame = self.frame;
+ self.instanceC = [[NSArrayController alloc] init];
+ self.serviceTypeLocalizer = [[CNServiceTypeLocalizer alloc] initWithDelegate: (id<CNServiceTypeLocalizerDelegate>)self];
+
+ // Bottom browser
+ frame.origin.x = frame.origin.y = 0;
+ NSBrowser * browserView = [[NSBrowser alloc] initWithFrame: frame];
+ browserView.delegate = (id<NSBrowserDelegate>)self;
+ browserView.action = @selector(clickAction:);
+ browserView.titled = NO;
+ browserView.separatesColumns = NO;
+ browserView.allowsEmptySelection = YES;
+ browserView.allowsMultipleSelection = NO;
+ browserView.takesTitleFromPreviousColumn = NO;
+ browserView.hasHorizontalScroller = YES;
+ browserView.columnResizingType = NSBrowserNoColumnResizing;
+ browserView.minColumnWidth = 50;
+ self.browser = browserView;
+
+ [self addSubview: browserView];
+}
+
+- (void)commonInit
+{
+ [self contentViewsInit];
+}
+
+- (void)viewWillMoveToWindow:(NSWindow *)newWindow
+{
+ [super viewWillMoveToWindow: newWindow];
+ if (newWindow)
+ {
+ [self.mainSplitView adjustSubviews];
+ }
+}
+
+- (void)setDomainSelectionToPathArray:(NSArray *)pathArray
+{
+ NSInteger column = 0;
+ for (NSString * nextPathComponent in pathArray)
+ {
+ NSArray * subPath = [self.browser pathArrayToColumn: column includeSelectedRow: NO];
+ NSArray * rowArray = [[self.bonjour subDomainsAtDomainPath: subPath] sortedArrayUsingComparator: ^(id obj1, id obj2) {
+ return (NSComparisonResult)[ obj1[_CNSubDomainKey_subPath] compare: obj2[_CNSubDomainKey_subPath]];
+ }];
+ NSInteger nextRow = [rowArray indexOfObjectPassingTest: ^BOOL(id obj, NSUInteger index, BOOL *stop) {
+ (void)index;
+ (void)stop;
+ return [obj[_CNSubDomainKey_subPath] isEqualToString: nextPathComponent];
+ }];
+ [self.browser selectRow: nextRow inColumn: column++];
+ }
+}
+
+- (NSInteger)maxNumberOfVisibleSubDomainRows
+{
+ NSInteger result = 0;
+
+ for (NSInteger i = self.browser.firstVisibleColumn ; i <= self.browser.lastVisibleColumn ; i++)
+ {
+ NSInteger rows = [self browser: self.browser numberOfRowsInColumn: i];
+ result = MAX(rows, result);
+ }
+
+ return(result);
+}
+
+#pragma mark - Public Methods
+
+- (void)setIgnoreLocal:(BOOL)ignoreLocal
+{
+ _ignoreLocal = ignoreLocal;
+ self.bonjour.ignoreLocal = _ignoreLocal;
+}
+
+- (void)setBrowseRegistration:(BOOL)browseRegistration
+{
+ _browseRegistration = browseRegistration;
+ self.bonjour.browseRegistration = _browseRegistration;
+}
+
+- (NSString *)selectedDNSDomain
+{
+ NSArray * pathArray = [self.browser pathArrayToColumn: self.browser.selectedColumn includeSelectedRow: YES];
+ return(DomainPathToDNSDomain(pathArray));
+}
+
+- (NSString *)defaultDNSDomain
+{
+ return(DomainPathToDNSDomain(self.bonjour.defaultDomainPath));
+}
+
+- (NSArray *)flattenedDNSDomains
+{
+ return(self.bonjour.flattenedDNSDomains);
+}
+
+
+- (void)startBrowse
+{
+ [self.bonjour startBrowser];
+}
+
+- (void)stopBrowse
+{
+ [self.bonjour stopBrowser];
+}
+
+- (BOOL)isBrowsing
+{
+ return(self.bonjour.isBrowsing);
+}
+
+#pragma mark - Notifications
+
+- (void)browser:(NSBrowser *)sender selectionDidChange:(NSArray *)pathArray
+{
+ if (_delegate && [_delegate respondsToSelector: @selector(bonjourBrowserDomainSelected:)] &&
+ sender == self.browser)
+ {
+ [_delegate bonjourBrowserDomainSelected: pathArray ? DomainPathToDNSDomain(pathArray) : nil];
+ }
+}
+
+#pragma mark - NSBrowserDelegate
+
+- (NSInteger)browser:(NSBrowser *)sender numberOfRowsInColumn:(NSInteger)column
+{
+ return ([self.bonjour subDomainsAtDomainPath: [sender pathArrayToColumn: column includeSelectedRow: NO]].count);
+}
+
+- (void)browser:(NSBrowser *)sender willDisplayCell:(id)cell atRow:(NSUInteger)row column:(NSInteger)column
+{
+ // Get the name
+ NSMutableArray * pathArray = [NSMutableArray arrayWithArray: [sender pathArrayToColumn: column includeSelectedRow: NO]];
+ NSArray * rowArray = [[self.bonjour subDomainsAtDomainPath: pathArray] sortedArrayUsingComparator: ^(id obj1, id obj2) {
+ return (NSComparisonResult)[ obj1[_CNSubDomainKey_subPath] compare: obj2[_CNSubDomainKey_subPath]];
+ }];
+ if (row < rowArray.count)
+ {
+ NSDictionary * item = [rowArray objectAtIndex: row];
+ NSString *val = item[_CNSubDomainKey_subPath];
+ [cell setStringValue: val];
+
+ // See if it's a leaf
+ [pathArray addObject: val];
+ ((NSBrowserCell*)cell).leaf = (![self.bonjour subDomainsAtDomainPath: pathArray].count);
+
+ // Make Default domain bold
+ if ([item[_CNSubDomainKey_defaultFlag] boolValue]) ((NSBrowserCell*)cell).font = [NSFont boldSystemFontOfSize: [NSFont systemFontSizeForControlSize: sender.controlSize]];
+ else ((NSBrowserCell*)cell).font = [NSFont controlContentFontOfSize: [NSFont systemFontSizeForControlSize: sender.controlSize]];
+ }
+}
+
+- (CGFloat)browser:(NSBrowser *)sender shouldSizeColumn:(NSInteger)column forUserResize:(BOOL)forUserResize toWidth:(CGFloat)suggestedWidth
+{
+ (void)forUserResize;
+ CGFloat newSize = 0;
+
+ NSArray * pathArray = [NSArray arrayWithArray: [sender pathArrayToColumn: column includeSelectedRow: NO]];
+ NSArray * rowArray = [[self.bonjour subDomainsAtDomainPath: pathArray] sortedArrayUsingComparator: ^(id obj1, id obj2) {
+ return (NSComparisonResult)[ obj1[_CNSubDomainKey_subPath] compare: obj2[_CNSubDomainKey_subPath]];
+ }];
+
+ for (NSDictionary * next in rowArray)
+ {
+ NSFont * font = [next[_CNSubDomainKey_defaultFlag] boolValue] ?
+ [NSFont boldSystemFontOfSize: [NSFont systemFontSizeForControlSize: sender.controlSize]]:
+ [NSFont controlContentFontOfSize: [NSFont systemFontSizeForControlSize: sender.controlSize]];
+ NSArray * itemArray = [pathArray arrayByAddingObjectsFromArray: [NSArray arrayWithObject: next[_CNSubDomainKey_subPath]]];
+ NSBrowserCell * cell = [[NSBrowserCell alloc] initTextCell: next[_CNSubDomainKey_subPath]];
+ cell.font = font;
+ cell.leaf = ([self.bonjour subDomainsAtDomainPath: itemArray].count == 0);
+ newSize = MAX(newSize, cell.cellSize.width + BROWSER_CELL_SPACING);
+ }
+
+ if (!newSize) newSize = suggestedWidth;
+ newSize = (NSInteger)(newSize + 0.5);
+
+ return(newSize);
+}
+
+#pragma mark - _CNDomainBrowser Delegates
+
+- (void)bonjourBrowserDomainUpdate:(NSArray *)defaultDomainPath
+{
+ (void)defaultDomainPath;
+ [self.browser loadColumnZero];
+ [self setDomainSelectionToPathArray: self.bonjour.defaultDomainPath];
+}
+
+#pragma mark - Commands
+
+- (IBAction)clickAction:(id)sender
+{
+ (void)sender;
+ NSArray * pathArray = [self.browser pathArrayToColumn: self.browser.selectedColumn includeSelectedRow: YES];
+ if (!pathArray.count) pathArray = self.bonjour.defaultDomainPath;
+ [self setDomainSelectionToPathArray: pathArray];
+ [self browser: self.browser selectionDidChange: pathArray];
+}
+
+@end
+
+@interface CNBonjourDomainCell()
+
+@property(strong) NSMutableArray * browserCells;
+
+@end
+
+@implementation CNBonjourDomainCell
+
+- (instancetype)init
+{
+ self = [super init];
+ if (self)
+ {
+ self.browserCells = [NSMutableArray array];
+ }
+ return self;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)coder
+{
+ self = [super initWithCoder:coder];
+ if (self)
+ {
+ self.browserCells = [NSMutableArray array];
+ }
+ return self;
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+ CNBonjourDomainCell *cell = [super copyWithZone: zone];
+ if (cell)
+ {
+ cell.browserCells = [NSMutableArray arrayWithArray: self.browserCells];
+ }
+ return cell;
+}
+
+- (void) setObjectValue:(id)objectValue
+{
+ [super setObjectValue: objectValue];
+
+ [self.browserCells removeAllObjects];
+ if ([objectValue isKindOfClass: [NSString class]])
+ {
+ NSUInteger count = 0;
+ NSArray * subPaths = DNSDomainToDomainPath(objectValue);
+ for (NSString * nextPath in subPaths)
+ {
+ NSBrowserCell * nextCell = [[NSBrowserCell alloc] initTextCell: nextPath];
+ nextCell.leaf = (++count == subPaths.count);
+ [self.browserCells addObject: nextCell];
+ }
+ }
+}
+
+- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
+{
+ CGFloat usedWidth = BROWSER_CELL_SPACING / 2;
+ for (NSBrowserCell * nextCell in self.browserCells)
+ {
+ NSRect nextRect = cellFrame;
+ nextRect.size.width = cellFrame.size.width - usedWidth;
+ nextRect.origin.x += usedWidth;
+
+ NSSize cellSize = [nextCell cellSizeForBounds: nextRect];
+ CGFloat yOffset = (nextRect.size.height - cellSize.height) / 2;
+ nextRect.size.width = cellSize.width;
+ nextRect.size.height = cellSize.height;
+ nextRect.origin.y += yOffset;
+
+ [nextCell drawInteriorWithFrame: nextRect
+ inView: controlView];
+ usedWidth += nextRect.size.width + BROWSER_CELL_SPACING;
+ }
+}
+
+@end
+
+@interface CNBonjourDomainView()
+
+@property(strong) CNBonjourDomainCell * cell;
+
+@end
+
+@implementation CNBonjourDomainView
+
+- (instancetype)initWithFrame:(NSRect)frameRect
+{
+ self = [super initWithFrame:frameRect];
+ if (self)
+ {
+ self.cell = [[CNBonjourDomainCell alloc] init];
+ }
+ return self;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)coder
+{
+ self = [super initWithCoder:coder];
+ if (self)
+ {
+ self.cell = [[CNBonjourDomainCell alloc] init];
+ }
+ return self;
+}
+
+- (void) setDomain:(NSString *)domain
+{
+ if (![domain isEqualToString: self.cell.stringValue])
+ {
+ self.cell.stringValue = domain;
+ self.needsDisplay = YES;
+ }
+}
+
+- (NSString *)domain
+{
+ return self.cell.stringValue;
+}
+
+- (void) drawRect:(NSRect)dirtyRect
+{
+ (void)dirtyRect; // Unused
+ [self.cell drawInteriorWithFrame: self.bounds inView: self];
+}
+
+@end
diff --git a/mDNSResponder/mDNSMacOSX/DomainBrowser/macOS/DomainBrowser.h b/mDNSResponder/mDNSMacOSX/DomainBrowser/macOS/DomainBrowser.h
new file mode 100644
index 00000000..bdc9a877
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DomainBrowser/macOS/DomainBrowser.h
@@ -0,0 +1,30 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+//! Project version number for DomainBrowser.
+FOUNDATION_EXPORT double DomainBrowserVersionNumber;
+
+//! Project version string for DomainBrowser.
+FOUNDATION_EXPORT const unsigned char DomainBrowserVersionString[];
+
+// In this header, you should import all the public headers of your framework using statements like #import <DomainBrowser/PublicHeader.h>
+
+
+#import <DomainBrowser/CNDomainBrowserView.h>
+#import <DomainBrowser/CNDomainBrowserPathUtils.h>
diff --git a/mDNSResponder/mDNSMacOSX/DomainBrowser/macOS/Info.plist b/mDNSResponder/mDNSMacOSX/DomainBrowser/macOS/Info.plist
new file mode 100644
index 00000000..d3de8eef
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/DomainBrowser/macOS/Info.plist
@@ -0,0 +1,26 @@
+<?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>en</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>$(CURRENT_PROJECT_VERSION)</string>
+ <key>NSPrincipalClass</key>
+ <string></string>
+</dict>
+</plist>
diff --git a/mDNSResponder/mDNSMacOSX/LegacyNATTraversal.c b/mDNSResponder/mDNSMacOSX/LegacyNATTraversal.c
index acfb3dca..2c90d929 100644
--- a/mDNSResponder/mDNSMacOSX/LegacyNATTraversal.c
+++ b/mDNSResponder/mDNSMacOSX/LegacyNATTraversal.c
@@ -27,7 +27,6 @@
# 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 )
@@ -80,7 +79,7 @@ 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)
+mDNSlocal void AllocAndCopy(char **const dst, const char *const src)
{
if (src == mDNSNULL) return;
if ((strlen((char*)src)) >= UINT32_MAX || (*dst = mDNSPlatformMemAllocate((mDNSu32)strlen((char*)src) + 1)) == mDNSNULL)
@@ -93,7 +92,7 @@ mDNSlocal void AllocAndCopy(mDNSu8 **const dst, const mDNSu8 *const 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)
+mDNSlocal mStatus ParseHttpUrl(const mDNSu8 *ptr, const mDNSu8 *const end, char **const addressAndPort, mDNSIPPort *const port, char **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)
@@ -210,7 +209,7 @@ mDNSlocal void handleLNTDeviceDescriptionResponse(tcpLNTInfo *tcpInfo)
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);
+ LogInfo("handleLNTDeviceDescriptionResponse: HTTP Result code: %d", http_result);
return;
}
@@ -318,7 +317,7 @@ mDNSlocal void handleLNTGetExternalAddressResponse(tcpLNTInfo *tcpInfo)
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);
+ LogInfo("handleLNTGetExternalAddressResponse: HTTP Result code: %d", http_result);
return;
}
@@ -336,7 +335,6 @@ mDNSlocal void handleLNTGetExternalAddressResponse(tcpLNTInfo *tcpInfo)
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;
@@ -380,12 +378,11 @@ mDNSlocal void handleLNTPortMappingResponse(tcpLNTInfo *tcpInfo)
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);
+ LogInfo("handleLNTPortMappingResponse: 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;
@@ -397,7 +394,7 @@ mDNSlocal void handleLNTPortMappingResponse(tcpLNTInfo *tcpInfo)
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);
+ LogInfo("handleLNTPortMappingResponse: HTTP Result code: %d", http_result);
}
mDNSlocal void DisposeInfoFromUnmapList(mDNS *m, tcpLNTInfo *tcpInfo)
@@ -479,20 +476,17 @@ exit:
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", "");
+ case LNTDiscoveryOp:
+ LogInfo("tcpConnectionCallback: DeviceDescription SOAP address %s SOAP path %s",
+ m->UPnPSOAPAddressString ? m->UPnPSOAPAddressString : "NULL", m->UPnPSOAPURL ? m->UPnPSOAPURL : "NULL");
break;
- case LNTExternalAddrOp: mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.AddressRequest",
- mDNSIPv4AddressIsZero(m->ExtAddress) ? "failure" : "success",
- mDNSIPv4AddressIsZero(m->ExtAddress) ? "failure" : "success", "");
+ case LNTExternalAddrOp:
+ LogInfo("tcpConnectionCallback: AddressRequest %s", 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);
+ case LNTPortMapOp:
+ if (tcpInfo->parentNATInfo)
+ LogInfo("tcpConnectionCallback: PortMapRequest %s result %d",
+ (tcpInfo->parentNATInfo->Result) ? "failure" : "success", tcpInfo->parentNATInfo->Result);
break;
case LNTPortMapDeleteOp: break;
default: break;
@@ -530,7 +524,7 @@ mDNSlocal mStatus MakeTCPConnection(mDNS *const m, tcpLNTInfo *info, const mDNSA
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);
+ info->sock = mDNSPlatformTCPSocket(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);
@@ -828,7 +822,7 @@ mDNSexport void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID Interface
}
if (ptr == mDNSNULL || ptr == end)
{
- mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Location", "");
+ LogInfo("LNT_ConfigureRouterInfo: Location field not found");
return; // not a message we care about
}
ptr += 9; //Skip over 'Location:'
@@ -856,7 +850,7 @@ mDNSexport void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID Interface
// 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", "");
+ LogInfo("LNT_ConfigureRouterInfo: Failed to parse URL");
return;
}
@@ -864,14 +858,12 @@ mDNSexport void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID Interface
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);
@@ -882,7 +874,6 @@ mDNSexport void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID Interface
// 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);
}
@@ -917,7 +908,7 @@ mDNSexport void LNT_SendDiscoveryMsg(mDNS *m)
if (!mDNSIPv4AddressIsZero(m->Router.ip.v4))
{
- if (!m->SSDPSocket) { m->SSDPSocket = mDNSPlatformUDPSocket(m, zeroIPPort); debugf("LNT_SendDiscoveryMsg created SSDPSocket %p", &m->SSDPSocket); }
+ if (!m->SSDPSocket) { m->SSDPSocket = mDNSPlatformUDPSocket(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);
}
diff --git a/mDNSResponder/mDNSMacOSX/Metrics.m b/mDNSResponder/mDNSMacOSX/Metrics.m
index bfff58e4..f8a3ae73 100644
--- a/mDNSResponder/mDNSMacOSX/Metrics.m
+++ b/mDNSResponder/mDNSMacOSX/Metrics.m
@@ -294,8 +294,6 @@ typedef struct
// Globals
//===========================================================================================================================
-extern mDNS mDNSStorage;
-
static DNSDomainStats * gDomainStatsList = NULL;
static ResolveStatsDomain * gResolveStatsList = NULL;
static ResolveStatsDNSServer * gResolveStatsServerList = NULL;
@@ -1487,10 +1485,10 @@ mDNSlocal mStatus SubmitAWDMetric(UInt32 inMetricID)
case AWDMetricId_MDNSResponder_ServicesStats:
[AWDMetricManagerSoft postMetricWithId:AWDMetricId_MDNSResponder_ServicesStats unsignedIntegerValue:max_num_regservices];
- KQueueLock(&mDNSStorage);
+ KQueueLock();
// reset the no of max services since we want to collect the max no of services registered per AWD submission period
max_num_regservices = curr_num_regservices;
- KQueueUnlock(&mDNSStorage, "SubmitAWDSimpleMetricServiceStats");
+ KQueueUnlock("SubmitAWDSimpleMetricServiceStats");
err = mStatus_NoError;
break;
@@ -1520,10 +1518,10 @@ mDNSlocal mStatus SubmitAWDMetricQueryStats(void)
err = CreateDomainStatsList(&newDomainStatsList);
require_noerr_quiet(err, exit);
- KQueueLock(&mDNSStorage);
+ KQueueLock();
domainStatsList = gDomainStatsList;
gDomainStatsList = newDomainStatsList;
- KQueueUnlock(&mDNSStorage, "SubmitAWDMetricQueryStats");
+ KQueueUnlock("SubmitAWDMetricQueryStats");
container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_DNSStatistics];
require_action_quiet(container, exit, err = mStatus_UnknownErr);
@@ -1578,14 +1576,14 @@ mDNSlocal mStatus SubmitAWDMetricResolveStats(void)
err = CreateResolveStatsList(&newResolveStatsList);
require_noerr_quiet(err, exit);
- KQueueLock(&mDNSStorage);
+ KQueueLock();
domainList = gResolveStatsList;
serverList = gResolveStatsServerList;
gResolveStatsList = newResolveStatsList;
gResolveStatsServerList = NULL;
gResolveStatsNextServerID = 0;
gResolveStatsObjCount = 0;
- KQueueUnlock(&mDNSStorage, "SubmitAWDMetricResolveStats");
+ KQueueUnlock("SubmitAWDMetricResolveStats");
container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_ResolveStats];
require_action_quiet(container, exit, err = mStatus_UnknownErr);
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_idle.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_idle.tiff
deleted file mode 100644
index b78b0c2a..00000000
--- a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_idle.tiff
+++ /dev/null
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_pressed.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_pressed.tiff
deleted file mode 100644
index b842e20c..00000000
--- a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/add_pressed.tiff
+++ /dev/null
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_disabled.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_disabled.tiff
deleted file mode 100644
index 70d3dd9c..00000000
--- a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_disabled.tiff
+++ /dev/null
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_idle.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_idle.tiff
deleted file mode 100644
index dacc97c3..00000000
--- a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_idle.tiff
+++ /dev/null
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_pressed.tiff b/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_pressed.tiff
deleted file mode 100644
index de3f8779..00000000
--- a/mDNSResponder/mDNSMacOSX/PreferencePane/Artwork/remove_pressed.tiff
+++ /dev/null
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Base.lproj/DNSServiceDiscoveryPref.nib/designable.nib b/mDNSResponder/mDNSMacOSX/PreferencePane/Base.lproj/DNSServiceDiscoveryPref.nib/designable.nib
new file mode 100644
index 00000000..187ac388
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Base.lproj/DNSServiceDiscoveryPref.nib/designable.nib
@@ -0,0 +1,821 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="12118" systemVersion="17A210a" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
+ <dependencies>
+ <deployment identifier="macosx"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="12118"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+ </dependencies>
+ <objects>
+ <customObject id="-2" userLabel="File's Owner" customClass="DNSServiceDiscoveryPref">
+ <connections>
+ <outlet property="_initialKeyView" destination="107" id="235"/>
+ <outlet property="_lastKeyView" destination="107" id="183"/>
+ <outlet property="_window" destination="12" id="142"/>
+ <outlet property="addBrowseDomainButton" destination="381" id="384"/>
+ <outlet property="addBrowseDomainManualWindow" destination="NFb-eI-atL" id="0AN-Mr-e84"/>
+ <outlet property="addBrowseDomainWindow" destination="333" id="363"/>
+ <outlet property="applyButton" destination="208" id="238"/>
+ <outlet property="bonjourBrowserView" destination="200327" id="200328"/>
+ <outlet property="browseCancelButton" destination="341" id="375"/>
+ <outlet property="browseDomainList" destination="327" id="349"/>
+ <outlet property="browseDomainTextField" destination="W2d-Us-Cpm" id="kOZ-wG-OPp"/>
+ <outlet property="browseOKButton" destination="340" id="376"/>
+ <outlet property="comboAuthButton" destination="137" id="201"/>
+ <outlet property="hostName" destination="107" id="224"/>
+ <outlet property="hostNameSharedSecretButton" destination="263" id="270"/>
+ <outlet property="regDomainTextField" destination="OEh-fL-Ol6" id="Dv0-aj-gah"/>
+ <outlet property="regDomainView" destination="Reu-VC-MNz" id="4I2-zS-sdq"/>
+ <outlet property="registrationBrowserView" destination="agb-WV-smo" id="j7U-ZK-LIb"/>
+ <outlet property="registrationSelectButton" destination="KqE-pc-8z0" id="CJS-ml-2CA"/>
+ <outlet property="registrationSharedSecretButton" destination="267" id="268"/>
+ <outlet property="removeBrowseDomainButton" destination="383" id="385"/>
+ <outlet property="revertButton" destination="290" id="292"/>
+ <outlet property="secretCancelButton" destination="341" id="373"/>
+ <outlet property="secretOKButton" destination="260" id="377"/>
+ <outlet property="selectRegistrationDomainManualWindow" destination="he2-0K-CWy" id="eXD-7o-XQU"/>
+ <outlet property="selectRegistrationDomainWindow" destination="ail-If-2Xp" id="34V-c7-D3b"/>
+ <outlet property="sharedSecretName" destination="256" id="275"/>
+ <outlet property="sharedSecretValue" destination="257" id="276"/>
+ <outlet property="sharedSecretWindow" destination="255" id="274"/>
+ <outlet property="statusImageView" destination="320" id="321"/>
+ <outlet property="tabView" destination="100" id="380"/>
+ <outlet property="wideAreaCheckBox" destination="179" id="240"/>
+ </connections>
+ </customObject>
+ <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
+ <customObject id="-3" userLabel="Application" customClass="NSObject"/>
+ <window title="Bonjour" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" deferred="NO" oneShot="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="12" userLabel="PrefPane">
+ <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/>
+ <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
+ <rect key="contentRect" x="51" y="335" width="596" height="343"/>
+ <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
+ <value key="minSize" type="size" width="213.66399999999999" height="10"/>
+ <view key="contentView" id="6">
+ <rect key="frame" x="0.0" y="0.0" width="596" height="343"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <tabView translatesAutoresizingMaskIntoConstraints="NO" id="100">
+ <rect key="frame" x="13" y="52" width="570" height="285"/>
+ <font key="font" metaFont="system"/>
+ <tabViewItems>
+ <tabViewItem label="Hostname" identifier="1" id="102">
+ <view key="view" id="101">
+ <rect key="frame" x="10" y="33" width="550" height="239"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="107">
+ <rect key="frame" x="119" y="155" width="383" height="22"/>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" alignment="left" placeholderString="steve.example.com" drawsBackground="YES" id="100107">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ <connections>
+ <outlet property="delegate" destination="-2" id="227"/>
+ </connections>
+ </textField>
+ <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="108">
+ <rect key="frame" x="43" y="158" width="70" height="17"/>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Hostname:" id="100108">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="117">
+ <rect key="frame" x="18" y="185" width="514" height="34"/>
+ <constraints>
+ <constraint firstAttribute="width" priority="499" constant="510" id="TMz-kS-KCv"/>
+ </constraints>
+ <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Enter a hostname for this computer. Other computers on the Internet will be able to reach your computer using this hostname." id="100117">
+ <font key="font" metaFont="systemBold"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="263">
+ <rect key="frame" x="113" y="119" width="109" height="32"/>
+ <buttonCell key="cell" type="push" title="Password…" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100263">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="changeButtonPressed:" target="-2" id="272"/>
+ </connections>
+ </button>
+ <imageView translatesAutoresizingMaskIntoConstraints="NO" id="320">
+ <rect key="frame" x="510" y="156" width="20" height="20"/>
+ <constraints>
+ <constraint firstAttribute="width" constant="20" id="7Qf-g0-5SV"/>
+ <constraint firstAttribute="height" constant="20" id="bfL-QJ-KFw"/>
+ </constraints>
+ <imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageAlignment="left" imageScaling="proportionallyDown" id="100320"/>
+ </imageView>
+ </subviews>
+ <constraints>
+ <constraint firstItem="263" firstAttribute="leading" secondItem="107" secondAttribute="leading" id="4Dv-gf-Cjr"/>
+ <constraint firstAttribute="trailing" secondItem="117" secondAttribute="trailing" constant="20" symbolic="YES" id="5zc-LQ-OC8"/>
+ <constraint firstItem="320" firstAttribute="leading" secondItem="107" secondAttribute="trailing" constant="8" symbolic="YES" id="BIu-YL-Fr2"/>
+ <constraint firstItem="263" firstAttribute="top" secondItem="107" secondAttribute="bottom" constant="8" symbolic="YES" id="K1w-WG-3KW"/>
+ <constraint firstItem="107" firstAttribute="centerY" secondItem="320" secondAttribute="centerY" id="LlU-Oy-3va"/>
+ <constraint firstItem="107" firstAttribute="top" secondItem="117" secondAttribute="bottom" constant="8" symbolic="YES" id="V8c-G1-gsR"/>
+ <constraint firstItem="117" firstAttribute="top" secondItem="101" secondAttribute="top" constant="20" symbolic="YES" id="Xnz-bz-ahU"/>
+ <constraint firstItem="117" firstAttribute="leading" secondItem="101" secondAttribute="leading" constant="20" symbolic="YES" id="ZIG-S4-cst"/>
+ <constraint firstItem="107" firstAttribute="leading" secondItem="108" secondAttribute="trailing" constant="8" symbolic="YES" id="cQG-zv-Ozo"/>
+ <constraint firstItem="108" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="101" secondAttribute="leading" constant="20" symbolic="YES" id="foH-DQ-yvJ"/>
+ <constraint firstItem="107" firstAttribute="leading" secondItem="101" secondAttribute="leading" priority="499" constant="119" id="qGZ-fm-Wgf"/>
+ <constraint firstAttribute="trailing" secondItem="320" secondAttribute="trailing" constant="20" symbolic="YES" id="w2R-Kc-Tj3"/>
+ <constraint firstItem="108" firstAttribute="baseline" secondItem="107" secondAttribute="baseline" id="xcr-32-mbs"/>
+ </constraints>
+ </view>
+ </tabViewItem>
+ <tabViewItem label="Registration" identifier="2" id="98">
+ <view key="view" id="99">
+ <rect key="frame" x="10" y="33" width="550" height="239"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <button translatesAutoresizingMaskIntoConstraints="NO" id="179">
+ <rect key="frame" x="41" y="157" width="72" height="18"/>
+ <buttonCell key="cell" type="check" title="Domain:" bezelStyle="regularSquare" imagePosition="left" alignment="right" inset="2" id="100179">
+ <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="wideAreaCheckBoxChanged:" target="-2" id="317"/>
+ </connections>
+ </button>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="267">
+ <rect key="frame" x="222" y="119" width="109" height="32"/>
+ <buttonCell key="cell" type="push" title="Password…" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100267">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="changeButtonPressed:" target="-2" id="273"/>
+ </connections>
+ </button>
+ <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="348">
+ <rect key="frame" x="18" y="185" width="514" height="34"/>
+ <constraints>
+ <constraint firstAttribute="width" priority="499" constant="510" id="lUQ-CZ-AzC"/>
+ </constraints>
+ <textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Check the box and select a registration domain to enable Bonjour advertising beyond the local subnet." id="100348">
+ <font key="font" metaFont="systemBold"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="KqE-pc-8z0">
+ <rect key="frame" x="113" y="119" width="109" height="32"/>
+ <buttonCell key="cell" type="push" title="Select…" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="TjV-QO-BW7">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="selectWideAreaDomainButtonPressed:" target="-2" id="d4S-la-iyw"/>
+ </connections>
+ </button>
+ <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cxI-8W-6HI">
+ <rect key="frame" x="119" y="155" width="411" height="22"/>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" enabled="NO" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="Oao-6x-0X9">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <customView translatesAutoresizingMaskIntoConstraints="NO" id="Reu-VC-MNz" customClass="CNBonjourDomainView">
+ <rect key="frame" x="119" y="155" width="411" height="22"/>
+ <constraints>
+ <constraint firstAttribute="height" constant="22" id="l7c-m9-GcE"/>
+ </constraints>
+ </customView>
+ </subviews>
+ <constraints>
+ <constraint firstItem="267" firstAttribute="leading" secondItem="KqE-pc-8z0" secondAttribute="trailing" constant="12" symbolic="YES" id="2kZ-P9-l60"/>
+ <constraint firstItem="Reu-VC-MNz" firstAttribute="centerY" secondItem="cxI-8W-6HI" secondAttribute="centerY" id="984-4H-aIz"/>
+ <constraint firstItem="179" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="99" secondAttribute="leading" constant="20" symbolic="YES" id="D3d-wd-QYX"/>
+ <constraint firstItem="Reu-VC-MNz" firstAttribute="top" secondItem="348" secondAttribute="bottom" constant="8" symbolic="YES" id="GcL-zf-7HQ"/>
+ <constraint firstItem="348" firstAttribute="top" secondItem="99" secondAttribute="top" constant="20" symbolic="YES" id="HDQ-fd-PwR"/>
+ <constraint firstItem="Reu-VC-MNz" firstAttribute="height" secondItem="cxI-8W-6HI" secondAttribute="height" id="HUo-M5-tyi"/>
+ <constraint firstItem="Reu-VC-MNz" firstAttribute="width" secondItem="cxI-8W-6HI" secondAttribute="width" id="JML-71-xrY"/>
+ <constraint firstItem="cxI-8W-6HI" firstAttribute="baseline" secondItem="179" secondAttribute="baseline" id="NX1-5X-UZI"/>
+ <constraint firstItem="348" firstAttribute="leading" secondItem="99" secondAttribute="leading" constant="20" symbolic="YES" id="P0u-7u-LJv"/>
+ <constraint firstItem="KqE-pc-8z0" firstAttribute="leading" secondItem="cxI-8W-6HI" secondAttribute="leading" id="RDS-Bc-KYd"/>
+ <constraint firstItem="Reu-VC-MNz" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="99" secondAttribute="leading" constant="20" symbolic="YES" id="d8L-Kb-W49"/>
+ <constraint firstItem="Reu-VC-MNz" firstAttribute="centerX" secondItem="cxI-8W-6HI" secondAttribute="centerX" id="dfu-qB-Ezj"/>
+ <constraint firstItem="Reu-VC-MNz" firstAttribute="leading" secondItem="179" secondAttribute="trailing" constant="8" symbolic="YES" id="rUC-3C-r32"/>
+ <constraint firstItem="KqE-pc-8z0" firstAttribute="top" secondItem="cxI-8W-6HI" secondAttribute="bottom" constant="8" symbolic="YES" id="skb-cf-d2E"/>
+ <constraint firstAttribute="trailing" secondItem="Reu-VC-MNz" secondAttribute="trailing" constant="20" symbolic="YES" id="ta5-1S-y3v"/>
+ <constraint firstAttribute="trailing" secondItem="348" secondAttribute="trailing" constant="20" symbolic="YES" id="tr3-Ed-I8w"/>
+ <constraint firstItem="267" firstAttribute="baseline" secondItem="KqE-pc-8z0" secondAttribute="baseline" id="vt0-3i-y05"/>
+ <constraint firstItem="267" firstAttribute="width" secondItem="KqE-pc-8z0" secondAttribute="width" id="vxX-jt-NDx"/>
+ <constraint firstItem="Reu-VC-MNz" firstAttribute="leading" secondItem="99" secondAttribute="leading" priority="499" constant="119" id="xdT-xB-bam"/>
+ </constraints>
+ </view>
+ </tabViewItem>
+ <tabViewItem label="Browsing" identifier="" id="322">
+ <view key="view" id="323">
+ <rect key="frame" x="10" y="33" width="550" height="239"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <scrollView horizontalLineScroll="24" horizontalPageScroll="10" verticalLineScroll="24" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="326">
+ <rect key="frame" x="20" y="82" width="510" height="112"/>
+ <clipView key="contentView" id="r8V-oO-qTS">
+ <rect key="frame" x="1" y="1" width="508" height="110"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <tableView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" alternatingRowBackgroundColors="YES" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="22" id="327">
+ <rect key="frame" x="0.0" y="0.0" width="508" height="110"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <size key="intercellSpacing" width="3" height="2"/>
+ <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
+ <color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
+ <tableColumns>
+ <tableColumn identifier="Enabled" width="35" minWidth="30" maxWidth="1000" id="328">
+ <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
+ <font key="font" metaFont="smallSystem"/>
+ <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" white="0.33333299" alpha="1" colorSpace="calibratedWhite"/>
+ </tableHeaderCell>
+ <buttonCell key="dataCell" type="check" bezelStyle="regularSquare" imagePosition="above" alignment="center" inset="2" id="358">
+ <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
+ <font key="font" metaFont="cellTitle"/>
+ <connections>
+ <action selector="enableBrowseDomainClicked:" target="-2" id="360"/>
+ </connections>
+ </buttonCell>
+ </tableColumn>
+ <tableColumn identifier="Domain" editable="NO" width="451.9541015625" minWidth="49.3466796875" maxWidth="1000" id="329">
+ <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Domain">
+ <font key="font" metaFont="smallSystem"/>
+ <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" white="0.33333299" alpha="1" colorSpace="calibratedWhite"/>
+ </tableHeaderCell>
+ <customCell key="dataCell" alignment="left" id="LhH-Yh-n33" customClass="CNBonjourDomainCell"/>
+ </tableColumn>
+ </tableColumns>
+ <connections>
+ <outlet property="dataSource" destination="-2" id="350"/>
+ <outlet property="delegate" destination="-2" id="351"/>
+ </connections>
+ </tableView>
+ </subviews>
+ </clipView>
+ <constraints>
+ <constraint firstAttribute="height" constant="112" id="Pf1-34-QXp"/>
+ </constraints>
+ <scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="100326">
+ <rect key="frame" x="-100" y="-100" width="493" height="15"/>
+ <autoresizingMask key="autoresizingMask"/>
+ </scroller>
+ <scroller key="verticalScroller" verticalHuggingPriority="750" horizontal="NO" id="200326">
+ <rect key="frame" x="493" y="1" width="16" height="110"/>
+ <autoresizingMask key="autoresizingMask"/>
+ </scroller>
+ </scrollView>
+ <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="330">
+ <rect key="frame" x="18" y="202" width="514" height="17"/>
+ <constraints>
+ <constraint firstAttribute="width" priority="499" constant="510" id="xXz-Xx-cVE"/>
+ </constraints>
+ <textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Choose which domains to browse using Wide-Area Bonjour." id="100330">
+ <font key="font" metaFont="systemBold"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <button toolTip="Click to define shortcuts within applications." verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="381">
+ <rect key="frame" x="20" y="49" width="24" height="26"/>
+ <constraints>
+ <constraint firstAttribute="width" constant="24" id="llU-4M-pcI"/>
+ <constraint firstAttribute="height" constant="24" id="qD8-y4-ZkW"/>
+ </constraints>
+ <buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSAddTemplate" imagePosition="overlaps" alignment="center" state="on" borderStyle="border" id="100381">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="addBrowseDomainClicked:" target="-2" id="386"/>
+ </connections>
+ </button>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="383">
+ <rect key="frame" x="43" y="49" width="24" height="26"/>
+ <buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSRemoveTemplate" imagePosition="overlaps" alignment="center" controlSize="small" state="on" borderStyle="border" id="100383">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="smallSystem"/>
+ <string key="keyEquivalent"></string>
+ </buttonCell>
+ <connections>
+ <action selector="removeBrowseDomainClicked:" target="-2" id="387"/>
+ </connections>
+ </button>
+ </subviews>
+ <constraints>
+ <constraint firstItem="326" firstAttribute="leading" secondItem="323" secondAttribute="leading" constant="20" symbolic="YES" id="BHw-zP-zzH"/>
+ <constraint firstItem="381" firstAttribute="centerY" secondItem="383" secondAttribute="centerY" id="Cae-WW-gYH"/>
+ <constraint firstItem="326" firstAttribute="leading" secondItem="381" secondAttribute="leading" id="GCR-nb-Kbp"/>
+ <constraint firstItem="381" firstAttribute="height" secondItem="383" secondAttribute="height" id="GYW-Vr-6c8"/>
+ <constraint firstAttribute="trailing" secondItem="326" secondAttribute="trailing" constant="20" symbolic="YES" id="HGK-Ej-oKA"/>
+ <constraint firstItem="383" firstAttribute="leading" secondItem="381" secondAttribute="trailing" constant="-1" id="KYa-XM-Qrh"/>
+ <constraint firstAttribute="trailing" secondItem="330" secondAttribute="trailing" constant="20" symbolic="YES" id="Lkk-cy-gcf"/>
+ <constraint firstItem="326" firstAttribute="top" secondItem="330" secondAttribute="bottom" constant="8" symbolic="YES" id="Pna-sQ-Iom"/>
+ <constraint firstItem="381" firstAttribute="top" secondItem="326" secondAttribute="bottom" constant="8" symbolic="YES" id="YmF-BH-VOk"/>
+ <constraint firstItem="381" firstAttribute="width" secondItem="383" secondAttribute="width" id="kJf-PK-P0M"/>
+ <constraint firstItem="330" firstAttribute="leading" secondItem="323" secondAttribute="leading" constant="20" symbolic="YES" id="luC-Nv-ec5"/>
+ <constraint firstItem="330" firstAttribute="top" secondItem="323" secondAttribute="top" constant="20" symbolic="YES" id="yVJ-PT-T31"/>
+ </constraints>
+ </view>
+ </tabViewItem>
+ </tabViewItems>
+ </tabView>
+ <customView translatesAutoresizingMaskIntoConstraints="NO" id="137" customClass="SFAuthorizationView">
+ <rect key="frame" x="20" y="20" width="356" height="34"/>
+ <constraints>
+ <constraint firstAttribute="height" constant="34" id="T24-JY-FUW"/>
+ <constraint firstAttribute="width" constant="356" id="hHs-jB-Xz8"/>
+ </constraints>
+ </customView>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="208">
+ <rect key="frame" x="502" y="13" width="80" height="32"/>
+ <buttonCell key="cell" type="push" title="Apply" bezelStyle="rounded" alignment="center" enabled="NO" borderStyle="border" inset="2" id="100208">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="applyClicked:" target="-2" id="209"/>
+ </connections>
+ </button>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="290">
+ <rect key="frame" x="422" y="13" width="80" height="32"/>
+ <buttonCell key="cell" type="push" title="Revert" bezelStyle="rounded" alignment="center" enabled="NO" borderStyle="border" inset="2" id="100290">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="revertClicked:" target="-2" id="293"/>
+ </connections>
+ </button>
+ </subviews>
+ <constraints>
+ <constraint firstAttribute="trailing" secondItem="100" secondAttribute="trailing" constant="20" symbolic="YES" id="DEs-Vk-n3D"/>
+ <constraint firstItem="208" firstAttribute="width" secondItem="290" secondAttribute="width" id="GMB-MK-qPS"/>
+ <constraint firstAttribute="bottom" secondItem="137" secondAttribute="bottom" constant="20" symbolic="YES" id="M0C-li-Dr1"/>
+ <constraint firstItem="100" firstAttribute="leading" secondItem="6" secondAttribute="leading" constant="20" symbolic="YES" id="Ozi-Cv-NdV"/>
+ <constraint firstAttribute="bottom" secondItem="208" secondAttribute="bottom" constant="20" symbolic="YES" id="PGr-uI-dUi"/>
+ <constraint firstItem="290" firstAttribute="baseline" secondItem="208" secondAttribute="baseline" id="Rcf-kj-OQp"/>
+ <constraint firstItem="137" firstAttribute="leading" secondItem="6" secondAttribute="leading" constant="20" symbolic="YES" id="dWc-kl-h8o"/>
+ <constraint firstItem="208" firstAttribute="leading" secondItem="290" secondAttribute="trailing" constant="12" symbolic="YES" id="g3l-gL-wIw"/>
+ <constraint firstItem="137" firstAttribute="top" secondItem="100" secondAttribute="bottom" constant="8" symbolic="YES" id="jDb-sm-pFt"/>
+ <constraint firstItem="100" firstAttribute="top" secondItem="6" secondAttribute="top" constant="12" symbolic="YES" id="nWn-mH-iEl"/>
+ <constraint firstAttribute="trailing" secondItem="208" secondAttribute="trailing" constant="20" symbolic="YES" id="xIc-XH-CzB"/>
+ </constraints>
+ </view>
+ <point key="canvasLocation" x="6" y="454"/>
+ </window>
+ <window title="Shared Secret" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="255" userLabel="SharedSecret">
+ <windowStyleMask key="styleMask" titled="YES"/>
+ <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
+ <rect key="contentRect" x="591" y="108" width="496" height="148"/>
+ <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
+ <value key="minSize" type="size" width="213" height="107"/>
+ <view key="contentView" id="254">
+ <rect key="frame" x="0.0" y="0.0" width="496" height="148"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="256">
+ <rect key="frame" x="96" y="81" width="380" height="22"/>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" alignment="left" drawsBackground="YES" id="100256">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ <connections>
+ <outlet property="delegate" destination="-2" id="283"/>
+ <outlet property="nextKeyView" destination="257" id="288"/>
+ </connections>
+ </textField>
+ <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="257" customClass="NSSecureTextField">
+ <rect key="frame" x="96" y="49" width="380" height="22"/>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" alignment="left" drawsBackground="YES" id="100257">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ <connections>
+ <outlet property="delegate" destination="-2" id="284"/>
+ <outlet property="nextKeyView" destination="256" id="289"/>
+ </connections>
+ </textField>
+ <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="258">
+ <rect key="frame" x="46" y="84" width="44" height="17"/>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Name:" id="100258">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="259">
+ <rect key="frame" x="24" y="52" width="66" height="17"/>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Password:" id="100259">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="260">
+ <rect key="frame" x="400" y="13" width="82" height="32"/>
+ <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100260">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ <string key="keyEquivalent" base64-UTF8="YES">
+DQ
+</string>
+ </buttonCell>
+ <connections>
+ <action selector="closeMyCustomSheet:" target="-2" id="279"/>
+ </connections>
+ </button>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="261">
+ <rect key="frame" x="318" y="13" width="82" height="32"/>
+ <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100261">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ <string key="keyEquivalent" base64-UTF8="YES">
+Gw
+</string>
+ </buttonCell>
+ <connections>
+ <action selector="closeMyCustomSheet:" target="-2" id="280"/>
+ </connections>
+ </button>
+ <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="262">
+ <rect key="frame" x="18" y="111" width="460" height="17"/>
+ <constraints>
+ <constraint firstAttribute="width" priority="499" constant="456" id="Mua-9c-7eO"/>
+ </constraints>
+ <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Enter a password if your DNS server requires authentication." id="100262">
+ <font key="font" metaFont="systemBold"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ </subviews>
+ <constraints>
+ <constraint firstAttribute="trailing" secondItem="256" secondAttribute="trailing" constant="20" symbolic="YES" id="3mf-gO-3d5"/>
+ <constraint firstAttribute="trailing" secondItem="262" secondAttribute="trailing" constant="20" symbolic="YES" id="7wb-gt-2py"/>
+ <constraint firstItem="261" firstAttribute="baseline" secondItem="260" secondAttribute="baseline" id="9Qx-ne-W5G"/>
+ <constraint firstItem="258" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="9jU-dY-JqX"/>
+ <constraint firstItem="260" firstAttribute="top" secondItem="257" secondAttribute="bottom" constant="8" symbolic="YES" id="Dt1-uv-H2r"/>
+ <constraint firstItem="262" firstAttribute="leading" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="El6-is-b6l"/>
+ <constraint firstItem="256" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="IAp-Sj-ojh"/>
+ <constraint firstItem="262" firstAttribute="top" secondItem="254" secondAttribute="top" constant="20" symbolic="YES" id="IKv-MA-MaG"/>
+ <constraint firstItem="260" firstAttribute="leading" secondItem="261" secondAttribute="trailing" constant="12" symbolic="YES" id="Jih-R5-3WX"/>
+ <constraint firstAttribute="trailing" secondItem="260" secondAttribute="trailing" constant="20" symbolic="YES" id="L7K-Si-lMS"/>
+ <constraint firstItem="256" firstAttribute="leading" secondItem="254" secondAttribute="leading" priority="499" constant="96" id="MGe-DK-IsJ"/>
+ <constraint firstItem="257" firstAttribute="leading" secondItem="256" secondAttribute="leading" id="XiH-SB-ew9"/>
+ <constraint firstItem="261" firstAttribute="width" secondItem="260" secondAttribute="width" id="ZBv-82-oHI"/>
+ <constraint firstItem="257" firstAttribute="leading" secondItem="254" secondAttribute="leading" priority="499" constant="96" id="ZSQ-Eu-kfv"/>
+ <constraint firstItem="257" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="awk-Ih-h6t"/>
+ <constraint firstAttribute="trailing" secondItem="257" secondAttribute="trailing" constant="20" symbolic="YES" id="b4B-N1-Kkw"/>
+ <constraint firstItem="256" firstAttribute="top" secondItem="262" secondAttribute="bottom" constant="8" symbolic="YES" id="bMU-Gr-KAT"/>
+ <constraint firstItem="259" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="djz-PT-u6u"/>
+ <constraint firstItem="259" firstAttribute="baseline" secondItem="257" secondAttribute="baseline" id="eqD-gu-QY7"/>
+ <constraint firstItem="256" firstAttribute="leading" secondItem="258" secondAttribute="trailing" constant="8" symbolic="YES" id="g6K-nY-Pnf"/>
+ <constraint firstAttribute="bottom" secondItem="260" secondAttribute="bottom" constant="20" symbolic="YES" id="qad-Pr-uFC"/>
+ <constraint firstItem="257" firstAttribute="top" secondItem="256" secondAttribute="bottom" constant="10" symbolic="YES" id="qyJ-gm-15K"/>
+ <constraint firstItem="257" firstAttribute="leading" secondItem="259" secondAttribute="trailing" constant="8" symbolic="YES" id="sAe-2s-bxV"/>
+ <constraint firstItem="258" firstAttribute="baseline" secondItem="256" secondAttribute="baseline" id="xZU-Nd-Q5f"/>
+ </constraints>
+ </view>
+ <point key="canvasLocation" x="148" y="69"/>
+ </window>
+ <window title="Add Browse Domains" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="333" userLabel="AddDomain">
+ <windowStyleMask key="styleMask" titled="YES"/>
+ <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
+ <rect key="contentRect" x="634" y="377" width="496" height="220"/>
+ <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
+ <value key="minSize" type="size" width="213" height="107"/>
+ <view key="contentView" id="334">
+ <rect key="frame" x="0.0" y="0.0" width="496" height="220"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="336">
+ <rect key="frame" x="18" y="183" width="460" height="17"/>
+ <constraints>
+ <constraint firstAttribute="width" priority="499" constant="456" id="qTJ-tL-p1s"/>
+ </constraints>
+ <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Choose a domain to add to your list of Bonjour browse domains." id="100336">
+ <font key="font" metaFont="systemBold"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <customView translatesAutoresizingMaskIntoConstraints="NO" id="200327" customClass="CNDomainBrowserView">
+ <rect key="frame" x="20" y="61" width="456" height="114"/>
+ <constraints>
+ <constraint firstAttribute="height" constant="114" id="ey8-36-A8G"/>
+ </constraints>
+ <userDefinedRuntimeAttributes>
+ <userDefinedRuntimeAttribute type="boolean" keyPath="registrationDomains" value="NO"/>
+ <userDefinedRuntimeAttribute type="boolean" keyPath="ignoreLocal" value="YES"/>
+ <userDefinedRuntimeAttribute type="boolean" keyPath="ignoreBTMM" value="NO"/>
+ <userDefinedRuntimeAttribute type="boolean" keyPath="browseRegistration" value="NO"/>
+ </userDefinedRuntimeAttributes>
+ </customView>
+ <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="340">
+ <rect key="frame" x="400" y="13" width="82" height="32"/>
+ <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100340">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ <string key="keyEquivalent" base64-UTF8="YES">
+DQ
+</string>
+ </buttonCell>
+ <connections>
+ <action selector="closeMyCustomSheet:" target="-2" id="365"/>
+ </connections>
+ </button>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="341">
+ <rect key="frame" x="318" y="13" width="82" height="32"/>
+ <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100341">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ <string key="keyEquivalent" base64-UTF8="YES">
+Gw
+</string>
+ </buttonCell>
+ <connections>
+ <action selector="closeMyCustomSheet:" target="-2" id="364"/>
+ </connections>
+ </button>
+ </subviews>
+ <constraints>
+ <constraint firstItem="341" firstAttribute="width" secondItem="340" secondAttribute="width" id="1kP-hH-4fg"/>
+ <constraint firstItem="336" firstAttribute="leading" secondItem="334" secondAttribute="leading" constant="20" symbolic="YES" id="6p2-FN-dgI"/>
+ <constraint firstItem="200327" firstAttribute="leading" secondItem="334" secondAttribute="leading" constant="20" symbolic="YES" id="BFf-ab-vji"/>
+ <constraint firstItem="341" firstAttribute="baseline" secondItem="340" secondAttribute="baseline" id="DdL-N2-sRf"/>
+ <constraint firstItem="336" firstAttribute="top" secondItem="334" secondAttribute="top" constant="20" symbolic="YES" id="Iei-fi-sMQ"/>
+ <constraint firstItem="340" firstAttribute="top" secondItem="200327" secondAttribute="bottom" constant="20" symbolic="YES" id="Ouj-CX-0R3"/>
+ <constraint firstAttribute="trailing" secondItem="200327" secondAttribute="trailing" constant="20" symbolic="YES" id="QWi-nn-fZb"/>
+ <constraint firstItem="200327" firstAttribute="top" secondItem="336" secondAttribute="bottom" constant="8" symbolic="YES" id="f1Y-2w-Xl7"/>
+ <constraint firstAttribute="trailing" secondItem="336" secondAttribute="trailing" constant="20" symbolic="YES" id="gOk-i6-e6u"/>
+ <constraint firstAttribute="trailing" secondItem="340" secondAttribute="trailing" constant="20" symbolic="YES" id="gvy-DL-dCw"/>
+ <constraint firstAttribute="bottom" secondItem="340" secondAttribute="bottom" constant="20" symbolic="YES" id="i1j-hc-gtt"/>
+ <constraint firstItem="340" firstAttribute="leading" secondItem="341" secondAttribute="trailing" constant="12" symbolic="YES" id="yRJ-0k-a3r"/>
+ </constraints>
+ </view>
+ <point key="canvasLocation" x="-27" y="-234"/>
+ </window>
+ <window title="Add Browse Domains" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="NFb-eI-atL" userLabel="AddDomainManual">
+ <windowStyleMask key="styleMask" titled="YES"/>
+ <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
+ <rect key="contentRect" x="634" y="377" width="496" height="133"/>
+ <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
+ <value key="minSize" type="size" width="213" height="107"/>
+ <view key="contentView" id="gUJ-3k-BQQ">
+ <rect key="frame" x="0.0" y="0.0" width="496" height="133"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="aoV-3v-A7q">
+ <rect key="frame" x="400" y="13" width="82" height="32"/>
+ <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="Jo3-6e-vxc">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ <string key="keyEquivalent" base64-UTF8="YES">
+DQ
+</string>
+ </buttonCell>
+ <connections>
+ <action selector="closeMyCustomSheet:" target="-2" id="hMi-BR-qQY"/>
+ </connections>
+ </button>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="a0y-0s-TTY">
+ <rect key="frame" x="318" y="13" width="82" height="32"/>
+ <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="qne-aW-QHl">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ <string key="keyEquivalent" base64-UTF8="YES">
+Gw
+</string>
+ </buttonCell>
+ <connections>
+ <action selector="closeMyCustomSheet:" target="-2" id="eUl-Y1-c5S"/>
+ </connections>
+ </button>
+ <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Sfp-nO-NP2">
+ <rect key="frame" x="36" y="52" width="54" height="17"/>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Domain:" id="b6L-KA-Dqu">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Myg-XJ-ngM">
+ <rect key="frame" x="18" y="79" width="460" height="34"/>
+ <constraints>
+ <constraint firstAttribute="width" priority="499" constant="456" id="nwj-Vn-nBx"/>
+ </constraints>
+ <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="The following domain will be added to your list of Bonjour browse domains." id="m5w-3d-gfR">
+ <font key="font" metaFont="systemBold"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="W2d-Us-Cpm">
+ <rect key="frame" x="96" y="49" width="380" height="22"/>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="kJz-0i-YUX">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ </subviews>
+ <constraints>
+ <constraint firstAttribute="trailing" secondItem="W2d-Us-Cpm" secondAttribute="trailing" constant="20" symbolic="YES" id="08z-5S-y1p"/>
+ <constraint firstAttribute="trailing" secondItem="Myg-XJ-ngM" secondAttribute="trailing" constant="20" symbolic="YES" id="2qd-6o-hRs"/>
+ <constraint firstAttribute="trailing" secondItem="aoV-3v-A7q" secondAttribute="trailing" constant="20" symbolic="YES" id="5WH-eg-Ibw"/>
+ <constraint firstItem="W2d-Us-Cpm" firstAttribute="leading" secondItem="gUJ-3k-BQQ" secondAttribute="leading" priority="499" constant="96" id="KBy-nt-u24"/>
+ <constraint firstItem="aoV-3v-A7q" firstAttribute="baseline" secondItem="a0y-0s-TTY" secondAttribute="baseline" id="L8X-K0-cNZ"/>
+ <constraint firstItem="W2d-Us-Cpm" firstAttribute="leading" secondItem="Sfp-nO-NP2" secondAttribute="trailing" constant="8" symbolic="YES" id="Pw7-gK-pJO"/>
+ <constraint firstItem="Myg-XJ-ngM" firstAttribute="top" secondItem="gUJ-3k-BQQ" secondAttribute="top" constant="20" symbolic="YES" id="Vkn-zN-QmY"/>
+ <constraint firstAttribute="bottom" secondItem="aoV-3v-A7q" secondAttribute="bottom" constant="20" symbolic="YES" id="aJb-Dk-Ofa"/>
+ <constraint firstItem="aoV-3v-A7q" firstAttribute="top" secondItem="W2d-Us-Cpm" secondAttribute="bottom" constant="8" symbolic="YES" id="bbw-LB-NG3"/>
+ <constraint firstItem="Myg-XJ-ngM" firstAttribute="leading" secondItem="gUJ-3k-BQQ" secondAttribute="leading" constant="20" symbolic="YES" id="cab-6m-9M7"/>
+ <constraint firstItem="W2d-Us-Cpm" firstAttribute="top" secondItem="Myg-XJ-ngM" secondAttribute="bottom" constant="8" symbolic="YES" id="ewM-hb-zj3"/>
+ <constraint firstItem="W2d-Us-Cpm" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="gUJ-3k-BQQ" secondAttribute="leading" constant="20" symbolic="YES" id="jsT-pp-iwi"/>
+ <constraint firstItem="Sfp-nO-NP2" firstAttribute="baseline" secondItem="W2d-Us-Cpm" secondAttribute="baseline" id="qPo-ba-jjr"/>
+ <constraint firstItem="aoV-3v-A7q" firstAttribute="leading" secondItem="a0y-0s-TTY" secondAttribute="trailing" constant="12" symbolic="YES" id="tzd-P2-c6b"/>
+ <constraint firstItem="Sfp-nO-NP2" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="gUJ-3k-BQQ" secondAttribute="leading" constant="20" symbolic="YES" id="vVs-34-dSS"/>
+ <constraint firstItem="aoV-3v-A7q" firstAttribute="width" secondItem="a0y-0s-TTY" secondAttribute="width" id="xg1-eb-4Pj"/>
+ </constraints>
+ </view>
+ <point key="canvasLocation" x="-27" y="-524"/>
+ </window>
+ <window title="Add Registration Domain" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="ail-If-2Xp" userLabel="SelectRegDomain">
+ <windowStyleMask key="styleMask" titled="YES"/>
+ <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
+ <rect key="contentRect" x="634" y="377" width="496" height="220"/>
+ <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
+ <value key="minSize" type="size" width="213" height="107"/>
+ <view key="contentView" id="W37-VK-yC5">
+ <rect key="frame" x="0.0" y="0.0" width="496" height="220"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="q4Y-tT-1h7">
+ <rect key="frame" x="18" y="183" width="460" height="17"/>
+ <constraints>
+ <constraint firstAttribute="width" priority="499" constant="456" id="zF0-CN-3xD"/>
+ </constraints>
+ <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Choose a domain to use as your Bonjour registration domain." id="EDB-Ul-M1P">
+ <font key="font" metaFont="systemBold"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <customView translatesAutoresizingMaskIntoConstraints="NO" id="agb-WV-smo" customClass="CNDomainBrowserView">
+ <rect key="frame" x="20" y="61" width="456" height="114"/>
+ <constraints>
+ <constraint firstAttribute="height" constant="114" id="3JN-68-aTf"/>
+ </constraints>
+ <userDefinedRuntimeAttributes>
+ <userDefinedRuntimeAttribute type="boolean" keyPath="registrationDomains" value="YES"/>
+ <userDefinedRuntimeAttribute type="boolean" keyPath="ignoreLocal" value="YES"/>
+ <userDefinedRuntimeAttribute type="boolean" keyPath="ignoreBTMM" value="NO"/>
+ <userDefinedRuntimeAttribute type="boolean" keyPath="browseRegistration" value="YES"/>
+ </userDefinedRuntimeAttributes>
+ </customView>
+ <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="8fZ-4V-xd6">
+ <rect key="frame" x="400" y="13" width="82" height="32"/>
+ <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="eLF-AD-BgY">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ <string key="keyEquivalent" base64-UTF8="YES">
+DQ
+</string>
+ </buttonCell>
+ <connections>
+ <action selector="closeMyCustomSheet:" target="-2" id="HFg-iF-1qy"/>
+ </connections>
+ </button>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="I6S-g0-R0G">
+ <rect key="frame" x="318" y="13" width="82" height="32"/>
+ <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="a1o-he-Kv7">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ <string key="keyEquivalent" base64-UTF8="YES">
+Gw
+</string>
+ </buttonCell>
+ <connections>
+ <action selector="closeMyCustomSheet:" target="-2" id="SQP-5g-qGG"/>
+ </connections>
+ </button>
+ </subviews>
+ <constraints>
+ <constraint firstItem="8fZ-4V-xd6" firstAttribute="top" secondItem="agb-WV-smo" secondAttribute="bottom" constant="20" symbolic="YES" id="4cD-Af-ApJ"/>
+ <constraint firstItem="q4Y-tT-1h7" firstAttribute="leading" secondItem="W37-VK-yC5" secondAttribute="leading" constant="20" symbolic="YES" id="8fj-II-NeF"/>
+ <constraint firstItem="q4Y-tT-1h7" firstAttribute="top" secondItem="W37-VK-yC5" secondAttribute="top" constant="20" symbolic="YES" id="Bq5-8Z-4eY"/>
+ <constraint firstItem="agb-WV-smo" firstAttribute="leading" secondItem="W37-VK-yC5" secondAttribute="leading" constant="20" symbolic="YES" id="Kex-pV-3tR"/>
+ <constraint firstAttribute="trailing" secondItem="q4Y-tT-1h7" secondAttribute="trailing" constant="20" symbolic="YES" id="Piu-PE-SEc"/>
+ <constraint firstItem="agb-WV-smo" firstAttribute="top" secondItem="q4Y-tT-1h7" secondAttribute="bottom" constant="8" symbolic="YES" id="Spl-BU-U7l"/>
+ <constraint firstItem="8fZ-4V-xd6" firstAttribute="width" secondItem="I6S-g0-R0G" secondAttribute="width" id="Xx2-3v-4H5"/>
+ <constraint firstItem="8fZ-4V-xd6" firstAttribute="leading" secondItem="I6S-g0-R0G" secondAttribute="trailing" constant="12" symbolic="YES" id="aly-0r-bvb"/>
+ <constraint firstAttribute="bottom" secondItem="8fZ-4V-xd6" secondAttribute="bottom" constant="20" symbolic="YES" id="eqT-TT-gxE"/>
+ <constraint firstItem="8fZ-4V-xd6" firstAttribute="baseline" secondItem="I6S-g0-R0G" secondAttribute="baseline" id="h1B-xs-zFp"/>
+ <constraint firstAttribute="trailing" secondItem="agb-WV-smo" secondAttribute="trailing" constant="20" symbolic="YES" id="xLH-br-4Uh"/>
+ <constraint firstAttribute="trailing" secondItem="8fZ-4V-xd6" secondAttribute="trailing" constant="20" symbolic="YES" id="xiF-Cr-13M"/>
+ </constraints>
+ </view>
+ <point key="canvasLocation" x="538" y="-234"/>
+ </window>
+ <window title="Add Registration Domain" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="he2-0K-CWy" userLabel="SelectRegDomainManual">
+ <windowStyleMask key="styleMask" titled="YES"/>
+ <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
+ <rect key="contentRect" x="634" y="377" width="496" height="133"/>
+ <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
+ <value key="minSize" type="size" width="213" height="107"/>
+ <view key="contentView" id="FYv-ly-yOd">
+ <rect key="frame" x="0.0" y="0.0" width="496" height="133"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="sau-gD-LVt">
+ <rect key="frame" x="400" y="13" width="82" height="32"/>
+ <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="jAh-nT-Qwg">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ <string key="keyEquivalent" base64-UTF8="YES">
+DQ
+</string>
+ </buttonCell>
+ <connections>
+ <action selector="closeMyCustomSheet:" target="-2" id="ySI-9p-3tZ"/>
+ </connections>
+ </button>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ypd-8h-xfJ">
+ <rect key="frame" x="318" y="13" width="82" height="32"/>
+ <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="Nd2-rR-DtX">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ <string key="keyEquivalent" base64-UTF8="YES">
+Gw
+</string>
+ </buttonCell>
+ <connections>
+ <action selector="closeMyCustomSheet:" target="-2" id="YM3-jW-TNM"/>
+ </connections>
+ </button>
+ <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="die-Uf-Bn9">
+ <rect key="frame" x="36" y="52" width="54" height="17"/>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Domain:" id="ZIy-WQ-OIZ">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="06e-WM-3MP">
+ <rect key="frame" x="18" y="79" width="460" height="34"/>
+ <constraints>
+ <constraint firstAttribute="width" priority="499" constant="456" id="ilh-EM-DG1"/>
+ </constraints>
+ <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="The following registration domain will be used by Bonjour to advertise beyond the local subnet." id="SLP-nX-Q2C">
+ <font key="font" metaFont="systemBold"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="OEh-fL-Ol6">
+ <rect key="frame" x="96" y="49" width="380" height="22"/>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="aIe-CQ-mQ3">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ </subviews>
+ <constraints>
+ <constraint firstItem="OEh-fL-Ol6" firstAttribute="leading" secondItem="FYv-ly-yOd" secondAttribute="leading" priority="499" constant="96" id="1Nc-CQ-lXd"/>
+ <constraint firstItem="06e-WM-3MP" firstAttribute="top" secondItem="FYv-ly-yOd" secondAttribute="top" constant="20" symbolic="YES" id="5wy-Ji-7tZ"/>
+ <constraint firstItem="OEh-fL-Ol6" firstAttribute="top" secondItem="06e-WM-3MP" secondAttribute="bottom" constant="8" symbolic="YES" id="7BD-rk-RTl"/>
+ <constraint firstItem="sau-gD-LVt" firstAttribute="leading" secondItem="Ypd-8h-xfJ" secondAttribute="trailing" constant="12" symbolic="YES" id="7oo-eg-nGA"/>
+ <constraint firstItem="die-Uf-Bn9" firstAttribute="baseline" secondItem="OEh-fL-Ol6" secondAttribute="baseline" id="DbC-UI-YFz"/>
+ <constraint firstItem="die-Uf-Bn9" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="FYv-ly-yOd" secondAttribute="leading" constant="20" symbolic="YES" id="Ip2-Q3-r3l"/>
+ <constraint firstAttribute="trailing" secondItem="sau-gD-LVt" secondAttribute="trailing" constant="20" symbolic="YES" id="Jce-ky-wTf"/>
+ <constraint firstItem="sau-gD-LVt" firstAttribute="width" secondItem="Ypd-8h-xfJ" secondAttribute="width" id="NkV-L2-e4p"/>
+ <constraint firstItem="sau-gD-LVt" firstAttribute="top" secondItem="OEh-fL-Ol6" secondAttribute="bottom" constant="8" symbolic="YES" id="Omq-c5-SZQ"/>
+ <constraint firstAttribute="trailing" secondItem="06e-WM-3MP" secondAttribute="trailing" constant="20" symbolic="YES" id="U0T-5s-Jip"/>
+ <constraint firstAttribute="bottom" secondItem="sau-gD-LVt" secondAttribute="bottom" constant="20" symbolic="YES" id="cWG-NL-TzC"/>
+ <constraint firstAttribute="trailing" secondItem="OEh-fL-Ol6" secondAttribute="trailing" constant="20" symbolic="YES" id="igv-0W-kuw"/>
+ <constraint firstItem="OEh-fL-Ol6" firstAttribute="leading" secondItem="die-Uf-Bn9" secondAttribute="trailing" constant="8" symbolic="YES" id="j71-MK-aiv"/>
+ <constraint firstItem="sau-gD-LVt" firstAttribute="baseline" secondItem="Ypd-8h-xfJ" secondAttribute="baseline" id="t9l-JC-Ab2"/>
+ <constraint firstItem="06e-WM-3MP" firstAttribute="leading" secondItem="FYv-ly-yOd" secondAttribute="leading" constant="20" symbolic="YES" id="wIW-Ja-ih6"/>
+ <constraint firstItem="OEh-fL-Ol6" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="FYv-ly-yOd" secondAttribute="leading" constant="20" symbolic="YES" id="wia-Av-Bte"/>
+ </constraints>
+ </view>
+ <point key="canvasLocation" x="538" y="-525"/>
+ </window>
+ </objects>
+ <resources>
+ <image name="NSAddTemplate" width="11" height="11"/>
+ <image name="NSRemoveTemplate" width="11" height="11"/>
+ </resources>
+</document>
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Base.lproj/DNSServiceDiscoveryPref.nib/keyedobjects.nib b/mDNSResponder/mDNSMacOSX/PreferencePane/Base.lproj/DNSServiceDiscoveryPref.nib/keyedobjects.nib
new file mode 100644
index 00000000..33cf8f83
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Base.lproj/DNSServiceDiscoveryPref.nib/keyedobjects.nib
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/BonjourPrefTool-Info.plist b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/BonjourPrefTool-Info.plist
new file mode 100644
index 00000000..3e9f22e6
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/BonjourPrefTool-Info.plist
@@ -0,0 +1,37 @@
+<?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>en</string>
+ <key>CFBundleDisplayName</key>
+ <string>BonjourPrefTool</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>XPC!</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>Copyright © 2017 Apple Inc. All rights reserved.</string>
+ <key>XPCService</key>
+ <dict>
+ <key>ServiceType</key>
+ <string>Application</string>
+ <key>_AllowedClients</key>
+ <array>
+ <string>identifier = com.apple.preference.bonjour.remoteservice and (anchor apple or (anchor apple generic and certificate leaf[field.1.2.840.113635.100.6.1.9]))</string>
+ </array>
+ <key>_RoleAccount</key>
+ <string>root</string>
+ </dict>
+</dict>
+</plist>
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/BonjourPrefTool.h b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/BonjourPrefTool.h
new file mode 100644
index 00000000..02d97711
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/BonjourPrefTool.h
@@ -0,0 +1,24 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import <Foundation/Foundation.h>
+#import "BonjourPrefToolProtocol.h"
+
+// This object implements the protocol which we have defined. It provides the actual behavior for the service.
+// It is 'exported' by the service to make it available to the process hosting the service over an NSXPCConnection.
+@interface BonjourPrefTool : NSObject <BonjourPrefToolProtocol>
+@end
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/BonjourPrefTool.m b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/BonjourPrefTool.m
new file mode 100644
index 00000000..c0d7bb9e
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/BonjourPrefTool.m
@@ -0,0 +1,158 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import "BonjourPrefTool.h"
+#import "BonjourSCStore.h"
+#import <Security/Security.h>
+#import <dns_sd.h>
+
+#define DYNDNS_KEYCHAIN_DESCRIPTION "Dynamic DNS Key"
+
+#pragma mark - Keychain Funcs
+
+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(NSDictionary * secretDictionary)
+// Create a new entry in system keychain, or replace existing
+{
+ CFStringRef keyNameString;
+ CFStringRef domainString;
+ CFStringRef secretString;
+ SecKeychainItemRef item = NULL;
+ int result = 0;
+ char keyname[kDNSServiceMaxDomainName];
+ char domain[kDNSServiceMaxDomainName];
+ char secret[kDNSServiceMaxDomainName];
+
+ keyNameString = (__bridge CFStringRef)[secretDictionary objectForKey:(NSString *)SC_DYNDNS_KEYNAME_KEY];
+ require(keyNameString != NULL, exit);
+
+ domainString = (__bridge CFStringRef)[secretDictionary objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
+ require(domainString != NULL, exit);
+
+ secretString = (__bridge CFStringRef)[secretDictionary objectForKey:(NSString *)SC_DYNDNS_SECRET_KEY];
+ require(secretString != NULL, exit);
+
+ 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);
+ }
+
+exit:
+ return result;
+}
+
+
+@implementation BonjourPrefTool
+
+- (void) setKeychainEntry:(NSDictionary *_Nonnull)secretDictionary withStatus:(void (^ _Nonnull)(OSStatus))status
+{
+ OSStatus result;
+
+ result = SetKeychainEntry (secretDictionary);
+// NSLog(@"setKeychainEntry: %@ result: %d", secretDictionary, result);
+
+ status (result);
+}
+
+@end
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/BonjourPrefToolProtocol.h b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/BonjourPrefToolProtocol.h
new file mode 100644
index 00000000..e82bfdf6
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/BonjourPrefToolProtocol.h
@@ -0,0 +1,27 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+// The protocol that this service will vend as its API. This header file will
+// also need to be visible to the process hosting the service.
+@protocol BonjourPrefToolProtocol
+
+- (void) setKeychainEntry:(NSDictionary *_Nonnull)secretDictionary withStatus:(void (^ _Nonnull)(OSStatus))status;
+
+@end
+
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/entitlements.plist b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/entitlements.plist
new file mode 100644
index 00000000..a3088cce
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/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.private.xpc.role-account</key>
+ <true/>
+</dict>
+</plist>
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/main.m b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/main.m
new file mode 100644
index 00000000..3ed65fc5
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/BonjourPrefTool/main.m
@@ -0,0 +1,62 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import <Foundation/Foundation.h>
+#import "BonjourPrefTool.h"
+
+@interface ServiceDelegate : NSObject <NSXPCListenerDelegate>
+@end
+
+@implementation ServiceDelegate
+
+- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {
+ // This method is where the NSXPCListener configures, accepts, and resumes a new incoming NSXPCConnection.
+ (void)listener; // Unused
+
+ // Configure the connection.
+ // First, set the interface that the exported object implements.
+ newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(BonjourPrefToolProtocol)];
+
+ // Next, set the object that the connection exports. All messages sent on the connection to this service will be sent to the exported object to handle. The connection retains the exported object.
+ BonjourPrefTool *exportedObject = [BonjourPrefTool new];
+ newConnection.exportedObject = exportedObject;
+
+ // Resuming the connection allows the system to deliver more incoming messages.
+ [newConnection resume];
+
+ // Returning YES from this method tells the system that you have accepted this connection. If you want to reject the connection for some reason, call -invalidate on the connection and return NO.
+ return YES;
+}
+
+@end
+
+int main(int argc, const char *argv[])
+{
+ (void)argc; // Unused
+ (void)argv; // Unused
+
+ // Create the delegate for the service.
+ ServiceDelegate *delegate = [ServiceDelegate new];
+
+ // Set up the one NSXPCListener for this service. It will handle all incoming connections.
+ NSXPCListener *listener = [NSXPCListener serviceListener];
+ listener.delegate = delegate;
+
+ // Resuming the serviceListener starts this service. This method does not return.
+ [listener resume];
+ return 0;
+}
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c b/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c
deleted file mode 100644
index 43da5025..00000000
--- a/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- 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; CFRelease(rightInfo));
-
- 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; CFRelease(rightInfo));
-
- 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
deleted file mode 100644
index 49da93d0..00000000
--- a/mDNSResponder/mDNSMacOSX/PreferencePane/ConfigurationAuthority.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- 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/DNSServiceDiscoveryPref.h b/mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.h
index f0586591..36bfee81 100644
--- a/mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.h
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.h
@@ -41,70 +41,62 @@
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;
-
+@class CNBonjourDomainView;
+@class CNDomainBrowserView;
@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;
+ IBOutlet NSTextField *hostName;
+ IBOutlet NSTextField *sharedSecretName;
+ IBOutlet NSSecureTextField *sharedSecretValue;
+ IBOutlet NSTextField *browseDomainTextField;
+ IBOutlet NSTextField *regDomainTextField;
+ IBOutlet CNBonjourDomainView *regDomainView;
+ IBOutlet NSButton *wideAreaCheckBox;
+ IBOutlet NSButton *hostNameSharedSecretButton;
+ IBOutlet NSButton *registrationSelectButton;
+ IBOutlet NSButton *registrationSharedSecretButton;
+ IBOutlet NSButton *applyButton;
+ IBOutlet NSButton *revertButton;
+ IBOutlet NSWindow *sharedSecretWindow;
+ IBOutlet NSWindow *addBrowseDomainWindow;
+ IBOutlet NSWindow *addBrowseDomainManualWindow;
+ IBOutlet NSWindow *selectRegistrationDomainWindow;
+ IBOutlet NSWindow *selectRegistrationDomainManualWindow;
+ IBOutlet NSButton *addBrowseDomainButton;
+ IBOutlet NSButton *removeBrowseDomainButton;
+ IBOutlet NSButton *secretOKButton;
+ IBOutlet NSButton *secretCancelButton;
+ IBOutlet NSImageView *statusImageView;
+ IBOutlet NSTabView *tabView;
+ IBOutlet NSTableView *browseDomainList;
+ IBOutlet CNDomainBrowserView *bonjourBrowserView;
+ IBOutlet CNDomainBrowserView *registrationBrowserView;
+ IBOutlet SFAuthorizationView *comboAuthButton;
+
+ NSWindow *mainWindow;
+ NSString *currentHostName;
+ NSString *currentRegDomain;
+ NSArray *currentBrowseDomainsArray;
+ NSMutableArray *browseDomainsArray;
+ NSString *defaultRegDomain;
+
+ NSString *hostNameSharedSecretName;
+ NSString *hostNameSharedSecretValue;
+ NSString *regSharedSecretName;
+ NSString *regSharedSecretValue;
+ BOOL currentWideAreaState;
+ BOOL prefsNeedUpdating;
+ BOOL browseDomainListEnabled;
+ NSImage *successImage;
+ NSImage *inprogressImage;
+ NSImage *failureImage;
+
+ NSMutableArray *registrationDataSource;
}
-(IBAction)applyClicked : (id)sender;
@@ -114,29 +106,21 @@ typedef struct MyDNSServiceState {
-(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;
@@ -154,7 +138,7 @@ typedef struct MyDNSServiceState {
-(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;
+-(NSDictionary *)dictionaryForSharedSecret : (NSString *)secret domain : (NSString *)domainName key : (NSString *)keyName;
-(BOOL)domainAlreadyInList : (NSString *)domainString;
-(NSString *)trimCharactersFromDomain : (NSString *)domain;
@@ -163,8 +147,6 @@ typedef struct MyDNSServiceState {
-(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
index ba5f64bf..f58f3013 100644
--- a/mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m
@@ -42,15 +42,46 @@
*/
#import "DNSServiceDiscoveryPref.h"
-#import "ConfigurationAuthority.h"
-#import "PrivilegedOperations.h"
-#import <unistd.h>
+#import "CNDomainBrowserView.h"
+#import "BonjourSCStore.h"
+#import "BonjourPrefTool.h"
+#import <Foundation/NSXPCConnection_Private.h>
#include "../../Clients/ClientCommon.h"
-#ifndef NSINTEGER_DEFINED
-#define NSInteger int
+#pragma mark - BonjourPrefTool
+
+static OSStatus
+DNSPrefTool_SetKeychainEntry(NSDictionary * secretDictionary)
+{
+ __block OSStatus result;
+ BonjourPrefTool * prefTool;
+
+ NSXPCConnection * _connectionToTool = [[NSXPCConnection alloc] initWithServiceName:@"com.apple.preference.bonjour.tool"];
+ _connectionToTool.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(BonjourPrefToolProtocol)];
+ [_connectionToTool resume];
+
+#if 0
+ prefTool = [_connectionToTool remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
+ NSLog( @"Cannot connect to BonjourPrefTool: %@.", error);
+ result = error.code;
+ }];
+#else
+ prefTool = [_connectionToTool synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
+ NSLog( @"Cannot connect to BonjourPrefTool: %@.", error);
+ result = error.code;
+ }];
#endif
+ [prefTool setKeychainEntry: secretDictionary withStatus: ^(OSStatus status){
+ result = status;
+ }];
+
+ [_connectionToTool invalidate];
+
+ return (result);
+}
+
+#pragma mark -
@implementation DNSServiceDiscoveryPref
@@ -75,162 +106,13 @@ static void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void
{
(void)store; // Unused
(void)changedKeys; // Unused
- DNSServiceDiscoveryPref * me = (DNSServiceDiscoveryPref *)context;
+ DNSServiceDiscoveryPref * me = (__bridge 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;
- 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];
- } 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];
@@ -242,7 +124,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
- (void)watchForPreferenceChanges
{
- SCDynamicStoreContext context = { 0, self, NULL, NULL, NULL };
+ SCDynamicStoreContext context = { 0, (__bridge void * _Nullable)(self), NULL, NULL, NULL };
SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("watchForPreferenceChanges"), NetworkChanged, &context);
CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFRunLoopSourceRef rls;
@@ -274,12 +156,11 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
assert(store != NULL);
- NSDictionary *dynamicDNS = (NSDictionary *)SCDynamicStoreCopyValue(store, SC_DYNDNS_STATE_KEY);
+ NSDictionary *dynamicDNS = (NSDictionary *)CFBridgingRelease(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);
@@ -287,53 +168,37 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
}
-- (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];
+ if (currentRegDomain) currentRegDomain = nil;
+ if (currentBrowseDomainsArray) currentBrowseDomainsArray = nil;
+ if (currentHostName) currentHostName = nil;
SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("com.apple.preference.bonjour"), NULL, NULL);
- origDict = (NSDictionary *)SCDynamicStoreCopyValue(store, SC_DYNDNS_SETUP_KEY);
+ origDict = (NSDictionary *)CFBridgingRelease(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:@""];
+ currentRegDomain = @"";
currentWideAreaState = NO;
}
- currentBrowseDomainsArray = [[origDict objectForKey:(NSString *)SC_DYNDNS_BROWSEDOMAINS_KEY] retain];
+ currentBrowseDomainsArray = [origDict objectForKey:(NSString *)SC_DYNDNS_BROWSEDOMAINS_KEY];
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:@""];
+ currentHostName = @"";
}
- if (origDict) CFRelease((CFDictionaryRef)origDict);
if (store) CFRelease(store);
}
@@ -344,27 +209,14 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
}
-- (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];
+ NSWindow * window = (([NSEvent modifierFlags] & NSAlternateKeyMask) == NSAlternateKeyMask) ? addBrowseDomainManualWindow : addBrowseDomainWindow;
+ [browseDomainTextField setStringValue: [NSString string]];
- [NSApp beginSheet:addBrowseDomainWindow modalForWindow:mainWindow modalDelegate:self
- didEndSelector:@selector(addBrowseDomainSheetDidEnd:returnCode:contextInfo:) contextInfo:sender];
+ [self disableControls];
+ [NSApp beginSheet:window modalForWindow:mainWindow modalDelegate:self
+ didEndSelector:@selector(addBrowseDomainSheetDidEnd:returnCode:contextInfo:) contextInfo:(__bridge void * _Null_unspecified)(sender)];
[browseDomainList deselectAll:sender];
[self updateApplyButtonState];
@@ -385,15 +237,14 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
{
NSTableView *tableView = sender;
NSMutableDictionary *browseDomainDict;
- int value;
+ NSInteger 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];
+ [browseDomainDict setObject:[NSNumber numberWithInt:(!value)] forKey:(NSString *)SC_DYNDNS_ENABLED_KEY];
[browseDomainsArray replaceObjectAtIndex:[tableView clickedRow] withObject:browseDomainDict];
[tableView reloadData];
[self updateApplyButtonState];
- [browseDomainDict release];
}
@@ -431,7 +282,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
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];
+ value = [browseDomainDict objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
}
}
}
@@ -449,7 +300,6 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
}
if (browseDomainsArray) {
- [browseDomainsArray release];
browseDomainsArray = nil;
}
@@ -458,9 +308,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
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];
+ [BonjourSCStore setObject: browseDomainsArray forKey: (NSString *)SC_DYNDNS_BROWSEDOMAINS_KEY];
currentBrowseDomainsArray = [browseDomainsArray copy];
}
}
@@ -470,11 +318,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
[browseDomainList reloadData];
if (currentRegDomain && ([currentRegDomain length] > 0)) {
- [regDomainsComboBox setStringValue:currentRegDomain];
- [registrationDataSource removeObject:currentRegDomain];
- [registrationDataSource addObject:currentRegDomain];
- [registrationDataSource sortUsingFunction:MyArrayCompareFunction context:nil];
- [regDomainsComboBox reloadData];
+ regDomainView.domain = currentRegDomain;
}
if (currentWideAreaState) {
@@ -484,12 +328,10 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
}
if (hostNameSharedSecretValue) {
- [hostNameSharedSecretValue release];
hostNameSharedSecretValue = nil;
}
if (regSharedSecretValue) {
- [regSharedSecretValue release];
regSharedSecretValue = nil;
}
@@ -502,11 +344,8 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
- (void)awakeFromNib
-{
- OSStatus err;
-
+{
prefsNeedUpdating = NO;
- toolInstalled = NO;
browseDomainListEnabled = NO;
defaultRegDomain = nil;
currentRegDomain = nil;
@@ -515,35 +354,40 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
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); }
}
+- (void)willSelect
+{
+ [super willSelect];
+ [bonjourBrowserView startBrowse];
+ [registrationBrowserView startBrowse];
+
+}
+
+- (void)willUnselect
+{
+ [super willUnselect];
+ [bonjourBrowserView stopBrowse];
+ [registrationBrowserView stopBrowse];
+}
- (IBAction)closeMyCustomSheet:(id)sender
{
- BOOL result = [sender isEqualTo:browseOKButton] || [sender isEqualTo:secretOKButton];
+ BOOL result = [sender tag];
if (result) [NSApp endSheet:[sender window] returnCode:NSOKButton];
else [NSApp endSheet:[sender window] returnCode:NSCancelButton];
@@ -552,7 +396,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
- (void)sharedSecretSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
{
- NSButton * button = (NSButton *)contextInfo;
+ NSButton * button = (__bridge NSButton *)contextInfo;
[sheet orderOut:self];
[self enableControls];
@@ -587,7 +431,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
- (NSString *)trimCharactersFromDomain:(NSString *)domain
{
- NSMutableCharacterSet * trimSet = [[[NSCharacterSet whitespaceCharacterSet] mutableCopy] autorelease];
+ NSMutableCharacterSet * trimSet = [NSMutableCharacterSet whitespaceCharacterSet];
[trimSet formUnionWithCharacterSet:[NSCharacterSet punctuationCharacterSet]];
return [domain stringByTrimmingCharactersInSet:trimSet];
}
@@ -600,15 +444,16 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
[self enableControls];
if (returnCode == NSOKButton) {
- NSString * newBrowseDomainString = [self trimCharactersFromDomain:[browseDomainsComboBox stringValue]];
+ NSString * newBrowseDomainString;
+ if(sheet == addBrowseDomainManualWindow) newBrowseDomainString = [self trimCharactersFromDomain:[browseDomainTextField stringValue]];
+ else newBrowseDomainString = [self trimCharactersFromDomain:bonjourBrowserView.selectedDNSDomain];
NSMutableDictionary *newBrowseDomainDict;
-
if (browseDomainsArray == nil) browseDomainsArray = [[NSMutableArray alloc] initWithCapacity:0];
if ([self domainAlreadyInList:newBrowseDomainString] == NO) {
- newBrowseDomainDict = [[[NSMutableDictionary alloc] initWithCapacity:2] autorelease];
+ newBrowseDomainDict = [[NSMutableDictionary alloc] initWithCapacity:2];
[newBrowseDomainDict setObject:newBrowseDomainString forKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
- [newBrowseDomainDict setObject:[[[NSNumber alloc] initWithBool:YES] autorelease] forKey:(NSString *)SC_DYNDNS_ENABLED_KEY];
+ [newBrowseDomainDict setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)SC_DYNDNS_ENABLED_KEY];
[browseDomainsArray addObject:newBrowseDomainDict];
[browseDomainsArray sortUsingFunction:MyDomainArrayCompareFunction context:nil];
@@ -618,12 +463,10 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
}
}
-
-(void)validateTextFields
{
[hostName validateEditing];
- [browseDomainsComboBox validateEditing];
- [regDomainsComboBox validateEditing];
+ [browseDomainTextField validateEditing];
}
@@ -650,11 +493,11 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
} else {
if (regSharedSecretValue) {
[sharedSecretValue setStringValue:regSharedSecretValue];
- } else if ((keyName = [self sharedSecretKeyName:[regDomainsComboBox stringValue]]) != NULL) {
+ } else if ((keyName = [self sharedSecretKeyName:regDomainView.domain]) != NULL) {
[sharedSecretName setStringValue:keyName];
[sharedSecretValue setStringValue:@"****************"];
} else {
- [sharedSecretName setStringValue:[regDomainsComboBox stringValue]];
+ [sharedSecretName setStringValue:regDomainView.domain];
[sharedSecretValue setStringValue:@""];
}
}
@@ -665,9 +508,36 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
else [sharedSecretWindow makeFirstResponder:sharedSecretName];
[NSApp beginSheet:sharedSecretWindow modalForWindow:mainWindow modalDelegate:self
- didEndSelector:@selector(sharedSecretSheetDidEnd:returnCode:contextInfo:) contextInfo:sender];
+ didEndSelector:@selector(sharedSecretSheetDidEnd:returnCode:contextInfo:) contextInfo:(__bridge void * _Null_unspecified)(sender)];
+}
+
+
+- (IBAction)selectWideAreaDomainButtonPressed:(id)sender
+{
+ NSWindow * window = (([NSEvent modifierFlags] & NSAlternateKeyMask) == NSAlternateKeyMask) ? selectRegistrationDomainManualWindow : selectRegistrationDomainWindow;
+ regDomainTextField.stringValue = regDomainView.domain;
+
+ [self disableControls];
+ [NSApp beginSheet:window modalForWindow:mainWindow modalDelegate:self
+ didEndSelector:@selector(selectWideAreaDomainSheetDidEnd:returnCode:contextInfo:) contextInfo:(__bridge void * _Null_unspecified)(sender)];
+
+ [self updateApplyButtonState];
}
+- (void)selectWideAreaDomainSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
+{
+ (void)contextInfo; // Unused
+ [sheet orderOut:self];
+ [self enableControls];
+
+ if (returnCode == NSOKButton) {
+ NSString * newRegDomainString;
+ if(sheet == selectRegistrationDomainManualWindow) newRegDomainString = [self trimCharactersFromDomain:[regDomainTextField stringValue]];
+ else newRegDomainString = [self trimCharactersFromDomain:registrationBrowserView.selectedDNSDomain];
+ regDomainView.domain = newRegDomainString;
+ [self updateApplyButtonState];
+ }
+}
- (IBAction)wideAreaCheckBoxChanged:(id)sender
{
@@ -677,10 +547,11 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
}
+
- (void)updateApplyButtonState
{
NSString *hostNameString = [hostName stringValue];
- NSString *regDomainString = [regDomainsComboBox stringValue];
+ NSString *regDomainString = regDomainView.domain;
if ((currentHostName && ([hostNameString compare:currentHostName] != NSOrderedSame)) ||
(currentRegDomain && ([regDomainString compare:currentRegDomain] != NSOrderedSame) && ([wideAreaCheckBox state])) ||
(currentHostName == nil && ([hostNameString length]) > 0) ||
@@ -697,7 +568,6 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
}
-
- (void)controlTextDidChange:(NSNotification *)notification
{
(void)notification; // Unused
@@ -705,69 +575,18 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
}
-
-- (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;
@@ -788,9 +607,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
- (void)setDefaultRegDomain:(NSString *)domain
{
- [defaultRegDomain release];
defaultRegDomain = domain;
- [defaultRegDomain retain];
}
@@ -800,13 +617,12 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
mainWindow = [[self mainView] window];
}
-
- (void)mainViewDidLoad
-{
+{
[comboAuthButton setString:"system.preferences"];
[comboAuthButton setDelegate:self];
- [comboAuthButton updateStatus:nil];
[comboAuthButton setAutoupdate:YES];
+ [super mainViewDidLoad];
}
@@ -821,12 +637,9 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
- (void)applyCurrentState
{
[self validateTextFields];
-
- if (toolInstalled == YES) {
- [self savePreferences];
- [self disableApplyButton];
- [mainWindow makeFirstResponder:nil];
- }
+ [self savePreferences];
+ [self disableApplyButton];
+ [mainWindow makeFirstResponder:nil];
}
@@ -849,7 +662,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
- (void)toggleWideAreaBonjour:(BOOL)state
{
[wideAreaCheckBox setState:state];
- [regDomainsComboBox setEnabled:state];
+ [registrationSelectButton setEnabled:state];
[registrationSharedSecretButton setEnabled:state];
}
@@ -871,7 +684,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
- (void)savePanelWillClose:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
{
(void)sheet; // Unused
- DNSServiceDiscoveryPref * me = (DNSServiceDiscoveryPref *)contextInfo;
+ DNSServiceDiscoveryPref * me = (__bridge DNSServiceDiscoveryPref *)contextInfo;
if (returnCode == NSAlertDefaultReturn) {
[me applyCurrentState];
@@ -942,7 +755,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
}
CFRelease(itemRef);
}
- return [keyName autorelease];
+ return keyName;
}
@@ -957,7 +770,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
ptr = (char *)GetNextLabel(ptr, text);
domainName = [[NSString alloc] initWithUTF8String:(const char *)ptr];
}
- return ([domainName autorelease]);
+ return (domainName);
}
@@ -967,11 +780,11 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
NSMutableDictionary *domainDict = nil;
if (domainName && [domainName length] > 0) {
- domainDict= [[[NSMutableDictionary alloc] initWithCapacity:2] autorelease];
+ domainDict= [NSMutableDictionary dictionaryWithCapacity:2];
[domainDict setObject:domainName forKey:(NSString *)SC_DYNDNS_DOMAIN_KEY];
- [domainDict setObject:[[[NSNumber alloc] initWithBool:enabled] autorelease] forKey:(NSString *)SC_DYNDNS_ENABLED_KEY];
+ [domainDict setObject:[NSNumber numberWithBool:enabled] forKey:(NSString *)SC_DYNDNS_ENABLED_KEY];
}
- domainsArray = [[[NSMutableArray alloc] initWithCapacity:1] autorelease];
+ domainsArray = [NSMutableArray arrayWithCapacity:1];
if (domainDict) [domainsArray addObject:domainDict];
return [NSArchiver archivedDataWithRootObject:domainsArray];
}
@@ -983,26 +796,25 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
}
-- (NSData *)dataForSharedSecret:(NSString *)secret domain:(NSString *)domainName key:(NSString *)keyName
+- (NSDictionary *)dictionaryForSharedSecret:(NSString *)secret domain:(NSString *)domainName key:(NSString *)keyName
{
- NSMutableDictionary *sharedSecretDict = [[[NSMutableDictionary alloc] initWithCapacity:3] autorelease];
+ NSMutableDictionary *sharedSecretDict = [NSMutableDictionary dictionaryWithCapacity:3];
[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];
+ return sharedSecretDict;
}
-(void)savePreferences
{
NSString *hostNameString = [hostName stringValue];
- NSString *regDomainString = [regDomainsComboBox stringValue];
+ NSString *regDomainString = regDomainView.domain;
NSString *tempHostNameSharedSecretName = hostNameSharedSecretName;
NSString *tempRegSharedSecretName = regSharedSecretName;
- NSData *browseDomainData = nil;
BOOL regSecretWasSet = NO;
BOOL hostSecretWasSet = NO;
- OSStatus err = noErr;
+ BOOL updateHostname = NO;
hostNameString = [self trimCharactersFromDomain:hostNameString];
regDomainString = [self trimCharactersFromDomain:regDomainString];
@@ -1010,7 +822,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
tempRegSharedSecretName = [self trimCharactersFromDomain:tempRegSharedSecretName];
[hostName setStringValue:hostNameString];
- [regDomainsComboBox setStringValue:regDomainString];
+ regDomainView.domain = regDomainString;
// Convert Shared Secret account names to lowercase.
tempHostNameSharedSecretName = [tempHostNameSharedSecretName lowercaseString];
@@ -1018,46 +830,48 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
// Save hostname shared secret.
if ([hostNameSharedSecretName length] > 0 && ([hostNameSharedSecretValue length] > 0)) {
- SetKeyForDomain((CFDataRef)[self dataForSharedSecret:hostNameSharedSecretValue domain:hostNameString key:tempHostNameSharedSecretName]);
- [hostNameSharedSecretValue release];
+ DNSPrefTool_SetKeychainEntry([self dictionaryForSharedSecret:hostNameSharedSecretValue domain:hostNameString key:tempHostNameSharedSecretName]);
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];
+ DNSPrefTool_SetKeychainEntry([self dictionaryForSharedSecret:regSharedSecretValue domain:regDomainString key:tempRegSharedSecretName]);
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];
+ updateHostname = YES;
} 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]);
+ currentHostName = @"";
+ updateHostname = YES;
+ }
+
+ if (updateHostname) {
+ [BonjourSCStore setObject: currentHostName.length ? @[@{
+ (NSString *)SC_DYNDNS_DOMAIN_KEY : currentHostName,
+ (NSString *)SC_DYNDNS_ENABLED_KEY : @YES
+ }] : nil
+ forKey: (NSString *)SC_DYNDNS_HOSTNAMES_KEY];
}
// 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);
+ [BonjourSCStore setObject: browseDomainsArray forKey: (NSString *)SC_DYNDNS_BROWSEDOMAINS_KEY];
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);
+ [BonjourSCStore setObject: @[@{
+ (NSString *)SC_DYNDNS_DOMAIN_KEY : regDomainString,
+ (NSString *)SC_DYNDNS_ENABLED_KEY : [wideAreaCheckBox state] ? @YES : @NO
+ }]
+ forKey: (NSString *)SC_DYNDNS_REGDOMAINS_KEY];
currentRegDomain = [regDomainString copy];
if ([currentRegDomain length] > 0) {
@@ -1065,16 +879,25 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
[registrationDataSource removeObject:regDomainString];
[registrationDataSource addObject:currentRegDomain];
[registrationDataSource sortUsingFunction:MyArrayCompareFunction context:nil];
- [regDomainsComboBox reloadData];
+ // [regDomainsComboBox reloadData];
} else {
currentWideAreaState = NO;
[self toggleWideAreaBonjour:NO];
- if (defaultRegDomain != nil) [regDomainsComboBox setStringValue:defaultRegDomain];
+ if (defaultRegDomain != nil) regDomainView.domain = 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]);
+ [BonjourSCStore setObject: @[@{
+ (NSString *)SC_DYNDNS_DOMAIN_KEY : @"",
+ (NSString *)SC_DYNDNS_ENABLED_KEY : @NO
+ }]
+ forKey: (NSString *)SC_DYNDNS_REGDOMAINS_KEY];
+ if ([currentRegDomain length] > 0) {
+ [BonjourSCStore setObject: @[@{
+ (NSString *)SC_DYNDNS_DOMAIN_KEY : currentRegDomain,
+ (NSString *)SC_DYNDNS_ENABLED_KEY : currentWideAreaState ? @YES : @NO
+ }]
+ forKey: (NSString *)SC_DYNDNS_REGDOMAINS_KEY];
+ }
}
}
@@ -1095,7 +918,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
self,
@selector( savePanelWillClose:returnCode:contextInfo: ),
NULL,
- (void *) self, // sender,
+ (__bridge void *) self, // sender,
@"" );
return NSUnselectLater;
}
@@ -1109,11 +932,10 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
{
[hostName setEnabled:NO];
[hostNameSharedSecretButton setEnabled:NO];
- [browseDomainsComboBox setEnabled:NO];
[applyButton setEnabled:NO];
[revertButton setEnabled:NO];
[wideAreaCheckBox setEnabled:NO];
- [regDomainsComboBox setEnabled:NO];
+ [registrationSelectButton setEnabled: NO];
[registrationSharedSecretButton setEnabled:NO];
[statusImageView setEnabled:NO];
@@ -1138,8 +960,8 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
{
[hostName setEnabled:YES];
[hostNameSharedSecretButton setEnabled:YES];
- [browseDomainsComboBox setEnabled:YES];
[wideAreaCheckBox setEnabled:YES];
+ [registrationSelectButton setEnabled: YES];
[registrationSharedSecretButton setEnabled:YES];
[self toggleWideAreaBonjour:[wideAreaCheckBox state]];
[statusImageView setEnabled:YES];
@@ -1157,14 +979,14 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query)
- (void)authorizationViewDidAuthorize:(SFAuthorizationView *)view
{
- (void)view; // Unused
+ (void)view; // unused
[self enableControls];
}
- (void)authorizationViewDidDeauthorize:(SFAuthorizationView *)view
{
- (void)view; // Unused
+ (void)view; // unused
[self disableControls];
}
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/classes.nib b/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/classes.nib
deleted file mode 100644
index 58c1f3e5..00000000
--- a/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/classes.nib
+++ /dev/null
@@ -1,59 +0,0 @@
-{
- 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
deleted file mode 100644
index e8dbd926..00000000
--- a/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/info.nib
+++ /dev/null
@@ -1,18 +0,0 @@
-<?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
deleted file mode 100644
index eec01ee4..00000000
--- a/mDNSResponder/mDNSMacOSX/PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib/keyedobjects.nib
+++ /dev/null
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/Info-PreferencePane.plist b/mDNSResponder/mDNSMacOSX/PreferencePane/Info-PreferencePane.plist
index e5cdb9f2..134a7647 100644
--- a/mDNSResponder/mDNSMacOSX/PreferencePane/Info-PreferencePane.plist
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/Info-PreferencePane.plist
@@ -1,5 +1,5 @@
<?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">
+<!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>
@@ -32,5 +32,7 @@
<string>Bonjour</string>
<key>NSPrincipalClass</key>
<string>DNSServiceDiscoveryPref</string>
+ <key>NSPrefPaneRemoteViewClass</key>
+ <string>BonjourPrefRemoteViewService</string>
</dict>
</plist>
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.c b/mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.c
deleted file mode 100644
index a279c983..00000000
--- a/mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.c
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- File: PrivilegedOperations.c
-
- Abstract: Interface to "ddnswriteconfig" setuid root tool.
-
- Copyright: (c) Copyright 2005-2015 Apple Inc. All rights reserved.
-
- Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple 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 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 <spawn.h>
-#include <sys/wait.h>
-#include <AssertMacros.h>
-#include <Security/Security.h>
-
-extern char **environ;
-Boolean gToolApproved = false;
-
-static pid_t execTool(const char *args[])
-{
- pid_t child;
-
- int err = posix_spawn(&child, args[0], NULL, NULL, (char *const *)args, environ);
- if (err)
- {
- printf("exec of %s failed; err = %d\n", args[0], err);
- return -1;
- }
- 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 = 0;
- 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);
- CFURLGetFileSystemRepresentation(bundleURL, false, (UInt8*) toolInstallerPath, sizeof toolInstallerPath);
- CFRelease(bundleURL);
-
- if (strlcat(toolSourcePath, "/Contents/Resources/" kToolName, sizeof toolSourcePath ) >= sizeof toolSourcePath ) return(-1);
- 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());
- snprintf(fileNum, sizeof(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 = 0;
- 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
deleted file mode 100644
index 91a60daf..00000000
--- a/mDNSResponder/mDNSMacOSX/PreferencePane/PrivilegedOperations.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- 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/RemoteViewService/BonjourPrefRemoteViewService-Info.plist b/mDNSResponder/mDNSMacOSX/PreferencePane/RemoteViewService/BonjourPrefRemoteViewService-Info.plist
new file mode 100644
index 00000000..0e72660a
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/RemoteViewService/BonjourPrefRemoteViewService-Info.plist
@@ -0,0 +1,41 @@
+<?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>CFBundleIdentifier</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>XPC!</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>CFBundleVisibleComponentName</key>
+ <string>$(CFBundleVisibleComponentName)</string>
+ <key>LSBackgroundOnly</key>
+ <true/>
+ <key>NSHumanReadableCopyright</key>
+ <string>Copyright © 2015 Apple Inc. All rights reserved.</string>
+ <key>NSPreferencePaneBundle</key>
+ <string>Bonjour</string>
+ <key>NSPrincipalClass</key>
+ <string>NSViewServiceApplication</string>
+ <key>XPCService</key>
+ <dict>
+ <key>JoinExistingSession</key>
+ <true/>
+ <key>RunLoopType</key>
+ <string>_NSApplicationMain</string>
+ </dict>
+</dict>
+</plist>
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/RemoteViewService/BonjourPrefRemoteViewService.h b/mDNSResponder/mDNSMacOSX/PreferencePane/RemoteViewService/BonjourPrefRemoteViewService.h
new file mode 100644
index 00000000..3f063e36
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/RemoteViewService/BonjourPrefRemoteViewService.h
@@ -0,0 +1,22 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import <ViewBridge/NSViewService.h>
+#import <PreferencePanes/NSPrefRemoteViewService.h>
+
+@interface BonjourPrefRemoteViewService : NSPrefRemoteViewService
+@end
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/RemoteViewService/BonjourPrefRemoteViewService.m b/mDNSResponder/mDNSMacOSX/PreferencePane/RemoteViewService/BonjourPrefRemoteViewService.m
new file mode 100644
index 00000000..821c6617
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/RemoteViewService/BonjourPrefRemoteViewService.m
@@ -0,0 +1,21 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import "BonjourPrefRemoteViewService.h"
+
+@implementation BonjourPrefRemoteViewService
+@end
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/RemoteViewService/InfoPlist.strings b/mDNSResponder/mDNSMacOSX/PreferencePane/RemoteViewService/InfoPlist.strings
new file mode 100644
index 00000000..d9d85419
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/RemoteViewService/InfoPlist.strings
@@ -0,0 +1,3 @@
+/* Localized versions of Info.plist keys */
+
+CFBundleVisibleComponentName = "System Preferences";
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/RemoteViewService/entitlements.plist b/mDNSResponder/mDNSMacOSX/PreferencePane/RemoteViewService/entitlements.plist
new file mode 100644
index 00000000..7017a781
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/RemoteViewService/entitlements.plist
@@ -0,0 +1,10 @@
+<?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.SCPreferences-write-access</key>
+ <array>
+ <string>preferences.plist</string>
+ </array>
+</dict>
+</plist>
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/RemoteViewService/main.m b/mDNSResponder/mDNSMacOSX/PreferencePane/RemoteViewService/main.m
new file mode 100644
index 00000000..e503647a
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/PreferencePane/RemoteViewService/main.m
@@ -0,0 +1,40 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import <Foundation/Foundation.h>
+#import <PreferencePanes/PreferencePaneXPCMain.h>
+
+int
+main(int inArgc, const char *inArgv[])
+{
+ int result = 0;
+
+ @autoreleasepool
+ {
+ @try
+ {
+ result = PreferencePaneMain(inArgc, inArgv);
+ }
+ @catch(NSException * e)
+ {
+ NSLog(@"%s caught %@: '%@' with user dictionary %@ and call stack %@", __func__, [e name], [e reason], [e userInfo], [e callStackSymbols]);
+ result = 1;
+ }
+ }
+
+ return result;
+}
diff --git a/mDNSResponder/mDNSMacOSX/PreferencePane/ddnswriteconfig.m b/mDNSResponder/mDNSMacOSX/PreferencePane/ddnswriteconfig.m
deleted file mode 100644
index 8e64fc46..00000000
--- a/mDNSResponder/mDNSMacOSX/PreferencePane/ddnswriteconfig.m
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- 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];
- CFRelease(domainData);
- free(p);
-
- 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);
- CFRelease(domainData);
- free(p);
-
-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];
- CFRelease(secretData);
- free(p);
-
- 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
deleted file mode 100755
index ce341c87..00000000
--- a/mDNSResponder/mDNSMacOSX/PreferencePane/installtool
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/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/dnsctl_server.c b/mDNSResponder/mDNSMacOSX/Private/dnsctl_server.c
index 9b3885e6..ad5136df 100644
--- a/mDNSResponder/mDNSMacOSX/Private/dnsctl_server.c
+++ b/mDNSResponder/mDNSMacOSX/Private/dnsctl_server.c
@@ -23,7 +23,7 @@ static dispatch_queue_t dnsctlserver_queue = NULL;
mDNSlocal void handle_logging(mDNSu32 log_level)
{
- KQueueLock(&mDNSStorage);
+ KQueueLock();
switch (log_level)
{
@@ -55,12 +55,12 @@ mDNSlocal void handle_logging(mDNSu32 log_level)
}
UpdateDebugState();
- KQueueUnlock(&mDNSStorage, "LogLevel changed");
+ KQueueUnlock("LogLevel changed");
}
mDNSlocal void handle_stateinfo(mDNSu32 state_level)
{
- KQueueLock(&mDNSStorage);
+ KQueueLock();
switch (state_level)
{
@@ -73,13 +73,13 @@ mDNSlocal void handle_stateinfo(mDNSu32 state_level)
break;
}
- KQueueUnlock(&mDNSStorage, "StateInfo dumped");
+ KQueueUnlock("StateInfo dumped");
}
mDNSlocal void handle_test_mode(mDNSu32 test_mode)
{
- KQueueLock(&mDNSStorage);
+ KQueueLock();
switch (test_mode)
{
@@ -99,7 +99,7 @@ mDNSlocal void handle_test_mode(mDNSu32 test_mode)
break;
}
- KQueueUnlock(&mDNSStorage, "Test Msg to mDNSResponderHelper");
+ KQueueUnlock("Test Msg to mDNSResponderHelper");
}
mDNSlocal void handle_terminate()
diff --git a/mDNSResponder/mDNSMacOSX/Private/xpc_services.c b/mDNSResponder/mDNSMacOSX/Private/xpc_services.c
index 4cad6ba0..8bf45a4b 100644
--- a/mDNSResponder/mDNSMacOSX/Private/xpc_services.c
+++ b/mDNSResponder/mDNSMacOSX/Private/xpc_services.c
@@ -41,11 +41,11 @@ mDNSlocal void ActivateDNSProxy(mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf, mDNSBool p
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);
+ KQueueLock();
+ DNSProxyInit(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");
+ mDNSPlatformInitDNSProxySkts(ProxyUDPCallback, ProxyTCPCallback);
+ KQueueUnlock("DNSProxy Activated");
}
mDNSlocal void handle_dps_terminate()
@@ -55,11 +55,11 @@ mDNSlocal void handle_dps_terminate()
// Clear the Client's PID, so that we can now accept new DPS requests
dps_client_pid = 0;
- KQueueLock(&mDNSStorage);
+ KQueueLock();
mDNSPlatformCloseDNSProxySkts(&mDNSStorage);
// TBD: Close TCP Sockets
- DNSProxyTerminate(&mDNSStorage);
- KQueueUnlock(&mDNSStorage, "DNSProxy Deactivated");
+ DNSProxyTerminate();
+ KQueueUnlock("DNSProxy Deactivated");
}
mDNSlocal void handle_dps_request(xpc_object_t req)
diff --git a/mDNSResponder/mDNSMacOSX/SettingsBundle/Assets.xcassets/Contents.json b/mDNSResponder/mDNSMacOSX/SettingsBundle/Assets.xcassets/Contents.json
new file mode 100644
index 00000000..da4a164c
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/SettingsBundle/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/mDNSResponder/mDNSMacOSX/SettingsBundle/Assets.xcassets/UIPreferencesBlueCheck.imageset/Contents.json b/mDNSResponder/mDNSMacOSX/SettingsBundle/Assets.xcassets/UIPreferencesBlueCheck.imageset/Contents.json
new file mode 100644
index 00000000..6bfae10b
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/SettingsBundle/Assets.xcassets/UIPreferencesBlueCheck.imageset/Contents.json
@@ -0,0 +1,22 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "UIPreferencesBlueCheck.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "filename" : "UIPreferencesBlueCheck@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/mDNSResponder/mDNSMacOSX/SettingsBundle/Assets.xcassets/UIPreferencesBlueCheck.imageset/UIPreferencesBlueCheck.png b/mDNSResponder/mDNSMacOSX/SettingsBundle/Assets.xcassets/UIPreferencesBlueCheck.imageset/UIPreferencesBlueCheck.png
new file mode 100644
index 00000000..44a1cc53
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/SettingsBundle/Assets.xcassets/UIPreferencesBlueCheck.imageset/UIPreferencesBlueCheck.png
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/SettingsBundle/Assets.xcassets/UIPreferencesBlueCheck.imageset/UIPreferencesBlueCheck@2x.png b/mDNSResponder/mDNSMacOSX/SettingsBundle/Assets.xcassets/UIPreferencesBlueCheck.imageset/UIPreferencesBlueCheck@2x.png
new file mode 100644
index 00000000..ce094512
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/SettingsBundle/Assets.xcassets/UIPreferencesBlueCheck.imageset/UIPreferencesBlueCheck@2x.png
Binary files differ
diff --git a/mDNSResponder/mDNSMacOSX/SettingsBundle/BonjourConstants.h b/mDNSResponder/mDNSMacOSX/SettingsBundle/BonjourConstants.h
new file mode 100644
index 00000000..189b58de
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/SettingsBundle/BonjourConstants.h
@@ -0,0 +1,15 @@
+//
+// BonjourSettingsController.m
+// mDNSResponder
+//
+// Created by Phil on 7/28/16.
+//
+//
+
+#import <Preferences/Preferences.h>
+
+@interface BonjourSettingsController: PSListItemsController {
+
+}
+
+@end
diff --git a/mDNSResponder/mDNSMacOSX/SettingsBundle/BonjourSCStore.h b/mDNSResponder/mDNSMacOSX/SettingsBundle/BonjourSCStore.h
new file mode 100644
index 00000000..15b12a6e
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/SettingsBundle/BonjourSCStore.h
@@ -0,0 +1,40 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import <SystemConfiguration/SystemConfiguration.h>
+#import <Security/Security.h>
+
+#define SC_DYNDNS_PREFS_KEY CFSTR("com.apple.preference.bonjour")
+#define SC_DYNDNS_SYSTEM_KEY CFSTR("/System/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 SC_DYNDNS_SETUP_KEY CFSTR("Setup:/Network/DynamicDNS")
+#define SC_DYNDNS_STATE_KEY CFSTR("State:/Network/DynamicDNS")
+
+@interface BonjourSCStore : NSObject
+
++ (NSArray *_Nullable)objectForKey:(NSString *_Nonnull)key;
++ (void)setObject:(NSArray *_Nullable)value forKey:(NSString *_Nonnull)key;
+
+@end
diff --git a/mDNSResponder/mDNSMacOSX/SettingsBundle/BonjourSCStore.m b/mDNSResponder/mDNSMacOSX/SettingsBundle/BonjourSCStore.m
new file mode 100644
index 00000000..e4f9b0d5
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/SettingsBundle/BonjourSCStore.m
@@ -0,0 +1,84 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import "BonjourSCStore.h"
+#import <Foundation/Foundation.h>
+#import <AssertMacros.h>
+
+@implementation BonjourSCStore
+
++ (NSArray * _Nullable)objectForKey:(NSString * _Nonnull)key
+{
+ NSArray * result = nil;
+ SCPreferencesRef store;
+ OSStatus err;
+ NSDictionary * origDict;
+
+ store = SCPreferencesCreateWithAuthorization(kCFAllocatorDefault, SC_DYNDNS_PREFS_KEY, NULL, NULL);
+ require_action(store != NULL, SysConfigErr, err = SCError());
+ require_action(true == SCPreferencesLock(store, true), LockFailed, err = SCError());
+
+ origDict = (__bridge NSDictionary *)SCPreferencesPathGetValue(store, SC_DYNDNS_SYSTEM_KEY);
+ if (origDict) origDict = [NSDictionary dictionaryWithDictionary: origDict];
+
+ result = [origDict objectForKey: key];
+
+ SCPreferencesUnlock(store);
+
+LockFailed:
+ CFRelease(store);
+SysConfigErr:
+ return(result);
+}
+
++ (void)setObject:(NSArray * _Nullable)value forKey:(NSString * _Nonnull)key
+{
+ SCPreferencesRef store;
+ OSStatus err;
+ NSMutableDictionary * origDict;
+ Boolean success;
+
+ store = SCPreferencesCreateWithAuthorization(kCFAllocatorDefault, SC_DYNDNS_PREFS_KEY, NULL, NULL);
+ require_action(store != NULL, SysConfigErr, err = SCError());
+ require_action(true == SCPreferencesLock(store, true), LockFailed, err = SCError());
+
+ origDict = (__bridge NSMutableDictionary *)SCPreferencesPathGetValue(store, SC_DYNDNS_SYSTEM_KEY);
+ if (!origDict) origDict = [NSMutableDictionary dictionary];
+ else origDict = [NSMutableDictionary dictionaryWithDictionary: origDict];
+
+ if (value.count) [origDict setObject: value forKey: key];
+ else [origDict removeObjectForKey: key];
+
+ success = SCPreferencesPathSetValue(store, SC_DYNDNS_SYSTEM_KEY, (__bridge CFDictionaryRef)origDict);
+ require_action(success, SCError, err = SCError(););
+
+ success = SCPreferencesCommitChanges(store);
+ require_action(success, SCError, err = SCError());
+ success = SCPreferencesApplyChanges(store);
+ require_action(success, SCError, err = SCError());
+
+SCError:
+ SCPreferencesUnlock(store);
+LockFailed:
+ CFRelease(store);
+SysConfigErr:
+ return;
+}
+
+
+@end
+
diff --git a/mDNSResponder/mDNSMacOSX/SettingsBundle/BonjourSettingsController.h b/mDNSResponder/mDNSMacOSX/SettingsBundle/BonjourSettingsController.h
new file mode 100644
index 00000000..0f3d95b3
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/SettingsBundle/BonjourSettingsController.h
@@ -0,0 +1,24 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import <Preferences/Preferences.h>
+
+@interface BonjourSettingsController: PSListItemsController {
+
+}
+
+@end
diff --git a/mDNSResponder/mDNSMacOSX/SettingsBundle/BonjourSettingsController.m b/mDNSResponder/mDNSMacOSX/SettingsBundle/BonjourSettingsController.m
new file mode 100644
index 00000000..86e4ae7a
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/SettingsBundle/BonjourSettingsController.m
@@ -0,0 +1,143 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import "BonjourSettingsController.h"
+#import "HostnameController.h"
+#import "BonjourSCStore.h"
+#import "CNBrowseDomainsController.h"
+#import <AssertMacros.h>
+
+#define LocalizedStringFromMyBundle(key, comment) \
+ NSLocalizedStringFromTableInBundle(key, @"Localizable", [NSBundle bundleForClass: [self class]], comment)
+
+@interface BonjourSettingsController ()
+
+@property (strong) NSString * bonjourHostname;
+@property (strong) NSArray * browseDomainsA;
+
+@end
+
+@implementation BonjourSettingsController
+
+- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
+{
+ if (self = [super initWithNibName: nibNameOrNil bundle: nibBundleOrNil])
+ {
+ [self commonInit];
+ }
+ return(self);
+}
+
+- (void)commonInit
+{
+}
+
+- (void)viewWillAppear:(BOOL)animated
+{
+ [super viewWillAppear: animated];
+ [self readPreferences];
+ [self reloadSpecifiers];
+}
+
+- (id) getDomainCount:(PSSpecifier *)specifier
+{
+ (void)specifier; // Unused
+ return [NSNumber numberWithInteger: [_browseDomainsA filteredArrayUsingPredicate: [NSPredicate predicateWithFormat: @"(%K == %@)", (NSString *)SC_DYNDNS_ENABLED_KEY, @YES]].count].stringValue;
+}
+
+- (id) getHostname:(PSSpecifier *)specifier
+{
+ (void)specifier; // Unused
+ return _bonjourHostname.length ? _bonjourHostname : LocalizedStringFromMyBundle(@"_bonjour.hostname.unset", nil);
+}
+
+- (NSArray *)specifiers
+{
+ if (!_specifiers) {
+ PSSpecifier * specifier;
+ NSMutableArray * specifiers = [NSMutableArray array];
+
+ specifier = [PSSpecifier groupSpecifierWithName: LocalizedStringFromMyBundle(@"_bonjour.hostname.groupname", nil)];
+ [specifiers addObject: specifier];
+ specifier = [PSSpecifier preferenceSpecifierNamed: LocalizedStringFromMyBundle(@"_bonjour.hostname.name", nil)
+ target: self
+ set: nil
+ get: @selector(getHostname:)
+ detail: [HostnameController class]
+ cell: PSLinkListCell
+ edit: nil];
+ [specifier setProperty: @"hostnameID"
+ forKey: PSIDKey];
+ [specifiers addObject: specifier];
+
+ specifier = [PSSpecifier groupSpecifierWithName: LocalizedStringFromMyBundle(@"_bonjour.browse.groupname", nil)];
+ [specifiers addObject: specifier];
+ specifier = [PSSpecifier preferenceSpecifierNamed: LocalizedStringFromMyBundle(@"_bonjour.browse.name", nil)
+ target: self
+ set: nil
+ get: @selector(getDomainCount:)
+ detail: [CNBrowseDomainsController class]
+ cell: PSLinkListCell
+ edit: nil];
+ [specifier setProperty: @"browseID"
+ forKey: PSIDKey];
+ [specifiers addObject: specifier];
+
+ _specifiers = specifiers;
+ }
+ return _specifiers;
+}
+
+-(void)readPreferences
+{
+ self.browseDomainsA = [BonjourSCStore objectForKey: (NSString *)SC_DYNDNS_BROWSEDOMAINS_KEY];
+
+ NSArray * hostArray;
+ hostArray = [BonjourSCStore objectForKey: (NSString *)SC_DYNDNS_HOSTNAMES_KEY];
+ if (hostArray && [hostArray count] > 0)
+ {
+ self.bonjourHostname = hostArray[0][(NSString *)SC_DYNDNS_DOMAIN_KEY];
+ }
+ else self.bonjourHostname = nil;
+
+ if (!_browseDomainsA) self.browseDomainsA = [NSMutableArray array];
+ if (!_bonjourHostname) self.bonjourHostname = [NSString string];
+}
+
+#pragma mark - TableView Delegates
+
+- (void)listItemSelected:(NSIndexPath *)indexPath //sender is NSIndexPath of selection
+{
+ if (indexPath.section == 0)
+ {
+ HostnameController * c = [[HostnameController alloc] initWithStyle: UITableViewStyleGrouped];
+ c.bonjourHostname = _bonjourHostname;
+ c.title = LocalizedStringFromMyBundle(@"_bonjour.hostname.name", nil);
+ [self.navigationController pushViewController: c animated: YES];
+ }
+ else if (indexPath.section == 1)
+ {
+ CNBrowseDomainsController * c = [[CNBrowseDomainsController alloc] initWithStyle: UITableViewStyleGrouped];
+ c.browseDomainsA = _browseDomainsA;
+ c.title = LocalizedStringFromMyBundle(@"_bonjour.browse.name", nil);
+ [self.navigationController pushViewController: c animated: YES];
+ }
+
+ [_table deselectRowAtIndexPath: indexPath animated: YES];
+}
+
+@end
diff --git a/mDNSResponder/mDNSMacOSX/SettingsBundle/CNBrowseDomainsController.h b/mDNSResponder/mDNSMacOSX/SettingsBundle/CNBrowseDomainsController.h
new file mode 100644
index 00000000..da6813ef
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/SettingsBundle/CNBrowseDomainsController.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import <UIKit/UIKit.h>
+
+@protocol CNBrowseDomainsDelegate;
+
+@interface CNBrowseDomainsController : UITableViewController
+
+@property (weak) IBOutlet id<CNBrowseDomainsDelegate> delegate;
+@property (strong) NSArray * browseDomainsA;
+
+- (void)addBrowseDomain:(NSString *)fullPath;
+
+@end
+
+@protocol CNBrowseDomainsDelegate <NSObject>
+
+@optional
+
+- (void)domainBrowserDomainSelected:(NSString *)domain;
+
+@end
diff --git a/mDNSResponder/mDNSMacOSX/SettingsBundle/CNBrowseDomainsController.m b/mDNSResponder/mDNSMacOSX/SettingsBundle/CNBrowseDomainsController.m
new file mode 100644
index 00000000..f729eb7d
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/SettingsBundle/CNBrowseDomainsController.m
@@ -0,0 +1,710 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import "CNBrowseDomainsController.h"
+#import "CNDomainBrowserViewController.h"
+#import "CNDomainBrowserPathUtils.h"
+#import "BonjourSCStore.h"
+#import <AssertMacros.h>
+
+#define kTag_AddBrowse 100
+#define kTag_AddManual 101
+
+const NSString * _CNBrowseDomainKey_fullname = (NSString *)SC_DYNDNS_DOMAIN_KEY;
+const NSString * _CNBrowseDomainKey_enabled = (NSString *)SC_DYNDNS_ENABLED_KEY;
+
+#define LocalizedStringFromMyBundle(key, comment ) \
+ NSLocalizedStringFromTableInBundle(key, @"Localizable", [NSBundle bundleForClass: [self class]], comment )
+
+@interface CNPathPopoverViewController : UIViewController
+
+@property (strong) UILabel * label;
+@property (copy) NSArray * pathArray;
+@property (assign) CGPoint offset;
+
+@end
+
+@implementation CNPathPopoverViewController
+
+- (instancetype)initWithPathArray:(NSArray *)pathArray
+{
+ if (self = [self initWithNibName: nil bundle: nil] )
+ {
+ _pathArray = pathArray;
+ NSMutableParagraphStyle * paragraphStyle = [[NSMutableParagraphStyle alloc] init];
+ [paragraphStyle setLineSpacing: [UIFont labelFontSize] * 0.3];
+
+ NSMutableAttributedString * itemStr = [[NSMutableAttributedString alloc] init];
+ NSUInteger count = 0;
+ for (NSString * next in _pathArray )
+ {
+ NSString * nextLine = [NSString stringWithFormat: @"%@%@", itemStr.length ? @"\n" : @"", next];
+ UIColor * nextColor = ((count++ == 0) || (count == _pathArray.count)) ? [UIColor grayColor] : [UIColor blackColor];
+ [itemStr appendAttributedString:
+ [[NSMutableAttributedString alloc] initWithString: nextLine
+ attributes: @{ NSForegroundColorAttributeName: nextColor,
+ NSParagraphStyleAttributeName: paragraphStyle
+ }]];
+ }
+
+ _label = [[UILabel alloc] initWithFrame: CGRectZero];
+ _label.numberOfLines = 0;
+ _label.attributedText = itemStr;
+ [_label sizeToFit];
+
+ _offset = CGPointMake(25, 15 );
+ CGRect rect = _label.frame;
+ rect.origin.x += _offset.x;
+ rect.origin.y += _offset.y;
+ [_label setFrame: rect];
+ }
+ return(self );
+}
+
+- (void)viewDidLoad
+{
+ [super viewDidLoad];
+ [self.view addSubview: _label];
+}
+
+- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator
+{
+ [super willTransitionToTraitCollection: newCollection withTransitionCoordinator: coordinator];
+ [self.presentingViewController dismissViewControllerAnimated: NO completion: nil];
+}
+
+@end
+
+@interface CNPathAccessoryView : UIView
+
+@property (strong, readonly) UIButton * elipsisButton;
+@property (strong, readonly) UIButton * pathLabel;
+@property (weak) UITableView * tableView;
+@property (weak) UITableViewCell * cell;
+@property (strong, readonly) NSArray * pathArray;
+
+@end
+
+@implementation CNPathAccessoryView
+
+- (instancetype) initWithFrame:(CGRect)frame pathArray:(NSArray *)pathArray
+{
+ self = [super initWithFrame:frame];
+ if (self) {
+ _pathArray = pathArray;
+ if (_pathArray )
+ {
+ _pathLabel = [UIButton buttonWithType: UIButtonTypeCustom];
+ [_pathLabel setTitle: _pathArray[_pathArray.count-1] forState: UIControlStateNormal];
+ [_pathLabel setTitleColor: [UIColor blackColor] forState: UIControlStateNormal];
+ _pathLabel.titleLabel.font = [UIFont systemFontOfSize: [UIFont labelFontSize]];
+ [self addSubview: _pathLabel];
+
+ _pathLabel.translatesAutoresizingMaskIntoConstraints = NO;
+ [_pathLabel sizeToFit];
+ [_pathLabel.widthAnchor constraintEqualToConstant: _pathLabel.frame.size.width].active = YES;
+ [_pathLabel.trailingAnchor constraintEqualToAnchor: self.trailingAnchor].active = YES;
+ [_pathLabel.topAnchor constraintEqualToAnchor: self.topAnchor].active = YES;
+ [_pathLabel.bottomAnchor constraintEqualToAnchor: self.bottomAnchor].active = YES;
+ }
+ if (_pathArray.count > 2 )
+ {
+ _elipsisButton = [UIButton buttonWithType: UIButtonTypeCustom];
+ [_elipsisButton setTitle: @"…" forState: UIControlStateNormal];
+ [_elipsisButton setTitleColor: _elipsisButton.tintColor forState: UIControlStateNormal];
+ [_elipsisButton setTitleColor: [UIColor grayColor] forState: UIControlStateHighlighted];
+ _elipsisButton.titleLabel.font = [UIFont boldSystemFontOfSize: [UIFont labelFontSize]];
+ [_elipsisButton addTarget: self action: @selector(pathButtonPressed:withEvent:) forControlEvents: UIControlEventTouchUpInside];
+ _elipsisButton.userInteractionEnabled = YES;
+ [self addSubview: _elipsisButton];
+
+ _elipsisButton.translatesAutoresizingMaskIntoConstraints = NO;
+ [_elipsisButton sizeToFit];
+ [_elipsisButton.widthAnchor constraintEqualToConstant: _elipsisButton.frame.size.width].active = YES;
+ [_elipsisButton.trailingAnchor constraintEqualToAnchor: _pathLabel.leadingAnchor].active = YES;
+ [_elipsisButton.topAnchor constraintGreaterThanOrEqualToAnchor: self.topAnchor].active = YES;
+ [_elipsisButton.bottomAnchor constraintLessThanOrEqualToAnchor: self.bottomAnchor].active = YES;
+ }
+ }
+ return self;
+}
+
+- (BOOL) canBecomeFirstResponder
+{
+ return YES;
+}
+
+- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller traitCollection:(UITraitCollection *)traitCollection
+{
+ (void)controller; // Unused
+ (void)traitCollection; // Unused
+ return UIModalPresentationNone;
+}
+
+- (void) pathButtonPressed:(UIControl *)button withEvent:(UIEvent *)event
+{
+ (void)button; // Unused
+
+ if (!self.cell.showingDeleteConfirmation )
+ {
+ [self becomeFirstResponder];
+
+ UIView *buttonView = [[event.allTouches anyObject] view];
+ CGRect buttonFrame = [buttonView convertRect: buttonView.frame toView: self];
+
+ CNPathPopoverViewController * controller = [[CNPathPopoverViewController alloc] initWithPathArray: self.pathArray];
+ controller.modalPresentationStyle = UIModalPresentationPopover;
+ controller.preferredContentSize = CGSizeMake(controller.label.frame.size.width + controller.offset.x * 2, controller.label.frame.size.height + controller.offset.y * 2 );
+
+ UIPopoverPresentationController *popover = controller.popoverPresentationController;
+ popover.delegate = (id<UIPopoverPresentationControllerDelegate>)self;
+ popover.sourceView = buttonView;
+ popover.sourceRect = buttonFrame;
+ popover.permittedArrowDirections = UIPopoverArrowDirectionLeft | UIPopoverArrowDirectionRight;
+
+ [(UIViewController *)self.tableView.delegate presentViewController: controller
+ animated: YES
+ completion: nil];
+ }
+}
+
+- (CGSize) sizeThatFits:(CGSize)size
+{
+ (void)size; // Unused
+ CGSize ret = CGSizeZero;
+ CGFloat maxX = 0.0;
+ CGFloat maxHeight = 0.0;
+ for (UIView *view in [self subviews] )
+ {
+ CGRect frame = view.frame;
+ CGFloat frameMaxX = CGRectGetMaxX(frame);
+ CGFloat frameHeight = CGRectGetHeight(frame);
+ maxX += frameMaxX;
+ if (frameHeight > maxHeight )
+ {
+ maxHeight = frameHeight;
+ }
+ }
+ ret.width = maxX;
+ ret.height = maxHeight;
+ return ret;
+}
+
+@end
+
+@interface CNManualDomainViewController : UITableViewController
+
+@property (weak) CNBrowseDomainsController * delegate;
+@property (weak) UITextField * textField;
+
+@end
+
+#define kTag_EditTextField 103
+
+@implementation CNManualDomainViewController
+
+- (void)viewDidLoad
+{
+ [super viewDidLoad];
+
+ self.tableView.dataSource = (id<UITableViewDataSource>)self;
+ self.tableView.delegate = (id<UITableViewDelegate>)self;
+
+ self.title = LocalizedStringFromMyBundle(@"_dnsBrowser.manualdomain.title", nil );
+ self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle: LocalizedStringFromMyBundle(@"_dnsBrowser.manualdomain.cancel", nil )
+ style: UIBarButtonItemStylePlain
+ target: self
+ action: @selector(cancelAction:)];
+
+ self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle: LocalizedStringFromMyBundle(@"_dnsBrowser.manualdomain.add", nil )
+ style: UIBarButtonItemStylePlain
+ target: self
+ action: @selector(addAction:)];
+ self.navigationItem.rightBarButtonItem.enabled = NO;
+}
+
+- (void)viewWillDisappear:(BOOL)animated
+{
+ [super viewWillDisappear: animated];
+ if (self.isMovingFromParentViewController )
+ {
+ [[NSNotificationCenter defaultCenter] removeObserver: self];
+ }
+}
+
+- (void)viewDidAppear:(BOOL)animated
+{
+ [super viewDidAppear: animated];
+ if (self.isMovingToParentViewController )
+ {
+ [self.textField becomeFirstResponder];
+ }
+}
+
+- (IBAction)addAction:(id)sender
+{
+ (void)sender; // Unused
+ [self.navigationController dismissViewControllerAnimated: YES completion: ^{
+ [self.delegate addBrowseDomain: self.textField.text];
+ }];
+}
+
+- (IBAction)cancelAction:(id)sender
+{
+ (void)sender; // Unused
+ [self.navigationController dismissViewControllerAnimated: YES completion: nil];
+}
+
+#pragma mark - Notifications
+
+- (void)textFieldDidChange:(NSNotification *)notification
+{
+ UITextField * textField = (UITextField *)notification.object;
+ self.navigationItem.rightBarButtonItem.enabled = (textField.text.length > 0);
+}
+
+#pragma mark - TableView Delegates
+
+- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
+{
+ (void)tableView; // Unused
+ (void)indexPath; // Unused
+ return UITableViewAutomaticDimension;
+}
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
+{
+ (void)tableView; // Unused
+ NSInteger result = 0;
+
+ if (tableView == self.tableView ) result = 1;
+
+ return(result );
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
+{
+ (void)section; // Unused
+ NSInteger result = 0;
+
+ if (tableView == self.tableView && section == 0 ) result = 1;
+
+ return(result );
+}
+
+- (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
+{
+ NSString * result = nil;
+
+ if (tableView == self.tableView && section == 0 )
+ {
+ result = LocalizedStringFromMyBundle(@"_dnsBrowser.manualdomain.footer", nil );
+ }
+
+ return(result );
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
+{
+ UITableViewCell *cell = nil;
+
+ if (tableView == self.tableView )
+ {
+ if (indexPath.section == 0 && indexPath.row == 0 )
+ {
+ static NSString *MyIdentifier = @"manual_domain_cell_id";
+ cell = [tableView dequeueReusableCellWithIdentifier: MyIdentifier];
+ if (!cell )
+ {
+ cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleValue1 reuseIdentifier: MyIdentifier];
+ }
+
+ cell.textLabel.hidden = YES;
+ cell.detailTextLabel.hidden = YES;
+
+ [[cell viewWithTag: kTag_EditTextField] removeFromSuperview];
+ UITextField * textField = [[UITextField alloc] initWithFrame:CGRectZero];
+ textField.tag = kTag_EditTextField;
+ textField.adjustsFontSizeToFitWidth = YES;
+ textField.placeholder = LocalizedStringFromMyBundle(@"_dnsBrowser.manualdomain.defaultValue", nil );
+ textField.keyboardType = UIKeyboardTypeURL;
+ textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
+ textField.autocorrectionType = UITextAutocorrectionTypeNo;
+ textField.enablesReturnKeyAutomatically = YES;
+ textField.clearButtonMode = UITextFieldViewModeAlways;
+ [cell.contentView addSubview: textField];
+
+ textField.translatesAutoresizingMaskIntoConstraints = NO;
+ [textField.leadingAnchor constraintEqualToAnchor: cell.layoutMarginsGuide.leadingAnchor].active = YES;
+ [textField.trailingAnchor constraintEqualToAnchor: cell.layoutMarginsGuide.trailingAnchor].active = YES;
+ [textField.topAnchor constraintEqualToAnchor: cell.layoutMarginsGuide.topAnchor].active = YES;
+ [textField.bottomAnchor constraintEqualToAnchor: cell.layoutMarginsGuide.bottomAnchor].active = YES;
+
+ [[NSNotificationCenter defaultCenter] addObserver: self
+ selector: @selector(textFieldDidChange:)
+ name: UITextFieldTextDidChangeNotification
+ object: textField];
+ self.textField = textField;
+ }
+ }
+
+ return(cell );
+}
+
+- (nullable NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
+{
+ (void)tableView; // Unused
+ (void)indexPath; // Unused
+ return(nil );
+}
+
+@end
+
+@interface CNBrowseDomainsController ()
+
+@property (strong) NSDictionary * selectedInstance;
+@property (strong) NSMutableDictionary * instanceInfoStrings;
+@property (strong) NSMutableDictionary * instanceStatusViews;
+
+@property (strong) CNDomainBrowserViewController * browseController;
+
+@end
+
+@implementation CNBrowseDomainsController
+
+- (instancetype)initWithStyle:(UITableViewStyle)style
+{
+ if (self = [super initWithStyle: style] )
+ {
+ [self commonInit];
+ }
+ return(self );
+}
+
+- (void)contentViewsInit
+{
+ self.tableView.allowsMultipleSelectionDuringEditing = NO;
+}
+
+- (void)commonInit
+{
+ self.instanceInfoStrings = [NSMutableDictionary dictionary];
+ self.instanceStatusViews = [NSMutableDictionary dictionary];
+ self.browseController = [[CNDomainBrowserViewController alloc] initWithStyle: UITableViewStylePlain];
+ _browseController.delegate = (id<CNDomainBrowserViewControllerDelegate>)self;
+ _browseController.ignoreLocal = YES;
+}
+
+- (void)viewDidLoad
+{
+ [super viewDidLoad];
+ [self contentViewsInit];
+
+ self.tableView.dataSource = (id<UITableViewDataSource>)self;
+ self.tableView.delegate = (id<UITableViewDelegate>)self;
+}
+
+- (void)viewWillAppear:(BOOL)animated
+{
+ [super viewWillAppear: animated];
+ if (self.isMovingToParentViewController)
+ {
+ [_browseController startBrowse];
+ }
+}
+
+- (void)viewWillDisappear:(BOOL)animated
+{
+ [super viewWillDisappear: animated];
+ if (self.isMovingFromParentViewController )
+ {
+ [self savePreferences];
+ [_browseController stopBrowse];
+ }
+}
+
+-(void)savePreferences
+{
+ [BonjourSCStore setObject: _browseDomainsA.count ? _browseDomainsA : nil forKey: (NSString *)SC_DYNDNS_BROWSEDOMAINS_KEY];
+}
+
+- (NSDictionary *)browseDomainForRow:(NSInteger)row
+{
+ NSDictionary * result = nil;
+ NSInteger curRow = 0;
+
+ for (NSDictionary * nextDomain in self.browseDomainsA )
+ {
+ if (curRow == row )
+ {
+ result = nextDomain;
+ break;
+ }
+ curRow++;
+ }
+
+ return(result );
+}
+
+- (NSInteger)indexOfDomainInList:(NSString *)domainString
+{
+ NSInteger index = 0;
+ if (_browseDomainsA ) {
+ NSDictionary *domainDict;
+ NSString *domainName;
+ NSEnumerator *arrayEnumerator = [_browseDomainsA objectEnumerator];
+ while ((domainDict = [arrayEnumerator nextObject]) != NULL)
+ {
+ domainName = [domainDict objectForKey:_CNBrowseDomainKey_fullname];
+ if ([domainString caseInsensitiveCompare:domainName] == NSOrderedSame) return index;
+ index++;
+ }
+ }
+ return NSNotFound;
+}
+
+- (void)addBrowseDomain:(NSString *)fullPath
+{
+ NSString * trimmedPath = TrimCharactersFromDNSDomain(fullPath );
+ NSInteger index = [self indexOfDomainInList: trimmedPath];
+ NSMutableArray * domains = [NSMutableArray arrayWithArray: self.browseDomainsA];
+
+ if (index == NSNotFound )
+ {
+ [domains addObject: @{
+ _CNBrowseDomainKey_fullname: trimmedPath,
+ _CNBrowseDomainKey_enabled: @YES
+ }];
+
+ self.browseDomainsA = [NSArray arrayWithArray: domains];
+ [self.tableView insertRowsAtIndexPaths: @[[NSIndexPath indexPathForRow: domains.count-1 inSection: 0]] withRowAnimation: UITableViewRowAnimationAutomatic];
+ }
+ else
+ {
+ NSDictionary * domain = domains[index];
+ domains[index] = @{
+ _CNBrowseDomainKey_fullname: domain[_CNBrowseDomainKey_fullname],
+ _CNBrowseDomainKey_enabled: @YES
+ };
+ self.browseDomainsA = [NSArray arrayWithArray: domains];
+ NSIndexPath * indexPath = [NSIndexPath indexPathForRow: index inSection: 0];
+ [CATransaction begin];
+ [CATransaction setCompletionBlock:^{
+ [self.tableView deselectRowAtIndexPath: indexPath animated: YES];
+ }];
+ [self.tableView reloadRowsAtIndexPaths: @[indexPath] withRowAnimation: UITableViewRowAnimationAutomatic];
+ [self.tableView selectRowAtIndexPath: indexPath animated: YES scrollPosition: UITableViewScrollPositionMiddle];
+ [CATransaction commit];
+
+ }
+}
+
+#pragma mark - CNDomainBrowserViewControllerDelegate
+
+- (void)domainBrowserDomainSelected:(NSString *)domain
+{
+ [self newPathSelected: domain];
+}
+
+- (void)bonjourBrowserDomainUpdate:(NSString *)defaultDomain
+{
+ (void)defaultDomain; // Unused
+ [self.tableView reloadData];
+}
+
+#pragma mark - TableView Delegates
+
+- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
+{
+ (void)tableView; // Unused
+ (void)indexPath; // Unused
+ return UITableViewAutomaticDimension;
+}
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
+{
+ (void)tableView; // Unused
+ NSInteger result = 0;
+
+ if (tableView == self.tableView ) result = (self.browseController.flattenedDNSDomains.count > 0) ? 3 : 2;
+ else result = 1;
+
+ return(result );
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
+{
+ (void)section; // Unused
+ NSInteger result = 0;
+
+ if (tableView == self.tableView )
+ {
+ if (section == 0 )
+ {
+ result = self.browseDomainsA.count;
+ }
+ else
+ {
+ result = 1;
+ }
+ }
+
+ return(result );
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
+{
+ UITableViewCell *cell = nil;
+
+ if (tableView == self.tableView )
+ {
+ if (indexPath.section == 0 )
+ {
+ NSDictionary * record = [self browseDomainForRow: indexPath.row];
+ if (record )
+ {
+ static NSString *MyIdentifier = @"browse_cell_id";
+ cell = [tableView dequeueReusableCellWithIdentifier: MyIdentifier];
+ if (!cell )
+ {
+ cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleSubtitle reuseIdentifier: MyIdentifier];
+ }
+ NSArray * pathArray = DNSDomainToDomainPath(record[_CNBrowseDomainKey_fullname] );
+ cell.textLabel.text = pathArray[pathArray.count-1];
+ cell.textLabel.textColor = nil;
+ cell.textLabel.numberOfLines = 0;
+ cell.accessoryType = UITableViewCellAccessoryNone;
+ cell.accessoryView = nil;
+ cell.imageView.image = [[UIImage imageNamed: @"UIPreferencesBlueCheck.png"
+ inBundle: [NSBundle bundleForClass: [self class]]
+ compatibleWithTraitCollection: nil] imageWithRenderingMode: UIImageRenderingModeAlwaysTemplate];
+ cell.imageView.hidden = ![record[_CNBrowseDomainKey_enabled] boolValue];
+
+ NSArray * accPathArray = (pathArray.count > 2) ?
+ [[pathArray reverseObjectEnumerator] allObjects] :
+ ((pathArray.count > 1) ? @[pathArray[0]] : nil);
+ if (accPathArray )
+ {
+ CNPathAccessoryView * accView = [[CNPathAccessoryView alloc] initWithFrame: CGRectZero
+ pathArray: accPathArray];
+ accView.tableView = tableView;
+ accView.cell = cell;
+ [accView sizeToFit];
+ cell.accessoryView = accView;
+ }
+ }
+ }
+ else
+ {
+ static NSString *MyIdentifier = @"button_cell_id";
+ cell = [tableView dequeueReusableCellWithIdentifier: MyIdentifier];
+ if (!cell )
+ {
+ cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: MyIdentifier];
+ }
+
+ if (self.browseController.flattenedDNSDomains.count > 0 && indexPath.section == 1 )
+ {
+ cell.textLabel.textColor = self.view.tintColor;
+ cell.textLabel.text = LocalizedStringFromMyBundle(@"_dnsBrowser.domains.selectdomain", nil );
+ cell.accessoryType = UITableViewCellAccessoryNone;
+ cell.tag = kTag_AddBrowse;
+ }
+ else
+ {
+ cell.textLabel.textColor = self.view.tintColor;
+ cell.textLabel.text = LocalizedStringFromMyBundle(@"_dnsBrowser.domains.selectmanual", nil );
+ cell.accessoryType = UITableViewCellAccessoryNone;
+ cell.tag = kTag_AddManual;
+ }
+ }
+ }
+
+ return(cell );
+}
+
+- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
+{
+ BOOL result = NO;
+
+ if (tableView == self.tableView && indexPath.section == 0 ) result = YES;
+
+ return(result );
+}
+
+- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
+{
+ if (editingStyle == UITableViewCellEditingStyleDelete )
+ {
+ NSMutableArray * domains = [NSMutableArray arrayWithArray: self.browseDomainsA];
+ [domains removeObjectAtIndex: indexPath.row];
+ self.browseDomainsA = [NSArray arrayWithArray: domains];
+ [tableView deleteRowsAtIndexPaths: @[indexPath] withRowAnimation: UITableViewRowAnimationAutomatic];
+ }
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
+{
+ UITableViewCell * cell = [tableView cellForRowAtIndexPath: indexPath];
+ if (tableView == self.tableView )
+ {
+ if (indexPath.section == 0 )
+ { // Toggle check and enable bit
+ NSMutableArray * domains = [NSMutableArray arrayWithArray: self.browseDomainsA];
+ NSMutableDictionary * selection = [NSMutableDictionary dictionaryWithDictionary: domains[indexPath.row]];
+ selection[_CNBrowseDomainKey_enabled] = [NSNumber numberWithBool: ![selection[_CNBrowseDomainKey_enabled] boolValue]];
+ domains[indexPath.row] = selection;
+ self.browseDomainsA = [NSArray arrayWithArray: domains];
+ [tableView reloadRowsAtIndexPaths: @[indexPath] withRowAnimation: UITableViewRowAnimationAutomatic];
+ }
+ else
+ {
+ if (cell.tag == kTag_AddBrowse )
+ {
+ CNDomainBrowserViewController *c = _browseController;
+ c.title = LocalizedStringFromMyBundle(@"_bonjour.browse.name", nil);
+ c.clearsSelectionOnViewWillAppear = NO;
+ c.modalPresentationStyle = UIModalPresentationFormSheet;
+ UINavigationController * nv = [[UINavigationController alloc] initWithRootViewController: c];
+ [self presentViewController: nv animated: YES completion: nil];
+ }
+ else if (cell.tag == kTag_AddManual )
+ {
+ CNManualDomainViewController * c = [[CNManualDomainViewController alloc] initWithStyle: UITableViewStyleGrouped];
+ c.delegate = self;
+ c.modalPresentationStyle = UIModalPresentationFormSheet;
+ UINavigationController * nv = [[UINavigationController alloc] initWithRootViewController: c];
+ [self presentViewController: nv animated: YES completion: nil];
+ }
+ }
+ }
+ [tableView deselectRowAtIndexPath: indexPath animated: YES];
+}
+
+#pragma mark - Commands
+
+- (void)newPathSelected:(NSString *)fullPath
+{
+ [CATransaction begin];
+ [CATransaction setCompletionBlock:^{
+ [self addBrowseDomain: fullPath];
+ }];
+ [self.navigationController popToViewController: self animated: YES];
+ [CATransaction commit];
+ }
+
+@end
diff --git a/mDNSResponder/mDNSMacOSX/SettingsBundle/HostnameController.h b/mDNSResponder/mDNSMacOSX/SettingsBundle/HostnameController.h
new file mode 100644
index 00000000..f6835463
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/SettingsBundle/HostnameController.h
@@ -0,0 +1,25 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import <UIKit/UIKit.h>
+
+@interface HostnameController : UITableViewController {
+
+}
+@property (strong) NSString * bonjourHostname;
+
+@end
diff --git a/mDNSResponder/mDNSMacOSX/SettingsBundle/HostnameController.m b/mDNSResponder/mDNSMacOSX/SettingsBundle/HostnameController.m
new file mode 100644
index 00000000..94edc369
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/SettingsBundle/HostnameController.m
@@ -0,0 +1,125 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+#import "HostnameController.h"
+#import "BonjourSCStore.h"
+#import <AssertMacros.h>
+#import <Preferences/Preferences.h>
+
+#define LocalizedStringFromMyBundle(key, comment) \
+ NSLocalizedStringFromTableInBundle(key, @"Localizable", [NSBundle bundleForClass: [self class]], comment)
+
+@interface HostnameController ()
+
+@property (strong) UITextField * textField;
+
+@end
+
+@implementation HostnameController
+
+- (void)viewDidLoad
+{
+ [super viewDidLoad];
+
+ self.tableView.dataSource = (id<UITableViewDataSource>)self;
+ self.tableView.delegate = (id<UITableViewDelegate>)self;
+}
+
+- (void)viewWillDisappear:(BOOL)animated
+{
+ [super viewWillDisappear: animated];
+ if (self.isMovingFromParentViewController)
+ {
+ [[self firstResponder] resignFirstResponder]; // Ends any outstanding edits
+ self.bonjourHostname = _textField.attributedText.string;
+ [self savePreferences]; }
+}
+
+-(void)savePreferences
+{
+ [BonjourSCStore setObject: _bonjourHostname.length ? @[@{
+ (NSString *)SC_DYNDNS_DOMAIN_KEY : _bonjourHostname,
+ (NSString *)SC_DYNDNS_ENABLED_KEY : @YES
+ }] : nil
+ forKey: (NSString *)SC_DYNDNS_HOSTNAMES_KEY];
+}
+
+- (void)_setHostname:(NSString *)value
+{
+ self.bonjourHostname = value;
+}
+
+#pragma mark - TableView Delegates
+
+- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
+{
+ (void)tableView; // Unused
+ (void)indexPath; // Unused
+ return UITableViewAutomaticDimension;
+}
+
+- (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
+{
+ (void)tableView; // Unused
+ (void)section; // Unused
+ return(LocalizedStringFromMyBundle(@"_bonjour.hostname.desc", nil));
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
+{
+ (void)tableView; // Unused
+ (void)section; // Unused
+ return(1);
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
+{
+ PSEditableTableCell *cell = nil;
+
+ if (tableView == self.tableView && indexPath.section == 0)
+ {
+ static NSString *MyIdentifier = @"hostname_cell_id";
+ cell = (PSEditableTableCell *)[tableView dequeueReusableCellWithIdentifier: MyIdentifier];
+ if (!cell)
+ {
+ cell = [[PSEditableTableCell alloc] initWithStyle: [PSEditableTableCell cellStyle] reuseIdentifier: MyIdentifier];
+ }
+ cell.placeholderText = LocalizedStringFromMyBundle(@"_bonjour.hostname.placeholder", nil);
+ cell.textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
+ cell.textField.clearButtonMode = UITextFieldViewModeAlways;
+ cell.textField.autocorrectionType = UITextAutocorrectionTypeNo;
+ cell.textField.keyboardType = UIKeyboardTypeURL;
+ cell.title = @"";
+ cell.value = _bonjourHostname;
+ self.textField = cell.textField;
+ }
+
+ return(cell);
+}
+
+- (BOOL)tableView:(UITableView *)tableView shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath
+{
+ (void)tableView; // Unused
+ BOOL result = YES;
+
+ if (indexPath.section == 0 && indexPath.row == 0) result = NO;
+
+ return(result);
+}
+
+@end
+
diff --git a/mDNSResponder/mDNSMacOSX/SettingsBundle/Info.plist b/mDNSResponder/mDNSMacOSX/SettingsBundle/Info.plist
new file mode 100644
index 00000000..9fe8b991
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/SettingsBundle/Info.plist
@@ -0,0 +1,26 @@
+<?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>en</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>NSPrincipalClass</key>
+ <string>BonjourSettingsController</string>
+ <key>CFBundleDisplayName</key>
+ <string>Bonjour</string>
+</dict>
+</plist>
diff --git a/mDNSResponder/mDNSMacOSX/SettingsBundle/Localizable.strings b/mDNSResponder/mDNSMacOSX/SettingsBundle/Localizable.strings
new file mode 100644
index 00000000..94ee788d
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/SettingsBundle/Localizable.strings
@@ -0,0 +1,34 @@
+/*
+ *
+ * Copyright (c) 2016 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.
+ */
+
+"_bonjour.hostname.groupname" = "Hostname";
+"_bonjour.hostname.name" = "Hostname";
+"_bonjour.hostname.unset" = "Not set";
+"_bonjour.hostname.desc" = "Enter a hostname for this device. Other computers on the Internet will be able to reach your device using this hostname.";
+"_bonjour.hostname.placeholder" = "steve.example.com";
+
+"_bonjour.browse.groupname" = "Browsing";
+"_bonjour.browse.name" = "Browse Domains";
+
+"_dnsBrowser.domains.selectdomain" = "Browse For Domain…";
+"_dnsBrowser.domains.selectmanual" = "Manually Enter Domain…";
+
+"_dnsBrowser.manualdomain.title" = "Manual Domain";
+"_dnsBrowser.manualdomain.add" = "Add";
+"_dnsBrowser.manualdomain.cancel" = "Cancel";
+"_dnsBrowser.manualdomain.defaultValue" = "example.com";
+"_dnsBrowser.manualdomain.footer" = "The domain will be added to your list of Bonjour browse domains.";
diff --git a/mDNSResponder/mDNSMacOSX/com.apple.mDNSResponderHelper.plist b/mDNSResponder/mDNSMacOSX/com.apple.mDNSResponderHelper.plist
index 91ed1da3..002e322e 100644
--- a/mDNSResponder/mDNSMacOSX/com.apple.mDNSResponderHelper.plist
+++ b/mDNSResponder/mDNSMacOSX/com.apple.mDNSResponderHelper.plist
@@ -1,21 +1,19 @@
<?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">
+<!DOCTYPE plist PUBLIC "-//Apple//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.reloaded</string>
- <key>OnDemand</key>
- <true/>
- <key>ProgramArguments</key>
- <array>
- <string>/usr/sbin/mDNSResponderHelper</string>
- </array>
- <key>MachServices</key>
- <dict>
- <key>com.apple.mDNSResponder_Helper</key>
- <true/>
- </dict>
- <key>POSIXSpawnType</key>
- <string>Interactive</string>
+ <key>Label</key>
+ <string>com.apple.mDNSResponderHelper.reloaded</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/sbin/mDNSResponderHelper</string>
+ </array>
+ <key>MachServices</key>
+ <dict>
+ <key>com.apple.mDNSResponder_Helper</key>
+ <true/>
+ </dict>
+ <key>POSIXSpawnType</key>
+ <string>Interactive</string>
</dict>
</plist>
diff --git a/mDNSResponder/mDNSMacOSX/coreBLE.h b/mDNSResponder/mDNSMacOSX/coreBLE.h
index cc00923a..29a0a17d 100644
--- a/mDNSResponder/mDNSMacOSX/coreBLE.h
+++ b/mDNSResponder/mDNSMacOSX/coreBLE.h
@@ -18,15 +18,22 @@
#ifndef _coreBLE_H_
#define _coreBLE_H_
+#if ENABLE_BLE_TRIGGERED_BONJOUR
+
#include "BLE.h"
@interface coreBLE : NSObject <CBCentralManagerDelegate, CBPeripheralManagerDelegate, CBPeripheralDelegate>
- (id)init;
-- (void) advertiseBrowses:(serviceHash_t) browseHash andRegistrations:(serviceHash_t) registeredHash;
+- (void) updateBeacon:(serviceHash_t) bloomFilter;
+- (void) startBeacon;
+- (bool) isBeaconing;
- (void) stopBeacon;
-- (void) updateScan:(bool) start;
+- (void) startScan;
+- (void) stopScan;
@end
+#endif // ENABLE_BLE_TRIGGERED_BONJOUR
+
#endif /* _coreBLE_H_ */
diff --git a/mDNSResponder/mDNSMacOSX/coreBLE.m b/mDNSResponder/mDNSMacOSX/coreBLE.m
index e764169a..8af8422c 100644
--- a/mDNSResponder/mDNSMacOSX/coreBLE.m
+++ b/mDNSResponder/mDNSMacOSX/coreBLE.m
@@ -15,6 +15,8 @@
* limitations under the License.
*/
+#if ENABLE_BLE_TRIGGERED_BONJOUR
+
#include "mDNSEmbeddedAPI.h"
#include "DNSCommon.h"
@@ -28,31 +30,51 @@
static coreBLE * coreBLEptr;
// Call Bluetooth subsystem to start/stop the the Bonjour BLE beacon and
-// beacon scanning based on the current browse and registration hashes.
-void updateBLEBeaconAndScan(serviceHash_t browseHash, serviceHash_t registeredHash)
+// beacon scanning based on the current Bloom filter.
+void updateBLEBeacon(serviceHash_t bloomFilter)
{
if (coreBLEptr == 0)
coreBLEptr = [[coreBLE alloc] init];
- LogInfo("updateBLEBeaconAndScan: browseHash = 0x%x, registeredHash = 0x%x", browseHash, registeredHash);
+ LogInfo("updateBLEBeacon: bloomFilter = 0x%lx", bloomFilter);
- [coreBLEptr advertiseBrowses:browseHash andRegistrations: registeredHash];
- [coreBLEptr updateScan:(browseHash || registeredHash)];
+ [coreBLEptr updateBeacon:bloomFilter];
}
// Stop the current BLE beacon.
void stopBLEBeacon(void)
{
if (coreBLEptr == 0)
- {
- LogInfo("stopBLEBeacon called before BLE scan initialized ??");
- return;
- }
+ coreBLEptr = [[coreBLE alloc] init];
- LogInfo("stopBLEBeacon Stopping beacon");
[coreBLEptr stopBeacon];
}
+bool currentlyBeaconing(void)
+{
+ if (coreBLEptr == 0)
+ coreBLEptr = [[coreBLE alloc] init];
+
+ return [coreBLEptr isBeaconing];
+}
+
+// Start the scan.
+void startBLEScan(void)
+{
+ if (coreBLEptr == 0)
+ coreBLEptr = [[coreBLE alloc] init];
+ [coreBLEptr startScan];
+}
+
+// Stop the scan.
+void stopBLEScan(void)
+{
+ if (coreBLEptr == 0)
+ coreBLEptr = [[coreBLE alloc] init];
+
+ [coreBLEptr stopScan];
+}
+
@implementation coreBLE
{
CBCentralManager *_centralManager;
@@ -60,9 +82,11 @@ void stopBLEBeacon(void)
NSData *_currentlyAdvertisedData;
- // [_centralManager isScanning] is only avilable on iOS and not OSX,
+ // [_centralManager isScanning] is only available on iOS and not OSX,
// so track scanning state locally.
BOOL _isScanning;
+ BOOL _centralManagerIsOn;
+ BOOL _peripheralManagerIsOn;
}
- (id)init
@@ -75,6 +99,8 @@ void stopBLEBeacon(void)
_peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()];
_currentlyAdvertisedData = nil;
_isScanning = NO;
+ _centralManagerIsOn = NO;
+ _peripheralManagerIsOn = NO;
if (_centralManager == nil || _peripheralManager == nil )
{
@@ -82,7 +108,7 @@ void stopBLEBeacon(void)
}
else
{
- LogInfo("coreBLE initialised");
+ LogInfo("coreBLE initialized");
}
}
@@ -92,7 +118,7 @@ void stopBLEBeacon(void)
#define ADVERTISEMENTDATALENGTH 28 // 31 - 3 (3 bytes for flags)
// TODO:
-// DBDeviceTypeBonjour should eventually be added to the DBDeviceType definitions in WirelessProximity
+// Define DBDeviceTypeBonjour for prototyping until we move to the TDS beacon format.
// The Bluetooth team recommended using a value < 32 for prototyping, since 32 is the number of
// beacon types they can track in their duplicate beacon filtering logic.
#define DBDeviceTypeBonjour 26
@@ -106,27 +132,31 @@ extern mDNSInterfaceID AWDLInterfaceID;
// Transmit the last beacon indicating we are no longer advertising or browsing any services for two seconds.
#define LastBeaconTime 2
-- (void) advertiseBrowses:(serviceHash_t) browseHash andRegistrations:(serviceHash_t) registeredHash
+- (void) updateBeacon:(serviceHash_t) bloomFilter
{
uint8_t advertisingData[ADVERTISEMENTDATALENGTH] = {0, 0xff, 0x4c, 0x00 };
uint8_t advertisingLength = 4;
- // TODO: If we have been transmitting a beacon, we probably want to continue transmitting
- // for a few seconds after both hashes are zero so that that any devices scanning
- // can see the beacon indicating we have stopped all browses and advertisements.
-
- // Stop the beacon if there is no data to advertise.
- if (browseHash == 0 && registeredHash == 0)
+ // If no longer browsing or advertising, beacon this state for 'LastBeaconTime' seconds
+ // so that peers have a chance to notice the state change.
+ if (bloomFilter == 0)
{
- LogInfo("advertiseBrowses:andRegistrations Stopping beacon in %d seconds", LastBeaconTime);
- if (mDNSStorage.NextBLEServiceTime)
- LogInfo("advertiseBrowses:andRegistrations: NextBLEServiceTime already set ??");
+ LogInfo("updateBeacon: Stopping beacon in %d seconds", LastBeaconTime);
- mDNSStorage.NextBLEServiceTime = NonZeroTime(mDNS_TimeNow_NoLock(& mDNSStorage) + LastBeaconTime * mDNSPlatformOneSecond);
+ if (mDNSStorage.timenow == 0)
+ {
+ // This should never happen since all calling code paths should have called mDNS_Lock(), which
+ // initializes the mDNSStorage.timenow value.
+ LogMsg("updateBeacon: NOTE, timenow == 0 ??");
+ }
+
+ mDNSStorage.NextBLEServiceTime = NonZeroTime(mDNSStorage.timenow + (LastBeaconTime * mDNSPlatformOneSecond));
+ finalBeacon = true;
}
else
{
- mDNSStorage.NextBLEServiceTime = 0;
+ // Cancel any pending final beacon processing.
+ finalBeacon = false;
}
// The beacon type.
@@ -135,17 +165,14 @@ extern mDNSInterfaceID AWDLInterfaceID;
// Flags and Version field
advertisingData[advertisingLength++] = BonjourBLEVersion;
- memcpy(& advertisingData[advertisingLength], & browseHash, sizeof(serviceHash_t));
+ memcpy(& advertisingData[advertisingLength], & bloomFilter, sizeof(serviceHash_t));
advertisingLength += sizeof(serviceHash_t);
- memcpy(& advertisingData[advertisingLength], & registeredHash, sizeof(serviceHash_t));
- advertisingLength += sizeof(serviceHash_t);
-
// Add the MAC address of the awdl0 interface. Don't cache it since
// it can get updated periodically.
if (AWDLInterfaceID)
{
- NetworkInterfaceInfoOSX *intf = IfindexToInterfaceInfoOSX(& mDNSStorage, AWDLInterfaceID);
+ NetworkInterfaceInfoOSX *intf = IfindexToInterfaceInfoOSX(AWDLInterfaceID);
if (intf)
memcpy(& advertisingData[advertisingLength], & intf->ifinfo.MAC, sizeof(mDNSEthAddr));
else
@@ -153,63 +180,129 @@ extern mDNSInterfaceID AWDLInterfaceID;
}
else
{
- // just use zero if not avaiblable
+ // Just use zero if not avaiblable.
memset( & advertisingData[advertisingLength], 0, sizeof(mDNSEthAddr));
}
advertisingLength += sizeof(mDNSEthAddr);
- // Total length of data advertised, minus this lenght byte.
+ // Total length of data advertised, minus this length byte.
advertisingData[0] = (advertisingLength - 1);
- LogInfo("advertiseBrowses:andRegistrations advertisingLength = %d", advertisingLength);
+ LogInfo("updateBeacon: advertisingLength = %d", advertisingLength);
- NSData* data = [NSData dataWithBytes:advertisingData length:advertisingLength];
+ if (_currentlyAdvertisedData)
+ [_currentlyAdvertisedData release];
+ _currentlyAdvertisedData = [[NSData alloc] initWithBytes:advertisingData length:advertisingLength];
+ [self startBeacon];
+}
- if([_peripheralManager isAdvertising] && [data isEqualToData: _currentlyAdvertisedData])
+- (void) startBeacon
+{
+ if (!_peripheralManagerIsOn)
{
- // No need to restart the advertisement if it is already active with the same data.
- LogInfo("advertiseBrowses:andRegistrations: No change in advertised data");
+ LogInfo("startBeacon: Not starting beacon, CBPeripheralManager not powered on");
+ return;
}
- else
- {
- _currentlyAdvertisedData = data;
- if ([_peripheralManager isAdvertising])
- {
- LogInfo("advertiseBrowses:andRegistrations: Stop current advertisement before restarting");
- [_peripheralManager stopAdvertising];
- }
- LogInfo("advertiseBrowses:andRegistrations: Starting beacon");
+ if (_currentlyAdvertisedData == nil)
+ {
+ LogInfo("startBeacon: Not starting beacon, no data to advertise");
+ return;
+ }
- [_peripheralManager startAdvertising:@{ CBAdvertisementDataAppleMfgData : _currentlyAdvertisedData, CBCentralManagerScanOptionIsPrivilegedDaemonKey : @YES, @"kCBAdvOptionUseFGInterval" : @YES }];
+ if ([_peripheralManager isAdvertising])
+ {
+ LogInfo("startBeacon: Stop current beacon transmission before restarting");
+ [_peripheralManager stopAdvertising];
}
+ LogInfo("startBeacon: Starting beacon");
+
+#if 0 // Move to this code during Fall 2018 develelopment if still using these APIs.
+ [_peripheralManager startAdvertising:@{ CBAdvertisementDataAppleMfgData : _currentlyAdvertisedData, CBManagerIsPrivilegedDaemonKey : @YES, @"kCBAdvOptionUseFGInterval" : @YES }];
+#else
+ // While CBCentralManagerScanOptionIsPrivilegedDaemonKey is deprecated in current MobileBluetooth project, it's still defined in the current and
+ // previous train SDKs. Suppress deprecated warning for now since we intend to move to a different Bluetooth API to manage the BLE Triggered Bonjour
+ // beacons when this code is enabled by default.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+ [_peripheralManager startAdvertising:@{ CBAdvertisementDataAppleMfgData : _currentlyAdvertisedData, CBCentralManagerScanOptionIsPrivilegedDaemonKey : @YES, @"kCBAdvOptionUseFGInterval" : @YES }];
+#pragma GCC diagnostic pop
+#endif
+}
+
+- (bool) isBeaconing
+{
+ return (_currentlyAdvertisedData != nil);
}
- (void) stopBeacon
{
- [_peripheralManager stopAdvertising];
+ if (!_peripheralManagerIsOn)
+ {
+ LogInfo("stopBeacon: CBPeripheralManager is not powered on");
+ return;
+ }
+
+ // Only beaconing if we have advertised data to send.
+ if (_currentlyAdvertisedData)
+ {
+ LogInfo("stoptBeacon: Stopping beacon");
+ [_peripheralManager stopAdvertising];
+ [_currentlyAdvertisedData release];
+ _currentlyAdvertisedData = nil;
+ }
+ else
+ LogInfo("stoptBeacon: Note currently beaconing");
+}
+
+- (void) startScan
+{
+ if (!_centralManagerIsOn)
+ {
+ LogInfo("startScan: Not starting scan, CBCentralManager is not powered on");
+ return;
+ }
+
+ if (_isScanning)
+ {
+ LogInfo("startScan: already scanning, stopping scan before restarting");
+ [_centralManager stopScan];
+ }
+
+ LogInfo("startScan: Starting scan");
+
+ _isScanning = YES;
+
+#if 0 // Move to this code during Fall 2018 develelopment if still using these APIs.
+ [_centralManager scanForPeripheralsWithServices:nil options:@{ CBCentralManagerScanOptionAllowDuplicatesKey : @YES , CBManagerIsPrivilegedDaemonKey : @YES}];
+#else
+ // While CBCentralManagerScanOptionIsPrivilegedDaemonKey is deprecated in current MobileBluetooth project, it's still defined in the current and
+ // previous train SDKs. Suppress deprecated warning for now since we intend to move to a different Bluetooth API to manage the BLE Triggered Bonjour
+ // beacons when this code is enabled by default.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+ [_centralManager scanForPeripheralsWithServices:nil options:@{ CBCentralManagerScanOptionAllowDuplicatesKey : @YES , CBCentralManagerScanOptionIsPrivilegedDaemonKey : @YES}];
+#pragma GCC diagnostic pop
+#endif
}
-- (void) updateScan:(bool) start
+- (void) stopScan
{
+ if (!_centralManagerIsOn)
+ {
+ LogInfo("stopScan: Not stopping scan, CBCentralManager is not powered on");
+ return;
+ }
+
if (_isScanning)
{
- if (!start)
- {
- LogInfo("updateScan: stopping scan");
- [_centralManager stopScan];
- _isScanning = NO;
- }
+ LogInfo("stopScan: Stopping scan");
+ [_centralManager stopScan];
+ _isScanning = NO;
}
else
{
- if (start)
- {
- LogInfo("updateScan: starting scan");
-
- _isScanning = YES;
- [_centralManager scanForPeripheralsWithServices:nil options:@{ CBCentralManagerScanOptionAllowDuplicatesKey : @NO }];
- }
+ LogInfo("stopScan: Not currently scanning");
}
}
@@ -218,28 +311,40 @@ extern mDNSInterfaceID AWDLInterfaceID;
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
switch (central.state) {
- case CBCentralManagerStateUnknown:
- LogInfo("centralManagerDidUpdateState: CBCentralManagerStateUnknown");
+ case CBManagerStateUnknown:
+ LogInfo("centralManagerDidUpdateState: CBManagerStateUnknown");
break;
- case CBCentralManagerStateResetting:
- LogInfo("centralManagerDidUpdateState: CBCentralManagerStateResetting");
+ case CBManagerStateResetting:
+ LogInfo("centralManagerDidUpdateState: CBManagerStateResetting");
break;
- case CBCentralManagerStateUnsupported:
- LogInfo("centralManagerDidUpdateState: CBCentralManagerStateUnsupported");
+ case CBManagerStateUnsupported:
+ LogInfo("centralManagerDidUpdateState: CBManagerStateUnsupported");
break;
- case CBCentralManagerStateUnauthorized:
- LogInfo("centralManagerDidUpdateState: CBCentralManagerStateUnauthorized");
+ case CBManagerStateUnauthorized:
+ LogInfo("centralManagerDidUpdateState: CBManagerStateUnauthorized");
break;
- case CBCentralManagerStatePoweredOff:
- LogInfo("centralManagerDidUpdateState: CBCentralManagerStatePoweredOff");
+ case CBManagerStatePoweredOff:
+ LogInfo("centralManagerDidUpdateState: CBManagerStatePoweredOff");
break;
- case CBCentralManagerStatePoweredOn:
- LogInfo("centralManagerDidUpdateState: CBCentralManagerStatePoweredOn");
+ case CBManagerStatePoweredOn:
+ // Hold lock to synchronize with main thread from this callback thread.
+ KQueueLock();
+
+ LogInfo("centralManagerDidUpdateState: CBManagerStatePoweredOn");
+ _centralManagerIsOn = YES;
+ // Only start scan if we have data we will be transmitting or if "suppressBeacons"
+ // is set, indicating we should be scanning, but not beaconing.
+ if (_currentlyAdvertisedData || suppressBeacons)
+ [self startScan];
+ else
+ LogInfo("centralManagerDidUpdateState:: Not starting scan");
+
+ KQueueUnlock("CBManagerStatePoweredOn");
break;
default:
@@ -248,8 +353,8 @@ extern mDNSInterfaceID AWDLInterfaceID;
}
}
-// offset of beacon type in recieved CBAdvertisementDataManufacturerDataKey bytes
-#define beaconTypeByteIndex 2
+#define beaconTypeByteIndex 2 // Offset of beacon type in received CBAdvertisementDataManufacturerDataKey byte array.
+#define beaconDataLength 18 // Total number of bytes in the CBAdvertisementDataManufacturerDataKey.
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *, id> *)advertisementData RSSI:(NSNumber *)RSSI
{
@@ -259,7 +364,9 @@ extern mDNSInterfaceID AWDLInterfaceID;
NSData *data = [advertisementData objectForKey:CBAdvertisementDataManufacturerDataKey];
- if (!data) {
+ // Just return if the beacon data does not match what we are looking for.
+ if (!data || ([data length] != beaconDataLength))
+ {
return;
}
@@ -268,8 +375,8 @@ extern mDNSInterfaceID AWDLInterfaceID;
// Just parse the DBDeviceTypeBonjour beacons.
if (bytes[beaconTypeByteIndex] == DBDeviceTypeBonjour)
{
- serviceHash_t browseHash, registeredHash;
- mDNSEthAddr senderMAC;
+ serviceHash_t peerBloomFilter;
+ mDNSEthAddr peerMAC;
unsigned char flagsAndVersion;
unsigned char *ptr;
@@ -279,41 +386,25 @@ extern mDNSInterfaceID AWDLInterfaceID;
#endif // VERBOSE_BLE_DEBUG
// The DBDeviceTypeBonjour beacon bytes will be:
- // x4C, 0x0, 0x2A, flags_and_version_byte,, browseHash, advertisingServices_hash_bytes,
- // 6_bytes_of_sender_AWDL_MAC_address
+ // 0x4C (1 byte), 0x0 (1 byte), DBDeviceTypeBonjour byte, flags and version byte, 8 byte Bloom filter,
+ // 6 byte sender AWDL MAC address
ptr = & bytes[beaconTypeByteIndex + 1];
flagsAndVersion = *ptr++;
- memcpy(& browseHash, ptr, sizeof(serviceHash_t));
+ memcpy(& peerBloomFilter, ptr, sizeof(serviceHash_t));
ptr += sizeof(serviceHash_t);
- memcpy(& registeredHash, ptr, sizeof(serviceHash_t));
- ptr += sizeof(serviceHash_t);
- memcpy(& senderMAC, ptr, sizeof(senderMAC));
+ memcpy(& peerMAC, ptr, sizeof(peerMAC));
#if VERBOSE_BLE_DEBUG
- LogInfo("didDiscoverPeripheral: version = 0x%x, browseHash = 0x%x, registeredHash = 0x%x",
- flagsAndVersion, browseHash, registeredHash);
+ LogInfo("didDiscoverPeripheral: version = 0x%x, peerBloomFilter = 0x%x",
+ flagsAndVersion, peerBloomFilter);
LogInfo("didDiscoverPeripheral: sender MAC = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
- senderMAC.b[0], senderMAC.b[1], senderMAC.b[2], senderMAC.b[3], senderMAC.b[4], senderMAC.b[5]);
+ peerMAC.b[0], peerMAC.b[1], peerMAC.b[2], peerMAC.b[3], peerMAC.b[4], peerMAC.b[5]);
#else
(void)flagsAndVersion; // Unused
#endif // VERBOSE_BLE_DEBUG
- responseReceived(browseHash, registeredHash, & senderMAC);
-
-#if VERBOSE_BLE_DEBUG
- // Log every 4th package during debug
- static int pkgsIn = 0;
-
- if (((pkgsIn++) & 3) == 0)
- {
- LogInfo("0x%x 0x%x 0x%x 0x%x 0x%x", bytes[0], bytes[1], bytes[2], bytes[3], bytes[4]);
-// LogInfo("0x%x 0x%x 0x%x 0x%x 0x%x", bytes[5], bytes[6], bytes[7], bytes[9], bytes[9]);
-// LogInfo("0x%x 0x%x 0x%x 0x%x 0x%x", bytes[10], bytes[11], bytes[12], bytes[13], bytes[14]);
-// LogInfo("0x%x 0x%x 0x%x 0x%x 0x%x", bytes[15], bytes[16], bytes[17], bytes[18], bytes[19]);
- }
-#endif // VERBOSE_BLE_DEBUG
-
+ responseReceived(peerBloomFilter, & peerMAC);
}
}
@@ -323,28 +414,38 @@ extern mDNSInterfaceID AWDLInterfaceID;
{
switch (peripheral.state) {
- case CBPeripheralManagerStateUnknown:
- LogInfo("peripheralManagerDidUpdateState: CBPeripheralManagerStateUnknown");
+ case CBManagerStateUnknown:
+ LogInfo("peripheralManagerDidUpdateState: CBManagerStateUnknown");
break;
- case CBPeripheralManagerStateResetting:
- LogInfo("peripheralManagerDidUpdateState: CBPeripheralManagerStateResetting");
+ case CBManagerStateResetting:
+ LogInfo("peripheralManagerDidUpdateState: CBManagerStateResetting");
break;
- case CBPeripheralManagerStateUnsupported:
- LogInfo("peripheralManagerDidUpdateState: CBPeripheralManagerStateUnsupported");
+ case CBManagerStateUnsupported:
+ LogInfo("peripheralManagerDidUpdateState: CBManagerStateUnsupported");
break;
- case CBPeripheralManagerStateUnauthorized:
- LogInfo("peripheralManagerDidUpdateState: CBPeripheralManagerStateUnauthorized");
+ case CBManagerStateUnauthorized:
+ LogInfo("peripheralManagerDidUpdateState: CBManagerStateUnauthorized");
break;
- case CBPeripheralManagerStatePoweredOff:
- LogInfo("peripheralManagerDidUpdateState: CBPeripheralManagerStatePoweredOff");
+ case CBManagerStatePoweredOff:
+ LogInfo("peripheralManagerDidUpdateState: CBManagerStatePoweredOff");
break;
- case CBPeripheralManagerStatePoweredOn:
- LogInfo("peripheralManagerDidUpdateState: CBPeripheralManagerStatePoweredOn");
+ case CBManagerStatePoweredOn:
+ // Hold lock to synchronize with main thread from this callback thread.
+ KQueueLock();
+
+ LogInfo("peripheralManagerDidUpdateState: CBManagerStatePoweredOn");
+ _peripheralManagerIsOn = YES;
+
+ // Start beaconing if we have initialized beacon data to send.
+ if (_currentlyAdvertisedData)
+ [self startBeacon];
+
+ KQueueUnlock("CBManagerStatePoweredOn");
break;
default:
@@ -369,3 +470,4 @@ extern mDNSInterfaceID AWDLInterfaceID;
}
@end
+#endif // ENABLE_BLE_TRIGGERED_BONJOUR
diff --git a/mDNSResponder/mDNSMacOSX/daemon.c b/mDNSResponder/mDNSMacOSX/daemon.c
index f3f00ca7..5dece763 100644
--- a/mDNSResponder/mDNSMacOSX/daemon.c
+++ b/mDNSResponder/mDNSMacOSX/daemon.c
@@ -32,7 +32,10 @@
#include <SystemConfiguration/SCDynamicStoreCopyDHCPInfo.h>
#include <err.h>
#include <sysexits.h>
-#include <dlfcn.h>
+
+#ifdef UNIT_TEST
+#include "unittest.h"
+#endif
#include "uDNS.h"
#include "DNSCommon.h"
@@ -63,7 +66,15 @@ static os_log_t log_general = NULL;
#define kPreferencesKey_StrictUnicastOrdering CFSTR("StrictUnicastOrdering")
#define kPreferencesKey_OfferSleepProxyService CFSTR("OfferSleepProxyService")
#define kPreferencesKey_UseInternalSleepProxy CFSTR("UseInternalSleepProxy")
+
+#if ENABLE_BLE_TRIGGERED_BONJOUR
#define kPreferencesKey_EnableBLEBasedDiscovery CFSTR("EnableBLEBasedDiscovery")
+#define kPreferencesKey_DefaultToBLETriggered CFSTR("DefaultToBLETriggered")
+#endif // ENABLE_BLE_TRIGGERED_BONJOUR
+
+#if TARGET_OS_IPHONE
+#define kPreferencesKey_PreallocateCacheMemory CFSTR("PreallocateCacheMemory")
+#endif
#endif
//*************************************************************************************************************
@@ -75,11 +86,12 @@ static mDNS_PlatformSupport PlatformStorage;
// Start off with a default cache of 32K (141 records of 232 bytes each)
// Each time we grow the cache we add another 141 records
-// 141 * 164 = 32712 bytes.
+// 141 * 232 = 32712 bytes.
// This fits in eight 4kB pages, with 56 bytes spare for memory block headers and similar overhead
#define RR_CACHE_SIZE ((32*1024) / sizeof(CacheRecord))
static CacheEntity rrcachestorage[RR_CACHE_SIZE];
struct CompileTimeAssertionChecks_RR_CACHE_SIZE { char a[(RR_CACHE_SIZE >= 141) ? 1 : -1]; };
+#define kRRCacheGrowSize (sizeof(CacheEntity) * RR_CACHE_SIZE)
#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
@@ -95,7 +107,16 @@ static mDNSBool NoMulticastAdvertisements = mDNSfalse; // By default, advertise
extern mDNSBool StrictUnicastOrdering;
extern mDNSBool AlwaysAppendSearchDomains;
+
+#if ENABLE_BLE_TRIGGERED_BONJOUR
extern mDNSBool EnableBLEBasedDiscovery;
+extern mDNSBool DefaultToBLETriggered;
+#endif // ENABLE_BLE_TRIGGERED_BONJOUR
+
+#if TARGET_OS_IPHONE
+static mDNSBool PreallocateCacheMemory = mDNSfalse;
+#define kRRCacheMemoryLimit 1000000 // For now, we limit the cache to at most 1MB on iOS devices.
+#endif
// We keep a list of client-supplied event sources in KQSocketEventSource records
typedef struct KQSocketEventSource
@@ -103,6 +124,8 @@ typedef struct KQSocketEventSource
struct KQSocketEventSource *next;
int fd;
KQueueEntry kqs;
+ udsEventCallback callback;
+ void *context;
} KQSocketEventSource;
static KQSocketEventSource *gEventSources;
@@ -258,13 +281,14 @@ mDNSexport void freeL(char *msg, void *x)
//*************************************************************************************************************
// Registration
-mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
+mDNSexport void RecordUpdatedNiceLabel(mDNSs32 delay)
{
- m->p->NotifyUser = NonZeroTime(m->timenow + delay);
+ mDNSStorage.p->NotifyUser = NonZeroTime(mDNSStorage.timenow + delay);
}
-mDNSlocal void mDNSPreferencesSetNames(mDNS *const m, int key, domainlabel *old, domainlabel *new)
+mDNSlocal void mDNSPreferencesSetNames(int key, domainlabel *old, domainlabel *new)
{
+ mDNS *const m = &mDNSStorage;
domainlabel *prevold, *prevnew;
switch (key)
{
@@ -327,13 +351,12 @@ mDNSlocal void mDNSPreferencesSetNames(mDNS *const m, int key, domainlabel *old,
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);
+ RecordUpdatedNiceLabel(mDNSPlatformOneSecond);
}
else if (result == mStatus_NameConflict)
{
@@ -342,7 +365,7 @@ mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
else if (m->timenow - m->p->HostNameConflict > 60 * mDNSPlatformOneSecond)
{
// Tell the helper we've given up
- mDNSPreferencesSetNames(m, kmDNSLocalHostName, &m->p->userhostlabel, NULL);
+ mDNSPreferencesSetNames(kmDNSLocalHostName, &m->p->userhostlabel, NULL);
}
}
else if (result == mStatus_GrowCache)
@@ -350,9 +373,9 @@ mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
// Allocate another chunk of cache storage
static unsigned int allocated = 0;
#if TARGET_OS_IPHONE
- if (allocated >= 1000000) return; // For now we limit the cache to at most 1MB on iOS devices
+ if (allocated >= kRRCacheMemoryLimit) return; // For now we limit the cache to at most 1MB on iOS devices
#endif
- allocated += sizeof(CacheEntity) * RR_CACHE_SIZE;
+ allocated += kRRCacheGrowSize;
// LogMsg("GrowCache %d * %d = %d; total so far %6u", sizeof(CacheEntity), RR_CACHE_SIZE, sizeof(CacheEntity) * RR_CACHE_SIZE, allocated);
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);
@@ -361,8 +384,8 @@ mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
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);
+ mDNSPreferencesSetNames(kmDNSComputerName, &m->p->usernicelabel, &m->nicelabel);
+ mDNSPreferencesSetNames(kmDNSLocalHostName, &m->p->userhostlabel, &m->hostlabel);
// Then we call into the UDS daemon code, to let it do the same
udsserver_handle_configchange(m);
@@ -425,7 +448,7 @@ mDNSexport void INFOCallback(void)
LogMsg("---- BEGIN STATE LOG ---- %s %s %d", mDNSResponderVersionString, OSXVers ? "OSXVers" : "iOSVers", OSXVers ? OSXVers : iOSVers);
- udsserver_info(&mDNSStorage);
+ udsserver_info();
LogMsgNoIdent("----- Platform Timers -----");
LogTimer("m->NextCacheCheck ", mDNSStorage.NextCacheCheck);
@@ -449,33 +472,38 @@ mDNSexport void INFOCallback(void)
if (!mDNSStorage.p->InterfaceList) LogMsgNoIdent("<None>");
else
{
+ LogMsgNoIdent(" Struct addr Registered MAC BSSID Interface Address");
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",
+ LogMsgNoIdent("%p %2ld, %p, %s %-6s %.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->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifinfo.ifname, &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",
+ LogMsgNoIdent("%p %2ld, %p, %s %-6s %.6a %.6a %s %s %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->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifinfo.ifname, &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);
+ // Only print the discovered sleep proxies once for the lead/active interface of an interface set.
+ if (i == i->Registered && (sps[0] || sps[1] || sps[2]))
+ {
+ LogMsgNoIdent(" Sleep Proxy Metric Name");
+ 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);
+ }
}
}
}
@@ -486,14 +514,15 @@ mDNSexport void INFOCallback(void)
{
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",
+ NetworkInterfaceInfoOSX *ifx = IfindexToInterfaceInfoOSX(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->req_A ? "v4" : "!v4",
s->req_AAAA ? "v6" : "!v6",
s->cellIntf ? "cell" : "!cell",
+ s->isExpensive ? "exp" : "!exp",
s->DNSSECAware ? "DNSSECAware" : "!DNSSECAware");
}
}
@@ -612,7 +641,7 @@ mDNSlocal void SignalCallback(CFMachPortRef port, void *msg, CFIndex size, void
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);
+ KQueueLock();
switch(msg_header->msgh_id)
{
case SIGHUP: {
@@ -658,7 +687,7 @@ mDNSlocal void SignalCallback(CFMachPortRef port, void *msg, CFIndex size, void
break;
case SIGPROF: mDNS_McastLoggingEnabled = mDNS_McastLoggingEnabled ? mDNSfalse : mDNStrue;
LogMsg("SIGPROF: Multicast Logging %s", mDNS_McastLoggingEnabled ? "Enabled" : "Disabled");
- LogMcastStateInfo(m, mDNSfalse, mDNStrue, mDNStrue);
+ LogMcastStateInfo(mDNSfalse, mDNStrue, mDNStrue);
mDNS_McastTracingEnabled = (mDNS_PacketLoggingEnabled && mDNS_McastLoggingEnabled) ? mDNStrue : mDNSfalse;
LogMsg("SIGPROF: Multicast Tracing is %s", mDNS_McastTracingEnabled ? "Enabled" : "Disabled");
UpdateDebugState();
@@ -670,7 +699,7 @@ mDNSlocal void SignalCallback(CFMachPortRef port, void *msg, CFIndex size, void
default: LogMsg("SignalCallback: Unknown signal %d", msg_header->msgh_id); break;
}
- KQueueUnlock(m, "Unix Signal");
+ KQueueUnlock("Unix Signal");
}
// MachServerName is com.apple.mDNSResponder (Supported only till 10.9.x)
@@ -689,6 +718,19 @@ mDNSlocal kern_return_t mDNSDaemonInitialize(void)
return(err);
}
+#if TARGET_OS_IPHONE
+ if (PreallocateCacheMemory)
+ {
+ const int growCount = (kRRCacheMemoryLimit + kRRCacheGrowSize - 1) / kRRCacheGrowSize;
+ int i;
+
+ for (i = 0; i < growCount; ++i)
+ {
+ mDNS_StatusCallback(&mDNSStorage, mStatus_GrowCache);
+ }
+ }
+#endif
+
CFMachPortRef i_port = CFMachPortCreate(NULL, SignalCallback, NULL, NULL);
CFRunLoopSourceRef i_rls = CFMachPortCreateRunLoopSource(NULL, i_port, 0);
signal_port = CFMachPortGetPort(i_port);
@@ -710,7 +752,7 @@ mDNSlocal void SignalDispatch(dispatch_source_t source)
{
int sig = (int)dispatch_source_get_handle(source);
mDNS *const m = &mDNSStorage;
- KQueueLock(m);
+ KQueueLock();
switch(sig)
{
case SIGHUP: {
@@ -741,7 +783,7 @@ mDNSlocal void SignalDispatch(dispatch_source_t source)
break;
default: LogMsg("SignalCallback: Unknown signal %d", sig); break;
}
- KQueueUnlock(m, "Unix Signal");
+ KQueueUnlock("Unix Signal");
}
mDNSlocal void mDNSSetupSignal(dispatch_queue_t queue, int sig)
@@ -834,7 +876,7 @@ mDNSlocal mDNSs32 mDNSDaemonIdle(mDNS *const m)
// 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->NetworkChanged && now - m->NetworkChanged >= 0) mDNSMacOSXNetworkChanged(m);
+ if (m->NetworkChanged && now - m->NetworkChanged >= 0) mDNSMacOSXNetworkChanged();
if (m->p->RequestReSleep && now - m->p->RequestReSleep >= 0)
{
@@ -865,13 +907,13 @@ mDNSlocal mDNSs32 mDNSDaemonIdle(mDNS *const m)
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);
+ mDNSPreferencesSetNames(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);
+ mDNSPreferencesSetNames(kmDNSLocalHostName, &m->p->userhostlabel, &m->hostlabel);
m->p->HostNameConflict = 0; // Clear our indicator, now name change has been successful
m->p->userhostlabel = m->hostlabel;
}
@@ -964,8 +1006,9 @@ mDNSlocal mDNSu32 DHCPWakeTime(void)
// 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)
+mDNSlocal mDNSBool AllowSleepNow(mDNSs32 now)
{
+ mDNS *const m = &mDNSStorage;
mDNSBool ready = mDNSCoreReadyForSleep(m, now);
if (m->SleepState && !ready && now - m->SleepLimit < 0) return(mDNSfalse);
@@ -1066,7 +1109,7 @@ mDNSlocal mDNSBool AllowSleepNow(mDNS *const m, mDNSs32 now)
m->SleepState = SleepState_Sleeping;
// Clear our interface list to empty state, ready to go to sleep
// As a side effect of doing this, we'll also cancel any outstanding SPS Resolve calls that didn't complete
- mDNSMacOSXNetworkChanged(m);
+ mDNSMacOSXNetworkChanged();
}
LogSPS("AllowSleepNow: %s(%lX) %s at %ld (%d ticks remaining)",
@@ -1079,15 +1122,6 @@ mDNSlocal mDNSBool AllowSleepNow(mDNS *const m, mDNSs32 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
@@ -1149,7 +1183,7 @@ mDNSlocal void PrepareForIdle(void *m_param)
}
if (m->SleepLimit)
- if (!AllowSleepNow(m, now))
+ if (!AllowSleepNow(now))
if (nextTimerEvent - m->SleepLimit >= 0)
nextTimerEvent = m->SleepLimit;
@@ -1175,7 +1209,7 @@ mDNSlocal void PrepareForIdle(void *m_param)
#else // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
-mDNSlocal void KQWokenFlushBytes(int fd, __unused short filter, __unused void *context)
+mDNSlocal void KQWokenFlushBytes(int fd, __unused short filter, __unused void *context, __unused mDNSBool encounteredEOF)
{
// Read all of the bytes so we won't wake again.
char buffer[100];
@@ -1253,7 +1287,7 @@ mDNSlocal void * KQueueLoop(void *m_param)
}
if (m->SleepLimit)
- if (!AllowSleepNow(m, now))
+ if (!AllowSleepNow(now))
if (nextTimerEvent - m->SleepLimit >= 0)
nextTimerEvent = m->SleepLimit;
@@ -1339,7 +1373,7 @@ mDNSlocal void * KQueueLoop(void *m_param)
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);
+ kqentry->KQcallback(new_events[i].ident, new_events[i].filter, kqentry->KQcontext, (new_events[i].flags & EV_EOF) != 0);
mDNSs32 etime = mDNSPlatformRawTime();
if (etime - stime >= WatchDogReportingThreshold)
LogInfo("WARNING: %s took %dms to complete", KQtask, etime - stime);
@@ -1441,18 +1475,10 @@ mDNSlocal void init_logging(void)
}
#endif
-#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
-mDNSlocal mDNSBool initialize_networkserviceproxy(void)
-{
- void *NSPImage = dlopen("/System/Library/PrivateFrameworks/NetworkServiceProxy.framework/NetworkServiceProxy", RTLD_LAZY | RTLD_LOCAL);
- if (NSPImage == NULL) {
- os_log_error(OS_LOG_DEFAULT, "dlopen NetworkServiceProxy.framework failed");
- return mDNSfalse;
- }
- return mDNStrue;
-}
-#endif
-
+#ifdef UNIT_TEST
+// Run the unit test main
+UNITTEST_MAIN
+#else
mDNSexport int main(int argc, char **argv)
{
int i;
@@ -1543,7 +1569,15 @@ mDNSexport int main(int argc, char **argv)
AlwaysAppendSearchDomains = PreferencesGetValueBool(kPreferencesKey_AlwaysAppendSearchDomains, AlwaysAppendSearchDomains);
OfferSleepProxyService = PreferencesGetValueInt(kPreferencesKey_OfferSleepProxyService, OfferSleepProxyService);
UseInternalSleepProxy = PreferencesGetValueInt(kPreferencesKey_UseInternalSleepProxy, UseInternalSleepProxy);
+
+#if ENABLE_BLE_TRIGGERED_BONJOUR
EnableBLEBasedDiscovery = PreferencesGetValueBool(kPreferencesKey_EnableBLEBasedDiscovery, EnableBLEBasedDiscovery);
+ DefaultToBLETriggered = PreferencesGetValueBool(kPreferencesKey_DefaultToBLETriggered, DefaultToBLETriggered);
+#endif // ENABLE_BLE_TRIGGERED_BONJOUR
+
+#if TARGET_OS_IPHONE
+ PreallocateCacheMemory = PreferencesGetValueBool(kPreferencesKey_PreallocateCacheMemory, PreallocateCacheMemory);
+#endif
#endif
// Note that mDNSPlatformInit will set DivertMulticastAdvertisements in the mDNS structure
@@ -1621,15 +1655,9 @@ mDNSexport int main(int argc, char **argv)
status = udsserver_init(launchd_fds, launchd_fds_count);
if (status) { LogMsg("Daemon start: udsserver_init failed"); goto exit; }
- mDNSMacOSXNetworkChanged(&mDNSStorage);
+ mDNSMacOSXNetworkChanged();
UpdateDebugState();
-#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
- if (initialize_networkserviceproxy() == mDNSfalse) {
- LogMsg("Failed to initialize NetworkServiceProxy");
- }
-#endif
-
#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
LogInfo("Daemon Start: Using LibDispatch");
// CFRunLoopRun runs both CFRunLoop sources and dispatch sources
@@ -1652,9 +1680,16 @@ mDNSexport int main(int argc, char **argv)
exit:
return(status);
}
+#endif // UNIT_TEST
// uds_daemon.c support routines /////////////////////////////////////////////
+mDNSlocal void kqUDSEventCallback(int fd, short filter, void *context, __unused mDNSBool encounteredEOF)
+{
+ const KQSocketEventSource *const source = context;
+ source->callback(fd, filter, source->context);
+}
+
// 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)
{
@@ -1668,8 +1703,10 @@ mDNSexport mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback,
newSource->next = mDNSNULL;
newSource->fd = fd;
- newSource->kqs.KQcallback = callback;
- newSource->kqs.KQcontext = context;
+ newSource->callback = callback;
+ newSource->context = context;
+ newSource->kqs.KQcallback = kqUDSEventCallback;
+ newSource->kqs.KQcontext = newSource;
newSource->kqs.KQtask = "UDS client";
#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
newSource->kqs.readSource = mDNSNULL;
@@ -1713,6 +1750,10 @@ mDNSexport mStatus udsSupportRemoveFDFromEventLoop(int fd, void *platform_data)
return mStatus_NoSuchNameErr;
}
+#ifdef UNIT_TEST
+#include "../unittests/daemon_ut.c"
+#endif // UNIT_TEST
+
#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;
diff --git a/mDNSResponder/mDNSMacOSX/mDNSMacOSX.c b/mDNSResponder/mDNSMacOSX/mDNSMacOSX.c
index 84e9de8c..ced72a69 100644
--- a/mDNSResponder/mDNSMacOSX/mDNSMacOSX.c
+++ b/mDNSResponder/mDNSMacOSX/mDNSMacOSX.c
@@ -29,7 +29,7 @@
#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 "dns_sd_private.h"
+#include "dns_sd_internal.h"
#include "PlatformCommon.h"
#include "uds_daemon.h"
#include "CryptoSupport.h"
@@ -83,7 +83,6 @@
#include "helper.h"
#include "P2PPacketFilter.h"
-#include <asl.h>
#include <SystemConfiguration/SCPrivate.h>
#if TARGET_OS_IPHONE
@@ -95,32 +94,12 @@
// Include definition of opaque_presence_indication for KEV_DL_NODE_PRESENCE handling logic.
#include <Kernel/IOKit/apple80211/apple80211_var.h>
+#include <network_information.h> // for nwi_state
#if APPLE_OSX_mDNSResponder
-#include <DeviceToDeviceManager/DeviceToDeviceManager.h>
#include <AWACS.h>
#include <ne_session.h> // for ne_session_set_socket_attributes()
-#if !NO_D2D
-#include "BLE.h"
-
-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));
-
-void xD2DAddToCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize);
-void xD2DRemoveFromCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize);
-
-#endif // ! NO_D2D
-
#else
-#define NO_D2D 1
#define NO_AWACS 1
#endif // APPLE_OSX_mDNSResponder
@@ -128,6 +107,10 @@ void xD2DRemoveFromCache(mDNS *const m, D2DStatus result, D2DServiceInstance ins
#include <IOKit/platform/IOPlatformSupportPrivate.h>
#endif // APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
+#ifdef UNIT_TEST
+#include "unittest.h"
+#endif
+
#define kInterfaceSpecificOption "interface="
#define mDNS_IOREG_KEY "mDNS_KEY"
@@ -207,952 +190,6 @@ const char dnsprefix[] = "dns:";
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, 0);
- if (interface->RR_PTR.resrec.RecordType)
- external_start_advertising_service(&interface->RR_PTR.resrec, 0);
- }
-}
-
-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, 0);
- if (interface->RR_PTR.resrec.RecordType)
- external_stop_advertising_service(&interface->RR_PTR.resrec, 0);
- }
-}
-
-// If record would have been advertised to the D2D plugin layer, stop that advertisement.
-mDNSexport void D2D_stop_advertising_record(AuthRecord *ar)
-{
- DNSServiceFlags flags = deriveD2DFlagsFromAuthRecType(ar->ARType);
- if (callExternalHelpers(ar->resrec.InterfaceID, ar->resrec.name, flags))
- {
- external_stop_advertising_service(&ar->resrec, flags);
- }
-}
-
-// If record should be advertised to the D2D plugin layer, start that advertisement.
-mDNSexport void D2D_start_advertising_record(AuthRecord *ar)
-{
- DNSServiceFlags flags = deriveD2DFlagsFromAuthRecType(ar->ARType);
- if (callExternalHelpers(ar->resrec.InterfaceID, ar->resrec.name, flags))
- {
- external_start_advertising_service(&ar->resrec, flags);
- }
-}
-
-// 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 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))
- {
- LogInfo("xD2DClearCache: Clearing cache record and deregistering %s", ARDisplayString(&mDNSStorage, &ptr->ar));
- mDNS_Deregister(&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);
-}
-
-// Returns true if found in list, false otherwise
-mDNSlocal bool 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 false; }
-
- (*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);
- }
- return true;
-}
-
-mDNSlocal mStatus xD2DParse(mDNS *const m, const mDNSu8 * const lhs, const mDNSu16 lhs_len, const mDNSu8 * const rhs, const mDNSu16 rhs_len, D2DRecordListElem **D2DListp)
-{
- // Sanity check that key array (lhs) has one domain name, followed by the record type and single byte D2D
- // plugin protocol version number.
- // Note, we don't have a DNSMessage pointer at this point, so just pass in the lhs value as the lower bound
- // of the input bytes we are processing. skipDomainName() does not try to follow name compression pointers,
- // so it is safe to pass it the key byte array since it will stop parsing the DNS name and return a pointer
- // to the byte after the first name compression pointer it encounters.
- const mDNSu8 *keyp = skipDomainName((const DNSMessage *const) lhs, lhs, lhs + lhs_len);
-
- // There should be 3 bytes remaining in a valid key,
- // two for the DNS record type, and one for the D2D protocol version number.
- if (keyp == NULL || (keyp + 3 != (lhs + lhs_len)))
- {
- LogInfo("xD2DParse: Could not parse DNS name in key");
- return mStatus_Incompatible;
- }
- keyp += 2; // point to D2D compression packet format version byte
- if (*keyp != compression_packet_v1)
- {
- LogInfo("xD2DParse: Invalid D2D packet version: %d", *keyp);
- return mStatus_Incompatible;
- }
-
- 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("xD2DParse: failed to get large RR");
- m->rec.r.resrec.RecordType = 0;
- return mStatus_UnknownErr;
- }
- else
- {
- LogInfo("xD2DParse: got rr: %s", CRDisplayString(m, &m->rec.r));
- }
-
- *D2DListp = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (m->rec.r.resrec.rdlength <= sizeof(RDataBody) ? 0 : m->rec.r.resrec.rdlength - sizeof(RDataBody)));
- if (!*D2DListp) return mStatus_NoMemoryErr;
-
- AuthRecord *rr = &(*D2DListp)->ar;
- 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;
-}
-
-mDNSexport 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 = NULL;
-
- err = xD2DParse(m, (const mDNSu8 * const)key, (const mDNSu16)keySize, (const mDNSu8 * const)value, (const mDNSu16)valueSize, &ptr);
- if (err)
- {
- LogMsg("xD2DAddToCache: xD2DParse returned error: %d", err);
- PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
- if (ptr)
- mDNSPlatformMemFree(ptr);
- return;
- }
-
- // If the record was created based on a BLE beacon, update the interface index to indicate
- // this and thus match BLE specific queries.
- if (transportType == D2DBLETransport)
- ptr->ar.resrec.InterfaceID = mDNSInterface_BLE;
-
- 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 = NULL;
-
- if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DFindInList: NULL Byte * passed in or length == 0"); return NULL; }
-
- mStatus err = xD2DParse(m, (const mDNSu8 *const)key, (const mDNSu16)keySize, (const mDNSu8 *const)value, (const mDNSu16)valueSize, &arptr);
- if (err)
- {
- LogMsg("xD2DFindInList: xD2DParse returned error: %d", err);
- PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
- if (arptr)
- 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;
-}
-
-mDNSexport 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;
-}
-
-// Similar to callExternalHelpers(), but without the checks for the BLE specific interface or flags.
-// It's assumed that the domain was already verified to be .local once we are at this level.
-mDNSlocal mDNSBool callInternalHelpers(mDNSInterfaceID InterfaceID, DNSServiceFlags flags)
-{
- if ( ((InterfaceID == mDNSInterface_Any) && (flags & (kDNSServiceFlagsIncludeP2P | kDNSServiceFlagsIncludeAWDL)))
- || mDNSPlatformInterfaceIsD2D(InterfaceID))
- return mDNStrue;
- else
- return mDNSfalse;
-}
-
-mDNSexport void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags, DNSQuestion * q)
-{
- // BLE support currently not handled by a D2D plugin
- if (applyToBLE(InterfaceID, flags))
- {
- domainname lower;
-
- DomainnameToLower(typeDomain, &lower);
- // pass in the key and keySize
- mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype);
- start_BLE_browse(q, &lower, qtype, flags, compression_lhs, end - compression_lhs);
- }
-
- if (callInternalHelpers(InterfaceID, flags))
- internal_start_browsing_for_service(InterfaceID, typeDomain, qtype, flags);
-}
-
-mDNSexport void internal_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags)
-{
- domainname lower;
-
- DomainnameToLower(typeDomain, &lower);
-
- if (!D2DBrowseListRefCount(&lower, qtype))
- {
- D2DTransportType transportType, excludedTransport;
-
- LogInfo("%s: Starting browse for: %##s %s", __func__, 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)
-{
- // BLE support currently not handled by a D2D plugin
- if (applyToBLE(InterfaceID, flags))
- {
- domainname lower;
-
- // If this is the last instance of this browse, clear any cached records recieved for it.
- // We are not guaranteed to get a D2DServiceLost event for all key, value pairs cached over BLE.
- DomainnameToLower(typeDomain, &lower);
- if (stop_BLE_browse(&lower, qtype, flags))
- xD2DClearCache(&lower, qtype);
- }
-
- if (callInternalHelpers(InterfaceID, flags))
- internal_stop_browsing_for_service(InterfaceID, typeDomain, qtype, flags);
-}
-
-mDNSexport void internal_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const typeDomain, DNS_TypeValues qtype, DNSServiceFlags flags)
-{
- domainname lower;
-
- DomainnameToLower(typeDomain, &lower);
-
- // If found in list and this is the last reference to this browse, remove the key from the D2D plugins.
- if (D2DBrowseListRelease(&lower, qtype) && !D2DBrowseListRefCount(&lower, qtype))
- {
- D2DTransportType transportType, excludedTransport;
-
- LogInfo("%s: Stopping browse for: %##s %s", __func__, 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)
-{
- // Note, start_BLE_advertise() is currently called directly from external_start_advertising_helper() since
- // it needs to pass the ServiceRecordSet so that we can promote the record advertisements to AWDL
- // when we see the corresponding browse indication over BLE.
-
- if (callInternalHelpers(resourceRecord->InterfaceID, flags))
- internal_start_advertising_service(resourceRecord, flags);
-}
-
-mDNSexport void internal_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("%s: %s", __func__, 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)
-{
- // BLE support currently not handled by a D2D plugin
- if (applyToBLE(resourceRecord->InterfaceID, flags))
- {
- domainname lower;
-
- DomainnameToLower(resourceRecord->name, &lower);
- stop_BLE_advertise(&lower, resourceRecord->rrtype, flags);
- }
-
- if (callInternalHelpers(resourceRecord->InterfaceID, flags))
- internal_stop_advertising_service(resourceRecord, flags);
-}
-
-mDNSexport void internal_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("%s: %s", __func__, RRDisplayString(&mDNSStorage, resourceRecord));
-
- // For SRV records, update packet filter if p2p interface already exists, otherwise,
- // 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, 0, 0);
- external_start_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, 0, 0);
- }
-}
-
-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, 0);
- external_stop_browsing_for_service(AWDLInterfaceID, fqdn, kDNSType_SRV, 0);
- }
-}
-
-#elif APPLE_OSX_mDNSResponder
-
-mDNSexport void internal_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 internal_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 internal_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;}
-mDNSexport void internal_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags) { (void)resourceRecord; (void)flags;}
-
-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; (void)q }
-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
@@ -1381,7 +418,7 @@ mDNSexport void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropert
CFWriteStreamRef stream = NULL;
CFDataRef bytes = NULL;
CFIndex ret;
- KQueueLock(&mDNSStorage);
+ KQueueLock();
if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(NULL, NULL)))
{
@@ -1417,15 +454,15 @@ mDNSexport void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropert
if (subkeyCopy)
mDNSPlatformMemFree(subkeyCopy);
- KQueueUnlock(&mDNSStorage, "mDNSDynamicStoreSetConfig");
+ KQueueUnlock("mDNSDynamicStoreSetConfig");
});
}
// 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)
+mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(const char *ifname, int type)
{
NetworkInterfaceInfoOSX *i;
- for (i = m->p->InterfaceList; i; i = i->next)
+ for (i = mDNSStorage.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) ||
@@ -1437,14 +474,15 @@ 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 (ifa->ifa_addr && 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)
+mDNSexport NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(mDNSInterfaceID ifindex)
{
+ mDNS *const m = &mDNSStorage;
mDNSu32 scope_id = (mDNSu32)(uintptr_t)ifindex;
NetworkInterfaceInfoOSX *i;
@@ -1457,18 +495,19 @@ mDNSexport NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(const mDNS *const
mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex)
{
+ (void) m;
if (ifindex == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
if (ifindex == kDNSServiceInterfaceIndexP2P ) return(mDNSInterface_P2P);
if (ifindex == kDNSServiceInterfaceIndexBLE ) return(mDNSInterface_BLE);
if (ifindex == kDNSServiceInterfaceIndexAny ) return(mDNSNULL);
- NetworkInterfaceInfoOSX* ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
+ NetworkInterfaceInfoOSX* ifi = IfindexToInterfaceInfoOSX((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);
+ mDNSMacOSXNetworkChanged();
+ ifi = IfindexToInterfaceInfoOSX((mDNSInterfaceID)(uintptr_t)ifindex);
}
if (!ifi) return(mDNSNULL);
@@ -1497,273 +536,13 @@ mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNS
// 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);
+ mDNSMacOSXNetworkChanged();
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
@@ -1816,6 +595,10 @@ mDNSlocal void setTrafficClass(int socketfd, mDNSBool useBackgroundTrafficClass)
(void) setsockopt(socketfd, SOL_SOCKET, SO_TRAFFIC_CLASS, (void *)&traffic_class, sizeof(traffic_class));
}
+#ifdef UNIT_TEST
+// Run the unit test main
+UNITTEST_SETSOCKOPT
+#else
mDNSlocal int mDNSPlatformGetSocktFd(void *sockCxt, mDNSTransport_Type transType, mDNSAddr_Type addrType)
{
if (transType == mDNSTransport_UDP)
@@ -1863,29 +646,8 @@ mDNSexport void mDNSPlatformSetSocktOpt(void *sockCxt, mDNSTransport_Type transT
int nowake = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_NOWAKEFROMSLEEP, &nowake, sizeof(nowake)) == -1)
LogInfo("mDNSPlatformSetSocktOpt: SO_NOWAKEFROMSLEEP failed %s", strerror(errno));
-
- if ((q->flags & kDNSServiceFlagsDenyCellular) || (q->flags & kDNSServiceFlagsDenyExpensive))
- {
-#if defined(SO_RESTRICT_DENY_CELLULAR)
- if (q->flags & kDNSServiceFlagsDenyCellular)
- {
- int restrictions = 0;
- restrictions = SO_RESTRICT_DENY_CELLULAR;
- if (setsockopt(sockfd, SOL_SOCKET, SO_RESTRICTIONS, &restrictions, sizeof(restrictions)) == -1)
- LogMsg("mDNSPlatformSetSocktOpt: SO_RESTRICT_DENY_CELLULAR failed %s", strerror(errno));
- }
-#endif
-#if defined(SO_RESTRICT_DENY_EXPENSIVE)
- if (q->flags & kDNSServiceFlagsDenyExpensive)
- {
- int restrictions = 0;
- restrictions = SO_RESTRICT_DENY_EXPENSIVE;
- if (setsockopt(sockfd, SOL_SOCKET, SO_RESTRICTIONS, &restrictions, sizeof(restrictions)) == -1)
- LogMsg("mDNSPlatformSetSocktOpt: SO_RESTRICT_DENY_EXPENSIVE failed %s", strerror(errno));
- }
-#endif
- }
}
+#endif // UNIT_TEST
// 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"
@@ -1902,7 +664,7 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
if (InterfaceID)
{
- info = IfindexToInterfaceInfoOSX(m, InterfaceID);
+ info = IfindexToInterfaceInfoOSX(InterfaceID);
if (info == NULL)
{
// We may not have registered interfaces with the "core" as we may not have
@@ -2137,13 +899,13 @@ mDNSexport ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
}
// What is this for, and why does it use xor instead of a simple quality check? -- SC
-mDNSlocal mDNSInterfaceID FindMyInterface(mDNS *const m, const mDNSAddr *addr)
+mDNSlocal mDNSInterfaceID FindMyInterface(const mDNSAddr *addr)
{
NetworkInterfaceInfo *intf;
if (addr->type == mDNSAddrType_IPv4)
{
- for (intf = m->HostInterfaces; intf; intf = intf->next)
+ for (intf = mDNSStorage.HostInterfaces; intf; intf = intf->next)
{
if (intf->ip.type == addr->type && intf->McastTxRx)
{
@@ -2157,7 +919,7 @@ mDNSlocal mDNSInterfaceID FindMyInterface(mDNS *const m, const mDNSAddr *addr)
if (addr->type == mDNSAddrType_IPv6)
{
- for (intf = m->HostInterfaces; intf; intf = intf->next)
+ for (intf = mDNSStorage.HostInterfaces; intf; intf = intf->next)
{
if (intf->ip.type == addr->type && intf->McastTxRx)
{
@@ -2174,7 +936,7 @@ mDNSlocal mDNSInterfaceID FindMyInterface(mDNS *const m, const mDNSAddr *addr)
return(mDNSInterface_Any);
}
-mDNSexport void myKQSocketCallBack(int s1, short filter, void *context)
+mDNSexport void myKQSocketCallBack(int s1, short filter, void *context, mDNSBool encounteredEOF)
{
KQSocketSet *const ss = (KQSocketSet *)context;
mDNS *const m = ss->m;
@@ -2189,6 +951,22 @@ mDNSexport void myKQSocketCallBack(int s1, short filter, void *context)
LogMsg("myKQSocketCallBack: sktv4 %d sktv6 %d", ss->sktv4, ss->sktv6);
}
+ if (encounteredEOF)
+ {
+ LogMsg("myKQSocketCallBack: socket %d is no longer readable (EOF)", s1);
+ if (s1 == ss->sktv4)
+ {
+ ss->sktv4EOF = mDNStrue;
+ KQueueSet(ss->sktv4, EV_DELETE, EVFILT_READ, &ss->kqsv4);
+ }
+ else if (s1 == ss->sktv6)
+ {
+ ss->sktv6EOF = mDNStrue;
+ KQueueSet(ss->sktv6, EV_DELETE, EVFILT_READ, &ss->kqsv6);
+ }
+ return;
+ }
+
while (!closed)
{
mDNSAddr senderAddr, destAddr = zeroAddr;
@@ -2248,7 +1026,7 @@ mDNSexport void myKQSocketCallBack(int s1, short filter, void *context)
if (!InterfaceID)
{
- InterfaceID = FindMyInterface(m, &destAddr);
+ InterfaceID = FindMyInterface(&destAddr);
}
// LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
@@ -2262,7 +1040,7 @@ mDNSexport void myKQSocketCallBack(int s1, short filter, void *context)
if (ss->proxy)
{
- m->p->UDPProxyCallback(m, &m->p->UDPProxy, &m->imsg.m, (unsigned char*)&m->imsg + err, &senderAddr,
+ m->p->UDPProxyCallback(&m->p->UDPProxy, &m->imsg.m, (unsigned char*)&m->imsg + err, &senderAddr,
senderPort, &destAddr, ss->port, InterfaceID, NULL);
}
else
@@ -2275,8 +1053,9 @@ mDNSexport void myKQSocketCallBack(int s1, short filter, void *context)
if (!closed) ss->closeFlag = mDNSNULL;
}
- // If a client application is put in the background, it's socket to us can go defunct and
- // we'll get an ENOTCONN error on that connection. Just close the socket in that case.
+ // If a client application's sockets are marked as defunct
+ // sockets we have delegated to it with SO_DELEGATED will also go defunct.
+ // We get an ENOTCONN error for defunct sockets and should just close the socket in that case.
if (err < 0 && errno == ENOTCONN)
{
LogInfo("myKQSocketCallBack: ENOTCONN, closing socket");
@@ -2317,8 +1096,7 @@ mDNSexport void myKQSocketCallBack(int s1, short filter, void *context)
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"
+ "Please send email to radar-3387020@group.apple.com.)\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
@@ -2386,13 +1164,12 @@ mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, SSLProtocolSide pside, SSLConne
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);
+ // Set the default ciphersuite configuration
+ err = SSLSetSessionConfig(sock->tlsContext, CFSTR("default"));
if (err)
- {
- LogMsg("ERROR: tlsSetupSock: SSLSetAllowAnonymousCiphers failed with error code: %d", err);
- goto fail;
+ {
+ LogMsg("ERROR: tlsSetupSock: SSLSetSessionConfig failed with error code: %d", err);
+ goto fail;
}
// We already checked for NULL in hostname and this should never happen. Hence, returning -1
@@ -2479,10 +1256,9 @@ 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);
+ KQueueLock();
debugf("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
if (sock->handshake == handshake_to_be_closed)
@@ -2515,7 +1291,7 @@ mDNSlocal void *doSSLHandshake(TCPSocket *sock)
}
debugf("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
- KQueueUnlock(m, "doSSLHandshake");
+ KQueueUnlock("doSSLHandshake");
return NULL;
}
#endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
@@ -2537,7 +1313,7 @@ mDNSlocal void spawnSSLHandshake(TCPSocket* sock)
#endif /* NO_SECURITYFRAMEWORK */
-mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context)
+mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context, __unused mDNSBool encounteredEOF)
{
TCPSocket *sock = context;
sock->err = mStatus_NoError;
@@ -2655,13 +1431,11 @@ mDNSexport int KQueueSet(int fd, u_short flags, short filter, KQueueEntry *const
return 0;
}
-mDNSexport void KQueueLock(mDNS *const m)
+mDNSexport void KQueueLock()
{
- (void)m; //unused
}
-mDNSexport void KQueueUnlock(mDNS *const m, const char const *task)
+mDNSexport void KQueueUnlock(const char const *task)
{
- (void)m; //unused
(void)task; //unused
}
#else
@@ -2672,14 +1446,16 @@ mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry
return (kevent(KQueueFD, &new_event, 1, NULL, 0, NULL) < 0) ? errno : 0;
}
-mDNSexport void KQueueLock(mDNS *const m)
+mDNSexport void KQueueLock()
{
+ mDNS *const m = &mDNSStorage;
pthread_mutex_lock(&m->p->BigMutex);
m->p->BigMutexStartTime = mDNSPlatformRawTime();
}
-mDNSexport void KQueueUnlock(mDNS *const m, const char* task)
+mDNSexport void KQueueUnlock(const char* task)
{
+ mDNS *const m = &mDNSStorage;
mDNSs32 end = mDNSPlatformRawTime();
(void)task;
if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
@@ -2785,17 +1561,16 @@ mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, u_short sa_family, mDNSIPPort
return mStatus_NoError;
}
-mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
+mDNSexport TCPSocket *mDNSPlatformTCPSocket(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.m = &mDNSStorage;
sock->ss.sktv4 = -1;
sock->ss.sktv6 = -1;
err = SetupTCPSocket(sock, AF_INET, port, useBackgroundTrafficClass);
@@ -2819,7 +1594,7 @@ mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags,
sock->setup = mDNSfalse;
sock->connected = mDNSfalse;
sock->handshake = handshake_required;
- sock->m = m;
+ sock->m = &mDNSStorage;
sock->err = mStatus_NoError;
return sock;
@@ -2889,7 +1664,7 @@ mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst,
// UDP). mDNSInterface_Unicast indicates this case and not a valid interface.
if (InterfaceID && InterfaceID != mDNSInterface_Unicast)
{
- NetworkInterfaceInfoOSX *info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
+ NetworkInterfaceInfoOSX *info = IfindexToInterfaceInfoOSX(InterfaceID);
if (dst->type == mDNSAddrType_IPv4)
{
#ifdef IP_BOUND_IF
@@ -3289,7 +2064,7 @@ fail:
return(err);
}
-mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport)
+mDNSexport UDPSocket *mDNSPlatformUDPSocket(const mDNSIPPort requestedport)
{
mStatus err;
mDNSIPPort port = requestedport;
@@ -3299,7 +2074,7 @@ mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requ
if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
mDNSPlatformMemZero(p, sizeof(UDPSocket));
p->ss.port = zeroIPPort;
- p->ss.m = m;
+ p->ss.m = &mDNSStorage;
p->ss.sktv4 = -1;
p->ss.sktv6 = -1;
p->ss.proxy = mDNSfalse;
@@ -3332,11 +2107,20 @@ mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requ
return(p);
}
+#ifdef UNIT_TEST
+UNITTEST_UDPCLOSE
+#else
mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
{
CloseSocketSet(&sock->ss);
freeL("UDPSocket", sock);
}
+#endif
+
+mDNSexport mDNSBool mDNSPlatformUDPSocketEncounteredEOF(const UDPSocket *sock)
+{
+ return (sock->ss.sktv4EOF || sock->ss.sktv6EOF);
+}
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
@@ -3350,10 +2134,10 @@ mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *c
if (!InterfaceID) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
NetworkInterfaceInfoOSX *info;
- info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
+ info = IfindexToInterfaceInfoOSX(InterfaceID);
if (info == NULL)
{
- LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
+ LogMsg("mDNSPlatformSendRawPacket: Invalid interface index %p", InterfaceID);
return;
}
if (info->BPF_fd < 0)
@@ -3366,15 +2150,15 @@ mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *c
}
}
-mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
+mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
{
if (!InterfaceID) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: No InterfaceID specified"); return; }
NetworkInterfaceInfoOSX *info;
- info = IfindexToInterfaceInfoOSX(m, InterfaceID);
+ info = IfindexToInterfaceInfoOSX(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))
+ if (!mDNS_AddressIsLocalSubnet(&mDNSStorage, InterfaceID, tpa))
LogSPS("Don't need address cache entry for %s %#a %.6a", info->ifinfo.ifname, tpa, tha);
else
{
@@ -3406,7 +2190,7 @@ mDNSlocal void CloseBPF(NetworkInterfaceInfoOSX *const i)
mDNSlocal void bpf_callback_common(NetworkInterfaceInfoOSX *info)
{
- KQueueLock(info->m);
+ KQueueLock();
// 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).
@@ -3449,7 +2233,7 @@ mDNSlocal void bpf_callback_common(NetworkInterfaceInfoOSX *info)
ptr += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
}
exit:
- KQueueUnlock(info->m, "bpf_callback");
+ KQueueUnlock("bpf_callback");
}
#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
mDNSlocal void bpf_callback_dispatch(NetworkInterfaceInfoOSX *const info)
@@ -3475,23 +2259,38 @@ mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIP
mDNSexport mStatus mDNSPlatformClearSPSData(void)
{
- CFStringRef spsAddress = NULL;
- CFStringRef ownerOPTRec = NULL;
+ CFStringRef spsAddressKey = NULL;
+ CFStringRef ownerOPTRecKey = NULL;
+ SCDynamicStoreRef addrStore = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:SPSAddresses"), NULL, NULL);
+ SCDynamicStoreRef optStore = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:SPSOPTRecord"), NULL, NULL);
- if ((spsAddress = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", "[^/]", "/BonjourSleepProxyAddress")))
+ spsAddressKey = SCDynamicStoreKeyCreateNetworkInterfaceEntity (kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCCompAnyRegex, CFSTR("BonjourSleepProxyAddress"));
+ if (spsAddressKey != NULL)
{
- if (SCDynamicStoreRemoveValue(NULL, spsAddress) == false)
- LogSPS("mDNSPlatformClearSPSData: Unable to remove sleep proxy address key");
+ CFArrayRef keyList = SCDynamicStoreCopyKeyList(addrStore, spsAddressKey);
+ if (keyList != NULL)
+ {
+ if (SCDynamicStoreSetMultiple(addrStore, NULL, keyList, NULL) == false)
+ LogSPS("mDNSPlatformClearSPSData: Unable to remove %s : error %s", CFStringGetCStringPtr( spsAddressKey, kCFStringEncodingASCII), SCErrorString(SCError()));
+ }
+ if (keyList) CFRelease(keyList);
}
-
- if((ownerOPTRec = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s%s"), "State:/Network/Interface/", "[^/]", "/BonjourSleepProxyOPTRecord")))
+ ownerOPTRecKey= SCDynamicStoreKeyCreateNetworkInterfaceEntity (kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCCompAnyRegex, CFSTR("BonjourSleepProxyOPTRecord"));
+ if(ownerOPTRecKey != NULL)
{
- if (SCDynamicStoreRemoveValue(NULL, ownerOPTRec) == false)
- LogSPS("mDNSPlatformClearSPSData: Unable to remove sleep proxy owner option record key");
+ CFArrayRef keyList = SCDynamicStoreCopyKeyList(addrStore, ownerOPTRecKey);
+ if (keyList != NULL)
+ {
+ if (SCDynamicStoreSetMultiple(optStore, NULL, keyList, NULL) == false)
+ LogSPS("mDNSPlatformClearSPSData: Unable to remove %s : error %s", CFStringGetCStringPtr(ownerOPTRecKey, kCFStringEncodingASCII), SCErrorString(SCError()));
+ }
+ if (keyList) CFRelease(keyList);
}
- if (spsAddress) CFRelease(spsAddress);
- if (ownerOPTRec) CFRelease(ownerOPTRec);
+ if (addrStore) CFRelease(addrStore);
+ if (optStore) CFRelease(optStore);
+ if (spsAddressKey) CFRelease(spsAddressKey);
+ if (ownerOPTRecKey) CFRelease(ownerOPTRecKey);
return KERN_SUCCESS;
}
@@ -3799,7 +2598,7 @@ fin:
return ret;
}
-mDNSlocal void mDNSGet_RemoteMAC(mDNS *const m, int family, v6addr_t raddr)
+mDNSlocal void mDNSGet_RemoteMAC(int family, v6addr_t raddr)
{
ethaddr_t eth;
IPAddressMACMapping *addrMapping;
@@ -3808,9 +2607,10 @@ mDNSlocal void mDNSGet_RemoteMAC(mDNS *const m, int family, v6addr_t raddr)
{
v6addr_t addr;
} dst;
-
+
+ bzero(eth, sizeof(ethaddr_t));
mDNSPlatformMemCopy(dst.addr, raddr, sizeof(v6addr_t));
-
+
kr = GetRemoteMacinternal(family, (uint8_t *)dst.addr, eth);
// If the call to get the remote MAC address succeeds, allocate and copy
@@ -3830,21 +2630,21 @@ mDNSlocal void mDNSGet_RemoteMAC(mDNS *const m, int family, v6addr_t raddr)
addrMapping->ipaddr.type = mDNSAddrType_IPv6;
mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v6.b, raddr, sizeof(v6addr_t));
}
- UpdateRMAC(m, addrMapping);
+ UpdateRMAC(&mDNSStorage, addrMapping);
}
}
-mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNS *const m, mDNSAddr *raddr)
+mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNSAddr *raddr)
{
int family = (raddr->type == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
LogInfo("mDNSPlatformGetRemoteMacAddr calling mDNSGet_RemoteMAC");
- mDNSGet_RemoteMAC(m, family, raddr->ip.v6.b);
+ mDNSGet_RemoteMAC(family, raddr->ip.v6.b);
return KERN_SUCCESS;
}
-mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNS *const m, mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
+mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
{
mDNSs32 intfid;
mDNSs32 error = 0;
@@ -3856,25 +2656,25 @@ mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNS *const m, mDNSAddr *laddr, m
LogMsg("%s: mDNSRetrieveTCPInfo returned : %d", __func__, error);
return error;
}
- mti->IntfId = mDNSPlatformInterfaceIDfromInterfaceIndex(m, intfid);
+ mti->IntfId = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, 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)
+mDNSlocal int CountProxyTargets(NetworkInterfaceInfoOSX *x, int *p4, int *p6)
{
int numv4 = 0, numv6 = 0;
AuthRecord *rr;
- for (rr = m->ResourceRecords; rr; rr=rr->next)
+ for (rr = mDNSStorage.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)
+ for (rr = mDNSStorage.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);
@@ -3886,8 +2686,9 @@ mDNSlocal int CountProxyTargets(mDNS *const m, NetworkInterfaceInfoOSX *x, int *
return(numv4 + numv6);
}
-mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
+mDNSexport void mDNSPlatformUpdateProxyList(const mDNSInterfaceID InterfaceID)
{
+ mDNS *const m = &mDNSStorage;
NetworkInterfaceInfoOSX *x;
// Note: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also.
@@ -3898,7 +2699,7 @@ mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID
#define MAX_BPF_ADDRS 250
int numv4 = 0, numv6 = 0;
- if (CountProxyTargets(m, x, &numv4, &numv6) > MAX_BPF_ADDRS)
+ if (CountProxyTargets(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;
@@ -3927,131 +2728,149 @@ mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID
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
+ // Special filter program to use when there are no address proxy records
+ static struct bpf_insn nullfilter[] =
+ {
+ BPF_STMT(BPF_RET | BPF_K, 0) // 0 Match no packets and return size 0
+ };
- // 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);
+ struct bpf_program prog;
+ if (!numv4 && !numv6)
+ {
+ LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
+ if (m->timenow == 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
- for (rr = m->ResourceRecords; rr; rr=rr->next)
- if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
+ // Cancel any previous ND group memberships we had
+ if (x->BPF_mcfd >= 0)
{
- 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);
+ close(x->BPF_mcfd);
+ x->BPF_mcfd = -1;
+ }
- 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);
+ // Schedule check to see if we can close this BPF_fd now
+ if (!m->NetworkChanged) m->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
+ if (x->BPF_fd < 0) return; // If we've already closed our BPF_fd, no need to generate an error message below
+ prog.bf_len = 1;
+ prog.bf_insns = nullfilter;
+ }
+ else
+ {
+ 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;
- LogSPS("Joined IPv6 ND multicast group %.16a for %.16a", &i6mr.ipv6mr_multiaddr, a);
- }
+ if (pc != chk6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc, chk6);
+ *pc++ = g6; // chk6 points here
- if (pc != fail) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc, fail);
- *pc++ = rf; // fail 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);
- if (pc != ret4) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc, ret4);
- *pc++ = r4a; // ret4 points here
- *pc++ = r4b;
- *pc++ = r4c;
- *pc++ = r4d;
+ 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 != ret6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc, ret6);
- *pc++ = r6a; // ret6 points here
+ if (pc != fail) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc, fail);
+ *pc++ = rf; // fail points here
- struct bpf_program prog = { pc - filter, filter };
+ 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
#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);
+ // 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->NetworkChanged) m->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
+ prog.bf_len = (u_int)(pc - filter);
+ prog.bf_insns = filter;
}
-
+
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)
+mDNSexport void mDNSPlatformReceiveBPF_fd(int fd)
{
+ mDNS *const m = &mDNSStorage;
mDNS_Lock(m);
NetworkInterfaceInfoOSX *i;
@@ -4119,7 +2938,7 @@ mDNSexport void mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd)
i->BPF_rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, i->BPF_cfs, 0);
CFRunLoopAddSource(CFRunLoopGetMain(), i->BPF_rls, kCFRunLoopDefaultMode);
#endif
- mDNSPlatformUpdateProxyList(m, i->ifinfo.InterfaceID);
+ mDNSPlatformUpdateProxyList(i->ifinfo.InterfaceID);
}
}
@@ -4333,7 +3152,7 @@ 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)
+ if (ifa->ifa_addr && 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)
@@ -4366,18 +3185,27 @@ mDNSlocal mDNSBool CheckInterfaceSupport(NetworkInterfaceInfo *const intf, cons
io_name_t n1, n2;
IOObjectGetClass(service, n1);
- io_object_t parent;
- mDNSBool ret = mDNSfalse;
+ io_object_t parent = IO_OBJECT_NULL;
+ 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);
+ CFTypeRef ref = mDNSNULL;
+
+ // Currently, the key can be in a different part of the IOKit hierarchy on the AppleTV.
+ // TODO: revist if it is ok to have the same call for all platforms.
+ if (IsAppleTV())
+ ref = IORegistryEntrySearchCFProperty(parent, kIOServicePlane, keystr, kCFAllocatorDefault, kIORegistryIterateParents | kIORegistryIterateRecursively);
+ else
+ ref = IORegistryEntryCreateCFProperty(parent, keystr, kCFAllocatorDefault, mDNSNULL);
+
if (!ref)
{
- LogSPS("CheckInterfaceSupport: No mDNS_IOREG_KEY for interface %s/%s/%s", intf->ifname, n1, n2);
+ LogSPS("CheckInterfaceSupport: No %s for interface %s/%s/%s", key, intf->ifname, n1, n2);
ret = mDNSfalse;
}
else
@@ -4393,6 +3221,7 @@ mDNSlocal mDNSBool CheckInterfaceSupport(NetworkInterfaceInfo *const intf, cons
LogSPS("CheckInterfaceSupport: IORegistryEntryGetParentEntry for %s/%s failed %d", intf->ifname, n1, kr);
ret = mDNSfalse;
}
+
IOObjectRelease(service);
return ret;
}
@@ -4439,7 +3268,7 @@ mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i)
// 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");
+ LogSPS("NetWakeInterface: %-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);
}
@@ -4464,7 +3293,6 @@ mDNSlocal u_int64_t getExtendedFlags(char * ifa_name)
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;
@@ -4543,50 +3371,78 @@ exit:
return isInitialized;
}
+#define CARPLAY_DEBUG 0
+
// Return true if the interface is associate to a CarPlay hosted SSID.
+// If we have associated with a CarPlay hosted SSID, then use the same
+// optimizations that are used when an interface has the IFEF_DIRECTLINK flag set.
mDNSlocal mDNSBool IsCarPlaySSID(char *ifa_name)
{
static WiFiManagerClientRef manager = NULL;
- mDNSBool rvalue = mDNSfalse;
+ CFArrayRef devices;
+ WiFiDeviceClientRef device;
+ WiFiNetworkRef network;
+ mDNSBool rvalue = mDNSfalse;
if (!MobileWiFiLibLoad())
+ {
+ LogInfo("IsCarPlaySSID: MobileWiFiLibLoad() failed!");
return mDNSfalse;
+ }
- // If we have associated with a CarPlay hosted SSID, then use the same
- // optimizations that are used if an interface has the IFEF_DIRECTLINK flag set.
-
- // Get one WiFiManagerClientRef to use for all calls.
+ // Cache the WiFiManagerClientRef.
if (manager == NULL)
manager = WiFiManagerClientCreate_p(NULL, kWiFiClientTypeNormal);
if (manager == NULL)
{
LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!");
+ return mDNSfalse;
}
- else
+
+ devices = WiFiManagerClientCopyDevices_p(manager);
+
+ // If the first call fails, update the cached WiFiManagerClientRef pointer and try again.
+ if (devices == NULL)
{
- CFArrayRef devices;
+ LogInfo("IsCarPlaySSID: First call to WiFiManagerClientCopyDevices() returned NULL for %s", ifa_name);
+ // Release the previously cached WiFiManagerClientRef which is apparently now stale.
+ CFRelease(manager);
+ manager = WiFiManagerClientCreate_p(NULL, kWiFiClientTypeNormal);
+ if (manager == NULL)
+ {
+ LogInfo("IsCarPlaySSID: WiFiManagerClientCreate() failed!");
+ return mDNSfalse;
+ }
devices = WiFiManagerClientCopyDevices_p(manager);
- if (devices != NULL)
+ if (devices == NULL)
{
- WiFiDeviceClientRef device;
- WiFiNetworkRef network;
+ LogInfo("IsCarPlaySSID: Second call to WiFiManagerClientCopyDevices() returned NULL for %s", ifa_name);
+ return mDNSfalse;
+ }
+ }
- device = (WiFiDeviceClientRef)CFArrayGetValueAtIndex(devices, 0);
- network = WiFiDeviceClientCopyCurrentNetwork_p(device);
- if (network != NULL)
- {
- if (WiFiNetworkIsCarPlay_p(network))
- {
- LogInfo("%s is CarPlay hosted", ifa_name);
- rvalue = mDNStrue;
- }
- CFRelease(network);
- }
- CFRelease(devices);
+ device = (WiFiDeviceClientRef)CFArrayGetValueAtIndex(devices, 0);
+ network = WiFiDeviceClientCopyCurrentNetwork_p(device);
+ if (network != NULL)
+ {
+ if (WiFiNetworkIsCarPlay_p(network))
+ {
+ LogInfo("IsCarPlaySSID: %s is CarPlay hosted", ifa_name);
+ rvalue = mDNStrue;
}
+#if CARPLAY_DEBUG
+ else
+ LogInfo("IsCarPlaySSID: %s is NOT CarPlay hosted", ifa_name);
+#endif // CARPLAY_DEBUG
+
+ CFRelease(network);
}
+ else
+ LogInfo("IsCarPlaySSID: WiFiDeviceClientCopyCurrentNetwork() returned NULL for %s", ifa_name);
+
+ CFRelease(devices);
return rvalue;
}
@@ -4607,8 +3463,9 @@ mDNSlocal mDNSBool IsCarPlaySSID(char *ifa_name)
// 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)
+mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(struct ifaddrs *ifa, mDNSs32 utc)
{
+ mDNS *const m = &mDNSStorage;
mDNSu32 scope_id = if_nametoindex(ifa->ifa_name);
mDNSEthAddr bssid = GetBSSID(ifa->ifa_name);
u_int64_t eflags = getExtendedFlags(ifa->ifa_name);
@@ -4676,17 +3533,27 @@ mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifad
// Setting DirectLink indicates we can do the optimization of skipping the probe phase
// for the interface address records since they should be unique.
- if (eflags & IFEF_DIRECTLINK)
+ // Unfortunately, the legacy p2p* interfaces do not set the IFEF_LOCALNET_PRIVATE
+ // or IFEF_DIRECTLINK flags, so we have to match against the name.
+ if ((eflags & (IFEF_DIRECTLINK | IFEF_AWDL)) || (strncmp(i->ifinfo.ifname, "p2p", 3) == 0))
i->ifinfo.DirectLink = mDNStrue;
else
i->ifinfo.DirectLink = IsCarPlaySSID(ifa->ifa_name);
+ if (i->ifinfo.DirectLink)
+ LogInfo("AddInterfaceToList: DirectLink set for %s", ifa->ifa_name);
+
i->next = mDNSNULL;
i->m = m;
i->Exists = mDNStrue;
i->Flashing = mDNSfalse;
i->Occulting = mDNSfalse;
- i->D2DInterface = (eflags & IFEF_LOCALNET_PRIVATE) ? mDNStrue: mDNSfalse;
+
+ i->D2DInterface = ((eflags & IFEF_LOCALNET_PRIVATE) || (strncmp(i->ifinfo.ifname, "p2p", 3) == 0)) ? mDNStrue: mDNSfalse;
+ if (i->D2DInterface)
+ LogInfo("AddInterfaceToList: D2DInterface set for %s", ifa->ifa_name);
+
+ i->isExpensive = (eflags & IFEF_EXPENSIVE) ? mDNStrue: mDNSfalse;
if (eflags & IFEF_AWDL)
{
// Set SupportsUnicastMDNSResponse false for the AWDL interface since unicast reserves
@@ -4694,7 +3561,6 @@ mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifad
// Bonjour requests over the AWDL interface.
i->ifinfo.SupportsUnicastMDNSResponse = mDNSfalse;
AWDLInterfaceID = i->ifinfo.InterfaceID;
- i->ifinfo.DirectLink = mDNStrue;
LogInfo("AddInterfaceToList: AWDLInterfaceID = %d", (int) AWDLInterfaceID);
}
else
@@ -4752,11 +3618,11 @@ mDNSlocal mStatus CheckQuestionForStatus(const DNSQuestion *const q)
return mStatus_NoError;
}
-mDNSlocal mStatus UpdateLLQStatus(const mDNS *const m, char *buffer, int bufsz, const DomainAuthInfo *const info)
+mDNSlocal mStatus UpdateLLQStatus(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)
+ for (q = mDNSStorage.Questions; q; q=q->next)
if (q->AuthInfo == info)
{
mStatus newStatus = CheckQuestionForStatus(q);
@@ -4772,12 +3638,12 @@ mDNSlocal mStatus UpdateLLQStatus(const mDNS *const m, char *buffer, int bufsz,
return status;
}
-mDNSlocal mStatus UpdateRRStatus(const mDNS *const m, char *buffer, int bufsz, const DomainAuthInfo *const info)
+mDNSlocal mStatus UpdateRRStatus(char *buffer, int bufsz, const DomainAuthInfo *const info)
{
AuthRecord *r;
if (info->deltime) return mStatus_NoError;
- for (r = m->ResourceRecords; r; r = r->next)
+ for (r = mDNSStorage.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),
@@ -4787,7 +3653,7 @@ mDNSlocal mStatus UpdateRRStatus(const mDNS *const m, char *buffer, int bufsz, c
while (n->c[0])
{
DomainAuthInfo *ptr;
- for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
+ for (ptr = mDNSStorage.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))
@@ -4805,14 +3671,14 @@ mDNSlocal mStatus UpdateRRStatus(const mDNS *const m, char *buffer, int bufsz, c
#endif // ndef NO_SECURITYFRAMEWORK
// MUST be called with lock held
-mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAuthInfo *const info)
+mDNSlocal void UpdateAutoTunnelDomainStatus(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
+ mDNS *const m = &mDNSStorage;
const NATTraversalInfo *const llq = m->LLQNAT.clientCallback ? &m->LLQNAT : mDNSNULL;
const NATTraversalInfo *const tun = m->AutoTunnelNAT.clientContext ? &m->AutoTunnelNAT : mDNSNULL;
char buffer[1024];
@@ -4937,8 +3803,8 @@ mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAut
}
mDNS_snprintf(buffer, sizeof(buffer), "Success");
- llqStatus = UpdateLLQStatus(m, llqBuffer, sizeof(llqBuffer), info);
- status = UpdateRRStatus(m, buffer, sizeof(buffer), info);
+ llqStatus = UpdateLLQStatus(llqBuffer, sizeof(llqBuffer), info);
+ status = UpdateRRStatus(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)
@@ -5024,9 +3890,7 @@ mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAut
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, "");
+ LogInfo("UpdateAutoTunnelDomainStatus: %s status %d", status ? "failure" : "success", status);
mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
}
}
@@ -5048,7 +3912,7 @@ mDNSexport void UpdateAutoTunnelDomainStatuses(const mDNS *const m)
DomainAuthInfo* info;
for (info = m->AuthInfoList; info; info = info->next)
if (info->AutoTunnel && !info->deltime)
- UpdateAutoTunnelDomainStatus(m, info);
+ UpdateAutoTunnelDomainStatus(info);
#endif // def NO_SECURITYFRAMEWORK
}
@@ -5243,7 +4107,7 @@ mDNSlocal void DeregisterAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
DeregisterAutoTunnelRecord(m, info, &info->AutoTunnel6Record);
UpdateAutoTunnelHostRecord(m, info);
- UpdateAutoTunnelDomainStatus(m, info);
+ UpdateAutoTunnelDomainStatus(info);
}
// Caller must hold the lock
@@ -5364,8 +4228,9 @@ mDNSlocal void AutoTunnelHostNameChanged(mDNS *m, DomainAuthInfo *info)
}
// Must be called with the lock held
-mDNSexport void StartServerTunnel(mDNS *const m, DomainAuthInfo *const info)
+mDNSexport void StartServerTunnel(DomainAuthInfo *const info)
{
+ mDNS *const m = &mDNSStorage;
if (info->deltime) return;
if (info->AutoTunnelServiceStarted)
@@ -5435,8 +4300,9 @@ mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew)
// 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)
+mDNSlocal void ReissueBlockedQuestionWithType(domainname *d, mDNSBool success, mDNSu16 qtype)
{
+ mDNS *const m = &mDNSStorage;
DNSQuestion *q = m->Questions;
while (q)
{
@@ -5462,29 +4328,31 @@ mDNSlocal void ReissueBlockedQuestionWithType(mDNS *const m, domainname *d, mDNS
}
}
-mDNSlocal void ReissueBlockedQuestions(mDNS *const m, domainname *d, mDNSBool success)
+mDNSlocal void ReissueBlockedQuestions(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);
+ ReissueBlockedQuestionWithType(d, success, kDNSType_AAAA);
+ ReissueBlockedQuestionWithType(d, mDNStrue, kDNSType_A);
}
-mDNSlocal void UnlinkAndReissueBlockedQuestions(mDNS *const m, ClientTunnel *tun, mDNSBool success)
+mDNSlocal void UnlinkAndReissueBlockedQuestions(ClientTunnel *tun, mDNSBool success)
{
+ mDNS *const m = &mDNSStorage;
ClientTunnel **p = &m->TunnelClients;
while (*p != tun && *p) p = &(*p)->next;
if (*p) *p = tun->next;
- ReissueBlockedQuestions(m, &tun->dstname, success);
+ ReissueBlockedQuestions(&tun->dstname, success);
LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun);
freeL("ClientTunnel", tun);
}
-mDNSlocal mDNSBool TunnelClientDeleteMatching(mDNS *const m, ClientTunnel *tun, mDNSBool v6Tunnel)
+mDNSlocal mDNSBool TunnelClientDeleteMatching(ClientTunnel *tun, mDNSBool v6Tunnel)
{
+ mDNS *const m = &mDNSStorage;
ClientTunnel **p;
mDNSBool needSetKeys = mDNStrue;
@@ -5564,7 +4432,7 @@ mDNSlocal mDNSBool TunnelClientDeleteMatching(mDNS *const m, ClientTunnel *tun,
// 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)
+mDNSlocal void TunnelClientDeleteAny(ClientTunnel *tun, mDNSBool v6Tunnel)
{
ClientTunnel **p;
@@ -5590,7 +4458,7 @@ mDNSlocal void TunnelClientDeleteAny(mDNS *const m, ClientTunnel *tun, mDNSBool
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);
+ mDNS_StopQuery(&mDNSStorage, &old->q);
}
else
{
@@ -5604,8 +4472,9 @@ mDNSlocal void TunnelClientDeleteAny(mDNS *const m, ClientTunnel *tun, mDNSBool
}
}
-mDNSlocal void TunnelClientFinish(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer)
+mDNSlocal void TunnelClientFinish(DNSQuestion *question, const ResourceRecord *const answer)
{
+ mDNS *const m = &mDNSStorage;
mDNSBool needSetKeys = mDNStrue;
ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
mDNSBool v6Tunnel = mDNSfalse;
@@ -5639,7 +4508,7 @@ mDNSlocal void TunnelClientFinish(mDNS *const m, DNSQuestion *question, const Re
if (!info)
{
LogMsg("TunnelClientFinish: Could not get AuthInfo for %##s", tun->dstname.c);
- ReissueBlockedQuestions(m, &tun->dstname, mDNSfalse);
+ ReissueBlockedQuestions(&tun->dstname, mDNSfalse);
return;
}
@@ -5649,18 +4518,16 @@ mDNSlocal void TunnelClientFinish(mDNS *const m, DNSQuestion *question, const Re
// 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);
+ TunnelClientDeleteAny(tun, !v6Tunnel);
+ needSetKeys = TunnelClientDeleteMatching(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, "");
+ LogInfo("TunnelClientFinish: Tunnel setup result %d", result);
// Kick off any questions that were held pending this tunnel setup
- ReissueBlockedQuestions(m, &tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse);
+ ReissueBlockedQuestions(&tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse);
}
mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
@@ -5678,10 +4545,7 @@ mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const R
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);
+ UnlinkAndReissueBlockedQuestions(tun, mDNSfalse);
return;
}
@@ -5696,19 +4560,19 @@ mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const R
if (!info)
{
LogMsg("AutoTunnelCallback: Could not get AuthInfo for %##s", tun->dstname.c);
- UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
+ UnlinkAndReissueBlockedQuestions(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);
+ UnlinkAndReissueBlockedQuestions(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);
+ UnlinkAndReissueBlockedQuestions(tun, mDNStrue);
return;
}
tun->rmt_inner = answer->rdata->u.ipv6;
@@ -5746,7 +4610,7 @@ mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const R
mDNS_StartQuery(m, &tun->q);
return;
}
- TunnelClientFinish(m, question, answer);
+ TunnelClientFinish(question, answer);
return;
case TC_STATE_SRV_PEER:
if (question->qtype != kDNSType_SRV)
@@ -5765,7 +4629,7 @@ mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const R
{
LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_ADDR_PEER", question->qtype);
}
- TunnelClientFinish(m, question, answer);
+ TunnelClientFinish(question, answer);
return;
default:
LogMsg("AutoTunnelCallback: Unknown question %p", question);
@@ -5773,8 +4637,9 @@ mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const R
}
// Must be called with the lock held
-mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q)
+mDNSexport void AddNewClientTunnel(DNSQuestion *const q)
{
+ mDNS *const m = &mDNSStorage;
ClientTunnel *p = mallocL("ClientTunnel", sizeof(ClientTunnel));
if (!p) return;
AssignDomainName(&p->dstname, &q->qname);
@@ -5828,8 +4693,72 @@ mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q)
#pragma mark - Power State & Configuration Change Management
#endif
-mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
+mDNSlocal mStatus ReorderInterfaceList()
{
+ // Disable Reorder lists till <rdar://problem/30071012> is fixed to prevent spurious name conflicts
+ return (mStatus_NoError);
+
+ mDNS *const m = &mDNSStorage;
+ nwi_state_t state = nwi_state_copy();
+
+ if (state == mDNSNULL)
+ {
+ LogMsg("NWI State is NULL!");
+ return (mStatus_Invalid);
+ }
+
+ // Get the count of interfaces
+ mDNSu32 count = nwi_state_get_interface_names(state, mDNSNULL, 0);
+ if (count == 0)
+ {
+ LogMsg("Unable to get the ordered list of interface names");
+ nwi_state_release(state);
+ return (mStatus_Invalid);
+ }
+
+ // Get the ordered interface list
+ int i;
+ const char *names[count];
+ count = nwi_state_get_interface_names(state, names, count);
+
+ NetworkInterfaceInfo *newList = mDNSNULL;
+ for (i = count-1; i >= 0; i--)
+ { // Build a new ordered interface list
+ NetworkInterfaceInfo **ptr = &m->HostInterfaces;
+ while (*ptr != mDNSNULL )
+ {
+ if (strcmp((*ptr)->ifname, names[i]) == 0)
+ {
+ NetworkInterfaceInfo *node = *ptr;
+ *ptr = (*ptr)->next;
+ node->next = newList;
+ newList = node;
+ }
+ else
+ ptr = &((*ptr)->next);
+ }
+ }
+
+ // Get to the end of the list
+ NetworkInterfaceInfo *newListEnd = newList;
+ while (newListEnd != mDNSNULL && newListEnd->next != mDNSNULL)
+ newListEnd = newListEnd->next;
+
+ // Add any remaing interfaces to the end of the sorted list
+ if (newListEnd != mDNSNULL)
+ newListEnd->next = m->HostInterfaces;
+
+ // If we have a valid new list, point to that now
+ if (newList != mDNSNULL)
+ m->HostInterfaces = newList;
+
+ nwi_state_release(state);
+ return (mStatus_NoError);
+}
+
+mDNSlocal mStatus UpdateInterfaceList(mDNSs32 utc)
+{
+ mDNS *const m = &mDNSStorage;
mDNSBool foundav4 = mDNSfalse;
mDNSBool foundav6 = mDNSfalse;
struct ifaddrs *ifa = myGetIfAddrs(0);
@@ -5845,30 +4774,41 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
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_addr)
+ {
+ 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);
+ }
+ else
+ LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X ifa_addr is NOT set",
+ ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags);
+
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);
+ ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
+ ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
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);
+ ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
+ ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
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);
+ ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
+ ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
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);
+ ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags,
+ ifa->ifa_addr ? ifa->ifa_addr->sa_family : 0);
#endif
- if (ifa->ifa_addr->sa_family == AF_LINK)
+ if (ifa->ifa_addr && 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))
@@ -5929,7 +4869,7 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
}
else
{
- NetworkInterfaceInfoOSX *i = AddInterfaceToList(m, ifa, utc);
+ NetworkInterfaceInfoOSX *i = AddInterfaceToList(ifa, utc);
if (i && MulticastInterface(i) && i->ifinfo.Advertise)
{
if (ifa->ifa_addr->sa_family == AF_INET)
@@ -5945,8 +4885,8 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
}
// 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);
+ if (!foundav4 && v4Loopback) AddInterfaceToList(v4Loopback, utc);
+ if (!foundav6 && v6Loopback) AddInterfaceToList(v6Loopback, utc);
// Now the list is complete, set the McastTxRx setting for each interface.
NetworkInterfaceInfoOSX *i;
@@ -5957,7 +4897,7 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
if (i->ifinfo.McastTxRx != txrx)
{
i->ifinfo.McastTxRx = txrx;
- i->Exists = 2; // State change; need to deregister and reregister this interface
+ i->Exists = MulticastStateChanged; // State change; need to deregister and reregister this interface
}
}
@@ -6041,8 +4981,9 @@ mDNSlocal int CountMaskBits(mDNSAddr *mask)
}
// Returns count of non-link local V4 addresses registered (why? -- SC)
-mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
+mDNSlocal int SetupActiveInterfaces(mDNSs32 utc)
{
+ mDNS *const m = &mDNSStorage;
NetworkInterfaceInfoOSX *i;
int count = 0;
@@ -6052,7 +4993,7 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
if (i->Exists)
{
NetworkInterfaceInfo *const n = &i->ifinfo;
- NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AF_UNSPEC);
+ NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(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
@@ -6063,6 +5004,8 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
if (!i->Registered)
{
+ InterfaceActivationSpeed activationSpeed;
+
// 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.
@@ -6073,27 +5016,31 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
// 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
- // every time it creates a new interface. We think it is a duplicate and hence consider it
+ // The "p2p*" interfaces used for legacy AirDrop reuse the scope-id, MAC address and the IP address
+ // every time a new interface is created. 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.
+ // The same logic applies when the 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);
+ activationSpeed = FastActivation;
+ LogInfo("SetupActiveInterfaces: %s DirectLink interface registering", i->ifinfo.ifname);
+ }
+ else if (i->Flashing && i->Occulting)
+ {
+ activationSpeed = SlowActivation;
}
else
{
- mDNS_RegisterInterface(m, n, i->Flashing && i->Occulting);
+ activationSpeed = NormalActivation;
}
+ mDNS_RegisterInterface(m, n, activationSpeed);
+
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),
+ LogInfo("SetupActiveInterfaces: Registered %7s(%u) BSSID %.6a Struct addr %p, primary %p, %#a/%d%s%s%s",
+ i->ifinfo.ifname, i->scope_id, &i->BSSID, i, primary, &n->ip, CountMaskBits(&n->mask),
i->Flashing ? " (Flashing)" : "",
i->Occulting ? " (Occulting)" : "",
n->InterfaceActive ? " (Primary)" : "");
@@ -6111,7 +5058,7 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
imr.imr_interface = primary->ifa_v4addr;
- if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET) == i)
+ if (SearchForInterfaceByName(i->ifinfo.ifname, AF_INET) == i)
{
LogInfo("SetupActiveInterfaces: %5s(%lu) Doing 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));
@@ -6125,7 +5072,7 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
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)
+ if (SearchForInterfaceByName(i->ifinfo.ifname, AF_INET6) == i)
{
LogInfo("SetupActiveInterfaces: %5s(%lu) Doing 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));
@@ -6154,7 +5101,7 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
// 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)
+ if (SearchForInterfaceByName(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));
@@ -6174,7 +5121,7 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
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)
+ if (SearchForInterfaceByName(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));
@@ -6195,10 +5142,10 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
return count;
}
-mDNSlocal void MarkAllInterfacesInactive(mDNS *const m, mDNSs32 utc)
+mDNSlocal void MarkAllInterfacesInactive(mDNSs32 utc)
{
NetworkInterfaceInfoOSX *i;
- for (i = m->p->InterfaceList; i; i = i->next)
+ for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
{
if (i->Exists) i->LastSeen = utc;
i->Exists = mDNSfalse;
@@ -6206,8 +5153,9 @@ mDNSlocal void MarkAllInterfacesInactive(mDNS *const m, mDNSs32 utc)
}
// Returns count of non-link local V4 addresses deregistered (why? -- SC)
-mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
+mDNSlocal int ClearInactiveInterfaces(mDNSs32 utc)
{
+ mDNS *const m = &mDNSStorage;
// 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.
@@ -6218,10 +5166,12 @@ mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
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);
+ NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(i->ifinfo.ifname, AF_UNSPEC);
if (i->Registered)
- if (i->Exists == 0 || i->Exists == 2 || i->Registered != primary)
+ if (i->Exists == 0 || i->Exists == MulticastStateChanged || i->Registered != primary)
{
+ InterfaceActivationSpeed activationSpeed;
+
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,
@@ -6230,23 +5180,27 @@ mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
i->Occulting ? " (Occulting)" : "",
i->ifinfo.InterfaceActive ? " (Primary)" : "");
- // Temporary fix to handle P2P flapping. P2P reuses the scope-id, mac address and the IP address
+ // "p2p*" interfaces used for legacy AirDrop reuse the scope-id, MAC address and the IP address
// every time 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.
+ // The same logic applies when the 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);
+ activationSpeed = FastActivation;
+ LogInfo("ClearInactiveInterfaces: %s DirectLink interface deregistering", i->ifinfo.ifname);
+ }
+ else if (i->Flashing && i->Occulting)
+ {
+ activationSpeed = SlowActivation;
}
else
{
- mDNS_DeregisterInterface(m, &i->ifinfo, i->Flashing && i->Occulting);
+ activationSpeed = NormalActivation;
}
+ mDNS_DeregisterInterface(m, &i->ifinfo, activationSpeed);
+
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,
@@ -6310,8 +5264,9 @@ mDNSlocal int compare_dns_configs(const void *aa, const void *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)
+mDNSlocal void UpdateSearchDomainHash(MD5_CTX *sdc, char *domain, mDNSInterfaceID InterfaceID)
{
+ mDNS *const m = &mDNSStorage;
char *buf = ".";
mDNSu32 scopeid = 0;
char ifid_buf[16];
@@ -6344,8 +5299,9 @@ mDNSlocal void UpdateSearchDomainHash(mDNS *const m, MD5_CTX *sdc, char *domain,
MD5_Update(sdc, ifid_buf, strlen(ifid_buf) + 1);
}
-mDNSlocal void FinalizeSearchDomainHash(mDNS *const m, MD5_CTX *sdc)
+mDNSlocal void FinalizeSearchDomainHash(MD5_CTX *sdc)
{
+ mDNS *const m = &mDNSStorage;
mDNSu8 md5_hash[MD5_LEN];
MD5_Final(md5_hash, sdc);
@@ -6377,7 +5333,7 @@ mDNSexport const char *DNSScopeToString(mDNSu32 scope)
}
}
-mDNSlocal void ConfigSearchDomains(mDNS *const m, dns_resolver_t *resolver, mDNSInterfaceID interfaceId, mDNSu32 scope, MD5_CTX *sdc, uint64_t generation)
+mDNSlocal void ConfigSearchDomains(dns_resolver_t *resolver, mDNSInterfaceID interfaceId, mDNSu32 scope, MD5_CTX *sdc, uint64_t generation)
{
const char *scopeString = DNSScopeToString(scope);
int j;
@@ -6393,10 +5349,10 @@ mDNSlocal void ConfigSearchDomains(mDNS *const m, dns_resolver_t *resolver, mDNS
if (MakeDomainNameFromDNSNameString(&d, resolver->search[j]) != NULL)
{
static char interface_buf[32];
- mDNS_snprintf(interface_buf, sizeof(interface_buf), "for interface %s", InterfaceNameForID(m, interfaceId));
+ mDNS_snprintf(interface_buf, sizeof(interface_buf), "for interface %s", InterfaceNameForID(&mDNSStorage, interfaceId));
LogInfo("ConfigSearchDomains: (%s) configuring search domain %s %s (generation= %llu)", scopeString,
resolver->search[j], (interfaceId == mDNSInterface_Any) ? "" : interface_buf, generation);
- UpdateSearchDomainHash(m, sdc, resolver->search[j], interfaceId);
+ UpdateSearchDomainHash(sdc, resolver->search[j], interfaceId);
mDNS_AddSearchDomain_CString(resolver->search[j], interfaceId);
}
else
@@ -6408,16 +5364,16 @@ mDNSlocal void ConfigSearchDomains(mDNS *const m, dns_resolver_t *resolver, mDNS
}
else
{
- LogInfo("ConfigSearchDomains: (%s) Ignoring search domain for interface %s", scopeString, InterfaceNameForID(m,interfaceId));
+ LogInfo("ConfigSearchDomains: (%s) Ignoring search domain for interface %s", scopeString, InterfaceNameForID(&mDNSStorage, interfaceId));
}
}
-mDNSlocal mDNSInterfaceID ConfigParseInterfaceID(mDNS *const m, mDNSu32 ifindex)
+mDNSlocal mDNSInterfaceID ConfigParseInterfaceID(mDNSu32 ifindex)
{
NetworkInterfaceInfoOSX *ni;
mDNSInterfaceID interface;
- for (ni = m->p->InterfaceList; ni; ni = ni->next)
+ for (ni = mDNSStorage.p->InterfaceList; ni; ni = ni->next)
{
if (ni->ifinfo.InterfaceID && ni->scope_id == ifindex)
break;
@@ -6442,7 +5398,7 @@ mDNSlocal mDNSInterfaceID ConfigParseInterfaceID(mDNS *const m, mDNSu32 ifindex)
return interface;
}
-mDNSlocal void ConfigNonUnicastResolver(mDNS *const m, dns_resolver_t *r)
+mDNSlocal void ConfigNonUnicastResolver(dns_resolver_t *r)
{
char *opt = r->options;
domainname d;
@@ -6454,17 +5410,19 @@ mDNSlocal void ConfigNonUnicastResolver(mDNS *const m, dns_resolver_t *r)
LogMsg("ConfigNonUnicastResolver: config->resolver bad domain %s", r->domain);
return;
}
- mDNS_AddMcastResolver(m, &d, mDNSInterface_Any, r->timeout);
+ mDNS_AddMcastResolver(&mDNSStorage, &d, mDNSInterface_Any, r->timeout);
}
}
-mDNSlocal void ConfigDNSServers(mDNS *const m, dns_resolver_t *r, mDNSInterfaceID interface, mDNSu32 scope, mDNSu16 resGroupID)
+mDNSlocal void ConfigDNSServers(dns_resolver_t *r, mDNSInterfaceID interface, mDNSu32 scope, mDNSu16 resGroupID)
{
int n;
domainname d;
int serviceID = 0;
mDNSBool cellIntf = mDNSfalse;
mDNSBool reqA, reqAAAA;
+ NetworkInterfaceInfoOSX *info;
+ mDNSBool isExpensive;
if (!r->domain || !*r->domain)
{
@@ -6486,6 +5444,8 @@ mDNSlocal void ConfigDNSServers(mDNS *const m, dns_resolver_t *r, mDNSInterfaceI
#endif
reqA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS ? mDNStrue : mDNSfalse);
reqAAAA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS ? mDNStrue : mDNSfalse);
+ info = IfindexToInterfaceInfoOSX(interface);
+ isExpensive = info ? info->isExpensive : mDNSfalse;
for (n = 0; n < r->n_nameserver; n++)
{
@@ -6508,8 +5468,8 @@ mDNSlocal void ConfigDNSServers(mDNS *const m, dns_resolver_t *r, mDNSInterfaceI
// 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);
+ s = mDNS_AddDNSServer(&mDNSStorage, &d, interface, serviceID, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort, scope,
+ (n == 0 ? (r->timeout ? r->timeout : DEFAULT_UDNS_TIMEOUT) : 0), cellIntf, isExpensive, 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);
@@ -6528,7 +5488,7 @@ mDNSlocal void ConfigDNSServers(mDNS *const m, dns_resolver_t *r, mDNSInterfaceI
// "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)
+mDNSlocal void ConfigResolvers(dns_config_t *config, mDNSu32 scope, mDNSBool setsearch, mDNSBool setservers, MD5_CTX *sdc, mDNSu16 resGroupID)
{
int i;
dns_resolver_t **resolver;
@@ -6566,12 +5526,12 @@ mDNSlocal void ConfigResolvers(mDNS *const m, dns_config_t *config, mDNSu32 scop
// Parse the interface index
if (r->if_index != 0)
{
- interface = ConfigParseInterfaceID(m, r->if_index);
+ interface = ConfigParseInterfaceID(r->if_index);
}
if (setsearch)
{
- ConfigSearchDomains(m, resolver[i], interface, scope, sdc, config->generation);
+ ConfigSearchDomains(resolver[i], interface, scope, sdc, config->generation);
// Parse other scoped resolvers for search lists
if (!setservers)
@@ -6580,7 +5540,7 @@ mDNSlocal void ConfigResolvers(mDNS *const m, dns_config_t *config, mDNSu32 scop
if (r->port == 5353 || r->n_nameserver == 0)
{
- ConfigNonUnicastResolver(m, r);
+ ConfigNonUnicastResolver(r);
}
else
{
@@ -6589,7 +5549,7 @@ mDNSlocal void ConfigResolvers(mDNS *const m, dns_config_t *config, mDNSu32 scop
if (scope != kScopeNone)
resGroupID++;
- ConfigDNSServers(m, r, interface, scope, resGroupID);
+ ConfigDNSServers(r, interface, scope, resGroupID);
}
}
}
@@ -6622,8 +5582,9 @@ mDNSlocal mDNSBool QuestionValidForDNSTrigger(DNSQuestion *q)
// 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)
+mDNSexport void mDNSPlatformUpdateDNSStatus(DNSQuestion *q)
{
+ mDNS *const m = &mDNSStorage;
if (!QuestionValidForDNSTrigger(q))
return;
@@ -6640,26 +5601,27 @@ mDNSexport void mDNSPlatformUpdateDNSStatus(mDNS *const m, DNSQuestion *q)
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,
+ LogInfo("mDNSPlatformUpdateDNSStatus: Trigger needed v4 %d, v6 %d, question %##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)
+mDNSlocal void AckConfigd(dns_config_t *config)
{
- mDNS_CheckLock(m);
+ mDNS_CheckLock(&mDNSStorage);
// Acking the configuration triggers configd to reissue the reachability queries
- m->p->DNSTrigger = NonZeroTime(m->timenow);
+ mDNSStorage.p->DNSTrigger = NonZeroTime(mDNSStorage.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)
+mDNSexport void mDNSPlatformTriggerDNSRetry(DNSQuestion *v4q, DNSQuestion *v6q)
{
+ mDNS *const m = &mDNSStorage;
mDNSBool trigger = mDNSfalse;
mDNSs32 timenow;
@@ -6722,7 +5684,7 @@ mDNSexport void mDNSPlatformTriggerDNSRetry(mDNS *const m, DNSQuestion *v4q, DNS
if (config)
{
mDNS_Lock(m);
- AckConfigd(m, config);
+ AckConfigd(config);
mDNS_Unlock(m);
dns_configuration_free(config);
}
@@ -6877,9 +5839,10 @@ mDNSlocal void SetupDDNSDomains(domainname *const fqdn, DNameListElem **RegDomai
}
// 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,
+mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn,
DNameListElem **RegDomains, DNameListElem **BrowseDomains, mDNSBool ackConfig)
{
+ mDNS *const m = &mDNSStorage;
MD5_CTX sdc; // search domain context
static mDNSu16 resolverGroupID = 0;
@@ -6932,7 +5895,7 @@ mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers,
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);
+ UpdateSearchDomainHash(&sdc, buf, NULL);
mDNS_AddSearchDomain_CString(buf, mDNSNULL);
}
ifa = ifa->ifa_next;
@@ -6956,20 +5919,24 @@ mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers,
{
LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d, generation %llu, last %llu", config->n_resolver, config->generation, m->p->LastConfigGeneration);
- // For every network change, the search domain list is updated.
- // This update is done without regard for generation number because it is
- // not an expensive update and it keeps the search domain list in sync (even when
- // a network change occurs, while currently processing a network
- // change).
- //
- // For every DNS configuration change, the DNS server list is updated.
- // This update is NOT done every network change because it may involve
- // updating cache entries which worst-case is expensive. Setting the generation
- // per DNS server list change keeps the list in sync with configd.
-
+ // For every network change, mDNSPlatformSetDNSConfig is called twice. First,
+ // to update the search domain list (in which case, the setsearch bool is set);
+ // and second, to update the DNS server list (in which case, the setservers bool
+ // is set). The code assumes only one of these flags, setsearch or setserver,
+ // will be set when mDNSPlatformSetDNSConfig is called to handle a network change.
+ // The mDNSPlatformSetDNSConfig function also assumes that ackCfg will be set
+ // when setservers is set.
+
+ // The search domains update occurs on every network change to avoid sync issues
+ // that may occur if a network change happens during the processing
+ // of a network change. The dns servers update occurs when the DNS config
+ // changes. The dns servers stay in sync by saving the config's generation number
+ // on every update; and only updating when the generation number changes.
+
+ // If this is a DNS server update and the configuration hasn't changed, then skip update
if (setservers && m->p->LastConfigGeneration == config->generation)
{
- LogInfo("mDNSPlatformSetDNSConfig: generation number %llu same, not processing", config->generation);
+ LogInfo("mDNSPlatformSetDNSConfig(setservers): generation number %llu same, not processing", config->generation);
dns_configuration_free(config);
SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
return mDNSfalse;
@@ -6985,13 +5952,13 @@ mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers,
// 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);
+ ConfigResolvers(config, kScopeNone, setsearch, setservers, &sdc, ++resolverGroupID);
resolverGroupID += config->n_resolver;
- ConfigResolvers(m, config, kScopeInterfaceID, setsearch, setservers, &sdc, resolverGroupID);
+ ConfigResolvers(config, kScopeInterfaceID, setsearch, setservers, &sdc, resolverGroupID);
resolverGroupID += config->n_scoped_resolver;
- ConfigResolvers(m, config, kScopeServiceID, setsearch, setservers, &sdc, resolverGroupID);
+ ConfigResolvers(config, kScopeServiceID, setsearch, setservers, &sdc, resolverGroupID);
// Acking provides a hint to other processes that the current DNS configuration has completed
// its update. When configd receives the ack, it publishes a notification.
@@ -7000,12 +5967,21 @@ mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers,
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);
+ AckConfigd(config);
}
dns_configuration_free(config);
- if (setsearch) FinalizeSearchDomainHash(m, &sdc);
+ if (setsearch) FinalizeSearchDomainHash(&sdc);
}
}
#endif // MDNS_NO_DNSINFO
@@ -7014,11 +5990,10 @@ mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers,
}
-mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r)
+mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r)
{
char buf[256];
- (void)m; // Unused
-
+
CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_IPv4);
if (dict)
{
@@ -7054,6 +6029,12 @@ mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4,
// find primary interface in list
while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6))
{
+ if (!ifa->ifa_addr)
+ {
+ LogMsg("Skip interface, %s, since ifa_addr is not set.", (ifa->ifa_name) ? ifa->ifa_name: "name not found");
+ ifa = ifa->ifa_next;
+ continue;
+ }
mDNSAddr tmp6 = zeroAddr;
if (!strcmp(buf, ifa->ifa_name))
{
@@ -7299,7 +6280,7 @@ mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
#endif // ! NO_AWACS
#if !TARGET_OS_EMBEDDED
-mDNSlocal void ProcessConndConfigChanges(mDNS *const m);
+mDNSlocal void ProcessConndConfigChanges(void);
#endif
#endif // APPLE_OSX_mDNSResponder
@@ -7543,7 +6524,7 @@ mDNSlocal void SetDomainSecrets_internal(mDNS *m)
else if (info->AutoTunnelServiceStarted)
needAutoTunnelNAT = true;
- UpdateAutoTunnelDomainStatus(m, info);
+ UpdateAutoTunnelDomainStatus(info);
}
}
@@ -7562,7 +6543,7 @@ mDNSlocal void SetDomainSecrets_internal(mDNS *m)
}
UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
- ProcessConndConfigChanges(m); // Update AutoTunnelInnerAddress values and default ipsec policies as necessary
+ ProcessConndConfigChanges(); // Update AutoTunnelInnerAddress values and default ipsec policies as necessary
}
#endif // APPLE_OSX_mDNSResponder
@@ -7840,8 +6821,9 @@ typedef struct
#include <IOKit/IOKitLib.h>
#include <dns_util.h>
-mDNSlocal mDNSu16 GetPortArray(mDNS *const m, int trans, mDNSIPPort *portarray)
+mDNSlocal mDNSu16 GetPortArray(int trans, mDNSIPPort *portarray)
{
+ mDNS *const m = &mDNSStorage;
const domainlabel *const tp = (trans == mDNSTransport_UDP) ? (const domainlabel *)"\x4_udp" : (const domainlabel *)"\x4_tcp";
int count = 0;
@@ -7913,8 +6895,9 @@ mDNSlocal mDNSBool OnBattery(void)
#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)
+mDNSlocal mDNSu32 CountProxyRecords(uint32_t *const numbytes, NetworkInterfaceInfo *const intf, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
{
+ mDNS *const m = &mDNSStorage;
*numbytes = 0;
int count = 0;
@@ -7957,8 +6940,9 @@ mDNSlocal mDNSu32 CountProxyRecords(mDNS *const m, uint32_t *const numbytes, Net
return(count);
}
-mDNSlocal void GetProxyRecords(mDNS *const m, DNSMessage *const msg, uint32_t *const numbytes, FatPtr *const records, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
+mDNSlocal void GetProxyRecords(DNSMessage *const msg, uint32_t *const numbytes, FatPtr *const records, mDNSBool TCPKAOnly, mDNSBool supportsTCPKA)
{
+ mDNS *const m = &mDNSStorage;
mDNSu8 *p = msg->data;
const mDNSu8 *const limit = p + *numbytes;
InitializeDNSMessage(&msg->h, zeroID, zeroID);
@@ -8013,7 +6997,7 @@ mDNSexport mDNSBool SupportsInNICProxy(NetworkInterfaceInfo *const intf)
return CheckInterfaceSupport(intf, mDNS_IOREG_KEY);
}
-mDNSexport mStatus ActivateLocalProxy(mDNS *const m, NetworkInterfaceInfo *const intf, mDNSBool *keepaliveOnly) // Called with the lock held
+mDNSexport mStatus ActivateLocalProxy(NetworkInterfaceInfo *const intf, mDNSBool *keepaliveOnly) // Called with the lock held
{
mStatus result = mStatus_UnknownErr;
mDNSBool TCPKAOnly = mDNSfalse;
@@ -8029,7 +7013,7 @@ mDNSexport mStatus ActivateLocalProxy(mDNS *const m, NetworkInterfaceInfo *const
// 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);
+ TCPKAOnly = supportsTCPKA && ((mDNSStorage.SystemWakeOnLANEnabled == mDNS_WakeOnBattery) || onbattery);
#else
(void) onbattery; // unused;
#endif
@@ -8037,15 +7021,48 @@ mDNSexport mStatus ActivateLocalProxy(mDNS *const m, NetworkInterfaceInfo *const
io_name_t n1, n2;
IOObjectGetClass(service, n1);
- io_object_t parent;
+ io_object_t parent = IO_OBJECT_NULL;
+
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);
+ CFTypeRef ref = mDNSNULL;
+ if (IsAppleTV())
+ {
+ while (service)
+ {
+ ref = IORegistryEntryCreateCFProperty(parent, CFSTR(mDNS_IOREG_KEY), kCFAllocatorDefault, mDNSNULL);
+ if (!ref)
+ {
+ IOObjectRelease(service);
+ service = parent;
+ kr = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent);
+ if (kr != KERN_SUCCESS)
+ {
+ IOObjectGetClass(service, n1);
+ LogMsg("ActivateLocalProxy: IORegistryEntryGetParentEntry for %s/%s failed %d", intf->ifname, n1, kr);
+ parent = IO_OBJECT_NULL;
+ result = mStatus_BadStateErr;
+ break;
+ }
+ }
+ else
+ {
+ IOObjectGetClass(parent, n2);
+ LogSPS("ActivateLocalProxy: Found %s Interface %s parent %s", mDNS_IOREG_KEY, intf->ifname, n2);
+ break;
+ }
+ }
+ }
+ else
+ {
+ IOObjectGetClass(parent, n2);
+ LogSPS("ActivateLocalProxy: Interface %s service %s parent %s", intf->ifname, n1, n2);
+ ref = IORegistryEntryCreateCFProperty(parent, CFSTR(mDNS_IOREG_KEY), kCFAllocatorDefault, mDNSNULL);
+ }
+
+ if (!ref || parent == IO_OBJECT_NULL) 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)))
@@ -8063,9 +7080,9 @@ mDNSexport mStatus ActivateLocalProxy(mDNS *const m, NetworkInterfaceInfo *const
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.numUDPPorts = GetPortArray(mDNSTransport_UDP, mDNSNULL);
+ cmd.numTCPPorts = GetPortArray(mDNSTransport_TCP, mDNSNULL);
+ cmd.numRRRecords = CountProxyRecords(&cmd.rrBufferSize, intf, TCPKAOnly, supportsTCPKA);
cmd.compression = sizeof(DNSMessageHeader);
DNSMessage *msg = (DNSMessage *)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader) + cmd.rrBufferSize);
@@ -8079,9 +7096,9 @@ mDNSexport mStatus ActivateLocalProxy(mDNS *const m, NetworkInterfaceInfo *const
cmd.udpPorts.ptr, cmd.numUDPPorts,
cmd.tcpPorts.ptr, cmd.numTCPPorts);
- if (msg && cmd.rrRecords.ptr) GetProxyRecords(m, msg, &cmd.rrBufferSize, cmd.rrRecords.ptr, TCPKAOnly, supportsTCPKA);
- if (cmd.udpPorts.ptr) cmd.numUDPPorts = GetPortArray(m, mDNSTransport_UDP, cmd.udpPorts.ptr);
- if (cmd.tcpPorts.ptr) cmd.numTCPPorts = GetPortArray(m, mDNSTransport_TCP, cmd.tcpPorts.ptr);
+ if (msg && cmd.rrRecords.ptr) GetProxyRecords(msg, &cmd.rrBufferSize, cmd.rrRecords.ptr, TCPKAOnly, supportsTCPKA);
+ if (cmd.udpPorts.ptr) cmd.numUDPPorts = GetPortArray(mDNSTransport_UDP, cmd.udpPorts.ptr);
+ if (cmd.tcpPorts.ptr) cmd.numTCPPorts = GetPortArray(mDNSTransport_TCP, cmd.tcpPorts.ptr);
char outputData[2];
size_t outputDataSize = sizeof(outputData);
@@ -8098,9 +7115,9 @@ mDNSexport mStatus ActivateLocalProxy(mDNS *const m, NetworkInterfaceInfo *const
}
CFRelease(ref);
}
- IOObjectRelease(parent);
+ if (parent != IO_OBJECT_NULL) IOObjectRelease(parent);
}
- IOObjectRelease(service);
+ if (service != IO_OBJECT_NULL) IOObjectRelease(service);
*keepaliveOnly = TCPKAOnly;
return result;
}
@@ -8168,8 +7185,9 @@ mDNSlocal mDNSBool SystemSleepOnlyIfWakeOnLAN(void)
// 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)
+mDNSexport mDNSBool RecordReadyForSleep(AuthRecord *rr)
{
+ mDNS *const m = &mDNSStorage;
if (!AuthRecord_uDNS(rr)) return mDNStrue;
if ((rr->resrec.rrtype == kDNSType_AAAA) && SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0c_autotunnel6"))
@@ -8385,8 +7403,9 @@ mDNSlocal mDNSv6Addr ParseBackToMyMacZone(CFDictionaryRef zones, DomainAuthInfo*
return addr;
}
-mDNSlocal void SetupBackToMyMacInnerAddresses(mDNS *const m, CFDictionaryRef BTMMDict)
+mDNSlocal void SetupBackToMyMacInnerAddresses(CFDictionaryRef BTMMDict)
{
+ mDNS *const m = &mDNSStorage;
DomainAuthInfo* info;
CFDictionaryRef zones = GetBackToMyMacZones(BTMMDict);
mDNSv6Addr newAddr;
@@ -8404,13 +7423,14 @@ mDNSlocal void SetupBackToMyMacInnerAddresses(mDNS *const m, CFDictionaryRef BTM
info->AutoTunnelInnerAddress = newAddr;
DeregisterAutoTunnelHostRecord(m, info);
UpdateAutoTunnelHostRecord(m, info);
- UpdateAutoTunnelDomainStatus(m, info);
+ UpdateAutoTunnelDomainStatus(info);
}
}
// MUST be called holding the lock
-mDNSlocal void ProcessConndConfigChanges(mDNS *const m)
+mDNSlocal void ProcessConndConfigChanges(void)
{
+ mDNS *const m = &mDNSStorage;
CFDictionaryRef dict = CopyConnectivityBackToMyMacDict();
if (!dict)
LogInfo("ProcessConndConfigChanges: No BTMM dictionary");
@@ -8418,7 +7438,7 @@ mDNSlocal void ProcessConndConfigChanges(mDNS *const m)
LogInfo("ProcessConndConfigChanges: relay %.16a", &relayAddr);
- SetupBackToMyMacInnerAddresses(m, dict);
+ SetupBackToMyMacInnerAddresses(dict);
if (dict) CFRelease(dict);
@@ -8432,7 +7452,7 @@ mDNSlocal void ProcessConndConfigChanges(mDNS *const m)
{
DeregisterAutoTunnel6Record(m, info);
UpdateAutoTunnel6Record(m, info);
- UpdateAutoTunnelDomainStatus(m, info);
+ UpdateAutoTunnelDomainStatus(info);
}
// Determine whether we need racoon to accept incoming connections
@@ -8462,8 +7482,9 @@ mDNSlocal mDNSBool IsAppleNetwork(mDNS *const m)
// Called with KQueueLock & mDNS lock
// SetNetworkChanged is allowed to shorten (but not extend) the pause while we wait for configuration changes to settle
-mDNSlocal void SetNetworkChanged(mDNS *const m, mDNSs32 delay)
+mDNSlocal void SetNetworkChanged(mDNSs32 delay)
{
+ mDNS *const m = &mDNSStorage;
mDNS_CheckLock(m);
if (!m->NetworkChanged || m->NetworkChanged - NonZeroTime(m->timenow + delay) > 0)
{
@@ -8475,8 +7496,9 @@ mDNSlocal void SetNetworkChanged(mDNS *const m, mDNSs32 delay)
}
// Called with KQueueLock & mDNS lock
-mDNSlocal void SetKeyChainTimer(mDNS *const m, mDNSs32 delay)
+mDNSlocal void SetKeyChainTimer(mDNSs32 delay)
{
+ mDNS *const m = &mDNSStorage;
// 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)
{
@@ -8485,8 +7507,9 @@ mDNSlocal void SetKeyChainTimer(mDNS *const m, mDNSs32 delay)
}
}
-mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
+mDNSexport void mDNSMacOSXNetworkChanged(void)
{
+ mDNS *const m = &mDNSStorage;
LogInfo("*** Network Configuration Change *** %d ticks late%s",
m->NetworkChanged ? mDNS_TimeNow(m) - m->NetworkChanged : 0,
m->NetworkChanged ? "" : " (no scheduled configuration change)");
@@ -8500,7 +7523,7 @@ mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
struct ifaddrs *ifa = myGetIfAddrs(1);
while (ifa)
{
- if (ifa->ifa_addr->sa_family == AF_INET6)
+ if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6)
{
struct in6_ifreq ifr6;
mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6));
@@ -8527,7 +7550,7 @@ mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
if (tentative)
{
mDNS_Lock(m);
- SetNetworkChanged(m, mDNSPlatformOneSecond / 2);
+ SetNetworkChanged(mDNSPlatformOneSecond / 2);
mDNS_Unlock(m);
return;
}
@@ -8537,15 +7560,16 @@ mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
mDNSs32 utc = mDNSPlatformUTC();
m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
m->SystemSleepOnlyIfWakeOnLAN = SystemSleepOnlyIfWakeOnLAN();
- MarkAllInterfacesInactive(m, utc);
- UpdateInterfaceList(m, utc);
- ClearInactiveInterfaces(m, utc);
- SetupActiveInterfaces(m, utc);
+ MarkAllInterfacesInactive(utc);
+ UpdateInterfaceList(utc);
+ ClearInactiveInterfaces(utc);
+ SetupActiveInterfaces(utc);
+ ReorderInterfaceList();
#if APPLE_OSX_mDNSResponder
#if !TARGET_OS_EMBEDDED
mDNS_Lock(m);
- ProcessConndConfigChanges(m);
+ ProcessConndConfigChanges();
mDNS_Unlock(m);
// Scan to find client tunnels whose questions have completed,
@@ -8601,7 +7625,7 @@ mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
{
if (!m->SPSSocket) // Not being Sleep Proxy Server; close any open BPF fds
{
- if (i->BPF_fd >= 0 && CountProxyTargets(m, i, mDNSNULL, mDNSNULL) == 0)
+ if (i->BPF_fd >= 0 && CountProxyTargets(i, mDNSNULL, mDNSNULL) == 0)
CloseBPF(i);
}
else // else, we're Sleep Proxy Server; open BPF fds
@@ -8764,7 +7788,7 @@ mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, v
{
(void)store; // Parameter not used
mDNS *const m = (mDNS *const)context;
- KQueueLock(m);
+ KQueueLock();
mDNS_Lock(m);
//mDNSs32 delay = mDNSPlatformOneSecond * 2; // Start off assuming a two-second delay
@@ -8781,7 +7805,7 @@ mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, v
int c_fast = 0;
// Do immediate network changed processing for "p2p*" interfaces and
- // for interfaces with the IFEF_DIRECTLINK flag set or association with a CarPlay
+ // for interfaces with the IFEF_DIRECTLINK or IFEF_AWDL flag set or association with a CarPlay
// hosted SSID.
{
CFArrayRef labels;
@@ -8812,7 +7836,7 @@ mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, v
// 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) || IsCarPlaySSID(buf)))
+ && (strstr(buf, "p2p") || (getExtendedFlags(buf) & (IFEF_DIRECTLINK | IFEF_AWDL)) || IsCarPlaySSID(buf)))
{
LogInfo("NetworkChanged: interface %s qualifies for reduced change handling delay", buf);
c_fast++;
@@ -8844,12 +7868,12 @@ mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, v
c_ddns ? "(DynamicDNS) " : "",
c_btmm ? "(BTMM) " : "",
c_v4ll ? "(kSCValNetIPv4ConfigMethodLinkLocal) " : "",
- c_fast ? "(P2P/IFEF_DIRECTLINK/IsCarPlaySSID) " : "",
+ c_fast ? "(P2P/IFEF_DIRECTLINK/IFEF_AWDL/IsCarPlaySSID) " : "",
delay,
(c_ddns || c_btmm) ? " + SetKeyChainTimer" : "");
}
- SetNetworkChanged(m, delay);
+ SetNetworkChanged(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
@@ -8857,12 +7881,12 @@ mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, v
// If we don't, then we will first try to register services in the clear, then later setup the
// DomainAuthInfo, which is incorrect.
if (c_ddns || c_btmm)
- SetKeyChainTimer(m, delay);
+ SetKeyChainTimer(delay);
// Don't try to call mDNSMacOSXNetworkChanged() here -- we're running on the wrong thread
mDNS_Unlock(m);
- KQueueUnlock(m, "NetworkChanged");
+ KQueueUnlock("NetworkChanged");
}
#if APPLE_OSX_mDNSResponder
@@ -8886,7 +7910,7 @@ mDNSlocal void DynamicStoreReconnected(SCDynamicStoreRef store, void *info)
mDNS *const m = (mDNS *const)info;
(void)store;
- KQueueLock(m); // serialize with KQueueLoop()
+ KQueueLock(); // serialize with KQueueLoop()
LogInfo("DynamicStoreReconnected: Reconnected");
@@ -8913,7 +7937,7 @@ mDNSlocal void DynamicStoreReconnected(SCDynamicStoreRef store, void *info)
if (spsStatusDict)
CFDictionaryApplyFunction(spsStatusDict, RefreshSPSStatus, NULL);
#endif
- KQueueUnlock(m, "DynamicStoreReconnected");
+ KQueueUnlock("DynamicStoreReconnected");
}
mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
@@ -8971,8 +7995,9 @@ exit:
#if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
-mDNSlocal void mDNSSetPacketFilterRules(mDNS *const m, char * ifname, const ResourceRecord *const excludeRecord)
+mDNSlocal void mDNSSetPacketFilterRules(char * ifname, const ResourceRecord *const excludeRecord)
{
+ mDNS *const m = &mDNSStorage;
AuthRecord *rr;
pfArray_t portArray;
pfArray_t protocolArray;
@@ -9043,7 +8068,7 @@ mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord
if (strncmp(intf->ifname, "p2p", 3) == 0)
{
LogInfo("mDNSInitPacketFilter: Setting rules for ifname %s", intf->ifname);
- mDNSSetPacketFilterRules(m, intf->ifname, excludeRecord);
+ mDNSSetPacketFilterRules(intf->ifname, excludeRecord);
break;
}
intf = GetFirstActiveInterface(intf->next);
@@ -9060,16 +8085,11 @@ mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord
#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)
+// AWDL should no longer generate KEV_DL_MASTER_ELECTED events, so just log a message if we receive one.
+mDNSlocal void newMasterElected(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);
@@ -9080,35 +8100,7 @@ mDNSlocal void newMasterElected(mDNS *const m, struct net_event_data * ptr)
return;
}
- LogInfo("newMasterElected: ifname = %s, interfaceIndex = %d", ifname, interfaceIndex);
- infoOSX = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)interfaceIndex);
- if (!infoOSX)
- {
- LogInfo("newMasterElected: interface %s not yet active", ifname);
- 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);
- }
- }
+ LogInfo("newMasterElected: KEV_DL_MASTER_ELECTED received on ifname = %s, interfaceIndex = %d", ifname, interfaceIndex);
}
// An ssth array of all zeroes indicates the peer has no services registered.
@@ -9136,8 +8128,9 @@ mDNSlocal mDNSBool allZeroSSTH(struct opaque_presence_indication *op)
}
// Mark records from this peer for deletion from the cache.
-mDNSlocal void removeCachedPeerRecords(mDNS *const m, mDNSu32 ifindex, mDNSAddr *ap, bool purgeNow)
+mDNSlocal void removeCachedPeerRecords(mDNSu32 ifindex, mDNSAddr *ap, bool purgeNow)
{
+ mDNS *const m = &mDNSStorage;
mDNSu32 slot;
CacheGroup *cg;
CacheRecord *cr;
@@ -9146,7 +8139,7 @@ mDNSlocal void removeCachedPeerRecords(mDNS *const m, mDNSu32 ifindex, mDNSAddr
// Using mDNSPlatformInterfaceIDfromInterfaceIndex() would lead to recursive
// locking issues, see: <rdar://problem/21332983>
- infoOSX = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
+ infoOSX = IfindexToInterfaceInfoOSX((mDNSInterfaceID)(uintptr_t)ifindex);
if (!infoOSX)
{
LogInfo("removeCachedPeerRecords: interface %d not yet active", ifindex);
@@ -9170,7 +8163,7 @@ mDNSlocal void removeCachedPeerRecords(mDNS *const m, mDNSu32 ifindex, mDNSAddr
}
// Handle KEV_DL_NODE_PRESENCE event.
-mDNSlocal void nodePresence(mDNS *const m, struct kev_dl_node_presence * p)
+mDNSlocal void nodePresence(struct kev_dl_node_presence * p)
{
char buf[INET6_ADDRSTRLEN];
struct opaque_presence_indication *op = (struct opaque_presence_indication *) p->node_service_info;
@@ -9190,12 +8183,12 @@ mDNSlocal void nodePresence(mDNS *const m, struct kev_dl_node_presence * p)
peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
LogInfo("nodePresence: ssth is all zeroes, reconfirm cached records for this peer");
- removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr, false);
+ removeCachedPeerRecords(p->sdl_node_address.sdl_index, & peerAddr, false);
}
}
// Handle KEV_DL_NODE_ABSENCE event.
-mDNSlocal void nodeAbsence(mDNS *const m, struct kev_dl_node_absence * p)
+mDNSlocal void nodeAbsence(struct kev_dl_node_absence * p)
{
mDNSAddr peerAddr;
char buf[INET6_ADDRSTRLEN];
@@ -9209,10 +8202,10 @@ mDNSlocal void nodeAbsence(mDNS *const m, struct kev_dl_node_absence * p)
peerAddr.ip.v6 = *(mDNSv6Addr*)&p->sin6_node_address.sin6_addr;
LogInfo("nodeAbsence: immediately purge cached records from this peer");
- removeCachedPeerRecords(m, p->sdl_node_address.sdl_index, & peerAddr, true);
+ removeCachedPeerRecords(p->sdl_node_address.sdl_index, & peerAddr, true);
}
-mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context)
+mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context, __unused mDNSBool encounteredEOF)
{
mDNS *const m = (mDNS *const)context;
@@ -9256,13 +8249,13 @@ mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context)
"?");
if (msg.k.event_code == KEV_DL_NODE_PRESENCE)
- nodePresence(m, (struct kev_dl_node_presence *) &msg.k.event_data);
+ nodePresence((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);
+ nodeAbsence((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);
+ newMasterElected((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)
@@ -9271,7 +8264,7 @@ mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context)
// 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);
+ SetNetworkChanged(mDNSPlatformOneSecond * 2);
#if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
@@ -9288,7 +8281,7 @@ mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context)
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);
+ mDNSSetPacketFilterRules(ifname, NULL);
}
}
@@ -9375,7 +8368,7 @@ mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCa
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);
+ KQueueLock();
mDNS_Lock(m);
// To not read the keychain twice: when BTMM is enabled, changes happen to the keychain
@@ -9389,10 +8382,10 @@ mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCa
//
// 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);
+ SetKeyChainTimer(mDNSPlatformOneSecond);
mDNS_Unlock(m);
- KQueueUnlock(m, "KeychainChanged");
+ KQueueUnlock("KeychainChanged");
}
}
CFRelease(skc);
@@ -9432,14 +8425,14 @@ mDNSlocal void PowerOn(mDNS *const m)
// Hold on to a sleep assertion to allow mDNSResponder to perform its maintenance activities.
// This allows for the network link to come up, DHCP to get an address, mDNS to issue queries etc.
// We will clear this assertion as soon as we think the mainenance activities are done.
- mDNSPlatformPreventSleep(m, DARK_WAKE_TIME, "mDNSResponder:maintenance");
+ mDNSPlatformPreventSleep(DARK_WAKE_TIME, "mDNSResponder:maintenance");
}
mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
{
mDNS *const m = (mDNS *const)refcon;
- KQueueLock(m);
+ KQueueLock();
(void)service; // Parameter not used
debugf("PowerChanged %X %lX", messageType, messageArgument);
@@ -9451,7 +8444,7 @@ mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messag
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);
+ if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged();
break;
case kIOMessageSystemWillNotPowerOff: LogSPS("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260
case kIOMessageCanSystemSleep: LogSPS("PowerChanged kIOMessageCanSystemSleep"); break; // E0000270
@@ -9470,7 +8463,7 @@ mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messag
// the System Configuration Framework "network changed" event that we expect
// to receive some time shortly after the kIOMessageSystemWillPowerOn message
mDNS_Lock(m);
- SetNetworkChanged(m, mDNSPlatformOneSecond * 2);
+ SetNetworkChanged(mDNSPlatformOneSecond * 2);
mDNS_Unlock(m);
break;
@@ -9482,7 +8475,7 @@ mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messag
{
LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m->SleepState);
m->SleepState = SleepState_Sleeping;
- mDNSMacOSXNetworkChanged(m);
+ mDNSMacOSXNetworkChanged();
}
PowerOn(m);
break;
@@ -9494,7 +8487,7 @@ mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messag
else if (messageType == kIOMessageCanSystemSleep)
IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument);
- KQueueUnlock(m, "PowerChanged Sleep/Wake");
+ KQueueUnlock("PowerChanged Sleep/Wake");
}
// iPhone OS doesn't currently have SnowLeopard's IO Power Management
@@ -9503,7 +8496,7 @@ mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messag
mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection, IOPMConnectionMessageToken token, IOPMSystemPowerStateCapabilities eventDescriptor)
{
mDNS *const m = (mDNS *const)refcon;
- KQueueLock(m);
+ KQueueLock();
LogSPS("SnowLeopardPowerChanged %X %X %X%s%s%s%s%s",
connection, token, eventDescriptor,
eventDescriptor & kIOPMSystemPowerStateCapabilityCPU ? " CPU" : "",
@@ -9535,7 +8528,7 @@ mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection,
// 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, mDNSPlatformOneSecond * 2);
+ SetNetworkChanged(mDNSPlatformOneSecond * 2);
mDNS_Unlock(m);
}
IOPMConnectionAcknowledgeEvent(connection, token);
@@ -9552,7 +8545,7 @@ mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection,
m->p->SleepCookie = token;
}
- KQueueUnlock(m, "SnowLeopardPowerChanged Sleep/Wake");
+ KQueueUnlock("SnowLeopardPowerChanged Sleep/Wake");
}
#endif
@@ -9594,10 +8587,9 @@ mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result
}
// 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)
+mDNSlocal mDNSBool mDNSMacOSXCreateEtcHostsEntry(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;
@@ -9638,9 +8630,8 @@ mDNSlocal mDNSBool mDNSMacOSXCreateEtcHostsEntry(mDNS *const m, const domainname
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);
+ ag = AuthGroupForName(auth, namehash, domain);
if (ag)
{
rr = ag->members;
@@ -9710,8 +8701,8 @@ mDNSlocal mDNSBool mDNSMacOSXCreateEtcHostsEntry(mDNS *const m, const domainname
}
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);
+ LogInfo("mDNSMacOSXCreateEtcHostsEntry: Adding resource record %s", ARDisplayString(&mDNSStorage, rr));
+ InsertAuthRecord(&mDNSStorage, auth, rr);
return mDNStrue;
}
@@ -9743,7 +8734,7 @@ mDNSlocal int EtcHostsParseOneName(int start, int length, char *buffer, char **n
return -1;
}
-mDNSlocal void mDNSMacOSXParseEtcHostsLine(mDNS *const m, char *buffer, ssize_t length, AuthHash *auth)
+mDNSlocal void mDNSMacOSXParseEtcHostsLine(char *buffer, ssize_t length, AuthHash *auth)
{
int i;
int ifStart = 0;
@@ -9808,7 +8799,7 @@ mDNSlocal void mDNSMacOSXParseEtcHostsLine(mDNS *const m, char *buffer, ssize_t
freeaddrinfo(gairesults);
return;
}
- mDNSMacOSXCreateEtcHostsEntry(m, &name1d, gairesults->ai_addr, mDNSNULL, ifname, auth);
+ mDNSMacOSXCreateEtcHostsEntry(&name1d, gairesults->ai_addr, mDNSNULL, ifname, auth);
}
else if (i != -1)
{
@@ -9823,7 +8814,7 @@ mDNSlocal void mDNSMacOSXParseEtcHostsLine(mDNS *const m, char *buffer, ssize_t
freeaddrinfo(gairesults);
return;
}
- mDNSMacOSXCreateEtcHostsEntry(m, &first, gairesults->ai_addr, mDNSNULL, ifname, auth);
+ mDNSMacOSXCreateEtcHostsEntry(&first, gairesults->ai_addr, mDNSNULL, ifname, auth);
// /etc/hosts alias discussion:
//
@@ -9867,7 +8858,7 @@ mDNSlocal void mDNSMacOSXParseEtcHostsLine(mDNS *const m, char *buffer, ssize_t
// Ignore if it points to itself
if (!SameDomainName(&first, &name2d))
{
- if (!mDNSMacOSXCreateEtcHostsEntry(m, &name2d, mDNSNULL, &first, ifname, auth))
+ if (!mDNSMacOSXCreateEtcHostsEntry(&name2d, mDNSNULL, &first, ifname, auth))
{
freeaddrinfo(gairesults);
return;
@@ -9891,7 +8882,7 @@ mDNSlocal void mDNSMacOSXParseEtcHostsLine(mDNS *const m, char *buffer, ssize_t
freeaddrinfo(gairesults);
}
-mDNSlocal void mDNSMacOSXParseEtcHosts(mDNS *const m, int fd, AuthHash *auth)
+mDNSlocal void mDNSMacOSXParseEtcHosts(int fd, AuthHash *auth)
{
mDNSBool good;
char buf[ETCHOSTS_BUFSIZE];
@@ -9939,15 +8930,16 @@ mDNSlocal void mDNSMacOSXParseEtcHosts(mDNS *const m, int fd, AuthHash *auth)
LogMsg("mDNSMacOSXParseEtcHosts: Length is zero!");
continue;
}
- mDNSMacOSXParseEtcHostsLine(m, buf, len, auth);
+ mDNSMacOSXParseEtcHostsLine(buf, len, auth);
}
fclose(fp);
}
mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m);
-mDNSlocal int mDNSMacOSXGetEtcHostsFD(mDNS *const m)
+mDNSlocal int mDNSMacOSXGetEtcHostsFD(void)
{
+ mDNS *const m = &mDNSStorage;
#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;
@@ -10090,8 +9082,9 @@ mDNSlocal void FlushAllCacheRecords(mDNS *const m)
}
// 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)
+mDNSlocal mDNSBool EtcHostsAddNewEntries(AuthHash *newhosts, mDNSBool justCheck)
{
+ mDNS *const m = &mDNSStorage;
AuthGroup *ag;
mDNSu32 slot;
AuthRecord *rr, *primary, *rrnext;
@@ -10105,7 +9098,7 @@ mDNSlocal mDNSBool EtcHostsAddNewEntries(mDNS *const m, AuthHash *newhosts, mDNS
AuthGroup *ag1;
AuthRecord *rr1;
mDNSBool found = mDNSfalse;
- ag1 = AuthGroupForRecord(&m->rrauth, slot, &rr->resrec);
+ ag1 = AuthGroupForRecord(&m->rrauth, &rr->resrec);
if (ag1 && ag1->members)
{
if (!primary) primary = ag1->members;
@@ -10149,8 +9142,9 @@ mDNSlocal mDNSBool EtcHostsAddNewEntries(mDNS *const m, AuthHash *newhosts, mDNS
// 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)
+mDNSlocal mDNSBool EtcHostsDeleteOldEntries(AuthHash *newhosts, mDNSBool justCheck)
{
+ mDNS *const m = &mDNSStorage;
AuthGroup *ag;
mDNSu32 slot;
AuthRecord *rr, *rrnext;
@@ -10163,7 +9157,7 @@ mDNSlocal mDNSBool EtcHostsDeleteOldEntries(mDNS *const m, AuthHash *newhosts, m
AuthRecord *rr1;
rrnext = rr->next;
if (rr->RecordCallback != FreeEtcHosts) continue;
- ag1 = AuthGroupForRecord(newhosts, slot, &rr->resrec);
+ ag1 = AuthGroupForRecord(newhosts, &rr->resrec);
if (ag1)
{
rr1 = ag1->members;
@@ -10218,9 +9212,9 @@ mDNSlocal void UpdateEtcHosts(mDNS *const m, void *context)
mDNS_CheckLock(m);
//Delete old entries from the core if they are not present in the newhosts
- EtcHostsDeleteOldEntries(m, newhosts, mDNSfalse);
+ EtcHostsDeleteOldEntries(newhosts, mDNSfalse);
// Add the new entries to the core if not already present in the core
- EtcHostsAddNewEntries(m, newhosts, mDNSfalse);
+ EtcHostsAddNewEntries(newhosts, mDNSfalse);
}
mDNSlocal void FreeNewHosts(AuthHash *newhosts)
@@ -10248,16 +9242,16 @@ mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m)
// As we will be modifying the core, we can only have one thread running at
// any point in time.
- KQueueLock(m);
+ KQueueLock();
mDNSPlatformMemZero(&newhosts, sizeof(AuthHash));
// Get the file desecriptor (will trigger us to start watching for changes)
- int fd = mDNSMacOSXGetEtcHostsFD(m);
+ int fd = mDNSMacOSXGetEtcHostsFD();
if (fd != -1)
{
LogInfo("mDNSMacOSXUpdateEtcHosts: Parsing /etc/hosts fd %d", fd);
- mDNSMacOSXParseEtcHosts(m, fd, &newhosts);
+ mDNSMacOSXParseEtcHosts(fd, &newhosts);
}
else LogInfo("mDNSMacOSXUpdateEtcHosts: /etc/hosts is not present");
@@ -10277,16 +9271,16 @@ mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m)
// 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))
+ if (!EtcHostsAddNewEntries(&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))
+ if (!EtcHostsDeleteOldEntries(&newhosts, mDNStrue))
{
LogInfo("mDNSMacOSXUpdateEtcHosts: No work");
FreeNewHosts(&newhosts);
mDNS_Unlock(m);
- KQueueUnlock(m, "/etc/hosts changed");
+ KQueueUnlock("/etc/hosts changed");
return;
}
}
@@ -10311,7 +9305,7 @@ mDNSlocal void mDNSMacOSXUpdateEtcHosts(mDNS *const m)
mDNSCoreRestartAddressQueries(m, mDNSfalse, FlushAllCacheRecords, UpdateEtcHosts, &newhosts);
FreeNewHosts(&newhosts);
mDNS_Unlock(m);
- KQueueUnlock(m, "/etc/hosts changed");
+ KQueueUnlock("/etc/hosts changed");
}
#if COMPILER_LIKES_PRAGMA_MARK
@@ -10383,7 +9377,7 @@ mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
return(err == 0);
}
-mDNSlocal void CreatePTRRecord(mDNS *const m, const domainname *domain)
+mDNSlocal void CreatePTRRecord(const domainname *domain)
{
AuthRecord *rr;
const domainname *pname = (domainname *)"\x9" "localhost";
@@ -10401,7 +9395,7 @@ mDNSlocal void CreatePTRRecord(mDNS *const m, const domainname *domain)
rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
- mDNS_Register(m, rr);
+ mDNS_Register(&mDNSStorage, rr);
}
// Setup PTR records for 127.0.0.1 and ::1. This helps answering them locally rather than relying
@@ -10411,7 +9405,7 @@ mDNSlocal void CreatePTRRecord(mDNS *const m, const domainname *domain)
//
// 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)
+mDNSlocal void SetupLocalHostRecords(void)
{
char buffer[MAX_REVERSE_MAPPING_NAME];
domainname name;
@@ -10424,7 +9418,7 @@ mDNSlocal void SetupLocalHostRecords(mDNS *const m)
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);
+ CreatePTRRecord(&name);
}
else LogMsg("SetupLocalHostRecords: ERROR!! inet_pton AF_INET failed");
@@ -10440,11 +9434,15 @@ mDNSlocal void SetupLocalHostRecords(mDNS *const m)
}
mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
MakeDomainNameFromDNSNameString(&name, buffer);
- CreatePTRRecord(m, &name);
+ CreatePTRRecord(&name);
}
else LogMsg("SetupLocalHostRecords: ERROR!! inet_pton AF_INET6 failed");
}
+#if APPLE_OSX_mDNSResponder // Don't compile for dnsextd target
+mDNSlocal void setSameDomainLabelPointer(void);
+#endif
+
// 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)
@@ -10462,6 +9460,10 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
char HINFO_SWstring[256] = "";
mDNSMacOSXSystemBuildNumber(HINFO_SWstring);
+#if APPLE_OSX_mDNSResponder
+ setSameDomainLabelPointer();
+#endif
+
err = mDNSHelperInit();
if (err)
return err;
@@ -10574,10 +9576,6 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
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);
@@ -10598,8 +9596,9 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
mDNSs32 utc = mDNSPlatformUTC();
m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
myGetIfAddrs(1);
- UpdateInterfaceList(m, utc);
- SetupActiveInterfaces(m, utc);
+ UpdateInterfaceList(utc);
+ SetupActiveInterfaces(utc);
+ ReorderInterfaceList();
// Explicitly ensure that our Keychain operations utilize the system domain.
#ifndef NO_SECURITYFRAMEWORK
@@ -10684,7 +9683,7 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
if (SSLqueue == mDNSNULL) LogMsg("dispatch_queue_create: SSL queue NULL");
mDNSMacOSXUpdateEtcHosts(m);
- SetupLocalHostRecords(m);
+ SetupLocalHostRecords();
return(mStatus_NoError);
}
@@ -10709,19 +9708,7 @@ mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
if (result == mStatus_NoError)
{
mDNSCoreInitComplete(m, mStatus_NoError);
-
-#if !NO_D2D
- // We only initialize if mDNSCore successfully initialized.
- if (D2DInitialize)
- {
- D2DStatus ds = D2DInitialize(CFRunLoopGetMain(), xD2DServiceCallback, m) ;
- if (ds != kD2DSuccess)
- LogMsg("D2DInitialiize failed: %d", ds);
- else
- LogMsg("D2DInitialize succeeded");
- }
-#endif // ! NO_D2D
-
+ initializeD2DPlugins(m);
}
result = DNSSECCryptoInit(m);
return(result);
@@ -10769,20 +9756,11 @@ mDNSexport void mDNSPlatformClose(mDNS *const m)
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
+ terminateD2DPlugins();
mDNSs32 utc = mDNSPlatformUTC();
- MarkAllInterfacesInactive(m, utc);
- ClearInactiveInterfaces(m, utc);
+ MarkAllInterfacesInactive(utc);
+ ClearInactiveInterfaces(utc);
CloseSocketSet(&m->p->permanentsockets);
#if APPLE_OSX_mDNSResponder
@@ -10893,8 +9871,9 @@ mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSP
#endif
mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }
-mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason)
+mDNSexport void mDNSPlatformSetAllowSleep(mDNSBool allowSleep, const char *reason)
{
+ mDNS *const m = &mDNSStorage;
if (allowSleep && m->p->IOPMAssertion)
{
LogInfo("%s Destroying NoIdleSleep power assertion", __FUNCTION__);
@@ -10918,9 +9897,10 @@ mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, co
}
}
-mDNSexport void mDNSPlatformPreventSleep(mDNS *const m, mDNSu32 timeout, const char *reason)
+mDNSexport void mDNSPlatformPreventSleep(mDNSu32 timeout, const char *reason)
{
- if (m->p->IOPMAssertion)
+ mDNS *const m = &mDNSStorage;
+ if (m->p->IOPMAssertion)
{
LogSPS("Sleep Assertion is already being held. Will not attempt to get it again for %d seconds for %s", timeout, reason);
return;
@@ -10954,12 +9934,12 @@ mDNSexport void mDNSPlatformPreventSleep(mDNS *const m, mDNSu32 timeout, const c
#endif
}
-mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
+mDNSexport void mDNSPlatformSendWakeupPacket(mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
{
mDNSu32 ifindex;
// Sanity check
- ifindex = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID, mDNStrue);
+ ifindex = mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, InterfaceID, mDNStrue);
if (ifindex <= 0)
{
LogMsg("mDNSPlatformSendWakeupPacket: ERROR!! Invalid InterfaceID %u", ifindex);
@@ -10990,7 +9970,7 @@ mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
if (AWDLInterfaceID && (InterfaceID == AWDLInterfaceID))
return mDNStrue;
- info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
+ info = IfindexToInterfaceInfoOSX(InterfaceID);
if (info == NULL)
{
// this log message can print when operations are stopped on an interface that has gone away
@@ -11101,9 +10081,9 @@ mDNSexport void mDNSPlatformDispatchAsync(mDNS *const m, void *context, AsyncDis
// 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);
+ KQueueLock();
func(m, context);
- KQueueUnlock(m, "mDNSPlatformDispatchAsync");
+ KQueueUnlock("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.
@@ -11195,5 +10175,359 @@ mDNSexport mDNSu32 initializeDeviceInfoTXT(mDNS *m, mDNSu8 *ptr)
return (ptr - bufferStart);
}
+#if APPLE_OSX_mDNSResponder // Don't compile for dnsextd target
+
+// Use the scalar version of SameDomainLabel() by default
+mDNSlocal mDNSBool scalarSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b);
+mDNSlocal mDNSBool vectorSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b);
+mDNSlocal mDNSBool (*SameDomainLabelPointer)(const mDNSu8 *a, const mDNSu8 *b) = scalarSameDomainLabel;
+
+#include <System/machine/cpu_capabilities.h>
+#define _cpu_capabilities ((uint32_t*) _COMM_PAGE_CPU_CAPABILITIES)[0]
+
+#if TARGET_OS_EMBEDDED
+
+#include <arm_neon.h>
+
+// Cache line aligned table that returns 32 for the upper case letters.
+// This will take up 4 cache lines.
+static const __attribute__ ((aligned(64))) uint8_t upper_to_lower_case_table[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// Neon version
+mDNSlocal mDNSBool vectorSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
+{
+ const int len = *a++;
+
+ if (len > MAX_DOMAIN_LABEL)
+ {
+ fprintf(stderr, "v: Malformed label (too long)\n");
+ return(mDNSfalse);
+ }
+
+ if (len != *b++)
+ {
+ return(mDNSfalse);
+ }
+
+ uint32_t len_count = len;
+
+ uint8x16_t vA, vB, vARotated, vBRotated, vMaskA, vMaskB;
+
+ uint8x16_t v32 = vdupq_n_u8(32);
+ uint8x16_t v37 = vdupq_n_u8(37);
+ uint8x16_t v101 = vdupq_n_u8(101);
+#if !defined __arm64__
+ uint32x4_t vtemp32;
+ uint32x2_t vtemp32d;
+ uint32_t sum;
+#endif
+
+ while(len_count > 15)
+ {
+ vA = vld1q_u8(a);
+ vB = vld1q_u8(b);
+ a += 16;
+ b += 16;
+
+ //Make vA to lowercase if there is any uppercase.
+ vARotated = vaddq_u8(vA, v37); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
+ vMaskA = vcgtq_s8(vARotated, v101); //Check if anything is greater than '101' which means we have uppercase letters.
+ vMaskA = vandq_u8(vMaskA, v32); //Prepare 32 for the elements with uppercase letters.
+ vA = vaddq_u8(vA, vMaskA); //Add 32 only to the uppercase letters to make them lowercase letters.
+
+ //Make vB to lowercase if there is any uppercase.
+ vBRotated = vaddq_u8(vB, v37); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
+ vMaskB = vcgtq_s8(vBRotated, v101); //Check if anything is greater than '101' which means we have uppercase letters.
+ vMaskB = vandq_u8(vMaskB, v32); //Prepare 32 for the elements with uppercase letters.
+ vB = vaddq_u8(vB, vMaskB); //Add 32 only to the uppercase letters to make them lowercase letters.
+
+ //Compare vA & vB
+ vA = vceqq_u8(vA, vB);
+
+#if defined __arm64__
+ //View 8-bit element as 32-bit => a3 a2 a1 a0
+ //If min of 4 32-bit values in vA is 0xffffffff, then it means we have 0xff for all 16.
+ if(vminvq_u32(vA) != 0xffffffffU)
+ {
+ return(mDNSfalse);
+
+ }
+#else
+ //See if any element was not same.
+ //View 8-bit element as 16-bit => a7 a6 a5 a4 a3 a2 a1 a0
+ //(a7+a6) (a5+a4) (a3+a2) (a1+a0) => Each will be 0xffff + 0xffff = 0x0001fffe when all same.
+ vtemp32 = vpaddlq_u16(vA);
+ vtemp32d = vpadd_u32(vget_low_u32(vtemp32), vget_high_u32(vtemp32));
+ vtemp32d = vpadd_u32(vtemp32d, vtemp32d);
+ sum = vget_lane_u32(vtemp32d, 0);
+
+ //0x0001fffe + 0x0001fffe + 0x0001fffe + 0x0001fffe = 0x0007fff8U when all same.
+ if(sum != 0x0007fff8U)
+ {
+ return(mDNSfalse);
+ }
+#endif
+
+ len_count -= 16;
+ }
+
+ uint8x8_t vAd, vBd, vARotatedd, vBRotatedd, vMaskAd, vMaskBd;
+
+ uint8x8_t v32d = vdup_n_u8(32);
+ uint8x8_t v37d = vdup_n_u8(37);
+ uint8x8_t v101d = vdup_n_u8(101);
+
+ while(len_count > 7)
+ {
+ vAd = vld1_u8(a);
+ vBd = vld1_u8(b);
+ a += 8;
+ b += 8;
+
+ //Make vA to lowercase if there is any uppercase.
+ vARotatedd = vadd_u8(vAd, v37d); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
+ vMaskAd = vcgt_s8(vARotatedd, v101d); //Check if anything is greater than '101' which means we have uppercase letters.
+ vMaskAd = vand_u8(vMaskAd, v32d); //Prepare 32 for the elements with uppercase letters.
+ vAd = vadd_u8(vAd, vMaskAd); //Add 32 only to the uppercase letters to make them lowercase letters.
+
+ //Make vB to lowercase if there is any uppercase.
+ vBRotatedd = vadd_u8(vBd, v37d); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
+ vMaskBd = vcgt_s8(vBRotatedd, v101d); //Check if anything is greater than '101' which means we have uppercase letters.
+ vMaskBd = vand_u8(vMaskBd, v32d); //Prepare 32 for the elements with uppercase letters.
+ vBd = vadd_u8(vBd, vMaskBd); //Add 32 only to the uppercase letters to make them lowercase letters.
+
+ //Compare vA & vB
+ vAd = vceq_u8(vAd, vBd);
+
+#if defined __arm64__
+ //View 8-bit element as 32-bit => a1 a0
+ //If min of 2 32-bit values in vAd is 0xffffffff, then it means we have 0xff for all 16.
+ if(vminv_u32(vAd) != 0xffffffffU)
+ {
+ return(mDNSfalse);
+
+ }
+#else
+ //See if any element was not same.
+ //View 8-bit element as 16-bit => a3 a2 a1 a0
+ //(a3+a2) (a1+a0) => Each will be 0xffff + 0xffff = 0x0001fffe when all same.
+ vtemp32d = vpaddl_u16(vAd);
+ vtemp32d = vpadd_u32(vtemp32d, vtemp32d);
+ sum = vget_lane_u32(vtemp32d, 0);
+
+ //0x0001fffe + 0x0001fffe = 0x0003fffc when all same.
+ if(sum != 0x0003fffcU)
+ {
+ return(mDNSfalse);
+ }
+#endif
+
+ len_count -= 8;
+ }
+
+ while(len_count > 0)
+ {
+ mDNSu8 ac = *a++;
+ mDNSu8 bc = *b++;
+
+ ac += upper_to_lower_case_table[ac];
+ bc += upper_to_lower_case_table[bc];
+
+ if (ac != bc)
+ {
+ return(mDNSfalse);
+ }
+
+ len_count -= 1;
+ }
+ return(mDNStrue);
+}
+
+// Use vectorized implementation if it is supported on this platform.
+mDNSlocal void setSameDomainLabelPointer(void)
+{
+ if(_cpu_capabilities & kHasNeon)
+ {
+ // Use Neon Code
+ SameDomainLabelPointer = vectorSameDomainLabel;
+ LogMsg("setSameDomainLabelPointer: using vector code");
+ }
+ else
+ LogMsg("setSameDomainLabelPointer: using scalar code");
+}
+
+#else // TARGET_OS_EMBEDDED
+
+#include <smmintrin.h>
+
+// Cache line aligned table that returns 32 for the upper case letters.
+// This will take up 4 cache lines.
+static const __attribute__ ((aligned(64))) uint8_t upper_to_lower_case_table[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// SSE2 version
+mDNSlocal mDNSBool vectorSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
+{
+ const int len = *a++;
+
+ if (len > MAX_DOMAIN_LABEL)
+ {
+ fprintf(stderr, "v: Malformed label (too long)\n");
+ return(mDNSfalse);
+ }
+
+ if (len != *b++)
+ {
+ return(mDNSfalse);
+ }
+
+ uint32_t len_count = len;
+
+ static const __attribute__ ((aligned(16))) unsigned char c_32[16] = { 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 };
+ static const __attribute__ ((aligned(16))) unsigned char c_37[16] = { 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37 };
+ static const __attribute__ ((aligned(16))) unsigned char c_101[16] = { 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101 };
+ __m128i v37 = _mm_load_si128((__m128i*)c_37);
+ __m128i v101 = _mm_load_si128((__m128i*)c_101);
+ __m128i v32 = _mm_load_si128((__m128i*)c_32);
+
+ uint32_t is_equal;
+ __m128i vA, vB, vARotated, vBRotated, vMaskA, vMaskB;
+
+ //AVX code that uses higher bandwidth (more elements per vector) was removed
+ //to speed up the processing on the small sizes.
+ //When I had them, the performance of 1 ~ 8 characters were slower by about 10% ~ 30%.
+ while(len_count > 15)
+ {
+ vA = _mm_loadu_si128((__m128i*)a);
+ vB = _mm_loadu_si128((__m128i*)b);
+ a += 16;
+ b += 16;
+
+ //Make vA to lowercase if there is any uppercase.
+ vARotated = _mm_add_epi8(vA, v37); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
+ vMaskA = _mm_cmpgt_epi8(vARotated, v101); //Check if anything is greater than '101' which means we have uppercase letters.
+ vMaskA = _mm_and_si128(vMaskA, v32); //Prepare 32 for the elements with uppercase letters.
+ vA = _mm_add_epi8(vA, vMaskA); //Add 32 only to the uppercase letters to make them lowercase letters.
+
+ //Make vB to lowercase if there is any uppercase.
+ vBRotated = _mm_add_epi8(vB, v37); //Map 'A' ~ 'Z' from '65' ~ '90' to '102' ~ '127'.
+ vMaskB = _mm_cmpgt_epi8(vBRotated, v101); //Check if anything is greater than '101' which means we have uppercase letters.
+ vMaskB = _mm_and_si128(vMaskB, v32); //Prepare 32 for the elements with uppercase letters.
+ vB = _mm_add_epi8(vB, vMaskB); //Add 32 only to the uppercase letters to make them lowercase letters.
+
+ //Compare vA & vB
+ vA = _mm_cmpeq_epi8(vA, vB);
+
+ //Return if any different.
+ is_equal = _mm_movemask_epi8(vA);
+ is_equal = is_equal & 0xffff;
+ if(is_equal != 0xffff)
+ {
+ return(mDNSfalse);
+ }
+
+ len_count -= 16;
+ }
+
+ while(len_count > 0)
+ {
+ mDNSu8 ac = *a++;
+ mDNSu8 bc = *b++;
+
+ //Table will return 32 for upper case letters only.
+ //0 will be returned for all others.
+ ac += upper_to_lower_case_table[ac];
+ bc += upper_to_lower_case_table[bc];
+
+ //Return if a & b are different.
+ if (ac != bc)
+ {
+ return(mDNSfalse);
+ }
+
+ len_count -= 1;
+ }
+ return(mDNStrue);
+}
+
+// Use vectorized implementation if it is supported on this platform.
+mDNSlocal void setSameDomainLabelPointer(void)
+{
+ if(_cpu_capabilities & kHasSSE4_1)
+ {
+ // Use SSE Code
+ SameDomainLabelPointer = vectorSameDomainLabel;
+ LogMsg("setSameDomainLabelPointer: using vector code");
+ }
+ else
+ LogMsg("setSameDomainLabelPointer: using scalar code");
+}
+
+#endif // TARGET_OS_EMBEDDED
+
+// Original SameDomainLabel() implementation.
+mDNSlocal mDNSBool scalarSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
+{
+ int i;
+ const int len = *a++;
+
+ if (len > MAX_DOMAIN_LABEL)
+ { debugf("Malformed label (too long)"); return(mDNSfalse); }
+
+ if (len != *b++) return(mDNSfalse);
+ for (i=0; i<len; i++)
+ {
+ mDNSu8 ac = *a++;
+ mDNSu8 bc = *b++;
+ if (mDNSIsUpperCase(ac)) ac += 'a' - 'A';
+ if (mDNSIsUpperCase(bc)) bc += 'a' - 'A';
+ if (ac != bc) return(mDNSfalse);
+ }
+ return(mDNStrue);
+}
+
+mDNSexport mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
+{
+ return (*SameDomainLabelPointer)(a, b);
+}
+
+#endif // APPLE_OSX_mDNSResponder
+
+
+#ifdef UNIT_TEST
+#include "../unittests/mdns_macosx_ut.c"
+#endif
diff --git a/mDNSResponder/mDNSMacOSX/mDNSMacOSX.h b/mDNSResponder/mDNSMacOSX/mDNSMacOSX.h
index 20f7a321..55c74c6c 100644
--- a/mDNSResponder/mDNSMacOSX/mDNSMacOSX.h
+++ b/mDNSResponder/mDNSMacOSX/mDNSMacOSX.h
@@ -62,7 +62,7 @@ enum mDNSDynamicStoreSetConfigKey
typedef struct NetworkInterfaceInfoOSX_struct NetworkInterfaceInfoOSX;
-typedef void (*KQueueEventCallback)(int fd, short filter, void *context);
+typedef void (*KQueueEventCallback)(int fd, short filter, void *context, mDNSBool encounteredEOF);
typedef struct
{
KQueueEventCallback KQcallback;
@@ -86,6 +86,8 @@ typedef struct
KQueueEntry kqsv6;
int *closeFlag;
mDNSBool proxy;
+ mDNSBool sktv4EOF;
+ mDNSBool sktv6EOF;
} KQSocketSet;
struct UDPSocket_struct
@@ -123,6 +125,9 @@ struct TCPSocket_struct
mStatus err;
};
+// Value assiged to 'Exists' to indicate the multicast state of the interface has changed.
+#define MulticastStateChanged 2
+
struct NetworkInterfaceInfoOSX_struct
{
NetworkInterfaceInfo ifinfo; // MUST be the first element in this structure
@@ -147,6 +152,7 @@ struct NetworkInterfaceInfoOSX_struct
int BPF_fd; // -1 uninitialized; -2 requested BPF; -3 failed
int BPF_mcfd; // Socket for our IPv6 ND group membership
u_int BPF_len;
+ mDNSBool isExpensive; // True if this interface has the IFEF_EXPENSIVE flag set.
#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
dispatch_source_t BPF_source;
#else
@@ -216,11 +222,11 @@ 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 mDNSMacOSXNetworkChanged(void);
extern void mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring);
-extern NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(const mDNS *const m, mDNSInterfaceID ifindex);
+extern NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(mDNSInterfaceID ifindex);
extern void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord);
-extern void myKQSocketCallBack(int s1, short filter, void *context);
+extern void myKQSocketCallBack(int s1, short filter, void *context, mDNSBool encounteredEOF);
extern void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropertyListRef value);
extern void UpdateDebugState(void);
@@ -233,15 +239,14 @@ extern int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *con
// 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 KQueueLock(void);
+extern void KQueueUnlock(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
@@ -267,14 +272,14 @@ 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_NetworkInterfaceInfoOSX[(sizeof(NetworkInterfaceInfoOSX) <= 7464) ? 1 : -1];
char sizecheck_mDNS_PlatformSupport [(sizeof(mDNS_PlatformSupport) <= 1378) ? 1 : -1];
};
+extern mDNSInterfaceID AWDLInterfaceID;
+void initializeD2DPlugins(mDNS *const m);
+void terminateD2DPlugins(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/mDNSResponder/mDNSMacOSX/mDNSNetMonitor/mDNSNetMonitor.8 b/mDNSResponder/mDNSMacOSX/mDNSNetMonitor/mDNSNetMonitor.8
new file mode 100644
index 00000000..455c3009
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/mDNSNetMonitor/mDNSNetMonitor.8
@@ -0,0 +1,40 @@
+.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples.
+.\"See Also:
+.\"man mdoc.samples for a complete listing of options
+.\"man mdoc for the short list of editing options
+.\"/usr/share/misc/mdoc.template
+.Dd 8/31/16 \" DATE
+.Dt mDNSNetMonitor 8 \" Program name and manual section number
+.Os Darwin
+.Sh NAME \" Section Header - required - don't modify
+.Nm mDNSNetMonitor
+.\" The following lines are read in generating the apropos(man -k) database. Use only key
+.\" words here as the database is built based on the words here and in the .ND line.
+.\" Use .Nm macro to designate other names for the documented program.
+.Nd dumps mDNS traffic on a network
+.Sh SYNOPSIS \" Section Header - required - don't modify
+.Nm
+.Op Fl i Ar interface
+.Op Ar host
+.Sh DESCRIPTION \" Section Header - required - don't modify
+.Nm
+prints out a description of the contents of mDNS packets on a network interface. It is similiar to tcpdump in that it continuously captures packets until it is interrupted by a SIGINT signal (generated, for example, by typing your interrupt character, typically control-C) or a SIGTERM signal (typically generated with the kill(1) command).
+
+When mDNSNetMonitor finishes capturing packets, it will report counts of packets captured per mDNS packet type, service type and source device.
+
+Note that mDNSNetMonitor will not capture unicast mDNS packets.
+.Sh OPTION
+
+-i interface Displays packets on specified interface.
+.Sh Example
+
+To print all packets arriving at or departing from
+.Pa sundown Ns :
+ % mDNSNetMonitor sundown
+.Sh SEE ALSO
+.\" List links in ascending order by section, alphabetically within a section.
+.\" Please do not reference files that do not exist without filing a bug report
+.Xr mDNSResponder 8 ,
+.Xr dns-sd 8
+.\" .Sh BUGS \" Document known, unremedied bugs
+.\" .Sh HISTORY \" Document history if command behaves in a unique manner
diff --git a/mDNSResponder/mDNSMacOSX/mDNSResponder-entitlements.plist b/mDNSResponder/mDNSMacOSX/mDNSResponder-entitlements.plist
index 6d0bd675..a1636401 100644
--- a/mDNSResponder/mDNSMacOSX/mDNSResponder-entitlements.plist
+++ b/mDNSResponder/mDNSMacOSX/mDNSResponder-entitlements.plist
@@ -20,8 +20,6 @@
<true/>
<key>com.apple.private.necp.match</key>
<true/>
- <key>com.apple.private.necp.policies</key>
- <true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.network.client</key>
@@ -34,13 +32,9 @@
<true/>
<key>com.apple.BTServer.appleMfgDataScanner</key>
<true/>
- <key>com.apple.developer.networking.networkextension</key>
- <array>
- <string>app-proxy-provider-system</string>
- </array>
- <key>com.apple.private.neagent</key>
+ <key>com.apple.BTServer.le.att</key>
<true/>
- <key>com.apple.private.nehelper.privileged</key>
+ <key>com.apple.private.network.delegation-whitelist</key>
<true/>
</dict>
</plist>
diff --git a/mDNSResponder/mDNSMacOSX/mDNSResponder-xcodeproj-explanation.txt b/mDNSResponder/mDNSMacOSX/mDNSResponder-xcodeproj-explanation.txt
new file mode 100644
index 00000000..e5dfaa3e
--- /dev/null
+++ b/mDNSResponder/mDNSMacOSX/mDNSResponder-xcodeproj-explanation.txt
@@ -0,0 +1,40 @@
+The mDNSResponder project has three umbrella targets:
+Build Some
+Build More
+Build All
+
+The “Build Some” target builds:
+mDNSResponder
+mDNSResponderHelper
+dns-sd tool
+dnsctl
+mDNSNetMonitor
+dns_services
+BonjourEvents
+
+The “Build More” target builds all of “Build Some”, plus
+dnsextd
+ddnswriteconfig
+PreferencePane
+
+The “Build All” target builds all of “Build More” (including “Build Some”) plus
+SystemLibraries
+
+Now, the explanation for this three-layer hierarchy:
+
+The “Build More” is the *first* target in the Xcode project.
+This is what B&I builds by default.
+Why not “Build All”? Because SystemLibraries is special.
+B&I builds the project in two passes. B&I builds SystemLibraries first, to
+make LibSystem. Then B&I builds builds the rest. The default target needs to
+be everything *except* SystemLibraries — i.e. the “Build More” target.
+
+The “Build Some” target builds the subset of “Build More”
+that is useful in routine day-to-day development.
+Since dnsextd, ddnswriteconfig and the PreferencePane aren’t usually
+what we’re working on, it’s quicker not to rebuild them every time.
+
+The “Build All” target is the final one. It builds absolutely everything.
+B&I never builds this (they do the two-pass build) but it’s there so that
+after making changes, but before checking them in, we can quickly and
+easily do a “Build All” and make sure our changes haven’t broken anything.
diff --git a/mDNSResponder/mDNSMacOSX/mDNSResponder.sb b/mDNSResponder/mDNSMacOSX/mDNSResponder.sb
index 807217ab..1458815c 100644
--- a/mDNSResponder/mDNSMacOSX/mDNSResponder.sb
+++ b/mDNSResponder/mDNSMacOSX/mDNSResponder.sb
@@ -45,6 +45,7 @@
; Mach communications
; These are needed for things like getpwnam, hostname changes, & keychain
(allow mach-lookup
+ (global-name "com.apple.analyticsd")
(global-name "com.apple.awdd")
(global-name "com.apple.bsd.dirhelper")
(global-name "com.apple.CoreServices.coreservicesd")
@@ -66,15 +67,18 @@
(global-name "com.apple.usymptomsd")
(global-name "com.apple.webcontentfilter.dns")
(global-name "com.apple.server.bluetooth")
+ (global-name "com.apple.server.bluetooth.le.att.xpc")
(global-name "com.apple.awacs")
(global-name "com.apple.networkd")
(global-name "com.apple.securityd")
(global-name "com.apple.wifi.manager")
+ ; "com.apple.blued" is the name used in pre Lobo builds,
+ ; leave it in place while still running roots on pre Lobo targets
(global-name "com.apple.blued")
+ (global-name "com.apple.bluetoothd")
(global-name "com.apple.mobilegestalt.xpc")
- (global-name "com.apple.snhelper")
- (global-name "com.apple.nehelper")
- (global-name "com.apple.networkserviceproxy"))
+ (global-name "com.apple.ReportCrash.SimulateCrash")
+ (global-name "com.apple.snhelper"))
(allow mach-register
(global-name "com.apple.d2d.ipc"))
@@ -100,6 +104,13 @@
; Our socket
(allow file-read* file-write* (literal "/private/var/run/mDNSResponder"))
+; BPF control for sleep proxy server
+(allow file-ioctl (prefix "/dev/bpf"))
+
+; Used by CoreCrypto AES routines.
+(allow file-read* file-write-data file-ioctl
+ (literal "/dev/aes_0"))
+
; System version, settings, and other miscellaneous necessary file system accesses
(allow file-read-data
; Needed for CFCopyVersionDictionary()
@@ -117,6 +128,8 @@
(literal "/private/var/preferences/SystemConfiguration/preferences.plist")
(subpath "/System/Library/Preferences/Logging")
(subpath "/AppleInternal/Library/Preferences/Logging")
+ (subpath "/private/var/preferences/Logging/Subsystems")
+ (subpath "/private/var/db/timezone")
(subpath "/Library/Preferences/Logging"))
@@ -156,3 +169,9 @@
(iokit-user-client-class "wlDNSOffloadUserClient")
(iokit-user-client-class "RootDomainUserClient")
(iokit-user-client-class "AppleMobileFileIntegrityUserClient"))))
+
+; Internal builds only
+(with-filter (system-attribute apple-internal)
+ (allow sysctl-read sysctl-write
+ (sysctl-name "vm.footprint_suspend"))) ; dyld performance reporting
+
diff --git a/mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj b/mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
index 3e6c3fd7..f1a8b1da 100644
--- a/mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
+++ b/mDNSResponder/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
@@ -15,8 +15,9 @@
dependencies = (
03067D860C849CC30022BE1F /* PBXTargetDependency */,
D284BF2C0ADD815A0027CCDF /* PBXTargetDependency */,
- D284BF2E0ADD81600027CCDF /* PBXTargetDependency */,
D284BF300ADD81630027CCDF /* PBXTargetDependency */,
+ 0C52E92F1E96AD74006EFE7B /* PBXTargetDependency */,
+ 0C4F36B41E206711005A536B /* PBXTargetDependency */,
);
name = "Build More";
productName = "Build All";
@@ -31,8 +32,10 @@
03067D6E0C83A39C0022BE1F /* PBXTargetDependency */,
03067D6C0C83A3920022BE1F /* PBXTargetDependency */,
BD7833F01ABA5E3500EC51ED /* PBXTargetDependency */,
+ 0C1596C71D7751AD00E09998 /* PBXTargetDependency */,
84C5B3411665544B00C324A8 /* PBXTargetDependency */,
217A4C49138EE14C000A5BA8 /* PBXTargetDependency */,
+ BD9BA7721EAFA3D500658CCF /* PBXTargetDependency */,
);
name = "Build Some";
productName = "Build Some";
@@ -41,6 +44,7 @@
isa = PBXAggregateTarget;
buildConfigurationList = 2141DD08123FFB830086D23E /* Build configuration list for PBXAggregateTarget "SystemLibraries" */;
buildPhases = (
+ B7E2951A1E259AA000C42F6D /* ShellScript */,
);
dependencies = (
2141DD0E123FFC960086D23E /* PBXTargetDependency */,
@@ -62,6 +66,18 @@
name = SystemLibrariesStatic;
productName = SystemLibrariesStatic;
};
+ B7C4B7251E71BD5000136C7A /* Build Some iOS */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = B7C4B7281E71BD5000136C7A /* Build configuration list for PBXAggregateTarget "Build Some iOS" */;
+ buildPhases = (
+ );
+ dependencies = (
+ B7C4B72E1E71BE3500136C7A /* PBXTargetDependency */,
+ B7C4B72C1E71BD6000136C7A /* PBXTargetDependency */,
+ );
+ name = "Build Some iOS";
+ productName = "Build More iOS";
+ };
FFA572650AF190F10055A0F1 /* SystemLibrariesDynamic */ = {
isa = PBXAggregateTarget;
buildConfigurationList = FFA5726E0AF191200055A0F1 /* Build configuration list for PBXAggregateTarget "SystemLibrariesDynamic" */;
@@ -90,6 +106,35 @@
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
+ 0C10EC281DDB956E00D7A0E3 /* LocalOnlyTimeoutTests.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C10EC261DDB956000D7A0E3 /* LocalOnlyTimeoutTests.c */; };
+ 0C1596B51D7740B500E09998 /* mDNSPosix.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C1596B31D7740B500E09998 /* mDNSPosix.c */; };
+ 0C1596B61D7740B500E09998 /* NetMonitor.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C1596B41D7740B500E09998 /* NetMonitor.c */; };
+ 0C1596B81D7740C100E09998 /* mDNSUNP.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C1596B71D7740C100E09998 /* mDNSUNP.c */; };
+ 0C1596B91D7740CD00E09998 /* anonymous.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DD8FBD161E9A250033C8F8 /* anonymous.c */; };
+ 0C1596BA1D7740D200E09998 /* CryptoAlg.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F4A145B2AE100939099 /* CryptoAlg.c */; };
+ 0C1596BB1D7740D700E09998 /* DNSDigest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F461DB5062DBF2900672BF3 /* DNSDigest.c */; };
+ 0C1596BC1D7740DC00E09998 /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; };
+ 0C1596BD1D7740E300E09998 /* uDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F70587CEF6001880B3 /* uDNS.c */; };
+ 0C1596BE1D7740E900E09998 /* mDNSDebug.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */; };
+ 0C1596BF1D7740EF00E09998 /* PlatformCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FFCB6D73075D539900B8AF62 /* PlatformCommon.c */; };
+ 0C1596C01D77410A00E09998 /* GenLinkedList.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE2C057E8F660085CAD0 /* GenLinkedList.c */; };
+ 0C5674B41DA2BF8600AF3367 /* mDNSCoreReceiveTest.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C5674B21DA2BF6300AF3367 /* mDNSCoreReceiveTest.c */; };
+ 0C635A891E9418D90026C796 /* bjIPAddr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C635A7D1E9418D90026C796 /* bjIPAddr.cpp */; };
+ 0C635A8A1E9418D90026C796 /* bjMACAddr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C635A7E1E9418D90026C796 /* bjMACAddr.cpp */; };
+ 0C635A8B1E9418D90026C796 /* bjsocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C635A7F1E9418D90026C796 /* bjsocket.cpp */; };
+ 0C635A8C1E9418D90026C796 /* bjstring.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C635A801E9418D90026C796 /* bjstring.cpp */; };
+ 0C635A8D1E9418D90026C796 /* bjStringtoStringMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C635A811E9418D90026C796 /* bjStringtoStringMap.cpp */; };
+ 0C635A8E1E9418D90026C796 /* BonjourTop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C635A821E9418D90026C796 /* BonjourTop.cpp */; };
+ 0C635A8F1E9418D90026C796 /* CaptureFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C635A831E9418D90026C796 /* CaptureFile.cpp */; };
+ 0C635A901E9418D90026C796 /* CollectBy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C635A841E9418D90026C796 /* CollectBy.cpp */; };
+ 0C635A911E9418D90026C796 /* DNSFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C635A851E9418D90026C796 /* DNSFrame.cpp */; };
+ 0C635A921E9418D90026C796 /* Frame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C635A861E9418D90026C796 /* Frame.cpp */; };
+ 0C635A931E9418D90026C796 /* LLRBTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C635A871E9418D90026C796 /* LLRBTree.cpp */; };
+ 0C635A941E9418D90026C796 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C635A881E9418D90026C796 /* main.cpp */; };
+ 0C6FB90F1D77767300DF6F51 /* mDNSNetMonitor.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 0C6FB90E1D775FE900DF6F51 /* mDNSNetMonitor.8 */; };
+ 0C7C00501DD553640078BA89 /* unittest_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C7C00491DD553490078BA89 /* unittest_common.c */; };
+ 0C7C00511DD5536E0078BA89 /* CNameRecordTests.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C7C004F1DD553490078BA89 /* CNameRecordTests.c */; };
+ 0CB1C7FC1D9C5C1100A5939F /* D2D.c in Sources */ = {isa = PBXBuildFile; fileRef = 22C7633D1D777B8C0077AFCA /* D2D.c */; };
21070E5F16486B9000A69507 /* DNSSECSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21070E5D16486B9000A69507 /* DNSSECSupport.c */; };
21070E6116486B9000A69507 /* DNSSECSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 21070E5E16486B9000A69507 /* DNSSECSupport.h */; };
2124FA2C1471E98C0021D7BB /* nsec.h in Headers */ = {isa = PBXBuildFile; fileRef = 2124FA2B1471E98C0021D7BB /* nsec.h */; };
@@ -117,6 +162,13 @@
21A57F4E145B2AE100939099 /* CryptoAlg.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A57F4B145B2AE100939099 /* CryptoAlg.h */; };
21A57F53145B2B1400939099 /* CryptoSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F51145B2B1400939099 /* CryptoSupport.c */; };
21A57F55145B2B1400939099 /* CryptoSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A57F52145B2B1400939099 /* CryptoSupport.h */; };
+ 21B830A21D8A63A300AE2001 /* libxml2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 219D5541149ED645004464AE /* libxml2.dylib */; };
+ 21B830A31D8A63AE00AE2001 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
+ 21B830A41D8A63BB00AE2001 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
+ 21B830A51D8A63CB00AE2001 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; };
+ 21B830A61D8A63E400AE2001 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
+ 21B830A71D8A641F00AE2001 /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 37538E131D7A43B600226BE4 /* libicucore.dylib */; };
+ 21B830A81D8A642200AE2001 /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 37538E131D7A43B600226BE4 /* libicucore.dylib */; };
21DCD05C1461B23700702FC8 /* CryptoAlg.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F4A145B2AE100939099 /* CryptoAlg.c */; };
21DD8FBF161E9A250033C8F8 /* anonymous.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DD8FBD161E9A250033C8F8 /* anonymous.c */; };
21DD8FC1161E9A250033C8F8 /* anonymous.h in Headers */ = {isa = PBXBuildFile; fileRef = 21DD8FBE161E9A250033C8F8 /* anonymous.h */; };
@@ -124,6 +176,7 @@
21F51DC11B3541940070B05C /* com.apple.mDNSResponder.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 21F51DBF1B35412D0070B05C /* com.apple.mDNSResponder.plist */; };
21F51DC31B3541F50070B05C /* com.apple.mDNSResponderHelper.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 21F51DBE1B3541030070B05C /* com.apple.mDNSResponderHelper.plist */; };
21F51DC51B3542210070B05C /* com.apple.dnsextd.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 21F51DBD1B3540DB0070B05C /* com.apple.dnsextd.plist */; };
+ 220ABBF21D78F10F008423A7 /* D2D.h in Headers */ = {isa = PBXBuildFile; fileRef = 220ABBF11D78F102008423A7 /* D2D.h */; };
222A3C5B1C1B75F2003A6FFD /* DNSServiceDiscoveryDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 222A3C581C1B743B003A6FFD /* DNSServiceDiscoveryDefines.h */; };
222A3C6A1C1B7777003A6FFD /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = 222A3C561C1B7415003A6FFD /* DNSServiceDiscovery.c */; };
222A3C6B1C1B7778003A6FFD /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = 222A3C561C1B7415003A6FFD /* DNSServiceDiscovery.c */; };
@@ -131,11 +184,11 @@
222A3C6D1C1B777A003A6FFD /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = 222A3C561C1B7415003A6FFD /* DNSServiceDiscovery.c */; };
222A3C6E1C1B777B003A6FFD /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = 222A3C561C1B7415003A6FFD /* DNSServiceDiscovery.c */; };
222A3C6F1C1B777C003A6FFD /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = 222A3C561C1B7415003A6FFD /* DNSServiceDiscovery.c */; };
- 2243AE391C90AECF0079023E /* CoreBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2243AE381C90AECF0079023E /* CoreBluetooth.framework */; };
22448EA31C90A7BE004F25CC /* BLE.c in Sources */ = {isa = PBXBuildFile; fileRef = 22448EA11C90A7B5004F25CC /* BLE.c */; };
22448EA41C90A7CB004F25CC /* BLE.h in Headers */ = {isa = PBXBuildFile; fileRef = 22448EA21C90A7B5004F25CC /* BLE.h */; };
22448EA71C90A837004F25CC /* coreBLE.h in Headers */ = {isa = PBXBuildFile; fileRef = 22448EA51C90A82D004F25CC /* coreBLE.h */; };
227687F31C90AD580019382D /* coreBLE.m in Sources */ = {isa = PBXBuildFile; fileRef = 22448EA61C90A82D004F25CC /* coreBLE.m */; };
+ 22C7633E1D777B940077AFCA /* D2D.c in Sources */ = {isa = PBXBuildFile; fileRef = 22C7633D1D777B8C0077AFCA /* D2D.c */; };
2E0405F50C3195F700F13B59 /* helper.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405F40C3195F700F13B59 /* helper.c */; };
2E0406150C3197CB00F13B59 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E0406140C3197CB00F13B59 /* libbsm.dylib */; };
2E04070A0C31EEEC00F13B59 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
@@ -158,7 +211,59 @@
371D0FBC1BF545FA00E5DB26 /* InterfaceTest.c in Sources */ = {isa = PBXBuildFile; fileRef = 371D0FBA1BF545FA00E5DB26 /* InterfaceTest.c */; };
371D0FBF1BF666EB00E5DB26 /* ResourceRecordTest.c in Sources */ = {isa = PBXBuildFile; fileRef = 371D0FBD1BF666EB00E5DB26 /* ResourceRecordTest.c */; };
373202101BAB4444007DE806 /* DNSMessageTest.c in Sources */ = {isa = PBXBuildFile; fileRef = 3732020F1BAB4349007DE806 /* DNSMessageTest.c */; };
+ 37538DFC1D7A424500226BE4 /* dnssd_ipc.h in Headers */ = {isa = PBXBuildFile; fileRef = F5E11B5B04A28126019798ED /* dnssd_ipc.h */; };
+ 37538DFD1D7A425700226BE4 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; };
+ 37538DFE1D7A427B00226BE4 /* helper-server.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EDC5E720C39EA640092701B /* helper-server.h */; };
+ 37538DFF1D7A428500226BE4 /* helpermsg-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */; };
+ 37538E001D7A429900226BE4 /* CryptoAlg.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A57F4B145B2AE100939099 /* CryptoAlg.h */; };
+ 37538E011D7A429900226BE4 /* CryptoSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A57F52145B2B1400939099 /* CryptoSupport.h */; };
+ 37538E021D7A42B000226BE4 /* nsec.h in Headers */ = {isa = PBXBuildFile; fileRef = 2124FA2B1471E98C0021D7BB /* nsec.h */; };
+ 37538E031D7A42B000226BE4 /* nsec3.h in Headers */ = {isa = PBXBuildFile; fileRef = 2127A47615C3C7B900A857FC /* nsec3.h */; };
+ 37538E041D7A42BE00226BE4 /* BLE.h in Headers */ = {isa = PBXBuildFile; fileRef = 22448EA21C90A7B5004F25CC /* BLE.h */; };
+ 37538E051D7A42D000226BE4 /* DNSServiceDiscoveryDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 222A3C581C1B743B003A6FFD /* DNSServiceDiscoveryDefines.h */; };
+ 37538E061D7A42DA00226BE4 /* dnsproxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 218E8E50156D8C0300720DA0 /* dnsproxy.h */; };
+ 37538E071D7A42E200226BE4 /* coreBLE.h in Headers */ = {isa = PBXBuildFile; fileRef = 22448EA51C90A82D004F25CC /* coreBLE.h */; };
+ 37538E081D7A42F000226BE4 /* dns_xpc.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5D516547F7200D2E8B4 /* dns_xpc.h */; };
+ 37538E091D7A42FC00226BE4 /* xpc_services.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5C9165477EB00D2E8B4 /* xpc_services.h */; };
+ 37538E0A1D7A430600226BE4 /* anonymous.h in Headers */ = {isa = PBXBuildFile; fileRef = 21DD8FBE161E9A250033C8F8 /* anonymous.h */; };
+ 37538E0B1D7A432200226BE4 /* Metrics.h in Headers */ = {isa = PBXBuildFile; fileRef = BDA3F0871C48DB6D0054FB4B /* Metrics.h */; };
+ 37538E0C1D7A435200226BE4 /* dnssec.h in Headers */ = {isa = PBXBuildFile; fileRef = 2124FA2F1471E9B50021D7BB /* dnssec.h */; };
+ 37538E0D1D7A437300226BE4 /* DNSSECSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 21070E5E16486B9000A69507 /* DNSSECSupport.h */; };
+ 37538E141D7A43B600226BE4 /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 37538E131D7A43B600226BE4 /* libicucore.dylib */; };
+ 37538E1B1D7A442300226BE4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDA3F0891C48DB910054FB4B /* Foundation.framework */; };
+ 37538E1C1D7A449000226BE4 /* Metrics.m in Sources */ = {isa = PBXBuildFile; fileRef = BDA3F0881C48DB6D0054FB4B /* Metrics.m */; };
+ 37538E1D1D7A449D00226BE4 /* coreBLE.m in Sources */ = {isa = PBXBuildFile; fileRef = 22448EA61C90A82D004F25CC /* coreBLE.m */; };
+ 37538E1E1D7A4F9D00226BE4 /* anonymous.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DD8FBD161E9A250033C8F8 /* anonymous.c */; };
+ 37538E1F1D7A504F00226BE4 /* helper-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */; };
3771F67D1BA387DD0072355E /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 37DDE9351BA386E70092AC61 /* main.c */; };
+ 37812CD41D7A307200F34505 /* BLE.c in Sources */ = {isa = PBXBuildFile; fileRef = 22448EA11C90A7B5004F25CC /* BLE.c */; };
+ 37812CD71D7A307200F34505 /* CryptoAlg.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F4A145B2AE100939099 /* CryptoAlg.c */; };
+ 37812CD81D7A307200F34505 /* CryptoSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F51145B2B1400939099 /* CryptoSupport.c */; };
+ 37812CD91D7A307200F34505 /* daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEC022EAF7200000109 /* daemon.c */; };
+ 37812CDA1D7A307200F34505 /* dns_services.c in Sources */ = {isa = PBXBuildFile; fileRef = 84C5B339166553AF00C324A8 /* dns_services.c */; };
+ 37812CDB1D7A307200F34505 /* DNSDigest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F461DB5062DBF2900672BF3 /* DNSDigest.c */; };
+ 37812CDE1D7A307200F34505 /* dnsproxy.c in Sources */ = {isa = PBXBuildFile; fileRef = 218E8E4F156D8C0300720DA0 /* dnsproxy.c */; };
+ 37812CDF1D7A307200F34505 /* DNSProxySupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DED43415702C0F0060B6B9 /* DNSProxySupport.c */; };
+ 37812CE01D7A307200F34505 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; };
+ 37812CE11D7A307300F34505 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; };
+ 37812CE21D7A307300F34505 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
+ 37812CE31D7A307300F34505 /* dnssec.c in Sources */ = {isa = PBXBuildFile; fileRef = 213BDC6C147319F400000896 /* dnssec.c */; };
+ 37812CE41D7A307300F34505 /* DNSSECSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21070E5D16486B9000A69507 /* DNSSECSupport.c */; };
+ 37812CE51D7A307300F34505 /* GenLinkedList.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE2C057E8F660085CAD0 /* GenLinkedList.c */; };
+ 37812CE91D7A307300F34505 /* LegacyNATTraversal.c in Sources */ = {isa = PBXBuildFile; fileRef = 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */; };
+ 37812CEA1D7A307300F34505 /* mDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBE9022EAF5A00000109 /* mDNS.c */; };
+ 37812CEB1D7A307300F34505 /* mDNSDebug.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */; };
+ 37812CEC1D7A307300F34505 /* mDNSMacOSX.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */; };
+ 37812CED1D7A307300F34505 /* nsec.c in Sources */ = {isa = PBXBuildFile; fileRef = 2124FA321471E9DE0021D7BB /* nsec.c */; };
+ 37812CEE1D7A307300F34505 /* nsec3.c in Sources */ = {isa = PBXBuildFile; fileRef = 2127A47515C3C7B900A857FC /* nsec3.c */; };
+ 37812CEF1D7A307300F34505 /* P2PPacketFilter.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BD2B638134FE09F002B96D5 /* P2PPacketFilter.c */; };
+ 37812CF11D7A307300F34505 /* PlatformCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FFCB6D73075D539900B8AF62 /* PlatformCommon.c */; };
+ 37812CF21D7A307300F34505 /* SymptomReporter.c in Sources */ = {isa = PBXBuildFile; fileRef = BD03E88C1AD31278005E8A81 /* SymptomReporter.c */; };
+ 37812CF31D7A307300F34505 /* uDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F70587CEF6001880B3 /* uDNS.c */; };
+ 37812CF41D7A307300F34505 /* uDNSPathEvalulation.c in Sources */ = {isa = PBXBuildFile; fileRef = 216D9ACD1720C9F5008066E1 /* uDNSPathEvalulation.c */; };
+ 37812CF51D7A307300F34505 /* uds_daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = F525E72804AA167501F1CF4D /* uds_daemon.c */; };
+ 37812CF61D7A307300F34505 /* dnsctl_server.c in Sources */ = {isa = PBXBuildFile; fileRef = 8417375A1B967CBE000CD5C2 /* dnsctl_server.c */; };
+ 37812CF71D7A307300F34505 /* xpc_services.c in Sources */ = {isa = PBXBuildFile; fileRef = 848DA5C6165477E000D2E8B4 /* xpc_services.c */; };
37DDE9331BA383D30092AC61 /* unittest.c in Sources */ = {isa = PBXBuildFile; fileRef = 37DDE9271BA3825C0092AC61 /* unittest.c */; };
37FEBD581BC789AA00638EA4 /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; };
4A7B9E8014FDA25000B84CC1 /* mDNSResponder.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4A7B9E7E14FDA1BB00B84CC1 /* mDNSResponder.plist */; };
@@ -175,13 +280,60 @@
848DA5D616547F7200D2E8B4 /* dns_xpc.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5D516547F7200D2E8B4 /* dns_xpc.h */; };
84C5B33C166553F100C324A8 /* dns_services.c in Sources */ = {isa = PBXBuildFile; fileRef = 84C5B339166553AF00C324A8 /* dns_services.c */; };
84F4C090188F050200D1E1DE /* dns_services.h in Headers */ = {isa = PBXBuildFile; fileRef = 84F4C08F188F04CF00D1E1DE /* dns_services.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ B7016F521D5D0D2900107E7C /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B7016F511D5D0D2900107E7C /* Localizable.strings */; };
+ B701E7041D9DD811008F3022 /* BonjourSCStore.m in Sources */ = {isa = PBXBuildFile; fileRef = B701E7031D9DD811008F3022 /* BonjourSCStore.m */; };
+ B7024D171E82FA9500312DEF /* com.apple.preference.bonjour.tool.xpc in CopyFiles */ = {isa = PBXBuildFile; fileRef = B76783AC1E82D65900DA271E /* com.apple.preference.bonjour.tool.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
+ B71C8B091E79F2CD00E99939 /* BonjourSCStore.m in Sources */ = {isa = PBXBuildFile; fileRef = B701E7031D9DD811008F3022 /* BonjourSCStore.m */; };
+ B7325FE81DA4737400663834 /* CNBrowseDomainsController.m in Sources */ = {isa = PBXBuildFile; fileRef = B7325FE71DA4737400663834 /* CNBrowseDomainsController.m */; };
+ B7325FF71DA47F9100663834 /* CNDomainBrowserViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = B7A214081D1B29D6005F7DD9 /* CNDomainBrowserViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ B7325FF81DA47FB000663834 /* CNDomainBrowserViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B7A214091D1B29D6005F7DD9 /* CNDomainBrowserViewController.m */; };
+ B7325FF91DA47FB000663834 /* _CNDomainBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = B7D6CA5E1D107573005E24CF /* _CNDomainBrowser.m */; };
+ B7325FFD1DA4809400663834 /* DomainBrowser.h in Headers */ = {isa = PBXBuildFile; fileRef = B74EC1271D494C5800A1D155 /* DomainBrowser.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ B7325FFF1DA480A500663834 /* DomainBrowser.strings in Resources */ = {isa = PBXBuildFile; fileRef = B7016F4F1D5D0D1900107E7C /* DomainBrowser.strings */; };
+ B74A96261DD4EDE60084A8C5 /* Preferences.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B74A96251DD4EDE60084A8C5 /* Preferences.framework */; };
+ B74F2B461E82FEAE0084960E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDA3F0891C48DB910054FB4B /* Foundation.framework */; };
+ B74F2B471E82FEFE0084960E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
+ B75700241E8347A6005CD56C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = B75700231E8347A6005CD56C /* InfoPlist.strings */; };
+ B764319F1DB0423800DB376D /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; };
+ B76431A01DB0423900DB376D /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; };
+ B76783C11E82D8F500DA271E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B76783BC1E82D8F500DA271E /* main.m */; };
+ B76783C21E82D8F500DA271E /* BonjourPrefTool.m in Sources */ = {isa = PBXBuildFile; fileRef = B76783BE1E82D8F500DA271E /* BonjourPrefTool.m */; };
+ B7706AA91DB83E9A00593FD5 /* CNDomainBrowserView.m in Sources */ = {isa = PBXBuildFile; fileRef = B7D6CA691D1076C6005E24CF /* CNDomainBrowserView.m */; };
+ B7706AAA1DB83EA700593FD5 /* _CNDomainBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = B7D6CA5E1D107573005E24CF /* _CNDomainBrowser.m */; };
+ B7706AAB1DB83EAC00593FD5 /* CNDomainBrowserPathUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = B799209E1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m */; };
+ B7706AAD1DBA9C0F00593FD5 /* CNDomainBrowserViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B7A214091D1B29D6005F7DD9 /* CNDomainBrowserViewController.m */; };
+ B7706AAE1DBA9C1800593FD5 /* _CNDomainBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = B7D6CA5E1D107573005E24CF /* _CNDomainBrowser.m */; };
+ B7706AAF1DBA9C1800593FD5 /* CNDomainBrowserPathUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = B799209E1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m */; };
+ B778EE4D1D51113800C814A2 /* HostnameController.m in Sources */ = {isa = PBXBuildFile; fileRef = B778EE4B1D51113800C814A2 /* HostnameController.m */; };
+ B778EE501D51287100C814A2 /* BonjourSettingsController.m in Sources */ = {isa = PBXBuildFile; fileRef = B778EE4F1D51287100C814A2 /* BonjourSettingsController.m */; };
+ B79568351D53F693005E3BED /* DomainBrowser.h in Headers */ = {isa = PBXBuildFile; fileRef = B74EC12B1D494C7200A1D155 /* DomainBrowser.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ B79568361D53F69B005E3BED /* CNDomainBrowserView.h in Headers */ = {isa = PBXBuildFile; fileRef = B7D6CA681D1076C6005E24CF /* CNDomainBrowserView.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ B799209F1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = B799209D1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ B79920A01DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = B799209D1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ B79920A11DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = B799209E1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m */; };
+ B79920A21DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = B799209E1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m */; };
+ B79920A41DA6C49700C6E02B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B79920A31DA6C49700C6E02B /* Assets.xcassets */; };
+ B7D566C91E81DA0000E43008 /* com.apple.preference.bonjour.remoteservice.xpc in CopyFiles */ = {isa = PBXBuildFile; fileRef = B7D566BA1E81D8FD00E43008 /* com.apple.preference.bonjour.remoteservice.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
+ B7D566CD1E81DDB600E43008 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDA3F0891C48DB910054FB4B /* Foundation.framework */; };
+ B7D566CE1E81DDB600E43008 /* PreferencePanes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */; };
+ B7D566D01E81DEC200E43008 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B7D566AC1E81D6A900E43008 /* main.m */; };
+ B7D566D11E81DEC400E43008 /* BonjourPrefRemoteViewService.m in Sources */ = {isa = PBXBuildFile; fileRef = B7D566A81E81D6A900E43008 /* BonjourPrefRemoteViewService.m */; };
+ B7D566D51E81E14E00E43008 /* ViewBridge.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B7D566D41E81E14E00E43008 /* ViewBridge.framework */; };
+ B7D6CA791D10770F005E24CF /* _CNDomainBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = B7D6CA5E1D107573005E24CF /* _CNDomainBrowser.m */; };
+ B7D6CA7A1D107714005E24CF /* CNDomainBrowserView.m in Sources */ = {isa = PBXBuildFile; fileRef = B7D6CA691D1076C6005E24CF /* CNDomainBrowserView.m */; };
+ B7E06B0D1DBA9DFE00E4580C /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; };
+ B7E06B0E1DBA9E9700E4580C /* DomainBrowser.strings in Resources */ = {isa = PBXBuildFile; fileRef = B7016F4F1D5D0D1900107E7C /* DomainBrowser.strings */; };
BD03E88D1AD31278005E8A81 /* SymptomReporter.c in Sources */ = {isa = PBXBuildFile; fileRef = BD03E88C1AD31278005E8A81 /* SymptomReporter.c */; };
+ BD691B2A1ED2F47100E6F317 /* DNS64.c in Sources */ = {isa = PBXBuildFile; fileRef = BD691B281ED2F43200E6F317 /* DNS64.c */; };
+ BD691B2B1ED2F4AB00E6F317 /* DNS64.h in Headers */ = {isa = PBXBuildFile; fileRef = BD691B291ED2F43200E6F317 /* DNS64.h */; };
+ BD9BA7551EAF91FB00658CCF /* dnssdutil.c in Sources */ = {isa = PBXBuildFile; fileRef = BD9BA7541EAF91E700658CCF /* dnssdutil.c */; };
+ BD9BA7581EAF929C00658CCF /* CoreUtils.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BD9BA7571EAF929C00658CCF /* CoreUtils.framework */; };
BDA3F08A1C48DB920054FB4B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDA3F0891C48DB910054FB4B /* Foundation.framework */; };
- BDA3F08D1C48DBEA0054FB4B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDA3F0891C48DB910054FB4B /* Foundation.framework */; };
BDA3F08E1C48DCA50054FB4B /* Metrics.h in Headers */ = {isa = PBXBuildFile; fileRef = BDA3F0871C48DB6D0054FB4B /* Metrics.h */; };
BDA3F08F1C48DCA50054FB4B /* Metrics.m in Sources */ = {isa = PBXBuildFile; fileRef = BDA3F0881C48DB6D0054FB4B /* Metrics.m */; };
BDA9A7881B3A924C00523835 /* dns_sd_private.h in Headers */ = {isa = PBXBuildFile; fileRef = BDA9A7871B3A923600523835 /* dns_sd_private.h */; settings = {ATTRIBUTES = (Private, ); }; };
BDA9A7891B3A92A500523835 /* dns_sd_private.h in Headers */ = {isa = PBXBuildFile; fileRef = BDA9A7871B3A923600523835 /* dns_sd_private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ BDBF9B941ED74B9C001498A8 /* DNS64State.h in Headers */ = {isa = PBXBuildFile; fileRef = BDBF9B931ED74B8C001498A8 /* DNS64State.h */; };
D284BE540ADD80740027CCDF /* dnssd_ipc.h in Headers */ = {isa = PBXBuildFile; fileRef = F5E11B5B04A28126019798ED /* dnssd_ipc.h */; };
D284BE580ADD80740027CCDF /* mDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBE9022EAF5A00000109 /* mDNS.c */; };
D284BE590ADD80740027CCDF /* uDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F70587CEF6001880B3 /* uDNS.c */; };
@@ -217,39 +369,25 @@
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 */; };
- 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 */; };
- FF3C72AA1CE3E62200CDF81E /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FF3C72A91CE3E62200CDF81E /* libicucore.dylib */; };
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 */; };
- FFAE66F0105F0CD900162116 /* ddnswriteconfig in Resources */ = {isa = PBXBuildFile; fileRef = D284BEE80ADD80A70027CCDF /* ddnswriteconfig */; };
FFB437150EB165BD00E17C68 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; };
FFD52A9E1AF858DD00CAD3EC /* CryptoAlg.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A57F4B145B2AE100939099 /* CryptoAlg.h */; };
FFF589B70E37F66800EF515C /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; };
@@ -313,6 +451,13 @@
remoteGlobalIDString = 03067D640C83A3700022BE1F;
remoteInfo = "Build Some";
};
+ 0C1596C61D7751AD00E09998 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 0C1596AB1D773FE300E09998;
+ remoteInfo = mDNSNetMonitor;
+ };
0C2AAB311B6929F300113637 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
@@ -320,6 +465,20 @@
remoteGlobalIDString = 84C5B3341665529800C324A8;
remoteInfo = dns_services;
};
+ 0C4F36B31E206711005A536B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 37DDE92C1BA383610092AC61;
+ remoteInfo = unittests;
+ };
+ 0C52E92E1E96AD74006EFE7B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 0C635A751E9418A60026C796;
+ remoteInfo = BonjourTop;
+ };
2130257012400E9300AC839F /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
@@ -383,6 +542,34 @@
remoteGlobalIDString = 84C5B3341665529800C324A8;
remoteInfo = dns_services;
};
+ B76783B81E82D83800DA271E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = B76783AB1E82D65900DA271E;
+ remoteInfo = ddnsWriteTool;
+ };
+ B7C4B72B1E71BD6000136C7A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = B74EC1151D47FC7700A1D155;
+ remoteInfo = BonjourSettings;
+ };
+ B7C4B72D1E71BE3500136C7A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 03067D640C83A3700022BE1F;
+ remoteInfo = "Build Some";
+ };
+ B7D566C71E81D9E700E43008 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = B7D566B91E81D8FD00E43008;
+ remoteInfo = RemoteViewService;
+ };
BD7833EF1ABA5E3500EC51ED /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
@@ -390,19 +577,19 @@
remoteGlobalIDString = 72FB545E166D5FB00090B2D9;
remoteInfo = dnsctl;
};
- D284BF2B0ADD815A0027CCDF /* PBXContainerItemProxy */ = {
+ BD9BA7711EAFA3D500658CCF /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = D284BEBF0ADD80A20027CCDF;
- remoteInfo = dnsextd;
+ remoteGlobalIDString = BD9BA7481EAF90E400658CCF;
+ remoteInfo = dnssdutil;
};
- D284BF2D0ADD81600027CCDF /* PBXContainerItemProxy */ = {
+ D284BF2B0ADD815A0027CCDF /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = D284BEDB0ADD80A70027CCDF;
- remoteInfo = ddnswriteconfig;
+ remoteGlobalIDString = D284BEBF0ADD80A20027CCDF;
+ remoteInfo = dnsextd;
};
D284BF2F0ADD81630027CCDF /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
@@ -432,13 +619,6 @@
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 */;
@@ -449,6 +629,25 @@
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
+ 0C1596AA1D773FE300E09998 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 0C6FB90F1D77767300DF6F51 /* mDNSNetMonitor.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 0C635A741E9418A60026C796 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
21F51DC01B35418C0070B05C /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
@@ -528,6 +727,17 @@
);
runOnlyForDeploymentPostprocessing = 1;
};
+ B7D566C61E81D9B600E43008 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "$(CONTENTS_FOLDER_PATH)/XPCServices";
+ dstSubfolderSpec = 16;
+ files = (
+ B7D566C91E81DA0000E43008 /* com.apple.preference.bonjour.remoteservice.xpc in CopyFiles */,
+ B7024D171E82FA9500312DEF /* com.apple.preference.bonjour.tool.xpc in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
D284BE6A0ADD80740027CCDF /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
@@ -574,6 +784,36 @@
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>"; };
+ 0C10EC261DDB956000D7A0E3 /* LocalOnlyTimeoutTests.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = LocalOnlyTimeoutTests.c; path = ../unittests/LocalOnlyTimeoutTests.c; sourceTree = "<group>"; };
+ 0C10EC271DDB956000D7A0E3 /* LocalOnlyTimeoutTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LocalOnlyTimeoutTests.h; path = ../unittests/LocalOnlyTimeoutTests.h; sourceTree = "<group>"; };
+ 0C1596AC1D773FE300E09998 /* mDNSNetMonitor */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSNetMonitor; sourceTree = BUILT_PRODUCTS_DIR; };
+ 0C1596B31D7740B500E09998 /* mDNSPosix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mDNSPosix.c; path = ../../mDNSPosix/mDNSPosix.c; sourceTree = "<group>"; };
+ 0C1596B41D7740B500E09998 /* NetMonitor.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = NetMonitor.c; path = ../../mDNSPosix/NetMonitor.c; sourceTree = "<group>"; };
+ 0C1596B71D7740C100E09998 /* mDNSUNP.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mDNSUNP.c; path = ../../mDNSPosix/mDNSUNP.c; sourceTree = "<group>"; };
+ 0C5674B11DA2BF6300AF3367 /* mDNSCoreReceiveTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mDNSCoreReceiveTest.h; path = ../unittests/mDNSCoreReceiveTest.h; sourceTree = "<group>"; };
+ 0C5674B21DA2BF6300AF3367 /* mDNSCoreReceiveTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mDNSCoreReceiveTest.c; path = ../unittests/mDNSCoreReceiveTest.c; sourceTree = "<group>"; };
+ 0C635A761E9418A60026C796 /* bonjourtop */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = bonjourtop; sourceTree = BUILT_PRODUCTS_DIR; };
+ 0C635A7D1E9418D90026C796 /* bjIPAddr.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = bjIPAddr.cpp; path = source/bjIPAddr.cpp; sourceTree = "<group>"; };
+ 0C635A7E1E9418D90026C796 /* bjMACAddr.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = bjMACAddr.cpp; path = source/bjMACAddr.cpp; sourceTree = "<group>"; };
+ 0C635A7F1E9418D90026C796 /* bjsocket.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = bjsocket.cpp; path = source/bjsocket.cpp; sourceTree = "<group>"; };
+ 0C635A801E9418D90026C796 /* bjstring.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = bjstring.cpp; path = source/bjstring.cpp; sourceTree = "<group>"; };
+ 0C635A811E9418D90026C796 /* bjStringtoStringMap.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = bjStringtoStringMap.cpp; path = source/bjStringtoStringMap.cpp; sourceTree = "<group>"; };
+ 0C635A821E9418D90026C796 /* BonjourTop.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = BonjourTop.cpp; path = source/BonjourTop.cpp; sourceTree = "<group>"; };
+ 0C635A831E9418D90026C796 /* CaptureFile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CaptureFile.cpp; path = source/CaptureFile.cpp; sourceTree = "<group>"; };
+ 0C635A841E9418D90026C796 /* CollectBy.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CollectBy.cpp; path = source/CollectBy.cpp; sourceTree = "<group>"; };
+ 0C635A851E9418D90026C796 /* DNSFrame.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DNSFrame.cpp; path = source/DNSFrame.cpp; sourceTree = "<group>"; };
+ 0C635A861E9418D90026C796 /* Frame.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Frame.cpp; path = source/Frame.cpp; sourceTree = "<group>"; };
+ 0C635A871E9418D90026C796 /* LLRBTree.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = LLRBTree.cpp; path = source/LLRBTree.cpp; sourceTree = "<group>"; };
+ 0C635A881E9418D90026C796 /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = main.cpp; path = source/main.cpp; sourceTree = "<group>"; };
+ 0C6FB90E1D775FE900DF6F51 /* mDNSNetMonitor.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mDNSNetMonitor.8; sourceTree = "<group>"; };
+ 0C7C00491DD553490078BA89 /* unittest_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unittest_common.c; path = ../unittests/unittest_common.c; sourceTree = "<group>"; };
+ 0C7C004A1DD553490078BA89 /* unittest_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = unittest_common.h; path = ../unittests/unittest_common.h; sourceTree = "<group>"; };
+ 0C7C004B1DD553490078BA89 /* mdns_macosx_ut.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mdns_macosx_ut.c; path = ../unittests/mdns_macosx_ut.c; sourceTree = "<group>"; };
+ 0C7C004C1DD553490078BA89 /* mdns_ut.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mdns_ut.c; path = ../unittests/mdns_ut.c; sourceTree = "<group>"; };
+ 0C7C004D1DD553490078BA89 /* uds_daemon_ut.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = uds_daemon_ut.c; path = ../unittests/uds_daemon_ut.c; sourceTree = "<group>"; };
+ 0C7C004E1DD553490078BA89 /* CNameRecordTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CNameRecordTests.h; path = ../unittests/CNameRecordTests.h; sourceTree = "<group>"; };
+ 0C7C004F1DD553490078BA89 /* CNameRecordTests.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = CNameRecordTests.c; path = ../unittests/CNameRecordTests.c; sourceTree = "<group>"; };
+ 0C84A2911E786AFF00E8B4C7 /* daemon_ut.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = daemon_ut.c; path = ../unittests/daemon_ut.c; sourceTree = "<group>"; };
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>"; };
2124FA2B1471E98C0021D7BB /* nsec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nsec.h; path = ../mDNSCore/nsec.h; sourceTree = "<group>"; };
@@ -603,14 +843,15 @@
21F51DBD1B3540DB0070B05C /* com.apple.dnsextd.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.dnsextd.plist; sourceTree = "<group>"; };
21F51DBE1B3541030070B05C /* com.apple.mDNSResponderHelper.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.mDNSResponderHelper.plist; sourceTree = "<group>"; };
21F51DBF1B35412D0070B05C /* com.apple.mDNSResponder.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.mDNSResponder.plist; sourceTree = "<group>"; };
+ 220ABBF11D78F102008423A7 /* D2D.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = D2D.h; sourceTree = "<group>"; };
222A3C561C1B7415003A6FFD /* DNSServiceDiscovery.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = DNSServiceDiscovery.c; sourceTree = "<group>"; };
222A3C571C1B743B003A6FFD /* DNSServiceDiscovery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNSServiceDiscovery.h; sourceTree = "<group>"; };
222A3C581C1B743B003A6FFD /* DNSServiceDiscoveryDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNSServiceDiscoveryDefines.h; sourceTree = "<group>"; };
- 2243AE381C90AECF0079023E /* CoreBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreBluetooth.framework; path = System/Library/Frameworks/CoreBluetooth.framework; sourceTree = SDKROOT; };
22448EA11C90A7B5004F25CC /* BLE.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = BLE.c; sourceTree = "<group>"; };
22448EA21C90A7B5004F25CC /* BLE.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BLE.h; sourceTree = "<group>"; };
22448EA51C90A82D004F25CC /* coreBLE.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = coreBLE.h; sourceTree = "<group>"; };
22448EA61C90A82D004F25CC /* coreBLE.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = coreBLE.m; sourceTree = "<group>"; };
+ 22C7633D1D777B8C0077AFCA /* D2D.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = D2D.c; 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>"; };
@@ -626,6 +867,7 @@
371D0FBE1BF666EB00E5DB26 /* ResourceRecordTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResourceRecordTest.h; path = ../unittests/ResourceRecordTest.h; sourceTree = "<group>"; };
3732020F1BAB4349007DE806 /* DNSMessageTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = DNSMessageTest.c; path = ../unittests/DNSMessageTest.c; sourceTree = "<group>"; };
373202111BAB63E8007DE806 /* DNSMessageTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DNSMessageTest.h; path = ../unittests/DNSMessageTest.h; sourceTree = "<group>"; };
+ 37538E131D7A43B600226BE4 /* libicucore.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libicucore.dylib; path = usr/lib/libicucore.dylib; sourceTree = SDKROOT; };
37AF802A1BF699AF00D657F6 /* DomainNameTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = DomainNameTest.c; path = ../unittests/DomainNameTest.c; sourceTree = "<group>"; };
37AF802B1BF699AF00D657F6 /* DomainNameTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DomainNameTest.h; path = ../unittests/DomainNameTest.h; sourceTree = "<group>"; };
37DDE9271BA3825C0092AC61 /* unittest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unittest.c; path = ../unittests/unittest.c; sourceTree = "<group>"; };
@@ -665,16 +907,66 @@
84C5B3351665529800C324A8 /* libdns_services.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libdns_services.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
84C5B339166553AF00C324A8 /* dns_services.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dns_services.c; path = Private/dns_services.c; sourceTree = "<group>"; };
84F4C08F188F04CF00D1E1DE /* dns_services.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dns_services.h; path = Private/dns_services.h; sourceTree = "<group>"; };
+ B7016F4F1D5D0D1900107E7C /* DomainBrowser.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = DomainBrowser.strings; sourceTree = "<group>"; };
+ B7016F511D5D0D2900107E7C /* Localizable.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = Localizable.strings; path = ../SettingsBundle/Localizable.strings; sourceTree = "<group>"; };
+ B701E7031D9DD811008F3022 /* BonjourSCStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BonjourSCStore.m; path = ../SettingsBundle/BonjourSCStore.m; sourceTree = "<group>"; };
+ B716801A1E8330B400459A35 /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = entitlements.plist; sourceTree = "<group>"; };
+ B72C96091D6236A500AD682A /* BonjourSCStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = BonjourSCStore.h; path = ../SettingsBundle/BonjourSCStore.h; sourceTree = "<group>"; };
+ B7325FE61DA4737400663834 /* CNBrowseDomainsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CNBrowseDomainsController.h; path = ../SettingsBundle/CNBrowseDomainsController.h; sourceTree = "<group>"; };
+ B7325FE71DA4737400663834 /* CNBrowseDomainsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CNBrowseDomainsController.m; path = ../SettingsBundle/CNBrowseDomainsController.m; sourceTree = "<group>"; };
+ B7325FEE1DA47EBA00663834 /* DomainBrowser.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DomainBrowser.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ B74A96251DD4EDE60084A8C5 /* Preferences.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Preferences.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.Internal.sdk/System/Library/PrivateFrameworks/Preferences.framework; sourceTree = DEVELOPER_DIR; };
+ B74EC1161D47FC7700A1D155 /* BonjourSettings.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BonjourSettings.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
+ B74EC11B1D47FC7800A1D155 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = ../SettingsBundle/Info.plist; sourceTree = "<group>"; };
+ B74EC1271D494C5800A1D155 /* DomainBrowser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DomainBrowser.h; sourceTree = "<group>"; };
+ B74EC1281D494C5800A1D155 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ B74EC1291D494C6700A1D155 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ B74EC12B1D494C7200A1D155 /* DomainBrowser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DomainBrowser.h; sourceTree = "<group>"; };
+ B75700231E8347A6005CD56C /* InfoPlist.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = InfoPlist.strings; sourceTree = "<group>"; };
+ B76783AC1E82D65900DA271E /* com.apple.preference.bonjour.tool.xpc */ = {isa = PBXFileReference; explicitFileType = "wrapper.xpc-service"; includeInIndex = 0; path = com.apple.preference.bonjour.tool.xpc; sourceTree = BUILT_PRODUCTS_DIR; };
+ B76783BB1E82D8F500DA271E /* BonjourPrefTool-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "BonjourPrefTool-Info.plist"; sourceTree = "<group>"; };
+ B76783BC1E82D8F500DA271E /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ B76783BD1E82D8F500DA271E /* BonjourPrefTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BonjourPrefTool.h; sourceTree = "<group>"; };
+ B76783BE1E82D8F500DA271E /* BonjourPrefTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BonjourPrefTool.m; sourceTree = "<group>"; };
+ B76783BF1E82D8F500DA271E /* BonjourPrefToolProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BonjourPrefToolProtocol.h; sourceTree = "<group>"; };
+ B778EE4A1D51113800C814A2 /* HostnameController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HostnameController.h; path = ../SettingsBundle/HostnameController.h; sourceTree = "<group>"; };
+ B778EE4B1D51113800C814A2 /* HostnameController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HostnameController.m; path = ../SettingsBundle/HostnameController.m; sourceTree = "<group>"; };
+ B778EE4E1D51287100C814A2 /* BonjourSettingsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BonjourSettingsController.h; path = ../SettingsBundle/BonjourSettingsController.h; sourceTree = "<group>"; };
+ B778EE4F1D51287100C814A2 /* BonjourSettingsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BonjourSettingsController.m; path = ../SettingsBundle/BonjourSettingsController.m; sourceTree = "<group>"; };
+ B799209D1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CNDomainBrowserPathUtils.h; sourceTree = "<group>"; };
+ B799209E1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CNDomainBrowserPathUtils.m; sourceTree = "<group>"; };
+ B79920A31DA6C49700C6E02B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = ../SettingsBundle/Assets.xcassets; sourceTree = "<group>"; };
+ B7A214081D1B29D6005F7DD9 /* CNDomainBrowserViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CNDomainBrowserViewController.h; sourceTree = "<group>"; };
+ B7A214091D1B29D6005F7DD9 /* CNDomainBrowserViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CNDomainBrowserViewController.m; sourceTree = "<group>"; };
+ B7D566A51E81D6A900E43008 /* BonjourPrefRemoteViewService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "BonjourPrefRemoteViewService-Info.plist"; sourceTree = "<group>"; };
+ B7D566A71E81D6A900E43008 /* BonjourPrefRemoteViewService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BonjourPrefRemoteViewService.h; sourceTree = "<group>"; };
+ B7D566A81E81D6A900E43008 /* BonjourPrefRemoteViewService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BonjourPrefRemoteViewService.m; sourceTree = "<group>"; };
+ B7D566AB1E81D6A900E43008 /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = entitlements.plist; sourceTree = "<group>"; };
+ B7D566AC1E81D6A900E43008 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ B7D566BA1E81D8FD00E43008 /* com.apple.preference.bonjour.remoteservice.xpc */ = {isa = PBXFileReference; explicitFileType = "wrapper.xpc-service"; includeInIndex = 0; path = com.apple.preference.bonjour.remoteservice.xpc; sourceTree = BUILT_PRODUCTS_DIR; };
+ B7D566D41E81E14E00E43008 /* ViewBridge.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ViewBridge.framework; path = ../../../../../../System/Library/PrivateFrameworks/ViewBridge.framework; sourceTree = "<group>"; };
+ B7D6CA5D1D107573005E24CF /* _CNDomainBrowser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _CNDomainBrowser.h; sourceTree = "<group>"; };
+ B7D6CA5E1D107573005E24CF /* _CNDomainBrowser.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = _CNDomainBrowser.m; sourceTree = "<group>"; };
+ B7D6CA681D1076C6005E24CF /* CNDomainBrowserView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CNDomainBrowserView.h; sourceTree = "<group>"; };
+ B7D6CA691D1076C6005E24CF /* CNDomainBrowserView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CNDomainBrowserView.m; sourceTree = "<group>"; };
+ B7D6CA701D1076F3005E24CF /* DomainBrowser.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DomainBrowser.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ B7E5920F1DB687A700A38085 /* Base */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = Base; path = Base.lproj/DNSServiceDiscoveryPref.nib; sourceTree = "<group>"; };
BD03E88C1AD31278005E8A81 /* SymptomReporter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SymptomReporter.c; sourceTree = "<group>"; };
+ BD691B281ED2F43200E6F317 /* DNS64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = DNS64.c; sourceTree = "<group>"; };
+ BD691B291ED2F43200E6F317 /* DNS64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNS64.h; sourceTree = "<group>"; };
+ BD9BA7531EAF90E400658CCF /* dnssdutil */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dnssdutil; sourceTree = BUILT_PRODUCTS_DIR; };
+ BD9BA7541EAF91E700658CCF /* dnssdutil.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssdutil.c; path = ../Clients/dnssdutil.c; sourceTree = "<group>"; };
+ BD9BA7571EAF929C00658CCF /* CoreUtils.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreUtils.framework; path = System/Library/PrivateFrameworks/CoreUtils.framework; sourceTree = SDKROOT; };
BDA3F0871C48DB6D0054FB4B /* Metrics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Metrics.h; sourceTree = "<group>"; };
BDA3F0881C48DB6D0054FB4B /* Metrics.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Metrics.m; sourceTree = "<group>"; };
BDA3F0891C48DB910054FB4B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
- BDA9A7871B3A923600523835 /* dns_sd_private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dns_sd_private.h; path = Private/dns_sd_private.h; sourceTree = "<group>"; };
+ BDA9A7871B3A923600523835 /* dns_sd_private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dns_sd_private.h; path = ../mDNSShared/dns_sd_private.h; sourceTree = "<group>"; };
+ BDBF9B931ED74B8C001498A8 /* DNS64State.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNS64State.h; sourceTree = "<group>"; };
+ BDE238C11DF69D8300B9F696 /* dns_sd_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dns_sd_internal.h; path = ../mDNSShared/dns_sd_internal.h; sourceTree = "<group>"; };
D284BE730ADD80740027CCDF /* mDNSResponder */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSResponder; 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; };
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; };
@@ -703,21 +995,13 @@
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; };
- FF3C72A91CE3E62200CDF81E /* libicucore.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libicucore.dylib; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.Internal.sdk/usr/lib/libicucore.dylib; sourceTree = DEVELOPER_DIR; };
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; };
@@ -726,20 +1010,30 @@
FFA572630AF190C20055A0F1 /* dns_sd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dns_sd.h; path = ../mDNSShared/dns_sd.h; sourceTree = SOURCE_ROOT; usesTabs = 0; };
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>"; };
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 */
+ 0C1596A91D773FE300E09998 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 21B830A71D8A641F00AE2001 /* libicucore.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 0C635A731E9418A60026C796 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
213FB21612028A7A002B3A08 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -785,6 +1079,13 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 37538E1B1D7A442300226BE4 /* Foundation.framework in Frameworks */,
+ 21B830A31D8A63AE00AE2001 /* SystemConfiguration.framework in Frameworks */,
+ 21B830A61D8A63E400AE2001 /* CoreFoundation.framework in Frameworks */,
+ 21B830A21D8A63A300AE2001 /* libxml2.dylib in Frameworks */,
+ 37538E141D7A43B600226BE4 /* libicucore.dylib in Frameworks */,
+ 21B830A41D8A63BB00AE2001 /* Security.framework in Frameworks */,
+ 21B830A51D8A63CB00AE2001 /* IOKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -803,17 +1104,65 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ B7325FEA1DA47EBA00663834 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B74EC1131D47FC7700A1D155 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B74A96261DD4EDE60084A8C5 /* Preferences.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B76783A91E82D65900DA271E /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B74F2B461E82FEAE0084960E /* Foundation.framework in Frameworks */,
+ B74F2B471E82FEFE0084960E /* Security.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B7D566B71E81D8FD00E43008 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B7D566CD1E81DDB600E43008 /* Foundation.framework in Frameworks */,
+ B7D566D51E81E14E00E43008 /* ViewBridge.framework in Frameworks */,
+ B7D566CE1E81DDB600E43008 /* PreferencePanes.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B7D6CA6C1D1076F3005E24CF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BD9BA74D1EAF90E400658CCF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BD9BA7581EAF929C00658CCF /* CoreUtils.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
D284BE640ADD80740027CCDF /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 2243AE391C90AECF0079023E /* CoreBluetooth.framework in Frameworks */,
D284BE650ADD80740027CCDF /* CoreFoundation.framework in Frameworks */,
- FF3C72AA1CE3E62200CDF81E /* libicucore.dylib in Frameworks */,
BDA3F08A1C48DB920054FB4B /* Foundation.framework in Frameworks */,
D284BE670ADD80740027CCDF /* IOKit.framework in Frameworks */,
D284BE680ADD80740027CCDF /* Security.framework in Frameworks */,
D284BE660ADD80740027CCDF /* SystemConfiguration.framework in Frameworks */,
+ 21B830A81D8A642200AE2001 /* libicucore.dylib in Frameworks */,
219D5542149ED645004464AE /* libxml2.dylib in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -845,17 +1194,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
- D284BEDF0ADD80A70027CCDF /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- BDA3F08D1C48DBEA0054FB4B /* 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;
@@ -895,16 +1233,19 @@
08FB7794FE84155DC02AAC07 /* mDNSResponder */ = {
isa = PBXGroup;
children = (
- 2243AE381C90AECF0079023E /* CoreBluetooth.framework */,
- 729DF45F1CD40630005ECF70 /* com.apple.mDNSResponder.plist */,
08FB7795FE84155DC02AAC07 /* mDNS Server Sources */,
6575FC1F022EB78C00000109 /* Command-Line Clients */,
213FB20912028902002B3A08 /* Bonjour Events Plugin */,
DB2CC4420662DCE500335AB3 /* Java Support */,
+ B7D6CA511D107573005E24CF /* DomainBrowser */,
+ B74EC11A1D47FC7800A1D155 /* SettingsBundle */,
FFFB0DA407B43BED00B88D48 /* PreferencePane */,
08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
+ 0C1596AD1D773FE300E09998 /* mDNSNetMonitor */,
+ 0C635A771E9418A60026C796 /* BonjourTop */,
19C28FBDFE9D53C911CA2CBB /* Products */,
37DDE9241BA382280092AC61 /* Unit Tests */,
+ BD9BA7561EAF929C00658CCF /* Frameworks */,
);
name = mDNSResponder;
sourceTree = "<group>";
@@ -912,6 +1253,8 @@
08FB7795FE84155DC02AAC07 /* mDNS Server Sources */ = {
isa = PBXGroup;
children = (
+ 220ABBF11D78F102008423A7 /* D2D.h */,
+ 22C7633D1D777B8C0077AFCA /* D2D.c */,
22448EA51C90A82D004F25CC /* coreBLE.h */,
22448EA61C90A82D004F25CC /* coreBLE.m */,
22448EA11C90A7B5004F25CC /* BLE.c */,
@@ -924,12 +1267,17 @@
21F51DBD1B3540DB0070B05C /* com.apple.dnsextd.plist */,
21F51DBF1B35412D0070B05C /* com.apple.mDNSResponder.plist */,
21F51DBE1B3541030070B05C /* com.apple.mDNSResponderHelper.plist */,
+ 729DF45F1CD40630005ECF70 /* com.apple.mDNSResponder.plist */,
21A57F4A145B2AE100939099 /* CryptoAlg.c */,
21A57F4B145B2AE100939099 /* CryptoAlg.h */,
21A57F51145B2B1400939099 /* CryptoSupport.c */,
21A57F52145B2B1400939099 /* CryptoSupport.h */,
6575FBEC022EAF7200000109 /* daemon.c */,
+ BD691B281ED2F43200E6F317 /* DNS64.c */,
+ BD691B291ED2F43200E6F317 /* DNS64.h */,
+ BDBF9B931ED74B8C001498A8 /* DNS64State.h */,
FFA572630AF190C20055A0F1 /* dns_sd.h */,
+ BDE238C11DF69D8300B9F696 /* dns_sd_internal.h */,
BDA9A7871B3A923600523835 /* dns_sd_private.h */,
84C5B339166553AF00C324A8 /* dns_services.c */,
84F4C08F188F04CF00D1E1DE /* dns_services.h */,
@@ -1007,10 +1355,12 @@
DB2CC4680662DFF500335AB3 /* JavaVM.framework */,
2E0406140C3197CB00F13B59 /* libbsm.dylib */,
8415A6561897109000BDBA26 /* libdns_services.dylib */,
+ 37538E131D7A43B600226BE4 /* libicucore.dylib */,
2E8165F60C59835F00485EB2 /* libipsec.dylib */,
219D5541149ED645004464AE /* libxml2.dylib */,
- FF3C72A91CE3E62200CDF81E /* libicucore.dylib */,
+ B74A96251DD4EDE60084A8C5 /* Preferences.framework */,
FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */,
+ B7D566D41E81E14E00E43008 /* ViewBridge.framework */,
7F869685066EE02400D2A2DC /* Security.framework */,
65713D46025A293200000109 /* SystemConfiguration.framework */,
21F432971134AA6800581B69 /* WebFilterDNS.framework */,
@@ -1018,12 +1368,41 @@
name = "External Frameworks and Libraries";
sourceTree = "<group>";
};
+ 0C1596AD1D773FE300E09998 /* mDNSNetMonitor */ = {
+ isa = PBXGroup;
+ children = (
+ 0C6FB90E1D775FE900DF6F51 /* mDNSNetMonitor.8 */,
+ 0C1596B71D7740C100E09998 /* mDNSUNP.c */,
+ 0C1596B31D7740B500E09998 /* mDNSPosix.c */,
+ 0C1596B41D7740B500E09998 /* NetMonitor.c */,
+ );
+ path = mDNSNetMonitor;
+ sourceTree = "<group>";
+ };
+ 0C635A771E9418A60026C796 /* BonjourTop */ = {
+ isa = PBXGroup;
+ children = (
+ 0C635A7D1E9418D90026C796 /* bjIPAddr.cpp */,
+ 0C635A851E9418D90026C796 /* DNSFrame.cpp */,
+ 0C635A861E9418D90026C796 /* Frame.cpp */,
+ 0C635A871E9418D90026C796 /* LLRBTree.cpp */,
+ 0C635A881E9418D90026C796 /* main.cpp */,
+ 0C635A7E1E9418D90026C796 /* bjMACAddr.cpp */,
+ 0C635A7F1E9418D90026C796 /* bjsocket.cpp */,
+ 0C635A801E9418D90026C796 /* bjstring.cpp */,
+ 0C635A811E9418D90026C796 /* bjStringtoStringMap.cpp */,
+ 0C635A821E9418D90026C796 /* BonjourTop.cpp */,
+ 0C635A831E9418D90026C796 /* CaptureFile.cpp */,
+ 0C635A841E9418D90026C796 /* CollectBy.cpp */,
+ );
+ path = BonjourTop;
+ sourceTree = "<group>";
+ };
19C28FBDFE9D53C911CA2CBB /* Products */ = {
isa = PBXGroup;
children = (
D284BF0C0ADD80B00027CCDF /* Bonjour.prefPane */,
213FB21812028A7A002B3A08 /* BonjourEvents.plugin */,
- D284BEE80ADD80A70027CCDF /* ddnswriteconfig */,
D284BEB00ADD80920027CCDF /* dns-sd */,
72FB545F166D5FB00090B2D9 /* dnsctl */,
D284BED90ADD80A20027CCDF /* dnsextd */,
@@ -1038,6 +1417,14 @@
D284BE730ADD80740027CCDF /* mDNSResponder */,
2E0405F00C31955500F13B59 /* mDNSResponderHelper */,
37DDE92D1BA383610092AC61 /* unittests */,
+ 0C1596AC1D773FE300E09998 /* mDNSNetMonitor */,
+ B7D6CA701D1076F3005E24CF /* DomainBrowser.framework */,
+ B74EC1161D47FC7700A1D155 /* BonjourSettings.bundle */,
+ B7325FEE1DA47EBA00663834 /* DomainBrowser.framework */,
+ B7D566BA1E81D8FD00E43008 /* com.apple.preference.bonjour.remoteservice.xpc */,
+ B76783AC1E82D65900DA271E /* com.apple.preference.bonjour.tool.xpc */,
+ 0C635A761E9418A60026C796 /* bonjourtop */,
+ BD9BA7531EAF90E400658CCF /* dnssdutil */,
);
name = Products;
sourceTree = "<group>";
@@ -1054,6 +1441,18 @@
37DDE9241BA382280092AC61 /* Unit Tests */ = {
isa = PBXGroup;
children = (
+ 0C84A2911E786AFF00E8B4C7 /* daemon_ut.c */,
+ 0C10EC261DDB956000D7A0E3 /* LocalOnlyTimeoutTests.c */,
+ 0C10EC271DDB956000D7A0E3 /* LocalOnlyTimeoutTests.h */,
+ 0C7C00491DD553490078BA89 /* unittest_common.c */,
+ 0C7C004A1DD553490078BA89 /* unittest_common.h */,
+ 0C7C004B1DD553490078BA89 /* mdns_macosx_ut.c */,
+ 0C7C004C1DD553490078BA89 /* mdns_ut.c */,
+ 0C7C004D1DD553490078BA89 /* uds_daemon_ut.c */,
+ 0C7C004E1DD553490078BA89 /* CNameRecordTests.h */,
+ 0C7C004F1DD553490078BA89 /* CNameRecordTests.c */,
+ 0C5674B11DA2BF6300AF3367 /* mDNSCoreReceiveTest.h */,
+ 0C5674B21DA2BF6300AF3367 /* mDNSCoreReceiveTest.c */,
37AF802A1BF699AF00D657F6 /* DomainNameTest.c */,
37AF802B1BF699AF00D657F6 /* DomainNameTest.h */,
371D0FBD1BF666EB00E5DB26 /* ResourceRecordTest.c */,
@@ -1076,10 +1475,107 @@
FF1C919F07021E3F001048AB /* dns-sd.c */,
72FB545A166D5F960090B2D9 /* dnsctl.c */,
FF5852100DD27BD300862BDF /* ClientCommon.c */,
+ BD9BA7541EAF91E700658CCF /* dnssdutil.c */,
);
name = "Command-Line Clients";
sourceTree = "<group>";
};
+ B74EC11A1D47FC7800A1D155 /* SettingsBundle */ = {
+ isa = PBXGroup;
+ children = (
+ B74EC11B1D47FC7800A1D155 /* Info.plist */,
+ B7016F511D5D0D2900107E7C /* Localizable.strings */,
+ B79920A31DA6C49700C6E02B /* Assets.xcassets */,
+ B72C96091D6236A500AD682A /* BonjourSCStore.h */,
+ B701E7031D9DD811008F3022 /* BonjourSCStore.m */,
+ B778EE4E1D51287100C814A2 /* BonjourSettingsController.h */,
+ B778EE4F1D51287100C814A2 /* BonjourSettingsController.m */,
+ B778EE4A1D51113800C814A2 /* HostnameController.h */,
+ B778EE4B1D51113800C814A2 /* HostnameController.m */,
+ B7325FE61DA4737400663834 /* CNBrowseDomainsController.h */,
+ B7325FE71DA4737400663834 /* CNBrowseDomainsController.m */,
+ );
+ path = SettingsBundle;
+ sourceTree = "<group>";
+ };
+ B76783BA1E82D8F500DA271E /* BonjourPrefTool */ = {
+ isa = PBXGroup;
+ children = (
+ B76783BB1E82D8F500DA271E /* BonjourPrefTool-Info.plist */,
+ B716801A1E8330B400459A35 /* entitlements.plist */,
+ B76783BC1E82D8F500DA271E /* main.m */,
+ B76783BD1E82D8F500DA271E /* BonjourPrefTool.h */,
+ B76783BE1E82D8F500DA271E /* BonjourPrefTool.m */,
+ B76783BF1E82D8F500DA271E /* BonjourPrefToolProtocol.h */,
+ );
+ path = BonjourPrefTool;
+ sourceTree = "<group>";
+ };
+ B7A214061D1B29D6005F7DD9 /* iOS */ = {
+ isa = PBXGroup;
+ children = (
+ B74EC1271D494C5800A1D155 /* DomainBrowser.h */,
+ B7A214081D1B29D6005F7DD9 /* CNDomainBrowserViewController.h */,
+ B7A214091D1B29D6005F7DD9 /* CNDomainBrowserViewController.m */,
+ B7016F4F1D5D0D1900107E7C /* DomainBrowser.strings */,
+ B74EC1281D494C5800A1D155 /* Info.plist */,
+ );
+ path = iOS;
+ sourceTree = "<group>";
+ };
+ B7D566A41E81D6A900E43008 /* RemoteViewService */ = {
+ isa = PBXGroup;
+ children = (
+ B7D566A51E81D6A900E43008 /* BonjourPrefRemoteViewService-Info.plist */,
+ B7D566AB1E81D6A900E43008 /* entitlements.plist */,
+ B7D566AC1E81D6A900E43008 /* main.m */,
+ B7D566A71E81D6A900E43008 /* BonjourPrefRemoteViewService.h */,
+ B7D566A81E81D6A900E43008 /* BonjourPrefRemoteViewService.m */,
+ B75700231E8347A6005CD56C /* InfoPlist.strings */,
+ );
+ path = RemoteViewService;
+ sourceTree = "<group>";
+ };
+ B7D6CA511D107573005E24CF /* DomainBrowser */ = {
+ isa = PBXGroup;
+ children = (
+ B7A214061D1B29D6005F7DD9 /* iOS */,
+ B7D6CA661D1076C6005E24CF /* macOS */,
+ B7D6CA5C1D107573005E24CF /* Shared */,
+ );
+ path = DomainBrowser;
+ sourceTree = "<group>";
+ };
+ B7D6CA5C1D107573005E24CF /* Shared */ = {
+ isa = PBXGroup;
+ children = (
+ B7D6CA5D1D107573005E24CF /* _CNDomainBrowser.h */,
+ B7D6CA5E1D107573005E24CF /* _CNDomainBrowser.m */,
+ B799209D1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.h */,
+ B799209E1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m */,
+ );
+ path = Shared;
+ sourceTree = "<group>";
+ };
+ B7D6CA661D1076C6005E24CF /* macOS */ = {
+ isa = PBXGroup;
+ children = (
+ B74EC12B1D494C7200A1D155 /* DomainBrowser.h */,
+ B7D6CA681D1076C6005E24CF /* CNDomainBrowserView.h */,
+ B7D6CA691D1076C6005E24CF /* CNDomainBrowserView.m */,
+ B74EC1291D494C6700A1D155 /* Info.plist */,
+ );
+ path = macOS;
+ sourceTree = "<group>";
+ };
+ BD9BA7561EAF929C00658CCF /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ BD9BA7571EAF929C00658CCF /* CoreUtils.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
DB2CC4420662DCE500335AB3 /* Java Support */ = {
isa = PBXGroup;
children = (
@@ -1105,17 +1601,11 @@
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 */,
);
@@ -1125,13 +1615,10 @@
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 */,
+ B76783BA1E82D8F500DA271E /* BonjourPrefTool */,
+ B7D566A41E81D6A900E43008 /* RemoteViewService */,
FF260A2307B4463400CE10E5 /* Resources */,
);
path = PreferencePane;
@@ -1175,6 +1662,31 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 37538DFB1D7A421500226BE4 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 37538E0D1D7A437300226BE4 /* DNSSECSupport.h in Headers */,
+ 37538E0C1D7A435200226BE4 /* dnssec.h in Headers */,
+ 37538E0B1D7A432200226BE4 /* Metrics.h in Headers */,
+ 37538E0A1D7A430600226BE4 /* anonymous.h in Headers */,
+ 37538E091D7A42FC00226BE4 /* xpc_services.h in Headers */,
+ 37538E081D7A42F000226BE4 /* dns_xpc.h in Headers */,
+ 37538E071D7A42E200226BE4 /* coreBLE.h in Headers */,
+ 37538E061D7A42DA00226BE4 /* dnsproxy.h in Headers */,
+ 37538E051D7A42D000226BE4 /* DNSServiceDiscoveryDefines.h in Headers */,
+ 37538E041D7A42BE00226BE4 /* BLE.h in Headers */,
+ 37538E021D7A42B000226BE4 /* nsec.h in Headers */,
+ 37538E031D7A42B000226BE4 /* nsec3.h in Headers */,
+ 37538E001D7A429900226BE4 /* CryptoAlg.h in Headers */,
+ 37538E011D7A429900226BE4 /* CryptoSupport.h in Headers */,
+ 37538DFF1D7A428500226BE4 /* helpermsg-types.h in Headers */,
+ 37538DFE1D7A427B00226BE4 /* helper-server.h in Headers */,
+ 37538DFD1D7A425700226BE4 /* helper.h in Headers */,
+ 37538DFC1D7A424500226BE4 /* dnssd_ipc.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
84C5B3331665529800C324A8 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
@@ -1183,11 +1695,39 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ B7325FEB1DA47EBA00663834 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B7325FFD1DA4809400663834 /* DomainBrowser.h in Headers */,
+ B7325FF71DA47F9100663834 /* CNDomainBrowserViewController.h in Headers */,
+ B799209F1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B7D6CA6D1D1076F3005E24CF /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B79568351D53F693005E3BED /* DomainBrowser.h in Headers */,
+ B79568361D53F69B005E3BED /* CNDomainBrowserView.h in Headers */,
+ B79920A01DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BD9BA7491EAF90E400658CCF /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
D284BE520ADD80740027CCDF /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
D284BE540ADD80740027CCDF /* dnssd_ipc.h in Headers */,
+ BDBF9B941ED74B9C001498A8 /* DNS64State.h in Headers */,
2E96A5260C39BE480087C4D2 /* helper.h in Headers */,
2EDC5E750C39EA640092701B /* helper-server.h in Headers */,
2ECC11A60C4FEC3800CB1885 /* helpermsg-types.h in Headers */,
@@ -1195,6 +1735,7 @@
21A57F55145B2B1400939099 /* CryptoSupport.h in Headers */,
2124FA2C1471E98C0021D7BB /* nsec.h in Headers */,
2124FA301471E9B50021D7BB /* dnssec.h in Headers */,
+ BD691B2B1ED2F4AB00E6F317 /* DNS64.h in Headers */,
218E8E53156D8C0300720DA0 /* dnsproxy.h in Headers */,
2127A47915C3C7B900A857FC /* nsec3.h in Headers */,
222A3C5B1C1B75F2003A6FFD /* DNSServiceDiscoveryDefines.h in Headers */,
@@ -1203,6 +1744,7 @@
848DA5CA165477EB00D2E8B4 /* xpc_services.h in Headers */,
BDA3F08E1C48DCA50054FB4B /* Metrics.h in Headers */,
22448EA71C90A837004F25CC /* coreBLE.h in Headers */,
+ 220ABBF21D78F10F008423A7 /* D2D.h in Headers */,
22448EA41C90A7CB004F25CC /* BLE.h in Headers */,
848DA5D616547F7200D2E8B4 /* dns_xpc.h in Headers */,
);
@@ -1231,13 +1773,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
- D284BEDC0ADD80A70027CCDF /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
D284BEED0ADD80B00027CCDF /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
@@ -1288,6 +1823,40 @@
/* End PBXLegacyTarget section */
/* Begin PBXNativeTarget section */
+ 0C1596AB1D773FE300E09998 /* mDNSNetMonitor */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 0C1596B21D773FE300E09998 /* Build configuration list for PBXNativeTarget "mDNSNetMonitor" */;
+ buildPhases = (
+ 0C1596A81D773FE300E09998 /* Sources */,
+ 0C1596A91D773FE300E09998 /* Frameworks */,
+ 0C1596AA1D773FE300E09998 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mDNSNetMonitor;
+ productName = mDNSNetMonitor;
+ productReference = 0C1596AC1D773FE300E09998 /* mDNSNetMonitor */;
+ productType = "com.apple.product-type.tool";
+ };
+ 0C635A751E9418A60026C796 /* BonjourTop */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 0C635A7C1E9418A60026C796 /* Build configuration list for PBXNativeTarget "BonjourTop" */;
+ buildPhases = (
+ 0C635A721E9418A60026C796 /* Sources */,
+ 0C635A731E9418A60026C796 /* Frameworks */,
+ 0C635A741E9418A60026C796 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = BonjourTop;
+ productName = BonjourTop;
+ productReference = 0C635A761E9418A60026C796 /* bonjourtop */;
+ productType = "com.apple.product-type.tool";
+ };
213FB21712028A7A002B3A08 /* BonjourEvents */ = {
isa = PBXNativeTarget;
buildConfigurationList = 213FB21B12028A7C002B3A08 /* Build configuration list for PBXNativeTarget "BonjourEvents" */;
@@ -1384,6 +1953,7 @@
37DDE9291BA383610092AC61 /* Sources */,
37DDE92A1BA383610092AC61 /* Frameworks */,
37DDE9341BA384000092AC61 /* ShellScript */,
+ 37538DFB1D7A421500226BE4 /* Headers */,
);
buildRules = (
);
@@ -1429,6 +1999,110 @@
productReference = 84C5B3351665529800C324A8 /* libdns_services.dylib */;
productType = "com.apple.product-type.library.dynamic";
};
+ B7325FED1DA47EBA00663834 /* DomainBrowser-iOS */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = B7325FF31DA47EBA00663834 /* Build configuration list for PBXNativeTarget "DomainBrowser-iOS" */;
+ buildPhases = (
+ B7325FE91DA47EBA00663834 /* Sources */,
+ B7325FEA1DA47EBA00663834 /* Frameworks */,
+ B7325FEB1DA47EBA00663834 /* Headers */,
+ B7325FEC1DA47EBA00663834 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "DomainBrowser-iOS";
+ productName = BonjourBrowser;
+ productReference = B7325FEE1DA47EBA00663834 /* DomainBrowser.framework */;
+ productType = "com.apple.product-type.framework";
+ };
+ B74EC1151D47FC7700A1D155 /* BonjourSettings */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = B74EC11E1D47FC7800A1D155 /* Build configuration list for PBXNativeTarget "BonjourSettings" */;
+ buildPhases = (
+ B74EC1121D47FC7700A1D155 /* Sources */,
+ B74EC1131D47FC7700A1D155 /* Frameworks */,
+ B74EC1141D47FC7700A1D155 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = BonjourSettings;
+ productName = BonjourSettings;
+ productReference = B74EC1161D47FC7700A1D155 /* BonjourSettings.bundle */;
+ productType = "com.apple.product-type.bundle";
+ };
+ B76783AB1E82D65900DA271E /* BonjourPrefsTool */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = B76783B71E82D65900DA271E /* Build configuration list for PBXNativeTarget "BonjourPrefsTool" */;
+ buildPhases = (
+ B76783A81E82D65900DA271E /* Sources */,
+ B76783A91E82D65900DA271E /* Frameworks */,
+ B76783AA1E82D65900DA271E /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = BonjourPrefsTool;
+ productName = tool;
+ productReference = B76783AC1E82D65900DA271E /* com.apple.preference.bonjour.tool.xpc */;
+ productType = "com.apple.product-type.xpc-service";
+ };
+ B7D566B91E81D8FD00E43008 /* RemoteViewService */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = B7D566C31E81D8FD00E43008 /* Build configuration list for PBXNativeTarget "RemoteViewService" */;
+ buildPhases = (
+ B7D566B61E81D8FD00E43008 /* Sources */,
+ B7D566B71E81D8FD00E43008 /* Frameworks */,
+ B7D566B81E81D8FD00E43008 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = RemoteViewService;
+ productName = remoteservice;
+ productReference = B7D566BA1E81D8FD00E43008 /* com.apple.preference.bonjour.remoteservice.xpc */;
+ productType = "com.apple.product-type.xpc-service";
+ };
+ B7D6CA6F1D1076F3005E24CF /* DomainBrowser-macOS */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = B7D6CA751D1076F3005E24CF /* Build configuration list for PBXNativeTarget "DomainBrowser-macOS" */;
+ buildPhases = (
+ B7D6CA6B1D1076F3005E24CF /* Sources */,
+ B7D6CA6C1D1076F3005E24CF /* Frameworks */,
+ B7D6CA6D1D1076F3005E24CF /* Headers */,
+ B7D6CA6E1D1076F3005E24CF /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "DomainBrowser-macOS";
+ productName = BonjourBrowserUI;
+ productReference = B7D6CA701D1076F3005E24CF /* DomainBrowser.framework */;
+ productType = "com.apple.product-type.framework";
+ };
+ BD9BA7481EAF90E400658CCF /* dnssdutil */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BD9BA7501EAF90E400658CCF /* Build configuration list for PBXNativeTarget "dnssdutil" */;
+ buildPhases = (
+ BD9BA7491EAF90E400658CCF /* Headers */,
+ BD9BA74A1EAF90E400658CCF /* Sources */,
+ BD9BA74D1EAF90E400658CCF /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = dnssdutil;
+ productName = dnssdutil;
+ productReference = BD9BA7531EAF90E400658CCF /* dnssdutil */;
+ productType = "com.apple.product-type.tool";
+ };
D284BE500ADD80740027CCDF /* mDNSResponder */ = {
isa = PBXNativeTarget;
buildConfigurationList = D284BE6D0ADD80740027CCDF /* Build configuration list for PBXNativeTarget "mDNSResponder" */;
@@ -1517,24 +2191,6 @@
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 */,
- );
- 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" */;
@@ -1543,11 +2199,13 @@
D284BEEE0ADD80B00027CCDF /* Resources */,
D284BEFD0ADD80B00027CCDF /* Sources */,
D284BF010ADD80B00027CCDF /* Frameworks */,
+ B7D566C61E81D9B600E43008 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
- FFAE66F9105F0CF100162116 /* PBXTargetDependency */,
+ B76783B91E82D83800DA271E /* PBXTargetDependency */,
+ B7D566C81E81D9E700E43008 /* PBXTargetDependency */,
);
name = PreferencePane;
productInstallPath = "${SYSTEM_LIBRARY_DIR}/PreferencePanes";
@@ -1615,9 +2273,40 @@
attributes = {
LastUpgradeCheck = 0700;
TargetAttributes = {
+ 0C635A751E9418A60026C796 = {
+ CreatedOnToolsVersion = 9.0;
+ DevelopmentTeam = 63ZFQSB63Y;
+ ProvisioningStyle = Automatic;
+ };
37DDE92C1BA383610092AC61 = {
CreatedOnToolsVersion = 7.0;
};
+ B7325FED1DA47EBA00663834 = {
+ CreatedOnToolsVersion = 8.0;
+ ProvisioningStyle = Automatic;
+ };
+ B74EC1151D47FC7700A1D155 = {
+ CreatedOnToolsVersion = 8.0;
+ DevelopmentTeam = 6DMBYZ9NJ7;
+ DevelopmentTeamName = "Apple Inc. - Embedded Platform";
+ ProvisioningStyle = Automatic;
+ };
+ B76783AB1E82D65900DA271E = {
+ CreatedOnToolsVersion = 8.3;
+ ProvisioningStyle = Automatic;
+ };
+ B7C4B7251E71BD5000136C7A = {
+ CreatedOnToolsVersion = 9.0;
+ ProvisioningStyle = Automatic;
+ };
+ B7D566B91E81D8FD00E43008 = {
+ CreatedOnToolsVersion = 8.3;
+ ProvisioningStyle = Automatic;
+ };
+ B7D6CA6F1D1076F3005E24CF = {
+ CreatedOnToolsVersion = 8.0;
+ ProvisioningStyle = Automatic;
+ };
};
};
buildConfigurationList = D284BE2B0ADD78180027CCDF /* Build configuration list for PBXProject "mDNSResponder" */;
@@ -1629,12 +2318,15 @@
Japanese,
French,
German,
+ Base,
+ en,
);
mainGroup = 08FB7794FE84155DC02AAC07 /* mDNSResponder */;
projectDirPath = "";
projectRoot = "";
targets = (
00AD62BB032D7A0C0CCA2C71 /* Build More */,
+ B7C4B7251E71BD5000136C7A /* Build Some iOS */,
03067D640C83A3700022BE1F /* Build Some */,
FFB7657B0AEED96B00583A2C /* Build All */,
D284BE500ADD80740027CCDF /* mDNSResponder */,
@@ -1642,8 +2334,12 @@
D284BEA50ADD80920027CCDF /* dns-sd tool */,
72FB545E166D5FB00090B2D9 /* dnsctl */,
D284BEBF0ADD80A20027CCDF /* dnsextd */,
- D284BEDB0ADD80A70027CCDF /* ddnswriteconfig */,
+ B7325FED1DA47EBA00663834 /* DomainBrowser-iOS */,
+ B7D6CA6F1D1076F3005E24CF /* DomainBrowser-macOS */,
+ B74EC1151D47FC7700A1D155 /* BonjourSettings */,
D284BEEA0ADD80B00027CCDF /* PreferencePane */,
+ B76783AB1E82D65900DA271E /* BonjourPrefsTool */,
+ B7D566B91E81D8FD00E43008 /* RemoteViewService */,
213FB21712028A7A002B3A08 /* BonjourEvents */,
2141DCF8123FFB5D0086D23E /* SystemLibraries */,
2141DD0B123FFC7F0086D23E /* SystemLibrariesStatic */,
@@ -1658,6 +2354,9 @@
D284BEB20ADD809A0027CCDF /* libjdns_sd.jnilib */,
4AE471670EAFF81900A6C5AD /* dns_sd.jar */,
37DDE92C1BA383610092AC61 /* unittests */,
+ 0C1596AB1D773FE300E09998 /* mDNSNetMonitor */,
+ 0C635A751E9418A60026C796 /* BonjourTop */,
+ BD9BA7481EAF90E400658CCF /* dnssdutil */,
);
};
/* End PBXProject section */
@@ -1670,24 +2369,57 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ B7325FEC1DA47EBA00663834 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B7325FFF1DA480A500663834 /* DomainBrowser.strings in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B74EC1141D47FC7700A1D155 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B7E06B0E1DBA9E9700E4580C /* DomainBrowser.strings in Resources */,
+ B79920A41DA6C49700C6E02B /* Assets.xcassets in Resources */,
+ B7016F521D5D0D2900107E7C /* Localizable.strings in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B76783AA1E82D65900DA271E /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B7D566B81E81D8FD00E43008 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B75700241E8347A6005CD56C /* InfoPlist.strings in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B7D6CA6E1D1076F3005E24CF /* 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;
};
@@ -1705,7 +2437,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "if [ -e \"${SDKROOT}/usr/local/include/vproc.h\" -o -e \"${SDKROOT}/usr/include/vproc.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nelse\ntouch \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/lib/libipsec.dylib\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libipsec.a\"\nelse\necho \"#define MDNS_NO_IPSEC 1\" > ${CONFIGURATION_TEMP_DIR}/ipsec_options.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libipsec.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n";
+ shellScript = "if [ -e \"${SDKROOT}/usr/local/include/vproc.h\" -o -e \"${SDKROOT}/usr/include/vproc.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nelse\ntouch \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nfi\n\nipsec=$(ls \"${SDKROOT}/usr/lib/libipsec.*\" 2> /dev/null | wc -l)\nif [ \"$ipsec\" != \"0\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libipsec.a\"\nelse\necho \"#define MDNS_NO_IPSEC 1\" > ${CONFIGURATION_TEMP_DIR}/ipsec_options.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libipsec.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n";
};
2130256B12400DE600AC839F /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
@@ -1735,7 +2467,7 @@
};
37DDE9341BA384000092AC61 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
+ buildActionMask = 12;
files = (
);
inputPaths = (
@@ -1765,6 +2497,19 @@
shellPath = /bin/sh;
shellScript = "/usr/bin/bison -o ${SCRIPT_OUTPUT_FILE_0} -d ${SCRIPT_INPUT_FILE_0}";
};
+ B7E2951A1E259AA000C42F6D /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "# Copy Sandbox profile\nif [[ ! \"${PLATFORM_NAME}\" =~ \"simulator\" ]] ; then\n if [ -z \"${IPHONEOS_DEPLOYMENT_TARGET}\" -a -z \"${TVOS_DEPLOYMENT_TARGET}\" -a -z \"${WATCHOS_DEPLOYMENT_TARGET}\" ] ; then\n SANDBOXDST=\"${DSTROOT}/usr/share/sandbox\"\n else\n SANDBOXDST=\"${DSTROOT}/usr/local/share/sandbox/profiles/embedded/builtin\"\n fi\n (umask 022; mkdir -p -m 0755 \"$SANDBOXDST\")\n cp \"${SRCROOT}/mDNSResponder.sb\" \"${SANDBOXDST}/mDNSResponder.sb\"\nfi";
+ };
D284BE510ADD80740027CCDF /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -1782,11 +2527,48 @@
name = "Run Script";
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}\" -a -z \"${TVOS_DEPLOYMENT_TARGET}\" -a -z \"${WATCHOS_DEPLOYMENT_TARGET}\" ] ; then\n SANDBOXDST=\"${DSTROOT}/usr/share/sandbox\"\nelse\n SANDBOXDST=\"${DSTROOT}/usr/local/share/sandbox/profiles/embedded/builtin\"\nfi\n(umask 022; mkdir -p -m 0755 \"$SANDBOXDST\")\ncp \"${SRCROOT}/mDNSResponder.sb\" \"${SANDBOXDST}/mDNSResponder.sb\"\n";
+ 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";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
+ 0C1596A81D773FE300E09998 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 0C1596B61D7740B500E09998 /* NetMonitor.c in Sources */,
+ 0C1596BB1D7740D700E09998 /* DNSDigest.c in Sources */,
+ 0C1596B81D7740C100E09998 /* mDNSUNP.c in Sources */,
+ 0C1596BD1D7740E300E09998 /* uDNS.c in Sources */,
+ 0C1596BC1D7740DC00E09998 /* DNSCommon.c in Sources */,
+ 0C1596C01D77410A00E09998 /* GenLinkedList.c in Sources */,
+ 0C1596BE1D7740E900E09998 /* mDNSDebug.c in Sources */,
+ 0C1596B91D7740CD00E09998 /* anonymous.c in Sources */,
+ 0C1596BF1D7740EF00E09998 /* PlatformCommon.c in Sources */,
+ 0C1596BA1D7740D200E09998 /* CryptoAlg.c in Sources */,
+ 0C1596B51D7740B500E09998 /* mDNSPosix.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 0C635A721E9418A60026C796 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 0C635A891E9418D90026C796 /* bjIPAddr.cpp in Sources */,
+ 0C635A8A1E9418D90026C796 /* bjMACAddr.cpp in Sources */,
+ 0C635A8B1E9418D90026C796 /* bjsocket.cpp in Sources */,
+ 0C635A8C1E9418D90026C796 /* bjstring.cpp in Sources */,
+ 0C635A8D1E9418D90026C796 /* bjStringtoStringMap.cpp in Sources */,
+ 0C635A8E1E9418D90026C796 /* BonjourTop.cpp in Sources */,
+ 0C635A8F1E9418D90026C796 /* CaptureFile.cpp in Sources */,
+ 0C635A901E9418D90026C796 /* CollectBy.cpp in Sources */,
+ 0C635A911E9418D90026C796 /* DNSFrame.cpp in Sources */,
+ 0C635A921E9418D90026C796 /* Frame.cpp in Sources */,
+ 0C635A931E9418D90026C796 /* LLRBTree.cpp in Sources */,
+ 0C635A941E9418D90026C796 /* main.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
213FB21512028A7A002B3A08 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -1843,12 +2625,49 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 0CB1C7FC1D9C5C1100A5939F /* D2D.c in Sources */,
+ 37538E1F1D7A504F00226BE4 /* helper-stubs.c in Sources */,
+ 37538E1E1D7A4F9D00226BE4 /* anonymous.c in Sources */,
+ 37538E1D1D7A449D00226BE4 /* coreBLE.m in Sources */,
+ 37538E1C1D7A449000226BE4 /* Metrics.m in Sources */,
+ 37812CD41D7A307200F34505 /* BLE.c in Sources */,
+ 37812CD71D7A307200F34505 /* CryptoAlg.c in Sources */,
+ 37812CD81D7A307200F34505 /* CryptoSupport.c in Sources */,
+ 37812CD91D7A307200F34505 /* daemon.c in Sources */,
+ 37812CDA1D7A307200F34505 /* dns_services.c in Sources */,
+ 37812CDB1D7A307200F34505 /* DNSDigest.c in Sources */,
+ 37812CDE1D7A307200F34505 /* dnsproxy.c in Sources */,
+ 37812CDF1D7A307200F34505 /* DNSProxySupport.c in Sources */,
+ 37812CE01D7A307200F34505 /* dnssd_clientlib.c in Sources */,
+ 37812CE11D7A307300F34505 /* dnssd_clientstub.c in Sources */,
+ 37812CE21D7A307300F34505 /* dnssd_ipc.c in Sources */,
+ 37812CE31D7A307300F34505 /* dnssec.c in Sources */,
+ 37812CE41D7A307300F34505 /* DNSSECSupport.c in Sources */,
+ 37812CE51D7A307300F34505 /* GenLinkedList.c in Sources */,
+ 37812CE91D7A307300F34505 /* LegacyNATTraversal.c in Sources */,
+ 37812CEA1D7A307300F34505 /* mDNS.c in Sources */,
+ 37812CEB1D7A307300F34505 /* mDNSDebug.c in Sources */,
+ 37812CEC1D7A307300F34505 /* mDNSMacOSX.c in Sources */,
+ 37812CED1D7A307300F34505 /* nsec.c in Sources */,
+ 37812CEE1D7A307300F34505 /* nsec3.c in Sources */,
+ 37812CEF1D7A307300F34505 /* P2PPacketFilter.c in Sources */,
+ 37812CF11D7A307300F34505 /* PlatformCommon.c in Sources */,
+ 37812CF21D7A307300F34505 /* SymptomReporter.c in Sources */,
+ 37812CF31D7A307300F34505 /* uDNS.c in Sources */,
+ 37812CF41D7A307300F34505 /* uDNSPathEvalulation.c in Sources */,
+ 37812CF51D7A307300F34505 /* uds_daemon.c in Sources */,
+ 37812CF61D7A307300F34505 /* dnsctl_server.c in Sources */,
+ 37812CF71D7A307300F34505 /* xpc_services.c in Sources */,
371D0FBF1BF666EB00E5DB26 /* ResourceRecordTest.c in Sources */,
37FEBD581BC789AA00638EA4 /* DNSCommon.c in Sources */,
+ 37DDE9331BA383D30092AC61 /* unittest.c in Sources */,
371D0FBC1BF545FA00E5DB26 /* InterfaceTest.c in Sources */,
373202101BAB4444007DE806 /* DNSMessageTest.c in Sources */,
+ 0C7C00501DD553640078BA89 /* unittest_common.c in Sources */,
+ 0C5674B41DA2BF8600AF3367 /* mDNSCoreReceiveTest.c in Sources */,
+ 0C10EC281DDB956E00D7A0E3 /* LocalOnlyTimeoutTests.c in Sources */,
+ 0C7C00511DD5536E0078BA89 /* CNameRecordTests.c in Sources */,
3771F67D1BA387DD0072355E /* main.c in Sources */,
- 37DDE9331BA383D30092AC61 /* unittest.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1868,12 +2687,77 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ B7325FE91DA47EBA00663834 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B7325FF81DA47FB000663834 /* CNDomainBrowserViewController.m in Sources */,
+ B79920A11DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m in Sources */,
+ B7325FF91DA47FB000663834 /* _CNDomainBrowser.m in Sources */,
+ B76431A01DB0423900DB376D /* ClientCommon.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B74EC1121D47FC7700A1D155 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B701E7041D9DD811008F3022 /* BonjourSCStore.m in Sources */,
+ B778EE501D51287100C814A2 /* BonjourSettingsController.m in Sources */,
+ B7706AAF1DBA9C1800593FD5 /* CNDomainBrowserPathUtils.m in Sources */,
+ B7325FE81DA4737400663834 /* CNBrowseDomainsController.m in Sources */,
+ B7706AAD1DBA9C0F00593FD5 /* CNDomainBrowserViewController.m in Sources */,
+ B778EE4D1D51113800C814A2 /* HostnameController.m in Sources */,
+ B7706AAE1DBA9C1800593FD5 /* _CNDomainBrowser.m in Sources */,
+ B7E06B0D1DBA9DFE00E4580C /* ClientCommon.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B76783A81E82D65900DA271E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B76783C11E82D8F500DA271E /* main.m in Sources */,
+ B76783C21E82D8F500DA271E /* BonjourPrefTool.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B7D566B61E81D8FD00E43008 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B7D566D11E81DEC400E43008 /* BonjourPrefRemoteViewService.m in Sources */,
+ B7D566D01E81DEC200E43008 /* main.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B7D6CA6B1D1076F3005E24CF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B79920A21DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m in Sources */,
+ B7D6CA791D10770F005E24CF /* _CNDomainBrowser.m in Sources */,
+ B7D6CA7A1D107714005E24CF /* CNDomainBrowserView.m in Sources */,
+ B764319F1DB0423800DB376D /* ClientCommon.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BD9BA74A1EAF90E400658CCF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BD9BA7551EAF91FB00658CCF /* dnssdutil.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
D284BE550ADD80740027CCDF /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 22C7633E1D777B940077AFCA /* D2D.c in Sources */,
227687F31C90AD580019382D /* coreBLE.m in Sources */,
D284BE580ADD80740027CCDF /* mDNS.c in Sources */,
+ BD691B2A1ED2F47100E6F317 /* DNS64.c in Sources */,
D284BE590ADD80740027CCDF /* uDNS.c in Sources */,
D284BE5A0ADD80740027CCDF /* DNSCommon.c in Sources */,
D284BE5B0ADD80740027CCDF /* DNSDigest.c in Sources */,
@@ -1938,22 +2822,16 @@
);
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 */,
+ B7706AAB1DB83EAC00593FD5 /* CNDomainBrowserPathUtils.m in Sources */,
+ B7706AA91DB83E9A00593FD5 /* CNDomainBrowserView.m in Sources */,
+ B71C8B091E79F2CD00E99939 /* BonjourSCStore.m in Sources */,
FFF589C10E37F67E00EF515C /* ClientCommon.c in Sources */,
+ B7706AAA1DB83EA700593FD5 /* _CNDomainBrowser.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2013,11 +2891,26 @@
target = 03067D640C83A3700022BE1F /* Build Some */;
targetProxy = 03067D850C849CC30022BE1F /* PBXContainerItemProxy */;
};
+ 0C1596C71D7751AD00E09998 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 0C1596AB1D773FE300E09998 /* mDNSNetMonitor */;
+ targetProxy = 0C1596C61D7751AD00E09998 /* PBXContainerItemProxy */;
+ };
0C2AAB321B6929F300113637 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 84C5B3341665529800C324A8 /* dns_services */;
targetProxy = 0C2AAB311B6929F300113637 /* PBXContainerItemProxy */;
};
+ 0C4F36B41E206711005A536B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 37DDE92C1BA383610092AC61 /* unittests */;
+ targetProxy = 0C4F36B31E206711005A536B /* PBXContainerItemProxy */;
+ };
+ 0C52E92F1E96AD74006EFE7B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 0C635A751E9418A60026C796 /* BonjourTop */;
+ targetProxy = 0C52E92E1E96AD74006EFE7B /* PBXContainerItemProxy */;
+ };
2130257112400E9300AC839F /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = FFA572650AF190F10055A0F1 /* SystemLibrariesDynamic */;
@@ -2063,21 +2956,41 @@
target = 84C5B3341665529800C324A8 /* dns_services */;
targetProxy = 84C5B3401665544B00C324A8 /* PBXContainerItemProxy */;
};
+ B76783B91E82D83800DA271E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = B76783AB1E82D65900DA271E /* BonjourPrefsTool */;
+ targetProxy = B76783B81E82D83800DA271E /* PBXContainerItemProxy */;
+ };
+ B7C4B72C1E71BD6000136C7A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = B74EC1151D47FC7700A1D155 /* BonjourSettings */;
+ targetProxy = B7C4B72B1E71BD6000136C7A /* PBXContainerItemProxy */;
+ };
+ B7C4B72E1E71BE3500136C7A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 03067D640C83A3700022BE1F /* Build Some */;
+ targetProxy = B7C4B72D1E71BE3500136C7A /* PBXContainerItemProxy */;
+ };
+ B7D566C81E81D9E700E43008 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = B7D566B91E81D8FD00E43008 /* RemoteViewService */;
+ targetProxy = B7D566C71E81D9E700E43008 /* PBXContainerItemProxy */;
+ };
BD7833F01ABA5E3500EC51ED /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 72FB545E166D5FB00090B2D9 /* dnsctl */;
targetProxy = BD7833EF1ABA5E3500EC51ED /* PBXContainerItemProxy */;
};
+ BD9BA7721EAFA3D500658CCF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BD9BA7481EAF90E400658CCF /* dnssdutil */;
+ targetProxy = BD9BA7711EAFA3D500658CCF /* 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 */;
@@ -2098,11 +3011,6 @@
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 */;
@@ -2114,7 +3022,7 @@
FF260A4807B4475600CE10E5 /* DNSServiceDiscoveryPref.nib */ = {
isa = PBXVariantGroup;
children = (
- FF260A4907B4475600CE10E5 /* English */,
+ B7E5920F1DB687A700A38085 /* Base */,
);
name = DNSServiceDiscoveryPref.nib;
path = PreferencePane;
@@ -2139,6 +3047,103 @@
};
name = Release;
};
+ 0C1596B01D773FE300E09998 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "-";
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "USE_LIBIDN=1",
+ "USE_AWD=0",
+ "__MAC_OS_X_VERSION_MIN_REQUIRED=1",
+ "IPV6_PKTINFO=1",
+ "HAVE_IPV6=1",
+ "_BUILDING_XCODE_PROJECT_=1",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = NO;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ ../mDNSCore,
+ ../mDNSShared,
+ );
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 0C1596B11D773FE300E09998 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "-";
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "HAVE_IPV6=1",
+ "_BUILDING_XCODE_PROJECT_=1",
+ "USE_AWD=0",
+ "__MAC_OS_X_VERSION_MIN_REQUIRED=1",
+ "IPV6_PKTINFO=1",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = NO;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ ../mDNSCore,
+ ../mDNSShared,
+ );
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
0C419F121BA20DF600A70FF7 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -2155,9 +3160,10 @@
"mDNSResponderVersion=${MVERS}",
_LEGACY_NAT_TRAVERSAL_,
"_BUILDING_XCODE_PROJECT_=1",
- "DEBUG=1",
"BONJOUR_ON_DEMAND=1",
"USE_LIBIDN=1",
+ "USE_AWD=1",
+ "DEBUG=1",
);
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
@@ -2218,6 +3224,10 @@
"$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
"$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
);
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "HAVE_DNS64=1",
+ );
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
HEADER_SEARCH_PATHS = (
"$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/PrivateHeaders",
@@ -2327,6 +3337,18 @@
0C419F1A1BA20DF600A70FF7 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ 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",
+ "BONJOUR_ON_DEMAND=1",
+ "USE_LIBIDN=1",
+ "USE_AWD=1",
+ );
HEADER_SEARCH_PATHS = (
"${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
@@ -2341,24 +3363,23 @@
};
name = Debug;
};
- 0C419F1B1BA20DF600A70FF7 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- INSTALL_PATH = "/Library/Application Support/Bonjour";
- MACOSX_DEPLOYMENT_TARGET = 10.6;
- OTHER_LDFLAGS = "-Wl,-pie";
- PRODUCT_NAME = ddnswriteconfig;
- };
- name = Debug;
- };
0C419F1C1BA20DF600A70FF7 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CODE_SIGN_IDENTITY = "-";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ );
GCC_ENABLE_OBJC_GC = supported;
+ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
INFOPLIST_FILE = "PreferencePane/Info-PreferencePane.plist";
INSTALL_PATH = /AppleInternal/Library/PreferencePanes;
- MACOSX_DEPLOYMENT_TARGET = 10.6;
+ MACOSX_DEPLOYMENT_TARGET = 10.9;
+ ONLY_ACTIVE_ARCH = YES;
PRODUCT_NAME = Bonjour;
+ SUPPORTED_PLATFORMS = macosx;
WRAPPER_EXTENSION = prefPane;
};
name = Debug;
@@ -2602,6 +3623,98 @@
};
name = Debug;
};
+ 0C635A7A1E9418A60026C796 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "-";
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DEVELOPMENT_TEAM = 63ZFQSB63Y;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = "";
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = NO;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ OTHER_LDFLAGS = "-lncurses";
+ PRODUCT_NAME = bonjourtop;
+ SDKROOT = macosx;
+ };
+ name = Release;
+ };
+ 0C635A7B1E9418A60026C796 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "-";
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ DEVELOPMENT_TEAM = 63ZFQSB63Y;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = NO;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ OTHER_LDFLAGS = "-lncurses";
+ PRODUCT_NAME = bonjourtop;
+ SDKROOT = macosx;
+ };
+ name = Debug;
+ };
213FB21A12028A7B002B3A08 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -2714,8 +3827,60 @@
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = YES;
+ DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ );
+ 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",
+ "BONJOUR_ON_DEMAND=1",
+ "USE_LIBIDN=1",
+ "USE_AWD=1",
+ "UNIT_TEST=1",
+ "NO_AWACS=1",
+ );
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/PrivateHeaders",
+ ../mDNSShared,
+ "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
+ "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
+ "${CONFIGURATION_TEMP_DIR}",
+ "$(SDKROOT)/usr/include/libxml2",
+ "$(SDKROOT)/usr/local/include/",
+ "$(SDKROOT)/usr/include/",
+ );
+ LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ ONLY_ACTIVE_ARCH = NO;
+ OTHER_LDFLAGS = (
+ "-weak_framework",
+ WebFilterDNS,
+ "-weak_framework",
+ DeviceToDeviceManager,
+ );
PRODUCT_NAME = unittests;
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = macosx;
+ WARNING_CFLAGS = (
+ "-W",
+ "-Wall",
+ "-Wmissing-prototypes",
+ "-Wno-four-char-constants",
+ "-Wno-unknown-pragmas",
+ "-Wshadow",
+ "-Wno-format",
+ "-Wformat-security",
+ );
};
name = Release;
};
@@ -2723,118 +3888,746 @@
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = NO;
+ DEAD_CODE_STRIPPING = YES;
+ ENABLE_TESTABILITY = YES;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ );
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
+ 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",
+ "DEBUG=1",
+ "BONJOUR_ON_DEMAND=1",
+ "USE_LIBIDN=1",
+ "USE_AWD=1",
+ "UNIT_TEST=1",
+ "NO_AWACS=1",
+ );
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/PrivateHeaders",
+ ../mDNSShared,
+ "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
+ "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
+ "${CONFIGURATION_TEMP_DIR}",
+ "$(SDKROOT)/usr/include/libxml2",
+ "$(SDKROOT)/usr/local/include/",
+ "$(SDKROOT)/usr/include/",
+ );
+ LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ ONLY_ACTIVE_ARCH = NO;
+ OTHER_LDFLAGS = (
+ "-weak_framework",
+ WebFilterDNS,
+ "-weak_framework",
+ DeviceToDeviceManager,
+ );
PRODUCT_NAME = unittests;
+ SUPPORTED_PLATFORMS = "macosx iphoneos";
};
name = Debug;
};
- 37DDE9321BA383610092AC61 /* Development */ = {
+ 72FB5466166D5FB00090B2D9 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ 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 = "dnsctl-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ 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/local/bin;
+ MACOSX_DEPLOYMENT_TARGET = 10.9;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE = "";
+ SDKROOT = macosx;
+ };
+ name = Release;
+ };
+ 84C5B3371665529800C324A8 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ EXECUTABLE_PREFIX = lib;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ 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 = Release;
+ };
+ B7325FF41DA47EBA00663834 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_SUSPICIOUS_MOVES = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "";
+ CURRENT_PROJECT_VERSION = 1;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DEFINES_MODULE = YES;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INFOPLIST_FILE = ../mDNSUI/DomainBrowser/iOS/Info.plist;
+ INSTALL_PATH = "@rpath";
+ IPHONEOS_DEPLOYMENT_TARGET = 10.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_BUNDLE_IDENTIFIER = com.apple.coseos.network.bonjour.DomainBrowser;
+ PRODUCT_NAME = DomainBrowser;
+ SDKROOT = iphoneos.internal;
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Release;
+ };
+ B7325FF51DA47EBA00663834 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_WARN_BOOL_CONVERSION = "$(CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION)";
- CLANG_WARN_CONSTANT_CONVERSION = "$(CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION)";
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_EMPTY_BODY = NO;
- CLANG_WARN_ENUM_CONVERSION = "$(CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION)";
- CLANG_WARN_INT_CONVERSION = "$(CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION)";
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_UNREACHABLE_CODE = NO;
+ CLANG_WARN_SUSPICIOUS_MOVES = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- COPY_PHASE_STRIP = NO;
+ CODE_SIGN_IDENTITY = "";
+ CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
+ DEFINES_MODULE = YES;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
- GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
- GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
- GCC_WARN_ABOUT_RETURN_TYPE = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_FUNCTION = NO;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- MACOSX_DEPLOYMENT_TARGET = 10.11;
+ INFOPLIST_FILE = ../mDNSUI/DomainBrowser/iOS/Info.plist;
+ INSTALL_PATH = "@rpath";
+ IPHONEOS_DEPLOYMENT_TARGET = 10.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = com.apple.coseos.network.bonjour.DomainBrowser;
+ PRODUCT_NAME = DomainBrowser;
+ SDKROOT = iphoneos.internal;
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Debug;
+ };
+ B74EC11C1D47FC7800A1D155 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CODE_SIGN_IDENTITY = "-";
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ );
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ INFOPLIST_FILE = SettingsBundle/Info.plist;
+ INSTALL_PATH = /AppleInternal/Library/PreferenceBundles;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_BUNDLE_IDENTIFIER = com.apple.network.bonjour.BonjourSettings;
PRODUCT_NAME = "$(TARGET_NAME)";
- SDKROOT = macosx;
- STRIP_INSTALLED_PRODUCT = NO;
+ SDKROOT = iphoneos.internal;
+ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
};
- name = Development;
+ name = Release;
};
- 72FB5466166D5FB00090B2D9 /* Release */ = {
+ B74EC11D1D47FC7800A1D155 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
+ CODE_SIGN_IDENTITY = "-";
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ );
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "${inherited}",
+ );
+ INFOPLIST_FILE = SettingsBundle/Info.plist;
+ INSTALL_PATH = /AppleInternal/Library/PreferenceBundles;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = com.apple.network.bonjour.BonjourSettings;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = iphoneos.internal;
+ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ B76783B51E82D65900DA271E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "compiler-default";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = PreferencePane/BonjourPrefTool/entitlements.plist;
+ CODE_SIGN_IDENTITY = "-";
+ COMBINE_HIDPI_IMAGES = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ );
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INFOPLIST_FILE = "$(SRCROOT)/PreferencePane/BonjourPrefTool/BonjourPrefTool-Info.plist";
+ MACOSX_DEPLOYMENT_TARGET = 10.9;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_NAME = com.apple.preference.bonjour.tool;
+ SDKROOT = macosx.internal;
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = macosx;
+ };
+ name = Release;
+ };
+ B76783B61E82D65900DA271E /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "compiler-default";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = PreferencePane/BonjourPrefTool/entitlements.plist;
+ CODE_SIGN_IDENTITY = "-";
+ COMBINE_HIDPI_IMAGES = YES;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_TESTABILITY = YES;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ );
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INFOPLIST_FILE = "$(SRCROOT)/PreferencePane/BonjourPrefTool/BonjourPrefTool-Info.plist";
+ MACOSX_DEPLOYMENT_TARGET = 10.9;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ PRODUCT_NAME = com.apple.preference.bonjour.tool;
+ SDKROOT = macosx.internal;
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = macosx;
+ };
+ name = Debug;
+ };
+ B7C4B7261E71BD5000136C7A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ B7C4B7271E71BD5000136C7A /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ B7D566C41E81D8FD00E43008 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "compiler-default";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- CODE_SIGN_ENTITLEMENTS = "dnsctl-entitlements.plist";
+ CODE_SIGN_ENTITLEMENTS = PreferencePane/RemoteViewService/entitlements.plist;
CODE_SIGN_IDENTITY = "-";
+ COMBINE_HIDPI_IMAGES = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ );
GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INFOPLIST_FILE = "$(SRCROOT)/PreferencePane/RemoteViewService/BonjourPrefRemoteViewService-Info.plist";
+ MACOSX_DEPLOYMENT_TARGET = 10.9;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_NAME = com.apple.preference.bonjour.remoteservice;
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = macosx;
+ };
+ name = Release;
+ };
+ B7D566C51E81D8FD00E43008 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "compiler-default";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = PreferencePane/RemoteViewService/entitlements.plist;
+ CODE_SIGN_IDENTITY = "-";
+ COMBINE_HIDPI_IMAGES = YES;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ );
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
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_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- INSTALL_PATH = /usr/local/bin;
+ INFOPLIST_FILE = "$(SRCROOT)/PreferencePane/RemoteViewService/BonjourPrefRemoteViewService-Info.plist";
MACOSX_DEPLOYMENT_TARGET = 10.9;
- PRODUCT_NAME = "$(TARGET_NAME)";
- PROVISIONING_PROFILE = "";
- SDKROOT = macosx;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ PRODUCT_NAME = com.apple.preference.bonjour.remoteservice;
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = macosx;
+ };
+ name = Debug;
+ };
+ B7D6CA761D1076F3005E24CF /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPRESSION = "respect-asset-catalog";
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "-";
+ COMBINE_HIDPI_IMAGES = YES;
+ CURRENT_PROJECT_VERSION = 1;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DEFINES_MODULE = YES;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ FRAMEWORK_VERSION = A;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INFOPLIST_FILE = ../mDNSUI/DomainBrowser/macOS/Info.plist;
+ INSTALL_PATH = "@rpath";
+ MACOSX_DEPLOYMENT_TARGET = 10.9;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_BUNDLE_IDENTIFIER = com.apple.coreos.network.bonjour.DomainBrowser;
+ PRODUCT_NAME = DomainBrowser;
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = macosx;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
};
name = Release;
};
- 84C5B3371665529800C324A8 /* Release */ = {
+ B7D6CA771D1076F3005E24CF /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPRESSION = lossless;
+ CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- EXECUTABLE_PREFIX = lib;
+ CODE_SIGN_IDENTITY = "-";
+ COMBINE_HIDPI_IMAGES = YES;
+ CURRENT_PROJECT_VERSION = 1;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ DEFINES_MODULE = YES;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ FRAMEWORK_VERSION = A;
GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
- GCC_SYMBOLS_PRIVATE_EXTERN = NO;
- GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INFOPLIST_FILE = ../mDNSUI/DomainBrowser/macOS/Info.plist;
+ INSTALL_PATH = "@rpath";
+ MACOSX_DEPLOYMENT_TARGET = 10.9;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = com.apple.coreos.network.bonjour.DomainBrowser;
+ PRODUCT_NAME = DomainBrowser;
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = macosx;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Debug;
+ };
+ BD9BA7511EAF90E400658CCF /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
+ CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
+ CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = NO;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_ASSIGN_ENUM = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_CXX0X_EXTENSIONS = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
+ CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES;
+ CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ );
+ GCC_PREPROCESSOR_DEFINITIONS = "MDNSRESPONDER_PROJECT=1";
+ GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
+ GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES;
+ GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
+ GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
+ GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
+ GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
+ GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
+ GCC_WARN_PEDANTIC = YES;
+ GCC_WARN_SHADOW = YES;
+ GCC_WARN_SIGN_COMPARE = YES;
+ GCC_WARN_STRICT_SELECTOR_MATCH = YES;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNKNOWN_PRAGMAS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_LABEL = YES;
+ GCC_WARN_UNUSED_PARAMETER = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- INSTALL_PATH = /usr/lib;
- MACOSX_DEPLOYMENT_TARGET = 10.8;
- ONLY_ACTIVE_ARCH = NO;
+ HEADER_SEARCH_PATHS = "$(SDKROOT)${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders";
+ INSTALL_PATH = /usr/local/bin;
PRODUCT_NAME = "$(TARGET_NAME)";
- SDKROOT = macosx;
+ WARNING_CFLAGS = "-Wno-nullability-extension";
};
name = Release;
};
+ BD9BA7521EAF90E400658CCF /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
+ CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
+ CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = NO;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_ASSIGN_ENUM = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_CXX0X_EXTENSIONS = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
+ CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES;
+ CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ );
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "MDNSRESPONDER_PROJECT=1",
+ "DEBUG=1",
+ );
+ GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
+ GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = YES;
+ GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
+ GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
+ GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
+ GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
+ GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
+ GCC_WARN_PEDANTIC = YES;
+ GCC_WARN_SHADOW = YES;
+ GCC_WARN_SIGN_COMPARE = YES;
+ GCC_WARN_STRICT_SELECTOR_MATCH = YES;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNKNOWN_PRAGMAS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_LABEL = YES;
+ GCC_WARN_UNUSED_PARAMETER = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = "$(SDKROOT)${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders";
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ WARNING_CFLAGS = "-Wno-nullability-extension";
+ };
+ name = Debug;
+ };
D284BE290ADD78180027CCDF /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -2859,6 +4652,7 @@
"_BUILDING_XCODE_PROJECT_=1",
"BONJOUR_ON_DEMAND=1",
"USE_LIBIDN=1",
+ "USE_AWD=1",
);
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
@@ -2896,6 +4690,10 @@
"$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
"$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
);
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "HAVE_DNS64=1",
+ );
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
HEADER_SEARCH_PATHS = (
"$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/PrivateHeaders",
@@ -2980,24 +4778,22 @@
};
name = Release;
};
- D284BEE60ADD80A70027CCDF /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- INSTALL_PATH = "/Library/Application Support/Bonjour";
- MACOSX_DEPLOYMENT_TARGET = 10.6;
- OTHER_LDFLAGS = "-Wl,-pie";
- PRODUCT_NAME = ddnswriteconfig;
- };
- name = Release;
- };
D284BF090ADD80B00027CCDF /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CODE_SIGN_IDENTITY = "-";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ );
GCC_ENABLE_OBJC_GC = supported;
+ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
INFOPLIST_FILE = "PreferencePane/Info-PreferencePane.plist";
INSTALL_PATH = /AppleInternal/Library/PreferencePanes;
- MACOSX_DEPLOYMENT_TARGET = 10.6;
+ MACOSX_DEPLOYMENT_TARGET = 10.9;
PRODUCT_NAME = Bonjour;
+ SUPPORTED_PLATFORMS = macosx;
WRAPPER_EXTENSION = prefPane;
};
name = Release;
@@ -3131,6 +4927,24 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ 0C1596B21D773FE300E09998 /* Build configuration list for PBXNativeTarget "mDNSNetMonitor" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 0C1596B01D773FE300E09998 /* Release */,
+ 0C1596B11D773FE300E09998 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 0C635A7C1E9418A60026C796 /* Build configuration list for PBXNativeTarget "BonjourTop" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 0C635A7A1E9418A60026C796 /* Release */,
+ 0C635A7B1E9418A60026C796 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
213FB21B12028A7C002B3A08 /* Build configuration list for PBXNativeTarget "BonjourEvents" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -3197,7 +5011,6 @@
37DDE9311BA383610092AC61 /* Build configuration list for PBXNativeTarget "unittests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- 37DDE9321BA383610092AC61 /* Development */,
37AF80281BF6997A00D657F6 /* Release */,
37AF80291BF6997A00D657F6 /* Debug */,
);
@@ -3231,6 +5044,69 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ B7325FF31DA47EBA00663834 /* Build configuration list for PBXNativeTarget "DomainBrowser-iOS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ B7325FF41DA47EBA00663834 /* Release */,
+ B7325FF51DA47EBA00663834 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ B74EC11E1D47FC7800A1D155 /* Build configuration list for PBXNativeTarget "BonjourSettings" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ B74EC11C1D47FC7800A1D155 /* Release */,
+ B74EC11D1D47FC7800A1D155 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ B76783B71E82D65900DA271E /* Build configuration list for PBXNativeTarget "BonjourPrefsTool" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ B76783B51E82D65900DA271E /* Release */,
+ B76783B61E82D65900DA271E /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ B7C4B7281E71BD5000136C7A /* Build configuration list for PBXAggregateTarget "Build Some iOS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ B7C4B7261E71BD5000136C7A /* Release */,
+ B7C4B7271E71BD5000136C7A /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ B7D566C31E81D8FD00E43008 /* Build configuration list for PBXNativeTarget "RemoteViewService" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ B7D566C41E81D8FD00E43008 /* Release */,
+ B7D566C51E81D8FD00E43008 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ B7D6CA751D1076F3005E24CF /* Build configuration list for PBXNativeTarget "DomainBrowser-macOS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ B7D6CA761D1076F3005E24CF /* Release */,
+ B7D6CA771D1076F3005E24CF /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BD9BA7501EAF90E400658CCF /* Build configuration list for PBXNativeTarget "dnssdutil" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BD9BA7511EAF90E400658CCF /* Release */,
+ BD9BA7521EAF90E400658CCF /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
D284BE280ADD78180027CCDF /* Build configuration list for PBXAggregateTarget "Build More" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -3285,15 +5161,6 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- D284BEE50ADD80A70027CCDF /* Build configuration list for PBXNativeTarget "ddnswriteconfig" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- D284BEE60ADD80A70027CCDF /* Release */,
- 0C419F1B1BA20DF600A70FF7 /* Debug */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
D284BF080ADD80B00027CCDF /* Build configuration list for PBXNativeTarget "PreferencePane" */ = {
isa = XCConfigurationList;
buildConfigurations = (
diff --git a/mDNSResponder/mDNSMacOSX/uDNSPathEvalulation.c b/mDNSResponder/mDNSMacOSX/uDNSPathEvalulation.c
index cc0d0bae..96d4a0db 100644
--- a/mDNSResponder/mDNSMacOSX/uDNSPathEvalulation.c
+++ b/mDNSResponder/mDNSMacOSX/uDNSPathEvalulation.c
@@ -18,11 +18,11 @@
#include "mDNSMacOSX.h"
#include <libproc.h>
#include <network/private.h>
+#include "dns_sd_internal.h"
//Gets the DNSPolicy from NW PATH EVALUATOR
-mDNSexport void mDNSPlatformGetDNSRoutePolicy(mDNS *const m, DNSQuestion *q, mDNSBool *isBlocked)
+mDNSexport void mDNSPlatformGetDNSRoutePolicy(DNSQuestion *q, mDNSBool *isBlocked)
{
- (void) m;
q->ServiceID = -1; // initialize the ServiceID to default value of -1
// Return for non-unicast DNS queries, invalid pid, if NWPathEvaluation is already done by the client, or NWPathEvaluation not available on this OS
@@ -57,6 +57,7 @@ mDNSexport void mDNSPlatformGetDNSRoutePolicy(mDNS *const m, DNSQuestion *q, mDN
|| (q->InterfaceID == mDNSInterface_LocalOnly)
|| (q->InterfaceID == mDNSInterfaceMark)
|| (q->InterfaceID == mDNSInterface_P2P)
+ || (q->InterfaceID == mDNSInterface_BLE)
|| (q->InterfaceID == uDNSInterfaceMark))
{
client_ifindex = 0;
diff --git a/mDNSResponder/mDNSPosix/ExampleClientApp.c b/mDNSResponder/mDNSPosix/ExampleClientApp.c
index f23248b8..be340912 100644
--- a/mDNSResponder/mDNSPosix/ExampleClientApp.c
+++ b/mDNSResponder/mDNSPosix/ExampleClientApp.c
@@ -61,7 +61,7 @@ mDNSexport void ExampleClientEventLoop(mDNS *const m)
// 2. Set up the timeout.
// This example client has no other work it needs to be doing,
// so we set an effectively infinite timeout
- timeout.tv_sec = 0x3FFFFFFF;
+ timeout.tv_sec = FutureTime;
timeout.tv_usec = 0;
// 3. Give the mDNSPosix layer a chance to add its information to the fd_set and timeout
diff --git a/mDNSResponder/mDNSPosix/NetMonitor.c b/mDNSResponder/mDNSPosix/NetMonitor.c
index a3823c54..418aadda 100644
--- a/mDNSResponder/mDNSPosix/NetMonitor.c
+++ b/mDNSResponder/mDNSPosix/NetMonitor.c
@@ -22,7 +22,7 @@
// We want to use much of the functionality provided by "mDNS.c",
// except we'll steal the packets that would be sent to normal mDNSCoreReceive() routine
#define mDNSCoreReceive __NOT__mDNSCoreReceive__NOT__
-#include "mDNS.c"
+#include "../mDNSCore/mDNS.c"
#undef mDNSCoreReceive
//*************************************************************************************************************
@@ -129,6 +129,8 @@ static ActivityStat *stats;
#define OPBanner "Total Ops Probe Goodbye BrowseQ BrowseA ResolveQ ResolveA"
+mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID);
+
//*************************************************************************************************************
// Utilities
@@ -312,7 +314,7 @@ mDNSlocal void SendUnicastQuery(mDNS *const m, HostEntry *entry, domainname *nam
InterfaceID = mDNSInterface_Any; // Send query from our unicast reply socket
}
- mDNSSendDNSMessage(&mDNSStorage, &query, qptr, InterfaceID, mDNSNULL, target, MulticastDNSPort, mDNSNULL, mDNSNULL, mDNSfalse);
+ mDNSSendDNSMessage(m, &query, qptr, InterfaceID, mDNSNULL, target, MulticastDNSPort, mDNSNULL, mDNSNULL, mDNSfalse);
}
mDNSlocal void AnalyseHost(mDNS *const m, HostEntry *entry, const mDNSInterfaceID InterfaceID)
@@ -372,7 +374,7 @@ mDNSlocal void ShowSortedHostList(HostList *list, int max)
//*************************************************************************************************************
// Receive and process packets
-mDNSexport mDNSBool ExtractServiceType(const domainname *const fqdn, domainname *const srvtype)
+mDNSlocal mDNSBool ExtractServiceType(const domainname *const fqdn, domainname *const srvtype)
{
int i, len;
const mDNSu8 *src = fqdn->c;
@@ -436,11 +438,11 @@ mDNSlocal void printstats(int max)
if (!stats) return;
for (i=0; i<max; i++)
{
- int max = 0;
+ int max_val = 0;
ActivityStat *s, *m = NULL;
for (s = stats; s; s=s->next)
- if (!s->printed && max < s->totalops)
- { m = s; max = s->totalops; }
+ if (!s->printed && max_val < s->totalops)
+ { m = s; max_val = s->totalops; }
if (!m) return;
m->printed = mDNStrue;
if (i==0) mprintf("%-25s%s\n", "Service Type", OPBanner);
@@ -890,7 +892,7 @@ mDNSlocal mStatus mDNSNetMonitor(void)
do
{
- struct timeval timeout = { 0x3FFFFFFF, 0 }; // wait until SIGINT or SIGTERM
+ struct timeval timeout = { FutureTime, 0 }; // wait until SIGINT or SIGTERM
mDNSBool gotSomething;
mDNSPosixRunEventLoopOnce(&mDNSStorage, &timeout, &signals, &gotSomething);
}
@@ -973,11 +975,16 @@ mDNSexport int main(int argc, char **argv)
for (i=1; i<argc; i++)
{
- if (i+1 < argc && !strcmp(argv[i], "-i") && atoi(argv[i+1]))
+ if (i+1 < argc && !strcmp(argv[i], "-i"))
{
- FilterInterface = atoi(argv[i+1]);
- i += 1;
- printf("Monitoring interface %d\n", FilterInterface);
+ FilterInterface = if_nametoindex(argv[i+1]);
+ if (!FilterInterface) FilterInterface = atoi(argv[i+1]);
+ if (!FilterInterface) {
+ fprintf(stderr, "Unknown interface %s\n", argv[i+1]);
+ goto usage;
+ }
+ printf("Monitoring interface %d/%s\n", FilterInterface, argv[i+1]);
+ i += 1;
}
else if (!strcmp(argv[i], "-6"))
{
@@ -1019,8 +1026,9 @@ mDNSexport int main(int argc, char **argv)
usage:
fprintf(stderr, "\nmDNS traffic monitor\n");
- fprintf(stderr, "Usage: %s [-i index] [host]\n", progname);
+ fprintf(stderr, "Usage: %s [-i index] [-6] [host]\n", progname);
fprintf(stderr, "Optional [-i index] parameter displays only packets from that interface index\n");
+ fprintf(stderr, "Optional [-6] parameter displays only ipv6 packets (defaults to only ipv4 packets)\n");
fprintf(stderr, "Optional [host] parameter displays only packets from that host\n");
fprintf(stderr, "\nPer-packet header output:\n");
diff --git a/mDNSResponder/mDNSPosix/PosixDaemon.c b/mDNSResponder/mDNSPosix/PosixDaemon.c
index 88b3292c..295e8421 100644
--- a/mDNSResponder/mDNSPosix/PosixDaemon.c
+++ b/mDNSResponder/mDNSPosix/PosixDaemon.c
@@ -118,11 +118,11 @@ mDNSlocal void ParseCmdLinArgs(int argc, char **argv)
}
}
-mDNSlocal void DumpStateLog(mDNS *const m)
+mDNSlocal void DumpStateLog()
// Dump a little log of what we've been up to.
{
- LogMsg("---- BEGIN STATE LOG ----");
- udsserver_info(m);
+ LogMsg("---- BEGIN STATE LOG ----");
+ udsserver_info();
LogMsg("---- END STATE LOG ----");
}
@@ -160,7 +160,7 @@ mDNSlocal mStatus MainLoop(mDNS *m) // Loop until we quit.
(void) mDNSPosixRunEventLoopOnce(m, &timeout, &signals, &gotData);
if (sigismember(&signals, SIGHUP )) Reconfigure(m);
- if (sigismember(&signals, SIGUSR1)) DumpStateLog(m);
+ if (sigismember(&signals, SIGUSR1)) DumpStateLog();
// SIGPIPE happens when we try to write to a dead client; death should be detected soon in request_callback() and cleaned up.
if (sigismember(&signals, SIGPIPE)) LogMsg("Received SIGPIPE - ignoring");
if (sigismember(&signals, SIGINT) || sigismember(&signals, SIGTERM)) break;
@@ -235,9 +235,8 @@ mStatus udsSupportRemoveFDFromEventLoop(int fd, void *platform_data) // N
return err;
}
-mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
+mDNSexport void RecordUpdatedNiceLabel(mDNSs32 delay)
{
- (void)m;
(void)delay;
// No-op, for now
}
diff --git a/mDNSResponder/mDNSPosix/ProxyResponder.c b/mDNSResponder/mDNSPosix/ProxyResponder.c
index 3982161d..bd0fe582 100644
--- a/mDNSResponder/mDNSPosix/ProxyResponder.c
+++ b/mDNSResponder/mDNSPosix/ProxyResponder.c
@@ -275,7 +275,7 @@ mDNSexport int main(int argc, char **argv)
do
{
- struct timeval timeout = { 0x3FFFFFFF, 0 }; // wait until SIGINT or SIGTERM
+ struct timeval timeout = { FutureTime, 0 }; // wait until SIGINT or SIGTERM
mDNSBool gotSomething;
mDNSPosixRunEventLoopOnce(&mDNSStorage, &timeout, &signals, &gotSomething);
}
diff --git a/mDNSResponder/mDNSPosix/Responder.c b/mDNSResponder/mDNSPosix/Responder.c
index 7a77bcdf..3850ea26 100755
--- a/mDNSResponder/mDNSPosix/Responder.c
+++ b/mDNSResponder/mDNSPosix/Responder.c
@@ -723,7 +723,7 @@ int main(int argc, char **argv)
// 2. Set up the timeout.
// This example client has no other work it needs to be doing,
// so we set an effectively infinite timeout
- timeout.tv_sec = 0x3FFFFFFF;
+ timeout.tv_sec = FutureTime;
timeout.tv_usec = 0;
// 3. Give the mDNSPosix layer a chance to add its information to the fd_set and timeout
diff --git a/mDNSResponder/mDNSPosix/mDNSPosix.c b/mDNSResponder/mDNSPosix/mDNSPosix.c
index 857c5832..fb9718ad 100755
--- a/mDNSResponder/mDNSPosix/mDNSPosix.c
+++ b/mDNSResponder/mDNSPosix/mDNSPosix.c
@@ -56,6 +56,7 @@
#include "mDNSUNP.h"
#include "GenLinkedList.h"
+#include "dnsproxy.h"
// ***************************************************************************
// Structures
@@ -320,9 +321,8 @@ mDNSlocal void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int s
&senderAddr, senderPort, &destAddr, MulticastDNSPort, InterfaceID);
}
-mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS * const m, TCPSocketFlags flags, mDNSIPPort * port, mDNSBool useBackgroundTrafficClass)
+mDNSexport TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSIPPort * port, mDNSBool useBackgroundTrafficClass)
{
- (void)m; // Unused
(void)flags; // Unused
(void)port; // Unused
(void)useBackgroundTrafficClass; // Unused
@@ -377,9 +377,8 @@ mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned
return 0;
}
-mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS * const m, mDNSIPPort port)
+mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNSIPPort port)
{
- (void)m; // Unused
(void)port; // Unused
return NULL;
}
@@ -389,9 +388,8 @@ mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
(void)sock; // Unused
}
-mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
+mDNSexport void mDNSPlatformUpdateProxyList(const mDNSInterfaceID InterfaceID)
{
- (void)m; // Unused
(void)InterfaceID; // Unused
}
@@ -402,9 +400,8 @@ mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *c
(void)InterfaceID; // Unused
}
-mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
+mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
{
- (void)m; // Unused
(void)tpa; // Unused
(void)tha; // Unused
(void)InterfaceID; // Unused
@@ -419,9 +416,8 @@ mDNSexport void mDNSPlatformTLSTearDownCerts(void)
{
}
-mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason)
+mDNSexport void mDNSPlatformSetAllowSleep(mDNSBool allowSleep, const char *reason)
{
- (void) m;
(void) allowSleep;
(void) reason;
}
@@ -443,10 +439,9 @@ mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result
#pragma mark ***** DDNS Config Platform Functions
#endif
-mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains,
+mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains,
DNameListElem **BrowseDomains, mDNSBool ackConfig)
{
- (void) m;
(void) setservers;
(void) fqdn;
(void) setsearch;
@@ -457,9 +452,8 @@ mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers,
return mDNStrue;
}
-mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS * const m, mDNSAddr * v4, mDNSAddr * v6, mDNSAddr * router)
+mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNSAddr * v4, mDNSAddr * v6, mDNSAddr * router)
{
- (void) m;
(void) v4;
(void) v6;
(void) router;
@@ -514,7 +508,7 @@ mDNSexport int ParseDNSServers(mDNS *m, const char *filePath)
mDNSAddr DNSAddr;
DNSAddr.type = mDNSAddrType_IPv4;
DNSAddr.ip.v4.NotAnInteger = ina.s_addr;
- mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, 0, &DNSAddr, UnicastDNSPort, kScopeNone, 0, mDNSfalse, 0, mDNStrue, mDNStrue, mDNSfalse);
+ mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, 0, &DNSAddr, UnicastDNSPort, kScopeNone, 0, mDNSfalse, mDNSfalse, 0, mDNStrue, mDNStrue, mDNSfalse);
numOfServers++;
}
}
@@ -614,7 +608,7 @@ mDNSlocal void ClearInterfaceList(mDNS *const m)
while (m->HostInterfaces)
{
PosixNetworkInterface *intf = (PosixNetworkInterface*)(m->HostInterfaces);
- mDNS_DeregisterInterface(m, &intf->coreIntf, mDNSfalse);
+ mDNS_DeregisterInterface(m, &intf->coreIntf, NormalActivation);
if (gMDNSPlatformPosixVerboseLevel > 0) fprintf(stderr, "Deregistered interface %s\n", intf->intfName);
FreePosixNetworkInterface(intf);
}
@@ -944,7 +938,7 @@ mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct
// The interface is all ready to go, let's register it with the mDNS core.
if (err == 0)
- err = mDNS_RegisterInterface(m, &intf->coreIntf, mDNSfalse);
+ err = mDNS_RegisterInterface(m, &intf->coreIntf, NormalActivation);
// Clean up.
if (err == 0)
@@ -1531,16 +1525,14 @@ mDNSexport mDNSu8 *DNSProxySetAttributes(DNSQuestion *q, DNSMessageHeader *h, DN
return ptr;
}
-mDNSexport void DNSProxyInit(mDNS *const m, mDNSu32 IpIfArr[], mDNSu32 OpIf)
+mDNSexport void DNSProxyInit(mDNSu32 IpIfArr[], mDNSu32 OpIf)
{
- (void) m;
(void) IpIfArr;
(void) OpIf;
}
-mDNSexport void DNSProxyTerminate(mDNS *const m)
+mDNSexport void DNSProxyTerminate(void)
{
- (void) m;
}
// mDNS core calls this routine to clear blocks of memory.
@@ -1553,12 +1545,19 @@ mDNSexport void mDNSPlatformMemZero(void *dst, mDNSu32 len)
mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(calloc(1, len)); }
mDNSexport void mDNSPlatformMemFree (void *mem) { free(mem); }
+#if _PLATFORM_HAS_STRONG_PRNG_
+mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
+{
+ return(arc4random());
+}
+#else
mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return(tv.tv_usec);
}
+#endif
mDNSexport mDNSs32 mDNSPlatformOneSecond = 1024;
@@ -1588,9 +1587,8 @@ mDNSexport mDNSs32 mDNSPlatformUTC(void)
return time(NULL);
}
-mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
+mDNSexport void mDNSPlatformSendWakeupPacket(mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration)
{
- (void) m;
(void) InterfaceID;
(void) EthAddr;
(void) IPAddr;
@@ -1631,9 +1629,8 @@ mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIP
(void) win; // Unused
}
-mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNS *const m, mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
+mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
{
- (void) m; // Unused
(void) laddr; // Unused
(void) raddr; // Unused
(void) lport; // Unused
@@ -1643,10 +1640,9 @@ mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNS *const m, mDNSAddr *laddr, m
return mStatus_NoError;
}
-mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNS *const m, mDNSAddr *raddr)
+mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNSAddr *raddr)
{
(void) raddr; // Unused
- (void) m; // Unused
return mStatus_NoError;
}
diff --git a/mDNSResponder/mDNSPosix/mDNSPosix.h b/mDNSResponder/mDNSPosix/mDNSPosix.h
index 9e16bb89..acff9c33 100755
--- a/mDNSResponder/mDNSPosix/mDNSPosix.h
+++ b/mDNSResponder/mDNSPosix/mDNSPosix.h
@@ -71,7 +71,7 @@ extern mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m);
// Call mDNSPosixGetFDSet before calling select(), to update the parameters
// as may be necessary to meet the needs of the mDNSCore code.
// The timeout pointer MUST NOT be NULL.
-// Set timeout->tv_sec to 0x3FFFFFFF if you want to have effectively no timeout
+// Set timeout->tv_sec to FutureTime if you want to have effectively no timeout
// After calling mDNSPosixGetFDSet(), call select(nfds, &readfds, NULL, NULL, &timeout); as usual
// After select() returns, call mDNSPosixProcessFDSet() to let mDNSCore do its work
extern void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, struct timeval *timeout);
diff --git a/mDNSResponder/mDNSShared/dns_sd.h b/mDNSResponder/mDNSShared/dns_sd.h
index 660b3707..80033920 100644
--- a/mDNSResponder/mDNSShared/dns_sd.h
+++ b/mDNSResponder/mDNSShared/dns_sd.h
@@ -66,7 +66,7 @@
*/
#ifndef _DNS_SD_H
-#define _DNS_SD_H 7655009
+#define _DNS_SD_H 8780101
#ifdef __cplusplus
extern "C" {
@@ -511,29 +511,24 @@ enum
* is only set in the callbacks and kDNSServiceFlagsThresholdOne is only set on
* input to a DNSServiceBrowse call.
*/
- kDNSServiceFlagsDenyCellular = 0x8000000,
+ kDNSServiceFlagsPrivateOne = 0x8000000,
/*
- * This flag is meaningful only for Unicast DNS queries. When set, the kernel will restrict
- * DNS resolutions on the cellular interface for that request.
+ * This flag is private and should not be used.
*/
- kDNSServiceFlagsServiceIndex = 0x10000000,
+ kDNSServiceFlagsPrivateTwo = 0x10000000,
/*
- * This flag is meaningful only for DNSServiceGetAddrInfo() for Unicast DNS queries.
- * When set, DNSServiceGetAddrInfo() will interpret the "interfaceIndex" argument of the call
- * as the "serviceIndex".
+ * This flag is private and should not be used.
*/
- kDNSServiceFlagsDenyExpensive = 0x20000000,
+ kDNSServiceFlagsPrivateThree = 0x20000000,
/*
- * This flag is meaningful only for Unicast DNS queries. When set, the kernel will restrict
- * DNS resolutions on interfaces defined as expensive for that request.
+ * This flag is private and should not be used.
*/
- kDNSServiceFlagsPathEvaluationDone = 0x40000000
+ kDNSServiceFlagsPrivateFour = 0x40000000
/*
- * This flag is meaningful for only Unicast DNS queries.
- * When set, it indicates that Network PathEvaluation has already been performed.
+ * This flag is private and should not be used.
*/
};
@@ -762,7 +757,7 @@ enum
* full DNS name, the helper function DNSServiceConstructFullName() is provided.
*
* The following (highly contrived) example illustrates the escaping process.
- * Suppose you have an service called "Dr. Smith\Dr. Johnson", of type "_ftp._tcp"
+ * Suppose you have a service called "Dr. Smith\Dr. Johnson", of type "_ftp._tcp"
* in subdomain "4th. Floor" of subdomain "Building 2" of domain "apple.com."
* The full (escaped) DNS name of this service's SRV record would be:
* Dr\.\032Smith\\Dr\.\032Johnson._ftp._tcp.4th\.\032Floor.Building\0322.apple.com.
@@ -806,6 +801,12 @@ enum
* local records are subsequently created that answer the question, then those
* answers will be delivered, for as long as the question is still active.
*
+ * If the kDNSServiceFlagsTimeout and kDNSServiceInterfaceIndexLocalOnly flags
+ * are set simultaneously when either DNSServiceQueryRecord or DNSServiceGetAddrInfo
+ * is called then both flags take effect. However, if DNSServiceQueryRecord is called
+ * with both the kDNSServiceFlagsSuppressUnusable and kDNSServiceInterfaceIndexLocalOnly
+ * flags set, then the kDNSServiceFlagsSuppressUnusable flag is ignored.
+ *
* Clients explicitly wishing to discover *only* LocalOnly services during a
* browse may do this, without flags, by inspecting the interfaceIndex of each
* service reported to a DNSServiceBrowseReply() callback function, and
@@ -1131,14 +1132,14 @@ typedef void (DNSSD_API *DNSServiceRegisterReply)
* and the registration will remain active indefinitely until the client
* terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
*
+ * flags: Indicates the renaming behavior on name conflict (most applications
+ * will pass 0). See flag definitions above for details.
+ *
* interfaceIndex: If non-zero, specifies the interface on which to register the service
* (the index for a given interface is determined via the if_nametoindex()
* family of calls.) Most applications will pass 0 to register on all
* available interfaces. See "Constants for specifying an interface index" for more details.
*
- * flags: Indicates the renaming behavior on name conflict (most applications
- * will pass 0). See flag definitions above for details.
- *
* name: If non-NULL, specifies the service name to be registered.
* Most applications will not specify a name, in which case the computer
* name is used (this name is communicated to the client via the callback).
@@ -1361,7 +1362,7 @@ DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
/* DNSServiceRemoveRecord
*
* Remove a record previously added to a service record set via DNSServiceAddRecord(), or deregister
- * an record registered individually via DNSServiceRegisterRecord().
+ * a record registered individually via DNSServiceRegisterRecord().
*
* Parameters:
*
@@ -1669,7 +1670,9 @@ DNSServiceErrorType DNSSD_API DNSServiceResolve
* only applies to clients that cancel the asynchronous operation when
* they get a result. Clients that leave the asynchronous operation
* running can safely assume that the data remains valid until they
- * get another callback telling them otherwise.
+ * get another callback telling them otherwise. The ttl value is not
+ * updated when the daemon answers from the cache, hence relying on
+ * the accuracy of the ttl value is not recommended.
*
* context: The context pointer that was passed to the callout.
*
@@ -1775,7 +1778,9 @@ DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
* only applies to clients that cancel the asynchronous operation when
* they get a result. Clients that leave the asynchronous operation
* running can safely assume that the data remains valid until they
- * get another callback telling them otherwise.
+ * get another callback telling them otherwise. The ttl value is not
+ * updated when the daemon answers from the cache, hence relying on
+ * the accuracy of the ttl value is not recommended.
*
* context: The context pointer that was passed to the callout.
*
diff --git a/mDNSResponder/mDNSShared/dns_sd_internal.h b/mDNSResponder/mDNSShared/dns_sd_internal.h
new file mode 100644
index 00000000..22931f24
--- /dev/null
+++ b/mDNSResponder/mDNSShared/dns_sd_internal.h
@@ -0,0 +1,15 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2016 Apple Inc. All rights reserved.
+ */
+
+#ifndef _DNS_SD_INTERNAL_H
+#define _DNS_SD_INTERNAL_H
+
+#if !APPLE_OSX_mDNSResponder
+#define DNSSD_NO_CREATE_DELEGATE_CONNECTION 1
+#endif
+
+#include "dns_sd_private.h"
+
+#endif
diff --git a/mDNSResponder/mDNSMacOSX/Private/dns_sd_private.h b/mDNSResponder/mDNSShared/dns_sd_private.h
index f3b480ea..4d023686 100644
--- a/mDNSResponder/mDNSMacOSX/Private/dns_sd_private.h
+++ b/mDNSResponder/mDNSShared/dns_sd_private.h
@@ -6,6 +6,37 @@
#ifndef _DNS_SD_PRIVATE_H
#define _DNS_SD_PRIVATE_H
+
+// Private flags (kDNSServiceFlagsPrivateOne, kDNSServiceFlagsPrivateTwo, kDNSServiceFlagsPrivateThree, kDNSServiceFlagsPrivateFour) from dns_sd.h
+enum
+{
+ kDNSServiceFlagsDenyCellular = 0x8000000,
+ /*
+ * This flag is meaningful only for Unicast DNS queries. When set, the daemon will restrict
+ * DNS resolutions on the cellular interface for that request.
+ */
+ kDNSServiceFlagsServiceIndex = 0x10000000,
+ /*
+ * This flag is meaningful only for DNSServiceGetAddrInfo() for Unicast DNS queries.
+ * When set, DNSServiceGetAddrInfo() will interpret the "interfaceIndex" argument of the call
+ * as the "serviceIndex".
+ */
+
+ kDNSServiceFlagsDenyExpensive = 0x20000000,
+ /*
+ * This flag is meaningful only for Unicast DNS queries. When set, the daemon will restrict
+ * DNS resolutions on interfaces defined as expensive for that request.
+ */
+
+ kDNSServiceFlagsPathEvaluationDone = 0x40000000
+ /*
+ * This flag is meaningful for only Unicast DNS queries.
+ * When set, it indicates that Network PathEvaluation has already been performed.
+ */
+};
+
+
+#if !DNSSD_NO_CREATE_DELEGATE_CONNECTION
/* DNSServiceCreateDelegateConnection()
*
* Parameters:
@@ -28,6 +59,7 @@
* to use this API.
*/
DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid);
+#endif
// Map the source port of the local UDP socket that was opened for sending the DNS query
// to the process ID of the application that triggered the DNS resolution.
diff --git a/mDNSResponder/mDNSShared/dnsextd.c b/mDNSResponder/mDNSShared/dnsextd.c
index b55d3f42..bc89ef89 100644
--- a/mDNSResponder/mDNSShared/dnsextd.c
+++ b/mDNSResponder/mDNSShared/dnsextd.c
@@ -302,7 +302,7 @@ mDNSlocal TCPSocket *ConnectToServer(DaemonInfo *d)
mDNSIPPort port = zeroIPPort;
int fd;
- TCPSocket *sock = mDNSPlatformTCPSocket( NULL, 0, &port, mDNSfalse );
+ TCPSocket *sock = mDNSPlatformTCPSocket(0, &port, mDNSfalse );
if ( !sock ) { LogErr("ConnectToServer", "socket"); return NULL; }
fd = mDNSPlatformTCPGetFD( sock );
if (!connect( fd, (struct sockaddr *)&d->ns_addr, sizeof(d->ns_addr))) return sock;
@@ -1506,13 +1506,14 @@ HandleRequest
char addrbuf[32];
TCPSocket * sock = NULL;
mStatus err;
- mDNSs32 lease = 0;
+ mDNSu32 lease = 0;
+ mDNSBool gotlease;
if ((request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) == kDNSFlag0_OP_Update)
{
int i, adds = 0, dels = 0;
const mDNSu8 *ptr, *end = (mDNSu8 *)&request->msg + request->len;
HdrNToH(request);
- lease = GetPktLease(&mDNSStorage, &request->msg, end);
+ gotlease = GetPktLease(&mDNSStorage, &request->msg, end, &lease);
ptr = LocateAuthorities(&request->msg, end);
for (i = 0; i < request->msg.h.mDNS_numUpdates; i++)
{
@@ -1521,7 +1522,7 @@ HandleRequest
if (lcr.r.resrec.RecordType != kDNSRecordTypePacketNegative && lcr.r.resrec.rroriginalttl) adds++;else dels++;
}
HdrHToN(request);
- if (adds && !lease)
+ if (adds && !gotlease)
{
static const mDNSOpaque16 UpdateRefused = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, kDNSFlag1_RC_Refused } };
Log("Rejecting Update Request with %d additions but no lease", adds);
@@ -3099,8 +3100,8 @@ void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const e
const mDNSAddr *const dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID iid)
{ ( void ) m; ( void ) msg; ( void ) end; ( void ) srcaddr; ( void ) srcport; ( void ) dstaddr; ( void ) dstport; ( void ) iid; }
DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const int serviceID, const mDNSAddr *addr, const mDNSIPPort port,
- mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSu16 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
-{ ( void ) m; ( void ) d; ( void ) interface; ( void ) serviceID; ( void ) addr; ( void ) port; ( void ) scoped; ( void ) timeout; (void) cellIntf;
+ mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSu16 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
+{ ( void ) m; ( void ) d; ( void ) interface; ( void ) serviceID; ( void ) addr; ( void ) port; ( void ) scoped; ( void ) timeout; (void) cellIntf; (void) isExpensive;
(void) resGroupID; (void) reqA; (void) reqAAAA; (void) reqDO; return(NULL); }
void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID) { (void)domain; (void) InterfaceID;}
void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
@@ -3108,15 +3109,15 @@ void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback
mDNSs32 mDNS_Execute (mDNS *const m) { ( void ) m; return 0; }
mDNSs32 mDNS_TimeNow(const mDNS *const m) { ( void ) m; return 0; }
mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr) { ( void ) m; ( void ) rr; return 0; }
-void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
-{ ( void ) m; ( void ) set; ( void ) flapping; }
+void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, InterfaceActivationSpeed activationSpeed)
+{ ( void ) m; ( void ) set; ( void ) activationSpeed; }
const char * const mDNS_DomainTypeNames[1] = {};
mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom,
const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context)
{ ( void ) m; ( void ) question; ( void ) DomainType; ( void ) dom; ( void ) InterfaceID; ( void ) Callback; ( void ) Context; return 0; }
mStatus mDNS_Register(mDNS *const m, AuthRecord *const rr) { ( void ) m; ( void ) rr; return 0; }
-mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
-{ ( void ) m; ( void ) set; ( void ) flapping; return 0; }
+mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, InterfaceActivationSpeed activationSpeed)
+{ ( void ) m; ( void ) set; ( void ) activationSpeed; return 0; }
void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn) { ( void ) m; ( void ) fqdn; }
void mDNS_SetFQDN(mDNS * const m) { ( void ) m; }
void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router)
diff --git a/mDNSResponder/mDNSShared/dnssd_clientstub.c b/mDNSResponder/mDNSShared/dnssd_clientstub.c
index 5cf4ebe9..27e90eee 100644
--- a/mDNSResponder/mDNSShared/dnssd_clientstub.c
+++ b/mDNSResponder/mDNSShared/dnssd_clientstub.c
@@ -35,7 +35,7 @@
#include <mach-o/dyld.h>
#include <uuid/uuid.h>
#include <TargetConditionals.h>
-#include "dns_sd_private.h"
+#include "dns_sd_internal.h"
#endif
#if defined(_WIN32)
@@ -195,9 +195,10 @@ static int write_all(dnssd_sock_t sd, char *buf, size_t len)
ssize_t num_written = send(sd, buf, (long)len, 0);
if (num_written < 0 || (size_t)num_written > len)
{
- // Should never happen. If it does, it indicates some OS bug,
+ // Check whether socket has gone defunct,
+ // otherwise, an error here indicates some OS bug
// or that the mDNSResponder daemon crashed (which should never happen).
- #if !defined(__ppc__) && defined(SO_ISDEFUNCT)
+#if !defined(__ppc__) && defined(SO_ISDEFUNCT)
int defunct = 0;
socklen_t dlen = sizeof (defunct);
if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0)
@@ -209,12 +210,12 @@ static int write_all(dnssd_sock_t sd, char *buf, size_t len)
(num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
else
syslog(LOG_INFO, "dnssd_clientstub write_all(%d) DEFUNCT", sd);
- #else
+#else
syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
(long)num_written, (long)len,
(num_written < 0) ? dnssd_errno : 0,
(num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
- #endif
+#endif
return -1;
}
buf += num_written;
@@ -245,7 +246,9 @@ static int read_all(dnssd_sock_t sd, char *buf, int len)
{
int printWarn = 0;
int defunct = 0;
- // Should never happen. If it does, it indicates some OS bug,
+
+ // Check whether socket has gone defunct,
+ // otherwise, an error here indicates some OS bug
// or that the mDNSResponder daemon crashed (which should never happen).
#if defined(WIN32)
// <rdar://problem/7481776> Suppress logs for "A non-blocking socket operation
@@ -450,8 +453,8 @@ static void FreeDNSServiceOp(DNSServiceOp *x)
x->disp_queue = NULL;
#endif
// DNSRecords may have been added to subordinate sdRef e.g., DNSServiceRegister/DNSServiceAddRecord
- // or on the main sdRef e.g., DNSServiceCreateConnection/DNSServiveRegisterRecord. DNSRecords may have
- // been freed if the application called DNSRemoveRecord
+ // or on the main sdRef e.g., DNSServiceCreateConnection/DNSServiceRegisterRecord.
+ // DNSRecords may have been freed if the application called DNSRemoveRecord.
FreeDNSRecords(x);
if (x->kacontext)
{
@@ -629,24 +632,30 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f
static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
{
+ uint32_t datalen;
+ dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
+ DNSServiceErrorType err = kDNSServiceErr_Unknown; // Default for the "goto cleanup" cases
+ int MakeSeparateReturnSocket;
+ #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
+ char *data;
+ #endif
+
if (!hdr)
{
syslog(LOG_WARNING, "dnssd_clientstub deliver_request: !hdr");
return kDNSServiceErr_Unknown;
}
- uint32_t datalen = hdr->datalen; // We take a copy here because we're going to convert hdr->datalen to network byte order
+ datalen = hdr->datalen; // We take a copy here because we're going to convert hdr->datalen to network byte order
#if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
- char *const data = (char *)hdr + sizeof(ipc_msg_hdr);
+ data = (char *)hdr + sizeof(ipc_msg_hdr);
#endif
- dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
- DNSServiceErrorType err = kDNSServiceErr_Unknown; // Default for the "goto cleanup" cases
// Note: need to check hdr->op, not sdr->op.
// hdr->op contains the code for the specific operation we're currently doing, whereas sdr->op
// contains the original parent DNSServiceOp (e.g. for an add_record_request, hdr->op will be
// add_record_request but the parent sdr->op will be connection_request or reg_service_request)
- const int MakeSeparateReturnSocket = (sdr->primary ||
+ MakeSeparateReturnSocket = (sdr->primary ||
hdr->op == reg_record_request || hdr->op == add_record_request || hdr->op == update_record_request || hdr->op == remove_record_request);
if (!DNSServiceRefValid(sdr))
@@ -1215,7 +1224,7 @@ DNSServiceErrorType DNSSD_API DNSServiceGetPID(const uint16_t srcport, int32_t *
{
char *ptr;
ipc_msg_hdr *hdr;
- DNSServiceOp *tmp;
+ DNSServiceOp *tmp = NULL;
size_t len = sizeof(int32_t);
DNSServiceErrorType err = ConnectToServer(&tmp, 0, getpid_request, NULL, NULL, NULL);
@@ -1312,7 +1321,8 @@ DNSServiceErrorType DNSSD_API DNSServiceResolve
((interfaceIndex == kDNSServiceInterfaceIndexAny) ||
(interfaceIndex == kDNSServiceInterfaceIndexLocalOnly) ||
(interfaceIndex == kDNSServiceInterfaceIndexUnicast) ||
- (interfaceIndex == kDNSServiceInterfaceIndexP2P)))
+ (interfaceIndex == kDNSServiceInterfaceIndexP2P) ||
+ (interfaceIndex == kDNSServiceInterfaceIndexBLE)))
{
return kDNSServiceErr_BadParam;
}
@@ -2123,7 +2133,7 @@ DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
char *ptr;
size_t len;
ipc_msg_hdr *hdr;
- DNSServiceOp *tmp;
+ DNSServiceOp *tmp = NULL;
if (!fullname || (!rdata && rdlen)) return kDNSServiceErr_BadParam;
diff --git a/mDNSResponder/mDNSShared/uds_daemon.c b/mDNSResponder/mDNSShared/uds_daemon.c
index 2552c8a7..946ad162 100644
--- a/mDNSResponder/mDNSShared/uds_daemon.c
+++ b/mDNSResponder/mDNSShared/uds_daemon.c
@@ -34,6 +34,7 @@
#include "DNSCommon.h"
#include "uDNS.h"
#include "uds_daemon.h"
+#include "dns_sd_internal.h"
// Normally we append search domains only for queries with a single label that are not
// fully qualified. This can be overridden to apply search domains for queries (that are
@@ -54,8 +55,10 @@ mDNSBool AlwaysAppendSearchDomains = mDNSfalse;
#include <sys/proc_info.h> // for struct proc_bsdshortinfo
#include <libproc.h> // for proc_pidinfo()
#endif //LOCAL_PEEREPID
-//upto 16 characters of process name (defined in <sys/proc.h> but we do not want to include that file)
-#define MAXCOMLEN 16
+
+#ifdef UNIT_TEST
+#include "unittest.h"
+#endif
#if APPLE_OSX_mDNSResponder
#include <WebFilterDNS/WebFilterDNS.h>
@@ -84,188 +87,6 @@ int WCFNameResolvesToName(WCFConnection *conn, char* fromName, char* toName, uid
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
-#pragma mark - Types and Data Structures
-#endif
-
-typedef enum
-{
- t_uninitialized,
- t_morecoming,
- t_complete,
- t_error,
- t_terminated
-} transfer_state;
-
-typedef struct request_state request_state;
-
-typedef void (*req_termination_fn)(request_state *request);
-
-typedef struct registered_record_entry
-{
- struct registered_record_entry *next;
- mDNSu32 key;
- client_context_t regrec_client_context;
- request_state *request;
- mDNSBool external_advertise;
- mDNSInterfaceID origInterfaceID;
- AuthRecord *rr; // Pointer to variable-sized AuthRecord (Why a pointer? Why not just embed it here?)
-} registered_record_entry;
-
-// A single registered service: ServiceRecordSet + bookkeeping
-// Note that we duplicate some fields from parent service_info object
-// to facilitate cleanup, when instances and parent may be deallocated at different times.
-typedef struct service_instance
-{
- struct service_instance *next;
- request_state *request;
- AuthRecord *subtypes;
- mDNSBool renameonmemfree; // Set on config change when we deregister original name
- mDNSBool clientnotified; // Has client been notified of successful registration yet?
- mDNSBool default_local; // is this the "local." from an empty-string registration?
- mDNSBool external_advertise; // is this is being advertised externally?
- domainname domain;
- ServiceRecordSet srs; // note -- variable-sized object -- must be last field in struct
-} service_instance;
-
-// for multi-domain default browsing
-typedef struct browser_t
-{
- struct browser_t *next;
- domainname domain;
- DNSQuestion q;
-} browser_t;
-
-#ifdef _WIN32
- typedef unsigned int pid_t;
- typedef unsigned int socklen_t;
-#endif
-
-struct request_state
-{
- request_state *next;
- request_state *primary; // If this operation is on a shared socket, pointer to primary
- // request_state for the original DNSServiceCreateConnection() operation
- dnssd_sock_t sd;
- pid_t process_id; // Client's PID value
- char pid_name[MAXCOMLEN]; // Client's process name
- char uuid[UUID_SIZE];
- mDNSBool validUUID;
- dnssd_sock_t errsd;
- mDNSu32 uid;
- void * platform_data;
-
- // Note: On a shared connection these fields in the primary structure, including hdr, are re-used
- // for each new request. This is because, until we've read the ipc_msg_hdr to find out what the
- // operation is, we don't know if we're going to need to allocate a new request_state or not.
- transfer_state ts;
- mDNSu32 hdr_bytes; // bytes of header already read
- ipc_msg_hdr hdr;
- mDNSu32 data_bytes; // bytes of message data already read
- char *msgbuf; // pointer to data storage to pass to free()
- const char *msgptr; // pointer to data to be read from (may be modified)
- char *msgend; // pointer to byte after last byte of message
-
- // reply, termination, error, and client context info
- int no_reply; // don't send asynchronous replies to client
- mDNSs32 time_blocked; // record time of a blocked client
- int unresponsiveness_reports;
- struct reply_state *replies; // corresponding (active) reply list
- req_termination_fn terminate;
- DNSServiceFlags flags;
- mDNSu32 interfaceIndex;
-
- union
- {
- registered_record_entry *reg_recs; // list of registrations for a connection-oriented request
- struct
- {
- mDNSInterfaceID interface_id;
- mDNSBool default_domain;
- mDNSBool ForceMCast;
- domainname regtype;
- browser_t *browsers;
- const mDNSu8 *AnonData;
- } browser;
- struct
- {
- mDNSInterfaceID InterfaceID;
- mDNSu16 txtlen;
- void *txtdata;
- mDNSIPPort port;
- domainlabel name;
- char type_as_string[MAX_ESCAPED_DOMAIN_NAME];
- domainname type;
- mDNSBool default_domain;
- domainname host;
- mDNSBool autoname; // Set if this name is tied to the Computer Name
- mDNSBool autorename; // Set if this client wants us to automatically rename on conflict
- mDNSBool allowremotequery; // Respond to unicast queries from outside the local link?
- int num_subtypes;
- mDNSBool AnonData;
- service_instance *instances;
- } servicereg;
- struct
- {
- mDNSInterfaceID interface_id;
- mDNSu32 flags;
- mDNSu32 protocol;
- DNSQuestion q4;
- DNSQuestion *q42;
- DNSQuestion q6;
- DNSQuestion *q62;
- mDNSu8 v4ans;
- mDNSu8 v6ans;
- } addrinfo;
- struct
- {
- mDNSIPPort ReqExt; // External port we originally requested, for logging purposes
- NATTraversalInfo NATinfo;
- } pm;
- struct
- {
- DNSServiceFlags flags;
- DNSQuestion q_all;
- DNSQuestion q_default;
- DNSQuestion q_autoall;
- } enumeration;
- struct
- {
- DNSQuestion q;
- DNSQuestion *q2;
- mDNSu8 ans;
- } queryrecord;
- struct
- {
- DNSQuestion qtxt;
- DNSQuestion qsrv;
- const ResourceRecord *txt;
- const ResourceRecord *srv;
- mDNSs32 ReportTime;
- mDNSBool external_advertise;
- } resolve;
- } u;
-};
-
-// struct physically sits between ipc message header and call-specific fields in the message buffer
-typedef struct
-{
- DNSServiceFlags flags; // Note: This field is in NETWORK byte order
- mDNSu32 ifi; // Note: This field is in NETWORK byte order
- DNSServiceErrorType error; // Note: This field is in NETWORK byte order
-} reply_hdr;
-
-typedef struct reply_state
-{
- struct reply_state *next; // If there are multiple unsent replies
- mDNSu32 totallen;
- mDNSu32 nwriten;
- ipc_msg_hdr mhdr[1];
- reply_hdr rhdr[1];
-} reply_state;
-
-// ***************************************************************************
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
#pragma mark - Globals
#endif
@@ -363,7 +184,7 @@ mDNSlocal void my_throttled_perror(char *err_msg)
// LogMcastQuestion/LogMcastQ should be called after the DNSQuestion struct is initialized(especially for q->TargetQID)
// Hence all calls are made after mDNS_StartQuery()/mDNS_StopQuery()/mDNS_StopBrowse() is called.
-mDNSlocal void LogMcastQuestion(mDNS *const m, const DNSQuestion *const q, request_state *req, q_state status)
+mDNSlocal void LogMcastQuestion(const DNSQuestion *const q, request_state *req, q_state status)
{
if (mDNSOpaque16IsZero(q->TargetQID)) // Check for Mcast Query
{
@@ -381,16 +202,16 @@ mDNSlocal void LogMcastQuestion(mDNS *const m, const DNSQuestion *const q, reque
q->InterfaceID == mDNSInterface_LocalOnly ? "lo" :
q->InterfaceID == mDNSInterface_P2P ? "p2p" :
q->InterfaceID == mDNSInterface_BLE ? "BLE" :
- q->InterfaceID == mDNSInterface_Any ? "any" : InterfaceNameForID(m, q->InterfaceID),
+ q->InterfaceID == mDNSInterface_Any ? "any" : InterfaceNameForID(&mDNSStorage, q->InterfaceID),
req->process_id, req->pid_name);
- LogMcastStateInfo(m, mflag, mDNSfalse, mDNSfalse);
+ LogMcastStateInfo(mflag, mDNSfalse, mDNSfalse);
}
return;
}
// LogMcastService/LogMcastS should be called after the AuthRecord struct is initialized
// Hence all calls are made after mDNS_Register()/ just before mDNS_Deregister()
-mDNSlocal void LogMcastService(mDNS *const m, const AuthRecord *const ar, request_state *req, reg_state status)
+mDNSlocal void LogMcastService(const AuthRecord *const ar, request_state *req, reg_state status)
{
if (!AuthRecord_uDNS(ar)) // Check for Mcast Service
{
@@ -408,16 +229,17 @@ mDNSlocal void LogMcastService(mDNS *const m, const AuthRecord *const ar, reques
ar->resrec.InterfaceID == mDNSInterface_LocalOnly ? "lo" :
ar->resrec.InterfaceID == mDNSInterface_P2P ? "p2p" :
ar->resrec.InterfaceID == mDNSInterface_BLE ? "BLE" :
- ar->resrec.InterfaceID == mDNSInterface_Any ? "all" : InterfaceNameForID(m, ar->resrec.InterfaceID),
+ ar->resrec.InterfaceID == mDNSInterface_Any ? "all" : InterfaceNameForID(&mDNSStorage, ar->resrec.InterfaceID),
req->process_id, req->pid_name);
- LogMcastStateInfo(m, mflag, mDNSfalse, mDNSfalse);
+ LogMcastStateInfo(mflag, mDNSfalse, mDNSfalse);
}
return;
}
// For complete Mcast State Log, pass mDNStrue to mstatelog in LogMcastStateInfo()
-mDNSexport void LogMcastStateInfo(mDNS *const m, mDNSBool mflag, mDNSBool start, mDNSBool mstatelog)
+mDNSexport void LogMcastStateInfo(mDNSBool mflag, mDNSBool start, mDNSBool mstatelog)
{
+ mDNS *const m = &mDNSStorage;
if (!mstatelog)
{
if (!all_requests)
@@ -862,13 +684,6 @@ mDNSlocal void external_start_advertising_helper(service_instance *const instanc
external_start_advertising_service(&instance->srs.RR_PTR.resrec, instance->request->flags);
external_start_advertising_service(&instance->srs.RR_SRV.resrec, instance->request->flags);
-#if APPLE_OSX_mDNSResponder
- if (applyToBLE(instance->srs.RR_SRV.resrec.InterfaceID, instance->request->flags))
- {
- start_BLE_advertise(& instance->srs, instance->srs.RR_SRV.resrec.name , instance->srs.RR_SRV.resrec.rrtype, instance->request->flags);
- }
-#endif // APPLE_OSX_mDNSResponder
-
external_start_advertising_service(&instance->srs.RR_TXT.resrec, instance->request->flags);
for (e = instance->srs.Extras; e; e = e->next)
@@ -964,13 +779,13 @@ mDNSlocal void unlink_and_free_service_instance(service_instance *srv)
// Count how many other service records we have locally with the same name, but different rdata.
// For auto-named services, we can have at most one per machine -- if we allowed two auto-named services of
// the same type on the same machine, we'd get into an infinite autoimmune-response loop of continuous renaming.
-mDNSexport int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs)
+mDNSexport int CountPeerRegistrations(ServiceRecordSet *const srs)
{
int count = 0;
ResourceRecord *r = &srs->RR_SRV.resrec;
AuthRecord *rr;
- for (rr = m->ResourceRecords; rr; rr=rr->next)
+ for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !IdenticalSameNameRecord(&rr->resrec, r))
count++;
@@ -1056,8 +871,8 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
LogInfo("regservice_callback: calling external_start_advertising_helper()");
external_start_advertising_helper(instance);
}
- if (instance->request->u.servicereg.autoname && CountPeerRegistrations(m, srs) == 0)
- RecordUpdatedNiceLabel(m, 0); // Successfully got new name, tell user immediately
+ if (instance->request->u.servicereg.autoname && CountPeerRegistrations(srs) == 0)
+ RecordUpdatedNiceLabel(0); // Successfully got new name, tell user immediately
}
else if (result == mStatus_MemFree)
{
@@ -1080,7 +895,7 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
if (instance->request->u.servicereg.autorename)
{
external_stop_advertising_helper(instance);
- if (instance->request->u.servicereg.autoname && CountPeerRegistrations(m, srs) == 0)
+ if (instance->request->u.servicereg.autoname && CountPeerRegistrations(srs) == 0)
{
// On conflict for an autoname service, rename and reregister *all* autoname services
IncrementLabelSuffix(&m->nicelabel, mDNStrue);
@@ -1253,7 +1068,7 @@ mDNSlocal void connection_termination(request_state *request)
ptr->external_advertise = mDNSfalse;
external_stop_advertising_service(&ptr->rr->resrec, request->flags);
}
- LogMcastS(&mDNSStorage, ptr->rr, request, reg_stop);
+ LogMcastS(ptr->rr, request, reg_stop);
mDNS_Deregister(&mDNSStorage, ptr->rr); // Will free ptr->rr for us
freeL("registered_record_entry/connection_termination", ptr);
}
@@ -1283,11 +1098,12 @@ mDNSlocal void handle_cancel_request(request_state *request)
mDNSlocal mStatus handle_regrecord_request(request_state *request)
{
mStatus err = mStatus_BadParamErr;
+ AuthRecord *rr;
if (request->terminate != connection_termination)
{ LogMsg("%3d: DNSServiceRegisterRecord(not a shared connection ref)", request->sd); return(err); }
- AuthRecord *rr = read_rr_from_ipc_msg(request, 1, 1);
+ rr = read_rr_from_ipc_msg(request, 1, 1);
if (rr)
{
registered_record_entry *re;
@@ -1333,7 +1149,7 @@ mDNSlocal mStatus handle_regrecord_request(request_state *request)
}
else
{
- LogMcastS(&mDNSStorage, rr, request, reg_start);
+ LogMcastS(rr, request, reg_start);
re->next = request->u.reg_recs;
request->u.reg_recs = re;
}
@@ -1366,7 +1182,7 @@ mDNSlocal void regservice_termination_callback(request_state *request)
// We can't clear p->request *after* the calling mDNS_DeregisterService/unlink_and_free_service_instance
// because by then we might have already freed p
p->request = NULL;
- LogMcastS(&mDNSStorage, &p->srs.RR_SRV, request, reg_stop);
+ LogMcastS(&p->srs.RR_SRV, request, reg_stop);
if (mDNS_DeregisterService(&mDNSStorage, &p->srs))
{
unlink_and_free_service_instance(p);
@@ -1400,7 +1216,6 @@ mDNSlocal mStatus add_record_to_service(request_state *request, service_instance
{
ServiceRecordSet *srs = &instance->srs;
mStatus result;
- mDNSu32 coreFlags = 0; // translate to corresponding mDNSCore flag definitions
size_t size = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody);
ExtraResourceRecord *extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
if (!extra) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
@@ -1413,18 +1228,13 @@ mDNSlocal mStatus add_record_to_service(request_state *request, service_instance
// use InterfaceID value from DNSServiceRegister() call that created the original service
extra->r.resrec.InterfaceID = request->u.servicereg.InterfaceID;
- if (request->flags & kDNSServiceFlagsIncludeP2P)
- coreFlags |= coreFlagIncludeP2P;
- if (request->flags & kDNSServiceFlagsIncludeAWDL)
- coreFlags |= coreFlagIncludeAWDL;
-
- result = mDNS_AddRecordToService(&mDNSStorage, srs, extra, &extra->r.rdatastorage, ttl, coreFlags);
+ result = mDNS_AddRecordToService(&mDNSStorage, srs, extra, &extra->r.rdatastorage, ttl, request->flags);
if (result)
{
freeL("ExtraResourceRecord/add_record_to_service", extra);
return result;
}
- LogMcastS(&mDNSStorage, &srs->RR_PTR, request, reg_start);
+ LogMcastS(&srs->RR_PTR, request, reg_start);
extra->ClientID = request->hdr.reg_index;
if ( instance->external_advertise
@@ -1461,8 +1271,9 @@ mDNSlocal mStatus handle_add_request(request_state *request)
if (mDNSIPPortIsZero(request->u.servicereg.port))
{ LogMsg("%3d: DNSServiceAddRecord: adding record to a service registered with zero port", request->sd); return(mStatus_BadParamErr); }
- LogOperation("%3d: DNSServiceAddRecord(%X, %##s, %s, %d)", request->sd, flags,
- (request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL, DNSTypeName(rrtype), rdlen);
+ LogOperation("%3d: DNSServiceAddRecord(%X, %##s, %s, %d) PID[%d](%s)", request->sd, flags,
+ (request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL, DNSTypeName(rrtype), rdlen,
+ request->process_id, request->pid_name);
for (i = request->u.servicereg.instances; i; i = i->next)
{
@@ -1552,8 +1363,9 @@ mDNSlocal mStatus handle_update_request(request_state *request)
if (reptr->key == hdr->reg_index)
{
result = update_record(reptr->rr, rdlen, rdata, ttl, &reptr->external_advertise);
- LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)",
- request->sd, reptr->rr->resrec.name->c, reptr->rr ? DNSTypeName(reptr->rr->resrec.rrtype) : "<NONE>");
+ LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s) PID[%d](%s)",
+ request->sd, reptr->rr->resrec.name->c, reptr->rr ? DNSTypeName(reptr->rr->resrec.rrtype) : "<NONE>",
+ request->process_id, request->pid_name);
goto end;
}
}
@@ -1601,9 +1413,10 @@ mDNSlocal mStatus handle_update_request(request_state *request)
end:
if (request->terminate == regservice_termination_callback)
- LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)", request->sd,
+ LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s) PID[%d](%s)", request->sd,
(request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL,
- rr ? DNSTypeName(rr->resrec.rrtype) : "<NONE>");
+ rr ? DNSTypeName(rr->resrec.rrtype) : "<NONE>",
+ request->process_id, request->pid_name);
return(result);
}
@@ -1619,14 +1432,15 @@ mDNSlocal mStatus remove_record(request_state *request)
e = *ptr;
*ptr = e->next; // unlink
- LogOperation("%3d: DNSServiceRemoveRecord(%u %s)", request->sd, e->key, RRDisplayString(&mDNSStorage, &e->rr->resrec));
+ LogOperation("%3d: DNSServiceRemoveRecord(%u %s) PID[%d](%s)",
+ request->sd, e->key, RRDisplayString(&mDNSStorage, &e->rr->resrec), request->process_id, request->pid_name);
e->rr->RecordContext = NULL;
if (e->external_advertise)
{
external_stop_advertising_service(&e->rr->resrec, request->flags);
e->external_advertise = mDNSfalse;
}
- LogMcastS(&mDNSStorage, e->rr, request, reg_stop);
+ LogMcastS(e->rr, request, reg_stop);
err = mDNS_Deregister(&mDNSStorage, e->rr); // Will free e->rr for us; we're responsible for freeing e
if (err)
{
@@ -1673,9 +1487,9 @@ mDNSlocal mStatus handle_removerecord_request(request_state *request)
{
service_instance *i;
mDNSu16 rrtype = 0;
- LogOperation("%3d: DNSServiceRemoveRecord(%##s, %s)", request->sd,
+ LogOperation("%3d: DNSServiceRemoveRecord(%##s, %s) PID[%d](%s)", request->sd,
(request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL,
- rrtype ? DNSTypeName(rrtype) : "<NONE>");
+ rrtype ? DNSTypeName(rrtype) : "<NONE>", request->process_id, request->pid_name);
for (i = request->u.servicereg.instances; i; i = i->next)
{
err = remove_extra(request, i, &rrtype);
@@ -1822,20 +1636,6 @@ mDNSlocal mStatus register_service_instance(request_state *request, const domain
const mDNSBool DomainIsLocal = SameDomainName(domain, &localdomain);
mStatus result;
mDNSInterfaceID interfaceID = request->u.servicereg.InterfaceID;
- mDNSu32 coreFlags = 0;
-
- if (request->flags & kDNSServiceFlagsIncludeP2P)
- coreFlags |= coreFlagIncludeP2P;
- if (request->flags & kDNSServiceFlagsIncludeAWDL)
- coreFlags |= coreFlagIncludeAWDL;
-
- // Client guarantees that record names are unique, so we can skip sending out initial
- // probe messages. Standard name conflict resolution is still done if a conflict is discovered.
- if (request->flags & kDNSServiceFlagsKnownUnique)
- coreFlags |= coreFlagKnownUnique;
-
- if (request->flags & kDNSServiceFlagsWakeOnlyService)
- coreFlags |= coreFlagWakeOnly;
// If the client specified an interface, but no domain, then we honor the specified interface for the "local" (mDNS)
// registration but for the wide-area registrations we don't (currently) have any concept of a wide-area unicast
@@ -1891,14 +1691,14 @@ mDNSlocal mStatus register_service_instance(request_state *request, const domain
request->u.servicereg.port,
request->u.servicereg.txtdata, request->u.servicereg.txtlen,
instance->subtypes, request->u.servicereg.num_subtypes,
- interfaceID, regservice_callback, instance, coreFlags);
+ interfaceID, regservice_callback, instance, request->flags);
if (!result)
{
*ptr = instance; // Append this to the end of our request->u.servicereg.instances list
LogOperation("%3d: DNSServiceRegister(%##s, %u) ADDED", instance->request->sd,
instance->srs.RR_SRV.resrec.name->c, mDNSVal16(request->u.servicereg.port));
- LogMcastS(&mDNSStorage, &instance->srs.RR_SRV, request, reg_start);
+ LogMcastS(&instance->srs.RR_SRV, request, reg_start);
}
else
{
@@ -2028,6 +1828,7 @@ mDNSlocal mDNSBool PreDefinedInterfaceIndex(mDNSu32 interfaceIndex)
case kDNSServiceInterfaceIndexLocalOnly:
case kDNSServiceInterfaceIndexUnicast:
case kDNSServiceInterfaceIndexP2P:
+ case kDNSServiceInterfaceIndexBLE:
return mDNStrue;
default:
return mDNSfalse;
@@ -2190,8 +1991,17 @@ mDNSlocal mStatus handle_regservice_request(request_state *request)
request->pid_name, count+1, srv.c, mDNSVal16(request->u.servicereg.port));
}
+#if APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
+ // Determine if this request should be promoted to use BLE triggered feature.
+ if (shouldUseBLE(InterfaceID, 0, &request->u.servicereg.type, &d))
+ {
+ request->flags |= (kDNSServiceFlagsAutoTrigger | kDNSServiceFlagsIncludeAWDL);
+ LogInfo("handle_regservice_request: registration promoted to use kDNSServiceFlagsAutoTrigger");
+ }
+#endif // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
+
LogOperation("%3d: DNSServiceRegister(%X, %d, \"%s\", \"%s\", \"%s\", \"%s\", %u) START PID[%d](%s)",
- request->sd, flags, interfaceIndex, name, request->u.servicereg.type_as_string, domain, host,
+ request->sd, request->flags, interfaceIndex, name, request->u.servicereg.type_as_string, domain, host,
mDNSVal16(request->u.servicereg.port), request->process_id, request->pid_name);
// We need to unconditionally set request->terminate, because even if we didn't successfully
@@ -2280,8 +2090,8 @@ mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const Resourc
validReply:
- LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %d: %s",
- req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv",
+ LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s interface %d: %s",
+ req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV",
mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse), RRDisplayString(m, answer));
append_reply(req, rep);
@@ -2289,7 +2099,6 @@ validReply:
mDNSlocal void SetQuestionPolicy(DNSQuestion *q, request_state *req)
{
- int i;
q->euid = req->uid;
// The policy is either based on pid or UUID. Pass a zero pid
// to the "core" if the UUID is valid. If we always pass the pid,
@@ -2303,10 +2112,7 @@ mDNSlocal void SetQuestionPolicy(DNSQuestion *q, request_state *req)
// pid in the question, we will reevaluate this strategy.
if (req->validUUID)
{
- for (i = 0; i < UUID_SIZE; i++)
- {
- q->uuid[i] = req->uuid[i];
- }
+ mDNSPlatformMemCopy(q->uuid, req->uuid, UUID_SIZE);
q->pid = 0;
}
else
@@ -2344,15 +2150,24 @@ mDNSlocal mStatus add_domain_to_browser(request_state *info, const domainname *d
{
b->next = info->u.browser.browsers;
info->u.browser.browsers = b;
- LogOperation("%3d: DNSServiceBrowse(%##s) START PID[%d](%s)", info->sd, b->q.qname.c, info->process_id,
- info->pid_name);
- LogMcastQ(&mDNSStorage, &b->q, info, q_start);
+
+#if APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
+ // Determine if this request should be promoted to use BLE triggered discovery.
+ if (shouldUseBLE(info->u.browser.interface_id, 0, &info->u.browser.regtype, (domainname *) d))
+ {
+ info->flags |= (kDNSServiceFlagsAutoTrigger | kDNSServiceFlagsIncludeAWDL);
+ b->q.flags |= (kDNSServiceFlagsAutoTrigger | kDNSServiceFlagsIncludeAWDL);
+ LogInfo("add_domain_to_browser: request promoted to use kDNSServiceFlagsAutoTrigger");
+ }
+#endif // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
+
+ LogMcastQ(&b->q, info, q_start);
if (callExternalHelpers(info->u.browser.interface_id, &b->domain, info->flags))
{
domainname tmp;
ConstructServiceName(&tmp, NULL, &info->u.browser.regtype, &b->domain);
LogInfo("add_domain_to_browser: calling external_start_browsing_for_service()");
- external_start_browsing_for_service(info->u.browser.interface_id, &tmp, kDNSType_PTR, info->flags, &b->q);
+ external_start_browsing_for_service(info->u.browser.interface_id, &tmp, kDNSType_PTR, info->flags);
}
}
return err;
@@ -2380,10 +2195,12 @@ mDNSlocal void browse_termination_callback(request_state *info)
external_stop_browsing_for_service(ptr->q.InterfaceID, &tmp, kDNSType_PTR, ptr->q.flags);
}
+ LogOperation("%3d: DNSServiceBrowse(%X, %d, \"%##s\") STOP PID[%d](%s)",
+ info->sd, info->flags, info->interfaceIndex, ptr->q.qname.c, info->process_id, info->pid_name);
+
info->u.browser.browsers = ptr->next;
- LogOperation("%3d: DNSServiceBrowse(%##s) STOP PID[%d](%s)", info->sd, ptr->q.qname.c, info->process_id, info->pid_name);
mDNS_StopBrowse(&mDNSStorage, &ptr->q); // no need to error-check result
- LogMcastQ(&mDNSStorage, &ptr->q, info, q_stop);
+ LogMcastQ(&ptr->q, info, q_stop);
freeL("browser_t/browse_termination_callback", ptr);
}
}
@@ -2617,7 +2434,7 @@ mDNSexport void udsserver_handle_configchange(mDNS *const m)
// Let the platform layer get the current DNS information
mDNS_Lock(m);
- mDNSPlatformSetDNSConfig(m, mDNSfalse, mDNSfalse, mDNSNULL, &RegDomains, &BrowseDomains, mDNSfalse);
+ mDNSPlatformSetDNSConfig(mDNSfalse, mDNSfalse, mDNSNULL, &RegDomains, &BrowseDomains, mDNSfalse);
mDNS_Unlock(m);
// Any automatic registration domains are also implicitly automatic browsing domains
@@ -2759,7 +2576,7 @@ mDNSlocal mStatus handle_browse_request(request_state *request)
request->u.browser.browsers = NULL;
LogOperation("%3d: DNSServiceBrowse(%X, %d, \"%##s\", \"%s\") START PID[%d](%s)",
- request->sd, request->flags, interfaceIndex, request->u.browser.regtype.c, domain, request->process_id, request->pid_name);
+ request->sd, request->flags, interfaceIndex, request->u.browser.regtype.c, domain, request->process_id, request->pid_name);
if (request->u.browser.default_domain)
{
@@ -2822,7 +2639,9 @@ mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, con
(answer->RecordType == kDNSRecordTypePacketNegative) ? kDNSServiceErr_NoSuchRecord : kDNSServiceErr_NoError;
(void)m; // Unused
- LogOperation("%3d: DNSServiceResolve(%##s) %s %s", req->sd, question->qname.c, AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer));
+ LogOperation("%3d: DNSServiceResolve(%##s) %s interface %d: %s",
+ req->sd, question->qname.c, AddRecord ? "ADD" : "RMV",
+ mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse), RRDisplayString(m, answer));
if (!AddRecord)
{
@@ -2872,10 +2691,11 @@ mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, con
mDNSlocal void resolve_termination_callback(request_state *request)
{
- LogOperation("%3d: DNSServiceResolve(%##s) STOP PID[%d](%s)", request->sd, request->u.resolve.qtxt.qname.c, request->process_id, request->pid_name);
+ LogOperation("%3d: DNSServiceResolve(%X, %d, \"%##s\") STOP PID[%d](%s)",
+ request->sd, request->flags, request->interfaceIndex, request->u.resolve.qtxt.qname.c, request->process_id, request->pid_name);
mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qtxt);
mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv);
- LogMcastQ(&mDNSStorage, &request->u.resolve.qsrv, request, q_stop);
+ LogMcastQ(&request->u.resolve.qsrv, request, q_stop);
if (request->u.resolve.external_advertise)
external_stop_resolving_service(request->u.resolve.qsrv.InterfaceID, &request->u.resolve.qsrv.qname, request->flags);
}
@@ -2931,6 +2751,15 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
mDNSPlatformMemZero(&request->u.resolve, sizeof(request->u.resolve));
+#if APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
+ // Determine if this request should be promoted to use BLE triggered discovery.
+ if (shouldUseBLE(InterfaceID, 0, (domainname *)SkipLeadingLabels(&fqdn, 1), &fqdn))
+ {
+ flags |= (kDNSServiceFlagsAutoTrigger | kDNSServiceFlagsIncludeAWDL);
+ LogInfo("handle_resolve_request: request promoted to use kDNSServiceFlagsAutoTrigger");
+ }
+#endif // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
+
request->flags = flags;
request->interfaceIndex = interfaceIndex;
@@ -2998,8 +2827,9 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
#endif
// ask the questions
- LogOperation("%3d: DNSServiceResolve(%X %d %##s) START PID[%d](%s)", request->sd, flags, interfaceIndex,
+ LogOperation("%3d: DNSServiceResolve(%X, %d, \"%##s\") START PID[%d](%s)", request->sd, flags, interfaceIndex,
request->u.resolve.qsrv.qname.c, request->process_id, request->pid_name);
+
err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qsrv);
if (!err)
@@ -3012,7 +2842,7 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
else
{
request->terminate = resolve_termination_callback;
- LogMcastQ(&mDNSStorage, &request->u.resolve.qsrv, request, q_start);
+ LogMcastQ(&request->u.resolve.qsrv, request, q_start);
if (callExternalHelpers(InterfaceID, &fqdn, flags))
{
request->u.resolve.external_advertise = mDNStrue;
@@ -3039,7 +2869,7 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
// Returns -1 to tell the caller that it should not try to reissue the query anymore
// Returns 1 on successfully appending a search domain and the caller should reissue the new query
// Returns 0 when there are no more search domains and the caller should reissue the query
-mDNSlocal int AppendNewSearchDomain(mDNS *const m, DNSQuestion *question)
+mDNSlocal int AppendNewSearchDomain(DNSQuestion *question)
{
domainname *sd;
mStatus err;
@@ -3068,7 +2898,7 @@ mDNSlocal int AppendNewSearchDomain(mDNS *const m, DNSQuestion *question)
LogInfo("AppendSearchDomain: qnameOrig %##s", question->qnameOrig->c);
}
- sd = uDNS_GetNextSearchDomain(m, question->InterfaceID, &question->SearchListIndex, !question->AppendLocalSearchDomains);
+ sd = uDNS_GetNextSearchDomain(question->InterfaceID, &question->SearchListIndex, !question->AppendLocalSearchDomains);
// We use -1 to indicate that we have searched all the domains and should try the single label
// query directly on the wire. uDNS_GetNextSearchDomain should never return a negative value
if (question->SearchListIndex == -1)
@@ -3088,7 +2918,7 @@ mDNSlocal int AppendNewSearchDomain(mDNS *const m, DNSQuestion *question)
// without appending search domains, then we are done.
if (!sd && !ApplySearchDomainsFirst(question))
{
- LogInfo("AppnedNewSearchDomain: No more search domains for question with name %##s (%s), not trying anymore", question->qname.c, DNSTypeName(question->qtype));
+ LogInfo("AppendNewSearchDomain: No more search domains for question with name %##s (%s), not trying anymore", question->qname.c, DNSTypeName(question->qtype));
return -1;
}
@@ -3139,7 +2969,7 @@ mDNSlocal mDNSBool DomainInSearchList(const domainname *domain, mDNSBool exclude
}
// The caller already checks that this is a dotlocal question.
-mDNSlocal mDNSBool ShouldDeliverNegativeResponse(mDNS *const m, DNSQuestion *question)
+mDNSlocal mDNSBool ShouldDeliverNegativeResponse(DNSQuestion *question)
{
mDNSu16 qtype;
@@ -3165,7 +2995,7 @@ mDNSlocal mDNSBool ShouldDeliverNegativeResponse(mDNS *const m, DNSQuestion *que
return mDNSfalse;
}
qtype = (question->qtype == kDNSType_A ? kDNSType_AAAA : kDNSType_A);
- if (!mDNS_CheckForCacheRecord(m, question, qtype))
+ if (!mDNS_CheckForCacheRecord(&mDNSStorage, question, qtype))
{
LogOperation("ShouldDeliverNegativeResponse:Question %##s (%s) not answering local question with negative unicast response"
" (can't find positive record)", question->qname.c, DNSTypeName(question->qtype));
@@ -3289,7 +3119,7 @@ mDNSlocal mStatus SendAdditionalQuery(DNSQuestion *q, request_state *request, mS
#endif // APPLE_OSX_mDNSResponder
// This function tries to append a search domain if valid and possible. If so, returns true.
-mDNSlocal mDNSBool RetryQuestionWithSearchDomains(mDNS *const m, DNSQuestion *question, request_state *req, QC_result AddRecord)
+mDNSlocal mDNSBool RetryQuestionWithSearchDomains(DNSQuestion *question, request_state *req, QC_result AddRecord)
{
int result;
// RetryWithSearchDomains tells the core to call us back so that we can retry with search domains if there is no
@@ -3303,7 +3133,7 @@ mDNSlocal mDNSBool RetryQuestionWithSearchDomains(mDNS *const m, DNSQuestion *qu
if ((AddRecord != QC_suppressed) && question->SearchListIndex != -1 && question->AppendSearchDomains)
{
question->RetryWithSearchDomains = 0;
- result = AppendNewSearchDomain(m, question);
+ result = AppendNewSearchDomain(question);
// As long as the result is either zero or 1, we retry the question. If we exahaust the search
// domains (result is zero) we try the original query (as it was before appending the search
// domains) as such on the wire as a last resort if we have not tried them before. For queries
@@ -3312,7 +3142,7 @@ mDNSlocal mDNSBool RetryQuestionWithSearchDomains(mDNS *const m, DNSQuestion *qu
if (result != -1)
{
mStatus err;
- err = mDNS_StartQuery(m, question);
+ err = mDNS_StartQuery(&mDNSStorage, question);
if (!err)
{
LogOperation("%3d: RetryQuestionWithSearchDomains(%##s, %s), retrying after appending search domain", req->sd, question->qname.c, DNSTypeName(question->qtype));
@@ -3348,9 +3178,10 @@ mDNSlocal void queryrecord_result_reply(mDNS *const m, request_state *req, DNSQu
ConvertDomainNameToCString(answer->name, name);
- LogOperation("%3d: %s(%##s, %s) %s %s", req->sd,
+ LogOperation("%3d: %s(%##s, %s) RESULT %s interface %d: %s", req->sd,
req->hdr.op == query_request ? "DNSServiceQueryRecord" : "DNSServiceGetAddrInfo",
- question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer));
+ question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV",
+ mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse), RRDisplayString(m, answer));
len = sizeof(DNSServiceFlags); // calculate reply data length
len += sizeof(mDNSu32); // interface index
@@ -3597,7 +3428,7 @@ mDNSlocal void queryrecord_result_callback(mDNS *const m, DNSQuestion *question,
// As we ignore negative unicast answers below, we would never reach the code where the search domains are appended.
// To keep things simple, we handle unicast ".local" separately here.
LogInfo("queryrecord_result_callback: Retrying .local question %##s (%s) as unicast after appending search domains", question->qname.c, DNSTypeName(question->qtype));
- if (RetryQuestionWithSearchDomains(m, question, req, AddRecord))
+ if (RetryQuestionWithSearchDomains(question, req, AddRecord))
return;
if (question->AppendSearchDomains && !question->AppendLocalSearchDomains && IsLocalDomain(&question->qname))
{
@@ -3661,7 +3492,7 @@ mDNSlocal void queryrecord_result_callback(mDNS *const m, DNSQuestion *question,
return;
}
#if APPLE_OSX_mDNSResponder
- if (!ShouldDeliverNegativeResponse(m, question))
+ if (!ShouldDeliverNegativeResponse(question))
{
return;
}
@@ -3687,7 +3518,7 @@ mDNSlocal void queryrecord_result_callback(mDNS *const m, DNSQuestion *question,
// normally happen just once because after we append .local, we ignore all negative
// responses for .local above.
LogInfo("queryrecord_result_callback: Retrying question %##s (%s) after appending search domains", question->qname.c, DNSTypeName(question->qtype));
- if (RetryQuestionWithSearchDomains(m, question, req, AddRecord))
+ if (RetryQuestionWithSearchDomains(question, req, AddRecord))
{
// Note: We need to call SendAdditionalQuery every time after appending a search domain as .local could
// be anywhere in the search domain list.
@@ -3705,12 +3536,12 @@ mDNSlocal void queryrecord_result_callback(mDNS *const m, DNSQuestion *question,
mDNSlocal void queryrecord_termination_callback(request_state *request)
{
- LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP PID[%d](%s)",
- request->sd, request->u.queryrecord.q.qname.c, DNSTypeName(request->u.queryrecord.q.qtype), request->process_id, request->pid_name);
+ LogOperation("%3d: DNSServiceQueryRecord(%X, %d, %##s, %s) STOP PID[%d](%s)",
+ request->sd, request->flags, request->interfaceIndex, request->u.queryrecord.q.qname.c, DNSTypeName(request->u.queryrecord.q.qtype), request->process_id, request->pid_name);
if (request->u.queryrecord.q.QuestionContext)
{
mDNS_StopQuery(&mDNSStorage, &request->u.queryrecord.q); // no need to error check
- LogMcastQ(&mDNSStorage, &request->u.queryrecord.q, request, q_stop);
+ LogMcastQ(&request->u.queryrecord.q, request, q_stop);
request->u.queryrecord.q.QuestionContext = mDNSNULL;
}
else
@@ -3725,10 +3556,10 @@ mDNSlocal void queryrecord_termination_callback(request_state *request)
request->u.queryrecord.q.qnameOrig = mDNSNULL;
}
- if (callExternalHelpers(request->u.queryrecord.q.InterfaceID, &request->u.queryrecord.q.qname, request->flags))
+ if (callExternalHelpers(request->u.queryrecord.q.InterfaceID, &request->u.queryrecord.q.qname, request->u.queryrecord.q.flags))
{
LogInfo("queryrecord_termination_callback: calling external_stop_browsing_for_service()");
- external_stop_browsing_for_service(request->u.queryrecord.q.InterfaceID, &request->u.queryrecord.q.qname, request->u.queryrecord.q.qtype, request->flags);
+ external_stop_browsing_for_service(request->u.queryrecord.q.InterfaceID, &request->u.queryrecord.q.qname, request->u.queryrecord.q.qtype, request->u.queryrecord.q.flags);
}
if (request->u.queryrecord.q2)
{
@@ -3736,7 +3567,7 @@ mDNSlocal void queryrecord_termination_callback(request_state *request)
{
LogInfo("queryrecord_termination_callback: Stopping q2 %##s", request->u.queryrecord.q2->qname.c);
mDNS_StopQuery(&mDNSStorage, request->u.queryrecord.q2);
- LogMcastQ(&mDNSStorage, request->u.queryrecord.q2, request, q_stop);
+ LogMcastQ(request->u.queryrecord.q2, request, q_stop);
}
else
{
@@ -3764,7 +3595,7 @@ mDNSlocal void queryrecord_termination_callback(request_state *request)
v4q = &request->u.queryrecord.q;
else if (request->u.queryrecord.q.qtype == kDNSType_AAAA)
v6q = &request->u.queryrecord.q;
- mDNSPlatformTriggerDNSRetry(&mDNSStorage, v4q, v6q);
+ mDNSPlatformTriggerDNSRetry(v4q, v6q);
}
}
#endif // APPLE_OSX_mDNSResponder
@@ -3842,6 +3673,7 @@ mDNSlocal mStatus handle_queryrecord_request(request_state *request)
q->QuestionCallback = queryrecord_result_callback;
q->QuestionContext = request;
q->SearchListIndex = 0;
+ q->StopTime = 0;
q->DNSSECAuthInfo = mDNSNULL;
q->DAIFreeCallback = mDNSNULL;
@@ -3881,8 +3713,18 @@ mDNSlocal mStatus handle_queryrecord_request(request_state *request)
q->qnameOrig = mDNSNULL;
SetQuestionPolicy(q, request);
+#if APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
+ // Determine if this request should be promoted to use BLE triggered discovery.
+ if (shouldUseBLE(InterfaceID, rrtype, (domainname *)SkipLeadingLabels(&q->qname, 1), &q->qname))
+ {
+ q->flags |= (kDNSServiceFlagsAutoTrigger | kDNSServiceFlagsIncludeAWDL);
+ request->flags |= (kDNSServiceFlagsAutoTrigger | kDNSServiceFlagsIncludeAWDL);
+ LogInfo("handle_queryrecord_request: request promoted to use kDNSServiceFlagsAutoTrigger");
+ }
+#endif // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
+
LogOperation("%3d: DNSServiceQueryRecord(%X, %d, %##s, %s) START PID[%d](%s)",
- request->sd, flags, interfaceIndex, q->qname.c, DNSTypeName(q->qtype), request->process_id, request->pid_name);
+ request->sd, request->flags, interfaceIndex, q->qname.c, DNSTypeName(q->qtype), request->process_id, request->pid_name);
err = mDNS_StartQuery(&mDNSStorage, q);
if (err)
@@ -3892,11 +3734,11 @@ mDNSlocal mStatus handle_queryrecord_request(request_state *request)
else
{
request->terminate = queryrecord_termination_callback;
- LogMcastQ(&mDNSStorage, q, request, q_start);
- if (callExternalHelpers(q->InterfaceID, &q->qname, flags))
+ LogMcastQ(q, request, q_start);
+ if (callExternalHelpers(q->InterfaceID, &q->qname, q->flags))
{
LogInfo("handle_queryrecord_request: calling external_start_browsing_for_service()");
- external_start_browsing_for_service(q->InterfaceID, &q->qname, q->qtype, flags, q);
+ external_start_browsing_for_service(q->InterfaceID, &q->qname, q->qtype, q->flags);
}
}
@@ -3984,7 +3826,7 @@ mDNSlocal void enum_result_callback(mDNS *const m,
reply = format_enumeration_reply(request, domain, flags, kDNSServiceInterfaceIndexAny, kDNSServiceErr_NoError);
if (!reply) { LogMsg("ERROR: enum_result_callback, format_enumeration_reply"); return; }
- LogOperation("%3d: DNSServiceEnumerateDomains(%#2s) RESULT %s: %s", request->sd, question->qname.c, AddRecord ? "Add" : "Rmv", domain);
+ LogOperation("%3d: DNSServiceEnumerateDomains(%#2s) RESULT %s: %s", request->sd, question->qname.c, AddRecord ? "ADD" : "RMV", domain);
append_reply(request, reply);
}
@@ -4071,10 +3913,11 @@ mDNSlocal mStatus handle_reconfirm_request(request_state *request)
status = mDNS_ReconfirmByValue(&mDNSStorage, &rr->resrec);
LogOperation(
(status == mStatus_NoError) ?
- "%3d: DNSServiceReconfirmRecord(%s) interface %d initiated" :
- "%3d: DNSServiceReconfirmRecord(%s) interface %d failed: %d",
+ "%3d: DNSServiceReconfirmRecord(%s) interface %d initiated PID[%d](%s)" :
+ "%3d: DNSServiceReconfirmRecord(%s) interface %d failed PID[%d](%s) status %d",
request->sd, RRDisplayString(&mDNSStorage, &rr->resrec),
- mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, rr->resrec.InterfaceID, mDNSfalse), status);
+ mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, rr->resrec.InterfaceID, mDNSfalse),
+ request->process_id, request->pid_name, status);
freeL("AuthRecord/handle_reconfirm_request", rr);
}
return(status);
@@ -4410,7 +4253,7 @@ mDNSlocal void addrinfo_termination_callback(request_state *request)
if (request->u.addrinfo.q4.QuestionContext)
{
mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q4);
- LogMcastQ(&mDNSStorage, &request->u.addrinfo.q4, request, q_stop);
+ LogMcastQ(&request->u.addrinfo.q4, request, q_stop);
request->u.addrinfo.q4.QuestionContext = mDNSNULL;
if (callExternalHelpers(request->u.addrinfo.interface_id, &request->u.addrinfo.q4.qname, request->flags))
@@ -4430,7 +4273,7 @@ mDNSlocal void addrinfo_termination_callback(request_state *request)
{
LogInfo("addrinfo_termination_callback: Stopping q42 %##s", request->u.addrinfo.q42->qname.c);
mDNS_StopQuery(&mDNSStorage, request->u.addrinfo.q42);
- LogMcastQ(&mDNSStorage, request->u.addrinfo.q42, request, q_stop);
+ LogMcastQ(request->u.addrinfo.q42, request, q_stop);
}
if (request->u.addrinfo.q42->qnameOrig)
{
@@ -4445,7 +4288,7 @@ mDNSlocal void addrinfo_termination_callback(request_state *request)
if (request->u.addrinfo.q6.QuestionContext)
{
mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q6);
- LogMcastQ(&mDNSStorage, &request->u.addrinfo.q6, request, q_stop);
+ LogMcastQ(&request->u.addrinfo.q6, request, q_stop);
request->u.addrinfo.q6.QuestionContext = mDNSNULL;
if (callExternalHelpers(request->u.addrinfo.interface_id, &request->u.addrinfo.q6.qname, request->flags))
@@ -4465,7 +4308,7 @@ mDNSlocal void addrinfo_termination_callback(request_state *request)
{
LogInfo("addrinfo_termination_callback: Stopping q62 %##s", request->u.addrinfo.q62->qname.c);
mDNS_StopQuery(&mDNSStorage, request->u.addrinfo.q62);
- LogMcastQ(&mDNSStorage, request->u.addrinfo.q62, request, q_stop);
+ LogMcastQ(request->u.addrinfo.q62, request, q_stop);
}
if (request->u.addrinfo.q62->qnameOrig)
{
@@ -4487,7 +4330,7 @@ mDNSlocal void addrinfo_termination_callback(request_state *request)
// valid response again.
if (request->u.addrinfo.q4.TimeoutQuestion && !request->u.addrinfo.v4ans)
{
- mDNSPlatformUpdateDNSStatus(&mDNSStorage, &request->u.addrinfo.q4);
+ mDNSPlatformUpdateDNSStatus(&request->u.addrinfo.q4);
}
// If we have a v4 answer and if we timed out prematurely before, provide
// a trigger to the upper layer so that it can retry questions if needed.
@@ -4498,12 +4341,12 @@ mDNSlocal void addrinfo_termination_callback(request_state *request)
{
if (request->u.addrinfo.q6.TimeoutQuestion && !request->u.addrinfo.v6ans)
{
- mDNSPlatformUpdateDNSStatus(&mDNSStorage, &request->u.addrinfo.q6);
+ mDNSPlatformUpdateDNSStatus(&request->u.addrinfo.q6);
}
if (request->u.addrinfo.v6ans)
v6q = &request->u.addrinfo.q6;
}
- mDNSPlatformTriggerDNSRetry(&mDNSStorage, v4q, v6q);
+ mDNSPlatformTriggerDNSRetry(v4q, v6q);
}
#endif // APPLE_OSX_mDNSResponder
}
@@ -4606,6 +4449,8 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request)
SetQuestionPolicy(&request->u.addrinfo.q4, request);
SetQuestionPolicy(&request->u.addrinfo.q6, request);
+ request->u.addrinfo.q4.StopTime = request->u.addrinfo.q6.StopTime = 0;
+
request->u.addrinfo.q4.DNSSECAuthInfo = request->u.addrinfo.q6.DNSSECAuthInfo = mDNSNULL;
request->u.addrinfo.q4.DAIFreeCallback = request->u.addrinfo.q6.DAIFreeCallback = mDNSNULL;
@@ -4649,11 +4494,11 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request)
if (!err)
{
request->terminate = addrinfo_termination_callback;
- LogMcastQ(&mDNSStorage, &request->u.addrinfo.q6, request, q_start);
+ LogMcastQ(&request->u.addrinfo.q6, request, q_start);
if (callExternalHelpers(InterfaceID, &d, flags))
{
LogInfo("handle_addrinfo_request: calling external_start_browsing_for_service() for kDNSServiceType_AAAA record");
- external_start_browsing_for_service(InterfaceID, &d, kDNSServiceType_AAAA, flags, &request->u.addrinfo.q6);
+ external_start_browsing_for_service(InterfaceID, &d, kDNSServiceType_AAAA, flags);
}
}
}
@@ -4705,11 +4550,11 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request)
if (!err)
{
request->terminate = addrinfo_termination_callback;
- LogMcastQ(&mDNSStorage, &request->u.addrinfo.q4, request, q_start);
+ LogMcastQ(&request->u.addrinfo.q4, request, q_start);
if (callExternalHelpers(InterfaceID, &d, flags))
{
LogInfo("handle_addrinfo_request: calling external_start_browsing_for_service() for kDNSServiceType_A record");
- external_start_browsing_for_service(InterfaceID, &d, kDNSServiceType_A, flags, &request->u.addrinfo.q4);
+ external_start_browsing_for_service(InterfaceID, &d, kDNSServiceType_A, flags);
}
}
}
@@ -4831,7 +4676,7 @@ mDNSlocal void read_msg(request_state *req)
{
dnssd_sock_t x = *(dnssd_sock_t *)CMSG_DATA(cmsg);
LogOperation("%3d: Got len %d, BPF %d", req->sd, cmsg->cmsg_len, x);
- mDNSPlatformReceiveBPF_fd(&mDNSStorage, x);
+ mDNSPlatformReceiveBPF_fd(x);
}
else
#endif // APPLE_OSX_mDNSResponder
@@ -4933,6 +4778,52 @@ rerror:
req->ts = t_error;
}
+mDNSlocal mStatus handle_client_request(request_state *req)
+{
+ mStatus err = mStatus_NoError;
+ switch(req->hdr.op)
+ {
+ // These are all operations that have their own first-class request_state object
+ case connection_request:
+ LogOperation("%3d: DNSServiceCreateConnection START PID[%d](%s)",
+ req->sd, req->process_id, req->pid_name);
+ req->terminate = connection_termination;
+ break;
+ case connection_delegate_request:
+ LogOperation("%3d: DNSServiceCreateDelegateConnection START PID[%d](%s)",
+ req->sd, req->process_id, req->pid_name);
+ req->terminate = connection_termination;
+ handle_connection_delegate_request(req);
+ break;
+ case resolve_request: err = handle_resolve_request (req); break;
+ case query_request: err = handle_queryrecord_request (req); break;
+ case browse_request: err = handle_browse_request (req); break;
+ case reg_service_request: err = handle_regservice_request (req); break;
+ case enumeration_request: err = handle_enum_request (req); break;
+ case reconfirm_record_request: err = handle_reconfirm_request (req); break;
+ case setdomain_request: err = handle_setdomain_request (req); break;
+ case getproperty_request: handle_getproperty_request (req); break;
+ case getpid_request: handle_getpid_request (req); break;
+ case port_mapping_request: err = handle_port_mapping_request(req); break;
+ case addrinfo_request: err = handle_addrinfo_request (req); break;
+ case send_bpf: /* Do nothing for send_bpf */ break;
+
+ // These are all operations that work with an existing request_state object
+ case reg_record_request: err = handle_regrecord_request (req); break;
+ case add_record_request: err = handle_add_request (req); break;
+ case update_record_request: err = handle_update_request (req); break;
+ case remove_record_request: err = handle_removerecord_request(req); break;
+ case cancel_request: handle_cancel_request (req); break;
+ case release_request: err = handle_release_request (req); break;
+ default: LogMsg("request_callback: %3d:ERROR: Unsupported UDS req:%d PID[%d][%s]",
+ req->sd, req->hdr.op, req->process_id, req->pid_name);
+ err = mStatus_BadParamErr;
+ break;
+ }
+
+ return err;
+}
+
#define RecordOrientedOp(X) \
((X) == reg_record_request || (X) == add_record_request || (X) == update_record_request || (X) == remove_record_request)
@@ -5022,12 +4913,8 @@ mDNSlocal void request_callback(int fd, short filter, void *info)
// relevant bits
if (req->validUUID)
{
- int i;
newreq->validUUID = mDNStrue;
- for (i = 0; i < UUID_SIZE; i++)
- {
- newreq->uuid[i] = req->uuid[i];
- }
+ mDNSPlatformMemCopy(newreq->uuid, req->uuid, UUID_SIZE);
}
else
{
@@ -5050,44 +4937,10 @@ mDNSlocal void request_callback(int fd, short filter, void *info)
// If we're shutting down, don't allow new client requests
// We do allow "cancel" and "getproperty" during shutdown
if (mDNSStorage.ShutdownTime && req->hdr.op != cancel_request && req->hdr.op != getproperty_request)
- {
err = mStatus_ServiceNotRunning;
- }
else
- {
- switch(req->hdr.op)
- {
- // These are all operations that have their own first-class request_state object
- case connection_request:
- LogOperation("%3d: DNSServiceCreateConnection START PID[%d](%s)",
- req->sd, req->process_id, req->pid_name);
- req->terminate = connection_termination;
- break;
- case connection_delegate_request: handle_connection_delegate_request(req); break;
- case resolve_request: err = handle_resolve_request (req); break;
- case query_request: err = handle_queryrecord_request (req); break;
- case browse_request: err = handle_browse_request (req); break;
- case reg_service_request: err = handle_regservice_request (req); break;
- case enumeration_request: err = handle_enum_request (req); break;
- case reconfirm_record_request: err = handle_reconfirm_request (req); break;
- case setdomain_request: err = handle_setdomain_request (req); break;
- case getproperty_request: handle_getproperty_request (req); break;
- case getpid_request: handle_getpid_request (req); break;
- case port_mapping_request: err = handle_port_mapping_request(req); break;
- case addrinfo_request: err = handle_addrinfo_request (req); break;
- case send_bpf: /* Do nothing for send_bpf */ break;
-
- // These are all operations that work with an existing request_state object
- case reg_record_request: err = handle_regrecord_request (req); break;
- case add_record_request: err = handle_add_request (req); break;
- case update_record_request: err = handle_update_request (req); break;
- case remove_record_request: err = handle_removerecord_request(req); break;
- case cancel_request: handle_cancel_request (req); break;
- case release_request: err = handle_release_request (req); break;
- default: LogMsg("request_callback: %3d:ERROR: Unsupported UDS req:%d PID[%d][%s]",
- req->sd, req->hdr.op, req->process_id, req->pid_name); break;
- }
- }
+ err = handle_client_request(req);
+
// req->msgbuf may be NULL, e.g. for connection_request or remove_record_request
if (req->msgbuf) freeL("request_state msgbuf", req->msgbuf);
@@ -5371,7 +5224,7 @@ mDNSexport int udsserver_exit(void)
return 0;
}
-mDNSlocal void LogClientInfo(mDNS *const m, request_state *req)
+mDNSlocal void LogClientInfo(request_state *req)
{
char prefix[16];
if (req->primary)
@@ -5393,8 +5246,8 @@ mDNSlocal void LogClientInfo(mDNS *const m, request_state *req)
req->process_id, req->pid_name);
for (p = req->u.reg_recs; p; p=p->next)
LogMsgNoIdent(" -> DNSServiceRegisterRecord 0x%08X %2d %3d %s PID[%d](%s)",
- req->flags, req->interfaceIndex, p->key, ARDisplayString(m, p->rr), req->process_id, req->pid_name);
- for (r = req->next; r; r=r->next) if (r->primary == req) LogClientInfo(m, r);
+ req->flags, req->interfaceIndex, p->key, ARDisplayString(&mDNSStorage, p->rr), req->process_id, req->pid_name);
+ for (r = req->next; r; r=r->next) if (r->primary == req) LogClientInfo(r);
}
else if (req->terminate == regservice_termination_callback)
{
@@ -5595,7 +5448,7 @@ mDNSlocal char *RecordTypeName(mDNSu8 rtype)
}
}
-mDNSlocal void LogEtcHosts(mDNS *const m)
+mDNSlocal int LogEtcHosts(mDNS *const m)
{
mDNSBool showheader = mDNStrue;
const AuthRecord *ar;
@@ -5631,6 +5484,7 @@ mDNSlocal void LogEtcHosts(mDNS *const m)
if (showheader) LogMsgNoIdent("<None>");
else if (truncated) LogMsgNoIdent("<Truncated: to 50 records, Total records %d, Total Auth Groups %d, Auth Slots %d>", count, m->rrauth.rrauth_totalused, authslot);
+ return count;
}
mDNSlocal void LogLocalOnlyAuthRecords(mDNS *const m)
@@ -5674,7 +5528,7 @@ mDNSlocal char *AnonInfoToString(AnonymousInfo *ai, char *anonstr, int anstrlen)
return anonstr;
}
-mDNSlocal void LogOneAuthRecord(mDNS *const m, const AuthRecord *ar, mDNSs32 now, const char *const ifname)
+mDNSlocal void LogOneAuthRecord(const AuthRecord *ar, mDNSs32 now, const char *const ifname)
{
char anstr[256];
if (AuthRecord_uDNS(ar))
@@ -5686,7 +5540,7 @@ mDNSlocal void LogOneAuthRecord(mDNS *const m, const AuthRecord *ar, mDNSs32 now
"-U-",
ar->state,
ar->AllowRemoteQuery ? "☠" : " ",
- ARDisplayString(m, ar));
+ ARDisplayString(&mDNSStorage, ar));
}
else
{
@@ -5697,18 +5551,18 @@ mDNSlocal void LogOneAuthRecord(mDNS *const m, const AuthRecord *ar, mDNSs32 now
ifname ? ifname : "ALL",
ar->resrec.RecordType,
ar->AllowRemoteQuery ? "☠" : " ",
- ARDisplayString(m, ar), AnonInfoToString(ar->resrec.AnonInfo, anstr, sizeof(anstr)));
+ ARDisplayString(&mDNSStorage, ar), AnonInfoToString(ar->resrec.AnonInfo, anstr, sizeof(anstr)));
}
}
-mDNSlocal void LogAuthRecords(mDNS *const m, const mDNSs32 now, AuthRecord *ResourceRecords, int *proxy)
+mDNSlocal void LogAuthRecords(const mDNSs32 now, AuthRecord *ResourceRecords, int *proxy)
{
mDNSBool showheader = mDNStrue;
const AuthRecord *ar;
OwnerOptData owner = zeroOwner;
for (ar = ResourceRecords; ar; ar=ar->next)
{
- const char *const ifname = InterfaceNameForID(m, ar->resrec.InterfaceID);
+ const char *const ifname = InterfaceNameForID(&mDNSStorage, ar->resrec.InterfaceID);
if ((ar->WakeUp.HMAC.l[0] != 0) == (proxy != mDNSNULL))
{
if (showheader) { showheader = mDNSfalse; LogMsgNoIdent(" Int Next Expire if State"); }
@@ -5725,22 +5579,22 @@ mDNSlocal void LogAuthRecords(mDNS *const m, const mDNSs32 now, AuthRecord *Reso
}
if (AuthRecord_uDNS(ar))
{
- LogOneAuthRecord(m, ar, now, ifname);
+ LogOneAuthRecord(ar, now, ifname);
}
else if (ar->ARType == AuthRecordLocalOnly)
{
- LogMsgNoIdent(" LO %s", ARDisplayString(m, ar));
+ LogMsgNoIdent(" LO %s", ARDisplayString(&mDNSStorage, ar));
}
else if (ar->ARType == AuthRecordP2P)
{
if (ar->resrec.InterfaceID == mDNSInterface_BLE)
- LogMsgNoIdent(" BLE %s", ARDisplayString(m, ar));
+ LogMsgNoIdent(" BLE %s", ARDisplayString(&mDNSStorage, ar));
else
- LogMsgNoIdent(" PP %s", ARDisplayString(m, ar));
+ LogMsgNoIdent(" PP %s", ARDisplayString(&mDNSStorage, ar));
}
else
{
- LogOneAuthRecord(m, ar, now, ifname);
+ LogOneAuthRecord(ar, now, ifname);
if (ar->resrec.AnonInfo)
{
ResourceRecord *nsec3 = ar->resrec.AnonInfo->nsec3RR;
@@ -5751,7 +5605,7 @@ mDNSlocal void LogAuthRecords(mDNS *const m, const mDNSs32 now, AuthRecord *Reso
ar->AnnounceCount ? (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond : 0,
ar->TimeExpire ? (ar->TimeExpire - now) / mDNSPlatformOneSecond : 0,
ifname ? ifname : "ALL",
- RRDisplayString(m, nsec3));
+ RRDisplayString(&mDNSStorage, nsec3));
}
}
}
@@ -5759,7 +5613,7 @@ mDNSlocal void LogAuthRecords(mDNS *const m, const mDNSs32 now, AuthRecord *Reso
if (showheader) LogMsgNoIdent("<None>");
}
-mDNSlocal void PrintOneCacheRecord(mDNS *const m, const CacheRecord *cr, mDNSu32 slot, const mDNSu32 remain, const char *ifname, mDNSu32 *CacheUsed)
+mDNSlocal void PrintOneCacheRecord(const CacheRecord *cr, mDNSu32 slot, const mDNSu32 remain, const char *ifname, mDNSu32 *CacheUsed)
{
LogMsgNoIdent("%3d %s%8d %-7s%s %-6s%s",
slot,
@@ -5769,11 +5623,11 @@ mDNSlocal void PrintOneCacheRecord(mDNS *const m, const CacheRecord *cr, mDNSu32
(cr->resrec.RecordType == kDNSRecordTypePacketNegative) ? "-" :
(cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? " " : "+",
DNSTypeName(cr->resrec.rrtype),
- CRDisplayString(m, cr));
+ CRDisplayString(&mDNSStorage, cr));
(*CacheUsed)++;
}
-mDNSlocal void PrintCachedRecords(mDNS *const m, const CacheRecord *cr, mDNSu32 slot, const mDNSu32 remain, const char *ifname, mDNSu32 *CacheUsed)
+mDNSlocal void PrintCachedRecords(const CacheRecord *cr, mDNSu32 slot, const mDNSu32 remain, const char *ifname, mDNSu32 *CacheUsed)
{
CacheRecord *nsec;
CacheRecord *soa;
@@ -5783,13 +5637,13 @@ mDNSlocal void PrintCachedRecords(mDNS *const m, const CacheRecord *cr, mDNSu32
// their own lifetime. If the main cache record expires, they also expire.
while (nsec)
{
- PrintOneCacheRecord(m, nsec, slot, remain, ifname, CacheUsed);
+ PrintOneCacheRecord(nsec, slot, remain, ifname, CacheUsed);
nsec = nsec->next;
}
soa = cr->soa;
if (soa)
{
- PrintOneCacheRecord(m, soa, slot, remain, ifname, CacheUsed);
+ PrintOneCacheRecord(soa, slot, remain, ifname, CacheUsed);
}
if (cr->resrec.AnonInfo)
{
@@ -5806,7 +5660,7 @@ mDNSlocal void PrintCachedRecords(mDNS *const m, const CacheRecord *cr, mDNSu32
(nsec3->RecordType == kDNSRecordTypePacketNegative) ? "-" :
(nsec3->RecordType & kDNSRecordTypePacketUniqueMask) ? " " : "+",
DNSTypeName(nsec3->rrtype),
- RRDisplayString(m, nsec3));
+ RRDisplayString(&mDNSStorage, nsec3));
}
}
}
@@ -5873,11 +5727,15 @@ mDNSexport void LogMDNSStatistics(mDNS *const m)
LogMsgNoIdent("Wakeup on Resolves %u", m->mDNSStats.WakeOnResolves);
}
-mDNSexport void udsserver_info(mDNS *const m)
+mDNSexport void udsserver_info()
{
+ mDNS *const m = &mDNSStorage;
const mDNSs32 now = mDNS_TimeNow(m);
mDNSu32 CacheUsed = 0, CacheActive = 0, slot;
int ProxyA = 0, ProxyD = 0;
+ mDNSu32 groupCount = 0;
+ mDNSu32 mcastRecordCount = 0;
+ mDNSu32 ucastRecordCount = 0;
const CacheGroup *cg;
const CacheRecord *cr;
const DNSQuestion *q;
@@ -5892,30 +5750,33 @@ mDNSexport void udsserver_info(mDNS *const m)
{
for (cg = m->rrcache_hash[slot]; cg; cg=cg->next)
{
- CacheUsed++; // Count one cache entity for the CacheGroup object
+ groupCount++; // Count one cache entity for the CacheGroup object
for (cr = cg->members; cr; cr=cr->next)
{
const mDNSs32 remain = cr->resrec.rroriginalttl - (now - cr->TimeRcvd) / mDNSPlatformOneSecond;
const char *ifname;
mDNSInterfaceID InterfaceID = cr->resrec.InterfaceID;
+ mDNSu32 *const countPtr = InterfaceID ? &mcastRecordCount : &ucastRecordCount;
if (!InterfaceID && cr->resrec.rDNSServer && cr->resrec.rDNSServer->scoped)
InterfaceID = cr->resrec.rDNSServer->interface;
ifname = InterfaceNameForID(m, InterfaceID);
if (cr->CRActiveQuestion) CacheActive++;
- PrintOneCacheRecord(m, cr, slot, remain, ifname, &CacheUsed);
- PrintCachedRecords(m, cr, slot, remain, ifname, &CacheUsed);
+ PrintOneCacheRecord(cr, slot, remain, ifname, countPtr);
+ PrintCachedRecords(cr, slot, remain, ifname, countPtr);
}
}
}
+ CacheUsed = groupCount + mcastRecordCount + ucastRecordCount;
if (m->rrcache_totalused != CacheUsed)
LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", m->rrcache_totalused, CacheUsed);
if (m->rrcache_active != CacheActive)
LogMsgNoIdent("Cache use mismatch: rrcache_active is %lu, true count %lu", m->rrcache_active, CacheActive);
- LogMsgNoIdent("Cache currently contains %lu entities; %lu referenced by active questions", CacheUsed, CacheActive);
+ LogMsgNoIdent("Cache size %u entities; %u in use (%u group, %u multicast, %u unicast); %u referenced by active questions",
+ m->rrcache_size, CacheUsed, groupCount, mcastRecordCount, ucastRecordCount, CacheActive);
LogMsgNoIdent("--------- Auth Records ---------");
- LogAuthRecords(m, now, m->ResourceRecords, mDNSNULL);
+ LogAuthRecords(now, m->ResourceRecords, mDNSNULL);
LogMsgNoIdent("--------- LocalOnly, P2P Auth Records ---------");
LogLocalOnlyAuthRecords(m);
@@ -5924,13 +5785,13 @@ mDNSexport void udsserver_info(mDNS *const m)
LogEtcHosts(m);
LogMsgNoIdent("------ Duplicate Records -------");
- LogAuthRecords(m, now, m->DuplicateRecords, mDNSNULL);
+ LogAuthRecords(now, m->DuplicateRecords, mDNSNULL);
LogMsgNoIdent("----- Auth Records Proxied -----");
- LogAuthRecords(m, now, m->ResourceRecords, &ProxyA);
+ LogAuthRecords(now, m->ResourceRecords, &ProxyA);
LogMsgNoIdent("-- Duplicate Records Proxied ---");
- LogAuthRecords(m, now, m->DuplicateRecords, &ProxyD);
+ LogAuthRecords(now, m->DuplicateRecords, &ProxyD);
LogMsgNoIdent("---------- Questions -----------");
if (!m->Questions) LogMsgNoIdent("<None>");
@@ -5947,12 +5808,13 @@ mDNSexport void udsserver_info(mDNS *const m)
char *ifname = InterfaceNameForID(m, q->InterfaceID);
CacheUsed++;
if (q->ThisQInterval) CacheActive++;
- LogMsgNoIdent("%6d%6d %-7s%s%s %5d 0x%x%x 0x%p 0x%p %1d %2d %-5s%##s%s%s",
+ LogMsgNoIdent("%6d%6d %-7s%s%s %5d 0x%x%x%x%x 0x%p 0x%p %1d %2d %-5s%##s%s%s",
i, n,
ifname ? ifname : mDNSOpaque16IsZero(q->TargetQID) ? "" : "-U-",
mDNSOpaque16IsZero(q->TargetQID) ? (q->LongLived ? "l" : " ") : (q->LongLived ? "L" : "O"),
PrivateQuery(q) ? "P" : q->ValidationRequired ? "V" : q->ValidatingResponse ? "R" : " ",
- q->CurrentAnswers, q->validDNSServers.l[1], q->validDNSServers.l[0], q, q->DuplicateOf,
+ q->CurrentAnswers, q->validDNSServers.l[3], q->validDNSServers.l[2], q->validDNSServers.l[1],
+ q->validDNSServers.l[0], q, q->DuplicateOf,
q->SuppressUnusable, q->SuppressQuery, DNSTypeName(q->qtype), q->qname.c,
AnonInfoToString(q->AnonInfo, anonstr, sizeof(anonstr)),
q->DuplicateOf ? " (dup)" : "");
@@ -5980,7 +5842,7 @@ mDNSexport void udsserver_info(mDNS *const m)
LogMsgNoIdent("%3d: Orhpan operation %p; parent %p not found in request list", req->sd);
}
// For non-subbordinate operations, and subbordinate operations that have lost their parent, write out their info
- LogClientInfo(m, req);
+ LogClientInfo(req);
foundparent:;
}
}
@@ -6098,7 +5960,6 @@ foundparent:;
LogInfo("--- DNSSEC Statistics ---");
- LogInfo("Next Stats Time %u", m->NextStatLogTime - mDNSPlatformUTC());
LogMsgNoIdent("Unicast Cache size %u", m->rrcache_totalused_unicast);
LogInfo("DNSSEC Cache size %u", m->DNSSECStats.TotalMemUsed);
if (m->rrcache_totalused_unicast)
@@ -6133,9 +5994,10 @@ foundparent:;
LogMsgNoIdent("BonjourEnabled %d", m->BonjourEnabled);
#endif // BONJOUR_ON_DEMAND
-#if APPLE_OSX_mDNSResponder
+#if APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
LogMsgNoIdent("EnableBLEBasedDiscovery %d", EnableBLEBasedDiscovery);
-#endif // APPLE_OSX_mDNSResponder
+ LogMsgNoIdent("DefaultToBLETriggered %d", DefaultToBLETriggered);
+#endif // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
if (!m->NewQuestions)
LogMsgNoIdent("NewQuestion <NONE>");
@@ -6340,7 +6202,7 @@ mDNSexport mDNSs32 udsserver_idle(mDNSs32 nextevent)
else if (result == t_error)
{
LogMsg("%3d: Could not write data to client PID[%d](%s) because of error - aborting connection", r->sd, r->process_id, r->pid_name);
- LogClientInfo(&mDNSStorage, r);
+ LogClientInfo(r);
abort_request(r);
}
break;
@@ -6369,7 +6231,7 @@ mDNSexport mDNSs32 udsserver_idle(mDNSs32 nextevent)
if (++r->unresponsiveness_reports >= 60)
{
LogMsg("%3d: Client PID[%d](%s) unresponsive; aborting connection", r->sd, r->process_id, r->pid_name);
- LogClientInfo(&mDNSStorage, r);
+ LogClientInfo(r);
abort_request(r);
}
}
@@ -6395,7 +6257,11 @@ struct CompileTimeAssertionChecks_uds_daemon
char sizecheck_request_state [(sizeof(request_state) <= 2954) ? 1 : -1];
char sizecheck_registered_record_entry[(sizeof(registered_record_entry) <= 60) ? 1 : -1];
char sizecheck_service_instance [(sizeof(service_instance) <= 6552) ? 1 : -1];
- char sizecheck_browser_t [(sizeof(browser_t) <= 1150) ? 1 : -1];
+ char sizecheck_browser_t [(sizeof(browser_t) <= 1202) ? 1 : -1];
char sizecheck_reply_hdr [(sizeof(reply_hdr) <= 12) ? 1 : -1];
char sizecheck_reply_state [(sizeof(reply_state) <= 64) ? 1 : -1];
};
+
+#ifdef UNIT_TEST
+#include "../unittests/uds_daemon_ut.c"
+#endif // UNIT_TEST
diff --git a/mDNSResponder/mDNSShared/uds_daemon.h b/mDNSResponder/mDNSShared/uds_daemon.h
index ef98450b..dc7d9ac2 100644
--- a/mDNSResponder/mDNSShared/uds_daemon.h
+++ b/mDNSResponder/mDNSShared/uds_daemon.h
@@ -15,9 +15,200 @@
* limitations under the License.
*/
+#ifndef UDS_DAEMON_H
+#define UDS_DAEMON_H
+
#include "mDNSEmbeddedAPI.h"
#include "dnssd_ipc.h"
+/* Client request: */
+
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Types and Data Structures
+#endif
+
+typedef enum
+{
+ t_uninitialized,
+ t_morecoming,
+ t_complete,
+ t_error,
+ t_terminated
+} transfer_state;
+
+typedef struct request_state request_state;
+
+typedef void (*req_termination_fn)(request_state *request);
+
+typedef struct registered_record_entry
+{
+ struct registered_record_entry *next;
+ mDNSu32 key;
+ client_context_t regrec_client_context;
+ request_state *request;
+ mDNSBool external_advertise;
+ mDNSInterfaceID origInterfaceID;
+ AuthRecord *rr; // Pointer to variable-sized AuthRecord (Why a pointer? Why not just embed it here?)
+} registered_record_entry;
+
+// A single registered service: ServiceRecordSet + bookkeeping
+// Note that we duplicate some fields from parent service_info object
+// to facilitate cleanup, when instances and parent may be deallocated at different times.
+typedef struct service_instance
+{
+ struct service_instance *next;
+ request_state *request;
+ AuthRecord *subtypes;
+ mDNSBool renameonmemfree; // Set on config change when we deregister original name
+ mDNSBool clientnotified; // Has client been notified of successful registration yet?
+ mDNSBool default_local; // is this the "local." from an empty-string registration?
+ mDNSBool external_advertise; // is this is being advertised externally?
+ domainname domain;
+ ServiceRecordSet srs; // note -- variable-sized object -- must be last field in struct
+} service_instance;
+
+// for multi-domain default browsing
+typedef struct browser_t
+{
+ struct browser_t *next;
+ domainname domain;
+ DNSQuestion q;
+} browser_t;
+
+#ifdef _WIN32
+typedef unsigned int pid_t;
+typedef unsigned int socklen_t;
+#endif
+
+#if (!defined(MAXCOMLEN))
+#define MAXCOMLEN 16
+#endif
+
+struct request_state
+{
+ request_state *next;
+ request_state *primary; // If this operation is on a shared socket, pointer to primary
+ // request_state for the original DNSServiceCreateConnection() operation
+ dnssd_sock_t sd;
+ pid_t process_id; // Client's PID value
+ char pid_name[MAXCOMLEN]; // Client's process name
+ mDNSu8 uuid[UUID_SIZE];
+ mDNSBool validUUID;
+ dnssd_sock_t errsd;
+ mDNSu32 uid;
+ void * platform_data;
+
+ // Note: On a shared connection these fields in the primary structure, including hdr, are re-used
+ // for each new request. This is because, until we've read the ipc_msg_hdr to find out what the
+ // operation is, we don't know if we're going to need to allocate a new request_state or not.
+ transfer_state ts;
+ mDNSu32 hdr_bytes; // bytes of header already read
+ ipc_msg_hdr hdr;
+ mDNSu32 data_bytes; // bytes of message data already read
+ char *msgbuf; // pointer to data storage to pass to free()
+ const char *msgptr; // pointer to data to be read from (may be modified)
+ char *msgend; // pointer to byte after last byte of message
+
+ // reply, termination, error, and client context info
+ int no_reply; // don't send asynchronous replies to client
+ mDNSs32 time_blocked; // record time of a blocked client
+ int unresponsiveness_reports;
+ struct reply_state *replies; // corresponding (active) reply list
+ req_termination_fn terminate;
+ DNSServiceFlags flags;
+ mDNSu32 interfaceIndex;
+
+ union
+ {
+ registered_record_entry *reg_recs; // list of registrations for a connection-oriented request
+ struct
+ {
+ mDNSInterfaceID interface_id;
+ mDNSBool default_domain;
+ mDNSBool ForceMCast;
+ domainname regtype;
+ browser_t *browsers;
+ const mDNSu8 *AnonData;
+ } browser;
+ struct
+ {
+ mDNSInterfaceID InterfaceID;
+ mDNSu16 txtlen;
+ void *txtdata;
+ mDNSIPPort port;
+ domainlabel name;
+ char type_as_string[MAX_ESCAPED_DOMAIN_NAME];
+ domainname type;
+ mDNSBool default_domain;
+ domainname host;
+ mDNSBool autoname; // Set if this name is tied to the Computer Name
+ mDNSBool autorename; // Set if this client wants us to automatically rename on conflict
+ mDNSBool allowremotequery; // Respond to unicast queries from outside the local link?
+ int num_subtypes;
+ mDNSBool AnonData;
+ service_instance *instances;
+ } servicereg;
+ struct
+ {
+ mDNSInterfaceID interface_id;
+ mDNSu32 flags;
+ mDNSu32 protocol;
+ DNSQuestion q4;
+ DNSQuestion *q42;
+ DNSQuestion q6;
+ DNSQuestion *q62;
+ mDNSu8 v4ans;
+ mDNSu8 v6ans;
+ } addrinfo;
+ struct
+ {
+ mDNSIPPort ReqExt; // External port we originally requested, for logging purposes
+ NATTraversalInfo NATinfo;
+ } pm;
+ struct
+ {
+ DNSServiceFlags flags;
+ DNSQuestion q_all;
+ DNSQuestion q_default;
+ DNSQuestion q_autoall;
+ } enumeration;
+ struct
+ {
+ DNSQuestion q;
+ DNSQuestion *q2;
+ mDNSu8 ans;
+ } queryrecord;
+ struct
+ {
+ DNSQuestion qtxt;
+ DNSQuestion qsrv;
+ const ResourceRecord *txt;
+ const ResourceRecord *srv;
+ mDNSs32 ReportTime;
+ mDNSBool external_advertise;
+ } resolve;
+ } u;
+};
+
+// struct physically sits between ipc message header and call-specific fields in the message buffer
+typedef struct
+{
+ DNSServiceFlags flags; // Note: This field is in NETWORK byte order
+ mDNSu32 ifi; // Note: This field is in NETWORK byte order
+ DNSServiceErrorType error; // Note: This field is in NETWORK byte order
+} reply_hdr;
+
+typedef struct reply_state
+{
+ struct reply_state *next; // If there are multiple unsent replies
+ mDNSu32 totallen;
+ mDNSu32 nwriten;
+ ipc_msg_hdr mhdr[1];
+ reply_hdr rhdr[1];
+} reply_state;
+
/* Client interface: */
#define SRS_PORT(S) mDNSVal16((S)->RR_SRV.resrec.rdata->u.srv.port)
@@ -26,10 +217,10 @@
extern int udsserver_init(dnssd_sock_t skts[], mDNSu32 count);
extern mDNSs32 udsserver_idle(mDNSs32 nextevent);
-extern void udsserver_info(mDNS *const m); // print out info about current state
+extern void udsserver_info(void); // print out info about current state
extern void udsserver_handle_configchange(mDNS *const m);
extern int udsserver_exit(void); // should be called prior to app exit
-extern void LogMcastStateInfo(mDNS *const m, mDNSBool mflag, mDNSBool start, mDNSBool mstatelog);
+extern void LogMcastStateInfo(mDNSBool mflag, mDNSBool start, mDNSBool mstatelog);
#define LogMcastQ (mDNS_McastLoggingEnabled == 0) ? ((void)0) : LogMcastQuestion
#define LogMcastS (mDNS_McastLoggingEnabled == 0) ? ((void)0) : LogMcastService
#define LogMcast (mDNS_McastLoggingEnabled == 0) ? ((void)0) : LogMsg
@@ -42,7 +233,7 @@ extern mStatus udsSupportAddFDToEventLoop(dnssd_sock_t fd, udsEventCallback call
extern int udsSupportReadFD(dnssd_sock_t fd, char* buf, int len, int flags, void *platform_data);
extern mStatus udsSupportRemoveFDFromEventLoop(dnssd_sock_t fd, void *platform_data); // Note: This also CLOSES the file descriptor as well
-extern void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay);
+extern void RecordUpdatedNiceLabel(mDNSs32 delay);
// Globals and functions defined in uds_daemon.c and also shared with the old "daemon.c" on OS X
@@ -55,12 +246,12 @@ extern AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p, char **AnonDat
extern int CountExistingRegistrations(domainname *srv, mDNSIPPort port);
extern mDNSBool callExternalHelpers(mDNSInterfaceID InterfaceID, const domainname *const domain, DNSServiceFlags flags);
extern void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result);
-extern int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs);
+extern int CountPeerRegistrations(ServiceRecordSet *const srs);
#if APPLE_OSX_mDNSResponder
// D2D interface support
-extern void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags, DNSQuestion * q);
+extern void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags);
extern void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags);
extern void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags);
extern void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags);
@@ -68,14 +259,9 @@ extern void external_start_resolving_service(mDNSInterfaceID InterfaceID, const
extern void external_stop_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags);
extern void external_connection_release(const domainname *instance);
-extern void internal_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags);
-extern void internal_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags);
-extern void internal_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags);
-extern void internal_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags);
-
#else // APPLE_OSX_mDNSResponder
-#define external_start_browsing_for_service(A,B,C,D,E) (void)(A)
+#define external_start_browsing_for_service(A,B,C,D) (void)(A)
#define external_stop_browsing_for_service(A,B,C,D) (void)(A)
#define external_start_advertising_service(A,B) (void)(A)
#define external_stop_advertising_service(A,B) do { (void)(A); (void)(B); } while (0)
@@ -92,3 +278,5 @@ extern const char mDNSResponderVersionString_SCCS[];
extern void SetDebugBoundPath(void);
extern int IsDebugSocketInUse(void);
#endif
+
+#endif /* UDS_DAEMON_H */
diff --git a/mDNSResponder/mDNSVxWorks/mDNSVxWorks.c b/mDNSResponder/mDNSVxWorks/mDNSVxWorks.c
index 685dbf76..2e9ca1b6 100644
--- a/mDNSResponder/mDNSVxWorks/mDNSVxWorks.c
+++ b/mDNSResponder/mDNSVxWorks/mDNSVxWorks.c
@@ -1093,7 +1093,7 @@ mDNSlocal int SetupActiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC )
// If it's is an old one that went away and came back in less than a minute, we're in a flapping scenario.
flapping = ( ( inUTC - i->lastSeen ) > 0 ) && ( ( inUTC - i->lastSeen ) < 60 );
- mDNS_RegisterInterface( inMDNS, n, flapping );
+ mDNS_RegisterInterface( inMDNS, n, (flapping ? SlowActivation : NormalActivation));
if( mDNSAddressIsNonLinkLocalIPv4( &i->ifinfo.ip ) ) ++count;
dmsg( kDebugLevelInfo, DEBUG_NAME "%s: Registered %8s(%u) InterfaceID %#p %#a%s%s\n", __ROUTINE__,
@@ -1176,7 +1176,7 @@ mDNSlocal int ClearInactiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC, mDNS
i->ifinfo.ifname, i->scopeID, i->ifinfo.InterfaceID, &i->ifinfo.ip,
i->ifinfo.InterfaceActive ? " (Primary)" : "" );
- mDNS_DeregisterInterface( inMDNS, &i->ifinfo, mDNSfalse );
+ mDNS_DeregisterInterface( inMDNS, &i->ifinfo, NormalActivation );
i->ifinfo.InterfaceID = NULL;
if( mDNSAddressIsNonLinkLocalIPv4( &i->ifinfo.ip ) ) ++count;
}
diff --git a/mDNSResponder/mDNSVxWorks/mDNSVxWorksIPv4Only.c b/mDNSResponder/mDNSVxWorks/mDNSVxWorksIPv4Only.c
index efb1f7a3..38a21d23 100644
--- a/mDNSResponder/mDNSVxWorks/mDNSVxWorksIPv4Only.c
+++ b/mDNSResponder/mDNSVxWorks/mDNSVxWorksIPv4Only.c
@@ -1002,7 +1002,7 @@ mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *i
item->hostSet.Advertise = inMDNS->AdvertiseLocalAddresses;
item->hostSet.McastTxRx = mDNStrue;
- err = mDNS_RegisterInterface( inMDNS, &item->hostSet, mDNSfalse );
+ err = mDNS_RegisterInterface( inMDNS, &item->hostSet, NormalActivation );
require_noerr( err, exit );
item->hostRegistered = mDNStrue;
@@ -1044,7 +1044,7 @@ mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, MDNSInterfaceItem *i
if( inItem->hostRegistered )
{
inItem->hostRegistered = mDNSfalse;
- mDNS_DeregisterInterface( inMDNS, &inItem->hostSet, mDNSfalse );
+ mDNS_DeregisterInterface( inMDNS, &inItem->hostSet, NormalActivation );
}
// Close the multicast socket.
diff --git a/mDNSResponder/mDNSWindows/BonjourQuickLooks.sln b/mDNSResponder/mDNSWindows/BonjourQuickLooks.sln
new file mode 100644
index 00000000..cef4fe62
--- /dev/null
+++ b/mDNSResponder/mDNSWindows/BonjourQuickLooks.sln
@@ -0,0 +1,81 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DLL", "DLL\dnssd.vcxproj", "{AB581101-18F0-46F6-B56A-83A6B1EA657E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mDNSResponder", "SystemService\Service.vcxproj", "{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mdnsNSP", "mdnsNSP\mdnsNSP.vcxproj", "{F4F15529-F0EB-402F-8662-73C5797EE557}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dns-sd", "..\Clients\DNS-SD.VisualStudio\dns-sd.vcxproj", "{AA230639-E115-4A44-AA5A-44A61235BA50}"
+ ProjectSection(ProjectDependencies) = postProject
+ {AB581101-18F0-46F6-B56A-83A6B1EA657E} = {AB581101-18F0-46F6-B56A-83A6B1EA657E}
+ EndProjectSection
+EndProject
+Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "BonjourQuickLooksInstaller", "BonjourQuickLooksInstaller\BonjourQuickLooksInstaller.wixproj", "{E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug|Win32.Build.0 = Debug|Win32
+ {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug|x64.ActiveCfg = Debug|x64
+ {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug|x64.Build.0 = Debug|x64
+ {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug|x86.ActiveCfg = Debug|Win32
+ {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release|Win32.ActiveCfg = Release|Win32
+ {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release|Win32.Build.0 = Release|Win32
+ {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release|x64.ActiveCfg = Release|x64
+ {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release|x64.Build.0 = Release|x64
+ {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release|x86.ActiveCfg = Release|Win32
+ {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug|Win32.Build.0 = Debug|Win32
+ {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug|x64.ActiveCfg = Debug|x64
+ {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug|x64.Build.0 = Debug|x64
+ {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug|x86.ActiveCfg = Debug|Win32
+ {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release|Win32.ActiveCfg = Release|Win32
+ {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release|Win32.Build.0 = Release|Win32
+ {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release|x64.ActiveCfg = Release|x64
+ {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release|x64.Build.0 = Release|x64
+ {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release|x86.ActiveCfg = Release|Win32
+ {F4F15529-F0EB-402F-8662-73C5797EE557}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F4F15529-F0EB-402F-8662-73C5797EE557}.Debug|Win32.Build.0 = Debug|Win32
+ {F4F15529-F0EB-402F-8662-73C5797EE557}.Debug|x64.ActiveCfg = Debug|x64
+ {F4F15529-F0EB-402F-8662-73C5797EE557}.Debug|x64.Build.0 = Debug|x64
+ {F4F15529-F0EB-402F-8662-73C5797EE557}.Debug|x86.ActiveCfg = Debug|Win32
+ {F4F15529-F0EB-402F-8662-73C5797EE557}.Release|Win32.ActiveCfg = Release|Win32
+ {F4F15529-F0EB-402F-8662-73C5797EE557}.Release|Win32.Build.0 = Release|Win32
+ {F4F15529-F0EB-402F-8662-73C5797EE557}.Release|x64.ActiveCfg = Release|x64
+ {F4F15529-F0EB-402F-8662-73C5797EE557}.Release|x64.Build.0 = Release|x64
+ {F4F15529-F0EB-402F-8662-73C5797EE557}.Release|x86.ActiveCfg = Release|Win32
+ {AA230639-E115-4A44-AA5A-44A61235BA50}.Debug|Win32.ActiveCfg = Debug|Win32
+ {AA230639-E115-4A44-AA5A-44A61235BA50}.Debug|Win32.Build.0 = Debug|Win32
+ {AA230639-E115-4A44-AA5A-44A61235BA50}.Debug|x64.ActiveCfg = Debug|x64
+ {AA230639-E115-4A44-AA5A-44A61235BA50}.Debug|x64.Build.0 = Debug|x64
+ {AA230639-E115-4A44-AA5A-44A61235BA50}.Debug|x86.ActiveCfg = Debug|Win32
+ {AA230639-E115-4A44-AA5A-44A61235BA50}.Release|Win32.ActiveCfg = Release|Win32
+ {AA230639-E115-4A44-AA5A-44A61235BA50}.Release|Win32.Build.0 = Release|Win32
+ {AA230639-E115-4A44-AA5A-44A61235BA50}.Release|x64.ActiveCfg = Release|x64
+ {AA230639-E115-4A44-AA5A-44A61235BA50}.Release|x64.Build.0 = Release|x64
+ {AA230639-E115-4A44-AA5A-44A61235BA50}.Release|x86.ActiveCfg = Release|Win32
+ {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Debug|Win32.ActiveCfg = Debug|x86
+ {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Debug|x64.ActiveCfg = Debug|x64
+ {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Debug|x64.Build.0 = Debug|x64
+ {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Debug|x86.ActiveCfg = Debug|x86
+ {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Debug|x86.Build.0 = Debug|x86
+ {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Release|Win32.ActiveCfg = Release|x86
+ {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Release|x64.ActiveCfg = Release|x64
+ {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Release|x64.Build.0 = Release|x64
+ {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Release|x86.ActiveCfg = Release|x86
+ {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Release|x86.Build.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/mDNSResponder/mDNSWindows/BonjourQuickLooksInstaller/BonjourQuickLooksInstaller.wixproj b/mDNSResponder/mDNSWindows/BonjourQuickLooksInstaller/BonjourQuickLooksInstaller.wixproj
new file mode 100644
index 00000000..f98a8505
--- /dev/null
+++ b/mDNSResponder/mDNSWindows/BonjourQuickLooksInstaller/BonjourQuickLooksInstaller.wixproj
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+ <ProductVersion>3.10</ProductVersion>
+ <ProjectGuid>e24a4dc1-9b6f-4da4-bd76-7d5fe73732bf</ProjectGuid>
+ <SchemaVersion>2.0</SchemaVersion>
+ <OutputName>BonjourQuickLooks</OutputName>
+ <OutputType>Package</OutputType>
+ <WixTargetsPath Condition=" '$(WixTargetsPath)' == '' AND '$(MSBuildExtensionsPath32)' != '' ">$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
+ <WixTargetsPath Condition=" '$(WixTargetsPath)' == '' ">$(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
+ <Name>BonjourQuickLooksInstaller</Name>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+ <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>
+ <IntermediateOutputPath>obj\$(Platform)\$(Configuration)\</IntermediateOutputPath>
+ <DefineConstants>Debug</DefineConstants>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+ <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>
+ <IntermediateOutputPath>obj\$(Platform)\$(Configuration)\</IntermediateOutputPath>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
+ <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>
+ <IntermediateOutputPath>obj\$(Platform)\$(Configuration)\</IntermediateOutputPath>
+ <DefineConstants>Debug</DefineConstants>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
+ <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>
+ <IntermediateOutputPath>obj\$(Platform)\$(Configuration)\</IntermediateOutputPath>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="Product.wxs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\Clients\DNS-SD.VisualStudio\dns-sd.vcxproj">
+ <Name>dns-sd</Name>
+ <Project>{aa230639-e115-4a44-aa5a-44a61235ba50}</Project>
+ <Private>True</Private>
+ <DoNotHarvest>True</DoNotHarvest>
+ <RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>
+ <RefTargetDir>INSTALLFOLDER</RefTargetDir>
+ </ProjectReference>
+ <ProjectReference Include="..\DLL\dnssd.vcxproj">
+ <Name>DLL</Name>
+ <Project>{ab581101-18f0-46f6-b56a-83a6b1ea657e}</Project>
+ <Private>True</Private>
+ <DoNotHarvest>True</DoNotHarvest>
+ <RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>
+ <RefTargetDir>INSTALLFOLDER</RefTargetDir>
+ </ProjectReference>
+ <ProjectReference Include="..\mdnsNSP\mdnsNSP.vcxproj">
+ <Name>mdnsNSP</Name>
+ <Project>{f4f15529-f0eb-402f-8662-73c5797ee557}</Project>
+ <Private>True</Private>
+ <DoNotHarvest>True</DoNotHarvest>
+ <RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>
+ <RefTargetDir>INSTALLFOLDER</RefTargetDir>
+ </ProjectReference>
+ <ProjectReference Include="..\SystemService\Service.vcxproj">
+ <Name>mDNSResponder</Name>
+ <Project>{c1d98254-ba27-4427-a3be-a68ca2cc5f69}</Project>
+ <Private>True</Private>
+ <DoNotHarvest>True</DoNotHarvest>
+ <RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>
+ <RefTargetDir>INSTALLFOLDER</RefTargetDir>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <WixExtension Include="WixFirewallExtension">
+ <HintPath>$(WixExtDir)\WixFirewallExtension.dll</HintPath>
+ <Name>WixFirewallExtension</Name>
+ </WixExtension>
+ </ItemGroup>
+ <Import Project="$(WixTargetsPath)" />
+ <!--
+ To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Wix.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/mDNSResponder/mDNSWindows/BonjourQuickLooksInstaller/Product.wxs b/mDNSResponder/mDNSWindows/BonjourQuickLooksInstaller/Product.wxs
new file mode 100644
index 00000000..88cb8314
--- /dev/null
+++ b/mDNSResponder/mDNSWindows/BonjourQuickLooksInstaller/Product.wxs
@@ -0,0 +1,176 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Copyright (c) 2016 Apple Inc. All rights reserved. -->
+
+<Wix xmlns = "http://schemas.microsoft.com/wix/2006/wi"
+ xmlns:fire = "http://schemas.microsoft.com/wix/FirewallExtension" >
+
+ <?define ProductManufacturer = "Apple Inc."?>
+ <?define ProductName = "Bonjour (QuickLooks Testing)"?>
+ <?define UpgradeCode = "46AE3251-43D6-41CF-8CDF-E902C38516D1"?>
+ <?define ProductVersion = "1.0.0"?>
+ <?define ProductVersionMarketing = "1.0.0"?>
+ <?if $(var.Platform) = x64?>
+ <?define Win64 = "yes" ?>
+ <?define PlatformSystemFolder = "System64Folder"?>
+ <?define PlatformProgramFilesFolder = "ProgramFiles64Folder"?>
+ <?define PlatformInstallDir = "INSTALLDIR64"?>
+ <?define GUID_DNSSDExe = "528ACC12-D4A8-11DE-927F-58D855D89593"?>
+ <?define GUID_DNSSDDLL = "20F30EC6-1F92-11DC-8314-0800200C9A66"?>
+ <?define GUID_MDNSNSPDLL = "255EBC6C-1F92-11DC-8314-0800200C9A66"?>
+ <?define GUID_MDNSResponderExe = "BB3076CA-D4DF-11E0-8AC8-AA0E4824019B"?>
+ <?else?>
+ <?define Win64 = "no" ?>
+ <?define PlatformSystemFolder = "SystemFolder"?>
+ <?define PlatformProgramFilesFolder = "ProgramFilesFolder"?>
+ <?define PlatformInstallDir = "INSTALLDIR"?>
+ <?define GUID_DNSSDExe = "DCA08E52-8D4E-43AF-A0F7-9B809FCCFEBF"?>
+ <?define GUID_DNSSDDLL = "E6B826D2-6338-4822-8DEA-EC03C2CA41A7"?>
+ <?define GUID_MDNSNSPDLL = "0E416468-0A21-4778-BE61-64AAA5BE1039"?>
+ <?define GUID_MDNSResponderExe = "836FE314-37A7-4905-90F0-AFE25F315CA3"?>
+ <?endif?>
+ <?define GUID_InstallerCache = "EDD5CC92-97D7-4364-9CA6-F7001C75A90E"?>
+
+ <Product
+ Id = "*"
+ Language = "1033"
+ Manufacturer = "$(var.ProductManufacturer)"
+ Name = "$(var.ProductName)"
+ UpgradeCode = "$(var.UpgradeCode)"
+ Version = "$(var.ProductVersion)" >
+
+ <Package
+ Keywords = "Installer,MSI"
+ Comments = "$(var.ProductName) $(var.ProductVersion)"
+ Compressed = "yes"
+ Description = "[ProductName] Installer"
+ InstallerVersion = "300"
+ Languages = "1033"
+ Manufacturer = "$(var.ProductManufacturer)"
+ SummaryCodepage = "1252" />
+
+ <!-- Launch Conditions -->
+ <Condition
+ Message = "You do not have sufficient privileges to complete this installation for all users of the machine. Log on as an administrator and then retry this installation." >
+ <![CDATA[Privileged]]>
+ </Condition>
+ <Condition
+ Message = "[ProductName] requires that your computer is running Windows XP SP2 or newer.">
+ <![CDATA[((VersionNT=501 AND ServicePackLevel>=2) OR VersionNT>501)]]>
+ </Condition>
+ <?if $(var.Win64) = "no"?>
+ <Condition
+ Message = "This installer is intended for 32-bit versions of Windows" >
+ <![CDATA[NOT VersionNT64]]>
+ </Condition>
+ <?endif?>
+
+ <!-- Directory Table -->
+ <Directory Id="TARGETDIR" Name="SourceDir">
+ <Directory Id="$(var.PlatformSystemFolder)" />
+ <Directory Id="$(var.PlatformProgramFilesFolder)">
+ <Directory Id="Bonjour64InstallFolder" Name="Bonjour">
+ <Directory Id="$(var.PlatformInstallDir)" />
+ </Directory>
+ </Directory>
+ <Directory Id="DesktopFolder" />
+ <Directory Id="CommonAppDataFolder" Name="Application Data">
+ <Directory Id="AppleCommonAppDataFolder" Name="Apple">
+ <Directory Id="CachedInstallationsFolder" Name="Installer Cache">
+ <Directory Id="INSTALLERCACHE" Name="$(var.ProductName) $(var.ProductVersion)" />
+ </Directory>
+ </Directory>
+ </Directory>
+ </Directory>
+
+ <!-- Features -->
+ <Feature Id="Bonjour" Title="Bonjour" Level="1" AllowAdvertise="no" Display="expand">
+ <ComponentRef Id="InstallerCache" />
+ <Feature Id="mDNSResponder" Title="mDNSResponder" Level="1" AllowAdvertise="no" Absent="disallow">
+ <ComponentRef Id="dns_sd.exe" />
+ <ComponentRef Id="dnssd.dll" />
+ <ComponentRef Id="mdnsNSP.dll" />
+ <ComponentRef Id="mDNSResponder.exe" />
+ </Feature>
+ </Feature>
+
+ <!-- InstallerCache -->
+ <DirectoryRef Id="INSTALLERCACHE">
+ <Component Id="InstallerCache" Guid="$(var.GUID_InstallerCache)" KeyPath="yes">
+ <Condition><![CDATA[NOT DONTCACHEMSI]]></Condition>
+ <CreateFolder />
+ <CopyFile Id="BonjourQuickLooks.msi" SourceProperty="SourceDir" SourceName="BonjourQuickLooks.msi" DestinationDirectory="INSTALLERCACHE" />
+ <RemoveFile Id="BonjourQuickLooks.msi" Directory="INSTALLERCACHE" Name="BonjourQuickLooks.msi" On="uninstall" />
+ <RemoveFolder Id="INSTALLERCACHE" Directory="INSTALLERCACHE" On="uninstall" />
+ </Component>
+ </DirectoryRef>
+
+ <!-- Bonjour -->
+ <DirectoryRef Id="$(var.PlatformSystemFolder)">
+ <Component Id="dns_sd.exe" Guid="$(var.GUID_DNSSDExe)" Win64="$(var.Win64)">
+ <File Id="dns_sd.exe" Name="dns-sd.exe" KeyPath="yes" Source="$(var.dns-sd.TargetPath)" />
+ </Component>
+ <Component Id="dnssd.dll" Guid="$(var.GUID_DNSSDDLL)" Win64="$(var.Win64)">
+ <File Id="dnssd.dll" Name="dnssd.dll" KeyPath="yes" Source="$(var.DLL.TargetPath)" />
+ </Component>
+ </DirectoryRef>
+
+ <DirectoryRef Id="$(var.PlatformInstallDir)">
+ <Component Id="mdnsNSP.dll" Guid="$(var.GUID_MDNSNSPDLL)" Win64="$(var.Win64)">
+ <File Id="mdnsNSP.dll" Name="mdnsNSP.dll" Source="$(var.mdnsNSP.TargetPath)" KeyPath="yes" SelfRegCost="1024" />
+ </Component>
+ <Component Id="mDNSResponder.exe" Guid="$(var.GUID_MDNSResponderExe)" Win64="$(var.Win64)">
+ <File Id="mDNSResponder.exe" Name="mDNSResponder.exe" Source="$(var.mDNSResponder.TargetPath)" KeyPath="yes">
+ <fire:FirewallException Id="mDNSException1" Name="Bonjour Service" IgnoreFailure="yes" Scope="any" />
+ </File>
+ <ServiceInstall
+ Id = "BonjourService"
+ Name = "Bonjour Service"
+ DisplayName = "Bonjour Service"
+ Description = "Enables hardware devices and software services to automatically configure themselves on the network and advertise their presence."
+ Start = "auto"
+ Type = "ownProcess"
+ ErrorControl = "normal"
+ Vital = "yes" >
+ <ServiceDependency Id="Tcpip" Group="no" />
+ </ServiceInstall>
+ <ServiceControl
+ Id = "BonjourService"
+ Name = "Bonjour Service"
+ Start = "install"
+ Stop = "both"
+ Remove = "uninstall"
+ Wait = "yes" />
+ <RegistryValue
+ Name = "ManageLLRouting"
+ Root = "HKLM"
+ Key = "SYSTEM\CurrentControlSet\Services\Bonjour Service\Parameters"
+ Type = "integer"
+ Value = "1" />
+ <RegistryKey
+ Root = "HKLM"
+ Key = "SOFTWARE\Apple Inc.\Bonjour"
+ Action = "createAndRemoveOnUninstall" >
+ <RegistryValue
+ Name = "InstallDir"
+ Type = "string"
+ Value = "[$(var.PlatformInstallDir)]" />
+ <RegistryValue
+ Name = "Version"
+ Type = "string"
+ Value = "$(var.ProductVersion)" />
+ </RegistryKey>
+ </Component>
+ </DirectoryRef>
+
+ <!-- Media -->
+ <Media Id="1" EmbedCab="yes" Cabinet="BonjourQuickLooks.cab" CompressionLevel="high" />
+
+ <!-- Properties -->
+ <Property Id="ALLUSERS" Value="1" />
+ <Property Id="ARPNOMODIFY" Value="1" />
+ <Property Id="MSIRESTARTMANAGERCONTROL" Value="Disable" />
+
+ <MajorUpgrade AllowDowngrades="yes" Schedule="afterInstallValidate" />
+ </Product>
+</Wix>
diff --git a/mDNSResponder/mDNSWindows/WinVersRes.h b/mDNSResponder/mDNSWindows/WinVersRes.h
index d7249be1..382bba49 100644
--- a/mDNSResponder/mDNSWindows/WinVersRes.h
+++ b/mDNSResponder/mDNSWindows/WinVersRes.h
@@ -24,10 +24,10 @@
#define MASTER_COMPANY_NAME "Apple Inc."
// Define the product version for mDNSResponder on Windows
-#define MASTER_PROD_VERS 3,0,0,2
-#define MASTER_PROD_VERS_STR "3,0,0,2"
-#define MASTER_PROD_VERS_STR2 "3.0.0.2"
-#define MASTER_PROD_VERS_STR3 "Explorer Plugin 3.0.0.2"
+#define MASTER_PROD_VERS 3,1,0,2
+#define MASTER_PROD_VERS_STR "3,1,0,2"
+#define MASTER_PROD_VERS_STR2 "3.1.0.2"
+#define MASTER_PROD_VERS_STR3 "Explorer Plugin 3.1.0.2"
// Define the legal copyright
#define MASTER_LEGAL_COPYRIGHT "Copyright (C) 2003-2011 Apple Inc."
diff --git a/mDNSResponder/mDNSWindows/mDNSWin32.c b/mDNSResponder/mDNSWindows/mDNSWin32.c
index f2c43190..fa07af02 100755
--- a/mDNSResponder/mDNSWindows/mDNSWin32.c
+++ b/mDNSResponder/mDNSWindows/mDNSWin32.c
@@ -1920,7 +1920,7 @@ SetDNSServers( mDNS *const m )
{
mDNSAddr addr;
err = StringToAddress( &addr, ipAddr->IpAddress.String );
- if ( !err ) mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, 0, &addr, UnicastDNSPort, kScopeNone, DEFAULT_UDNS_TIMEOUT, mDNSfalse, 0, mDNStrue, mDNStrue, mDNSfalse);
+ if ( !err ) mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, 0, &addr, UnicastDNSPort, kScopeNone, DEFAULT_UDNS_TIMEOUT, mDNSfalse, mDNSfalse, 0, mDNStrue, mDNStrue, mDNSfalse);
}
exit:
@@ -2843,7 +2843,7 @@ mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inI
ifd->interfaceInfo.DirectLink = mDNSfalse;
ifd->interfaceInfo.SupportsUnicastMDNSResponse = mDNStrue;
- err = mDNS_RegisterInterface( inMDNS, &ifd->interfaceInfo, mDNSfalse );
+ err = mDNS_RegisterInterface( inMDNS, &ifd->interfaceInfo, NormalActivation );
require_noerr( err, exit );
ifd->hostRegistered = mDNStrue;
@@ -2880,7 +2880,7 @@ mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inI
if( inIFD->hostRegistered )
{
inIFD->hostRegistered = mDNSfalse;
- mDNS_DeregisterInterface( inMDNS, &inIFD->interfaceInfo, mDNSfalse );
+ mDNS_DeregisterInterface( inMDNS, &inIFD->interfaceInfo, NormalActivation );
}
// Tear down the multicast socket.
diff --git a/mDNSResponder/unittests/CNameRecordTests.c b/mDNSResponder/unittests/CNameRecordTests.c
new file mode 100644
index 00000000..9b3fb016
--- /dev/null
+++ b/mDNSResponder/unittests/CNameRecordTests.c
@@ -0,0 +1,400 @@
+#include "CNameRecordTests.h"
+#include "unittest_common.h"
+
+mDNSlocal int InitThisUnitTest(void);
+mDNSlocal int StartClientQueryRequest(void);
+mDNSlocal int PopulateCacheWithClientResponseRecords(void);
+mDNSlocal int SimulateNetworkChangeAndVerifyTest(void);
+mDNSlocal int FinalizeUnitTest(void);
+mDNSlocal mStatus AddDNSServer(void);
+
+// This unit test's variables
+static UDPSocket* local_socket;
+static request_state* client_request_message;
+
+struct UDPSocket_struct
+{
+ mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
+};
+typedef struct UDPSocket_struct UDPSocket;
+
+// This client request was generated using the following command: "dns-sd -Q 123server.dotbennu.com. A".
+uint8_t query_client_msgbuf[35] = {
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x33, 0x73, 0x65, 0x72, 0x76, 0x65,
+ 0x72, 0x2e, 0x64, 0x6f, 0x74, 0x62, 0x65, 0x6e, 0x6e, 0x75, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00,
+ 0x01, 0x00, 0x01
+};
+
+// This uDNS message is a canned response that was originally captured by wireshark.
+uint8_t query_response_msgbuf[108] = {
+ 0x69, 0x41, // transaction id
+ 0x85, 0x80, // flags
+ 0x00, 0x01, // 1 question for 123server.dotbennu.com. Addr
+ 0x00, 0x02, // 2 anwsers: 123server.dotbennu.com. CNAME test212.dotbennu.com., test212.dotbennu.com. Addr 10.100.0.1,
+ 0x00, 0x01, // 1 authorities anwser: dotbennu.com. NS cardinal2.apple.com.
+ 0x00, 0x00, 0x09, 0x31, 0x32, 0x33,
+ 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x08, 0x64, 0x6f, 0x74, 0x62, 0x65, 0x6e, 0x6e, 0x75, 0x03,
+ 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00,
+ 0x02, 0x56, 0x00, 0x0a, 0x07, 0x74, 0x65, 0x73, 0x74, 0x32, 0x31, 0x32, 0xc0, 0x16, 0xc0, 0x34,
+ 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x04, 0x0a, 0x64, 0x00, 0x01, 0xc0, 0x16,
+ 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x12, 0x09, 0x63, 0x61, 0x72, 0x64, 0x69,
+ 0x6e, 0x61, 0x6c, 0x32, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x65, 0xc0, 0x1f
+};
+
+// Variables associated with contents of the above uDNS message
+#define uDNS_TargetQID 16745
+char udns_original_domainname_cstr[] = "123server.dotbennu.com.";
+char udns_cname_domainname_cstr[] = "test212.dotbennu.com.";
+static const mDNSv4Addr dns_response_ipv4 = {{ 10, 100, 0, 1 }};
+
+UNITTEST_HEADER(CNameRecordTests)
+ UNITTEST_TEST(InitThisUnitTest)
+ UNITTEST_TEST(StartClientQueryRequest)
+ UNITTEST_TEST(PopulateCacheWithClientResponseRecords)
+ UNITTEST_TEST(SimulateNetworkChangeAndVerifyTest)
+ UNITTEST_TEST(FinalizeUnitTest)
+UNITTEST_FOOTER
+
+// The InitThisUnitTest() initializes the mDNSResponder environment as well as
+// a DNSServer. It also allocates memory for a local_socket and client request.
+// Note: This unit test does not send packets on the wire and it does not open sockets.
+UNITTEST_HEADER(InitThisUnitTest)
+ // Init unit test environment and verify no error occurred.
+ mStatus result = init_mdns_environment(mDNStrue);
+ UNITTEST_ASSERT(result == mStatus_NoError);
+
+ // Add one DNS server and verify it was added.
+ AddDNSServer();
+ UNITTEST_ASSERT(NumUnicastDNSServers == 1);
+
+ // Create memory for a socket that is never used or opened.
+ local_socket = mDNSPlatformMemAllocate(sizeof(UDPSocket));
+ mDNSPlatformMemZero(local_socket, sizeof(UDPSocket));
+
+ // Create memory for a request that is used to make this unit test's client request.
+ client_request_message = calloc(1, sizeof(request_state));
+UNITTEST_FOOTER
+
+// This test simulates a uds client request by setting up a client request and then
+// calling mDNSResponder's handle_client_request. The handle_client_request function
+// processes the request and starts a query. This unit test verifies
+// the client request and query were setup as expected. This unit test also calls
+// mDNS_execute which determines the cache does not contain the new question's
+// answer.
+UNITTEST_HEADER(StartClientQueryRequest)
+ mDNS *const m = &mDNSStorage;
+ request_state* req = client_request_message;
+ char *msgptr = (char *)query_client_msgbuf;
+ size_t msgsz = sizeof(query_client_msgbuf);
+ mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4;
+ DNSQuestion *q;
+ mStatus err = mStatus_NoError;
+ char qname_cstr[MAX_ESCAPED_DOMAIN_NAME];
+
+ // Process the unit test's client request
+ start_client_request(req, msgptr, msgsz, query_request, local_socket);
+ UNITTEST_ASSERT(err == mStatus_NoError);
+
+ // Verify the request fields were set as expected
+ UNITTEST_ASSERT(req->next == mDNSNULL);
+ UNITTEST_ASSERT(req->primary == mDNSNULL);
+ UNITTEST_ASSERT(req->sd == client_req_sd);
+ UNITTEST_ASSERT(req->process_id == client_req_process_id);
+ UNITTEST_ASSERT(!strcmp(req->pid_name, client_req_pid_name));
+ UNITTEST_ASSERT(req->validUUID == mDNSfalse);
+ UNITTEST_ASSERT(req->errsd == 0);
+ UNITTEST_ASSERT(req->uid == client_req_uid);
+ UNITTEST_ASSERT(req->ts == t_complete);
+ UNITTEST_ASSERT((mDNSs32)req->data_bytes > min_size);
+ UNITTEST_ASSERT(req->msgend == msgptr+msgsz);
+ UNITTEST_ASSERT(req->msgbuf == mDNSNULL);
+ UNITTEST_ASSERT(req->hdr.version == VERSION);
+ UNITTEST_ASSERT(req->replies == mDNSNULL);
+ UNITTEST_ASSERT(req->terminate != mDNSNULL);
+ UNITTEST_ASSERT(req->flags == kDNSServiceFlagsReturnIntermediates);
+ UNITTEST_ASSERT(req->interfaceIndex == kDNSServiceInterfaceIndexAny);
+
+ // Verify the query fields were set as expected
+ q = &req->u.queryrecord.q;
+ UNITTEST_ASSERT(q != mDNSNULL);
+ UNITTEST_ASSERT(q == m->Questions);
+ UNITTEST_ASSERT(q == m->NewQuestions);
+ UNITTEST_ASSERT(q->SuppressUnusable == mDNSfalse);
+ UNITTEST_ASSERT(q->ReturnIntermed == mDNStrue);
+ UNITTEST_ASSERT(q->SuppressQuery == mDNSfalse);
+
+ UNITTEST_ASSERT(q->qnameOrig == mDNSNULL);
+ ConvertDomainNameToCString(&q->qname, qname_cstr);
+ UNITTEST_ASSERT(!strcmp(qname_cstr, udns_original_domainname_cstr));
+ UNITTEST_ASSERT(q->qnamehash == DomainNameHashValue(&q->qname));
+
+ UNITTEST_ASSERT(q->InterfaceID == mDNSInterface_Any);
+ UNITTEST_ASSERT(q->flags == req->flags);
+ UNITTEST_ASSERT(q->qtype == 1);
+ UNITTEST_ASSERT(q->qclass == 1);
+ UNITTEST_ASSERT(q->LongLived == 0);
+ UNITTEST_ASSERT(q->ExpectUnique == mDNSfalse);
+ UNITTEST_ASSERT(q->ForceMCast == 0);
+ UNITTEST_ASSERT(q->TimeoutQuestion == 0);
+ UNITTEST_ASSERT(q->WakeOnResolve == 0);
+ UNITTEST_ASSERT(q->UseBackgroundTrafficClass == 0);
+ UNITTEST_ASSERT(q->ValidationRequired == 0);
+ UNITTEST_ASSERT(q->ValidatingResponse == 0);
+ UNITTEST_ASSERT(q->ProxyQuestion == 0);
+ UNITTEST_ASSERT(q->AnonInfo == mDNSNULL);
+ UNITTEST_ASSERT(q->QuestionCallback != mDNSNULL);
+ UNITTEST_ASSERT(q->QuestionContext == req);
+ UNITTEST_ASSERT(q->SearchListIndex == 0);
+ UNITTEST_ASSERT(q->DNSSECAuthInfo == mDNSNULL);
+ UNITTEST_ASSERT(q->DAIFreeCallback == mDNSNULL);
+ UNITTEST_ASSERT(q->RetryWithSearchDomains == 0);
+ UNITTEST_ASSERT(q->AppendSearchDomains == 0);
+ UNITTEST_ASSERT(q->AppendLocalSearchDomains == 0);
+ UNITTEST_ASSERT(q->DuplicateOf == mDNSNULL);
+
+ // Call mDNS_Execute to see if the new question, q, has an answer in the cache.
+ // It won't be yet because the cache is empty.
+ m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+ mDNS_Execute(m);
+
+ // Verify mDNS_Execute processed the new question.
+ UNITTEST_ASSERT(m->NewQuestions == mDNSNULL);
+
+ // Verify the cache is empty and the request got no reply.
+ UNITTEST_ASSERT(m->rrcache_totalused == 0);
+ UNITTEST_ASSERT(req->replies == mDNSNULL);
+
+UNITTEST_FOOTER
+
+// This unit test receives a canned uDNS response message by calling the mDNSCoreReceive() function.
+// It then verifies cache entries were added for the CNAME and A records that were contained in the
+// answers of the canned response, query_response_msgbuf. This unit test also verifies that
+// 2 add events were generated for the client.
+UNITTEST_HEADER(PopulateCacheWithClientResponseRecords)
+ mDNS *const m = &mDNSStorage;
+ DNSMessage *msgptr = (DNSMessage *)query_response_msgbuf;
+ size_t msgsz = sizeof(query_response_msgbuf);
+ struct reply_state *reply;
+ request_state* req = client_request_message;
+ DNSQuestion *q = &req->u.queryrecord.q;
+ const char *data;
+ const char *end;
+ char name[kDNSServiceMaxDomainName];
+ uint16_t rrtype, rrclass, rdlen;
+ const char *rdata;
+ size_t len;
+ char domainname_cstr[MAX_ESCAPED_DOMAIN_NAME];
+
+ // Receive and populate the cache with canned response
+ receive_response(req, msgptr, msgsz);
+
+ // Verify 2 cache entries for CName and A record are present
+ mDNSu32 CacheUsed =0, notUsed =0;
+ LogCacheRecords_ut(mDNS_TimeNow(m), &CacheUsed, &notUsed);
+ UNITTEST_ASSERT(CacheUsed == m->rrcache_totalused);
+ UNITTEST_ASSERT(CacheUsed == 4); // 2 for the CacheGroup object plus 2 for the A and CNAME records
+ UNITTEST_ASSERT(m->PktNum == 1); // one packet was received
+
+ // Verify question's qname is now set with the A record's domainname
+ UNITTEST_ASSERT(q->qnameOrig == mDNSNULL);
+ ConvertDomainNameToCString(&q->qname, domainname_cstr);
+ UNITTEST_ASSERT(q->qnamehash == DomainNameHashValue(&q->qname));
+ UNITTEST_ASSERT(!strcmp(domainname_cstr, udns_cname_domainname_cstr));
+
+ // Verify client's add event for CNAME is properly formed
+ reply = req->replies;
+ UNITTEST_ASSERT(reply != mDNSNULL);
+ UNITTEST_ASSERT(reply->next == mDNSNULL);
+
+ data = (char *)&reply->rhdr[1];
+ end = data+reply->totallen;
+ get_string(&data, data+reply->totallen, name, kDNSServiceMaxDomainName);
+ rrtype = get_uint16(&data, end);
+ rrclass = get_uint16(&data, end);
+ rdlen = get_uint16(&data, end);
+ rdata = get_rdata(&data, end, rdlen);
+ len = get_reply_len(name, rdlen);
+
+ UNITTEST_ASSERT(reply->totallen == len + sizeof(ipc_msg_hdr));
+ UNITTEST_ASSERT(reply->mhdr->version == VERSION);
+ UNITTEST_ASSERT(reply->mhdr->datalen == len);
+ UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
+ UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
+
+ UNITTEST_ASSERT(reply->rhdr->flags == htonl(kDNSServiceFlagsAdd));
+ UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexAny);
+ UNITTEST_ASSERT(reply->rhdr->error == kDNSServiceErr_NoError);
+
+ UNITTEST_ASSERT(rrtype == kDNSType_CNAME);
+ UNITTEST_ASSERT(rrclass == kDNSClass_IN);
+ ConvertDomainNameToCString((const domainname *const)rdata, domainname_cstr);
+ UNITTEST_ASSERT(!strcmp(domainname_cstr, "test212.dotbennu.com."));
+
+ // The mDNS_Execute call generates an add event for the A record
+ m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+ mDNS_Execute(m);
+
+ // Verify the client's reply contains a properly formed add event for the A record.
+ reply = req->replies;
+ UNITTEST_ASSERT(reply != mDNSNULL);
+ UNITTEST_ASSERT(reply->next != mDNSNULL);
+ reply = reply->next;
+
+ data = (char *)&reply->rhdr[1];
+ end = data+reply->totallen;
+ get_string(&data, data+reply->totallen, name, kDNSServiceMaxDomainName);
+ rrtype = get_uint16(&data, end);
+ rrclass = get_uint16(&data, end);
+ rdlen = get_uint16(&data, end);
+ rdata = get_rdata(&data, end, rdlen);
+ len = get_reply_len(name, rdlen);
+
+ UNITTEST_ASSERT(reply->totallen == len + sizeof(ipc_msg_hdr));
+ UNITTEST_ASSERT(reply->mhdr->version == VERSION);
+ UNITTEST_ASSERT(reply->mhdr->datalen == len);
+
+ UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
+ UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
+
+ UNITTEST_ASSERT(reply->rhdr->flags == htonl(kDNSServiceFlagsAdd));
+ UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexAny);
+ UNITTEST_ASSERT(reply->rhdr->error == kDNSServiceErr_NoError);
+
+ UNITTEST_ASSERT(rrtype == kDNSType_A);
+ UNITTEST_ASSERT(rrclass == kDNSClass_IN);
+ UNITTEST_ASSERT(rdata[0] == dns_response_ipv4.b[0]);
+ UNITTEST_ASSERT(rdata[1] == dns_response_ipv4.b[1]);
+ UNITTEST_ASSERT(rdata[2] == dns_response_ipv4.b[2]);
+ UNITTEST_ASSERT(rdata[3] == dns_response_ipv4.b[3]);
+
+UNITTEST_FOOTER
+
+// This function verifies the cache and event handling occurred as expected when a network change happened.
+// The uDNS_SetupDNSConfig is called to simulate a network change and two outcomes occur. First the A record
+// query is restarted and sent to a new DNS server. Second the cache records are purged. Then mDNS_Execute
+// is called and it removes the purged cache records and generates a remove event for the A record.
+// The following are verified:
+// 1.) The restart of query for A record.
+// 2.) The cache is empty after mDNS_Execute removes the cache entres.
+// 3.) The remove event is verified by examining the request's reply data.
+UNITTEST_HEADER(SimulateNetworkChangeAndVerifyTest)
+ mDNS *const m = &mDNSStorage;
+ request_state* req = client_request_message;
+ DNSQuestion* q = &req->u.queryrecord.q;
+ mDNSu32 CacheUsed =0, notUsed =0;
+ const char *data; const char *end;
+ char name[kDNSServiceMaxDomainName];
+ uint16_t rrtype, rrclass, rdlen;
+ const char *rdata;
+ size_t len;
+
+ // The uDNS_SetupDNSConfig reconfigures the resolvers so the A record query is restarted and
+ // both the CNAME and A record are purged.
+ uDNS_SetupDNSConfig(m);
+
+ // Verify the A record query was restarted. This is done indirectly by noticing the transaction id and interval have changed.
+ UNITTEST_ASSERT(q->ThisQInterval == InitialQuestionInterval);
+ UNITTEST_ASSERT(q->TargetQID.NotAnInteger != uDNS_TargetQID);
+
+ // Then mDNS_Execute removes both records from the cache and calls the client back with a remove event for A record.
+ m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+ mDNS_Execute(m);
+
+ // Verify the cache entries are removed
+ LogCacheRecords_ut(mDNS_TimeNow(m), &CacheUsed, &notUsed);
+ UNITTEST_ASSERT(CacheUsed == m->rrcache_totalused);
+ UNITTEST_ASSERT(CacheUsed == 0);
+
+ // Verify the A record's remove event is setup as expected in the reply data
+ struct reply_state *reply;
+ reply = req->replies;
+ UNITTEST_ASSERT(reply != mDNSNULL);
+
+ UNITTEST_ASSERT(reply != mDNSNULL);
+ UNITTEST_ASSERT(reply->next != mDNSNULL);
+ UNITTEST_ASSERT(reply->next->next != mDNSNULL);
+
+ reply = reply->next->next; // Get to last event to verify remove event
+ data = (char *)&reply->rhdr[1];
+ end = data+reply->totallen;
+ get_string(&data, data+reply->totallen, name, kDNSServiceMaxDomainName);
+ rrtype = get_uint16(&data, end);
+ rrclass = get_uint16(&data, end);
+ rdlen = get_uint16(&data, end);
+ rdata = get_rdata(&data, end, rdlen);
+ len = get_reply_len(name, rdlen);
+
+ UNITTEST_ASSERT(reply->totallen == reply->mhdr->datalen + sizeof(ipc_msg_hdr));
+ UNITTEST_ASSERT(reply->mhdr->version == VERSION);
+ UNITTEST_ASSERT(reply->mhdr->datalen == len);
+ UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
+ UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
+
+ UNITTEST_ASSERT(reply->rhdr->flags != htonl(kDNSServiceFlagsAdd));
+ UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexAny);
+ UNITTEST_ASSERT(reply->rhdr->error == kDNSServiceErr_NoError);
+
+ UNITTEST_ASSERT(rrtype == kDNSType_A);
+ UNITTEST_ASSERT(rrclass == kDNSClass_IN);
+ UNITTEST_ASSERT(rdata[0] == dns_response_ipv4.b[0]);
+ UNITTEST_ASSERT(rdata[1] == dns_response_ipv4.b[1]);
+ UNITTEST_ASSERT(rdata[2] == dns_response_ipv4.b[2]);
+ UNITTEST_ASSERT(rdata[3] == dns_response_ipv4.b[3]);
+
+UNITTEST_FOOTER
+
+// This function does memory cleanup and no verification.
+UNITTEST_HEADER(FinalizeUnitTest)
+ mDNS *m = &mDNSStorage;
+ request_state* req = client_request_message;
+ DNSServer *ptr, **p = &m->DNSServers;
+
+ while (req->replies)
+ {
+ reply_state *reply = req->replies;
+ req->replies = req->replies->next;
+ mDNSPlatformMemFree(reply);
+ }
+ mDNSPlatformMemFree(req);
+
+ mDNSPlatformMemFree(local_socket);
+
+ while (*p)
+ {
+ ptr = *p;
+ *p = (*p)->next;
+ LogInfo("FinalizeUnitTest: Deleting server %p %#a:%d (%##s)", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c);
+ mDNSPlatformMemFree(ptr);
+ }
+UNITTEST_FOOTER
+
+// The mDNS_AddDNSServer function adds a dns server to mDNSResponder's list.
+mDNSlocal mStatus AddDNSServer(void)
+{
+ mDNS *m = &mDNSStorage;
+ m->timenow = 0;
+ mDNS_Lock(m);
+ domainname d;
+ mDNSAddr addr;
+ mDNSIPPort port;
+ mDNSs32 serviceID = 0;
+ mDNSu32 scoped = 0;
+ mDNSu32 timeout = dns_server_timeout;
+ mDNSBool cellIntf = 0;
+ mDNSBool isExpensive = 0;
+ mDNSu16 resGroupID = dns_server_resGroupID;
+ mDNSBool reqA = mDNStrue;
+ mDNSBool reqAAAA = mDNStrue;
+ mDNSBool reqDO = mDNSfalse;
+ d.c[0] = 0;
+ addr.type = mDNSAddrType_IPv4;
+ addr.ip.v4.NotAnInteger = dns_server_ipv4.NotAnInteger;
+ port.NotAnInteger = client_resp_src_port;
+ mDNS_AddDNSServer(m, &d, primary_interfaceID, serviceID, &addr, port, scoped, timeout,
+ cellIntf, isExpensive, resGroupID,
+ reqA, reqAAAA, reqDO);
+ mDNS_Unlock(m);
+ return mStatus_NoError;
+}
+
+
diff --git a/mDNSResponder/unittests/CNameRecordTests.h b/mDNSResponder/unittests/CNameRecordTests.h
new file mode 100644
index 00000000..2c2a3a1c
--- /dev/null
+++ b/mDNSResponder/unittests/CNameRecordTests.h
@@ -0,0 +1,9 @@
+
+#ifndef ReconfirmRecordTests_h
+#define ReconfirmRecordTests_h
+
+#include "unittest.h"
+
+int CNameRecordTests(void);
+
+#endif /* ReconfirmRecordTests_h */
diff --git a/mDNSResponder/unittests/LocalOnlyTimeoutTests.c b/mDNSResponder/unittests/LocalOnlyTimeoutTests.c
new file mode 100644
index 00000000..e2959480
--- /dev/null
+++ b/mDNSResponder/unittests/LocalOnlyTimeoutTests.c
@@ -0,0 +1,378 @@
+#include "LocalOnlyTimeoutTests.h"
+#include "unittest_common.h"
+
+mDNSlocal int InitUnitTest(void);
+mDNSlocal int StartLocalOnlyClientQueryRequest(void);
+mDNSlocal int PopulateCacheWithClientLOResponseRecords(void);
+mDNSlocal int RestartLocalOnlyClientQueryRequest(void);
+mDNSlocal int FinalizeUnitTest(void);
+mDNSlocal mStatus InitEtcHostsRecords();
+
+// This unit test's variables
+static request_state* client_request_message;
+static UDPSocket* local_socket;
+static char domainname_cstr[MAX_ESCAPED_DOMAIN_NAME];
+
+// This query request message was generated from the following command: "dns-sd -lo -timeout -Q cardinal2.apple.com. A"
+char query_req_msgbuf[33]= {
+ 0x00, 0x01, 0x90, 0x00,
+ // DNSServiceFlags.L = (kDNSServiceFlagsReturnIntermediates |kDNSServiceFlagsSuppressUnusable | kDNSServiceFlagsTimeout)
+ 0xff, 0xff, 0xff, 0xff,
+ // interfaceIndex = mDNSInterface_LocalOnly
+ 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c,
+ 0x32, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x00, 0x00, 0x01, 0x00,
+ 0x01
+};
+
+UNITTEST_HEADER(LocalOnlyTimeoutTests)
+ UNITTEST_TEST(InitUnitTest)
+ UNITTEST_TEST(StartLocalOnlyClientQueryRequest)
+ UNITTEST_TEST(PopulateCacheWithClientLOResponseRecords)
+ UNITTEST_TEST(RestartLocalOnlyClientQueryRequest)
+ UNITTEST_TEST(FinalizeUnitTest)
+UNITTEST_FOOTER
+
+// The InitUnitTest() initializes a minimal mDNSResponder environment as
+// well as allocates memory for a local_socket and client request.
+// It also sets the domainname_cstr specified in the client's query request.
+// Note: This unit test does not send packets on the wire and it does not open sockets.
+UNITTEST_HEADER(InitUnitTest)
+
+ // Init mDNSStorage
+ mStatus result = init_mdns_storage();
+ if (result != mStatus_NoError)
+ return result;
+
+ // Allocate a client request
+ local_socket = calloc(1, sizeof(request_state));
+
+ // Allocate memory for a request that is used to make client requests.
+ client_request_message = calloc(1, sizeof(request_state));
+
+ // Init domainname that is used by unit tests
+ strlcpy(domainname_cstr, "cardinal2.apple.com.", sizeof(domainname_cstr));
+
+UNITTEST_FOOTER
+
+// This unit test starts a local only request for "cardinal2.apple.com.". It first
+// calls start_client_request to start a query, it then verifies the
+// req and query data structures are set as expected. Next, the cache is verified to
+// be empty by AnswerNewLocalOnlyQuestion() and so results in GenerateNegativeResponse()
+// getting called which sets up a reply with a negative answer in it for the client.
+// On return from mDNS_Execute, the client's reply structure is verified to be set as
+// expected. Lastly the timeout is simulated and mDNS_Execute is called. This results
+// in a call to TimeoutQuestions(). And again, the GenerateNegativeResponse() is called
+// which returns a negative response to the client. This time the client reply is verified
+// to be setup with a timeout result.
+UNITTEST_HEADER(StartLocalOnlyClientQueryRequest)
+
+ mDNS *const m = &mDNSStorage;
+ request_state* req = client_request_message;
+ char *msgptr = (char *)query_req_msgbuf;
+ size_t msgsz = sizeof(query_req_msgbuf);
+ DNSQuestion *q;
+ mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4;
+ mStatus err = mStatus_NoError;
+ char qname_cstr[MAX_ESCAPED_DOMAIN_NAME];
+ struct reply_state *reply;
+ size_t len;
+
+ // Process the unit test's client request
+ start_client_request(req, msgptr, msgsz, query_request, local_socket);
+ UNITTEST_ASSERT(err == mStatus_NoError);
+
+ // Verify the query initialized and request fields were set as expected
+ UNITTEST_ASSERT(err == mStatus_NoError);
+ UNITTEST_ASSERT(req->hdr.version == VERSION);
+ UNITTEST_ASSERT((mDNSs32)req->data_bytes > min_size);
+ UNITTEST_ASSERT(req->flags == (kDNSServiceFlagsSuppressUnusable | kDNSServiceFlagsReturnIntermediates | kDNSServiceFlagsTimeout));
+ UNITTEST_ASSERT(req->interfaceIndex == kDNSServiceInterfaceIndexLocalOnly);
+ UNITTEST_ASSERT(req->terminate != mDNSNULL);
+
+ q = &req->u.queryrecord.q;
+ UNITTEST_ASSERT(q == m->NewLocalOnlyQuestions);
+ UNITTEST_ASSERT(m->Questions == NULL);
+ UNITTEST_ASSERT(m->NewQuestions == NULL);
+ UNITTEST_ASSERT(q->SuppressUnusable == 1);
+ UNITTEST_ASSERT(q->ReturnIntermed == 1);
+ UNITTEST_ASSERT(q->SuppressQuery == 0); // Regress <rdar://problem/27571734>
+
+ UNITTEST_ASSERT(q->qnameOrig == mDNSNULL);
+ ConvertDomainNameToCString(&q->qname, qname_cstr);
+ UNITTEST_ASSERT(!strcmp(qname_cstr, domainname_cstr));
+ UNITTEST_ASSERT(q->qnamehash == DomainNameHashValue(&q->qname));
+
+ UNITTEST_ASSERT(q->InterfaceID == mDNSInterface_LocalOnly);
+ UNITTEST_ASSERT(q->flags == req->flags);
+ UNITTEST_ASSERT(q->qtype == 1);
+ UNITTEST_ASSERT(q->qclass == 1);
+ UNITTEST_ASSERT(q->LongLived == 0);
+ UNITTEST_ASSERT(q->ExpectUnique == mDNSfalse);
+ UNITTEST_ASSERT(q->ForceMCast == 0);
+ UNITTEST_ASSERT(q->TimeoutQuestion == 1);
+ UNITTEST_ASSERT(q->WakeOnResolve == 0);
+ UNITTEST_ASSERT(q->UseBackgroundTrafficClass == 0);
+ UNITTEST_ASSERT(q->ValidationRequired == 0);
+ UNITTEST_ASSERT(q->ValidatingResponse == 0);
+ UNITTEST_ASSERT(q->ProxyQuestion == 0);
+ UNITTEST_ASSERT(q->AnonInfo == mDNSNULL);
+ UNITTEST_ASSERT(q->QuestionCallback != mDNSNULL);
+ UNITTEST_ASSERT(q->QuestionContext == req);
+ UNITTEST_ASSERT(q->SearchListIndex == 0);
+ UNITTEST_ASSERT(q->DNSSECAuthInfo == mDNSNULL);
+ UNITTEST_ASSERT(q->DAIFreeCallback == mDNSNULL);
+ UNITTEST_ASSERT(q->RetryWithSearchDomains == 0);
+ UNITTEST_ASSERT(q->StopTime != 0);
+ UNITTEST_ASSERT(q->AppendSearchDomains == 0);
+ UNITTEST_ASSERT(q->AppendLocalSearchDomains == 0);
+ UNITTEST_ASSERT(q->DuplicateOf == mDNSNULL);
+
+ // At this point the the cache is empty. Calling mDNS_Execute will answer the local-only
+ // question with a negative response.
+ m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+ mDNS_Execute(m); // Regress <rdar://problem/28721294>
+
+ // Verify reply is a negative response and error code is set to kDNSServiceErr_NoSuchRecord error.
+ reply = req->replies;
+ UNITTEST_ASSERT(reply != mDNSNULL);
+
+ UNITTEST_ASSERT(m->NewLocalOnlyQuestions == NULL);
+ UNITTEST_ASSERT(q->LOAddressAnswers == 0);
+
+ len = get_reply_len(qname_cstr, 0);
+
+ UNITTEST_ASSERT(reply->next == mDNSNULL);
+ UNITTEST_ASSERT(reply->totallen == reply->mhdr->datalen + sizeof(ipc_msg_hdr));
+ UNITTEST_ASSERT(reply->mhdr->version == VERSION);
+ UNITTEST_ASSERT(reply->mhdr->datalen == len);
+ UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
+ UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
+
+ UNITTEST_ASSERT(reply->rhdr->flags == htonl(kDNSServiceFlagsAdd));
+ UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexLocalOnly); // Regress <rdar://problem/27340874>
+ UNITTEST_ASSERT(reply->rhdr->error ==
+ (DNSServiceErrorType)htonl(kDNSServiceErr_NoSuchRecord)); // Regress <rdar://problem/24827555>
+
+ // Simulate what udsserver_idle normally does for clean up
+ freeL("StartLocalOnlyClientQueryRequest:reply", reply);
+ req->replies = NULL;
+
+ // Simulate the query time out of the local-only question.
+ // The expected behavior is a negative answer with time out error
+ m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+ q->StopTime = mDNS_TimeNow_NoLock(m);
+ m->NextScheduledStopTime -= mDNSPlatformOneSecond*5;
+ mDNS_Execute(m);
+
+ // Verify the reply is a negative response with timeout error.
+ reply = req->replies;
+ UNITTEST_ASSERT(reply != NULL);
+ UNITTEST_ASSERT(m->NewLocalOnlyQuestions == NULL);
+ UNITTEST_ASSERT(q->LOAddressAnswers == 0);
+
+ len = get_reply_len(qname_cstr, 0);
+
+ UNITTEST_ASSERT(reply->next == mDNSNULL);
+ UNITTEST_ASSERT(reply->totallen == len + sizeof(ipc_msg_hdr));
+ UNITTEST_ASSERT(reply->mhdr->version == VERSION);
+ UNITTEST_ASSERT(reply->mhdr->datalen == len);
+ UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
+ UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
+ UNITTEST_ASSERT(reply->rhdr->flags == htonl(kDNSServiceFlagsAdd));
+ UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexLocalOnly); // Regress <rdar://problem/27340874>
+ UNITTEST_ASSERT(reply->rhdr->error ==
+ (DNSServiceErrorType)htonl(kDNSServiceErr_Timeout)); // Regress <rdar://problem/27562965>
+
+ // Free request and reallocate to use when query is restarted
+ free_req(req);
+ client_request_message = calloc(1, sizeof(request_state));
+
+UNITTEST_FOOTER
+
+// This unit test populates the cache with four /etc/hosts records and then
+// verifies there are four entries in the cache.
+UNITTEST_HEADER(PopulateCacheWithClientLOResponseRecords)
+
+ mDNS *const m = &mDNSStorage;
+
+ // Verify cache is empty
+ int count = LogEtcHosts_ut(m);
+ UNITTEST_ASSERT(count == 0);
+
+ // Populate /etc/hosts
+ mStatus result = InitEtcHostsRecords();
+ UNITTEST_ASSERT(result == mStatus_NoError);
+
+ // mDNS_Execute is called to populate the /etc/hosts cache.
+ m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+ mDNS_Execute(m);
+
+ count = LogEtcHosts_ut(m);
+ UNITTEST_ASSERT(count == 4);
+
+UNITTEST_FOOTER
+
+// This unit test starts a local only request for "cardinal2.apple.com.". It first
+// calls start_client_request to start a query, it then verifies the
+// req and query data structures are set as expected. Next, the cache is verified to
+// contain the answer by AnswerNewLocalOnlyQuestion() and so results in setting up an
+// answer reply to the client. On return from mDNS_Execute, the client's reply structure
+// is verified to be set as expected. Lastly the timeout is simulated and mDNS_Execute is
+// called. This results in a call to TimeoutQuestions(). And this time, the
+// GenerateNegativeResponse() is called which returns a negative response to the client
+// which specifies the timeout occurred. Again, the answer reply is verified to
+// to specify a timeout.
+UNITTEST_HEADER(RestartLocalOnlyClientQueryRequest)
+
+ mDNS *const m = &mDNSStorage;
+ request_state* req = client_request_message;
+ char *msgptr = (char *)query_req_msgbuf;
+ size_t msgsz = sizeof(query_req_msgbuf); DNSQuestion *q;
+ mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4;
+ mStatus err = mStatus_NoError;
+ char qname_cstr[MAX_ESCAPED_DOMAIN_NAME];
+ struct reply_state *reply;
+ size_t len;
+
+ // Process the unit test's client request
+ start_client_request(req, msgptr, msgsz, query_request, local_socket);
+ UNITTEST_ASSERT(err == mStatus_NoError);
+
+ UNITTEST_ASSERT(err == mStatus_NoError);
+ UNITTEST_ASSERT(req->hdr.version == VERSION);
+ UNITTEST_ASSERT((mDNSs32)req->data_bytes > min_size);
+ UNITTEST_ASSERT(req->flags == (kDNSServiceFlagsSuppressUnusable | kDNSServiceFlagsReturnIntermediates | kDNSServiceFlagsTimeout));
+ UNITTEST_ASSERT(req->interfaceIndex == kDNSServiceInterfaceIndexLocalOnly);
+ UNITTEST_ASSERT(req->terminate != mDNSNULL);
+ UNITTEST_ASSERT(m->Questions == NULL);
+
+ q = &req->u.queryrecord.q;
+ UNITTEST_ASSERT(q == m->NewLocalOnlyQuestions);
+ UNITTEST_ASSERT(q->SuppressUnusable == 1);
+ UNITTEST_ASSERT(q->ReturnIntermed == 1);
+ UNITTEST_ASSERT(q->SuppressQuery == 0); // Regress <rdar://problem/27571734>
+ UNITTEST_ASSERT(q->qnamehash == DomainNameHashValue(&q->qname));
+ UNITTEST_ASSERT(q->InterfaceID == mDNSInterface_LocalOnly);
+ UNITTEST_ASSERT(q->flags == req->flags);
+ UNITTEST_ASSERT(q->qtype == 1);
+ UNITTEST_ASSERT(q->qclass == 1);
+ UNITTEST_ASSERT(q->LongLived == 0);
+ UNITTEST_ASSERT(q->ExpectUnique == mDNSfalse);
+ UNITTEST_ASSERT(q->ForceMCast == 0);
+ UNITTEST_ASSERT(q->TimeoutQuestion == 1);
+ UNITTEST_ASSERT(q->WakeOnResolve == 0);
+ UNITTEST_ASSERT(q->UseBackgroundTrafficClass == 0);
+ UNITTEST_ASSERT(q->ValidationRequired == 0);
+ UNITTEST_ASSERT(q->ValidatingResponse == 0);
+ UNITTEST_ASSERT(q->ProxyQuestion == 0);
+ UNITTEST_ASSERT(q->AnonInfo == mDNSNULL);
+ UNITTEST_ASSERT(q->QuestionCallback != mDNSNULL);
+ UNITTEST_ASSERT(q->QuestionContext == req);
+ UNITTEST_ASSERT(q->SearchListIndex == 0);
+ UNITTEST_ASSERT(q->DNSSECAuthInfo == mDNSNULL);
+ UNITTEST_ASSERT(q->DAIFreeCallback == mDNSNULL);
+ UNITTEST_ASSERT(q->RetryWithSearchDomains == 0);
+ UNITTEST_ASSERT(q->StopTime != 0);
+ UNITTEST_ASSERT(q->AppendSearchDomains == 0);
+ UNITTEST_ASSERT(q->AppendLocalSearchDomains == 0);
+ UNITTEST_ASSERT(q->DuplicateOf == mDNSNULL);
+ ConvertDomainNameToCString(&q->qname, qname_cstr);
+ UNITTEST_ASSERT(!strcmp(qname_cstr, domainname_cstr));
+
+ // Answer local-only question with found cache entry
+ m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+ mDNS_Execute(m); // Regress <rdar://problem/28721294>
+ UNITTEST_ASSERT(m->NewLocalOnlyQuestions == NULL);
+ UNITTEST_ASSERT(req->u.queryrecord.ans == 1);
+ UNITTEST_ASSERT(q->LOAddressAnswers == 1);
+ UNITTEST_ASSERT(q == m->LocalOnlyQuestions);
+
+ reply = req->replies;
+ len = get_reply_len(qname_cstr, 4);
+
+ UNITTEST_ASSERT(reply->next == mDNSNULL);
+ UNITTEST_ASSERT(reply->totallen == len + sizeof(ipc_msg_hdr));
+ UNITTEST_ASSERT(reply->mhdr->version == VERSION);
+ UNITTEST_ASSERT(reply->mhdr->datalen == len);
+ UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
+ UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
+ UNITTEST_ASSERT(reply->rhdr->flags == htonl(kDNSServiceFlagsAdd));
+ UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexLocalOnly); // Regress <rdar://problem/27340874>
+ UNITTEST_ASSERT(reply->rhdr->error == kDNSServiceErr_NoError);
+
+ // Simulate the query time out of the local-only question.
+ // The expected behavior is a negative answer with time out error
+ m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+ q->StopTime = mDNS_TimeNow_NoLock(m);
+ m->NextScheduledStopTime -= mDNSPlatformOneSecond*5;
+ mDNS_Execute(m);
+
+ reply = req->replies->next;
+ UNITTEST_ASSERT(reply != NULL);
+ UNITTEST_ASSERT(reply->next == NULL);
+ UNITTEST_ASSERT(m->NewLocalOnlyQuestions == NULL);
+ UNITTEST_ASSERT(q->LOAddressAnswers == 0);
+ len = get_reply_len(qname_cstr, 0);
+
+ UNITTEST_ASSERT(reply->next == mDNSNULL);
+ UNITTEST_ASSERT(reply->totallen == len + + sizeof(ipc_msg_hdr));
+ UNITTEST_ASSERT(reply->mhdr->version == VERSION);
+ UNITTEST_ASSERT(reply->mhdr->datalen == len);
+ UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
+ UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
+ UNITTEST_ASSERT(reply->rhdr->flags == htonl(kDNSServiceFlagsAdd));
+ UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexLocalOnly); // Regress <rdar://problem/27340874>
+ UNITTEST_ASSERT(reply->rhdr->error ==
+ (DNSServiceErrorType)htonl(kDNSServiceErr_Timeout)); // Regress <rdar://problem/27562965>
+
+ free_req(req);
+UNITTEST_FOOTER
+
+// This function does memory cleanup and no verification.
+UNITTEST_HEADER(FinalizeUnitTest)
+ mDNSPlatformMemFree(local_socket);
+UNITTEST_FOOTER
+
+mDNSlocal mStatus InitEtcHostsRecords(void)
+{
+ mDNS *m = &mDNSStorage;
+ struct sockaddr_storage hostaddr;
+
+ AuthHash newhosts;
+ mDNSPlatformMemZero(&newhosts, sizeof(AuthHash));
+
+ memset(&hostaddr, 0, sizeof(hostaddr));
+ get_ip("127.0.0.1", &hostaddr);
+
+ domainname domain;
+ MakeDomainNameFromDNSNameString(&domain, "localhost");
+
+ mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
+
+ memset(&hostaddr, 0, sizeof(hostaddr));
+ get_ip("0000:0000:0000:0000:0000:0000:0000:0001", &hostaddr);
+
+ MakeDomainNameFromDNSNameString(&domain, "localhost");
+
+ mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
+
+ memset(&hostaddr, 0, sizeof(hostaddr));
+ get_ip("255.255.255.255", &hostaddr);
+
+ MakeDomainNameFromDNSNameString(&domain, "broadcasthost");
+
+ mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
+
+ memset(&hostaddr, 0, sizeof(hostaddr));
+ get_ip("17.226.40.200", &hostaddr);
+
+ MakeDomainNameFromDNSNameString(&domain, "cardinal2.apple.com");
+
+ mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
+ UpdateEtcHosts_ut(&newhosts);
+
+ m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+ mDNS_Execute(m);
+
+ return mStatus_NoError;
+}
diff --git a/mDNSResponder/unittests/LocalOnlyTimeoutTests.h b/mDNSResponder/unittests/LocalOnlyTimeoutTests.h
new file mode 100644
index 00000000..3ff56082
--- /dev/null
+++ b/mDNSResponder/unittests/LocalOnlyTimeoutTests.h
@@ -0,0 +1,9 @@
+
+#ifndef LocalOnlyTimeoutTests_h
+#define LocalOnlyTimeoutTests_h
+
+#include "unittest.h"
+
+int LocalOnlyTimeoutTests(void);
+
+#endif /* LocalOnlyTimeoutTests_h */
diff --git a/mDNSResponder/unittests/ResourceRecordTest.c b/mDNSResponder/unittests/ResourceRecordTest.c
index d0530086..3c976c3d 100644
--- a/mDNSResponder/unittests/ResourceRecordTest.c
+++ b/mDNSResponder/unittests/ResourceRecordTest.c
@@ -18,7 +18,7 @@ UNITTEST_HEADER(TXTSetupTest)
AuthRecord authRec;
mDNS_SetupResourceRecord(&authRec, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeShared, AuthRecordAny,mDNSNULL, mDNSNULL);
- UNITTEST_ASSERT_RETURN(authRec.resrec.RecordType == kDNSType_TXT);
+ // This fails >> UNITTEST_ASSERT_RETURN(authRec.resrec.RecordType == kDNSType_TXT);
UNITTEST_ASSERT_RETURN(authRec.resrec.rdata->MaxRDLength == sizeof(RDataBody));
// Retest with a RDataStorage set to a a buffer
@@ -28,7 +28,8 @@ UNITTEST_FOOTER
UNITTEST_HEADER(ASetupTest)
AuthRecord authRec;
mDNS_SetupResourceRecord(&authRec, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
- UNITTEST_ASSERT_RETURN(authRec.resrec.RecordType == kDNSType_A);
+
+ // This fails >> UNITTEST_ASSERT_RETURN(authRec.resrec.RecordType == kDNSType_A);
// Add more verifications
UNITTEST_FOOTER
diff --git a/mDNSResponder/unittests/daemon_ut.c b/mDNSResponder/unittests/daemon_ut.c
new file mode 100644
index 00000000..526b3513
--- /dev/null
+++ b/mDNSResponder/unittests/daemon_ut.c
@@ -0,0 +1,35 @@
+#include "DNSCommon.h"
+
+mDNSexport void init_logging_ut(void)
+{
+#if APPLE_OSX_mDNSResponder
+ init_logging();
+
+ /* When doing unit testing, it is likely that some local functions and
+ * variables will not be needed to do unit testing validation. So to get
+ * around compiler warnings about unused functions or variables, each
+ * warning work-around is handled explicitly below.
+ */
+
+ /* The next three LogOperation() are used to trick the compiler into
+ * suppressing unused function and variable warnings. This is done by
+ * outputting the function or variable pointer to a log message.
+ */
+ LogOperation("Quiet compiler warnings for KQueueLoop= %p, "
+ "KQWokenFlushBytes= %p, SignalCallback= %p, "
+ "mDNS_StatusCallback= %p, LaunchdCheckin= %p",
+ KQueueLoop, KQWokenFlushBytes,
+ SignalCallback, mDNS_StatusCallback,
+ LaunchdCheckin);
+ LogOperation("Quiet compiler warnings for SandboxProcess= %p, "
+ "mDNSDaemonInitialize= %p, HandleSIG= %p, "
+ "PreferencesGetValueInt= %p, PreferencesGetValueBool= %p",
+ SandboxProcess, mDNSDaemonInitialize,
+ HandleSIG, PreferencesGetValueInt,
+ PreferencesGetValueBool);
+ LogOperation("Quiet compiler warnings for rrcachestorage= %p, "
+ "NoMulticastAdvertisements= %p",
+ rrcachestorage, NoMulticastAdvertisements);
+
+#endif // APPLE_OSX_mDNSResponder
+}
diff --git a/mDNSResponder/unittests/mDNSCoreReceiveTest.c b/mDNSResponder/unittests/mDNSCoreReceiveTest.c
new file mode 100644
index 00000000..ece21407
--- /dev/null
+++ b/mDNSResponder/unittests/mDNSCoreReceiveTest.c
@@ -0,0 +1,151 @@
+#include "mDNSCoreReceiveTest.h"
+#include "unittest_common.h"
+
+int InitmDNSCoreReceiveTest(void);
+int ValidQueryReqTest(void);
+int NullDstQueryReqTest(void);
+int ReceiveArpLogMsgTest(void);
+void InitmDNSStorage(mDNS *const m);
+
+// This DNS message was gleaned from a uDNS query request packet that was captured with Wireshark.
+uint8_t udns_query_request_message[28] = { // contains 1 question for www.f5.com
+ 0x31, 0xca, // transaction id
+ 0x01, 0x00, // flags
+ 0x00, 0x01, // 1 question
+ 0x00, 0x00, // no anwsers
+ 0x00, 0x00, // no authoritative answers
+ 0x00, 0x00, // no additionals
+ 0x03, 0x77, 0x77, 0x77, 0x02, 0x66, 0x35, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01
+};
+
+// This DNS message was gleaned from a uDNS query request packet that was captured with Wireshark.
+// Then the header id (more specifically, the msg->h.id) was deliberately cleared to force code
+// path to traverse regression case, <rdar://problem/28556513>.
+uint8_t udns_query_request_message_with_invalid_id[28] = { // contains 1 question for www.f5.com, msg->h.id = 0
+ 0x00, 0x00, // transaction id
+ 0x01, 0x00, // flags
+ 0x00, 0x01, // 1 question
+ 0x00, 0x00, // no anwsers
+ 0x00, 0x00, // no authoritative answers
+ 0x00, 0x00, // no additionals
+ 0x03, 0x77, 0x77, 0x77, 0x02, 0x66, 0x35, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01
+};
+
+uint8_t arp_request_packet[28] = { // contains 1 question for www.f5.com, msg->h.id = 0
+ 0x00, 0x01, // hardware type: enet
+ 0x08, 0x00, // protocol type: IP
+ 0x06, // hardware size
+ 0x04, // Protcol size
+ 0x00, 0x01, // opcode request
+ 0x24, 0x01, 0xc7, 0x24, 0x35, 0x00, // Sender mac addr
+ 0x11, 0xe2, 0x14, 0x01, // Sender ip addr
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // target mac addr
+ 0x11, 0xe2, 0x17, 0xbe // target ip addr
+};
+UNITTEST_HEADER(mDNSCoreReceiveTest)
+ UNITTEST_TEST(InitmDNSCoreReceiveTest)
+ UNITTEST_TEST(ValidQueryReqTest)
+ UNITTEST_TEST(NullDstQueryReqTest)
+ UNITTEST_TEST(ReceiveArpLogMsgTest)
+UNITTEST_FOOTER
+
+UNITTEST_HEADER(InitmDNSCoreReceiveTest)
+ mDNSPlatformTimeInit();
+ init_logging_ut();
+ mDNS_LoggingEnabled = 0;
+ mDNS_PacketLoggingEnabled = 0;
+UNITTEST_FOOTER
+
+UNITTEST_HEADER(ReceiveArpLogMsgTest)
+ // Init unit test environment and verify no error occurred.
+ mStatus result = init_mdns_environment(mDNStrue);
+ UNITTEST_ASSERT(result == mStatus_NoError);
+
+ UNITTEST_ASSERT(result == mStatus_NoError);
+ ArpLogMsgTest(&mDNSStorage, (const ARP_EthIP *) arp_request_packet, primary_interfaceID);
+ UNITTEST_ASSERT(result == mStatus_NoError);
+UNITTEST_FOOTER
+
+UNITTEST_HEADER(ValidQueryReqTest)
+ mDNS *const m = &mDNSStorage;
+ mDNSAddr srcaddr, dstaddr;
+ mDNSIPPort srcport, dstport;
+ DNSMessage * msg;
+ const mDNSu8 * end;
+
+ // This test case does not require setup of interfaces, the record's cache, or pending questions
+ // so m is initialized to all zeros.
+ InitmDNSStorage(m);
+
+ // Used random values for srcaddr and srcport
+ srcaddr.type = mDNSAddrType_IPv4;
+ srcaddr.ip.v4.b[0] = 192;
+ srcaddr.ip.v4.b[1] = 168;
+ srcaddr.ip.v4.b[2] = 1;
+ srcaddr.ip.v4.b[3] = 10;
+ srcport.NotAnInteger = swap16((mDNSu16)53);
+
+ // Used random values for dstaddr and dstport
+ dstaddr.type = mDNSAddrType_IPv4;
+ dstaddr.ip.v4.b[0] = 192;
+ dstaddr.ip.v4.b[1] = 168;
+ dstaddr.ip.v4.b[2] = 1;
+ dstaddr.ip.v4.b[3] = 20;
+ dstport.NotAnInteger = swap16((mDNSu16)49339);
+
+ // Set message to a DNS message (copied from a WireShark packet)
+ msg = (DNSMessage *)udns_query_request_message;
+ end = udns_query_request_message + sizeof(udns_query_request_message);
+
+ // Execute mDNSCoreReceive using a valid DNS message
+ mDNSCoreReceive(m, msg, end, &srcaddr, srcport, &dstaddr, dstport, if_nametoindex("en0"));
+
+ // Verify that mDNSCoreReceiveQuery traversed the normal code path
+ UNITTEST_ASSERT(m->mDNSStats.NormalQueries == 1);
+
+UNITTEST_FOOTER
+
+UNITTEST_HEADER(NullDstQueryReqTest)
+
+ mDNS *const m = &mDNSStorage;
+ mDNSAddr srcaddr;
+ mDNSIPPort srcport, dstport;
+ DNSMessage * msg;
+ const mDNSu8 * end;
+
+ // This test case does not require setup of interfaces, the record's cache, or pending questions
+ // so m is initialized to all zeros.
+ InitmDNSStorage(m);
+
+ // Used random values for srcaddr and srcport
+ srcaddr.type = mDNSAddrType_IPv4;
+ srcaddr.ip.v4.b[0] = 192;
+ srcaddr.ip.v4.b[1] = 168;
+ srcaddr.ip.v4.b[2] = 1;
+ srcaddr.ip.v4.b[3] = 10;
+ srcport.NotAnInteger = swap16((mDNSu16)53);
+
+ // Used random value for dstport
+ dstport.NotAnInteger = swap16((mDNSu16)49339);
+
+ // Set message to a DNS message (copied from a WireShark packet)
+ msg = (DNSMessage *)udns_query_request_message_with_invalid_id;
+ end = udns_query_request_message_with_invalid_id + sizeof(udns_query_request_message_with_invalid_id);
+
+ // Execute mDNSCoreReceive to regress <rdar://problem/28556513>
+ mDNSCoreReceive(m, msg, end, &srcaddr, srcport, NULL, dstport, if_nametoindex("en0"));
+
+ // Verify that mDNSCoreReceiveQuery was NOT traversed through the normal code path
+ UNITTEST_ASSERT(m->mDNSStats.NormalQueries == 0);
+
+ // Verify code path that previously crashed, in <rdar://problem/28556513>, now traverses successfully
+ // by checking a counter that was incremented on code path that crashed.
+ UNITTEST_ASSERT(m->MPktNum == 1);
+
+UNITTEST_FOOTER
+
+void InitmDNSStorage(mDNS *const m)
+{
+ memset(m, 0, sizeof(mDNS));
+}
+
diff --git a/mDNSResponder/unittests/mDNSCoreReceiveTest.h b/mDNSResponder/unittests/mDNSCoreReceiveTest.h
new file mode 100644
index 00000000..7c7274e9
--- /dev/null
+++ b/mDNSResponder/unittests/mDNSCoreReceiveTest.h
@@ -0,0 +1,9 @@
+
+#ifndef mDNSCoreReceiveTest_h
+#define mDNSCoreReceiveTest_h
+
+#include "unittest.h"
+
+int mDNSCoreReceiveTest(void);
+
+#endif /* mDNSCoreReceiveTest_h */
diff --git a/mDNSResponder/unittests/main.c b/mDNSResponder/unittests/main.c
index 752fffb7..9b30ab4c 100644
--- a/mDNSResponder/unittests/main.c
+++ b/mDNSResponder/unittests/main.c
@@ -18,16 +18,25 @@
#include "unittest.h"
#include "DNSMessageTest.h"
+#include "ResourceRecordTest.h"
+#include "mDNSCoreReceiveTest.h"
+#include "CNameRecordTests.h"
+#include "LocalOnlyTimeoutTests.h"
const char *HWVersionString = "unittestMac1,1";
const char *OSVersionString = "unittest 1.1.1 (1A111)";
const char *BinaryNameString = "unittest";
const char *VersionString = "unittest mDNSResponer-00 (Jan 1 1970 00:00:00)";
-int run_tests(void);
+
UNITTEST_HEADER(run_tests)
UNITTEST_GROUP(DNSMessageTest)
+UNITTEST_GROUP(ResourceRecordTest)
+UNITTEST_GROUP(mDNSCoreReceiveTest)
+//UNITTEST_GROUP(CNameRecordTests) // Commenting out until issue reported in <rdar://problem/30589360> is debugged.
+UNITTEST_GROUP(LocalOnlyTimeoutTests)
UNITTEST_FOOTER
-UNITTEST_MAIN
+// UNITTEST_MAIN is run in daemon.c
+
diff --git a/mDNSResponder/unittests/mdns_macosx_ut.c b/mDNSResponder/unittests/mdns_macosx_ut.c
new file mode 100644
index 00000000..9dae75a0
--- /dev/null
+++ b/mDNSResponder/unittests/mdns_macosx_ut.c
@@ -0,0 +1,66 @@
+#include "DNSCommon.h" // Defines general DNS utility routines
+
+// To match *either* a v4 or v6 instance of this interface
+mDNSlocal mDNSInterfaceID SearchForInterfaceByAddr(mDNSAddr* addr)
+{
+ NetworkInterfaceInfoOSX *i;
+ for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
+ if (i->Exists)
+ {
+ if ((i->ifinfo.ip.type == mDNSAddrType_IPv4) &&
+ i->ifinfo.ip.ip.v4.NotAnInteger == addr->ip.v4.NotAnInteger)
+ return i->ifinfo.InterfaceID;
+ else if ((i->ifinfo.ip.type == mDNSAddrType_IPv6) &&
+ (i->ifinfo.ip.ip.v6.l[0] == addr->ip.v6.l[0] &&
+ i->ifinfo.ip.ip.v6.l[1] == addr->ip.v6.l[1] &&
+ i->ifinfo.ip.ip.v6.l[2] == addr->ip.v6.l[2] &&
+ i->ifinfo.ip.ip.v6.l[3] == addr->ip.v6.l[3])
+ )
+ return i->ifinfo.InterfaceID;
+ }
+ return(NULL);
+}
+
+mDNSexport void SetInterfaces_ut(mDNSInterfaceID* pri_id, mDNSAddr *pri_v4, mDNSAddr* pri_v6, mDNSAddr* pri_router)
+{
+ mDNSs32 utc = mDNSPlatformUTC();
+
+ MarkAllInterfacesInactive(utc);
+ UpdateInterfaceList(utc);
+ ClearInactiveInterfaces(utc);
+ SetupActiveInterfaces(utc);
+
+ // set primary interface info
+ {
+ mDNSAddr* addr;
+ 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);
+
+ mDNSPlatformGetPrimaryInterface(pri_v4, pri_v6, pri_router);
+ addr = (pri_v4->type == mDNSAddrType_IPv4) ? pri_v4 : pri_v6;
+ *pri_id = SearchForInterfaceByAddr(addr);
+
+ CFRelease(NetworkChangedKey_IPv4);
+ CFRelease(NetworkChangedKey_IPv6);
+ CFRelease(NetworkChangedKey_Hostnames);
+ CFRelease(NetworkChangedKey_Computername);
+ CFRelease(NetworkChangedKey_DNS);
+ CFRelease(NetworkChangedKey_StateInterfacePrefix);
+ }
+}
+
+mDNSexport mDNSBool mDNSMacOSXCreateEtcHostsEntry_ut(const domainname *domain, const struct sockaddr *sa, const domainname *cname, char *ifname, AuthHash *auth)
+{
+ return mDNSMacOSXCreateEtcHostsEntry(domain, sa, cname, ifname, auth);
+}
+
+mDNSexport void UpdateEtcHosts_ut(void *context)
+{
+ mDNS_Lock(&mDNSStorage);
+ UpdateEtcHosts(&mDNSStorage, context);
+ mDNS_Unlock(&mDNSStorage);
+}
diff --git a/mDNSResponder/unittests/mdns_ut.c b/mDNSResponder/unittests/mdns_ut.c
new file mode 100644
index 00000000..907cfa69
--- /dev/null
+++ b/mDNSResponder/unittests/mdns_ut.c
@@ -0,0 +1,17 @@
+#include "DNSCommon.h" // Defines general DNS utility routines
+
+mDNSexport mStatus mDNS_InitStorage_ut(mDNS *const m, mDNS_PlatformSupport *const p,
+ CacheEntity *rrcachestorage, mDNSu32 rrcachesize,
+ mDNSBool AdvertiseLocalAddresses, mDNSCallback *Callback, void *Context)
+{
+ return mDNS_InitStorage(m, p, rrcachestorage, rrcachesize, AdvertiseLocalAddresses, Callback, Context);
+}
+
+mDNSexport mStatus ArpLogMsgTest(mDNS *const m, const ARP_EthIP *const arp, const mDNSInterfaceID InterfaceID)
+{
+ NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
+ static const char msg[] = "ARP Req message";
+ LogMsg("Arp %-7s %s %.6a %.4a for %.4a",
+ intf->ifname, msg, arp->sha.b, arp->spa.b, arp->tpa.b);
+ return mStatus_NoError;
+}
diff --git a/mDNSResponder/unittests/uds_daemon_ut.c b/mDNSResponder/unittests/uds_daemon_ut.c
new file mode 100644
index 00000000..8a07e9ba
--- /dev/null
+++ b/mDNSResponder/unittests/uds_daemon_ut.c
@@ -0,0 +1,43 @@
+#include "DNSCommon.h" // Defines general DNS utility routines
+
+mDNSexport mStatus handle_client_request_ut(void *req)
+{
+ return handle_client_request((request_state*)req);
+}
+
+mDNSexport void LogCacheRecords_ut(mDNSs32 now, mDNSu32* retCacheUsed, mDNSu32* retCacheActive)
+{
+ mDNSu32 CacheUsed =0, CacheActive =0, slot;
+ const CacheGroup *cg;
+ const CacheRecord *cr;
+
+ LogMsgNoIdent("------------ Cache -------------");
+ LogMsgNoIdent("Slt Q TTL if U Type rdlen");
+ for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
+ {
+ for (cg = mDNSStorage.rrcache_hash[slot]; cg; cg=cg->next)
+ {
+ CacheUsed++; // Count one cache entity for the CacheGroup object
+ for (cr = cg->members; cr; cr=cr->next)
+ {
+ const mDNSs32 remain = cr->resrec.rroriginalttl - (now - cr->TimeRcvd) / mDNSPlatformOneSecond;
+ const char *ifname;
+ mDNSInterfaceID InterfaceID = cr->resrec.InterfaceID;
+ if (!InterfaceID && cr->resrec.rDNSServer && cr->resrec.rDNSServer->scoped)
+ InterfaceID = cr->resrec.rDNSServer->interface;
+ ifname = InterfaceNameForID(&mDNSStorage, InterfaceID);
+ if (cr->CRActiveQuestion) CacheActive++;
+ PrintOneCacheRecord(cr, slot, remain, ifname, &CacheUsed);
+ PrintCachedRecords(cr, slot, remain, ifname, &CacheUsed);
+ }
+ }
+ }
+
+ *retCacheUsed = CacheUsed;
+ *retCacheActive = CacheActive;
+}
+
+mDNSexport int LogEtcHosts_ut(mDNS *const m)
+{
+ return LogEtcHosts(m);
+}
diff --git a/mDNSResponder/unittests/unittest.h b/mDNSResponder/unittests/unittest.h
index a219aa86..84dd5d77 100644
--- a/mDNSResponder/unittests/unittest.h
+++ b/mDNSResponder/unittests/unittest.h
@@ -20,7 +20,9 @@
#include <unistd.h>
#include <assert.h>
#include <signal.h>
+#include "unittest_common.h"
+#include <MacTypes.h>
#ifndef _UNITTEST_H_
#define _UNITTEST_H_
@@ -38,7 +40,8 @@ typedef struct __test_item_
int iter_count;
} __test_item;
-
+int run_tests(void);
+
#define UNITTEST_HEADER(X) int X() { int __success = 1; __test_item* __i = NULL;
#define UNITTEST_GROUP(X) { printf("== %s ==\n", #X); __success = X() && __success; }
@@ -61,9 +64,14 @@ void _unittest_print_list(__test_item* __i);
signal(SIGPIPE, SIG_IGN); \
FILE* fp; \
unlink("unittest_success"); \
- if (!run_tests()) return -1; \
+ if (!run_tests()) \
+ { \
+ printf("unit test FAILED\n"); \
+ return -1; \
+ } \
fp = fopen("unittest_success", "w"); \
if (!fp) return -2; \
+ fprintf(fp, "unit test %s\n", "SUCCEEDED"); \
fclose(fp); \
printf("unit test SUCCESS\n"); \
if (argc != 1) \
@@ -74,6 +82,38 @@ void _unittest_print_list(__test_item* __i);
} \
return 0; \
}
+#define UNITTEST_SENDDNSMESSAGE mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end, \
+ mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, \
+ mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo, \
+ mDNSBool useBackgroundTrafficClass) \
+ { \
+ (void)(m); \
+ (void)(msg); \
+ (void)(end); \
+ (void)(InterfaceID); \
+ (void)(src); \
+ (void)(dst); \
+ (void)(dstport); \
+ (void)(sock); \
+ (void)(authInfo); \
+ (void)(useBackgroundTrafficClass); \
+ return 0; \
+ }
+
+#define UNITTEST_SETSOCKOPT void mDNSPlatformSetSocktOpt(void *sockCxt, mDNSTransport_Type transType, \
+ mDNSAddr_Type addrType, const DNSQuestion *q) \
+ { \
+ (void)(sockCxt); \
+ (void)(transType); \
+ (void)(addrType); \
+ (void)(q); \
+ return; \
+ }
+
+#define UNITTEST_UDPCLOSE void mDNSPlatformUDPClose(UDPSocket *sock) \
+ { \
+ (void)(sock); \
+ }
#define UNITTEST_FAIL_ASSERT { assert(((void*)__func__) == 0); }
diff --git a/mDNSResponder/unittests/unittest_common.c b/mDNSResponder/unittests/unittest_common.c
new file mode 100644
index 00000000..39718059
--- /dev/null
+++ b/mDNSResponder/unittests/unittest_common.c
@@ -0,0 +1,157 @@
+#include "unittest_common.h"
+#include "dns_sd.h"
+#include "mDNSEmbeddedAPI.h"
+#include "mDNSMacOSX.h"
+
+static mDNS_PlatformSupport PlatformStorage;
+#define RR_CACHE_SIZE ((32*1024) / sizeof(CacheRecord))
+static CacheEntity gRrcachestorage[RR_CACHE_SIZE];
+
+// Primary interface info that is used when simulating the receive of the response packet
+mDNSInterfaceID primary_interfaceID;
+mDNSAddr primary_v4;
+mDNSAddr primary_v6;
+mDNSAddr primary_router;
+
+// This function sets up the minimum environement to run a unit test. It
+// initializes logging, interfaces, and timenow.
+mDNSexport mStatus init_mdns_environment(mDNSBool enableLogging)
+{
+ mDNS *m = &mDNSStorage;
+
+ init_logging_ut();
+ mDNS_LoggingEnabled = enableLogging;
+ mDNS_PacketLoggingEnabled = enableLogging;
+
+ mStatus result = mDNS_InitStorage_ut(m, &PlatformStorage, gRrcachestorage, RR_CACHE_SIZE, mDNSfalse, mDNSNULL, mDNSNULL);
+ if (result != mStatus_NoError)
+ return result;
+
+ primary_v4 = primary_v6 = primary_router = zeroAddr;
+ SetInterfaces_ut(&primary_interfaceID, &primary_v4, &primary_v6, &primary_router);
+
+ m->timenow = mDNS_TimeNow_NoLock(m);
+ return mStatus_NoError;
+}
+
+// This function sets up the minimum environement to run a unit test. It
+// initializes logging and timenow. This is the call to use if your
+// unit test does not use interfaces.
+mDNSexport mStatus init_mdns_storage()
+{
+ mDNS *m = &mDNSStorage;
+
+ init_logging_ut();
+ mDNS_LoggingEnabled = 1;
+ mDNS_PacketLoggingEnabled = 1;
+
+ mStatus result = mDNS_InitStorage_ut(m, &PlatformStorage, gRrcachestorage, RR_CACHE_SIZE, mDNSfalse, mDNSNULL, mDNSNULL);
+ if (result != mStatus_NoError)
+ return result;
+
+ return mStatus_NoError;
+}
+
+mDNSlocal void init_client_request(request_state* req, char *msgbuf, size_t msgSize, uint32_t op)
+{
+ // Simulate read_msg behavior since unit test does not open a socket
+ memset(req, 0, sizeof(request_state));
+
+ req->ts = t_complete;
+ req->msgbuf = mDNSNULL;
+ req->msgptr = msgbuf;
+ req->msgend = msgbuf + msgSize;
+
+ // The rest of the request values are set in order to simulate a request
+ req->sd = client_req_sd;
+ req->uid = client_req_uid;
+ req->hdr_bytes = client_req_hdr_bytes;
+ req->hdr.version = client_req_hdr_version;
+ req->hdr.op = op; // query_request
+ req->hdr.datalen = msgSize;
+ req->data_bytes = msgSize;
+ req->process_id = client_req_process_id;
+ memcpy(req->pid_name, client_req_pid_name, strlen(client_req_pid_name));
+}
+
+// This function calls the mDNSResponder handle_client_request() API. It initializes
+// the request and query data structures.
+mDNSexport mStatus start_client_request(request_state* req, char *msgbuf, size_t msgsz, uint32_t op, UDPSocket* socket)
+{
+ // Process the unit test's client request
+ init_client_request(req, msgbuf, msgsz, op);
+
+ mStatus result = handle_client_request_ut((void*)req);
+ DNSQuestion* q = &req->u.queryrecord.q;
+ q->LocalSocket = socket;
+ return result;
+}
+
+// This function calls the mDNSResponder mDNSCoreReceive() API.
+mDNSexport void receive_response(const request_state* req, DNSMessage *msg, size_t msgSize)
+{
+ mDNS *m = &mDNSStorage;
+ mDNSAddr srcaddr;
+ mDNSIPPort srcport, dstport;
+ const mDNSu8 * end;
+ DNSQuestion *q = (DNSQuestion *)&req->u.queryrecord.q;
+ UInt8* data = (UInt8*)msg;
+
+ // Used same values for DNS server as specified during init of unit test
+ srcaddr.type = mDNSAddrType_IPv4;
+ srcaddr.ip.v4.NotAnInteger = dns_server_ipv4.NotAnInteger;
+ srcport.NotAnInteger = client_resp_src_port;
+
+ // Used random value for dstport
+ dstport.NotAnInteger = swap16((mDNSu16)client_resp_dst_port);
+
+ // Set DNS message (that was copied from a WireShark packet)
+ end = (const mDNSu8 *)msg + msgSize;
+
+ // Set socket info that mDNSCoreReceive uses to verify socket context
+ q->LocalSocket->ss.port.NotAnInteger = swap16((mDNSu16)client_resp_dst_port);
+ q->TargetQID.b[0] = data[0];
+ q->TargetQID.b[1] = data[1];
+
+ // Execute mDNSCoreReceive which copies two DNS records into the cache
+ mDNSCoreReceive(m, msg, end, &srcaddr, srcport, &primary_v4, dstport, primary_interfaceID);
+}
+
+mDNSexport size_t get_reply_len(char* name, uint16_t rdlen)
+{
+ size_t len = sizeof(DNSServiceFlags);
+ len += sizeof(mDNSu32); // interface index
+ len += sizeof(DNSServiceErrorType);
+ len += strlen(name) + 1;
+ len += 3 * sizeof(mDNSu16); // type, class, rdlen
+ len += rdlen;
+ len += sizeof(mDNSu32); // TTL
+ return len;
+}
+
+
+void free_req(request_state* req)
+{
+ // Cleanup request's memory usage
+ while (req->replies)
+ {
+ reply_state *reply = req->replies;
+ req->replies = req->replies->next;
+ mDNSPlatformMemFree(reply);
+ }
+ req->replies = NULL;
+ mDNSPlatformMemFree(req);
+}
+
+// Unit test support functions follow
+#define SA_LEN(addr) (((addr)->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))
+
+mDNSexport void get_ip(const char *const name, struct sockaddr_storage *result)
+{
+ struct addrinfo* aiList;
+ int err = getaddrinfo(name, NULL, NULL, &aiList);
+ if (err) fprintf(stderr, "getaddrinfo error %d for %s", err, name);
+ else memcpy(result, aiList->ai_addr, SA_LEN(aiList->ai_addr));
+ if (aiList) freeaddrinfo(aiList);
+}
+
diff --git a/mDNSResponder/unittests/unittest_common.h b/mDNSResponder/unittests/unittest_common.h
new file mode 100644
index 00000000..a4af2e67
--- /dev/null
+++ b/mDNSResponder/unittests/unittest_common.h
@@ -0,0 +1,57 @@
+#ifndef UNITTEST_COMMON_H
+#define UNITTEST_COMMON_H
+
+#include "dns_sd.h"
+#include "uds_daemon.h"
+#include "uDNS.h"
+#include "dnssd_ipc.h"
+#include <netdb.h> // for getaddrinfo
+#include <net/if.h>
+#include <pthread.h>
+
+// Primary interface info that is used when simulating the receive of the response packet
+extern mDNSInterfaceID primary_interfaceID;
+extern mDNSAddr primary_v4;
+extern mDNSAddr primary_v6;
+extern mDNSAddr primary_router;
+
+// Arbitrary values to simulate a client_request request
+#define client_req_sd 12
+#define client_req_uid 502
+#define client_req_hdr_bytes 28
+#define client_req_hdr_version 1
+#define client_resp_src_port 13568
+#define client_resp_dst_port 49339
+#define uDNS_TargetQID 16745
+#define client_req_process_id 15418
+static char client_req_pid_name[MAXCOMLEN] = "mDNSUnitTest";
+
+//Arbitrary values to simulate a DNS server
+#define dns_server_timeout 30
+#define dns_server_resGroupID 12
+static const mDNSv4Addr dns_server_ipv4 = {{ 192, 168, 1, 20 }};
+
+extern mStatus init_mdns_environment(mDNSBool enableLogging);
+extern mStatus init_mdns_storage(void);
+extern size_t get_reply_len(char* name, uint16_t rdlen);
+extern mStatus start_client_request(request_state* req, char *msgbuf, size_t msgsz, uint32_t op, UDPSocket* socket);
+extern void receive_response(const request_state* req, DNSMessage *msg, size_t msgSize);
+extern void get_ip(const char *const name, struct sockaddr_storage *result);
+extern void free_req(request_state* req);
+
+extern mStatus mDNS_InitStorage_ut(mDNS *const m, mDNS_PlatformSupport *const p,
+ CacheEntity *rrcachestorage, mDNSu32 rrcachesize,
+ mDNSBool AdvertiseLocalAddresses, mDNSCallback *Callback, void *Context);
+extern void init_logging_ut(void);
+extern void SetInterfaces_ut(mDNSInterfaceID* primary_interfaceID, mDNSAddr *primary_v4,
+ mDNSAddr* primary_v6, mDNSAddr* primary_router);
+extern mStatus handle_client_request_ut(void *req);
+extern void LogCacheRecords_ut(mDNSs32 now, mDNSu32* retCacheUsed, mDNSu32* retCacheActive);
+extern int LogEtcHosts_ut(mDNS *const m);
+extern mDNSBool mDNSMacOSXCreateEtcHostsEntry_ut(const domainname *domain, const struct sockaddr *sa,
+ const domainname *cname, char *ifname, AuthHash *auth);
+extern void UpdateEtcHosts_ut(void *context);
+extern mStatus ArpLogMsgTest(mDNS *const m, const ARP_EthIP *const arp, const mDNSInterfaceID InterfaceID);
+
+
+#endif /* UNITTEST_COMMON_H */