From 67c8f8a10700c05d2460d60f5927f23cb5cb9241 Mon Sep 17 00:00:00 2001 From: Apple Date: Thu, 11 Oct 2007 05:39:05 +0000 Subject: [PATCH] mDNSResponder-161.1.tar.gz --- APPLE_LICENSE | 367 - Clients/BonjourExample/BonjourExample.cpp | 29 +- Clients/BonjourExample/stdafx.cpp | 29 +- Clients/BonjourExample/stdafx.h | 29 +- Clients/DNS-SD.VisualStudio/dns-sd.rc | 2 +- Clients/DNS-SD.xcode/project.pbxproj | 583 -- Clients/DNS-SD.xcodeproj/project.pbxproj | 733 ++ Clients/DNSServiceBrowser-Info.plist | 4 +- Clients/DNSServiceBrowser.NET/AssemblyInfo.cs | 29 +- .../DNSServiceBrowser.cs | 29 +- Clients/DNSServiceBrowser.m | 873 +- Clients/DNSServiceBrowser.nib/classes.nib | 1 + Clients/DNSServiceBrowser.nib/info.nib | 6 +- Clients/DNSServiceBrowser.nib/objects.nib | Bin 10423 -> 9008 bytes Clients/DNSServiceReg.m | 29 +- Clients/ExplorerPlugin/ClassFactory.cpp | 29 +- Clients/ExplorerPlugin/ClassFactory.h | 29 +- Clients/ExplorerPlugin/ExplorerBar.cpp | 29 +- Clients/ExplorerPlugin/ExplorerBar.h | 29 +- Clients/ExplorerPlugin/ExplorerBarWindow.cpp | 29 +- Clients/ExplorerPlugin/ExplorerBarWindow.h | 29 +- Clients/ExplorerPlugin/ExplorerPlugin.cpp | 29 +- Clients/ExplorerPlugin/ExplorerPlugin.def | 27 +- Clients/ExplorerPlugin/ExplorerPlugin.h | 29 +- Clients/ExplorerPlugin/ExplorerPlugin.rc | 2 +- Clients/ExplorerPlugin/ExplorerPlugin.vcproj | 6 +- .../ExplorerPlugin/ExplorerPluginLocRes.rc | 2 +- Clients/ExplorerPlugin/ExplorerPluginRes.rc | 2 +- Clients/ExplorerPlugin/LoginDialog.cpp | 29 +- Clients/ExplorerPlugin/LoginDialog.h | 29 +- Clients/ExplorerPlugin/Resource.h | 26 +- Clients/ExplorerPlugin/StdAfx.cpp | 29 +- Clients/ExplorerPlugin/StdAfx.h | 29 +- Clients/ExplorerPlugin/res/button-xp.ico | Bin 2462 -> 5342 bytes Clients/Java/BrowserApp.java | 3 +- Clients/Java/DNSSDUnitTest.java | 60 +- Clients/Java/SimpleChat.java | 3 +- Clients/Java/SwingBrowseListener.java | 3 +- Clients/Java/SwingDomainListener.java | 3 +- Clients/Java/SwingQueryListener.java | 3 +- Clients/Java/SwingResolveListener.java | 3 +- Clients/Java/nmakefile | 26 +- Clients/Makefile | 66 +- Clients/PrinterSetupWizard/FirstPage.cpp | 29 +- Clients/PrinterSetupWizard/FirstPage.h | 29 +- Clients/PrinterSetupWizard/FourthPage.cpp | 29 +- Clients/PrinterSetupWizard/FourthPage.h | 29 +- .../PrinterSetupWizard/PrinterSetupWizard.rc | 2 +- .../PrinterSetupWizard.vcproj | 6 +- .../PrinterSetupWizardApp.cpp | 29 +- .../PrinterSetupWizardApp.h | 29 +- .../PrinterSetupWizardLocRes.rc | 2 +- .../PrinterSetupWizardRes.rc | 2 +- .../PrinterSetupWizardSheet.cpp | 29 +- .../PrinterSetupWizardSheet.h | 29 +- Clients/PrinterSetupWizard/SecondPage.cpp | 29 +- Clients/PrinterSetupWizard/SecondPage.h | 53 +- Clients/PrinterSetupWizard/ThirdPage.cpp | 308 +- Clients/PrinterSetupWizard/ThirdPage.h | 59 +- Clients/PrinterSetupWizard/UtilTypes.h | 34 +- Clients/PrinterSetupWizard/resource.h | 26 +- Clients/PrinterSetupWizard/stdafx.cpp | 29 +- Clients/PrinterSetupWizard/stdafx.h | 29 +- Clients/SimpleChat.NET/AssemblyInfo.cs | 29 +- Clients/SimpleChat.NET/SimpleChat.cs | 29 +- Clients/dns-sd.c | 735 +- LICENSE | 13 + Makefile | 16 +- PrivateDNS.txt | 275 + mDNSCore/DNSCommon.c | 1762 +++- mDNSCore/DNSCommon.h | 265 +- mDNSCore/DNSDigest.c | 299 +- mDNSCore/mDNS.c | 5027 +++++------ mDNSCore/mDNSDebug.h | 99 +- mDNSCore/mDNSEmbeddedAPI.h | 2295 +++-- mDNSCore/uDNS.c | 7999 ++++++++--------- mDNSCore/uDNS.h | 291 +- mDNSMacOS9/CarbonResource.r | 29 +- mDNSMacOS9/Mac OS Test Responder.c | 29 +- mDNSMacOS9/Mac OS Test Searcher.c | 37 +- mDNSMacOS9/Responder.c | 29 +- mDNSMacOS9/Searcher.c | 36 +- mDNSMacOS9/SubTypeTester.c | 29 +- mDNSMacOS9/mDNSLibrary.c | 29 +- mDNSMacOS9/mDNSLibraryLoader.c | 29 +- mDNSMacOS9/mDNSLibraryResources.r | 99 +- mDNSMacOS9/mDNSMacOS9.c | 117 +- mDNSMacOS9/mDNSMacOS9.h | 29 +- mDNSMacOS9/mDNSPrefix.h | 29 +- mDNSMacOSX/DNSServiceDiscovery.c | 674 ++ .../DNSServiceDiscovery.h | 252 +- mDNSMacOSX/DNSServiceDiscoveryDefines.h | 34 +- mDNSMacOSX/DNSServiceDiscoveryReply.defs | 26 +- mDNSMacOSX/DNSServiceDiscoveryRequest.defs | 26 +- mDNSMacOSX/LaunchDaemonInfo.dnsextd.plist | 19 + mDNSMacOSX/LaunchDaemonInfo.helper.plist | 21 + mDNSMacOSX/LaunchDaemonInfo.plist | 27 +- mDNSMacOSX/LegacyNATTraversal.c | 3533 ++------ mDNSMacOSX/PreferencePane/BonjourPref.icns | Bin 39196 -> 39193 bytes .../PreferencePane/ConfigurationRights.h | 4 + .../PreferencePane/DNSServiceDiscoveryPref.h | 4 + .../PreferencePane/DNSServiceDiscoveryPref.m | 72 +- .../English.lproj/InfoPlist.strings | Bin 536 -> 484 bytes .../PreferencePane/Info-PreferencePane.plist | 36 + .../PreferencePane/PrivilegedOperations.c | 29 +- .../PreferencePane/PrivilegedOperations.h | 4 + mDNSMacOSX/PreferencePane/ddnswriteconfig.m | 80 +- mDNSMacOSX/PreferencePane/installtool | 7 + mDNSMacOSX/README.privsep | 47 + mDNSMacOSX/SamplemDNSClient.c | 594 +- mDNSMacOSX/daemon.c | 1832 ++-- mDNSMacOSX/helper-error.h | 75 + mDNSMacOSX/helper-main.c | 323 + mDNSMacOSX/helper-server.h | 43 + mDNSMacOSX/helper-stubs.c | 267 + mDNSMacOSX/helper.c | 1778 ++++ mDNSMacOSX/helper.h | 90 + mDNSMacOSX/helpermsg-types.h | 35 + mDNSMacOSX/helpermsg.defs | 103 + mDNSMacOSX/ipsec_strerror.h | 78 + mDNSMacOSX/libpfkey.h | 105 + mDNSMacOSX/mDNSMacOSX.c | 4789 +++++----- mDNSMacOSX/mDNSMacOSX.h | 338 +- mDNSMacOSX/mDNSMacOSXPuma.c | 241 - .../English.lproj/Localizable.strings | 19 +- .../French.lproj/Localizable.strings | 19 +- mDNSMacOSX/mDNSResponder.order | 744 +- .../mDNSResponder.pbproj/project.pbxproj | 189 +- mDNSMacOSX/mDNSResponder.sb | 182 + .../mDNSResponder.xcodeproj/project.pbxproj | 2269 +++++ mDNSMacOSX/mDNSResponderHelper.8 | 60 + mDNSMacOSX/mDNSResponderHelper.plist | 13 + mDNSMacOSX/pfkey.c | 2126 +++++ mDNSPosix/Client.c | 44 +- mDNSPosix/ExampleClientApp.c | 31 +- mDNSPosix/ExampleClientApp.h | 26 +- mDNSPosix/Identify.c | 158 +- mDNSPosix/Makefile | 187 +- mDNSPosix/NetMonitor.c | 367 +- mDNSPosix/PosixDaemon.c | 246 +- mDNSPosix/ProxyResponder.c | 65 +- mDNSPosix/ReadMe.txt | 67 +- mDNSPosix/Responder.c | 38 +- mDNSPosix/dnsextd.c | 2122 ----- mDNSPosix/mDNSPosix.c | 698 +- mDNSPosix/mDNSPosix.h | 31 +- mDNSPosix/mDNSUNP.c | 56 +- mDNSPosix/mDNSUNP.h | 26 +- mDNSPosix/mdnsd.sh | 38 +- mDNSPosix/nss_mdns.c | 73 +- mDNSPosix/nss_mdns.conf | 10 +- mDNSPosix/parselog.py | 38 +- mDNSResponder.sln | 10 + {mDNSWindows => mDNSShared}/CommonServices.h | 47 +- {mDNSWindows => mDNSShared}/DebugServices.c | 29 +- {mDNSWindows => mDNSShared}/DebugServices.h | 29 +- mDNSShared/GenLinkedList.c | 29 +- mDNSShared/GenLinkedList.h | 29 +- mDNSShared/Java/BaseListener.java | 29 +- mDNSShared/Java/BrowseListener.java | 29 +- mDNSShared/Java/DNSRecord.java | 29 +- mDNSShared/Java/DNSSD.java | 318 +- mDNSShared/Java/DNSSDException.java | 95 +- mDNSShared/Java/DNSSDRecordRegistrar.java | 77 + mDNSShared/Java/DNSSDRegistration.java | 29 +- mDNSShared/Java/DNSSDService.java | 29 +- mDNSShared/Java/DomainListener.java | 29 +- mDNSShared/Java/JNISupport.c | 248 +- mDNSShared/Java/QueryListener.java | 39 +- mDNSShared/Java/RegisterListener.java | 29 +- mDNSShared/Java/RegisterRecordListener.java | 48 + mDNSShared/Java/ResolveListener.java | 29 +- mDNSShared/Java/TXTRecord.java | 49 +- mDNSShared/PlatformCommon.c | 66 +- mDNSShared/PlatformCommon.h | 42 +- mDNSShared/dns-sd.1 | 28 +- mDNSShared/dns_sd.h | 1120 ++- mDNSShared/dnsextd.8 | 28 +- mDNSShared/dnsextd.c | 3255 +++++++ mDNSShared/dnsextd.conf | 60 + mDNSShared/dnsextd.h | 185 + mDNSShared/dnsextd_lexer.l | 103 + mDNSShared/dnsextd_parser.y | 615 ++ mDNSShared/dnssd_clientlib.c | 56 +- mDNSShared/dnssd_clientshim.c | 67 +- mDNSShared/dnssd_clientstub.c | 2510 +++--- mDNSShared/dnssd_ipc.c | 133 +- mDNSShared/dnssd_ipc.h | 208 +- mDNSShared/mDNS.1 | 28 +- mDNSShared/mDNSDebug.c | 71 +- mDNSShared/mDNSResponder.8 | 33 +- mDNSShared/uds_daemon.c | 6456 ++++++------- mDNSShared/uds_daemon.h | 89 +- mDNSVxWorks/mDNSVxWorks.c | 67 +- mDNSVxWorks/mDNSVxWorks.h | 29 +- mDNSVxWorks/mDNSVxWorksIPv4Only.c | 62 +- mDNSVxWorks/mDNSVxWorksIPv4Only.h | 29 +- mDNSWindows/ControlPanel/ConfigDialog.cpp | 29 +- mDNSWindows/ControlPanel/ConfigDialog.h | 29 +- .../ControlPanel/ConfigPropertySheet.cpp | 29 +- .../ControlPanel/ConfigPropertySheet.h | 38 +- mDNSWindows/ControlPanel/ControlPanel.cpp | 38 +- mDNSWindows/ControlPanel/ControlPanel.def | 27 +- mDNSWindows/ControlPanel/ControlPanel.h | 29 +- mDNSWindows/ControlPanel/ControlPanel.rc | 37 - mDNSWindows/ControlPanel/ControlPanel.vcproj | 4 +- mDNSWindows/ControlPanel/ControlPanelDll.rc | 132 + mDNSWindows/ControlPanel/ControlPanelExe.cpp | 317 + mDNSWindows/ControlPanel/ControlPanelExe.h | 60 + mDNSWindows/ControlPanel/ControlPanelExe.rc | 132 + .../ControlPanel/ControlPanelExe.vcproj | 328 + mDNSWindows/ControlPanel/FirstPage.cpp | 29 +- mDNSWindows/ControlPanel/FirstPage.h | 29 +- mDNSWindows/ControlPanel/SecondPage.cpp | 29 +- mDNSWindows/ControlPanel/SecondPage.h | 29 +- mDNSWindows/ControlPanel/SharedSecret.cpp | 36 +- mDNSWindows/ControlPanel/SharedSecret.h | 29 +- mDNSWindows/ControlPanel/ThirdPage.cpp | 29 +- mDNSWindows/ControlPanel/ThirdPage.h | 152 +- .../res/ControlPanel.dll.manifest | 10 + .../res/ControlPanel.exe.manifest | 17 + mDNSWindows/ControlPanel/res/controlpanel.ico | Bin 11854 -> 22486 bytes mDNSWindows/ControlPanel/stdafx.cpp | 29 +- mDNSWindows/ControlPanel/stdafx.h | 35 +- mDNSWindows/DLL.NET/AssemblyInfo.cpp | 29 +- mDNSWindows/DLL.NET/PString.h | 32 +- mDNSWindows/DLL.NET/Stdafx.cpp | 29 +- mDNSWindows/DLL.NET/Stdafx.h | 29 +- mDNSWindows/DLL.NET/dnssd_NET.cpp | 29 +- mDNSWindows/DLL.NET/dnssd_NET.h | 29 +- mDNSWindows/DLL.NET/dnssd_NET.rc | 2 +- mDNSWindows/DLL/dll.rc | 2 +- mDNSWindows/DLL/dllmain.c | 29 +- mDNSWindows/DLL/dnssd.def | 32 +- mDNSWindows/DLL/dnssd.vcproj | 6 +- .../Windows/Resources/Application.rc2 | 29 +- .../Windows/Sources/AboutDialog.cpp | 29 +- .../Windows/Sources/AboutDialog.h | 29 +- .../Windows/Sources/Application.cpp | 29 +- .../Windows/Sources/Application.h | 29 +- .../Windows/Sources/ChooserDialog.cpp | 29 +- .../Windows/Sources/ChooserDialog.h | 29 +- .../Windows/Sources/LoginDialog.cpp | 29 +- .../Windows/Sources/LoginDialog.h | 29 +- .../Windows/Sources/StdAfx.cpp | 29 +- .../Windows/Sources/StdAfx.h | 29 +- .../WindowsCE/Sources/Application.cpp | 29 +- .../WindowsCE/Sources/Application.h | 29 +- .../WindowsCE/Sources/BrowserDialog.cpp | 29 +- .../WindowsCE/Sources/BrowserDialog.h | 29 +- .../WindowsCE/Sources/StdAfx.cpp | 29 +- .../WindowsCE/Sources/StdAfx.h | 29 +- mDNSWindows/DNSServiceTest/Tool.c | 1076 --- .../DNSServiceTest/ToolPrefixWindows.h | 45 - .../DNSServiceTest/ToolPrefixWindowsDebug.h | 46 - mDNSWindows/DNSServiceTest/ToolWin32.mcp | Bin 127071 -> 0 bytes .../DNSServiceTest/ToolWin32VS2002.sln | 21 - .../DNSServiceTest/ToolWin32VS2002.vcproj | 171 - .../DNSServiceTest/ToolWin32VS2003.sln | 21 - .../DNSServiceTest/ToolWin32VS2003.vcproj | 185 - mDNSWindows/DNSServices/DNSServiceDiscovery.c | 787 -- mDNSWindows/DNSServices/DNSServices.c | 3203 ------- mDNSWindows/DNSServices/DNSServices.h | 1925 ---- mDNSWindows/Java/jdns_sd.rc | 36 +- mDNSWindows/Java/makefile | 33 +- mDNSWindows/NSPTool/NSPTool.c | 29 +- mDNSWindows/NSPTool/NSPTool.rc | 2 +- mDNSWindows/NSPTool/NSPTool.vcproj | 10 +- mDNSWindows/NSPTool/Prefix.h | 29 +- mDNSWindows/RegNames.h | 29 +- mDNSWindows/SystemService/Firewall.cpp | 29 +- mDNSWindows/SystemService/Firewall.h | 125 +- mDNSWindows/SystemService/Prefix.h | 29 +- mDNSWindows/SystemService/Service.c | 44 +- mDNSWindows/SystemService/Service.rc | 2 +- mDNSWindows/SystemService/Service.vcproj | 12 +- mDNSWindows/VPCDetect.cpp | 101 +- mDNSWindows/VPCDetect.h | 37 +- mDNSWindows/WinServices.cpp | 29 +- mDNSWindows/WinServices.h | 29 +- mDNSWindows/WinVersRes.h | 51 +- mDNSWindows/dDNS.c | 680 -- mDNSWindows/dDNS.h | 82 - mDNSWindows/isocode.h | 26 +- mDNSWindows/loclibrary.c | 26 +- mDNSWindows/loclibrary.h | 26 +- mDNSWindows/mDNSWin32.c | 1225 ++- mDNSWindows/mDNSWin32.h | 41 +- mDNSWindows/mdnsNSP/mdnsNSP.c | 35 +- mDNSWindows/mdnsNSP/mdnsNSP.def | 27 +- mDNSWindows/mdnsNSP/mdnsNSP.rc | 2 +- mDNSWindows/mdnsNSP/mdnsNSP.vcproj | 6 +- 292 files changed, 41114 insertions(+), 37560 deletions(-) delete mode 100644 APPLE_LICENSE delete mode 100644 Clients/DNS-SD.xcode/project.pbxproj create mode 100644 Clients/DNS-SD.xcodeproj/project.pbxproj create mode 100644 LICENSE create mode 100644 PrivateDNS.txt create mode 100644 mDNSMacOSX/DNSServiceDiscovery.c rename {mDNSWindows/DNSServices => mDNSMacOSX}/DNSServiceDiscovery.h (57%) create mode 100644 mDNSMacOSX/LaunchDaemonInfo.dnsextd.plist create mode 100644 mDNSMacOSX/LaunchDaemonInfo.helper.plist create mode 100644 mDNSMacOSX/PreferencePane/Info-PreferencePane.plist create mode 100644 mDNSMacOSX/README.privsep create mode 100644 mDNSMacOSX/helper-error.h create mode 100644 mDNSMacOSX/helper-main.c create mode 100644 mDNSMacOSX/helper-server.h create mode 100644 mDNSMacOSX/helper-stubs.c create mode 100644 mDNSMacOSX/helper.c create mode 100644 mDNSMacOSX/helper.h create mode 100644 mDNSMacOSX/helpermsg-types.h create mode 100644 mDNSMacOSX/helpermsg.defs create mode 100644 mDNSMacOSX/ipsec_strerror.h create mode 100644 mDNSMacOSX/libpfkey.h delete mode 100644 mDNSMacOSX/mDNSMacOSXPuma.c create mode 100644 mDNSMacOSX/mDNSResponder.sb create mode 100644 mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj create mode 100644 mDNSMacOSX/mDNSResponderHelper.8 create mode 100644 mDNSMacOSX/mDNSResponderHelper.plist create mode 100644 mDNSMacOSX/pfkey.c delete mode 100644 mDNSPosix/dnsextd.c rename {mDNSWindows => mDNSShared}/CommonServices.h (97%) rename {mDNSWindows => mDNSShared}/DebugServices.c (99%) rename {mDNSWindows => mDNSShared}/DebugServices.h (98%) create mode 100644 mDNSShared/Java/DNSSDRecordRegistrar.java create mode 100644 mDNSShared/Java/RegisterRecordListener.java create mode 100644 mDNSShared/dnsextd.c create mode 100644 mDNSShared/dnsextd.conf create mode 100644 mDNSShared/dnsextd.h create mode 100644 mDNSShared/dnsextd_lexer.l create mode 100644 mDNSShared/dnsextd_parser.y create mode 100644 mDNSWindows/ControlPanel/ControlPanelDll.rc create mode 100755 mDNSWindows/ControlPanel/ControlPanelExe.cpp create mode 100644 mDNSWindows/ControlPanel/ControlPanelExe.h create mode 100644 mDNSWindows/ControlPanel/ControlPanelExe.rc create mode 100755 mDNSWindows/ControlPanel/ControlPanelExe.vcproj create mode 100644 mDNSWindows/ControlPanel/res/ControlPanel.dll.manifest create mode 100644 mDNSWindows/ControlPanel/res/ControlPanel.exe.manifest delete mode 100644 mDNSWindows/DNSServiceTest/Tool.c delete mode 100644 mDNSWindows/DNSServiceTest/ToolPrefixWindows.h delete mode 100644 mDNSWindows/DNSServiceTest/ToolPrefixWindowsDebug.h delete mode 100644 mDNSWindows/DNSServiceTest/ToolWin32.mcp delete mode 100644 mDNSWindows/DNSServiceTest/ToolWin32VS2002.sln delete mode 100644 mDNSWindows/DNSServiceTest/ToolWin32VS2002.vcproj delete mode 100644 mDNSWindows/DNSServiceTest/ToolWin32VS2003.sln delete mode 100644 mDNSWindows/DNSServiceTest/ToolWin32VS2003.vcproj delete mode 100644 mDNSWindows/DNSServices/DNSServiceDiscovery.c delete mode 100755 mDNSWindows/DNSServices/DNSServices.c delete mode 100755 mDNSWindows/DNSServices/DNSServices.h delete mode 100755 mDNSWindows/dDNS.c delete mode 100755 mDNSWindows/dDNS.h diff --git a/APPLE_LICENSE b/APPLE_LICENSE deleted file mode 100644 index fe81a60..0000000 --- a/APPLE_LICENSE +++ /dev/null @@ -1,367 +0,0 @@ -APPLE PUBLIC SOURCE LICENSE -Version 2.0 - August 6, 2003 - -Please read this License carefully before downloading this software. -By downloading or using this software, you are agreeing to be bound by -the terms of this License. If you do not or cannot agree to the terms -of this License, please do not download or use the software. - -1. General; Definitions. This License applies to any program or other -work which Apple Computer, Inc. ("Apple") makes publicly available and -which contains a notice placed by Apple identifying such program or -work as "Original Code" and stating that it is subject to the terms of -this Apple Public Source License version 2.0 ("License"). As used in -this License: - -1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is -the grantor of rights, (i) claims of patents that are now or hereafter -acquired, owned by or assigned to Apple and (ii) that cover subject -matter contained in the Original Code, but only to the extent -necessary to use, reproduce and/or distribute the Original Code -without infringement; and (b) in the case where You are the grantor of -rights, (i) claims of patents that are now or hereafter acquired, -owned by or assigned to You and (ii) that cover subject matter in Your -Modifications, taken alone or in combination with Original Code. - -1.2 "Contributor" means any person or entity that creates or -contributes to the creation of Modifications. - -1.3 "Covered Code" means the Original Code, Modifications, the -combination of Original Code and any Modifications, and/or any -respective portions thereof. - -1.4 "Externally Deploy" means: (a) to sublicense, distribute or -otherwise make Covered Code available, directly or indirectly, to -anyone other than You; and/or (b) to use Covered Code, alone or as -part of a Larger Work, in any way to provide a service, including but -not limited to delivery of content, through electronic communication -with a client other than You. - -1.5 "Larger Work" means a work which combines Covered Code or portions -thereof with code not governed by the terms of this License. - -1.6 "Modifications" mean any addition to, deletion from, and/or change -to, the substance and/or structure of the Original Code, any previous -Modifications, the combination of Original Code and any previous -Modifications, and/or any respective portions thereof. When code is -released as a series of files, a Modification is: (a) any addition to -or deletion from the contents of a file containing Covered Code; -and/or (b) any new file or other representation of computer program -statements that contains any part of Covered Code. - -1.7 "Original Code" means (a) the Source Code of a program or other -work as originally made available by Apple under this License, -including the Source Code of any updates or upgrades to such programs -or works made available by Apple under this License, and that has been -expressly identified by Apple as such in the header file(s) of such -work; and (b) the object code compiled from such Source Code and -originally made available by Apple under this License. - -1.8 "Source Code" means the human readable form of a program or other -work that is suitable for making modifications to it, including all -modules it contains, plus any associated interface definition files, -scripts used to control compilation and installation of an executable -(object code). - -1.9 "You" or "Your" means an individual or a legal entity exercising -rights under this License. For legal entities, "You" or "Your" -includes any entity which controls, is controlled by, or is under -common control with, You, where "control" means (a) the power, direct -or indirect, to cause the direction or management of such entity, -whether by contract or otherwise, or (b) ownership of fifty percent -(50%) or more of the outstanding shares or beneficial ownership of -such entity. - -2. Permitted Uses; Conditions & Restrictions. Subject to the terms -and conditions of this License, Apple hereby grants You, effective on -the date You accept this License and download the Original Code, a -world-wide, royalty-free, non-exclusive license, to the extent of -Apple's Applicable Patent Rights and copyrights covering the Original -Code, to do the following: - -2.1 Unmodified Code. You may use, reproduce, display, perform, -internally distribute within Your organization, and Externally Deploy -verbatim, unmodified copies of the Original Code, for commercial or -non-commercial purposes, provided that in each instance: - -(a) You must retain and reproduce in all copies of Original Code the -copyright and other proprietary notices and disclaimers of Apple as -they appear in the Original Code, and keep intact all notices in the -Original Code that refer to this License; and - -(b) You must include a copy of this License with every copy of Source -Code of Covered Code and documentation You distribute or Externally -Deploy, and You may not offer or impose any terms on such Source Code -that alter or restrict this License or the recipients' rights -hereunder, except as permitted under Section 6. - -2.2 Modified Code. You may modify Covered Code and use, reproduce, -display, perform, internally distribute within Your organization, and -Externally Deploy Your Modifications and Covered Code, for commercial -or non-commercial purposes, provided that in each instance You also -meet all of these conditions: - -(a) You must satisfy all the conditions of Section 2.1 with respect to -the Source Code of the Covered Code; - -(b) You must duplicate, to the extent it does not already exist, the -notice in Exhibit A in each file of the Source Code of all Your -Modifications, and cause the modified files to carry prominent notices -stating that You changed the files and the date of any change; and - -(c) If You Externally Deploy Your Modifications, You must make -Source Code of all Your Externally Deployed Modifications either -available to those to whom You have Externally Deployed Your -Modifications, or publicly available. Source Code of Your Externally -Deployed Modifications must be released under the terms set forth in -this License, including the license grants set forth in Section 3 -below, for as long as you Externally Deploy the Covered Code or twelve -(12) months from the date of initial External Deployment, whichever is -longer. You should preferably distribute the Source Code of Your -Externally Deployed Modifications electronically (e.g. download from a -web site). - -2.3 Distribution of Executable Versions. In addition, if You -Externally Deploy Covered Code (Original Code and/or Modifications) in -object code, executable form only, You must include a prominent -notice, in the code itself as well as in related documentation, -stating that Source Code of the Covered Code is available under the -terms of this License with information on how and where to obtain such -Source Code. - -2.4 Third Party Rights. You expressly acknowledge and agree that -although Apple and each Contributor grants the licenses to their -respective portions of the Covered Code set forth herein, no -assurances are provided by Apple or any Contributor that the Covered -Code does not infringe the patent or other intellectual property -rights of any other entity. Apple and each Contributor disclaim any -liability to You for claims brought by any other entity based on -infringement of intellectual property rights or otherwise. As a -condition to exercising the rights and licenses granted hereunder, You -hereby assume sole responsibility to secure any other intellectual -property rights needed, if any. For example, if a third party patent -license is required to allow You to distribute the Covered Code, it is -Your responsibility to acquire that license before distributing the -Covered Code. - -3. Your Grants. In consideration of, and as a condition to, the -licenses granted to You under this License, You hereby grant to any -person or entity receiving or distributing Covered Code under this -License a non-exclusive, royalty-free, perpetual, irrevocable license, -under Your Applicable Patent Rights and other intellectual property -rights (other than patent) owned or controlled by You, to use, -reproduce, display, perform, modify, sublicense, distribute and -Externally Deploy Your Modifications of the same scope and extent as -Apple's licenses under Sections 2.1 and 2.2 above. - -4. Larger Works. You may create a Larger Work by combining Covered -Code with other code not governed by the terms of this License and -distribute the Larger Work as a single product. In each such instance, -You must make sure the requirements of this License are fulfilled for -the Covered Code or any portion thereof. - -5. Limitations on Patent License. Except as expressly stated in -Section 2, no other patent rights, express or implied, are granted by -Apple herein. Modifications and/or Larger Works may require additional -patent licenses from Apple which Apple may grant in its sole -discretion. - -6. Additional Terms. You may choose to offer, and to charge a fee for, -warranty, support, indemnity or liability obligations and/or other -rights consistent with the scope of the license granted herein -("Additional Terms") to one or more recipients of Covered Code. -However, You may do so only on Your own behalf and as Your sole -responsibility, and not on behalf of Apple or any Contributor. You -must obtain the recipient's agreement that any such Additional Terms -are offered by You alone, and You hereby agree to indemnify, defend -and hold Apple and every Contributor harmless for any liability -incurred by or claims asserted against Apple or such Contributor by -reason of any such Additional Terms. - -7. Versions of the License. Apple may publish revised and/or new -versions of this License from time to time. Each version will be given -a distinguishing version number. Once Original Code has been published -under a particular version of this License, You may continue to use it -under the terms of that version. You may also choose to use such -Original Code under the terms of any subsequent version of this -License published by Apple. No one other than Apple has the right to -modify the terms applicable to Covered Code created under this -License. - -8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in -part pre-release, untested, or not fully tested works. The Covered -Code may contain errors that could cause failures or loss of data, and -may be incomplete or contain inaccuracies. You expressly acknowledge -and agree that use of the Covered Code, or any portion thereof, is at -Your sole and entire risk. THE COVERED CODE IS PROVIDED "AS IS" AND -WITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND AND APPLE AND -APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" FOR THE -PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM -ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT -NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF -MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR -PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD -PARTY RIGHTS. APPLE AND EACH CONTRIBUTOR DOES NOT WARRANT AGAINST -INTERFERENCE WITH YOUR ENJOYMENT OF THE COVERED CODE, THAT THE -FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR REQUIREMENTS, -THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR -ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO -ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE -AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY. -You acknowledge that the Covered Code is not intended for use in the -operation of nuclear facilities, aircraft navigation, communication -systems, or air traffic control machines in which case the failure of -the Covered Code could lead to death, personal injury, or severe -physical or environmental damage. - -9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO -EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING -TO THIS LICENSE OR YOUR USE OR INABILITY TO USE THE COVERED CODE, OR -ANY PORTION THEREOF, WHETHER UNDER A THEORY OF CONTRACT, WARRANTY, -TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF -APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY -REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF -INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY -TO YOU. In no event shall Apple's total liability to You for all -damages (other than as may be required by applicable law) under this -License exceed the amount of fifty dollars ($50.00). - -10. Trademarks. This License does not grant any rights to use the -trademarks or trade names "Apple", "Apple Computer", "Mac", "Mac OS", -"QuickTime", "QuickTime Streaming Server" or any other trademarks, -service marks, logos or trade names belonging to Apple (collectively -"Apple Marks") or to any trademark, service mark, logo or trade name -belonging to any Contributor. You agree not to use any Apple Marks in -or as part of the name of products derived from the Original Code or -to endorse or promote products derived from the Original Code other -than as expressly permitted by and in strict compliance at all times -with Apple's third party trademark usage guidelines which are posted -at http://www.apple.com/legal/guidelinesfor3rdparties.html. - -11. Ownership. Subject to the licenses granted under this License, -each Contributor retains all rights, title and interest in and to any -Modifications made by such Contributor. Apple retains all rights, -title and interest in and to the Original Code and any Modifications -made by or on behalf of Apple ("Apple Modifications"), and such Apple -Modifications will not be automatically subject to this License. Apple -may, at its sole discretion, choose to license such Apple -Modifications under this License, or on different terms from those -contained in this License or may choose not to license them at all. - -12. Termination. - -12.1 Termination. This License and the rights granted hereunder will -terminate: - -(a) automatically without notice from Apple if You fail to comply with -any term(s) of this License and fail to cure such breach within 30 -days of becoming aware of such breach; - -(b) immediately in the event of the circumstances described in Section -13.5(b); or - -(c) automatically without notice from Apple if You, at any time during -the term of this License, commence an action for patent infringement -against Apple; provided that Apple did not first commence -an action for patent infringement against You in that instance. - -12.2 Effect of Termination. Upon termination, You agree to immediately -stop any further use, reproduction, modification, sublicensing and -distribution of the Covered Code. All sublicenses to the Covered Code -which have been properly granted prior to termination shall survive -any termination of this License. Provisions which, by their nature, -should remain in effect beyond the termination of this License shall -survive, including but not limited to Sections 3, 5, 8, 9, 10, 11, -12.2 and 13. No party will be liable to any other for compensation, -indemnity or damages of any sort solely as a result of terminating -this License in accordance with its terms, and termination of this -License will be without prejudice to any other right or remedy of -any party. - -13. Miscellaneous. - -13.1 Government End Users. The Covered Code is a "commercial item" as -defined in FAR 2.101. Government software and technical data rights in -the Covered Code include only those rights customarily provided to the -public as defined in this License. This customary commercial license -in technical data and software is provided in accordance with FAR -12.211 (Technical Data) and 12.212 (Computer Software) and, for -Department of Defense purchases, DFAR 252.227-7015 (Technical Data -- -Commercial Items) and 227.7202-3 (Rights in Commercial Computer -Software or Computer Software Documentation). Accordingly, all U.S. -Government End Users acquire Covered Code with only those rights set -forth herein. - -13.2 Relationship of Parties. This License will not be construed as -creating an agency, partnership, joint venture or any other form of -legal association between or among You, Apple or any Contributor, and -You will not represent to the contrary, whether expressly, by -implication, appearance or otherwise. - -13.3 Independent Development. Nothing in this License will impair -Apple's right to acquire, license, develop, have others develop for -it, market and/or distribute technology or products that perform the -same or similar functions as, or otherwise compete with, -Modifications, Larger Works, technology or products that You may -develop, produce, market or distribute. - -13.4 Waiver; Construction. Failure by Apple or any Contributor to -enforce any provision of this License will not be deemed a waiver of -future enforcement of that or any other provision. Any law or -regulation which provides that the language of a contract shall be -construed against the drafter will not apply to this License. - -13.5 Severability. (a) If for any reason a court of competent -jurisdiction finds any provision of this License, or portion thereof, -to be unenforceable, that provision of the License will be enforced to -the maximum extent permissible so as to effect the economic benefits -and intent of the parties, and the remainder of this License will -continue in full force and effect. (b) Notwithstanding the foregoing, -if applicable law prohibits or restricts You from fully and/or -specifically complying with Sections 2 and/or 3 or prevents the -enforceability of either of those Sections, this License will -immediately terminate and You must immediately discontinue any use of -the Covered Code and destroy all copies of it that are in your -possession or control. - -13.6 Dispute Resolution. Any litigation or other dispute resolution -between You and Apple relating to this License shall take place in the -Northern District of California, and You and Apple hereby consent to -the personal jurisdiction of, and venue in, the state and federal -courts within that District with respect to this License. The -application of the United Nations Convention on Contracts for the -International Sale of Goods is expressly excluded. - -13.7 Entire Agreement; Governing Law. This License constitutes the -entire agreement between the parties with respect to the subject -matter hereof. This License shall be governed by the laws of the -United States and the State of California, except that body of -California law concerning conflicts of law. - -Where You are located in the province of Quebec, Canada, the following -clause applies: The parties hereby confirm that they have requested -that this License and all related documents be drafted in English. Les -parties ont exige que le present contrat et tous les documents -connexes soient rediges en anglais. - -EXHIBIT A. - -"Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights -Reserved. - -This file contains Original Code and/or Modifications of Original Code -as defined in and that are subject to the Apple Public Source License -Version 2.0 (the 'License'). You may not use this file except in -compliance with the License. Please obtain a copy of the License at -http://www.opensource.apple.com/apsl/ and read it before using this -file. - -The Original Code and all software distributed under the License are -distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER -EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, -INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. -Please see the License for the specific language governing rights and -limitations under the License." diff --git a/Clients/BonjourExample/BonjourExample.cpp b/Clients/BonjourExample/BonjourExample.cpp index ec448f4..ff50a39 100644 --- a/Clients/BonjourExample/BonjourExample.cpp +++ b/Clients/BonjourExample/BonjourExample.cpp @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: BonjourExample.cpp,v $ +Revision 1.2 2006/08/14 23:23:57 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.1 2005/05/20 22:01:01 bradley Bonjour for Windows example code to browse for HTTP services and deliver via Window messages. diff --git a/Clients/BonjourExample/stdafx.cpp b/Clients/BonjourExample/stdafx.cpp index 2b2483e..c6899cd 100644 --- a/Clients/BonjourExample/stdafx.cpp +++ b/Clients/BonjourExample/stdafx.cpp @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: stdafx.cpp,v $ +Revision 1.2 2006/08/14 23:23:57 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.1 2005/05/20 22:01:02 bradley Bonjour for Windows example code to browse for HTTP services and deliver via Window messages. diff --git a/Clients/BonjourExample/stdafx.h b/Clients/BonjourExample/stdafx.h index 6ded040..461d119 100644 --- a/Clients/BonjourExample/stdafx.h +++ b/Clients/BonjourExample/stdafx.h @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: stdafx.h,v $ +Revision 1.2 2006/08/14 23:23:57 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.1 2005/05/20 22:01:02 bradley Bonjour for Windows example code to browse for HTTP services and deliver via Window messages. diff --git a/Clients/DNS-SD.VisualStudio/dns-sd.rc b/Clients/DNS-SD.VisualStudio/dns-sd.rc index a57a430..79df1ba 100755 --- a/Clients/DNS-SD.VisualStudio/dns-sd.rc +++ b/Clients/DNS-SD.VisualStudio/dns-sd.rc @@ -70,7 +70,7 @@ BEGIN BEGIN BLOCK "040904b0" BEGIN - VALUE "CompanyName", "Apple Computer, Inc." + VALUE "CompanyName", MASTER_COMPANY_NAME VALUE "FileDescription", "Bonjour Console Utility" VALUE "FileVersion", MASTER_PROD_VERS_STR VALUE "InternalName", "dns-sd.exe" diff --git a/Clients/DNS-SD.xcode/project.pbxproj b/Clients/DNS-SD.xcode/project.pbxproj deleted file mode 100644 index 574ad8b..0000000 --- a/Clients/DNS-SD.xcode/project.pbxproj +++ /dev/null @@ -1,583 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 39; - objects = { - 014CEA490018CE3211CA2923 = { - buildRules = ( - ); - buildSettings = { - COPY_PHASE_STRIP = NO; - DEBUGGING_SYMBOLS = YES; - GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_FIX_AND_CONTINUE = YES; - GCC_GENERATE_DEBUGGING_SYMBOLS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - OPTIMIZATION_CFLAGS = "-O0"; - ZERO_LINK = NO; - }; - isa = PBXBuildStyle; - name = Development; - }; - 014CEA4A0018CE3211CA2923 = { - buildRules = ( - ); - buildSettings = { - COPY_PHASE_STRIP = YES; - GCC_ENABLE_FIX_AND_CONTINUE = NO; - ZERO_LINK = NO; - }; - isa = PBXBuildStyle; - name = Deployment; - }; -//010 -//011 -//012 -//013 -//014 -//080 -//081 -//082 -//083 -//084 - 08FB7793FE84155DC02AAC07 = { - buildSettings = { - }; - buildStyles = ( - 014CEA490018CE3211CA2923, - 014CEA4A0018CE3211CA2923, - ); - hasScannedForEncodings = 1; - isa = PBXProject; - mainGroup = 08FB7794FE84155DC02AAC07; - projectDirPath = ""; - targets = ( - FFF520490671177900DA3D49, - 8DD76F740486A8DE00D96B5E, - FF1B691006711383002304DD, - FF1E351206711B5C003DD5BC, - ); - }; - 08FB7794FE84155DC02AAC07 = { - children = ( - 08FB7795FE84155DC02AAC07, - 08FB779DFE84155DC02AAC07, - 19C28FBDFE9D53C911CA2CBB, - ); - isa = PBXGroup; - name = mDNS; - refType = 4; - sourceTree = ""; - }; - 08FB7795FE84155DC02AAC07 = { - children = ( - 08FB7796FE84155DC02AAC07, - FF1B6914067114AF002304DD, - FF964DAB067115710099215A, - FF1E351B06711BCF003DD5BC, - FF1E352506711BD6003DD5BC, - ); - isa = PBXGroup; - name = Source; - refType = 4; - sourceTree = ""; - }; - 08FB7796FE84155DC02AAC07 = { - fileEncoding = 4; - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.c; - path = "dns-sd.c"; - refType = 4; - sourceTree = ""; - }; - 08FB779DFE84155DC02AAC07 = { - children = ( - FF964CA90671155C0099215A, - FF964AA00671153B0099215A, - ); - isa = PBXGroup; - name = Frameworks; - refType = 4; - sourceTree = ""; - }; -//080 -//081 -//082 -//083 -//084 -//190 -//191 -//192 -//193 -//194 - 19C28FBDFE9D53C911CA2CBB = { - children = ( - 8DD76F7E0486A8DE00D96B5E, - FF1B691106711383002304DD, - FF1E351306711B5C003DD5BC, - ); - isa = PBXGroup; - name = Products; - refType = 4; - sourceTree = ""; - }; -//190 -//191 -//192 -//193 -//194 -//8D0 -//8D1 -//8D2 -//8D3 -//8D4 - 8DD76F740486A8DE00D96B5E = { - buildPhases = ( - 8DD76F750486A8DE00D96B5E, - 8DD76F760486A8DE00D96B5E, - 8DD76F780486A8DE00D96B5E, - 8DD76F7A0486A8DE00D96B5E, - 8DD76F7B0486A8DE00D96B5E, - ); - buildRules = ( - ); - buildSettings = { - FRAMEWORK_SEARCH_PATHS = ""; - GCC_ENABLE_TRIGRAPHS = NO; - GCC_GENERATE_DEBUGGING_SYMBOLS = NO; - GCC_PRECOMPILE_PREFIX_HEADER = NO; - GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; - GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; - GCC_WARN_UNKNOWN_PRAGMAS = NO; - HEADER_SEARCH_PATHS = ../mDNSShared; - INSTALL_PATH = "$(HOME)/bin"; - LIBRARY_SEARCH_PATHS = ""; - OTHER_CFLAGS = ""; - OTHER_LDFLAGS = ""; - OTHER_REZFLAGS = ""; - PRODUCT_NAME = "dns-sd"; - REZ_EXECUTABLE = YES; - SECTORDER_FLAGS = ""; - WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas"; - ZERO_LINK = NO; - }; - dependencies = ( - ); - isa = PBXNativeTarget; - name = "dns-sd"; - productInstallPath = "$(HOME)/bin"; - productName = mDNS; - productReference = 8DD76F7E0486A8DE00D96B5E; - productType = "com.apple.product-type.tool"; - }; - 8DD76F750486A8DE00D96B5E = { - buildActionMask = 2147483647; - files = ( - ); - isa = PBXHeadersBuildPhase; - runOnlyForDeploymentPostprocessing = 0; - }; - 8DD76F760486A8DE00D96B5E = { - buildActionMask = 2147483647; - files = ( - 8DD76F770486A8DE00D96B5E, - ); - isa = PBXSourcesBuildPhase; - runOnlyForDeploymentPostprocessing = 0; - }; - 8DD76F770486A8DE00D96B5E = { - fileRef = 08FB7796FE84155DC02AAC07; - isa = PBXBuildFile; - settings = { - ATTRIBUTES = ( - ); - }; - }; - 8DD76F780486A8DE00D96B5E = { - buildActionMask = 2147483647; - files = ( - ); - isa = PBXFrameworksBuildPhase; - runOnlyForDeploymentPostprocessing = 0; - }; - 8DD76F7A0486A8DE00D96B5E = { - buildActionMask = 2147483647; - files = ( - ); - isa = PBXRezBuildPhase; - runOnlyForDeploymentPostprocessing = 0; - }; - 8DD76F7B0486A8DE00D96B5E = { - buildActionMask = 8; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - isa = PBXCopyFilesBuildPhase; - runOnlyForDeploymentPostprocessing = 1; - }; - 8DD76F7E0486A8DE00D96B5E = { - explicitFileType = "compiled.mach-o.executable"; - includeInIndex = 0; - isa = PBXFileReference; - path = "dns-sd"; - refType = 3; - sourceTree = BUILT_PRODUCTS_DIR; - }; -//8D0 -//8D1 -//8D2 -//8D3 -//8D4 -//FF0 -//FF1 -//FF2 -//FF3 -//FF4 - FF1B690C06711383002304DD = { - buildActionMask = 2147483647; - files = ( - ); - isa = PBXHeadersBuildPhase; - runOnlyForDeploymentPostprocessing = 0; - }; - FF1B690D06711383002304DD = { - buildActionMask = 2147483647; - files = ( - FF964DAC067115710099215A, - ); - isa = PBXResourcesBuildPhase; - runOnlyForDeploymentPostprocessing = 0; - }; - FF1B690E06711383002304DD = { - buildActionMask = 2147483647; - files = ( - FF1B6915067114AF002304DD, - ); - isa = PBXSourcesBuildPhase; - runOnlyForDeploymentPostprocessing = 0; - }; - FF1B690F06711383002304DD = { - buildActionMask = 2147483647; - files = ( - FF964AA10671153B0099215A, - FF964CAA0671155C0099215A, - ); - isa = PBXFrameworksBuildPhase; - runOnlyForDeploymentPostprocessing = 0; - }; - FF1B691006711383002304DD = { - buildPhases = ( - FF1B690C06711383002304DD, - FF1B690D06711383002304DD, - FF1B690E06711383002304DD, - FF1B690F06711383002304DD, - ); - buildRules = ( - ); - buildSettings = { - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; - GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; - GCC_WARN_UNKNOWN_PRAGMAS = NO; - HEADER_SEARCH_PATHS = ../mDNSShared; - INFOPLIST_FILE = "DNSServiceBrowser-Info.plist"; - INSTALL_PATH = "$(USER_APPS_DIR)"; - OTHER_CFLAGS = ""; - OTHER_LDFLAGS = "-framework Foundation -framework AppKit"; - OTHER_REZFLAGS = ""; - PRODUCT_NAME = "DNS Service Browser"; - SECTORDER_FLAGS = ""; - WARNING_CFLAGS = "-Wmost"; - }; - dependencies = ( - ); - isa = PBXNativeTarget; - name = "DNS Service Browser"; - productName = "DNS Service Browser"; - productReference = FF1B691106711383002304DD; - productSettingsXML = " - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - DNS Service Browser - CFBundleGetInfoString - - CFBundleIconFile - - CFBundleIdentifier - com.apple.DNS_Service_Browser - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - APPL - CFBundleShortVersionString - - CFBundleSignature - ???? - CFBundleVersion - 1.0.0d1 - NSMainNibFile - DNSServiceBrowser - NSPrincipalClass - NSApplication - - -"; - productType = "com.apple.product-type.application"; - }; - FF1B691106711383002304DD = { - explicitFileType = wrapper.application; - includeInIndex = 0; - isa = PBXFileReference; - path = "DNS Service Browser.app"; - refType = 3; - sourceTree = BUILT_PRODUCTS_DIR; - }; - FF1B6914067114AF002304DD = { - fileEncoding = 4; - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.objc; - path = DNSServiceBrowser.m; - refType = 4; - sourceTree = ""; - }; - FF1B6915067114AF002304DD = { - fileRef = FF1B6914067114AF002304DD; - isa = PBXBuildFile; - settings = { - }; - }; - FF1E350E06711B5C003DD5BC = { - buildActionMask = 2147483647; - files = ( - ); - isa = PBXHeadersBuildPhase; - runOnlyForDeploymentPostprocessing = 0; - }; - FF1E350F06711B5C003DD5BC = { - buildActionMask = 2147483647; - files = ( - FF1E352606711BD6003DD5BC, - ); - isa = PBXResourcesBuildPhase; - runOnlyForDeploymentPostprocessing = 0; - }; - FF1E351006711B5C003DD5BC = { - buildActionMask = 2147483647; - files = ( - FF1E351C06711BCF003DD5BC, - ); - isa = PBXSourcesBuildPhase; - runOnlyForDeploymentPostprocessing = 0; - }; - FF1E351106711B5C003DD5BC = { - buildActionMask = 2147483647; - files = ( - ); - isa = PBXFrameworksBuildPhase; - runOnlyForDeploymentPostprocessing = 0; - }; - FF1E351206711B5C003DD5BC = { - buildPhases = ( - FF1E350E06711B5C003DD5BC, - FF1E350F06711B5C003DD5BC, - FF1E351006711B5C003DD5BC, - FF1E351106711B5C003DD5BC, - ); - buildRules = ( - ); - buildSettings = { - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; - GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; - GCC_WARN_UNKNOWN_PRAGMAS = NO; - HEADER_SEARCH_PATHS = ../mDNSShared; - INFOPLIST_FILE = "DNSServiceReg-Info.plist"; - INSTALL_PATH = "$(USER_APPS_DIR)"; - OTHER_CFLAGS = ""; - OTHER_LDFLAGS = "-framework Foundation -framework AppKit"; - OTHER_REZFLAGS = ""; - PRODUCT_NAME = "DNS Service Registration"; - SECTORDER_FLAGS = ""; - WARNING_CFLAGS = "-Wmost"; - }; - dependencies = ( - ); - isa = PBXNativeTarget; - name = "DNS Service Registration"; - productName = "DNS Service Registration"; - productReference = FF1E351306711B5C003DD5BC; - productSettingsXML = " - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - DNS Service Registration - CFBundleGetInfoString - - CFBundleIconFile - - CFBundleIdentifier - com.apple.DNS_Service_Registration - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - APPL - CFBundleShortVersionString - - CFBundleSignature - ???? - CFBundleVersion - 1.0.0d1 - NSMainNibFile - DNSServiceReg - NSPrincipalClass - NSApplication - - -"; - productType = "com.apple.product-type.application"; - }; - FF1E351306711B5C003DD5BC = { - explicitFileType = wrapper.application; - includeInIndex = 0; - isa = PBXFileReference; - path = "DNS Service Registration.app"; - refType = 3; - sourceTree = BUILT_PRODUCTS_DIR; - }; - FF1E351706711B6A003DD5BC = { - containerPortal = 08FB7793FE84155DC02AAC07; - isa = PBXContainerItemProxy; - proxyType = 1; - remoteGlobalIDString = FF1E351206711B5C003DD5BC; - remoteInfo = DNSServiceReg; - }; - FF1E351806711B6A003DD5BC = { - isa = PBXTargetDependency; - target = FF1E351206711B5C003DD5BC; - targetProxy = FF1E351706711B6A003DD5BC; - }; - FF1E351B06711BCF003DD5BC = { - fileEncoding = 4; - isa = PBXFileReference; - lastKnownFileType = sourcecode.c.objc; - path = DNSServiceReg.m; - refType = 4; - sourceTree = ""; - }; - FF1E351C06711BCF003DD5BC = { - fileRef = FF1E351B06711BCF003DD5BC; - isa = PBXBuildFile; - settings = { - }; - }; - FF1E352506711BD6003DD5BC = { - isa = PBXFileReference; - lastKnownFileType = wrapper.nib; - path = DNSServiceReg.nib; - refType = 4; - sourceTree = ""; - }; - FF1E352606711BD6003DD5BC = { - fileRef = FF1E352506711BD6003DD5BC; - isa = PBXBuildFile; - settings = { - }; - }; - FF383825067117F300FEF615 = { - containerPortal = 08FB7793FE84155DC02AAC07; - isa = PBXContainerItemProxy; - proxyType = 1; - remoteGlobalIDString = 8DD76F740486A8DE00D96B5E; - remoteInfo = "dns-sd"; - }; - FF383826067117F300FEF615 = { - isa = PBXTargetDependency; - target = 8DD76F740486A8DE00D96B5E; - targetProxy = FF383825067117F300FEF615; - }; - FF383827067117F600FEF615 = { - containerPortal = 08FB7793FE84155DC02AAC07; - isa = PBXContainerItemProxy; - proxyType = 1; - remoteGlobalIDString = FF1B691006711383002304DD; - remoteInfo = "DNS Service Browser"; - }; - FF383828067117F600FEF615 = { - isa = PBXTargetDependency; - target = FF1B691006711383002304DD; - targetProxy = FF383827067117F600FEF615; - }; - FF964AA00671153B0099215A = { - isa = PBXFileReference; - lastKnownFileType = wrapper.framework; - name = Foundation.framework; - path = /System/Library/Frameworks/Foundation.framework; - refType = 0; - sourceTree = ""; - }; - FF964AA10671153B0099215A = { - fileRef = FF964AA00671153B0099215A; - isa = PBXBuildFile; - settings = { - }; - }; - FF964CA90671155C0099215A = { - isa = PBXFileReference; - lastKnownFileType = wrapper.framework; - name = AppKit.framework; - path = /System/Library/Frameworks/AppKit.framework; - refType = 0; - sourceTree = ""; - }; - FF964CAA0671155C0099215A = { - fileRef = FF964CA90671155C0099215A; - isa = PBXBuildFile; - settings = { - }; - }; - FF964DAB067115710099215A = { - isa = PBXFileReference; - lastKnownFileType = wrapper.nib; - path = DNSServiceBrowser.nib; - refType = 4; - sourceTree = ""; - }; - FF964DAC067115710099215A = { - fileRef = FF964DAB067115710099215A; - isa = PBXBuildFile; - settings = { - }; - }; - FFF520490671177900DA3D49 = { - buildPhases = ( - ); - buildSettings = { - OTHER_CFLAGS = ""; - OTHER_LDFLAGS = ""; - OTHER_REZFLAGS = ""; - PRODUCT_NAME = "Build All"; - SECTORDER_FLAGS = ""; - WARNING_CFLAGS = "-Wmost -Wno-four-char-constants -Wno-unknown-pragmas"; - }; - dependencies = ( - FF383826067117F300FEF615, - FF383828067117F600FEF615, - FF1E351806711B6A003DD5BC, - ); - isa = PBXAggregateTarget; - name = "Build All"; - productName = "Build All"; - }; - }; - rootObject = 08FB7793FE84155DC02AAC07; -} diff --git a/Clients/DNS-SD.xcodeproj/project.pbxproj b/Clients/DNS-SD.xcodeproj/project.pbxproj new file mode 100644 index 0000000..6ed5d53 --- /dev/null +++ b/Clients/DNS-SD.xcodeproj/project.pbxproj @@ -0,0 +1,733 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 42; + objects = { + +/* Begin PBXAggregateTarget section */ + FFF520490671177900DA3D49 /* Build All */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 21D91E890B12A03D003981D9 /* Build configuration list for PBXAggregateTarget "Build All" */; + buildPhases = ( + ); + dependencies = ( + FF383826067117F300FEF615 /* PBXTargetDependency */, + FF383828067117F600FEF615 /* PBXTargetDependency */, + FF1E351806711B6A003DD5BC /* PBXTargetDependency */, + ); + name = "Build All"; + productName = "Build All"; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 8DD76F770486A8DE00D96B5E /* dns-sd.c in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* dns-sd.c */; settings = {ATTRIBUTES = (); }; }; + FF1B6915067114AF002304DD /* DNSServiceBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = FF1B6914067114AF002304DD /* DNSServiceBrowser.m */; }; + FF1E351C06711BCF003DD5BC /* DNSServiceReg.m in Sources */ = {isa = PBXBuildFile; fileRef = FF1E351B06711BCF003DD5BC /* DNSServiceReg.m */; }; + FF1E352606711BD6003DD5BC /* DNSServiceReg.nib in Resources */ = {isa = PBXBuildFile; fileRef = FF1E352506711BD6003DD5BC /* DNSServiceReg.nib */; }; + FF964AA10671153B0099215A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF964AA00671153B0099215A /* Foundation.framework */; }; + FF964CAA0671155C0099215A /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF964CA90671155C0099215A /* AppKit.framework */; }; + FF964DAC067115710099215A /* DNSServiceBrowser.nib in Resources */ = {isa = PBXBuildFile; fileRef = FF964DAB067115710099215A /* DNSServiceBrowser.nib */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + FF1E351706711B6A003DD5BC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FF1E351206711B5C003DD5BC; + remoteInfo = DNSServiceReg; + }; + FF383825067117F300FEF615 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8DD76F740486A8DE00D96B5E; + remoteInfo = "dns-sd"; + }; + FF383827067117F600FEF615 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FF1B691006711383002304DD; + remoteInfo = "DNS Service Browser"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 8DD76F7B0486A8DE00D96B5E /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 08FB7796FE84155DC02AAC07 /* dns-sd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "dns-sd.c"; sourceTree = ""; }; + 8DD76F7E0486A8DE00D96B5E /* dns-sd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "dns-sd"; sourceTree = BUILT_PRODUCTS_DIR; }; + FF1B691106711383002304DD /* DNS Service Browser.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DNS Service Browser.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + FF1B6914067114AF002304DD /* DNSServiceBrowser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNSServiceBrowser.m; sourceTree = ""; }; + FF1E351306711B5C003DD5BC /* DNS Service Registration.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DNS Service Registration.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + FF1E351B06711BCF003DD5BC /* DNSServiceReg.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNSServiceReg.m; sourceTree = ""; }; + FF1E352506711BD6003DD5BC /* DNSServiceReg.nib */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; path = DNSServiceReg.nib; sourceTree = ""; }; + FF964AA00671153B0099215A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; + FF964CA90671155C0099215A /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; + FF964DAB067115710099215A /* DNSServiceBrowser.nib */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; path = DNSServiceBrowser.nib; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8DD76F780486A8DE00D96B5E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FF1B690F06711383002304DD /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + FF964AA10671153B0099215A /* Foundation.framework in Frameworks */, + FF964CAA0671155C0099215A /* AppKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FF1E351106711B5C003DD5BC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* mDNS */ = { + isa = PBXGroup; + children = ( + 08FB7795FE84155DC02AAC07 /* Source */, + 21D91EBD0B12A2B6003981D9 /* Resources */, + 08FB779DFE84155DC02AAC07 /* Frameworks */, + 19C28FBDFE9D53C911CA2CBB /* Products */, + ); + name = mDNS; + sourceTree = ""; + }; + 08FB7795FE84155DC02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + 08FB7796FE84155DC02AAC07 /* dns-sd.c */, + FF1B6914067114AF002304DD /* DNSServiceBrowser.m */, + FF1E351B06711BCF003DD5BC /* DNSServiceReg.m */, + ); + name = Source; + sourceTree = ""; + }; + 08FB779DFE84155DC02AAC07 /* Frameworks */ = { + isa = PBXGroup; + children = ( + FF964CA90671155C0099215A /* AppKit.framework */, + FF964AA00671153B0099215A /* Foundation.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 19C28FBDFE9D53C911CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8DD76F7E0486A8DE00D96B5E /* dns-sd */, + FF1B691106711383002304DD /* DNS Service Browser.app */, + FF1E351306711B5C003DD5BC /* DNS Service Registration.app */, + ); + name = Products; + sourceTree = ""; + }; + 21D91EBD0B12A2B6003981D9 /* Resources */ = { + isa = PBXGroup; + children = ( + FF964DAB067115710099215A /* DNSServiceBrowser.nib */, + FF1E352506711BD6003DD5BC /* DNSServiceReg.nib */, + ); + name = Resources; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 8DD76F750486A8DE00D96B5E /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FF1B690C06711383002304DD /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FF1E350E06711B5C003DD5BC /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 8DD76F740486A8DE00D96B5E /* dns-sd */ = { + isa = PBXNativeTarget; + buildConfigurationList = 21D91E7D0B12A03D003981D9 /* Build configuration list for PBXNativeTarget "dns-sd" */; + buildPhases = ( + 8DD76F750486A8DE00D96B5E /* Headers */, + 8DD76F760486A8DE00D96B5E /* Sources */, + 8DD76F780486A8DE00D96B5E /* Frameworks */, + 8DD76F7A0486A8DE00D96B5E /* Rez */, + 8DD76F7B0486A8DE00D96B5E /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "dns-sd"; + productInstallPath = "$(HOME)/bin"; + productName = mDNS; + productReference = 8DD76F7E0486A8DE00D96B5E /* dns-sd */; + productType = "com.apple.product-type.tool"; + }; + FF1B691006711383002304DD /* DNS Service Browser */ = { + isa = PBXNativeTarget; + buildConfigurationList = 21D91E810B12A03D003981D9 /* Build configuration list for PBXNativeTarget "DNS Service Browser" */; + buildPhases = ( + FF1B690C06711383002304DD /* Headers */, + FF1B690D06711383002304DD /* Resources */, + FF1B690E06711383002304DD /* Sources */, + FF1B690F06711383002304DD /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "DNS Service Browser"; + productName = "DNS Service Browser"; + productReference = FF1B691106711383002304DD /* DNS Service Browser.app */; + productType = "com.apple.product-type.application"; + }; + FF1E351206711B5C003DD5BC /* DNS Service Registration */ = { + isa = PBXNativeTarget; + buildConfigurationList = 21D91E850B12A03D003981D9 /* Build configuration list for PBXNativeTarget "DNS Service Registration" */; + buildPhases = ( + FF1E350E06711B5C003DD5BC /* Headers */, + FF1E350F06711B5C003DD5BC /* Resources */, + FF1E351006711B5C003DD5BC /* Sources */, + FF1E351106711B5C003DD5BC /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "DNS Service Registration"; + productName = "DNS Service Registration"; + productReference = FF1E351306711B5C003DD5BC /* DNS Service Registration.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 21D91E8D0B12A03D003981D9 /* Build configuration list for PBXProject "DNS-SD" */; + hasScannedForEncodings = 1; + mainGroup = 08FB7794FE84155DC02AAC07 /* mDNS */; + projectDirPath = ""; + targets = ( + FFF520490671177900DA3D49 /* Build All */, + 8DD76F740486A8DE00D96B5E /* dns-sd */, + FF1B691006711383002304DD /* DNS Service Browser */, + FF1E351206711B5C003DD5BC /* DNS Service Registration */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + FF1B690D06711383002304DD /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FF964DAC067115710099215A /* DNSServiceBrowser.nib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FF1E350F06711B5C003DD5BC /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FF1E352606711BD6003DD5BC /* DNSServiceReg.nib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXRezBuildPhase section */ + 8DD76F7A0486A8DE00D96B5E /* Rez */ = { + isa = PBXRezBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXRezBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8DD76F760486A8DE00D96B5E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8DD76F770486A8DE00D96B5E /* dns-sd.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FF1B690E06711383002304DD /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FF1B6915067114AF002304DD /* DNSServiceBrowser.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FF1E351006711B5C003DD5BC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FF1E351C06711BCF003DD5BC /* DNSServiceReg.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + FF1E351806711B6A003DD5BC /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FF1E351206711B5C003DD5BC /* DNS Service Registration */; + targetProxy = FF1E351706711B6A003DD5BC /* PBXContainerItemProxy */; + }; + FF383826067117F300FEF615 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 8DD76F740486A8DE00D96B5E /* dns-sd */; + targetProxy = FF383825067117F300FEF615 /* PBXContainerItemProxy */; + }; + FF383828067117F600FEF615 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FF1B691006711383002304DD /* DNS Service Browser */; + targetProxy = FF383827067117F600FEF615 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 21D91E7E0B12A03D003981D9 /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + DEBUGGING_SYMBOLS = YES; + FRAMEWORK_SEARCH_PATHS = ""; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_ENABLE_TRIGRAPHS = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = NO; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + GCC_WARN_UNKNOWN_PRAGMAS = NO; + HEADER_SEARCH_PATHS = ../mDNSShared; + INSTALL_PATH = "$(HOME)/bin"; + LIBRARY_SEARCH_PATHS = ""; + OPTIMIZATION_CFLAGS = "-O0"; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = "dns-sd"; + REZ_EXECUTABLE = YES; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = ( + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + ZERO_LINK = NO; + }; + name = Development; + }; + 21D91E7F0B12A03D003981D9 /* Deployment */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + FRAMEWORK_SEARCH_PATHS = ""; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_ENABLE_TRIGRAPHS = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_PRECOMPILE_PREFIX_HEADER = NO; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + GCC_WARN_UNKNOWN_PRAGMAS = NO; + HEADER_SEARCH_PATHS = ../mDNSShared; + INSTALL_PATH = "$(HOME)/bin"; + LIBRARY_SEARCH_PATHS = ""; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = "dns-sd"; + REZ_EXECUTABLE = YES; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = ( + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + ZERO_LINK = NO; + }; + name = Deployment; + }; + 21D91E800B12A03D003981D9 /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ""; + GCC_ENABLE_TRIGRAPHS = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_PRECOMPILE_PREFIX_HEADER = NO; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + GCC_WARN_UNKNOWN_PRAGMAS = NO; + HEADER_SEARCH_PATHS = ../mDNSShared; + INSTALL_PATH = "$(HOME)/bin"; + LIBRARY_SEARCH_PATHS = ""; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = "dns-sd"; + REZ_EXECUTABLE = YES; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = ( + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + ZERO_LINK = NO; + }; + name = Default; + }; + 21D91E820B12A03D003981D9 /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + DEBUGGING_SYMBOLS = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + GCC_WARN_UNKNOWN_PRAGMAS = NO; + HEADER_SEARCH_PATHS = ../mDNSShared; + INFOPLIST_FILE = "DNSServiceBrowser-Info.plist"; + INSTALL_PATH = "$(USER_APPS_DIR)"; + OPTIMIZATION_CFLAGS = "-O0"; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ( + "-framework", + Foundation, + "-framework", + AppKit, + ); + OTHER_REZFLAGS = ""; + PRODUCT_NAME = "DNS Service Browser"; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = "-Wmost"; + ZERO_LINK = NO; + }; + name = Development; + }; + 21D91E830B12A03D003981D9 /* Deployment */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + GCC_WARN_UNKNOWN_PRAGMAS = NO; + HEADER_SEARCH_PATHS = ../mDNSShared; + INFOPLIST_FILE = "DNSServiceBrowser-Info.plist"; + INSTALL_PATH = "$(USER_APPS_DIR)"; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ( + "-framework", + Foundation, + "-framework", + AppKit, + ); + OTHER_REZFLAGS = ""; + PRODUCT_NAME = "DNS Service Browser"; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = "-Wmost"; + ZERO_LINK = NO; + }; + name = Deployment; + }; + 21D91E840B12A03D003981D9 /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + GCC_WARN_UNKNOWN_PRAGMAS = NO; + HEADER_SEARCH_PATHS = ../mDNSShared; + INFOPLIST_FILE = "DNSServiceBrowser-Info.plist"; + INSTALL_PATH = "$(USER_APPS_DIR)"; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ( + "-framework", + Foundation, + "-framework", + AppKit, + ); + OTHER_REZFLAGS = ""; + PRODUCT_NAME = "DNS Service Browser"; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = "-Wmost"; + }; + name = Default; + }; + 21D91E860B12A03D003981D9 /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + DEBUGGING_SYMBOLS = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + GCC_WARN_UNKNOWN_PRAGMAS = NO; + HEADER_SEARCH_PATHS = ../mDNSShared; + INFOPLIST_FILE = "DNSServiceReg-Info.plist"; + INSTALL_PATH = "$(USER_APPS_DIR)"; + OPTIMIZATION_CFLAGS = "-O0"; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ( + "-framework", + Foundation, + "-framework", + AppKit, + ); + OTHER_REZFLAGS = ""; + PRODUCT_NAME = "DNS Service Registration"; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = "-Wmost"; + ZERO_LINK = NO; + }; + name = Development; + }; + 21D91E870B12A03D003981D9 /* Deployment */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + GCC_WARN_UNKNOWN_PRAGMAS = NO; + HEADER_SEARCH_PATHS = ../mDNSShared; + INFOPLIST_FILE = "DNSServiceReg-Info.plist"; + INSTALL_PATH = "$(USER_APPS_DIR)"; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ( + "-framework", + Foundation, + "-framework", + AppKit, + ); + OTHER_REZFLAGS = ""; + PRODUCT_NAME = "DNS Service Registration"; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = "-Wmost"; + ZERO_LINK = NO; + }; + name = Deployment; + }; + 21D91E880B12A03D003981D9 /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + GCC_WARN_UNKNOWN_PRAGMAS = NO; + HEADER_SEARCH_PATHS = ../mDNSShared; + INFOPLIST_FILE = "DNSServiceReg-Info.plist"; + INSTALL_PATH = "$(USER_APPS_DIR)"; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ( + "-framework", + Foundation, + "-framework", + AppKit, + ); + OTHER_REZFLAGS = ""; + PRODUCT_NAME = "DNS Service Registration"; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = "-Wmost"; + }; + name = Default; + }; + 21D91E8A0B12A03D003981D9 /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + DEBUGGING_SYMBOLS = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + OPTIMIZATION_CFLAGS = "-O0"; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = "Build All"; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = ( + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + ZERO_LINK = NO; + }; + name = Development; + }; + 21D91E8B0B12A03D003981D9 /* Deployment */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = "Build All"; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = ( + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + ZERO_LINK = NO; + }; + name = Deployment; + }; + 21D91E8C0B12A03D003981D9 /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = "Build All"; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = ( + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + }; + name = Default; + }; + 21D91E8E0B12A03D003981D9 /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + PREBINDING = NO; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + }; + name = Development; + }; + 21D91E8F0B12A03D003981D9 /* Deployment */ = { + isa = XCBuildConfiguration; + buildSettings = { + PREBINDING = NO; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + }; + name = Deployment; + }; + 21D91E900B12A03D003981D9 /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + PREBINDING = NO; + SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; + }; + name = Default; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 21D91E7D0B12A03D003981D9 /* Build configuration list for PBXNativeTarget "dns-sd" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 21D91E7E0B12A03D003981D9 /* Development */, + 21D91E7F0B12A03D003981D9 /* Deployment */, + 21D91E800B12A03D003981D9 /* Default */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Default; + }; + 21D91E810B12A03D003981D9 /* Build configuration list for PBXNativeTarget "DNS Service Browser" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 21D91E820B12A03D003981D9 /* Development */, + 21D91E830B12A03D003981D9 /* Deployment */, + 21D91E840B12A03D003981D9 /* Default */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Default; + }; + 21D91E850B12A03D003981D9 /* Build configuration list for PBXNativeTarget "DNS Service Registration" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 21D91E860B12A03D003981D9 /* Development */, + 21D91E870B12A03D003981D9 /* Deployment */, + 21D91E880B12A03D003981D9 /* Default */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Default; + }; + 21D91E890B12A03D003981D9 /* Build configuration list for PBXAggregateTarget "Build All" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 21D91E8A0B12A03D003981D9 /* Development */, + 21D91E8B0B12A03D003981D9 /* Deployment */, + 21D91E8C0B12A03D003981D9 /* Default */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Default; + }; + 21D91E8D0B12A03D003981D9 /* Build configuration list for PBXProject "DNS-SD" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 21D91E8E0B12A03D003981D9 /* Development */, + 21D91E8F0B12A03D003981D9 /* Deployment */, + 21D91E900B12A03D003981D9 /* Default */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Default; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/Clients/DNSServiceBrowser-Info.plist b/Clients/DNSServiceBrowser-Info.plist index 9ccdde6..093d7b4 100644 --- a/Clients/DNSServiceBrowser-Info.plist +++ b/Clients/DNSServiceBrowser-Info.plist @@ -11,7 +11,7 @@ CFBundleIconFile CFBundleIdentifier - com.apple.DNS_Service_Browser + com.apple.DNSServiceBrowser CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType @@ -21,7 +21,7 @@ CFBundleSignature ???? CFBundleVersion - 1.0.0d1 + 1.0 NSMainNibFile DNSServiceBrowser NSPrincipalClass diff --git a/Clients/DNSServiceBrowser.NET/AssemblyInfo.cs b/Clients/DNSServiceBrowser.NET/AssemblyInfo.cs index 793362b..588f438 100755 --- a/Clients/DNSServiceBrowser.NET/AssemblyInfo.cs +++ b/Clients/DNSServiceBrowser.NET/AssemblyInfo.cs @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: AssemblyInfo.cs,v $ +Revision 1.2 2006/08/14 23:23:58 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.1 2004/07/19 07:54:24 shersche Initial revision diff --git a/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.cs b/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.cs index f2cf813..e279d18 100755 --- a/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.cs +++ b/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.cs @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: DNSServiceBrowser.cs,v $ +Revision 1.7 2006/08/14 23:23:58 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.6 2005/02/10 22:35:06 cheshire Update name diff --git a/Clients/DNSServiceBrowser.m b/Clients/DNSServiceBrowser.m index da42780..ac4f1ab 100755 --- a/Clients/DNSServiceBrowser.m +++ b/Clients/DNSServiceBrowser.m @@ -1,28 +1,37 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: DNSServiceBrowser.m,v $ +Revision 1.35 2006/11/27 08:27:49 mkrochma +Fix a crashing bug + +Revision 1.34 2006/11/24 05:41:07 mkrochma +More cleanup and more service types + +Revision 1.33 2006/11/24 01:34:24 mkrochma +Display interface index and query for IPv6 addresses even when there's no IPv4 + +Revision 1.32 2006/11/24 00:25:31 mkrochma + Tools: DNS Service Browser contains some bugs + +Revision 1.31 2006/08/14 23:23:55 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.30 2005/01/27 17:46:16 cheshire Added comment @@ -33,53 +42,52 @@ Revision 1.28 2004/05/18 23:51:26 cheshire Tidy up all checkin comments to use consistent "" format for bug numbers Revision 1.27 2003/11/19 18:49:48 rpantos -: couple of little tweaks to previous checkin + couple of little tweaks to previous checkin Revision 1.26 2003/11/07 19:35:20 rpantos -/6: Display multiple IP addresses. Connect using host rather than IP addr. + Display multiple IP addresses. Connect using host rather than IP addr. Revision 1.25 2003/10/29 05:16:54 rpantos Checkpoint: transition from DNSServiceDiscovery.h to dns_sd.h Revision 1.24 2003/10/28 02:25:45 rpantos -/9,10: Cancel pending resolve when focus changes or service disappears. + Cancel pending resolve when focus changes or service disappears. Revision 1.23 2003/10/28 01:29:15 rpantos -/4,5: Restructure a bit to make arrow keys work & views behave better. + Restructure a bit to make arrow keys work & views behave better. Revision 1.22 2003/10/28 01:23:27 rpantos -/11: Bail if mDNS cannot be initialized at startup. + Bail if mDNS cannot be initialized at startup. Revision 1.21 2003/10/28 01:19:45 rpantos -/3,11: Do not put a trailing '.' on service names. Handle PATH for HTTP txtRecords. + Do not put a trailing '.' on service names. Handle PATH for HTTP txtRecords. Revision 1.20 2003/10/28 01:13:49 rpantos -/2: Remove filter when displaying browse results. + Remove filter when displaying browse results. Revision 1.19 2003/10/28 01:10:14 rpantos -/1: Change 'compare' to 'caseInsensitiveCompare' to fix sort order. + Change 'compare' to 'caseInsensitiveCompare' to fix sort order. Revision 1.18 2003/08/12 19:55:07 cheshire Update to APSL 2.0 - */ +*/ +#import +#include +#include +#include #include #include -#include #include - -#import -#import - #include -#include "dns_sd.h" +#include +#include -@class ServiceController; // holds state corresponding to outstanding DNSServiceRef +@class ServiceController; // holds state corresponding to outstanding DNSServiceRef @interface BrowserController : NSObject { - IBOutlet id domainField; IBOutlet id nameField; IBOutlet id typeField; @@ -93,27 +101,20 @@ Update to APSL 2.0 IBOutlet id ipAddressField; IBOutlet id ip6AddressField; IBOutlet id portField; + IBOutlet id interfaceField; IBOutlet id textField; - NSMutableArray *srvtypeKeys; - NSMutableArray *srvnameKeys; - NSMutableArray *domainKeys; - NSMutableArray *nameKeys; - NSString *Domain; - NSString *SrvType; - NSString *SrvName; - NSString *Name; - - ServiceController *fDomainBrowser; - ServiceController *fServiceBrowser; - ServiceController *fServiceResolver; - ServiceController *fAddressResolver; + NSMutableArray *_srvtypeKeys; + NSMutableArray *_srvnameKeys; + NSMutableArray *_sortedServices; + NSMutableDictionary *_servicesDict; + ServiceController *_serviceBrowser; + ServiceController *_serviceResolver; + ServiceController *_ipv4AddressResolver; + ServiceController *_ipv6AddressResolver; } -- (IBAction)handleDomainClick:(id)sender; -- (IBAction)handleNameClick:(id)sender; -- (IBAction)handleTypeClick:(id)sender; - (void)notifyTypeSelectionChange:(NSNotification*)note; - (void)notifyNameSelectionChange:(NSNotification*)note; @@ -123,15 +124,11 @@ Update to APSL 2.0 - (IBAction)removeSelected:(id)sender; - (IBAction)addNewService:(id)sender; -- (IBAction)update:(NSString *)Type Domain:(NSString *)Domain; -- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication; -- (IBAction)loadDomains:(id)sender; +- (IBAction)update:(NSString *)Type; -- (void)updateBrowseWithResult:(DNSServiceFlags)flags name:(NSString *)name type:(NSString *)resulttype domain:(NSString *)domain; -- (void)updateEnumWithResult:(DNSServiceFlags)flags domain:(NSString *)domain; +- (void)updateBrowseWithName:(const char *)name type:(const char *)resulttype domain:(const char *)domain interface:(uint32_t)interface flags:(DNSServiceFlags)flags; - (void)resolveClientWitHost:(NSString *)host port:(uint16_t)port interfaceIndex:(uint32_t)interface txtRecord:(const char*)txtRecord txtLen:(uint16_t)txtLen; -- (void)updateAddress:(uint16_t)rrtype addr:(const void *)buff addrLen:(uint16_t)addrLen - host:(const char*) host interfaceIndex:(uint32_t)interface more:(boolean_t)moreToCome; +- (void)updateAddress:(uint16_t)rrtype addr:(const void *)buff addrLen:(uint16_t)addrLen host:(const char*)host interfaceIndex:(uint32_t)interface more:(boolean_t)moreToCome; - (void)_cancelPendingResolve; - (void)_clearResolvedInfo; @@ -141,75 +138,81 @@ Update to APSL 2.0 // The ServiceController manages cleanup of DNSServiceRef & runloop info for an outstanding request @interface ServiceController : NSObject { - DNSServiceRef fServiceRef; - CFSocketRef fSocketRef; - CFRunLoopSourceRef fRunloopSrc; + DNSServiceRef fServiceRef; + CFSocketRef fSocketRef; + CFRunLoopSourceRef fRunloopSrc; } -- (id) initWithServiceRef:(DNSServiceRef) ref; -- (boolean_t) addToCurrentRunLoop; -- (DNSServiceRef) serviceRef; -- (void) dealloc; +- (id)initWithServiceRef:(DNSServiceRef)ref; +- (void)addToCurrentRunLoop; +- (DNSServiceRef)serviceRef; +- (void)dealloc; @end // interface ServiceController -static void ProcessSockData( CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) -// CFRunloop callback that notifies dns_sd when new data appears on a DNSServiceRef's socket. +static void +ProcessSockData(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) { - DNSServiceRef serviceRef = (DNSServiceRef) info; - DNSServiceErrorType err = DNSServiceProcessResult( serviceRef); - if ( err != kDNSServiceErr_NoError) - printf( "DNSServiceProcessResult() returned an error! %d\n", err); + DNSServiceRef serviceRef = (DNSServiceRef)info; + DNSServiceErrorType err = DNSServiceProcessResult(serviceRef); + if (err != kDNSServiceErr_NoError) { + printf("DNSServiceProcessResult() returned an error! %d\n", err); + } } -static void DomainEnumReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, - DNSServiceErrorType errorCode, const char *replyDomain, void *context ) -// Report newly-discovered domains to the BrowserController. + +static void +ServiceBrowseReply(DNSServiceRef sdRef, DNSServiceFlags servFlags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, + const char *serviceName, const char *regtype, const char *replyDomain, void *context) { - if ( errorCode == kDNSServiceErr_NoError) { - BrowserController *pSelf = (BrowserController*) context; - [pSelf updateEnumWithResult:flags domain:[NSString stringWithUTF8String:replyDomain]]; + if (errorCode == kDNSServiceErr_NoError) { + [(BrowserController*)context updateBrowseWithName:serviceName type:regtype domain:replyDomain interface:interfaceIndex flags:servFlags]; } else { - printf( "DomainEnumReply got an error! %d\n", errorCode); + printf("ServiceBrowseReply got an error! %d\n", errorCode); } } -static void ServiceBrowseReply( DNSServiceRef sdRef, DNSServiceFlags servFlags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, - const char *serviceName, const char *regtype, const char *replyDomain, void *context ) -// Report newly-discovered services to the BrowserController. + +static void +ServiceResolveReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, + const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const char *txtRecord, void *context) { - if ( errorCode == kDNSServiceErr_NoError) { - BrowserController *pSelf = (BrowserController*) context; - [pSelf updateBrowseWithResult:servFlags name:[NSString stringWithUTF8String:serviceName] - type:[NSString stringWithUTF8String:regtype] domain:[NSString stringWithUTF8String:replyDomain]]; + if (errorCode == kDNSServiceErr_NoError) { + [(BrowserController*)context resolveClientWitHost:[NSString stringWithUTF8String:hosttarget] port:port interfaceIndex:interfaceIndex txtRecord:txtRecord txtLen:txtLen]; } else { - printf( "ServiceBrowseReply got an error! %d\n", errorCode); + printf("ServiceResolveReply got an error! %d\n", errorCode); } } -static void ServiceResolveReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, - DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port, - uint16_t txtLen, const char *txtRecord, void *context ) -// Pass along resolved service info to the BrowserController. + +static void +QueryRecordReply(DNSServiceRef DNSServiceRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, + const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context) { - if ( errorCode == kDNSServiceErr_NoError) { - BrowserController *pSelf = (BrowserController*) context; - [pSelf resolveClientWitHost:[NSString stringWithUTF8String:hosttarget] port:port interfaceIndex:interfaceIndex txtRecord:txtRecord txtLen:txtLen]; - } else { - printf( "ServiceResolveReply got an error! %d\n", errorCode); - } + if (errorCode == kDNSServiceErr_NoError) { + [(BrowserController*)context updateAddress:rrtype addr:rdata addrLen:rdlen host:fullname interfaceIndex:interfaceIndex more:(flags & kDNSServiceFlagsMoreComing)]; + } else { + printf("QueryRecordReply got an error! %d\n", errorCode); + } } -static void QueryRecordReply( DNSServiceRef DNSServiceRef, DNSServiceFlags flags, uint32_t interfaceIndex, - DNSServiceErrorType errorCode, const char *fullname, uint16_t rrtype, uint16_t rrclass, - uint16_t rdlen, const void *rdata, uint32_t ttl, void *context ) -// DNSServiceQueryRecord callback used to look up IP addresses. -{ - BrowserController *pBrowser = (BrowserController*) context; - [pBrowser updateAddress:rrtype addr:rdata addrLen:rdlen host:fullname interfaceIndex:interfaceIndex - more:((flags & kDNSServiceFlagsMoreComing) != 0)]; +static void +InterfaceIndexToName(uint32_t interface, char *interfaceName) +{ + assert(interfaceName); + + if (interface == kDNSServiceInterfaceIndexAny) { + // All active network interfaces. + strlcpy(interfaceName, "all", IF_NAMESIZE); + } else if (interface == kDNSServiceInterfaceIndexLocalOnly) { + // Only available locally on this machine. + strlcpy(interfaceName, "local", IF_NAMESIZE); + } else { + // Converts interface index to interface name. + if_indextoname(interface, interfaceName); + } } @@ -219,18 +222,33 @@ static void QueryRecordReply( DNSServiceRef DNSServiceRef, DNSServiceFlags flags { NSMutableDictionary *regDict = [NSMutableDictionary dictionary]; - NSArray *typeArray = [NSArray arrayWithObjects:@"_ftp._tcp", @"_tftp._tcp", - @"_ssh._tcp", @"_telnet._tcp", + NSArray *typeArray = [NSArray arrayWithObjects:@"_afpovertcp._tcp", + @"_smb._tcp", + @"_rfb._tcp", + @"_ssh._tcp", + @"_ftp._tcp", @"_http._tcp", - @"_printer._tcp", @"_ipp._tcp", - @"_ichat._tcp", @"_eppc._tcp", - @"_afpovertcp._tcp", @"_afpovertcp._tcp", @"_MacOSXDupSuppress._tcp", nil]; - NSArray *nameArray = [NSArray arrayWithObjects:@"File Transfer (ftp)", @"Trivial File Transfer (tftp)", - @"Secure Shell (ssh)", @"Telnet", - @"Web Server (http)", - @"LPR Printer", @"IPP Printer", - @"iChat", @"Remote AppleEvents", - @"AppleShare Server", @"SMB File Server", @"Mystery Service", nil]; + @"_printer._tcp", + @"_ipp._tcp", + @"_airport._tcp", + @"_presence._tcp", + @"_daap._tcp", + @"_dpap._tcp", + nil]; + + NSArray *nameArray = [NSArray arrayWithObjects:@"AppleShare Servers", + @"Windows Sharing", + @"Screen Sharing", + @"Secure Shell", + @"FTP Servers", + @"Web Servers", + @"LPR Printers", + @"IPP Printers", + @"AirPort Base Stations", + @"iChat Buddies", + @"iTunes Libraries", + @"iPhoto Libraries", + nil]; [regDict setObject:typeArray forKey:@"SrvTypeKeys"]; [regDict setObject:nameArray forKey:@"SrvNameKeys"]; @@ -241,385 +259,285 @@ static void QueryRecordReply( DNSServiceRef DNSServiceRef, DNSServiceFlags flags - (id)init { - [self registerDefaults]; - - fDomainBrowser = nil; - fServiceBrowser = nil; - fServiceResolver = nil; - fAddressResolver = nil; - - return [super init]; + self = [super init]; + if (self) { + _srvtypeKeys = nil; + _srvnameKeys = nil; + _serviceBrowser = nil; + _serviceResolver = nil; + _ipv4AddressResolver = nil; + _ipv6AddressResolver = nil; + _sortedServices = [[NSMutableArray alloc] init]; + _servicesDict = [[NSMutableDictionary alloc] init]; + } + return self; } -- (void)awakeFromNib //BrowserController startup procedure -{ - SrvType=NULL; - Domain=NULL; - srvtypeKeys = [NSMutableArray array]; //Define arrays for Type, Domain, and Name - srvnameKeys = [NSMutableArray array]; - - domainKeys = [NSMutableArray array]; - [domainKeys retain]; - - nameKeys = [NSMutableArray array]; - [nameKeys retain]; - [srvtypeKeys retain]; //Keep arrays in memory until BrowserController closes - [srvnameKeys retain]; //Keep arrays in memory until BrowserController closes - [typeField sizeLastColumnToFit]; //Set column sizes to use their whole table's width. +- (void)awakeFromNib +{ + [typeField sizeLastColumnToFit]; [nameField sizeLastColumnToFit]; - [domainField sizeLastColumnToFit]; -// (self is specified as the NSTableViews' data source in the nib) - [nameField setDoubleAction:@selector(connect:)]; - // Listen for table selection changes - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notifyTypeSelectionChange:) - name:NSTableViewSelectionDidChangeNotification object:typeField]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notifyNameSelectionChange:) - name:NSTableViewSelectionDidChangeNotification object:nameField]; - - //[srvtypeKeys addObject:@"_ftp._tcp"]; //Add supported protocols and domains to their - //[srvnameKeys addObject:@"File Transfer (ftp)"]; - //[srvtypeKeys addObject:@"_printer._tcp"]; //respective arrays - //[srvnameKeys addObject:@"Printer (lpr)"]; - //[srvtypeKeys addObject:@"_http._tcp"]; //respective arrays - //[srvnameKeys addObject:@"Web Server (http)"]; - //[srvtypeKeys addObject:@"_afp._tcp"]; //respective arrays - //[srvnameKeys addObject:@"AppleShare Server (afp)"]; - - [self _clearResolvedInfo]; - - [srvtypeKeys addObjectsFromArray:[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvTypeKeys"]]; - [srvnameKeys addObjectsFromArray:[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvNameKeys"]]; - - - [typeField reloadData]; //Reload (redraw) data in fields - [domainField reloadData]; - - [self loadDomains:self]; - + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notifyTypeSelectionChange:) name:NSTableViewSelectionDidChangeNotification object:typeField]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notifyNameSelectionChange:) name:NSTableViewSelectionDidChangeNotification object:nameField]; + + _srvtypeKeys = [[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvTypeKeys"] mutableCopy]; + _srvnameKeys = [[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvNameKeys"] mutableCopy]; + + if (!_srvtypeKeys || !_srvnameKeys) { + [_srvtypeKeys release]; + [_srvnameKeys release]; + [self registerDefaults]; + _srvtypeKeys = [[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvTypeKeys"] mutableCopy]; + _srvnameKeys = [[[NSUserDefaults standardUserDefaults] arrayForKey:@"SrvNameKeys"] mutableCopy]; + } + + [typeField reloadData]; } -- (void)dealloc //Deallocation method + +- (void)dealloc { - [srvtypeKeys release]; - [srvnameKeys release]; - [nameKeys release]; - [domainKeys release]; + [_srvtypeKeys release]; + [_srvnameKeys release]; + [_servicesDict release]; + [_sortedServices release]; + [super dealloc]; } + -(void)tableView:(NSTableView *)theTableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(int)row { - if (row<0) return; + if (row < 0) return; } + - (int)numberOfRowsInTableView:(NSTableView *)theTableView //Begin mandatory TableView methods { - if (theTableView == typeField) - { - return [srvnameKeys count]; - } - if (theTableView == domainField) - { - return [domainKeys count]; + if (theTableView == typeField) { + return [_srvnameKeys count]; } - if (theTableView == nameField) - { - return [nameKeys count]; + if (theTableView == nameField) { + return [_servicesDict count]; } - if (theTableView == serviceDisplayTable) - { - return [srvnameKeys count]; + if (theTableView == serviceDisplayTable) { + return [_srvnameKeys count]; } return 0; } + - (id)tableView:(NSTableView *)theTableView objectValueForTableColumn:(NSTableColumn *)theColumn row:(int)rowIndex { - if (theTableView == typeField) - { - return [srvnameKeys objectAtIndex:rowIndex]; - } - if (theTableView == domainField) - { - return [domainKeys objectAtIndex:rowIndex]; + if (theTableView == typeField) { + return [_srvnameKeys objectAtIndex:rowIndex]; } - if (theTableView == nameField) - { - return [[nameKeys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)] objectAtIndex:rowIndex]; + if (theTableView == nameField) { + return [[_servicesDict objectForKey:[_sortedServices objectAtIndex:rowIndex]] name]; } - if (theTableView == serviceDisplayTable) - { + if (theTableView == serviceDisplayTable) { if (theColumn == typeColumn) { - return [srvtypeKeys objectAtIndex:rowIndex]; + return [_srvtypeKeys objectAtIndex:rowIndex]; } if (theColumn == nameColumn) { - return [srvnameKeys objectAtIndex:rowIndex]; + return [_srvnameKeys objectAtIndex:rowIndex]; } - return 0; + return nil; } - else - return(0); -} //End of mandatory TableView methods - -- (IBAction)handleTypeClick:(id)sender //Handle clicks for Type -{ - // 3282283: No longer used - update happens in notifyTypeSelectionChange -} - - -- (IBAction)handleDomainClick:(id)sender //Handle clicks for Domain -{ - int index=[sender selectedRow]; //Find index of selected row - if (index==-1) return; //Error checking - Domain = [domainKeys objectAtIndex:index]; //Save desired Domain - - [self _cancelPendingResolve]; - - if (SrvType!=NULL) [self update:SrvType Domain:Domain]; //If Type and Domain are set, update records + + return nil; } -- (IBAction)handleNameClick:(id)sender //Handle clicks for Name -{ - // 3282283: No longer used - update happens in notifyNameSelectionChange -} - (void)notifyTypeSelectionChange:(NSNotification*)note -/* Called when the selection of the Type table changes */ { - int index=[[note object] selectedRow]; //Find index of selected row - if (index==-1) return; //Error checking - SrvType = [srvtypeKeys objectAtIndex:index]; //Save desired Type - SrvName = [srvnameKeys objectAtIndex:index]; //Save desired Type - [self _cancelPendingResolve]; - [self update:SrvType Domain:Domain]; //If Type and Domain are set, update records + int index = [[note object] selectedRow]; + if (index != -1) { + [self update:[_srvtypeKeys objectAtIndex:index]]; + } else { + [self update:nil]; + } } + - (void)notifyNameSelectionChange:(NSNotification*)note -/* Called when the selection of the Name table changes */ { - int index=[[note object] selectedRow]; //Find index of selected row - - [self _cancelPendingResolve]; // Cancel any pending Resolve for any table selection change - - if (index==-1) { - Name = nil; // Name may no longer point to a list member + [self _cancelPendingResolve]; + + int index = [[note object] selectedRow]; + if (index == -1) { return; } - Name=[[nameKeys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)] objectAtIndex:index]; //Save desired name - - [self _clearResolvedInfo]; - - DNSServiceRef serviceRef; - DNSServiceErrorType err; - err = DNSServiceResolve ( &serviceRef, (DNSServiceFlags) 0, 0, (char *)[Name UTF8String], (char *)[SrvType UTF8String], - (char *)(Domain?[Domain UTF8String]:""), ServiceResolveReply, self); - if ( kDNSServiceErr_NoError == err) { - fServiceResolver = [[ServiceController alloc] initWithServiceRef:serviceRef]; - [fServiceResolver addToCurrentRunLoop]; + + // Get the currently selected service + NSNetService *service = [_servicesDict objectForKey:[_sortedServices objectAtIndex:index]]; + + DNSServiceRef serviceRef; + DNSServiceErrorType err = DNSServiceResolve(&serviceRef, + (DNSServiceFlags)0, + kDNSServiceInterfaceIndexAny, + (const char *)[[service name] UTF8String], + (const char *)[[service type] UTF8String], + (const char *)[[service domain] UTF8String], + (DNSServiceResolveReply)ServiceResolveReply, + self); + + if (kDNSServiceErr_NoError == err) { + _serviceResolver = [[ServiceController alloc] initWithServiceRef:serviceRef]; + [_serviceResolver addToCurrentRunLoop]; } } -- (IBAction)loadDomains:(id)sender -{ - DNSServiceErrorType err; - DNSServiceRef serviceRef; - - err = DNSServiceEnumerateDomains( &serviceRef, kDNSServiceFlagsBrowseDomains, 0, DomainEnumReply, self); - if ( kDNSServiceErr_NoError == err) { - fDomainBrowser = [[ServiceController alloc] initWithServiceRef:serviceRef]; - [fDomainBrowser addToCurrentRunLoop]; - } - else { - NSAlert *alert = [NSAlert alertWithMessageText:@"Could not connect to mDNSResponder!" - defaultButton:@"Quit" alternateButton:nil otherButton:nil informativeTextWithFormat: - @"Check to see if mDNSResponder is still running."]; - if ( alert != NULL) - [alert runModal]; - exit( err); - } -} -- (IBAction)update:theType Domain:theDomain; //The Big Kahuna: Fetch PTR records and update application +- (IBAction)update:(NSString *)theType { - const char * DomainC; - const char * TypeC=[theType UTF8String]; //Type in C string format - - DNSServiceErrorType err = kDNSServiceErr_NoError; - - if (theDomain) { - DomainC = [theDomain UTF8String]; //Domain in C string format - } else { - DomainC = ""; - } - - [nameKeys removeAllObjects]; //Get rid of displayed records if we're going to go get new ones - [nameField reloadData]; //Reload (redraw) names to show the old data is gone + [_servicesDict removeAllObjects]; + [_sortedServices removeAllObjects]; + [nameField reloadData]; // get rid of the previous browser if one exists - if ( fServiceBrowser != nil) { - [fServiceBrowser release]; - fServiceBrowser = nil; + if (_serviceBrowser != nil) { + [_serviceBrowser release]; + _serviceBrowser = nil; + } + + if (theType) { + DNSServiceRef serviceRef; + DNSServiceErrorType err = DNSServiceBrowse(&serviceRef, (DNSServiceFlags)0, 0, [theType UTF8String], NULL, ServiceBrowseReply, self); + if (kDNSServiceErr_NoError == err) { + _serviceBrowser = [[ServiceController alloc] initWithServiceRef:serviceRef]; + [_serviceBrowser addToCurrentRunLoop]; + } } - - // now create a browser to return the values for the nameField ... - DNSServiceRef serviceRef; - err = DNSServiceBrowse( &serviceRef, (DNSServiceFlags) 0, 0, TypeC, DomainC, ServiceBrowseReply, self); - if ( kDNSServiceErr_NoError == err) { - fServiceBrowser = [[ServiceController alloc] initWithServiceRef:serviceRef]; - [fServiceBrowser addToCurrentRunLoop]; - } } -- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication //Quit when main window is closed +- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication { return YES; } -- (BOOL)windowShouldClose:(NSWindow *)sender //Save domains to our domain file when quitting -{ - [domainField reloadData]; - return YES; -} -- (void)updateEnumWithResult:(DNSServiceFlags)flags domain:(NSString *)domain +- (void)updateBrowseWithName:(const char *)name type:(const char *)type domain:(const char *)domain interface:(uint32_t)interface flags:(DNSServiceFlags)flags { - if ( ( flags & kDNSServiceFlagsAdd) != 0) { // new domain received - // add the domain to the list - [domainKeys addObject:domain]; - } else if (!(flags & kDNSServiceFlagsAdd)) { - // remove the domain from the list - NSEnumerator *dmnEnum = [domainKeys objectEnumerator]; - NSString *aDomain = nil; + NSString *key = [NSString stringWithFormat:@"%s.%s%s%d", name, type, domain, interface]; + NSNetService *service = [[NSNetService alloc] initWithDomain:[NSString stringWithUTF8String:domain] type:[NSString stringWithUTF8String:type] name:[NSString stringWithUTF8String:name]]; + + if (flags & kDNSServiceFlagsAdd) { + [_servicesDict setObject:service forKey:key]; + } else { + [_servicesDict removeObjectForKey:key]; + } - while (aDomain = [dmnEnum nextObject]) { - if ([aDomain isEqualToString:domain]) { - [domainKeys removeObject:domain]; - break; - } + // If not expecting any more data, then reload (redraw) TableView with newly found data + if (!(flags & kDNSServiceFlagsMoreComing)) { + + // Save the current TableView selection + int index = [nameField selectedRow]; + NSString *selected = (index != -1) ? [[_sortedServices objectAtIndex:index] copy] : nil; + + [_sortedServices release]; + _sortedServices = [[_servicesDict allKeys] mutableCopy]; + [_sortedServices sortUsingSelector:@selector(caseInsensitiveCompare:)]; + [nameField reloadData]; + + // Restore the previous TableView selection + index = selected ? [_sortedServices indexOfObject:selected] : NSNotFound; + if (index != NSNotFound) { + [nameField selectRowIndexes:[NSIndexSet indexSetWithIndex:index] byExtendingSelection:NO]; + [nameField scrollRowToVisible:index]; } + + [selected release]; } - // update the domain table - [domainField reloadData]; - // Terminate the enumeration once the last domain is delivered. - if ( ( flags & kDNSServiceFlagsMoreComing) == 0) { - [fDomainBrowser release]; - fDomainBrowser = nil; - } - - // At some point, we may want to support a TableView for domain browsing. For now, just pick first domain that comes up. - if ( Domain == nil) - Domain = [domain retain]; + [service release]; return; } - -- (void)updateBrowseWithResult:(DNSServiceFlags)flags name:(NSString *)name type:(NSString *)resulttype domain:(NSString *)domain +- (void)resolveClientWitHost:(NSString *)host port:(uint16_t)port interfaceIndex:(uint32_t)interface txtRecord:(const char*)txtRecord txtLen:(uint16_t)txtLen { + DNSServiceRef serviceRef; - //NSLog(@"Received result %@ %@ %@ %d", name, resulttype, domain, type); + if (_ipv4AddressResolver) { + [_ipv4AddressResolver release]; + _ipv4AddressResolver = nil; + } + + if (_ipv6AddressResolver) { + [_ipv6AddressResolver release]; + _ipv6AddressResolver = nil; + } - if (!(flags & kDNSServiceFlagsAdd)) { - if ([nameKeys containsObject:name]) { - [nameKeys removeObject:name]; + // Start an async lookup for IPv4 addresses + DNSServiceErrorType err = DNSServiceQueryRecord(&serviceRef, (DNSServiceFlags)0, interface, [host UTF8String], kDNSServiceType_A, kDNSServiceClass_IN, QueryRecordReply, self); + if (err == kDNSServiceErr_NoError) { + _ipv4AddressResolver = [[ServiceController alloc] initWithServiceRef:serviceRef]; + [_ipv4AddressResolver addToCurrentRunLoop]; + } - // 3282283: Cancel pending browse if object goes away. - if ( [name isEqualToString:Name]) - [nameField deselectAll:self]; - } - } - else if ( ( flags & kDNSServiceFlagsAdd) != 0) { - if (![nameKeys containsObject:name]) { - [nameKeys addObject:name]; - } + // Start an async lookup for IPv6 addresses + err = DNSServiceQueryRecord(&serviceRef, (DNSServiceFlags)0, interface, [host UTF8String], kDNSServiceType_AAAA, kDNSServiceClass_IN, QueryRecordReply, self); + if (err == kDNSServiceErr_NoError) { + _ipv6AddressResolver = [[ServiceController alloc] initWithServiceRef:serviceRef]; + [_ipv6AddressResolver addToCurrentRunLoop]; } - // If not expecting any more data, then reload (redraw) Name TableView with newly found data - if ((flags & kDNSServiceFlagsMoreComing) == 0) - [nameField reloadData]; - return; -} - -- (void)resolveClientWitHost:(NSString *)host port:(uint16_t)port interfaceIndex:(uint32_t)interface - txtRecord:(const char*)txtRecord txtLen:(uint16_t)txtLen -/* Display resolved information about the selected service. */ -{ - DNSServiceErrorType err; - DNSServiceRef serviceRef; - - // Start an async lookup for IPv4 & IPv6 addresses - if ( fAddressResolver != nil) { - [fAddressResolver release]; - fAddressResolver = nil; - } - err = DNSServiceQueryRecord( &serviceRef, (DNSServiceFlags) 0, interface, [host UTF8String], - ns_t_a, ns_c_in, QueryRecordReply, self); - if ( err == kDNSServiceErr_NoError) { - fAddressResolver = [[ServiceController alloc] initWithServiceRef:serviceRef]; - [fAddressResolver addToCurrentRunLoop]; - } + char interfaceName[IF_NAMESIZE]; + InterfaceIndexToName(interface, interfaceName); [hostField setStringValue:host]; - [portField setIntValue:port]; + [interfaceField setStringValue:[NSString stringWithUTF8String:interfaceName]]; + [portField setIntValue:ntohs(port)]; // kind of a hack: munge txtRecord so it's human-readable - if ( txtLen > 0) { - char *readableText = (char*) malloc( txtLen); - if ( readableText != nil) { - ByteCount index, subStrLen; - memcpy( readableText, txtRecord, txtLen); - for ( index=0; index < txtLen - 1; index += subStrLen + 1) { - subStrLen = readableText[ index]; - readableText[ index] = '\n'; + if (txtLen > 0) { + char *readableText = (char*) malloc(txtLen); + if (readableText != nil) { + ByteCount index, subStrLen; + memcpy(readableText, txtRecord, txtLen); + for (index=0; index < txtLen - 1; index += subStrLen + 1) { + subStrLen = readableText[index]; + readableText[index] = ' '; } [textField setStringValue:[NSString stringWithCString:&readableText[1] length:txtLen - 1]]; - free( readableText); + free(readableText); } } } -- (void)updateAddress:(uint16_t)rrtype addr:(const void *)buff addrLen:(uint16_t)addrLen - host:(const char*) host interfaceIndex:(uint32_t)interface more:(boolean_t)moreToCome -/* Update address field(s) with info obtained by fAddressResolver. */ + +- (void)updateAddress:(uint16_t)rrtype addr:(const void *)buff addrLen:(uint16_t)addrLen host:(const char*) host interfaceIndex:(uint32_t)interface more:(boolean_t)moreToCome { - if ( rrtype == ns_t_a) { // IPv4 - char addrBuff[256]; - inet_ntop( AF_INET, buff, addrBuff, sizeof addrBuff); - strcat( addrBuff, " "); + char addrBuff[256]; + + if (rrtype == kDNSServiceType_A) { + inet_ntop(AF_INET, buff, addrBuff, sizeof(addrBuff)); + if ([[ipAddressField stringValue] length] > 0) { + [ipAddressField setStringValue:[NSString stringWithFormat:@"%@, ", [ipAddressField stringValue]]]; + } [ipAddressField setStringValue:[NSString stringWithFormat:@"%@%s", [ipAddressField stringValue], addrBuff]]; - if ( !moreToCome) { - [fAddressResolver release]; - fAddressResolver = nil; - - // After we find v4 we look for v6 - DNSServiceRef serviceRef; - DNSServiceErrorType err; - err = DNSServiceQueryRecord( &serviceRef, (DNSServiceFlags) 0, interface, host, - ns_t_aaaa, ns_c_in, QueryRecordReply, self); - if ( err == kDNSServiceErr_NoError) { - fAddressResolver = [[ServiceController alloc] initWithServiceRef:serviceRef]; - [fAddressResolver addToCurrentRunLoop]; - } + if (!moreToCome) { + [_ipv4AddressResolver release]; + _ipv4AddressResolver = nil; } - } - else if ( rrtype == ns_t_aaaa) // IPv6 - { - char addrBuff[256]; - inet_ntop( AF_INET6, buff, addrBuff, sizeof addrBuff); - strcat( addrBuff, " "); + } else if (rrtype == kDNSServiceType_AAAA) { + inet_ntop(AF_INET6, buff, addrBuff, sizeof(addrBuff)); + if ([[ip6AddressField stringValue] length] > 0) { + [ip6AddressField setStringValue:[NSString stringWithFormat:@"%@, ", [ip6AddressField stringValue]]]; + } [ip6AddressField setStringValue:[NSString stringWithFormat:@"%@%s", [ip6AddressField stringValue], addrBuff]]; - if ( !moreToCome) { - [fAddressResolver release]; - fAddressResolver = nil; + if (!moreToCome) { + [_ipv6AddressResolver release]; + _ipv6AddressResolver = nil; } } } @@ -628,51 +546,48 @@ static void QueryRecordReply( DNSServiceRef DNSServiceRef, DNSServiceFlags flags - (void)connect:(id)sender { NSString *host = [hostField stringValue]; - int port = [portField intValue]; NSString *txtRecord = [textField stringValue]; - - if (!txtRecord) txtRecord = @""; - - if (!host || !port) return; - - if ([SrvType isEqualToString:@"_http._tcp"]) - { - NSString *pathDelim = @"path="; - NSRange where; + int port = [portField intValue]; + + int index = [nameField selectedRow]; + NSString *selected = (index >= 0) ? [_sortedServices objectAtIndex:index] : nil; + NSString *type = [[_servicesDict objectForKey:selected] type]; + + if ([type isEqual:@"_http._tcp."]) { + NSString *pathDelim = @"path="; + NSRange where; // If the TXT record specifies a path, extract it. where = [txtRecord rangeOfString:pathDelim options:NSCaseInsensitiveSearch]; - if ( where.length) - { - NSRange targetRange = { where.location + where.length, [txtRecord length] - where.location - where.length }; - NSRange endDelim = [txtRecord rangeOfString:@"\n" options:kNilOptions range:targetRange]; + if (where.length) { + NSRange targetRange = { where.location + where.length, [txtRecord length] - where.location - where.length }; + NSRange endDelim = [txtRecord rangeOfString:@"\n" options:kNilOptions range:targetRange]; - if ( endDelim.length) // if a delimiter was found, truncate the target range + if (endDelim.length) // if a delimiter was found, truncate the target range targetRange.length = endDelim.location - targetRange.location; NSString *path = [txtRecord substringWithRange:targetRange]; [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://%@:%d%@", host, port, path]]]; - } - else + } else { [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://%@:%d", host, port]]]; + } } - else if ([SrvType isEqualToString:@"_ftp._tcp"]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ftp://%@:%d/", host, port]]]; - else if ([SrvType isEqualToString:@"_tftp._tcp"]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"tftp://%@:%d/", host, port]]]; - else if ([SrvType isEqualToString:@"_ssh._tcp"]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ssh://%@:%d/", host, port]]]; - else if ([SrvType isEqualToString:@"_telnet._tcp"]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"telnet://%@:%d/", host, port]]]; - else if ([SrvType isEqualToString:@"_printer._tcp"]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"lpr://%@:%d/", host, port]]]; - else if ([SrvType isEqualToString:@"_ipp._tcp"]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ipp://%@:%d/", host, port]]]; - else if ([SrvType isEqualToString:@"_afpovertcp._tcp"]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"afp://%@:%d/", host, port]]]; - else if ([SrvType isEqualToString:@"_smb._tcp"]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"smb://%@:%d/", host, port]]]; + else if ([type isEqual:@"_ftp._tcp."]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ftp://%@:%d/", host, port]]]; + else if ([type isEqual:@"_ssh._tcp."]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"ssh://%@:%d/", host, port]]]; + else if ([type isEqual:@"_afpovertcp._tcp."]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"afp://%@:%d/", host, port]]]; + else if ([type isEqual:@"_smb._tcp."]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"smb://%@:%d/", host, port]]]; + else if ([type isEqual:@"_rfb._tcp."]) [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"vnc://%@:%d/", host, port]]]; return; } + - (IBAction)handleTableClick:(id)sender { //populate the text fields } + - (IBAction)removeSelected:(id)sender { // remove the selected row and force a refresh @@ -681,62 +596,63 @@ static void QueryRecordReply( DNSServiceRef DNSServiceRef, DNSServiceFlags flags if (selectedRow) { - [srvtypeKeys removeObjectAtIndex:selectedRow]; - [srvnameKeys removeObjectAtIndex:selectedRow]; + [_srvtypeKeys removeObjectAtIndex:selectedRow]; + [_srvnameKeys removeObjectAtIndex:selectedRow]; - [[NSUserDefaults standardUserDefaults] setObject:srvtypeKeys forKey:@"SrvTypeKeys"]; - [[NSUserDefaults standardUserDefaults] setObject:srvnameKeys forKey:@"SrvNameKeys"]; + [[NSUserDefaults standardUserDefaults] setObject:_srvtypeKeys forKey:@"SrvTypeKeys"]; + [[NSUserDefaults standardUserDefaults] setObject:_srvnameKeys forKey:@"SrvNameKeys"]; [typeField reloadData]; [serviceDisplayTable reloadData]; } } + - (IBAction)addNewService:(id)sender { // add new entries from the edit fields to the arrays for the defaults - NSString *newType = [serviceTypeField stringValue]; - NSString *newName = [serviceNameField stringValue]; + NSString *newType = [serviceTypeField stringValue]; + NSString *newName = [serviceNameField stringValue]; // 3282283: trim trailing '.' from service type field if ([newType length] && [newType hasSuffix:@"."]) newType = [newType substringToIndex:[newType length] - 1]; if ([newType length] && [newName length]) { - [srvtypeKeys addObject:newType]; - [srvnameKeys addObject:newName]; + [_srvtypeKeys addObject:newType]; + [_srvnameKeys addObject:newName]; - [[NSUserDefaults standardUserDefaults] setObject:srvtypeKeys forKey:@"SrvTypeKeys"]; - [[NSUserDefaults standardUserDefaults] setObject:srvnameKeys forKey:@"SrvNameKeys"]; + [[NSUserDefaults standardUserDefaults] setObject:_srvtypeKeys forKey:@"SrvTypeKeys"]; + [[NSUserDefaults standardUserDefaults] setObject:_srvnameKeys forKey:@"SrvNameKeys"]; [typeField reloadData]; [serviceDisplayTable reloadData]; } } + - (void)_cancelPendingResolve -// If there a a Resolve outstanding, cancel it. { - if ( fAddressResolver != nil) { - [fAddressResolver release]; - fAddressResolver = nil; - } + [_ipv4AddressResolver release]; + _ipv4AddressResolver = nil; - if ( fServiceResolver != nil) { - [fServiceResolver release]; - fServiceResolver = nil; - } + [_ipv6AddressResolver release]; + _ipv6AddressResolver = nil; + + [_serviceResolver release]; + _serviceResolver = nil; [self _clearResolvedInfo]; } + - (void)_clearResolvedInfo -// Erase the display of resolved info. { [hostField setStringValue:@""]; [ipAddressField setStringValue:@""]; [ip6AddressField setStringValue:@""]; [portField setStringValue:@""]; + [interfaceField setStringValue:@""]; [textField setStringValue:@""]; } @@ -745,58 +661,71 @@ static void QueryRecordReply( DNSServiceRef DNSServiceRef, DNSServiceFlags flags @implementation ServiceController : NSObject { - DNSServiceRef fServiceRef; - CFSocketRef fSocketRef; - CFRunLoopSourceRef fRunloopSrc; + DNSServiceRef fServiceRef; + CFSocketRef fSocketRef; + CFRunLoopSourceRef fRunloopSrc; } -- (id) initWithServiceRef:(DNSServiceRef) ref + +- (id)initWithServiceRef:(DNSServiceRef)ref { - [super init]; - fServiceRef = ref; + self = [super init]; + if (self) { + fServiceRef = ref; + fSocketRef = NULL; + fRunloopSrc = NULL; + } return self; } -- (boolean_t) addToCurrentRunLoop -/* Add the service to the current runloop. Returns non-zero on success. */ + +- (void)addToCurrentRunLoop { - CFSocketContext ctx = { 1, (void*) fServiceRef, nil, nil, nil }; + CFSocketContext context = { 0, (void*)fServiceRef, NULL, NULL, NULL }; - fSocketRef = CFSocketCreateWithNative( kCFAllocatorDefault, DNSServiceRefSockFD( fServiceRef), - kCFSocketReadCallBack, ProcessSockData, &ctx); - if ( fSocketRef != nil) - fRunloopSrc = CFSocketCreateRunLoopSource( kCFAllocatorDefault, fSocketRef, 1); - if ( fRunloopSrc != nil) - CFRunLoopAddSource( CFRunLoopGetCurrent(), fRunloopSrc, kCFRunLoopDefaultMode); - else + fSocketRef = CFSocketCreateWithNative(kCFAllocatorDefault, DNSServiceRefSockFD(fServiceRef), kCFSocketReadCallBack, ProcessSockData, &context); + if (fSocketRef) { + // Prevent CFSocketInvalidate from closing DNSServiceRef's socket. + CFOptionFlags sockFlags = CFSocketGetSocketFlags(fSocketRef); + CFSocketSetSocketFlags(fSocketRef, sockFlags & (~kCFSocketCloseOnInvalidate)); + fRunloopSrc = CFSocketCreateRunLoopSource(kCFAllocatorDefault, fSocketRef, 0); + } + if (fRunloopSrc) { + CFRunLoopAddSource(CFRunLoopGetCurrent(), fRunloopSrc, kCFRunLoopDefaultMode); + } else { printf("Could not listen to runloop socket\n"); - - return fRunloopSrc != nil; + } } -- (DNSServiceRef) serviceRef + +- (DNSServiceRef)serviceRef { return fServiceRef; } -- (void) dealloc -/* Remove service from runloop, deallocate service and associated resources */ + +- (void)dealloc { - if ( fSocketRef != nil) { - CFSocketInvalidate( fSocketRef); // Note: Also closes the underlying socket - CFRelease( fSocketRef); + if (fSocketRef) { + CFSocketInvalidate(fSocketRef); // Note: Also closes the underlying socket + CFRelease(fSocketRef); + + // 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. + usleep(1000); } - if ( fRunloopSrc != nil) { - CFRunLoopRemoveSource( CFRunLoopGetCurrent(), fRunloopSrc, kCFRunLoopDefaultMode); - CFRelease( fRunloopSrc); + if (fRunloopSrc) { + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), fRunloopSrc, kCFRunLoopDefaultMode); + CFRelease(fRunloopSrc); } - DNSServiceRefDeallocate( fServiceRef); + DNSServiceRefDeallocate(fServiceRef); [super dealloc]; } + @end // implementation ServiceController int main(int argc, const char *argv[]) diff --git a/Clients/DNSServiceBrowser.nib/classes.nib b/Clients/DNSServiceBrowser.nib/classes.nib index f5d5e98..482d0aa 100644 --- a/Clients/DNSServiceBrowser.nib/classes.nib +++ b/Clients/DNSServiceBrowser.nib/classes.nib @@ -16,6 +16,7 @@ OUTLETS = { domainField = id; hostField = id; + interfaceField = id; ip6AddressField = id; ipAddressField = id; nameColumn = id; diff --git a/Clients/DNSServiceBrowser.nib/info.nib b/Clients/DNSServiceBrowser.nib/info.nib index ffdf970..34ca9f0 100644 --- a/Clients/DNSServiceBrowser.nib/info.nib +++ b/Clients/DNSServiceBrowser.nib/info.nib @@ -10,13 +10,13 @@ 22 474 271 44 0 0 1152 746 IBFramework Version - 349.0 + 446.1 IBOpenObjects - 220 201 + 220 IBSystem Version - 7B85 + 8L2127 diff --git a/Clients/DNSServiceBrowser.nib/objects.nib b/Clients/DNSServiceBrowser.nib/objects.nib index 3cebce38cee6e21bf38eb5ad455335fa409a594c..3f28e7a824911c9e7015fd45290c016bd1a20480 100644 GIT binary patch literal 9008 zcmbta4U|;XeZO~S7xs(&00KfKolwL|K@P|fyQj?#JAlkFESBZeoKvC;GO*zJpV?5G?B6={VMKV%jtWhh?O*JG;#N zj_2ayhs?H{`v<%hR&c!`(R?>GYCgM3WlXeP@&CQ6!%vQ`a()n1<7!iNoFhNY_cunFZHeolKkw}EuM~*Dm z+&>T=Fs!@Ggc0tuGW)ZJ<#-bLoHtok`~XCr3s(AbVzSk>A9kngc_0#t5v53vsi`g5 zv^SH_g=eIBke?o3w`x(P1O8 zZzOK*bDV;GOnwDDm`pv}&AW}{KrWs$&;?84$I+r4CDl4^wTwZ-GSUend;Rs-JC7Y= ztSgY<%Z10QXP}dvdF;w#h-$NMtZW@UyCa+5I|8vbCCC{)S|Iz8N0|Lk#Vq^iB-6^> z(LWH7B3&HE7k##ZT(!+i8kaLQA9k*&EosuG3GB!X8&pX3jluS z<)k8uw8J6}spJydZUHtk>712GU3b?r@8QHn)J4lt@Gv#{!|%TA~s)QmK#Hb~{wkXrRBlwS4ro2@Bjb z53x(U5yY`{8c8nLU|z5kcOiuI&_cwj-3nPgJTbZ2Zu+AQ8xo(G1Ej9N@ARdQu{=vK zlOt4B!0vK`*t0JH$pT5kt>=qN2$N(tgFcSXBhSJz*7_tsr&a|aNp3* z(cKK%6&Mp|m^cFKcyIR&&rOfRLj}7H$_)Rx zL8IFvg6I;6fw;Si#DJ#xku>6UGodOHNhDy3Msl7bPP5;pJ;1iR{lVLeIKW8$zxu@| z;e64^j+chp-8v~HnbjmHbb`Z+??|H*Wo&$O|`^n%ZnbLYInn0vu-LJcKQEb>9o7fmpX$=;Ni%h)A#KU0Zy>%QRkp9a3wFg$aiNce~ z*n$Nx0JFjHZ>oZjcn<_>!Vuw`d|HYq1gugp>5q>fn7kYS<>E>9%6TlxXJ|=&&!;`# zUx07A(^X6E2QIH!6cGIv{u ztHg!Q2K(~4TqX^SdmGh?W3*9qw2M!(Fg%54uvKY{=m_jhp+MC8?Gk2KGhwD{OA`Bc zkeE=~R5EY3-IC3kI^Bzi7uXVhXgYGpc?{VNLhsuJ%3lJYhP4m^3-%Pd7W?J3rTwxN zsEx$5DR%2!8+x3QlNVP4w4UZ?XGQbYjFqdPx%7%OKQRj_8+UztR|UakGZ9?wDZZK% z7vE-3ot{-5s9L3um2?izM9#M($bI$$l3P9#xsr6fkZQG-ZFQ||{L)9foaA^}wiT7c z=KDbVh^Oi?-o6_^+g%N_g*C96i+n1L15g=FE59{s3>}@7zk#6}E8MfHQsw|dB?E|~ zAJCp_W+GRH`Af4Baa$%^3CXoH(JYJj(iKFE=*+P>!YaJ9ekO9hh|N3~1{lMag`!@E zq1e_63vRdqz12MT!Qj2IOw6IJyhU_1h`-{%pniKH6$uvYHEg+`?wxhdOfn6#h6d5d z#b2P$dn0YvL0AWM@k_QrG*fbbZv75GZO`?RvIO=~f8AAD44X+QRauZj;#!-hyrc8o zr`h=5zVxwP$LR?*FvwVx_H+J$!V|RDSLw$bqCf`yu2xBJugGA}y1h^dY2;kmdZT)4 z)qPE_{ieI6X6wDVe(UY#8F0YUz1icSQ`>LUrJ0n`UVXNX=q*}QB7nq}p6(WqxrKiH z9nfb}g)`;GlUW>Xe$aApAwKcDed zsFzfM*Dc~Jj1~@_Rs59zbmzn&)<}WA zL?(Tb|6VC>wNTvhPE|P9`AK~>?Y7xUT{`J!d0*9@39` zf)YeA@nwz!Meufe0Z;ts$lh4n8Sy$_tc>TBK<+YgDbx)A9|u_k0WxZ+6zrqzIL;Ov zT}?%~cC!`VZ&>`BZsBQhJI5}hU$+M@yD=6U9OSIC(-;4+v?UcZyZxdn5+EulrBGfi zIOu%X)ullc6t~CCv@UreVusv%soo~;V@Ih(H|I7poy_d7D}Fs%Sz8PS>FG4N;7xAc zZl=u<^HaK(%10dRtd}c)(iGZwuUr5P2+!}MS~OMV!nsU%s|C&KBn--PR6*)MnZ;8i zTT$r@bZp#aq(2BN4&13{2$WqTCmi8}aue7~EZy>8KQ+(Oe&$l2%kUhh#n~Hxwt= z$}?md`Tk%gvzU0Ui79@ z{Y@8`*E@3Bn_i}fwk@@7>l}FwZI!iYM?Qg;(7N^LgR4~C!^tpO(oYsSN0 z1-Sx^l{IjP2~uIS61zbCb8t%*`!#(#R&m3cEsc4K z#x&8GQq!cKmQPb7HpjYYw!KgrVn-gy3UW4G5z!_Rud`Fr8o_C}{TAbZUS(v6x7evM z>S)O!CDY+U+lQJ7lPzf+d#aibkD<9ai9~!z-;4S*2(AmV-aYSTGmEY0fL+xT;>jd3Xg{i#`eM}AJq%l>3@-xVHhQ1eO;Qq^yL`r!R#pi+Mo0{L z=>%8Rt4X&eac4fDZ-@iUb$h*v6xUkGO#U%2Fdv1-R#Yl@cGHG2HK^&Bd)RT}`!JxQVL#6k`?sUGngT&2NH!C5eb zDvIav{U8(H!b`DFsng;xzJAVN1tnf%*Qk4MQWsF}Q{tygyus8ONT620%Ia(45L0`^ zKQX1mi%e~SLDWXEjH{{NRbn0&t$b4aCZ9w`_|TEASYI@g$i%l=Sc>~I^xrxD7dV`h AGynhq literal 10423 zcmb_i4{#LMd4G!}kaR*q2+4-p)01t+n2ce-E;zy%A*mRdAXE-ql@Qs--AX!hx;@_? z1g1@Sr@eKVdXnZw?0^ipv6;pbFhMPC8kjgkQoCu4$7$V^4dXINolgJ6Zc1rsX=z1& z-+Q}zdv_9CXM8ueyZ7Greee7C-uu4qZM83TAg+d!se~FF9Kh^cxzJP3D*_;IFPA5~^sBC;>LZ8z~s7-x=t?5*7PgD)05|P-jA~5ae z30?Wj{Jy}(csv>j1yd0%W@HUri9BTj)7KZ+q3%y@im1`>VqLH63v_F-R6>hBqU&?} z0?$U&F+2fkyPAw^v9Ow86FL1vE<4HehE9Bj?2qKm=3-+a5j?-_a##}y^rLSHc357bD0z{I?<*QqbMxWC41`rDo`}DtAut!fD zp@c{zQ>{$14C`b}uO_ziW5?zP)Wp6>NcHyxN7W7kL?O^7NY^?s`H)`o`N!6TzAzWu zEWvO3Hv1e)vk;50FblG$SpwG>o>dT3hJ3mbVyBhU>~w>X&0@R`*dv=esaJ(MJBeKg z+O0)3DChKCy-JQhH*g@CQb!H2(h!nL6)=YW=IJVZ&d|{KhUKSDD+c|ad-e>#7T91U zc>#2a0mguOl#Z-HUI0Y|LNHO3ti#zyCrGag4neQ_Ym-$3Q4e;akvR2toXDM<%&?2H zSD{|AIr$28uRosq=A=MmkSxm>XYX@%%(>^jDNXY_tdiAz5Nv1&zmASb7KG+MM`9;p zYJx~H@`?u;xZP`$f(7`aU;$F5M`Q5gT5_b$&QJ(ysNR9uVQ_X~ z8O;q{Z?=Iqt3mi5+5EoW|5~P+Pc!z03;y+N_Dx}w>={N1o*IAZ6lvF0ZqtZBFX;9U zp?T0*v}(GOy^+;VO+NJXO5EYpe7FI*LNyd7hdgf&sVK&j!C3CRVN}g=2X3>i+7%4# z9ZqQJSXkQjY=O7B;Y7r4mAr3&Pr~ZW*=(lG4~k-b7-S(uDY4Kwbe^Z5UPJl|y$2&I z!cX7@(ofU`XMc5E_<`3toc&N~62_)$jtJrVI)={X&goS{Lmg~xS!nA7 zGv`loSBmD!h1`cFljCE1a?m~Zp`$TOjz7-oZ&m95-~AT3Eiq<{cMl&M81Gu5K2N^> zw%4sizson=`p>@ab=Y?u@4I@2U79i!mb*%B_ul*DGz&Y+oTiBLE8zSp{Vq7}@_`WD zR)v_noPFYT4?=O>;|f_7uJM-Z4Wu|Pw(AY$ctzg8$)Vv7|6}_D-Gx7pa{nRsPg2R> z@p^*T+`7`Klon&h$$}3tdr$E-aQ3pF-0Ee&v#SWN5R0Znq4i_K*K9AT1txh(^RI>@ zDZjm8B>gK^tT0^teyrCelaUDRDxIAD`C=twWIAsHi5dD)T(a+Gu{=xv#Mp9oBmZPa z`?0_EyZc*_e^z(Ok$t`W{*B>qLQN(+4AdZU;9OgZ_PtQ6+=*0@F?ZG1wXoW7az)0VC(t4{rlF;;6*iF-h~%=Rm555 z)3QZv*+5W>XCi!~0wHQPYe}!e`pRe)GyjcGi}}XFKw^Wf<8zw1@-m!9+~u-|*kv+P z%)rr4i-E}k19^(cv2SlxW9eQ5k9H0taCW%Rx;I3NiyUu#`3NP}Gf%0VRTGzyE*jzGLtI`X}n zBVlz$J%GA0VtDOUCLXcw69l%UM$|;IjQeu^)dohiG5^MB^e(U!^Z#pUY@jpQk@$ac zHvUC&1l>_`syd2m5w0x!qk6L%jhC@lFvgQG01}Etx%C44-WeG13lhY|hFQ7522Py# zz==Dj3_)@3uSa5GZR`##z#kkSXBzeh)Y`3)SY$Nvl9)Zp=xl=%_dON(i6pwPi}HIi zoIj=cHzlwymht9Tn?!1aNK%BPt=?91b-Q^pZ(h!u=kn&#c3N>TgC)=obu=Eu4Cczs z39Ka%5rucsC)7BHvu|_uWv=`^XaA9j??+~Q>{tr|f|c9VQEi{cZQox$NK$o_E`H5TrAvo<8vg1TI7U1HEc z7C=lMk^;#z6(#q#LD}$B%Pmt&gm+);9yLn{wp#-nC*+Bq!0)l$oaOvL##NvSR*`db_POW}I7N-_rW}rB=8HK1Q+lOlkC8`h$x>X2x80|G>3@+vDD}uqV z+=W3*V1J)F=FHv#g9m43@FhFjfkGYvbE1}qv9@sb2F)5=ixlEy5Uf)wq}b2gB#W~{ zg(!&91~2)>N59y{*caPM2~WH@y)h#QU-J+eKcl#{mzETAhSI{zB~Rgn`eiu=jFkyI4B*8jUAHW#D0ML4iHWelL)YjdI0$(@5( zq#Z=^fX=L9q)8nB5bHjSGksikf%*WetKRjTbKW9GNZl(ul z>%&IXlL(Hf3FWJ~>=ai9xl%1}gZ53Y?(H2KQdm=ytn4Te&2|`%#F9$&Q3Ui^ zs0M*VRzx1vRLv+03kp#aZOH-z+mMgq56(_V#GMFsh*RYy;|>w03%*^o!FSya{O)n2 zL$sNwyfJzJD3|E3PU*I4i z+ZWN&BKlLpmEg7QOj6KDT0=$2k7|-%N`ZmZN(i*bqBKRqE*Zi03$tO%&9dO|wShRw zfrzN@pk2-`L9ZgeM*c1I>T}Q>-FD12ptOd>Y81J%-@z4}uB!xbNim{-W77W{T3UvL zvn918Dg9c_kFJ_4+RfoXbJu{m2I0QDN^FW?l`q9FUL^!bVU_r?kiH7xf?z&&XXYjJ zylrtc=IBYQ1j9!d{_Sc=oguj?;;#r2Y>HHnv!A__IV4x&dNF_fBK0Yi)SD)?Ax)A4 z_GqE>Cj7C^x17#AjO&as>cnp6@&}5I0`@jghN`Y zS4$wn97L1%+|@8|lv2Wo2v|y5SEKc$jq8vz%!6pbQN29S0K{7SuU>_ZVNRA1SOv+` zXhWPM!40zye;0b{XMQ_VH+M?PZ|aNVTtF_o?%X- z&3lNyYBh0(!yUAH3Y^qL;f@=IQNv}>Wrq0-R~DI<(dpGChO0$WF)wKB$pZ0kIq(J| za=oM-oE*Uz4Ya&Hob+!S!x6S&ehes&nr@a3Lju&Gkq)n2JwOdh(N+cdi1i6PJLMqr z9R3s?)*I$6G!^p>w5w<=b`FHAcAGPhVV*C8QqbaY1N+?o=S>hbg*OvWWx+fJTS~8j zuwVkI;%k!+5M*m#pf9q=4k7I$3JnLvKNN4G$Syjz&=SoPXP?eOT`h4nK}SAR*9xZ6 z36!=vDEH*b^0QkApecx#Jz~RZZ%h=X+|CWuS(ik`k!o>n^IEb&eM(J?Mq;Qrx$O^9 z`~6x1hy8*MYRa*2FcB8D;{ISvjk=(#k3a=&BdDE<%BSZY7o4WqtgR%N8iH|~9v5io z7&W4lR)(hQi-dNzrI83BKNROTLOERd%-Ji#5;0h2i+Vtmw!}zJp2e9kb=9Si0E&q( zSr8p$4OVw7AUDLVjUFZO6NdO z;iw409;7~ux0wRsRKd}Q-7}New3gJ90_}=bLAA6-*OLZIdvZI`;|n1f!oFQ>4{~{Q zHpGKCDoEMuoJ$hDGiZPLSsazqnlvw^4G%{huMs+-)wMAaN6mx|Y>T7?Et=eQaV;TN zeMeYy&|+9er3Mei^0Ua|#qi*qCYr1J^Rj&gy5On?4_E3eyn}VGbrEykYH6{!vWv6ZxNYa`Kdm*K9l`U;m#m(9t%p(f zwXivHb`5RMaP}`&A7_7q=SP;}(#6?_77lj**7}IEKLsE><44wV957nLcs~gcsJ7Kx zHC$O}ZP4&{H&>Wd%as;uC1(a2c5rsnYX7Wt885fs@8>xCck2ocNv$J_b)747EFV|y zv7XtDz8=ngZmk=}(. diff --git a/Clients/ExplorerPlugin/ClassFactory.h b/Clients/ExplorerPlugin/ClassFactory.h index 76e4b5e..f5fe9d5 100644 --- a/Clients/ExplorerPlugin/ClassFactory.h +++ b/Clients/ExplorerPlugin/ClassFactory.h @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: ClassFactory.h,v $ +Revision 1.3 2006/08/14 23:24:00 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.2 2004/07/13 21:24:21 rpantos Fix for . diff --git a/Clients/ExplorerPlugin/ExplorerBar.cpp b/Clients/ExplorerPlugin/ExplorerBar.cpp index 1c71c9b..f09d983 100644 --- a/Clients/ExplorerPlugin/ExplorerBar.cpp +++ b/Clients/ExplorerPlugin/ExplorerBar.cpp @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: ExplorerBar.cpp,v $ +Revision 1.4 2006/08/14 23:24:00 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.3 2004/07/26 05:44:08 shersche remove extraneous debug statement diff --git a/Clients/ExplorerPlugin/ExplorerBar.h b/Clients/ExplorerPlugin/ExplorerBar.h index fe58176..5af86eb 100644 --- a/Clients/ExplorerPlugin/ExplorerBar.h +++ b/Clients/ExplorerPlugin/ExplorerBar.h @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: ExplorerBar.h,v $ +Revision 1.3 2006/08/14 23:24:00 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.2 2004/07/13 21:24:21 rpantos Fix for . diff --git a/Clients/ExplorerPlugin/ExplorerBarWindow.cpp b/Clients/ExplorerPlugin/ExplorerBarWindow.cpp index d4ea5c1..88f4858 100644 --- a/Clients/ExplorerPlugin/ExplorerBarWindow.cpp +++ b/Clients/ExplorerPlugin/ExplorerBarWindow.cpp @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: ExplorerBarWindow.cpp,v $ +Revision 1.22 2006/08/14 23:24:00 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.21 2005/04/06 01:13:07 shersche Use the product icon instead of globe icon for 'About' link. diff --git a/Clients/ExplorerPlugin/ExplorerBarWindow.h b/Clients/ExplorerPlugin/ExplorerBarWindow.h index deade95..f035872 100644 --- a/Clients/ExplorerPlugin/ExplorerBarWindow.h +++ b/Clients/ExplorerPlugin/ExplorerBarWindow.h @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: ExplorerBarWindow.h,v $ +Revision 1.8 2006/08/14 23:24:00 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.7 2005/02/25 19:57:30 shersche Remove FTP browsing from plugin diff --git a/Clients/ExplorerPlugin/ExplorerPlugin.cpp b/Clients/ExplorerPlugin/ExplorerPlugin.cpp index 34b981e..c2c661b 100644 --- a/Clients/ExplorerPlugin/ExplorerPlugin.cpp +++ b/Clients/ExplorerPlugin/ExplorerPlugin.cpp @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: ExplorerPlugin.cpp,v $ +Revision 1.9 2006/08/14 23:24:00 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.8 2005/06/30 18:01:54 shersche Cause IE to rebuild cache so we don't have to reboot following an install. diff --git a/Clients/ExplorerPlugin/ExplorerPlugin.def b/Clients/ExplorerPlugin/ExplorerPlugin.def index e825180..acef773 100644 --- a/Clients/ExplorerPlugin/ExplorerPlugin.def +++ b/Clients/ExplorerPlugin/ExplorerPlugin.def @@ -1,28 +1,25 @@ ; +; ; Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved. ; -; @APPLE_LICENSE_HEADER_START@ +; 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 ; -; This file contains Original Code and/or Modifications of Original Code -; as defined in and that are subject to the Apple Public Source License -; Version 2.0 (the 'License'). You may not use this file except in -; compliance with the License. Please obtain a copy of the License at -; http://www.opensource.apple.com/apsl/ and read it before using this -; file. +; http://www.apache.org/licenses/LICENSE-2.0 ; -; The Original Code and all software distributed under the License are -; distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER -; EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, -; INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, -; FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. -; Please see the License for the specific language governing rights and +; 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. -; -; @APPLE_LICENSE_HEADER_END@ ; ; Change History (most recent first): ; ; $Log: ExplorerPlugin.def,v $ +; Revision 1.3 2006/08/14 23:24:00 cheshire +; Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 +; ; Revision 1.2 2004/07/13 21:24:21 rpantos ; Fix for . ; diff --git a/Clients/ExplorerPlugin/ExplorerPlugin.h b/Clients/ExplorerPlugin/ExplorerPlugin.h index 40a709a..d14edd3 100644 --- a/Clients/ExplorerPlugin/ExplorerPlugin.h +++ b/Clients/ExplorerPlugin/ExplorerPlugin.h @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: ExplorerPlugin.h,v $ +Revision 1.4 2006/08/14 23:24:00 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.3 2005/01/25 18:35:38 shersche Declare APIs for obtaining handles to resource modules diff --git a/Clients/ExplorerPlugin/ExplorerPlugin.rc b/Clients/ExplorerPlugin/ExplorerPlugin.rc index 1b97397..03320d5 100644 --- a/Clients/ExplorerPlugin/ExplorerPlugin.rc +++ b/Clients/ExplorerPlugin/ExplorerPlugin.rc @@ -80,7 +80,7 @@ BEGIN BEGIN BLOCK "040904b0" BEGIN - VALUE "CompanyName", "Apple Computer, Inc." + VALUE "CompanyName", MASTER_COMPANY_NAME VALUE "FileDescription", "Bonjour Explorer Bar" VALUE "FileVersion", MASTER_PROD_VERS_STR VALUE "InternalName", "ExplorerPlugin.dll" diff --git a/Clients/ExplorerPlugin/ExplorerPlugin.vcproj b/Clients/ExplorerPlugin/ExplorerPlugin.vcproj index 4d875a8..6a5c4fc 100644 --- a/Clients/ExplorerPlugin/ExplorerPlugin.vcproj +++ b/Clients/ExplorerPlugin/ExplorerPlugin.vcproj @@ -176,13 +176,13 @@ Name="Support" Filter=""> + RelativePath="..\..\mDNSShared\CommonServices.h"> + RelativePath="..\..\mDNSShared\DebugServices.c"> + RelativePath="..\..\mDNSShared\DebugServices.h"> diff --git a/Clients/ExplorerPlugin/ExplorerPluginLocRes.rc b/Clients/ExplorerPlugin/ExplorerPluginLocRes.rc index 34cf048..4d74187 100755 --- a/Clients/ExplorerPlugin/ExplorerPluginLocRes.rc +++ b/Clients/ExplorerPlugin/ExplorerPluginLocRes.rc @@ -80,7 +80,7 @@ BEGIN BEGIN BLOCK "040904b0" BEGIN - VALUE "CompanyName", "Apple Computer, Inc." + VALUE "CompanyName", MASTER_COMPANY_NAME VALUE "FileDescription", "Bonjour Resource Module" VALUE "FileVersion", MASTER_PROD_VERS_STR VALUE "InternalName", "ExplorerPluginLocalized.dll" diff --git a/Clients/ExplorerPlugin/ExplorerPluginRes.rc b/Clients/ExplorerPlugin/ExplorerPluginRes.rc index 5ed5f4e..bf0d64c 100755 --- a/Clients/ExplorerPlugin/ExplorerPluginRes.rc +++ b/Clients/ExplorerPlugin/ExplorerPluginRes.rc @@ -80,7 +80,7 @@ BEGIN BEGIN BLOCK "040904b0" BEGIN - VALUE "CompanyName", "Apple Computer, Inc." + VALUE "CompanyName", MASTER_COMPANY_NAME VALUE "FileDescription", "Bonjour Resource Module" VALUE "FileVersion", MASTER_PROD_VERS_STR VALUE "InternalName", "ExplorerPluginResources.dll" diff --git a/Clients/ExplorerPlugin/LoginDialog.cpp b/Clients/ExplorerPlugin/LoginDialog.cpp index ccee81c..c2afe22 100644 --- a/Clients/ExplorerPlugin/LoginDialog.cpp +++ b/Clients/ExplorerPlugin/LoginDialog.cpp @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: LoginDialog.cpp,v $ +Revision 1.3 2006/08/14 23:24:00 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.2 2004/07/13 21:24:21 rpantos Fix for . diff --git a/Clients/ExplorerPlugin/LoginDialog.h b/Clients/ExplorerPlugin/LoginDialog.h index a89c3a6..0f7bee6 100644 --- a/Clients/ExplorerPlugin/LoginDialog.h +++ b/Clients/ExplorerPlugin/LoginDialog.h @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: LoginDialog.h,v $ +Revision 1.3 2006/08/14 23:24:00 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.2 2004/07/13 21:24:21 rpantos Fix for . diff --git a/Clients/ExplorerPlugin/Resource.h b/Clients/ExplorerPlugin/Resource.h index e6a7b32..9b1f0ab 100644 --- a/Clients/ExplorerPlugin/Resource.h +++ b/Clients/ExplorerPlugin/Resource.h @@ -1,24 +1,18 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): diff --git a/Clients/ExplorerPlugin/StdAfx.cpp b/Clients/ExplorerPlugin/StdAfx.cpp index b97d864..1d64495 100644 --- a/Clients/ExplorerPlugin/StdAfx.cpp +++ b/Clients/ExplorerPlugin/StdAfx.cpp @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: StdAfx.cpp,v $ +Revision 1.3 2006/08/14 23:24:00 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.2 2004/07/13 21:24:21 rpantos Fix for . diff --git a/Clients/ExplorerPlugin/StdAfx.h b/Clients/ExplorerPlugin/StdAfx.h index 407ff3c..7976129 100644 --- a/Clients/ExplorerPlugin/StdAfx.h +++ b/Clients/ExplorerPlugin/StdAfx.h @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: StdAfx.h,v $ +Revision 1.4 2006/08/14 23:24:00 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.3 2005/10/19 19:50:34 herscher Workaround a bug in the latest Microsoft Platform SDK when compiling C++ files that include (directly or indirectly) diff --git a/Clients/ExplorerPlugin/res/button-xp.ico b/Clients/ExplorerPlugin/res/button-xp.ico index 5b22ef70bd95eb6fcd4c5e4cc3f71ad52a044ec6..5d6360ee1837b462b8a612aac6786c3ff08c5bd5 100755 GIT binary patch literal 5342 zcmcgw33OD|8GbQogQAc^3s|+d)r!`NJ!)&qQPfJ|SfzTbMktLSltn}kgpkQ3vt(v6 z>znn>`rhnoGLuXuvye$9nM@)O61IdSWFsL6Ap{tMtV42pU+5r-p~ZSm?>Yb6cmMnU z-@WhM|NhG$ND7jQ%$bA0{$Zr>ZUlJ|L6D#R^u{>!V+4snUPi`^@wzkw*$$tdgfdVC znGcE7`=PC^t^K~v&Q5-7Ypb`fukXE6Cr_pPP|WiKovF=-4=g@>c>im5o8?m$hYt#Q zLVzhXiK?o|F1XIq|LYpxob5`nR`p63D$asMs&k{buUVu~D;*rZ5EK-00hPuC2BW#Z zx3~8<|H~T2lCK_p;*+Zv=Hvh{I~#!KcaC;D-GNN49tXI|48#fyD?v%8u;3$MflIu2`-BT%icygn{~f@s(<< zw5X`4L#8^M`@ui^pPx)$B$nq3#ZsVD(7Eo)X=G)0t)x@Ss`h{4Rem zkX}<8n^GC6P9=GJ_BNy#%vN!@s+zpUchuV2+R~bvoBvo{6Wt`1D$c02dcD!&$b#RC zVRbl7j$(I}&FQN4lzOB7V6eevcb=`UulKdIv{2w(AYIFCTPReKWiVUz2~g=*Qn{K^ zRvw7(1nBM}k9UTKFwauyjK7d5RL}8I>0eoef*e$i`6Zb0Yq1;ys8kMcy)hB3t>sKy z;PmN%v{G-Gg3jUq28(+}B*9)FWlj$czN*sVXUYSixf6BBvBmCME|e(d7xGcMQm4C4 z-h~1NEm{@w|M6D&Krob-&tL;Kmk(?%cjm2g7Q0ic(HXLD<&n?+;I2REE%uxwU#7rT zyNVnPQAx9VwWW8+9O<$S4|Qc6JJ$1<5S5-U6o>${GG6~doR@4zjMwP06fG7;K6MPfEEv+zHdrC^pN-YuI6^V`6Xi|pksnQEeUR-rOzJfmj zp2|!Nt!G@!c}xO=MJWP47o(p<7Qoj@iNYqZ5RTDG@+&#t}gj5DXY zQoFi4pWVNIKg;fLcA_#lu-IH%CSsH0y1F_sB{vT!F!89-L|oG0%D&3#s$Y+Mbo7P|egvAPk5?QR=Uom40{Fa}^ zYtF5De(iPezGwtI_Teblz&xHM$D{;|xf^Z~8+(*u>Manz-|BJ!S7|A5xZOajH^d7H z`6?!h_p^!eJ!4FWT4GSk~3q z^$yIxZu*lu{Z@(Lu9SmqNB?Yzb`-e%;m`Seeh;fYX?OJjgCU%7MW%+S<3#eDCJ_`-WL0eA%FRQD|h zi5z~#N|RaFV{$mg?icCbzx;Cd(mTadn~%J@BKuPP-)V_!OFp?=rnR@sw!7>PQK-zn z@kNruWNxFy_53@*Q)#d?oKX60wvwi8xgE>iTzz%idr4%fXW?D!gZV(2LaDv$zhOcj znj%)HO87#?Fr8ie@?`RQlU2bNN=y>D^1tGd`dWi|Lm^+(snM$MpA64l@7Uu&ho#7AA-@nTfN}wyUdiwor#^4)`K;q$(24x*>Vv*W(LK zvpS16x3(Uc>-PugI-^Awtc>2QF--o;KYC+hLh<|00eEID#9Nh+6v9iX)an4l1qK6- zb+#V5_g2hcIP!wWQyNw4h^De&WQcGr6rThWJRo84C( zt=&--sothHnxZr&3y5HTDI#MaVNeGv!ehSCTVk8OVsq@xS?`0v=koxVwHyp@VjpA@ zg!oH|T(vs6C!tinO{P*`gYgciA(`xUK-O1<0@QAIxXCj5X0wM*rEO$hps&rlaC{}@ zl1!=%{fbVbey4_nIr0l!0ZK)s3Im&b$Y=g7kIowBGm@ZG^nB*0l=I=u1s67`4ZaL& zF6Af5xn$23h<`$3aF!IXxm$85w0~^RrjCo1AU%#;NrjX$MoVBHk8h5H_?7t3m8m5?ec|@TwKeSXSyR>lF#R(CcA#|}vsrsy40BsHkDu7Luko+rgeMu~2)dWOy*+XI z<&7gfba~rLCad8k=xdZ@EvUf>ViJ{`ER9Z{ZZIe#7#1jfXU)YiKSNID<`tyC8dL}C zpqNCag#Xw~-XxeN1>Sj&K*)7Ylz_F)tI%fY6ZyA};WtXPJB!%RM_LUg&97|^^J1Sr z@ZqkC@VmZ1fa(u~vYYlF7|UsI)!V&$&t1-<;+3u6;EvT`2G3%_Bqd0Flf-)wj{Rk*?OdU6d||IAft z^>6b^Hkv_z;O*o;hEqp9<1w}MUuUH_KeBA~b4O3N!A_4&$e29wq6 z3w`UqTHE`7DO9#csDgnWp1S`{7|YfWxF#;d%Uo-WJ@uB@SKB+=4lOA4dLx)xcgk#a zZ4F0i9;%Ji-yH}9<{1n`1VwqHdO~|87%YF?;jqots7$M0+B8s^4*mZVTd(&i@bYr0 zjCV?Jw!aGNiPw!*TNOOVklt+RN8x`m5~T`2bJCUvcioJ+%X7c};xF5;4ZXGX8z%>~ zW{M^J1<7~eq2jj%VreOiwFl%XbtRL-%T=n0aXvBd|-0dYH#68~4&Y$t4kpzWd$=F=eRBa1t5~Beu1OdD>7zQbDqk*zVe=x528jMN!A)EvAJ>QMSgS0nq5oLJkWJ>tU|=H%ffUu0_zhg{Rr z*HT!phQ90`#1tLj1u)@*ujCqkbT{|nB^NJZCOPMQD7feE)l29pi=~gQ_qvyTsJGbLeznIRU2!OM9|F8(%i)jg9OPsv z-XC&LQSa)9;Dn#}liPG(#SP5q0}pT;^)}f%=waRu%C}gmLu7^V7>9(~ca z>N(1f43B=m0c>JOy%3|ReeDPMS-ZjMRKq%#?g8AZEaZF`qcBS z)$fUNqr5G5v9q4m7UY@UN!(Pg`A&^}D4*ROrI<LH+HX+kMB@?tJ$>{`zC0K7Y;U zt-R6r(p*26Tp*fXyffGOH+6M9GnXfi%-0iRW^dQ#$ Java needs to implement DNSServiceRegisterRecord equivalent + Revision 1.4 2004/08/04 01:07:43 rpantos Update unit test for . @@ -107,6 +107,7 @@ class DNSSDUnitTest fRegTest = new RegTest(); new BrowseTest(); new DomainTest(); + new RegistrarTest(); this.waitForEnd(); } @@ -325,3 +326,30 @@ class QueryTest extends TermReporter implements QueryListener } } +class RegistrarTest extends TermReporter implements RegisterRecordListener +{ + public RegistrarTest() + { + try { + byte[] kResponsiblePerson = { 'g','r','o','v','e','r' }; + fRegistrar = DNSSD.createRecordRegistrar( this); + fRegistrar.registerRecord( DNSSD.UNIQUE, 0, + "test.registrartest.local", 17 /*ns_t_rp*/, 1, kResponsiblePerson, 3600); + } catch( Exception e) { e.printStackTrace(); } + } + + public void recordRegistered( DNSRecord record, int flags) + { + String s = "RegistrarTest result flags:" + String.valueOf( flags); + System.out.println( s); + + try { + byte[] kResponsiblePerson = { 'e','l','m','o' }; + record.update( 0, kResponsiblePerson, 3600); + record.remove(); + } catch( Exception e) { e.printStackTrace(); } + } + + protected DNSSDRecordRegistrar fRegistrar; +} + diff --git a/Clients/Java/SimpleChat.java b/Clients/Java/SimpleChat.java index 745b9a0..a1fee5c 100644 --- a/Clients/Java/SimpleChat.java +++ b/Clients/Java/SimpleChat.java @@ -1,4 +1,5 @@ -/* +/* -*- Mode: Java; tab-width: 4 -*- + * * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. * * Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. diff --git a/Clients/Java/SwingBrowseListener.java b/Clients/Java/SwingBrowseListener.java index 78bfe4f..db971b2 100644 --- a/Clients/Java/SwingBrowseListener.java +++ b/Clients/Java/SwingBrowseListener.java @@ -1,4 +1,5 @@ -/* +/* -*- Mode: Java; tab-width: 4 -*- + * * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. * * Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. diff --git a/Clients/Java/SwingDomainListener.java b/Clients/Java/SwingDomainListener.java index c6c380b..b67313b 100644 --- a/Clients/Java/SwingDomainListener.java +++ b/Clients/Java/SwingDomainListener.java @@ -1,4 +1,5 @@ -/* +/* -*- Mode: Java; tab-width: 4 -*- + * * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. * * Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. diff --git a/Clients/Java/SwingQueryListener.java b/Clients/Java/SwingQueryListener.java index 5f2de1d..fcac75b 100644 --- a/Clients/Java/SwingQueryListener.java +++ b/Clients/Java/SwingQueryListener.java @@ -1,4 +1,5 @@ -/* +/* -*- Mode: Java; tab-width: 4 -*- + * * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. * * Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. diff --git a/Clients/Java/SwingResolveListener.java b/Clients/Java/SwingResolveListener.java index f2be4b0..19c1799 100644 --- a/Clients/Java/SwingResolveListener.java +++ b/Clients/Java/SwingResolveListener.java @@ -1,4 +1,5 @@ -/* +/* -*- Mode: Java; tab-width: 4 -*- + * * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. * * Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. diff --git a/Clients/Java/nmakefile b/Clients/Java/nmakefile index 4c01633..9b08ccb 100644 --- a/Clients/Java/nmakefile +++ b/Clients/Java/nmakefile @@ -1,24 +1,18 @@ +# -*- tab-width: 4 -*- +# # Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. # -# @APPLE_LICENSE_HEADER_START@ +# 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 # -# This file contains Original Code and/or Modifications of Original Code -# as defined in and that are subject to the Apple Public Source License -# Version 2.0 (the 'License'). You may not use this file except in -# compliance with the License. Please obtain a copy of the License at -# http://www.opensource.apple.com/apsl/ and read it before using this -# file. +# http://www.apache.org/licenses/LICENSE-2.0 # -# The Original Code and all software distributed under the License are -# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER -# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, -# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. -# Please see the License for the specific language governing rights and +# 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. -# -# @APPLE_LICENSE_HEADER_END@ -# # # This Makefile builds .jar files for the DNS-SD Java sample apps. # You must have the Java support installed. diff --git a/Clients/Makefile b/Clients/Makefile index 709bd2b..3fbb8df 100755 --- a/Clients/Makefile +++ b/Clients/Makefile @@ -1,25 +1,36 @@ +# -*- tab-width: 4 -*- +# # Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. # -# @APPLE_LICENSE_HEADER_START@ +# 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 # -# This file contains Original Code and/or Modifications of Original Code -# as defined in and that are subject to the Apple Public Source License -# Version 2.0 (the 'License'). You may not use this file except in -# compliance with the License. Please obtain a copy of the License at -# http://www.opensource.apple.com/apsl/ and read it before using this -# file. +# http://www.apache.org/licenses/LICENSE-2.0 # -# The Original Code and all software distributed under the License are -# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER -# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, -# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. -# Please see the License for the specific language governing rights and +# 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. -# -# @APPLE_LICENSE_HEADER_END@ # # $Log: Makefile,v $ +# Revision 1.11 2007/05/29 19:57:33 cheshire +# Use "-Wall" for stricter compiler warnings +# +# Revision 1.10 2006/09/21 00:56:37 cheshire +# Need 64-bit version of dns-sd command-line tool +# Add in missing "build/" in targets line for builds other than OS X +# +# Revision 1.9 2006/09/18 18:55:39 cheshire +# Need 64-bit version of dns-sd command-line tool +# +# Revision 1.8 2006/08/14 23:23:55 cheshire +# Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 +# +# Revision 1.7 2006/01/06 01:06:17 cheshire +# Compile library and client programs in one pass +# # Revision 1.6 2004/09/24 21:15:26 cheshire # Library "libmdns" misnamed; should be "libdns_sd" # @@ -48,15 +59,17 @@ ############################################################################# - -# If library /usr/lib/libdns_sd.* exists, then link it -ifneq "$(wildcard /usr/lib/libdns_sd.*)" "" -LIBS = -ldns_sd -else +# On OS X the dns_sd library functions are included in libSystem, which is implicitly linked with every executable +# If /usr/lib/libSystem.dylib exists, then we're on OS X, so we don't need also to link the "dns_sd" shared library +ifneq "$(wildcard /usr/lib/libSystem.dylib)" "" +TARGETS = build/dns-sd build/dns-sd64 LIBS = +else +TARGETS = build/dns-sd +LIBS = -L../mDNSPosix/build/prod/ -ldns_sd endif -targets: build/dns-sd +all: $(TARGETS) clean: rm -rf build @@ -65,4 +78,13 @@ build: mkdir build build/dns-sd: build dns-sd.c - cc $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -o $@ + cc $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -Wall -o $@ + +build/dns-sd64: build dns-sd.c + cc $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -Wall -o $@ -m64 + +# Note, we can make a 'fat' version of dns-sd using 'lipo', as shown below, but we +# don't, because we don't want or need a 'fat' version of dns-sd, because it will +# never need to access more than 4GB of data. We build the 64-bit version purely so +# we have a test tool for making sure that the APIs work properly from 64-bit clients. +# lipo -create dns-sd dns-sd64 -output dns-sd-fat diff --git a/Clients/PrinterSetupWizard/FirstPage.cpp b/Clients/PrinterSetupWizard/FirstPage.cpp index b5131da..8d4b881 100644 --- a/Clients/PrinterSetupWizard/FirstPage.cpp +++ b/Clients/PrinterSetupWizard/FirstPage.cpp @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: FirstPage.cpp,v $ +Revision 1.6 2006/08/14 23:24:09 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.5 2005/07/07 17:53:20 shersche Fix problems associated with the CUPS printer workaround fix. diff --git a/Clients/PrinterSetupWizard/FirstPage.h b/Clients/PrinterSetupWizard/FirstPage.h index a798eb0..c7c96f4 100644 --- a/Clients/PrinterSetupWizard/FirstPage.h +++ b/Clients/PrinterSetupWizard/FirstPage.h @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: FirstPage.h,v $ +Revision 1.3 2006/08/14 23:24:09 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.2 2005/07/07 17:53:20 shersche Fix problems associated with the CUPS printer workaround fix. diff --git a/Clients/PrinterSetupWizard/FourthPage.cpp b/Clients/PrinterSetupWizard/FourthPage.cpp index 876e28b..66e5145 100644 --- a/Clients/PrinterSetupWizard/FourthPage.cpp +++ b/Clients/PrinterSetupWizard/FourthPage.cpp @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: FourthPage.cpp,v $ +Revision 1.8 2006/08/14 23:24:09 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.7 2005/07/07 17:53:20 shersche Fix problems associated with the CUPS printer workaround fix. diff --git a/Clients/PrinterSetupWizard/FourthPage.h b/Clients/PrinterSetupWizard/FourthPage.h index fca8cd1..fc72059 100644 --- a/Clients/PrinterSetupWizard/FourthPage.h +++ b/Clients/PrinterSetupWizard/FourthPage.h @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: FourthPage.h,v $ +Revision 1.4 2006/08/14 23:24:09 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.3 2005/07/07 17:53:20 shersche Fix problems associated with the CUPS printer workaround fix. diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizard.rc b/Clients/PrinterSetupWizard/PrinterSetupWizard.rc index 71c00d0..982b0f2 100644 --- a/Clients/PrinterSetupWizard/PrinterSetupWizard.rc +++ b/Clients/PrinterSetupWizard/PrinterSetupWizard.rc @@ -102,7 +102,7 @@ BEGIN BEGIN BLOCK "040904e4" BEGIN - VALUE "CompanyName", "Apple Computer, Inc." + VALUE "CompanyName", MASTER_COMPANY_NAME VALUE "FileDescription", "Bonjour Printer Wizard" VALUE "FileVersion", MASTER_PROD_VERS_STR VALUE "InternalName", "PrinterWizard.exe" diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj b/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj index c407853..a4b4135 100644 --- a/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj +++ b/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj @@ -243,13 +243,13 @@ Name="Support" Filter=""> + RelativePath="..\..\mDNSShared\CommonServices.h"> + RelativePath="..\..\mDNSShared\DebugServices.c"> + RelativePath="..\..\mDNSShared\DebugServices.h"> diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp b/Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp index 7b65443..e9e255f 100644 --- a/Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp +++ b/Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: PrinterSetupWizardApp.cpp,v $ +Revision 1.9 2006/08/14 23:24:09 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.8 2005/04/13 17:43:39 shersche Change "PrinterWizard.dll" to "PrinterWizardResources.dll" diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardApp.h b/Clients/PrinterSetupWizard/PrinterSetupWizardApp.h index 871de5d..08a1829 100644 --- a/Clients/PrinterSetupWizard/PrinterSetupWizardApp.h +++ b/Clients/PrinterSetupWizard/PrinterSetupWizardApp.h @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: PrinterSetupWizardApp.h,v $ +Revision 1.3 2006/08/14 23:24:09 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.2 2005/01/25 08:52:55 shersche Add APIs to return localizable and non-localizable resource DLL handles Bug #: 3911084 diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.rc b/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.rc index 56319c3..ea189ec 100755 --- a/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.rc +++ b/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.rc @@ -211,7 +211,7 @@ BEGIN BEGIN BLOCK "040904e4" BEGIN - VALUE "CompanyName", "Apple Computer, Inc." + VALUE "CompanyName", MASTER_COMPANY_NAME VALUE "FileDescription", "Bonjour Resource Module" VALUE "FileVersion", MASTER_PROD_VERS_STR VALUE "InternalName", "PrinterWizardLocalized.dll" diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardRes.rc b/Clients/PrinterSetupWizard/PrinterSetupWizardRes.rc index a75e40f..9e9e30f 100755 --- a/Clients/PrinterSetupWizard/PrinterSetupWizardRes.rc +++ b/Clients/PrinterSetupWizard/PrinterSetupWizardRes.rc @@ -120,7 +120,7 @@ BEGIN BEGIN BLOCK "040904e4" BEGIN - VALUE "CompanyName", "Apple Computer, Inc." + VALUE "CompanyName", MASTER_COMPANY_NAME VALUE "FileDescription", "Bonjour Resource Module" VALUE "FileVersion", MASTER_PROD_VERS_STR VALUE "InternalName", "PrinterWizardLocalized.dll" diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp index 6c0c9f3..e912716 100644 --- a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp +++ b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: PrinterSetupWizardSheet.cpp,v $ +Revision 1.35 2006/08/14 23:24:09 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.34 2005/10/05 17:32:51 herscher Use a case insensitive compare operation to check whether a printer with the same name has already been installed. diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h index 63dc0c0..b9cc5ff 100644 --- a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h +++ b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: PrinterSetupWizardSheet.h,v $ +Revision 1.12 2006/08/14 23:24:09 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.11 2005/10/05 17:32:51 herscher Use a case insensitive compare operation to check whether a printer with the same name has already been installed. diff --git a/Clients/PrinterSetupWizard/SecondPage.cpp b/Clients/PrinterSetupWizard/SecondPage.cpp index c64030d..83e6685 100644 --- a/Clients/PrinterSetupWizard/SecondPage.cpp +++ b/Clients/PrinterSetupWizard/SecondPage.cpp @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: SecondPage.cpp,v $ +Revision 1.19 2006/08/14 23:24:09 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.18 2005/07/20 17:44:54 shersche UI fixes for CUPS workaround diff --git a/Clients/PrinterSetupWizard/SecondPage.h b/Clients/PrinterSetupWizard/SecondPage.h index 5cf1852..b857334 100644 --- a/Clients/PrinterSetupWizard/SecondPage.h +++ b/Clients/PrinterSetupWizard/SecondPage.h @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: SecondPage.h,v $ +Revision 1.9 2006/08/14 23:24:09 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.8 2005/03/20 20:08:37 shersche Second screen should not select a printer by default @@ -123,14 +120,22 @@ private: SetPrinterInformationState( BOOL state ); std::string m_selectedName; - -private: - - CStatic m_printerInformation; - CStatic m_descriptionLabel; - CStatic m_descriptionField; - CStatic m_locationLabel; - CStatic m_locationField; + + +private: + + + + CStatic m_printerInformation; + + CStatic m_descriptionLabel; + + CStatic m_descriptionField; + + CStatic m_locationLabel; + + CStatic m_locationField; + bool m_gotChoice; }; diff --git a/Clients/PrinterSetupWizard/ThirdPage.cpp b/Clients/PrinterSetupWizard/ThirdPage.cpp index bf16fe2..4c156fd 100644 --- a/Clients/PrinterSetupWizard/ThirdPage.cpp +++ b/Clients/PrinterSetupWizard/ThirdPage.cpp @@ -1,28 +1,53 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: ThirdPage.cpp,v $ +Revision 1.37 2007/06/08 06:30:26 herscher + Fix uninitialized pointers when detecting generic PCL and PS drivers + +Revision 1.36 2007/06/06 20:39:10 cheshire + Printer Setup Wizard started crashing in Bonjour104A8, after update to Visual Studio 2005 + +Revision 1.35 2007/06/06 20:08:01 cheshire + mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle +AutoScroll model list as well as manufacturer list + +Revision 1.34 2007/06/06 19:53:48 cheshire + Move build train to Visual Studio 2005 + +Revision 1.33 2007/04/20 22:58:10 herscher + mDNS: Printer Wizard doesn't offer generic HP printers or generic PS support on Vista RC2 + +Revision 1.32 2007/04/13 23:42:20 herscher + mDNS: Printers added using Bonjour should be set as the default printer. + +Revision 1.31 2007/04/13 21:38:46 herscher + mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle + +Revision 1.30 2007/04/13 20:23:40 herscher +Fixed mistake in previous checkin that reverted license text for this file + +Revision 1.29 2007/04/13 18:10:24 herscher + mDNS: Don't allow user to choose non-working driver + +Revision 1.28 2006/08/14 23:24:09 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.27 2005/10/05 21:41:45 herscher Use "application/octet-stream" to determine if CUPS shared queue supports raw @@ -115,8 +140,6 @@ Submitted by: herscher Revision 1.1 2004/06/18 04:36:58 rpantos First checked in - - */ #include "stdafx.h" @@ -131,13 +154,17 @@ First checked in // local variable is initialize but not referenced #pragma warning(disable:4189) - // // This is the printer description file that is shipped -// with Windows +// with Windows XP and below // #define kNTPrintFile L"inf\\ntprint.inf" +// +// Windows Vista ships with a set of prn*.inf files +// +#define kVistaPrintFiles L"inf\\prn*.inf" + // // These are pre-defined names for Generic manufacturer and model // @@ -152,7 +179,6 @@ First checked in #define kGenericPCLColorDriver L"HP Color LaserJet 4550 PCL" #define kGenericPCLDriver L"HP LaserJet 4050 Series PCL" - // // states for parsing ntprint.inf // @@ -164,18 +190,24 @@ enum PrinterParsingState ParsingStrings }; - // CThirdPage dialog IMPLEMENT_DYNAMIC(CThirdPage, CPropertyPage) CThirdPage::CThirdPage() : CPropertyPage(CThirdPage::IDD), + m_manufacturerSelected( NULL ), + m_modelSelected( NULL ), + m_genericPostscript( NULL ), + m_genericPCL( NULL ), m_initialized(false), m_printerImage( NULL ) { static const int bufferSize = 32768; TCHAR windowsDirectory[bufferSize]; CString header; + WIN32_FIND_DATA findFileData; + HANDLE findHandle; + CString prnFiles; CString ntPrint; OSStatus err; BOOL ok; @@ -193,9 +225,38 @@ CThirdPage::CThirdPage() err = translate_errno( ok, errno_compat(), kUnknownErr ); require_noerr( err, exit ); - ntPrint.Format(L"%s\\%s", windowsDirectory, kNTPrintFile); - err = LoadPrintDriverDefsFromFile( m_manufacturers, ntPrint, false ); - require_noerr(err, exit); + // + // + // + // If there are no *prn.inf files, we'll assume that the information + // is in ntprint.inf + // + prnFiles.Format( L"%s\\%s", windowsDirectory, kVistaPrintFiles ); + findHandle = FindFirstFile( prnFiles, &findFileData ); + + if ( findHandle != INVALID_HANDLE_VALUE ) + { + CString absolute; + + absolute.Format( L"%s\\inf\\%s", windowsDirectory, findFileData.cFileName ); + err = LoadPrintDriverDefsFromFile( m_manufacturers, absolute, false ); + require_noerr( err, exit ); + + while ( FindNextFile( findHandle, &findFileData ) ) + { + absolute.Format( L"%s\\inf\\%s", windowsDirectory, findFileData.cFileName ); + err = LoadPrintDriverDefsFromFile( m_manufacturers, absolute, false ); + require_noerr( err, exit ); + } + + FindClose( findHandle ); + } + else + { + ntPrint.Format(L"%s\\%s", windowsDirectory, kNTPrintFile); + err = LoadPrintDriverDefsFromFile( m_manufacturers, ntPrint, false ); + require_noerr(err, exit); + } // // load printer drivers that have been installed on this machine @@ -214,7 +275,6 @@ exit: return; } - CThirdPage::~CThirdPage() { // @@ -241,13 +301,12 @@ CThirdPage::~CThirdPage() } } - // ---------------------------------------------------- // SelectMatch // // SelectMatch will do all the UI work associated with // selected a manufacturer and model of printer. It also -// makes sure the printer object is update with the +// makes sure the printer object is update with the // latest settings // // ---------------------------------------------------- @@ -272,7 +331,10 @@ CThirdPage::SelectMatch(Printer * printer, Service * service, Manufacturer * man if (nIndex != -1) { m_manufacturerListCtrl.SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED); - m_manufacturerListCtrl.EnsureVisible(nIndex, FALSE); + // + // mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle + // + AutoScroll(m_manufacturerListCtrl, nIndex); } // @@ -286,7 +348,7 @@ CThirdPage::SelectMatch(Printer * printer, Service * service, Manufacturer * man if (nIndex != -1) { m_modelListCtrl.SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED); - m_modelListCtrl.EnsureVisible(nIndex, FALSE); + AutoScroll( m_modelListCtrl, nIndex ); m_modelListCtrl.SetFocus(); } @@ -294,7 +356,6 @@ CThirdPage::SelectMatch(Printer * printer, Service * service, Manufacturer * man CopyPrinterSettings( printer, service, manufacturer, model ); } - void CThirdPage::SelectMatch(Manufacturers & manufacturers, Printer * printer, Service * service, Manufacturer * manufacturer, Model * model) { @@ -303,7 +364,6 @@ CThirdPage::SelectMatch(Manufacturers & manufacturers, Printer * printer, Servic SelectMatch( printer, service, manufacturer, model ); } - // -------------------------------------------------------- // CopyPrinterSettings // @@ -359,6 +419,61 @@ CThirdPage::CopyPrinterSettings( Printer * printer, Service * service, Manufactu } } +// -------------------------------------------------------- +// DefaultPrinterExists +// +// Checks to see if a default printer has been configured +// on this machine +// -------------------------------------------------------- +BOOL +CThirdPage::DefaultPrinterExists() +{ + CPrintDialog dlg(FALSE); + + dlg.m_pd.Flags |= PD_RETURNDEFAULT; + + return dlg.GetDefaults(); +} + +// -------------------------------------------------------- +// AutoScroll +// +// Ensure selected item is in middle of list +// -------------------------------------------------------- +void +CThirdPage::AutoScroll( CListCtrl & list, int nIndex ) +{ + // + // mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle + // + + int top; + int count; + + list.EnsureVisible( nIndex, FALSE ); + + top = list.GetTopIndex(); + count = list.GetCountPerPage(); + + if ( ( nIndex == top ) || ( ( nIndex + 1 ) == ( top + count ) ) ) + { + CRect rect; + int rows; + + rows = ( count / 2 ); + + if ( nIndex == top ) + { + list.GetItemRect(0, rect, LVIR_BOUNDS); + list.Scroll( CPoint( 0, rows * rect.Height() * -1 ) ); + } + else + { + list.GetItemRect(0, rect, LVIR_BOUNDS); + list.Scroll( CPoint( 0, rows * rect.Height() ) ); + } + } +} // ------------------------------------------------------ // LoadPrintDriverDefsFromFile @@ -381,7 +496,7 @@ CThirdPage::CopyPrinterSettings( Printer * printer, Service * service, Manufactu // easy format. Tags are strings that are enclosed in brackets. // We are only interested in [MANUFACTURERS] and models. // -// The only potentially opaque thing about this function is the +// The only potentially opaque thing about this function is the // checkForDuplicateModels flag. The problem here is that ntprint.inf // doesn't contain duplicate models, and it has hundreds of models // listed. You wouldn't check for duplicates there. But oftentimes, @@ -514,14 +629,27 @@ CThirdPage::LoadPrintDriverDefsFromFile(Manufacturers & manufacturers, const CSt } else { + CString name; + int curPos; + + // // remove the leading and trailing delimiters // s.Remove('['); s.Remove(']'); + // + // + // + // Ignore decorations in model declarations + // + curPos = 0; + name = s.Tokenize( L".", curPos ); + + // // check to see if this is a printer entry // - iter = manufacturers.find(s); + iter = manufacturers.find( name ); if (iter != manufacturers.end()) { @@ -545,7 +673,7 @@ CThirdPage::LoadPrintDriverDefsFromFile(Manufacturers & manufacturers, const CSt // if we're parsing manufacturers, then we will parse // an entry of the form key=val, where key is a delimited // string specifying a manufacturer name, and val is - // a tag that is used later in the file. the key is + // a tag that is used later in the file. the key is // delimited by either '"' (quotes) or '%' (percent sign). // // the tag is used further down the file when models are @@ -609,6 +737,22 @@ CThirdPage::LoadPrintDriverDefsFromFile(Manufacturers & manufacturers, const CSt curPos = 0; val = val.Tokenize(L",", curPos); + for ( ;; ) + { + CString decoration; + + decoration = val.Tokenize( L",", curPos ); + + if ( decoration.GetLength() > 0 ) + { + manufacturer->decorations.push_back( decoration ); + } + else + { + break; + } + } + manufacturer->name = NormalizeManufacturerName( key ); manufacturer->tag = val; @@ -658,6 +802,15 @@ CThirdPage::LoadPrintDriverDefsFromFile(Manufacturers & manufacturers, const CSt } } + // + // Stock Vista printer inf files embed guids in the model + // declarations for Epson printers. Let's ignore those. + // + if ( name.Find( L"{", 0 ) != -1 ) + { + continue; + } + try { model = new Model; @@ -694,7 +847,6 @@ exit: return (err); } - // ------------------------------------------------------- // LoadPrintDriverDefs // @@ -747,7 +899,7 @@ CThirdPage::LoadPrintDriverDefs( Manufacturers & manufacturers ) // // skip over anything that doesn't have a manufacturer field. This - // fixes a bug that I noticed that occurred after I installed + // fixes a bug that I noticed that occurred after I installed // ProComm. This program add a print driver with no manufacturer // that screwed up this wizard. // @@ -829,7 +981,6 @@ exit: return err; } - // ------------------------------------------------------- // LoadGenericPrintDriverDefs // @@ -853,10 +1004,10 @@ CThirdPage::LoadGenericPrintDriverDefs( Manufacturers & manufacturers ) // First try and find our generic driver names iter = m_manufacturers.find(L"HP"); - require_action( iter != manufacturers.end(), exit, err = kUnknownErr ); + require_action( iter != m_manufacturers.end(), exit, err = kUnknownErr ); manufacturer = iter->second; - // Look for Postscript + // Look for Postscript model = manufacturer->find( kGenericPSColorDriver ); @@ -868,7 +1019,6 @@ CThirdPage::LoadGenericPrintDriverDefs( Manufacturers & manufacturers ) if ( model ) { psDriverName = model->name; - } // Look for PCL @@ -882,7 +1032,7 @@ CThirdPage::LoadGenericPrintDriverDefs( Manufacturers & manufacturers ) if ( model ) { - pclDriverName = model->name; + pclDriverName = model->name; } // If we found either a generic PS driver, or a generic PCL driver, @@ -964,7 +1114,7 @@ exit: // ------------------------------------------------------ // ConvertToManufacturerName // -// This function is responsible for tweaking the +// This function is responsible for tweaking the // name so that subsequent string operations won't fail because // of capitalizations/different names for the same manufacturer // (i.e. Hewlett-Packard/HP/Hewlett Packard) @@ -1001,7 +1151,6 @@ CThirdPage::ConvertToManufacturerName( const CString & name ) return lower; } - // ------------------------------------------------------ // ConvertToModelName // @@ -1022,7 +1171,6 @@ CThirdPage::ConvertToModelName( const CString & name ) return lower; } - // ------------------------------------------------------ // NormalizeManufacturerName // @@ -1047,7 +1195,6 @@ CThirdPage::NormalizeManufacturerName( const CString & name ) return normalized; } - // ------------------------------------------------------- // MatchPrinter // @@ -1120,7 +1267,7 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print hasGenericDriver = true; } - // Use "application/octet-stream" to determine if CUPS + // Use "application/octet-stream" to determine if CUPS // shared queue supports raw if ( q->pdl.Find( L"application/octet-stream" ) != -1 ) @@ -1130,7 +1277,14 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print if ( useCUPSWorkaround && printer->isSharedFromOSX && hasGenericDriver ) { - SelectMatch(manufacturers, printer, service, genericManufacturer, genericModel ); + // + // mDNS: Don't allow user to choose non-working driver + // + Manufacturers genericManufacturers; + + LoadGenericPrintDriverDefs( genericManufacturers ); + + SelectMatch( genericManufacturers, printer, service, genericManufacturer, genericModel ); } else { @@ -1150,17 +1304,25 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print text.LoadString(IDS_PRINTER_MATCH_GOOD); } else if ( MatchGeneric( manufacturers, printer, service, &genericManufacturer, &genericModel ) ) - { + { if ( printer->isSharedFromOSX ) { + // + // mDNS: Don't allow user to choose non-working driver + // + Manufacturers genericManufacturers; + + LoadGenericPrintDriverDefs( genericManufacturers ); + + SelectMatch( genericManufacturers, printer, service, genericManufacturer, genericModel ); + text.LoadString(IDS_PRINTER_MATCH_GOOD); } else { + SelectMatch( manufacturers, printer, service, genericManufacturer, genericModel ); text.LoadString(IDS_PRINTER_MATCH_MAYBE); } - - SelectMatch( manufacturers, printer, service, genericManufacturer, genericModel ); } else { @@ -1190,7 +1352,11 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print if (nIndex != -1) { m_manufacturerListCtrl.SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED); - m_manufacturerListCtrl.EnsureVisible(nIndex, FALSE); + + // + // mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle + // + AutoScroll(m_manufacturerListCtrl, nIndex); } } } @@ -1200,7 +1366,6 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print return err; } - // ------------------------------------------------------ // MatchManufacturer // @@ -1237,7 +1402,6 @@ CThirdPage::MatchManufacturer( Manufacturers & manufacturers, const CString & na return NULL; } - // ------------------------------------------------------- // MatchModel // @@ -1288,7 +1452,6 @@ CThirdPage::MatchModel(Manufacturer * manufacturer, const CString & name) return NULL; } - // ------------------------------------------------------- // MatchGeneric // @@ -1318,12 +1481,12 @@ CThirdPage::MatchGeneric( Manufacturers & manufacturers, Printer * printer, Serv pdl = q->pdl; pdl.MakeLower(); - if ( pdl.Find( kPDLPCLKey ) != -1 ) + if ( m_genericPCL && ( pdl.Find( kPDLPCLKey ) != -1 ) ) { *model = m_genericPCL; ok = TRUE; } - else if ( pdl.Find( kPDLPostscriptKey ) != -1 ) + else if ( m_genericPostscript && ( pdl.Find( kPDLPostscriptKey ) != -1 ) ) { *model = m_genericPostscript; ok = TRUE; @@ -1334,7 +1497,6 @@ exit: return ok; } - // ----------------------------------------------------------- // OnInitPage // @@ -1349,12 +1511,9 @@ OSStatus CThirdPage::OnInitPage() OSStatus err = kNoErr; // Load printer icon - - - check( m_printerImage == NULL ); - m_printerImage = (CStatic*) GetDlgItem( IDR_MANIFEST ); + m_printerImage = (CStatic*) GetDlgItem( 1 ); // 1 == IDR_MANIFEST check( m_printerImage ); if ( m_printerImage != NULL ) @@ -1372,7 +1531,7 @@ OSStatus CThirdPage::OnInitPage() // // - // we have to make sure that we only do this once. Typically, + // we have to make sure that we only do this once. Typically, // we would do this in something like OnInitDialog, but we don't // have this in Wizards, because the window is a PropertySheet. // We're considered fully initialized when we receive the first @@ -1389,7 +1548,6 @@ OSStatus CThirdPage::OnInitPage() return (err); } - void CThirdPage::DoDataExchange(CDataExchange* pDX) { CPropertyPage::DoDataExchange(pDX); @@ -1401,7 +1559,6 @@ void CThirdPage::DoDataExchange(CDataExchange* pDX) } - // ---------------------------------------------------------- // OnSetActive // @@ -1436,6 +1593,20 @@ CThirdPage::OnSetActive() m_initialized = true; } + // + // mDNS: Printers added using Bonjour should be set as the default printer. + // + if ( DefaultPrinterExists() ) + { + m_defaultPrinterCtrl.SetCheck( BST_UNCHECKED ); + printer->deflt = false; + } + else + { + m_defaultPrinterCtrl.SetCheck( BST_CHECKED ); + printer->deflt = true; + } + // // update the UI with the printer name // @@ -1465,14 +1636,13 @@ exit: return CPropertyPage::OnSetActive(); } - BOOL CThirdPage::OnKillActive() { CPrinterSetupWizardSheet * psheet; psheet = reinterpret_cast(GetParent()); - require_quiet( psheet, exit ); + require_quiet( psheet, exit ); psheet->SetLastPage(this); @@ -1481,7 +1651,6 @@ exit: return CPropertyPage::OnKillActive(); } - // ------------------------------------------------------- // PopulateUI // @@ -1510,7 +1679,6 @@ CThirdPage::PopulateUI(Manufacturers & manufacturers) return 0; } - BEGIN_MESSAGE_MAP(CThirdPage, CPropertyPage) ON_NOTIFY(LVN_ITEMCHANGED, IDC_PRINTER_MANUFACTURER, OnLvnItemchangedManufacturer) ON_NOTIFY(LVN_ITEMCHANGED, IDC_PRINTER_MODEL, OnLvnItemchangedPrinterModel) @@ -1518,7 +1686,6 @@ BEGIN_MESSAGE_MAP(CThirdPage, CPropertyPage) ON_BN_CLICKED(IDC_HAVE_DISK, OnBnClickedHaveDisk) END_MESSAGE_MAP() - // CThirdPage message handlers void CThirdPage::OnLvnItemchangedManufacturer(NMHDR *pNMHDR, LRESULT *pResult) { @@ -1595,7 +1762,6 @@ exit: *pResult = 0; } - void CThirdPage::OnBnClickedDefaultPrinter() { CPrinterSetupWizardSheet * psheet; diff --git a/Clients/PrinterSetupWizard/ThirdPage.h b/Clients/PrinterSetupWizard/ThirdPage.h index 8331421..2ab62b1 100644 --- a/Clients/PrinterSetupWizard/ThirdPage.h +++ b/Clients/PrinterSetupWizard/ThirdPage.h @@ -1,28 +1,34 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: ThirdPage.h,v $ +Revision 1.9 2007/04/13 23:42:20 herscher + mDNS: Printers added using Bonjour should be set as the default printer. + +Revision 1.8 2007/04/13 21:38:46 herscher + mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle + +Revision 1.7 2007/04/13 20:18:30 herscher + mDNS: Epson shows up twice in the list + +Revision 1.6 2006/08/14 23:24:09 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.5 2005/07/07 17:53:20 shersche Fix problems associated with the CUPS printer workaround fix. @@ -76,7 +82,18 @@ protected: private: - typedef std::map Manufacturers; + // + // mDNS: Epson shows up twice in the list. Use case insensitive compare + // + struct compare_func + { + bool operator()( const CString & s1, const CString & s2 ) const + { + return s1.CompareNoCase( s2 ) < 0; + } + }; + + typedef std::map Manufacturers; // // LoadPrintDriverDefsFromFile @@ -133,6 +150,14 @@ private: void SelectMatch(Printer * printer, Service * service, Manufacturer * manufacturer, Model * model); void SelectMatch(Manufacturers & manufacturers, Printer * printer, Service * service, Manufacturer * manufacturer, Model * model); void CopyPrinterSettings(Printer * printer, Service * service, Manufacturer * manufacturer, Model * model); + // + // mDNS: Printers added using Bonjour should be set as the default printer. + // + BOOL DefaultPrinterExists(); + // + // mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle + // + void AutoScroll(CListCtrl & list, int nIndex); Manufacturers m_manufacturers; diff --git a/Clients/PrinterSetupWizard/UtilTypes.h b/Clients/PrinterSetupWizard/UtilTypes.h index e5512b9..c467f3d 100644 --- a/Clients/PrinterSetupWizard/UtilTypes.h +++ b/Clients/PrinterSetupWizard/UtilTypes.h @@ -1,28 +1,28 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: UtilTypes.h,v $ +Revision 1.16 2007/04/20 22:58:10 herscher + mDNS: Printer Wizard doesn't offer generic HP printers or generic PS support on Vista RC2 + +Revision 1.15 2006/08/14 23:24:09 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.14 2005/06/30 18:02:54 shersche Workaround for Mac OS X Printer Sharing bug @@ -97,6 +97,7 @@ namespace PrinterSetupWizard typedef std::list Printers; typedef std::list Services; typedef std::list Models; + typedef std::list Decorations; struct Printer { @@ -219,6 +220,7 @@ namespace PrinterSetupWizard CString name; CString tag; Models models; + Decorations decorations; Model* find( const CString & name ); diff --git a/Clients/PrinterSetupWizard/resource.h b/Clients/PrinterSetupWizard/resource.h index 5d21d40..a44c06f 100644 --- a/Clients/PrinterSetupWizard/resource.h +++ b/Clients/PrinterSetupWizard/resource.h @@ -1,24 +1,18 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): diff --git a/Clients/PrinterSetupWizard/stdafx.cpp b/Clients/PrinterSetupWizard/stdafx.cpp index 53abf25..548f66f 100644 --- a/Clients/PrinterSetupWizard/stdafx.cpp +++ b/Clients/PrinterSetupWizard/stdafx.cpp @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: stdafx.cpp,v $ +Revision 1.2 2006/08/14 23:24:09 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.1 2004/06/18 04:36:58 rpantos First checked in diff --git a/Clients/PrinterSetupWizard/stdafx.h b/Clients/PrinterSetupWizard/stdafx.h index 8ec4bdb..e1ecec8 100644 --- a/Clients/PrinterSetupWizard/stdafx.h +++ b/Clients/PrinterSetupWizard/stdafx.h @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: stdafx.h,v $ +Revision 1.3 2006/08/14 23:24:09 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.2 2005/10/19 19:50:35 herscher Workaround a bug in the latest Microsoft Platform SDK when compiling C++ files that include (directly or indirectly) diff --git a/Clients/SimpleChat.NET/AssemblyInfo.cs b/Clients/SimpleChat.NET/AssemblyInfo.cs index a778420..4fc7745 100755 --- a/Clients/SimpleChat.NET/AssemblyInfo.cs +++ b/Clients/SimpleChat.NET/AssemblyInfo.cs @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: AssemblyInfo.cs,v $ +Revision 1.2 2006/08/14 23:24:21 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.1 2004/07/19 07:57:08 shersche Initial revision diff --git a/Clients/SimpleChat.NET/SimpleChat.cs b/Clients/SimpleChat.NET/SimpleChat.cs index fb841f2..e7f3b1e 100755 --- a/Clients/SimpleChat.NET/SimpleChat.cs +++ b/Clients/SimpleChat.NET/SimpleChat.cs @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: SimpleChat.cs,v $ +Revision 1.6 2006/08/14 23:24:21 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.5 2004/09/13 19:37:42 shersche Change code to reflect namespace and type changes to dnssd.NET library diff --git a/Clients/dns-sd.c b/Clients/dns-sd.c index 699a932..279e5ef 100644 --- a/Clients/dns-sd.c +++ b/Clients/dns-sd.c @@ -1,5 +1,6 @@ -/* - * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2002-2006 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 @@ -58,31 +59,64 @@ POSIX systems: gcc dns-sd.c -o dns-sd -I../mDNSShared -ldns_sd Windows: -cl dns-sd.c -I../mDNSShared -DNOT_HAVE_GETOPT -DNOT_HAVE_SETLINEBUF ws2_32.lib ..\mDNSWindows\DLL\Release\dnssd.lib +cl dns-sd.c -I../mDNSShared -DNOT_HAVE_GETOPT ws2_32.lib ..\mDNSWindows\DLL\Release\dnssd.lib (may require that you run a Visual Studio script such as vsvars32.bat first) */ -#include "dns_sd.h" +// For testing changes to dnssd_clientstub.c, uncomment this line and the code will be compiled +// with an embedded copy of the client stub instead of linking the system library version at runtime. +// This also useful to work around link errors when you're working on an older version of Mac OS X, +// and trying to build a newer version of the "dns-sd" command which uses new API entry points that +// aren't in the system's /usr/lib/libSystem.dylib. +//#define TEST_NEW_CLIENTSTUB 1 + #include #include // For stdout, stderr #include // For exit() #include // For strlen(), strcpy(), bzero() -#include // For errno, EINTR +#include // For errno, EINTR #include -#include // For u_char +#include // For u_char #ifdef _WIN32 -#include -typedef int pid_t; -#define getpid _getpid -#define strcasecmp _stricmp -#define snprintf _snprintf + #include + #include + #include + typedef int pid_t; + #define getpid _getpid + #define strcasecmp _stricmp + #define snprintf _snprintf + static const char kFilePathSep = '\\'; #else -#include // For struct timeval -#include // For getopt() and optind -#include // For inet_addr() + #include // For getopt() and optind + #include // For getaddrinfo() + #include // For struct timeval + #include // For AF_INET + #include // For struct sockaddr_in() + #include // For inet_addr() + #include // For if_nametoindex() + static const char kFilePathSep = '/'; +#endif + +#if (TEST_NEW_CLIENTSTUB && !defined(__APPLE_API_PRIVATE)) +#define __APPLE_API_PRIVATE 1 #endif +#include "dns_sd.h" + +#if TEST_NEW_CLIENTSTUB +#include "../mDNSShared/dnssd_ipc.c" +#include "../mDNSShared/dnssd_clientlib.c" +#include "../mDNSShared/dnssd_clientstub.c" +#endif + +// The "+0" is to cope with the case where _DNS_SD_H is defined but empty (e.g. on Mac OS X 10.4 and earlier) +#if _DNS_SD_H+0 >= 116 +#define HAS_NAT_PMP_API 1 +#define HAS_ADDRINFO_API 1 +#else +#define kDNSServiceFlagsReturnIntermediates 0 +#endif //************************************************************************************************************* // Globals @@ -91,15 +125,17 @@ typedef union { unsigned char b[2]; unsigned short NotAnInteger; } Opaque16; static int operation; static uint32_t opinterface = kDNSServiceInterfaceIndexAny; -static DNSServiceRef client = NULL; -static DNSServiceRef client2 = NULL; +static DNSServiceRef client = NULL; +static DNSServiceRef client_pa = NULL; // DNSServiceRef for RegisterProxyAddressRecord +static DNSServiceRef sc1, sc2, sc3; // DNSServiceRefs for kDNSServiceFlagsShareConnection testing + static int num_printed; static char addtest = 0; static DNSRecordRef record = NULL; static char myhinfoW[14] = "\002PC\012Windows XP"; static char myhinfoX[ 9] = "\003Mac\004OS X"; static char updatetest[3] = "\002AA"; -static char bigNULL[4096]; +static char bigNULL[8200]; // Note: the select() implementation on Windows (Winsock2) fails with any timeout much larger than this #define LONG_TIME 100000000 @@ -108,7 +144,7 @@ static volatile int stopNow = 0; static volatile int timeOut = LONG_TIME; //************************************************************************************************************* -// Supporting Utility Function +// Supporting Utility Functions static uint16_t GetRRType(const char *s) { @@ -163,6 +199,21 @@ static uint16_t GetRRType(const char *s) else return(atoi(s)); } +#if HAS_NAT_PMP_API | HAS_ADDRINFO_API +static DNSServiceProtocol GetProtocol(const char *s) + { + if (!strcasecmp(s, "v4" )) return(kDNSServiceProtocol_IPv4); + else if (!strcasecmp(s, "v6" )) return(kDNSServiceProtocol_IPv6); + else if (!strcasecmp(s, "v4v6" )) return(kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6); + else if (!strcasecmp(s, "v6v4" )) return(kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6); + else if (!strcasecmp(s, "udp" )) return(kDNSServiceProtocol_UDP); + else if (!strcasecmp(s, "tcp" )) return(kDNSServiceProtocol_TCP); + else if (!strcasecmp(s, "udptcp" )) return(kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP); + else if (!strcasecmp(s, "tcpudp" )) return(kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP); + else return(atoi(s)); + } +#endif + //************************************************************************************************************* // Sample callback functions for each of the operation types @@ -214,124 +265,140 @@ static const char *GetNextLabel(const char *cstr, char label[64]) return(cstr); } -static void DNSSD_API enum_reply(DNSServiceRef client, DNSServiceFlags flags, uint32_t ifIndex, +static void DNSSD_API enum_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode, const char *replyDomain, void *context) { + DNSServiceFlags partialflags = flags & ~(kDNSServiceFlagsMoreComing | kDNSServiceFlagsAdd | kDNSServiceFlagsDefault); int labels = 0, depth = 0, i, initial = 0; char text[64]; const char *label[128]; - (void)client; // Unused + (void)sdref; // Unused (void)ifIndex; // Unused - (void)errorCode; // Unused (void)context; // Unused - - if (!*replyDomain) return; // 1. Print the header if (num_printed++ == 0) printf("Timestamp Recommended %s domain\n", operation == 'E' ? "Registration" : "Browsing"); printtimestamp(); - printf("%-10s", DomainMsg(flags)); - printf("%-8s", (flags & kDNSServiceFlagsMoreComing) ? "(More)" : ""); - flags &= ~kDNSServiceFlagsMoreComing; - flags &= ~kDNSServiceFlagsAdd; - flags &= ~kDNSServiceFlagsDefault; - if (flags) printf("Flags: %4X ", flags); - else printf(" "); - - // 2. Count the labels - while (*replyDomain) + if (errorCode) + printf("Error code %d\n", errorCode); + else if (!*replyDomain) + printf("Error: No reply domain\n"); + else { - label[labels++] = replyDomain; - replyDomain = GetNextLabel(replyDomain, text); - } + printf("%-10s", DomainMsg(flags)); + printf("%-8s", (flags & kDNSServiceFlagsMoreComing) ? "(More)" : ""); + if (partialflags) printf("Flags: %4X ", partialflags); + else printf(" "); + + // 2. Count the labels + while (*replyDomain) + { + label[labels++] = replyDomain; + replyDomain = GetNextLabel(replyDomain, text); + } + + // 3. Decide if we're going to clump the last two or three labels (e.g. "apple.com", or "nicta.com.au") + if (labels >= 3 && replyDomain - label[labels-1] <= 3 && label[labels-1] - label[labels-2] <= 4) initial = 3; + else if (labels >= 2 && replyDomain - label[labels-1] <= 4) initial = 2; + else initial = 1; + labels -= initial; - // 3. Decide if we're going to clump the last two or three labels (e.g. "apple.com", or "nicta.com.au") - if (labels >= 3 && replyDomain - label[labels-1] <= 3 && label[labels-1] - label[labels-2] <= 4) initial = 3; - else if (labels >= 2 && replyDomain - label[labels-1] <= 4) initial = 2; - else initial = 1; - labels -= initial; - - // 4. Print the initial one-, two- or three-label clump - for (i=0; i0) printf("."); - printf("%s", text); - } - printf("\n"); - - // 5. Print the remainder of the hierarchy - for (depth=0; depth %s\n", text); + // 4. Print the initial one-, two- or three-label clump + for (i=0; i0) printf("."); + printf("%s", text); + } + printf("\n"); + + // 5. Print the remainder of the hierarchy + for (depth=0; depth %s\n", text); + } } - fflush( stdout ); + if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout); } -static void DNSSD_API browse_reply(DNSServiceRef client, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode, +static void DNSSD_API browse_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode, const char *replyName, const char *replyType, const char *replyDomain, void *context) { char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv"; - (void)client; // Unused - (void)errorCode; // Unused + (void)sdref; // Unused (void)context; // Unused - if (num_printed++ == 0) printf("Timestamp A/R Flags if %-24s %-24s %s\n", "Domain", "Service Type", "Instance Name"); + if (num_printed++ == 0) printf("Timestamp A/R Flags if %-25s %-25s %s\n", "Domain", "Service Type", "Instance Name"); printtimestamp(); - printf("%s%6X%3d %-24s %-24s %s\n", op, flags, ifIndex, replyDomain, replyType, replyName); - fflush( stdout ); + if (errorCode) printf("Error code %d\n", errorCode); + else printf("%s%6X%3d %-25s %-25s %s\n", op, flags, ifIndex, replyDomain, replyType, replyName); + if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout); + + // To test selective cancellation of operations of shared sockets, + // cancel the current operation when we've got a multiple of five results + //if (operation == 'S' && num_printed % 5 == 0) DNSServiceRefDeallocate(sdref); + } + +static void ShowTXTRecord(uint16_t txtLen, const unsigned char *txtRecord) + { + const unsigned char *ptr = txtRecord; + const unsigned char *max = txtRecord + txtLen; + while (ptr < max) + { + const unsigned char *const end = ptr + 1 + ptr[0]; + if (end > max) { printf("<< invalid data >>"); break; } + if (++ptr < end) printf(" "); // As long as string is non-empty, begin with a space + while (ptr^()[]{}$", *ptr)) printf("\\"); + if (*ptr == '\\') printf("\\\\\\\\"); + else if (*ptr >= ' ' ) printf("%c", *ptr); + else printf("\\\\x%02X", *ptr); + ptr++; + } + } } -static void DNSSD_API resolve_reply(DNSServiceRef client, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode, - const char *fullname, const char *hosttarget, uint16_t opaqueport, uint16_t txtLen, const char *txtRecord, void *context) +static void DNSSD_API resolve_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode, + const char *fullname, const char *hosttarget, uint16_t opaqueport, uint16_t txtLen, const unsigned char *txtRecord, void *context) { - const char *src = txtRecord; union { uint16_t s; u_char b[2]; } port = { opaqueport }; uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1]; - (void)client; // Unused + (void)sdref; // Unused (void)ifIndex; // Unused - (void)errorCode; // Unused - (void)txtLen; // Unused (void)context; // Unused printtimestamp(); - printf("%s can be reached at %s:%u", fullname, hosttarget, PortAsNumber); - - if (flags) printf(" Flags: %X", flags); - if (*src) + if (errorCode) printf("Error code %d\n", errorCode); + else { - char txtInfo[64]; // Display at most first 64 characters of TXT record - char *dst = txtInfo; - const char *const lim = &txtInfo[sizeof(txtInfo)]; - while (*src && dst < lim-1) - { - if (*src == '\\') *dst++ = '\\'; // '\' displays as "\\" - if (*src >= ' ') *dst++ = *src++; // Display normal characters as-is - else - { - *dst++ = '\\'; // Display a backslash - if (*src == 1) *dst++ = ' '; // String boundary displayed as "\ " - else // Other chararacters displayed as "\0xHH" - { - static const char hexchars[16] = "0123456789ABCDEF"; - *dst++ = '0'; - *dst++ = 'x'; - *dst++ = hexchars[*src >> 4]; - *dst++ = hexchars[*src & 0xF]; - } - src++; - } - } - *dst++ = 0; - printf(" TXT %s", txtInfo); + printf("%s can be reached at %s:%u", fullname, hosttarget, PortAsNumber); + if (flags) printf(" Flags: %X", flags); + // Don't show degenerate TXT records containing nothing but a single empty string + if (txtLen > 1) { printf("\n"); ShowTXTRecord(txtLen, txtRecord); } + printf("\n"); } - printf("\n"); - fflush( stdout ); + + if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout); } static void myTimerCallBack(void) @@ -375,6 +442,7 @@ static void myTimerCallBack(void) { printf("Adding big NULL record\n"); err = DNSServiceAddRecord(client, &record, 0, kDNSServiceType_NULL, sizeof(bigNULL), &bigNULL[0], 0); + if (err) printf("Failed: %d\n", err); else printf("Succeeded\n"); timeOut = LONG_TIME; } break; @@ -382,67 +450,187 @@ static void myTimerCallBack(void) if (err != kDNSServiceErr_NoError) { - fprintf(stderr, "DNSService call failed %ld\n", (long int)err); + fprintf(stderr, "DNSService add/update/remove failed %ld\n", (long int)err); stopNow = 1; } } -static void DNSSD_API reg_reply(DNSServiceRef client, DNSServiceFlags flags, DNSServiceErrorType errorCode, +static void DNSSD_API reg_reply(DNSServiceRef sdref, const DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, void *context) { - (void)client; // Unused + (void)sdref; // Unused (void)flags; // Unused (void)context; // Unused - printf("Got a reply for %s.%s%s: ", name, regtype, domain); - switch (errorCode) + printtimestamp(); + printf("Got a reply for service %s.%s%s: ", name, regtype, domain); + + if (errorCode == kDNSServiceErr_NoError) { - case kDNSServiceErr_NoError: printf("Name now registered and active\n"); break; - case kDNSServiceErr_NameConflict: printf("Name in use, please choose another\n"); exit(-1); - default: printf("Error %d\n", errorCode); return; + if (flags & kDNSServiceFlagsAdd) printf("Name now registered and active\n"); + else printf("Name registration removed\n"); + if (operation == 'A' || operation == 'U' || operation == 'N') timeOut = 5; + } + else if (errorCode == kDNSServiceErr_NameConflict) + { + printf("Name in use, please choose another\n"); + exit(-1); } + else + printf("Error %d\n", errorCode); - if (operation == 'A' || operation == 'U' || operation == 'N') timeOut = 5; - fflush( stdout ); + if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout); } -static void DNSSD_API qr_reply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode, +// Output the wire-format domainname pointed to by rd +static int snprintd(char *p, int max, const unsigned char **rd) + { + const char *const buf = p; + const char *const end = p + max; + while (**rd) { p += snprintf(p, end-p, "%.*s.", **rd, *rd+1); *rd += 1 + **rd; } + *rd += 1; // Advance over the final zero byte + return(p-buf); + } + +static void DNSSD_API qr_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode, const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context) { char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv"; const unsigned char *rd = rdata; const unsigned char *end = (const unsigned char *) rdata + rdlen; - char rdb[1000]; - char *p = rdb; - const char * const lim = rdb + sizeof(rdb); + char rdb[1000] = "", *p = rdb; + int unknowntype = 0; - (void)sdRef; // Unused + (void)sdref; // Unused (void)flags; // Unused (void)ifIndex; // Unused - (void)errorCode;// Unused (void)ttl; // Unused (void)context; // Unused - switch (rrtype) + if (num_printed++ == 0) printf("Timestamp A/R Flags if %-30s%4s%4s Rdata\n", "Name", "T", "C"); + printtimestamp(); + + if (!errorCode) { - case kDNSServiceType_A: sprintf(rdb, "%d.%d.%d.%d", rd[0], rd[1], rd[2], rd[3]); break; - default : p += snprintf(p, lim-p, "%d bytes%s", rdlen, rdlen ? ":" : ""); - while (rd < end && p < lim) p += snprintf(p, lim-p, " %02X", *rd++); - break; + switch (rrtype) + { + case kDNSServiceType_A: + snprintf(rdb, sizeof(rdb), "%d.%d.%d.%d", rd[0], rd[1], rd[2], rd[3]); + break; + + case kDNSServiceType_NS: + case kDNSServiceType_CNAME: + case kDNSServiceType_PTR: + case kDNSServiceType_DNAME: + p += snprintd(p, sizeof(rdb), &rd); + break; + + case kDNSServiceType_SOA: + p += snprintd(p, rdb + sizeof(rdb) - p, &rd); // mname + p += snprintf(p, rdb + sizeof(rdb) - p, " "); + p += snprintd(p, rdb + sizeof(rdb) - p, &rd); // rname + p += snprintf(p, rdb + sizeof(rdb) - p, " Ser %d Ref %d Ret %d Exp %d Min %d", + ntohl(((uint32_t*)rd)[0]), ntohl(((uint32_t*)rd)[1]), ntohl(((uint32_t*)rd)[2]), ntohl(((uint32_t*)rd)[3]), ntohl(((uint32_t*)rd)[4])); + break; + + case kDNSServiceType_AAAA: + snprintf(rdb, sizeof(rdb), "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X", + rd[0x0], rd[0x1], rd[0x2], rd[0x3], rd[0x4], rd[0x5], rd[0x6], rd[0x7], + rd[0x8], rd[0x9], rd[0xA], rd[0xB], rd[0xC], rd[0xD], rd[0xE], rd[0xF]); + break; + + case kDNSServiceType_SRV: + p += snprintf(p, rdb + sizeof(rdb) - p, "%d %d %d ", // priority, weight, port + ntohs(*(unsigned short*)rd), ntohs(*(unsigned short*)(rd+2)), ntohs(*(unsigned short*)(rd+4))); + rd += 6; + p += snprintd(p, rdb + sizeof(rdb) - p, &rd); // target host + break; + + default : snprintf(rdb, sizeof(rdb), "%d bytes%s", rdlen, rdlen ? ":" : ""); unknowntype = 1; break; + } } - if (num_printed++ == 0) printf("Timestamp A/R Flags if %-30s%4s%4s Rdata\n", "Name", "T", "C"); + + printf("%s%6X%3d %-30s%4d%4d %s", op, flags, ifIndex, fullname, rrtype, rrclass, rdb); + if (unknowntype) while (rd < end) printf(" %02X", *rd++); + if (errorCode) + { + if (errorCode == kDNSServiceErr_NoSuchRecord) printf("No Such Record"); + else printf("Error code %d", errorCode); + } + printf("\n"); + + if (operation == 'C') + if (flags & kDNSServiceFlagsAdd) + DNSServiceReconfirmRecord(flags, ifIndex, fullname, rrtype, rrclass, rdlen, rdata); + + if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout); + } + +#if HAS_NAT_PMP_API +static void DNSSD_API port_mapping_create_reply(DNSServiceRef sdref, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode, uint32_t publicAddress, uint32_t protocol, uint16_t privatePort, uint16_t publicPort, uint32_t ttl, void *context) + { + (void)sdref; // Unused + (void)context; // Unused + (void)flags; // Unused + + if (num_printed++ == 0) printf("Timestamp if %-20s %-15s %-15s %-15s %s\n", "External Address", "Protocol", "Internal Port", "External Port", "TTL"); + printtimestamp(); + if (errorCode) printf("Error code %d\n", errorCode); + else + { + const unsigned char *digits = (const unsigned char *)&publicAddress; + char addr[256]; + + snprintf(addr, sizeof(addr), "%d.%d.%d.%d", digits[0], digits[1], digits[2], digits[3]); + printf("%-4d %-20s %-15d %-15d %-15d %d\n", ifIndex, addr, protocol, ntohs(privatePort), ntohs(publicPort), ttl); + } + fflush(stdout); + } +#endif + +#if HAS_ADDRINFO_API +static void DNSSD_API addrinfo_reply(DNSServiceRef sdref, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *address, uint32_t ttl, void *context) + { + char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv"; + char addr[256] = ""; + (void) sdref; + (void) context; + + if (num_printed++ == 0) printf("Timestamp A/R Flags if %-25s %-40s %s\n", "Hostname", "Address", "TTL"); printtimestamp(); - printf("%s%6X%3d %-30s%4d%4d %s\n", op, flags, ifIndex, fullname, rrtype, rrclass, rdb); - fflush( stdout ); + + if (address && address->sa_family == AF_INET) + { + const unsigned char *digits = (const unsigned char *) &((struct sockaddr_in *)address)->sin_addr; + snprintf(addr, sizeof(addr), "%d.%d.%d.%d", digits[0], digits[1], digits[2], digits[3]); + } + else if (address && address->sa_family == AF_INET6) + { + const unsigned char *digits = (const unsigned char *) &((struct sockaddr_in6 *)address)->sin6_addr; + snprintf(addr, sizeof(addr), "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X", + digits[0x0], digits[0x1], digits[0x2], digits[0x3], digits[0x4], digits[0x5], digits[0x6], digits[0x7], + digits[0x8], digits[0x9], digits[0xA], digits[0xB], digits[0xC], digits[0xD], digits[0xE], digits[0xF]); + } + + printf("%s%6X%3d %-25s %-40s %d", op, flags, interfaceIndex, hostname, addr, ttl); + if (errorCode) + { + if (errorCode == kDNSServiceErr_NoSuchRecord) printf(" No Such Record"); + else printf(" Error code %d", errorCode); + } + printf("\n"); + + if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout); } +#endif //************************************************************************************************************* // The main test function static void HandleEvents(void) { - int dns_sd_fd = client ? DNSServiceRefSockFD(client ) : -1; - int dns_sd_fd2 = client2 ? DNSServiceRefSockFD(client2) : -1; + int dns_sd_fd = client ? DNSServiceRefSockFD(client ) : -1; + int dns_sd_fd2 = client_pa ? DNSServiceRefSockFD(client_pa) : -1; int nfds = dns_sd_fd + 1; fd_set readfds; struct timeval tv; @@ -458,19 +646,19 @@ static void HandleEvents(void) FD_ZERO(&readfds); // 2. Add the fd for our client(s) to the fd_set - if (client ) FD_SET(dns_sd_fd , &readfds); - if (client2) FD_SET(dns_sd_fd2, &readfds); + if (client ) FD_SET(dns_sd_fd , &readfds); + if (client_pa) FD_SET(dns_sd_fd2, &readfds); // 3. Set up the timeout. - tv.tv_sec = timeOut; + tv.tv_sec = timeOut; tv.tv_usec = 0; result = select(nfds, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv); if (result > 0) { DNSServiceErrorType err = kDNSServiceErr_NoError; - if (client && FD_ISSET(dns_sd_fd , &readfds)) err = DNSServiceProcessResult(client ); - else if (client2 && FD_ISSET(dns_sd_fd2, &readfds)) err = DNSServiceProcessResult(client2); + if (client && FD_ISSET(dns_sd_fd , &readfds)) err = DNSServiceProcessResult(client ); + else if (client_pa && FD_ISSET(dns_sd_fd2, &readfds)) err = DNSServiceProcessResult(client_pa); if (err) { fprintf(stderr, "DNSServiceProcessResult returned %d\n", err); stopNow = 1; } } else if (result == 0) @@ -483,15 +671,15 @@ static void HandleEvents(void) } } -static int getfirstoption( int argc, char **argv, const char *optstr, int *pOptInd) +static int getfirstoption(int argc, char **argv, const char *optstr, int *pOptInd) // Return the recognized option in optstr and the option index of the next arg. #if NOT_HAVE_GETOPT { - int i; - for ( i=1; i < argc; i++) + int i; + for (i=1; i < argc; i++) { - if ( argv[i][0] == '-' && &argv[i][1] && - NULL != strchr( optstr, argv[i][1])) + if (argv[i][0] == '-' && &argv[i][1] && + NULL != strchr(optstr, argv[i][1])) { *pOptInd = i + 1; return argv[i][1]; @@ -501,14 +689,14 @@ static int getfirstoption( int argc, char **argv, const char *optstr, int *pOptI } #else { - int operation = getopt(argc, (char * const *)argv, optstr); + int operation = getopt(argc, (char *const *)argv, optstr); *pOptInd = optind; return operation; } #endif -static void DNSSD_API MyRegisterRecordCallback(DNSServiceRef service, DNSRecordRef record, DNSServiceFlags flags, - DNSServiceErrorType errorCode, void * context) +static void DNSSD_API MyRegisterRecordCallback(DNSServiceRef service, DNSRecordRef record, const DNSServiceFlags flags, + DNSServiceErrorType errorCode, void *context) { char *name = (char *)context; @@ -516,28 +704,63 @@ static void DNSSD_API MyRegisterRecordCallback(DNSServiceRef service, DNSRecordR (void)record; // Unused (void)flags; // Unused - printf("Got a reply for %s: ", name); + printtimestamp(); + printf("Got a reply for record %s: ", name); + switch (errorCode) { case kDNSServiceErr_NoError: printf("Name now registered and active\n"); break; case kDNSServiceErr_NameConflict: printf("Name in use, please choose another\n"); exit(-1); - default: printf("Error %d\n", errorCode); return; + default: printf("Error %d\n", errorCode); break; + } + if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout); + // DNSServiceRemoveRecord(service, record, 0); to test record removal + } + +static unsigned long getip(const char *const name) + { + unsigned long ip = 0; + struct addrinfo hints; + struct addrinfo *addrs = NULL; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + + if (getaddrinfo(name, NULL, &hints, &addrs) == 0) + { + ip = ((struct sockaddr_in*) addrs->ai_addr)->sin_addr.s_addr; + } + + if (addrs) + { + freeaddrinfo(addrs); } - fflush( stdout ); + + return(ip); } -static DNSServiceErrorType RegisterProxyAddressRecord(DNSServiceRef *sdRef, const char *host, const char *ip) +static DNSServiceErrorType RegisterProxyAddressRecord(DNSServiceRef sdref, const char *host, const char *ip) { - unsigned long addr = inet_addr(ip); - DNSServiceErrorType err = DNSServiceCreateConnection(sdRef); - if (err) { fprintf(stderr, "DNSServiceCreateConnection returned %d\n", err); return(err); } - return(DNSServiceRegisterRecord(*sdRef, &record, kDNSServiceFlagsUnique, kDNSServiceInterfaceIndexAny, host, + // Call getip() after the call DNSServiceCreateConnection(). + // On the Win32 platform, WinSock must be initialized for getip() to succeed. + // Any DNSService* call will initialize WinSock for us, so we make sure + // DNSServiceCreateConnection() is called before getip() is. + unsigned long addr = getip(ip); + return(DNSServiceRegisterRecord(sdref, &record, kDNSServiceFlagsUnique, opinterface, host, kDNSServiceType_A, kDNSServiceClass_IN, sizeof(addr), &addr, 240, MyRegisterRecordCallback, (void*)host)); + // Note, should probably add support for creating proxy AAAA records too, one day } -static DNSServiceErrorType RegisterService(DNSServiceRef *sdRef, +#define HexVal(X) ( ((X) >= '0' && (X) <= '9') ? ((X) - '0' ) : \ + ((X) >= 'A' && (X) <= 'F') ? ((X) - 'A' + 10) : \ + ((X) >= 'a' && (X) <= 'f') ? ((X) - 'a' + 10) : 0) + +#define HexPair(P) ((HexVal((P)[0]) << 4) | HexVal((P)[1])) + +static DNSServiceErrorType RegisterService(DNSServiceRef *sdref, const char *nam, const char *typ, const char *dom, const char *host, const char *port, int argc, char **argv) { + DNSServiceFlags flags = 0; uint16_t PortAsNumber = atoi(port); Opaque16 registerPort = { { PortAsNumber >> 8, PortAsNumber & 0xFF } }; unsigned char txt[2048] = ""; @@ -547,34 +770,54 @@ static DNSServiceErrorType RegisterService(DNSServiceRef *sdRef, if (nam[0] == '.' && nam[1] == 0) nam = ""; // We allow '.' on the command line as a synonym for empty string if (dom[0] == '.' && dom[1] == 0) dom = ""; // We allow '.' on the command line as a synonym for empty string - for (i = 0; i < argc; i++) + printf("Registering Service %s.%s%s%s", nam[0] ? nam : "<>", typ, dom[0] ? "." : "", dom); + if (host && *host) printf(" host %s", host); + printf(" port %s", port); + + if (argc) { - unsigned char *len = ptr++; - *len = strlen(argv[i]); - strcpy((char*)ptr, argv[i]); - ptr += *len; + for (i = 0; i < argc; i++) + { + const char *p = argv[i]; + *ptr = 0; + while (*p && *ptr < 255 && ptr + 1 + *ptr < txt+sizeof(txt)) + { + if (p[0] != '\\' || p[1] == 0) { ptr[++*ptr] = *p; p+=1; } + else if (p[1] == 'x' && isxdigit(p[2]) && isxdigit(p[3])) { ptr[++*ptr] = HexPair(p+2); p+=4; } + else { ptr[++*ptr] = p[1]; p+=2; } + } + ptr += 1 + *ptr; + } + printf(" TXT"); + ShowTXTRecord(ptr-txt, txt); } + printf("\n"); - printf("Registering Service %s.%s%s", nam, typ, dom); - if (host && *host) printf(" host %s", host); - printf(" port %s %s\n", port, txt); - return(DNSServiceRegister(sdRef, /* kDNSServiceFlagsAllowRemoteQuery */ 0, opinterface, nam, typ, dom, host, registerPort.NotAnInteger, ptr-txt, txt, reg_reply, NULL)); + //flags |= kDNSServiceFlagsAllowRemoteQuery; + //flags |= kDNSServiceFlagsNoAutoRename; + + return(DNSServiceRegister(sdref, flags, opinterface, nam, typ, dom, host, registerPort.NotAnInteger, (uint16_t) (ptr-txt), txt, reg_reply, NULL)); } int main(int argc, char **argv) { -#ifdef _WIN32 - const char kFilePathSep = '\\'; -#else - const char kFilePathSep = '/'; -#endif DNSServiceErrorType err; char *dom; - int optind; - const char *progname = strrchr(argv[0], kFilePathSep) ? strrchr(argv[0], kFilePathSep) + 1 : argv[0]; -#ifndef NOT_HAVE_SETLINEBUF - setlinebuf(stdout); // Want to see lines as they appear, not block buffered -#endif + int optind; + + // Extract the program name from argv[0], which by convention contains the path to this executable. + // Note that this is just a voluntary convention, not enforced by the kernel -- + // the process calling exec() can pass bogus data in argv[0] if it chooses to. + const char *a0 = strrchr(argv[0], kFilePathSep) + 1; + if (a0 == (const char *)1) a0 = argv[0]; + + if (sizeof(argv) == 8) printf("Running in 64-bit mode\n"); + + // Test code for TXTRecord functions + //TXTRecordRef txtRecord; + //TXTRecordCreate(&txtRecord, 0, NULL); + //TXTRecordSetValue(&txtRecord, "aaa", 1, "b"); + //printf("%d\n", TXTRecordContainsKey(TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord), "Aaa")); if (argc > 1 && !strcmp(argv[1], "-lo")) { @@ -584,10 +827,28 @@ int main(int argc, char **argv) printf("Using LocalOnly\n"); } + if (argc > 2 && !strcmp(argv[1], "-i")) + { + opinterface = if_nametoindex(argv[2]); + if (!opinterface) opinterface = atoi(argv[2]); + if (!opinterface) { fprintf(stderr, "Unknown interface %s\n", argv[2]); goto Fail; } + argc -= 2; + argv += 2; + } + if (argc < 2) goto Fail; // Minimum command line is the command name and one argument - operation = getfirstoption( argc, argv, "EFBLQRPAUNTMI", &optind); + operation = getfirstoption(argc, argv, "EFBLRPQCAUNTMISV" + #if HAS_NAT_PMP_API + "X" + #endif + #if HAS_ADDRINFO_API + "G" + #endif + , &optind); if (operation == -1) goto Fail; + if (opinterface) printf("Using interface %d\n", opinterface); + switch (operation) { case 'E': printf("Looking for recommended registration domains:\n"); @@ -602,18 +863,22 @@ int main(int argc, char **argv) //enum_reply(client, kDNSServiceFlagsAdd, 0, 0, "dns-sd.ibm.com.", NULL); break; - case 'B': if (argc < optind+1) goto Fail; - dom = (argc < optind+2) ? "" : argv[optind+1]; + case 'B': { + char buffer[64], *typ; + typ = (argc < optind+1) ? "_http" : argv[optind+0]; // If no type argument, browse for advertised web pages + dom = (argc < optind+2) ? "" : argv[optind+1]; // Missing domain argument is the same as empty string i.e. use system default(s) if (dom[0] == '.' && dom[1] == 0) dom[0] = 0; // We allow '.' on the command line as a synonym for empty string - printf("Browsing for %s%s\n", argv[optind+0], dom); - err = DNSServiceBrowse(&client, 0, opinterface, argv[optind+0], dom, browse_reply, NULL); + if (!strchr(typ, '.')) { snprintf(buffer, sizeof(buffer), "%s._tcp", typ); typ = buffer; } + printf("Browsing for %s%s%s\n", typ, dom[0] ? "." : "", dom); + err = DNSServiceBrowse(&client, 0, opinterface, typ, dom, browse_reply, NULL); break; + } case 'L': if (argc < optind+2) goto Fail; dom = (argc < optind+3) ? "local" : argv[optind+2]; if (dom[0] == '.' && dom[1] == 0) dom = "local"; // We allow '.' on the command line as a synonym for "local" printf("Lookup %s.%s.%s\n", argv[optind+0], argv[optind+1], dom); - err = DNSServiceResolve(&client, 0, opinterface, argv[optind+0], argv[optind+1], dom, resolve_reply, NULL); + err = DNSServiceResolve(&client, 0, opinterface, argv[optind+0], argv[optind+1], dom, (DNSServiceResolveReply)resolve_reply, NULL); break; case 'R': if (argc < optind+4) goto Fail; @@ -621,14 +886,20 @@ int main(int argc, char **argv) break; case 'P': if (argc < optind+6) goto Fail; - err = RegisterProxyAddressRecord(&client2, argv[optind+4], argv[optind+5]); + err = DNSServiceCreateConnection(&client_pa); + if (err) { fprintf(stderr, "DNSServiceCreateConnection returned %d\n", err); return(err); } + err = RegisterProxyAddressRecord(client_pa, argv[optind+4], argv[optind+5]); + //err = RegisterProxyAddressRecord(client_pa, "two", argv[optind+5]); if (err) break; err = RegisterService(&client, argv[optind+0], argv[optind+1], argv[optind+2], argv[optind+4], argv[optind+3], argc-(optind+6), argv+(optind+6)); + //DNSServiceRemoveRecord(client_pa, record, 0); + //DNSServiceRemoveRecord(client_pa, record, 0); break; - case 'Q': { + case 'Q': + case 'C': { uint16_t rrtype, rrclass; - DNSServiceFlags flags = 0; + DNSServiceFlags flags = kDNSServiceFlagsReturnIntermediates; if (argc < optind+1) goto Fail; rrtype = (argc <= optind+1) ? kDNSServiceType_A : GetRRType(argv[optind+1]); rrclass = (argc <= optind+2) ? kDNSServiceClass_IN : atoi(argv[optind+2]); @@ -679,6 +950,63 @@ int main(int argc, char **argv) break; } +#if HAS_NAT_PMP_API + case 'X': { + if (argc == optind) // If no arguments, just fetch IP address + err = DNSServiceNATPortMappingCreate(&client, 0, 0, 0, 0, 0, 0, port_mapping_create_reply, NULL); + else if (argc >= optind+2 && atoi(argv[optind+0]) == 0) + { + DNSServiceProtocol prot = GetProtocol(argv[optind+0]); // Must specify TCP or UDP + uint16_t IntPortAsNumber = atoi(argv[optind+1]); // Must specify internal port + uint16_t ExtPortAsNumber = (argc < optind+3) ? 0 : atoi(argv[optind+2]); // Optional desired external port + uint32_t ttl = (argc < optind+4) ? 0 : atoi(argv[optind+3]); // Optional desired lease lifetime + Opaque16 intp = { { IntPortAsNumber >> 8, IntPortAsNumber & 0xFF } }; + Opaque16 extp = { { ExtPortAsNumber >> 8, ExtPortAsNumber & 0xFF } }; + err = DNSServiceNATPortMappingCreate(&client, 0, 0, prot, intp.NotAnInteger, extp.NotAnInteger, ttl, port_mapping_create_reply, NULL); + } + else goto Fail; + break; + } +#endif + +#if HAS_ADDRINFO_API + case 'G': { + if (argc != optind+2) goto Fail; + else err = DNSServiceGetAddrInfo(&client, kDNSServiceFlagsReturnIntermediates, opinterface, GetProtocol(argv[optind+0]), argv[optind+1], addrinfo_reply, NULL); + break; + } +#endif + + case 'S': { + Opaque16 registerPort = { { 0x23, 0x45 } }; + err = DNSServiceCreateConnection(&client); + if (err) { fprintf(stderr, "DNSServiceCreateConnection failed %ld\n", (long int)err); return (-1); } + + sc1 = client; + err = DNSServiceBrowse(&sc1, kDNSServiceFlagsShareConnection, opinterface, "_http._tcp", "", browse_reply, NULL); + if (err) { fprintf(stderr, "DNSServiceBrowse _http._tcp failed %ld\n", (long int)err); return (-1); } + + sc2 = client; + err = DNSServiceBrowse(&sc2, kDNSServiceFlagsShareConnection, opinterface, "_ftp._tcp", "", browse_reply, NULL); + if (err) { fprintf(stderr, "DNSServiceBrowse _ftp._tcp failed %ld\n", (long int)err); return (-1); } + + sc3 = client; + err = DNSServiceRegister(&sc3, kDNSServiceFlagsShareConnection, opinterface, "kDNSServiceFlagsShareConnection", + "_http._tcp", "local", NULL, registerPort.NotAnInteger, 0, NULL, reg_reply, NULL); + if (err) { fprintf(stderr, "SharedConnection DNSServiceRegister failed %ld\n", (long int)err); return (-1); } + + break; + } + + case 'V': { + uint32_t v; + uint32_t size = sizeof(v); + err = DNSServiceGetProperty(kDNSServiceProperty_DaemonVersion, &v, &size); + if (err) fprintf(stderr, "DNSServiceGetProperty failed %ld\n", (long int)err); + else printf("Currently running daemon (system service) is version %d.%d\n", v / 10000, v / 100 % 100); + exit(0); + } + default: goto Fail; } @@ -686,23 +1014,46 @@ int main(int argc, char **argv) HandleEvents(); // Be sure to deallocate the DNSServiceRef when you're finished - if (client ) DNSServiceRefDeallocate(client ); - if (client2) DNSServiceRefDeallocate(client2); + if (client ) DNSServiceRefDeallocate(client ); + if (client_pa) DNSServiceRefDeallocate(client_pa); return 0; Fail: - fprintf(stderr, "%s -E (Enumerate recommended registration domains)\n", progname); - fprintf(stderr, "%s -F (Enumerate recommended browsing domains)\n", progname); - fprintf(stderr, "%s -B (Browse for services instances)\n", progname); - fprintf(stderr, "%s -L (Look up a service instance)\n", progname); - fprintf(stderr, "%s -R [...] (Register a service)\n", progname); - fprintf(stderr, "%s -P [...] (Proxy)\n", progname); - fprintf(stderr, "%s -Q (Generic query for any record type)\n", progname); - fprintf(stderr, "%s -A (Test Adding/Updating/Deleting a record)\n", progname); - fprintf(stderr, "%s -U (Test updating a TXT record)\n", progname); - fprintf(stderr, "%s -N (Test adding a large NULL record)\n", progname); - fprintf(stderr, "%s -T (Test creating a large TXT record)\n", progname); - fprintf(stderr, "%s -M (Test creating a registration with multiple TXT records)\n", progname); - fprintf(stderr, "%s -I (Test registering and then immediately updating TXT record)\n", progname); + fprintf(stderr, "%s -E (Enumerate recommended registration domains)\n", a0); + fprintf(stderr, "%s -F (Enumerate recommended browsing domains)\n", a0); + fprintf(stderr, "%s -B (Browse for services instances)\n", a0); + fprintf(stderr, "%s -L (Look up a service instance)\n", a0); + fprintf(stderr, "%s -R [...] (Register a service)\n", a0); + fprintf(stderr, "%s -P [...] (Proxy)\n", a0); + fprintf(stderr, "%s -Q (Generic query for any record type)\n", a0); + fprintf(stderr, "%s -C (Query; reconfirming each result)\n", a0); +#if HAS_NAT_PMP_API + fprintf(stderr, "%s -X udp/tcp/udptcp (NAT Port Mapping)\n", a0); +#endif +#if HAS_ADDRINFO_API + fprintf(stderr, "%s -G v4/v6/v4v6 (Get address information for hostname)\n", a0); +#endif + fprintf(stderr, "%s -A (Test Adding/Updating/Deleting a record)\n", a0); + fprintf(stderr, "%s -U (Test updating a TXT record)\n", a0); + fprintf(stderr, "%s -N (Test adding a large NULL record)\n", a0); + fprintf(stderr, "%s -T (Test creating a large TXT record)\n", a0); + fprintf(stderr, "%s -M (Test creating a registration with multiple TXT records)\n", a0); + fprintf(stderr, "%s -I (Test registering and then immediately updating TXT record)\n", a0); + fprintf(stderr, "%s -S (Test multiple operations on a shared socket)\n", a0); + fprintf(stderr, "%s -V (Get version of currently running daemon / system service)\n", a0); return 0; } + +// 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[] = "@(#) dns-sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")"; + +// 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"); diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f458904 --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +The majority of the source code in the mDNSResponder project is licensed +under the terms of the Apache License, Version 2.0, available from: + + +To accommodate license compatibility with the widest possible range +of client code licenses, the shared library code, which is linked +at runtime into the same address space as the client using it, is +licensed under the terms of the "Three-Clause BSD License". + +The Linux Name Service Switch code, contributed by National ICT +Australia Ltd (NICTA) is licensed under the terms of the NICTA Public +Software Licence (which is substantially similar to the "Three-Clause +BSD License", with some additional language pertaining to Australian law). diff --git a/Makefile b/Makefile index 1239e65..f19fe5a 100644 --- a/Makefile +++ b/Makefile @@ -16,13 +16,23 @@ include /Developer/Makefiles/pb_makefiles/platform.make -MVERS = "mDNSResponder-108.6" +MVERS = "mDNSResponder-161.1" + +DDNSWRITECONFIG = "$(DSTROOT)/Library/Application Support/Bonjour/ddnswriteconfig" + +installSome: + cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target Build\ Some + +SystemLibraries: + cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target SystemLibraries install: - cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) + cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) + # 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} + ditto . "$(SRCROOT)" installhdrs:: cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild installhdrs OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) diff --git a/PrivateDNS.txt b/PrivateDNS.txt new file mode 100644 index 0000000..8d62907 --- /dev/null +++ b/PrivateDNS.txt @@ -0,0 +1,275 @@ +Private DNS + +Summary + +Private DNS is an extension to standard Wide Area Bonjour that allows +for secure, encrypted, and authorized communications. Private data sent +from a client to a DNS server is encrypted using Transport Layer +Security (TLS), ensuring that the data is hidden from prying eyes, and +contains Transaction Signatures (TSIG), so the server can authorize the +request. TSIGs are typically associated with Dynamic Updates; we are +using them for standard and long-lived queries as well. Private DNS also +protects Dynamic Updates from eavesdropping, by wrapping the update in a +TLS communication channel if the server has been configured appropriately. + +Architectural Overview + +mDNSResponder has been modified to automatically issue a private query +when necessary. After receiving an NXDOMAIN error, mDNSResponder checks +in the system keychain to see if the user has a DNS query key (TSIG key) +for the name in question, or for a parent of that name. If a suitable +key is found, mDNSResponder looks up the zone data associated with the +name of the question. After determining the correct name server, +mDNSResponder looks up an additional SRV record "_dns-private._tcp". If +it finds this record, mDNSResponder will re-issue the query privately. +If either there is no _dns-private._tcp record, or there is no secret +key, the call fails as it initially did, with an NXDOMAIN error. + +Once the secret key is found and the SRV record is looked up, mDNSResponder +opens a TLS connection to the server on the port specified in the SRV +record just looked up. After the connection succeeds, mDNSResponder +can proceed to use that communication channel to make requests of +the server. Every private packet must also have a TSIG record; +the DNS server uses this TSIG record to allow access to its data. + +When setting up a long-lived query over TCP (with or without TLS) +TCP's standard three-way handshake makes the full four-packet LLQ setup +exchange described in +unnecessary. Instead, when connecting over TCP, the client simply sends +a setup message and expects to receive ACK + Answers. The setup message +sent is formatted as described in the LLQ document, however there is +an additional TSIG' resource record added to the end of it. The TSIG +resource records looks and acts exactly as it does in a secure update. +So when the server receives an LLQ (or a standard query), it looks to +see if the zone that is being referenced is public or private. If it's +private, then it makes sure that the client is authorized to query that +zone (by using the TSIG signature) and returns the appropriate data. +When a zone is configured as private, the server will do this type of +authorization checking for every query except those queries that are +looking for SOA and NS records. + +Implementation Issues + +dnsextd + +dnsextd has been modified to behave much like a DNS firewall. The "real" +DNS server is configured to listen on non-standard ports on the loopback +interface. dnsextd then listens on the standard DNS ports (TCP/UDP port +53) and intercepts all DNS traffic. It is responsible for determining +what zone a DNS request is associated with, determining whether the +client is allowed access to that zone, and returning the appropriate +information back to the caller. If the packet is allowed access, dnsextd +forwards the request to the "real" nameserver, and returns the result to +the caller. + +It was tempting to use BIND9's facility for configuring TSIG enabled +queries while doing this work. However after proceeding down that path, +enough subtle interaction problems were found that it was not practical +to pursue this direction, so instead dnsextd does all TSIG processing +for queries itself. It does continue to use BIND9 for processing TSIG +enabled dynamic updates, though one minor downside with this is that +there are two configuration files (named.conf or dnsextd.conf) that have +the same secret key information. That seems redundant and error-prone, +and moving all TSIG processing for both queries and updates into dnsextd +would fix this. + +All private LLQ operations are TSIG-enabled and sent over a secure +encrypted TLS channel. To accommodate service providers who don't want +to have to keep open a large number of TLS connections to a large number +of client machines, the server has the option of dropping the TSL +connection after initial LLQ setup and sending subsequent events and +refreshes using unencrypted UDP packets. This results in less load on +the server, at the cost of slightly lower security (LLQs can only be set +up by an authorized client, but once set up, subsequent change event +packets sent over unencrypted UDP could be observed by an eavesdropper). +A potential solution to this deficiency might be in using DTLS, which is +a protocol based on TLS that is capable of securing datagram traffic. +More investigation needs to be done to see if DTLS is suitable for +private DNS. + +It was necessary to relax one of the checks that dnsextd performs during +processing of an LLQ refresh. Prior to these changes, dnsextd would +verify that the refresh request came from the same entity that setup the +LLQ by comparing both the IP Address and port number of the request +packet with the IP Address and port number of the setup packet. Because +of the preceding issue, a refresh request might be sent over two +different sockets. While their IP addresses would be the same, their +port numbers could potentially differ. This check has been modified to +only check that the IP addresses match. + +When setting up a semi-private LLQ (where the request and initial answer +set is sent over TLS/TCP, but subsequent change events are sent over +unencrypted UDP), dnsextd uses the port number of the client's TCP +socket to determine the UDP event port number. While this eliminates the +need to pass the UDP event port number in the LLQ setup request +(obviating a potential data mismatch error), I think it does more harm +than good, for three reasons: + +1) We are relying that all the routers out there implement the Port + Mapping Protocol spec correctly. + +2) Upon setup every LLQ must NAT map two ports. Upon tear down every LLQ + must tear down two NAT mappings. + +3) Every LLQ opens up two sockets (TCP and UDP), rather than just the + one TCP socket. + +All of this just to avoid sending two bytes in the LLQ setup packet +doesn't seem logical. The approach also necessitates creating an +additional UDP socket for every private LLQ, port mapping both the TCP +socket as well as the UDP socket, and moderately increasing the +complexity and efficiency of the code. Because of this we plan to allow +the LLQ setup packet to specify a different UDP port for change event +packets. This will allow mDNSResponder to receive all UDP change event +packets on a single UDP port, instead of a different one for each LLQ. + +Currently, dnsextd is buggy on multi-homed hosts. If it receives a +packet on interface 2, it will reply on interface 1 causing an error in +the client program. + +dnsextd doesn't fully process all of its option parameters. +Specifically, it doesn't process the keywords: "listen-on", +"nameserver", "private", and "llq". It defaults to expecting the "real" +nameserver to be listening on 127.0.0.1:5030. + + +mDNSResponder + +Currently, mDNSResponder attempts to issue private queries for all +queries that initially result in an NXDOMAIN error. This behavior might +be modified in future versions, however it seems patently incorrect to +do this for reverse name lookups. The code that attempts to get the zone +data associated with the name will never find the zone for a reverse +name lookup, and so will issue a number of wasteful DNS queries. + +mDNSResponder doesn't handle SERV_FULL or STATIC return codes after +setting up an LLQ over TCP. This isn't a terrible problem right now, +because dnsextd doesn't ever return them, but this should be fixed so +that mDNSResponder will work when talking to other servers that do +return these error codes. + + +Configuration: + +Sample named.conf: + +// +// Include keys file +// +include "/etc/rndc.key"; +// Declares control channels to be used by the rndc utility. +// +// It is recommended that 127.0.0.1 be the only address used. +// This also allows non-privileged users on the local host to manage +// your name server. + +// +// Default controls +// +controls + { + inet 127.0.0.1 port 54 allow { any; } keys { "rndc-key"; }; + }; + +options + { + directory "/var/named"; + /* + * If there is a firewall between you and nameservers you want + * to talk to, you might need to uncomment the query-source + * directive below. Previous versions of BIND always asked + * questions using port 53, but BIND 8.1 uses an unprivileged + * port by default. + */ + + forwarders + { + 65.23.128.2; + 65.23.128.3; + }; + + listen-on port 5030 { 127.0.0.1; }; + recursion true; + }; + +// +// a caching only nameserver config +// +zone "." IN + { + type hint; + file "named.ca"; + }; + +zone "localhost" IN + { + type master; + file "localhost.zone"; + allow-update { none; }; + }; + +zone "0.0.127.in-addr.arpa" IN + { + type master; + file "named.local"; + allow-update { none; }; + }; + +zone "hungrywolf.org." in + { + type master; + file "db.hungrywolf.org"; + allow-update { key hungrywolf.org.; }; + }; + +zone "157.23.65.in-addr.arpa" IN + { + file "db.65.23.157"; + type master; + }; + +zone "100.255.17.in-addr.arpa" IN + { + file "db.17.255.100"; + type master; + }; + +zone "66.6.24.in-addr.arpa" IN + { + file "db.24.6.66"; + type master; + }; + +key hungrywolf.org. + { + algorithm hmac-md5; + secret "c8LWr16K6ju6KMO5zT6Tyg=="; + }; + +logging + { + category default { _default_log; }; + + channel _default_log + { + file "/Library/Logs/named.log"; + severity info; + print-time yes; + }; + }; + + +Sample dnsextd.conf: + +options { }; + +key "hungrywolf.org." + { + secret "c8LWr16K6ju6KMO5zT6Tyg=="; + }; + +zone "hungrywolf.org." + { + type private; + allow-query { key hungrywolf.org.; }; + }; diff --git a/mDNSCore/DNSCommon.c b/mDNSCore/DNSCommon.c index e16b4ae..2b4356d 100644 --- a/mDNSCore/DNSCommon.c +++ b/mDNSCore/DNSCommon.c @@ -2,347 +2,331 @@ * * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: DNSCommon.c,v $ -Revision 1.96.2.1 2006/10/31 02:50:16 cheshire - mDNSResponder insufficiently defensive against malformed browsing PTR responses +Revision 1.184 2007/10/05 17:56:07 cheshire +Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files -Revision 1.96 2006/03/10 21:51:42 cheshire - After record update, old record sometimes remains in cache -Split out SameRDataBody() into a separate routine so it can be called from other code +Revision 1.183 2007/10/02 18:33:46 cheshire +Improved GetRRDisplayString to show all constituent strings within a text record +(up to the usual MaxMsg 120-character limit) -Revision 1.95 2006/03/08 22:43:11 cheshire -Use "localdomain" symbol instead of literal string +Revision 1.182 2007/10/01 19:45:01 cheshire + BTMM: Sometimes Back to My Mac autotunnel registrations are malformed -Revision 1.94 2006/03/02 21:59:55 cheshire - Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use" -Improve sanity checks & debugging support in GetLargeResourceRecord() +Revision 1.181 2007/10/01 18:36:53 cheshire +Yet another fix to finally get the DumpPacket RCODE display right -Revision 1.93 2006/03/02 20:30:47 cheshire -Improved GetRRDisplayString to also show priority, weight, and port for SRV records - -Revision 1.92 2005/09/16 21:06:49 cheshire -Use mDNS_TimeNow_NoLock macro, instead of writing "mDNSPlatformRawTime() + m->timenow_adjust" all over the place - -Revision 1.91 2005/07/10 22:10:37 cheshire -The getOptRdata routine implicitly assumes the destination ResourceRecord is large enough to -hold MaximumRDSize bytes, but its parameter was a generic ResourceRecord, which need not be that -large. Changing the parameter to a LargeCacheRecord makes it clearer what the routine requires. +Revision 1.180 2007/09/29 21:30:38 cheshire +In DumpPacket/DumpRecords, show an error line if we run out of packet data -Revision 1.90 2005/03/21 00:33:51 shersche - Fix build warnings on Win32 platform +Revision 1.179 2007/09/29 20:44:56 cheshire +Fix error in DumpPacket where it was not displaying the RCODE field properly -Revision 1.89 2005/03/17 18:59:38 ksekar - Properly parse multiple LLQ Options per packet on Windows +Revision 1.178 2007/09/27 21:11:44 cheshire +Fixed spelling mistake: ROCDE -> RCODE -Revision 1.88 2005/03/16 00:42:32 ksekar - Long-lived queries not working on Windows +Revision 1.177 2007/09/27 18:51:26 cheshire +Improved DumpPacket to use "Zone/Prerequisites/Updates" nomenclature when displaying a DNS Update packet -Revision 1.87 2005/02/25 04:21:00 cheshire - mDNS -F returns the same domain multiple times with different casing +Revision 1.176 2007/09/27 17:53:37 cheshire +Add display of RCODE and flags in DumpPacket output -Revision 1.86 2005/02/18 00:43:12 cheshire - mDNSResponder should auto-truncate service names that are too long +Revision 1.175 2007/09/26 22:26:40 cheshire +Also show DNS query/response ID in DumpPacket output -Revision 1.85 2005/02/10 22:35:17 cheshire - Update name +Revision 1.174 2007/09/26 16:36:02 cheshire +In DumpPacket output, begin header line with "-- " to make it visually stand out better -Revision 1.84 2005/02/03 00:44:38 cheshire - DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL +Revision 1.173 2007/09/26 00:49:46 cheshire +Improve packet logging to show sent and received packets, +transport protocol (UDP/TCP/TLS) and source/destination address:port -Revision 1.83 2005/01/27 22:57:55 cheshire -Fix compile errors on gcc4 +Revision 1.172 2007/09/21 23:14:39 cheshire + BTMM: Need to log updates and query packet contents in verbose debug mode +Changed DumpRecords to use LargeCacheRecord on the stack instead of the shared m->rec storage, +to eliminate "GetLargeResourceRecord: m->rec appears to be already in use" warnings -Revision 1.82 2005/01/19 03:27:03 cheshire - CPU Spin in mDNSResponder -GetNextScheduledEvent() needs to check LocalRecordReady() +Revision 1.171 2007/09/21 21:12:36 cheshire + BTMM: Need to log updates and query packet contents -Revision 1.81 2004/12/18 03:13:45 cheshire - kDNSServiceInterfaceIndexLocalOnly should return all local records +Revision 1.170 2007/09/07 21:16:58 cheshire +Add new symbol "NATPMPAnnouncementPort" (5350) -Revision 1.80 2004/12/16 21:46:43 cheshire -Add DNSTypeName case for kDNSType_SOA +Revision 1.169 2007/08/30 00:31:20 cheshire +Improve "locking failure" debugging messages to show function name using __func__ macro -Revision 1.79 2004/12/16 21:38:37 cheshire -Add DNSTypeName case for kDNSType_NS +Revision 1.168 2007/08/28 23:58:42 cheshire +Rename HostTarget -> AutoTarget -Revision 1.78 2004/12/16 21:27:37 ksekar -Fixed build failures when compiled with verbose debugging messages +Revision 1.167 2007/08/10 23:10:05 vazquez + mDNS: Reverse lookups of IPv6 link-local addresses always fail -Revision 1.77 2004/12/16 20:12:59 cheshire - Cache memory management improvements +Revision 1.166 2007/08/01 16:09:13 cheshire +Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly -Revision 1.76 2004/12/16 08:05:29 shersche -Remove extranenous semicolons that cause compilation errors on Windows +Revision 1.165 2007/08/01 00:04:13 cheshire + Crash in tcpKQSocketCallback +Half-open TCP connections were not being cancelled properly -Revision 1.75 2004/12/15 02:11:22 ksekar - Don't check for Dynamic DNS hostname uniqueness +Revision 1.164 2007/07/27 20:48:43 cheshire +In DumpRecords(), include record TTL in output -Revision 1.74 2004/12/09 22:49:15 ksekar - Wide-Area Goodbyes broken +Revision 1.163 2007/07/16 20:10:11 vazquez + LegacyNATTraversal: Need complete rewrite +Added SSDP port number -Revision 1.73 2004/12/07 22:49:06 cheshire - BIND doesn't allow zero-length TXT records +Revision 1.162 2007/07/10 01:59:33 cheshire + Performance: Core code will not work on platforms with small stacks +Fixed GetPktLease to use shared m->rec instead of putting LargeCacheRecord on the stack -Revision 1.72 2004/12/06 21:15:20 ksekar - mDNSResponder crashed in CheckServiceRegistrations +Revision 1.161 2007/07/06 18:56:26 cheshire +Check m->NextScheduledNATOp in GetNextScheduledEvent() -Revision 1.71 2004/12/04 02:12:45 cheshire - mDNSResponder puts LargeCacheRecord on the stack +Revision 1.160 2007/06/29 00:06:42 vazquez + Clean up NAT state machine (necessary for 6 other fixes) -Revision 1.70 2004/12/03 19:52:44 ksekar -Use PutResourceRecordTTLJumbo for putDeletionRecord() +Revision 1.159 2007/06/28 21:17:17 cheshire +Rename "m->nextevent" as more informative "m->NextuDNSEvent" -Revision 1.69 2004/12/03 07:20:50 ksekar - Wide-Area: Registration of large TXT record fails +Revision 1.158 2007/05/25 00:25:43 cheshire + Need to enhance putRData to output all current known types -Revision 1.68 2004/11/24 00:10:43 cheshire - For unicast operations, verify that service types are legal +Revision 1.157 2007/05/23 00:32:15 cheshire +Don't treat uDNS responses as an entire RRSet (kDNSRecordTypePacketUniqueMask) +when received in a truncated UDP response -Revision 1.67 2004/10/26 03:52:02 cheshire -Update checkin comments +Revision 1.156 2007/05/15 00:29:00 cheshire +Print «ZERO ADDRESS» for %#a with a zero mDNSAddr -Revision 1.66 2004/10/23 01:16:00 cheshire - uDNS operations not always reliable on multi-homed hosts +Revision 1.155 2007/05/07 22:07:47 cheshire + Enhance GetLargeResourceRecord to decompress more record types -Revision 1.65 2004/10/20 02:15:09 cheshire -Add case in GetRRDisplayString() to display NS rdata +Revision 1.154 2007/05/04 20:19:53 cheshire +Improve DumpPacket() output -Revision 1.64 2004/10/13 00:24:02 cheshire -Disable "array is too small to include a terminating null character" warning on Windows +Revision 1.153 2007/05/01 21:46:31 cheshire +Move GetLLQOptData/GetPktLease from uDNS.c into DNSCommon.c so that dnsextd can use them -Revision 1.63 2004/10/10 06:57:14 cheshire -Change definition of "localdomain" to make code compile a little smaller +Revision 1.152 2007/04/27 19:28:01 cheshire +Any code that calls StartGetZoneData needs to keep a handle to the structure, so +it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop +-- it would start a query and then quickly cancel it, and then when +StartGetZoneData completed, it had a dangling pointer and crashed.) -Revision 1.62 2004/10/06 01:44:19 cheshire - Resolving too quickly sometimes returns stale TXT record +Revision 1.151 2007/04/26 13:35:25 cheshire +Add kDNSType_SOA case in SameRDataBody, and a comment in GetLargeResourceRecord about why this is important -Revision 1.61 2004/09/30 00:24:56 ksekar - Dynamically update default registration domains on config change +Revision 1.150 2007/04/24 00:17:33 cheshire +Made LocateLLQOptData guard against packets with bogus numAdditionals value -Revision 1.60 2004/09/27 23:25:30 cheshire -Fix compiler warning: soa.serial is signed, not unsigned +Revision 1.149 2007/04/23 21:43:00 cheshire +Remove debugging check -Revision 1.59 2004/09/27 22:53:45 ksekar -Fixed getLargeResourceRecord for SOA rdata. +Revision 1.148 2007/04/23 04:55:29 cheshire +Add some defensive null pointer checks -Revision 1.58 2004/09/25 02:41:39 cheshire - Deliver near-pending "remove" events before new "add" events +Revision 1.147 2007/04/22 20:18:10 cheshire +Add comment about mDNSRandom() -Revision 1.57 2004/09/25 02:24:27 cheshire -Removed unused rr->UseCount +Revision 1.146 2007/04/22 06:02:02 cheshire + Query should immediately return failure when no server -Revision 1.56 2004/09/24 20:57:39 cheshire - Eliminate inappropriate casts that cause misaligned-address errors +Revision 1.145 2007/04/20 21:17:24 cheshire +For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative -Revision 1.55 2004/09/17 01:08:48 cheshire -Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h - The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces - declared in that file are ONLY appropriate to single-address-space embedded applications. - For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used. +Revision 1.144 2007/04/19 18:02:43 cheshire + Unicast DNS response records should tagged with kDNSRecordTypePacketUnique bit -Revision 1.54 2004/09/17 00:49:51 cheshire -Get rid of now-unused GetResourceRecord -- the correct (safe) routine to use -is GetLargeResourceRecord +Revision 1.143 2007/04/16 21:53:49 cheshire +Improve display of negative cache entries -Revision 1.53 2004/09/17 00:31:51 cheshire -For consistency with ipv6, renamed rdata field 'ip' to 'ipv4' +Revision 1.142 2007/04/05 22:55:35 cheshire + Records are ending up in Lighthouse without expiry information -Revision 1.52 2004/09/17 00:19:10 cheshire -For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4 +Revision 1.141 2007/04/04 01:33:11 cheshire + DNSServiceAddRecord is failing to advertise NULL record +Overly defensive code was zeroing too much of the AuthRecord structure -Revision 1.51 2004/09/16 02:29:39 cheshire -Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around -uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService - -Revision 1.50 2004/09/16 01:58:14 cheshire -Fix compiler warnings +Revision 1.140 2007/04/03 19:37:58 cheshire +Rename mDNSAddrIsv4Private() to more precise mDNSAddrIsRFC1918() -Revision 1.49 2004/09/14 23:42:35 cheshire - Need to seed random number generator from platform-layer data +Revision 1.139 2007/04/03 19:18:39 cheshire +Use mDNSSameIPv4Address (and similar) instead of accessing internal fields directly -Revision 1.48 2004/09/14 23:27:46 cheshire -Fix compile errors +Revision 1.138 2007/03/28 21:14:08 cheshire +The rrclass field of an OPT pseudo-RR holds the sender's UDP payload size -Revision 1.47 2004/08/25 02:50:04 cheshire - Browses are no longer piggybacking on other browses -Make mDNSSameAddress() recognise that two mDNSAddrType_None addresses are necessarily equal +Revision 1.137 2007/03/28 20:59:26 cheshire + Remove inappropriate use of IsPrivateV4Addr() -Revision 1.46 2004/08/18 17:35:40 ksekar -: Feature #9586: Need support for Legacy NAT gateways +Revision 1.136 2007/03/28 15:56:37 cheshire + Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output -Revision 1.45 2004/08/15 18:26:00 cheshire -Don't use strcpy() on "struct domainname" objects; use AssignDomainName() instead -(A "struct domainname" is a collection of packed pascal strings, not a C string.) +Revision 1.135 2007/03/28 01:20:05 cheshire + Improve/create logging for secure browse -Revision 1.44 2004/08/13 23:46:58 cheshire -"asyncronous" -> "asynchronous" +Revision 1.134 2007/03/27 23:25:35 cheshire +Fix error caching SOA records +(cache entry was size of wire-format packed data, not size of in-memory structure) -Revision 1.43 2004/08/12 02:55:46 ksekar -Fix param order error moving putPrereqNameNotInUse from uDNS.c using -ustrcpy macro to DNSCommon.c using mDNSPlatformStrCopy(). +Revision 1.133 2007/03/26 22:55:45 cheshire +Add OPT and TSIG to list of types DNSTypeName() knows about -Revision 1.42 2004/08/10 23:19:14 ksekar -: DNS Extension daemon for Wide Area Service Discovery -Moved routines/constants to allow extern access for garbage collection daemon +Revision 1.132 2007/03/22 18:31:48 cheshire +Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy -Revision 1.41 2004/08/10 01:10:01 cheshire - Current method of doing subtypes causes name collisions -Minor revision from Roger Pantos +Revision 1.131 2007/03/21 21:55:20 cheshire + Hostname gets ; or : which are illegal characters +Error in AppendLabelSuffix() for numbers close to the 32-bit limit -Revision 1.40 2004/08/04 22:10:46 cheshire - Current method of doing subtypes causes name collisions -Change to use "._sub." instead of ".s." to mark subtypes. +Revision 1.130 2007/03/21 19:23:37 cheshire + jmDNS advertised garbage that shows up weird in Safari +Make check less strict so we don't break Bonjour Browser -Revision 1.39 2004/07/13 21:24:24 rpantos -Fix for . +Revision 1.129 2007/03/21 01:00:45 cheshire + jmDNS advertised garbage that shows up weird in Safari +DeconstructServiceName() needs to be more defensive about what it considers legal -Revision 1.38 2004/06/18 21:08:58 cheshire - Applications are registering invalid records -Attempts to create domain names like "www..apple.com." now logged to aid debugging +Revision 1.128 2007/03/21 00:30:02 cheshire + Multiple errors in DNameList-related code -Revision 1.37 2004/06/18 20:25:42 cheshire - Add a syslog message if someone tries to use "local.arpa". +Revision 1.127 2007/03/20 17:07:15 cheshire +Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket" -Revision 1.36 2004/06/18 19:09:59 cheshire - Current method of doing subtypes causes name collisions +Revision 1.126 2007/03/10 03:26:44 cheshire + uDNS: LLQ refresh response packet causes cached records to be removed from cache -Revision 1.35 2004/06/05 00:14:44 cheshire -Fix signed/unsigned and other compiler warnings +Revision 1.125 2007/03/07 00:08:58 cheshire + Don't allow hyphens at start of service type -Revision 1.34 2004/06/04 00:25:25 cheshire -Fix misaligned write exception that occurs on some platforms +Revision 1.124 2007/01/19 18:04:05 cheshire +For naming consistency, use capital letters for RR types: rdataOpt should be rdataOPT -Revision 1.33 2004/06/04 00:16:18 cheshire -Remove non-portable use of 'inline' +Revision 1.123 2007/01/10 22:45:51 cheshire +Cast static strings to "(const domainname*)", not "(domainname*)" -Revision 1.32 2004/06/03 03:09:58 ksekar -: Garbage Collection for Dynamic Updates +Revision 1.122 2007/01/06 00:47:35 cheshire +Improve GetRRDisplayString to indicate when record has zero-length rdata -Revision 1.31 2004/05/28 23:42:36 ksekar -: Feature: DNS server->client notification on record changes (#7805) +Revision 1.121 2007/01/05 08:30:39 cheshire +Trim excessive "$Log" checkin history from before 2006 +(checkin history still available via "cvs log ..." of course) -Revision 1.30 2004/05/26 09:08:04 bradley -Added cast to correct structure pointer when allocating domain name list element to fix C++ builds. +Revision 1.120 2007/01/05 05:23:00 cheshire +Zero DNSQuestion structure in getQuestion (specifically, need TargetQID to be zero'd) -Revision 1.29 2004/05/18 23:51:25 cheshire -Tidy up all checkin comments to use consistent "" format for bug numbers +Revision 1.119 2007/01/05 04:30:16 cheshire +Change a couple of "(domainname *)" casts to "(const domainname *)" -Revision 1.28 2004/05/13 04:54:20 ksekar -Unified list copy/free code. Added symetric list for +Revision 1.118 2007/01/04 20:21:59 cheshire + uDNS: Need to start caching unicast records +Don't return multicast answers in response to unicast questions -Revision 1.27 2004/04/22 20:29:07 cheshire -Log error message if no count field passed to PutResourceRecordTTL() +Revision 1.117 2006/12/22 20:59:49 cheshire + Read *all* DNS keys from keychain, + not just key for the system-wide default registration domain -Revision 1.26 2004/04/22 04:07:01 cheshire -Fix from Bob Bradley: Don't try to do inline functions on compilers that don't support it +Revision 1.116 2006/12/21 00:04:07 cheshire +To be defensive, put a mDNSPlatformMemZero() at the start of mDNS_SetupResourceRecord() -Revision 1.25 2004/04/22 03:05:28 cheshire -kDNSClass_ANY should be kDNSQClass_ANY +Revision 1.115 2006/12/20 04:07:34 cheshire +Remove uDNS_info substructure from AuthRecord_struct -Revision 1.24 2004/04/22 02:51:20 cheshire -Use common code for HINFO/TXT and TSIG cases in putRData - -Revision 1.23 2004/04/15 00:51:28 bradley -Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers. -Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers. - -Revision 1.22 2004/04/14 23:09:28 ksekar -Support for TSIG signed dynamic updates. +Revision 1.114 2006/12/19 22:40:04 cheshire +Fix compiler warnings -Revision 1.21 2004/04/09 16:47:28 cheshire -: mDNSResponder escape handling inconsistent with BIND +Revision 1.113 2006/12/19 02:21:08 cheshire +Delete spurious spaces -Revision 1.20 2004/04/09 16:37:15 cheshire -Suggestion from Bob Bradley: -Move NumCacheRecordsForInterfaceID() to DNSCommon.c so it's available to all platform layers +Revision 1.112 2006/12/15 20:42:10 cheshire + ValidateRData() should be stricter about malformed MX and SRV records +Additional defensive coding in GetLargeResourceRecord() to reject apparently-valid +rdata that actually runs past the end of the received packet data. -Revision 1.19 2004/04/02 19:34:38 cheshire -Fix broken comment +Revision 1.111 2006/12/15 19:09:57 cheshire + ValidateRData() should be stricter about malformed MX and SRV records +Made DomainNameLength() more defensive by adding a limit parameter, so it can be +safely used to inspect potentially malformed data received from external sources. +Without this, a domain name that starts off apparently valid, but extends beyond the end of +the received packet data, could have appeared valid if the random bytes are already in memory +beyond the end of the packet just happened to have reasonable values (e.g. all zeroes). -Revision 1.18 2004/03/30 06:45:00 cheshire -Compiler warning fixes from Don Woodward at Roku Labs +Revision 1.110 2006/11/18 05:01:30 cheshire +Preliminary support for unifying the uDNS and mDNS code, +including caching of uDNS answers -Revision 1.17 2004/03/19 22:25:20 cheshire -: Need to limit service types to fourteen characters -Won't actually do this for now, but keep the code around just in case +Revision 1.109 2006/11/10 00:54:14 cheshire + Changing case of Computer Name doesn't work -Revision 1.16 2004/03/08 02:45:35 cheshire -Minor change to make a couple of the log messages a bit shorter +Revision 1.108 2006/10/05 23:11:18 cheshire + ValidateRData() should be stricter about malformed MX and SRV records -Revision 1.15 2004/03/08 02:44:09 cheshire -: Need to limit service types to fourteen characters +Revision 1.107 2006/09/15 21:20:14 cheshire +Remove uDNS_info substructure from mDNS_struct -Revision 1.14 2004/02/21 02:06:24 cheshire -Can't use anonymous unions -- they're non-standard and don't work on all compilers +Revision 1.106 2006/08/14 23:24:22 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 -Revision 1.13 2004/02/06 23:04:18 ksekar -Basic Dynamic Update support via mDNS_Register (dissabled via -UNICAST_REGISTRATION #define) +Revision 1.105 2006/07/15 02:01:28 cheshire + Add Private DNS client functionality to mDNSResponder +Fix broken "empty string" browsing -Revision 1.12 2004/02/03 22:37:10 cheshire -Delete unused (commented-out) code +Revision 1.104 2006/07/05 23:09:13 cheshire + Add Private DNS client functionality to mDNSResponder +Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int" -Revision 1.11 2004/02/03 22:35:34 cheshire -: Should not allow empty string for resolve domain +Revision 1.103 2006/06/29 07:42:14 cheshire + Performance: Remove unnecessary SameDomainName() checks -Revision 1.10 2004/02/03 19:47:36 ksekar -Added an asynchronous state machine mechanism to uDNS.c, including -calls to find the parent zone for a domain name. Changes include code -in repository previously dissabled via "#if 0 incomplete". Codepath -is currently unused, and will be called to create update records, etc. +Revision 1.102 2006/06/22 19:49:11 cheshire +Added (commented out) definitions for the LLMNR UDP port and multicast addresses -Revision 1.9 2004/01/27 20:15:22 cheshire -: Time to prune obsolete code for listening on port 53 +Revision 1.101 2006/06/15 21:35:15 cheshire +Move definitions of mDNS_vsnprintf, mDNS_SetupResourceRecord, and some constants +from mDNS.c to DNSCommon.c, so they can be accessed from dnsextd code -Revision 1.8 2004/01/24 23:24:36 cheshire -Expanded out the list of local domains to reduce risk of mistakes in future +Revision 1.100 2006/06/08 22:58:46 cheshire + IPv6 link-local address prefix is FE80::/10, not FE80::/16 -Revision 1.7 2004/01/24 08:32:30 bradley -Mask values with 0xFF before casting to avoid runtime truncation errors on Windows debug builds. -Separated octal-escaped sequences preceding decimal digits to avoid errors with some compilers wanting -to signal potentially hidden errors about the subsequent digit not being part of the octal sequence. +Revision 1.99 2006/05/18 01:32:33 cheshire + iChat: Lost connection with Bonjour +(mDNSResponder insufficiently defensive against malformed browsing PTR responses) -Revision 1.6 2004/01/24 04:59:15 cheshire -Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again +Revision 1.98 2006/03/19 17:00:58 cheshire +Define symbol MaxMsg instead of using hard-coded constant value '80' -Revision 1.5 2004/01/23 23:23:14 ksekar -Added TCP support for truncated unicast messages. +Revision 1.97 2006/03/18 21:47:56 cheshire + Improve logic for delaying packets after repeated interface transitions -Revision 1.4 2004/01/22 02:15:33 cheshire -: Link-local reverse-mapping domains need to be resolved using link-local multicast +Revision 1.96 2006/03/10 21:51:42 cheshire + After record update, old record sometimes remains in cache +Split out SameRDataBody() into a separate routine so it can be called from other code -Revision 1.3 2004/01/21 21:16:29 cheshire -Minor tidy-up: Deleted a bunch of blank lines, trailing spaces, tabs, etc. +Revision 1.95 2006/03/08 22:43:11 cheshire +Use "localdomain" symbol instead of literal string -Revision 1.2 2003/12/13 05:47:48 bradley -Made local ptr const to fix error when assigning from const structure. Disable benign conditional -expression is constant warning when building with Microsoft compilers. +Revision 1.94 2006/03/02 21:59:55 cheshire + Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use" +Improve sanity checks & debugging support in GetLargeResourceRecord() -Revision 1.1 2003/12/13 03:05:27 ksekar -: DynDNS: Unicast query of service records +Revision 1.93 2006/03/02 20:30:47 cheshire +Improved GetRRDisplayString to also show priority, weight, and port for SRV records - */ +*/ // Set mDNS_InstantiateInlines to tell mDNSEmbeddedAPI.h to instantiate inline functions, if necessary #define mDNS_InstantiateInlines 1 @@ -361,37 +345,67 @@ Revision 1.1 2003/12/13 03:05:27 ksekar // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK -#pragma mark - -#pragma mark - DNameList copy/deallocation routines +#pragma mark - Program Constants #endif -mDNSexport DNameListElem *mDNS_CopyDNameList(const DNameListElem *orig) - { - DNameListElem *copy = mDNSNULL, *newelem; - const DNameListElem *ptr; - - for (ptr = orig; ptr; ptr = ptr->next) - { - newelem = (DNameListElem*)mDNSPlatformMemAllocate(sizeof(DNameListElem)); - if (!newelem) { LogMsg("ERROR: malloc"); return mDNSNULL; } - AssignDomainName(&newelem->name, &ptr->name); - newelem->next = copy; - copy = newelem; - } - return copy; - } - -mDNSexport void mDNS_FreeDNameList(DNameListElem *list) - { - DNameListElem *fptr; - - while (list) - { - fptr = list; - list = list->next; - mDNSPlatformMemFree(fptr); - } - } +mDNSexport const mDNSIPPort zeroIPPort = { { 0 } }; +mDNSexport const mDNSv4Addr zerov4Addr = { { 0 } }; +mDNSexport const mDNSv6Addr zerov6Addr = { { 0 } }; +mDNSexport const mDNSEthAddr zeroEthAddr = { { 0 } }; +mDNSexport const mDNSv4Addr onesIPv4Addr = { { 255, 255, 255, 255 } }; +mDNSexport const mDNSv6Addr onesIPv6Addr = { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } }; +mDNSexport const mDNSAddr zeroAddr = { mDNSAddrType_None, {{{ 0 }}} }; + +mDNSexport const mDNSInterfaceID mDNSInterface_Any = 0; +mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)1; +mDNSexport const mDNSInterfaceID mDNSInterface_Unicast = (mDNSInterfaceID)2; + +// Note: Microsoft's proposed "Link Local Multicast Name Resolution Protocol" (LLMNR) is essentially a limited version of +// Multicast DNS, using the same packet formats, naming syntax, and record types as Multicast DNS, but on a different UDP +// port and multicast address, which means it won't interoperate with the existing installed base of Multicast DNS responders. +// LLMNR uses IPv4 multicast address 224.0.0.252, IPv6 multicast address FF02::0001:0003, and UDP port 5355. +// Uncomment the appropriate lines below to build a special Multicast DNS responder for testing interoperability +// with Microsoft's LLMNR client code. + +#define SSDPPortAsNumber 1900 + +#define UnicastDNSPortAsNumber 53 +#define NATPMPAnnouncementPortAsNumber 5350 +#define NATPMPPortAsNumber 5351 +#define DNSEXTPortAsNumber 5352 // Port used for end-to-end DNS operations like LLQ, Updates with Leases, etc. +#define MulticastDNSPortAsNumber 5353 +#define LoopbackIPCPortAsNumber 5354 +//#define MulticastDNSPortAsNumber 5355 // LLMNR + +#define NSIPCPortAsNumber 5030 // Port used for dnsextd to talk to local nameserver bound to loopback +#define PrivateDNSPortAsNumber 5533 + +mDNSexport const mDNSIPPort SSDPPort = { { SSDPPortAsNumber >> 8, SSDPPortAsNumber & 0xFF } }; + +mDNSexport const mDNSIPPort UnicastDNSPort = { { UnicastDNSPortAsNumber >> 8, UnicastDNSPortAsNumber & 0xFF } }; +mDNSexport const mDNSIPPort NATPMPAnnouncementPort = { { NATPMPAnnouncementPortAsNumber >> 8, NATPMPAnnouncementPortAsNumber & 0xFF } }; +mDNSexport const mDNSIPPort NATPMPPort = { { NATPMPPortAsNumber >> 8, NATPMPPortAsNumber & 0xFF } }; +mDNSexport const mDNSIPPort DNSEXTPort = { { DNSEXTPortAsNumber >> 8, DNSEXTPortAsNumber & 0xFF } }; +mDNSexport const mDNSIPPort MulticastDNSPort = { { MulticastDNSPortAsNumber >> 8, MulticastDNSPortAsNumber & 0xFF } }; +mDNSexport const mDNSIPPort LoopbackIPCPort = { { LoopbackIPCPortAsNumber >> 8, LoopbackIPCPortAsNumber & 0xFF } }; + +mDNSexport const mDNSIPPort NSIPCPort = { { NSIPCPortAsNumber >> 8, NSIPCPortAsNumber & 0xFF } }; +mDNSexport const mDNSIPPort PrivateDNSPort = { { PrivateDNSPortAsNumber >> 8, PrivateDNSPortAsNumber & 0xFF } }; + +mDNSexport const mDNSv4Addr AllDNSAdminGroup = { { 239, 255, 255, 251 } }; +mDNSexport const mDNSAddr AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224, 0, 0, 251 } } } }; +//mDNSexport const mDNSAddr AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224, 0, 0, 252 } } } }; // LLMNR +mDNSexport const mDNSAddr AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } } } }; +//mDNSexport const mDNSAddr AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x01,0x00,0x03 } } } }; // LLMNR + +mDNSexport const mDNSOpaque16 zeroID = { { 0, 0 } }; +mDNSexport const mDNSOpaque16 QueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery, 0 } }; +mDNSexport const mDNSOpaque16 uQueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery | kDNSFlag0_RD, 0 } }; +mDNSexport const mDNSOpaque16 ResponseFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } }; +mDNSexport const mDNSOpaque16 UpdateReqFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_Update, 0 } }; +mDNSexport const mDNSOpaque16 UpdateRespFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, 0 } }; + +mDNSexport const mDNSOpaque64 zeroOpaque64 = { { 0 } }; // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK @@ -400,16 +414,11 @@ mDNSexport void mDNS_FreeDNameList(DNameListElem *list) #endif // return true for RFC1918 private addresses -mDNSexport mDNSBool IsPrivateV4Addr(mDNSAddr *addr) +mDNSexport mDNSBool mDNSv4AddrIsRFC1918(mDNSv4Addr *addr) { - mDNSu8 *b; - - if (addr->type != mDNSAddrType_IPv4) return mDNSfalse; - b = addr->ip.v4.b; - - return ((b[0] == 10) || // 10/8 prefix - (b[0] == 172 && b[1] > 15 && b[1] < 32) || // 172.16/12 - (b[0] == 192 && b[1] == 168)); // 192.168/16 + return ((addr->b[0] == 10) || // 10/8 prefix + (addr->b[0] == 172 && (addr->b[1] & 0xF0) == 16) || // 172.16/12 + (addr->b[0] == 192 && addr->b[1] == 168)); // 192.168/16 } mDNSexport const NetworkInterfaceInfo *GetFirstActiveInterface(const NetworkInterfaceInfo *intf) @@ -448,6 +457,8 @@ mDNSexport char *DNSTypeName(mDNSu16 rrtype) case kDNSType_TXT: return("TXT"); case kDNSType_AAAA: return("AAAA"); case kDNSType_SRV: return("SRV"); + case kDNSType_OPT: return("OPT"); + case kDNSType_TSIG: return("TSIG"); case kDNSQType_ANY: return("ANY"); default: { static char buffer[16]; @@ -462,29 +473,62 @@ mDNSexport char *DNSTypeName(mDNSu16 rrtype) // long as this routine is only used for debugging messages, it probably isn't a big problem. mDNSexport char *GetRRDisplayString_rdb(const ResourceRecord *rr, RDataBody *rd, char *buffer) { + #define Max (MaxMsg-1) char *ptr = buffer; - mDNSu32 length = mDNS_snprintf(buffer, 79, "%4d %##s %s ", rr->rdlength, rr->name->c, DNSTypeName(rr->rrtype)); + mDNSu32 length = mDNS_snprintf(buffer, Max, "%4d %##s %s ", rr->rdlength, rr->name->c, DNSTypeName(rr->rrtype)); + if (rr->RecordType == kDNSRecordTypePacketNegative) return(buffer); + if (!rr->rdlength) { mDNS_snprintf(buffer+length, Max-length, "<< ZERO RDATA LENGTH >>"); return(buffer); } + switch (rr->rrtype) { - case kDNSType_A: mDNS_snprintf(buffer+length, 79-length, "%.4a", &rd->ipv4); break; + case kDNSType_A: mDNS_snprintf(buffer+length, Max-length, "%.4a", &rd->ipv4); break; case kDNSType_NS: // Same as PTR case kDNSType_CNAME:// Same as PTR - case kDNSType_PTR: mDNS_snprintf(buffer+length, 79-length, "%##s", rd->name.c); break; + case kDNSType_PTR: mDNS_snprintf(buffer+length, Max-length, "%##s", rd->name.c); break; - case kDNSType_HINFO:// Display this the same as TXT (just show first string) - case kDNSType_TXT: mDNS_snprintf(buffer+length, 79-length, "%#s", rd->txt.c); break; + case kDNSType_SOA: mDNS_snprintf(buffer+length, Max-length, "%##s %##s %d %d %d %d %d", + rd->soa.mname.c, rd->soa.rname.c, + rd->soa.serial, rd->soa.refresh, rd->soa.retry, rd->soa.expire, rd->soa.min); + break; + + case kDNSType_HINFO:// Display this the same as TXT (show all constituent string) + case kDNSType_TXT: { + mDNSu8 *t = rd->txt.c; + while (t < rd->txt.c + rr->rdlength) + { + length += mDNS_snprintf(buffer+length, Max-length, "%s%#s", t > rd->txt.c ? "¦" : "", t); + t += 1 + t[0]; + } + } break; - case kDNSType_AAAA: mDNS_snprintf(buffer+length, 79-length, "%.16a", &rd->ipv6); break; - case kDNSType_SRV: mDNS_snprintf(buffer+length, 79-length, "%u %u %u %##s", + case kDNSType_AAAA: mDNS_snprintf(buffer+length, Max-length, "%.16a", &rd->ipv6); break; + case kDNSType_SRV: mDNS_snprintf(buffer+length, Max-length, "%u %u %u %##s", rd->srv.priority, rd->srv.weight, mDNSVal16(rd->srv.port), rd->srv.target.c); break; - default: mDNS_snprintf(buffer+length, 79-length, "RDLen %d: %s", rr->rdlength, rd->data); break; + case kDNSType_OPT: length += mDNS_snprintf(buffer+length, Max-length, "%d Len %d ", rd->opt.opt, rd->opt.optlen); + length += mDNS_snprintf(buffer+length, Max-length, "Max UDP %d ", rr->rrclass); + if (rd->opt.opt == kDNSOpt_LLQ) + { + length += mDNS_snprintf(buffer+length, Max-length, "Vers %d ", rd->opt.OptData.llq.vers); + length += mDNS_snprintf(buffer+length, Max-length, "Op %d ", rd->opt.OptData.llq.llqOp); + length += mDNS_snprintf(buffer+length, Max-length, "Err/Port %d ", rd->opt.OptData.llq.err); + length += mDNS_snprintf(buffer+length, Max-length, "ID %08X%08X ", rd->opt.OptData.llq.id.l[0], rd->opt.OptData.llq.id.l[1]); + length += mDNS_snprintf(buffer+length, Max-length, "Lease %d", rd->opt.OptData.llq.llqlease); + } + else if (rd->opt.opt == kDNSOpt_Lease) + length += mDNS_snprintf(buffer+length, Max-length, "kDNSOpt_Lease Lease %d", rd->opt.OptData.updatelease); + else + length += mDNS_snprintf(buffer+length, Max-length, "Unknown opt %d", rd->opt.opt); + break; + default: mDNS_snprintf(buffer+length, Max-length, "RDLen %d: %s", rr->rdlength, rd->data); + // Really should scan buffer to check if text is valid UTF-8 and only replace with dots if not + for (ptr = buffer; *ptr; ptr++) if (*ptr < ' ') *ptr = '.'; + break; } - for (ptr = buffer; *ptr; ptr++) if (*ptr < ' ') *ptr='.'; return(buffer); } -mDNSexport mDNSu32 mDNSRandom(mDNSu32 max) +mDNSexport mDNSu32 mDNSRandom(mDNSu32 max) // Returns pseudo-random result from zero to max inclusive { static mDNSu32 seed = 0; mDNSu32 mask = 1; @@ -500,6 +544,14 @@ mDNSexport mDNSu32 mDNSRandom(mDNSu32 max) return (seed & mask); } +mDNSexport mDNSu32 mDNSRandomFromFixedSeed(mDNSu32 seed, mDNSu32 max) + { + mDNSu32 mask = 1; + while (mask < max) mask = (mask << 1) | 1; + do seed = seed * 21 + 1; while ((seed & mask) > max); + return (seed & mask); + } + mDNSexport mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2) { if (ip1->type == ip2->type) @@ -518,11 +570,8 @@ mDNSexport mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip) { switch(ip->type) { - case mDNSAddrType_IPv4: return(mDNSBool)(ip->ip.v4.NotAnInteger == AllDNSLinkGroupv4.NotAnInteger); - case mDNSAddrType_IPv6: return(mDNSBool)(ip->ip.v6.l[0] == AllDNSLinkGroupv6.l[0] && - ip->ip.v6.l[1] == AllDNSLinkGroupv6.l[1] && - ip->ip.v6.l[2] == AllDNSLinkGroupv6.l[2] && - ip->ip.v6.l[3] == AllDNSLinkGroupv6.l[3] ); + case mDNSAddrType_IPv4: return(mDNSBool)(mDNSSameIPv4Address(ip->ip.v4, AllDNSLinkGroup_v4.ip.v4)); + case mDNSAddrType_IPv6: return(mDNSBool)(mDNSSameIPv6Address(ip->ip.v6, AllDNSLinkGroup_v6.ip.v6)); default: return(mDNSfalse); } } @@ -571,47 +620,59 @@ mDNSexport mDNSBool SameDomainName(const domainname *const d1, const domainname return(mDNStrue); } +mDNSexport mDNSBool SameDomainNameCS(const domainname *const d1, const domainname *const d2) + { + mDNSu16 l1 = DomainNameLength(d1); + mDNSu16 l2 = DomainNameLength(d2); + return(l1 <= MAX_DOMAIN_NAME && l1 == l2 && mDNSPlatformMemSame(d1, d2, l1)); + } + mDNSexport mDNSBool IsLocalDomain(const domainname *d) { // Domains that are defined to be resolved via link-local multicast are: - // local., 254.169.in-addr.arpa., and 0.8.E.F.ip6.arpa. - static const domainname *n0 = (domainname*)"\x5" "local"; - static const domainname *n1 = (domainname*)"\x3" "254" "\x3" "169" "\x7" "in-addr" "\x4" "arpa"; - static const domainname *n2 = (domainname*)"\x1" "0" "\x1" "8" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa"; - - const domainname *d1, *d2, *d3, *d4, *d5, *d6; // Top-level domain, second-level domain, etc. - d1 = d2 = d3 = d4 = d5 = d6 = mDNSNULL; + // local., 254.169.in-addr.arpa., and {8,9,A,B}.E.F.ip6.arpa. + static const domainname *nL = (const domainname*)"\x5" "local"; + static const domainname *nR = (const domainname*)"\x3" "254" "\x3" "169" "\x7" "in-addr" "\x4" "arpa"; + static const domainname *n8 = (const domainname*)"\x1" "8" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa"; + static const domainname *n9 = (const domainname*)"\x1" "9" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa"; + static const domainname *nA = (const domainname*)"\x1" "a" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa"; + static const domainname *nB = (const domainname*)"\x1" "b" "\x1" "e" "\x1" "f" "\x3" "ip6" "\x4" "arpa"; + + const domainname *d1, *d2, *d3, *d4, *d5; // Top-level domain, second-level domain, etc. + d1 = d2 = d3 = d4 = d5 = mDNSNULL; while (d->c[0]) { - d6 = d5; d5 = d4; d4 = d3; d3 = d2; d2 = d1; d1 = d; - d = (domainname*)(d->c + 1 + d->c[0]); + d5 = d4; d4 = d3; d3 = d2; d2 = d1; d1 = d; + d = (const domainname*)(d->c + 1 + d->c[0]); } - if (d1 && SameDomainName(d1, n0)) return(mDNStrue); - if (d4 && SameDomainName(d4, n1)) return(mDNStrue); - if (d6 && SameDomainName(d6, n2)) return(mDNStrue); + if (d1 && SameDomainName(d1, nL)) return(mDNStrue); + if (d4 && SameDomainName(d4, nR)) return(mDNStrue); + if (d5 && SameDomainName(d5, n8)) return(mDNStrue); + if (d5 && SameDomainName(d5, n9)) return(mDNStrue); + if (d5 && SameDomainName(d5, nA)) return(mDNStrue); + if (d5 && SameDomainName(d5, nB)) return(mDNStrue); return(mDNSfalse); } // Returns length of a domain name INCLUDING the byte for the final null label -// i.e. for the root label "." it returns one +// e.g. for the root label "." it returns one // For the FQDN "com." it returns 5 (length byte, three data bytes, final zero) // Legal results are 1 (just root label) to 255 (MAX_DOMAIN_NAME) -// If the given domainname is invalid, result is 256 -mDNSexport mDNSu16 DomainNameLength(const domainname *const name) +// If the given domainname is invalid, result is 256 (MAX_DOMAIN_NAME+1) +mDNSexport mDNSu16 DomainNameLengthLimit(const domainname *const name, const mDNSu8 *limit) { const mDNSu8 *src = name->c; - while (*src) + while (src < limit && *src <= MAX_DOMAIN_LABEL) { - if (*src > MAX_DOMAIN_LABEL) return(MAX_DOMAIN_NAME+1); + if (*src == 0) return((mDNSu16)(src - name->c + 1)); src += 1 + *src; - if (src - name->c >= MAX_DOMAIN_NAME) return(MAX_DOMAIN_NAME+1); } - return((mDNSu16)(src - name->c + 1)); + return(MAX_DOMAIN_NAME+1); } // CompressedDomainNameLength returns the length of a domain name INCLUDING the byte -// for the final null label i.e. for the root label "." it returns one. +// for the final null label, e.g. for the root label "." it returns one. // E.g. for the FQDN "foo.com." it returns 9 // (length, three data bytes, length, three more data bytes, final zero). // In the case where a parent domain name is provided, and the given name is a child @@ -626,18 +687,36 @@ mDNSexport mDNSu16 CompressedDomainNameLength(const domainname *const name, cons while (*src) { if (*src > MAX_DOMAIN_LABEL) return(MAX_DOMAIN_NAME+1); - if (parent && SameDomainName((domainname *)src, parent)) return((mDNSu16)(src - name->c + 2)); + if (parent && SameDomainName((const domainname *)src, parent)) return((mDNSu16)(src - name->c + 2)); src += 1 + *src; if (src - name->c >= MAX_DOMAIN_NAME) return(MAX_DOMAIN_NAME+1); } return((mDNSu16)(src - name->c + 1)); } +// CountLabels() returns number of labels in name, excluding final root label +// (e.g. for "apple.com." CountLabels returns 2.) +mDNSexport int CountLabels(const domainname *d) + { + int count = 0; + const mDNSu8 *ptr; + for (ptr = d->c; *ptr; ptr = ptr + ptr[0] + 1) count++; + return count; + } + +// SkipLeadingLabels skips over the first 'skip' labels in the domainname, +// returning a pointer to the suffix with 'skip' labels removed. +mDNSexport const domainname *SkipLeadingLabels(const domainname *d, int skip) + { + while (skip > 0 && d->c[0]) { d = (const domainname *)(d->c + 1 + d->c[0]); skip--; } + return(d); + } + // AppendLiteralLabelString appends a single label to an existing (possibly empty) domainname. // The C string contains the label as-is, with no escaping, etc. // Any dots in the name are literal dots, not label separators // If successful, AppendLiteralLabelString returns a pointer to the next unused byte -// in the domainname bufer (i.e., the next byte after the terminating zero). +// in the domainname bufer (i.e. the next byte after the terminating zero). // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes) // AppendLiteralLabelString returns mDNSNULL. mDNSexport mDNSu8 *AppendLiteralLabelString(domainname *const name, const char *cstr) @@ -659,7 +738,7 @@ mDNSexport mDNSu8 *AppendLiteralLabelString(domainname *const name, const char * // The C string is in conventional DNS syntax: // Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots. // If successful, AppendDNSNameString returns a pointer to the next unused byte -// in the domainname bufer (i.e., the next byte after the terminating zero). +// in the domainname bufer (i.e. the next byte after the terminating zero). // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes) // AppendDNSNameString returns mDNSNULL. mDNSexport mDNSu8 *AppendDNSNameString(domainname *const name, const char *cstring) @@ -701,7 +780,7 @@ mDNSexport mDNSu8 *AppendDNSNameString(domainname *const name, const char *cstri // AppendDomainLabel appends a single label to a name. // If successful, AppendDomainLabel returns a pointer to the next unused byte -// in the domainname bufer (i.e., the next byte after the terminating zero). +// in the domainname bufer (i.e. the next byte after the terminating zero). // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes) // AppendDomainLabel returns mDNSNULL. mDNSexport mDNSu8 *AppendDomainLabel(domainname *const name, const domainlabel *const label) @@ -725,7 +804,7 @@ mDNSexport mDNSu8 *AppendDomainName(domainname *const name, const domainname *co mDNSu8 * ptr = name->c + DomainNameLength(name) - 1; // Find end of current name const mDNSu8 *const lim = name->c + MAX_DOMAIN_NAME - 1; // Limit of how much we can add (not counting final zero) const mDNSu8 * src = append->c; - while(src[0]) + while (src[0]) { int i; if (ptr + 1 + src[0] > lim) return(mDNSNULL); @@ -755,7 +834,7 @@ mDNSexport mDNSBool MakeDomainLabelFromLiteralString(domainlabel *const label, c // The C string is in conventional DNS syntax: // Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots. // If successful, MakeDomainNameFromDNSNameString returns a pointer to the next unused byte -// in the domainname bufer (i.e., the next byte after the terminating zero). +// in the domainname bufer (i.e. the next byte after the terminating zero). // If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes) // MakeDomainNameFromDNSNameString returns mDNSNULL. mDNSexport mDNSu8 *MakeDomainNameFromDNSNameString(domainname *const name, const char *cstr) @@ -840,6 +919,10 @@ 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) { @@ -866,12 +949,12 @@ mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn, len = *src; for (i=0; i <= len; i++) *dst++ = *src++; for (i=0; i < (int)sizeof(SubTypeLabel); i++) *dst++ = SubTypeLabel[i]; - type = (domainname *)s1; + type = (const domainname *)s1; - // Special support for queries done by some third-party network monitoring software + // Special support to enable the DNSServiceBrowse call made by Bonjour Browser // For these queries, we retract the "._sub" we just added between the subtype and the main type - if (SameDomainName((domainname*)s0, (domainname*)"\x09_services\x07_dns-sd\x04_udp") || - SameDomainName((domainname*)s0, (domainname*)"\x09_services\x05_mdns\x04_udp")) + // Remove after Bonjour Browser is updated to use DNSServiceQueryRecord instead of DNSServiceBrowse + if (SameDomainName((domainname*)s0, (const domainname*)"\x09_services\x07_dns-sd\x04_udp")) dst -= sizeof(SubTypeLabel); } } @@ -882,7 +965,7 @@ mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn, { src = name->c; // Put the service name into the domain name len = *src; - if (len >= 0x40) { errormsg="Service instance name too long"; goto fail; } + if (len >= 0x40) { errormsg = "Service instance name too long"; goto fail; } for (i=0; i<=len; i++) *dst++ = *src++; } else @@ -892,30 +975,34 @@ mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn, len = *src; if (len < 2 || len >= 0x40 || (len > 15 && !SameDomainName(domain, &localdomain))) { - errormsg="Application protocol name must be underscore plus 1-14 characters. See "; + errormsg = "Application protocol name must be underscore plus 1-14 characters. See "; goto fail; } - if (src[1] != '_') { errormsg="Application protocol name must begin with underscore"; goto fail; } + if (src[1] != '_') { errormsg = "Application protocol name must begin with underscore"; goto fail; } for (i=2; i<=len; i++) - if (!mdnsIsLetter(src[i]) && !mdnsIsDigit(src[i]) && src[i] != '-' && src[i] != '_') - { errormsg="Application protocol name must contain only letters, digits, and hyphens"; goto fail; } + { + // Letters and digits are allowed anywhere + if (mdnsIsLetter(src[i]) || mdnsIsDigit(src[i])) continue; + // Hyphens are only allowed as interior characters + // Underscores are not supposed to be allowed at all, but for backwards compatibility with some old products we do allow them, + // with the same rule as hyphens + if ((src[i] == '-' || src[i] == '_') && i > 2 && i < len) continue; + errormsg = "Application protocol name must contain only letters, digits, and hyphens"; goto fail; + } for (i=0; i<=len; i++) *dst++ = *src++; len = *src; - if (!(len == 4 && src[1] == '_' && - (((src[2] | 0x20) == 'u' && (src[3] | 0x20) == 'd') || ((src[2] | 0x20) == 't' && (src[3] | 0x20) == 'c')) && - (src[4] | 0x20) == 'p')) - { errormsg="Transport protocol name must be _udp or _tcp"; goto fail; } + if (!ValidTransportProtocol(src)) { errormsg = "Transport protocol name must be _udp or _tcp"; goto fail; } for (i=0; i<=len; i++) *dst++ = *src++; - if (*src) { errormsg="Service type must have only two labels"; goto fail; } + if (*src) { errormsg = "Service type must have only two labels"; goto fail; } *dst = 0; - if (!domain->c[0]) { errormsg="Service domain must be non-empty"; goto fail; } - if (SameDomainName(domain, (domainname*)"\x05" "local" "\x04" "arpa")) - { errormsg="Illegal domain \"local.arpa.\" Use \"local.\" (or empty string)"; goto fail; } + if (!domain->c[0]) { errormsg = "Service domain must be non-empty"; goto fail; } + if (SameDomainName(domain, (const domainname*)"\x05" "local" "\x04" "arpa")) + { errormsg = "Illegal domain \"local.arpa.\" Use \"local.\" (or empty string)"; goto fail; } dst = AppendDomainName(fqdn, domain); - if (!dst) { errormsg="Service domain too long"; goto fail; } + if (!dst) { errormsg = "Service domain too long"; goto fail; } return(dst); fail: @@ -938,19 +1025,22 @@ mDNSexport mDNSBool DeconstructServiceName(const domainname *const fqdn, dst = name->c; // Extract the service name len = *src; - if (!len) { debugf("DeconstructServiceName: FQDN empty!"); return(mDNSfalse); } - if (len >= 0x40) { debugf("DeconstructServiceName: Instance name too long"); return(mDNSfalse); } + if (!len) { debugf("DeconstructServiceName: FQDN empty!"); return(mDNSfalse); } + if (len >= 0x40) { debugf("DeconstructServiceName: Instance name too long"); return(mDNSfalse); } for (i=0; i<=len; i++) *dst++ = *src++; dst = type->c; // Extract the service type len = *src; - if (!len) { debugf("DeconstructServiceName: FQDN contains only one label!"); return(mDNSfalse); } - if (len >= 0x40) { debugf("DeconstructServiceName: Application protocol name too long"); return(mDNSfalse); } + if (!len) { debugf("DeconstructServiceName: FQDN contains only one label!"); return(mDNSfalse); } + if (len >= 0x40) { debugf("DeconstructServiceName: Application protocol name too long"); return(mDNSfalse); } + if (src[1] != '_'){ debugf("DeconstructServiceName: No _ at start of application protocol"); return(mDNSfalse); } for (i=0; i<=len; i++) *dst++ = *src++; len = *src; - if (!len) { debugf("DeconstructServiceName: FQDN contains only two labels!"); return(mDNSfalse); } - if (len >= 0x40) { debugf("DeconstructServiceName: Transport protocol name too long"); return(mDNSfalse); } + if (!len) { debugf("DeconstructServiceName: FQDN contains only two labels!"); return(mDNSfalse); } + // Can't do this check right now, until Bonjour Browser is updated to use DNSServiceQueryRecord instead of DNSServiceBrowse + //if (!ValidTransportProtocol(src)) + // { debugf("DeconstructServiceName: Transport protocol must be _udp or _tcp"); return(mDNSfalse); } for (i=0; i<=len; i++) *dst++ = *src++; *dst++ = 0; // Put terminator on the end of service type @@ -988,8 +1078,8 @@ mDNSexport mDNSu32 TruncateUTF8ToLength(mDNSu8 *string, mDNSu32 length, mDNSu32 { if (length > max) { - mDNSu8 c1 = string[max]; // First byte after cut point - mDNSu8 c2 = (max+1 < length) ? string[max+1] : 0xB0; // Second byte after cut point + mDNSu8 c1 = string[max]; // First byte after cut point + mDNSu8 c2 = (max+1 < length) ? string[max+1] : (mDNSu8)0xB0; // Second byte after cut point length = max; // Trim length down while (length > 0) { @@ -1062,7 +1152,7 @@ mDNSexport mDNSu32 RemoveLabelSuffix(domainlabel *name, mDNSBool RichText) // appends a numerical suffix to a label, with the number following a whitespace and enclosed // in parentheses (rich text) or following two consecutive hyphens (RFC 1034 domain label). -mDNSexport void AppendLabelSuffix(domainlabel *name, mDNSu32 val, mDNSBool RichText) +mDNSexport void AppendLabelSuffix(domainlabel *const name, mDNSu32 val, const mDNSBool RichText) { mDNSu32 divisor = 1, chars = 2; // Shortest possible RFC1034 name suffix is 2 characters ("-2") if (RichText) chars = 4; // Shortest possible RichText suffix is 4 characters (" (2)") @@ -1070,7 +1160,7 @@ mDNSexport void AppendLabelSuffix(domainlabel *name, mDNSu32 val, mDNSBool RichT // Truncate trailing spaces from RichText names if (RichText) while (name->c[name->c[0]] == ' ') name->c[0]--; - while (val >= divisor * 10) { divisor *= 10; chars++; } + while (divisor < 0xFFFFFFFFUL/10 && val >= divisor * 10) { divisor *= 10; chars++; } name->c[0] = (mDNSu8) TruncateUTF8ToLength(name->c+1, name->c[0], MAX_DOMAIN_LABEL - chars); @@ -1111,6 +1201,74 @@ mDNSexport void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText) #pragma mark - Resource Record Utility Functions #endif +// Set up a AuthRecord with sensible default values. +// These defaults may be overwritten with new values before mDNS_Register is called +mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID, + mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, mDNSRecordCallback Callback, void *Context) + { + // Don't try to store a TTL bigger than we can represent in platform time units + if (ttl > 0x7FFFFFFFUL / mDNSPlatformOneSecond) + ttl = 0x7FFFFFFFUL / mDNSPlatformOneSecond; + else if (ttl == 0) // And Zero TTL is illegal + ttl = DefaultTTLforRRType(rrtype); + + // Field Group 1: The actual information pertaining to this resource record + rr->resrec.RecordType = RecordType; + rr->resrec.InterfaceID = InterfaceID; + rr->resrec.name = &rr->namestorage; + rr->resrec.rrtype = rrtype; + rr->resrec.rrclass = kDNSClass_IN; + rr->resrec.rroriginalttl = ttl; +// rr->resrec.rdlength = MUST set by client and/or in mDNS_Register_internal +// rr->resrec.rdestimate = set in mDNS_Register_internal +// rr->resrec.rdata = MUST be set by client + + if (RDataStorage) + rr->resrec.rdata = RDataStorage; + else + { + rr->resrec.rdata = &rr->rdatastorage; + rr->resrec.rdata->MaxRDLength = sizeof(RDataBody); + } + + // Field Group 2: Persistent metadata for Authoritative Records + rr->Additional1 = mDNSNULL; + rr->Additional2 = mDNSNULL; + rr->DependentOn = mDNSNULL; + rr->RRSet = mDNSNULL; + rr->RecordCallback = Callback; + rr->RecordContext = Context; + + rr->AutoTarget = Target_Manual; + rr->AllowRemoteQuery = mDNSfalse; + rr->ForceMCast = mDNSfalse; + + // Field Group 3: Transient state for Authoritative Records (set in mDNS_Register_internal) + // Field Group 4: Transient uDNS state for Authoritative Records (set in mDNS_Register_internal) + + // For now, until the uDNS code is fully integrated, it's helpful to zero the uDNS state fields here too, just in case + // (e.g. uDNS_RegisterService short-circuits the usual mDNS_Register_internal record registration calls, so a bunch + // of fields don't get set up properly. In particular, if we don't zero rr->QueuedRData then the uDNS code crashes.) + rr->state = regState_Zero; + rr->uselease = 0; + rr->expire = 0; + rr->Private = 0; + rr->id = zeroID; + rr->zone.c[0] = 0; + rr->UpdateServer = zeroAddr; + rr->UpdatePort = zeroIPPort; + rr->nta = mDNSNULL; + rr->tcp = mDNSNULL; + rr->OrigRData = 0; + rr->OrigRDLen = 0; + rr->InFlightRData = 0; + rr->InFlightRDLen = 0; + rr->QueuedRData = 0; + rr->QueuedRDLen = 0; + + rr->namestorage.c[0] = 0; // MUST be set by client before calling mDNS_Register() + } + mDNSexport mDNSu32 RDataHashValue(mDNSu16 const rdlength, const RDataBody *const rdb) { mDNSu32 sum = 0; @@ -1133,13 +1291,38 @@ mDNSexport mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBod { switch(r1->rrtype) { - case kDNSType_CNAME:// Same as PTR - case kDNSType_PTR: return(SameDomainName(&r1->rdata->u.name, &r2->name)); - - case kDNSType_SRV: return(mDNSBool)( r1->rdata->u.srv.priority == r2->srv.priority && - r1->rdata->u.srv.weight == r2->srv.weight && - r1->rdata->u.srv.port.NotAnInteger == r2->srv.port.NotAnInteger && - SameDomainName(&r1->rdata->u.srv.target, &r2->srv.target) ); + case kDNSType_NS: + case kDNSType_CNAME: + case kDNSType_PTR: + case kDNSType_DNAME:return(SameDomainName(&r1->rdata->u.name, &r2->name)); + + case kDNSType_SOA: return(mDNSBool)( r1->rdata->u.soa.serial == r2->soa.serial && + r1->rdata->u.soa.refresh == r2->soa.refresh && + r1->rdata->u.soa.retry == r2->soa.retry && + r1->rdata->u.soa.expire == r2->soa.expire && + r1->rdata->u.soa.min == r2->soa.min && + SameDomainName(&r1->rdata->u.soa.mname, &r2->soa.mname) && + SameDomainName(&r1->rdata->u.soa.rname, &r2->soa.rname)); + + case kDNSType_MX: + case kDNSType_AFSDB: + case kDNSType_RT: + case kDNSType_KX: return(mDNSBool)( r1->rdata->u.mx.preference == r2->mx.preference && + SameDomainName(&r1->rdata->u.mx.exchange, &r2->mx.exchange)); + + case kDNSType_RP: return(mDNSBool)( SameDomainName(&r1->rdata->u.rp.mbox, &r2->rp.mbox) && + SameDomainName(&r1->rdata->u.rp.txt, &r2->rp.txt)); + + case kDNSType_PX: return(mDNSBool)( r1->rdata->u.px.preference == r2->px.preference && + SameDomainName(&r1->rdata->u.px.map822, &r2->px.map822) && + SameDomainName(&r1->rdata->u.px.mapx400, &r2->px.mapx400)); + + case kDNSType_SRV: return(mDNSBool)( r1->rdata->u.srv.priority == r2->srv.priority && + r1->rdata->u.srv.weight == r2->srv.weight && + mDNSSameIPPort(r1->rdata->u.srv.port, r2->srv.port) && + SameDomainName(&r1->rdata->u.srv.target, &r2->srv.target)); + + case kDNSType_OPT: // Okay to use memory compare because there are no 'holes' in the in-memory representation default: return(mDNSPlatformMemSame(r1->rdata->u.data, r2->data, r1->rdlength)); } @@ -1156,17 +1339,51 @@ mDNSexport mDNSBool SameRData(const ResourceRecord *const r1, const ResourceReco mDNSexport mDNSBool SameResourceRecord(ResourceRecord *r1, ResourceRecord *r2) { return (r1->namehash == r2->namehash && - r1->rrtype == r2->rrtype && + r1->rrtype == r2->rrtype && SameDomainName(r1->name, r2->name) && SameRData(r1, r2)); } +// ResourceRecordAnswersQuestion returns mDNStrue if the given resource record is a valid answer to the given question. +// SameNameRecordAnswersQuestion is the same, except it skips the expensive SameDomainName() call. +// SameDomainName() is generally cheap when the names don't match, but expensive when they do match, +// because it has to check all the way to the end of the names to be sure. +// In cases where we know in advance that the names match it's especially advantageous to skip the +// SameDomainName() call because that's precisely the time when it's most expensive and least useful. + +mDNSexport mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q) + { + if (rr->InterfaceID && + q ->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly && + rr->InterfaceID != q->InterfaceID) return(mDNSfalse); + + // If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question + if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse); + + // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class. + if (rr->rrtype != kDNSType_CNAME && rr->rrtype != q->qtype && q->qtype != kDNSQType_ANY ) return(mDNSfalse); + if ( rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse); + +#if VerifySameNameAssumptions + if (rr->namehash != q->qnamehash || !SameDomainName(rr->name, &q->qname)) + { + LogMsg("Bogus SameNameRecordAnswersQuestion call: RR %##s does not match Q %##s", rr->name->c, q->qname.c); + return(mDNSfalse); + } +#endif + + return(mDNStrue); + } + mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q) { if (rr->InterfaceID && q ->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly && rr->InterfaceID != q->InterfaceID) return(mDNSfalse); + // If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question + if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse); + // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class. if (rr->rrtype != kDNSType_CNAME && rr->rrtype != q->qtype && q->qtype != kDNSQType_ANY ) return(mDNSfalse); if ( rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse); @@ -1177,21 +1394,47 @@ mDNSexport mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate { const RDataBody *rd = &rr->rdata->u; const domainname *const name = estimate ? rr->name : mDNSNULL; - switch (rr->rrtype) + if (rr->rrclass == kDNSQClass_ANY) return(rr->rdlength); // Used in update packets to mean "Delete An RRset" (RFC 2136) + else switch (rr->rrtype) { case kDNSType_A: return(sizeof(rd->ipv4)); - case kDNSType_CNAME:// Same as PTR - case kDNSType_NS: // Same as PTR - case kDNSType_PTR: return(CompressedDomainNameLength(&rd->name, name)); + + case kDNSType_NS: + case kDNSType_CNAME: + case kDNSType_PTR: + case kDNSType_DNAME:return(CompressedDomainNameLength(&rd->name, name)); + + case kDNSType_SOA: return(mDNSu16)(CompressedDomainNameLength(&rd->soa.mname, name) + + CompressedDomainNameLength(&rd->soa.rname, name) + + 5 * sizeof(mDNSOpaque32)); + + case kDNSType_NULL: + case kDNSType_TSIG: + case kDNSType_TXT: + case kDNSType_X25: + case kDNSType_ISDN: + case kDNSType_LOC: + case kDNSType_DHCID:return(rr->rdlength); // Not self-describing, so have to just trust rdlength + case kDNSType_HINFO:return(mDNSu16)(2 + (int)rd->data[0] + (int)rd->data[1 + (int)rd->data[0]]); - case kDNSType_NULL: // Same as TXT -- not self-describing, so have to just trust rdlength - case kDNSType_TXT: return(rr->rdlength); // TXT is not self-describing, so have to just trust rdlength + + case kDNSType_MX: + case kDNSType_AFSDB: + case kDNSType_RT: + case kDNSType_KX: return(mDNSu16)(2 + CompressedDomainNameLength(&rd->mx.exchange, name)); + + case kDNSType_RP: return(mDNSu16)(CompressedDomainNameLength(&rd->rp.mbox, name) + + CompressedDomainNameLength(&rd->rp.txt, name)); + + case kDNSType_PX: return(mDNSu16)(2 + CompressedDomainNameLength(&rd->px.map822, name) + + CompressedDomainNameLength(&rd->px.mapx400, name)); + case kDNSType_AAAA: return(sizeof(rd->ipv6)); + case kDNSType_SRV: return(mDNSu16)(6 + CompressedDomainNameLength(&rd->srv.target, name)); - case kDNSType_SOA: return (mDNSu16)(CompressedDomainNameLength(&rd->soa.mname, name) + - CompressedDomainNameLength(&rd->soa.rname, name) + - 5 * sizeof(mDNSOpaque32)); + case kDNSType_OPT: return(rr->rdlength); + default: debugf("Warning! Don't know how to get length of resource type %d", rr->rrtype); return(rr->rdlength); } @@ -1215,8 +1458,7 @@ mDNSexport mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, case kDNSType_MR: // Same as PTR //case kDNSType_NULL not checked (no specified format, so always valid) //case kDNSType_WKS not checked - case kDNSType_PTR: if (!rdlength) return(mDNSfalse); - len = DomainNameLength(&rd->u.name); + case kDNSType_PTR: len = DomainNameLengthLimit(&rd->u.name, rd->u.data + rdlength); return(len <= MAX_DOMAIN_NAME && rdlength == len); case kDNSType_HINFO:// Same as TXT (roughly) @@ -1231,12 +1473,14 @@ mDNSexport mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, case kDNSType_AAAA: return(rdlength == sizeof(mDNSv6Addr)); - case kDNSType_MX: if (!rdlength) return(mDNSfalse); - len = DomainNameLength(&rd->u.mx.exchange); + case kDNSType_MX: // Must be at least two-byte preference, plus domainname + // Call to DomainNameLengthLimit() implicitly enforces both requirements for us + len = DomainNameLengthLimit(&rd->u.mx.exchange, rd->u.data + rdlength); return(len <= MAX_DOMAIN_NAME && rdlength == 2+len); - case kDNSType_SRV: if (!rdlength) return(mDNSfalse); - len = DomainNameLength(&rd->u.srv.target); + case kDNSType_SRV: // Must be at least priority+weight+port, plus domainname + // Call to DomainNameLengthLimit() implicitly enforces both requirements for us + len = DomainNameLengthLimit(&rd->u.srv.target, rd->u.data + rdlength); return(len <= MAX_DOMAIN_NAME && rdlength == 6+len); default: return(mDNStrue); // Allow all other types without checking @@ -1246,7 +1490,6 @@ mDNSexport mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - -#pragma mark - #pragma mark - DNS Message Creation Functions #endif @@ -1318,6 +1561,8 @@ mDNSexport mDNSu8 *putDomainNameAsLabels(const DNSMessage *const msg, const mDNSu8 * pointer = mDNSNULL; const mDNSu8 *const searchlimit = ptr; + if (!ptr) { LogMsg("putDomainNameAsLabels ptr is null"); return(mDNSNULL); } + while (*np && ptr < limit-1) // While we've got characters in the name, and space to write them in the message... { if (*np > MAX_DOMAIN_LABEL) @@ -1378,16 +1623,16 @@ mDNSlocal mDNSu8 *putVal32(mDNSu8 *ptr, mDNSu32 val) return ptr + sizeof(mDNSu32); } -mDNSlocal mDNSu8 *putOptRData(mDNSu8 *ptr, const mDNSu8 *limit, ResourceRecord *rr) +mDNSlocal mDNSu8 *putOptRData(mDNSu8 *ptr, const mDNSu8 *limit, const ResourceRecord *const rr) { int nput = 0; - rdataOpt *opt; + rdataOPT *opt; while (nput < rr->rdlength) { // check if space for opt/optlen if (ptr + (2 * sizeof(mDNSu16)) > limit) goto space_err; - opt = (rdataOpt *)(rr->rdata->u.data + nput); + opt = (rdataOPT *)(rr->rdata->u.data + nput); ptr = putVal16(ptr, opt->opt); ptr = putVal16(ptr, opt->optlen); nput += 2 * sizeof(mDNSu16); @@ -1397,15 +1642,15 @@ mDNSlocal mDNSu8 *putOptRData(mDNSu8 *ptr, const mDNSu8 *limit, ResourceRecord * ptr = putVal16(ptr, opt->OptData.llq.vers); ptr = putVal16(ptr, opt->OptData.llq.llqOp); ptr = putVal16(ptr, opt->OptData.llq.err); - mDNSPlatformMemCopy(opt->OptData.llq.id, ptr, 8); // 8-byte id + mDNSPlatformMemCopy(ptr, opt->OptData.llq.id.b, 8); // 8-byte id ptr += 8; - ptr = putVal32(ptr, opt->OptData.llq.lease); + ptr = putVal32(ptr, opt->OptData.llq.llqlease); nput += LLQ_OPTLEN; } else if (opt->opt == kDNSOpt_Lease) { if (ptr + sizeof(mDNSs32) > limit) goto space_err; - ptr = putVal32(ptr, opt->OptData.lease); + ptr = putVal32(ptr, opt->OptData.updatelease); nput += sizeof(mDNSs32); } else { LogMsg("putOptRData - unknown option %d", opt->opt); return mDNSNULL; } @@ -1429,9 +1674,9 @@ mDNSlocal const mDNSu8 *getOptRdata(const mDNSu8 *ptr, const mDNSu8 *const limit { int nread = 0; ResourceRecord *const rr = &cr->r.resrec; - rdataOpt *opt = (rdataOpt *)rr->rdata->u.data; + rdataOPT *opt = (rdataOPT *)rr->rdata->u.data; - while (nread < pktRDLen && (mDNSu8 *)opt < rr->rdata->u.data + MaximumRDSize - sizeof(rdataOpt)) + while (nread < pktRDLen && (mDNSu8 *)opt < rr->rdata->u.data + MaximumRDSize - sizeof(rdataOPT)) { // space for opt + optlen if (nread + (2 * sizeof(mDNSu16)) > rr->rdata->MaxRDLength) goto space_err; @@ -1444,11 +1689,11 @@ mDNSlocal const mDNSu8 *getOptRdata(const mDNSu8 *ptr, const mDNSu8 *const limit opt->OptData.llq.vers = getVal16(&ptr); opt->OptData.llq.llqOp = getVal16(&ptr); opt->OptData.llq.err = getVal16(&ptr); - mDNSPlatformMemCopy(ptr, opt->OptData.llq.id, 8); + mDNSPlatformMemCopy(opt->OptData.llq.id.b, ptr, 8); ptr += 8; - opt->OptData.llq.lease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]); - if (opt->OptData.llq.lease > 0x70000000UL / mDNSPlatformOneSecond) - opt->OptData.llq.lease = 0x70000000UL / mDNSPlatformOneSecond; + opt->OptData.llq.llqlease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]); + if (opt->OptData.llq.llqlease > 0x70000000UL / mDNSPlatformOneSecond) + opt->OptData.llq.llqlease = 0x70000000UL / mDNSPlatformOneSecond; ptr += sizeof(mDNSOpaque32); nread += LLQ_OPTLEN; } @@ -1456,9 +1701,9 @@ mDNSlocal const mDNSu8 *getOptRdata(const mDNSu8 *ptr, const mDNSu8 *const limit { if ((unsigned)(limit - ptr) < sizeof(mDNSs32)) goto space_err; - opt->OptData.lease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]); - if (opt->OptData.lease > 0x70000000UL / mDNSPlatformOneSecond) - opt->OptData.lease = 0x70000000UL / mDNSPlatformOneSecond; + opt->OptData.updatelease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]); + if (opt->OptData.updatelease > 0x70000000UL / mDNSPlatformOneSecond) + opt->OptData.updatelease = 0x70000000UL / mDNSPlatformOneSecond; ptr += sizeof(mDNSs32); nread += sizeof(mDNSs32); } @@ -1474,7 +1719,8 @@ mDNSlocal const mDNSu8 *getOptRdata(const mDNSu8 *ptr, const mDNSu8 *const limit return mDNSNULL; } -mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, ResourceRecord *rr) +// msg points to the message we're building (pass mDNSNULL if we don't want to use compression pointers) +mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const ResourceRecord *const rr) { switch (rr->rrtype) { @@ -1490,8 +1736,51 @@ mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNS *ptr++ = rr->rdata->u.ipv4.b[3]; return(ptr); - case kDNSType_CNAME:// Same as PTR - case kDNSType_PTR: return(putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.name)); + case kDNSType_NS: + case kDNSType_CNAME: + case kDNSType_PTR: + case kDNSType_DNAME:return(putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.name)); + + case kDNSType_SOA: ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.soa.mname); + if (!ptr) return(mDNSNULL); + ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.soa.rname); + if (!ptr || ptr + 20 > limit) return(mDNSNULL); + ptr = putVal32(ptr, rr->rdata->u.soa.serial); + ptr = putVal32(ptr, rr->rdata->u.soa.refresh); + ptr = putVal32(ptr, rr->rdata->u.soa.retry); + ptr = putVal32(ptr, rr->rdata->u.soa.expire); + ptr = putVal32(ptr, rr->rdata->u.soa.min); + return(ptr); + + case kDNSType_NULL: + case kDNSType_HINFO: + case kDNSType_TSIG: + case kDNSType_TXT: + case kDNSType_X25: + case kDNSType_ISDN: + case kDNSType_LOC: + case kDNSType_DHCID:if (ptr + rr->rdlength > limit) return(mDNSNULL); + mDNSPlatformMemCopy(ptr, rr->rdata->u.data, rr->rdlength); + return(ptr + rr->rdlength); + + case kDNSType_MX: + case kDNSType_AFSDB: + case kDNSType_RT: + case kDNSType_KX: if (ptr + 3 > limit) return(mDNSNULL); + ptr = putVal16(ptr, rr->rdata->u.mx.preference); + return(putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.mx.exchange)); + + case kDNSType_RP: ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.rp.mbox); + if (!ptr) return(mDNSNULL); + ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.rp.txt); + return(ptr); + + case kDNSType_PX: if (ptr + 5 > limit) return(mDNSNULL); + ptr = putVal16(ptr, rr->rdata->u.px.preference); + ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.px.map822); + if (!ptr) return(mDNSNULL); + ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.px.mapx400); + return(ptr); case kDNSType_AAAA: if (rr->rdlength != sizeof(rr->rdata->u.ipv6)) { @@ -1499,10 +1788,10 @@ mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNS return(mDNSNULL); } if (ptr + sizeof(rr->rdata->u.ipv6) > limit) return(mDNSNULL); - mDNSPlatformMemCopy(&rr->rdata->u.ipv6, ptr, sizeof(rr->rdata->u.ipv6)); + mDNSPlatformMemCopy(ptr, &rr->rdata->u.ipv6, sizeof(rr->rdata->u.ipv6)); return(ptr + sizeof(rr->rdata->u.ipv6)); - case kDNSType_SRV: if (ptr + 6 > limit) return(mDNSNULL); + case kDNSType_SRV: if (ptr + 7 > limit) return(mDNSNULL); *ptr++ = (mDNSu8)(rr->rdata->u.srv.priority >> 8); *ptr++ = (mDNSu8)(rr->rdata->u.srv.priority & 0xFF); *ptr++ = (mDNSu8)(rr->rdata->u.srv.weight >> 8); @@ -1510,20 +1799,19 @@ mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNS *ptr++ = rr->rdata->u.srv.port.b[0]; *ptr++ = rr->rdata->u.srv.port.b[1]; return(putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.srv.target)); + case kDNSType_OPT: return putOptRData(ptr, limit, rr); default: debugf("putRData: Warning! Writing unknown resource type %d as raw data", rr->rrtype); - // Fall through to common code below - case kDNSType_HINFO: - case kDNSType_TXT: - case kDNSType_TSIG: if (ptr + rr->rdlength > limit) return(mDNSNULL); - mDNSPlatformMemCopy(rr->rdata->u.data, ptr, rr->rdlength); + if (ptr + rr->rdlength > limit) return(mDNSNULL); + mDNSPlatformMemCopy(ptr, rr->rdata->u.data, rr->rdlength); return(ptr + rr->rdlength); } } mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 ttl, const mDNSu8 *limit) { + mDNSu16 rrclass = (rr->rrtype == kDNSType_OPT) ? NormalMaxDNSMessageData : rr->rrclass; mDNSu8 *endofrdata; mDNSu16 actualLength; @@ -1533,12 +1821,14 @@ mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 * return(ptr); } + if (!ptr) { LogMsg("PutResourceRecordTTLWithLimit ptr is null"); return(mDNSNULL); } + ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name); if (!ptr || ptr + 10 >= limit) return(mDNSNULL); // If we're out-of-space, return mDNSNULL ptr[0] = (mDNSu8)(rr->rrtype >> 8); ptr[1] = (mDNSu8)(rr->rrtype & 0xFF); - ptr[2] = (mDNSu8)(rr->rrclass >> 8); - ptr[3] = (mDNSu8)(rr->rrclass & 0xFF); + ptr[2] = (mDNSu8)(rrclass >> 8); + ptr[3] = (mDNSu8)(rrclass & 0xFF); ptr[4] = (mDNSu8)((ttl >> 24) & 0xFF); ptr[5] = (mDNSu8)((ttl >> 16) & 0xFF); ptr[6] = (mDNSu8)((ttl >> 8) & 0xFF); @@ -1605,26 +1895,21 @@ mDNSexport mDNSu8 *putZone(DNSMessage *const msg, mDNSu8 *ptr, mDNSu8 *limit, co } // for dynamic updates -mDNSexport mDNSu8 *putPrereqNameNotInUse(domainname *name, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *end) +mDNSexport mDNSu8 *putPrereqNameNotInUse(const domainname *const name, DNSMessage *const msg, mDNSu8 *const ptr, mDNSu8 *const end) { AuthRecord prereq; - - mDNSPlatformMemZero(&prereq, sizeof(AuthRecord)); mDNS_SetupResourceRecord(&prereq, mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, mDNSNULL, mDNSNULL); - AssignDomainName(prereq.resrec.name, name); + AssignDomainName(&prereq.namestorage, name); prereq.resrec.rrtype = kDNSQType_ANY; prereq.resrec.rrclass = kDNSClass_NONE; - ptr = putEmptyResourceRecord(msg, ptr, end, &msg->h.mDNS_numPrereqs, &prereq); - return ptr; + return putEmptyResourceRecord(msg, ptr, end, &msg->h.mDNS_numPrereqs, &prereq); } // for dynamic updates mDNSexport mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr) { - mDNSu16 origclass; // deletion: specify record w/ TTL 0, class NONE - - origclass = rr->rrclass; + const mDNSu16 origclass = rr->rrclass; rr->rrclass = kDNSClass_NONE; ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.mDNS_numUpdates, rr, 0); rr->rrclass = origclass; @@ -1673,24 +1958,15 @@ mDNSexport mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domain mDNSexport mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease) { AuthRecord rr; - ResourceRecord *opt = &rr.resrec; - rdataOpt *optRD; - - mDNSPlatformMemZero(&rr, sizeof(AuthRecord)); - mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, 0, mDNSNULL, mDNSNULL); - - opt->RecordType = kDNSRecordTypeKnownUnique; // to avoid warnings in other layers - opt->rrtype = kDNSType_OPT; - opt->rdlength = LEASE_OPT_RDLEN; - opt->rdestimate = LEASE_OPT_RDLEN; - - optRD = &rr.resrec.rdata->u.opt; - optRD->opt = kDNSOpt_Lease; - optRD->optlen = sizeof(mDNSs32); - optRD->OptData.lease = lease; - end = PutResourceRecordTTLJumbo(msg, end, &msg->h.numAdditionals, opt, 0); + mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL); + rr.resrec.rrclass = NormalMaxDNSMessageData; + rr.resrec.rdlength = LEASE_OPT_RDLEN; + rr.resrec.rdestimate = LEASE_OPT_RDLEN; + rr.resrec.rdata->u.opt.opt = kDNSOpt_Lease; + rr.resrec.rdata->u.opt.optlen = sizeof(mDNSs32); + rr.resrec.rdata->u.opt.OptData.updatelease = lease; + end = PutResourceRecordTTLJumbo(msg, end, &msg->h.numAdditionals, &rr.resrec, 0); if (!end) { LogMsg("ERROR: putUpdateLease - PutResourceRecordTTL"); return mDNSNULL; } - return end; } @@ -1824,7 +2100,7 @@ mDNSexport const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8 return(ptr + pktrdlength); } -mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage * const msg, const mDNSu8 *ptr, +mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *largecr) { CacheRecord *rr = &largecr->r; @@ -1851,10 +2127,10 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage rr->NextInCFList = mDNSNULL; rr->resrec.InterfaceID = InterfaceID; - ptr = getDomainName(msg, ptr, end, rr->resrec.name); - if (!ptr) { debugf("GetResourceRecord: Malformed RR name"); return(mDNSNULL); } + ptr = getDomainName(msg, ptr, end, &largecr->namestorage); + if (!ptr) { debugf("GetLargeResourceRecord: Malformed RR name"); return(mDNSNULL); } - if (ptr + 10 > end) { debugf("GetResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); } + if (ptr + 10 > end) { debugf("GetLargeResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); } rr->resrec.rrtype = (mDNSu16) ((mDNSu16)ptr[0] << 8 | ptr[1]); rr->resrec.rrclass = (mDNSu16)(((mDNSu16)ptr[2] << 8 | ptr[3]) & kDNSClass_Mask); @@ -1864,10 +2140,14 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage // Note: We don't have to adjust m->NextCacheCheck here -- this is just getting a record into memory for // us to look at. If we decide to copy it into the cache, then we'll update m->NextCacheCheck accordingly. pktrdlength = (mDNSu16)((mDNSu16)ptr[8] << 8 | ptr[9]); - if (ptr[2] & (kDNSClass_UniqueRRSet >> 8)) + + // If mDNS record has cache-flush bit set, we mark it unique + // For uDNS records, all are implicitly deemed unique (a single DNS server is always + // authoritative for the entire RRSet), unless this is a truncated response + if (ptr[2] & (kDNSClass_UniqueRRSet >> 8) || (!InterfaceID && !(msg->h.flags.b[0] & kDNSFlag0_TC))) RecordType |= kDNSRecordTypePacketUniqueMask; ptr += 10; - if (ptr + pktrdlength > end) { debugf("GetResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); } + if (ptr + pktrdlength > end) { debugf("GetLargeResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); } end = ptr + pktrdlength; // Adjust end to indicate the end of the rdata for this resource record rr->resrec.rdata = (RData*)&rr->rdatastorage; @@ -1875,66 +2155,107 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage if (!RecordType) LogMsg("GetLargeResourceRecord: No RecordType for %##s", rr->resrec.name->c); - switch (rr->resrec.rrtype) + // IMPORTANT: Any record type we understand and unpack into a structure containing domainnames needs to have + // a corresponding case in SameRDataBody() to do a semantic comparison of the structure instead of a blind + // bitwise memory compare. This is because a domainname is a fixed size structure holding variable-length data. + // Any bytes past the logical end of the name are undefined, and a blind bitwise memory compare may indicate that + // two domainnames are different when semantically they are the same name and it's only the unused bytes that differ. + if (rr->resrec.rrclass == kDNSQClass_ANY && pktrdlength == 0) // Used in update packets to mean "Delete An RRset" (RFC 2136) + rr->resrec.rdlength = 0; + else switch (rr->resrec.rrtype) { - case kDNSType_A: rr->resrec.rdata->u.ipv4.b[0] = ptr[0]; + case kDNSType_A: if (pktrdlength != sizeof(mDNSv4Addr)) return(mDNSNULL); + rr->resrec.rdata->u.ipv4.b[0] = ptr[0]; rr->resrec.rdata->u.ipv4.b[1] = ptr[1]; rr->resrec.rdata->u.ipv4.b[2] = ptr[2]; rr->resrec.rdata->u.ipv4.b[3] = ptr[3]; break; - case kDNSType_CNAME:// Same as PTR case kDNSType_NS: - case kDNSType_PTR: if (!getDomainName(msg, ptr, end, &rr->resrec.rdata->u.name)) - { debugf("GetResourceRecord: Malformed CNAME/PTR RDATA name"); return(mDNSNULL); } + case kDNSType_CNAME: + case kDNSType_PTR: + case kDNSType_DNAME:ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.name); + if (ptr != end) { debugf("GetLargeResourceRecord: Malformed CNAME/PTR RDATA name"); return(mDNSNULL); } //debugf("%##s PTR %##s rdlen %d", rr->resrec.name.c, rr->resrec.rdata->u.name.c, pktrdlength); break; - case kDNSType_NULL: //Same as TXT - case kDNSType_HINFO://Same as TXT - case kDNSType_TXT: if (pktrdlength > rr->resrec.rdata->MaxRDLength) + case kDNSType_SOA: ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.soa.mname); + if (!ptr) { debugf("GetLargeResourceRecord: Malformed SOA RDATA mname"); return mDNSNULL; } + ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.soa.rname); + if (!ptr) { debugf("GetLargeResourceRecord: Malformed SOA RDATA rname"); return mDNSNULL; } + if (ptr + 0x14 != end) { debugf("GetLargeResourceRecord: Malformed SOA RDATA"); return mDNSNULL; } + rr->resrec.rdata->u.soa.serial = (mDNSs32) ((mDNSs32)ptr[0x00] << 24 | (mDNSs32)ptr[0x01] << 16 | (mDNSs32)ptr[0x02] << 8 | ptr[0x03]); + rr->resrec.rdata->u.soa.refresh = (mDNSu32) ((mDNSu32)ptr[0x04] << 24 | (mDNSu32)ptr[0x05] << 16 | (mDNSu32)ptr[0x06] << 8 | ptr[0x07]); + rr->resrec.rdata->u.soa.retry = (mDNSu32) ((mDNSu32)ptr[0x08] << 24 | (mDNSu32)ptr[0x09] << 16 | (mDNSu32)ptr[0x0A] << 8 | ptr[0x0B]); + rr->resrec.rdata->u.soa.expire = (mDNSu32) ((mDNSu32)ptr[0x0C] << 24 | (mDNSu32)ptr[0x0D] << 16 | (mDNSu32)ptr[0x0E] << 8 | ptr[0x0F]); + rr->resrec.rdata->u.soa.min = (mDNSu32) ((mDNSu32)ptr[0x10] << 24 | (mDNSu32)ptr[0x11] << 16 | (mDNSu32)ptr[0x12] << 8 | ptr[0x13]); + break; + + case kDNSType_NULL: + case kDNSType_HINFO: + case kDNSType_TSIG: + case kDNSType_TXT: + case kDNSType_X25: + case kDNSType_ISDN: + case kDNSType_LOC: + case kDNSType_DHCID:if (pktrdlength > rr->resrec.rdata->MaxRDLength) { - debugf("GetResourceRecord: %s rdata size (%d) exceeds storage (%d)", + debugf("GetLargeResourceRecord: %s rdata size (%d) exceeds storage (%d)", DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength); return(mDNSNULL); } rr->resrec.rdlength = pktrdlength; - mDNSPlatformMemCopy(ptr, rr->resrec.rdata->u.data, pktrdlength); + mDNSPlatformMemCopy(rr->resrec.rdata->u.data, ptr, pktrdlength); break; - case kDNSType_AAAA: mDNSPlatformMemCopy(ptr, &rr->resrec.rdata->u.ipv6, sizeof(rr->resrec.rdata->u.ipv6)); + case kDNSType_MX: + case kDNSType_AFSDB: + case kDNSType_RT: + case kDNSType_KX: if (pktrdlength < 3) return(mDNSNULL); // Preference + domainname + rr->resrec.rdata->u.mx.preference = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); + ptr = getDomainName(msg, ptr+2, end, &rr->resrec.rdata->u.mx.exchange); + if (ptr != end) { debugf("GetLargeResourceRecord: Malformed MX name"); return(mDNSNULL); } + //debugf("%##s SRV %##s rdlen %d", rr->resrec.name.c, rr->resrec.rdata->u.srv.target.c, pktrdlength); + break; + + case kDNSType_RP: ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.rp.mbox); // Domainname + domainname + if (!ptr) { debugf("GetLargeResourceRecord: Malformed RP mbox"); return mDNSNULL; } + ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.rp.txt); + if (ptr != end) { debugf("GetLargeResourceRecord: Malformed RP txt"); return mDNSNULL; } + break; + + case kDNSType_PX: if (pktrdlength < 4) return(mDNSNULL); // Preference + domainname + domainname + rr->resrec.rdata->u.px.preference = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); + ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.px.map822); + if (!ptr) { debugf("GetLargeResourceRecord: Malformed PX map822"); return mDNSNULL; } + ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.px.mapx400); + if (ptr != end) { debugf("GetLargeResourceRecord: Malformed PX mapx400"); return mDNSNULL; } break; - case kDNSType_SRV: rr->resrec.rdata->u.srv.priority = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); + case kDNSType_AAAA: if (pktrdlength != sizeof(mDNSv6Addr)) return(mDNSNULL); + mDNSPlatformMemCopy(&rr->resrec.rdata->u.ipv6, ptr, sizeof(rr->resrec.rdata->u.ipv6)); + break; + + case kDNSType_SRV: if (pktrdlength < 7) return(mDNSNULL); // Priority + weight + port + domainname + rr->resrec.rdata->u.srv.priority = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); rr->resrec.rdata->u.srv.weight = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]); rr->resrec.rdata->u.srv.port.b[0] = ptr[4]; rr->resrec.rdata->u.srv.port.b[1] = ptr[5]; - if (!getDomainName(msg, ptr+6, end, &rr->resrec.rdata->u.srv.target)) - { debugf("GetResourceRecord: Malformed SRV RDATA name"); return(mDNSNULL); } + ptr = getDomainName(msg, ptr+6, end, &rr->resrec.rdata->u.srv.target); + if (ptr != end) { debugf("GetLargeResourceRecord: Malformed SRV RDATA name"); return(mDNSNULL); } //debugf("%##s SRV %##s rdlen %d", rr->resrec.name.c, rr->resrec.rdata->u.srv.target.c, pktrdlength); break; - case kDNSType_SOA: ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.soa.mname); - if (!ptr) { debugf("GetResourceRecord: Malformed SOA RDATA mname"); return mDNSNULL; } - ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.soa.rname); - if (!ptr) { debugf("GetResourceRecord: Malformed SOA RDATA rname"); return mDNSNULL; } - if (ptr + 0x14 != end) { debugf("GetResourceRecord: Malformed SOA RDATA"); return mDNSNULL; } - rr->resrec.rdata->u.soa.serial = (mDNSs32) ((mDNSs32)ptr[0x00] << 24 | (mDNSs32)ptr[0x01] << 16 | (mDNSs32)ptr[0x02] << 8 | ptr[0x03]); - rr->resrec.rdata->u.soa.refresh = (mDNSu32) ((mDNSu32)ptr[0x04] << 24 | (mDNSu32)ptr[0x05] << 16 | (mDNSu32)ptr[0x06] << 8 | ptr[0x07]); - rr->resrec.rdata->u.soa.retry = (mDNSu32) ((mDNSu32)ptr[0x08] << 24 | (mDNSu32)ptr[0x09] << 16 | (mDNSu32)ptr[0x0A] << 8 | ptr[0x0B]); - rr->resrec.rdata->u.soa.expire = (mDNSu32) ((mDNSu32)ptr[0x0C] << 24 | (mDNSu32)ptr[0x0D] << 16 | (mDNSu32)ptr[0x0E] << 8 | ptr[0x0F]); - rr->resrec.rdata->u.soa.min = (mDNSu32) ((mDNSu32)ptr[0x10] << 24 | (mDNSu32)ptr[0x11] << 16 | (mDNSu32)ptr[0x12] << 8 | ptr[0x13]); - break; - - case kDNSType_OPT: getOptRdata(ptr, end, largecr, pktrdlength); break; + case kDNSType_OPT: ptr = getOptRdata(ptr, end, largecr, pktrdlength); break; + if (ptr != end) { LogMsg("GetLargeResourceRecord: Malformed OptRdata"); return(mDNSNULL); } default: if (pktrdlength > rr->resrec.rdata->MaxRDLength) { - debugf("GetResourceRecord: rdata %d (%s) size (%d) exceeds storage (%d)", + debugf("GetLargeResourceRecord: rdata %d (%s) size (%d) exceeds storage (%d)", rr->resrec.rrtype, DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength); return(mDNSNULL); } - debugf("GetResourceRecord: Warning! Reading resource type %d (%s) as opaque data", + debugf("GetLargeResourceRecord: Warning! Reading resource type %d (%s) as opaque data", rr->resrec.rrtype, DNSTypeName(rr->resrec.rrtype)); // Note: Just because we don't understand the record type, that doesn't // mean we fail. The DNS protocol specifies rdlength, so we can @@ -1942,16 +2263,16 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage // We also grab a binary copy of the rdata anyway, since the caller // might know how to interpret it even if we don't. rr->resrec.rdlength = pktrdlength; - mDNSPlatformMemCopy(ptr, rr->resrec.rdata->u.data, pktrdlength); + mDNSPlatformMemCopy(rr->resrec.rdata->u.data, ptr, pktrdlength); break; } rr->resrec.namehash = DomainNameHashValue(rr->resrec.name); - SetNewRData(&rr->resrec, mDNSNULL, 0); + SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rdlength, rdestimate, rdatahash for us // Success! Now fill in RecordType to show this record contains valid data rr->resrec.RecordType = RecordType; - return(ptr + pktrdlength); + return(end); } mDNSexport const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end) @@ -1965,6 +2286,7 @@ mDNSexport const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, mDNSexport const mDNSu8 *getQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end, const mDNSInterfaceID InterfaceID, DNSQuestion *question) { + mDNSPlatformMemZero(question, sizeof(*question)); question->InterfaceID = InterfaceID; ptr = getDomainName(msg, ptr, end, &question->qname); if (!ptr) { debugf("Malformed domain name in DNS question section"); return(mDNSNULL); } @@ -2000,19 +2322,172 @@ mDNSexport const mDNSu8 *LocateAdditionals(const DNSMessage *const msg, const mD return (ptr); } +mDNSexport const mDNSu8 *LocateLLQOptData(const DNSMessage *const msg, const mDNSu8 *const end) + { + int i; + const mDNSu8 *ptr = LocateAdditionals(msg, end); + + // Locate the OPT record. + // According to RFC 2671, "One OPT pseudo-RR can be added to the additional data section of either a request or a response." + // This implies that there may be *at most* one OPT record per DNS message, in the Additional Section, + // but not necessarily the *last* entry in the Additional Section. + for (i = 0; ptr && i < msg->h.numAdditionals; i++) + { + if (ptr + 10 + LLQ_OPT_RDLEN <= end && // Make sure we have 10+22 bytes of data + ptr[0] == 0 && // Name must be root label + ptr[1] == (kDNSType_OPT >> 8 ) && // rrtype OPT + ptr[2] == (kDNSType_OPT & 0xFF) && + ((mDNSu16)ptr[9] << 8 | (mDNSu16)ptr[10]) >= (mDNSu16)LLQ_OPT_RDLEN) + return(ptr); + else + ptr = skipResourceRecord(msg, ptr, end); + } + return(mDNSNULL); + } + +// On success, GetLLQOptData returns pointer to storage within shared "m->rec"; +// it is callers responsibilty to clear m->rec.r.resrec.RecordType after use +// Note: An OPT RDataBody actually contains one or more variable-length rdataOPT objects packed together +// The code that currently calls this assumes there's only one, instead of iterating through the set +mDNSexport const rdataOPT *GetLLQOptData(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end) + { + const mDNSu8 *ptr = LocateLLQOptData(msg, end); + if (ptr) + { + ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec); + if (ptr) return(&m->rec.r.resrec.rdata->u.opt); + } + return(mDNSNULL); + } + +mDNSexport const mDNSu8 *LocateLeaseOptData(const DNSMessage *const msg, const mDNSu8 *const end) + { + int i; + const mDNSu8 *ptr = LocateAdditionals(msg, end); + + // Locate the OPT record. + // According to RFC 2671, "One OPT pseudo-RR can be added to the additional data section of either a request or a response." + // This implies that there may be *at most* one OPT record per DNS message, in the Additional Section, + // but not necessarily the *last* entry in the Additional Section. + for (i = 0; ptr && i < msg->h.numAdditionals; i++) + { + if (ptr + 10 + LEASE_OPT_RDLEN <= end && // Make sure we have 10+8 bytes of data + ptr[0] == 0 && // Name must be root label + ptr[1] == (kDNSType_OPT >> 8 ) && // rrtype OPT + ptr[2] == (kDNSType_OPT & 0xFF) && + ((mDNSu16)ptr[9] << 8 | (mDNSu16)ptr[10]) >= (mDNSu16)LEASE_OPT_RDLEN) + return(ptr); + else + ptr = skipResourceRecord(msg, ptr, end); + } + return(mDNSNULL); + } + +// 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) + { + mDNSu32 result = 0; + const mDNSu8 *ptr = LocateLeaseOptData(msg, end); + if (ptr) ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec); + if (ptr && m->rec.r.resrec.rdlength >= LEASE_OPT_RDLEN && m->rec.r.resrec.rdata->u.opt.opt == kDNSOpt_Lease) + result = m->rec.r.resrec.rdata->u.opt.OptData.updatelease; + m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it + return(result); + } + +mDNSlocal const mDNSu8 *DumpRecords(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end, int count, char *label) + { + int i; + LogMsg("%2d %s", count, label); + for (i = 0; i < count && ptr; i++) + { + // This puts a LargeCacheRecord on the stack instead of using the shared m->rec storage, + // but since it's only used for debugging (and probably only on OS X, not on + // embedded systems) putting a 9kB object on the stack isn't a big problem. + LargeCacheRecord largecr; + ptr = GetLargeResourceRecord(m, msg, ptr, end, mDNSInterface_Any, kDNSRecordTypePacketAns, &largecr); + if (ptr) LogMsg("%2d TTL%7d %s", i, largecr.r.resrec.rroriginalttl, CRDisplayString(m, &largecr.r)); + } + if (!ptr) LogMsg("ERROR: Premature end of packet data"); + return(ptr); + } + +#define DNS_OP_Name(X) ( \ + (X) == kDNSFlag0_OP_StdQuery ? "" : \ + (X) == kDNSFlag0_OP_Iquery ? "Iquery " : \ + (X) == kDNSFlag0_OP_Status ? "Status " : \ + (X) == kDNSFlag0_OP_Unused3 ? "Unused3 " : \ + (X) == kDNSFlag0_OP_Notify ? "Notify " : \ + (X) == kDNSFlag0_OP_Update ? "Update " : "?? " ) + +#define DNS_RC_Name(X) ( \ + (X) == kDNSFlag1_RC_NoErr ? "NoErr" : \ + (X) == kDNSFlag1_RC_FmtErr ? "FmtErr" : \ + (X) == kDNSFlag1_RC_SrvErr ? "SrvErr" : \ + (X) == kDNSFlag1_RC_NXDomain ? "NXDomain" : \ + (X) == kDNSFlag1_RC_NotImpl ? "NotImpl" : \ + (X) == kDNSFlag1_RC_Refused ? "Refused" : \ + (X) == kDNSFlag1_RC_YXDomain ? "YXDomain" : \ + (X) == kDNSFlag1_RC_YXRRSet ? "YXRRSet" : \ + (X) == kDNSFlag1_RC_NXRRSet ? "NXRRSet" : \ + (X) == kDNSFlag1_RC_NotAuth ? "NotAuth" : \ + (X) == kDNSFlag1_RC_NotZone ? "NotZone" : "??" ) + +// Note: DumpPacket expects the packet header fields in host byte order, not network byte order +mDNSexport void DumpPacket(mDNS *const m, mDNSBool sent, char *transport, const mDNSAddr *addr, mDNSIPPort port, const DNSMessage *const msg, const mDNSu8 *const end) + { + mDNSBool IsUpdate = ((msg->h.flags.b[0] & kDNSFlag0_OP_Mask) == kDNSFlag0_OP_Update); + const mDNSu8 *ptr = msg->data; + int i; + DNSQuestion q; + + LogMsg("-- %s %s DNS %s%s (flags %02X%02X) RCODE: %s (%d) %s%s%s%s%s%sID: %d %d bytes %s %#a:%d%s --", + sent ? "Sent" : "Received", transport, + DNS_OP_Name(msg->h.flags.b[0] & kDNSFlag0_OP_Mask), + msg->h.flags.b[0] & kDNSFlag0_QR_Response ? "Response" : "Query", + msg->h.flags.b[0], msg->h.flags.b[1], + DNS_RC_Name(msg->h.flags.b[1] & kDNSFlag1_RC_Mask), + msg->h.flags.b[1] & kDNSFlag1_RC_Mask, + msg->h.flags.b[0] & kDNSFlag0_AA ? "AA " : "", + msg->h.flags.b[0] & kDNSFlag0_TC ? "TC " : "", + msg->h.flags.b[0] & kDNSFlag0_RD ? "RD " : "", + msg->h.flags.b[1] & kDNSFlag1_RA ? "RA " : "", + msg->h.flags.b[1] & kDNSFlag1_AD ? "AD " : "", + msg->h.flags.b[1] & kDNSFlag1_CD ? "CD " : "", + mDNSVal16(msg->h.id), + end - msg->data, + sent ? "to" : "from", addr, mDNSVal16(port), + (msg->h.flags.b[0] & kDNSFlag0_TC) ? " (truncated)" : "" + ); + + LogMsg("%2d %s", msg->h.numQuestions, IsUpdate ? "Zone" : "Questions"); + for (i = 0; i < msg->h.numQuestions && ptr; i++) + { + ptr = getQuestion(msg, ptr, end, mDNSInterface_Any, &q); + if (ptr) LogMsg("%2d %##s %s", i, q.qname.c, DNSTypeName(q.qtype)); + } + ptr = DumpRecords(m, msg, ptr, end, msg->h.numAnswers, IsUpdate ? "Prerequisites" : "Answers"); + ptr = DumpRecords(m, msg, ptr, end, msg->h.numAuthorities, IsUpdate ? "Updates" : "Authorities"); + ptr = DumpRecords(m, msg, ptr, end, msg->h.numAdditionals, "Additionals"); + LogMsg("--------------"); + } + // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - -#pragma mark - #pragma mark - Packet Sending Functions #endif -mDNSexport mStatus mDNSSendDNSMessage(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end, - mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, int sd, uDNS_AuthInfo *authInfo) +// Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.) +struct TCPSocket_struct { TCPSocketFlags flags; /* ... */ }; + +mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end, + mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo) { mStatus status; - int nsent; - mDNSs32 msglen; + long nsent; + unsigned long msglen; mDNSu8 lenbuf[2]; mDNSu16 numQuestions = msg->h.numQuestions; mDNSu16 numAnswers = msg->h.numAnswers; @@ -2032,22 +2507,23 @@ mDNSexport mStatus mDNSSendDNSMessage(const mDNS *const m, DNSMessage *const msg if (authInfo) { - end = DNSDigest_SignMessage(msg, &end, &numAdditionals, authInfo); + end = DNSDigest_SignMessage(msg, &end, authInfo, 0); if (!end) return mStatus_UnknownErr; } // Send the packet on the wire - - if (sd >= 0) + if (sock) { msglen = (mDNSu16)(end - (mDNSu8 *)msg); lenbuf[0] = (mDNSu8)(msglen >> 8); // host->network byte conversion lenbuf[1] = (mDNSu8)(msglen & 0xFF); - nsent = mDNSPlatformWriteTCP(sd, (char*)lenbuf, 2); + + nsent = mDNSPlatformWriteTCP(sock, (char*)lenbuf, 2); //!!!KRS make sure kernel is sending these as 1 packet! if (nsent != 2) goto tcp_error; - nsent = mDNSPlatformWriteTCP(sd, (char *)msg, msglen); - if (nsent != msglen) goto tcp_error; + + nsent = mDNSPlatformWriteTCP(sock, (char *)msg, msglen); + if (nsent != (long)msglen) goto tcp_error; status = mStatus_NoError; } else @@ -2059,7 +2535,14 @@ mDNSexport mStatus mDNSSendDNSMessage(const mDNS *const m, DNSMessage *const msg msg->h.numQuestions = numQuestions; msg->h.numAnswers = numAnswers; msg->h.numAuthorities = numAuthorities; - msg->h.numAdditionals = (mDNSu16)(authInfo ? numAdditionals - 1 : numAdditionals); + msg->h.numAdditionals = numAdditionals; + + if (mDNS_LogLevel >= MDNS_LOG_VERBOSE_DEBUG && !mDNSOpaque16IsZero(msg->h.id)) + { + if (authInfo) msg->h.numAdditionals++; // Want to include TSIG in DumpPacket output + DumpPacket(m, mDNStrue, sock && (sock->flags & kTCPSocketFlags_UseTLS) ? "TLS" : sock ? "TCP" : "UDP", dst, dstport, msg, end); + if (authInfo) msg->h.numAdditionals--; + } return(status); @@ -2074,7 +2557,7 @@ mDNSexport mStatus mDNSSendDNSMessage(const mDNS *const m, DNSMessage *const msg #pragma mark - RR List Management & Task Management #endif -mDNSexport void mDNS_Lock(mDNS *const m) +mDNSexport void mDNS_Lock_(mDNS *const m) { // MUST grab the platform lock FIRST! mDNSPlatformLock(m); @@ -2083,8 +2566,13 @@ mDNSexport void mDNS_Lock(mDNS *const m) // However, when we call a client callback mDNS_busy is one, and we increment mDNS_reentrancy too // If that client callback does mDNS API calls, mDNS_reentrancy and mDNS_busy will both be one // If mDNS_busy != mDNS_reentrancy that's a bad sign +#if ForceAlerts if (m->mDNS_busy != m->mDNS_reentrancy) + { LogMsg("mDNS_Lock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); + *(long*)0 = 0; + } +#endif // If this is an initial entry into the mDNSCore code, set m->timenow // else, if this is a re-entrant entry into the mDNSCore code, m->timenow should already be set @@ -2127,23 +2615,29 @@ mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m) if (m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords)) return(m->timenow); if (m->SuppressSending) return(m->SuppressSending); #ifndef UNICAST_DISABLED - if (e - m->uDNS_info.nextevent > 0) e = m->uDNS_info.nextevent; + if (e - m->NextuDNSEvent > 0) e = m->NextuDNSEvent; #endif if (e - m->NextCacheCheck > 0) e = m->NextCacheCheck; if (e - m->NextScheduledQuery > 0) e = m->NextScheduledQuery; if (e - m->NextScheduledProbe > 0) e = m->NextScheduledProbe; if (e - m->NextScheduledResponse > 0) e = m->NextScheduledResponse; + if (e - m->NextScheduledNATOp > 0) e = m->NextScheduledNATOp; return(e); } -mDNSexport void mDNS_Unlock(mDNS *const m) +mDNSexport void mDNS_Unlock_(mDNS *const m) { // Decrement mDNS_busy m->mDNS_busy--; // Check for locking failures +#if ForceAlerts if (m->mDNS_busy != m->mDNS_reentrancy) + { LogMsg("mDNS_Unlock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); + *(long*)0 = 0; + } +#endif // If this is a final exit from the mDNSCore code, set m->NextScheduledEvent and clear m->timenow if (m->mDNS_busy == 0) @@ -2156,3 +2650,313 @@ mDNSexport void mDNS_Unlock(mDNS *const m) // MUST release the platform lock LAST! mDNSPlatformUnlock(m); } + +// *************************************************************************** +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - +#pragma mark - Specialized mDNS version of vsnprintf +#endif + +static const struct mDNSprintf_format + { + unsigned leftJustify : 1; + unsigned forceSign : 1; + unsigned zeroPad : 1; + unsigned havePrecision : 1; + unsigned hSize : 1; + unsigned lSize : 1; + char altForm; + char sign; // +, - or space + unsigned int fieldWidth; + unsigned int precision; + } mDNSprintf_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg) + { + mDNSu32 nwritten = 0; + int c; + if (buflen == 0) return(0); + buflen--; // Pre-reserve one space in the buffer for the terminating null + if (buflen == 0) goto exit; + + for (c = *fmt; c != 0; c = *++fmt) + { + if (c != '%') + { + *sbuffer++ = (char)c; + if (++nwritten >= buflen) goto exit; + } + else + { + unsigned int i=0, j; + // The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for + // generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc. + // The size needs to be enough for a 256-byte domain name plus some error text. + #define mDNS_VACB_Size 300 + char mDNS_VACB[mDNS_VACB_Size]; + #define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size]) + #define mDNS_VACB_Remain(s) ((mDNSu32)(mDNS_VACB_Lim - s)) + char *s = mDNS_VACB_Lim, *digits; + struct mDNSprintf_format F = mDNSprintf_format_default; + + while (1) // decode flags + { + c = *++fmt; + if (c == '-') F.leftJustify = 1; + else if (c == '+') F.forceSign = 1; + else if (c == ' ') F.sign = ' '; + else if (c == '#') F.altForm++; + else if (c == '0') F.zeroPad = 1; + else break; + } + + if (c == '*') // decode field width + { + int f = va_arg(arg, int); + if (f < 0) { f = -f; F.leftJustify = 1; } + F.fieldWidth = (unsigned int)f; + c = *++fmt; + } + else + { + for (; c >= '0' && c <= '9'; c = *++fmt) + F.fieldWidth = (10 * F.fieldWidth) + (c - '0'); + } + + if (c == '.') // decode precision + { + if ((c = *++fmt) == '*') + { F.precision = va_arg(arg, unsigned int); c = *++fmt; } + else for (; c >= '0' && c <= '9'; c = *++fmt) + F.precision = (10 * F.precision) + (c - '0'); + F.havePrecision = 1; + } + + if (F.leftJustify) F.zeroPad = 0; + + 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; + case 'd' : + case 'i' : if (F.lSize) n = (unsigned long)va_arg(arg, long); + else n = (unsigned long)va_arg(arg, int); + if (F.hSize) n = (short) n; + if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; } + else if (F.forceSign) F.sign = '+'; + goto decimal; + case 'u' : if (F.lSize) n = va_arg(arg, unsigned long); + else n = va_arg(arg, unsigned int); + if (F.hSize) n = (unsigned short) n; + F.sign = 0; + goto decimal; + decimal: if (!F.havePrecision) + { + if (F.zeroPad) + { + F.precision = F.fieldWidth; + if (F.sign) --F.precision; + } + if (F.precision < 1) F.precision = 1; + } + if (F.precision > mDNS_VACB_Size - 1) + F.precision = mDNS_VACB_Size - 1; + for (i = 0; n; n /= 10, i++) *--s = (char)(n % 10 + '0'); + for (; i < F.precision; i++) *--s = '0'; + if (F.sign) { *--s = F.sign; i++; } + break; + + case 'o' : if (F.lSize) n = va_arg(arg, unsigned long); + else n = va_arg(arg, unsigned int); + if (F.hSize) n = (unsigned short) n; + if (!F.havePrecision) + { + if (F.zeroPad) F.precision = F.fieldWidth; + if (F.precision < 1) F.precision = 1; + } + if (F.precision > mDNS_VACB_Size - 1) + F.precision = mDNS_VACB_Size - 1; + for (i = 0; n; n /= 8, i++) *--s = (char)(n % 8 + '0'); + if (F.altForm && i && *s != '0') { *--s = '0'; i++; } + for (; i < F.precision; i++) *--s = '0'; + break; + + case 'a' : { + unsigned char *a = va_arg(arg, unsigned char *); + if (!a) { static char emsg[] = "<>"; s = emsg; i = sizeof(emsg)-1; } + else + { + s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end + if (F.altForm) + { + mDNSAddr *ip = (mDNSAddr*)a; + switch (ip->type) + { + case mDNSAddrType_IPv4: F.precision = 4; a = (unsigned char *)&ip->ip.v4; break; + case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break; + default: F.precision = 0; break; + } + } + if (F.altForm && !F.precision) + i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "«ZERO ADDRESS»"); + else switch (F.precision) + { + case 4: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d", + a[0], a[1], a[2], a[3]); break; + case 6: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X", + a[0], a[1], a[2], a[3], a[4], a[5]); break; + case 16: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), + "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X", + a[0x0], a[0x1], a[0x2], a[0x3], a[0x4], a[0x5], a[0x6], a[0x7], + a[0x8], a[0x9], a[0xA], a[0xB], a[0xC], a[0xD], a[0xE], a[0xF]); break; + default: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify" + " address size (i.e. %.4a=IPv4, %.6a=Ethernet, %.16a=IPv6) >>"); break; + } + } + } + break; + + case 'p' : F.havePrecision = F.lSize = 1; + F.precision = 8; + case 'X' : digits = "0123456789ABCDEF"; + goto hexadecimal; + case 'x' : digits = "0123456789abcdef"; + hexadecimal:if (F.lSize) n = va_arg(arg, unsigned long); + else n = va_arg(arg, unsigned int); + if (F.hSize) n = (unsigned short) n; + if (!F.havePrecision) + { + if (F.zeroPad) + { + F.precision = F.fieldWidth; + if (F.altForm) F.precision -= 2; + } + if (F.precision < 1) F.precision = 1; + } + if (F.precision > mDNS_VACB_Size - 1) + F.precision = mDNS_VACB_Size - 1; + for (i = 0; n; n /= 16, i++) *--s = digits[n % 16]; + for (; i < F.precision; i++) *--s = '0'; + if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; } + break; + + case 'c' : *--s = (char)va_arg(arg, int); i = 1; break; + + case 's' : s = va_arg(arg, char *); + if (!s) { static char emsg[] = "<>"; s = emsg; i = sizeof(emsg)-1; } + else switch (F.altForm) + { + case 0: i=0; + if (!F.havePrecision) // C string + while (s[i]) i++; + else + { + while ((i < F.precision) && s[i]) i++; + // Make sure we don't truncate in the middle of a UTF-8 character + // If last character we got was any kind of UTF-8 multi-byte character, + // then see if we have to back up. + // This is not as easy as the similar checks below, because + // here we can't assume it's safe to examine the *next* byte, so we + // have to confine ourselves to working only backwards in the string. + j = i; // Record where we got to + // Now, back up until we find first non-continuation-char + while (i>0 && (s[i-1] & 0xC0) == 0x80) i--; + // Now s[i-1] is the first non-continuation-char + // and (j-i) is the number of continuation-chars we found + if (i>0 && (s[i-1] & 0xC0) == 0xC0) // If we found a start-char + { + i--; // Tentatively eliminate this start-char as well + // Now (j-i) is the number of characters we're considering eliminating. + // To be legal UTF-8, the start-char must contain (j-i) one-bits, + // followed by a zero bit. If we shift it right by (7-(j-i)) bits + // (with sign extension) then the result has to be 0xFE. + // If this is right, then we reinstate the tentatively eliminated bytes. + if (((j-i) < 7) && (((s[i] >> (7-(j-i))) & 0xFF) == 0xFE)) i = j; + } + } + break; + case 1: i = (unsigned char) *s++; break; // Pascal string + case 2: { // DNS label-sequence name + unsigned char *a = (unsigned char *)s; + s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end + if (*a == 0) *s++ = '.'; // Special case for root DNS name + while (*a) + { + char buf[63*4+1]; + if (*a > 63) + { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<>", *a); break; } + if (s + *a >= &mDNS_VACB[254]) + { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<>"); break; } + // Need to use ConvertDomainLabelToCString to do proper escaping here, + // so it's clear what's a literal dot and what's a label separator + ConvertDomainLabelToCString((domainlabel*)a, buf); + s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "%s.", buf); + a += 1 + *a; + } + i = (mDNSu32)(s - mDNS_VACB); + s = mDNS_VACB; // Reset s back to the start of the buffer + break; + } + } + // Make sure we don't truncate in the middle of a UTF-8 character (see similar comment below) + if (F.havePrecision && i > F.precision) + { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; } + break; + + case 'n' : s = va_arg(arg, char *); + if (F.hSize) * (short *) s = (short)nwritten; + else if (F.lSize) * (long *) s = (long)nwritten; + else * (int *) s = (int)nwritten; + continue; + + default: s = mDNS_VACB; + i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "<>", c); + + case '%' : *sbuffer++ = (char)c; + if (++nwritten >= buflen) goto exit; + break; + } + + if (i < F.fieldWidth && !F.leftJustify) // Pad on the left + do { + *sbuffer++ = ' '; + if (++nwritten >= buflen) goto exit; + } while (i < --F.fieldWidth); + + // Make sure we don't truncate in the middle of a UTF-8 character. + // Note: s[i] is the first eliminated character; i.e. the next character *after* the last character of the + // allowed output. If s[i] is a UTF-8 continuation character, then we've cut a unicode character in half, + // so back up 'i' until s[i] is no longer a UTF-8 continuation character. (if the input was proprly + // formed, s[i] will now be the UTF-8 start character of the multi-byte character we just eliminated). + if (i > buflen - nwritten) + { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--; } + for (j=0; j= buflen) goto exit; + + for (; i < F.fieldWidth; i++) // Pad on the right + { + *sbuffer++ = ' '; + if (++nwritten >= buflen) goto exit; + } + } + } + exit: + *sbuffer++ = 0; + return(nwritten); + } + +mDNSexport mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...) + { + mDNSu32 length; + + va_list ptr; + va_start(ptr,fmt); + length = mDNS_vsnprintf(sbuffer, buflen, fmt, ptr); + va_end(ptr); + + return(length); + } diff --git a/mDNSCore/DNSCommon.h b/mDNSCore/DNSCommon.h index 0f236c0..8479573 100644 --- a/mDNSCore/DNSCommon.h +++ b/mDNSCore/DNSCommon.h @@ -1,140 +1,95 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: DNSCommon.h,v $ -Revision 1.33 2006/03/10 21:51:41 cheshire - After record update, old record sometimes remains in cache -Split out SameRDataBody() into a separate routine so it can be called from other code - -Revision 1.32 2005/03/21 00:33:51 shersche - Fix build warnings on Win32 platform - -Revision 1.31 2005/02/18 00:43:11 cheshire - mDNSResponder should auto-truncate service names that are too long - -Revision 1.30 2005/01/19 03:12:44 cheshire -Move LocalRecordReady() macro from mDNS.c to DNSCommon.h - -Revision 1.29 2004/12/15 02:11:22 ksekar - Don't check for Dynamic DNS hostname uniqueness - -Revision 1.28 2004/12/06 21:15:22 ksekar - mDNSResponder crashed in CheckServiceRegistrations - -Revision 1.27 2004/12/03 07:20:50 ksekar - Wide-Area: Registration of large TXT record fails - -Revision 1.26 2004/12/03 05:18:33 ksekar - mDNSResponder needs to return more specific TSIG errors - -Revision 1.25 2004/10/26 03:52:02 cheshire -Update checkin comments - -Revision 1.24 2004/10/23 01:16:00 cheshire - uDNS operations not always reliable on multi-homed hosts - -Revision 1.23 2004/10/03 23:18:58 cheshire -Move address comparison macros from DNSCommon.h to mDNSEmbeddedAPI.h +Revision 1.54 2007/10/05 17:56:10 cheshire +Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files -Revision 1.22 2004/09/30 00:24:56 ksekar - Dynamically update default registration domains on config change +Revision 1.53 2007/09/27 17:42:49 cheshire +Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask" -Revision 1.21 2004/09/17 01:08:48 cheshire -Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h - The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces - declared in that file are ONLY appropriate to single-address-space embedded applications. - For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used. +Revision 1.52 2007/09/26 00:49:46 cheshire +Improve packet logging to show sent and received packets, +transport protocol (UDP/TCP/TLS) and source/destination address:port -Revision 1.20 2004/09/17 00:49:51 cheshire -Get rid of now-unused GetResourceRecord -- the correct (safe) routine to use -is GetLargeResourceRecord +Revision 1.51 2007/09/21 21:12:36 cheshire + BTMM: Need to log updates and query packet contents -Revision 1.19 2004/09/16 21:59:15 cheshire -For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr +Revision 1.50 2007/09/20 01:12:06 cheshire +Moved HashSlot(X) from mDNS.c to DNSCommon.h so it's usable in other files -Revision 1.18 2004/09/16 02:29:39 cheshire -Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around -uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService +Revision 1.49 2007/08/30 00:31:20 cheshire +Improve "locking failure" debugging messages to show function name using __func__ macro -Revision 1.17 2004/09/14 23:27:46 cheshire -Fix compile errors +Revision 1.48 2007/05/25 00:25:44 cheshire + Need to enhance putRData to output all current known types -Revision 1.16 2004/08/13 23:46:58 cheshire -"asyncronous" -> "asynchronous" +Revision 1.47 2007/05/01 21:46:31 cheshire +Move GetLLQOptData/GetPktLease from uDNS.c into DNSCommon.c so that dnsextd can use them -Revision 1.15 2004/08/10 23:19:14 ksekar -: DNS Extension daemon for Wide Area Service Discovery -Moved routines/constants to allow extern access for garbage collection daemon +Revision 1.46 2007/04/22 20:18:10 cheshire +Add comment about mDNSRandom() -Revision 1.14 2004/05/28 23:42:36 ksekar -: Feature: DNS server->client notification on record changes (#7805) +Revision 1.45 2007/04/22 06:02:02 cheshire + Query should immediately return failure when no server -Revision 1.13 2004/05/18 23:51:25 cheshire -Tidy up all checkin comments to use consistent "" format for bug numbers +Revision 1.44 2007/03/28 01:20:05 cheshire + Improve/create logging for secure browse -Revision 1.12 2004/04/22 04:03:59 cheshire -Headers should use "extern" declarations, not "mDNSexport" +Revision 1.43 2007/03/20 17:07:15 cheshire +Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket" -Revision 1.11 2004/04/14 23:09:28 ksekar -Support for TSIG signed dynamic updates. +Revision 1.42 2007/03/10 03:26:44 cheshire + uDNS: LLQ refresh response packet causes cached records to be removed from cache -Revision 1.10 2004/03/13 01:57:33 ksekar -: DynDNS: Dynamic update of service records +Revision 1.41 2007/01/18 23:18:17 cheshire +Source code tidying: Delete extraneous white space -Revision 1.9 2004/02/21 08:56:58 bradley -Wrap prototypes with extern "C" for C++ builds. +Revision 1.40 2007/01/05 08:30:40 cheshire +Trim excessive "$Log" checkin history from before 2006 +(checkin history still available via "cvs log ..." of course) -Revision 1.8 2004/02/06 23:04:18 ksekar -Basic Dynamic Update support via mDNS_Register (dissabled via -UNICAST_REGISTRATION #define) +Revision 1.39 2007/01/04 21:45:20 cheshire +Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros, +to do additional lock sanity checking around callback invocations -Revision 1.7 2004/02/03 19:47:36 ksekar -Added an asynchronous state machine mechanism to uDNS.c, including -calls to find the parent zone for a domain name. Changes include code -in repository previously dissabled via "#if 0 incomplete". Codepath -is currently unused, and will be called to create update records, etc. +Revision 1.38 2006/12/22 20:59:49 cheshire + Read *all* DNS keys from keychain, + not just key for the system-wide default registration domain -Revision 1.6 2004/01/27 20:15:22 cheshire -: Time to prune obsolete code for listening on port 53 +Revision 1.37 2006/08/14 23:24:22 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 -Revision 1.5 2004/01/24 03:40:56 cheshire -Move mDNSAddrIsDNSMulticast() from DNSCommon.h to mDNSEmbeddedAPI.h so embedded clients can use it +Revision 1.36 2006/07/05 22:56:07 cheshire + Add Private DNS client functionality to mDNSResponder +Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int" -Revision 1.4 2004/01/24 03:38:27 cheshire -Fix minor syntactic error: Headers should use "extern" declarations, not "mDNSexport" +Revision 1.35 2006/06/29 07:42:14 cheshire + Performance: Remove unnecessary SameDomainName() checks -Revision 1.3 2004/01/23 23:23:14 ksekar -Added TCP support for truncated unicast messages. +Revision 1.34 2006/03/18 21:47:56 cheshire + Improve logic for delaying packets after repeated interface transitions -Revision 1.2 2004/01/21 21:12:23 cheshire -Add missing newline at end of file to make Unix tools happier - -Revision 1.1 2003/12/13 03:05:27 ksekar -: DynDNS: Unicast query of service records +Revision 1.33 2006/03/10 21:51:41 cheshire + After record update, old record sometimes remains in cache +Split out SameRDataBody() into a separate routine so it can be called from other code - - */ +*/ #ifndef __DNSCOMMON_H_ #define __DNSCOMMON_H_ @@ -155,7 +110,7 @@ typedef enum kDNSFlag0_QR_Mask = 0x80, // Query or response? kDNSFlag0_QR_Query = 0x00, kDNSFlag0_QR_Response = 0x80, - + kDNSFlag0_OP_Mask = 0x78, // Operation type kDNSFlag0_OP_StdQuery = 0x00, kDNSFlag0_OP_Iquery = 0x08, @@ -163,19 +118,19 @@ typedef enum kDNSFlag0_OP_Unused3 = 0x18, kDNSFlag0_OP_Notify = 0x20, kDNSFlag0_OP_Update = 0x28, - + kDNSFlag0_QROP_Mask = kDNSFlag0_QR_Mask | kDNSFlag0_OP_Mask, - + kDNSFlag0_AA = 0x04, // Authoritative Answer? kDNSFlag0_TC = 0x02, // Truncated? kDNSFlag0_RD = 0x01, // Recursion Desired? kDNSFlag1_RA = 0x80, // Recursion Available? - + kDNSFlag1_Zero = 0x40, // Reserved; must be zero kDNSFlag1_AD = 0x20, // Authentic Data [RFC 2535] kDNSFlag1_CD = 0x10, // Checking Disabled [RFC 2535] - kDNSFlag1_RC = 0x0F, // Response code + kDNSFlag1_RC_Mask = 0x0F, // Response code kDNSFlag1_RC_NoErr = 0x00, kDNSFlag1_RC_FmtErr = 0x01, kDNSFlag1_RC_SrvErr = 0x02, @@ -195,7 +150,7 @@ typedef enum TSIG_ErrBadKey = 17, TSIG_ErrBadTime = 18 } TSIG_ErrorCode; - + // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - @@ -205,32 +160,32 @@ typedef enum extern const NetworkInterfaceInfo *GetFirstActiveInterface(const NetworkInterfaceInfo *intf); extern mDNSInterfaceID GetNextActiveInterfaceID(const NetworkInterfaceInfo *intf); -extern mDNSu32 mDNSRandom(mDNSu32 max); - +extern mDNSu32 mDNSRandom(mDNSu32 max); // Returns pseudo-random result from zero to max inclusive +extern mDNSu32 mDNSRandomFromFixedSeed(mDNSu32 seed, mDNSu32 max); // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - #pragma mark - Domain Name Utility Functions #endif - + #define mdnsIsDigit(X) ((X) >= '0' && (X) <= '9') #define mDNSIsUpperCase(X) ((X) >= 'A' && (X) <= 'Z') #define mDNSIsLowerCase(X) ((X) >= 'a' && (X) <= 'z') #define mdnsIsLetter(X) (mDNSIsUpperCase(X) || mDNSIsLowerCase(X)) - + #define mdnsValidHostChar(X, notfirst, notlast) (mdnsIsLetter(X) || mdnsIsDigit(X) || ((notfirst) && (notlast) && (X) == '-') ) extern mDNSu16 CompressedDomainNameLength(const domainname *const name, const domainname *parent); +extern int CountLabels(const domainname *d); +extern const domainname *SkipLeadingLabels(const domainname *d, int skip); extern mDNSu32 TruncateUTF8ToLength(mDNSu8 *string, mDNSu32 length, mDNSu32 max); extern mDNSBool LabelContainsSuffix(const domainlabel *const name, const mDNSBool RichText); extern mDNSu32 RemoveLabelSuffix(domainlabel *name, mDNSBool RichText); extern void AppendLabelSuffix(domainlabel *name, mDNSu32 val, mDNSBool RichText); -extern void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result); #define ValidateDomainName(N) (DomainNameLength(N) <= MAX_DOMAIN_NAME) - // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - @@ -238,112 +193,86 @@ extern void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus r #endif extern mDNSu32 RDataHashValue(mDNSu16 const rdlength, const RDataBody *const rdb); - extern mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2); extern mDNSBool SameRData(const ResourceRecord *const r1, const ResourceRecord *const r2); - extern mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q); - +extern mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q); extern mDNSBool SameResourceRecord(ResourceRecord *r1, ResourceRecord *r2); - extern mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate); +extern mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd); #define GetRRDomainNameTarget(RR) ( \ ((RR)->rrtype == kDNSType_CNAME || (RR)->rrtype == kDNSType_PTR || (RR)->rrtype == kDNSType_NS) \ ? &(RR)->rdata->u.name : \ ((RR)->rrtype == kDNSType_SRV ) ? &(RR)->rdata->u.srv.target : mDNSNULL ) -extern mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd); #define LocalRecordReady(X) ((X)->resrec.RecordType != kDNSRecordTypeUnique && (X)->resrec.RecordType != kDNSRecordTypeDeregistering) - // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - -#pragma mark - #pragma mark - DNS Message Creation Functions #endif extern void InitializeDNSMessage(DNSMessageHeader *h, mDNSOpaque16 id, mDNSOpaque16 flags); extern const mDNSu8 *FindCompressionPointer(const mDNSu8 *const base, const mDNSu8 *const end, const mDNSu8 *const domname); - extern mDNSu8 *putDomainNameAsLabels(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name); - -extern mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, ResourceRecord *rr); +extern mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const ResourceRecord *const rr); // If we have a single large record to put in the packet, then we allow the packet to be up to 9K bytes, -// but in the normal case we try to keep the packets below 1500 to avoid IP fragmentation on standard Ethernet - +// but in the normal case we try to keep the packets below 1500 to avoid IP fragmentation on standard Ethernet extern mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 ttl, const mDNSu8 *limit); - #define PutResourceRecordTTL(msg, ptr, count, rr, ttl) PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), \ ((msg)->h.numAnswers || (msg)->h.numAuthorities || (msg)->h.numAdditionals) ? (msg)->data + NormalMaxDNSMessageData : (msg)->data + AbsoluteMaxDNSMessageData) - #define PutResourceRecordTTLJumbo(msg, ptr, count, rr, ttl) PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), \ (msg)->data + AbsoluteMaxDNSMessageData) - extern mDNSu8 *PutResourceRecordCappedTTL(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 maxttl); - extern mDNSu8 *putEmptyResourceRecord(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, mDNSu16 *count, const AuthRecord *rr); extern mDNSu8 *putQuestion(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name, mDNSu16 rrtype, mDNSu16 rrclass); - extern mDNSu8 *putZone(DNSMessage *const msg, mDNSu8 *ptr, mDNSu8 *limit, const domainname *zone, mDNSOpaque16 zoneClass); - -extern mDNSu8 *putPrereqNameNotInUse(domainname *name, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *end); - +extern mDNSu8 *putPrereqNameNotInUse(const domainname *const name, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *end); extern mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr); - extern mDNSu8 *putDeleteRRSet(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype); - extern mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domainname *name); - extern mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease); - #define PutResourceRecord(MSG, P, C, RR) PutResourceRecordTTL((MSG), (P), (C), (RR), (RR)->rroriginalttl) - // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - #pragma mark - DNS Message Parsing Functions #endif +#define HashSlot(X) (DomainNameHashValue(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); - extern const mDNSu8 *getDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end, domainname *const name); - extern const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end); - -extern const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage * const msg, const mDNSu8 *ptr, +extern const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage * const msg, const mDNSu8 *ptr, const mDNSu8 * end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *largecr); - extern const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end); - extern const mDNSu8 *getQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end, const mDNSInterfaceID InterfaceID, DNSQuestion *question); - extern const mDNSu8 *LocateAnswers(const DNSMessage *const msg, const mDNSu8 *const end); - extern const mDNSu8 *LocateAuthorities(const DNSMessage *const msg, const mDNSu8 *const end); - extern const mDNSu8 *LocateAdditionals(const DNSMessage *const msg, const mDNSu8 *const end); +extern const mDNSu8 *LocateLLQOptData(const DNSMessage *const msg, const mDNSu8 *const end); +extern const rdataOPT *GetLLQOptData(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end); +extern const mDNSu8 *LocateLeaseOptData(const DNSMessage *const msg, const mDNSu8 *const end); +extern mDNSu32 GetPktLease(mDNS *m, DNSMessage *msg, const mDNSu8 *end); +extern void DumpPacket(mDNS *const m, mDNSBool sent, char *type, const mDNSAddr *addr, mDNSIPPort port, const DNSMessage *const msg, const mDNSu8 *const end); // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - -#pragma mark - #pragma mark - Packet Sending Functions #endif -extern mStatus mDNSSendDNSMessage(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end, - mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, int sd, uDNS_AuthInfo *authInfo); +extern mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end, + mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo); // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK @@ -351,8 +280,24 @@ extern mStatus mDNSSendDNSMessage(const mDNS *const m, DNSMessage *const msg, mD #pragma mark - RR List Management & Task Management #endif -extern void mDNS_Lock(mDNS *const m); -extern void mDNS_Unlock(mDNS *const m); +extern void mDNS_Lock_(mDNS *const m); +extern void mDNS_Unlock_(mDNS *const m); + +#define mDNS_Lock(X) do { \ + if ((X)->mDNS_busy != (X)->mDNS_reentrancy) LogMsg("%s: mDNS_Lock locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", __func__, (X)->mDNS_busy, (X)->mDNS_reentrancy); \ + mDNS_Lock_(X); } while (0) + +#define mDNS_Unlock(X) do { mDNS_Unlock_(X); \ + if ((X)->mDNS_busy != (X)->mDNS_reentrancy) LogMsg("%s: mDNS_Unlock locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", __func__, (X)->mDNS_busy, (X)->mDNS_reentrancy); \ + } while (0) + +#define mDNS_DropLockBeforeCallback() do { m->mDNS_reentrancy++; \ + if (m->mDNS_busy != m->mDNS_reentrancy) LogMsg("%s: Locking Failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", __func__, m->mDNS_busy, m->mDNS_reentrancy); \ + } while (0) + +#define mDNS_ReclaimLockAfterCallback() do { \ + if (m->mDNS_busy != m->mDNS_reentrancy) LogMsg("%s: Unlocking Failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", __func__, m->mDNS_busy, m->mDNS_reentrancy); \ + m->mDNS_reentrancy--; } while (0) #ifdef __cplusplus } diff --git a/mDNSCore/DNSDigest.c b/mDNSCore/DNSDigest.c index 89d7b01..809499b 100644 --- a/mDNSCore/DNSDigest.c +++ b/mDNSCore/DNSDigest.c @@ -1,28 +1,54 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: DNSDigest.c,v $ +Revision 1.23 2007/09/21 21:12:36 cheshire +DNSDigest_SignMessage does not need separate "mDNSu16 *numAdditionals" parameter + +Revision 1.22 2007/04/22 06:02:02 cheshire + Query should immediately return failure when no server + +Revision 1.21 2007/03/22 18:31:48 cheshire +Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy + +Revision 1.20 2006/12/22 20:59:49 cheshire + Read *all* DNS keys from keychain, + not just key for the system-wide default registration domain + +Revision 1.19 2006/12/21 00:06:07 cheshire +Don't need to do mDNSPlatformMemZero() -- mDNS_SetupResourceRecord() does it for us + +Revision 1.18 2006/12/19 22:41:21 cheshire +Fix compiler warnings + +Revision 1.17 2006/08/14 23:24:22 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + +Revision 1.16 2006/07/05 23:05:15 cheshire + Add Private DNS server functionality to dnsextd +Add DNSDigest_VerifyMessage() function + +Revision 1.15 2006/06/20 04:12:30 cheshire + DNS Update broken + +Revision 1.14 2006/02/25 23:12:07 cheshire + Fix to avoid code generation warning/error on FreeBSD 7 + Revision 1.13 2004/12/16 20:12:59 cheshire Cache memory management improvements @@ -88,6 +114,22 @@ extern "C" { #pragma warning(disable:4127) #endif + + // *************************************************************************** +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - Byte Swapping Functions +#endif + +mDNSlocal mDNSu16 NToH16(mDNSu8 * bytes) + { + return (mDNSu16)((mDNSu16)bytes[0] << 8 | (mDNSu16)bytes[1]); + } + +mDNSlocal mDNSu32 NToH32(mDNSu8 * bytes) + { + return (mDNSu32)((mDNSu32) bytes[0] << 24 | (mDNSu32) bytes[1] << 16 | (mDNSu32) bytes[2] << 8 | (mDNSu32)bytes[3]); + } + // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - MD5 Hash Functions @@ -461,7 +503,7 @@ void md5_block_data_order (MD5_CTX *c, const void *p,int num); # define ROTATE(a,n) (unsigned MD32_REG_T)__rlwinm((int)a,n,0,31) # elif defined(__MC68K__) /* Motorola specific tweak. */ -# define ROTATE(a,n) ( n<24 ? __rol(a,n) : __ror(a,32-n) ) +# define ROTATE(a,n) (n<24 ? __rol(a,n) : __ror(a,32-n)) # else # define ROTATE(a,n) __rol(a,n) # endif @@ -1165,20 +1207,18 @@ void md5_block_data_order (MD5_CTX *c, const void *data_, int num) #endif - // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - base64 -> binary conversion #endif -static const char Base64[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char Pad64 = '='; #define mDNSisspace(x) (x == '\t' || x == '\n' || x == '\v' || x == '\f' || x == '\r' || x == ' ') -static const char *mDNSstrchr(const char *s, int c) +mDNSlocal const char *mDNSstrchr(const char *s, int c) { while (1) { @@ -1194,7 +1234,7 @@ static const char *mDNSstrchr(const char *s, int c) // it returns the number of data bytes stored at the target, or -1 on error. // adapted from BIND sources -mDNSexport mDNSs32 DNSDigest_Base64ToBin(const char *src, mDNSu8 *target, mDNSu32 targsize) +mDNSlocal mDNSs32 DNSDigest_Base64ToBin(const char *src, mDNSu8 *target, mDNSu32 targsize) { int tarindex, state, ch; const char *pos; @@ -1324,7 +1364,7 @@ mDNSexport mDNSs32 DNSDigest_Base64ToBin(const char *src, mDNSu8 *target, mDNSu3 #define HMAC_MD5_AlgName (*(const domainname*) "\010" "hmac-md5" "\007" "sig-alg" "\003" "reg" "\003" "int") // Adapted from Appendix, RFC 2104 -mDNSexport void DNSDigest_ConstructHMACKey(uDNS_AuthInfo *info, const mDNSu8 *key, mDNSu32 len) +mDNSlocal void DNSDigest_ConstructHMACKey(DomainAuthInfo *info, const mDNSu8 *key, mDNSu32 len) { MD5_CTX k; mDNSu8 buf[MD5_LEN]; @@ -1341,24 +1381,33 @@ mDNSexport void DNSDigest_ConstructHMACKey(uDNS_AuthInfo *info, const mDNSu8 *ke } // store key in pads - mDNSPlatformMemZero(info->key.ipad, HMAC_LEN); - mDNSPlatformMemZero(info->key.opad, HMAC_LEN); - mDNSPlatformMemCopy(key, info->key.ipad, len); - mDNSPlatformMemCopy(key, info->key.opad, len); + mDNSPlatformMemZero(info->keydata_ipad, HMAC_LEN); + mDNSPlatformMemZero(info->keydata_opad, HMAC_LEN); + mDNSPlatformMemCopy(info->keydata_ipad, key, len); + mDNSPlatformMemCopy(info->keydata_opad, key, len); // XOR key with ipad and opad values for (i = 0; i < HMAC_LEN; i++) { - info->key.ipad[i] ^= HMAC_IPAD; - info->key.opad[i] ^= HMAC_OPAD; + info->keydata_ipad[i] ^= HMAC_IPAD; + info->keydata_opad[i] ^= HMAC_OPAD; } } -mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16 *numAdditionals, uDNS_AuthInfo *info) +mDNSexport mDNSs32 DNSDigest_ConstructHMACKeyfromBase64(DomainAuthInfo *info, const char *b64key) + { + mDNSu8 keybuf[1024]; + mDNSs32 keylen = DNSDigest_Base64ToBin(b64key, keybuf, sizeof(keybuf)); + if (keylen < 0) return(keylen); + DNSDigest_ConstructHMACKey(info, keybuf, (mDNSu32)keylen); + return(keylen); + } + +mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAuthInfo *info, mDNSu16 tcode) { AuthRecord tsig; - mDNSu8 *countPtr, *rdata; + mDNSu8 *rdata, *const countPtr = (mDNSu8 *)&msg->h.numAdditionals; // Get existing numAdditionals value mDNSu32 utc32; mDNSu8 utc48[6]; mDNSu8 digest[MD5_LEN]; @@ -1366,18 +1415,18 @@ mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16 mDNSu32 len; mDNSOpaque16 buf; MD5_CTX c; + mDNSu16 numAdditionals = (mDNSu16)((mDNSu16)countPtr[0] << 8 | countPtr[1]); // Init MD5 context, digest inner key pad and message MD5_Init(&c); - MD5_Update(&c, info->key.ipad, HMAC_LEN); + MD5_Update(&c, info->keydata_ipad, HMAC_LEN); MD5_Update(&c, (mDNSu8 *)msg, (unsigned long)(*end - (mDNSu8 *)msg)); // Construct TSIG RR, digesting variables as apporpriate - mDNSPlatformMemZero(&tsig, sizeof(AuthRecord)); mDNS_SetupResourceRecord(&tsig, mDNSNULL, 0, kDNSType_TSIG, 0, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL); // key name - AssignDomainName(tsig.resrec.name, &info->keyname); + AssignDomainName(&tsig.namestorage, &info->keyname); MD5_Update(&c, info->keyname.c, DomainNameLength(&info->keyname)); // class @@ -1403,23 +1452,24 @@ mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16 utc48[1] = 0; utc48[2] = (mDNSu8)((utc32 >> 24) & 0xff); utc48[3] = (mDNSu8)((utc32 >> 16) & 0xff); - utc48[4] = (mDNSu8)((utc32 >> 8) & 0xff); + utc48[4] = (mDNSu8)((utc32 >> 8) & 0xff); utc48[5] = (mDNSu8)( utc32 & 0xff); - mDNSPlatformMemCopy(utc48, rdata, 6); + mDNSPlatformMemCopy(rdata, utc48, 6); rdata += 6; MD5_Update(&c, utc48, 6); - // fudge - buf = mDNSOpaque16fromIntVal(300); // 300 sec is fudge recommended in RFC 2485 - rdata[0] = buf.b[0]; - rdata[1] = buf.b[1]; + // 300 sec is fudge recommended in RFC 2485 + rdata[0] = (mDNSu8)((300 >> 8) & 0xff); + rdata[1] = (mDNSu8)( 300 & 0xff); + MD5_Update(&c, rdata, sizeof(mDNSOpaque16)); rdata += sizeof(mDNSOpaque16); - MD5_Update(&c, buf.b, sizeof(mDNSOpaque16)); - // digest error and other data len (both zero) - we'll add them to the rdata later - buf.NotAnInteger = 0; + // digest error (tcode) and other data len (zero) - we'll add them to the rdata later + buf.b[0] = (mDNSu8)((tcode >> 8) & 0xff); + buf.b[1] = (mDNSu8)( tcode & 0xff); MD5_Update(&c, buf.b, sizeof(mDNSOpaque16)); // error + buf.NotAnInteger = 0; MD5_Update(&c, buf.b, sizeof(mDNSOpaque16)); // other data len // finish the message & tsig var hash @@ -1427,7 +1477,7 @@ mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16 // perform outer MD5 (outer key pad, inner digest) MD5_Init(&c); - MD5_Update(&c, info->key.opad, HMAC_LEN); + MD5_Update(&c, info->keydata_opad, HMAC_LEN); MD5_Update(&c, digest, MD5_LEN); MD5_Final(digest, &c); @@ -1435,28 +1485,173 @@ mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16 rdata[0] = (mDNSu8)((MD5_LEN >> 8) & 0xff); rdata[1] = (mDNSu8)( MD5_LEN & 0xff); rdata += sizeof(mDNSOpaque16); - mDNSPlatformMemCopy(digest, rdata, MD5_LEN); // MAC + mDNSPlatformMemCopy(rdata, digest, MD5_LEN); // MAC rdata += MD5_LEN; rdata[0] = msg->h.id.b[0]; // original ID rdata[1] = msg->h.id.b[1]; - rdata[2] = 0; // no error - rdata[3] = 0; + rdata[2] = (mDNSu8)((tcode >> 8) & 0xff); + rdata[3] = (mDNSu8)( tcode & 0xff); rdata[4] = 0; // other data len rdata[5] = 0; rdata += 6; tsig.resrec.rdlength = (mDNSu16)(rdata - tsig.resrec.rdata->u.data); - *end = PutResourceRecordTTLJumbo(msg, ptr, numAdditionals, &tsig.resrec, 0); + *end = PutResourceRecordTTLJumbo(msg, ptr, &numAdditionals, &tsig.resrec, 0); if (!*end) { LogMsg("ERROR: DNSDigest_SignMessage - could not put TSIG"); return mDNSNULL; } - // update num additionals - countPtr = (mDNSu8 *)&msg->h.numAdditionals; // increment (network-byte ordered) header value - *countPtr++ = (mDNSu8)(*numAdditionals >> 8); - *countPtr++ = (mDNSu8)(*numAdditionals & 0xFF); + // Write back updated numAdditionals value + countPtr[0] = (mDNSu8)(numAdditionals >> 8); + countPtr[1] = (mDNSu8)(numAdditionals & 0xFF); return *end; } +mDNSexport mDNSBool DNSDigest_VerifyMessage(DNSMessage *msg, mDNSu8 *end, LargeCacheRecord * lcr, DomainAuthInfo *info, mDNSu16 * rcode, mDNSu16 * tcode) + { + mDNSu8 * ptr = (mDNSu8*) &lcr->r.resrec.rdata->u.data; + mDNSs32 now; + mDNSs32 then; + mDNSu8 thisDigest[MD5_LEN]; + mDNSu8 thatDigest[MD5_LEN]; + mDNSu32 macsize; + mDNSOpaque16 buf; + mDNSu8 utc48[6]; + mDNSs32 delta; + mDNSu16 fudge; + domainname * algo; + MD5_CTX c; + mDNSBool ok = mDNSfalse; + + // We only support HMAC-MD5 for now + + algo = (domainname*) ptr; + + if (!SameDomainName(algo, &HMAC_MD5_AlgName)) + { + LogMsg("ERROR: DNSDigest_VerifyMessage - TSIG algorithm not supported: %##s", algo->c); + *rcode = kDNSFlag1_RC_NotAuth; + *tcode = TSIG_ErrBadKey; + ok = mDNSfalse; + goto exit; + } + + ptr += DomainNameLength(algo); + + // Check the times + + now = mDNSPlatformUTC(); + if (now == -1) + { + LogMsg("ERROR: DNSDigest_VerifyMessage - mDNSPlatformUTC returned bad time -1"); + *rcode = kDNSFlag1_RC_NotAuth; + *tcode = TSIG_ErrBadTime; + ok = mDNSfalse; + goto exit; + } + + // Get the 48 bit time field, skipping over the first word + + utc48[0] = *ptr++; + utc48[1] = *ptr++; + utc48[2] = *ptr++; + utc48[3] = *ptr++; + utc48[4] = *ptr++; + utc48[5] = *ptr++; + + then = (mDNSs32)NToH32(utc48 + sizeof(mDNSu16)); + + fudge = NToH16(ptr); + + ptr += sizeof(mDNSu16); + + delta = (now > then) ? now - then : then - now; + + if (delta > fudge) + { + LogMsg("ERROR: DNSDigest_VerifyMessage - time skew > %d", fudge); + *rcode = kDNSFlag1_RC_NotAuth; + *tcode = TSIG_ErrBadTime; + ok = mDNSfalse; + goto exit; + } + + // MAC size + + macsize = (mDNSu32) NToH16(ptr); + + ptr += sizeof(mDNSu16); + + // MAC + + mDNSPlatformMemCopy(thatDigest, ptr, MD5_LEN); + + // Init MD5 context, digest inner key pad and message + + MD5_Init(&c); + MD5_Update(&c, info->keydata_ipad, HMAC_LEN); + MD5_Update(&c, (mDNSu8*) msg, (unsigned long)(end - (mDNSu8*) msg)); + + // Key name + + MD5_Update(&c, lcr->r.resrec.name->c, DomainNameLength(lcr->r.resrec.name)); + + // Class name + + buf = mDNSOpaque16fromIntVal(lcr->r.resrec.rrclass); + MD5_Update(&c, buf.b, sizeof(mDNSOpaque16)); + + // TTL + + MD5_Update(&c, (mDNSu8*) &lcr->r.resrec.rroriginalttl, sizeof(lcr->r.resrec.rroriginalttl)); + + // Algorithm + + MD5_Update(&c, algo->c, DomainNameLength(algo)); + + // Time + + MD5_Update(&c, utc48, 6); + + // Fudge + + buf = mDNSOpaque16fromIntVal(fudge); + MD5_Update(&c, buf.b, sizeof(mDNSOpaque16)); + + // Digest error and other data len (both zero) - we'll add them to the rdata later + + buf.NotAnInteger = 0; + MD5_Update(&c, buf.b, sizeof(mDNSOpaque16)); // error + MD5_Update(&c, buf.b, sizeof(mDNSOpaque16)); // other data len + + // Finish the message & tsig var hash + + MD5_Final(thisDigest, &c); + + // perform outer MD5 (outer key pad, inner digest) + + MD5_Init(&c); + MD5_Update(&c, info->keydata_opad, HMAC_LEN); + MD5_Update(&c, thisDigest, MD5_LEN); + MD5_Final(thisDigest, &c); + + if (!mDNSPlatformMemSame(thisDigest, thatDigest, MD5_LEN)) + { + LogMsg("ERROR: DNSDigest_VerifyMessage - bad signature"); + *rcode = kDNSFlag1_RC_NotAuth; + *tcode = TSIG_ErrBadSig; + ok = mDNSfalse; + goto exit; + } + + // set remaining rdata fields + ok = mDNStrue; + +exit: + + return ok; + } + + #ifdef __cplusplus } #endif diff --git a/mDNSCore/mDNS.c b/mDNSCore/mDNS.c index 8c9b566..4b0d972 100755 --- a/mDNSCore/mDNS.c +++ b/mDNSCore/mDNS.c @@ -2,30 +2,23 @@ * * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ * * This code is completely 100% portable C. It does not depend on any external header files * from outside the mDNS project -- all the types it expects to find are defined right here. * * The previous point is very important: This file does not depend on any external - * header files. It should complile on *any* platform that has a C compiler, without + * header files. It should compile on *any* platform that has a C compiler, without * making *any* assumptions about availability of so-called "standard" C functions, * routines, or types (which may or may not be present on any given platform). @@ -45,1703 +38,662 @@ Change History (most recent first): $Log: mDNS.c,v $ -Revision 1.535.2.3 2006/11/10 19:36:42 cheshire -Further refinement: Only harmonize TTL if the value we're adjusting it to is at least 2 seconds - -Revision 1.535.2.2 2006/10/31 02:11:26 cheshire -Compile error: Need to put back AllDNSLinkGroupv4 definition - -Revision 1.535.2.1 2006/10/31 01:28:06 cheshire - After service restarts on different port, for a few seconds DNS-SD may return stale port number - -Revision 1.535 2006/03/02 20:41:17 cheshire - After record update, old record sometimes remains in cache -Minor code tidying and comments to reduce the risk of similar programming errors in future - -Revision 1.534 2006/03/02 03:25:46 cheshire - After record update, old record sometimes remains in cache -Code to harmonize RRSet TTLs was inadvertently rescuing expiring records - -Revision 1.533 2006/02/26 00:54:41 cheshire -Fixes to avoid code generation warning/error on FreeBSD 7 - -Revision 1.532 2005/12/02 20:24:36 cheshire - Adjust cutoff time for KA list by one second - -Revision 1.531 2005/12/02 19:05:42 cheshire -Tidy up constants - -Revision 1.530 2005/11/07 01:49:48 cheshire -For consistency, use NonZeroTime() function instead of ?: expression - -Revision 1.529 2005/10/25 23:42:24 cheshire - Error in ResolveSimultaneousProbe() when type or class don't match -Changed switch statement to an "if" - -Revision 1.528 2005/10/25 23:34:22 cheshire - RequireGoodbye state not set/respected sometimes when machine going to sleep - -Revision 1.527 2005/10/25 22:43:59 cheshire -Add clarifying comments - -Revision 1.526 2005/10/20 00:10:33 cheshire - Add check to avoid crashing NAT gateways that have buggy DNS relay code - -Revision 1.525 2005/09/24 00:47:17 cheshire -Fix comment typos - -Revision 1.524 2005/09/16 21:06:49 cheshire -Use mDNS_TimeNow_NoLock macro, instead of writing "mDNSPlatformRawTime() + m->timenow_adjust" all over the place - -Revision 1.523 2005/03/21 00:33:51 shersche - Fix build warnings on Win32 platform - -Revision 1.522 2005/03/04 21:48:12 cheshire - Fractional time rounded down instead of up on platforms with coarse clock granularity - -Revision 1.521 2005/02/25 04:21:00 cheshire - mDNS -F returns the same domain multiple times with different casing - -Revision 1.520 2005/02/16 01:14:11 cheshire -Convert RR Cache LogOperation() calls to debugf() - -Revision 1.519 2005/02/15 01:57:20 cheshire -When setting "q->LastQTxTime = m->timenow", must also clear q->RecentAnswerPkts to zero - -Revision 1.518 2005/02/10 22:35:17 cheshire - Update name - -Revision 1.517 2005/02/03 00:21:21 cheshire -Update comments about BIND named and zero-length TXT records - -Revision 1.516 2005/01/28 06:06:32 cheshire -Update comment - -Revision 1.515 2005/01/27 00:21:49 cheshire - Remove mDNSResponder sleep/wake syslog message - -Revision 1.514 2005/01/21 01:33:45 cheshire - Shutdown time regression: mDNSResponder not responding to SIGTERM - -Revision 1.513 2005/01/21 00:07:54 cheshire - Infinite loop when the same service is registered twice, and then suffers a name conflict - -Revision 1.512 2005/01/20 00:37:45 cheshire - mDNSResponder crashed in mDNSCoreReceiveResponse -Take care not to recycle records while they are on the CacheFlushRecords list - -Revision 1.511 2005/01/19 22:48:53 cheshire - Handle services with subtypes correctly when doing mDNS_RenameAndReregisterService() - -Revision 1.510 2005/01/19 03:12:45 cheshire -Move LocalRecordReady() macro from mDNS.c to DNSCommon.h - -Revision 1.509 2005/01/19 03:08:49 cheshire - CPU Spin in mDNSResponder -Log messages to help catch and report CPU spins - -Revision 1.508 2005/01/18 18:56:32 cheshire - QU responses not promoted to multicast responses when appropriate - -Revision 1.507 2005/01/18 01:12:07 cheshire - Logging into VPN causes mDNSResponder to reissue multicast probes - -Revision 1.506 2005/01/17 23:28:53 cheshire -Fix compile error - -Revision 1.505 2005/01/11 02:02:56 shersche -Move variable declaration to the beginning of statement block - -Revision 1.504 2004/12/20 20:24:35 cheshire - Network efficiency: Don't keep polling if we have at least one unique-type answer - -Revision 1.503 2004/12/20 18:41:47 cheshire - Low memory support: Provide answers even when we don't have cache space - -Revision 1.502 2004/12/20 18:04:08 cheshire - For now, don't put standard wide-area unicast responses in our main cache - -Revision 1.501 2004/12/19 23:50:18 cheshire - kDNSServiceInterfaceIndexLocalOnly should return all local records -Don't show "No active interface to send" messages for kDNSServiceInterfaceIndexLocalOnly services - -Revision 1.500 2004/12/18 03:13:46 cheshire - kDNSServiceInterfaceIndexLocalOnly should return all local records - -Revision 1.499 2004/12/17 23:37:45 cheshire - Guard against repeating wireless dissociation/re-association -(and other repetitive configuration changes) - -Revision 1.498 2004/12/17 05:25:46 cheshire - Shorten DNS-SD queries to avoid NAT bugs - -Revision 1.497 2004/12/17 03:20:58 cheshire - Don't send unicast replies we know will be ignored - -Revision 1.496 2004/12/16 22:18:26 cheshire -Make AddressIsLocalSubnet() a little more selective -- ignore point-to-point interfaces - -Revision 1.495 2004/12/16 21:27:37 ksekar -Fixed build failures when compiled with verbose debugging messages - -Revision 1.494 2004/12/16 20:46:56 cheshire -Fix compiler warnings - -Revision 1.493 2004/12/16 20:13:00 cheshire - Cache memory management improvements - -Revision 1.492 2004/12/16 08:03:24 shersche -Fix compilation error when UNICAST_DISABLED is set - -Revision 1.491 2004/12/11 01:52:11 cheshire - Support kDNSServiceFlagsAllowRemoteQuery for registering services too - -Revision 1.490 2004/12/10 20:06:25 cheshire - Reduce egregious stack space usage -Reduced SendDelayedUnicastResponse() stack frame from 9K to 112 bytes - -Revision 1.489 2004/12/10 20:03:43 cheshire - Reduce egregious stack space usage -Reduced mDNSCoreReceiveQuery() stack frame from 9K to 144 bytes - -Revision 1.488 2004/12/10 19:50:41 cheshire - Reduce egregious stack space usage -Reduced SendResponses() stack frame from 9K to 176 bytes - -Revision 1.487 2004/12/10 19:39:13 cheshire - Reduce egregious stack space usage -Reduced SendQueries() stack frame from 18K to 112 bytes - -Revision 1.486 2004/12/10 14:16:17 cheshire - Relax update rate limiting -We now allow an average rate of ten updates per minute. -Updates in excess of that are rate limited, but more gently than before. - -Revision 1.485 2004/12/10 02:09:24 cheshire - Modify default TTLs - -Revision 1.484 2004/12/09 03:15:40 ksekar - use _legacy instead of _default to find "empty string" browse domains - -Revision 1.483 2004/12/07 23:00:14 ksekar - DNSServiceRegisterRecord() can crash on deregistration: -Call RecordProbeFailure even if there is no record callback - -Revision 1.482 2004/12/07 22:49:06 cheshire - BIND doesn't allow zero-length TXT records - -Revision 1.481 2004/12/07 21:26:04 ksekar - DNSServiceRegisterRecord() can crash on deregistration - -Revision 1.480 2004/12/07 20:42:33 cheshire -Add explicit context parameter to mDNS_RemoveRecordFromService() - -Revision 1.479 2004/12/07 17:50:49 ksekar - BIND doesn't allow zero-length TXT records - -Revision 1.478 2004/12/06 21:15:22 ksekar - mDNSResponder crashed in CheckServiceRegistrations - -Revision 1.477 2004/12/04 02:12:45 cheshire - mDNSResponder puts LargeCacheRecord on the stack - -Revision 1.476 2004/11/29 23:34:31 cheshire -On platforms with coarse time resolutions, ORing time values with one to ensure they are non-zero -is crude, and effectively halves the time resolution. The more selective NonZeroTime() function -only nudges the time value to 1 if the interval calculation happens to result in the value zero. - -Revision 1.475 2004/11/29 23:13:31 cheshire - All unique records in a set should have the cache flush bit set -Additional check: Make sure we don't unnecessarily send packets containing only additionals. -(This could occur with multi-packet KA lists, if the answer and additionals were marked -by the query packet, and then the answer were later suppressed in a subsequent KA packet.) - -Revision 1.474 2004/11/29 17:18:12 cheshire -Remove "Unknown DNS packet type" message for update responses - -Revision 1.473 2004/11/25 01:57:52 cheshire - All unique records in a set should have the cache flush bit set - -Revision 1.472 2004/11/25 01:28:09 cheshire - Need to implement random delay for 'QU' unicast replies (and set cache flush bit too) - -Revision 1.471 2004/11/25 01:10:13 cheshire -Move code to add additional records to a subroutine called AddAdditionalsToResponseList() - -Revision 1.470 2004/11/24 21:54:44 cheshire - mDNSCore not receiving unicast responses properly - -Revision 1.469 2004/11/24 04:50:39 cheshire -Minor tidying - -Revision 1.468 2004/11/24 01:47:07 cheshire - DNSServiceRegisterRecord should call CallBack on success. - -Revision 1.467 2004/11/24 01:41:28 cheshire -Rename CompleteProbing() to AcknowledgeRecord() - -Revision 1.466 2004/11/23 21:08:07 ksekar -Don't use ID to demux multicast/unicast now that unicast uses random IDs - -Revision 1.465 2004/11/15 20:09:21 ksekar - Wide Area support for Add/Remove record - -Revision 1.464 2004/11/03 01:44:36 cheshire -Update debugging messages - -Revision 1.463 2004/10/29 02:38:48 cheshire -Fix Windows compile errors - -Revision 1.462 2004/10/28 19:21:07 cheshire -Guard against registering interface with zero InterfaceID - -Revision 1.461 2004/10/28 19:02:16 cheshire -Remove \n from LogMsg() call - -Revision 1.460 2004/10/28 03:24:40 cheshire -Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353 - -Revision 1.459 2004/10/26 22:34:37 cheshire - Need to protect mDNSResponder from unbounded packet flooding - -Revision 1.458 2004/10/26 20:45:28 cheshire -Show mask in "invalid mask" message - -Revision 1.457 2004/10/26 06:28:36 cheshire -Now that we don't check IP TTL any more, remove associated log message - -Revision 1.456 2004/10/26 06:21:42 cheshire -Adjust mask validity check to allow an all-ones mask (for IPv6 ::1 loopback address) - -Revision 1.455 2004/10/26 06:11:40 cheshire -Add improved logging to aid in diagnosis of mDNSResponder crashed - -Revision 1.454 2004/10/23 01:16:00 cheshire - uDNS operations not always reliable on multi-homed hosts - -Revision 1.453 2004/10/22 20:52:06 ksekar - Create NAT port mappings for Long Lived Queries - -Revision 1.452 2004/10/20 01:50:40 cheshire - Cannot resolve non-local registrations using the mach API -Implemented ForceMCast mode for AuthRecords as well as for Questions - -Revision 1.451 2004/10/19 21:33:15 cheshire - Cannot resolve non-local registrations using the mach API -Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name -doesn't force multicast unless you set this flag to indicate explicitly that this is what you want - -Revision 1.450 2004/10/19 17:42:59 ksekar -Fixed compiler warnings for non-debug builds. - -Revision 1.449 2004/10/18 22:57:07 cheshire - Seen in console: Ignored apparent spoof mDNS Response with TTL 1 - -Revision 1.448 2004/10/16 00:16:59 cheshire - Replace IP TTL 255 check with local subnet source address check - -Revision 1.447 2004/10/15 00:51:21 cheshire - Seen in console: Ignored apparent spoof mDNS Response with TTL 1 - -Revision 1.446 2004/10/14 00:43:34 cheshire - Services continue to announce SRV and HINFO - -Revision 1.445 2004/10/12 21:07:09 cheshire -Set up m->p in mDNS_Init() before calling mDNSPlatformTimeInit() - -Revision 1.444 2004/10/11 17:54:16 ksekar -Changed hashtable pointer output from debugf to verbosedebugf. - -Revision 1.443 2004/10/10 07:05:45 cheshire -For consistency, use symbol "localdomain" instead of literal string - -Revision 1.442 2004/10/08 20:25:10 cheshire -Change of plan for -- we're not going to do that at this time - -Revision 1.441 2004/10/08 03:25:01 ksekar - domain enumeration should use LLQs - -Revision 1.440 2004/10/06 01:44:19 cheshire - Resolving too quickly sometimes returns stale TXT record - -Revision 1.439 2004/10/03 23:14:11 cheshire -Add "mDNSEthAddr" type and "zeroEthAddr" constant - -Revision 1.438 2004/09/29 23:07:04 cheshire -Patch from Pavel Repin to fix compile error on Windows - -Revision 1.437 2004/09/28 02:23:50 cheshire - Deliver near-pending "remove" events before new "add" events -Don't need to search the entire cache for nearly-expired records -- just the appropriate hash slot -For records with the cache flush bit set, defer the decision until the end of the packet - -Revision 1.436 2004/09/28 01:27:04 cheshire -Update incorrect log message - -Revision 1.435 2004/09/25 02:41:39 cheshire - Deliver near-pending "remove" events before new "add" events - -Revision 1.434 2004/09/25 02:32:06 cheshire -Update comments - -Revision 1.433 2004/09/25 02:24:27 cheshire -Removed unused rr->UseCount - -Revision 1.432 2004/09/24 21:35:17 cheshire - Browses are no longer piggybacking on other browses -TargetPort and TargetQID are allowed to be undefined if no question->Target is set - -Revision 1.431 2004/09/24 21:33:12 cheshire -Adjust comment - -Revision 1.430 2004/09/24 02:15:49 cheshire - Late conflicts don't send goodbye packets on other interfaces - -Revision 1.429 2004/09/24 00:20:21 cheshire - Any rrtype is a conflict for unique records - -Revision 1.428 2004/09/24 00:12:25 cheshire -Get rid of unused RRUniqueOrKnownUnique(RR) - -Revision 1.427 2004/09/23 20:44:11 cheshire - Reduce timeout before expiring records on failure - -Revision 1.426 2004/09/23 20:21:07 cheshire - Refine "immediate answer burst; restarting exponential backoff sequence" logic -Associate a unique sequence number with each received packet, and only increment the count of recent answer -packets if the packet sequence number for this answer record is not one we've already seen and counted. - -Revision 1.425 2004/09/23 20:14:38 cheshire -Rename "question->RecentAnswers" to "question->RecentAnswerPkts" - -Revision 1.424 2004/09/23 00:58:36 cheshire - Rate limiting interferes with updating TXT records - -Revision 1.423 2004/09/23 00:50:53 cheshire - Don't send a (DE) if a service is unregistered after wake from sleep - -Revision 1.422 2004/09/22 02:34:46 cheshire -Move definitions of default TTL times from mDNS.c to mDNSEmbeddedAPI.h - -Revision 1.421 2004/09/21 23:29:49 cheshire - DNSServiceResolve should delay sending packets - -Revision 1.420 2004/09/21 23:01:42 cheshire -Update debugf messages - -Revision 1.419 2004/09/21 19:51:14 cheshire -Move "Starting time value" message from mDNS.c to mDNSMacOSX/daemon.c - -Revision 1.418 2004/09/21 18:40:17 cheshire - Adjust default record TTLs - -Revision 1.417 2004/09/21 17:32:16 cheshire - Rate limiting imposed too soon - -Revision 1.416 2004/09/20 23:52:01 cheshire -CFSocket{Puma}.c renamed to mDNSMacOSX{Puma}.c - -Revision 1.415 2004/09/18 01:14:09 cheshire - Resolve() should not bother doing AAAA queries on machines with no IPv6 interfaces - -Revision 1.414 2004/09/18 01:06:48 cheshire -Add comments - -Revision 1.413 2004/09/17 01:08:48 cheshire -Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h - The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces - declared in that file are ONLY appropriate to single-address-space embedded applications. - For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used. - -Revision 1.412 2004/09/17 00:46:33 cheshire -mDNS_TimeNow should take const mDNS parameter - -Revision 1.411 2004/09/17 00:31:51 cheshire -For consistency with ipv6, renamed rdata field 'ip' to 'ipv4' - -Revision 1.410 2004/09/17 00:19:10 cheshire -For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4 - -Revision 1.409 2004/09/16 21:59:15 cheshire -For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr - -Revision 1.408 2004/09/16 21:36:36 cheshire - Fix unsafe use of mDNSPlatformTimeNow() -Changes to add necessary locking calls around unicast DNS operations - -Revision 1.407 2004/09/16 02:29:39 cheshire -Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around -uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService - -Revision 1.406 2004/09/16 01:58:14 cheshire -Fix compiler warnings - -Revision 1.405 2004/09/16 00:24:48 cheshire - Fix unsafe use of mDNSPlatformTimeNow() - -Revision 1.404 2004/09/15 21:44:11 cheshire - Randomize initial timenow_adjust value in mDNS_Init -Show time value in log to help diagnose errors - -Revision 1.403 2004/09/15 00:46:32 ksekar -Changed debugf to verbosedebugf in CheckCacheExpiration - -Revision 1.402 2004/09/14 23:59:55 cheshire - Randomize initial timenow_adjust value in mDNS_Init - -Revision 1.401 2004/09/14 23:27:46 cheshire -Fix compile errors - -Revision 1.400 2004/09/02 03:48:47 cheshire - Disable targeted unicast query support by default -1. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record -2. New field AllowRemoteQuery in AuthRecord structure -3. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set -4. mDNS.c only answers remote queries if AllowRemoteQuery is set - -Revision 1.399 2004/09/02 01:39:40 cheshire -For better readability, follow consistent convention that QR bit comes first, followed by OP bits - -Revision 1.398 2004/09/01 03:59:29 ksekar -: Conditionally compile out uDNS code on Windows - -Revision 1.397 2004/08/25 22:04:25 rpantos -Fix the standard Windows compile error. - -Revision 1.396 2004/08/25 00:37:27 ksekar -: Cleanup DynDNS hostname registration code - -Revision 1.395 2004/08/18 17:21:18 ksekar -Removed double-call of uDNS_AdvertiseInterface from mDNS_SetFQDNs() - -Revision 1.394 2004/08/14 03:22:41 cheshire - Dynamic DNS UI <-> mDNSResponder glue -Add GetUserSpecifiedDDNSName() routine -Convert ServiceRegDomain to domainname instead of C string -Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs - -Revision 1.393 2004/08/13 23:42:52 cheshire -Removed unused "zeroDomainNamePtr" - -Revision 1.392 2004/08/13 23:37:02 cheshire -Now that we do both uDNS and mDNS, global replace "uDNS_info.hostname" with -"uDNS_info.UnicastHostname" for clarity - -Revision 1.391 2004/08/13 23:25:00 cheshire -Now that we do both uDNS and mDNS, global replace "m->hostname" with -"m->MulticastHostname" for clarity - -Revision 1.390 2004/08/11 02:17:01 cheshire - Registering service with port number 0 should create a "No Such Service" record - -Revision 1.389 2004/08/10 23:19:14 ksekar -: DNS Extension daemon for Wide Area Service Discovery -Moved routines/constants to allow extern access for garbage collection daemon - -Revision 1.388 2004/07/30 17:40:06 ksekar -: TXT Record updates not available for wide-area services - -Revision 1.387 2004/07/26 22:49:30 ksekar -: Feature #9516: Need support for NAT-PMP in client - -Revision 1.386 2004/07/13 21:24:24 rpantos -Fix for . - -Revision 1.385 2004/06/18 19:09:59 cheshire - Current method of doing subtypes causes name collisions - -Revision 1.384 2004/06/15 04:31:23 cheshire -Make sure to clear m->CurrentRecord at the end of AnswerNewLocalOnlyQuestion() - -Revision 1.383 2004/06/11 00:04:59 cheshire - TTL must be greater than zero for DNSServiceRegisterRecord - -Revision 1.382 2004/06/08 04:59:40 cheshire -Tidy up wording -- log messages are already prefixed with "mDNSResponder", so don't need to repeat it - -Revision 1.381 2004/06/05 00:57:30 cheshire -Remove incorrect LogMsg() - -Revision 1.380 2004/06/05 00:04:26 cheshire -: wide-area domains should be returned in reg. domain enumeration - -Revision 1.379 2004/05/28 23:42:36 ksekar -: Feature: DNS server->client notification on record changes (#7805) - -Revision 1.378 2004/05/25 17:25:25 cheshire -Remove extraneous blank lines and white space - -Revision 1.377 2004/05/18 23:51:25 cheshire -Tidy up all checkin comments to use consistent "" format for bug numbers - -Revision 1.376 2004/05/05 18:30:44 ksekar -Restored surpressed Cache Tail debug messages. - -Revision 1.375 2004/04/26 21:36:25 cheshire -Only send IPv4 (or v6) multicast when IPv4 (or v6) multicast send/receive -is indicated as being available on that interface - -Revision 1.374 2004/04/21 02:53:26 cheshire -Typo in debugf statement - -Revision 1.373 2004/04/21 02:49:11 cheshire -To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx' - -Revision 1.372 2004/04/21 02:38:51 cheshire -Add debugging checks - -Revision 1.371 2004/04/14 23:09:28 ksekar -Support for TSIG signed dynamic updates. - -Revision 1.370 2004/04/09 17:40:26 cheshire -Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field - -Revision 1.369 2004/04/09 16:34:00 cheshire -Debugging code for later; currently unused - -Revision 1.368 2004/04/02 19:19:48 cheshire -Add code to do optional logging of multi-packet KA list time intervals - -Revision 1.367 2004/03/20 03:16:10 cheshire -Minor refinement to "Excessive update rate" message - -Revision 1.366 2004/03/20 03:12:57 cheshire -: UpdateCredits not granted promptly enough - -Revision 1.365 2004/03/19 23:51:22 cheshire -Change to use symbolic constant kUpdateCreditRefreshInterval instead of (mDNSPlatformOneSecond * 60) - -Revision 1.364 2004/03/13 01:57:33 ksekar -: DynDNS: Dynamic update of service records - -Revision 1.363 2004/03/12 21:00:51 cheshire -Also show port numbers when logging "apparent spoof mDNS Response" messages - -Revision 1.362 2004/03/12 08:58:18 cheshire -Guard against empty TXT records - -Revision 1.361 2004/03/09 03:00:46 cheshire - Don't take lock until after mDNS_Update() has validated that the data is good. - -Revision 1.360 2004/03/08 02:52:41 cheshire -Minor debugging fix: Make sure 'target' is initialized so we don't crash writing debugging log messages - -Revision 1.359 2004/03/02 03:21:56 cheshire - Properly support "_services._dns-sd._udp" meta-queries - -Revision 1.358 2004/02/20 08:18:34 cheshire -: mDNSResponder sometimes announces AAAA records unnecessarily - -Revision 1.357 2004/02/18 01:47:41 cheshire -: Insufficient delay waiting for multi-packet KA lists causes AirPort traffic storms - -Revision 1.356 2004/02/06 23:04:19 ksekar -Basic Dynamic Update support via mDNS_Register (dissabled via -UNICAST_REGISTRATION #define) - -Revision 1.355 2004/02/05 09:32:33 cheshire -Fix from Bob Bradley: When using the "%.*s" string form, -guard against truncating in the middle of a multi-byte UTF-8 character. - -Revision 1.354 2004/02/05 09:30:22 cheshire -Update comments - -Revision 1.353 2004/01/28 03:41:00 cheshire -: Need ability to do targeted queries as well as multicast queries - -Revision 1.352 2004/01/28 02:30:07 ksekar -Added default Search Domains to unicast browsing, controlled via -Networking sharing prefs pane. Stopped sending unicast messages on -every interface. Fixed unicast resolving via mach-port API. - -Revision 1.351 2004/01/27 20:15:22 cheshire -: Time to prune obsolete code for listening on port 53 - -Revision 1.350 2004/01/24 23:38:16 cheshire -Use mDNSVal16() instead of shifting and ORing operations - -Revision 1.349 2004/01/23 23:23:14 ksekar -Added TCP support for truncated unicast messages. - -Revision 1.348 2004/01/22 03:54:11 cheshire -Create special meta-interface 'mDNSInterface_ForceMCast' (-2), -which means "do this query via multicast, even if it's apparently a unicast domain" - -Revision 1.347 2004/01/22 03:50:49 cheshire -If the client has specified an explicit InterfaceID, then do query by multicast, not unicast - -Revision 1.346 2004/01/22 03:48:41 cheshire -Make sure uDNS client doesn't accidentally use query ID zero - -Revision 1.345 2004/01/22 03:43:08 cheshire -Export constants like mDNSInterface_LocalOnly so that the client layers can use them - -Revision 1.344 2004/01/21 21:53:18 cheshire -: Don't try to receive unicast responses if we're not the first to bind to the UDP port - -Revision 1.343 2003/12/23 00:07:47 cheshire -Make port number in debug message be five-character field, left justified - -Revision 1.342 2003/12/20 01:34:28 cheshire -: Error putting additional records into packets -Another fix from Rampi: responseptr needs to be updated inside the "for" loop, -after every record, not once at the end. - -Revision 1.341 2003/12/18 22:56:12 cheshire -: Reduce syslog messages about ignored spoof packets - -Revision 1.340 2003/12/16 02:31:37 cheshire -Minor update to comments - -Revision 1.339 2003/12/13 05:50:33 bradley -Fixed crash with mDNS_Lock/Unlock being called for the initial GrowCache before the platform -layer has been initialized. Protect mDNS_reentrancy when completing the core initialization to -fix a race condition during async initialization. Fixed buffer overrun for 1 byte mDNS_snprintf. - -Revision 1.338 2003/12/13 03:05:27 ksekar -: DynDNS: Unicast query of service records - -Revision 1.337 2003/12/01 21:46:05 cheshire -mDNS_StartQuery returns mStatus_BadInterfaceErr if the specified interface does not exist - -Revision 1.336 2003/12/01 21:26:19 cheshire -Guard against zero-length sbuffer in mDNS_vsnprintf() - -Revision 1.335 2003/12/01 20:27:48 cheshire -Display IPv6 addresses correctly (e.g. in log messages) on little-endian processors - -Revision 1.334 2003/11/20 22:59:53 cheshire -Changed runtime checks in mDNS.c to be compile-time checks in mDNSEmbeddedAPI.h -Thanks to Bob Bradley for suggesting the ingenious compiler trick to make this work. - -Revision 1.333 2003/11/20 20:49:53 cheshire -Another fix from HP: Use packedstruct macro to ensure proper packing for on-the-wire packet structures - -Revision 1.332 2003/11/20 05:47:37 cheshire -: Don't exclude known answers whose expiry time is before the next query -Now that we only include answers in the known answer list if they are less than -halfway to expiry, the check to also see if we have another query scheduled -before the record expires is no longer necessary (and in fact, not correct). - -Revision 1.331 2003/11/19 22:31:48 cheshire -When automatically adding A records to SRVs, add them as additionals, not answers - -Revision 1.330 2003/11/19 22:28:50 cheshire -Increment/Decrement mDNS_reentrancy around calls to m->MainCallback() -to allow client to make mDNS calls (specifically the call to mDNS_GrowCache()) - -Revision 1.329 2003/11/19 22:19:24 cheshire -Show log message when ignoring packets with bad TTL. -This is to help diagnose problems on Linux versions that may not report the TTL reliably. - -Revision 1.328 2003/11/19 22:06:38 cheshire -Show log messages when a service or hostname is renamed - -Revision 1.327 2003/11/19 22:03:44 cheshire -Move common "m->NextScheduledResponse = m->timenow" to before "if" statement - -Revision 1.326 2003/11/17 22:27:02 cheshire -Another fix from ramaprasad.kr@hp.com: Improve reply delay computation -on platforms that have native clock rates below fifty ticks per second. - -Revision 1.325 2003/11/17 20:41:44 cheshire -Fix some missing mDNS_Lock(m)/mDNS_Unlock(m) calls. - -Revision 1.324 2003/11/17 20:36:32 cheshire -Function rename: Remove "mDNS_" prefix from AdvertiseInterface() and -DeadvertiseInterface() -- they're internal private routines, not API routines. - -Revision 1.323 2003/11/14 20:59:08 cheshire -Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h. -Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file. - -Revision 1.322 2003/11/14 19:47:52 cheshire -Define symbol MAX_ESCAPED_DOMAIN_NAME to indicate recommended buffer size for ConvertDomainNameToCString - -Revision 1.321 2003/11/14 19:18:34 cheshire -Move AssignDomainName macro to mDNSEmbeddedAPI.h to that client layers can use it too - -Revision 1.320 2003/11/13 06:45:04 cheshire -Fix compiler warning on certain compilers - -Revision 1.319 2003/11/13 00:47:40 cheshire - We should delay AAAA record query if A record already in cache. - -Revision 1.318 2003/11/13 00:33:26 cheshire -Change macro "RRIsAddressType" to "RRTypeIsAddressType" - -Revision 1.317 2003/11/13 00:10:49 cheshire -: Verify that rr data is different before updating. - -Revision 1.316 2003/11/08 23:37:54 cheshire -Give explicit zero initializers to blank static structure, required by certain compilers. -(Thanks to ramaprasad.kr@hp.com for reporting this.) - -Revision 1.315 2003/11/07 03:32:56 cheshire - mDNSResponder delivers answers in inconsistent order -This is the real fix. Checkin 1.312 was overly simplistic; Calling GetFreeCacheRR() can sometimes -purge records from the cache, causing tail pointer *rp to be stale on return. The correct fix is -to maintain a system-wide tail pointer for each cache slot, and then if neccesary GetFreeCacheRR() -can update this pointer, so that mDNSCoreReceiveResponse() appends records in the right place. - -Revision 1.314 2003/11/07 03:19:49 cheshire -Minor variable renaming for clarity - -Revision 1.313 2003/11/07 03:14:49 cheshire -Previous checkin proved to be overly simplistic; reversing - -Revision 1.312 2003/11/03 23:45:15 cheshire - mDNSResponder delivers answers in inconsistent order -Build cache lists in FIFO order, not customary C LIFO order -(Append new elements to tail of cache list, instead of prepending at the head.) - -Revision 1.311 2003/10/09 18:00:11 cheshire -Another compiler warning fix. - -Revision 1.310 2003/10/07 20:27:05 cheshire -Patch from Bob Bradley, to fix warning and compile error on Windows - -Revision 1.309 2003/09/26 01:06:36 cheshire - Set kDNSClass_UniqueRRSet bit for updates too -Made new routine HaveSentEntireRRSet() to check if flag should be set - -Revision 1.308 2003/09/23 01:05:01 cheshire -Minor changes to comments and debugf() message - -Revision 1.307 2003/09/09 20:13:30 cheshire - Don't send a Goodbye record if we never announced it -Ammend checkin 1.304: Off-by-one error: By this place in the function we've already decremented -rr->AnnounceCount, so the check needs to be for InitialAnnounceCount-1, not InitialAnnounceCount - -Revision 1.306 2003/09/09 03:00:03 cheshire - Services take a long time to disappear when switching networks. -Added two constants: kDefaultReconfirmTimeForNoAnswer and kDefaultReconfirmTimeForCableDisconnect - -Revision 1.305 2003/09/09 02:49:31 cheshire - Initial probes and queries not grouped on wake-from-sleep +Revision 1.729 2007/10/05 17:56:10 cheshire +Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files -Revision 1.304 2003/09/09 02:41:19 cheshire - Don't send a Goodbye record if we never announced it +Revision 1.728 2007/10/04 23:18:14 cheshire + mDNSResponder flooding DNS servers with unreasonable query level -Revision 1.303 2003/09/05 19:55:02 cheshire - Include address records when announcing SRV records +Revision 1.727 2007/10/04 22:51:57 cheshire +Added debugging LogOperation message to show when we're sending cache expiration queries -Revision 1.302 2003/09/05 00:01:36 cheshire - Don't accelerate queries that have large KA lists +Revision 1.726 2007/10/03 00:14:24 cheshire +Removed write to null to generate stack trace for SetNextQueryTime locking failure -Revision 1.301 2003/09/04 22:51:13 cheshire - Group probes and goodbyes better +Revision 1.725 2007/10/02 21:11:08 cheshire + LLQ refreshes don't work, which breaks BTMM browsing -Revision 1.300 2003/09/03 02:40:37 cheshire - mDNSResponder complains about '_'s -Underscores are not supposed to be legal in standard DNS names, but IANA appears -to have allowed them in previous service name registrations, so we should too. +Revision 1.724 2007/10/02 20:10:23 cheshire +Additional debugging checks on shutdown -- list all records we didn't send a goodbye for, not just the first one -Revision 1.299 2003/09/03 02:33:09 cheshire - CacheRecordRmv ERROR -Don't update m->NewQuestions until *after* CheckCacheExpiration(); +Revision 1.723 2007/10/02 19:56:54 cheshire + Double-dispose causes crash changing Dynamic DNS hostname -Revision 1.298 2003/09/03 01:47:01 cheshire - Services always in a state of flux -Change mDNS_Reconfirm_internal() minimum timeout from 5 seconds to 45-60 seconds +Revision 1.722 2007/10/01 22:59:46 cheshire + mDNSResponder did not shut down after 20 seconds +Need to shut down NATTraversals on exit -Revision 1.297 2003/08/29 19:44:15 cheshire - Traffic reduction: Eliminate synchronized QUs when a new service appears -1. Use m->RandomQueryDelay to impose a random delay in the range 0-500ms on queries - that already have at least one unique answer in the cache -2. For these queries, go straight to QM, skipping QU +Revision 1.721 2007/10/01 18:42:07 cheshire +To make packet logs appear in a more intuitive order, dump received packets *before* handling them, not after -Revision 1.296 2003/08/29 19:08:21 cheshire - Traffic reduction: Eliminate huge KA lists after wake from sleep -Known answers are no longer eligible to go in the KA list if they are more than half-way to their expiry time. +Revision 1.720 2007/09/29 20:40:19 cheshire + Crash in ReissueBlockedQuestions -Revision 1.295 2003/08/28 01:10:59 cheshire - Add syslog message to report when query is reset because of immediate answer burst +Revision 1.719 2007/09/27 22:23:56 cheshire + uDNS: Use SOA to determine TTL for negative answers +Need to clear m->rec.r.resrec.RecordType after we've finished using m->rec -Revision 1.294 2003/08/27 02:30:22 cheshire - Traffic Reduction: Inefficiencies in DNSServiceResolverResolve() -One more change: "query->GotTXT" is now a straightforward bi-state boolean again +Revision 1.718 2007/09/27 22:02:33 cheshire + BTMM: Registered records in BTMM don't get removed from server after calling RemoveRecord -Revision 1.293 2003/08/27 02:25:31 cheshire - Traffic Reduction: Inefficiencies in DNSServiceResolverResolve() +Revision 1.717 2007/09/27 21:21:39 cheshire +Export CompleteDeregistration so it's callable from other files -Revision 1.292 2003/08/21 19:27:36 cheshire - Traffic reduction: No need to announce record for longer than TTL +Revision 1.716 2007/09/27 02:12:21 cheshire +Updated GrantCacheExtensions degugging message to show new record lifetime -Revision 1.291 2003/08/21 18:57:44 cheshire - Synchronized queries on the network +Revision 1.715 2007/09/27 01:20:06 cheshire + BTMM: Need to refresh LLQs based on lease life and not TTL of response -Revision 1.290 2003/08/21 02:25:23 cheshire -Minor changes to comments and debugf() messages +Revision 1.714 2007/09/27 00:37:01 cheshire + BTMM: Use SOA to determine TTL for negative answers -Revision 1.289 2003/08/21 02:21:50 cheshire - Efficiency: Reduce repeated queries +Revision 1.713 2007/09/27 00:25:39 cheshire +Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for: + uDNS: Use SOA to determine TTL for negative answers -Revision 1.288 2003/08/20 23:39:30 cheshire - Review syslog messages, and remove as appropriate +Revision 1.712 2007/09/26 23:16:58 cheshire + BTMM: Leopard sending excessive LLQ registration requests to .Mac -Revision 1.287 2003/08/20 20:47:18 cheshire -Fix compiler warning +Revision 1.711 2007/09/26 22:06:02 cheshire + BTMM: No immediate failure notifications for BTMM names -Revision 1.286 2003/08/20 02:18:51 cheshire - Cleanup: Review syslog messages +Revision 1.710 2007/09/26 00:49:46 cheshire +Improve packet logging to show sent and received packets, +transport protocol (UDP/TCP/TLS) and source/destination address:port -Revision 1.285 2003/08/20 01:59:06 cheshire - rdatahash and rdnamehash not updated after changing rdata -Made new routine SetNewRData() to update rdlength, rdestimate, rdatahash and rdnamehash in one place +Revision 1.709 2007/09/21 21:12:36 cheshire + BTMM: Need to log updates and query packet contents -Revision 1.284 2003/08/19 22:20:00 cheshire - Don't use IPv6 on interfaces that have a routable IPv4 address configured -More minor refinements +Revision 1.708 2007/09/20 23:13:37 cheshire + BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network +Additional fix: If we have no DNS servers at all, then immediately purge all unicast cache records (including for LLQs) -Revision 1.283 2003/08/19 22:16:27 cheshire -Minor fix: Add missing "mDNS_Unlock(m);" in mDNS_DeregisterInterface() error case. +Revision 1.707 2007/09/20 02:29:37 cheshire + BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network -Revision 1.282 2003/08/19 06:48:25 cheshire - Guard against excessive record updates -Each record starts with 10 UpdateCredits. -Every update consumes one UpdateCredit. -UpdateCredits are replenished at a rate of one one per minute, up to a maximum of 10. -As the number of UpdateCredits declines, the number of announcements is similarly scaled back. -When fewer than 5 UpdateCredits remain, the first announcement is also delayed by an increasing amount. +Revision 1.706 2007/09/20 01:13:19 cheshire +Export CacheGroupForName so it's callable from other files -Revision 1.281 2003/08/19 04:49:28 cheshire - Interaction between v4, v6 and dual-stack hosts not working quite right -1. A dual-stack host should only suppress its own query if it sees the same query from other hosts on BOTH IPv4 and IPv6. -2. When we see the first v4 (or first v6) member of a group, we re-trigger questions and probes on that interface. -3. When we see the last v4 (or v6) member of a group go away, we revalidate all the records received on that interface. +Revision 1.705 2007/09/20 01:12:06 cheshire +Moved HashSlot(X) from mDNS.c to DNSCommon.h so it's usable in other files -Revision 1.280 2003/08/19 02:33:36 cheshire -Update comments +Revision 1.704 2007/09/19 22:47:25 cheshire + Memory corruption freeing a "no such service" service record -Revision 1.279 2003/08/19 02:31:11 cheshire - mDNSResponder overenthusiastic with final expiration queries -Final expiration queries now only mark the question for sending on the particular interface -pertaining to the record that's expiring. +Revision 1.703 2007/09/14 01:46:59 cheshire +Fix Posix build (#ifdef _LEGACY_NAT_TRAVERSAL_ section included a closing curly brace it should not have) -Revision 1.278 2003/08/18 22:53:37 cheshire - mDNSResponder divide by zero in mDNSPlatformRawTime() +Revision 1.702 2007/09/13 22:06:46 cheshire + Tully's Free WiFi: DNS fails +Need to accept DNS responses where the query ID field matches, even if the source address does not -Revision 1.277 2003/08/18 19:05:44 cheshire - UpdateRecord not working right -Added "newrdlength" field to hold new length of updated rdata +Revision 1.701 2007/09/12 23:22:32 cheshire + Only accept NAT Port Mapping packets from our default gateway -Revision 1.276 2003/08/16 03:39:00 cheshire - InterfaceID -1 indicates "local only" +Revision 1.700 2007/09/12 23:03:08 cheshire + DNSServiceNATPortMappingCreate callback not giving correct interface index -Revision 1.275 2003/08/16 02:51:27 cheshire - mDNSResponder takes too much RPRVT -Don't try to compute namehash etc, until *after* validating the name +Revision 1.699 2007/09/12 22:19:28 cheshire + Need to listen for port 5350 NAT-PMP announcements -Revision 1.274 2003/08/16 01:12:40 cheshire - mDNSResponder takes too much RPRVT -Now that the minimum rdata object size has been reduced to 64 bytes, it is no longer safe to do a -simple C structure assignment of a domainname, because that object is defined to be 256 bytes long, -and in the process of copying it, the C compiler may run off the end of the rdata object into -unmapped memory. All assignments of domainname objects of uncertain size are now replaced with a -call to the macro AssignDomainName(), which is careful to copy only as many bytes as are valid. +Revision 1.698 2007/09/12 22:13:27 cheshire +Remove DynDNSHostNames cleanly on shutdown -Revision 1.273 2003/08/15 20:16:02 cheshire - mDNSResponder takes too much RPRVT -We want to avoid touching the rdata pages, so we don't page them in. -1. RDLength was stored with the rdata, which meant touching the page just to find the length. - Moved this from the RData to the ResourceRecord object. -2. To avoid unnecessarily touching the rdata just to compare it, - compute a hash of the rdata and store the hash in the ResourceRecord object. +Revision 1.697 2007/09/12 01:44:47 cheshire + Eliminate "Correcting TTL" syslog messages for unicast DNS records -Revision 1.272 2003/08/14 19:29:04 cheshire - Include cache records in SIGINFO output -Moved declarations of DNSTypeName() and GetRRDisplayString to mDNSEmbeddedAPI.h so daemon.c can use them +Revision 1.696 2007/09/12 01:26:08 cheshire +Initialize LastNATReplyLocalTime to timenow, so that gateway uptime checks work more reliably -Revision 1.271 2003/08/14 02:17:05 cheshire - Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord +Revision 1.695 2007/09/11 19:19:16 cheshire +Correct capitalization of "uPNP" to "UPnP" -Revision 1.270 2003/08/13 17:07:28 ksekar -: Extra RR linked to list even if registration fails - causes crash -Added check to result of mDNS_Register() before linking extra record into list. +Revision 1.694 2007/09/10 22:06:51 cheshire +Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds -Revision 1.269 2003/08/12 19:56:23 cheshire -Update to APSL 2.0 +Revision 1.693 2007/09/07 22:24:36 vazquez + Need to stop spewing mDNSResponderHelper logs -Revision 1.268 2003/08/12 15:01:10 cheshire -Add comments +Revision 1.692 2007/09/07 00:12:09 cheshire + Unicast DNS changes broke efficiency fix 3928456 -Revision 1.267 2003/08/12 14:59:27 cheshire - Rate-limiting blocks some legitimate responses -When setting LastMCTime also record LastMCInterface. When checking LastMCTime to determine -whether to suppress the response, also check LastMCInterface to see if it matches. +Revision 1.691 2007/09/05 22:25:01 vazquez + update_record mDNSResponder leak -Revision 1.266 2003/08/12 12:47:16 cheshire -In mDNSCoreMachineSleep debugf message, display value of m->timenow +Revision 1.690 2007/09/05 21:48:01 cheshire + BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone. +Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance cod needs +to update the cache lifetimes of all relevant records every time it successfully renews an LLQ, +otherwise those records will expire and vanish from the cache. -Revision 1.265 2003/08/11 20:04:28 cheshire - Improve efficiency by restricting cases where we have to walk the entire cache +Revision 1.689 2007/09/05 02:29:06 cheshire + mDNSResponder taking up 100% CPU in ReissueBlockedQuestions +Additional fixes to code implementing "NoAnswer" logic -Revision 1.264 2003/08/09 00:55:02 cheshire - mDNSResponder is taking 20-30% of the CPU -Don't scan the whole cache after every packet. +Revision 1.688 2007/08/31 22:56:39 cheshire + BTMM: TTLs incorrect on cached BTMM records -Revision 1.263 2003/08/09 00:35:29 cheshire -Moved AnswerNewQuestion() later in the file, in preparation for next checkin +Revision 1.687 2007/08/31 19:53:14 cheshire + BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup +If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist -Revision 1.262 2003/08/08 19:50:33 cheshire - Remove "Cache size now xxx" messages +Revision 1.686 2007/08/30 00:01:56 cheshire +Added comment about SetTargetToHostName() -Revision 1.261 2003/08/08 19:18:45 cheshire - Only retrigger questions on platforms with the "PhantomInterfaces" bug +Revision 1.685 2007/08/29 01:19:24 cheshire + BTMM: Tunneled services do not need NAT port mappings +Set AutoTarget to Target_AutoHostAndNATMAP for non-AutoTunnel wide-area services -Revision 1.260 2003/08/08 18:55:48 cheshire - Guard against time going backwards +Revision 1.684 2007/08/28 23:58:42 cheshire +Rename HostTarget -> AutoTarget -Revision 1.259 2003/08/08 18:36:04 cheshire - Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug +Revision 1.683 2007/08/28 23:53:21 cheshire +Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete -Revision 1.258 2003/08/08 16:22:05 cheshire - Need to check validity of TXT (and other) records -Remove unneeded LogMsg +Revision 1.682 2007/08/27 20:28:19 cheshire +Improve "suspect uDNS response" log message -Revision 1.257 2003/08/07 01:41:08 cheshire - Ignore packets with invalid source address (all zeroes or all ones) +Revision 1.681 2007/08/24 23:37:23 cheshire +Added debugging message to show when ExtraResourceRecord callback gets invoked -Revision 1.256 2003/08/06 23:25:51 cheshire - Increase TTL for A/AAAA/SRV from one minute to four +Revision 1.680 2007/08/24 00:15:19 cheshire +Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held -Revision 1.255 2003/08/06 23:22:50 cheshire -Add symbolic constants: kDefaultTTLforUnique (one minute) and kDefaultTTLforShared (two hours) +Revision 1.679 2007/08/23 21:47:09 vazquez + BTMM: mDNSResponder sends NAT-PMP packets on public network +make sure we clean up port mappings on base stations by sending a lease value of 0, +and only send NAT-PMP packets on private networks; also save some memory by +not using packet structs in NATTraversals. -Revision 1.254 2003/08/06 21:33:39 cheshire -Fix compiler warnings on PocketPC 2003 (Windows CE) +Revision 1.678 2007/08/01 16:09:13 cheshire +Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly -Revision 1.253 2003/08/06 20:43:57 cheshire - Need to check validity of TXT (and other) records -Created ValidateDomainName() and ValidateRData(), used by mDNS_Register_internal() and mDNS_Update() +Revision 1.677 2007/08/01 01:58:24 cheshire +Added RecordType sanity check in mDNS_Register_internal -Revision 1.252 2003/08/06 20:35:47 cheshire -Enhance debugging routine GetRRDisplayString() so it can also be used to display -other RDataBody objects, not just the one currently attached the given ResourceRecord +Revision 1.676 2007/08/01 00:04:13 cheshire + Crash in tcpKQSocketCallback +Half-open TCP connections were not being cancelled properly -Revision 1.251 2003/08/06 19:07:34 cheshire - mDNSResponder not inhibiting multicast responses as much as it should -Was checking LastAPTime instead of LastMCTime +Revision 1.675 2007/07/31 02:28:35 vazquez + NAT-PMP: Detect public IP address changes and base station reboot -Revision 1.250 2003/08/06 19:01:55 cheshire -Update comments +Revision 1.674 2007/07/31 01:57:23 cheshire +Adding code to respect TTL received in uDNS responses turned out to +expose other problems; backing out change for now. -Revision 1.249 2003/08/06 00:13:28 cheshire -Tidy up debugf messages +Revision 1.673 2007/07/30 23:31:26 cheshire +Code for respecting TTL received in uDNS responses should exclude LLQ-type responses -Revision 1.248 2003/08/05 22:20:15 cheshire - Need to check IP TTL on responses +Revision 1.672 2007/07/28 01:25:56 cheshire + BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT -Revision 1.247 2003/08/05 00:56:39 cheshire - mDNSResponder sending additional records, even after precursor record suppressed +Revision 1.671 2007/07/27 22:32:54 cheshire +When processing TTLs in uDNS responses, we'll currently impose a minimum effective TTL +of 2 seconds, or other stuff breaks (e.g. we end up making a negative cache entry). -Revision 1.246 2003/08/04 19:20:49 cheshire -Add kDNSQType_ANY to list in DNSTypeName() so it can be displayed in debugging messages +Revision 1.670 2007/07/27 20:54:43 cheshire +Fixed code to respect real record TTL received in uDNS responses -Revision 1.245 2003/08/02 01:56:29 cheshire -For debugging: log message if we ever get more than one question in a truncated packet +Revision 1.669 2007/07/27 20:09:32 cheshire +Don't need to dump out all received mDNS packets; they're easily viewed using mDNSNetMonitor -Revision 1.244 2003/08/01 23:55:32 cheshire -Fix for compiler warnings on Windows, submitted by Bob Bradley +Revision 1.668 2007/07/27 19:58:47 cheshire +Use symbolic names QC_add and QC_rmv instead of mDNStrue/mDNSfalse -Revision 1.243 2003/07/25 02:26:09 cheshire -Typo: FIxed missing semicolon +Revision 1.667 2007/07/27 19:52:10 cheshire +Don't increment m->rrcache_active for no-cache add events -Revision 1.242 2003/07/25 01:18:41 cheshire -Fix memory leak on shutdown in mDNS_Close() (detected in Windows version) +Revision 1.666 2007/07/27 19:30:39 cheshire +Changed mDNSQuestionCallback parameter from mDNSBool to QC_result, +to properly reflect tri-state nature of the possible responses -Revision 1.241 2003/07/23 21:03:42 cheshire -Only show "Found record..." debugf message in verbose mode +Revision 1.665 2007/07/27 18:44:01 cheshire +Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord" -Revision 1.240 2003/07/23 21:01:11 cheshire - Need Nagle-style algorithm to coalesce multiple packets into one -After sending a packet, suppress further sending for the next 100ms. +Revision 1.664 2007/07/27 18:38:56 cheshire +Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion" -Revision 1.239 2003/07/22 01:30:05 cheshire - Don't try to add the same question to the duplicate-questions list more than once +Revision 1.663 2007/07/25 03:05:02 vazquez +Fixes for: + LegacyNATTraversal: UPnP heap overflow + LegacyNATTraversal: UPnP stack buffer overflow +and a myriad of other security problems -Revision 1.238 2003/07/22 00:10:20 cheshire - ConvertDomainLabelToCString() needs to escape escape characters +Revision 1.662 2007/07/24 20:22:46 cheshire +Make sure all fields of main mDNS object are initialized correctly -Revision 1.237 2003/07/19 03:23:13 cheshire - mDNSResponder needs to receive and cache larger records +Revision 1.661 2007/07/21 00:54:45 cheshire + Delay IPv6 address callback until AutoTunnel route and policy is configured -Revision 1.236 2003/07/19 03:04:55 cheshire -Fix warnings; some debugf message improvements +Revision 1.660 2007/07/20 20:00:45 cheshire +"Legacy Browse" is better called "Automatic Browse" -Revision 1.235 2003/07/19 00:03:32 cheshire - ScheduleNextTask needs to be smarter after a no-op packet is received -ScheduleNextTask is quite an expensive operation. -We don't need to do all that work after receiving a no-op packet that didn't change our state. +Revision 1.659 2007/07/20 00:54:18 cheshire + Need separate SCPreferences for per-user .Mac settings -Revision 1.234 2003/07/18 23:52:11 cheshire -To improve consistency of field naming, global search-and-replace: -NextProbeTime -> NextScheduledProbe -NextResponseTime -> NextScheduledResponse +Revision 1.658 2007/07/18 02:28:57 cheshire +Don't set AutoTunnel settings in uDNS_RegisterService; should be done in GetServiceTarget -Revision 1.233 2003/07/18 00:29:59 cheshire - Remove mDNSResponder version from packet header and use HINFO record instead +Revision 1.657 2007/07/18 00:57:10 cheshire + Automatically configure IPSec policy when resolving services +Only need to call AddNewClientTunnel() for IPv6 addresses -Revision 1.232 2003/07/18 00:11:38 cheshire -Add extra case to switch statements to handle HINFO data for Get, Put and Display -(In all but GetRDLength(), this is is just a fall-through to kDNSType_TXT) +Revision 1.656 2007/07/16 23:54:48 cheshire + Crash when removing or changing DNS keys -Revision 1.231 2003/07/18 00:06:37 cheshire -To make code a little easier to read in GetRDLength(), search-and-replace "rr->rdata->u." with "rd->" +Revision 1.655 2007/07/16 20:11:37 vazquez + LegacyNATTraversal: Need complete rewrite +Init LNT stuff and handle SSDP packets -Revision 1.230 2003/07/17 18:16:54 cheshire - Services always in a state of flux -In preparation for working on this, made some debugf messages a little more selective +Revision 1.654 2007/07/12 23:30:23 cheshire +Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog -Revision 1.229 2003/07/17 17:35:04 cheshire - Rate-limit responses, to guard against packet flooding +Revision 1.653 2007/07/12 02:51:27 cheshire + Automatically configure IPSec policy when resolving services -Revision 1.228 2003/07/16 20:50:27 cheshire - Need to implement "unicast response" request, using top bit of qclass +Revision 1.652 2007/07/11 23:43:42 cheshire +Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord -Revision 1.227 2003/07/16 05:01:36 cheshire -Add fields 'LargeAnswers' and 'ExpectUnicastResponse' in preparation for - Need to implement "unicast response" request, using top bit of qclass +Revision 1.651 2007/07/11 22:44:40 cheshire + SIGHUP should purge the cache -Revision 1.226 2003/07/16 04:51:44 cheshire -Fix use of constant 'mDNSPlatformOneSecond' where it should have said 'InitialQuestionInterval' +Revision 1.650 2007/07/11 21:34:09 cheshire + Register IPSec tunnel with IPv4-only hostname and create NAT port mappings +Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName/mDNS_RemoveDynDNSHostName -Revision 1.225 2003/07/16 04:46:41 cheshire -Minor wording cleanup: The correct DNS term is "response", not "reply" +Revision 1.649 2007/07/11 02:52:52 cheshire + Register IPv6-only hostname and don't create port mappings for AutoTunnel services +In uDNS_RegisterService, set HostTarget for AutoTunnel services -Revision 1.224 2003/07/16 04:39:02 cheshire -Textual cleanup (no change to functionality): -Construct "c >= 'A' && c <= 'Z'" appears in too many places; replaced with macro "mDNSIsUpperCase(c)" +Revision 1.648 2007/07/09 23:48:12 cheshire +Add parentheses around bitwise operation for clarity -Revision 1.223 2003/07/16 00:09:22 cheshire -Textual cleanup (no change to functionality): -Construct "((mDNSs32)rr->rroriginalttl * mDNSPlatformOneSecond)" appears in too many places; -replace with macro "TicksTTL(rr)" -Construct "rr->TimeRcvd + ((mDNSs32)rr->rroriginalttl * mDNSPlatformOneSecond)" -replaced with macro "RRExpireTime(rr)" +Revision 1.647 2007/07/06 21:17:55 cheshire +Initialize m->retryGetAddr to timenow + 0x78000000; -Revision 1.222 2003/07/15 23:40:46 cheshire -Function rename: UpdateDupSuppressInfo() is more accurately called ExpireDupSuppressInfo() +Revision 1.646 2007/07/06 18:55:49 cheshire +Initialize m->NextScheduledNATOp -Revision 1.221 2003/07/15 22:17:56 cheshire - mDNSResponder is not being efficient when doing certain queries +Revision 1.645 2007/06/29 22:55:54 cheshire +Move declaration of DNSServer *s; Fixed incomplete comment. -Revision 1.220 2003/07/15 02:12:51 cheshire -Slight tidy-up of debugf messages and comments +Revision 1.644 2007/06/29 00:07:29 vazquez + Clean up NAT state machine (necessary for 6 other fixes) -Revision 1.219 2003/07/15 01:55:12 cheshire - Need to implement service registration with subtypes +Revision 1.643 2007/06/20 01:10:12 cheshire + Sync iPhone changes into main mDNSResponder code -Revision 1.218 2003/07/14 16:26:06 cheshire - Duplicate query suppression not working right -Refinement: Don't record DS information for a question in the first quarter second -right after we send it -- in the case where a question happens to be accelerated by -the maximum allowed amount, we don't want it to then be suppressed because the previous -time *we* sent that question falls (just) within the valid duplicate suppression window. +Revision 1.642 2007/06/15 21:54:50 cheshire + Add packet logging to help debugging private browsing over TLS -Revision 1.217 2003/07/13 04:43:53 cheshire - Services on multiple interfaces not always resolving -Minor refinement: No need to make address query broader than the original SRV query that provoked it +Revision 1.641 2007/05/25 00:30:24 cheshire +When checking for duplicate questions, make sure privacy (or not) status, and long-lived (or not) +status matches. This is particularly important when doing a private query for an SOA record, +which will result in a call StartGetZoneData which does a non-private query for the same SOA record. +If the latter is tagged as a duplicate of the former, then we have deadlock, and neither will complete. -Revision 1.216 2003/07/13 03:13:17 cheshire - Services on multiple interfaces not always resolving -If we get an identical SRV on a second interface, convert address queries to non-specific +Revision 1.640 2007/05/25 00:25:44 cheshire + Need to enhance putRData to output all current known types -Revision 1.215 2003/07/13 02:28:00 cheshire - SendResponses didn't all its responses -Delete all references to RRInterfaceActive -- it's now superfluous +Revision 1.639 2007/05/23 00:51:33 cheshire +Increase threshold for shedding cache records from 512 to 3000. The 512 figure was calculated when +each cache entry took about 700 bytes; now they're only 164 bytes. Also, machines have more RAM these +days, and there are more services being advertised using DNS-SD, so it makes sense to cache more. -Revision 1.214 2003/07/13 01:47:53 cheshire -Fix one error and one warning in the Windows build +Revision 1.638 2007/05/23 00:43:16 cheshire +If uDNS UDP response has TC (truncated) bit set, don't interpret it as being the entire RRSet -Revision 1.213 2003/07/12 04:25:48 cheshire -Fix minor signed/unsigned warnings +Revision 1.637 2007/05/14 23:53:00 cheshire +Export mDNS_StartQuery_internal and mDNS_StopQuery_internal so they can be called from uDNS.c -Revision 1.212 2003/07/12 01:59:11 cheshire -Minor changes to debugf messages +Revision 1.636 2007/05/10 23:27:15 cheshire +Update mDNS_Deregister_internal debugging messages -Revision 1.211 2003/07/12 01:47:01 cheshire - After name conflict, appended number should be higher than previous number +Revision 1.635 2007/05/07 20:43:45 cheshire + Reduce the number of queries and announcements -Revision 1.210 2003/07/12 01:43:28 cheshire - Duplicate query suppression not working right -The correct cutoff time for duplicate query suppression is timenow less one-half the query interval. -The code was incorrectly using the last query time plus one-half the query interval. -This was only correct in the case where query acceleration was not in effect. +Revision 1.634 2007/05/04 22:09:08 cheshire +Only do "restarting exponential backoff sequence" for mDNS questions +In mDNS_RegisterInterface, only retrigger mDNS questions +In uDNS_SetupDNSConfig, use ActivateUnicastQuery() instead of just setting q->ThisQInterval directly -Revision 1.209 2003/07/12 01:27:50 cheshire - Hostname conflict naming should not use two hyphens -Fix missing "-1" in RemoveLabelSuffix() +Revision 1.633 2007/05/04 21:45:12 cheshire +Get rid of unused q->RestartTime; Get rid of uDNS_Close (synonym for uDNS_Sleep) -Revision 1.208 2003/07/11 01:32:38 cheshire -Syntactic cleanup (no change to funcationality): Now that we only have one host name, -rename field "hostname1" to "hostname", and field "RR_A1" to "RR_A". +Revision 1.632 2007/05/04 20:20:50 cheshire + RegisterRecord and RegisterService need to cancel StartGetZoneData +Need to set srs->nta = mDNSNULL; when regState_NoTarget -Revision 1.207 2003/07/11 01:28:00 cheshire - No more local.arpa +Revision 1.631 2007/05/04 00:39:42 cheshire + Eliminate looping SOA lookups +When creating a cascade of negative SOA cache entries, CacheGroup pointer cg needs to be updated +each time round the loop to reference the right CacheGroup for each newly fabricated SOA name -Revision 1.206 2003/07/11 00:45:02 cheshire - Client should get callback confirming successful host name registration +Revision 1.630 2007/05/03 22:40:38 cheshire + mDNSResponder ignores bogus null target in SRV record -Revision 1.205 2003/07/11 00:40:18 cheshire -Tidy up debug message in HostNameCallback() +Revision 1.629 2007/05/03 00:15:51 cheshire + Eliminate looping SOA lookups -Revision 1.204 2003/07/11 00:20:32 cheshire - mDNSResponder should log a message after 16 unsuccessful probes +Revision 1.628 2007/05/02 22:21:33 cheshire + RegisterRecord and RegisterService need to cancel StartGetZoneData -Revision 1.203 2003/07/10 23:53:41 cheshire - Hostname conflict naming should not use two hyphens +Revision 1.627 2007/04/30 19:29:13 cheshire +Fix display of port number in "Updating DNS Server" message -Revision 1.202 2003/07/04 02:23:20 cheshire - Responder too aggressive at flushing stale data -Changed mDNSResponder to require four unanswered queries before purging a record, instead of two. +Revision 1.626 2007/04/30 04:21:13 cheshire +Can't safely call AnswerLocalQuestions() from within mDNS_Deregister() -- need to defer it until mDNS_Execute time -Revision 1.201 2003/07/04 01:09:41 cheshire - Need to implement subtype queries -Modified ConstructServiceName() to allow three-part service types +Revision 1.625 2007/04/28 01:34:21 cheshire +Fixed crashing bug: We need to update rr->CRActiveQuestion pointers for *all* questions +(Code was explicitly ignoring wide-area unicast questions, leading to stale pointers and crashes) -Revision 1.200 2003/07/03 23:55:26 cheshire -Minor change to wording of syslog warning messages +Revision 1.624 2007/04/27 21:04:30 cheshire +On network configuration change, need to call uDNS_RegisterSearchDomains -Revision 1.199 2003/07/03 23:51:13 cheshire -: Lots of "have given xxx answers" syslog warnings -Added more detailed debugging information +Revision 1.623 2007/04/27 19:28:01 cheshire +Any code that calls StartGetZoneData needs to keep a handle to the structure, so +it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop +-- it would start a query and then quickly cancel it, and then when +StartGetZoneData completed, it had a dangling pointer and crashed.) -Revision 1.198 2003/07/03 22:19:30 cheshire - Bug fix in 3274153 breaks TiVo -Make exception to allow _tivo_servemedia._tcp. +Revision 1.622 2007/04/26 16:09:22 cheshire +mDNS_StopQueryWithRemoves should ignore kDNSRecordTypePacketNegative records -Revision 1.197 2003/07/02 22:33:05 cheshire - mDNSResponder needs to start with a smaller cache and then grow it as needed -Minor refinements: -When cache is exhausted, verify that rrcache_totalused == rrcache_size and report if not -Allow cache to grow to 512 records before considering it a potential denial-of-service attack +Revision 1.621 2007/04/26 15:43:22 cheshire +Make sure DNSServer *s is non-null before using value in LogOperation -Revision 1.196 2003/07/02 21:19:45 cheshire - Update copyright notices, etc., in source code comments +Revision 1.620 2007/04/26 13:11:05 cheshire +Fixed crash when logging out of VPN -Revision 1.195 2003/07/02 19:56:58 cheshire - mDNSResponder needs to start with a smaller cache and then grow it as needed -Minor refinement: m->rrcache_active was not being decremented when -an active record was deleted because its TTL expired +Revision 1.619 2007/04/26 00:35:15 cheshire + uDNS: Domain discovery not working over VPN +Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server +inside the firewall may give answers where a public one gives none, and vice versa.) -Revision 1.194 2003/07/02 18:47:40 cheshire -Minor wording change to log messages +Revision 1.618 2007/04/25 19:26:01 cheshire +m->NextScheduledQuery was getting set too early in SendQueries() +Improved "SendQueries didn't send all its queries" debugging message -Revision 1.193 2003/07/02 02:44:13 cheshire -Fix warning in non-debug build +Revision 1.617 2007/04/25 17:48:22 cheshire +Update debugging message -Revision 1.192 2003/07/02 02:41:23 cheshire - mDNSResponder needs to start with a smaller cache and then grow it as needed +Revision 1.616 2007/04/25 16:38:32 cheshire +If negative cache entry already exists, reactivate it instead of creating a new one -Revision 1.191 2003/07/02 02:30:51 cheshire -HashSlot() returns an array index. It can't be negative; hence it should not be signed. +Revision 1.615 2007/04/25 02:14:38 cheshire + uDNS: Identical client queries should reference a single shared core query +Additional fixes to make LLQs work properly -Revision 1.190 2003/06/27 00:03:05 vlubet - Merge of build failure fix for gcc 3.3 +Revision 1.614 2007/04/23 21:52:45 cheshire + IPv6 filtering in AirPort base station breaks Wide-Area Bonjour -Revision 1.189 2003/06/11 19:24:03 cheshire - Crash in SendQueries/SendResponses when no active interfaces -Slight refinement to previous checkin +Revision 1.613 2007/04/23 04:58:20 cheshire + Crash when setting extremely large TXT records -Revision 1.188 2003/06/10 20:33:28 cheshire - Crash in SendQueries/SendResponses when no active interfaces +Revision 1.612 2007/04/22 20:39:38 cheshire + Add 20 to 120ms random delay to browses -Revision 1.187 2003/06/10 04:30:44 cheshire - Need to re-probe/re-announce on configuration change -Only interface-specific records were re-probing and re-announcing, not non-specific records. +Revision 1.611 2007/04/22 18:16:29 cheshire +Removed incorrect ActiveQuestion(q) check that was preventing suspended questions from getting reactivated -Revision 1.186 2003/06/10 04:24:39 cheshire - React when we observe other people query unsuccessfully for a record that's in our cache -Some additional refinements: -Don't try to do this for unicast-response queries -better tracking of Qs and KAs in multi-packet KA lists +Revision 1.610 2007/04/22 06:02:02 cheshire + Query should immediately return failure when no server -Revision 1.185 2003/06/10 03:52:49 cheshire -Update comments and debug messages +Revision 1.609 2007/04/20 21:17:24 cheshire +For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative -Revision 1.184 2003/06/10 02:26:39 cheshire - mDNSResponder needs an mDNS_Reconfirm() function -Make mDNS_Reconfirm() call mDNS_Lock(), like the other API routines +Revision 1.608 2007/04/20 19:45:31 cheshire +In LogAllOperations mode, dump out unknown DNS packets in their entirety -Revision 1.183 2003/06/09 18:53:13 cheshire -Simplify some debugf() statements (replaced block of 25 lines with 2 lines) +Revision 1.607 2007/04/19 23:56:25 cheshire +Don't do cache-flush processing for LLQ answers -Revision 1.182 2003/06/09 18:38:42 cheshire - Need to be more tolerant when there are mDNS proxies on the network -Only issue a correction if the TTL in the proxy packet is less than half the correct value. +Revision 1.606 2007/04/19 22:50:53 cheshire + Identical client queries should reference a single shared core query -Revision 1.181 2003/06/07 06:45:05 cheshire - No need for multiple machines to all be sending the same queries +Revision 1.605 2007/04/19 20:06:41 cheshire +Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer) -Revision 1.180 2003/06/07 06:31:07 cheshire -Create little four-line helper function "FindIdenticalRecordInCache()" +Revision 1.604 2007/04/19 18:03:04 cheshire +Add "const" declaration -Revision 1.179 2003/06/07 06:28:13 cheshire -For clarity, change name of "DNSQuestion q" to "DNSQuestion pktq" +Revision 1.603 2007/04/06 21:00:25 cheshire +Fix log message typo -Revision 1.178 2003/06/07 06:25:12 cheshire -Update some comments +Revision 1.602 2007/04/05 22:55:35 cheshire + Records are ending up in Lighthouse without expiry information -Revision 1.177 2003/06/07 04:50:53 cheshire - React when we observe other people query unsuccessfully for a record that's in our cache +Revision 1.601 2007/04/04 21:48:52 cheshire + Combine unicast authoritative answer list with multicast list -Revision 1.176 2003/06/07 04:33:26 cheshire - When query produces zero results, call mDNS_Reconfirm() on any antecedent records -Minor change: Increment/decrement logic for q->CurrentAnswers should be in -CacheRecordAdd() and CacheRecordRmv(), not AnswerQuestionWithResourceRecord() - -Revision 1.175 2003/06/07 04:11:52 cheshire -Minor changes to comments and debug messages - -Revision 1.174 2003/06/07 01:46:38 cheshire - When query produces zero results, call mDNS_Reconfirm() on any antecedent records - -Revision 1.173 2003/06/07 01:22:13 cheshire - mDNSResponder needs an mDNS_Reconfirm() function - -Revision 1.172 2003/06/07 00:59:42 cheshire - Need some randomness to spread queries on the network - -Revision 1.171 2003/06/06 21:41:10 cheshire -For consistency, mDNS_StopQuery() should return an mStatus result, just like all the other mDNSCore routines - -Revision 1.170 2003/06/06 21:38:55 cheshire -Renamed 'NewData' as 'FreshData' (The data may not be new data, just a refresh of data that we -already had in our cache. This refreshes our TTL on the data, but the data itself stays the same.) - -Revision 1.169 2003/06/06 21:35:55 cheshire -Fix mis-named macro: GetRRHostNameTarget is really GetRRDomainNameTarget -(the target is a domain name, but not necessarily a host name) - -Revision 1.168 2003/06/06 21:33:31 cheshire -Instead of using (mDNSPlatformOneSecond/2) all over the place, define a constant "InitialQuestionInterval" - -Revision 1.167 2003/06/06 21:30:42 cheshire - Don't delay queries for shared record types - -Revision 1.166 2003/06/06 17:20:14 cheshire -For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass -(Global search-and-replace; no functional change to code execution.) - -Revision 1.165 2003/06/04 02:53:21 cheshire -Add some "#pragma warning" lines so it compiles clean on Microsoft compilers - -Revision 1.164 2003/06/04 01:25:33 cheshire - Cannot perform multi-packet known-answer suppression messages -Display time interval between first and subsequent queries - -Revision 1.163 2003/06/03 19:58:14 cheshire - mDNS_DeregisterService() fixes: -When forcibly deregistering after a conflict, ensure we don't send an incorrect goodbye packet. -Guard against a couple of possible mDNS_DeregisterService() race conditions. - -Revision 1.162 2003/06/03 19:30:39 cheshire -Minor addition refinements for - Duplicate registrations not handled as efficiently as they should be - -Revision 1.161 2003/06/03 18:29:03 cheshire -Minor changes to comments and debugf() messages - -Revision 1.160 2003/06/03 05:02:16 cheshire - Duplicate registrations not handled as efficiently as they should be - -Revision 1.159 2003/06/03 03:31:57 cheshire - False self-conflict when there are duplicate registrations on one machine - -Revision 1.158 2003/06/02 22:57:09 cheshire -Minor clarifying changes to comments and log messages; -IdenticalResourceRecordAnyInterface() is really more accurately called just IdenticalResourceRecord() - -Revision 1.157 2003/05/31 00:09:49 cheshire - Add ability to discover what services are on a network - -Revision 1.156 2003/05/30 23:56:49 cheshire - Crash after error in mDNS_RegisterService() -Need to set "sr->Extras = mDNSNULL" before returning - -Revision 1.155 2003/05/30 23:48:00 cheshire - Announcements not properly grouped -Due to inconsistent setting of rr->LastAPTime at different places in the -code, announcements were not properly grouped into a single packet. -Fixed by creating a single routine called InitializeLastAPTime(). - -Revision 1.154 2003/05/30 23:38:14 cheshire - Fix error in IPv6 reverse-mapping PTR records -Wrote buffer[32] where it should have said buffer[64] - -Revision 1.153 2003/05/30 19:10:56 cheshire - ConstructServiceName needs to be more restrictive - -Revision 1.152 2003/05/29 22:39:16 cheshire - Don't truncate strings in the middle of a UTF-8 character - -Revision 1.151 2003/05/29 06:35:42 cheshire - mDNSCoreReceiveResponse() purging wrong record - -Revision 1.150 2003/05/29 06:25:45 cheshire - Need to call CheckCacheExpiration() *before* AnswerNewQuestion() - -Revision 1.149 2003/05/29 06:18:39 cheshire - Split AnswerLocalQuestions into CacheRecordAdd and CacheRecordRmv - -Revision 1.148 2003/05/29 06:11:34 cheshire - Report if there appear to be too many "Resolve" callbacks - -Revision 1.147 2003/05/29 06:01:18 cheshire -Change some debugf() calls to LogMsg() calls to help with debugging - -Revision 1.146 2003/05/28 21:00:44 cheshire -Re-enable "immediate answer burst" debugf message - -Revision 1.145 2003/05/28 20:57:44 cheshire - mDNSResponder reports "Cannot perform multi-packet -known-answer suppression ..." This is a known issue caused by a bug in the OS X 10.2 -version of mDNSResponder, so for now we should suppress this warning message. - -Revision 1.144 2003/05/28 18:05:12 cheshire - mDNSResponder allows invalid service registrations -Fix silly mistake: old logic allowed "TDP" and "UCP" as valid names - -Revision 1.143 2003/05/28 04:31:29 cheshire - mDNSResponder not sending probes at the prescribed time - -Revision 1.142 2003/05/28 03:13:07 cheshire - mDNSResponder allows invalid service registrations -Require that the transport protocol be _udp or _tcp - -Revision 1.141 2003/05/28 02:19:12 cheshire - Misleading messages generated by iChat -Better fix: Only generate the log message for queries where the TC bit is set. - -Revision 1.140 2003/05/28 01:55:24 cheshire -Minor change to log messages - -Revision 1.139 2003/05/28 01:52:51 cheshire - Misleading messages generated by iChat - -Revision 1.138 2003/05/27 22:35:00 cheshire - mDNS_RegisterInterface needs to retrigger questions - -Revision 1.137 2003/05/27 20:04:33 cheshire - mDNSResponder crash in mDNS_vsnprintf() - -Revision 1.136 2003/05/27 18:50:07 cheshire - mDNS_StartResolveService doesn't inform client of port number changes - -Revision 1.135 2003/05/26 04:57:28 cheshire - Delay queries when there are already answers in the cache - -Revision 1.134 2003/05/26 04:54:54 cheshire - sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead -Accidentally deleted '%' case from the switch statement - -Revision 1.133 2003/05/26 03:21:27 cheshire -Tidy up address structure naming: -mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr) -mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4 -mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6 - -Revision 1.132 2003/05/26 03:01:26 cheshire - sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead - -Revision 1.131 2003/05/26 00:42:05 cheshire - Temporarily include mDNSResponder version in packets - -Revision 1.130 2003/05/24 16:39:48 cheshire - SendResponses also needs to handle multihoming better - -Revision 1.129 2003/05/23 02:15:37 cheshire -Fixed misleading use of the term "duplicate suppression" where it should have -said "known answer suppression". (Duplicate answer suppression is something -different, and duplicate question suppression is yet another thing, so the use -of the completely vague term "duplicate suppression" was particularly bad.) - -Revision 1.128 2003/05/23 01:55:13 cheshire - After name change, mDNSResponder needs to re-probe for name uniqueness +Revision 1.600 2007/04/04 01:31:33 cheshire +Improve debugging message -Revision 1.127 2003/05/23 01:02:15 ksekar -: mDNSResponder needs to include unique id in default name +Revision 1.599 2007/04/04 00:03:26 cheshire + DNSServiceQueryRecord is returning kDNSServiceErr_NoSuchRecord for empty rdata -Revision 1.126 2003/05/22 02:29:22 cheshire - SendQueries needs to handle multihoming better -Complete rewrite of SendQueries. Works much better now :-) +Revision 1.598 2007/04/03 19:43:16 cheshire +Use mDNSSameIPPort (and similar) instead of accessing internal fields directly -Revision 1.125 2003/05/22 01:50:45 cheshire -Fix warnings, and improve log messages +Revision 1.597 2007/03/31 00:32:32 cheshire +After skipping OPT and TSIG, clear m->rec.r.resrec.RecordType -Revision 1.124 2003/05/22 01:41:50 cheshire -DiscardDeregistrations doesn't need InterfaceID parameter +Revision 1.596 2007/03/28 20:59:26 cheshire + Remove inappropriate use of IsPrivateV4Addr() -Revision 1.123 2003/05/22 01:38:55 cheshire -Change bracketing of #pragma mark +Revision 1.595 2007/03/26 23:48:16 cheshire + Advertise model information via Bonjour +Refinements to reduce unnecessary transmissions of the DeviceInfo TXT record -Revision 1.122 2003/05/21 19:59:04 cheshire - ER: Tweak responder's default name conflict behavior -Minor refinements; make sure we don't truncate in the middle of a multi-byte UTF-8 character +Revision 1.594 2007/03/26 23:05:05 cheshire + Don't cache TSIG records -Revision 1.121 2003/05/21 17:54:07 ksekar - ER: Tweak responder's default name conflict behavior -New rename behavior - domain name "foo" becomes "foo--2" on conflict, richtext name becomes "foo (2)" +Revision 1.593 2007/03/23 17:40:08 cheshire + Bug when auto-renaming Computer Name after name collision -Revision 1.120 2003/05/19 22:14:14 ksekar - mDNS probe denials/conflicts not detected unless conflict is of the same type +Revision 1.592 2007/03/22 18:31:48 cheshire +Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy -Revision 1.119 2003/05/16 01:34:10 cheshire -Fix some warnings +Revision 1.591 2007/03/22 00:49:19 cheshire + Advertise model information via Bonjour -Revision 1.118 2003/05/14 18:48:40 cheshire - mDNSResponder should be smarter about reconfigurations -More minor refinements: -mDNSMacOSX.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory -mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away +Revision 1.590 2007/03/21 23:05:59 cheshire +Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields -Revision 1.117 2003/05/14 07:08:36 cheshire - mDNSResponder should be smarter about reconfigurations -Previously, when there was any network configuration change, mDNSResponder -would tear down the entire list of active interfaces and start again. -That was very disruptive, and caused the entire cache to be flushed, -and caused lots of extra network traffic. Now it only removes interfaces -that have really gone, and only adds new ones that weren't there before. +Revision 1.589 2007/03/20 15:37:19 cheshire +Delete unnecessary log message -Revision 1.116 2003/05/14 06:51:56 cheshire - mDNSResponder doesn't refresh server info if changed during sleep +Revision 1.588 2007/03/20 00:24:44 cheshire + Should deliver "name registered" callback slightly *before* announcing PTR record -Revision 1.115 2003/05/14 06:44:31 cheshire -Improve debugging message +Revision 1.587 2007/03/16 22:10:56 cheshire + mDNS: Query for *either* type A or AAAA should return both types -Revision 1.114 2003/05/07 01:47:03 cheshire - Also protect against NULL domainlabels +Revision 1.586 2007/03/10 03:26:44 cheshire + uDNS: LLQ refresh response packet causes cached records to be removed from cache -Revision 1.113 2003/05/07 00:28:18 cheshire - Need to make mDNSResponder more defensive against bad clients +Revision 1.585 2007/03/10 02:02:58 cheshire + uDNS: LLQ refresh response packet causes cached records to be removed from cache +Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer -Revision 1.112 2003/05/06 00:00:46 cheshire - Rationalize naming of domainname manipulation functions +Revision 1.584 2007/02/28 01:51:27 cheshire +Added comment about reverse-order IP address -Revision 1.111 2003/05/05 23:42:08 cheshire - Resolves never succeed -Was setting "rr->LastAPTime = timenow - rr->LastAPTime" -instead of "rr->LastAPTime = timenow - rr->ThisAPInterval" +Revision 1.583 2007/01/27 03:19:33 cheshire +Need to initialize question->sock -Revision 1.110 2003/04/30 21:09:59 cheshire - mDNS_vsnprintf needs to be more defensive against invalid domain names +Revision 1.582 2007/01/25 00:40:16 cheshire +Unified CNAME-following functionality into cache management code (which means CNAME-following +should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine. -Revision 1.109 2003/04/26 02:41:56 cheshire - Change timenow from a local variable to a structure member +Revision 1.581 2007/01/23 02:56:11 cheshire +Store negative results in the cache, instead of generating them out of pktResponseHndlr() -Revision 1.108 2003/04/25 01:45:56 cheshire - mDNS_RegisterNoSuchService needs to include a host name +Revision 1.580 2007/01/19 21:17:33 cheshire +StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion -Revision 1.107 2003/04/25 00:41:31 cheshire - Create single routine PurgeCacheResourceRecord(), to avoid bugs in future +Revision 1.579 2007/01/19 18:39:10 cheshire +Fix a bunch of parameters that should have been declared "const" -Revision 1.106 2003/04/22 03:14:45 cheshire - Include Include instrumented mDNSResponder in panther now +Revision 1.578 2007/01/10 22:51:57 cheshire + Add support for one-shot private queries as well as long-lived private queries -Revision 1.105 2003/04/22 01:07:43 cheshire - DNSServiceRegistrationUpdateRecord should support a default ttl -If TTL parameter is zero, leave record TTL unchanged +Revision 1.577 2007/01/10 02:05:21 cheshire +Delay uDNS_SetupDNSConfig() until *after* the platform layer +has set up the interface list and security credentials -Revision 1.104 2003/04/21 19:15:52 cheshire -Fix some compiler warnings +Revision 1.576 2007/01/09 02:40:57 cheshire +uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer); +moved it to mDNS_Init() in mDNS.c (core code) -Revision 1.103 2003/04/19 02:26:35 cheshire - Incorrect goodbye packet after conflict +Revision 1.575 2007/01/09 00:17:25 cheshire +Improve "ERROR m->CurrentRecord already set" debugging messages -Revision 1.102 2003/04/17 03:06:28 cheshire - No need to query again when a service goes away -Set UnansweredQueries to 2 when receiving a "goodbye" packet +Revision 1.574 2007/01/05 08:30:41 cheshire +Trim excessive "$Log" checkin history from before 2006 +(checkin history still available via "cvs log ..." of course) -Revision 1.101 2003/04/15 20:58:31 jgraessl - Added a hash to lookup records in the cache. +Revision 1.573 2007/01/05 06:34:03 cheshire +Improve "ERROR m->CurrentQuestion already set" debugging messages -Revision 1.100 2003/04/15 18:53:14 cheshire - Bug in ScheduleNextTask -mDNS.c 1.94 incorrectly combined two "if" statements into one. +Revision 1.572 2007/01/04 23:11:11 cheshire + uDNS: Need to start caching unicast records +When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries -Revision 1.99 2003/04/15 18:09:13 jgraessl - -Reviewed by: Stuart Cheshire -Added code to keep track of when the next cache item will expire so we can -call TidyRRCache only when necessary. +Revision 1.571 2007/01/04 21:45:20 cheshire +Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros, +to do additional lock sanity checking around callback invocations -Revision 1.98 2003/04/03 03:43:55 cheshire - Off-by-one error in probe rate limiting +Revision 1.570 2007/01/04 20:57:47 cheshire +Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates) -Revision 1.97 2003/04/02 01:48:17 cheshire - mDNSResponder sometimes suffers false self-conflicts when it sees its own packets -Additional fix pointed out by Josh: -Also set ProbeFailTime when incrementing NumFailedProbes when resetting a record back to probing state +Revision 1.569 2007/01/04 20:27:27 cheshire +Change a LogMsg() to debugf() -Revision 1.96 2003/04/01 23:58:55 cheshire -Minor comment changes +Revision 1.568 2007/01/04 02:39:53 cheshire + Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations -Revision 1.95 2003/04/01 23:46:05 cheshire - mDNSResponder can get stuck in infinite loop after many location cycles -mDNS_DeregisterInterface() flushes the RR cache by marking all records received on that interface -to expire in one second. However, if a mDNS_StartResolveService() call is made in that one-second -window, it can get an SRV answer from one of those soon-to-be-deleted records, resulting in -FoundServiceInfoSRV() making an interface-specific query on the interface that was just removed. +Revision 1.567 2006/12/21 00:01:37 cheshire +Tidy up code alignment -Revision 1.94 2003/03/29 01:55:19 cheshire - mDNSResponder sometimes suffers false self-conflicts when it sees its own packets -Solution: Major cleanup of packet timing and conflict handling rules +Revision 1.566 2006/12/20 04:07:34 cheshire +Remove uDNS_info substructure from AuthRecord_struct -Revision 1.93 2003/03/28 01:54:36 cheshire -Minor tidyup of IPv6 (AAAA) code +Revision 1.565 2006/12/19 22:49:23 cheshire +Remove uDNS_info substructure from ServiceRecordSet_struct -Revision 1.92 2003/03/27 03:30:55 cheshire - Name conflicts not handled properly, resulting in memory corruption, and eventual crash -Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback -Fixes: -1. Make mDNS_DeregisterInterface() safe to call from a callback -2. Make HostNameCallback() use DeadvertiseInterface() instead - (it never really needed to deregister the interface at all) +Revision 1.564 2006/12/19 02:38:20 cheshire +Get rid of unnecessary duplicate query ID field from DNSQuestion_struct -Revision 1.91 2003/03/15 04:40:36 cheshire -Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID" +Revision 1.563 2006/12/19 02:18:48 cheshire +Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct -Revision 1.90 2003/03/14 20:26:37 cheshire -Reduce debugging messages (reclassify some "debugf" as "verbosedebugf") +Revision 1.562 2006/12/16 01:58:31 cheshire + uDNS: Need to start caching unicast records -Revision 1.89 2003/03/12 19:57:50 cheshire -Fixed typo in debug message +Revision 1.561 2006/12/01 07:38:53 herscher +Only perform cache workaround fix if query is wide-area -Revision 1.88 2003/03/12 00:17:44 cheshire - GetFreeCacheRR needs to be more willing to throw away recent records +Revision 1.560 2006/11/30 23:07:56 herscher + uDNS: Sync up with Lighthouse changes for Private DNS -Revision 1.87 2003/03/11 01:27:20 cheshire -Reduce debugging messages (reclassify some "debugf" as "verbosedebugf") +Revision 1.559 2006/11/27 08:20:57 cheshire +Preliminary support for unifying the uDNS and mDNS code, including caching of uDNS answers -Revision 1.86 2003/03/06 20:44:33 cheshire -Comment tidyup +Revision 1.558 2006/11/10 07:44:03 herscher + Fix Daemon locking failures while toggling BTMM -Revision 1.85 2003/03/05 03:38:35 cheshire - Bogus error message in console: died or deallocated, but no record of client can be found! -Fixed by leaving client in list after conflict, until client explicitly deallocates +Revision 1.557 2006/11/10 01:12:51 cheshire + Incorrect TTL corrections -Revision 1.84 2003/03/05 01:27:30 cheshire - Different TTL for multicast versus unicast responses -When building unicast responses, record TTLs are capped to 10 seconds +Revision 1.556 2006/11/10 00:54:14 cheshire + Changing case of Computer Name doesn't work -Revision 1.83 2003/03/04 23:48:52 cheshire - Double probes after wake from sleep -Don't reset record type to kDNSRecordTypeUnique if record is DependentOn another +Revision 1.555 2006/10/30 20:03:37 cheshire + After service restarts on different port, for a few seconds DNS-SD may return stale port number -Revision 1.82 2003/03/04 23:38:29 cheshire - mDNSResponder needs performance improvements -Only set rr->CRActiveQuestion to point to the -currently active representative of a question set +Revision 1.554 2006/10/20 05:35:04 herscher + uDNS: Merge unicast active question list with multicast list. -Revision 1.81 2003/02/21 03:35:34 cheshire - mDNSResponder needs to include AAAA records in additional answer section +Revision 1.553 2006/10/05 03:42:43 herscher +Remove embedded uDNS_info struct in DNSQuestion_struct -Revision 1.80 2003/02/21 02:47:53 cheshire - mDNSResponder needs performance improvements -Several places in the code were calling CacheRRActive(), which searched the entire -question list every time, to see if this cache resource record answers any question. -Instead, we now have a field "CRActiveQuestion" in the resource record structure +Revision 1.552 2006/09/15 21:20:15 cheshire +Remove uDNS_info substructure from mDNS_struct -Revision 1.79 2003/02/21 01:54:07 cheshire - mDNSResponder needs performance improvements -Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt") +Revision 1.551 2006/08/14 23:24:22 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 -Revision 1.78 2003/02/20 06:48:32 cheshire - Xserve RAID needs to do interface-specific registrations -Reviewed by: Josh Graessley, Bob Bradley +Revision 1.550 2006/07/27 17:58:34 cheshire +Improved text of "SendQueries didn't send all its queries; will try again" debugging message -Revision 1.77 2003/01/31 03:35:59 cheshire - mDNSResponder sometimes fails to find the correct results -When there were *two* active questions in the list, they were incorrectly -finding *each other* and *both* being marked as duplicates of another question +Revision 1.549 2006/07/20 22:07:31 mkrochma + Wide-area browsing is currently broken in TOT +More fixes for uninitialized variables -Revision 1.76 2003/01/29 02:46:37 cheshire -Fix for IPv6: -A physical interface is identified solely by its InterfaceID (not by IP and type). -On a given InterfaceID, mDNSCore may send both v4 and v6 multicasts. -In cases where the requested outbound protocol (v4 or v6) is not supported on -that InterfaceID, the platform support layer should simply discard that packet. +Revision 1.548 2006/07/20 19:30:19 mkrochma + Wide-area browsing sometimes doesn't work in TOT -Revision 1.75 2003/01/29 01:47:40 cheshire -Rename 'Active' to 'CRActive' or 'InterfaceActive' for improved clarity +Revision 1.547 2006/07/15 02:31:30 cheshire + Suppress log messages for certain old devices with inconsistent TXT RRSet TTLs -Revision 1.74 2003/01/28 05:26:25 cheshire - mDNSResponder sometimes fails to find the correct results -Add 'Active' flag for interfaces - -Revision 1.73 2003/01/28 03:45:12 cheshire -Fixed missing "not" in "!mDNSAddrIsDNSMulticast(dstaddr)" +Revision 1.546 2006/07/07 01:09:09 cheshire + Add Private DNS server functionality to dnsextd +Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd -Revision 1.72 2003/01/28 01:49:48 cheshire - mDNSResponder sometimes fails to find the correct results -FindDuplicateQuestion() was incorrectly finding the question itself in the list, -and incorrectly marking it as a duplicate (of itself), so that it became inactive. - -Revision 1.71 2003/01/28 01:41:44 cheshire - Race condition when network change causes bad stuff -When an interface goes away, interface-specific questions on that interface become orphaned. -Orphan questions cause HaveQueries to return true, but there's no interface to send them on. -Fix: mDNS_DeregisterInterface() now calls DeActivateInterfaceQuestions() +Revision 1.545 2006/07/05 23:10:30 cheshire + Add Private DNS client functionality to mDNSResponder +Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int" -Revision 1.70 2003/01/23 19:00:20 cheshire -Protect against infinite loops in mDNS_Execute +Revision 1.544 2006/06/29 07:42:14 cheshire + Performance: Remove unnecessary SameDomainName() checks -Revision 1.69 2003/01/21 22:56:32 jgraessl - service name changes are not properly handled -Submitted by: Stuart Cheshire -Reviewed by: Joshua Graessley -Applying changes for 3124348 to main branch. 3124348 changes went in to a -branch for SU. +Revision 1.543 2006/06/29 01:38:43 cheshire + Only request unicast responses on wake from sleep and network connection -Revision 1.68 2003/01/17 04:09:27 cheshire - mDNSResponder Resolves are unreliable on multi-homed hosts +Revision 1.542 2006/06/27 23:40:29 cheshire +Fix typo in comment: mis-spelled "compile" -Revision 1.67 2003/01/17 03:56:45 cheshire -Default 24-hour TTL is far too long. Changing to two hours. +Revision 1.541 2006/06/27 19:46:24 cheshire +Updated comments and debugging messages -Revision 1.66 2003/01/13 23:49:41 jgraessl -Merged changes for the following fixes in to top of tree: - computer name changes not handled properly - service name changes are not properly handled - announcements sent in pairs, failing chattiness test +Revision 1.540 2006/06/15 21:35:16 cheshire +Move definitions of mDNS_vsnprintf, mDNS_SetupResourceRecord, and some constants +from mDNS.c to DNSCommon.c, so they can be accessed from dnsextd code -Revision 1.65 2002/12/23 22:13:28 jgraessl -Reviewed by: Stuart Cheshire -Initial IPv6 support for mDNSResponder. +Revision 1.539 2006/06/08 23:45:46 cheshire +Change SimultaneousProbe messages from debugf() to LogOperation() -Revision 1.64 2002/11/26 20:49:06 cheshire - RFC 1123 allows the first character of a name label to be either a letter or a digit +Revision 1.538 2006/03/19 17:13:06 cheshire + Need faster purging of stale records +Shorten kDefaultReconfirmTimeForNoAnswer to five seconds +and reconfirm whole chain of antecedents ot once -Revision 1.63 2002/09/21 20:44:49 zarzycki -Added APSL info +Revision 1.537 2006/03/19 02:00:07 cheshire + Improve logic for delaying packets after repeated interface transitions -Revision 1.62 2002/09/20 03:25:37 cheshire -Fix some compiler warnings +Revision 1.536 2006/03/08 23:29:53 cheshire + Improve "Service Renamed" log message -Revision 1.61 2002/09/20 01:05:24 cheshire -Don't kill the Extras list in mDNS_DeregisterService() - -Revision 1.60 2002/09/19 23:47:35 cheshire -Added mDNS_RegisterNoSuchService() function for assertion of non-existence -of a particular named service - -Revision 1.59 2002/09/19 21:25:34 cheshire -mDNS_snprintf() doesn't need to be in a separate file +Revision 1.535 2006/03/02 20:41:17 cheshire + After record update, old record sometimes remains in cache +Minor code tidying and comments to reduce the risk of similar programming errors in future -Revision 1.58 2002/09/19 04:20:43 cheshire -Remove high-ascii characters that confuse some systems +Revision 1.534 2006/03/02 03:25:46 cheshire + After record update, old record sometimes remains in cache +Code to harmonize RRSet TTLs was inadvertently rescuing expiring records -Revision 1.57 2002/09/17 01:07:08 cheshire -Change mDNS_AdvertiseLocalAddresses to be a parameter to mDNS_Init() +Revision 1.533 2006/02/26 00:54:41 cheshire +Fixes to avoid code generation warning/error on FreeBSD 7 -Revision 1.56 2002/09/16 19:44:17 cheshire -Merge in license terms from Quinn's copy, in preparation for Darwin release */ #include "DNSCommon.h" // Defines general DNS untility routines #include "uDNS.h" // Defines entry points into unicast-specific routines + // Disable certain benign warnings with Microsoft compilers #if(defined(_MSC_VER)) // Disable "conditional expression is constant" warning for debug macros. @@ -1759,47 +711,12 @@ Merge in license terms from Quinn's copy, in preparation for Darwin release // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK -#pragma mark - #pragma mark - Program Constants #endif -mDNSexport const mDNSIPPort zeroIPPort = { { 0 } }; -mDNSexport const mDNSv4Addr zerov4Addr = { { 0 } }; -mDNSexport const mDNSv6Addr zerov6Addr = { { 0 } }; -mDNSexport const mDNSEthAddr zeroEthAddr = { { 0 } }; -mDNSexport const mDNSv4Addr onesIPv4Addr = { { 255, 255, 255, 255 } }; -mDNSexport const mDNSv6Addr onesIPv6Addr = { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } }; -mDNSexport const mDNSAddr zeroAddr = { mDNSAddrType_None, {{{ 0 }}} }; - -mDNSexport const mDNSInterfaceID mDNSInterface_Any = 0; -mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)1; - -mDNSlocal const mDNSInterfaceID mDNSInterfaceMark = (mDNSInterfaceID)~0; - -#define UnicastDNSPortAsNumber 53 -#define NATPMPPortAsNumber 5351 -#define DNSEXTPortAsNumber 5352 // Port used for end-to-end DNS operations like LLQ, Updates with Leases, etc. -#define MulticastDNSPortAsNumber 5353 -#define LoopbackIPCPortAsNumber 5354 - -mDNSexport const mDNSIPPort UnicastDNSPort = { { UnicastDNSPortAsNumber >> 8, UnicastDNSPortAsNumber & 0xFF } }; -mDNSexport const mDNSIPPort NATPMPPort = { { NATPMPPortAsNumber >> 8, NATPMPPortAsNumber & 0xFF } }; -mDNSexport const mDNSIPPort DNSEXTPort = { { DNSEXTPortAsNumber >> 8, DNSEXTPortAsNumber & 0xFF } }; -mDNSexport const mDNSIPPort MulticastDNSPort = { { MulticastDNSPortAsNumber >> 8, MulticastDNSPortAsNumber & 0xFF } }; -mDNSexport const mDNSIPPort LoopbackIPCPort = { { LoopbackIPCPortAsNumber >> 8, LoopbackIPCPortAsNumber & 0xFF } }; - -mDNSexport const mDNSv4Addr AllDNSAdminGroup = { { 239, 255, 255, 251 } }; -mDNSexport const mDNSv4Addr AllDNSLinkGroupv4 = { { 224, 0, 0, 251 } }; -mDNSexport const mDNSv6Addr AllDNSLinkGroupv6 = { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } }; -mDNSexport const mDNSAddr AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224, 0, 0, 251 } } } }; -mDNSexport const mDNSAddr AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } } } }; - -mDNSexport const mDNSOpaque16 zeroID = { { 0, 0 } }; -mDNSexport const mDNSOpaque16 QueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery, 0 } }; -mDNSexport const mDNSOpaque16 uQueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery | kDNSFlag0_RD, 0 } }; -mDNSexport const mDNSOpaque16 ResponseFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } }; -mDNSexport const mDNSOpaque16 UpdateReqFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_Update, 0 } }; -mDNSexport const mDNSOpaque16 UpdateRespFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, 0 } }; +#define NO_HINFO 1 + +mDNSlocal const mDNSInterfaceID mDNSInterfaceMark = (mDNSInterfaceID)~0; // Any records bigger than this are considered 'large' records #define SmallRecordLimit 1024 @@ -1811,7 +728,7 @@ mDNSexport const char *const mDNS_DomainTypeNames[] = { "b._dns-sd._udp.", // Browse "db._dns-sd._udp.", // Default Browse - "lb._dns-sd._udp.", // Legacy Browse + "lb._dns-sd._udp.", // Automatic Browse "r._dns-sd._udp.", // Registration "dr._dns-sd._udp." // Default Registration }; @@ -1820,325 +737,34 @@ mDNSexport const char *const mDNS_DomainTypeNames[] = #define uDNS_IsActiveQuery(q, u) mDNSfalse #endif -// *************************************************************************** -#if COMPILER_LIKES_PRAGMA_MARK -#pragma mark - -#pragma mark - Specialized mDNS version of vsnprintf -#endif - -static const struct mDNSprintf_format - { - unsigned leftJustify : 1; - unsigned forceSign : 1; - unsigned zeroPad : 1; - unsigned havePrecision : 1; - unsigned hSize : 1; - unsigned lSize : 1; - char altForm; - char sign; // +, - or space - unsigned int fieldWidth; - unsigned int precision; - } mDNSprintf_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - -mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg) - { - mDNSu32 nwritten = 0; - int c; - if (buflen == 0) return(0); - buflen--; // Pre-reserve one space in the buffer for the terminating null - if (buflen == 0) goto exit; - - for (c = *fmt; c != 0; c = *++fmt) - { - if (c != '%') - { - *sbuffer++ = (char)c; - if (++nwritten >= buflen) goto exit; - } - else - { - unsigned int i=0, j; - // The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for - // generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc. - // The size needs to be enough for a 256-byte domain name plus some error text. - #define mDNS_VACB_Size 300 - char mDNS_VACB[mDNS_VACB_Size]; - #define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size]) - #define mDNS_VACB_Remain(s) ((mDNSu32)(mDNS_VACB_Lim - s)) - char *s = mDNS_VACB_Lim, *digits; - struct mDNSprintf_format F = mDNSprintf_format_default; - - while (1) // decode flags - { - c = *++fmt; - if (c == '-') F.leftJustify = 1; - else if (c == '+') F.forceSign = 1; - else if (c == ' ') F.sign = ' '; - else if (c == '#') F.altForm++; - else if (c == '0') F.zeroPad = 1; - else break; - } - - if (c == '*') // decode field width - { - int f = va_arg(arg, int); - if (f < 0) { f = -f; F.leftJustify = 1; } - F.fieldWidth = (unsigned int)f; - c = *++fmt; - } - else - { - for (; c >= '0' && c <= '9'; c = *++fmt) - F.fieldWidth = (10 * F.fieldWidth) + (c - '0'); - } - - if (c == '.') // decode precision - { - if ((c = *++fmt) == '*') - { F.precision = va_arg(arg, unsigned int); c = *++fmt; } - else for (; c >= '0' && c <= '9'; c = *++fmt) - F.precision = (10 * F.precision) + (c - '0'); - F.havePrecision = 1; - } - - if (F.leftJustify) F.zeroPad = 0; - - 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; - case 'd' : - case 'i' : if (F.lSize) n = (unsigned long)va_arg(arg, long); - else n = (unsigned long)va_arg(arg, int); - if (F.hSize) n = (short) n; - if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; } - else if (F.forceSign) F.sign = '+'; - goto decimal; - case 'u' : if (F.lSize) n = va_arg(arg, unsigned long); - else n = va_arg(arg, unsigned int); - if (F.hSize) n = (unsigned short) n; - F.sign = 0; - goto decimal; - decimal: if (!F.havePrecision) - { - if (F.zeroPad) - { - F.precision = F.fieldWidth; - if (F.sign) --F.precision; - } - if (F.precision < 1) F.precision = 1; - } - if (F.precision > mDNS_VACB_Size - 1) - F.precision = mDNS_VACB_Size - 1; - for (i = 0; n; n /= 10, i++) *--s = (char)(n % 10 + '0'); - for (; i < F.precision; i++) *--s = '0'; - if (F.sign) { *--s = F.sign; i++; } - break; - - case 'o' : if (F.lSize) n = va_arg(arg, unsigned long); - else n = va_arg(arg, unsigned int); - if (F.hSize) n = (unsigned short) n; - if (!F.havePrecision) - { - if (F.zeroPad) F.precision = F.fieldWidth; - if (F.precision < 1) F.precision = 1; - } - if (F.precision > mDNS_VACB_Size - 1) - F.precision = mDNS_VACB_Size - 1; - for (i = 0; n; n /= 8, i++) *--s = (char)(n % 8 + '0'); - if (F.altForm && i && *s != '0') { *--s = '0'; i++; } - for (; i < F.precision; i++) *--s = '0'; - break; - - case 'a' : { - unsigned char *a = va_arg(arg, unsigned char *); - if (!a) { static char emsg[] = "<>"; s = emsg; i = sizeof(emsg)-1; } - else - { - s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end - if (F.altForm) - { - mDNSAddr *ip = (mDNSAddr*)a; - switch (ip->type) - { - case mDNSAddrType_IPv4: F.precision = 4; a = (unsigned char *)&ip->ip.v4; break; - case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break; - default: F.precision = 0; break; - } - } - switch (F.precision) - { - case 4: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d", - a[0], a[1], a[2], a[3]); break; - case 6: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X", - a[0], a[1], a[2], a[3], a[4], a[5]); break; - case 16: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), - "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X", - a[0x0], a[0x1], a[0x2], a[0x3], a[0x4], a[0x5], a[0x6], a[0x7], - a[0x8], a[0x9], a[0xA], a[0xB], a[0xC], a[0xD], a[0xE], a[0xF]); break; - default: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify address size " - "(i.e. %.4a=IPv4, %.6a=Ethernet, %.16a=IPv6) >>"); break; - } - } - } - break; - - case 'p' : F.havePrecision = F.lSize = 1; - F.precision = 8; - case 'X' : digits = "0123456789ABCDEF"; - goto hexadecimal; - case 'x' : digits = "0123456789abcdef"; - hexadecimal:if (F.lSize) n = va_arg(arg, unsigned long); - else n = va_arg(arg, unsigned int); - if (F.hSize) n = (unsigned short) n; - if (!F.havePrecision) - { - if (F.zeroPad) - { - F.precision = F.fieldWidth; - if (F.altForm) F.precision -= 2; - } - if (F.precision < 1) F.precision = 1; - } - if (F.precision > mDNS_VACB_Size - 1) - F.precision = mDNS_VACB_Size - 1; - for (i = 0; n; n /= 16, i++) *--s = digits[n % 16]; - for (; i < F.precision; i++) *--s = '0'; - if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; } - break; - - case 'c' : *--s = (char)va_arg(arg, int); i = 1; break; - - case 's' : s = va_arg(arg, char *); - if (!s) { static char emsg[] = "<>"; s = emsg; i = sizeof(emsg)-1; } - else switch (F.altForm) - { - case 0: i=0; - if (!F.havePrecision) // C string - while(s[i]) i++; - else - { - while ((i < F.precision) && s[i]) i++; - // Make sure we don't truncate in the middle of a UTF-8 character - // If last character we got was any kind of UTF-8 multi-byte character, - // then see if we have to back up. - // This is not as easy as the similar checks below, because - // here we can't assume it's safe to examine the *next* byte, so we - // have to confine ourselves to working only backwards in the string. - j = i; // Record where we got to - // Now, back up until we find first non-continuation-char - while (i>0 && (s[i-1] & 0xC0) == 0x80) i--; - // Now s[i-1] is the first non-continuation-char - // and (j-i) is the number of continuation-chars we found - if (i>0 && (s[i-1] & 0xC0) == 0xC0) // If we found a start-char - { - i--; // Tentatively eliminate this start-char as well - // Now (j-i) is the number of characters we're considering eliminating. - // To be legal UTF-8, the start-char must contain (j-i) one-bits, - // followed by a zero bit. If we shift it right by (7-(j-i)) bits - // (with sign extension) then the result has to be 0xFE. - // If this is right, then we reinstate the tentatively eliminated bytes. - if (((j-i) < 7) && (((s[i] >> (7-(j-i))) & 0xFF) == 0xFE)) i = j; - } - } - break; - case 1: i = (unsigned char) *s++; break; // Pascal string - case 2: { // DNS label-sequence name - unsigned char *a = (unsigned char *)s; - s = mDNS_VACB; // Adjust s to point to the start of the buffer, not the end - if (*a == 0) *s++ = '.'; // Special case for root DNS name - while (*a) - { - if (*a > 63) { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<>", *a); break; } - if (s + *a >= &mDNS_VACB[254]) { s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<>"); break; } - s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "%#s.", a); - a += 1 + *a; - } - i = (mDNSu32)(s - mDNS_VACB); - s = mDNS_VACB; // Reset s back to the start of the buffer - break; - } - } - // Make sure we don't truncate in the middle of a UTF-8 character (see similar comment below) - if (F.havePrecision && i > F.precision) - { i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; } - break; - - case 'n' : s = va_arg(arg, char *); - if (F.hSize) * (short *) s = (short)nwritten; - else if (F.lSize) * (long *) s = (long)nwritten; - else * (int *) s = (int)nwritten; - continue; - - default: s = mDNS_VACB; - i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "<>", c); - - case '%' : *sbuffer++ = (char)c; - if (++nwritten >= buflen) goto exit; - break; - } - - if (i < F.fieldWidth && !F.leftJustify) // Pad on the left - do { - *sbuffer++ = ' '; - if (++nwritten >= buflen) goto exit; - } while (i < --F.fieldWidth); - - // Make sure we don't truncate in the middle of a UTF-8 character. - // Note: s[i] is the first eliminated character; i.e. the next character *after* the last character of the allowed output. If s[i] is a - // UTF-8 continuation character, then we've cut a unicode character in half, so back up 'i' until s[i] is no longer a UTF-8 continuation - // character. (if the input was proprly formed, s[i] will now be the UTF-8 start character of the multi-byte character we just eliminated). - if (i > buflen - nwritten) - { i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--; } - for (j=0; j= buflen) goto exit; - - for (; i < F.fieldWidth; i++) // Pad on the right - { - *sbuffer++ = ' '; - if (++nwritten >= buflen) goto exit; - } - } - } - exit: - *sbuffer++ = 0; - return(nwritten); - } - -mDNSexport mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...) - { - mDNSu32 length; - - va_list ptr; - va_start(ptr,fmt); - length = mDNS_vsnprintf(sbuffer, buflen, fmt, ptr); - va_end(ptr); - - return(length); - } - // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - #pragma mark - General Utility Functions #endif -#define InitialQuestionInterval (mDNSPlatformOneSecond/2) #define ActiveQuestion(Q) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf) #define TimeToSendThisQuestion(Q,time) (ActiveQuestion(Q) && (time) - ((Q)->LastQTime + (Q)->ThisQInterval) >= 0) -mDNSlocal void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q) +mDNSexport void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q) { + if (m->mDNS_busy != m->mDNS_reentrancy+1) + LogMsg("SetNextQueryTime: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); + if (ActiveQuestion(q)) - if (m->NextScheduledQuery - (q->LastQTime + q->ThisQInterval) > 0) - m->NextScheduledQuery = (q->LastQTime + q->ThisQInterval); + { + mDNSs32 sendtime = q->LastQTime + q->ThisQInterval; + + // Don't allow sendtime to be earlier than SuppressStdPort53Queries + if (!mDNSOpaque16IsZero(q->TargetQID) && !q->LongLived && m->SuppressStdPort53Queries && (sendtime - m->SuppressStdPort53Queries < 0)) + sendtime = m->SuppressStdPort53Queries; + + if (m->NextScheduledQuery - sendtime > 0) + m->NextScheduledQuery = sendtime; + } } -mDNSlocal 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 slot, const mDNSu32 namehash, const domainname *const name) { CacheGroup *cg; for (cg = m->rrcache_hash[slot]; cg; cg=cg->next) @@ -2158,7 +784,8 @@ mDNSlocal mDNSBool AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID Int if (addr->type == mDNSAddrType_IPv4) { - if (addr->ip.v4.b[0] == 169 && addr->ip.v4.b[1] == 254) return(mDNStrue); + // Normally we resist touching the NotAnInteger fields, but here we're doing tricky bitwise masking so we make an exception + if (mDNSv4AddressIsLinkLocal(&addr->ip.v4)) return(mDNStrue); for (intf = m->HostInterfaces; intf; intf = intf->next) if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx) if (((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) & intf->mask.ip.v4.NotAnInteger) == 0) @@ -2167,7 +794,7 @@ mDNSlocal mDNSBool AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID Int if (addr->type == mDNSAddrType_IPv6) { - if (addr->ip.v6.b[0] == 0xFE && addr->ip.v6.b[1] == 0x80) return(mDNStrue); + if (mDNSv6AddressIsLinkLocal(&addr->ip.v4)) return(mDNStrue); for (intf = m->HostInterfaces; intf; intf = intf->next) if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx) if ((((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) & intf->mask.ip.v6.l[0]) == 0) && @@ -2180,73 +807,26 @@ mDNSlocal mDNSBool AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID Int return(mDNSfalse); } -// Set up a AuthRecord with sensible default values. -// These defaults may be overwritten with new values before mDNS_Register is called -mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID, - mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, mDNSRecordCallback Callback, void *Context) - { - mDNSPlatformMemZero(&rr->uDNS_info, sizeof(uDNS_RegInfo)); - // Don't try to store a TTL bigger than we can represent in platform time units - if (ttl > 0x7FFFFFFFUL / mDNSPlatformOneSecond) - ttl = 0x7FFFFFFFUL / mDNSPlatformOneSecond; - else if (ttl == 0) // And Zero TTL is illegal - ttl = DefaultTTLforRRType(rrtype); - - // Field Group 1: The actual information pertaining to this resource record - rr->resrec.RecordType = RecordType; - rr->resrec.InterfaceID = InterfaceID; - rr->resrec.name = &rr->namestorage; - rr->resrec.rrtype = rrtype; - rr->resrec.rrclass = kDNSClass_IN; - rr->resrec.rroriginalttl = ttl; -// rr->resrec.rdlength = MUST set by client and/or in mDNS_Register_internal -// rr->resrec.rdestimate = set in mDNS_Register_internal -// rr->resrec.rdata = MUST be set by client - - if (RDataStorage) - rr->resrec.rdata = RDataStorage; - else - { - rr->resrec.rdata = &rr->rdatastorage; - rr->resrec.rdata->MaxRDLength = sizeof(RDataBody); - } - - // Field Group 2: Persistent metadata for Authoritative Records - rr->Additional1 = mDNSNULL; - rr->Additional2 = mDNSNULL; - rr->DependentOn = mDNSNULL; - rr->RRSet = mDNSNULL; - rr->RecordCallback = Callback; - rr->RecordContext = Context; - - rr->HostTarget = mDNSfalse; - rr->AllowRemoteQuery = mDNSfalse; - rr->ForceMCast = mDNSfalse; - - // Field Group 3: Transient state for Authoritative Records (set in mDNS_Register_internal) - - rr->namestorage.c[0] = 0; // MUST be set by client before calling mDNS_Register() - } - // For a single given DNSQuestion, deliver an add/remove result for the single given AuthRecord // Used by AnswerLocalQuestions() and AnswerNewLocalOnlyQuestion() -mDNSlocal void AnswerLocalOnlyQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, AuthRecord *rr, mDNSBool AddRecord) +mDNSlocal void AnswerLocalOnlyQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, AuthRecord *rr, QC_result AddRecord) { // Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it if (AddRecord) rr->LocalAnswer = mDNStrue; - m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback - if (q->QuestionCallback) + mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback + if (q->QuestionCallback && !q->NoAnswer) q->QuestionCallback(m, q, &rr->resrec, AddRecord); - m->mDNS_reentrancy--; // Decrement to block mDNS API calls again + mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again } -// When a new local AuthRecord is created or deleted, AnswerLocalQuestions() runs though our LocalOnlyQuestions delivering answers to each, -// stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion(). +// When a new local AuthRecord is created or deleted, AnswerLocalQuestions() runs though our LocalOnlyQuestions delivering answers +// to each, stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion(). // If the AuthRecord is marked mDNSInterface_LocalOnly, then we also deliver it to any other questions we have using mDNSInterface_Any. // Used by AnswerForNewLocalRecords() and mDNS_Deregister_internal() -mDNSlocal void AnswerLocalQuestions(mDNS *const m, AuthRecord *rr, mDNSBool AddRecord) +mDNSlocal void AnswerLocalQuestions(mDNS *const m, AuthRecord *rr, QC_result AddRecord) { - if (m->CurrentQuestion) LogMsg("AnswerLocalQuestions ERROR m->CurrentQuestion already set"); + if (m->CurrentQuestion) + LogMsg("AnswerLocalQuestions ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); m->CurrentQuestion = m->LocalOnlyQuestions; while (m->CurrentQuestion && m->CurrentQuestion != m->NewLocalOnlyQuestions) @@ -2293,7 +873,7 @@ mDNSlocal void AnswerLocalQuestions(mDNS *const m, AuthRecord *rr, mDNSBool AddR #define DefaultProbeCountForTypeUnique ((mDNSu8)3) #define DefaultProbeCountForRecordType(X) ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0) -#define InitialAnnounceCount ((mDNSu8)10) +#define InitialAnnounceCount ((mDNSu8)8) // Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not. // This means that because the announce interval is doubled after sending the first packet, the first @@ -2320,14 +900,19 @@ mDNSlocal void AnswerLocalQuestions(mDNS *const m, AuthRecord *rr, mDNSBool AddR // This is used for cache flush management: // When sending a unique record, all other records matching "SameResourceRecordSignature" must also be sent // When receiving a unique record, all old cache records matching "SameResourceRecordSignature" are flushed -mDNSlocal mDNSBool SameResourceRecordSignature(const ResourceRecord *const r1, const ResourceRecord *const r2) + +mDNSlocal mDNSBool SameResourceRecordSignature(const AuthRecord *const r1, const AuthRecord *const r2) { if (!r1) { LogMsg("SameResourceRecordSignature ERROR: r1 is NULL"); return(mDNSfalse); } if (!r2) { LogMsg("SameResourceRecordSignature ERROR: r2 is NULL"); return(mDNSfalse); } - if (r1->InterfaceID && - r2->InterfaceID && - r1->InterfaceID != r2->InterfaceID) return(mDNSfalse); - return(mDNSBool)(r1->rrtype == r2->rrtype && r1->rrclass == r2->rrclass && r1->namehash == r2->namehash && SameDomainName(r1->name, r2->name)); + if (r1->resrec.InterfaceID && + r2->resrec.InterfaceID && + r1->resrec.InterfaceID != r2->resrec.InterfaceID) return(mDNSfalse); + return(mDNSBool)( + r1->resrec.rrtype == r2->resrec.rrtype && + r1->resrec.rrclass == r2->resrec.rrclass && + r1->resrec.namehash == r2->resrec.namehash && + SameDomainName(r1->resrec.name, r2->resrec.name)); } // PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if our @@ -2343,16 +928,42 @@ mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, cons authrr->resrec.InterfaceID && pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse); if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) && pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse); - return(mDNSBool)(pktrr->resrec.rrclass == authrr->resrec.rrclass && pktrr->resrec.namehash == authrr->resrec.namehash && SameDomainName(pktrr->resrec.name, authrr->resrec.name)); + return(mDNSBool)( + pktrr->resrec.rrclass == authrr->resrec.rrclass && + pktrr->resrec.namehash == authrr->resrec.namehash && + SameDomainName(pktrr->resrec.name, authrr->resrec.name)); } // IdenticalResourceRecord returns true if two resources records have // the same name, type, class, and identical rdata (InterfaceID and TTL may differ) + +// IdenticalSameNameRecord is the same, except it skips the expensive SameDomainName() check, +// which is at its most expensive and least useful in cases where we know in advance that the names match + mDNSlocal mDNSBool IdenticalResourceRecord(const ResourceRecord *const r1, const ResourceRecord *const r2) { if (!r1) { LogMsg("IdenticalResourceRecord ERROR: r1 is NULL"); return(mDNSfalse); } if (!r2) { LogMsg("IdenticalResourceRecord ERROR: r2 is NULL"); return(mDNSfalse); } - if (r1->rrtype != r2->rrtype || r1->rrclass != r2->rrclass || r1->namehash != r2->namehash || !SameDomainName(r1->name, r2->name)) return(mDNSfalse); + if (r1->rrtype != r2->rrtype || r1->rrclass != r2->rrclass || r1->namehash != r2->namehash || !SameDomainName(r1->name, r2->name)) + return(mDNSfalse); + return(SameRData(r1, r2)); + } + +mDNSlocal mDNSBool IdenticalSameNameRecord(const ResourceRecord *const r1, const ResourceRecord *const r2) + { + if (!r1) { LogMsg("IdenticalSameNameRecord ERROR: r1 is NULL"); return(mDNSfalse); } + if (!r2) { LogMsg("IdenticalSameNameRecord ERROR: r2 is NULL"); return(mDNSfalse); } + if (r1->rrtype != r2->rrtype || r1->rrclass != r2->rrclass) + return(mDNSfalse); + +#if VerifySameNameAssumptions + if (r1->namehash != r2->namehash || !SameDomainName(r1->name, r2->name)) + { + LogMsg("Bogus IdenticalSameNameRecord call: %##s does not match %##s", r1->name->c, r1->name->c); + return(mDNSfalse); + } +#endif + return(SameRData(r1, r2)); } @@ -2384,7 +995,8 @@ mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const r { if (rr->resrec.RecordType == kDNSRecordTypeUnique) { - //LogMsg("ProbeCount %d Next %ld %s", rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr)); + //LogMsg("ProbeCount %d Next %ld %s", + // rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr)); if (m->NextScheduledProbe - (rr->LastAPTime + rr->ThisAPInterval) >= 0) m->NextScheduledProbe = (rr->LastAPTime + rr->ThisAPInterval); } @@ -2416,10 +1028,6 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr) m->SuppressProbes = m->NextScheduledQuery; } - // We announce to flush stale data from other caches. It is a reasonable assumption that any - // old stale copies will probably have the same TTL we're using, so announcing longer than - // this serves no purpose -- any stale copies of that record will have expired by then anyway. - rr->AnnounceUntil = m->timenow + TicksTTL(rr); rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval; // Set LastMCTime to now, to inhibit multicast responses // (no need to send additional multicast responses when we're announcing anyway) @@ -2439,8 +1047,8 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr) SetNextAnnounceProbeTime(m, rr); } -#define HashSlot(X) (DomainNameHashValue(X) % CACHE_HASH_SLOTS) - +// Right now this only applies to mDNS (.local) services where the target host is always m->MulticastHostname +// Eventually we should unify this with GetServiceTarget() in uDNS.c mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr) { domainname *target = GetRRDomainNameTarget(&rr->resrec); @@ -2453,7 +1061,7 @@ mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr) if (target && !SameDomainName(target, &m->MulticastHostname)) { AssignDomainName(target, &m->MulticastHostname); - SetNewRData(&rr->resrec, mDNSNULL, 0); + SetNewRData(&rr->resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash // If we're in the middle of probing this record, we need to start again, // because changing its rdata may change the outcome of the tie-breaker. @@ -2464,7 +1072,8 @@ mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr) // changing to the new rdata. However, in practice, we only do SetTargetToHostName for unique records, // so when we announce them we'll set the kDNSClass_UniqueRRSet and clear any stale data that way. if (rr->RequireGoodbye && rr->resrec.RecordType == kDNSRecordTypeShared) - debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); + debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating", + rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); rr->AnnounceCount = InitialAnnounceCount; rr->RequireGoodbye = mDNSfalse; @@ -2475,44 +1084,43 @@ mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr) mDNSlocal void AcknowledgeRecord(mDNS *const m, AuthRecord *const rr) { - if (!rr->Acknowledged && rr->RecordCallback) + if (rr->RecordCallback) { // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. rr->Acknowledged = mDNStrue; - m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback + mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback rr->RecordCallback(m, rr, mStatus_NoError); - m->mDNS_reentrancy--; // Decrement to block mDNS API calls again + mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again } } // Two records qualify to be local duplicates if the RecordTypes are the same, or if one is Unique and the other Verified -#define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified)) -#define RecordIsLocalDuplicate(A,B) ((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec)) +#define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \ + ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified)) +#define RecordIsLocalDuplicate(A,B) \ + ((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec)) -mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) +// Exported so uDNS.c can call this +mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) { domainname *target = GetRRDomainNameTarget(&rr->resrec); AuthRecord *r; AuthRecord **p = &m->ResourceRecords; AuthRecord **d = &m->DuplicateRecords; - mDNSPlatformMemZero(&rr->uDNS_info, sizeof(uDNS_RegInfo)); - if ((mDNSs32)rr->resrec.rroriginalttl <= 0) { LogMsg("mDNS_Register_internal: TTL must be 1 - 0x7FFFFFFF %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); } - -#ifndef UNICAST_DISABLED - if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->ForceMCast || IsLocalDomain(rr->resrec.name)) - rr->uDNS_info.id = zeroID; - else return uDNS_RegisterRecord(m, rr); -#endif - + + if (!rr->resrec.RecordType) + { LogMsg("mDNS_Register_internal: RecordType must be non-zero %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); } + while (*p && *p != rr) p=&(*p)->next; while (*d && *d != rr) d=&(*d)->next; if (*d || *p) { - LogMsg("Error! Tried to register a AuthRecord %p %##s (%s) that's already in the list", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); + LogMsg("Error! Tried to register AuthRecord %p %##s (%s) that's already in the list", + rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return(mStatus_AlreadyRegistered); } @@ -2549,20 +1157,23 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) rr->next = mDNSNULL; - // Field Group 1: Persistent metadata for Authoritative Records -// rr->Additional1 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client -// rr->Additional2 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client -// rr->DependentOn = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client -// rr->RRSet = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client -// rr->Callback = already set in mDNS_SetupResourceRecord -// rr->Context = already set in mDNS_SetupResourceRecord -// rr->RecordType = already set in mDNS_SetupResourceRecord + // Field Group 1: The actual information pertaining to this resource record + // Set up by client prior to call + + // Field Group 2: Persistent metadata for Authoritative Records +// rr->Additional1 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client +// rr->Additional2 = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client +// rr->DependentOn = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client +// rr->RRSet = set to mDNSNULL in mDNS_SetupResourceRecord; may be overridden by client +// rr->Callback = already set in mDNS_SetupResourceRecord +// rr->Context = already set in mDNS_SetupResourceRecord +// rr->RecordType = already set in mDNS_SetupResourceRecord // rr->HostTarget = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client // rr->AllowRemoteQuery = set to mDNSfalse in mDNS_SetupResourceRecord; may be overridden by client // Make sure target is not uninitialized data, or we may crash writing debugging log messages - if (rr->HostTarget && target) target->c[0] = 0; + if (rr->AutoTarget && target) target->c[0] = 0; - // Field Group 2: Transient state for Authoritative Records + // Field Group 3: Transient state for Authoritative Records rr->Acknowledged = mDNSfalse; rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); rr->AnnounceCount = InitialAnnounceCount; @@ -2579,8 +1190,7 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType); - if (!rr->HostTarget) InitializeLastAPTime(m, rr); -// rr->AnnounceUntil = Set for us in InitializeLastAPTime() + if (!rr->AutoTarget) InitializeLastAPTime(m, rr); // rr->LastAPTime = Set for us in InitializeLastAPTime() // rr->LastMCTime = Set for us in InitializeLastAPTime() // rr->LastMCInterface = Set for us in InitializeLastAPTime() @@ -2591,6 +1201,24 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) rr->NextUpdateCredit = 0; rr->UpdateBlocked = 0; + // Field Group 4: Transient uDNS state for Authoritative Records + rr->state = regState_Zero; + rr->uselease = 0; + rr->expire = 0; + rr->Private = 0; + rr->id = zeroID; + rr->zone.c[0] = 0; + rr->UpdateServer = zeroAddr; + rr->UpdatePort = zeroIPPort; + rr->nta = mDNSNULL; + rr->tcp = mDNSNULL; + rr->OrigRData = 0; + rr->OrigRDLen = 0; + rr->InFlightRData = 0; + rr->InFlightRDLen = 0; + rr->QueuedRData = 0; + rr->QueuedRDLen = 0; + // rr->resrec.interface = already set in mDNS_SetupResourceRecord // rr->resrec.name->c = MUST be set by client // rr->resrec.rrtype = already set in mDNS_SetupResourceRecord @@ -2598,7 +1226,7 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) // rr->resrec.rroriginalttl = already set in mDNS_SetupResourceRecord // rr->resrec.rdata = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set - if (rr->HostTarget) + if (rr->AutoTarget) SetTargetToHostName(m, rr); // Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime(); else { @@ -2630,7 +1258,7 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) for (r = m->ResourceRecords; r; r=r->next) { const AuthRecord *s2 = r->RRSet ? r->RRSet : r; - if (s1 != s2 && SameResourceRecordSignature(&r->resrec, &rr->resrec) && !SameRData(&r->resrec, &rr->resrec)) + if (s1 != s2 && SameResourceRecordSignature(r, rr) && !SameRData(&r->resrec, &rr->resrec)) break; } if (r) // If we found a conflict, set RecordType = kDNSRecordTypeDeregistering so we'll deliver the callback @@ -2665,10 +1293,25 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) *p = rr; } - // For records that are not going to probe, acknowledge them right away - if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering) - AcknowledgeRecord(m, rr); - + if (rr->resrec.InterfaceID != mDNSInterface_Any || rr->ForceMCast || IsLocalDomain(rr->resrec.name)) + { + // For records that are not going to probe, acknowledge them right away + if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering) + AcknowledgeRecord(m, rr); + } +#ifndef UNICAST_DISABLED + else + { + if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified; + rr->ProbeCount = 0; + rr->AnnounceCount = 0; + rr->state = regState_FetchingZoneData; + rr->uselease = mDNStrue; + rr->nta = StartGetZoneData(m, rr->resrec.name, ZoneServiceUpdate, RecordRegistrationCallback, rr); + return rr->nta ? mStatus_NoError : mStatus_NoMemoryErr; + } +#endif + return(mStatus_NoError); } @@ -2700,24 +1343,15 @@ mDNSlocal void CompleteRDataUpdate(mDNS *const m, AuthRecord *const rr) rr->UpdateCallback(m, rr, OldRData); // ... and let the client know } -// mDNS_Dereg_normal is used for most calls to mDNS_Deregister_internal -// mDNS_Dereg_conflict is used to indicate that this record is being forcibly deregistered because of a conflict -// mDNS_Dereg_repeat is used when cleaning up, for records that may have already been forcibly deregistered -typedef enum { mDNS_Dereg_normal, mDNS_Dereg_conflict, mDNS_Dereg_repeat } mDNS_Dereg_type; - // NOTE: mDNS_Deregister_internal 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. -mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt) +// Exported so uDNS.c can call this +mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt) { AuthRecord *r2; mDNSu8 RecordType = rr->resrec.RecordType; AuthRecord **p = &m->ResourceRecords; // Find this record in our list of active records -#ifndef UNICAST_DISABLED - if (!(rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->ForceMCast || IsLocalDomain(rr->resrec.name))) - return uDNS_DeregisterRecord(m, rr); -#endif - while (*p && *p != rr) p=&(*p)->next; if (*p) @@ -2727,7 +1361,7 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, { // Scan for duplicates of rr, and mark them for deregistration at the end of this routine, after we've finished // deregistering rr. We need to do this scan *before* we give the client the chance to free and reuse the rr memory. - for (r2 = m->DuplicateRecords; r2; r2=r2->next) if (RecordIsLocalDuplicate(r2, rr)) r2->ProbeCount = 0xFF; + for (r2 = m->DuplicateRecords; r2; r2=r2->next) if (RecordIsLocalDuplicate(r2, rr)) r2->ProbeCount = 0xFF; } else { @@ -2738,7 +1372,8 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, if (*d) { AuthRecord *dup = *d; - debugf("Duplicate record %p taking over from %p %##s (%s)", dup, rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); + debugf("Duplicate record %p taking over from %p %##s (%s)", + dup, rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); *d = dup->next; // Cut replacement record from DuplicateRecords list dup->next = rr->next; // And then... rr->next = dup; // ... splice it in right after the record we're about to delete @@ -2752,7 +1387,6 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, dup->v4Requester = rr->v4Requester; dup->v6Requester = rr->v6Requester; dup->ThisAPInterval = rr->ThisAPInterval; - dup->AnnounceUntil = rr->AnnounceUntil; dup->LastAPTime = rr->LastAPTime; dup->LastMCTime = rr->LastMCTime; dup->LastMCInterface = rr->LastMCInterface; @@ -2767,22 +1401,51 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, while (*p && *p != rr) p=&(*p)->next; // If we found our record on the duplicate list, then make sure we don't send a goodbye for it if (*p) rr->RequireGoodbye = mDNSfalse; - if (*p) debugf("DNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); + if (*p) debugf("DNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)", + rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); } if (!*p) { // No need to log an error message if we already know this is a potentially repeated deregistration if (drt != mDNS_Dereg_repeat) - LogMsg("mDNS_Deregister_internal: Record %p %##s (%s) not found in list", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); + LogMsg("mDNS_Deregister_internal: Record %p %##s (%s) not found in list", + rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return(mStatus_BadReferenceErr); } // If this is a shared record and we've announced it at least once, // we need to retract that announcement before we delete the record - if (RecordType == kDNSRecordTypeShared && rr->RequireGoodbye) + + // If this is a record (including mDNSInterface_LocalOnly records) for which we've given local answers then + // it's tempting to just do "AnswerLocalQuestions(m, rr, mDNSfalse)" here, but that would not not be safe. + // The AnswerLocalQuestions routine walks the question list invoking client callbacks, using the "m->CurrentQuestion" + // mechanism to cope with the client callback modifying the question list while that's happening. + // However, mDNS_Deregister could have been called from a client callback (e.g. from the domain enumeration callback FoundDomain) + // which means that the "m->CurrentQuestion" mechanism is already in use to protect that list, so we can't use it twice. + // More generally, if we invoke callbacks from within a client callback, then those callbacks could deregister other + // records, thereby invoking yet more callbacks, without limit. + // The solution is to defer delivering the "Remove" events until mDNS_Execute time, just like we do for sending + // actual goodbye packets. + +#ifndef UNICAST_DISABLED + if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly && !rr->ForceMCast && !IsLocalDomain(rr->resrec.name)) + if (rr->RequireGoodbye) + { + if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; } + rr->resrec.RecordType = kDNSRecordTypeDeregistering; + uDNS_DeregisterRecord(m, rr); + // At this point unconditionally we bail out + // Either uDNS_DeregisterRecord will have completed synchronously, and called CompleteDeregistration, + // which calls us back here with RequireGoodbye set to false, or it will have initiated the deregistration + // process and will complete asynchronously. Either way we don't need to do anything more here. + return(mStatus_NoError); + } +#endif UNICAST_DISABLED + + if (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->LocalAnswer)) { - verbosedebugf("mDNS_Deregister_internal: Sending deregister for %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); + verbosedebugf("mDNS_Deregister_internal: Sending deregister for %s", ARDisplayString(m, rr)); rr->resrec.RecordType = kDNSRecordTypeDeregistering; rr->resrec.rroriginalttl = 0; rr->ImmedAnswer = mDNSInterfaceMark; @@ -2798,14 +1461,12 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, rr->next = mDNSNULL; if (RecordType == kDNSRecordTypeUnregistered) - debugf("mDNS_Deregister_internal: Record %##s (%s) already marked kDNSRecordTypeUnregistered", - rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); + LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeUnregistered", ARDisplayString(m, rr)); else if (RecordType == kDNSRecordTypeDeregistering) - debugf("mDNS_Deregister_internal: Record %##s (%s) already marked kDNSRecordTypeDeregistering", - rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); + LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeDeregistering", ARDisplayString(m, rr)); else { - verbosedebugf("mDNS_Deregister_internal: Deleting record for %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); + verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m, rr)); rr->resrec.RecordType = kDNSRecordTypeUnregistered; } @@ -2815,22 +1476,25 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, // If we have an update queued up which never executed, give the client a chance to free that memory if (rr->NewRData) CompleteRDataUpdate(m, rr); // Update our rdata, clear the NewRData pointer, and return memory to the client - - if (rr->LocalAnswer) AnswerLocalQuestions(m, rr, mDNSfalse); + + if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; } + if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; } // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. // In this case the likely client action to the mStatus_MemFree message is to free the memory, // so any attempt to touch rr after this is likely to lead to a crash. - m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback + mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback if (drt != mDNS_Dereg_conflict) { - if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_MemFree); // MUST NOT touch rr after this + if (rr->RecordCallback) + rr->RecordCallback(m, rr, mStatus_MemFree); // MUST NOT touch rr after this } else { RecordProbeFailure(m, rr); - if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_NameConflict); // MUST NOT touch rr after this + if (rr->RecordCallback) + rr->RecordCallback(m, rr, mStatus_NameConflict); // MUST NOT touch rr after this // Now that we've finished deregistering rr, check our DuplicateRecords list for any that we marked previously. // Note that with all the client callbacks going on, by the time we get here all the // records we marked may have been explicitly deregistered by the client anyway. @@ -2841,7 +1505,7 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, else { mDNS_Deregister_internal(m, r2, mDNS_Dereg_conflict); r2 = m->DuplicateRecords; } } } - m->mDNS_reentrancy--; // Decrement to block mDNS API calls again + mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again } return(mStatus_NoError); } @@ -2849,7 +1513,6 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - -#pragma mark - #pragma mark - Packet Sending Functions #endif @@ -2880,15 +1543,32 @@ mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseR if (rr->Additional2 && ResourceRecordIsValidInterfaceAnswer(rr->Additional2, InterfaceID)) AddRecordToResponseList(nrpp, rr->Additional2, rr); - + // For SRV records, automatically add the Address record(s) for the target host if (rr->resrec.rrtype == kDNSType_SRV) + { for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ... ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ... rr->resrec.rdatahash == rr2->resrec.namehash && // ... whose name is the name of the SRV target SameDomainName(&rr->resrec.rdata->u.srv.target, rr2->resrec.name)) AddRecordToResponseList(nrpp, rr2, rr); + } + else if (RRTypeIsAddressType(rr->resrec.rrtype)) // For A or AAAA, put counterpart as additional + { + for (rr2=m->ResourceRecords; rr2; rr2=rr2->next) // Scan list of resource records + if (RRTypeIsAddressType(rr2->resrec.rrtype) && // For all address records (A/AAAA) ... + ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) && // ... which are valid for answer ... + rr->resrec.namehash == rr2->resrec.namehash && // ... and have the same name + SameDomainName(rr->resrec.name, rr2->resrec.name)) + AddRecordToResponseList(nrpp, rr2, rr); + } + else if (rr->resrec.rrtype == kDNSType_PTR) // For service PTR, see if we want to add DeviceInfo record + { + if (ResourceRecordIsValidInterfaceAnswer(&m->DeviceInfo, InterfaceID) && + SameDomainLabel(rr->resrec.rdata->u.name.c, m->DeviceInfo.resrec.name->c)) + AddRecordToResponseList(nrpp, &m->DeviceInfo, rr); + } } } @@ -2963,16 +1643,17 @@ mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const d rr->NR_AdditionalTo = mDNSNULL; } - if (m->omsg.h.numAnswers) mDNSSendDNSMessage(m, &m->omsg, responseptr, mDNSInterface_Any, dest, MulticastDNSPort, -1, mDNSNULL); + if (m->omsg.h.numAnswers) mDNSSendDNSMessage(m, &m->omsg, responseptr, mDNSInterface_Any, dest, MulticastDNSPort, mDNSNULL, mDNSNULL); } } -mDNSlocal void CompleteDeregistration(mDNS *const m, AuthRecord *rr) +mDNSexport void CompleteDeregistration(mDNS *const m, AuthRecord *rr) { - // Clearing rr->RequireGoodbye signals mDNS_Deregister_internal() - // that it should go ahead and immediately dispose of this registration + // Clearing rr->RequireGoodbye signals mDNS_Deregister_internal() that + // it should go ahead and immediately dispose of this registration rr->resrec.RecordType = kDNSRecordTypeShared; rr->RequireGoodbye = mDNSfalse; + if (rr->LocalAnswer) { AnswerLocalQuestions(m, rr, mDNSfalse); rr->LocalAnswer = mDNSfalse; } mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); // Don't touch rr after this } @@ -2981,7 +1662,8 @@ mDNSlocal void CompleteDeregistration(mDNS *const m, AuthRecord *rr) // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. mDNSlocal void DiscardDeregistrations(mDNS *const m) { - if (m->CurrentRecord) LogMsg("DiscardDeregistrations ERROR m->CurrentRecord already set"); + if (m->CurrentRecord) + LogMsg("DiscardDeregistrations ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); m->CurrentRecord = m->ResourceRecords; while (m->CurrentRecord) @@ -3072,6 +1754,7 @@ mDNSlocal void SendResponses(mDNS *const m) // which will be non-null. If by some chance there is an address record that's not interface-specific (should never happen) // then all that means is that it won't get sent -- which would not be the end of the world. for (rr = m->ResourceRecords; rr; rr=rr->next) + { if (rr->ImmedAnswer && rr->resrec.rrtype == kDNSType_SRV) for (r2=m->ResourceRecords; r2; r2=r2->next) // Scan list of resource records if (RRTypeIsAddressType(r2->resrec.rrtype) && // For all address records (A/AAAA) ... @@ -3081,6 +1764,16 @@ mDNSlocal void SendResponses(mDNS *const m) SameDomainName(&rr->resrec.rdata->u.srv.target, r2->resrec.name) && (rr->ImmedAnswer == mDNSInterfaceMark || rr->ImmedAnswer == r2->resrec.InterfaceID)) r2->ImmedAdditional = r2->resrec.InterfaceID; // ... then mark this address record for sending too + // We also make sure we send the DeviceInfo TXT record too, if necessary + // We check for RecordType == kDNSRecordTypeShared because we don't want to tag the + // DeviceInfo TXT record onto a goodbye packet (RecordType == kDNSRecordTypeDeregistering). + if (rr->ImmedAnswer && rr->resrec.RecordType == kDNSRecordTypeShared && rr->resrec.rrtype == kDNSType_PTR) + if (ResourceRecordIsValidAnswer(&m->DeviceInfo) && SameDomainLabel(rr->resrec.rdata->u.name.c, m->DeviceInfo.resrec.name->c)) + { + if (!m->DeviceInfo.ImmedAnswer) m->DeviceInfo.ImmedAnswer = rr->ImmedAnswer; + else m->DeviceInfo.ImmedAnswer = mDNSInterfaceMark; + } + } // If there's a record which is supposed to be unique that we're going to send, then make sure that we give // the whole RRSet as an atomic unit. That means that if we have any other records with the same name/type/class @@ -3095,14 +1788,15 @@ mDNSlocal void SendResponses(mDNS *const m) { for (r2 = m->ResourceRecords; r2; r2=r2->next) if (ResourceRecordIsValidAnswer(r2)) - if (r2->ImmedAnswer != mDNSInterfaceMark && r2->ImmedAnswer != rr->ImmedAnswer && SameResourceRecordSignature(&r2->resrec, &rr->resrec)) + if (r2->ImmedAnswer != mDNSInterfaceMark && + r2->ImmedAnswer != rr->ImmedAnswer && SameResourceRecordSignature(r2, rr)) r2->ImmedAnswer = rr->ImmedAnswer; } else if (rr->ImmedAdditional) // If we're sending this as additional, see that its whole RRSet is similarly marked { for (r2 = m->ResourceRecords; r2; r2=r2->next) if (ResourceRecordIsValidAnswer(r2)) - if (r2->ImmedAdditional != rr->ImmedAdditional && SameResourceRecordSignature(&r2->resrec, &rr->resrec)) + if (r2->ImmedAdditional != rr->ImmedAdditional && SameResourceRecordSignature(r2, rr)) r2->ImmedAdditional = rr->ImmedAdditional; } } @@ -3122,7 +1816,6 @@ mDNSlocal void SendResponses(mDNS *const m) rr->AnnounceCount--; rr->ThisAPInterval *= 2; rr->LastAPTime = m->timenow; - if (rr->LastAPTime + rr->ThisAPInterval - rr->AnnounceUntil >= 0) rr->AnnounceCount = 0; debugf("Announcing %##s (%s) %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->AnnounceCount); } } @@ -3164,9 +1857,8 @@ mDNSlocal void SendResponses(mDNS *const m) if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) { newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0); - if (!newptr && m->omsg.h.numAnswers) break; - numDereg++; - responseptr = newptr; + if (newptr) { responseptr = newptr; numDereg++; } + else if (m->omsg.h.numAnswers) break; } else if (rr->NewRData && !m->SleepState) // If we have new data for this record { @@ -3176,10 +1868,8 @@ mDNSlocal void SendResponses(mDNS *const m) if (ResourceRecordIsValidAnswer(rr) && rr->RequireGoodbye) { newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0); - if (!newptr && m->omsg.h.numAnswers) break; - numDereg++; - responseptr = newptr; - rr->RequireGoodbye = mDNSfalse; + if (newptr) { responseptr = newptr; numDereg++; rr->RequireGoodbye = mDNSfalse; } + else if (m->omsg.h.numAnswers) break; } // Now try to see if we can fit the update in the same packet (not fatal if we can't) SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength); @@ -3196,10 +1886,13 @@ mDNSlocal void SendResponses(mDNS *const m) rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, m->SleepState ? 0 : rr->resrec.rroriginalttl); rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state - if (!newptr && m->omsg.h.numAnswers) break; - rr->RequireGoodbye = (mDNSu8) (!m->SleepState); - if (rr->LastAPTime == m->timenow) numAnnounce++; else numAnswer++; - responseptr = newptr; + if (newptr) + { + responseptr = newptr; + rr->RequireGoodbye = (mDNSu8) (!m->SleepState); + if (rr->LastAPTime == m->timenow) numAnnounce++; else numAnswer++; + } + else if (m->omsg.h.numAnswers) break; } // If sending on all interfaces, go to next interface; else we're finished now if (rr->ImmedAnswer == mDNSInterfaceMark && rr->resrec.InterfaceID == mDNSInterface_Any) @@ -3226,7 +1919,7 @@ mDNSlocal void SendResponses(mDNS *const m) for (a = m->ResourceRecords; a; a=a->next) if (a->LastMCTime == m->timenow && a->LastMCInterface == intf->InterfaceID && - SameResourceRecordSignature(&a->resrec, &rr->resrec)) { SendAdditional = mDNStrue; break; } + SameResourceRecordSignature(a, rr)) { SendAdditional = mDNStrue; break; } } if (!SendAdditional) // If we don't want to send this after all, rr->ImmedAdditional = mDNSNULL; // then cancel its ImmedAdditional field @@ -3258,8 +1951,8 @@ mDNSlocal void SendResponses(mDNS *const m) numAnnounce, numAnnounce == 1 ? "" : "s", numAnswer, numAnswer == 1 ? "" : "s", m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s", intf->InterfaceID); - if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, -1, mDNSNULL); - if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, -1, mDNSNULL); + if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL); + if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL); if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10); if (++pktcount >= 1000) { LogMsg("SendResponses exceeded loop limit %d: giving up", pktcount); break; } // There might be more things to send on this interface, so go around one more time and try again. @@ -3279,7 +1972,8 @@ mDNSlocal void SendResponses(mDNS *const m) // *** 3. Cleanup: Now that everything is sent, call client callback functions, and reset state variables // *** - if (m->CurrentRecord) LogMsg("SendResponses: ERROR m->CurrentRecord already set"); + if (m->CurrentRecord) + LogMsg("SendResponses ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); m->CurrentRecord = m->ResourceRecords; while (m->CurrentRecord) { @@ -3344,8 +2038,9 @@ mDNSlocal void SetNextCacheCheckTime(mDNS *const m, CacheRecord *const rr) { rr->NextRequiredQuery -= TicksTTL(rr)/20 * (MaxUnansweredQueries - rr->UnansweredQueries); rr->NextRequiredQuery += mDNSRandom((mDNSu32)TicksTTL(rr)/50); - verbosedebugf("SetNextCacheCheckTime: %##s (%s) NextRequiredQuery in %ld sec", - rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), (rr->NextRequiredQuery - m->timenow) / mDNSPlatformOneSecond); + verbosedebugf("SetNextCacheCheckTime: %##s (%s) NextRequiredQuery in %ld sec CacheCheckGracePeriod %d ticks", + rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), + (rr->NextRequiredQuery - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr)); } if (m->NextCacheCheck - (rr->NextRequiredQuery + CacheCheckGracePeriod(rr)) > 0) @@ -3356,9 +2051,10 @@ mDNSlocal void SetNextCacheCheckTime(mDNS *const m, CacheRecord *const rr) m->NextCacheCheck = rr->DelayDelivery; } -#define kDefaultReconfirmTimeForNoAnswer ((mDNSu32)mDNSPlatformOneSecond * 15) -#define kDefaultReconfirmTimeForCableDisconnect ((mDNSu32)mDNSPlatformOneSecond * 5) -#define kMinimumReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 5) +#define kMinimumReconfirmTime ((mDNSu32)mDNSPlatformOneSecond * 5) +#define kDefaultReconfirmTimeForWake ((mDNSu32)mDNSPlatformOneSecond * 5) +#define kDefaultReconfirmTimeForNoAnswer ((mDNSu32)mDNSPlatformOneSecond * 5) +#define kDefaultReconfirmTimeForFlappingInterface ((mDNSu32)mDNSPlatformOneSecond * 30) mDNSlocal mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr, mDNSu32 interval) { @@ -3371,12 +2067,16 @@ mDNSlocal mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr, if (RRExpireTime(rr) - m->timenow > (mDNSs32)((interval * 4) / 3)) { // Add a 33% random amount to the interval, to avoid synchronization between multiple hosts - interval += mDNSRandom(interval/3); + // 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); + interval += mDNSRandomFromFixedSeed(m->RandomReconfirmDelay, interval/3); rr->TimeRcvd = m->timenow - (mDNSs32)interval * 3; - rr->resrec.rroriginalttl = interval * 4 / mDNSPlatformOneSecond; + rr->resrec.rroriginalttl = (interval * 4 + mDNSPlatformOneSecond - 1) / mDNSPlatformOneSecond; SetNextCacheCheckTime(m, rr); } - debugf("mDNS_Reconfirm_internal:%5ld ticks to go for %s", RRExpireTime(rr) - m->timenow, CRDisplayString(m, rr)); + debugf("mDNS_Reconfirm_internal:%6ld ticks to go for %s %p", + RRExpireTime(rr) - m->timenow, CRDisplayString(m, rr), rr->CRActiveQuestion); return(mStatus_NoError); } @@ -3394,12 +2094,13 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer mDNSu8 *newptr = putQuestion(query, *queryptr, limit, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit)); if (!newptr) { - debugf("BuildQuestion: No more space in this packet for question %##s", q->qname.c); + debugf("BuildQuestion: No more space in this packet for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return(mDNSfalse); } else if (newptr + *answerforecast >= limit) { - verbosedebugf("BuildQuestion: Retracting question %##s new forecast total %d", q->qname.c, newptr + *answerforecast - query->data); + verbosedebugf("BuildQuestion: Retracting question %##s (%s) new forecast total %d", + q->qname.c, DNSTypeName(q->qtype), newptr + *answerforecast - query->data); query->h.numQuestions--; return(mDNSfalse); } @@ -3407,7 +2108,7 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer { mDNSu32 forecast = *answerforecast; const mDNSu32 slot = HashSlot(&q->qname); - CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); + const CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); CacheRecord *rr; CacheRecord **ka = *kalistptrptr; // Make a working copy of the pointer we're going to update @@ -3415,7 +2116,7 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer if (rr->resrec.InterfaceID == q->SendQNow && // received on this interface rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList && // which is not already in the known answer list rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet - ResourceRecordAnswersQuestion(&rr->resrec, q) && // which answers our question + SameNameRecordAnswersQuestion(&rr->resrec, q) && // which answers our question rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow > // and its half-way-to-expiry time is at least 1 second away mDNSPlatformOneSecond) // (also ensures we never include goodbye records with TTL=1) { @@ -3436,35 +2137,16 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer } } - // Traffic reduction: - // If we already have at least one unique answer in the cache, - // OR we have so many shared answers that the KA list is too big to fit in one packet - // The we suppress queries number 3 and 5: - // Query 1 (immediately; ThisQInterval = 1 sec; request unicast replies) - // Query 2 (after 1 second; ThisQInterval = 2 sec; send normally) - // Query 3 (after 2 seconds; ThisQInterval = 4 sec; may suppress) - // Query 4 (after 4 seconds; ThisQInterval = 8 sec; send normally) - // Query 5 (after 8 seconds; ThisQInterval = 16 sec; may suppress) - // Query 6 (after 16 seconds; ThisQInterval = 32 sec; send normally) - if (q->UniqueAnswers || newptr + forecast >= limit) - if (q->ThisQInterval == InitialQuestionInterval * 8 || q->ThisQInterval == InitialQuestionInterval * 32) - { - query->h.numQuestions--; - ka = *kalistptrptr; // Go back to where we started and retract these answer records - while (*ka) { CacheRecord *rr = *ka; *ka = mDNSNULL; ka = &rr->NextInKAList; } - return(mDNStrue); // Return true: pretend we succeeded, even though we actually suppressed this question - } - // Success! Update our state pointers, increment UnansweredQueries as appropriate, and return *queryptr = newptr; // Update the packet pointer *answerforecast = forecast; // Update the forecast *kalistptrptr = ka; // Update the known answer list pointer - if (ucast) m->ExpectUnicastResponse = m->timenow; + if (ucast) q->ExpectUnicastResp = NonZeroTime(m->timenow); for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // For every resource record in our cache, if (rr->resrec.InterfaceID == q->SendQNow && // received on this interface rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList && // which is not in the known answer list - ResourceRecordAnswersQuestion(&rr->resrec, q)) // which answers our question + SameNameRecordAnswersQuestion(&rr->resrec, q)) // which answers our question { rr->UnansweredQueries++; // indicate that we're expecting a response rr->LastUnansweredTime = m->timenow; @@ -3475,15 +2157,34 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer } } -mDNSlocal void ReconfirmAntecedents(mDNS *const m, DNSQuestion *q) +// When we have a query looking for a specified name, but there appear to be no answers with +// that name, ReconfirmAntecedents() is called with depth=0 to start the reconfirmation process +// for any records in our cache that reference the given name (e.g. PTR and SRV records). +// For any such cache record we find, we also recursively call ReconfirmAntecedents() for *its* name. +// We increment depth each time we recurse, to guard against possible infinite loops, with a limit of 5. +// A typical reconfirmation scenario might go like this: +// Depth 0: Name "myhost.local" has no address records +// Depth 1: SRV "My Service._example._tcp.local." refers to "myhost.local"; may be stale +// Depth 2: PTR "_example._tcp.local." refers to "My Service"; may be stale +// Depth 3: PTR "_services._dns-sd._udp.local." refers to "_example._tcp.local."; may be stale +// Currently depths 4 and 5 are not expected to occur; if we did get to depth 5 we'd reconfim any records we +// found referring to the given name, but not recursively descend any further reconfirm *their* antecedents. +mDNSlocal void ReconfirmAntecedents(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const int depth) { mDNSu32 slot; CacheGroup *cg; - CacheRecord *rr; - domainname *target; - FORALL_CACHERECORDS(slot, cg, rr) - if ((target = GetRRDomainNameTarget(&rr->resrec)) && rr->resrec.rdatahash == q->qnamehash && SameDomainName(target, &q->qname)) - mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForNoAnswer); + CacheRecord *cr; + debugf("ReconfirmAntecedents (depth=%d) for %##s", depth, name->c); + FORALL_CACHERECORDS(slot, cg, cr) + { + domainname *crtarget = GetRRDomainNameTarget(&cr->resrec); + if (crtarget && cr->resrec.rdatahash == namehash && SameDomainName(crtarget, name)) + { + LogOperation("ReconfirmAntecedents: Reconfirming (depth=%d) %s", depth, CRDisplayString(m, cr)); + mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); + if (depth < 5) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, depth+1); + } + } } // Only DupSuppressInfos newer than the specified 'time' are allowed to remain active @@ -3550,11 +2251,11 @@ 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); - CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); + const CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); 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 - ResourceRecordAnswersQuestion(&rr->resrec, q) && // which answers our question + SameNameRecordAnswersQuestion(&rr->resrec, q) && // which answers our question rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >= 0 && // and it is less than half-way to expiry rr->NextRequiredQuery - (m->timenow + q->ThisQInterval) > 0)// and we'll ask at least once again before NextRequiredQuery { @@ -3582,6 +2283,10 @@ mDNSlocal mDNSBool AccelerateThisQuery(mDNS *const m, DNSQuestion *q) mDNSlocal void SendQueries(mDNS *const m) { + mDNSu32 slot; + CacheGroup *cg; + CacheRecord *cr; + AuthRecord *ar; int pktcount = 0; DNSQuestion *q; // For explanation of maxExistingQuestionInterval logic, see comments for maxExistingAnnounceInterval @@ -3592,10 +2297,7 @@ mDNSlocal void SendQueries(mDNS *const m) // 1. If time for a query, work out what we need to do if (m->timenow - m->NextScheduledQuery >= 0) { - mDNSu32 slot; - CacheGroup *cg; CacheRecord *rr; - m->NextScheduledQuery = m->timenow + 0x78000000; // We're expecting to send a query anyway, so see if any expiring cache records are close enough // to their NextRequiredQuery to be worth batching them together with this one @@ -3603,61 +2305,91 @@ mDNSlocal void SendQueries(mDNS *const m) if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries) if (m->timenow + TicksTTL(rr)/50 - rr->NextRequiredQuery >= 0) { + LogOperation("Sending %d%% cache expiration query for %s", 80 + 5 * rr->UnansweredQueries, CRDisplayString(m, rr)); q = rr->CRActiveQuestion; ExpireDupSuppressInfoOnInterface(q->DupSuppress, m->timenow - TicksTTL(rr)/20, rr->resrec.InterfaceID); - if (q->Target.type) q->SendQNow = mDNSInterfaceMark; // If unicast query, mark it + if (q->Target.type) q->SendQNow = mDNSInterfaceMark; // If targeted query, mark it + else if (!mDNSOpaque16IsZero(q->TargetQID)) q->LastQTime = m->timenow - q->ThisQInterval; // For uDNS, adjust LastQTime else if (q->SendQNow == mDNSNULL) q->SendQNow = rr->resrec.InterfaceID; else if (q->SendQNow != rr->resrec.InterfaceID) q->SendQNow = mDNSInterfaceMark; } - // Scan our list of questions to see which *unicast* queries need to be sent - for (q = m->Questions; q; q=q->next) - if (q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow))) + if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0) + m->SuppressStdPort53Queries = 0; // If suppression time has passed, clear it + + // Scan our list of questions to see which: + // *WideArea* queries need to be sent + // *unicast* queries need to be sent + // *multicast* queries we're definitely going to send + if (m->CurrentQuestion) + LogMsg("SendQueries ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); + m->CurrentQuestion = m->Questions; + while (m->CurrentQuestion) + { + q = m->CurrentQuestion; + if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID)) uDNS_CheckCurrentQuestion(m); + else if (mDNSOpaque16IsZero(q->TargetQID) && q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow))) { mDNSu8 *qptr = m->omsg.data; const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data); InitializeDNSMessage(&m->omsg.h, q->TargetQID, QueryFlags); qptr = putQuestion(&m->omsg, qptr, limit, &q->qname, q->qtype, q->qclass); - mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, &q->Target, q->TargetPort, -1, mDNSNULL); - q->ThisQInterval *= 2; + mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, &q->Target, q->TargetPort, mDNSNULL, mDNSNULL); + q->ThisQInterval *= QuestionIntervalStep; if (q->ThisQInterval > MaxQuestionInterval) q->ThisQInterval = MaxQuestionInterval; - q->LastQTime = m->timenow; - q->LastQTxTime = m->timenow; - q->RecentAnswerPkts = 0; - q->SendQNow = mDNSNULL; - m->ExpectUnicastResponse = m->timenow; + q->LastQTime = m->timenow; + q->LastQTxTime = m->timenow; + q->RecentAnswerPkts = 0; + q->SendQNow = mDNSNULL; + q->ExpectUnicastResp = NonZeroTime(m->timenow); } - - // Scan our list of questions to see which *multicast* queries we're definitely going to send - for (q = m->Questions; q; q=q->next) - if (!q->Target.type && TimeToSendThisQuestion(q, m->timenow)) + else if (mDNSOpaque16IsZero(q->TargetQID) && !q->Target.type && TimeToSendThisQuestion(q, m->timenow)) { + //LogOperation("Time to send %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval)); q->SendQNow = mDNSInterfaceMark; // Mark this question for sending on all interfaces if (maxExistingQuestionInterval < q->ThisQInterval) maxExistingQuestionInterval = q->ThisQInterval; } - + // If m->CurrentQuestion wasn't modified out from under us, advance it now + // We can't do this at the start of the loop because uDNS_CheckCurrentQuestion() depends on having + // m->CurrentQuestion point to the right question + if (q == m->CurrentQuestion) m->CurrentQuestion = m->CurrentQuestion->next; + } + // Scan our list of questions // (a) to see if there are any more that are worth accelerating, and // (b) to update the state variables for *all* the questions we're going to send + // 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; for (q = m->Questions; q; q=q->next) { - if (q->SendQNow || - (!q->Target.type && ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q))) + if (mDNSOpaque16IsZero(q->TargetQID) && (q->SendQNow || + (!q->Target.type && ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q)))) { // If at least halfway to next query time, advance to next interval - // If less than halfway to next query time, treat this as logically a repeat of the last transmission, without advancing the interval + // If less than halfway to next query time, then + // treat this as logically a repeat of the last transmission, without advancing the interval if (m->timenow - (q->LastQTime + q->ThisQInterval/2) >= 0) { + //LogOperation("Accelerating %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval)); q->SendQNow = mDNSInterfaceMark; // Mark this question for sending on all interfaces - q->ThisQInterval *= 2; + q->ThisQInterval *= QuestionIntervalStep; if (q->ThisQInterval > MaxQuestionInterval) q->ThisQInterval = MaxQuestionInterval; - else if (q->CurrentAnswers == 0 && q->ThisQInterval == InitialQuestionInterval * 8) + else if (q->CurrentAnswers == 0 && q->ThisQInterval == InitialQuestionInterval * QuestionIntervalStep2) { - debugf("SendQueries: Zero current answers for %##s (%s); will reconfirm antecedents", q->qname.c, DNSTypeName(q->qtype)); - ReconfirmAntecedents(m, q); // If sending third query, and no answers yet, time to begin doubting the source + // Generally don't need to log this. + // It's not especially noteworthy if a query finds no results -- this usually happens for domain + // enumeration queries in the LL subdomain (e.g. "db._dns-sd._udp.0.0.254.169.in-addr.arpa") + // and when there simply happen to be no instances of the service the client is looking + // for (e.g. iTunes is set to look for RAOP devices, and the current network has none). + debugf("SendQueries: Zero current answers for %##s (%s); will reconfirm antecedents", + q->qname.c, DNSTypeName(q->qtype)); + // Sending third query, and no answers yet; time to begin doubting the source + ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0); } } @@ -3687,7 +2419,8 @@ mDNSlocal void SendQueries(mDNS *const m) { m->NextScheduledProbe = m->timenow + 0x78000000; - if (m->CurrentRecord) LogMsg("SendQueries: ERROR m->CurrentRecord already set"); + if (m->CurrentRecord) + LogMsg("SendQueries ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); m->CurrentRecord = m->ResourceRecords; while (m->CurrentRecord) { @@ -3708,20 +2441,34 @@ mDNSlocal void SendQueries(mDNS *const m) rr->LastAPTime = m->timenow; rr->ProbeCount--; SetNextAnnounceProbeTime(m, rr); + if (rr->ProbeCount == 0) + { + // If this is the last probe for this record, then see if we have any matching records + // on our duplicate list which should similarly have their ProbeCount cleared to zero... + AuthRecord *r2; + for (r2 = m->DuplicateRecords; r2; r2=r2->next) + if (r2->resrec.RecordType == kDNSRecordTypeUnique && RecordIsLocalDuplicate(r2, rr)) + r2->ProbeCount = 0; + // ... then acknowledge this record to the client. + // We do this optimistically, just as we're about to send the third probe. + // This helps clients that both advertise and browse, and want to filter themselves + // from the browse results list, because it helps ensure that the registration + // confirmation will be delivered 1/4 second *before* the browse "add" event. + // A potential downside is that we could deliver a registration confirmation and then find out + // moments later that there's a name conflict, but applications have to be prepared to handle + // late conflicts anyway (e.g. on connection of network cable, etc.), so this is nothing new. + if (!rr->Acknowledged) AcknowledgeRecord(m, rr); + } } - // else, if it has now finished probing, move it to state Verified, and update m->NextScheduledResponse so it will be announced + // else, if it has now finished probing, move it to state Verified, + // and update m->NextScheduledResponse so it will be announced else { - AuthRecord *r2; + if (!rr->Acknowledged) AcknowledgeRecord(m, rr); // Defensive, just in case it got missed somehow rr->resrec.RecordType = kDNSRecordTypeVerified; rr->ThisAPInterval = DefaultAnnounceIntervalForTypeUnique; rr->LastAPTime = m->timenow - DefaultAnnounceIntervalForTypeUnique; SetNextAnnounceProbeTime(m, rr); - // If we have any records on our duplicate list that match this one, they have now also completed probing - for (r2 = m->DuplicateRecords; r2; r2=r2->next) - if (r2->resrec.RecordType == kDNSRecordTypeUnique && RecordIsLocalDuplicate(r2, rr)) - r2->ProbeCount = 0; - AcknowledgeRecord(m, rr); } } } @@ -3730,12 +2477,13 @@ mDNSlocal void SendQueries(mDNS *const m) { AuthRecord *rr = m->CurrentRecord; m->CurrentRecord = rr->next; - if (rr->resrec.RecordType == kDNSRecordTypeUnique && rr->ProbeCount == 0) + if (rr->resrec.RecordType == kDNSRecordTypeUnique && rr->ProbeCount == 0 && !rr->Acknowledged) AcknowledgeRecord(m, rr); } } - // 3. Now we know which queries and probes we're sending, go through our interface list sending the appropriate queries on each interface + // 3. Now we know which queries and probes we're sending, + // go through our interface list sending the appropriate queries on each interface while (intf) { AuthRecord *rr; @@ -3750,7 +2498,8 @@ mDNSlocal void SendQueries(mDNS *const m) // Put query questions in this packet for (q = m->Questions; q; q=q->next) - if (q->SendQNow == intf->InterfaceID) + { + if (mDNSOpaque16IsZero(q->TargetQID) && (q->SendQNow == intf->InterfaceID)) { debugf("SendQueries: %s question for %##s (%s) at %d forecast total %d", SuppressOnThisInterface(q->DupSuppress, intf) ? "Suppressing" : "Putting ", @@ -3760,6 +2509,7 @@ mDNSlocal void SendQueries(mDNS *const m) BuildQuestion(m, &m->omsg, &queryptr, q, &kalistptr, &answerforecast)) q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf); } + } // Put probe questions in this packet for (rr = m->ResourceRecords; rr; rr=rr->next) @@ -3777,11 +2527,13 @@ mDNSlocal void SendQueries(mDNS *const m) answerforecast = forecast; rr->SendRNow = (rr->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf); rr->IncludeInProbe = mDNStrue; - verbosedebugf("SendQueries: Put Question %##s (%s) probecount %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->ProbeCount); + verbosedebugf("SendQueries: Put Question %##s (%s) probecount %d", + rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->ProbeCount); } else { - verbosedebugf("SendQueries: Retracting Question %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); + verbosedebugf("SendQueries: Retracting Question %##s (%s)", + rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); m->omsg.h.numQuestions--; } } @@ -3795,7 +2547,8 @@ mDNSlocal void SendQueries(mDNS *const m) mDNSu8 *newptr = PutResourceRecordTTL(&m->omsg, queryptr, &m->omsg.h.numAnswers, &rr->resrec, rr->resrec.rroriginalttl - SecsSinceRcvd); if (newptr) { - verbosedebugf("SendQueries: Put %##s (%s) at %d - %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data); + verbosedebugf("SendQueries: Put %##s (%s) at %d - %d", + rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data); queryptr = newptr; KnownAnswerList = rr->NextInKAList; rr->NextInKAList = mDNSNULL; @@ -3829,8 +2582,8 @@ mDNSlocal void SendQueries(mDNS *const m) m->omsg.h.numQuestions, m->omsg.h.numQuestions == 1 ? "" : "s", m->omsg.h.numAnswers, m->omsg.h.numAnswers == 1 ? "" : "s", m->omsg.h.numAuthorities, m->omsg.h.numAuthorities == 1 ? "" : "s", intf->InterfaceID); - if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, -1, mDNSNULL); - if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, -1, mDNSNULL); + if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL); + if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL); if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10); if (++pktcount >= 1000) { LogMsg("SendQueries exceeded loop limit %d: giving up", pktcount); break; } @@ -3848,17 +2601,39 @@ mDNSlocal void SendQueries(mDNS *const m) } } - // Final sanity check for debugging purposes - { - AuthRecord *rr; - for (rr = m->ResourceRecords; rr; rr=rr->next) - if (rr->SendRNow) - { - if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly) - LogMsg("SendQueries: No active interface to send: %s", ARDisplayString(m, rr)); - rr->SendRNow = mDNSNULL; - } - } + // 4. Final housekeeping + + // 4a. Debugging check: Make sure we announced all our records + for (ar = m->ResourceRecords; ar; ar=ar->next) + if (ar->SendRNow) + { + if (ar->resrec.InterfaceID != mDNSInterface_LocalOnly) + LogMsg("SendQueries: No active interface to send: %s", ARDisplayString(m, ar)); + ar->SendRNow = mDNSNULL; + } + + // 4b. When we have lingering cache records that we're keeping around for a few seconds in the hope + // that their interface which went away might come back again, the logic will want to send queries + // for those records, but we can't because their interface isn't here any more, so to keep the + // state machine ticking over we just pretend we did so. + // If the interface does not come back in time, the cache record will expire naturally + FORALL_CACHERECORDS(slot, cg, cr) + if (cr->CRActiveQuestion && cr->UnansweredQueries < MaxUnansweredQueries && m->timenow - cr->NextRequiredQuery >= 0) + { + cr->UnansweredQueries++; + cr->CRActiveQuestion->SendQNow = mDNSNULL; + SetNextCacheCheckTime(m, cr); + } + + // 4c. Debugging check: Make sure we sent all our planned questions + // Do this AFTER the lingering cache records check above, because that will prevent spurious warnings for questions + // we legitimately couldn't send because the interface is no longer available + for (q = m->Questions; q; q=q->next) + if (q->SendQNow) + { + LogMsg("SendQueries: No active interface to send: %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + q->SendQNow = mDNSNULL; + } } // *************************************************************************** @@ -3867,21 +2642,26 @@ mDNSlocal void SendQueries(mDNS *const m) #pragma mark - RR List Management & Task Management #endif -// NOTE: AnswerQuestionWithResourceRecord 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. -mDNSlocal void AnswerQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, CacheRecord *rr, mDNSBool AddRecord) +// NOTE: AnswerCurrentQuestionWithResourceRecord can call a user callback, which may change the record list and/or question list. +// Any code walking either list must use the m->CurrentQuestion (and possibly m->CurrentRecord) mechanism to protect against this. +// In fact, to enforce this, the routine will *only* answer the question currently pointed to by m->CurrentQuestion, +// which will be auto-advanced (possibly to NULL) if the client callback cancels the question. +mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheRecord *const rr, const QC_result AddRecord) { - verbosedebugf("AnswerQuestionWithResourceRecord:%4lu %s TTL%6lu %##s (%s)", - q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); + DNSQuestion *const q = m->CurrentQuestion; + mDNSBool followcname = rr->resrec.RecordType != kDNSRecordTypePacketNegative && AddRecord && + rr->resrec.rrtype == kDNSType_CNAME && q->qtype != kDNSType_CNAME; + verbosedebugf("AnswerCurrentQuestionWithResourceRecord:%4lu %s TTL %d %s", q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, CRDisplayString(m, rr)); - // Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerQuestionWithResourceRecord(... mDNStrue) + // Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerCurrentQuestionWithResourceRecord(... mDNStrue) // may be called twice, once when the record is received, and again when it's time to notify local clients. // If any counters or similar are added here, care must be taken to ensure that they are not double-incremented by this. rr->LastUsed = m->timenow; - if (ActiveQuestion(q) && rr->CRActiveQuestion != q) + if (AddRecord == QC_add && !q->DuplicateOf && rr->CRActiveQuestion != q) { if (!rr->CRActiveQuestion) m->rrcache_active++; // If not previously active, increment rrcache_active count + debugf("AnswerCurrentQuestionWithResourceRecord: Updating CRActiveQuestion to %p for cache record %s", q, CRDisplayString(m,rr)); rr->CRActiveQuestion = q; // We know q is non-null SetNextCacheCheckTime(m, rr); } @@ -3891,41 +2671,63 @@ mDNSlocal void AnswerQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, C // (b) a normal add, where we have at least one unique-type answer, // then there's no need to keep polling the network. // (If we have an answer in the cache, then we'll automatically ask again in time to stop it expiring.) - if ((AddRecord == 2 && !q->RequestUnicast) || - (AddRecord == 1 && (q->ExpectUnique || (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)))) - if (ActiveQuestion(q)) + // We do this for mDNS questions and uDNS one-shot questions, but not for + // uDNS LongLived questions, because that would mess up our LLQ lease renewal timing. + if ((AddRecord == QC_addnocache && !q->RequestUnicast) || + (AddRecord == QC_add && (q->ExpectUnique || (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)))) + if (ActiveQuestion(q) && (mDNSOpaque16IsZero(q->TargetQID) || !q->LongLived)) { - q->LastQTime = m->timenow; - q->LastQTxTime = m->timenow; + q->LastQTime = m->timenow; + q->LastQTxTime = m->timenow; q->RecentAnswerPkts = 0; - q->ThisQInterval = MaxQuestionInterval; - q->RequestUnicast = mDNSfalse; + q->ThisQInterval = MaxQuestionInterval; + q->RequestUnicast = mDNSfalse; } if (rr->DelayDelivery) return; // We'll come back later when CacheRecordDeferredAdd() calls us - m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback - if (q->QuestionCallback) + // Only deliver negative answers if client has explicitly requested them + if (rr->resrec.RecordType == kDNSRecordTypePacketNegative && (!AddRecord || !q->ReturnIntermed)) return; + + // For CNAME results to non-CNAME questions, only inform the client if they explicitly requested that + if (q->QuestionCallback && !q->NoAnswer && (!followcname || q->ReturnIntermed)) + { + mDNS_DropLockBeforeCallback(); // Allow client (and us) to legally make mDNS API calls q->QuestionCallback(m, q, &rr->resrec, AddRecord); - m->mDNS_reentrancy--; // Decrement to block mDNS API calls again - // CAUTION: MUST NOT do anything more with q after calling q->QuestionCallback(), because the client's callback function - // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. - // Right now the only routines that call AnswerQuestionWithResourceRecord() are CacheRecordAdd(), CacheRecordRmv() - // and AnswerNewQuestion(), and all of them use the "m->CurrentQuestion" mechanism to protect against questions - // being deleted out from under them. + mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again + } + // NOTE: Proceed with caution here because client callback function is allowed to do anything, + // including starting/stopping queries, registering/deregistering records, etc. + + if (followcname && m->CurrentQuestion == q && q->CNAMEReferrals < 10) + { + const mDNSu32 c = q->CNAMEReferrals + 1; + // Right now we just stop and re-use the existing query. If we really wanted to be 100% perfect, + // and track CNAMEs coming and going, we should really create a subbordinate query here, + // which we would subsequently cancel and retract if the CNAME referral record were removed. + // In reality this is such a corner case we'll ignore it until someone actually needs it. + LogOperation("AnswerCurrentQuestionWithResourceRecord: following CNAME referral for %s", CRDisplayString(m, rr)); + mDNS_StopQuery_internal(m, q); // Stop old query + AssignDomainName(&q->qname, &rr->resrec.rdata->u.name); // Update qname + q->qnamehash = DomainNameHashValue(&q->qname); // and namehash + mDNS_StartQuery_internal(m, q); // start new query + q->CNAMEReferrals = c; // and keep count of how many times we've done this + } } mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr) { rr->DelayDelivery = 0; // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared - if (m->CurrentQuestion) LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set"); + if (m->CurrentQuestion) + LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); m->CurrentQuestion = m->Questions; while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) { DNSQuestion *q = m->CurrentQuestion; - m->CurrentQuestion = q->next; if (ResourceRecordAnswersQuestion(&rr->resrec, q)) - AnswerQuestionWithResourceRecord(m, q, rr, mDNStrue); + AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add); + if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now + m->CurrentQuestion = q->next; } m->CurrentQuestion = mDNSNULL; } @@ -3938,10 +2740,9 @@ mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *c CacheGroup *cg = CacheGroupForName(m, slot, namehash, name); CacheRecord *rr; for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) - if (rr->resrec.namehash == namehash && SameDomainName(rr->resrec.name, name)) - if (threshhold - RRExpireTime(rr) >= 0) // If we have records about to expire within a second - if (delay - RRExpireTime(rr) < 0) // then delay until after they've been deleted - delay = RRExpireTime(rr); + if (threshhold - RRExpireTime(rr) >= 0) // If we have records about to expire within a second + if (delay - RRExpireTime(rr) < 0) // then delay until after they've been deleted + delay = RRExpireTime(rr); if (delay - start > 0) return(NonZeroTime(delay)); else return(0); } @@ -3951,29 +2752,27 @@ mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *c // the end of the question list, and m->NewQuestions will be set to indicate the first new question. // rr is a new CacheRecord just received into our cache // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique). -// NOTE: CacheRecordAdd calls AnswerQuestionWithResourceRecord which can call a user callback, +// NOTE: CacheRecordAdd calls AnswerCurrentQuestionWithResourceRecord 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. mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr) { - if (m->CurrentQuestion) LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set"); - m->CurrentQuestion = m->Questions; - while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) + DNSQuestion *q; + for (q = m->Questions; q; q=q->next) { - DNSQuestion *q = m->CurrentQuestion; - m->CurrentQuestion = q->next; if (ResourceRecordAnswersQuestion(&rr->resrec, q)) { - // If this question is one that's actively sending queries, and it's received ten answers within one second of sending the last - // query packet, then that indicates some radical network topology change, so reset its exponential backoff back to the start. - // We must be at least at the eight-second interval to do this. If we're at the four-second interval, or less, - // there's not much benefit accelerating because we will anyway send another query within a few seconds. - // The first reset query is sent out randomized over the next four seconds to reduce possible synchronization between machines. + // If this question is one that's actively sending queries, and it's received ten answers within one + // second of sending the last query packet, then that indicates some radical network topology change, + // so reset its exponential backoff back to the start. We must be at least at the eight-second interval + // to do this. If we're at the four-second interval, or less, there's not much benefit accelerating + // because we will anyway send another query within a few seconds. The first reset query is sent out + // randomized over the next four seconds to reduce possible synchronization between machines. if (q->LastAnswerPktNum != m->PktNum) { q->LastAnswerPktNum = m->PktNum; - if (ActiveQuestion(q) && ++q->RecentAnswerPkts >= 10 && - q->ThisQInterval > InitialQuestionInterval*32 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond) + if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q) && ++q->RecentAnswerPkts >= 10 && + q->ThisQInterval > InitialQuestionInterval * QuestionIntervalStep3 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond) { LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst; restarting exponential backoff sequence", q->qname.c, DNSTypeName(q->qtype)); @@ -3982,7 +2781,8 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr) SetNextQueryTime(m,q); } } - verbosedebugf("CacheRecordAdd %p %##s (%s) %lu", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl); + verbosedebugf("CacheRecordAdd %p %##s (%s) %lu", + rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl); q->CurrentAnswers++; if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++; if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++; @@ -3992,14 +2792,28 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr) if (msgcount++ < 10) LogMsg("CacheRecordAdd: %##s (%s) has %d answers; shedding records to resist DOS attack", q->qname.c, DNSTypeName(q->qtype), q->CurrentAnswers); - rr->resrec.rroriginalttl = 1; + rr->resrec.rroriginalttl = 0; rr->UnansweredQueries = MaxUnansweredQueries; } - AnswerQuestionWithResourceRecord(m, q, rr, mDNStrue); - // MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord() } } - m->CurrentQuestion = mDNSNULL; + + if (!rr->DelayDelivery) + { + if (m->CurrentQuestion) + LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); + m->CurrentQuestion = m->Questions; + while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) + { + DNSQuestion *q = m->CurrentQuestion; + if (ResourceRecordAnswersQuestion(&rr->resrec, q)) + AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add); + if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now + m->CurrentQuestion = q->next; + } + m->CurrentQuestion = mDNSNULL; + } + SetNextCacheCheckTime(m, rr); } @@ -4010,21 +2824,22 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr) // but we don't have any place to cache it. We'll deliver question 'add' events now, but we won't have any // way to deliver 'remove' events in future, nor will we be able to include this in known-answer lists, // so we immediately bump ThisQInterval up to MaxQuestionInterval to avoid pounding the network. -// NOTE: NoCacheAnswer calls AnswerQuestionWithResourceRecord which can call a user callback, +// NOTE: NoCacheAnswer calls AnswerCurrentQuestionWithResourceRecord 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. mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr) { LogMsg("No cache space: Delivering non-cached result for %##s", m->rec.r.resrec.name->c); - if (m->CurrentQuestion) LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set"); + if (m->CurrentQuestion) + LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); m->CurrentQuestion = m->Questions; while (m->CurrentQuestion) { DNSQuestion *q = m->CurrentQuestion; - m->CurrentQuestion = q->next; if (ResourceRecordAnswersQuestion(&rr->resrec, q)) - AnswerQuestionWithResourceRecord(m, q, rr, 2); // Value '2' indicates "don't expect 'remove' events for this" - // MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord() + AnswerCurrentQuestionWithResourceRecord(m, rr, QC_addnocache); // QC_addnocache means "don't expect remove events for this" + if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now + m->CurrentQuestion = q->next; } m->CurrentQuestion = mDNSNULL; } @@ -4034,43 +2849,51 @@ mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr) // the end of the question list, and m->NewQuestions will be set to indicate the first new question. // rr is an existing cache CacheRecord that just expired and is being deleted // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique). -// NOTE: CacheRecordRmv calls AnswerQuestionWithResourceRecord which can call a user callback, +// NOTE: CacheRecordRmv calls AnswerCurrentQuestionWithResourceRecord 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. mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr) { - if (m->CurrentQuestion) LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set"); + if (m->CurrentQuestion) + LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); m->CurrentQuestion = m->Questions; while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions) { DNSQuestion *q = m->CurrentQuestion; - m->CurrentQuestion = q->next; if (ResourceRecordAnswersQuestion(&rr->resrec, q)) { verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr)); + q->FlappingInterface1 = mDNSNULL; + q->FlappingInterface2 = mDNSNULL; if (q->CurrentAnswers == 0) - LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?", q, q->qname.c, DNSTypeName(q->qtype)); + LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?", + q, q->qname.c, DNSTypeName(q->qtype)); else { q->CurrentAnswers--; if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--; if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--; } - if (q->CurrentAnswers == 0) + if (rr->resrec.rdata->MaxRDLength) // Never generate "remove" events for negative results { - debugf("CacheRecordRmv: Zero current answers for %##s (%s); will reconfirm antecedents", q->qname.c, DNSTypeName(q->qtype)); - ReconfirmAntecedents(m, q); + if (q->CurrentAnswers == 0) + { + LogOperation("CacheRecordRmv: Last answer for %##s (%s) expired from cache; will reconfirm antecedents", + q->qname.c, DNSTypeName(q->qtype)); + ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0); + } + AnswerCurrentQuestionWithResourceRecord(m, rr, QC_rmv); } - AnswerQuestionWithResourceRecord(m, q, rr, mDNSfalse); - // MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord() } + if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now + m->CurrentQuestion = q->next; } m->CurrentQuestion = mDNSNULL; } mDNSlocal void ReleaseCacheEntity(mDNS *const m, CacheEntity *e) { -#if MACOSX_MDNS_MALLOC_DEBUGGING >= 1 +#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1 unsigned int i; for (i=0; iname->c, (*cp)->name->c); - if ((*cp)->rrcache_tail != &(*cp)->members) LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)"); - //if ((*cp)->name != (domainname*)((*cp)->namestorage)) LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage)); + //LogMsg("ReleaseCacheGroup: Releasing CacheGroup for %p, %##s", (*cp)->name->c, (*cp)->name->c); + if ((*cp)->rrcache_tail != &(*cp)->members) + LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)"); + //if ((*cp)->name != (domainname*)((*cp)->namestorage)) + // LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage)); if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name); (*cp)->name = mDNSNULL; *cp = (*cp)->next; // Cut record from list @@ -4093,14 +2918,16 @@ mDNSlocal void ReleaseCacheGroup(mDNS *const m, CacheGroup **cp) mDNSlocal void ReleaseCacheRecord(mDNS *const m, CacheRecord *r) { + //LogMsg("ReleaseCacheRecord: Releasing %s", CRDisplayString(m, r)); if (r->resrec.rdata && r->resrec.rdata != (RData*)&r->rdatastorage) mDNSPlatformMemFree(r->resrec.rdata); r->resrec.rdata = mDNSNULL; ReleaseCacheEntity(m, (CacheEntity *)r); } -// Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering CacheRecordDeferredAdd calls -// The in-order nature of the cache lists ensures that all callbacks for old records are delivered before callbacks for newer records -mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *cg) +// Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering +// CacheRecordDeferredAdd calls. The in-order nature of the cache lists ensures that all +// callbacks for old records are delivered before callbacks for newer records. +mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *const cg) { CacheRecord **rp = &cg->members; @@ -4114,7 +2941,8 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *cg) if (m->timenow - event >= 0) // If expired, delete it { *rp = rr->next; // Cut it from the list - verbosedebugf("CheckCacheExpiration: Deleting %s", CRDisplayString(m, rr)); + verbosedebugf("CheckCacheExpiration: Deleting%7d %4d %p %s", + m->timenow - rr->TimeRcvd, rr->resrec.rroriginalttl, rr->CRActiveQuestion, CRDisplayString(m, rr)); if (rr->CRActiveQuestion) // If this record has one or more active questions, tell them it's going away { CacheRecordRmv(m, rr); @@ -4139,11 +2967,13 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *cg) // SendQueries() will see that we have records close to expiration, and send FEQs for them. m->NextScheduledQuery = m->timenow; // After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTime(), - // which will correctly update m->NextCacheCheck for us + // which will correctly update m->NextCacheCheck for us. event = m->timenow + 0x3FFFFFFF; } } } + verbosedebugf("CheckCacheExpiration:%6d %5d %s", + (event - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m, rr)); if (m->NextCacheCheck - (event + CacheCheckGracePeriod(rr)) > 0) m->NextCacheCheck = (event + CacheCheckGracePeriod(rr)); rp = &rr->next; @@ -4160,7 +2990,7 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m) CacheRecord *rr; DNSQuestion *q = m->NewQuestions; // Grab the question we're going to answer const mDNSu32 slot = HashSlot(&q->qname); - CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); + CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); @@ -4170,15 +3000,28 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m) if (m->lock_rrcache) LogMsg("AnswerNewQuestion ERROR! Cache already locked!"); // This should be safe, because calling the client's question callback may cause the // question list to be modified, but should not ever cause the rrcache list to be modified. - // If the client's question callback deletes the question, then m->CurrentQuestion will + // If the client's question callback deletes the question, then m->CurrentQuestion will // be advanced, and we'll exit out of the loop m->lock_rrcache = 1; - if (m->CurrentQuestion) LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set"); + if (m->CurrentQuestion) + LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted - if (q->InterfaceID == mDNSInterface_Any) // If 'mDNSInterface_Any' question, see if we want to tell it about LocalOnly records + if (q->NoAnswer == NoAnswer_Fail) + { + LogMsg("AnswerNewQuestion: NoAnswer_Fail %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + MakeNegativeCacheRecord(m, &q->qname, q->qnamehash, q->qtype, q->qclass, 60); + q->NoAnswer = NoAnswer_Normal; // Temporarily turn off answer suppression + AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache); + q->NoAnswer = NoAnswer_Fail; // Restore NoAnswer state + m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it + } + + // If 'mDNSInterface_Any' question, see if we want to tell it about LocalOnly records + if (m->CurrentQuestion == q && q->InterfaceID == mDNSInterface_Any) { - if (m->CurrentRecord) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set"); + if (m->CurrentRecord) + LogMsg("AnswerNewQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); m->CurrentRecord = m->ResourceRecords; while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords) { @@ -4188,52 +3031,62 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m) if (ResourceRecordAnswersQuestion(&rr->resrec, q)) { AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, mDNStrue); - // MUST NOT dereference q again after calling AnswerLocalOnlyQuestionWithResourceRecord() if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here } } - m->CurrentRecord = mDNSNULL; + m->CurrentRecord = mDNSNULL; } - for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) - if (ResourceRecordAnswersQuestion(&rr->resrec, q)) - { - // SecsSinceRcvd is whole number of elapsed seconds, rounded down - mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond; - if (rr->resrec.rroriginalttl <= SecsSinceRcvd) + if (m->CurrentQuestion == q) + { + for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) + if (SameNameRecordAnswersQuestion(&rr->resrec, q)) { - LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %##s (%s)", - rr->resrec.rroriginalttl, SecsSinceRcvd, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); - continue; // Go to next one in loop + // SecsSinceRcvd is whole number of elapsed seconds, rounded down + mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond; + if (rr->resrec.rroriginalttl <= SecsSinceRcvd) + { + LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %##s (%s) %d %d", + rr->resrec.rroriginalttl, SecsSinceRcvd, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), m->timenow, rr->TimeRcvd); + continue; // Go to next one in loop + } + + // If this record set is marked unique, then that means we can reasonably assume we have the whole set + // -- we don't need to rush out on the network and query immediately to see if there are more answers out there + if ((rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique)) + ShouldQueryImmediately = mDNSfalse; + q->CurrentAnswers++; + if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++; + if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++; + AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add); + if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here } + else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype)) + if (rr->resrec.namehash == q->qnamehash && SameDomainName(rr->resrec.name, &q->qname)) + ShouldQueryImmediately = mDNSfalse; + } - // If this record set is marked unique, then that means we can reasonably assume we have the whole set - // -- we don't need to rush out on the network and query immediately to see if there are more answers out there - if ((rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique)) - ShouldQueryImmediately = mDNSfalse; - q->CurrentAnswers++; - if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++; - if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++; - AnswerQuestionWithResourceRecord(m, q, rr, mDNStrue); - // MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord() - if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here - } - else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype)) - if (rr->resrec.namehash == q->qnamehash && SameDomainName(rr->resrec.name, &q->qname)) - ShouldQueryImmediately = mDNSfalse; - - if (ShouldQueryImmediately && m->CurrentQuestion == q) + if (m->CurrentQuestion == q && ShouldQueryImmediately && ActiveQuestion(q)) { q->ThisQInterval = InitialQuestionInterval; q->LastQTime = m->timenow - q->ThisQInterval; + if (mDNSOpaque16IsZero(q->TargetQID)) + { + // Compute random delay in the range 1-6 seconds, then divide by 50 to get 20-120ms + if (!m->RandomQueryDelay) + m->RandomQueryDelay = (mDNSPlatformOneSecond + mDNSRandom(mDNSPlatformOneSecond*5) - 1) / 50 + 1; + q->LastQTime += m->RandomQueryDelay; + } + m->NextScheduledQuery = m->timenow; } + m->CurrentQuestion = mDNSNULL; m->lock_rrcache = 0; } -// When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any appropriate answers, -// stopping if it reaches a NewLocalRecord -- these will be handled by AnswerLocalQuestions +// When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any +// appropriate answers, stopping if it reaches a NewLocalRecord -- these will be handled by AnswerLocalQuestions mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m) { DNSQuestion *q = m->NewLocalOnlyQuestions; // Grab the question we're going to answer @@ -4241,11 +3094,14 @@ mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m) debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); - if (m->CurrentQuestion) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set"); + if (m->CurrentQuestion) + LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted - if (m->CurrentRecord) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set"); + if (m->CurrentRecord) + LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); m->CurrentRecord = m->ResourceRecords; + while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords) { AuthRecord *rr = m->CurrentRecord; @@ -4253,7 +3109,6 @@ mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m) if (ResourceRecordAnswersQuestion(&rr->resrec, q)) { AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, mDNStrue); - // MUST NOT dereference q again after calling AnswerLocalOnlyQuestionWithResourceRecord() if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here } } @@ -4278,16 +3133,17 @@ mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const Pre // We don't want to be vulnerable to a malicious attacker flooding us with an infinite // number of bogus records so that we keep growing our cache until the machine runs out of memory. - // To guard against this, if we're actively using less than 1/32 of our cache, then we - // purge all the unused records and recycle them, instead of allocating more memory. - if (m->rrcache_size >= 512 && m->rrcache_size / 32 > m->rrcache_active) - debugf("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu", + // To guard against this, if our cache grows above 512kB (approx 3168 records at 164 bytes each), + // and we're actively using less than 1/32 of that cache, then we purge all the unused records + // and recycle them, instead of allocating more memory. + if (m->rrcache_size > 3000 && m->rrcache_size / 32 > m->rrcache_active) + LogOperation("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu", m->rrcache_size, m->rrcache_active); else { - m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback + mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback m->MainCallback(m, mStatus_GrowCache); - m->mDNS_reentrancy--; // Decrement to block mDNS API calls again + mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again } } @@ -4295,7 +3151,7 @@ mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const Pre // Enumerating the entire cache is moderately expensive, so when we do it, we reclaim all the records we can in one pass. if (!m->rrcache_free) { - #if MDNS_DEBUGMSGS + #if LogAllOperations || MDNS_DEBUGMSGS mDNSu32 oldtotalused = m->rrcache_totalused; #endif mDNSu32 slot; @@ -4318,15 +3174,15 @@ mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const Pre ReleaseCacheRecord(m, rr); } } - if ((*cp)->rrcache_tail != rp) verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot, (*cp)->rrcache_tail, rp); + if ((*cp)->rrcache_tail != rp) + verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot, (*cp)->rrcache_tail, rp); (*cp)->rrcache_tail = rp; if ((*cp)->members || (*cp)==PreserveCG) cp=&(*cp)->next; else ReleaseCacheGroup(m, cp); } } - #if MDNS_DEBUGMSGS - debugf("Clear unused records; m->rrcache_totalused was %lu; now %lu", oldtotalused, m->rrcache_totalused); - #endif + LogOperation("GetCacheEntity recycled %d records to reduce cache from %d to %d", + oldtotalused - m->rrcache_totalused, oldtotalused, m->rrcache_totalused); } if (m->rrcache_free) // If there are records in the free list, take one @@ -4335,7 +3191,7 @@ mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const Pre m->rrcache_free = e->next; if (++m->rrcache_totalused >= m->rrcache_report) { - debugf("RR Cache now using %ld objects", m->rrcache_totalused); + LogOperation("RR Cache now using %ld objects", m->rrcache_totalused); if (m->rrcache_report < 100) m->rrcache_report += 10; else m->rrcache_report += 100; } @@ -4373,7 +3229,8 @@ mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const Res cg->members = mDNSNULL; cg->rrcache_tail = &cg->members; cg->name = (domainname*)cg->namestorage; - //LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s", (namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c); + //LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s", + // (namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c); if (namelen > InlineCacheGroupNameSize) cg->name = mDNSPlatformMemAllocate(namelen); if (!cg->name) { @@ -4390,7 +3247,7 @@ mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const Res return(cg); } -mDNSlocal void PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr) +mDNSexport void mDNS_PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr) { // Make sure we mark this record as thoroughly expired -- we don't ever want to give // a positive answer using an expired record (e.g. from an interface that has gone away). @@ -4428,7 +3285,8 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m) int i; verbosedebugf("mDNS_Execute"); - if (m->CurrentQuestion) LogMsg("mDNS_Execute: ERROR! m->CurrentQuestion already set"); + if (m->CurrentQuestion) + LogMsg("mDNS_Execute: ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); // 1. If we're past the probe suppression time, we can clear it if (m->SuppressProbes && m->timenow - m->SuppressProbes >= 0) m->SuppressProbes = 0; @@ -4478,22 +3336,28 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m) { // If the platform code is ready, and we're not suppressing packet generation right now // then send our responses, probes, and questions. - // We check the cache first, because there might be records close to expiring that trigger questions to refresh them + // We check the cache first, because there might be records close to expiring that trigger questions to refresh them. // We send queries next, because there might be final-stage probes that complete their probing here, causing // them to advance to announcing state, and we want those to be included in any announcements we send out. - // Finally, we send responses, including the previously mentioned records that just completed probing + // Finally, we send responses, including the previously mentioned records that just completed probing. m->SuppressSending = 0; // 6. Send Query packets. This may cause some probing records to advance to announcing state if (m->timenow - m->NextScheduledQuery >= 0 || m->timenow - m->NextScheduledProbe >= 0) SendQueries(m); if (m->timenow - m->NextScheduledQuery >= 0) { - LogMsg("mDNS_Execute: SendQueries didn't send all its queries; will try again in one second"); + DNSQuestion *q; + LogMsg("mDNS_Execute: SendQueries didn't send all its queries (%d - %d = %d) will try again in one second", + m->timenow, m->NextScheduledQuery, m->timenow - m->NextScheduledQuery); m->NextScheduledQuery = m->timenow + mDNSPlatformOneSecond; + for (q = m->Questions; q; q=q->next) + if (ActiveQuestion(q) && q->LastQTime + q->ThisQInterval - m->timenow <= 0) + LogMsg("mDNS_Execute: SendQueries didn't send %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); } if (m->timenow - m->NextScheduledProbe >= 0) { - LogMsg("mDNS_Execute: SendQueries didn't send all its probes; will try again in one second"); + LogMsg("mDNS_Execute: SendQueries didn't send all its probes (%d - %d = %d) will try again in one second", + m->timenow, m->NextScheduledProbe, m->timenow - m->NextScheduledProbe); m->NextScheduledProbe = m->timenow + mDNSPlatformOneSecond; } @@ -4506,7 +3370,9 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m) } } - m->RandomQueryDelay = 0; // Clear m->RandomQueryDelay, ready to pick a new different value, when necessary + // Clear RandomDelay values, ready to pick a new different value next time + m->RandomQueryDelay = 0; + m->RandomReconfirmDelay = 0; } // Note about multi-threaded systems: @@ -4560,7 +3426,7 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate) { #ifndef UNICAST_DISABLED uDNS_Sleep(m); -#endif +#endif // Mark all the records we need to deregister and send them for (rr = m->ResourceRecords; rr; rr=rr->next) if (rr->resrec.RecordType == kDNSRecordTypeShared && rr->RequireGoodbye) @@ -4579,7 +3445,7 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate) #endif // 1. Retrigger all our questions for (q = m->Questions; q; q=q->next) // Scan our list of questions - if (ActiveQuestion(q)) + if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q)) { q->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it @@ -4592,7 +3458,7 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate) // 2. Re-validate our cache records m->NextCacheCheck = m->timenow; FORALL_CACHERECORDS(slot, cg, cr) - mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForCableDisconnect); + mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForWake); // 3. Retrigger probing and announcing for all our authoritative records for (rr = m->ResourceRecords; rr; rr=rr->next) @@ -4806,10 +3672,10 @@ mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const q if (!result) result = (int)our->resrec.rrtype - (int)m->rec.r.resrec.rrtype; if (!result) result = CompareRData(our, &m->rec.r); if (result > 0) - debugf("ResolveSimultaneousProbe: %##s (%s): We won", our->resrec.name->c, DNSTypeName(our->resrec.rrtype)); + LogOperation("ResolveSimultaneousProbe: %##s (%s): We won", our->resrec.name->c, DNSTypeName(our->resrec.rrtype)); else if (result < 0) { - debugf("ResolveSimultaneousProbe: %##s (%s): We lost", our->resrec.name->c, DNSTypeName(our->resrec.rrtype)); + LogOperation("ResolveSimultaneousProbe: %##s (%s): We lost", our->resrec.name->c, DNSTypeName(our->resrec.rrtype)); mDNS_Deregister_internal(m, our, mDNS_Dereg_conflict); goto exit; } @@ -4818,7 +3684,7 @@ mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const q m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it } if (!FoundUpdate) - debugf("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our->resrec.name->c, DNSTypeName(our->resrec.rrtype)); + LogOperation("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our->resrec.name->c, DNSTypeName(our->resrec.rrtype)); exit: m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it } @@ -4829,16 +3695,16 @@ mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, ResourceR CacheGroup *cg = CacheGroupForRecord(m, slot, pktrr); CacheRecord *rr; for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) - if (pktrr->InterfaceID == rr->resrec.InterfaceID && IdenticalResourceRecord(pktrr, &rr->resrec)) break; + if (pktrr->InterfaceID == rr->resrec.InterfaceID && IdenticalSameNameRecord(pktrr, &rr->resrec)) break; return(rr); } // ProcessQuery examines a received query to see if we have any answers to give mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end, - const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, mDNSBool QueryWasMulticast, mDNSBool QueryWasLocalUnicast, - DNSMessage *const response) + const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, mDNSBool QueryWasMulticast, + mDNSBool QueryWasLocalUnicast, DNSMessage *const response) { - mDNSBool FromLocalSubnet = AddressIsLocalSubnet(m, InterfaceID, srcaddr); + mDNSBool FromLocalSubnet = srcaddr && AddressIsLocalSubnet(m, InterfaceID, srcaddr); AuthRecord *ResponseRecords = mDNSNULL; AuthRecord **nrp = &ResponseRecords; CacheRecord *ExpectedAnswers = mDNSNULL; // Records in our cache we expect to see updated @@ -4881,7 +3747,8 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con // Also note: we just mark potential answer records here, without trying to build the // "ResponseRecords" list, because we don't want to risk user callbacks deleting records // from that list while we're in the middle of trying to build it. - if (m->CurrentRecord) LogMsg("ProcessQuery ERROR m->CurrentRecord already set"); + if (m->CurrentRecord) + LogMsg("ProcessQuery ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); m->CurrentRecord = m->ResourceRecords; while (m->CurrentRecord) { @@ -4931,7 +3798,7 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con // 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 for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) - if (ResourceRecordAnswersQuestion(&rr->resrec, &pktq) && rr->resrec.rdlength <= SmallRecordLimit) + if (SameNameRecordAnswersQuestion(&rr->resrec, &pktq) && rr->resrec.rdlength <= SmallRecordLimit) if (!rr->NextInKAList && eap != &rr->NextInKAList) { *eap = rr; @@ -4956,7 +3823,9 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con if (!q->Target.type && ActiveQuestion(q) && m->timenow - q->LastQTxTime > mDNSPlatformOneSecond / 4) if (!q->InterfaceID || q->InterfaceID == InterfaceID) if (q->NextInDQList == mDNSNULL && dqp != &q->NextInDQList) - if (q->qtype == pktq.qtype && q->qclass == pktq.qclass && q->qnamehash == pktq.qnamehash && SameDomainName(&q->qname, &pktq.qname)) + if (q->qtype == pktq.qtype && + q->qclass == pktq.qclass && + q->qnamehash == pktq.qnamehash && SameDomainName(&q->qname, &pktq.qname)) { *dqp = q; dqp = &q->NextInDQList; } } } @@ -5258,11 +4127,13 @@ mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg, const mDNSInterfaceID InterfaceID) { mDNSu8 *responseend = mDNSNULL; - mDNSBool QueryWasLocalUnicast = !mDNSAddrIsDNSMulticast(dstaddr) && AddressIsLocalSubnet(m, InterfaceID, srcaddr); + mDNSBool QueryWasLocalUnicast = srcaddr && dstaddr && + !mDNSAddrIsDNSMulticast(dstaddr) && AddressIsLocalSubnet(m, InterfaceID, srcaddr); - if (!InterfaceID && mDNSAddrIsDNSMulticast(dstaddr)) + if (!InterfaceID && dstaddr && mDNSAddrIsDNSMulticast(dstaddr)) { - LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with %2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s (Multicast, but no InterfaceID)", + LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with " + "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s (Multicast, but no InterfaceID)", srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID, msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,", msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,", @@ -5270,8 +4141,9 @@ mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg, msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s"); return; } - - verbosedebugf("Received Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with %2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s", + + verbosedebugf("Received Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with " + "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s", srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID, msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,", msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,", @@ -5279,7 +4151,7 @@ mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg, msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s"); responseend = ProcessQuery(m, msg, end, srcaddr, InterfaceID, - (srcport.NotAnInteger != MulticastDNSPort.NotAnInteger), mDNSAddrIsDNSMulticast(dstaddr), QueryWasLocalUnicast, &m->omsg); + !mDNSSameIPPort(srcport, MulticastDNSPort), mDNSAddrIsDNSMulticast(dstaddr), QueryWasLocalUnicast, &m->omsg); if (responseend) // If responseend is non-null, that means we built a unicast response packet { @@ -5288,8 +4160,175 @@ mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg, m->omsg.h.numAnswers, m->omsg.h.numAnswers == 1 ? "" : "s", m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s", srcaddr, mDNSVal16(srcport), InterfaceID, srcaddr->type); - mDNSSendDNSMessage(m, &m->omsg, responseend, InterfaceID, srcaddr, srcport, -1, mDNSNULL); + mDNSSendDNSMessage(m, &m->omsg, responseend, InterfaceID, srcaddr, srcport, mDNSNULL, mDNSNULL); + } + } + +mDNSlocal mDNSBool TrustedSource(const mDNS *const m, const mDNSAddr *const srcaddr) + { + DNSServer *s; + (void)m; // Unused + (void)srcaddr; // Unused + for (s = m->DNSServers; s; s = s->next) + if (mDNSSameAddress(srcaddr, &s->addr)) return(mDNStrue); + return(mDNSfalse); + } + +mDNSlocal const DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m, const mDNSOpaque16 id, const DNSQuestion *const question) + { + DNSQuestion *q; + for (q = m->Questions; q; q=q->next) + if (mDNSSameOpaque16(q->TargetQID, id) && + q->qtype == question->qtype && + q->qclass == question->qclass && + q->qnamehash == question->qnamehash && + SameDomainName(&q->qname, &question->qname)) + return(q); + return(mDNSNULL); + } + +mDNSlocal mDNSBool ExpectingUnicastResponseForRecord(mDNS *const m, const mDNSAddr *const srcaddr, const mDNSBool SrcLocal, const mDNSOpaque16 id, const CacheRecord *const rr) + { + DNSQuestion *q; + (void)id; + for (q = m->Questions; q; q=q->next) + if (ResourceRecordAnswersQuestion(&rr->resrec, q)) + { + if (!mDNSOpaque16IsZero(q->TargetQID)) + { + // For now we don't do this check -- for LLQ updates, the ID doesn't seem to match the ID in the question + // if (mDNSSameOpaque16(q->TargetQID, id) + { + if (mDNSSameAddress(srcaddr, &q->Target)) return(mDNStrue); + if (mDNSSameOpaque16(q->TargetQID, id)) return(mDNStrue); + // if (q->LongLived && mDNSSameAddress(srcaddr, &q->servAddr)) return(mDNStrue); Shouldn't need this now that we have LLQType checking + if (TrustedSource(m, srcaddr)) return(mDNStrue); + LogOperation("WARNING: Ignoring suspect uDNS response for %##s (%s) %#a from %#a: %s", + q->qname.c, DNSTypeName(q->qtype), &q->Target, srcaddr, CRDisplayString(m, rr)); + return(mDNSfalse); + } + } + else + { + if (SrcLocal && q->ExpectUnicastResp && (mDNSu32)(m->timenow - q->ExpectUnicastResp) < (mDNSu32)(mDNSPlatformOneSecond*2)) + return(mDNStrue); + } + } + return(mDNSfalse); + } + +mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, CacheGroup *cg) + { + CacheRecord *rr = mDNSNULL; + + // Certain data types need more space for in-memory storage than their in-packet rdlength would imply + // Currently this applies only to rdata types containing more than one domainname, + // or types where the domainname is not the last item in the structure + mDNSu16 RDLength; + switch (m->rec.r.resrec.rrtype) + { + case kDNSType_SOA: RDLength = sizeof(rdataSOA); break; + case kDNSType_RP: RDLength = sizeof(rdataRP); break; + case kDNSType_PX: RDLength = sizeof(rdataPX); break; + default: RDLength = m->rec.r.resrec.rdlength; break; + } + + //if (RDLength > InlineCacheRDSize) + // LogOperation("Rdata len %4d > InlineCacheRDSize %d %s", RDLength, InlineCacheRDSize, CRDisplayString(m, &m->rec.r)); + + if (!cg) cg = GetCacheGroup(m, slot, &m->rec.r.resrec); // If we don't have a CacheGroup for this name, make one now + if (cg) rr = GetCacheRecord(m, cg, RDLength); // Make a cache record, being careful not to recycle cg + if (!rr) NoCacheAnswer(m, &m->rec.r); + else + { + RData *saveptr = rr->resrec.rdata; // Save the rr->resrec.rdata pointer + *rr = m->rec.r; // Block copy the CacheRecord object + rr->resrec.rdata = saveptr; // Restore rr->resrec.rdata after the structure assignment + rr->resrec.name = cg->name; // And set rr->resrec.name to point into our CacheGroup header + + // If this is an oversized record with external storage allocated, copy rdata to external storage + if (rr->resrec.rdata == (RData*)&rr->rdatastorage && RDLength > InlineCacheRDSize) + LogMsg("rr->resrec.rdata == &rr->rdatastorage but length > InlineCacheRDSize %##s", m->rec.r.resrec.name->c); + else if (rr->resrec.rdata != (RData*)&rr->rdatastorage && RDLength <= InlineCacheRDSize) + LogMsg("rr->resrec.rdata != &rr->rdatastorage but length <= InlineCacheRDSize %##s", m->rec.r.resrec.name->c); + if (RDLength > InlineCacheRDSize) + mDNSPlatformMemCopy(rr->resrec.rdata, m->rec.r.resrec.rdata, sizeofRDataHeader + RDLength); + + rr->next = mDNSNULL; // Clear 'next' pointer + *(cg->rrcache_tail) = rr; // Append this record to tail of cache slot list + cg->rrcache_tail = &(rr->next); // Advance tail pointer + if (rr->resrec.RecordType == kDNSRecordTypePacketNegative) + rr->DelayDelivery = NonZeroTime(m->timenow); + else if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask && // If marked unique, + rr->resrec.rdata->MaxRDLength != 0) // and non-negative, assume we may have + rr->DelayDelivery = NonZeroTime(m->timenow + mDNSPlatformOneSecond); // to delay delivery of this 'add' event + else + rr->DelayDelivery = CheckForSoonToExpireRecords(m, rr->resrec.name, rr->resrec.namehash, slot); + + CacheRecordAdd(m, rr); // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us + } + return(rr); + } + +mDNSlocal void RefreshCacheRecord(mDNS *const m, CacheRecord *rr, mDNSu32 ttl) + { + rr->TimeRcvd = m->timenow; + rr->resrec.rroriginalttl = ttl; + rr->UnansweredQueries = 0; + rr->MPUnansweredQ = 0; + rr->MPUnansweredKA = 0; + rr->MPExpectingKA = mDNSfalse; + SetNextCacheCheckTime(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); + for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) + if (rr->CRActiveQuestion == q) + { + //LogOperation("GrantCacheExtensions: new lease %d / %s", lease, CRDisplayString(m, rr)); + RefreshCacheRecord(m, rr, lease); + } + } + +mDNSlocal mDNSu32 GetEffectiveTTL(const uDNS_LLQType LLQType, mDNSu32 ttl) // TTL in seconds + { + if (LLQType == uDNS_LLQ_Poll) ttl = LLQ_POLL_INTERVAL * 2 / mDNSPlatformOneSecond; + else if (LLQType == uDNS_LLQ_Setup) ttl = kLLQ_DefLease; + else if (LLQType == uDNS_LLQ_Events) + { + // If the TTL is -1 for uDNS LLQ event packet, that means "remove" + if (ttl == 0xFFFFFFFF) ttl = 0; + else ttl = kLLQ_DefLease; + } + else // else not LLQ (standard uDNS response) + { + // The TTL is already capped to a maximum value in GetLargeResourceRecord, but just to be extra safe we + // also do this check here to make sure we can't get integer overflow below + if (ttl > 0x8000000UL) ttl = 0x8000000UL; + + // Adjustment factor to avoid race condition: + // Suppose real record as TTL of 3600, and our local caching server has held it for 3500 seconds, so it returns an aged TTL of 100. + // If we do our normal refresh at 80% of the TTL, our local caching server will return 20 seconds, so we'll do another + // 80% refresh after 16 seconds, and then the server will return 4 seconds, and so on, in the fashion of Zeno's paradox. + // To avoid this, we extend the record's effective TTL to give it a little extra grace period. + // We adjust the 100 second TTL to 126. This means that when we do our 80% query at 101 seconds, + // the cached copy at our local caching server will already have expired, so the server will be forced + // to fetch a fresh copy from the authoritative server, and then return a fresh record with the full TTL of 3600 seconds. + ttl += ttl/4 + 2; + + // For mDNS, TTL zero means "delete this record" + // For uDNS, TTL zero means: this data is true at this moment, but don't cache it. + // For the sake of network efficiency, we impose a minimum effective TTL of 15 seconds. + // If we allow a TTL of less than 2 seconds things really break (e.g. we end up making a negative cache entry). + // In the future we may want to revisit this and consider properly supporting non-cached (TTL=0) uDNS answers. + if (ttl < 15) ttl = 15; } + + return ttl; } // NOTE: mDNSCoreReceiveResponse calls mDNS_Deregister_internal which can call a user callback, which may change @@ -5301,9 +4340,9 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, const mDNSInterfaceID InterfaceID) { int i; - - // We ignore questions (if any) in a DNS response packet - const mDNSu8 *ptr = LocateAnswers(response, end); + mDNSBool ResponseMCast = dstaddr && mDNSAddrIsDNSMulticast(dstaddr); + mDNSBool ResponseSrcLocal = !srcaddr || AddressIsLocalSubnet(m, InterfaceID, srcaddr); + uDNS_LLQType LLQType = uDNS_recvLLQResponse(m, response, end, srcaddr, srcport); // "(CacheRecord*)1" is a special (non-zero) end-of-list marker // We use this non-zero marker so that records in our CacheFlushRecords list will always have NextInCFList @@ -5315,115 +4354,174 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, // to guard against spoof responses, then the only credible protection against that is cryptographic // security, e.g. DNSSEC., not worring about which section in the spoof packet contained the record int totalrecords = response->h.numAnswers + response->h.numAuthorities + response->h.numAdditionals; + const mDNSu8 *ptr = response->data; - (void)srcaddr; // Currently used only for display in debugging message + // Currently used only for display in debugging message (void)srcport; (void)dstport; - verbosedebugf("Received Response from %#-15a addressed to %#-15a on %p with %2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s", + debugf("Received Response from %#-15a addressed to %#-15a on %p with " + "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s LLQType %d", srcaddr, dstaddr, InterfaceID, response->h.numQuestions, response->h.numQuestions == 1 ? ", " : "s,", response->h.numAnswers, response->h.numAnswers == 1 ? ", " : "s,", response->h.numAuthorities, response->h.numAuthorities == 1 ? "y, " : "ies,", - response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s"); - - // If we get a unicast response when we weren't expecting one, then we assume it is someone trying to spoof us - if (!mDNSAddrIsDNSMulticast(dstaddr)) + response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s", LLQType); + + // 1. We ignore questions (if any) in mDNS response packets + // 2. If this is an LLQ response, we handle it much the same + // 3. If we get a uDNS UDP response with the TC (truncated) bit set, then we can't treat this + // answer as being the authoritative complete RRSet, and respond by deleting all other + // matching cache records that don't appear in this packet. + // Otherwise, this is a authoritative uDNS answer, so arrange for any stale records to be purged + if (ResponseMCast || LLQType == uDNS_LLQ_Events || (response->h.flags.b[0] & kDNSFlag0_TC)) + ptr = LocateAnswers(response, end); + // Otherwise, for one-shot queries, any answers in our cache that are not also contained + // in this response packet are immediately deemed to be invalid. + else { - if (!AddressIsLocalSubnet(m, InterfaceID, srcaddr) || (mDNSu32)(m->timenow - m->ExpectUnicastResponse) > (mDNSu32)(mDNSPlatformOneSecond*2)) - return; - // For now we don't put standard wide-area unicast responses in our main cache - // (Later we should fix this and cache all known results in a unified manner.) - if (response->h.id.NotAnInteger != 0 || srcport.NotAnInteger != MulticastDNSPort.NotAnInteger) - return; + // We could possibly combine this with the similar loop at the end of this function -- + // instead of tagging cache records here and then rescuing them if we find them in the answer section, + // we could instead use the "m->PktNum" mechanism to tag each cache record with the packet number in + // which it was received (or refreshed), and then at the end if we find any cache records which + // answer questions in this packet's question section, but which aren't tagged with this packet's + // packet number, then we deduce they are old and delete them + for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++) + { + DNSQuestion q; + ptr = getQuestion(response, ptr, end, InterfaceID, &q); + if (ptr && ExpectingUnicastResponseForQuestion(m, response->h.id, &q)) + { + CacheRecord *rr; + const mDNSu32 slot = HashSlot(&q.qname); + CacheGroup *cg = CacheGroupForName(m, slot, q.qnamehash, &q.qname); + for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) + if (SameNameRecordAnswersQuestion(&rr->resrec, &q)) + { + //LogMsg("uDNS Q for %s", CRDisplayString(m, rr)); + // Don't want to disturb rroriginalttl here, because code below might need it for the exponential backoff doubling algorithm + rr->TimeRcvd = m->timenow - rr->resrec.rroriginalttl * mDNSPlatformOneSecond; + rr->UnansweredQueries = MaxUnansweredQueries; + } + } + } } for (i = 0; i < totalrecords && ptr && ptr < end; i++) { + // All responses sent via LL multicast are acceptable for caching + // All responses received over our outbound TCP connections are acceptable for caching + mDNSBool AcceptableResponse = ResponseMCast || !dstaddr || LLQType; + // (Note that just because we are willing to cache something, that doesn't necessarily make it a trustworthy answer + // to any specific question -- any code reading records from the cache needs to make that determination for itself.) + const mDNSu8 RecordType = (mDNSu8)((i < response->h.numAnswers) ? kDNSRecordTypePacketAns : kDNSRecordTypePacketAdd); ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, RecordType, &m->rec); if (!ptr) goto exit; // Break out of the loop and clean up our CacheFlushRecords list before exiting + // Don't want to cache OPT or TSIG pseudo-RRs + if (m->rec.r.resrec.rrtype == kDNSType_OPT || m->rec.r.resrec.rrtype == kDNSType_TSIG) + { m->rec.r.resrec.RecordType = 0; continue; } + + // When we receive uDNS LLQ responses, we assume a long cache lifetime -- + // In the case of active LLQs, we'll get remove events when the records actually do go away + // In the case of polling LLQs, we assume the record remains valid until the next poll + if (!mDNSOpaque16IsZero(response->h.id)) + m->rec.r.resrec.rroriginalttl = GetEffectiveTTL(LLQType, m->rec.r.resrec.rroriginalttl); + + // If response was not sent via LL multicast, + // then see if it answers a recent query of ours, which would also make it acceptable for caching. + if (!AcceptableResponse) AcceptableResponse = ExpectingUnicastResponseForRecord(m, srcaddr, ResponseSrcLocal, response->h.id, &m->rec.r); // 1. Check that this packet resource record does not conflict with any of ours - if (m->CurrentRecord) LogMsg("mDNSCoreReceiveResponse ERROR m->CurrentRecord already set"); - m->CurrentRecord = m->ResourceRecords; - while (m->CurrentRecord) + if (mDNSOpaque16IsZero(response->h.id)) { - AuthRecord *rr = m->CurrentRecord; - m->CurrentRecord = rr->next; - if (PacketRRMatchesSignature(&m->rec.r, rr)) // If interface, name, type (if shared record) and class match... + if (m->CurrentRecord) + LogMsg("mDNSCoreReceiveResponse ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); + m->CurrentRecord = m->ResourceRecords; + while (m->CurrentRecord) { - // ... check to see if type and rdata are identical - if (m->rec.r.resrec.rrtype == rr->resrec.rrtype && SameRData(&m->rec.r.resrec, &rr->resrec)) - { - // If the RR in the packet is identical to ours, just check they're not trying to lower the TTL on us - if (m->rec.r.resrec.rroriginalttl >= rr->resrec.rroriginalttl/2 || m->SleepState) - { - // If we were planning to send on this -- and only this -- interface, then we don't need to any more - if (rr->ImmedAnswer == InterfaceID) { rr->ImmedAnswer = mDNSNULL; rr->ImmedUnicast = mDNSfalse; } - } - else - { - if (rr->ImmedAnswer == mDNSNULL) { rr->ImmedAnswer = InterfaceID; m->NextScheduledResponse = m->timenow; } - else if (rr->ImmedAnswer != InterfaceID) { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; } - } - } - // else, the packet RR has different type or different rdata -- check to see if this is a conflict - else if (m->rec.r.resrec.rroriginalttl > 0 && PacketRRConflict(m, rr, &m->rec.r)) + AuthRecord *rr = m->CurrentRecord; + m->CurrentRecord = rr->next; + // We accept all multicast responses, and unicast responses resulting from queries we issued + // For other unicast responses, this code accepts them only for responses with an + // (apparently) local source address that pertain to a record of our own that's in probing state + if (!AcceptableResponse && !(ResponseSrcLocal && rr->resrec.RecordType == kDNSRecordTypeUnique)) continue; + if (PacketRRMatchesSignature(&m->rec.r, rr)) // If interface, name, type (if shared record) and class match... { - debugf("mDNSCoreReceiveResponse: Our Record: %08lX %s", rr-> resrec.rdatahash, ARDisplayString(m, rr)); - debugf("mDNSCoreReceiveResponse: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r)); - - // If this record is marked DependentOn another record for conflict detection purposes, - // then *that* record has to be bumped back to probing state to resolve the conflict - while (rr->DependentOn) rr = rr->DependentOn; - - // If we've just whacked this record's ProbeCount, don't need to do it again - if (rr->ProbeCount <= DefaultProbeCountForTypeUnique) + // ... check to see if type and rdata are identical + if (m->rec.r.resrec.rrtype == rr->resrec.rrtype && SameRData(&m->rec.r.resrec, &rr->resrec)) { - // If we'd previously verified this record, put it back to probing state and try again - if (rr->resrec.RecordType == kDNSRecordTypeVerified) + // If the RR in the packet is identical to ours, just check they're not trying to lower the TTL on us + if (m->rec.r.resrec.rroriginalttl >= rr->resrec.rroriginalttl/2 || m->SleepState) { - debugf("mDNSCoreReceiveResponse: Reseting to Probing: %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); - rr->resrec.RecordType = kDNSRecordTypeUnique; - rr->ProbeCount = DefaultProbeCountForTypeUnique + 1; - rr->ThisAPInterval = DefaultAPIntervalForRecordType(kDNSRecordTypeUnique); - InitializeLastAPTime(m, rr); - RecordProbeFailure(m, rr); // Repeated late conflicts also cause us to back off to the slower probing rate + // If we were planning to send on this -- and only this -- interface, then we don't need to any more + if (rr->ImmedAnswer == InterfaceID) { rr->ImmedAnswer = mDNSNULL; rr->ImmedUnicast = mDNSfalse; } } - // If we're probing for this record, we just failed - else if (rr->resrec.RecordType == kDNSRecordTypeUnique) + else { - debugf("mDNSCoreReceiveResponse: Will rename %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); - mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict); + if (rr->ImmedAnswer == mDNSNULL) { rr->ImmedAnswer = InterfaceID; m->NextScheduledResponse = m->timenow; } + else if (rr->ImmedAnswer != InterfaceID) { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; } } - // We assumed this record must be unique, but we were wrong. - // (e.g. There are two mDNSResponders on the same machine giving - // different answers for the reverse mapping record.) - // This is simply a misconfiguration, and we don't try to recover from it. - else if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique) + } + // else, the packet RR has different type or different rdata -- check to see if this is a conflict + else if (m->rec.r.resrec.rroriginalttl > 0 && PacketRRConflict(m, rr, &m->rec.r)) + { + debugf("mDNSCoreReceiveResponse: Our Record: %08lX %s", rr-> resrec.rdatahash, ARDisplayString(m, rr)); + debugf("mDNSCoreReceiveResponse: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r)); + + // If this record is marked DependentOn another record for conflict detection purposes, + // then *that* record has to be bumped back to probing state to resolve the conflict + while (rr->DependentOn) rr = rr->DependentOn; + + // If we've just whacked this record's ProbeCount, don't need to do it again + if (rr->ProbeCount <= DefaultProbeCountForTypeUnique) { - debugf("mDNSCoreReceiveResponse: Unexpected conflict on %##s (%s) -- discarding our record", - rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); - mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict); + // If we'd previously verified this record, put it back to probing state and try again + if (rr->resrec.RecordType == kDNSRecordTypeVerified) + { + debugf("mDNSCoreReceiveResponse: Reseting to Probing: %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); + rr->resrec.RecordType = kDNSRecordTypeUnique; + rr->ProbeCount = DefaultProbeCountForTypeUnique + 1; + rr->ThisAPInterval = DefaultAPIntervalForRecordType(kDNSRecordTypeUnique); + InitializeLastAPTime(m, rr); + RecordProbeFailure(m, rr); // Repeated late conflicts also cause us to back off to the slower probing rate + } + // If we're probing for this record, we just failed + else if (rr->resrec.RecordType == kDNSRecordTypeUnique) + { + debugf("mDNSCoreReceiveResponse: Will rename %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); + mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict); + } + // We assumed this record must be unique, but we were wrong. + // (e.g. There are two mDNSResponders on the same machine giving + // different answers for the reverse mapping record.) + // This is simply a misconfiguration, and we don't try to recover from it. + else if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique) + { + debugf("mDNSCoreReceiveResponse: Unexpected conflict on %##s (%s) -- discarding our record", + rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); + mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict); + } + else + debugf("mDNSCoreReceiveResponse: Unexpected record type %X %##s (%s)", + rr->resrec.RecordType, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); } - else - debugf("mDNSCoreReceiveResponse: Unexpected record type %X %##s (%s)", - rr->resrec.RecordType, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); } + // Else, matching signature, different type or rdata, but not a considered a conflict. + // If the packet record has the cache-flush bit set, then we check to see if we + // 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) + { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; } } - // Else, matching signature, different type or rdata, but not a considered a conflict. - // If the packet record has the cache-flush bit set, then we check to see if we - // 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) - { rr->ImmedAnswer = mDNSInterfaceMark; m->NextScheduledResponse = m->timenow; } } } // 2. See if we want to add this packet resource record to our cache - if (m->rrcache_size) // Only try to cache answers if we have a cache to put them in + // We only try to cache answers if we have a cache to put them in + // Also, we ignore any apparent attempts at cache poisoning unicast to us that do not answer any outstanding active query + if (m->rrcache_size && AcceptableResponse) { const mDNSu32 slot = HashSlot(m->rec.r.resrec.name); CacheGroup *cg = CacheGroupForRecord(m, slot, &m->rec.r.resrec); @@ -5432,7 +4530,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) { // If we found this exact resource record, refresh its TTL - if (rr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &rr->resrec)) + if (rr->resrec.InterfaceID == InterfaceID && IdenticalSameNameRecord(&m->rec.r.resrec, &rr->resrec)) { if (m->rec.r.resrec.rdlength > InlineCacheRDSize) verbosedebugf("Found record size %5d interface %p already in cache: %s", @@ -5442,7 +4540,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, if (m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) { // If this packet record has the kDNSClass_UniqueRRSet flag set, then add it to our cache flushing list - if (rr->NextInCFList == mDNSNULL && cfp != &rr->NextInCFList) + if (rr->NextInCFList == mDNSNULL && cfp != &rr->NextInCFList && LLQType != uDNS_LLQ_Events) { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; } // If this packet record is marked unique, and our previous cached copy was not, then fix it @@ -5466,12 +4564,8 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, } else if (m->rec.r.resrec.rroriginalttl > 0) { - rr->resrec.rroriginalttl = m->rec.r.resrec.rroriginalttl; - rr->UnansweredQueries = 0; - rr->MPUnansweredQ = 0; - rr->MPUnansweredKA = 0; - rr->MPExpectingKA = mDNSfalse; - SetNextCacheCheckTime(m, rr); + //if (rr->resrec.rroriginalttl == 0) LogMsg("uDNS rescuing %s", CRDisplayString(m, rr)); + RefreshCacheRecord(m, rr, m->rec.r.resrec.rroriginalttl); break; } else @@ -5493,32 +4587,9 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, // (unless it is just a deletion of a record we never had, in which case we don't care) if (!rr && m->rec.r.resrec.rroriginalttl > 0) { - // If we don't have a CacheGroup for this name, make one now - if (!cg) cg = GetCacheGroup(m, slot, &m->rec.r.resrec); - if (cg) rr = GetCacheRecord(m, cg, m->rec.r.resrec.rdlength); // Make a cache record, being careful not to recycle cg - if (!rr) NoCacheAnswer(m, &m->rec.r); - else - { - RData *saveptr = rr->resrec.rdata; // Save the rr->resrec.rdata pointer - *rr = m->rec.r; // Block copy the CacheRecord object - rr->resrec.rdata = saveptr; // Restore rr->resrec.rdata after the structure assignment - rr->resrec.name = cg->name; // And set rr->resrec.name to point into our CacheGroup header - if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) - { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; } - // If this is an oversized record with external storage allocated, copy rdata to external storage - if (rr->resrec.rdata != (RData*)&rr->rdatastorage && !(m->rec.r.resrec.rdlength > InlineCacheRDSize)) - LogMsg("rr->resrec.rdata != &rr->rdatastorage but length <= InlineCacheRDSize %##s", m->rec.r.resrec.name->c); - if (m->rec.r.resrec.rdlength > InlineCacheRDSize) - mDNSPlatformMemCopy(m->rec.r.resrec.rdata, rr->resrec.rdata, sizeofRDataHeader + m->rec.r.resrec.rdlength); - rr->next = mDNSNULL; // Clear 'next' pointer - *(cg->rrcache_tail) = rr; // Append this record to tail of cache slot list - cg->rrcache_tail = &(rr->next); // Advance tail pointer - if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) // If marked unique, assume we may have - rr->DelayDelivery = m->timenow + mDNSPlatformOneSecond; // to delay delivery of this 'add' event - else - rr->DelayDelivery = CheckForSoonToExpireRecords(m, rr->resrec.name, rr->resrec.namehash, slot); - CacheRecordAdd(m, rr); // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us - } + rr = CreateNewCacheEntry(m, slot, cg); + if (rr && (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) && LLQType != uDNS_LLQ_Events) + { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; } } } m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it @@ -5533,19 +4604,53 @@ exit: { CacheRecord *r1 = CacheFlushRecords, *r2; const mDNSu32 slot = HashSlot(r1->resrec.name); - CacheGroup *cg = CacheGroupForRecord(m, slot, &r1->resrec); + const CacheGroup *cg = CacheGroupForRecord(m, slot, &r1->resrec); CacheFlushRecords = CacheFlushRecords->NextInCFList; r1->NextInCFList = mDNSNULL; + + // Look for records in the cache with the same signature as this new one with the cache flush + // bit set, and either (a) if they're fresh, just make sure the whole RRSet has the same TTL + // (as required by DNS semantics) or (b) if they're old, mark them for deletion in one second. + // We make these TTL adjustments *only* for records that still have *more* than one second + // remaining to live. Otherwise, a record that we tagged for deletion half a second ago + // (and now has half a second remaining) could inadvertently get its life extended, by either + // (a) if we got an explicit goodbye packet half a second ago, the record would be considered + // "fresh" and would be incorrectly resurrected back to the same TTL as the rest of the RRSet, + // or (b) otherwise, the record would not be fully resurrected, but would be reset to expire + // in one second, thereby inadvertently delaying its actual expiration, instead of hastening it. + // If this were to happen repeatedly, the record's expiration could be deferred indefinitely. + // To avoid this, we need to ensure that the cache flushing operation will only act to + // *decrease* a record's remaining lifetime, never *increase* it. If a record has less than + // one second to go, we simply leave it alone, and leave it to expire at its assigned time. for (r2 = cg ? cg->members : mDNSNULL; r2; r2=r2->next) - if (SameResourceRecordSignature(&r1->resrec, &r2->resrec)) + if (r1->resrec.InterfaceID == r2->resrec.InterfaceID && + r1->resrec.rrtype == r2->resrec.rrtype && + r1->resrec.rrclass == r2->resrec.rrclass) if (RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond) { // If record is recent, just ensure the whole RRSet has the same TTL (as required by DNS semantics) // else, if record is old, mark it to be flushed if (m->timenow - r2->TimeRcvd < mDNSPlatformOneSecond) { + // If we find mismatched TTLs in an RRSet, correct them. + // We only do this for records with a TTL of 2 or higher. It's possible to have a + // goodbye announcement with the cache flush bit set (or a case change on record rdata, + // which we treat as a goodbye followed by an addition) and in that case it would be + // inappropriate to synchronize all the other records to a TTL of 0 (or 1). + // We suppress the message for the specific case of correcting from 240 to 60 for type TXT, + // because certain early Bonjour devices are known to have this specific mismatch, and + // there's no point filling syslog with messages about something we already know about. + // We also don't log this for uDNS responses, since a caching name server is obliged + // to give us an aged TTL to correct for how long it has held the record, + // so our received TTLs are expected to vary in that case if (r2->resrec.rroriginalttl != r1->resrec.rroriginalttl && r1->resrec.rroriginalttl > 1) + { + if (r2->resrec.rroriginalttl != 240 && r1->resrec.rroriginalttl != 60 && r2->resrec.rrtype != kDNSType_TXT && + mDNSOpaque16IsZero(response->h.id)) + LogMsg("Correcting TTL from %4d to %4d for %s", + r2->resrec.rroriginalttl, r1->resrec.rroriginalttl, CRDisplayString(m, r2)); r2->resrec.rroriginalttl = r1->resrec.rroriginalttl; + } } else // else, if record is old, mark it to be flushed { @@ -5574,56 +4679,201 @@ exit: if (!r1->DelayDelivery) CacheRecordDeferredAdd(m, r1); } } + + // See if we need to generate negative cache entries for unanswered unicast questions + ptr = response->data; + for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++) + { + DNSQuestion q; + ptr = getQuestion(response, ptr, end, InterfaceID, &q); + if (ptr && ExpectingUnicastResponseForQuestion(m, response->h.id, &q)) + { + CacheRecord *rr; + mDNSu32 slot = HashSlot(&q.qname); + CacheGroup *cg = CacheGroupForName(m, slot, q.qnamehash, &q.qname); + for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) + if (SameNameRecordAnswersQuestion(&rr->resrec, &q)) + { + // 1. If we got a fresh answer to this query, then don't need to generate a negative entry + // 2. If we already had a negative entry which we were about to discard, then we should resurrect it + if (rr->resrec.rroriginalttl) break; + if (rr->resrec.RecordType == kDNSRecordTypePacketNegative) break; + } + + if (!rr || rr->resrec.RecordType == kDNSRecordTypePacketNegative) + { + // We start off assuming a negative caching TTL of 60 seconds + // but then look to see if we can find an SOA authority record to tell us a better value we should be using + mDNSu32 negttl = 60; + int repeat = 0; + const domainname *name = &q.qname; + mDNSu32 hash = q.qnamehash; + + // If we're going to make (or update) a negative entry, then look for the appropriate TTL from the SOA record + if (response->h.numAuthorities && (ptr = LocateAuthorities(response, end)) != mDNSNULL) + { + ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &m->rec); + if (ptr && m->rec.r.resrec.rrtype == kDNSType_SOA) + { + mDNSu32 ttl_s = m->rec.r.resrec.rroriginalttl < m->rec.r.resrec.rdata->u.soa.min ? + m->rec.r.resrec.rroriginalttl : m->rec.r.resrec.rdata->u.soa.min; + if (negttl < ttl_s) negttl = ttl_s; + + // 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 + // is d.com, and consequently SOA records b.c.d.com and c.d.com don't exist either. + // To do this we set the repeat count so the while loop below will make a series of negative cache entries for us + if (q.qtype == kDNSType_SOA) + { + int qcount = CountLabels(&q.qname); + int scount = CountLabels(m->rec.r.resrec.name); + if (qcount - 1 > scount) + if (SameDomainName(SkipLeadingLabels(&q.qname, qcount - scount), m->rec.r.resrec.name)) + repeat = qcount - 1 - scount; + } + } + m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it + } + + // If we already had a negative entry in the cache, then we double our existing negative TTL. This is to avoid + // the case where the record doesn't exist (e.g. particularly for things like our lb._dns-sd._udp. query), + // and the server returns no SOA record (or an SOA record with a small MIN TTL) so we assume a TTL + // of 60 seconds, and we end up polling the server every minute for a record that doesn't exist. + // With this fix in place, when this happens, we double the effective TTL each time (up to one hour), + // so that we back off our polling rate and don't keep hitting the server continually. + if (rr) + { + if (negttl < rr->resrec.rroriginalttl * 2) + negttl = rr->resrec.rroriginalttl * 2; + if (negttl > 3600) + negttl = 3600; + } + + negttl = GetEffectiveTTL(LLQType, negttl); // Add 25% grace period if necessary + + if (rr) LogOperation("Renewing negative TTL from %d to %d %s", rr->resrec.rroriginalttl, negttl, CRDisplayString(m, rr)); + + // If we already had a negative cache entry just update it, else make one or more new negative cache entries + if (rr) + RefreshCacheRecord(m, rr, negttl); + else while (1) + { + LogOperation("Making negative cache entry TTL %d for %##s (%s)", negttl, name->c, DNSTypeName(q.qtype)); + MakeNegativeCacheRecord(m, name, hash, q.qtype, q.qclass, negttl); + CreateNewCacheEntry(m, slot, cg); + m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it + if (!repeat) break; + repeat--; + name = (const domainname *)(name->c + 1 + name->c[0]); + hash = DomainNameHashValue(name); + slot = HashSlot(name); + cg = CacheGroupForName(m, slot, hash, name); + } + } + } + } + } + +mDNSexport void MakeNegativeCacheRecord(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds) + { + // Create empty resource record + m->rec.r.resrec.RecordType = kDNSRecordTypePacketNegative; + m->rec.r.resrec.InterfaceID = mDNSInterface_Any; + m->rec.r.resrec.name = name; // Will be updated to point to cg->name when we call CreateNewCacheEntry + m->rec.r.resrec.rrtype = rrtype; + m->rec.r.resrec.rrclass = rrclass; + m->rec.r.resrec.rroriginalttl = ttl_seconds; + m->rec.r.resrec.rdlength = 0; + m->rec.r.resrec.rdestimate = 0; + m->rec.r.resrec.namehash = namehash; + m->rec.r.resrec.rdatahash = 0; + m->rec.r.resrec.rdata = (RData*)&m->rec.r.rdatastorage; + m->rec.r.resrec.rdata->MaxRDLength = m->rec.r.resrec.rdlength; + + m->rec.r.NextInKAList = mDNSNULL; + m->rec.r.TimeRcvd = m->timenow; + m->rec.r.DelayDelivery = 0; + m->rec.r.NextRequiredQuery = m->timenow; + m->rec.r.LastUsed = m->timenow; + m->rec.r.CRActiveQuestion = mDNSNULL; + m->rec.r.UnansweredQueries = 0; + m->rec.r.LastUnansweredTime = 0; + m->rec.r.MPUnansweredQ = 0; + m->rec.r.MPLastUnansweredQT = 0; + m->rec.r.MPUnansweredKA = 0; + m->rec.r.MPExpectingKA = mDNSfalse; + m->rec.r.NextInCFList = mDNSNULL; } mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *const end, - const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr, const mDNSIPPort dstport, + const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID) { + mDNSInterfaceID ifid = InterfaceID; DNSMessage *msg = (DNSMessage *)pkt; const mDNSu8 StdQ = kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery; const mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery; + const mDNSu8 UpdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update; mDNSu8 QR_OP; mDNSu8 *ptr = mDNSNULL; - const mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update; + mDNSBool TLS = (dstaddr == (mDNSAddr *)1); // For debug logs: dstaddr = 0 means TCP; dstaddr = 1 means TLS + if (TLS) dstaddr = mDNSNULL; -#ifndef UNICAST_DISABLED - if (srcport.NotAnInteger == NATPMPPort.NotAnInteger) +#ifndef UNICAST_DISABLED + if (mDNSSameAddress(srcaddr, &m->Router)) { - mDNS_Lock(m); - uDNS_ReceiveNATMap(m, pkt, (mDNSu16)(end - (mDNSu8 *)pkt)); - mDNS_Unlock(m); - return; + if (mDNSSameIPPort(srcport, NATPMPPort)) + { + mDNS_Lock(m); + uDNS_ReceiveNATPMPPacket(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt)); + mDNS_Unlock(m); + return; + } +#ifdef _LEGACY_NAT_TRAVERSAL_ + if (mDNSSameIPPort(srcport, SSDPPort)) + { + mDNS_Lock(m); + LNT_ConfigureRouterInfo(m, InterfaceID, pkt, (mDNSu16)(end - (mDNSu8 *)pkt)); + mDNS_Unlock(m); + return; + } +#endif } -#endif +#endif if ((unsigned)(end - (mDNSu8 *)pkt) < sizeof(DNSMessageHeader)) { LogMsg("DNS Message too short"); return; } QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask); // 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]); - msg->h.numAnswers = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]); - msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]); - msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]); + msg->h.numQuestions = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); + msg->h.numAnswers = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]); + msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]); + msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]); if (!m) { LogMsg("mDNSCoreReceive ERROR m is NULL"); return; } // We use zero addresses and all-ones addresses at various places in the code to indicate special values like "no address" // If we accept and try to process a packet with zero or all-ones source address, that could really mess things up - if (!mDNSAddressIsValid(srcaddr)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr); return; } + if (srcaddr && !mDNSAddressIsValid(srcaddr)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr); return; } mDNS_Lock(m); m->PktNum++; #ifndef UNICAST_DISABLED - if (!mDNSAddressIsAllDNSLinkGroup(dstaddr) && (QR_OP == StdR || QR_OP == UpdateR)) - uDNS_ReceiveMsg(m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID); + if (!dstaddr || (!mDNSAddressIsAllDNSLinkGroup(dstaddr) && (QR_OP == StdR || QR_OP == UpdR))) + { + if (!mDNSOpaque16IsZero(msg->h.id)) ifid = mDNSInterface_Any; + if (mDNS_LogLevel >= MDNS_LOG_VERBOSE_DEBUG) + DumpPacket(m, mDNSfalse, TLS ? "TLS" : !dstaddr ? "TCP" : "UDP", srcaddr, srcport, msg, end); + uDNS_ReceiveMsg(m, msg, end, srcaddr, srcport); // Note: mDNSCore also needs to get access to received unicast responses -#endif - if (QR_OP == StdQ) mDNSCoreReceiveQuery (m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID); - else if (QR_OP == StdR) mDNSCoreReceiveResponse(m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID); - else if (QR_OP != UpdateR) + } +#endif + if (QR_OP == StdQ) mDNSCoreReceiveQuery (m, msg, end, srcaddr, srcport, dstaddr, dstport, ifid); + else if (QR_OP == StdR) mDNSCoreReceiveResponse(m, msg, end, srcaddr, srcport, dstaddr, dstport, ifid); + else if (QR_OP != UpdR) + { LogMsg("Unknown DNS packet type %02X%02X from %#-15a:%-5d to %#-15a:%-5d on %p (ignored)", msg->h.flags.b[0], msg->h.flags.b[1], srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID); - + } // Packet reception often causes a change to the task list: // 1. Inbound queries can cause us to need to send responses // 2. Conflicing response packets received from other hosts can cause us to need to send defensive responses @@ -5635,11 +4885,14 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *co // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - -#pragma mark - #pragma mark - Searcher Functions #endif -#define SameQTarget(A,B) (mDNSSameAddress(&(A)->Target, &(B)->Target) && (A)->TargetPort.NotAnInteger == (B)->TargetPort.NotAnInteger) +// Targets are considered the same if both queries are untargeted, or +// if both are targeted to the same address+port +// (If Target address is zero, TargetPort is undefined) +#define SameQTarget(A,B) (((A)->Target.type == mDNSAddrType_None && (B)->Target.type == mDNSAddrType_None) || \ + (mDNSSameAddress(&(A)->Target, &(B)->Target) && mDNSSameIPPort((A)->TargetPort, (B)->TargetPort))) mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuestion *const question) { @@ -5648,39 +4901,121 @@ mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuest // This prevents circular references, where two questions are each marked as a duplicate of the other. // Accordingly, we break out of the loop when we get to 'question', because there's no point searching // further in the list. - for (q = m->Questions; q && q != question; q=q->next) // Scan our list of questions - if (q->InterfaceID == question->InterfaceID && // for another question with the same InterfaceID, + for (q = m->Questions; q && q != question; q=q->next) // Scan our list for another question + if (q->InterfaceID == question->InterfaceID && // with the same InterfaceID, SameQTarget(q, question) && // and same unicast/multicast target settings q->qtype == question->qtype && // type, q->qclass == question->qclass && // class, + q->AuthInfo == question->AuthInfo && // and privacy status matches + q->LongLived == question->LongLived && // and long-lived status matches q->qnamehash == question->qnamehash && SameDomainName(&q->qname, &question->qname)) // and name return(q); return(mDNSNULL); } -// This is called after a question is deleted, in case other identical questions were being -// suppressed as duplicates -mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, const DNSQuestion *const question) +// This is called after a question is deleted, in case other identical questions were being +// suppressed as duplicates +mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const question) + { + DNSQuestion *q; + for (q = m->Questions; q; q=q->next) // Scan our list of questions + if (q->DuplicateOf == question) // To see if any questions were referencing this as their duplicate + if ((q->DuplicateOf = FindDuplicateQuestion(m, q)) == mDNSNULL) + { + // If q used to be a duplicate, but now is not, + // then inherit the state from the question that's going away + q->LastQTime = question->LastQTime; + q->ThisQInterval = question->ThisQInterval; + q->ExpectUnicastResp = question->ExpectUnicastResp; + q->LastAnswerPktNum = question->LastAnswerPktNum; + q->RecentAnswerPkts = question->RecentAnswerPkts; + q->RequestUnicast = question->RequestUnicast; + q->LastQTxTime = question->LastQTxTime; + q->CNAMEReferrals = question->CNAMEReferrals; + q->nta = question->nta; + q->servAddr = question->servAddr; + q->servPort = question->servPort; + + q->state = question->state; + // q->NATInfoUDP = question->NATInfoUDP; + q->eventPort = question->eventPort; + // q->tcp = question->tcp; + q->origLease = question->origLease; + q->expire = question->expire; + q->ntries = question->ntries; + q->id = question->id; + + question->nta = mDNSNULL; // If we've got a GetZoneData in progress, transfer it to the newly active question + // question->NATInfoUDP = mDNSNULL; + // question->tcp = mDNSNULL; + if (q->nta) + { + LogOperation("UpdateQuestionDuplicates transferred nta pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + q->nta->ZoneDataContext = q; + } + + // Need to work out how to safely transfer this state too -- appropriate context pointers need to be updated or the code will crash + if (question->tcp) LogOperation("UpdateQuestionDuplicates did not transfer tcp pointer"); + + SetNextQueryTime(m,q); + } + } + +// lookup a DNS Server, matching by name in split-dns configurations. Result stored in addr parameter if successful +mDNSlocal DNSServer *GetServerForName(mDNS *m, const domainname *name) + { + DNSServer *curmatch = mDNSNULL, *p; + int curmatchlen = -1, ncount = name ? CountLabels(name) : 0; + + for (p = m->DNSServers; p; p = p->next) + { + int scount = CountLabels(&p->domain); + if (!p->del && ncount >= scount && scount > curmatchlen) + if (SameDomainName(SkipLeadingLabels(name, ncount - scount), &p->domain)) + { curmatch = p; curmatchlen = scount; } + } + return(curmatch); + } + +#define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \ + (mDNSSameIPPort((Q)->TargetPort, UnicastDNSPort) || mDNSSameIPPort((Q)->TargetPort, MulticastDNSPort))) + +mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question) { - DNSQuestion *q; - for (q = m->Questions; q; q=q->next) // Scan our list of questions - if (q->DuplicateOf == question) // To see if any questions were referencing this as their duplicate + // For now this AutoTunnel 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 +#if APPLE_OSX_mDNSResponder + if (question->qtype == kDNSType_AAAA && question->AuthInfo && question->AuthInfo->AutoTunnel && question->QuestionCallback != AutoTunnelCallback) + { + question->NoAnswer = NoAnswer_Suspended; + AddNewClientTunnel(m, question); + return; + } +#endif // APPLE_OSX_mDNSResponder + + if (!question->DuplicateOf) + { + if (question->LongLived) { - q->ThisQInterval = question->ThisQInterval; - q->RequestUnicast = question->RequestUnicast; - q->LastQTime = question->LastQTime; - q->RecentAnswerPkts = 0; - q->DuplicateOf = FindDuplicateQuestion(m, q); - q->LastQTxTime = question->LastQTxTime; - SetNextQueryTime(m,q); + question->ThisQInterval = 0; // Question is suspended, waiting for GetZoneData to complete + question->LastQTime = m->timenow; + LogOperation("uDNS_InitLongLivedQuery: %##s %s %s %d", + question->qname.c, DNSTypeName(question->qtype), question->AuthInfo ? "(Private)" : "", question->ThisQInterval); + if (question->nta) CancelGetZoneData(m, question->nta); + question->state = LLQ_GetZoneInfo; // Necessary to stop "bad state" error in startLLQHandshakeCallback + question->nta = StartGetZoneData(m, &question->qname, ZoneServiceLLQ, startLLQHandshakeCallback, question); + if (!question->nta) LogMsg("ERROR: startLLQ - StartGetZoneData failed"); + } + else + { + question->ThisQInterval = InitialQuestionInterval; + question->LastQTime = m->timenow - question->ThisQInterval; } + } } -#define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \ - ((Q)->TargetPort.NotAnInteger == UnicastDNSPort.NotAnInteger || (Q)->TargetPort.NotAnInteger == MulticastDNSPort.NotAnInteger)) - -mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question) +mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question) { if (question->Target.type && !ValidQuestionTarget(question)) { @@ -5695,25 +5030,34 @@ mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const que question->TargetQID = zeroID; } -#ifndef UNICAST_DISABLED +#ifndef UNICAST_DISABLED // If the client has specified 'kDNSServiceFlagsForceMulticast' // then we do a multicast query on that interface, even for unicast domains. - if (question->InterfaceID == mDNSInterface_LocalOnly || question->ForceMCast || IsLocalDomain(&question->qname)) - question->uDNS_info.id = zeroID; - else return uDNS_StartQuery(m, question); + if (question->InterfaceID == mDNSInterface_LocalOnly || question->ForceMCast || IsLocalDomain(&question->qname)) + question->TargetQID = zeroID; + else + question->TargetQID = mDNS_NewMessageID(m); #else - question->uDNS_info.id = zeroID; + question->TargetQID = zeroID; #endif // UNICAST_DISABLED - - //LogOperation("mDNS_StartQuery %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); - + + debugf("mDNS_StartQuery: %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); + if (m->rrcache_size == 0) // Can't do queries if we have no cache space allocated return(mStatus_NoCache); else { int i; + DNSQuestion **q; + + if (!ValidateDomainName(&question->qname)) + { + LogMsg("Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); + return(mStatus_Invalid); + } + // Note: It important that new questions are appended at the *end* of the list, not prepended at the start - DNSQuestion **q = &m->Questions; + q = &m->Questions; if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions; while (*q && *q != question) q=&(*q)->next; @@ -5724,59 +5068,79 @@ mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const que return(mStatus_AlreadyRegistered); } - // If this question is referencing a specific interface, make sure it exists + *q = question; + + // If this question is referencing a specific interface, verify it exists if (question->InterfaceID && question->InterfaceID != mDNSInterface_LocalOnly) { NetworkInterfaceInfo *intf; for (intf = m->HostInterfaces; intf; intf = intf->next) if (intf->InterfaceID == question->InterfaceID) break; if (!intf) - { - debugf("mDNS_StartQuery_internal: Question %##s InterfaceID %p not found", question->qname.c, question->InterfaceID); - return(mStatus_BadInterfaceErr); - } - } - - if (!ValidateDomainName(&question->qname)) - { - LogMsg("Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); - return(mStatus_Invalid); + LogMsg("Note: InterfaceID %p for question %##s (%s) not currently found in active interface list", + question->InterfaceID, question->qname.c, DNSTypeName(question->qtype)); } // Note: In the case where we already have the answer to this question in our cache, that may be all the client // wanted, and they may immediately cancel their question. In this case, sending an actual query on the wire would - // be a waste. For that reason, we schedule our first query to go out in half a second. If AnswerNewQuestion() finds - // that we have *no* relevant answers currently in our cache, then it will accelerate that to go out immediately. - if (!m->RandomQueryDelay) m->RandomQueryDelay = 1 + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval); - - question->next = mDNSNULL; - question->qnamehash = DomainNameHashValue(&question->qname); // MUST do this before FindDuplicateQuestion() - question->DelayAnswering = CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash, HashSlot(&question->qname)); - question->ThisQInterval = InitialQuestionInterval * 2; // MUST be > zero for an active question - question->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it - question->LastQTime = m->timenow - m->RandomQueryDelay; // Avoid inter-machine synchronization - question->LastAnswerPktNum = m->PktNum; - question->RecentAnswerPkts = 0; - question->CurrentAnswers = 0; - question->LargeAnswers = 0; - question->UniqueAnswers = 0; - question->DuplicateOf = FindDuplicateQuestion(m, question); - question->NextInDQList = mDNSNULL; + // be a waste. For that reason, we schedule our first query to go out in half a second (InitialQuestionInterval). + // If AnswerNewQuestion() finds that we have *no* relevant answers currently in our cache, then it will accelerate + // that to go out immediately. + question->next = mDNSNULL; + question->qnamehash = DomainNameHashValue(&question->qname); // MUST do this before FindDuplicateQuestion() + question->DelayAnswering = CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash, HashSlot(&question->qname)); + question->LastQTime = m->timenow; + question->ThisQInterval = InitialQuestionInterval; // MUST be > zero for an active question + question->ExpectUnicastResp = 0; + question->LastAnswerPktNum = m->PktNum; + question->RecentAnswerPkts = 0; + question->CurrentAnswers = 0; + question->LargeAnswers = 0; + question->UniqueAnswers = 0; + question->FlappingInterface1 = mDNSNULL; + question->FlappingInterface2 = mDNSNULL; + // GetZoneData queries are a special case -- even if we have a key for them, we don't do them privately, + // because that would result in an infinite loop (i.e. to do a private query we first need to get + // the _dns-query-tls SRV record for the zone, and we can't do *that* privately because to do so + // we'd need to already know the _dns-query-tls SRV record. + // Also: Make sure we set AuthInfo before calling FindDuplicateQuestion() + question->AuthInfo = (question->QuestionCallback == GetZoneData_QuestionCallback) ? mDNSNULL + : GetAuthInfoForName_internal(m, &question->qname); + question->DuplicateOf = FindDuplicateQuestion(m, question); + question->NextInDQList = mDNSNULL; + question->SendQNow = mDNSNULL; + question->SendOnAll = mDNSfalse; + question->RequestUnicast = 0; + question->LastQTxTime = m->timenow; + question->CNAMEReferrals = 0; + + question->qDNSServer = mDNSNULL; + question->nta = mDNSNULL; + question->servAddr = zeroAddr; + question->servPort = zeroIPPort; + question->tcp = mDNSNULL; + question->NoAnswer = NoAnswer_Normal; + + question->state = LLQ_GetZoneInfo; + mDNSPlatformMemZero(&question->NATInfoUDP, sizeof(question->NATInfoUDP)); + question->eventPort = zeroIPPort; + question->origLease = 0; + question->expire = 0; + question->ntries = 0; + question->id = zeroOpaque64; + for (i=0; iDupSuppress[i].InterfaceID = mDNSNULL; - // question->InterfaceID must be already set by caller - question->SendQNow = mDNSNULL; - question->SendOnAll = mDNSfalse; - question->LastQTxTime = m->timenow; if (!question->DuplicateOf) - verbosedebugf("mDNS_StartQuery_internal: Question %##s (%s) %p %d (%p) started", - question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, question->LastQTime + question->ThisQInterval - m->timenow, question); + debugf("mDNS_StartQuery: Question %##s (%s) %p %d (%p) started", + question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, + question->LastQTime + question->ThisQInterval - m->timenow, question); else - verbosedebugf("mDNS_StartQuery_internal: Question %##s (%s) %p %d (%p) duplicate of (%p)", - question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, question->LastQTime + question->ThisQInterval - m->timenow, question, question->DuplicateOf); + debugf("mDNS_StartQuery: Question %##s (%s) %p %d (%p) duplicate of (%p)", + question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, + question->LastQTime + question->ThisQInterval - m->timenow, question, question->DuplicateOf); - *q = question; if (question->InterfaceID == mDNSInterface_LocalOnly) { if (!m->NewLocalOnlyQuestions) m->NewLocalOnlyQuestions = question; @@ -5784,6 +5148,18 @@ mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const que else { if (!m->NewQuestions) m->NewQuestions = question; + + // If the question's id is non-zero, then it's Wide Area + // MUST NOT do this Wide Area setup until near the end of + // mDNS_StartQuery_internal -- this code may itself issue queries (e.g. SOA, + // NS, etc.) and if we haven't finished setting up our own question and setting + // m->NewQuestions if necessary then we could end up recursively re-entering + // this routine with the question list data structures in an inconsistent state. + if (!mDNSOpaque16IsZero(question->TargetQID)) + { + question->qDNSServer = GetServerForName(m, &question->qname); + ActivateUnicastQuery(m, question); + } SetNextQueryTime(m,question); } @@ -5791,15 +5167,23 @@ mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const que } } -mDNSlocal mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question) +// CancelGetZoneData is an internal routine (i.e. must be called with the lock already held) +mDNSexport void CancelGetZoneData(mDNS *const m, ZoneData *nta) + { + LogOperation("CancelGetZoneData %##s (%s)", nta->question.qname.c, DNSTypeName(nta->question.qtype)); + mDNS_StopQuery_internal(m, &nta->question); + mDNSPlatformMemFree(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); CacheRecord *rr; DNSQuestion **q = &m->Questions; - - if (uDNS_IsActiveQuery(question, &m->uDNS_info)) return uDNS_StopQuery(m, question); + //LogOperation("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); + if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions; while (*q && *q != question) q=&(*q)->next; if (*q) *q = (*q)->next; @@ -5808,6 +5192,9 @@ mDNSlocal mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const ques if (question->ThisQInterval >= 0) // Only log error message if the query was supposed to be active LogMsg("mDNS_StopQuery_internal: Question %##s (%s) not found in active list", question->qname.c, DNSTypeName(question->qtype)); +#if ForceAlerts + *(long*)0 = 0; +#endif return(mStatus_BadReferenceErr); } @@ -5816,8 +5203,8 @@ mDNSlocal mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const ques // But don't trash ThisQInterval until afterwards. question->ThisQInterval = -1; - // If there are any cache records referencing this as their active question, then see if any other - // question that is also referencing them, else their CRActiveQuestion needs to get set to NULL. + // If there are any cache records referencing this as their active question, then see if there is any + // other question that is also referencing them, else their CRActiveQuestion needs to get set to NULL. for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) { if (rr->CRActiveQuestion == question) @@ -5826,13 +5213,13 @@ mDNSlocal mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const ques for (q = m->Questions; q; q=q->next) // Scan our list of questions if (ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q)) break; - verbosedebugf("mDNS_StopQuery_internal: Cache RR %##s (%s) setting CRActiveQuestion to %p", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), q); + debugf("mDNS_StopQuery_internal: Updating CRActiveQuestion to %p for cache record %s", q, CRDisplayString(m,rr)); rr->CRActiveQuestion = q; // Question used to be active; new value may or may not be null if (!q) m->rrcache_active--; // If no longer active, decrement rrcache_active count } } - // If we just deleted the question that CacheRecordAdd() or CacheRecordRmv()is about to look at, + // If we just deleted the question that CacheRecordAdd() or CacheRecordRmv() is about to look at, // bump its pointer forward one question. if (m->CurrentQuestion == question) { @@ -5852,6 +5239,18 @@ mDNSlocal mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const ques // Take care not to trash question->next until *after* we've updated m->CurrentQuestion and m->NewQuestions question->next = mDNSNULL; + + // LogMsg("mDNS_StopQuery_internal: Question %##s (%s) removed", question->qname.c, DNSTypeName(question->qtype)); + + // And finally, cancel any associated GetZoneData operation that's still running. + // Must not do this until last, because there's a good chance the GetZoneData question is the next in the list, + // so if we delete it earlier in this routine, we could find that our "question->next" pointer above is already + // invalid before we even use it. By making sure that we update m->CurrentQuestion and m->NewQuestions if necessary + // *first*, then they're all ready to be updated a second time if necessary when we cancel our GetZoneData query. + if (question->nta) CancelGetZoneData(m, question->nta); + if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; } + if (!mDNSOpaque16IsZero(question->TargetQID) && question->LongLived) uDNS_StopLongLivedQuery(m, question); + return(mStatus_NoError); } @@ -5873,11 +5272,44 @@ mDNSexport mStatus mDNS_StopQuery(mDNS *const m, DNSQuestion *const question) return(status); } -mDNSexport mStatus mDNS_Reconfirm(mDNS *const m, CacheRecord *const rr) +// Note that mDNS_StopQueryWithRemoves() does not currently implement the full generality of the other APIs +// Specifically, question callbacks invoked as a result of this call cannot themselves make API calls. +// We invoke the callback without using mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback +// specifically to catch and report if the client callback does try to make API calls +mDNSexport mStatus mDNS_StopQueryWithRemoves(mDNS *const m, DNSQuestion *const question) + { + mStatus status; + DNSQuestion *qq; + mDNS_Lock(m); + + // Check if question is new -- don't want to give remove events for a question we haven't even answered yet + for (qq = m->NewQuestions; qq; qq=qq->next) if (qq == question) break; + + status = mDNS_StopQuery_internal(m, question); + if (status == mStatus_NoError && !qq) + { + CacheRecord *rr; + const mDNSu32 slot = HashSlot(&question->qname); + CacheGroup *const cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname); + LogOperation("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)) + { + // Don't use mDNS_DropLockBeforeCallback() here, since we don't allow API calls + if (question->QuestionCallback) + question->QuestionCallback(m, question, &rr->resrec, mDNSfalse); + } + } + mDNS_Unlock(m); + return(status); + } + +mDNSexport mStatus mDNS_Reconfirm(mDNS *const m, CacheRecord *const cr) { mStatus status; mDNS_Lock(m); - status = mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForNoAnswer); + status = mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); + if (status == mStatus_NoError) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, 0); mDNS_Unlock(m); return(status); } @@ -5888,7 +5320,9 @@ mDNSexport mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr CacheRecord *cr; mDNS_Lock(m); cr = FindIdenticalRecordInCache(m, rr); + debugf("mDNS_ReconfirmByValue: %p %s", cr, RRDisplayString(m, rr)); if (cr) status = mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); + if (status == mStatus_NoError) ReconfirmAntecedents(m, cr->resrec.name, cr->resrec.namehash, 0); mDNS_Unlock(m); return(status); } @@ -5904,30 +5338,20 @@ mDNSexport mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question, question->LongLived = mDNSfalse; question->ExpectUnique = mDNSfalse; question->ForceMCast = ForceMCast; + question->ReturnIntermed = mDNSfalse; question->QuestionCallback = Callback; question->QuestionContext = Context; if (!ConstructServiceName(&question->qname, mDNSNULL, srv, domain)) return(mStatus_BadParamErr); #ifndef UNICAST_DISABLED - if (question->InterfaceID == mDNSInterface_LocalOnly || question->ForceMCast || IsLocalDomain(&question->qname)) - { - question->LongLived = mDNSfalse; - question->uDNS_info.id = zeroID; - return(mDNS_StartQuery(m, question)); - } - else + if (question->InterfaceID != mDNSInterface_LocalOnly && !question->ForceMCast && !IsLocalDomain(&question->qname)) { - mStatus status; - // Need to explicitly lock here, because mDNS_StartQuery does locking but uDNS_StartQuery does not - mDNS_Lock(m); - question->LongLived = mDNStrue; - status = uDNS_StartQuery(m, question); - mDNS_Unlock(m); - return(status); + question->LongLived = mDNStrue; + question->ThisQInterval = InitialQuestionInterval; + question->LastQTime = m->timenow - question->ThisQInterval; } -#else - return(mDNS_StartQuery(m, question)); #endif // UNICAST_DISABLED + return(mDNS_StartQuery(m, question)); } mDNSlocal mDNSBool MachineHasActiveIPv6(mDNS *const m) @@ -5938,10 +5362,10 @@ mDNSlocal mDNSBool MachineHasActiveIPv6(mDNS *const m) return(mDNSfalse); } -mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) +mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) { ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext; - mDNSBool PortChanged = (mDNSBool)(query->info->port.NotAnInteger != answer->rdata->u.srv.port.NotAnInteger); + mDNSBool PortChanged = !mDNSSameIPPort(query->info->port, answer->rdata->u.srv.port); if (!AddRecord) return; if (answer->rrtype != kDNSType_SRV) return; @@ -5982,7 +5406,7 @@ mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const R query->qAv6.InterfaceID = answer->InterfaceID; AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target); } - debugf("FoundServiceInfoSRV: Restarting address queries for %##s", query->qAv4.qname.c); + debugf("FoundServiceInfoSRV: Restarting address queries for %##s (%s)", query->qAv4.qname.c, DNSTypeName(query->qAv4.qtype)); mDNS_StartQuery(m, &query->qAv4); // Only do the AAAA query if this machine actually has IPv6 active if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6); @@ -5999,7 +5423,7 @@ mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const R // callback function is allowed to do anything, including deleting this query and freeing its memory. } -mDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) +mDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) { ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext; if (!AddRecord) return; @@ -6009,7 +5433,7 @@ mDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const R query->GotTXT = mDNStrue; query->info->TXTlen = answer->rdlength; query->info->TXTinfo[0] = 0; // In case answer->rdlength is zero - mDNSPlatformMemCopy(answer->rdata->u.txt.c, query->info->TXTinfo, answer->rdlength); + mDNSPlatformMemCopy(query->info->TXTinfo, answer->rdata->u.txt.c, answer->rdlength); verbosedebugf("FoundServiceInfoTXT: %##s GotADD=%d", query->info->name.c, query->GotADD); @@ -6024,7 +5448,7 @@ mDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const R } } -mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) +mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) { ServiceInfoQuery *query = (ServiceInfoQuery *)question->QuestionContext; //LogOperation("FoundServiceInfo %d %s", AddRecord, RRDisplayString(m, answer)); @@ -6056,12 +5480,10 @@ mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const Reso if (query->ServiceInfoQueryCallback && query->GotTXT) { if (++query->Answers >= 100) - { - if (answer->rrtype == kDNSType_A) - debugf("**** WARNING **** have given %lu answers for %##s (A) %.4a", query->Answers, query->qSRV.qname.c, &answer->rdata->u.ipv4); - else - debugf("**** WARNING **** have given %lu answers for %##s (AAAA) %.16a", query->Answers, query->qSRV.qname.c, &answer->rdata->u.ipv6); - } + debugf(answer->rrtype == kDNSType_A ? + "**** WARNING **** have given %lu answers for %##s (A) %.4a" : + "**** WARNING **** have given %lu answers for %##s (AAAA) %.16a", + query->Answers, query->qSRV.qname.c, &answer->rdata->u.data); query->ServiceInfoQueryCallback(m, query); } } @@ -6085,6 +5507,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m, query->qSRV.LongLived = mDNSfalse; query->qSRV.ExpectUnique = mDNStrue; query->qSRV.ForceMCast = mDNSfalse; + query->qSRV.ReturnIntermed = mDNSfalse; query->qSRV.QuestionCallback = FoundServiceInfoSRV; query->qSRV.QuestionContext = query; @@ -6097,6 +5520,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m, query->qTXT.LongLived = mDNSfalse; query->qTXT.ExpectUnique = mDNStrue; query->qTXT.ForceMCast = mDNSfalse; + query->qTXT.ReturnIntermed = mDNSfalse; query->qTXT.QuestionCallback = FoundServiceInfoTXT; query->qTXT.QuestionContext = query; @@ -6109,6 +5533,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m, query->qAv4.LongLived = mDNSfalse; query->qAv4.ExpectUnique = mDNStrue; query->qAv4.ForceMCast = mDNSfalse; + query->qAv4.ReturnIntermed = mDNSfalse; query->qAv4.QuestionCallback = FoundServiceInfo; query->qAv4.QuestionContext = query; @@ -6121,6 +5546,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m, query->qAv6.LongLived = mDNSfalse; query->qAv6.ExpectUnique = mDNStrue; query->qAv6.ForceMCast = mDNSfalse; + query->qAv6.ReturnIntermed = mDNSfalse; query->qAv6.QuestionCallback = FoundServiceInfo; query->qAv6.QuestionContext = query; @@ -6152,10 +5578,10 @@ mDNSexport void mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *q) { mDNS_Lock(m); // We use mDNS_StopQuery_internal here because we're already holding the lock - if (q->qSRV.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qSRV, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qSRV); - if (q->qTXT.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qTXT, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qTXT); - if (q->qAv4.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qAv4, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qAv4); - if (q->qAv6.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qAv6, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qAv6); + if (q->qSRV.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qSRV); + if (q->qTXT.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qTXT); + if (q->qAv4.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qAv4); + if (q->qAv6.ThisQInterval >= 0) mDNS_StopQuery_internal(m, &q->qAv6); mDNS_Unlock(m); } @@ -6169,6 +5595,7 @@ mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, m question->LongLived = mDNSfalse; question->ExpectUnique = mDNSfalse; question->ForceMCast = mDNSfalse; + question->ReturnIntermed = mDNSfalse; question->QuestionCallback = Callback; question->QuestionContext = Context; if (DomainType > mDNS_DomainTypeMax) return(mStatus_BadParamErr); @@ -6203,7 +5630,10 @@ mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newt #endif if (!ValidateRData(rr->resrec.rrtype, newrdlength, newrdata)) - { LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(&rr->resrec, &newrdata->u, m->MsgBuffer)); return(mStatus_Invalid); } + { + LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(&rr->resrec, &newrdata->u, m->MsgBuffer)); + return(mStatus_Invalid); + } mDNS_Lock(m); @@ -6226,7 +5656,8 @@ mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newt if (unicast) { mStatus status = uDNS_UpdateRecord(m, rr); mDNS_Unlock(m); return(status); } - if (rr->resrec.rroriginalttl == newttl && rr->resrec.rdlength == newrdlength && mDNSPlatformMemSame(rr->resrec.rdata->u.data, newrdata->u.data, newrdlength)) + if (rr->resrec.rroriginalttl == newttl && + rr->resrec.rdlength == newrdlength && mDNSPlatformMemSame(rr->resrec.rdata->u.data, newrdata->u.data, newrdlength)) CompleteRDataUpdate(m, rr); else { @@ -6252,7 +5683,8 @@ mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newt if (!rr->UpdateBlocked) rr->UpdateBlocked = NonZeroTime(m->timenow + (mDNSs32)delay * mDNSPlatformOneSecond); rr->ThisAPInterval *= 4; rr->LastAPTime = rr->UpdateBlocked - rr->ThisAPInterval; - LogMsg("Excessive update rate for %##s; delaying announcement by %ld second%s", rr->resrec.name->c, delay, delay > 1 ? "s" : ""); + LogMsg("Excessive update rate for %##s; delaying announcement by %ld second%s", + rr->resrec.name->c, delay, delay > 1 ? "s" : ""); } rr->resrec.rroriginalttl = newttl; } @@ -6273,7 +5705,8 @@ mDNSexport mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr) return(status); } -mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result); +// Circular reference: AdvertiseInterface references mDNS_HostNameCallback, which calls mDNS_SetFQDN, which call AdvertiseInterface +mDNSlocal void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result); mDNSlocal NetworkInterfaceInfo *FindFirstAdvertisedInterface(mDNS *const m) { @@ -6285,7 +5718,7 @@ mDNSlocal NetworkInterfaceInfo *FindFirstAdvertisedInterface(mDNS *const m) mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set) { - char buffer[256]; + char buffer[MAX_REVERSE_MAPPING_NAME]; NetworkInterfaceInfo *primary = FindFirstAdvertisedInterface(m); if (!primary) primary = set; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary @@ -6301,12 +5734,12 @@ mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set) #endif // 1. Set up Address record to map from host name ("foo.local.") to IP address // 2. Set up reverse-lookup PTR record to map from our address back to our host name - AssignDomainName(set->RR_A.resrec.name, &m->MulticastHostname); + AssignDomainName(&set->RR_A.namestorage, &m->MulticastHostname); if (set->ip.type == mDNSAddrType_IPv4) { set->RR_A.resrec.rrtype = kDNSType_A; set->RR_A.resrec.rdata->u.ipv4 = set->ip.ip.v4; - // Note: This is reverse order compared to a normal dotted-decimal IP address + // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", set->ip.ip.v4.b[3], set->ip.ip.v4.b[2], set->ip.ip.v4.b[1], set->ip.ip.v4.b[0]); } @@ -6326,23 +5759,23 @@ mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set) mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa."); } - MakeDomainNameFromDNSNameString(set->RR_PTR.resrec.name, buffer); - set->RR_PTR.HostTarget = mDNStrue; // Tell mDNS that the target of this PTR is to be kept in sync with our host name - set->RR_PTR.ForceMCast = mDNStrue; // This PTR points to our dot-local name, so don't ever try to write it into a uDNS server + MakeDomainNameFromDNSNameString(&set->RR_PTR.namestorage, buffer); + set->RR_PTR.AutoTarget = Target_AutoHost; // Tell mDNS that the target of this PTR is to be kept in sync with our host name + set->RR_PTR.ForceMCast = mDNStrue; // This PTR points to our dot-local name, so don't ever try to write it into a uDNS server - set->RR_A.RRSet = &primary->RR_A; // May refer to self + set->RR_A.RRSet = &primary->RR_A; // May refer to self mDNS_Register_internal(m, &set->RR_A); mDNS_Register_internal(m, &set->RR_PTR); - if (m->HIHardware.c[0] > 0 && m->HISoftware.c[0] > 0 && m->HIHardware.c[0] + m->HISoftware.c[0] <= 254) + if (!NO_HINFO && m->HIHardware.c[0] > 0 && m->HISoftware.c[0] > 0 && m->HIHardware.c[0] + m->HISoftware.c[0] <= 254) { mDNSu8 *p = set->RR_HINFO.resrec.rdata->u.data; - AssignDomainName(set->RR_HINFO.resrec.name, &m->MulticastHostname); + AssignDomainName(&set->RR_HINFO.namestorage, &m->MulticastHostname); set->RR_HINFO.DependentOn = &set->RR_A; - mDNSPlatformMemCopy(&m->HIHardware, p, 1 + (mDNSu32)m->HIHardware.c[0]); + mDNSPlatformMemCopy(p, &m->HIHardware, 1 + (mDNSu32)m->HIHardware.c[0]); p += 1 + (int)p[0]; - mDNSPlatformMemCopy(&m->HISoftware, p, 1 + (mDNSu32)m->HISoftware.c[0]); + mDNSPlatformMemCopy(p, &m->HISoftware, 1 + (mDNSu32)m->HISoftware.c[0]); mDNS_Register_internal(m, &set->RR_HINFO); } else @@ -6382,11 +5815,11 @@ mDNSexport void mDNS_SetFQDN(mDNS *const m) if (!AppendDomainLabel(&newmname, &m->hostlabel)) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; } if (!AppendLiteralLabelString(&newmname, "local")) { LogMsg("ERROR: mDNS_SetFQDN: Cannot create MulticastHostname"); return; } - if (SameDomainName(&m->MulticastHostname, &newmname)) { LogMsg("mDNS_SetFQDN - hostname unchanged"); return; } + if (SameDomainNameCS(&m->MulticastHostname, &newmname)) { LogMsg("mDNS_SetFQDN - hostname unchanged"); return; } mDNS_Lock(m); - AssignDomainName(&m->MulticastHostname, &newmname); + AssignDomainName(&m->MulticastHostname, &newmname); // 1. Stop advertising our address records on all interfaces for (intf = m->HostInterfaces; intf; intf = intf->next) if (intf->Advertise) DeadvertiseInterface(m, intf); @@ -6397,13 +5830,13 @@ mDNSexport void mDNS_SetFQDN(mDNS *const m) // 3. Make sure that any SRV records (and the like) that reference our // host name in their rdata get updated to reference this new host name - for (rr = m->ResourceRecords; rr; rr=rr->next) if (rr->HostTarget) SetTargetToHostName(m, rr); - for (rr = m->DuplicateRecords; rr; rr=rr->next) if (rr->HostTarget) SetTargetToHostName(m, rr); - + for (rr = m->ResourceRecords; rr; rr=rr->next) if (rr->AutoTarget) SetTargetToHostName(m, rr); + for (rr = m->DuplicateRecords; rr; rr=rr->next) if (rr->AutoTarget) SetTargetToHostName(m, rr); + mDNS_Unlock(m); } -mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result) +mDNSlocal void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result) { (void)rr; // Unused parameter @@ -6420,11 +5853,7 @@ mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStat { // Notify the client that the host name is successfully registered if (m->MainCallback) - { - m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback - m->MainCallback(m, result); - m->mDNS_reentrancy--; // Decrement to block mDNS API calls again - } + m->MainCallback(m, mStatus_NoError); } else if (result == mStatus_NameConflict) { @@ -6432,14 +5861,12 @@ mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStat // 1. First give the client callback a chance to pick a new name if (m->MainCallback) - { - m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback m->MainCallback(m, mStatus_NameConflict); - m->mDNS_reentrancy--; // Decrement to block mDNS API calls again - } // 2. If the client callback didn't do it, add (or increment) an index ourselves - if (SameDomainLabel(m->hostlabel.c, oldlabel.c)) + // This needs to be case-insensitive compare, because we need to know that the name has been changed so as to + // remedy the conflict, and a name that differs only in capitalization will just suffer the exact same conflict again. + if (SameDomainLabelCS(m->hostlabel.c, oldlabel.c)) IncrementLabelSuffix(&m->hostlabel, mDNSfalse); // 3. Generate the FQDNs from the hostlabel, @@ -6470,7 +5897,7 @@ mDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *act } } -mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSs32 delay) +mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping) { mDNSBool FirstOfType = mDNStrue; NetworkInterfaceInfo **p = &m->HostInterfaces; @@ -6483,11 +5910,12 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s mDNS_Lock(m); - // Assume this interface will be active + // Assume this interface will be active now, unless we find a duplicate already in the list set->InterfaceActive = mDNStrue; set->IPv4Available = (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx); set->IPv6Available = (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx); + // Scan list to see if this InterfaceID is already represented while (*p) { if (*p == set) @@ -6497,9 +5925,9 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s return(mStatus_AlreadyRegistered); } - // This InterfaceID is already in the list, so mark this interface inactive for now if ((*p)->InterfaceID == set->InterfaceID) { + // This InterfaceID already represented by a different interface in the list, so mark this instance inactive for now set->InterfaceActive = mDNSfalse; if (set->ip.type == (*p)->ip.type) FirstOfType = mDNSfalse; if (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx) (*p)->IPv4Available = mDNStrue; @@ -6515,12 +5943,12 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s if (set->Advertise) AdvertiseInterface(m, set); - debugf("mDNS_RegisterInterface: InterfaceID %p %#a %s", set->InterfaceID, &set->ip, + LogOperation("mDNS_RegisterInterface: InterfaceID %p %s (%#a) %s", set->InterfaceID, set->ifname, &set->ip, set->InterfaceActive ? "not represented in list; marking active and retriggering queries" : "already represented in list; marking inactive for now"); - // In some versions of OS X the IPv6 address remains on an interface even when the interface is turned off, + // In early versions of OS X the IPv6 address remains on an interface even when the interface is turned off, // giving the false impression that there's an active representative of this interface when there really isn't. // Therefore, when registering an interface, we want to re-trigger our questions and re-probe our Resource Records, // even if we believe that we previously had an active representative of this interface. @@ -6528,31 +5956,42 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s { DNSQuestion *q; AuthRecord *rr; - mDNSs32 initial = InitialQuestionInterval; + // If flapping, delay between first and second queries is eight seconds instead of one + mDNSs32 delay = flapping ? mDNSPlatformOneSecond * 5 : 0; + mDNSu8 announce = flapping ? (mDNSu8)1 : InitialAnnounceCount; // 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 to all go and hit the network with identical queries at exactly the same moment. + // 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. if (!m->SuppressSending) m->SuppressSending = m->timenow + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval); - if (delay) + if (flapping) { - LogMsg("Repeated transitions for interface %s (%#a); delaying packets by %d seconds", - set->ifname, &set->ip, delay/mDNSPlatformOneSecond); - initial = InitialQuestionInterval * 8; // Delay between first and second queries is eight seconds + LogMsg("Note: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect", set->ifname, &set->ip); if (!m->SuppressProbes || m->SuppressProbes - (m->timenow + delay) < 0) m->SuppressProbes = (m->timenow + delay); } - for (q = m->Questions; q; q=q->next) // Scan our list of questions - if (!q->InterfaceID || q->InterfaceID == set->InterfaceID) // If non-specific Q, or Q on this specific interface, - { // then reactivate this question - q->ThisQInterval = initial; // MUST be > zero for an active question - q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it - q->LastQTime = m->timenow - q->ThisQInterval + delay; - q->RecentAnswerPkts = 0; - SetNextQueryTime(m,q); - } + + for (q = m->Questions; q; q=q->next) // Scan our list of questions + if (mDNSOpaque16IsZero(q->TargetQID)) + if (!q->InterfaceID || q->InterfaceID == set->InterfaceID) // If non-specific Q, or Q on this specific interface, + { // then reactivate this question + mDNSBool dodelay = flapping && (q->FlappingInterface1 == set->InterfaceID || q->FlappingInterface2 == set->InterfaceID); + mDNSs32 initial = dodelay ? InitialQuestionInterval * QuestionIntervalStep2 : InitialQuestionInterval; + mDNSs32 qdelay = dodelay ? mDNSPlatformOneSecond * 5 : 0; + if (dodelay) LogOperation("No cache records for expired %##s (%s); okay to delay questions a little", q->qname.c, DNSTypeName(q->qtype)); + + if (!q->ThisQInterval || q->ThisQInterval > initial) + { + q->ThisQInterval = initial; + q->RequestUnicast = 2; // Set to 2 because is decremented once *before* we check it + } + q->LastQTime = m->timenow - q->ThisQInterval + qdelay; + q->RecentAnswerPkts = 0; + SetNextQueryTime(m,q); + } // For all our non-specific authoritative resource records (and any dormant records specific to this interface) // we now need them to re-probe if necessary, and then re-announce. @@ -6561,7 +6000,7 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s { if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique; rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); - rr->AnnounceCount = delay ? (mDNSu8)1 : InitialAnnounceCount; + if (rr->AnnounceCount < announce) rr->AnnounceCount = announce; rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType); InitializeLastAPTime(m, rr); } @@ -6574,7 +6013,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) +mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping) { NetworkInterfaceInfo **p = &m->HostInterfaces; @@ -6610,8 +6049,8 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se break; if (intf) { - debugf("mDNS_DeregisterInterface: Another representative of InterfaceID %p exists; making it active", - set->InterfaceID); + LogOperation("mDNS_DeregisterInterface: Another representative of InterfaceID %p %s (%#a) exists;" + " making it active", set->InterfaceID, set->ifname, &set->ip); intf->InterfaceActive = mDNStrue; UpdateInterfaceProtocols(m, intf); @@ -6628,19 +6067,52 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se CacheGroup *cg; CacheRecord *rr; DNSQuestion *q; - debugf("mDNS_DeregisterInterface: Last representative of InterfaceID %p deregistered; marking questions etc. dormant", - set->InterfaceID); + DNSServer *s; + + LogOperation("mDNS_DeregisterInterface: Last representative of InterfaceID %p %s (%#a) deregistered;" + " marking questions etc. dormant", set->InterfaceID, set->ifname, &set->ip); - // 1. Deactivate any questions specific to this interface + if (flapping) + LogMsg("Note: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect", + set->ifname, &set->ip); + + // 1. Deactivate any questions specific to this interface, and tag appropriate questions + // so that mDNS_RegisterInterface() knows how swiftly it needs to reactivate them for (q = m->Questions; q; q=q->next) - if (q->InterfaceID == set->InterfaceID) - q->ThisQInterval = 0; + { + if (q->InterfaceID == set->InterfaceID) q->ThisQInterval = 0; + if (!q->InterfaceID || q->InterfaceID == set->InterfaceID) + { + q->FlappingInterface2 = q->FlappingInterface1; + q->FlappingInterface1 = set->InterfaceID; // Keep history of the last two interfaces to go away + } + } // 2. Flush any cache records received on this interface revalidate = mDNSfalse; // Don't revalidate if we're flushing the records FORALL_CACHERECORDS(slot, cg, rr) if (rr->resrec.InterfaceID == set->InterfaceID) - PurgeCacheResourceRecord(m, rr); + { + // If this interface is deemed flapping, + // postpone deleting the cache records in case the interface comes back again + if (!flapping) mDNS_PurgeCacheResourceRecord(m, rr); + else + { + // We want these record to go away in 30 seconds + // 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 + mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface); + rr->UnansweredQueries = MaxUnansweredQueries; + } + } + + // 3. Any DNS servers specific to this interface are now unusable + for (s = m->DNSServers; s; s = s->next) + if (s->interface == set->InterfaceID) + { + s->interface = mDNSInterface_Any; + s->teststate = DNSServer_Disabled; + } } } @@ -6659,7 +6131,7 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se m->NextCacheCheck = m->timenow; FORALL_CACHERECORDS(slot, cg, rr) if (rr->resrec.InterfaceID == set->InterfaceID) - mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForCableDisconnect); + mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface); } mDNS_Unlock(m); @@ -6717,6 +6189,46 @@ mDNSlocal void NSSCallback(mDNS *const m, AuthRecord *const rr, mStatus result) sr->ServiceCallback(m, sr, result); } +mDNSlocal mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs) + { + mDNSu32 i; + ServiceRecordSet **p = &m->ServiceRegistrations; + while (*p && *p != srs) p=&(*p)->uDNS_next; + if (*p) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs, srs->RR_SRV.resrec.name->c); return(mStatus_AlreadyRegistered); } + + srs->uDNS_next = mDNSNULL; + *p = srs; + + srs->RR_SRV.resrec.rroriginalttl = kHostNameTTL; + srs->RR_TXT.resrec.rroriginalttl = kStandardTTL; + srs->RR_PTR.resrec.rroriginalttl = kStandardTTL; + for (i = 0; i < srs->NumSubTypes;i++) srs->SubTypes[i].resrec.rroriginalttl = kStandardTTL; + + srs->srs_uselease = mDNStrue; + + if (srs->RR_SRV.AutoTarget) + { + // For autotunnel services pointing at our IPv6 ULA we don't need or want a NAT mapping, but for all other + // advertised services referencing our uDNS hostname, we want NAT mappings automatically created as appropriate, + // with the port number in our advertised SRV record automatically tracking the external mapped port. + DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name); + if (!AuthInfo || !AuthInfo->AutoTunnel) srs->RR_SRV.AutoTarget = Target_AutoHostAndNATMAP; + } + + if (!GetServiceTarget(m, srs)) + { + // defer registration until we've got a target + debugf("uDNS_RegisterService - no target for %##s", srs->RR_SRV.resrec.name->c); + srs->state = regState_NoTarget; + srs->nta = mDNSNULL; + return mStatus_NoError; + } + + srs->state = regState_FetchingZoneData; + srs->nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationZoneDataComplete, srs); + return srs->nta ? mStatus_NoError : mStatus_NoMemoryErr; + } + // Note: // Name is first label of domain name (any dots in the name are actual dots, not label separators) // Type is service type (e.g. "_ipp._tcp.") @@ -6725,6 +6237,7 @@ mDNSlocal void NSSCallback(mDNS *const m, AuthRecord *const rr, mStatus result) // left waiting forever looking for a nonexistent record.) // If the host parameter is mDNSNULL or the root domain (ASCII NUL), // then the default host name (m->MulticastHostname) is automatically used +// If the optional target host parameter is set, then the storage it points to must remain valid for the lifetime of the service registration mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr, const domainlabel *const name, const domainname *const type, const domainname *const domain, const domainname *const host, mDNSIPPort port, const mDNSu8 txtinfo[], mDNSu16 txtlen, @@ -6734,24 +6247,41 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr, mStatus err; mDNSu32 i; + sr->state = regState_Zero; + sr->srs_uselease = 0; + sr->expire = 0; + sr->TestForSelfConflict = 0; + sr->Private = 0; + sr->id = zeroID; + sr->zone.c[0] = 0; + sr->ns = zeroAddr; + sr->SRSUpdatePort = zeroIPPort; + mDNSPlatformMemZero(&sr->NATinfo, sizeof(sr->NATinfo)); + sr->ClientCallbackDeferred = 0; + sr->DeferredStatus = 0; + sr->SRVUpdateDeferred = 0; + sr->SRVChanged = 0; + sr->tcp = mDNSNULL; + sr->ServiceCallback = Callback; sr->ServiceContext = Context; + sr->Conflict = mDNSfalse; + sr->Extras = mDNSNULL; sr->NumSubTypes = NumSubTypes; sr->SubTypes = SubTypes; - sr->Conflict = mDNSfalse; - if (host && host->c[0]) sr->Host = *host; - else sr->Host.c[0] = 0; - // If port number is zero, that means the client is really trying to do a RegisterNoSuchService - if (!port.NotAnInteger) return(mDNS_RegisterNoSuchService(m, &sr->RR_SRV, name, type, domain, mDNSNULL, mDNSInterface_Any, NSSCallback, sr)); - // Initialize the AuthRecord objects to sane values + // Need to initialize everything correctly *before* making the decision whether to do a RegisterNoSuchService and bail out mDNS_SetupResourceRecord(&sr->RR_ADV, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeAdvisory, ServiceCallback, sr); mDNS_SetupResourceRecord(&sr->RR_PTR, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, ServiceCallback, sr); mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique, ServiceCallback, sr); mDNS_SetupResourceRecord(&sr->RR_TXT, mDNSNULL, InterfaceID, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnique, ServiceCallback, sr); + // If port number is zero, that means the client is really trying to do a RegisterNoSuchService + if (mDNSIPPortIsZero(port)) + return(mDNS_RegisterNoSuchService(m, &sr->RR_SRV, name, type, domain, mDNSNULL, mDNSInterface_Any, NSSCallback, sr)); + // If the client is registering an oversized TXT record, // it is the client's responsibility to alloate a ServiceRecordSet structure that is large enough for it if (sr->RR_TXT.resrec.rdata->MaxRDLength < txtlen) @@ -6760,11 +6290,11 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr, // Set up the record names // For now we only create an advisory record for the main type, not for subtypes // We need to gain some operational experience before we decide if there's a need to create them for subtypes too - if (ConstructServiceName(sr->RR_ADV.resrec.name, (domainlabel*)"\x09_services", (domainname*)"\x07_dns-sd\x04_udp", domain) == mDNSNULL) + if (ConstructServiceName(&sr->RR_ADV.namestorage, (const domainlabel*)"\x09_services", (const domainname*)"\x07_dns-sd\x04_udp", domain) == mDNSNULL) return(mStatus_BadParamErr); - if (ConstructServiceName(sr->RR_PTR.resrec.name, mDNSNULL, type, domain) == mDNSNULL) return(mStatus_BadParamErr); - if (ConstructServiceName(sr->RR_SRV.resrec.name, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr); - AssignDomainName(sr->RR_TXT.resrec.name, sr->RR_SRV.resrec.name); + if (ConstructServiceName(&sr->RR_PTR.namestorage, mDNSNULL, type, domain) == mDNSNULL) return(mStatus_BadParamErr); + if (ConstructServiceName(&sr->RR_SRV.namestorage, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr); + AssignDomainName(&sr->RR_TXT.namestorage, sr->RR_SRV.resrec.name); // 1. Set up the ADV record rdata to advertise our service type AssignDomainName(&sr->RR_ADV.resrec.rdata->u.name, sr->RR_PTR.resrec.name); @@ -6785,8 +6315,8 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr, st.c[1+st.c[0]] = 0; // Only want the first label, not the whole FQDN (particularly for mDNS_RenameAndReregisterService()) AppendDomainName(&st, type); mDNS_SetupResourceRecord(&sr->SubTypes[i], mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, ServiceCallback, sr); - if (ConstructServiceName(sr->SubTypes[i].resrec.name, mDNSNULL, &st, domain) == mDNSNULL) return(mStatus_BadParamErr); - AssignDomainName(&sr->SubTypes[i].resrec.rdata->u.name, sr->RR_SRV.resrec.name); + if (ConstructServiceName(&sr->SubTypes[i].namestorage, mDNSNULL, &st, domain) == mDNSNULL) return(mStatus_BadParamErr); + AssignDomainName(&sr->SubTypes[i].resrec.rdata->u.name, &sr->RR_SRV.namestorage); sr->SubTypes[i].Additional1 = &sr->RR_SRV; sr->SubTypes[i].Additional2 = &sr->RR_TXT; } @@ -6796,9 +6326,9 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr, sr->RR_SRV.resrec.rdata->u.srv.weight = 0; sr->RR_SRV.resrec.rdata->u.srv.port = port; - // Setting HostTarget tells DNS that the target of this SRV is to be automatically kept in sync with our host name - if (sr->Host.c[0]) AssignDomainName(&sr->RR_SRV.resrec.rdata->u.srv.target, &sr->Host); - else { sr->RR_SRV.HostTarget = mDNStrue; sr->RR_SRV.resrec.rdata->u.srv.target.c[0] = '\0'; } + // Setting AutoTarget tells DNS that the target of this SRV is to be automatically kept in sync with our host name + if (host && host->c[0]) AssignDomainName(&sr->RR_SRV.resrec.rdata->u.srv.target, host); + else { sr->RR_SRV.AutoTarget = Target_AutoHost; sr->RR_SRV.resrec.rdata->u.srv.target.c[0] = '\0'; } // 4. Set up the TXT record rdata, // and set DependentOn because we're depending on the SRV record to find and resolve conflicts for us @@ -6807,14 +6337,14 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr, { sr->RR_TXT.resrec.rdlength = txtlen; if (sr->RR_TXT.resrec.rdlength > sr->RR_TXT.resrec.rdata->MaxRDLength) return(mStatus_BadParamErr); - mDNSPlatformMemCopy(txtinfo, sr->RR_TXT.resrec.rdata->u.txt.c, txtlen); + mDNSPlatformMemCopy(sr->RR_TXT.resrec.rdata->u.txt.c, txtinfo, txtlen); } sr->RR_TXT.DependentOn = &sr->RR_SRV; -#ifndef UNICAST_DISABLED +#ifndef UNICAST_DISABLED // If the client has specified an explicit InterfaceID, // then we do a multicast registration on that interface, even for unicast domains. - if (!(InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name))) + if (!(InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&sr->RR_SRV.namestorage))) { mStatus status; mDNS_Lock(m); @@ -6823,6 +6353,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr, // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here. // (We have to duplicate this check here because uDNS_RegisterService() bypasses the usual mDNS_Register_internal() bottleneck) if (!sr->RR_TXT.resrec.rdlength) { sr->RR_TXT.resrec.rdlength = 1; sr->RR_TXT.resrec.rdata->u.txt.c[0] = 0; } + status = uDNS_RegisterService(m, sr); mDNS_Unlock(m); return(status); @@ -6846,6 +6377,14 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr, return(err); } +mDNSlocal void DummyCallback(mDNS *const m, AuthRecord *rr, mStatus result) + { + (void)m; // Unused + (void)rr; // Unused + (void)result; // Unused + LogOperation("DummyCallback %d %s", result, ARDisplayString(m, rr)); + } + mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl) { @@ -6853,24 +6392,9 @@ mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, mStatus status; extra->next = mDNSNULL; - mDNS_SetupResourceRecord(&extra->r, rdata, sr->RR_PTR.resrec.InterfaceID, extra->r.resrec.rrtype, ttl, kDNSRecordTypeUnique, ServiceCallback, sr); - AssignDomainName(extra->r.resrec.name, sr->RR_SRV.resrec.name); - -#ifndef UNICAST_DISABLED - if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name))) - { - mDNS_Lock(m); - // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct, - // since RFC 1035 specifies a TXT record as "One or more s", not "Zero or more s". - // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here. - // (We have to duplicate this check here because uDNS_AddRecordToService() bypasses the usual mDNS_Register_internal() bottleneck) - if (extra->r.resrec.rrtype == kDNSType_TXT && extra->r.resrec.rdlength == 0) - { extra->r.resrec.rdlength = 1; extra->r.resrec.rdata->u.txt.c[0] = 0; } - status = uDNS_AddRecordToService(m, sr, extra); - mDNS_Unlock(m); - return status; - } -#endif + mDNS_SetupResourceRecord(&extra->r, rdata, sr->RR_PTR.resrec.InterfaceID, + extra->r.resrec.rrtype, ttl, kDNSRecordTypeUnique, ServiceCallback, sr); + AssignDomainName(&extra->r.namestorage, sr->RR_SRV.resrec.name); mDNS_Lock(m); e = &sr->Extras; @@ -6879,16 +6403,30 @@ mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, if (ttl == 0) ttl = kStandardTTL; extra->r.DependentOn = &sr->RR_SRV; - - debugf("mDNS_AddRecordToService adding record to %##s", extra->r.resrec.name->c); - + + debugf("mDNS_AddRecordToService adding record to %##s %s %d", + extra->r.resrec.name->c, DNSTypeName(extra->r.resrec.rrtype), extra->r.resrec.rdlength); + status = mDNS_Register_internal(m, &extra->r); - if (status == mStatus_NoError) *e = extra; + if (status == mStatus_NoError) + { + *e = extra; +#ifndef UNICAST_DISABLED + if (sr->RR_SRV.resrec.InterfaceID != mDNSInterface_LocalOnly && !IsLocalDomain(sr->RR_SRV.resrec.name)) + { + extra->r.resrec.RecordType = kDNSRecordTypeShared; // don't want it to conflict with the service name (???) + extra->r.RecordCallback = DummyCallback; // don't generate callbacks for extra RRs for unicast services (WHY NOT????) + if (sr->state != regState_Registered && sr->state != regState_Refresh) extra->r.state = regState_ExtraQueued; + } +#endif + } + mDNS_Unlock(m); return(status); } -mDNSexport mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, mDNSRecordCallback MemFreeCallback, void *Context) +mDNSexport mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, + mDNSRecordCallback MemFreeCallback, void *Context) { ExtraResourceRecord **e; mStatus status; @@ -6907,11 +6445,6 @@ mDNSexport mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet extra->r.RecordCallback = MemFreeCallback; extra->r.RecordContext = Context; *e = (*e)->next; -#ifndef UNICAST_DISABLED - if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name))) - status = uDNS_DeregisterRecord(m, &extra->r); - else -#endif status = mDNS_Deregister_internal(m, &extra->r, mDNS_Dereg_normal); } mDNS_Unlock(m); @@ -6924,7 +6457,7 @@ mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordS // mDNS_RegisterService() and mDNS_AddRecordToService(), which do the right locking internally. domainlabel name1, name2; domainname type, domain; - domainname *host = mDNSNULL; + const domainname *host = sr->RR_SRV.AutoTarget ? mDNSNULL : &sr->RR_SRV.resrec.rdata->u.srv.target; ExtraResourceRecord *extras = sr->Extras; mStatus err; @@ -6935,9 +6468,11 @@ mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordS IncrementLabelSuffix(&name2, mDNStrue); newname = &name2; } - LogMsg("Service \"%##s\" renamed to \"%#s\"", sr->RR_SRV.resrec.name->c, newname->c); - if (sr->RR_SRV.HostTarget == mDNSfalse && sr->Host.c[0]) host = &sr->Host; + if (SameDomainName(&domain, &localdomain)) + LogMsg("%##s service renamed from \"%#s\" to \"%#s\"", type.c, name1.c, newname->c); + else LogMsg("%##s service (domain %##s) renamed from \"%#s\" to \"%#s\"",type.c, domain.c, name1.c, newname->c); + err = mDNS_RegisterService(m, sr, newname, &type, &domain, host, sr->RR_SRV.resrec.rdata->u.srv.port, sr->RR_TXT.resrec.rdata->u.txt.c, sr->RR_TXT.resrec.rdlength, sr->SubTypes, sr->NumSubTypes, @@ -6962,9 +6497,9 @@ mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordS mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr) { // If port number is zero, that means this was actually registered using mDNS_RegisterNoSuchService() - if (!sr->RR_SRV.resrec.rdata->u.srv.port.NotAnInteger) return(mDNS_DeregisterNoSuchService(m, &sr->RR_SRV)); + if (mDNSIPPortIsZero(sr->RR_SRV.resrec.rdata->u.srv.port)) return(mDNS_DeregisterNoSuchService(m, &sr->RR_SRV)); -#ifndef UNICAST_DISABLED +#ifndef UNICAST_DISABLED if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name))) { mStatus status; @@ -6982,6 +6517,18 @@ mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr) else if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeDeregistering) { debugf("Service set for %##s already in the process of deregistering", sr->RR_SRV.resrec.name->c); + // Avoid race condition: + // If a service gets a conflict, then we set the Conflict flag to tell us to generate + // an mStatus_NameConflict message when we get the mStatus_MemFree for our PTR record. + // If the client happens to deregister the service in the middle of that process, then + // we clear the flag back to the normal state, so that we deliver a plain mStatus_MemFree + // instead of incorrectly promoting it to mStatus_NameConflict. + // This race condition is exposed particularly when the conformance test generates + // a whole batch of simultaneous conflicts across a range of services all advertised + // using the same system default name, and if we don't take this precaution then + // we end up incrementing m->nicelabel multiple times instead of just once. + // Bug when auto-renaming Computer Name after name collision + sr->Conflict = mDNSfalse; return(mStatus_NoError); } else @@ -7033,12 +6580,12 @@ mDNSexport mStatus mDNS_RegisterNoSuchService(mDNS *const m, AuthRecord *const r const mDNSInterfaceID InterfaceID, mDNSRecordCallback Callback, void *Context) { mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique, Callback, Context); - if (ConstructServiceName(rr->resrec.name, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr); + if (ConstructServiceName(&rr->namestorage, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr); rr->resrec.rdata->u.srv.priority = 0; rr->resrec.rdata->u.srv.weight = 0; rr->resrec.rdata->u.srv.port = zeroIPPort; if (host && host->c[0]) AssignDomainName(&rr->resrec.rdata->u.srv.target, host); - else rr->HostTarget = mDNStrue; + else rr->AutoTarget = Target_AutoHost; return(mDNS_Register(m, rr)); } @@ -7046,15 +6593,23 @@ mDNSexport mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr, mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, char *domname) { mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, mDNSNULL, mDNSNULL); - if (!MakeDomainNameFromDNSNameString(rr->resrec.name, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr); + if (!MakeDomainNameFromDNSNameString(&rr->namestorage, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr); if (!MakeDomainNameFromDNSNameString(&rr->resrec.rdata->u.name, domname)) return(mStatus_BadParamErr); return(mDNS_Register(m, rr)); } + +mDNSOpaque16 mDNS_NewMessageID(mDNS * const m) + { + static mDNSBool randomized = mDNSfalse; + + if (!randomized) { m->NextMessageID = (mDNSu16)mDNSRandom(0xFFFF); randomized = mDNStrue; } + if (m->NextMessageID == 0) m->NextMessageID++; + return mDNSOpaque16fromIntVal(m->NextMessageID++); + } // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - -#pragma mark - #pragma mark - Startup and Shutdown #endif @@ -7090,7 +6645,7 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, m->p = p; m->KnownBugs = 0; - m->CanReceiveUnicastOn5353 = mDNSfalse; // Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise + m->CanReceiveUnicastOn5353 = mDNSfalse; // Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise m->AdvertiseLocalAddresses = AdvertiseLocalAddresses; m->mDNSPlatformStatus = mStatus_Waiting; m->UnicastPort4 = zeroIPPort; @@ -7121,8 +6676,9 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, m->NextScheduledQuery = timenow + 0x78000000; m->NextScheduledProbe = timenow + 0x78000000; m->NextScheduledResponse = timenow + 0x78000000; - m->ExpectUnicastResponse = timenow + 0x78000000; + m->NextScheduledNATOp = timenow + 0x78000000; m->RandomQueryDelay = 0; + m->RandomReconfirmDelay = 0; m->PktNum = 0; m->SendDeregistrations = mDNSfalse; m->SendImmediateAnswers = mDNSfalse; @@ -7159,24 +6715,182 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, m->NumFailedProbes = 0; m->SuppressProbes = 0; -#ifndef UNICAST_DISABLED - uDNS_Init(m); +#ifndef UNICAST_DISABLED + m->NextuDNSEvent = timenow + 0x78000000; + m->NextSRVUpdate = timenow + 0x78000000; m->SuppressStdPort53Queries = 0; + + m->ServiceRegistrations = mDNSNULL; + m->NextMessageID = 0; + m->DNSServers = mDNSNULL; + + m->Router = zeroAddr; + m->AdvertisedV4 = zeroAddr; + m->AdvertisedV6 = zeroAddr; + + m->AuthInfoList = mDNSNULL; + + m->ReverseMap.ThisQInterval = -1; + m->StaticHostname.c[0] = 0; + m->FQDN.c[0] = 0; + m->Hostnames = mDNSNULL; + m->AutoTunnelHostAddr.b[0] = 0; + m->AutoTunnelHostAddrActive = mDNSfalse; + m->AutoTunnelLabel.c[0] = 0; + + m->RegisterSearchDomains = mDNSfalse; + + // NAT traversal fields + 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->ExternalAddress = zerov4Addr; + + m->NATMcastRecvskt = mDNSNULL; + m->NATMcastRecvsk2 = mDNSNULL; + m->LastNATupseconds = 0; + m->LastNATReplyLocalTime = timenow; + + m->UPnPInterfaceID = 0; + m->UPnPRouterPort = zeroIPPort; + m->UPnPSOAPPort = zeroIPPort; + m->UPnPRouterURL = mDNSNULL; + m->UPnPSOAPURL = mDNSNULL; + m->UPnPRouterAddressString = mDNSNULL; + m->UPnPSOAPAddressString = mDNSNULL; +#endif + +#if APPLE_OSX_mDNSResponder + m->TunnelClients = mDNSNULL; #endif + result = mDNSPlatformInit(m); +#ifndef UNICAST_DISABLED + // It's better to do this *after* the platform layer has set up the + // interface list and security credentials + uDNS_SetupDNSConfig(m); // Get initial DNS configuration +#endif + return(result); } +mDNSlocal void DynDNSHostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result) + { + (void)m; // unused + debugf("NameStatusCallback: result %d for registration of name %##s", result, rr->resrec.name->c); + mDNSPlatformDynDNSHostNameStatusChanged(rr->resrec.name, result); + } + +mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) + { + mDNSu32 slot; + CacheGroup *cg; + CacheRecord *cr; + + mDNSAddr v4, v6, r; + domainname fqdn; + DNSServer *ptr, **p = &m->DNSServers; + DNSQuestion *q; + + if (m->RegisterSearchDomains) uDNS_RegisterSearchDomains(m); + + mDNS_Lock(m); + + // Let the platform layer get the current DNS information + // The m->RegisterSearchDomains boolean is so that we lazily get the search domain list only on-demand + // (no need to hit the network with domain enumeration queries until we actually need that information). + for (ptr = m->DNSServers; ptr; ptr = ptr->next) ptr->del = mDNStrue; + + mDNSPlatformSetDNSConfig(m, mDNStrue, mDNSfalse, &fqdn, mDNSNULL, mDNSNULL); + + // Update our qDNSServer pointers before we go and free the DNSServer object memory + for (q = m->Questions; q; q=q->next) + if (!mDNSOpaque16IsZero(q->TargetQID)) + { + DNSServer *s = GetServerForName(m, &q->qname); + if (q->qDNSServer != s) + { + // If DNS Server for this question has changed, reactivate it + LogOperation("Updating DNS Server from %#a:%d to %#a:%d for %##s (%s)", + q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort), + s ? &s->addr : mDNSNULL, mDNSVal16(s ? s->port : zeroIPPort), + q->qname.c, DNSTypeName(q->qtype)); + q->qDNSServer = s; + ActivateUnicastQuery(m, q); + } + } + + while (*p) + { + if ((*p)->del) + { + // Scan our cache, looking for uDNS records that we would have queried this server for. + // We reconfirm any records that match, because in this world of split DNS, firewalls, etc. + // different DNS servers can give different answers to the same question. + ptr = *p; + ptr->del = mDNSfalse; // Clear del so GetServerForName will (temporarily) find this server again before it's finally deleted + FORALL_CACHERECORDS(slot, cg, cr) + if (!cr->resrec.InterfaceID && GetServerForName(m, cr->resrec.name) == ptr) + mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); + *p = (*p)->next; + mDNSPlatformMemFree(ptr); + } + else + p = &(*p)->next; + } + + // If we have no DNS servers at all, then immediately purge all unicast cache records (including for LLQs) + // This is important for giving prompt remove events when the user disconnects the Ethernet cable or turns off wireless + // Otherwise, stale data lingers for 5-10 seconds, which is not the user-experience people expect from Bonjour + if (!m->DNSServers) FORALL_CACHERECORDS(slot, cg, cr) if (!cr->resrec.InterfaceID) mDNS_PurgeCacheResourceRecord(m, cr); + + // Did our FQDN change? + if (!SameDomainName(&fqdn, &m->FQDN)) + { + if (m->FQDN.c[0]) mDNS_RemoveDynDNSHostName(m, &m->FQDN); + + AssignDomainName(&m->FQDN, &fqdn); + + if (m->FQDN.c[0]) + { + mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1); + mDNS_AddDynDNSHostName(m, &m->FQDN, DynDNSHostNameCallback, mDNSNULL); + } + } + + mDNS_Unlock(m); + + // handle router and primary interface changes + v4 = v6 = r = zeroAddr; + v4.type = r.type = mDNSAddrType_IPv4; + + if (mDNSPlatformGetPrimaryInterface(m, &v4, &v6, &r) == mStatus_NoError && !mDNSv4AddressIsLinkLocal(&v4.ip.v4)) + { + mDNS_SetPrimaryInterfaceInfo(m, + !mDNSIPv4AddressIsZero(v4.ip.v4) ? &v4 : mDNSNULL, + !mDNSIPv6AddressIsZero(v6.ip.v6) ? &v6 : mDNSNULL, + !mDNSIPv4AddressIsZero(r .ip.v4) ? &r : mDNSNULL); + } + else + { + mDNS_SetPrimaryInterfaceInfo(m, mDNSNULL, mDNSNULL, mDNSNULL); + if (m->FQDN.c[0]) mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1); // Set status to 1 to indicate temporary failure + } + + return mStatus_NoError; + } + mDNSexport void mDNSCoreInitComplete(mDNS *const m, mStatus result) { m->mDNSPlatformStatus = result; if (m->MainCallback) { mDNS_Lock(m); - m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback + mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback m->MainCallback(m, mStatus_NoError); - m->mDNS_reentrancy--; // Decrement to block mDNS API calls again + mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again mDNS_Unlock(m); } } @@ -7187,25 +6901,28 @@ mDNSexport void mDNS_Close(mDNS *const m) mDNSu32 rrcache_totalused = 0; mDNSu32 slot; NetworkInterfaceInfo *intf; + AuthRecord *rr; mDNS_Lock(m); m->mDNS_shutdown = mDNStrue; -#ifndef UNICAST_DISABLED - uDNS_Close(m); +#ifndef UNICAST_DISABLED + uDNS_Sleep(m); + while (m->Hostnames) mDNS_RemoveDynDNSHostName(m, &m->Hostnames->fqdn); #endif + rrcache_totalused = m->rrcache_totalused; for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) { - while(m->rrcache_hash[slot]) + while (m->rrcache_hash[slot]) { CacheGroup *cg = m->rrcache_hash[slot]; while (cg->members) { - CacheRecord *rr = cg->members; + CacheRecord *cr = cg->members; cg->members = cg->members->next; - if (rr->CRActiveQuestion) rrcache_active++; - ReleaseCacheRecord(m, rr); + if (cr->CRActiveQuestion) rrcache_active++; + ReleaseCacheRecord(m, cr); } cg->rrcache_tail = &cg->members; ReleaseCacheGroup(m, &m->rrcache_hash[slot]); @@ -7219,17 +6936,45 @@ mDNSexport void mDNS_Close(mDNS *const m) if (intf->Advertise) DeadvertiseInterface(m, intf); + // Shut down all our active NAT Traversals + while (m->NATTraversals) + { + NATTraversalInfo *t = m->NATTraversals; + mDNS_StopNATOperation_internal(m, t); // This will cut 't' from the list, thereby advancing m->NATTraversals in the process + + // After stopping the NAT Traversal, we zero out the fields. + // This has particularly important implications for our AutoTunnel records -- + // when we deregister our AutoTunnel records below, we don't want their mStatus_MemFree + // handlers to just turn around and attempt to re-register those same records. + // Clearing t->ExternalPort will cause the mStatus_MemFree callback handlers to not do this. + t->ExternalAddress = zerov4Addr; + t->ExternalPort = zeroIPPort; + t->Lifetime = 0; + t->Result = mStatus_NoError; + } + // Make sure there are nothing but deregistering records remaining in the list - if (m->CurrentRecord) LogMsg("mDNS_Close ERROR m->CurrentRecord already set"); + if (m->CurrentRecord) + LogMsg("mDNS_Close ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); + + // First we deregister any non-shared records. In particular, we want to make sure we deregister + // any extra records added to a Service Record Set first, before we deregister its PTR record. m->CurrentRecord = m->ResourceRecords; while (m->CurrentRecord) { - AuthRecord *rr = m->CurrentRecord; + rr = m->CurrentRecord; + if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) + mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); + else + m->CurrentRecord = rr->next; + } + + // Now deregister any remaining records we didn't get the first time through + while (m->CurrentRecord) + { + rr = m->CurrentRecord; if (rr->resrec.RecordType != kDNSRecordTypeDeregistering) - { - debugf("mDNS_Close: Record type %X still in ResourceRecords list %##s", rr->resrec.RecordType, rr->resrec.name->c); mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); - } else m->CurrentRecord = rr->next; } @@ -7240,7 +6985,9 @@ mDNSexport void mDNS_Close(mDNS *const m) // If any deregistering records remain, send their deregistration announcements before we exit if (m->mDNSPlatformStatus != mStatus_NoError) DiscardDeregistrations(m); else if (m->ResourceRecords) SendResponses(m); - if (m->ResourceRecords) LogMsg("mDNS_Close failed to send goodbye for: %s", ARDisplayString(m, m->ResourceRecords)); + + for (rr = m->ResourceRecords; rr; rr = rr->next) + LogMsg("mDNS_Close failed to send goodbye for: %s", ARDisplayString(m, rr)); mDNS_Unlock(m); debugf("mDNS_Close: mDNSPlatformClose"); diff --git a/mDNSCore/mDNSDebug.h b/mDNSCore/mDNSDebug.h index 11c9737..e5ad7d0 100755 --- a/mDNSCore/mDNSDebug.h +++ b/mDNSCore/mDNSDebug.h @@ -1,28 +1,56 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: mDNSDebug.h,v $ +Revision 1.36 2007/10/01 19:06:19 cheshire +Defined symbolic constant MDNS_LOG_INITIAL_LEVEL to set the logging level we start out at + +Revision 1.35 2007/07/27 20:19:56 cheshire +For now, comment out unused log levels MDNS_LOG_ERROR, MDNS_LOG_WARN, MDNS_LOG_INFO, MDNS_LOG_DEBUG + +Revision 1.34 2007/07/24 17:23:33 cheshire + Add list validation checks for debugging + +Revision 1.33 2007/06/15 21:54:50 cheshire + Add packet logging to help debugging private browsing over TLS + +Revision 1.32 2007/05/25 16:03:03 cheshire +Remove unused LogMalloc + +Revision 1.31 2007/04/06 19:50:05 cheshire +Add ProgramName declaration + +Revision 1.30 2007/03/24 01:22:44 cheshire +Add validator for uDNS data structures + +Revision 1.29 2006/08/14 23:24:23 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + +Revision 1.28 2006/07/07 01:09:09 cheshire + Add Private DNS server functionality to dnsextd +Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd + +Revision 1.27 2006/06/29 07:42:14 cheshire + Performance: Remove unnecessary SameDomainName() checks + +Revision 1.26 2005/07/04 22:40:26 cheshire +Additional debugging code to help catch memory corruption + Revision 1.25 2004/12/14 21:34:16 cheshire Add "#define ANSWER_REMOTE_HOSTNAME_QUERIES 0" and comment @@ -139,10 +167,26 @@ extern void verbosedebugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1 #endif // LogMsg is used even in shipping code, to write truly serious error messages to syslog (or equivalent) -extern int mDNS_DebugMode; // If non-zero, LogMsg() writes to stderr instead of syslog +typedef enum + { + MDNS_LOG_NONE, +// MDNS_LOG_ERROR, +// MDNS_LOG_WARN, +// MDNS_LOG_INFO, +// MDNS_LOG_DEBUG, + MDNS_LOG_VERBOSE_DEBUG + } LogLevel_t; + +#define MDNS_LOG_INITIAL_LEVEL MDNS_LOG_NONE + +extern LogLevel_t mDNS_LogLevel; +extern int mDNS_DebugMode; // If non-zero, LogMsg() writes to stderr instead of syslog +extern const char ProgramName[]; // Program Name for use with LogMsgIdent + extern void LogMsg(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); extern void LogMsgIdent(const char *ident, const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(2,3); extern void LogMsgNoIdent(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); +extern void SigLogLevel(void); // Set this symbol to 1 to answer remote queries for our Address, reverse mapping PTR, and HINFO records #define ANSWER_REMOTE_HOSTNAME_QUERIES 0 @@ -151,26 +195,17 @@ extern void LogMsgNoIdent(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1, // Set this symbol to 2 to write a log message for every malloc() and free() #define MACOSX_MDNS_MALLOC_DEBUGGING 0 -#if MACOSX_MDNS_MALLOC_DEBUGGING >= 1 +#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1 extern void *mallocL(char *msg, unsigned int size); extern void freeL(char *msg, void *x); +extern void LogMemCorruption(const char *format, ...); +extern void uds_validatelists(void); +extern void udns_validatelists(void *const v); #else #define mallocL(X,Y) malloc(Y) #define freeL(X,Y) free(Y) #endif -#if MACOSX_MDNS_MALLOC_DEBUGGING >= 2 -#define LogMalloc LogMsg -#else - #if (defined( __GNUC__ )) - #define LogMalloc(ARGS...) ((void)0) - #elif (defined( __MWERKS__ )) - #define LogMalloc( ... ) - #else - #define LogMalloc 1 ? ((void)0) : (void) - #endif -#endif - #define LogAllOperations 0 #if LogAllOperations @@ -179,6 +214,10 @@ extern void freeL(char *msg, void *x); #define LogOperation debugf #endif +#define ForceAlerts 0 + +#define VerifySameNameAssumptions 0 + #ifdef __cplusplus } #endif diff --git a/mDNSCore/mDNSEmbeddedAPI.h b/mDNSCore/mDNSEmbeddedAPI.h index 3113ff1..c761645 100755 --- a/mDNSCore/mDNSEmbeddedAPI.h +++ b/mDNSCore/mDNSEmbeddedAPI.h @@ -1,24 +1,18 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ NOTE: @@ -60,945 +54,540 @@ Change History (most recent first): $Log: mDNSEmbeddedAPI.h,v $ -Revision 1.287 2005/10/20 00:10:33 cheshire - Add check to avoid crashing NAT gateways that have buggy DNS relay code - -Revision 1.286 2005/09/24 01:09:40 cheshire -Fix comment typos - -Revision 1.285 2005/09/16 20:57:47 cheshire -Add macro mDNS_TimeNow_NoLock(m) to get properly adjusted time without also acquiring lock - -Revision 1.284 2005/07/29 18:04:22 ksekar - Hostname registration should register IPv6 AAAA record with DNS Update - -Revision 1.283 2005/05/13 20:45:09 ksekar - Rapid wide-area txt record updates don't work - -Revision 1.282 2005/03/16 00:42:32 ksekar - Long-lived queries not working on Windows - -Revision 1.281 2005/02/25 17:47:44 ksekar - SendServiceRegistration fails on wake from sleep - -Revision 1.280 2005/02/25 04:21:00 cheshire - mDNS -F returns the same domain multiple times with different casing - -Revision 1.279 2005/02/17 01:56:14 cheshire -Increase ifname field to 64 bytes - -Revision 1.278 2005/02/09 23:38:51 ksekar - Reregister hostname when DNS server changes but IP address does not - -Revision 1.277 2005/02/09 23:31:12 ksekar - NAT-PMP response callback should return a boolean indicating if the packet matched the request - -Revision 1.276 2005/02/01 19:33:29 ksekar - Keychain format too restrictive - -Revision 1.275 2005/01/27 22:57:55 cheshire -Fix compile errors on gcc4 - -Revision 1.274 2005/01/19 21:01:54 ksekar - uDNS needs to support subtype registration and browsing - -Revision 1.273 2005/01/19 19:15:31 ksekar -Refinement to - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer - -Revision 1.272 2005/01/18 18:10:55 ksekar - Use 10.4 resolver API to get search domains - -Revision 1.271 2005/01/15 00:56:41 ksekar - Unicast services don't disappear when logging -out of VPN - -Revision 1.270 2005/01/14 18:34:22 ksekar - Services registered outside of firewall don't succeed after location change - -Revision 1.269 2005/01/11 22:50:52 ksekar -Fixed constant naming (was using kLLQ_DefLease for update leases) - -Revision 1.268 2004/12/22 22:25:47 ksekar - NAT-PMP: handle location changes - -Revision 1.267 2004/12/22 00:13:49 ksekar - Change version, port, and polling interval for LLQ - -Revision 1.266 2004/12/18 03:13:45 cheshire - kDNSServiceInterfaceIndexLocalOnly should return all local records - -Revision 1.265 2004/12/17 23:37:45 cheshire - Guard against repeating wireless dissociation/re-association -(and other repetitive configuration changes) - -Revision 1.264 2004/12/17 05:25:46 cheshire - Shorten DNS-SD queries to avoid NAT bugs - -Revision 1.263 2004/12/16 20:40:25 cheshire -Fix compile warnings - -Revision 1.262 2004/12/16 20:13:00 cheshire - Cache memory management improvements - -Revision 1.261 2004/12/14 21:21:20 ksekar - NAT-PMP: Update response format to contain "Seconds Since Boot" - -Revision 1.260 2004/12/12 23:51:42 ksekar - Wide-area registrations should fallback to using DHCP hostname as target - -Revision 1.259 2004/12/11 20:55:29 ksekar - Clean up registration state machines - -Revision 1.258 2004/12/10 20:48:32 cheshire - Need to pick final EDNS numbers for LLQ and GC - -Revision 1.257 2004/12/10 02:09:23 cheshire - Modify default TTLs - -Revision 1.256 2004/12/09 03:15:40 ksekar - use _legacy instead of _default to find "empty string" browse domains - -Revision 1.255 2004/12/07 22:48:37 cheshire -Tidying - -Revision 1.254 2004/12/07 21:26:04 ksekar - DNSServiceRegisterRecord() can crash on deregistration - -Revision 1.253 2004/12/07 20:42:33 cheshire -Add explicit context parameter to mDNS_RemoveRecordFromService() - -Revision 1.252 2004/12/07 03:02:12 ksekar -Fixed comments, grouped unicast-specific routines together - -Revision 1.251 2004/12/06 21:15:22 ksekar - mDNSResponder crashed in CheckServiceRegistrations - -Revision 1.250 2004/12/04 02:12:45 cheshire - mDNSResponder puts LargeCacheRecord on the stack - -Revision 1.249 2004/12/03 05:18:33 ksekar - mDNSResponder needs to return more specific TSIG errors - -Revision 1.248 2004/12/02 20:03:48 ksekar - Still publishes wide-area domains even after switching to a local subnet - -Revision 1.247 2004/12/01 20:57:19 ksekar - Wide Area Service Discovery must be split-DNS aware +Revision 1.444 2007/09/29 03:14:52 cheshire + BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal +Added AutoTunnelUnregistered macro to check state of DomainAuthInfo AuthRecords -Revision 1.246 2004/11/29 23:26:32 cheshire -Added NonZeroTime() function, which usually returns the value given, with the exception -that if the value given is zero, it returns one instead. For timer values where zero is -used to mean "not set", this can be used to ensure that setting them to the result of an -interval computation (e.g. "now+interval") does not inadvertently result in a zero value. +Revision 1.443 2007/09/27 21:21:39 cheshire +Export CompleteDeregistration so it's callable from other files -Revision 1.245 2004/11/25 01:28:09 cheshire - Need to implement random delay for 'QU' unicast replies (and set cache flush bit too) +Revision 1.442 2007/09/27 00:25:39 cheshire +Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for: + uDNS: Use SOA to determine TTL for negative answers -Revision 1.244 2004/11/24 22:00:59 cheshire -Move definition of mDNSAddressIsAllDNSLinkGroup() from mDNSMacOSX.c to mDNSEmbeddedAPI.h +Revision 1.441 2007/09/26 23:17:49 cheshire +Get rid of unused kWideAreaTTL constant -Revision 1.243 2004/11/23 22:43:53 cheshire -Tidy up code alignment +Revision 1.440 2007/09/26 22:06:02 cheshire + BTMM: No immediate failure notifications for BTMM names -Revision 1.242 2004/11/23 03:39:46 cheshire -Let interface name/index mapping capability live directly in JNISupport.c, -instead of having to call through to the daemon via IPC to get this information. +Revision 1.439 2007/09/21 21:12:36 cheshire +DNSDigest_SignMessage does not need separate "mDNSu16 *numAdditionals" parameter -Revision 1.241 2004/11/22 17:16:19 ksekar - Unicast services don't disappear when you disable all networking +Revision 1.438 2007/09/19 20:32:09 cheshire +Export GetAuthInfoForName so it's callable from other files -Revision 1.240 2004/11/19 02:32:43 ksekar -Wide-Area Security: Add LLQ-ID to events +Revision 1.437 2007/09/18 21:42:29 cheshire +To reduce programming mistakes, renamed ExtPort to RequestedPort -Revision 1.239 2004/11/15 20:09:23 ksekar - Wide Area support for Add/Remove record +Revision 1.436 2007/09/14 21:26:08 cheshire + BTMM: Need to manually avoid port conflicts when using UPnP gateways -Revision 1.238 2004/11/12 03:16:48 rpantos -rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName +Revision 1.435 2007/09/13 00:16:41 cheshire + Miscellaneous NAT Traversal improvements -Revision 1.237 2004/11/10 20:40:53 ksekar - LLQ mobility fragile on non-primary interface +Revision 1.434 2007/09/12 23:03:07 cheshire + DNSServiceNATPortMappingCreate callback not giving correct interface index -Revision 1.236 2004/11/01 20:36:11 ksekar - mDNSResponder should not receive Keychain Notifications +Revision 1.433 2007/09/12 22:19:28 cheshire + Need to listen for port 5350 NAT-PMP announcements -Revision 1.235 2004/11/01 17:48:14 cheshire -Changed SOA serial number back to signed. RFC 1035 may describe it as "unsigned", but -it's wrong. The SOA serial is a modular counter, as explained in "DNS & BIND", page -137. Since C doesn't have a modular type, we used signed, C's closest approximation. +Revision 1.432 2007/09/12 19:22:19 cheshire +Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport +Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers -Revision 1.234 2004/10/29 21:59:02 ksekar -SOA serial should be a unsigned integer, as per RFC 1035 +Revision 1.431 2007/09/11 19:19:16 cheshire +Correct capitalization of "uPNP" to "UPnP" -Revision 1.233 2004/10/28 03:24:41 cheshire -Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353 +Revision 1.430 2007/09/10 22:06:50 cheshire +Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds -Revision 1.232 2004/10/26 06:20:23 cheshire -Add mDNSAddressIsValidNonZero() macro +Revision 1.429 2007/09/07 21:16:58 cheshire +Add new symbol "NATPMPAnnouncementPort" (5350) -Revision 1.231 2004/10/26 06:11:41 cheshire -Add improved logging to aid in diagnosis of mDNSResponder crashed +Revision 1.428 2007/09/05 21:48:01 cheshire + BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone. +Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance cod needs +to update the cache lifetimes of all relevant records every time it successfully renews an LLQ, +otherwise those records will expire and vanish from the cache. -Revision 1.230 2004/10/26 03:52:02 cheshire -Update checkin comments +Revision 1.427 2007/09/05 20:47:12 cheshire +Tidied up alignment of code layout -Revision 1.229 2004/10/25 19:30:52 ksekar - Simplify dynamic host name structures +Revision 1.426 2007/09/04 20:37:06 cheshire + mDNSResponder taking up 100% CPU in ReissueBlockedQuestions +Reorder fields into more logical order, with AuthInfo before DuplicateOf -Revision 1.228 2004/10/23 01:16:00 cheshire - uDNS operations not always reliable on multi-homed hosts +Revision 1.425 2007/08/31 19:53:14 cheshire + BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup +If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist -Revision 1.227 2004/10/22 20:52:07 ksekar - Create NAT port mappings for Long Lived Queries +Revision 1.424 2007/08/31 18:49:49 vazquez + BTMM: Need to properly deregister when stopping BTMM -Revision 1.226 2004/10/20 01:50:40 cheshire - Cannot resolve non-local registrations using the mach API -Implemented ForceMCast mode for AuthRecords as well as for Questions +Revision 1.423 2007/08/31 00:04:28 cheshire +Added comment explaining deltime in DomainAuthInfo structure -Revision 1.225 2004/10/19 21:33:17 cheshire - Cannot resolve non-local registrations using the mach API -Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name -doesn't force multicast unless you set this flag to indicate explicitly that this is what you want +Revision 1.422 2007/08/28 23:58:42 cheshire +Rename HostTarget -> AutoTarget -Revision 1.224 2004/10/16 00:16:59 cheshire - Replace IP TTL 255 check with local subnet source address check +Revision 1.421 2007/08/27 20:30:43 cheshire +Only include TunnelClients list when building for OS X -Revision 1.223 2004/10/15 23:00:17 ksekar - Need to update LLQs on location changes +Revision 1.420 2007/08/23 21:47:09 vazquez + BTMM: mDNSResponder sends NAT-PMP packets on public network +make sure we clean up port mappings on base stations by sending a lease value of 0, +and only send NAT-PMP packets on private networks; also save some memory by +not using packet structs in NATTraversals. -Revision 1.222 2004/10/12 02:49:20 ksekar - Clean up LLQ sleep/wake, error handling +Revision 1.419 2007/08/08 21:07:47 vazquez + BTMM: Need to advertise model information via wide-area bonjour -Revision 1.221 2004/10/10 06:57:15 cheshire -Change definition of "localdomain" to make code compile a little smaller +Revision 1.418 2007/08/01 16:09:13 cheshire +Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly -Revision 1.220 2004/10/06 01:44:19 cheshire - Resolving too quickly sometimes returns stale TXT record +Revision 1.417 2007/08/01 03:04:59 cheshire +Add NATTraversalInfo structures to HostnameInfo and DomainAuthInfo -Revision 1.219 2004/10/03 23:18:58 cheshire -Move address comparison macros from DNSCommon.h to mDNSEmbeddedAPI.h +Revision 1.416 2007/08/01 00:04:13 cheshire + Crash in tcpKQSocketCallback +Half-open TCP connections were not being cancelled properly -Revision 1.218 2004/10/03 23:14:12 cheshire -Add "mDNSEthAddr" type and "zeroEthAddr" constant +Revision 1.415 2007/07/31 02:28:35 vazquez + NAT-PMP: Detect public IP address changes and base station reboot -Revision 1.217 2004/09/30 00:24:56 ksekar - Dynamically update default registration domains on config change +Revision 1.414 2007/07/30 23:34:19 cheshire +Remove unused "udpSock" from DNSQuestion -Revision 1.216 2004/09/27 23:24:32 cheshire -Fix typo: SOA refresh interval is supposed to be unsigned +Revision 1.413 2007/07/28 01:25:56 cheshire + BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT -Revision 1.215 2004/09/26 23:20:35 ksekar - Allow default registrations in multiple wide-area domains +Revision 1.412 2007/07/27 23:57:23 cheshire +Added compile-time structure size checks -Revision 1.214 2004/09/25 02:41:39 cheshire - Deliver near-pending "remove" events before new "add" events +Revision 1.411 2007/07/27 22:50:08 vazquez +Allocate memory for UPnP request and reply buffers instead of using arrays -Revision 1.213 2004/09/25 02:24:27 cheshire -Removed unused rr->UseCount +Revision 1.410 2007/07/27 19:37:19 cheshire +Moved AutomaticBrowseDomainQ into main mDNS object -Revision 1.212 2004/09/24 20:57:39 cheshire - Eliminate inappropriate casts that cause misaligned-address errors +Revision 1.409 2007/07/27 19:30:39 cheshire +Changed mDNSQuestionCallback parameter from mDNSBool to QC_result, +to properly reflect tri-state nature of the possible responses -Revision 1.211 2004/09/24 20:33:22 cheshire -Remove unused DNSDigest_MD5 declaration +Revision 1.408 2007/07/27 18:44:01 cheshire +Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord" -Revision 1.210 2004/09/23 20:21:07 cheshire - Refine "immediate answer burst; restarting exponential backoff sequence" logic -Associate a unique sequence number with each received packet, and only increment the count of recent answer -packets if the packet sequence number for this answer record is not one we've already seen and counted. +Revision 1.407 2007/07/26 21:19:26 vazquez +Retry port mapping with incremented port number (up to max) in order to handle +port mapping conflicts on UPnP gateways -Revision 1.209 2004/09/23 20:14:39 cheshire -Rename "question->RecentAnswers" to "question->RecentAnswerPkts" +Revision 1.406 2007/07/25 22:19:59 cheshire +ClientTunnel structure also needs a rmt_outer_port field -Revision 1.208 2004/09/23 00:50:53 cheshire - Don't send a (DE) if a service is unregistered after wake from sleep +Revision 1.405 2007/07/25 03:05:02 vazquez +Fixes for: + LegacyNATTraversal: UPnP heap overflow + LegacyNATTraversal: UPnP stack buffer overflow +and a myriad of other security problems -Revision 1.207 2004/09/22 02:34:46 cheshire -Move definitions of default TTL times from mDNS.c to mDNSEmbeddedAPI.h +Revision 1.404 2007/07/24 20:22:07 cheshire +Add AutoTunnelHostAddrActive flag -Revision 1.206 2004/09/22 00:41:59 cheshire -Move tcp connection status codes into the legal range allocated for mDNS use +Revision 1.403 2007/07/24 04:14:29 cheshire + LLQs not working in with NAT Traversal -Revision 1.205 2004/09/21 23:40:11 ksekar - mDNSResponder to return errors on NAT traversal failure +Revision 1.402 2007/07/21 00:54:44 cheshire + Delay IPv6 address callback until AutoTunnel route and policy is configured -Revision 1.204 2004/09/21 23:29:50 cheshire - DNSServiceResolve should delay sending packets +Revision 1.401 2007/07/20 20:01:38 cheshire +Rename "mDNS_DomainTypeBrowseLegacy" as "mDNS_DomainTypeBrowseAutomatic" -Revision 1.203 2004/09/21 20:58:22 cheshire -Add ifname field to NetworkInterfaceInfo_struct +Revision 1.400 2007/07/20 00:54:18 cheshire + Need separate SCPreferences for per-user .Mac settings -Revision 1.202 2004/09/17 00:46:34 cheshire -mDNS_TimeNow should take const mDNS parameter +Revision 1.399 2007/07/18 03:22:35 cheshire +SetupLocalAutoTunnelInterface_internal needs to be callable from uDNS.c -Revision 1.201 2004/09/17 00:31:51 cheshire -For consistency with ipv6, renamed rdata field 'ip' to 'ipv4' +Revision 1.398 2007/07/18 02:26:56 cheshire +Don't need to declare UpdateTunnels here -Revision 1.200 2004/09/17 00:19:10 cheshire -For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4 +Revision 1.397 2007/07/18 01:03:50 cheshire + Automatically configure IPSec policy when resolving services +Add list of client tunnels so we can automatically reconfigure when local address changes -Revision 1.199 2004/09/16 21:59:16 cheshire -For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr +Revision 1.396 2007/07/16 23:54:48 cheshire + Crash when removing or changing DNS keys -Revision 1.198 2004/09/16 21:36:36 cheshire - Fix unsafe use of mDNSPlatformTimeNow() -Changes to add necessary locking calls around unicast DNS operations +Revision 1.395 2007/07/16 20:12:33 vazquez + LegacyNATTraversal: Need complete rewrite -Revision 1.197 2004/09/16 00:24:48 cheshire - Fix unsafe use of mDNSPlatformTimeNow() +Revision 1.394 2007/07/12 02:51:27 cheshire + Automatically configure IPSec policy when resolving services -Revision 1.196 2004/09/14 23:42:35 cheshire - Need to seed random number generator from platform-layer data +Revision 1.393 2007/07/11 23:43:42 cheshire +Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord -Revision 1.195 2004/09/14 23:27:46 cheshire -Fix compile errors +Revision 1.392 2007/07/11 22:44:40 cheshire + SIGHUP should purge the cache -Revision 1.194 2004/09/10 00:49:57 cheshire - Add error code kDNSServiceErr_Firewall, for future use +Revision 1.391 2007/07/11 20:30:45 cheshire + Register IPSec tunnel with IPv4-only hostname and create NAT port mappings +Added AutoTunnelTarget and AutoTunnelService to DomainAuthInfo structure -Revision 1.193 2004/09/03 19:23:05 ksekar -: Need retransmission mechanism for wide-area service registrations +Revision 1.390 2007/07/11 18:56:55 cheshire +Added comments about AutoTunnelHostAddr and AutoTunnelLabel -Revision 1.192 2004/09/02 03:48:47 cheshire - Disable targeted unicast query support by default -1. New flag kDNSServiceFlagsAllowRemoteQuery to indicate we want to allow remote queries for this record -2. New field AllowRemoteQuery in AuthRecord structure -3. uds_daemon.c sets AllowRemoteQuery if kDNSServiceFlagsAllowRemoteQuery is set -4. mDNS.c only answers remote queries if AllowRemoteQuery is set +Revision 1.389 2007/07/11 02:44:03 cheshire + Register IPv6-only hostname and don't create port mappings for AutoTunnel services +Added AutoTunnel fields to structures -Revision 1.191 2004/08/25 00:37:27 ksekar -: Cleanup DynDNS hostname registration code +Revision 1.388 2007/07/10 01:53:18 cheshire + uDNS: mDNSresponder is leaking TCP connections to DNS server +AuthRecord, ServiceRecordSet, and DNSQuestion structures need tcpInfo_t pointers +so they can keep track of what TCP connections they open -Revision 1.190 2004/08/18 17:35:41 ksekar -: Feature #9586: Need support for Legacy NAT gateways +Revision 1.387 2007/07/06 18:55:15 cheshire +Add explicit NextScheduledNATOp scheduling variable -Revision 1.189 2004/08/14 03:22:41 cheshire - Dynamic DNS UI <-> mDNSResponder glue -Add GetUserSpecifiedDDNSName() routine -Convert ServiceRegDomain to domainname instead of C string -Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs +Revision 1.386 2007/07/03 20:54:11 cheshire +Tidied up code layout of NATTraversalInfo_struct fields and comments -Revision 1.188 2004/08/13 23:46:58 cheshire -"asyncronous" -> "asynchronous" +Revision 1.385 2007/07/03 00:40:23 vazquez +More changes for Clean up NAT state machine (necessary for 6 other fixes) +Safely deal with packet replies and client callbacks -Revision 1.187 2004/08/13 23:37:02 cheshire -Now that we do both uDNS and mDNS, global replace "uDNS_info.hostname" with -"uDNS_info.UnicastHostname" for clarity +Revision 1.384 2007/06/29 00:08:07 vazquez + Clean up NAT state machine (necessary for 6 other fixes) -Revision 1.186 2004/08/13 23:25:00 cheshire -Now that we do both uDNS and mDNS, global replace "m->hostname" with -"m->MulticastHostname" for clarity +Revision 1.383 2007/06/20 01:10:12 cheshire + Sync iPhone changes into main mDNSResponder code -Revision 1.185 2004/08/12 00:32:36 ksekar -: LLQ Refreshes never terminate if unanswered +Revision 1.382 2007/06/19 20:31:59 cheshire +Add DNSServer_Disabled state +Add mDNSInterfaceID for DNS servers reachable over specific interfaces -Revision 1.184 2004/08/11 17:09:31 cheshire -Add comment clarifying the applicability of these APIs +Revision 1.381 2007/06/15 18:11:16 cheshire + mDNSResponder crashed in memove() near end of MobileSafari stress test +Made AssignDomainName more defensive when source name is garbage -Revision 1.183 2004/08/10 23:19:14 ksekar -: DNS Extension daemon for Wide Area Service Discovery -Moved routines/constants to allow extern access for garbage collection daemon +Revision 1.380 2007/05/25 00:04:51 cheshire +Added comment explaining rdlength -Revision 1.182 2004/07/30 17:40:06 ksekar -: TXT Record updates not available for wide-area services +Revision 1.379 2007/05/21 18:04:40 cheshire +Updated comments -- port_mapping_create_reply renamed to port_mapping_reply -Revision 1.181 2004/07/29 19:27:15 ksekar -NAT-PMP Support - minor fixes and cleanup +Revision 1.378 2007/05/17 19:11:46 cheshire +Tidy up code layout -Revision 1.180 2004/07/29 02:03:35 ksekar -Delete unused #define and structure field +Revision 1.377 2007/05/15 00:43:33 cheshire +Remove unused regState_Cancelled -Revision 1.179 2004/07/26 22:49:30 ksekar -: Feature #9516: Need support for NAT-PMP in client +Revision 1.376 2007/05/14 23:51:49 cheshire +Added constants MAX_REVERSE_MAPPING_NAME_V4 and MAX_REVERSE_MAPPING_NAME_V6 -Revision 1.178 2004/07/13 21:24:24 rpantos -Fix for . +Revision 1.375 2007/05/10 21:19:18 cheshire +Rate-limit DNS test queries to at most one per three seconds +(useful when we have a dozen active WAB queries, and then we join a new network) -Revision 1.177 2004/06/05 00:04:26 cheshire -: wide-area domains should be returned in reg. domain enumeration +Revision 1.374 2007/05/07 22:07:47 cheshire + Enhance GetLargeResourceRecord to decompress more record types -Revision 1.176 2004/06/04 08:58:29 ksekar -: Keychain integration for secure dynamic update +Revision 1.373 2007/05/07 20:43:45 cheshire + Reduce the number of queries and announcements -Revision 1.175 2004/06/04 00:15:06 cheshire -Move misplaced brackets +Revision 1.372 2007/05/04 22:15:29 cheshire +Get rid of unused q->RestartTime -Revision 1.174 2004/06/03 23:30:16 cheshire -Remove extraneous blank lines and white space +Revision 1.371 2007/05/03 22:40:37 cheshire + mDNSResponder ignores bogus null target in SRV record -Revision 1.173 2004/06/03 03:09:58 ksekar -: Garbage Collection for Dynamic Updates +Revision 1.370 2007/05/02 22:18:09 cheshire +Renamed NATTraversalInfo_struct context to NATTraversalContext -Revision 1.172 2004/06/01 23:46:50 ksekar -: DynDNS: dynamically look up LLQ/Update ports +Revision 1.369 2007/05/01 21:21:42 cheshire +Add missing parentheses in LEASE_OPT_RDLEN definition -Revision 1.171 2004/05/28 23:42:37 ksekar -: Feature: DNS server->client notification on record changes (#7805) +Revision 1.368 2007/04/30 21:33:38 cheshire +Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop +is iterating through the m->ServiceRegistrations list -Revision 1.170 2004/05/18 23:51:25 cheshire -Tidy up all checkin comments to use consistent "" format for bug numbers +Revision 1.367 2007/04/28 01:31:59 cheshire +Improve debugging support for catching memory corruption problems -Revision 1.169 2004/05/13 04:54:20 ksekar -Unified list copy/free code. Added symetric list for +Revision 1.366 2007/04/27 19:28:02 cheshire +Any code that calls StartGetZoneData needs to keep a handle to the structure, so +it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop +-- it would start a query and then quickly cancel it, and then when +StartGetZoneData completed, it had a dangling pointer and crashed.) -Revision 1.168 2004/05/12 22:03:09 ksekar -Made GetSearchDomainList a true platform-layer call (declaration moved -from mDNSMacOSX.h to mDNSEmbeddedAPI.h), implemented to return "local" -only on non-OSX platforms. Changed call to return a copy of the list -to avoid shared memory issues. Added a routine to free the list. +Revision 1.365 2007/04/26 00:35:15 cheshire + uDNS: Domain discovery not working over VPN +Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server +inside the firewall may give answers where a public one gives none, and vice versa.) -Revision 1.167 2004/04/22 04:07:01 cheshire -Fix from Bob Bradley: Don't try to do inline functions on compilers that don't support it +Revision 1.364 2007/04/24 02:07:42 cheshire + Identical client queries should reference a single shared core query +Deleted some more redundant code -Revision 1.166 2004/04/22 03:15:56 cheshire -Fix use of "struct __attribute__((__packed__))" so it only applies on GCC >= 2.9 +Revision 1.363 2007/04/24 00:09:47 cheshire +Remove MappedV4 field from mDNS_struct (not actually used anywhere) -Revision 1.165 2004/04/22 03:05:28 cheshire -kDNSClass_ANY should be kDNSQClass_ANY +Revision 1.362 2007/04/22 06:02:02 cheshire + Query should immediately return failure when no server -Revision 1.164 2004/04/21 02:55:03 cheshire -Update comments describing 'InterfaceActive' field +Revision 1.361 2007/04/21 19:43:33 cheshire +Code tidying: represent NAT opcodes as bitwise combinations rather than numerical additions -Revision 1.163 2004/04/21 02:49:11 cheshire -To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx' +Revision 1.360 2007/04/20 21:17:24 cheshire +For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative -Revision 1.162 2004/04/15 00:51:28 bradley -Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers. -Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers. +Revision 1.359 2007/04/19 22:50:53 cheshire + Identical client queries should reference a single shared core query -Revision 1.161 2004/04/14 23:09:28 ksekar -Support for TSIG signed dynamic updates. +Revision 1.358 2007/04/19 20:06:41 cheshire +Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer) -Revision 1.160 2004/04/09 17:40:26 cheshire -Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field +Revision 1.357 2007/04/19 18:14:51 cheshire +In mDNS_AddSearchDomain_CString check for NULL pointer before calling MakeDomainNameFromDNSNameString() -Revision 1.159 2004/04/09 16:37:15 cheshire -Suggestion from Bob Bradley: -Move NumCacheRecordsForInterfaceID() to DNSCommon.c so it's available to all platform layers +Revision 1.356 2007/04/18 20:56:46 cheshire +Added mDNS_AddSearchDomain_CString macro -Revision 1.158 2004/04/02 19:38:33 cheshire -Update comment about typical RR TTLs +Revision 1.355 2007/04/17 19:21:29 cheshire + Domain discovery not working over VPN -Revision 1.157 2004/04/02 19:35:53 cheshire -Add clarifying comments about legal mDNSInterfaceID values +Revision 1.354 2007/04/05 22:55:34 cheshire + Records are ending up in Lighthouse without expiry information -Revision 1.156 2004/04/02 19:19:48 cheshire -Add code to do optional logging of multi-packet KA list time intervals +Revision 1.353 2007/04/05 20:40:37 cheshire +Remove unused mDNSPlatformTCPGetFlags() -Revision 1.155 2004/03/24 00:29:45 ksekar -Make it safe to call StopQuery in a unicast question callback +Revision 1.352 2007/04/04 21:48:52 cheshire + Combine unicast authoritative answer list with multicast list -Revision 1.154 2004/03/20 01:05:49 cheshire -Test __LP64__ and __ILP64__ to compile properly on a wider range of 64-bit architectures +Revision 1.351 2007/04/04 01:27:45 cheshire +Update comment -Revision 1.153 2004/03/13 01:57:33 ksekar -: DynDNS: Dynamic update of service records +Revision 1.350 2007/04/04 00:03:26 cheshire + DNSServiceQueryRecord is returning kDNSServiceErr_NoSuchRecord for empty rdata -Revision 1.152 2004/03/09 02:27:16 cheshire -Remove erroneous underscore in 'packed_struct' (makes no difference now, but might in future) +Revision 1.349 2007/04/03 19:37:58 cheshire +Rename mDNSAddrIsv4Private() to more precise mDNSAddrIsRFC1918() -Revision 1.151 2004/03/02 03:21:56 cheshire - Properly support "_services._dns-sd._udp" meta-queries +Revision 1.348 2007/04/03 19:13:39 cheshire +Added macros mDNSSameIPPort, mDNSSameOpaque16, mDNSIPPortIsZero, mDNSOpaque16IsZero -Revision 1.150 2004/02/21 02:06:24 cheshire -Can't use anonymous unions -- they're non-standard and don't work on all compilers +Revision 1.347 2007/03/28 20:59:26 cheshire + Remove inappropriate use of IsPrivateV4Addr() -Revision 1.149 2004/02/06 23:04:19 ksekar -Basic Dynamic Update support via mDNS_Register (dissabled via -UNICAST_REGISTRATION #define) +Revision 1.346 2007/03/28 15:56:37 cheshire + Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output -Revision 1.148 2004/02/03 19:47:36 ksekar -Added an asynchronous state machine mechanism to uDNS.c, including -calls to find the parent zone for a domain name. Changes include code -in repository previously dissabled via "#if 0 incomplete". Codepath -is currently unused, and will be called to create update records, etc. +Revision 1.345 2007/03/22 19:29:23 cheshire +Add comment and check to ensure StandardAuthRDSize is at least 256 bytes -Revision 1.147 2004/02/03 18:57:35 cheshire -Update comment for "IsLocalDomain()" +Revision 1.344 2007/03/22 18:31:48 cheshire +Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy -Revision 1.146 2004/01/30 02:20:24 bradley -Map inline to __inline when building with Microsoft C compilers since they do not support C99 inline. +Revision 1.343 2007/03/22 00:49:20 cheshire + Advertise model information via Bonjour -Revision 1.145 2004/01/29 02:59:17 ksekar -Unicast DNS: Changed from a resource record oriented question/response -matching to packet based matching. New callback architecture allows -collections of records in a response to be processed differently -depending on the nature of the request, and allows the same structure -to be used for internal and client-driven queries with different processing needs. +Revision 1.342 2007/03/21 23:06:00 cheshire +Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields -Revision 1.144 2004/01/28 20:20:45 ksekar -Unified ActiveQueries and ActiveInternalQueries lists, using a flag to -demux them. Check-in includes work-in-progress code, #ifdef'd out. +Revision 1.341 2007/03/21 20:44:11 cheshire +Added mDNSAddressIsv4LinkLocal macro -Revision 1.143 2004/01/28 03:41:00 cheshire -: Need ability to do targeted queries as well as multicast queries +Revision 1.340 2007/03/21 00:30:02 cheshire + Multiple errors in DNameList-related code -Revision 1.142 2004/01/28 02:30:07 ksekar -Added default Search Domains to unicast browsing, controlled via -Networking sharing prefs pane. Stopped sending unicast messages on -every interface. Fixed unicast resolving via mach-port API. +Revision 1.339 2007/03/20 17:07:15 cheshire +Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket" -Revision 1.141 2004/01/27 20:15:22 cheshire -: Time to prune obsolete code for listening on port 53 +Revision 1.338 2007/03/10 02:28:28 cheshire +Added comment explaining NATResponseHndlr -Revision 1.140 2004/01/24 23:37:08 cheshire -At Kiren's suggestion, made functions to convert mDNSOpaque16s to/from integer values +Revision 1.337 2007/03/10 02:02:58 cheshire + uDNS: LLQ refresh response packet causes cached records to be removed from cache +Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer -Revision 1.139 2004/01/24 08:46:26 bradley -Added InterfaceID<->Index platform interfaces since they are now used by all platforms for the DNS-SD APIs. +Revision 1.336 2007/02/28 22:12:24 cheshire +Get rid of unused mDNSVal32 and mDNSOpaque32fromIntVal -Revision 1.138 2004/01/24 04:59:15 cheshire -Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again +Revision 1.335 2007/02/28 21:49:07 cheshire +Off-by-one error: SameDomainLabelCS (case-sensitive) was stopping one character short of +the end of the label, e.g. it would fail to detect that "chesh1" and "chesh2" are different. -Revision 1.137 2004/01/24 03:40:56 cheshire -Move mDNSAddrIsDNSMulticast() from DNSCommon.h to mDNSEmbeddedAPI.h so clients can use it +Revision 1.334 2007/02/28 01:44:26 cheshire + Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c -Revision 1.136 2004/01/24 03:38:27 cheshire -Fix minor syntactic error: Headers should use "extern" declarations, not "mDNSexport" +Revision 1.333 2007/02/27 22:55:22 cheshire +Get rid of unused AllDNSLinkGroupv4 and AllDNSLinkGroupv6 -Revision 1.135 2004/01/23 23:23:15 ksekar -Added TCP support for truncated unicast messages. +Revision 1.332 2007/02/27 02:48:24 cheshire +Parameter to LNT_GetPublicIP function is IPv4 address, not anonymous "mDNSOpaque32" object -Revision 1.134 2004/01/22 03:54:11 cheshire -Create special meta-interface 'mDNSInterface_ForceMCast' (-2), -which means "do this query via multicast, even if it's apparently a unicast domain" +Revision 1.331 2007/02/14 03:16:39 cheshire + Eliminate unnecessary malloc/free in mDNSCore code -Revision 1.133 2004/01/22 03:48:41 cheshire -Make sure uDNS client doesn't accidentally use query ID zero +Revision 1.330 2007/02/08 21:12:28 cheshire + Stop reading /etc/mDNSResponder.conf on every sleep/wake -Revision 1.132 2004/01/22 03:43:08 cheshire -Export constants like mDNSInterface_LocalOnly so that the client layers can use them +Revision 1.329 2007/02/07 01:19:36 cheshire + API: Reconcile conflicting error code values -Revision 1.131 2004/01/21 21:53:18 cheshire -: Don't try to receive unicast responses if we're not the first to bind to the UDP port +Revision 1.328 2007/01/25 00:19:40 cheshire +Add CNAMEReferrals field to DNSQuestion_struct -Revision 1.130 2003/12/14 05:05:29 cheshire -Add comments explaining mDNS_Init_NoCache and mDNS_Init_ZeroCacheSize +Revision 1.327 2007/01/23 02:56:10 cheshire +Store negative results in the cache, instead of generating them out of pktResponseHndlr() -Revision 1.129 2003/12/13 03:05:27 ksekar -: DynDNS: Unicast query of service records - -Revision 1.128 2003/12/01 21:44:23 cheshire -Add mStatus_BadInterfaceErr = -65552 for consistency with dns_sd.h - -Revision 1.127 2003/12/01 18:26:37 cheshire -Also pack the OpaqueXX union types. Otherwise, on some systems, mDNSOpaque16 is four bytes! - -Revision 1.126 2003/12/01 18:23:48 cheshire -: Scalar size problem in mDNS code on some 64-bit architectures - -Revision 1.125 2003/11/22 00:18:27 cheshire -Add compile-time asserts to verify correct sizes of mDNSu32, mDNSOpaque16, etc. - -Revision 1.124 2003/11/20 22:59:54 cheshire -Changed runtime checks in mDNS.c to be compile-time checks in mDNSEmbeddedAPI.h -Thanks to Bob Bradley for suggesting the ingenious compiler trick to make this work. - -Revision 1.123 2003/11/20 22:53:01 cheshire -Add comment about MAX_ESCAPED_DOMAIN_LABEL - -Revision 1.122 2003/11/20 20:49:53 cheshire -Another fix from HP: Use packedstruct macro to ensure proper packing for on-the-wire packet structures - -Revision 1.121 2003/11/20 05:01:38 cheshire -Update comments; add explanation of Advertise/DontAdvertiseLocalAddresses - -Revision 1.120 2003/11/14 20:59:08 cheshire -Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h. -Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file. - -Revision 1.119 2003/11/14 19:47:52 cheshire -Define symbol MAX_ESCAPED_DOMAIN_NAME to indicate recommended buffer size for ConvertDomainNameToCString - -Revision 1.118 2003/11/14 19:18:34 cheshire -Move AssignDomainName macro to mDNSEmbeddedAPI.h to that client layers can use it too - -Revision 1.117 2003/11/08 23:32:24 cheshire -Gave name to anonymous struct, to avoid errors on certain compilers. -(Thanks to ramaprasad.kr@hp.com for reporting this.) - -Revision 1.116 2003/11/07 03:32:56 cheshire - mDNSResponder delivers answers in inconsistent order -This is the real fix. Checkin 1.312 was overly simplistic; Calling GetFreeCacheRR() can sometimes -purge records from the cache, causing tail pointer *rp to be stale on return. The correct fix is -to maintain a system-wide tail pointer for each cache slot, and then if neccesary GetFreeCacheRR() -can update this pointer, so that mDNSCoreReceiveResponse() appends records in the right place. - -Revision 1.115 2003/09/23 00:53:54 cheshire -NumFailedProbes should be unsigned - -Revision 1.114 2003/08/29 19:44:15 cheshire - Traffic reduction: Eliminate synchronized QUs when a new service appears -1. Use m->RandomQueryDelay to impose a random delay in the range 0-500ms on queries - that already have at least one unique answer in the cache -2. For these queries, go straight to QM, skipping QU - -Revision 1.113 2003/08/21 19:31:58 cheshire -Cosmetic: Swap order of fields - -Revision 1.112 2003/08/21 19:27:36 cheshire - Traffic reduction: No need to announce record for longer than TTL - -Revision 1.111 2003/08/21 02:21:50 cheshire - Efficiency: Reduce repeated queries - -Revision 1.110 2003/08/20 23:39:31 cheshire - Review syslog messages, and remove as appropriate - -Revision 1.109 2003/08/19 22:24:10 cheshire -Comment change - -Revision 1.108 2003/08/19 22:20:00 cheshire - Don't use IPv6 on interfaces that have a routable IPv4 address configured -More minor refinements - -Revision 1.107 2003/08/19 06:48:25 cheshire - Guard against excessive record updates -Each record starts with 10 UpdateCredits. -Every update consumes one UpdateCredit. -UpdateCredits are replenished at a rate of one one per minute, up to a maximum of 10. -As the number of UpdateCredits declines, the number of announcements is similarly scaled back. -When fewer than 5 UpdateCredits remain, the first announcement is also delayed by an increasing amount. - -Revision 1.106 2003/08/19 04:49:28 cheshire - Interaction between v4, v6 and dual-stack hosts not working quite right -1. A dual-stack host should only suppress its own query if it sees the same query from other hosts on BOTH IPv4 and IPv6. -2. When we see the first v4 (or first v6) member of a group, we re-trigger questions and probes on that interface. -3. When we see the last v4 (or v6) member of a group go away, we revalidate all the records received on that interface. - -Revision 1.105 2003/08/19 02:33:37 cheshire +Revision 1.326 2007/01/20 01:30:49 cheshire Update comments -Revision 1.104 2003/08/19 02:31:11 cheshire - mDNSResponder overenthusiastic with final expiration queries -Final expiration queries now only mark the question for sending on the particular interface -pertaining to the record that's expiring. - -Revision 1.103 2003/08/18 19:05:44 cheshire - UpdateRecord not working right -Added "newrdlength" field to hold new length of updated rdata - -Revision 1.102 2003/08/16 03:39:00 cheshire - InterfaceID -1 indicates "local only" - -Revision 1.101 2003/08/15 20:16:02 cheshire - mDNSResponder takes too much RPRVT -We want to avoid touching the rdata pages, so we don't page them in. -1. RDLength was stored with the rdata, which meant touching the page just to find the length. - Moved this from the RData to the ResourceRecord object. -2. To avoid unnecessarily touching the rdata just to compare it, - compute a hash of the rdata and store the hash in the ResourceRecord object. - -Revision 1.100 2003/08/14 19:29:04 cheshire - Include cache records in SIGINFO output -Moved declarations of DNSTypeName() and GetRRDisplayString to mDNSEmbeddedAPI.h so daemon.c can use them - -Revision 1.99 2003/08/14 02:17:05 cheshire - Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord - -Revision 1.98 2003/08/12 19:56:23 cheshire -Update to APSL 2.0 - -Revision 1.97 2003/08/12 14:59:27 cheshire - Rate-limiting blocks some legitimate responses -When setting LastMCTime also record LastMCInterface. When checking LastMCTime to determine -whether to suppress the response, also check LastMCInterface to see if it matches. - -Revision 1.96 2003/08/12 13:57:04 cheshire - Improve cache performance -Changed the number of hash table slots from 37 to 499 - -Revision 1.95 2003/08/09 00:55:02 cheshire - mDNSResponder is taking 20-30% of the CPU -Don't scan the whole cache after every packet. - -Revision 1.94 2003/08/09 00:35:29 cheshire - -Revision 1.93 2003/08/08 18:55:48 cheshire - Guard against time going backwards - -Revision 1.92 2003/08/08 18:36:04 cheshire - Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug - -Revision 1.91 2003/08/06 21:33:39 cheshire -Fix compiler warnings on PocketPC 2003 (Windows CE) - -Revision 1.90 2003/08/06 20:30:17 cheshire -Add structure definition for rdataMX (not currently used, but good to have it for completeness) - -Revision 1.89 2003/08/06 18:58:19 cheshire -Update comments - -Revision 1.88 2003/07/24 23:45:44 cheshire -To eliminate compiler warnings, changed definition of mDNSBool from -"unsigned char" to "int", since "int" is in fact truly the type that C uses -for the result of comparison operators (a: Feature: New DNS-SD APIs (#7875) (mDNSResponder component) -Added error type for incompatibility between daemon and client versions +Revision 1.324 2007/01/19 18:04:04 cheshire +For naming consistency, use capital letters for RR types: rdataOpt should be rdataOPT -Revision 1.85 2003/07/19 03:23:13 cheshire - mDNSResponder needs to receive and cache larger records +Revision 1.323 2007/01/17 21:46:02 cheshire +Remove redundant duplicated "isPrivate" field from LLQ_Info -Revision 1.84 2003/07/18 23:52:12 cheshire -To improve consistency of field naming, global search-and-replace: -NextProbeTime -> NextScheduledProbe -NextResponseTime -> NextScheduledResponse +Revision 1.322 2007/01/10 22:51:56 cheshire + Add support for one-shot private queries as well as long-lived private queries -Revision 1.83 2003/07/18 00:29:59 cheshire - Remove mDNSResponder version from packet header and use HINFO record instead +Revision 1.321 2007/01/09 22:37:18 cheshire +Provide ten-second grace period for deleted keys, to give mDNSResponder +time to delete host name before it gives up access to the required key. -Revision 1.82 2003/07/17 17:35:04 cheshire - Rate-limit responses, to guard against packet flooding +Revision 1.320 2007/01/05 08:30:41 cheshire +Trim excessive "$Log" checkin history from before 2006 +(checkin history still available via "cvs log ..." of course) -Revision 1.81 2003/07/16 05:01:36 cheshire -Add fields 'LargeAnswers' and 'ExpectUnicastResponse' in preparation for - Need to implement "unicast response" request, using top bit of qclass +Revision 1.319 2007/01/04 23:11:11 cheshire + uDNS: Need to start caching unicast records +When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries -Revision 1.80 2003/07/15 01:55:12 cheshire - Need to implement service registration with subtypes +Revision 1.318 2007/01/04 20:57:48 cheshire +Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates) -Revision 1.79 2003/07/13 02:28:00 cheshire - SendResponses didn't all its responses -Delete all references to RRInterfaceActive -- it's now superfluous +Revision 1.317 2007/01/04 02:39:53 cheshire + Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations -Revision 1.78 2003/07/13 01:47:53 cheshire -Fix one error and one warning in the Windows build +Revision 1.316 2006/12/22 20:59:49 cheshire + Read *all* DNS keys from keychain, + not just key for the system-wide default registration domain -Revision 1.77 2003/07/11 01:32:38 cheshire -Syntactic cleanup (no change to funcationality): Now that we only have one host name, -rename field "hostname1" to "hostname", and field "RR_A1" to "RR_A". +Revision 1.315 2006/12/20 04:07:35 cheshire +Remove uDNS_info substructure from AuthRecord_struct -Revision 1.76 2003/07/11 01:28:00 cheshire - No more local.arpa +Revision 1.314 2006/12/19 22:49:23 cheshire +Remove uDNS_info substructure from ServiceRecordSet_struct -Revision 1.75 2003/07/02 21:19:45 cheshire - Update copyright notices, etc., in source code comments +Revision 1.313 2006/12/19 02:38:20 cheshire +Get rid of unnecessary duplicate query ID field from DNSQuestion_struct -Revision 1.74 2003/07/02 02:41:23 cheshire - mDNSResponder needs to start with a smaller cache and then grow it as needed +Revision 1.312 2006/12/19 02:18:48 cheshire +Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct -Revision 1.73 2003/06/10 04:24:39 cheshire - React when we observe other people query unsuccessfully for a record that's in our cache -Some additional refinements: -Don't try to do this for unicast-response queries -better tracking of Qs and KAs in multi-packet KA lists +Revision 1.311 2006/12/16 01:58:31 cheshire + uDNS: Need to start caching unicast records -Revision 1.72 2003/06/10 01:46:27 cheshire -Add better comments explaining how these data structures are intended to be used from the client layer +Revision 1.310 2006/12/15 19:09:56 cheshire + ValidateRData() should be stricter about malformed MX and SRV records +Made DomainNameLength() more defensive by adding a limit parameter, so it can be +safely used to inspect potentially malformed data received from external sources. +Without this, a domain name that starts off apparently valid, but extends beyond the end of +the received packet data, could have appeared valid if the random bytes are already in memory +beyond the end of the packet just happened to have reasonable values (e.g. all zeroes). -Revision 1.71 2003/06/07 06:45:05 cheshire - No need for multiple machines to all be sending the same queries +Revision 1.309 2006/12/14 03:02:37 cheshire + Tools: dns-sd -G 0 only returns IPv6 when you have a routable IPv6 address -Revision 1.70 2003/06/07 04:50:53 cheshire - React when we observe other people query unsuccessfully for a record that's in our cache +Revision 1.308 2006/11/30 23:07:56 herscher + uDNS: Sync up with Lighthouse changes for Private DNS -Revision 1.69 2003/06/07 04:22:17 cheshire -Add MsgBuffer for error log and debug messages +Revision 1.307 2006/11/18 05:01:30 cheshire +Preliminary support for unifying the uDNS and mDNS code, +including caching of uDNS answers -Revision 1.68 2003/06/07 01:46:38 cheshire - When query produces zero results, call mDNS_Reconfirm() on any antecedent records +Revision 1.306 2006/11/10 07:44:04 herscher + Fix Daemon locking failures while toggling BTMM -Revision 1.67 2003/06/07 01:22:14 cheshire - mDNSResponder needs an mDNS_Reconfirm() function +Revision 1.305 2006/11/10 00:54:15 cheshire + Changing case of Computer Name doesn't work -Revision 1.66 2003/06/07 00:59:43 cheshire - Need some randomness to spread queries on the network +Revision 1.304 2006/10/20 05:35:05 herscher + uDNS: Merge unicast active question list with multicast list. -Revision 1.65 2003/06/06 21:41:11 cheshire -For consistency, mDNS_StopQuery() should return an mStatus result, just like all the other mDNSCore routines +Revision 1.303 2006/10/04 21:37:33 herscher +Remove uDNS_info substructure from DNSQuestion_struct -Revision 1.64 2003/06/06 21:38:55 cheshire -Renamed 'NewData' as 'FreshData' (The data may not be new data, just a refresh of data that we -already had in our cache. This refreshes our TTL on the data, but the data itself stays the same.) +Revision 1.302 2006/09/26 01:53:25 herscher + NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol) -Revision 1.63 2003/06/06 17:20:14 cheshire -For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass -(Global search-and-replace; no functional change to code execution.) +Revision 1.301 2006/09/15 21:20:15 cheshire +Remove uDNS_info substructure from mDNS_struct -Revision 1.62 2003/06/04 01:25:33 cheshire - Cannot perform multi-packet known-answer suppression messages -Display time interval between first and subsequent queries +Revision 1.300 2006/08/14 23:24:23 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 -Revision 1.61 2003/06/03 05:02:16 cheshire - Duplicate registrations not handled as efficiently as they should be +Revision 1.299 2006/07/15 02:01:28 cheshire + Add Private DNS client functionality to mDNSResponder +Fix broken "empty string" browsing -Revision 1.60 2003/05/31 00:09:49 cheshire - Add ability to discover what services are on a network +Revision 1.298 2006/07/05 22:55:03 cheshire + Add Private DNS client functionality to mDNSResponder +Need Private field in uDNS_RegInfo -Revision 1.59 2003/05/29 06:11:35 cheshire -: Report if there appear to be too many "Resolve" callbacks +Revision 1.297 2006/07/05 22:20:03 cheshire + Add Private DNS client functionality to mDNSResponder -Revision 1.58 2003/05/29 05:48:06 cheshire -Minor fix for when generating printf warnings: mDNS_snprintf arguments are now 3,4 +Revision 1.296 2006/06/29 05:28:01 cheshire +Added comment about mDNSlocal and mDNSexport -Revision 1.57 2003/05/26 03:21:27 cheshire -Tidy up address structure naming: -mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr) -mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4 -mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6 +Revision 1.295 2006/06/29 03:02:43 cheshire + mDNSResponder NXDOMAIN and CNAME support -Revision 1.56 2003/05/26 03:01:27 cheshire - sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead +Revision 1.294 2006/06/28 06:50:08 cheshire +In future we may want to change definition of mDNSs32 from "signed long" to "signed int" +I doubt anyone is building mDNSResponder on systems where int is 16-bits, +but lets add a compile-time assertion to make sure. -Revision 1.55 2003/05/26 00:47:30 cheshire -Comment clarification +Revision 1.293 2006/06/12 18:00:43 cheshire +To make code a little more defensive, check _ILP64 before _LP64, +in case both are set by mistake on some platforms -Revision 1.54 2003/05/24 16:39:48 cheshire - SendResponses also needs to handle multihoming better +Revision 1.292 2006/03/19 17:00:57 cheshire +Define symbol MaxMsg instead of using hard-coded constant value '80' -Revision 1.53 2003/05/23 02:15:37 cheshire -Fixed misleading use of the term "duplicate suppression" where it should have -said "known answer suppression". (Duplicate answer suppression is something -different, and duplicate question suppression is yet another thing, so the use -of the completely vague term "duplicate suppression" was particularly bad.) +Revision 1.291 2006/03/19 02:00:07 cheshire + Improve logic for delaying packets after repeated interface transitions -Revision 1.52 2003/05/22 02:29:22 cheshire - SendQueries needs to handle multihoming better -Complete rewrite of SendQueries. Works much better now :-) +Revision 1.290 2006/03/08 22:42:23 cheshire +Fix spelling mistake: LocalReverseMapomain -> LocalReverseMapDomain -Revision 1.51 2003/05/21 20:14:55 cheshire -Fix comments and warnings - -Revision 1.50 2003/05/14 07:08:36 cheshire - mDNSResponder should be smarter about reconfigurations -Previously, when there was any network configuration change, mDNSResponder -would tear down the entire list of active interfaces and start again. -That was very disruptive, and caused the entire cache to be flushed, -and caused lots of extra network traffic. Now it only removes interfaces -that have really gone, and only adds new ones that weren't there before. - -Revision 1.49 2003/05/07 01:49:36 cheshire -Remove "const" in ConstructServiceName prototype - -Revision 1.48 2003/05/07 00:18:44 cheshire -Fix typo: "kDNSQClass_Mask" should be "kDNSClass_Mask" - -Revision 1.47 2003/05/06 00:00:46 cheshire - Rationalize naming of domainname manipulation functions - -Revision 1.46 2003/04/30 20:39:09 cheshire -Add comment - -Revision 1.45 2003/04/29 00:40:50 cheshire -Fix compiler warnings - -Revision 1.44 2003/04/26 02:41:56 cheshire - Change timenow from a local variable to a structure member - -Revision 1.43 2003/04/25 01:45:56 cheshire - mDNS_RegisterNoSuchService needs to include a host name - -Revision 1.42 2003/04/15 20:58:31 jgraessl - - Added a hash to lookup records in the cache. - -Revision 1.41 2003/04/15 18:09:13 jgraessl - - -Reviewed by: Stuart Cheshire -Added code to keep track of when the next cache item will expire so we can -call TidyRRCache only when necessary. - -Revision 1.40 2003/03/29 01:55:19 cheshire - mDNSResponder sometimes suffers false self-conflicts when it sees its own packets -Solution: Major cleanup of packet timing and conflict handling rules - -Revision 1.39 2003/03/27 03:30:55 cheshire - Name conflicts not handled properly, resulting in memory corruption, and eventual crash -Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback -Fixes: -1. Make mDNS_DeregisterInterface() safe to call from a callback -2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead - (it never really needed to deregister the interface at all) - -Revision 1.38 2003/03/15 04:40:36 cheshire -Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID" - -Revision 1.37 2003/03/14 21:34:11 cheshire - Can't setup and print to Lexmark PS printers via Airport Extreme -Increase size of cache rdata from 512 to 768 - -Revision 1.36 2003/03/05 03:38:35 cheshire - Bogus error message in console: died or deallocated, but no record of client can be found! -Fixed by leaving client in list after conflict, until client explicitly deallocates - -Revision 1.35 2003/02/21 02:47:54 cheshire - mDNSResponder needs performance improvements -Several places in the code were calling CacheRRActive(), which searched the entire -question list every time, to see if this cache resource record answers any question. -Instead, we now have a field "CRActiveQuestion" in the resource record structure - -Revision 1.34 2003/02/21 01:54:08 cheshire - mDNSResponder needs performance improvements -Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt") - -Revision 1.33 2003/02/20 06:48:32 cheshire - Xserve RAID needs to do interface-specific registrations -Reviewed by: Josh Graessley, Bob Bradley - -Revision 1.32 2003/01/31 03:35:59 cheshire - mDNSResponder sometimes fails to find the correct results -When there were *two* active questions in the list, they were incorrectly -finding *each other* and *both* being marked as duplicates of another question - -Revision 1.31 2003/01/29 02:46:37 cheshire -Fix for IPv6: -A physical interface is identified solely by its InterfaceID (not by IP and type). -On a given InterfaceID, mDNSCore may send both v4 and v6 multicasts. -In cases where the requested outbound protocol (v4 or v6) is not supported on -that InterfaceID, the platform support layer should simply discard that packet. - -Revision 1.30 2003/01/29 01:47:08 cheshire -Rename 'Active' to 'CRActive' or 'InterfaceActive' for improved clarity - -Revision 1.29 2003/01/28 05:23:43 cheshire - mDNSResponder sometimes fails to find the correct results -Add 'Active' flag for interfaces - -Revision 1.28 2003/01/28 01:35:56 cheshire -Revise comment about ThisQInterval to reflect new semantics - -Revision 1.27 2003/01/13 23:49:42 jgraessl -Merged changes for the following fixes in to top of tree: - computer name changes not handled properly - service name changes are not properly handled - announcements sent in pairs, failing chattiness test - -Revision 1.26 2002/12/23 22:13:28 jgraessl - -Reviewed by: Stuart Cheshire -Initial IPv6 support for mDNSResponder. - -Revision 1.25 2002/09/21 20:44:49 zarzycki -Added APSL info - -Revision 1.24 2002/09/19 23:47:35 cheshire -Added mDNS_RegisterNoSuchService() function for assertion of non-existence -of a particular named service - -Revision 1.23 2002/09/19 21:25:34 cheshire -mDNS_snprintf() doesn't need to be in a separate file - -Revision 1.22 2002/09/19 04:20:43 cheshire -Remove high-ascii characters that confuse some systems - -Revision 1.21 2002/09/17 01:06:35 cheshire -Change mDNS_AdvertiseLocalAddresses to be a parameter to mDNS_Init() - -Revision 1.20 2002/09/16 18:41:41 cheshire -Merge in license terms from Quinn's copy, in preparation for Darwin release +Revision 1.289 2006/02/26 00:54:41 cheshire +Fixes to avoid code generation warning/error on FreeBSD 7 */ #ifndef __mDNSClientAPI_h #define __mDNSClientAPI_h +#if defined(EFI32) || defined(EFI64) +// EFI doesn't have stdarg.h +#include "Tiano.h" +#define va_list VA_LIST +#define va_start(a, b) VA_START(a, b) +#define va_end(a) VA_END(a) +#define va_arg(a, b) VA_ARG(a, b) +#else #include // stdarg.h is required for for va_list support for the mDNS_vsnprintf declaration +#endif + #include "mDNSDebug.h" #ifdef __cplusplus @@ -1020,6 +609,19 @@ Merge in license terms from Quinn's copy, in preparation for Darwin release #define mDNSexport #endif +// Explanation: These local/export markers are a little habit of mine for signaling the programmers' intentions. +// When "mDNSlocal" is just a synonym for "static", and "mDNSexport" is a complete no-op, you could be +// forgiven for asking what purpose they serve. The idea is that if you see "mDNSexport" in front of a +// function definition it means the programmer intended it to be exported and callable from other files +// in the project. If you see "mDNSlocal" in front of a function definition it means the programmer +// intended it to be private to that file. If you see neither in front of a function definition it +// means the programmer forgot (so you should work out which it is supposed to be, and fix it). +// Using "mDNSlocal" instead of "static" makes it easier to do a textual searches for one or the other. +// For example you can do a search for "static" to find if any functions declare any local variables as "static" +// (generally a bad idea unless it's also "const", because static storage usually risks being non-thread-safe) +// without the results being cluttered with hundreds of matches for functions declared static. +// - Stuart Cheshire + // *************************************************************************** // Structure packing macro @@ -1075,13 +677,47 @@ typedef enum // From RFC 1035 kDNSType_MINFO, // 14 Mailbox information kDNSType_MX, // 15 Mail Exchanger kDNSType_TXT, // 16 Arbitrary text string - - kDNSType_AAAA = 28, // 28 IPv6 address - kDNSType_SRV = 33, // 33 Service record - kDNSType_OPT = 41, // EDNS0 OPT record - kDNSType_TSIG = 250, // 250 Transaction Signature - - kDNSQType_ANY = 255 // Not a DNS type, but a DNS query type, meaning "all types" + kDNSType_RP, // 17 Responsible person. + kDNSType_AFSDB, // 18 AFS cell database. + kDNSType_X25, // 19 X_25 calling address. + kDNSType_ISDN, // 20 ISDN calling address. + kDNSType_RT, // 21 Router. + kDNSType_NSAP, // 22 NSAP address. + kDNSType_NSAP_PTR, // 23 Reverse NSAP lookup (deprecated). + kDNSType_SIG, // 24 Security signature. + kDNSType_KEY, // 25 Security key. + kDNSType_PX, // 26 X.400 mail mapping. + kDNSType_GPOS, // 27 Geographical position (withdrawn). + kDNSType_AAAA, // 28 IPv6 Address. + kDNSType_LOC, // 29 Location Information. + kDNSType_NXT, // 30 Next domain (security). + kDNSType_EID, // 31 Endpoint identifier. + kDNSType_NIMLOC, // 32 Nimrod Locator. + kDNSType_SRV, // 33 Service record. + kDNSType_ATMA, // 34 ATM Address + kDNSType_NAPTR, // 35 Naming Authority PoinTeR + kDNSType_KX, // 36 Key Exchange + kDNSType_CERT, // 37 Certification record + kDNSType_A6, // 38 IPv6 Address (deprecated) + kDNSType_DNAME, // 39 Non-terminal DNAME (for IPv6) + kDNSType_SINK, // 40 Kitchen sink (experimentatl) + kDNSType_OPT, // 41 EDNS0 option (meta-RR) + kDNSType_APL, // 42 Address Prefix List + kDNSType_DS, // 43 Delegation Signer + kDNSType_SSHFP, // 44 SSH Key Fingerprint + kDNSType_IPSECKEY, // 45 IPSECKEY + kDNSType_RRSIG, // 46 RRSIG + kDNSType_NSEC, // 47 NSEC + kDNSType_DNSKEY, // 48 DNSKEY + kDNSType_DHCID, // 49 DHCID + + kDNSType_TKEY = 249, // 249 Transaction key + kDNSType_TSIG, // 250 Transaction signature. + kDNSType_IXFR, // 251 Incremental zone transfer. + kDNSType_AXFR, // 252 Transfer zone of authority. + kDNSType_MAILB, // 253 Transfer mailbox records. + kDNSType_MAILA, // 254 Transfer mail agent records. + kDNSQType_ANY // Not a DNS type, but a DNS query type, meaning "all types" } DNS_TypeValues; // *************************************************************************** @@ -1105,15 +741,17 @@ typedef unsigned short mDNSu16; // Macro Name __LP64__ Value 1 // A quick Google search for "defined(__LP64__)" OR "#ifdef __LP64__" gives 2590 hits and // a search for "#if __LP64__" gives only 12, so I think we'll go with the majority and use defined() -#if defined(_LP64) || defined(__LP64__) -typedef signed int mDNSs32; -typedef unsigned int mDNSu32; -#elif defined(_ILP64) || defined(__ILP64__) +#if defined(_ILP64) || defined(__ILP64__) typedef signed int32 mDNSs32; typedef unsigned int32 mDNSu32; +#elif defined(_LP64) || defined(__LP64__) +typedef signed int mDNSs32; +typedef unsigned int mDNSu32; #else typedef signed long mDNSs32; typedef unsigned long mDNSu32; +//typedef signed int mDNSs32; +//typedef unsigned int mDNSu32; #endif // To enforce useful type checking, we make mDNSInterfaceID be a pointer to a dummy struct @@ -1131,6 +769,7 @@ typedef struct mDNSInterfaceID_dummystruct { void *dummy; } *mDNSInterfaceID; typedef packedunion { mDNSu8 b[ 2]; mDNSu16 NotAnInteger; } mDNSOpaque16; typedef packedunion { mDNSu8 b[ 4]; mDNSu32 NotAnInteger; } mDNSOpaque32; typedef packedunion { mDNSu8 b[ 6]; mDNSu16 w[3]; mDNSu32 l[1]; } mDNSOpaque48; +typedef packedunion { mDNSu8 b[ 8]; mDNSu16 w[4]; mDNSu32 l[2]; } mDNSOpaque64; typedef packedunion { mDNSu8 b[16]; mDNSu16 w[8]; mDNSu32 l[4]; } mDNSOpaque128; typedef mDNSOpaque16 mDNSIPPort; // An IP port is a two-byte opaque identifier (not an integer) @@ -1166,33 +805,36 @@ enum // the bottom end of the range (FFFE FF00) is used for non-error values; // Error codes: - mStatus_UnknownErr = -65537, // First value: 0xFFFE FFFF - mStatus_NoSuchNameErr = -65538, - mStatus_NoMemoryErr = -65539, - mStatus_BadParamErr = -65540, - mStatus_BadReferenceErr = -65541, - mStatus_BadStateErr = -65542, - mStatus_BadFlagsErr = -65543, - mStatus_UnsupportedErr = -65544, - mStatus_NotInitializedErr = -65545, - mStatus_NoCache = -65546, - mStatus_AlreadyRegistered = -65547, - mStatus_NameConflict = -65548, - mStatus_Invalid = -65549, - mStatus_Firewall = -65550, - mStatus_Incompatible = -65551, - mStatus_BadInterfaceErr = -65552, - mStatus_Refused = -65553, - mStatus_NoSuchRecord = -65554, - mStatus_NoAuth = -65555, - mStatus_NoSuchKey = -65556, - mStatus_NATTraversal = -65557, - mStatus_DoubleNAT = -65558, - mStatus_BadTime = -65559, - mStatus_BadSig = -65560, // while we define this per RFC 2845, BIND 9 returns Refused for bad/missing signatures - mStatus_BadKey = -65561, - mStatus_TransientErr = -65562, // transient failures, e.g. sending packets shortly after a network transition or wake from sleep - // -65563 to -65786 currently unused; available for allocation + mStatus_UnknownErr = -65537, // First value: 0xFFFE FFFF + mStatus_NoSuchNameErr = -65538, + mStatus_NoMemoryErr = -65539, + mStatus_BadParamErr = -65540, + mStatus_BadReferenceErr = -65541, + mStatus_BadStateErr = -65542, + mStatus_BadFlagsErr = -65543, + mStatus_UnsupportedErr = -65544, + mStatus_NotInitializedErr = -65545, + mStatus_NoCache = -65546, + mStatus_AlreadyRegistered = -65547, + mStatus_NameConflict = -65548, + mStatus_Invalid = -65549, + mStatus_Firewall = -65550, + mStatus_Incompatible = -65551, + mStatus_BadInterfaceErr = -65552, + mStatus_Refused = -65553, + mStatus_NoSuchRecord = -65554, + mStatus_NoAuth = -65555, + mStatus_NoSuchKey = -65556, + mStatus_NATTraversal = -65557, + mStatus_DoubleNAT = -65558, + mStatus_BadTime = -65559, + mStatus_BadSig = -65560, // while we define this per RFC 2845, BIND 9 returns Refused for bad/missing signatures + mStatus_BadKey = -65561, + mStatus_TransientErr = -65562, // transient failures, e.g. sending packets shortly after a network transition or wake from sleep + mStatus_ServiceNotRunning = -65563, // Background daemon not running + mStatus_NATPortMappingUnsupported = -65564, // No NAT or if the NAT doesn't support NAT-PMP or UPnP + mStatus_NATPortMappingDisabled = -65565, // NAT supports NAT-PMP or UPnP but it's disabled by the administrator + // -65566 to -65786 currently unused; available for allocation // tcp connection status mStatus_ConnPending = -65787, @@ -1203,7 +845,6 @@ enum mStatus_GrowCache = -65790, mStatus_ConfigChanged = -65791, mStatus_MemFree = -65792 // Last value: 0xFFFE FF00 - // mStatus_MemFree is the last legal mDNS error code, at the end of the range allocated for mDNS }; @@ -1234,17 +875,21 @@ typedef struct { mDNSu8 c[256]; } UTF8str255; // Null-terminated C string #define MAX_ESCAPED_DOMAIN_LABEL 254 #define MAX_ESCAPED_DOMAIN_NAME 1005 +// MAX_REVERSE_MAPPING_NAME +// For IPv4: "123.123.123.123.in-addr.arpa." 30 bytes including terminating NUL +// For IPv6: "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." 74 bytes including terminating NUL + +#define MAX_REVERSE_MAPPING_NAME_V4 30 +#define MAX_REVERSE_MAPPING_NAME_V6 74 +#define MAX_REVERSE_MAPPING_NAME 74 + // Most records have a TTL of 75 minutes, so that their 80% cache-renewal query occurs once per hour. // For records containing a hostname (in the name on the left, or in the rdata on the right), // like A, AAAA, reverse-mapping PTR, and SRV, we use a two-minute TTL by default, because we don't want // them to hang around for too long in the cache if the host in question crashes or otherwise goes away. -// Wide-area service discovery records have a very short TTL to avoid poluting intermediate caches with -// dynamic records. When discovered via Long Lived Queries (with change notifications), resource record -// TTLs can be safely ignored. - + #define kStandardTTL (3600UL * 100 / 80) #define kHostNameTTL 120UL -#define kWideAreaTTL 3 #define DefaultTTLforRRType(X) (((X) == kDNSType_A || (X) == kDNSType_AAAA || (X) == kDNSType_SRV) ? kHostNameTTL : kStandardTTL) @@ -1359,12 +1004,16 @@ enum kDNSRecordTypePacketAns = 0xC0, // Received in the Answer Section of a DNS Response kDNSRecordTypePacketAnsUnique = 0xD0, // Received in the Answer Section of a DNS Response with kDNSClass_UniqueRRSet set - kDNSRecordTypePacketAnsMask = 0x40, // True for PacketAns and PacketAnsUnique + kDNSRecordTypePacketNegative = 0xF0, // Pseudo-RR generated to cache non-existence results like NXDomain + kDNSRecordTypePacketUniqueMask = 0x10 // True for PacketAddUnique, PacketAnsUnique, PacketAuthUnique }; typedef packedstruct { mDNSu16 priority; mDNSu16 weight; mDNSIPPort port; domainname target; } rdataSRV; typedef packedstruct { mDNSu16 preference; domainname exchange; } rdataMX; +typedef packedstruct { domainname mbox; domainname txt; } rdataRP; +typedef packedstruct { mDNSu16 preference; domainname map822; domainname mapx400; } rdataPX; + typedef packedstruct { domainname mname; @@ -1378,27 +1027,29 @@ typedef packedstruct typedef packedstruct { - mDNSu16 vers; - mDNSu16 llqOp; - mDNSu16 err; - mDNSu8 id[8]; - mDNSu32 lease; + mDNSu16 vers; + mDNSu16 llqOp; + mDNSu16 err; // Or UDP reply port, in setup request + mDNSOpaque64 id; + mDNSu32 llqlease; } LLQOptData; +// Windows adds pad bytes to sizeof(LLQOptData). +// Use this macro when setting length fields or validating option rdata from off the wire. +// Use sizeof(LLQOptData) when dealing with structures (e.g. memcpy). +// Never memcpy between on-the-wire representation and a structure. + #define LLQ_OPTLEN ((3 * sizeof(mDNSu16)) + 8 + sizeof(mDNSu32)) -// Windows adds pad bytes to sizeof(LLQOptData). Use this macro when setting length fields or validating option rdata from -// off the wire. Use sizeof(LLQOptData) when dealing with structures (e.g. memcpy). Never memcpy between on-the-wire -// representation and a structure - -// NOTE: rdataOpt format may be repeated an arbitrary number of times in a single resource record + +// NOTE: rdataOPT format may be repeated an arbitrary number of times in a single resource record typedef packedstruct { mDNSu16 opt; mDNSu16 optlen; - union { LLQOptData llq; mDNSu32 lease; } OptData; - } rdataOpt; + union { LLQOptData llq; mDNSu32 updatelease; } OptData; + } rdataOPT; -// StandardAuthRDSize is 264 (256+8), which is large enough to hold a maximum-sized SRV record +// StandardAuthRDSize is 264 (256+8), which is large enough to hold a maximum-sized SRV record (6 + 256 bytes) // MaximumRDSize is 8K the absolute maximum we support (at least for now) #define StandardAuthRDSize 264 #define MaximumRDSize 8192 @@ -1423,13 +1074,15 @@ typedef union { mDNSu8 data[StandardAuthRDSize]; mDNSv4Addr ipv4; // For 'A' record + domainname name; // For PTR, NS, CNAME, DNAME + rdataSOA soa; + UTF8str255 txt; + rdataMX mx; + rdataRP rp; + rdataPX px; mDNSv6Addr ipv6; // For 'AAAA' record - domainname name; // For PTR, NS, and CNAME records - UTF8str255 txt; // For TXT record - rdataSRV srv; // For SRV record - rdataMX mx; // For MX record - rdataSOA soa; // For SOA record - rdataOpt opt; // For eDNS0 opt record + rdataSRV srv; + rdataOPT opt; // For EDNS0 OPT record; RDataBody may contain multiple variable-length rdataOPT objects packed together } RDataBody; typedef struct @@ -1443,6 +1096,7 @@ typedef struct AuthRecord_struct AuthRecord; typedef struct CacheRecord_struct CacheRecord; typedef struct CacheGroup_struct CacheGroup; typedef struct DNSQuestion_struct DNSQuestion; +typedef struct ZoneData_struct ZoneData; typedef struct mDNS_struct mDNS; typedef struct mDNS_PlatformSupport_struct mDNS_PlatformSupport; typedef struct NATTraversalInfo_struct NATTraversalInfo; @@ -1456,21 +1110,169 @@ typedef void mDNSRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus res // The internal data structures of the mDNS code may not be in a state where mDNS API calls may be made safely. typedef void mDNSRecordUpdateCallback(mDNS *const m, AuthRecord *const rr, RData *OldRData); +// *************************************************************************** +#if 0 +#pragma mark - NAT Traversal structures and constants +#endif + +#define NATMAP_MAX_RETRY_INTERVAL ((mDNSPlatformOneSecond * 60) * 15) // Max retry interval is 15 minutes +#define NATMAP_MIN_RETRY_INTERVAL (mDNSPlatformOneSecond * 2) // Min retry interval is 2 seconds +#define NATMAP_INIT_RETRY (mDNSPlatformOneSecond / 4) // start at 250ms w/ exponential decay +#define NATMAP_DEFAULT_LEASE (60 * 60) // lease life in seconds +#define NATMAP_VERS 0 + +// Structure to abstract away the differences between TCP/SSL sockets, and one for UDP sockets +// The actual definition of these structures in the in the appropriate platform support code +typedef struct TCPSocket_struct TCPSocket; +typedef struct UDPSocket_struct UDPSocket; + +typedef enum + { + NATOp_AddrRequest = 0, + NATOp_MapUDP = 1, + NATOp_MapTCP = 2, + + NATOp_AddrResponse = 0x80 | 0, + NATOp_MapUDPResponse = 0x80 | 1, + NATOp_MapTCPResponse = 0x80 | 2, + } NATOp_t; + +enum + { + NATErr_None = 0, + NATErr_Vers = 1, + NATErr_Refused = 2, + NATErr_NetFail = 3, + NATErr_Res = 4, + NATErr_Opcode = 5 + }; + +typedef mDNSu16 NATErr_t; + +typedef packedstruct + { + mDNSu8 vers; + mDNSu8 opcode; + } NATAddrRequest; + +typedef packedstruct + { + mDNSu8 vers; + mDNSu8 opcode; + mDNSu16 err; + mDNSu32 upseconds; // Time since last NAT engine reboot, in seconds + mDNSv4Addr ExtAddr; + } NATAddrReply; + +typedef packedstruct + { + mDNSu8 vers; + mDNSu8 opcode; + mDNSOpaque16 unused; + mDNSIPPort intport; + mDNSIPPort extport; + mDNSu32 NATReq_lease; + } NATPortMapRequest; + +typedef packedstruct + { + mDNSu8 vers; + mDNSu8 opcode; + mDNSu16 err; + mDNSu32 upseconds; // Time since last NAT engine reboot, in seconds + mDNSIPPort intport; + mDNSIPPort extport; + mDNSu32 NATRep_lease; + } NATPortMapReply; + +typedef enum + { + LNTDiscoveryOp = 1, + LNTExternalAddrOp = 2, + LNTPortMapOp = 3, + LNTPortMapDeleteOp = 4 + } LNTOp_t; + +#define LNT_MAXBUFSIZE 4096 +typedef struct tcpLNTInfo_struct tcpLNTInfo; +struct tcpLNTInfo_struct + { + tcpLNTInfo *next; + mDNS *m; + NATTraversalInfo *parentNATInfo; // pointer back to the parent NATTraversalInfo + TCPSocket *sock; + LNTOp_t op; // operation performed using this connection + mDNSAddr Address; // router address + mDNSIPPort Port; // router port + mDNSs8 *Request; // xml request to router + int requestLen; + mDNSs8 *Reply; // xml reply from router + int replyLen; + unsigned long nread; // number of bytes read so far + int retries; // number of times we've tried to do this port mapping + }; + +typedef void (*NATTraversalClientCallback)(mDNS *m, NATTraversalInfo *n); + +// if m->timenow < ExpiryTime then we have an active mapping, and we'll renew halfway to expiry +// if m->timenow >= ExpiryTime then our mapping has expired, and we're trying to create one + +struct NATTraversalInfo_struct + { + // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them. + NATTraversalInfo *next; + + mDNSs32 ExpiryTime; // Time this mapping expires, or zero if no mapping + mDNSs32 retryInterval; // Current interval, between last packet we sent and the next one + mDNSs32 retryPortMap; // If Protocol is nonzero, time to send our next mapping packet + mStatus NewResult; // New error code; will be copied to Result just prior to invoking callback + +#ifdef _LEGACY_NAT_TRAVERSAL_ + tcpLNTInfo tcpInfo; // Legacy NAT traversal (UPnP) TCP connection +#endif + + // Result fields: When the callback is invoked these fields contain the answers the client is looking for + // When the callback is invoked ExternalPort is *usually* set to be the same the same as RequestedPort, except: + // (a) When we're behind a NAT gateway with port mapping disabled, ExternalPort is reported as zero to + // indicate that we don't currently have a working mapping (but RequestedPort retains the external port + // we'd like to get, the next time we meet an accomodating NAT gateway willing to give us one). + // (b) When we have a routable non-RFC1918 address, we don't *need* a port mapping, so ExternalPort + // is reported as the same as our InternalPort, since that is effectively our externally-visible port too. + // Again, RequestedPort retains the external port we'd like to get the next time we find ourself behind a NAT gateway. + // To improve stability of port mappings, RequestedPort is updated any time we get a successful + // mapping response from the NAT-PMP or UPnP gateway. For example, if we ask for port 80, and + // get assigned port 81, then thereafter we'll contine asking for port 81. + mDNSInterfaceID InterfaceID; + mDNSv4Addr ExternalAddress; + mDNSIPPort ExternalPort; + mDNSu32 Lifetime; + mStatus Result; + + // Client API fields: The client must set up these fields *before* making any NAT traversal API calls + mDNSu8 Protocol; // NATOp_MapUDP or NATOp_MapTCP, or zero if just requesting the external IP address + mDNSIPPort IntPort; // Client's internal port number (doesn't change) + mDNSIPPort RequestedPort; // Requested public port mapping; may be updated with actual value assigned by gateway + mDNSu32 NATLease; // Requested lifetime in seconds (doesn't change) + NATTraversalClientCallback clientCallback; + void *clientContext; + }; + typedef struct { - mDNSu8 RecordType; // See enum above - mDNSInterfaceID InterfaceID; // Set if this RR is specific to one interface + mDNSu8 RecordType; // See enum above + mDNSInterfaceID InterfaceID; // Set if this RR is specific to one interface // For records received off the wire, InterfaceID is *always* set to the receiving interface // For our authoritative records, InterfaceID is usually zero, except for those few records // that are interface-specific (e.g. address records, especially linklocal addresses) - domainname *name; - mDNSu16 rrtype; - mDNSu16 rrclass; - mDNSu32 rroriginalttl; // In seconds - mDNSu16 rdlength; // Size of the raw rdata, in bytes - mDNSu16 rdestimate; // Upper bound on size of rdata after name compression - mDNSu32 namehash; // Name-based (i.e. case-insensitive) hash of name - mDNSu32 rdatahash; // For rdata containing domain name (e.g. PTR, SRV, CNAME etc.), case-insensitive name hash + const domainname *name; + mDNSu16 rrtype; + mDNSu16 rrclass; + 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) + mDNSu16 rdestimate; // Upper bound on size of rdata after name compression + mDNSu32 namehash; // Name-based (i.e. case-insensitive) hash of name + mDNSu32 rdatahash; // For rdata containing domain name (e.g. PTR, SRV, CNAME etc.), case-insensitive name hash // else, for all other rdata, 32-bit hash of the raw rdata // Note: This requirement is important. Various routines like AddAdditionalsToResponseList(), // ReconfirmAntecedents(), etc., use rdatahash as a pre-flight check to see @@ -1479,57 +1281,30 @@ typedef struct RData *rdata; // Pointer to storage for this rdata } ResourceRecord; -// Unless otherwise noted, states may apply to either independent record registrations or service registrations +// Unless otherwise noted, states may apply to either independent record registrations or service registrations typedef enum { + regState_Zero = 0, regState_FetchingZoneData = 1, // getting info - update not sent regState_Pending = 2, // update sent, reply not received regState_Registered = 3, // update sent, reply received regState_DeregPending = 4, // dereg sent, reply not received regState_DeregDeferred = 5, // dereg requested while in Pending state - send dereg AFTER registration is confirmed - regState_Cancelled = 6, // update not sent, reg. cancelled by client regState_Unregistered = 8, // not in any list regState_Refresh = 9, // outstanding refresh (or target change) message - regState_NATMap = 10, // establishing NAT port mapping or learning public address + regState_NATMap = 10, // establishing NAT port mapping (service registrations only) regState_UpdatePending = 11, // update in flight as result of mDNS_Update call regState_NoTarget = 12, // service registration pending registration of hostname (ServiceRegistrations only) - regState_ExtraQueued = 13, // extra record to be registered upon completion of service registration (RecordRegistrations only) + regState_ExtraQueued = 13, // extra record to be registered upon completion of service registration (RecordRegistrations only) regState_NATError = 14 // unable to complete NAT traversal - } regState_t; + } regState_t; -// context for both ServiceRecordSet and individual AuthRec structs -typedef struct +enum { - // registration/lease state - regState_t state; - mDNSBool lease; // dynamic update contains (should contain) lease option - mDNSs32 expire; // expiration of lease (-1 for static) - mDNSBool TestForSelfConflict; // on name conflict, check if we're just seeing our own orphaned records - - // identifier to match update request and response - mDNSOpaque16 id; - - // server info - domainname zone; // the zone that is updated - mDNSAddr ns; // primary name server for the record's zone !!!KRS not technically correct to cache longer than TTL - mDNSIPPort port; // port on which server accepts dynamic updates - - // NAT traversal context - NATTraversalInfo *NATinfo; // may be NULL - - // state for deferred operations - mDNSBool ClientCallbackDeferred; // invoke client callback on completion of pending operation(s) - mStatus DeferredStatus; // status to deliver when above flag is set - mDNSBool SRVUpdateDeferred; // do we need to change target or port once current operation completes? - mDNSBool SRVChanged; // temporarily deregistered service because its SRV target or port changed - - // uDNS_UpdateRecord support fields - RData *OrigRData; mDNSu16 OrigRDLen; // previously registered, being deleted - RData *InFlightRData; mDNSu16 InFlightRDLen; // currently being registered - RData *QueuedRData; mDNSu16 QueuedRDLen; // if the client call Update while an update is in flight, we must finish the - // pending operation (re-transmitting if necessary) THEN register the queued update - mDNSRecordUpdateCallback *UpdateRDCallback; // client callback to free old rdata - } uDNS_RegInfo; + Target_Manual = 0, + Target_AutoHost = 1, + Target_AutoHostAndNATMAP = 2 + }; struct AuthRecord_struct { @@ -1541,16 +1316,15 @@ struct AuthRecord_struct AuthRecord *next; // Next in list; first element of structure for efficiency reasons // Field Group 1: Common ResourceRecord fields ResourceRecord resrec; - uDNS_RegInfo uDNS_info; // Field Group 2: Persistent metadata for Authoritative Records - AuthRecord *Additional1; // Recommended additional record to include in response - AuthRecord *Additional2; // Another additional + AuthRecord *Additional1; // Recommended additional record to include in response (e.g. SRV for PTR record) + AuthRecord *Additional2; // Another additional (e.g. TXT for record) AuthRecord *DependentOn; // This record depends on another for its uniqueness checking AuthRecord *RRSet; // This unique record is part of an RRSet mDNSRecordCallback *RecordCallback; // Callback function to call for state changes, and to free memory asynchronously on deregistration void *RecordContext; // Context parameter for the callback function - mDNSu8 HostTarget; // Set if the target of this record (PTR, CNAME, SRV, etc.) is our host name + mDNSu8 AutoTarget; // Set if the target of this record (PTR, CNAME, SRV, etc.) is our host name mDNSu8 AllowRemoteQuery; // Set if we allow hosts not on the local link to query this record mDNSu8 ForceMCast; // Set by client to advertise solely via multicast, even for apparently unicast names @@ -1574,7 +1348,6 @@ struct AuthRecord_struct const mDNSu8 *NR_AnswerTo; // Set if this record was selected by virtue of being a direct answer to a question AuthRecord *NR_AdditionalTo; // Set if this record was selected by virtue of being additional to another mDNSs32 ThisAPInterval; // In platform time units: Current interval for announce/probe - mDNSs32 AnnounceUntil; // In platform time units: Creation time + TTL mDNSs32 LastAPTime; // In platform time units: Last time we sent announcement/probe mDNSs32 LastMCTime; // Last time we multicast this record (used to guard against packet-storm attacks) mDNSInterfaceID LastMCInterface; // Interface this record was multicast on at the time LastMCTime was recorded @@ -1585,6 +1358,33 @@ struct AuthRecord_struct mDNSs32 NextUpdateCredit; // Time next token is added to bucket mDNSs32 UpdateBlocked; // Set if update delaying is in effect + // Field Group 4: Transient uDNS state for Authoritative Records + regState_t state; // Maybe combine this with resrec.RecordType state? Right now it's ambiguous and confusing. + // e.g. rr->resrec.RecordType can be kDNSRecordTypeUnregistered, + // and rr->state can be regState_Unregistered + // What if we find one of those statements is true and the other false? What does that mean? + mDNSBool uselease; // dynamic update contains (should contain) lease option + mDNSs32 expire; // expiration of lease (-1 for static) + mDNSBool Private; // If zone is private, DNS updates may have to be encrypted to prevent eavesdropping + mDNSOpaque16 id; // identifier to match update request and response + domainname zone; // the zone that is updated + mDNSAddr UpdateServer; // DNS server that handles updates for this zone + mDNSIPPort UpdatePort; // port on which server accepts dynamic updates + // !!!KRS not technically correct to cache longer than TTL + // SDC Perhaps should keep a reference to the relevant SRV record in the cache? + ZoneData *nta; + struct tcpInfo_t *tcp; + + // uDNS_UpdateRecord support fields + // Do we really need all these in *addition* to NewRData and newrdlength above? + RData *OrigRData; + mDNSu16 OrigRDLen; // previously registered, being deleted + RData *InFlightRData; + mDNSu16 InFlightRDLen; // currently being registered + RData *QueuedRData; // if the client call Update while an update is in flight, we must finish the + mDNSu16 QueuedRDLen; // pending operation (re-transmitting if necessary) THEN register the queued update + + // Field Group 5: Large data objects go at the end domainname namestorage; RData rdatastorage; // Normally the storage is right here, except for oversized records // rdatastorage MUST be the last thing in the structure -- when using oversized AuthRecords, extra bytes @@ -1643,30 +1443,35 @@ typedef struct domainname namestorage; // Needs to go *after* the extra rdata bytes } LargeCacheRecord; -typedef struct uDNS_HostnameInfo +typedef struct HostnameInfo { - struct uDNS_HostnameInfo *next; - domainname fqdn; - AuthRecord *arv4; // registered IPv4 address record - AuthRecord *arv6; // registered IPv6 address record + struct HostnameInfo *next; + NATTraversalInfo natinfo; + domainname fqdn; + AuthRecord arv4; // registered IPv4 address record + AuthRecord arv6; // registered IPv6 address record mDNSRecordCallback *StatusCallback; // callback to deliver success or error code to client layer const void *StatusContext; // Client Context - } uDNS_HostnameInfo; + } HostnameInfo; enum - { - DNSServer_Untested = 0, - DNSServer_Failed = 1, - DNSServer_Passed = 2 - }; + { + DNSServer_Untested = 0, + DNSServer_Passed = 1, + DNSServer_Failed = 2, + DNSServer_Disabled = 3 + }; typedef struct DNSServer { - struct DNSServer *next; - mDNSAddr addr; - mDNSBool del; // Set when we're planning to delete this from the list - mDNSu32 teststate; // Have we sent bug-detection query to this server? - domainname domain; // name->server matching for "split dns" + struct DNSServer *next; + mDNSInterfaceID interface; // For specialized uses; we can have DNS servers reachable over specific interfaces + mDNSAddr addr; + mDNSIPPort port; + mDNSBool del; // Set when we're planning to delete this from the list + mDNSu32 teststate; // Have we sent bug-detection query to this server? + mDNSs32 lasttest; // Time we sent last bug-detection query to this server + domainname domain; // name->server matching for "split dns" } DNSServer; typedef struct NetworkInterfaceInfo_struct NetworkInterfaceInfo; @@ -1707,7 +1512,7 @@ typedef struct ExtraResourceRecord_struct ExtraResourceRecord; struct ExtraResourceRecord_struct { ExtraResourceRecord *next; - mDNSu32 ClientID; // Opaque ID field to be used by client to map an AddRecord call to a set of Extra records + mDNSu32 ClientID; // Opaque ID field to be used by client to map an AddRecord call to a set of Extra records AuthRecord r; // Note: Add any additional fields *before* the AuthRecord in this structure, not at the end. // In some cases clients can allocate larger chunks of memory and set r->rdata->MaxRDLength to indicate @@ -1717,20 +1522,58 @@ struct ExtraResourceRecord_struct // Note: Within an mDNSServiceCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute() typedef struct ServiceRecordSet_struct ServiceRecordSet; typedef void mDNSServiceCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result); + +// A ServiceRecordSet is basically a convenience structure to group together +// the PTR/SRV/TXT records that make up a standard service registration +// It contains its own ServiceCallback+ServiceContext to report aggregate results up to the next layer of software above +// It also contains: +// * the "_services" PTR record for service enumeration +// * the optional target host name (for proxy registrations) +// * the optional list of SubType PTR records +// * the optional list of additional records attached to the service set (e.g. iChat pictures) +// +// ... and a bunch of stuff related to uDNS, some of which could be simplified or eliminated + struct ServiceRecordSet_struct { - // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them. + // These internal state fields are used internally by mDNSCore; the client layer needn't be concerned with them. // No fields need to be set up by the client prior to calling mDNS_RegisterService(); // all required data is passed as parameters to that function. - ServiceRecordSet *next; - uDNS_RegInfo uDNS_info; + + // Begin uDNS info **************** + // Hopefully much of this stuff can be simplified or eliminated + + // NOTE: The current uDNS code keeps an explicit list of registered services, and handles them + // differently to how individual records are treated (this is probably a mistake). What this means is + // that ServiceRecordSets for uDNS are kept in a linked list, whereas ServiceRecordSets for mDNS exist + // just as a convenient placeholder to group the component records together and are not kept on any list. + ServiceRecordSet *uDNS_next; + regState_t state; + mDNSBool srs_uselease; // dynamic update contains (should contain) lease option + mDNSs32 expire; // expiration of lease (-1 for static) + mDNSBool TestForSelfConflict; // on name conflict, check if we're just seeing our own orphaned records + mDNSBool Private; // If zone is private, DNS updates may have to be encrypted to prevent eavesdropping + ZoneData *nta; + mDNSOpaque16 id; + domainname zone; // the zone that is updated + mDNSAddr ns; // primary name server for the record's zone !!!KRS not technically correct to cache longer than TTL + mDNSIPPort SRSUpdatePort; // port on which server accepts dynamic updates + NATTraversalInfo NATinfo; // may be NULL + mDNSBool ClientCallbackDeferred; // invoke client callback on completion of pending operation(s) + mStatus DeferredStatus; // status to deliver when above flag is set + mDNSBool SRVUpdateDeferred; // do we need to change target or port once current operation completes? + mDNSBool SRVChanged; // temporarily deregistered service because its SRV target or port changed + struct tcpInfo_t *tcp; + + // End uDNS info **************** + mDNSServiceCallback *ServiceCallback; void *ServiceContext; + mDNSBool Conflict; // Set if this record set was forcibly deregistered because of a conflict + ExtraResourceRecord *Extras; // Optional list of extra AuthRecords attached to this service registration mDNSu32 NumSubTypes; AuthRecord *SubTypes; - mDNSBool Conflict; // Set if this record set was forcibly deregistered because of a conflict - domainname Host; // Set if this service record does not use the standard target host name AuthRecord RR_ADV; // e.g. _services._dns-sd._udp.local. PTR _printer._tcp.local. AuthRecord RR_PTR; // e.g. _printer._tcp.local. PTR Name._printer._tcp.local. AuthRecord RR_SRV; // e.g. Name._printer._tcp.local. SRV 0 0 port target @@ -1766,12 +1609,12 @@ typedef enum LLQ_SecondaryRequest = 3, LLQ_Refresh = 4, LLQ_Retry = 5, - LLQ_Established = 6, - LLQ_Suspended = 7, + LLQ_Established = 6, + LLQ_Suspended = 7, LLQ_SuspendDeferred = 8, // suspend once we get zone info LLQ_SuspendedPoll = 9, // suspended from polling state - LLQ_NatMapWait = 10, - + LLQ_NatMapWaitUDP = 10, + // Established/error states LLQ_Static = 16, LLQ_Poll = 17, @@ -1779,21 +1622,6 @@ typedef enum LLQ_Cancelled = 19 } LLQ_State; -typedef struct - { - LLQ_State state; - mDNSAddr servAddr; - mDNSIPPort servPort; - DNSQuestion *question; - mDNSu32 origLease; // seconds (relative) - mDNSs32 retry; // ticks (absolute) - mDNSs32 expire; // ticks (absolute) - mDNSs16 ntries; - mDNSu8 id[8]; - mDNSBool deriveRemovesOnResume; - mDNSBool NATMap; // does this LLQ use the global LLQ NAT mapping? - } LLQ_Info; - // LLQ constants #define kDNSOpt_LLQ 1 #define kDNSOpt_Lease 2 @@ -1807,8 +1635,8 @@ typedef struct #define kLLQOp_Refresh 2 #define kLLQOp_Event 3 -#define LLQ_OPT_RDLEN ((2 * sizeof(mDNSu16)) + LLQ_OPTLEN) -#define LEASE_OPT_RDLEN (2 * sizeof(mDNSu16)) + sizeof(mDNSs32) +#define LLQ_OPT_RDLEN ((2 * sizeof(mDNSu16)) + LLQ_OPTLEN ) +#define LEASE_OPT_RDLEN ((2 * sizeof(mDNSu16)) + sizeof(mDNSs32)) // LLQ Errror Codes enum @@ -1822,21 +1650,39 @@ enum LLQErr_UnknownErr = 6 }; -typedef void (*InternalResponseHndlr)(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *internalContext); -typedef struct +enum { NoAnswer_Normal = 0, NoAnswer_Suspended = 1, NoAnswer_Fail = 2 }; + +#define HMAC_LEN 64 +#define HMAC_IPAD 0x36 +#define HMAC_OPAD 0x5c +#define MD5_LEN 16 + +#define AutoTunnelUnregistered(X) ( \ + (X)->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered && \ + (X)->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered && \ + (X)->AutoTunnelService. resrec.RecordType == kDNSRecordTypeUnregistered ) + +// Internal data structure to maintain authentication information +typedef struct DomainAuthInfo { - mDNSOpaque16 id; - mDNSBool internal; - InternalResponseHndlr responseCallback; // NULL if internal field is false - LLQ_Info *llq; // NULL for 1-shot queries - mDNSBool Answered; // have we received an answer (including NXDOMAIN) for this question? - CacheRecord *knownAnswers; - mDNSs32 RestartTime; // Mark when we restart a suspended query - void *context; - } uDNS_QuestionInfo; + struct DomainAuthInfo *next; + mDNSs32 deltime; // If we're planning to delete this DomainAuthInfo, the time we want it deleted + mDNSBool AutoTunnel; + AuthRecord AutoTunnelHostRecord; // User-visible hostname; used as SRV target for AutoTunnel services + AuthRecord AutoTunnelTarget; // Opaque hostname of tunnel endpoint; used as SRV target for AutoTunnelService record + AuthRecord AutoTunnelDeviceInfo; // Device info of tunnel endpoint + AuthRecord AutoTunnelService; // Service record (possibly NAT-Mapped) of IKE daemon implementing tunnel endpoint + NATTraversalInfo AutoTunnelNAT; + domainname domain; + domainname keyname; + char b64keydata[32]; + mDNSu8 keydata_ipad[HMAC_LEN]; // padded key for inner hash rounds + mDNSu8 keydata_opad[HMAC_LEN]; // padded key for outer hash rounds + } DomainAuthInfo; // Note: Within an mDNSQuestionCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Close(), mDNS_Execute() -typedef void mDNSQuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord); +typedef enum { QC_rmv = 0, QC_add = 1, QC_addnocache = 2 } QC_result; +typedef void mDNSQuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord); struct DNSQuestion_struct { // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them. @@ -1847,12 +1693,16 @@ struct DNSQuestion_struct mDNSs32 ThisQInterval; // LastQTime + ThisQInterval is the next scheduled transmission of this Q // ThisQInterval > 0 for an active question; // ThisQInterval = 0 for a suspended question that's still in the list - // ThisQInterval = -1 for a cancelled question that's been removed from the list + // ThisQInterval = -1 for a cancelled question (should not still be in list) + mDNSs32 ExpectUnicastResp;// Set when we send a query with the kDNSQClass_UnicastResponse bit set mDNSs32 LastAnswerPktNum; // The sequence number of the last response packet containing an answer to this Q mDNSu32 RecentAnswerPkts; // Number of answers since the last time we sent this query mDNSu32 CurrentAnswers; // Number of records currently in the cache that answer this question mDNSu32 LargeAnswers; // Number of answers with rdata > 1024 bytes mDNSu32 UniqueAnswers; // Number of answers received with kDNSClass_UniqueRRSet bit set + mDNSInterfaceID FlappingInterface1;// Set when an interface goes away, to flag if remove events are delivered for this Q + mDNSInterfaceID FlappingInterface2;// Set when an interface goes away, to flag if remove events are delivered for this Q + DomainAuthInfo *AuthInfo; // Non-NULL if query is currently being done using Private DNS DNSQuestion *DuplicateOf; DNSQuestion *NextInDQList; DupSuppressInfo DupSuppress[DupSuppressInfoSize]; @@ -1860,7 +1710,25 @@ struct DNSQuestion_struct mDNSBool SendOnAll; // Set if we're sending this question on all active interfaces mDNSu32 RequestUnicast; // Non-zero if we want to send query with kDNSQClass_UnicastResponse bit set mDNSs32 LastQTxTime; // Last time this Q was sent on one (but not necessarily all) interfaces - uDNS_QuestionInfo uDNS_info; + mDNSu32 CNAMEReferrals; // Count of how many CNAME redirections we've done + + // Wide Area fields. These are used internally by the uDNS core + DNSServer *qDNSServer; // Caching server for this query (in the absence of an SRV saying otherwise) + + ZoneData *nta; // Used for getting zone data for private or LLQ query + mDNSAddr servAddr; // Address and port learned from _dns-llq, _dns-llq-tls or _dns-query-tls SRV query + mDNSIPPort servPort; + struct tcpInfo_t *tcp; + mDNSu8 NoAnswer; // Set if we want to suppress answers until tunnel setup has completed + + // LLQ-specific fields. These fields are only meaningful when LongLived flag is set + LLQ_State state; + NATTraversalInfo NATInfoUDP; + mDNSIPPort eventPort; // This is non-zero if this is a private LLQ. If we're behind NAT, it's the external UDP port. + mDNSu32 origLease; // seconds (relative) + mDNSs32 expire; // ticks (absolute) + mDNSs16 ntries; + mDNSOpaque64 id; // Client API fields: The client must set up these fields *before* calling mDNS_StartQuery() mDNSInterfaceID InterfaceID; // Non-zero if you want to issue queries only on a single specific IP interface @@ -1873,6 +1741,7 @@ struct DNSQuestion_struct mDNSBool LongLived; // Set by client for calls to mDNS_StartQuery to indicate LLQs to unicast layer. mDNSBool ExpectUnique; // Set by client if it's expecting unique RR(s) for this question, not shared RRs mDNSBool ForceMCast; // Set by client to force mDNS query, even for apparently uDNS names + mDNSBool ReturnIntermed; // Set by client to request callbacks for intermediate CNAME/NXDOMAIN results mDNSQuestionCallback *QuestionCallback; void *QuestionContext; }; @@ -1913,104 +1782,51 @@ struct ServiceInfoQuery_struct void *ServiceInfoQueryContext; }; -// *************************************************************************** -#if 0 -#pragma mark - NAT Traversal structures and constants -#endif - -#define NATMAP_INIT_RETRY (mDNSPlatformOneSecond / 4) // start at 250ms w/ exponential decay -#define NATMAP_MAX_RETRY mDNSPlatformOneSecond // back off to once per second -#define NATMAP_MAX_TRIES 3 // for max 3 tries -#define NATMAP_DEFAULT_LEASE (60 * 60) // lease life in seconds -#define NATMAP_VERS 0 -#define NATMAP_PORT 5351 -#define NATMAP_RESPONSE_MASK 0x80 - -typedef enum - { - NATOp_AddrRequest = 0, - NATOp_MapUDP = 1, - NATOp_MapTCP = 2 - } NATOp_t; +typedef enum { ZoneServiceUpdate, ZoneServiceQuery, ZoneServiceLLQ } ZoneService; -enum - { - NATErr_None = 0, - NATErr_Vers = 1, - NATErr_Refused = 2, - NATErr_NetFail = 3, - NATErr_Res = 4, - NATErr_Opcode = 5 - }; +typedef void ZoneDataCallback(mDNS *const m, mStatus err, const ZoneData *result); -typedef mDNSu16 NATErr_t; - -typedef enum +struct ZoneData_struct { - NATState_Init = 0, - NATState_Request = 1, - NATState_Established = 2, - NATState_Legacy = 3, - NATState_Error = 4, - NATState_Refresh = 5, - NATState_Deleted = 6 - } NATState_t; -// Note: we have no explicit "cancelled" state, where a service/interface is deregistered while we - // have an outstanding NAT request. This is conveyed by the "reg" pointer being set to NULL + domainname ChildName; // Name for which we're trying to find the responsible server + ZoneService ZoneService; // Which service we're seeking for this zone (update, query, or LLQ) + domainname *CurrentSOA; // Points to somewhere within ChildName + domainname ZoneName; // Discovered result: Left-hand-side of SOA record + mDNSu16 ZoneClass; // Discovered result: DNS Class from SOA record + domainname Host; // Discovered result: Target host from SRV record + mDNSIPPort Port; // Discovered result: Update port, query port, or LLQ port from SRV record + mDNSAddr Addr; // Discovered result: Address of Target host from SRV record + mDNSBool ZonePrivate; // Discovered result: Does zone require encrypted queries? + ZoneDataCallback *ZoneDataCallback; // Caller-specified function to be called upon completion + void *ZoneDataContext; + DNSQuestion question; // Storage for any active question + }; -typedef packedstruct - { - mDNSu8 vers; - mDNSu8 opcode; - } NATAddrRequest; - -typedef packedstruct - { - mDNSu8 vers; - mDNSu8 opcode; - mDNSOpaque16 err; - mDNSOpaque32 uptime; - mDNSv4Addr PubAddr; - } NATAddrReply; +extern ZoneData *StartGetZoneData(mDNS *const m, const domainname *const name, const ZoneService target, ZoneDataCallback callback, void *callbackInfo); +extern void CancelGetZoneData(mDNS *const m, ZoneData *nta); -typedef packedstruct - { - mDNSu8 vers; - mDNSu8 opcode; - mDNSOpaque16 unused; - mDNSIPPort priv; - mDNSIPPort pub; - mDNSOpaque32 lease; - } NATPortMapRequest; - -typedef packedstruct +typedef struct DNameListElem { - mDNSu8 vers; - mDNSu8 opcode; - mDNSOpaque16 err; - mDNSOpaque32 uptime; - mDNSIPPort priv; - mDNSIPPort pub; - mDNSOpaque32 lease; - } NATPortMapReply; - -// Pass NULL for pkt on error (including timeout) -typedef mDNSBool (*NATResponseHndlr)(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len); + struct DNameListElem *next; + mDNSu32 uid; + domainname name; + } DNameListElem; -struct NATTraversalInfo_struct +#if APPLE_OSX_mDNSResponder +typedef struct ClientTunnel { - NATOp_t op; - NATResponseHndlr ReceiveResponse; - union { AuthRecord *RecordRegistration; ServiceRecordSet *ServiceRegistration; } reg; - mDNSAddr Router; - mDNSIPPort PublicPort; - union { NATAddrRequest AddrReq; NATPortMapRequest PortReq; } request; - mDNSs32 retry; // absolute time when we retry - mDNSs32 RetryInterval; // delta between time sent and retry - int ntries; - NATState_t state; - NATTraversalInfo *next; - }; + struct ClientTunnel *next; + domainname dstname; + mDNSBool markedForDeletion; + mDNSv6Addr loc_inner; + mDNSv4Addr loc_outer; + mDNSv6Addr rmt_inner; + mDNSv4Addr rmt_outer; + mDNSIPPort rmt_outer_port; + char b64keydata[32]; + DNSQuestion q; + } ClientTunnel; +#endif // *************************************************************************** #if 0 @@ -2026,33 +1842,6 @@ enum mDNS_KnownBug_PhantomInterfaces = 1 }; -typedef struct - { - mDNSs32 nextevent; - DNSQuestion *ActiveQueries; //!!!KRS this should be a hashtable (hash on messageID) - DNSQuestion *CurrentQuery; // pointer to ActiveQueries list being examined in a loop. Functions that remove - // elements from the ActiveQueries list must update this pointer (if non-NULL) as necessary. - //!!!KRS do the same for registration lists - ServiceRecordSet *ServiceRegistrations; - AuthRecord *RecordRegistrations; - NATTraversalInfo *NATTraversals; - mDNSu16 NextMessageID; - DNSServer *Servers; // list of DNS servers - mDNSAddr Router; - mDNSAddr AdvertisedV4; // IPv4 address pointed to by hostname - mDNSAddr MappedV4; // Cache of public address if PrimaryIP is behind a NAT - mDNSAddr AdvertisedV6; // IPv6 address pointed to by hostname - NATTraversalInfo *LLQNatInfo; // Nat port mapping to receive LLQ events - domainname ServiceRegDomain; // (going away w/ multi-user support) - struct uDNS_AuthInfo *AuthInfoList; // list of domains requiring authentication for updates. - uDNS_HostnameInfo *Hostnames; // List of registered hostnames + hostname metadata - DNSQuestion ReverseMap; // Reverse-map query to find static hostname for service target - mDNSBool ReverseMapActive; // Is above query active? - domainname StaticHostname; // Current answer to reverse-map query (above) - mDNSBool DelaySRVUpdate; // Delay SRV target/port update to avoid "flap" - mDNSs32 NextSRVUpdate; // Time to perform delayed update - } uDNS_GlobalInfo; - struct mDNS_struct { // Internal state fields. These hold the main internal state of mDNSCore; @@ -2077,7 +1866,8 @@ struct mDNS_struct mDNSu8 lock_rrcache; // For debugging: Set at times when these lists may not be modified mDNSu8 lock_Questions; mDNSu8 lock_Records; - char MsgBuffer[80]; // Temp storage used while building error log messages + #define MaxMsg 120 + char MsgBuffer[MaxMsg]; // Temp storage used while building error log messages // Task Scheduling variables mDNSs32 timenow_adjust; // Correction applied if we ever discover time went backwards @@ -2089,8 +1879,9 @@ struct mDNS_struct mDNSs32 NextScheduledQuery; // Next time to send query in its exponential backoff sequence mDNSs32 NextScheduledProbe; // Next time to probe for new authoritative record mDNSs32 NextScheduledResponse; // Next time to send authoritative record(s) in responses - mDNSs32 ExpectUnicastResponse; // Set when we send a query with the kDNSQClass_UnicastResponse bit set + mDNSs32 NextScheduledNATOp; // Next time to send NAT-traversal packets mDNSs32 RandomQueryDelay; // For de-synchronization of query packets on the wire + mDNSu32 RandomReconfirmDelay; // For de-synchronization of reconfirmation queries on the wire mDNSs32 PktNum; // Unique sequence number assigned to each received packet mDNSBool SendDeregistrations; // Set if we need to send deregistrations (immediately) mDNSBool SendImmediateAnswers; // Set if we need to send answers (immediately -- or as soon as SuppressSending clears) @@ -2115,6 +1906,7 @@ struct mDNS_struct domainname MulticastHostname; // Fully Qualified "dot-local" Host Name, e.g. "Foo.local." UTF8str255 HIHardware; UTF8str255 HISoftware; + AuthRecord DeviceInfo; AuthRecord *ResourceRecords; AuthRecord *DuplicateRecords; // Records currently 'on hold' because they are duplicates of existing records AuthRecord *NewLocalRecords; // Fresh local-only records not yet delivered to local-only questions @@ -2125,18 +1917,67 @@ struct mDNS_struct mDNSs32 SuppressProbes; // unicast-specific data - uDNS_GlobalInfo uDNS_info; - mDNSs32 SuppressStdPort53Queries; // Wait before allowing the next standard unicast query to the user's configured DNS server + mDNSs32 NextuDNSEvent; // uDNS next event + mDNSs32 NextSRVUpdate; // Time to perform delayed update + mDNSs32 SuppressStdPort53Queries; // Wait before allowing the next standard unicast query to the user's configured DNS server + + ServiceRecordSet *ServiceRegistrations; + mDNSu16 NextMessageID; + DNSServer *DNSServers; // list of DNS servers + + mDNSAddr Router; + mDNSAddr AdvertisedV4; // IPv4 address pointed to by hostname + mDNSAddr AdvertisedV6; // IPv6 address pointed to by hostname + + DomainAuthInfo *AuthInfoList; // list of domains requiring authentication for updates + + DNSQuestion ReverseMap; // Reverse-map query to find static hostname for service target + DNSQuestion AutomaticBrowseDomainQ; + domainname StaticHostname; // Current answer to reverse-map query + domainname FQDN; + HostnameInfo *Hostnames; // List of registered hostnames + hostname metadata + mDNSv6Addr AutoTunnelHostAddr; // IPv6 address advertised for AutoTunnel services on this machine + mDNSBool AutoTunnelHostAddrActive; + domainlabel AutoTunnelLabel; // Used to construct hostname for *IPv4* address of tunnel endpoints + + mDNSBool RegisterSearchDomains; + + // NAT traversal fields + NATTraversalInfo *NATTraversals; + NATTraversalInfo *CurrentNATTraversal; + mDNSs32 retryIntervalGetAddr; // delta between time sent and retry + mDNSs32 retryGetAddr; // absolute time when we retry + mDNSv4Addr ExternalAddress; + + UDPSocket *NATMcastRecvskt; // For receiving NAT-PMP AddrReply multicasts from router on port 5350 + UDPSocket *NATMcastRecvsk2; // For backwards compatibility, same as above but listening on port 5351 + mDNSu32 LastNATupseconds; // NAT engine uptime in seconds, from most recent NAT packet + mDNSs32 LastNATReplyLocalTime; // Local time in ticks when most recent NAT packet was received + + tcpLNTInfo tcpAddrInfo; // legacy NAT traversal TCP connection info for external address + tcpLNTInfo tcpDeviceInfo; // legacy NAT traversal TCP connection info for device info + tcpLNTInfo *tcpInfoUnmapList; // list of pending unmap requests + mDNSInterfaceID UPnPInterfaceID; + mDNSIPPort UPnPRouterPort; // port we send discovery messages to + mDNSIPPort UPnPSOAPPort; // port we send SOAP messages to + mDNSu8 *UPnPRouterURL; // router's URL string + 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 + +#if APPLE_OSX_mDNSResponder + ClientTunnel *TunnelClients; +#endif // Fixed storage, to avoid creating large objects on the stack - DNSMessage imsg; // Incoming message received from wire - DNSMessage omsg; // Outgoing message we're building - LargeCacheRecord rec; // Resource Record extracted from received message + DNSMessage imsg; // Incoming message received from wire + DNSMessage omsg; // Outgoing message we're building + LargeCacheRecord rec; // Resource Record extracted from received message }; -#define FORALL_CACHERECORDS(SLOT,CG,CR) \ - for ((SLOT) = 0; (SLOT) < CACHE_HASH_SLOTS; (SLOT)++) \ - for((CG)=m->rrcache_hash[(SLOT)]; (CG); (CG)=(CG)->next) \ +#define FORALL_CACHERECORDS(SLOT,CG,CR) \ + for ((SLOT) = 0; (SLOT) < CACHE_HASH_SLOTS; (SLOT)++) \ + for ((CG)=m->rrcache_hash[(SLOT)]; (CG); (CG)=(CG)->next) \ for ((CR) = (CG)->members; (CR); (CR)=(CR)->next) // *************************************************************************** @@ -2154,14 +1995,23 @@ extern const mDNSAddr zeroAddr; extern const mDNSInterfaceID mDNSInterface_Any; // Zero extern const mDNSInterfaceID mDNSInterface_LocalOnly; // Special value +extern const mDNSInterfaceID mDNSInterface_Unicast; // Special value -extern const mDNSIPPort UnicastDNSPort; -extern const mDNSIPPort MulticastDNSPort; -extern const mDNSv4Addr AllDNSAdminGroup; -extern const mDNSv4Addr AllDNSLinkGroupv4; -extern const mDNSv6Addr AllDNSLinkGroupv6; -extern const mDNSAddr AllDNSLinkGroup_v4; -extern const mDNSAddr AllDNSLinkGroup_v6; +extern const mDNSIPPort SSDPPort; + +extern const mDNSIPPort UnicastDNSPort; +extern const mDNSIPPort NATPMPAnnouncementPort; +extern const mDNSIPPort NATPMPPort; +extern const mDNSIPPort DNSEXTPort; +extern const mDNSIPPort MulticastDNSPort; +extern const mDNSIPPort LoopbackIPCPort; + +extern const mDNSIPPort NSIPCPort; +extern const mDNSIPPort PrivateDNSPort; + +extern const mDNSv4Addr AllDNSAdminGroup; +extern const mDNSAddr AllDNSLinkGroup_v4; +extern const mDNSAddr AllDNSLinkGroup_v6; extern const mDNSOpaque16 zeroID; extern const mDNSOpaque16 QueryFlags; @@ -2170,9 +2020,12 @@ extern const mDNSOpaque16 ResponseFlags; extern const mDNSOpaque16 UpdateReqFlags; extern const mDNSOpaque16 UpdateRespFlags; -#define localdomain (*(const domainname *)"\x5local") -#define LocalReverseMapomain (*(const domainname *)"\x3" "254" "\x3" "169" "\x7" "in-addr" "\x4" "arpa") - +extern const mDNSOpaque64 zeroOpaque64; + +#define localdomain (*(const domainname *)"\x5" "local") +#define LocalReverseMapDomain (*(const domainname *)"\x3" "254" "\x3" "169" "\x7" "in-addr" "\x4" "arpa") +#define DeviceInfoName (*(const domainname *)"\xC" "_device-info" "\x4" "_tcp") + // *************************************************************************** #if 0 #pragma mark - Inline functions @@ -2188,9 +2041,7 @@ extern const mDNSOpaque16 UpdateRespFlags; #if !defined(mDNSinline) extern mDNSs32 NonZeroTime(mDNSs32 t); extern mDNSu16 mDNSVal16(mDNSOpaque16 x); -extern mDNSu32 mDNSVal32(mDNSOpaque32 x); extern mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v); -extern mDNSOpaque32 mDNSOpaque32fromIntVal(mDNSu32 v); #endif // If we're compiling the particular C file that instantiates our inlines, then we @@ -2204,7 +2055,6 @@ extern mDNSOpaque32 mDNSOpaque32fromIntVal(mDNSu32 v); mDNSinline mDNSs32 NonZeroTime(mDNSs32 t) { if (t) return(t); else return(1); } mDNSinline mDNSu16 mDNSVal16(mDNSOpaque16 x) { return((mDNSu16)((mDNSu16)x.b[0] << 8 | (mDNSu16)x.b[1])); } -mDNSinline mDNSu32 mDNSVal32(mDNSOpaque32 x) { return((mDNSu32)((mDNSu32)x.b[0] << 24 | (mDNSu32)x.b[1] << 16 | (mDNSu32)x.b[2] << 8 | (mDNSu32)x.b[3])); } mDNSinline mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v) { @@ -2214,16 +2064,6 @@ mDNSinline mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v) return(x); } -mDNSinline mDNSOpaque32 mDNSOpaque32fromIntVal(mDNSu32 v) - { - mDNSOpaque32 x; - x.b[0] = (mDNSu8) (v >> 24) ; - x.b[1] = (mDNSu8)((v >> 16) & 0xFF); - x.b[2] = (mDNSu8)((v >> 8 ) & 0xFF); - x.b[3] = (mDNSu8)((v ) & 0xFF); - return x; - } - #endif // *************************************************************************** @@ -2299,10 +2139,18 @@ extern mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr); extern mStatus mDNS_StartQuery(mDNS *const m, DNSQuestion *const question); extern mStatus mDNS_StopQuery (mDNS *const m, DNSQuestion *const question); +extern mStatus mDNS_StopQueryWithRemoves(mDNS *const m, DNSQuestion *const question); extern mStatus mDNS_Reconfirm (mDNS *const m, CacheRecord *const cacherr); extern mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr); +extern void mDNS_PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr); extern mDNSs32 mDNS_TimeNow(const mDNS *const m); +extern mStatus mDNS_StartNATOperation(mDNS *const m, NATTraversalInfo *traversal); +extern mStatus mDNS_StopNATOperation(mDNS *const m, NATTraversalInfo *traversal); +extern mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *traversal); + +extern DomainAuthInfo *GetAuthInfoForName(mDNS *m, const domainname *const name); + // *************************************************************************** #if 0 #pragma mark - Platform support functions that are accessible to the client layer too @@ -2327,7 +2175,7 @@ extern mDNSs32 mDNSPlatformOneSecond; // via mDNS_RemoveRecordFromService, or by deregistering the service. mDNS_RemoveRecordFromService is passed a // callback to free the memory associated with the extra RR when it is safe to do so. The ExtraResourceRecord // object can be found in the record's context pointer. - + // mDNS_GetBrowseDomains is a special case of the mDNS_StartQuery call, where the resulting answers // are a list of PTR records indicating (in the rdata) domains that are recommended for browsing. // After getting the list of domains to browse, call mDNS_StopQuery to end the search. @@ -2368,10 +2216,10 @@ typedef enum { mDNS_DomainTypeBrowse = 0, mDNS_DomainTypeBrowseDefault = 1, - mDNS_DomainTypeBrowseLegacy = 2, + mDNS_DomainTypeBrowseAutomatic = 2, mDNS_DomainTypeRegistration = 3, mDNS_DomainTypeRegistrationDefault = 4, - + mDNS_DomainTypeMax = 4 } mDNS_DomainType; @@ -2383,6 +2231,8 @@ extern mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_ extern mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr, mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, char *domname); #define mDNS_StopAdvertiseDomains mDNS_Deregister +extern mDNSOpaque16 mDNS_NewMessageID(mDNS *const m); + // *************************************************************************** #if 0 #pragma mark - DNS name utility functions @@ -2397,16 +2247,20 @@ extern mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr, mDNS_DomainT // A simple C structure assignment of a domainname can cause a protection fault by accessing unmapped memory, // because that object is defined to be 256 bytes long, but not all domainname objects are truly the full size. // This macro uses mDNSPlatformMemCopy() to make sure it only touches the actual bytes that are valid. -#define AssignDomainName(DST, SRC) mDNSPlatformMemCopy((SRC)->c, (DST)->c, DomainNameLength((SRC))) +#define AssignDomainName(DST, SRC) do { mDNSu16 len = DomainNameLength((SRC)); \ + if (len <= MAX_DOMAIN_NAME) mDNSPlatformMemCopy((DST)->c, (SRC)->c, len); else (DST)->c[0] = 0; } while(0) // Comparison functions +#define SameDomainLabelCS(A,B) ((A)[0] == (B)[0] && mDNSPlatformMemSame((A)+1, (B)+1, (A)[0])) extern mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b); extern mDNSBool SameDomainName(const domainname *const d1, const domainname *const d2); +extern mDNSBool SameDomainNameCS(const domainname *const d1, const domainname *const d2); extern mDNSBool IsLocalDomain(const domainname *d); // returns true for domains that by default should be looked up using link-local multicast // Get total length of domain name, in native DNS format, including terminal root label // (e.g. length of "com." is 5 (length byte, three data bytes, final zero) -extern mDNSu16 DomainNameLength(const domainname *const name); +extern mDNSu16 DomainNameLengthLimit(const domainname *const name, const mDNSu8 *limit); +#define DomainNameLength(name) DomainNameLengthLimit((name), (name)->c + MAX_DOMAIN_NAME + 1) // Append functions to append one or more labels to an existing native format domain name: // AppendLiteralLabelString adds a single label from a literal C string, with no escape character interpretation. @@ -2476,21 +2330,29 @@ extern char *GetRRDisplayString_rdb(const ResourceRecord *rr, RDataBody *rd, cha #define CRDisplayString(m, rr) GetRRDisplayString_rdb(&(rr)->resrec, &(rr)->resrec.rdata->u, (m)->MsgBuffer) extern mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2); extern void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText); -extern mDNSBool IsPrivateV4Addr(mDNSAddr *addr); // returns true for RFC1918 private addresses +extern mDNSBool mDNSv4AddrIsRFC1918(mDNSv4Addr *addr); // returns true for RFC1918 private addresses +#define mDNSAddrIsRFC1918(X) ((X)->type == mDNSAddrType_IPv4 && mDNSv4AddrIsRFC1918(&(X)->ip.v4)) +#define mDNSSameIPPort(A,B) ((A).NotAnInteger == (B).NotAnInteger) +#define mDNSSameOpaque16(A,B) ((A).NotAnInteger == (B).NotAnInteger) #define mDNSSameIPv4Address(A,B) ((A).NotAnInteger == (B).NotAnInteger) #define mDNSSameIPv6Address(A,B) ((A).l[0] == (B).l[0] && (A).l[1] == (B).l[1] && (A).l[2] == (B).l[2] && (A).l[3] == (B).l[3]) #define mDNSSameEthAddress(A,B) ((A)->w[0] == (B)->w[0] && (A)->w[1] == (B)->w[1] && (A)->w[2] == (B)->w[2]) +#define mDNSSameOpaque64(A,B) ((A)->l[0] == (B)->l[0] && (A)->l[1] == (B)->l[1]) +#define mDNSOpaque64IsZero(A) ((A)->l[0] == 0 && (A)->l[1] == 0) + +#define mDNSIPPortIsZero(A) mDNSSameIPPort((A), zeroIPPort) +#define mDNSOpaque16IsZero(A) mDNSSameOpaque16((A), zeroIPPort) #define mDNSIPv4AddressIsZero(A) mDNSSameIPv4Address((A), zerov4Addr) #define mDNSIPv6AddressIsZero(A) mDNSSameIPv6Address((A), zerov6Addr) #define mDNSIPv4AddressIsOnes(A) mDNSSameIPv4Address((A), onesIPv4Addr) #define mDNSIPv6AddressIsOnes(A) mDNSSameIPv6Address((A), onesIPv6Addr) -#define mDNSAddressIsAllDNSLinkGroup(X) ( \ - ((X)->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address((X)->ip.v4, AllDNSLinkGroupv4)) || \ - ((X)->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address((X)->ip.v6, AllDNSLinkGroupv6)) ) +#define mDNSAddressIsAllDNSLinkGroup(X) ( \ + ((X)->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address((X)->ip.v4, AllDNSLinkGroup_v4.ip.v4)) || \ + ((X)->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address((X)->ip.v6, AllDNSLinkGroup_v6.ip.v6)) ) #define mDNSAddressIsZero(X) ( \ ((X)->type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero((X)->ip.v4)) || \ @@ -2508,49 +2370,35 @@ extern mDNSBool IsPrivateV4Addr(mDNSAddr *addr); // returns true for RFC1918 pr ((X)->type == mDNSAddrType_IPv4) ? !(mDNSIPv4AddressIsZero((X)->ip.v4) || mDNSIPv4AddressIsOnes((X)->ip.v4)) : \ ((X)->type == mDNSAddrType_IPv6) ? !(mDNSIPv6AddressIsZero((X)->ip.v6) || mDNSIPv6AddressIsOnes((X)->ip.v6)) : mDNSfalse) +#define mDNSv4AddressIsLinkLocal(X) ((X)->b[0] == 169 && (X)->b[1] == 254) +#define mDNSv6AddressIsLinkLocal(X) ((X)->b[0] == 0xFE && ((X)->b[1] & 0xC0) == 0x80) + +#define mDNSAddressIsLinkLocal(X) ( \ + ((X)->type == mDNSAddrType_IPv4) ? mDNSv4AddressIsLinkLocal(&(X)->ip.v4) : \ + ((X)->type == mDNSAddrType_IPv6) ? mDNSv6AddressIsLinkLocal(&(X)->ip.v6) : mDNSfalse) // *************************************************************************** #if 0 #pragma mark - Authentication Support #endif -#define HMAC_LEN 64 -#define HMAC_IPAD 0x36 -#define HMAC_OPAD 0x5c -#define MD5_LEN 16 - -// padded keys for inned/outer hash rounds -typedef struct - { - mDNSu8 ipad[HMAC_LEN]; - mDNSu8 opad[HMAC_LEN]; - } HMAC_Key; - -// Internal data structure to maintain authentication information for an update domain -typedef struct uDNS_AuthInfo - { - domainname zone; - domainname keyname; - HMAC_Key key; - struct uDNS_AuthInfo *next; - } uDNS_AuthInfo; - // Unicast DNS and Dynamic Update specific Client Calls // -// mDNS_SetSecretForZone tells the core to authenticate (via TSIG with an HMAC_MD5 hash of the shared secret) +// mDNS_SetSecretForDomain tells the core to authenticate (via TSIG with an HMAC_MD5 hash of the shared secret) // when dynamically updating a given zone (and its subdomains). The key used in authentication must be in // domain name format. The shared secret must be a null-terminated base64 encoded string. A minimum size of // 16 bytes (128 bits) is recommended for an MD5 hash as per RFC 2485. // Calling this routine multiple times for a zone replaces previously entered values. Call with a NULL key // to dissable authentication for the zone. -extern mStatus mDNS_SetSecretForZone(mDNS *m, const domainname *zone, const domainname *key, const char *sharedSecret); +extern mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info, + const domainname *domain, const domainname *keyname, const char *b64keydata, mDNSBool AutoTunnel); // Hostname/Unicast Interface Configuration // All hostnames advertised point to one IPv4 address and/or one IPv6 address, set via SetPrimaryInterfaceInfo. Invoking this routine // updates all existing hostnames to point to the new address. - + // A hostname is added via AddDynDNSHostName, which points to the primary interface's v4 and/or v6 addresss // The status callback is invoked to convey success or failure codes - the callback should not modify the AuthRecord or free memory. @@ -2560,33 +2408,39 @@ extern mStatus mDNS_SetSecretForZone(mDNS *m, const domainname *zone, const doma // these values are initialized. // When routable V4 interfaces are added or removed, mDNS_UpdateLLQs should be called to re-estabish LLQs in case the -// destination address for events (i.e. the route) has changed. For performance reasons, the caller is responsible for +// destination address for events (i.e. the route) has changed. For performance reasons, the caller is responsible for // batching changes, e.g. calling the routine only once if multiple interfaces are simultanously removed or added. -// DNS servers used to resolve unicast queries are specified by mDNS_AddDNSServer, and may later be removed via mDNS_DeleteDNSServers. +// DNS servers used to resolve unicast queries are specified by mDNS_AddDNSServer. // For "split" DNS configurations, in which queries for different domains are sent to different servers (e.g. VPN and external), // a domain may be associated with a DNS server. For standard configurations, specify the root label (".") or NULL. - + extern void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext); 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 void mDNS_UpdateLLQs(mDNS *m); -extern void mDNS_AddDNSServer(mDNS *const m, const mDNSAddr *dnsAddr, const domainname *domain); -extern void mDNS_DeleteDNSServers(mDNS *const m); +extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port); +extern void mDNS_AddSearchDomain(const domainname *const domain); -// Routines called by the core, exported by DNSDigest.c +#define mDNS_AddSearchDomain_CString(X) \ + do { domainname d; if ((X) && MakeDomainNameFromDNSNameString(&d, (X)) && d.c[0]) mDNS_AddSearchDomain(&d); } while(0) -// Convert a base64 encoded key into a binary byte stream -extern mDNSs32 DNSDigest_Base64ToBin(const char *src, mDNSu8 *target, mDNSu32 targsize); +// Routines called by the core, exported by DNSDigest.c -// Convert an arbitrary binary key (of any length) into an HMAC key (stored in AuthInfo struct) -extern void DNSDigest_ConstructHMACKey(uDNS_AuthInfo *info, const mDNSu8 *key, mDNSu32 len); +// Convert an arbitrary base64 encoded key key into an HMAC key (stored in AuthInfo struct) +extern mDNSs32 DNSDigest_ConstructHMACKeyfromBase64(DomainAuthInfo *info, const char *b64key); -// sign a DNS message. The message must be compete, with all values in network byte order. end points to the end +// sign a DNS message. The message must be complete, with all values in network byte order. end points to the end // of the message, and is modified by this routine. numAdditionals is a pointer to the number of additional // records in HOST byte order, which is incremented upon successful completion of this routine. The function returns // the new end pointer on success, and NULL on failure. -extern mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16 *numAdditionals, uDNS_AuthInfo *info); +extern mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAuthInfo *info, mDNSu16 tcode); + +// verify a DNS message. The message must be complete, with all values in network byte order. end points to the +// end of the record. tsig is a pointer to the resource record that contains the TSIG OPT record. info is +// the matching key to use for verifying the message. This function expects that the additionals member +// of the DNS message header has already had one subtracted from it. +extern mDNSBool DNSDigest_VerifyMessage(DNSMessage *msg, mDNSu8 *end, LargeCacheRecord *tsig, DomainAuthInfo *info, mDNSu16 *rcode, mDNSu16 *tcode); // *************************************************************************** #if 0 @@ -2630,12 +2484,16 @@ mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstport); extern void mDNSPlatformLock (const mDNS *const m); extern void mDNSPlatformUnlock (const mDNS *const m); -extern void mDNSPlatformStrCopy (const void *src, void *dst); -extern mDNSu32 mDNSPlatformStrLen (const void *src); -extern void mDNSPlatformMemCopy (const void *src, void *dst, mDNSu32 len); -extern mDNSBool mDNSPlatformMemSame (const void *src, const void *dst, mDNSu32 len); -extern void mDNSPlatformMemZero ( void *dst, mDNSu32 len); +extern void mDNSPlatformStrCopy ( void *dst, const void *src); +extern mDNSu32 mDNSPlatformStrLen ( const void *src); +extern void mDNSPlatformMemCopy ( void *dst, const void *src, mDNSu32 len); +extern mDNSBool mDNSPlatformMemSame (const void *dst, const void *src, mDNSu32 len); +extern void mDNSPlatformMemZero ( void *dst, mDNSu32 len); +#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING +#define mDNSPlatformMemAllocate(X) mallocL(#X, X) +#else extern void * mDNSPlatformMemAllocate (mDNSu32 len); +#endif extern void mDNSPlatformMemFree (void *mem); extern mDNSu32 mDNSPlatformRandomSeed (void); extern mStatus mDNSPlatformTimeInit (void); @@ -2646,8 +2504,8 @@ extern mDNSs32 mDNSPlatformUTC (void); // 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. -extern mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS *const m, mDNSu32 index); -extern mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mDNSInterfaceID id); +extern mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 index); +extern mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id); // Every platform support module must provide the following functions if it is to support unicast DNS // and Dynamic Update. @@ -2661,46 +2519,47 @@ extern mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mD // asynchronously fails, the TCPConnectionCallback should be invoked as usual, with the error being // returned in subsequent calls to PlatformReadTCP or PlatformWriteTCP. (This allows for platforms // with limited asynchronous error detection capabilities.) PlatformReadTCP and PlatformWriteTCP must -// return the number of bytes read/written, 0 if the call would block, and -1 if an error. +// return the number of bytes read/written, 0 if the call would block, and -1 if an error. PlatformReadTCP +// should set the closed argument if the socket has been closed. // PlatformTCPCloseConnection must close the connection to the peer and remove the descriptor from the // event loop. CloseConnectin may be called at any time, including in a ConnectionCallback. -typedef void (*TCPConnectionCallback)(int sd, void *context, mDNSBool ConnectionEstablished); -extern mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID, - TCPConnectionCallback callback, void *context, int *descriptor); -extern void mDNSPlatformTCPCloseConnection(int sd); -extern int mDNSPlatformReadTCP(int sd, void *buf, int buflen); -extern int mDNSPlatformWriteTCP(int sd, const char *msg, int len); +typedef enum + { + kTCPSocketFlags_Zero = 0, + kTCPSocketFlags_UseTLS = (1 << 0) + } TCPSocketFlags; + +typedef void (*TCPConnectionCallback)(TCPSocket *sock, void *context, mDNSBool ConnectionEstablished, mStatus err); +extern TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port); // 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, mDNSInterfaceID InterfaceID, + TCPConnectionCallback callback, void *context); +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, mDNSIPPort port); +extern void mDNSPlatformUDPClose(UDPSocket *sock); + +// mDNSPlatformTLSSetupCerts/mDNSPlatformTLSTearDownCerts used by dnsextd +extern mStatus mDNSPlatformTLSSetupCerts(void); +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. -// The Get() functions must return a linked list of DNameListElem structs, allocated via mDNSPlatformMemAllocate. -// Platforms may implement the Get() calls via the mDNS_CopyDNameList() helper routine. -// Callers should free lists obtained via the Get() calls with th mDNS_FreeDNameList routine, provided by the core. - -typedef struct DNameListElem - { - domainname name; - struct DNameListElem *next; - } DNameListElem; - -extern DNameListElem *mDNSPlatformGetSearchDomainList(void); -extern DNameListElem *mDNSPlatformGetRegDomainList(void); -// Helper functions provided by the core -extern DNameListElem *mDNS_CopyDNameList(const DNameListElem *orig); -extern void mDNS_FreeDNameList(DNameListElem *list); +extern void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains); +extern mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *router); +extern void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status); #ifdef _LEGACY_NAT_TRAVERSAL_ // Support for legacy NAT traversal protocols, implemented by the platform layer and callable by the core. - -#define DYN_PORT_MIN 49152 // ephemeral port range -#define DYN_PORT_MAX 65535 -#define LEGACY_NATMAP_MAX_TRIES 4 // if our desired mapping is taken, how many times we try mapping to a random port - -extern mStatus LNT_GetPublicIP(mDNSOpaque32 *ip); -extern mStatus LNT_MapPort(mDNSIPPort priv, mDNSIPPort pub, mDNSBool tcp); -extern mStatus LNT_UnmapPort(mDNSIPPort PubPort, mDNSBool tcp); +extern void LNT_SendDiscoveryMsg(mDNS *m); +extern void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID InterfaceID, mDNSu8 *data, mDNSu16 len); +extern mStatus LNT_GetExternalAddress(mDNS *m); +extern mStatus LNT_MapPort(mDNS *m, NATTraversalInfo *n); +extern mStatus LNT_UnmapPort(mDNS *m, NATTraversalInfo *n); #endif // _LEGACY_NAT_TRAVERSAL_ // The core mDNS code provides these functions, for the platform support code to call at appropriate times @@ -2739,8 +2598,8 @@ extern mStatus LNT_UnmapPort(mDNSIPPort PubPort, mDNSBool tcp); // not lightweight second-by-second CPU power management modes.) extern void mDNS_SetFQDN(mDNS *const m); -extern mStatus mDNS_RegisterInterface (mDNS *const m, NetworkInterfaceInfo *set, mDNSs32 delay); -extern void mDNS_DeregisterInterface(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); extern void mDNSCoreInitComplete(mDNS *const m, mStatus result); extern void mDNSCoreReceive(mDNS *const m, void *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport, @@ -2749,6 +2608,20 @@ extern void mDNSCoreMachineSleep(mDNS *const m, mDNSBool wake); extern mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip); +extern CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, CacheGroup *cg); +extern void GrantCacheExtensions(mDNS *const m, DNSQuestion *q, mDNSu32 lease); +extern void MakeNegativeCacheRecord(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds); +extern void CompleteDeregistration(mDNS *const m, AuthRecord *rr); +extern void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheRecord *const rr, const QC_result AddRecord); + +// For now this AutoTunnel 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 +#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 SetupLocalAutoTunnelInterface_internal(mDNS *const m); +#endif + // *************************************************************************** #if 0 #pragma mark - Compile-Time assertion checks @@ -2760,7 +2633,7 @@ extern mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip); // what's wrong until you run the software. This way, if the assertion condition // is false, the array size is negative, and the complier complains immediately. -struct mDNS_CompileTimeAssertionChecks +struct CompileTimeAssertionChecks_mDNS { // Check that the compiler generated our on-the-wire packet format structure definitions // properly packed, without adding padding bytes to align fields on 32-bit or 64-bit boundaries. @@ -2777,6 +2650,28 @@ struct mDNS_CompileTimeAssertionChecks char assertA[(sizeof(mDNSOpaque32) == 4 ) ? 1 : -1]; char assertB[(sizeof(mDNSOpaque128) == 16 ) ? 1 : -1]; char assertC[(sizeof(CacheRecord ) >= sizeof(CacheGroup) ) ? 1 : -1]; + char assertD[(sizeof(int) >= 4 ) ? 1 : -1]; + char assertE[(StandardAuthRDSize >= 256 ) ? 1 : -1]; + + // 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. + char sizecheck_ResourceRecord [(sizeof(ResourceRecord) <= 40) ? 1 : -1]; + char sizecheck_AuthRecord [(sizeof(AuthRecord) <= 1290) ? 1 : -1]; + char sizecheck_CacheRecord [(sizeof(CacheRecord) <= 170) ? 1 : -1]; + char sizecheck_CacheGroup [(sizeof(CacheGroup) <= 170) ? 1 : -1]; + char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 700) ? 1 : -1]; + char sizecheck_ZoneData [(sizeof(ZoneData) <= 1600) ? 1 : -1]; + char sizecheck_NATTraversalInfo [(sizeof(NATTraversalInfo) <= 140) ? 1 : -1]; + char sizecheck_HostnameInfo [(sizeof(HostnameInfo) <= 3000) ? 1 : -1]; + char sizecheck_DNSServer [(sizeof(DNSServer) <= 300) ? 1 : -1]; + char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 4000) ? 1 : -1]; + char sizecheck_ServiceRecordSet [(sizeof(ServiceRecordSet) <= 5700) ? 1 : -1]; + char sizecheck_DomainAuthInfo [(sizeof(DomainAuthInfo) <= 6000) ? 1 : -1]; + char sizecheck_ServiceInfoQuery [(sizeof(ServiceInfoQuery) <= 2900) ? 1 : -1]; +#if APPLE_OSX_mDNSResponder + char sizecheck_ClientTunnel [(sizeof(ClientTunnel) <= 1040) ? 1 : -1]; +#endif }; // *************************************************************************** diff --git a/mDNSCore/uDNS.c b/mDNSCore/uDNS.c index 6e2d70e..9db4e9c 100755 --- a/mDNSCore/uDNS.c +++ b/mDNSCore/uDNS.c @@ -1,763 +1,926 @@ -/* - * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. +/* -*- Mode: C; tab-width: 4 -*- * - * @APPLE_LICENSE_HEADER_START@ + * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ - Change History (most recent first): + * To Do: + * Elimate all mDNSPlatformMemAllocate/mDNSPlatformMemFree from this code -- the core code + * is supposed to be malloc-free so that it runs in constant memory determined at compile-time. + * Any dynamic run-time requirements should be handled by the platform layer below or client layer above + + Change History (most recent first): $Log: uDNS.c,v $ -Revision 1.225 2005/10/21 22:51:17 cheshire - Add check to avoid crashing NAT gateways that have buggy DNS relay code -Refinement: Shorten "check-for-broken-dns-relay" to just "dnsbugtest" -to avoid crashing NAT gateways that have a different DNS relay bug +Revision 1.496 2007/10/04 22:38:59 cheshire +Added LogOperation message showing new q->ThisQInterval after sending uDNS query packet + +Revision 1.495 2007/10/03 00:16:19 cheshire +In startPrivateQueryCallback, need to grab lock before calling SetNextQueryTime + +Revision 1.494 2007/10/02 21:11:08 cheshire + LLQ refreshes don't work, which breaks BTMM browsing + +Revision 1.493 2007/10/02 19:50:23 cheshire +Improved debugging message + +Revision 1.492 2007/09/29 03:15:43 cheshire + BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal +Use AutoTunnelUnregistered macro instead of checking record state directly + +Revision 1.491 2007/09/29 01:33:45 cheshire + BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal + +Revision 1.490 2007/09/29 01:06:17 mcguire + 9A564: mDNSResponder crash in mDNS_Execute + +Revision 1.489 2007/09/27 22:02:33 cheshire + BTMM: Registered records in BTMM don't get removed from server after calling RemoveRecord + +Revision 1.488 2007/09/27 21:20:17 cheshire +Improved debugging syslog messages + +Revision 1.487 2007/09/27 18:55:11 cheshire + BTMM: Multiple SRV records get registered after changing Computer Name + +Revision 1.486 2007/09/27 17:42:49 cheshire +Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask" + +Revision 1.485 2007/09/27 02:16:30 cheshire + BTMM: LLQ refreshes being sent in the clear to the wrong port + +Revision 1.484 2007/09/27 00:25:39 cheshire +Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for: + uDNS: Use SOA to determine TTL for negative answers + +Revision 1.483 2007/09/26 23:16:58 cheshire + BTMM: Leopard sending excessive LLQ registration requests to .Mac + +Revision 1.482 2007/09/26 22:06:02 cheshire + BTMM: No immediate failure notifications for BTMM names + +Revision 1.481 2007/09/26 00:49:46 cheshire +Improve packet logging to show sent and received packets, +transport protocol (UDP/TCP/TLS) and source/destination address:port + +Revision 1.480 2007/09/21 21:08:52 cheshire +Get rid of unnecessary DumpPacket() calls -- it makes more sense +to do this in mDNSSendDNSMessage and mDNSCoreReceive instead + +Revision 1.479 2007/09/21 20:01:17 cheshire + BTMM: Skip directly to member name in SOA queries to avoid sending names in the clear + +Revision 1.478 2007/09/21 19:29:14 cheshire +Added dump of uDNS questions when in MDNS_LOG_VERBOSE_DEBUG mode + +Revision 1.477 2007/09/20 02:29:37 cheshire + BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network + +Revision 1.476 2007/09/20 01:19:49 cheshire +Improve debugging messages: report startLLQHandshake errors; show state in uDNS_StopLongLivedQuery message + +Revision 1.475 2007/09/19 23:51:26 cheshire + BTMM: Need to log a message when NAT port mapping fails + +Revision 1.474 2007/09/19 20:32:09 cheshire +Export GetAuthInfoForName so it's callable from other files + +Revision 1.473 2007/09/18 21:42:29 cheshire +To reduce programming mistakes, renamed ExtPort to RequestedPort + +Revision 1.472 2007/09/14 21:26:08 cheshire + BTMM: Need to manually avoid port conflicts when using UPnP gateways + +Revision 1.471 2007/09/14 01:07:10 cheshire +If UPnP NAT gateway returns 0.0.0.0 as external address (e.g. because it hasn't +got a DHCP address yet) then retry periodically until it gives us a real address. + +Revision 1.470 2007/09/13 00:36:26 cheshire + NAT Reboot detection logic incorrect + +Revision 1.469 2007/09/13 00:28:50 cheshire + Host records not updated on NAT address change + +Revision 1.468 2007/09/13 00:16:41 cheshire + Miscellaneous NAT Traversal improvements + +Revision 1.467 2007/09/12 23:03:08 cheshire + DNSServiceNATPortMappingCreate callback not giving correct interface index -Revision 1.224 2005/10/20 00:10:33 cheshire - Add check to avoid crashing NAT gateways that have buggy DNS relay code +Revision 1.466 2007/09/12 22:19:29 cheshire + Need to listen for port 5350 NAT-PMP announcements -Revision 1.223 2005/10/17 18:52:42 cheshire - mDNSResponder crashed in CheckRecordRegistrations -Move code to unregister the service's extra records from uDNS_DeregisterService() to unlinkSRS(). +Revision 1.465 2007/09/12 19:22:19 cheshire +Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport +Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers -Revision 1.222 2005/10/05 23:04:10 cheshire -Add more information to unlinkAR and startLLQHandshakeCallback error messages +Revision 1.464 2007/09/12 01:22:13 cheshire +Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0 -Revision 1.221 2005/10/05 17:27:48 herscher - Change 200ms delay to 10ms +Revision 1.463 2007/09/11 20:23:28 vazquez + CrashTracer: 3 crashes in mDNSResponder at mDNSResponder: natTraversalHandlePortMapReply + 107 +Make sure we clean up NATTraversals before free'ing HostnameInfo -Revision 1.220 2005/09/24 01:10:09 cheshire -Fix comment typos +Revision 1.462 2007/09/11 19:19:16 cheshire +Correct capitalization of "uPNP" to "UPnP" -Revision 1.219 2005/09/22 07:28:25 herscher -Double the delay to 200000 usec after sending out a DNS query +Revision 1.461 2007/09/10 22:08:17 cheshire +Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds -Revision 1.218 2005/09/13 01:06:14 herscher - Add 100ms delay in sendQuery. +Revision 1.460 2007/09/07 21:47:43 vazquez + BTMM: SetupSocket 5351 failed; Can't allocate UDP multicast socket spew on wake from sleep with internet sharing on +Try to allocate using port 5350 if we get a failure, and only log message if that fails too. -Revision 1.217 2005/08/04 18:08:24 cheshire -Update comments +Revision 1.459 2007/09/07 01:01:05 cheshire + BTMM: Services being registered and deregistered in a loop +In hndlServiceUpdateReply, need to clear SRVUpdateDeferred -Revision 1.216 2005/07/29 23:05:22 ksekar - Hostname registration should register IPv6 AAAA record with DNS Update -Services should point to IPv6 address if IPv4 NAT mapping fails +Revision 1.458 2007/09/06 19:14:33 cheshire +Fixed minor error introduced in 1.379 (an "if" statement was deleted but the "else" following it was left there) -Revision 1.215 2005/07/29 21:01:51 ksekar - Hostname registration should register IPv6 AAAA record with DNS Update -correction to original checkin - misplaced return in HostnameCallback and logic error determining v6 changes +Revision 1.457 2007/09/05 21:48:01 cheshire + BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone. +Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance cod needs +to update the cache lifetimes of all relevant records every time it successfully renews an LLQ, +otherwise those records will expire and vanish from the cache. -Revision 1.214 2005/07/29 19:46:10 ksekar - reduce polling period on failed LLQs to 15 minutes +Revision 1.456 2007/09/05 21:00:17 cheshire + mDNSResponder taking up 100% CPU in ReissueBlockedQuestions +Additional refinement: ThisQInterval needs to be restored in tcpCallback, not in startPrivateQueryCallback -Revision 1.213 2005/07/29 18:04:22 ksekar - Hostname registration should register IPv6 AAAA record with DNS Update +Revision 1.455 2007/09/05 20:53:06 cheshire +Tidied up alignment of code layout; code was clearing m->tcpAddrInfo.sock instead of m->tcpDeviceInfo.sock -Revision 1.212 2005/07/22 19:35:50 ksekar - SUTiger: LLQ event acknowledgments are not formated correctly +Revision 1.454 2007/09/05 02:32:55 cheshire +Fixed posix build error (mixed declarations and code) -Revision 1.211 2005/07/21 18:51:04 ksekar - mDNSResponder times out when mapping ports after sleep +Revision 1.453 2007/09/05 02:26:57 cheshire + mDNSResponder taking up 100% CPU in ReissueBlockedQuestions +In startPrivateQueryCallback, restore q->ThisQInterval to non-zero value after GetZoneData completes -Revision 1.210 2005/07/21 18:47:31 ksekar - NAT-PMP refresh Requested Public Port should contain actual mapped port +Revision 1.452 2007/08/31 22:58:22 cheshire +If we have an existing TCP connection we should re-use it instead of just bailing out +After receiving dnsbugtest response, need to set m->NextScheduledQuery to cause queries to be re-issued -Revision 1.209 2005/07/04 21:16:37 cheshire -Minor code tidying -- initialize variables where they are declared +Revision 1.451 2007/08/31 18:49:49 vazquez + BTMM: Need to properly deregister when stopping BTMM -Revision 1.208 2005/06/28 00:24:28 ksekar - memory smasher in conQueryCallback +Revision 1.450 2007/08/30 22:50:04 mcguire + BTMM: Tunneled services are registered when autotunnel can't be setup -Revision 1.207 2005/05/13 20:45:10 ksekar - Rapid wide-area txt record updates don't work +Revision 1.449 2007/08/30 00:43:17 cheshire +Need to clear m->rec.r.resrec.RecordType before returning from uDNS_recvLLQResponse -Revision 1.206 2005/03/31 02:19:55 cheshire - Fix build warnings -Reviewed by: Scott Herscher +Revision 1.448 2007/08/30 00:18:46 cheshire + Error messages: "SendServiceRegistration: Already have TCP connection..." -Revision 1.205 2005/03/21 00:33:51 shersche - Fix build warnings on Win32 platform +Revision 1.447 2007/08/29 01:18:33 cheshire + BTMM: Tunneled services do not need NAT port mappings +Only create NAT mappings for SRV records with AutoTarget set to Target_AutoHostAndNATMAP -Revision 1.204 2005/03/16 00:42:32 ksekar - Long-lived queries not working on Windows +Revision 1.446 2007/08/28 23:58:42 cheshire +Rename HostTarget -> AutoTarget -Revision 1.203 2005/03/04 03:00:03 ksekar - Retransmissions happen too early, causing registrations to conflict with themselves +Revision 1.445 2007/08/28 23:53:21 cheshire +Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete -Revision 1.202 2005/03/01 19:29:17 ksekar -changed LogMsgs to debugfs +Revision 1.444 2007/08/27 20:29:20 cheshire +Additional debugging messages -Revision 1.201 2005/02/26 03:04:13 cheshire - Should not indicate successful dynamic update if no network connection -Don't try to do updates to root name server. This ensures status dot turns red if user -enters a bad host name such as just "fred" instead of a properly fully-qualified name. +Revision 1.443 2007/08/24 23:18:28 cheshire +mDNS_SetSecretForDomain is called with lock held; needs to use +GetAuthInfoForName_internal() instead of external version GetAuthInfoForName() -Revision 1.200 2005/02/25 17:47:45 ksekar - SendServiceRegistration fails on wake from sleep +Revision 1.442 2007/08/24 22:43:06 cheshire +Tidied up coded layout -Revision 1.199 2005/02/25 04:21:00 cheshire - mDNS -F returns the same domain multiple times with different casing +Revision 1.441 2007/08/24 01:20:55 cheshire + BTMM: Memory corruption in KeychainChanged event handling -Revision 1.198 2005/02/25 02:35:22 cheshire - Should not indicate successful dynamic update if no network connection -If we get NXDomain error looking for the _dns-update._udp record, -update status from 1 (in progress) to mStatus_NoSuchNameErr (failed) +Revision 1.440 2007/08/24 00:15:20 cheshire +Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held -Revision 1.197 2005/02/24 21:56:59 ksekar -Change LogMsgs to debugfs +Revision 1.439 2007/08/23 21:47:09 vazquez + BTMM: mDNSResponder sends NAT-PMP packets on public network +make sure we clean up port mappings on base stations by sending a lease value of 0, +and only send NAT-PMP packets on private networks; also save some memory by +not using packet structs in NATTraversals. -Revision 1.196 2005/02/24 21:52:28 ksekar - Remove "deferred deregistration" logic for hostnames +Revision 1.438 2007/08/22 17:50:08 vazquez + Need to handle errors returned by NAT-PMP routers properly +Propagate router errors to clients, and stop logging spurious "message too short" logs. -Revision 1.195 2005/02/22 17:53:08 ksekar -Changed successful NAT Traversals from LogMsg to LogOperation +Revision 1.437 2007/08/18 00:54:15 mcguire + BTMM: Should not register private addresses or zeros -Revision 1.194 2005/02/15 18:38:03 ksekar - change expected/redundant log messages to debugfs. +Revision 1.436 2007/08/08 21:07:48 vazquez + BTMM: Need to advertise model information via wide-area bonjour -Revision 1.193 2005/02/15 01:17:48 ksekar -Fixed build failure. +Revision 1.435 2007/08/03 02:04:09 vazquez + BTMM: Private LLQs never fall back to polling +Fix case where NAT-PMP returns an external address but does not support +port mappings. Undo previous change and now, if the router returns an +error in the reply packet we respect it. -Revision 1.192 2005/02/14 23:01:28 ksekar -Refinement to previous checkin - don't log bad LLQ opcode if we had to send the request more than once. +Revision 1.434 2007/08/02 21:03:05 vazquez +Change NAT logic to fix case where base station with port mapping turned off +returns an external address but does not make port mappings. -Revision 1.191 2005/02/14 18:26:51 ksekar - mDNSResponder complains about bad LLQ Opcode 2 +Revision 1.433 2007/08/02 03:30:11 vazquez + BTMM: Private LLQs never fall back to polling -Revision 1.190 2005/02/11 19:44:06 shersche -Remove extra semicolon at end of line +Revision 1.432 2007/08/01 18:15:19 cheshire +Fixed crash in tcpCallback; fixed some problems with LLQ setup behind NAT -Revision 1.189 2005/02/10 21:07:02 ksekar -Don't goto error in ReceiveNATAddrResponse if we receive a malformatted response +Revision 1.431 2007/08/01 16:11:06 cheshire +Fixed "mixed declarations and code" compiler error in Posix build -Revision 1.188 2005/02/10 02:02:44 ksekar -Remove double semi-colon +Revision 1.430 2007/08/01 16:09:13 cheshire +Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly -Revision 1.187 2005/02/09 23:28:01 ksekar - NAT-PMP response callback should return a -boolean indicating if the packet matched the request +Revision 1.429 2007/08/01 03:09:22 cheshire + BTMM: Create NAT port mapping for autotunnel port -Revision 1.186 2005/02/04 21:56:29 ksekar - Simultaneous port map requests sometimes fail -- Refinement to previous checkin. +Revision 1.428 2007/08/01 01:43:36 cheshire +Need to do mDNS_DropLockBeforeCallback/ReclaimLock around invokation of NAT client callback -Revision 1.185 2005/02/03 23:48:22 ksekar - Simultaneous port map requests sometimes fail +Revision 1.427 2007/08/01 01:31:13 cheshire +Need to initialize traversal->tcpInfo fields or code may crash -Revision 1.184 2005/02/01 19:33:29 ksekar - Keychain format too restrictive +Revision 1.426 2007/08/01 01:15:57 cheshire + Need to invoke NAT client callback when not on RFC1918 private network -Revision 1.183 2005/01/27 22:57:55 cheshire -Fix compile errors on gcc4 +Revision 1.425 2007/08/01 00:04:14 cheshire + Crash in tcpKQSocketCallback +Half-open TCP connections were not being cancelled properly -Revision 1.182 2005/01/25 18:55:05 ksekar -Shortened log message +Revision 1.424 2007/07/31 02:28:35 vazquez + NAT-PMP: Detect public IP address changes and base station reboot -Revision 1.181 2005/01/25 02:17:32 cheshire - Don't use query ID zero in uDNS queries +Revision 1.423 2007/07/30 23:31:26 cheshire +Code for respecting TTL received in uDNS responses should exclude LLQ-type responses -Revision 1.180 2005/01/19 21:01:54 ksekar - uDNS needs to support subtype registration and browsing +Revision 1.422 2007/07/28 01:25:57 cheshire + BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT -Revision 1.179 2005/01/19 19:15:35 ksekar -Refinement to - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer +Revision 1.421 2007/07/28 00:04:14 cheshire +Various fixes for comments and debugging messages -Revision 1.178 2005/01/17 23:47:58 cheshire - Wide-area services not found on little-endian +Revision 1.420 2007/07/27 23:59:18 cheshire +Added compile-time structure size checks -Revision 1.177 2005/01/17 23:41:26 cheshire -Fix compile errors +Revision 1.419 2007/07/27 20:52:29 cheshire +Made uDNS_recvLLQResponse() return tri-state result: LLQ_Not, LLQ_First, or LLQ_Events -Revision 1.176 2005/01/17 21:03:04 cheshire - Wide-area services not found on little-endian +Revision 1.418 2007/07/27 20:32:05 vazquez +Flag a UPnP NAT traversal before starting a UPnP port mapping, and make sure all +calls to mDNS_StopNATOperation() go through the UPnP code -Revision 1.175 2005/01/15 00:56:41 ksekar - Unicast services don't disappear when logging -out of VPN +Revision 1.417 2007/07/27 20:19:42 cheshire +Use MDNS_LOG_VERBOSE_DEBUG for dumping out packets instead of MDNS_LOG_DEBUG -Revision 1.174 2005/01/14 18:44:28 ksekar - mDNSResponder is crashing when changing domains +Revision 1.416 2007/07/27 19:59:28 cheshire +MUST NOT touch m->CurrentQuestion (or q) after calling AnswerCurrentQuestionWithResourceRecord() -Revision 1.173 2005/01/14 18:34:22 ksekar - Services registered outside of firewall don't succeed after location change +Revision 1.415 2007/07/27 19:51:01 cheshire +Use symbol QC_addnocache instead of literal constant "2" -Revision 1.172 2005/01/11 22:50:52 ksekar -Fixed constant naming (was using kLLQ_DefLease for update leases) +Revision 1.414 2007/07/27 19:30:39 cheshire +Changed mDNSQuestionCallback parameter from mDNSBool to QC_result, +to properly reflect tri-state nature of the possible responses -Revision 1.171 2005/01/10 04:52:49 ksekar -Changed LogMsg to debugf +Revision 1.413 2007/07/27 18:44:01 cheshire +Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord" -Revision 1.170 2005/01/08 00:50:05 ksekar -Fixed spelling mistake in log msg +Revision 1.412 2007/07/27 18:38:56 cheshire +Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion" -Revision 1.169 2005/01/08 00:42:18 ksekar - Clean up syslog messages +Revision 1.411 2007/07/27 00:57:13 cheshire +Create hostname address records using standard kHostNameTTL (2 minutes) instead of 1 second -Revision 1.168 2004/12/23 23:22:47 ksekar - Unicast known answers "name" pointers point to garbage stack memory +Revision 1.410 2007/07/25 21:41:00 vazquez +Make sure we clean up opened sockets when there are network transitions and when changing +port mappings -Revision 1.167 2004/12/22 22:25:47 ksekar - NAT-PMP: handle location changes +Revision 1.409 2007/07/25 03:05:02 vazquez +Fixes for: + LegacyNATTraversal: UPnP heap overflow + LegacyNATTraversal: UPnP stack buffer overflow +and a myriad of other security problems -Revision 1.166 2004/12/22 00:04:12 ksekar - mDNSResponder crashing in ReceivePortMapReply +Revision 1.408 2007/07/24 21:47:51 cheshire +Don't do mDNS_StopNATOperation() for operations we never started -Revision 1.165 2004/12/18 03:14:22 cheshire -DblNAT -> DoubleNAT +Revision 1.407 2007/07/24 17:23:33 cheshire + Add list validation checks for debugging -Revision 1.164 2004/12/17 03:55:40 ksekar -Don't use -1 as special meaning for expiration timer (it is a valid -value, and is redundant with our state variables) +Revision 1.406 2007/07/24 04:14:30 cheshire + LLQs not working in with NAT Traversal -Revision 1.163 2004/12/17 03:51:53 ksekar - Don't update TXT record if service registration fails +Revision 1.405 2007/07/24 01:29:03 cheshire + DNSServiceNATPortMappingCreate() returns stale external address information -Revision 1.162 2004/12/17 01:29:11 ksekar - Questions can go deaf on location changes +Revision 1.404 2007/07/20 23:10:51 cheshire +Fix code layout -Revision 1.161 2004/12/16 20:42:02 cheshire -Fix compiler warnings +Revision 1.403 2007/07/20 20:12:37 cheshire +Rename "mDNS_DomainTypeBrowseLegacy" as "mDNS_DomainTypeBrowseAutomatic" -Revision 1.160 2004/12/16 20:13:00 cheshire - Cache memory management improvements +Revision 1.402 2007/07/20 00:54:20 cheshire + Need separate SCPreferences for per-user .Mac settings -Revision 1.159 2004/12/15 02:11:22 ksekar - Don't check for Dynamic DNS hostname uniqueness +Revision 1.401 2007/07/18 03:23:33 cheshire +In GetServiceTarget, need to call SetupLocalAutoTunnelInterface_internal to bring up tunnel on demand, if necessary -Revision 1.158 2004/12/15 02:04:28 ksekar -Refinement to previous checkin - we should still return NatTraversal error when the port mapping fails +Revision 1.400 2007/07/18 02:30:25 cheshire +Defer AutoTunnel server record advertising until we have at least one service to advertise +Do AutoTunnel target host selection in GetServiceTarget (instead of uDNS_RegisterService) -Revision 1.157 2004/12/15 01:39:21 ksekar -Refinement to previous checkin - we should still return NatTraversal error when the port mapping fails +Revision 1.399 2007/07/18 01:02:28 cheshire + Register IPSec tunnel with IPv4-only hostname and create NAT port mappings +Declare records as kDNSRecordTypeKnownUnique so we don't get name conflicts with ourselves -Revision 1.156 2004/12/15 01:18:57 ksekar - Call DeregisterService on nat port map failure +Revision 1.398 2007/07/16 23:54:48 cheshire + Crash when removing or changing DNS keys -Revision 1.155 2004/12/14 21:21:20 ksekar - NAT-PMP: Update response format to contain "Seconds Since Boot" +Revision 1.397 2007/07/16 20:13:31 vazquez + LegacyNATTraversal: Need complete rewrite -Revision 1.154 2004/12/14 20:52:27 cheshire -Add question->qnamehash and cr->resrec.namehash to log message +Revision 1.396 2007/07/14 00:33:04 cheshire +Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working -Revision 1.153 2004/12/14 20:45:02 cheshire -Improved error logging in "unexpected answer" message +Revision 1.395 2007/07/12 23:56:23 cheshire +Change "GetZoneData GOT SRV" message to debugf to reduce verbosity in syslog -Revision 1.152 2004/12/14 03:02:10 ksekar - Rare race condition can cause crash +Revision 1.394 2007/07/12 23:36:08 cheshire +Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog -Revision 1.151 2004/12/13 21:45:08 ksekar -uDNS_DeregisterService should return NoError if called twice (to follow mDNS behavior expected by daemon layer) +Revision 1.393 2007/07/12 22:15:10 cheshire +Modified mDNS_SetSecretForDomain() so it can be called to update an existing entry -Revision 1.150 2004/12/13 20:42:41 ksekar -Fixed LogMsg +Revision 1.392 2007/07/12 02:51:27 cheshire + Automatically configure IPSec policy when resolving services -Revision 1.149 2004/12/13 18:10:03 ksekar -Fixed LogMsg +Revision 1.391 2007/07/11 23:16:31 cheshire + Register IPSec tunnel with IPv4-only hostname and create NAT port mappings +Need to prepend _autotunnel._udp to start of AutoTunnel SRV record name -Revision 1.148 2004/12/13 01:18:04 ksekar -Fixed unused variable warning for non-debug builds +Revision 1.390 2007/07/11 22:47:55 cheshire + Register IPv6-only hostname and don't create port mappings for services +In mDNS_SetSecretForDomain(), don't register records until after we've validated the parameters -Revision 1.147 2004/12/12 23:51:42 ksekar - Wide-area registrations should fallback to using DHCP hostname as target +Revision 1.389 2007/07/11 21:33:10 cheshire + Register IPSec tunnel with IPv4-only hostname and create NAT port mappings +Set up and register AutoTunnelTarget and AutoTunnelService DNS records -Revision 1.146 2004/12/12 23:30:40 ksekar - Extra RRs not properly unlinked when parent service registration fails +Revision 1.388 2007/07/11 19:27:10 cheshire + Register IPv6-only hostname and don't create port mappings for services +For temporary testing fake up an IPv4LL address instead of IPv6 ULA -Revision 1.145 2004/12/12 22:56:29 ksekar - Need to properly handle duplicate long-lived queries +Revision 1.387 2007/07/11 03:04:08 cheshire + Register IPv6-only hostname and don't create port mappings for AutoTunnel services +Add AutoTunnel parameter to mDNS_SetSecretForDomain; Set up AutoTunnel information for domains that require it -Revision 1.144 2004/12/11 20:55:29 ksekar - Clean up registration state machines +Revision 1.386 2007/07/10 01:57:28 cheshire + uDNS: mDNSresponder is leaking TCP connections to DNS server +Turned vast chunks of replicated code into a subroutine MakeTCPConn(...); +Made routines hold on to the reference it returns instead of leaking it -Revision 1.143 2004/12/10 01:21:27 cheshire - Get rid of "LLQ Responses over TCP not currently supported" message +Revision 1.385 2007/07/09 23:50:18 cheshire +unlinkSRS needs to call mDNS_StopNATOperation_internal(), not mDNS_StopNATOperation() -Revision 1.142 2004/12/08 02:03:31 ksekar - Looping on NAT Traversal error - check for -NULL RR on error +Revision 1.384 2007/07/06 21:20:21 cheshire +Fix scheduling error (was causing "Task Scheduling Error: Continuously busy for more than a second") -Revision 1.141 2004/12/07 01:39:28 cheshire -Don't fail if the same server is responsible for more than one domain -(e.g. the same DNS server may be responsible for both apple.com. and 17.in-addr.arpa.) +Revision 1.383 2007/07/06 18:59:59 cheshire +Avoid spinning in an infinite loop when uDNS_SendNATMsg() returns an error -Revision 1.140 2004/12/06 21:15:22 ksekar - mDNSResponder crashed in CheckServiceRegistrations +Revision 1.382 2007/07/04 00:49:43 vazquez +Clean up extraneous comments -Revision 1.139 2004/12/06 19:08:03 cheshire -Add clarifying comment -- CountLabels() excludes the final root label. +Revision 1.381 2007/07/03 00:41:14 vazquez + More changes for Clean up NAT state machine (necessary for 6 other fixes) + Safely deal with packet replies and client callbacks -Revision 1.138 2004/12/06 01:45:54 ksekar -Correct wording in LogMsg +Revision 1.380 2007/07/02 22:08:47 cheshire +Fixed crash in "Received public IP address" message -Revision 1.137 2004/12/03 20:40:35 ksekar - Looping on NAT Traversal error +Revision 1.379 2007/06/29 00:08:49 vazquez + Clean up NAT state machine (necessary for 6 other fixes) -Revision 1.136 2004/12/03 07:20:50 ksekar - Wide-Area: Registration of large TXT record fails +Revision 1.378 2007/06/27 20:25:10 cheshire +Expanded dnsbugtest comment, explaining requirement that we also need these +test queries to black-hole before they get to the root name servers. -Revision 1.135 2004/12/03 05:18:33 ksekar - mDNSResponder needs to return more specific TSIG errors +Revision 1.377 2007/06/22 21:27:21 cheshire +Modified "could not convert shared secret from base64" log message -Revision 1.134 2004/12/02 20:03:49 ksekar - Still publishes wide-area domains even after switching to a local subnet +Revision 1.376 2007/06/20 01:10:12 cheshire + Sync iPhone changes into main mDNSResponder code -Revision 1.133 2004/12/02 18:37:52 ksekar - Registering with port number zero should not create a port mapping +Revision 1.375 2007/06/15 21:54:51 cheshire + Add packet logging to help debugging private browsing over TLS -Revision 1.132 2004/12/01 20:57:19 ksekar - Wide Area Service Discovery must be split-DNS aware +Revision 1.374 2007/06/12 02:15:26 cheshire +Fix incorrect "DNS Server passed" LogOperation message -Revision 1.131 2004/12/01 19:59:27 cheshire - Crash in mDNSPlatformTCPConnect -If a TCP response has the TC bit set, don't respond by just trying another TCP connection +Revision 1.373 2007/05/31 00:25:43 cheshire + Only send dnsbugtest query for questions where it's warranted -Revision 1.130 2004/12/01 02:43:23 cheshire -Don't call StatusCallback if function pointer is null +Revision 1.372 2007/05/25 17:03:45 cheshire +lenptr needs to be declared unsigned, otherwise sign extension can mess up the shifting and ORing operations -Revision 1.129 2004/11/30 23:51:06 cheshire -Remove double semicolons +Revision 1.371 2007/05/24 00:11:44 cheshire +Remove unnecessary lenbuf field from tcpInfo_t -Revision 1.128 2004/11/25 01:48:30 ksekar - Logging into VPN does not trigger registration of address record +Revision 1.370 2007/05/23 00:30:59 cheshire +Don't change question->TargetQID when repeating query over TCP -Revision 1.127 2004/11/25 01:41:36 ksekar -Changed unnecessary LogMsgs to debugfs +Revision 1.369 2007/05/21 18:04:40 cheshire +Updated comments -- port_mapping_create_reply renamed to port_mapping_reply -Revision 1.126 2004/11/23 23:54:17 ksekar - Wide-Area DNSServiceRegisterRecord() failures -can crash mDNSResponder +Revision 1.368 2007/05/17 19:12:16 cheshire +Updated comment about finding matching pair of sockets -Revision 1.125 2004/11/23 04:16:48 cheshire -Removed receiveMsg() routine. +Revision 1.367 2007/05/15 23:38:00 cheshire +Need to grab lock before calling SendRecordRegistration(); -Revision 1.124 2004/11/23 04:06:51 cheshire -Get rid of floating point constant -- in a small embedded device, bringing in all -the floating point libraries just to halve an integer value is a bit too heavyweight. +Revision 1.366 2007/05/15 00:43:05 cheshire + uDNS serviceRegistrationCallback locking failures -Revision 1.123 2004/11/22 17:16:20 ksekar - Unicast services don't disappear when you disable all networking +Revision 1.365 2007/05/10 21:19:18 cheshire +Rate-limit DNS test queries to at most one per three seconds +(useful when we have a dozen active WAB queries, and then we join a new network) -Revision 1.122 2004/11/19 18:00:34 ksekar - Security: use random ID for one-shot unicast queries +Revision 1.364 2007/05/07 20:43:45 cheshire + Reduce the number of queries and announcements -Revision 1.121 2004/11/19 04:24:08 ksekar - Security: Enforce a "window" on one-shot wide-area queries +Revision 1.363 2007/05/04 22:12:48 cheshire +Work towards solving "uDNS_CheckQuery: LastQTime" log messages +When code gets in this invalid state, double ThisQInterval each time, to avoid excessive logging -Revision 1.120 2004/11/19 02:32:43 ksekar - Wide-Area Security: Add LLQ-ID to events +Revision 1.362 2007/05/04 21:23:05 cheshire + Private DNS always returns no answers in the initial LLQ setup response +Preparatory work to enable us to do a four-way LLQ handshake over TCP, if we decide that's what we want -Revision 1.119 2004/11/18 23:21:24 ksekar - LLQ Security: Need to verify src port/address for LLQ handshake +Revision 1.361 2007/05/03 23:50:48 cheshire + mDNSResponder ignores bogus null target in SRV record +In the case of negative answers for the address record, set the server address to zerov4Addr -Revision 1.118 2004/11/18 22:58:37 ksekar -Removed old comment. +Revision 1.360 2007/05/03 22:40:38 cheshire + mDNSResponder ignores bogus null target in SRV record -Revision 1.117 2004/11/18 18:04:21 ksekar -Restore checkins lost due to repository disk failure: Update comments & +Revision 1.359 2007/05/02 22:21:33 cheshire + RegisterRecord and RegisterService need to cancel StartGetZoneData -Revision 1.xxx 2004/11/17 06:17:57 cheshire -Update comments to show correct SRV names: _dns-update._udp.. and _dns-llq._udp.. +Revision 1.358 2007/05/01 21:46:31 cheshire +Move GetLLQOptData/GetPktLease from uDNS.c into DNSCommon.c so that dnsextd can use them -Revision 1.xxx 2004/11/17 00:45:28 ksekar - Result of putUpdateLease not error-checked +Revision 1.357 2007/05/01 01:33:49 cheshire +Removed "#define LLQ_Info DNSQuestion" and manually reconciled code that was still referring to "LLQ_Info" -Revision 1.116 2004/11/16 01:41:47 ksekar -Fixed typo in debugf +Revision 1.356 2007/04/30 21:51:06 cheshire +Updated comments -Revision 1.115 2004/11/15 20:09:24 ksekar - Wide Area support for Add/Remove record +Revision 1.355 2007/04/30 21:33:38 cheshire +Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop +is iterating through the m->ServiceRegistrations list -Revision 1.114 2004/11/13 02:32:47 ksekar - LLQ mobility fragile on non-primary interface -- fixed incorrect state comparison in CheckQueries +Revision 1.354 2007/04/30 01:30:04 cheshire +GetZoneData_QuestionCallback needs to call client callback function on error, so client knows operation is finished +RecordRegistrationCallback and serviceRegistrationCallback need to clear nta reference when they're invoked -Revision 1.113 2004/11/13 02:29:52 ksekar - LLQ refreshes not reliable +Revision 1.353 2007/04/28 01:28:25 cheshire +Fixed memory leak on error path in FoundDomain -Revision 1.112 2004/11/11 20:45:14 ksekar - self-conflict test not compatible with some BIND servers +Revision 1.352 2007/04/27 19:49:53 cheshire +In uDNS_ReceiveTestQuestionResponse, also check that srcport matches -Revision 1.111 2004/11/11 20:14:55 ksekar - Wide-Area registrations not deregistered on sleep +Revision 1.351 2007/04/27 19:28:02 cheshire +Any code that calls StartGetZoneData needs to keep a handle to the structure, so +it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop +-- it would start a query and then quickly cancel it, and then when +StartGetZoneData completed, it had a dangling pointer and crashed.) -Revision 1.110 2004/11/10 23:53:53 ksekar -Remove no longer relevant comment +Revision 1.350 2007/04/26 22:47:14 cheshire +Defensive coding: tcpCallback only needs to check "if (closed)", not "if (!n && closed)" -Revision 1.109 2004/11/10 20:40:53 ksekar - LLQ mobility fragile on non-primary interface +Revision 1.349 2007/04/26 16:04:06 cheshire +In mDNS_AddDNSServer, check whether port matches +In uDNS_CheckQuery, handle case where startLLQHandshake changes q->llq->state to LLQ_Poll -Revision 1.108 2004/11/01 20:36:16 ksekar - mDNSResponder should not receive Keychain Notifications +Revision 1.348 2007/04/26 04:01:59 cheshire +Copy-and-paste error: Test should be "if (result == DNSServer_Passed)" not "if (result == DNSServer_Failed)" -Revision 1.107 2004/10/26 06:11:41 cheshire -Add improved logging to aid in diagnosis of mDNSResponder crashed +Revision 1.347 2007/04/26 00:35:15 cheshire + uDNS: Domain discovery not working over VPN +Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server +inside the firewall may give answers where a public one gives none, and vice versa.) -Revision 1.106 2004/10/26 03:52:03 cheshire -Update checkin comments +Revision 1.346 2007/04/25 19:16:59 cheshire +Don't set SuppressStdPort53Queries unless we do actually send a DNS packet -Revision 1.105 2004/10/26 01:15:06 cheshire -Use "#if 0" instead of commenting out code +Revision 1.345 2007/04/25 18:05:11 cheshire +Don't try to restart inactive (duplicate) queries -Revision 1.104 2004/10/25 21:41:38 ksekar - wide-area name conflicts can cause crash +Revision 1.344 2007/04/25 17:54:07 cheshire +Don't cancel Private LLQs using a clear-text UDP packet -Revision 1.103 2004/10/25 19:30:52 ksekar - Simplify dynamic host name structures +Revision 1.343 2007/04/25 16:40:08 cheshire +Add comment explaining uDNS_recvLLQResponse logic -Revision 1.102 2004/10/23 01:16:00 cheshire - uDNS operations not always reliable on multi-homed hosts +Revision 1.342 2007/04/25 02:14:38 cheshire + uDNS: Identical client queries should reference a single shared core query +Additional fixes to make LLQs work properly -Revision 1.101 2004/10/22 20:52:07 ksekar - Create NAT port mappings for Long Lived Queries +Revision 1.341 2007/04/24 02:07:42 cheshire + Identical client queries should reference a single shared core query +Deleted some more redundant code -Revision 1.100 2004/10/20 02:16:41 cheshire -Improve "could not confirm existence of NS record" error message -Don't call newRR->RecordCallback if it is NULL +Revision 1.340 2007/04/23 22:01:23 cheshire + IPv6 filtering in AirPort base station breaks Wide-Area Bonjour +As of March 2007, AirPort base stations now block incoming IPv6 connections by default, so there's no point +advertising IPv6 addresses in DNS any more -- we have to assume that most of the time a host's IPv6 address +probably won't work for incoming connections (but its IPv4 address probably will, using NAT-PMP). -Revision 1.99 2004/10/19 21:33:18 cheshire - Cannot resolve non-local registrations using the mach API -Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name -doesn't force multicast unless you set this flag to indicate explicitly that this is what you want +Revision 1.339 2007/04/22 06:02:03 cheshire + Query should immediately return failure when no server -Revision 1.98 2004/10/16 00:16:59 cheshire - Replace IP TTL 255 check with local subnet source address check +Revision 1.338 2007/04/21 19:44:11 cheshire +Improve uDNS_HandleNATPortMapReply log message -Revision 1.97 2004/10/15 23:00:18 ksekar - Need to update LLQs on location changes +Revision 1.337 2007/04/21 02:03:00 cheshire +Also need to set AddressRec->resrec.RecordType in the NAT case too -Revision 1.96 2004/10/12 23:30:44 ksekar - mDNSResponder needs to follow CNAME referrals +Revision 1.336 2007/04/20 21:16:12 cheshire +Fixed bogus double-registration of host name -- was causing these warning messages in syslog: +Error! Tried to register AuthRecord 0181FB0C host.example.com. (Addr) that's already in the list -Revision 1.95 2004/10/12 03:15:09 ksekar - mDNS_StartQuery shouldn't return transient no-server error +Revision 1.335 2007/04/19 23:57:20 cheshire +Temporary workaround for some AirPort base stations that don't seem to like us requesting public port zero -Revision 1.94 2004/10/12 02:49:20 ksekar - Clean up LLQ sleep/wake, error handling +Revision 1.334 2007/04/19 23:21:51 cheshire +Fixed a couple of places where the StartGetZoneData check was backwards -Revision 1.93 2004/10/08 04:17:25 ksekar - Don't use DNS extensions if the server does not advertise required SRV record +Revision 1.333 2007/04/19 22:50:53 cheshire + Identical client queries should reference a single shared core query -Revision 1.92 2004/10/08 03:54:35 ksekar - Refine unicast polling intervals +Revision 1.332 2007/04/19 20:34:32 cheshire +Add debugging log message in uDNS_CheckQuery() -Revision 1.91 2004/09/30 17:45:34 ksekar - lots of log messages: mDNS_SetPrimaryIP: IP address unchanged +Revision 1.331 2007/04/19 20:06:41 cheshire +Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer) -Revision 1.90 2004/09/25 00:22:13 ksekar - Crash in uDNS_RegisterService +Revision 1.330 2007/04/19 19:51:54 cheshire +Get rid of unnecessary initializeQuery() routine -Revision 1.89 2004/09/24 19:14:53 cheshire -Remove unused "extern mDNS mDNSStorage" +Revision 1.329 2007/04/19 18:03:52 cheshire +Improved "mDNS_AddSearchDomain" log message -Revision 1.88 2004/09/23 20:48:15 ksekar -Clarify retransmission debugf messages. +Revision 1.328 2007/04/18 20:57:20 cheshire +Commented out "GetAuthInfoForName none found" debugging message -Revision 1.87 2004/09/22 00:41:59 cheshire -Move tcp connection status codes into the legal range allocated for mDNS use +Revision 1.327 2007/04/17 19:21:29 cheshire + Domain discovery not working over VPN -Revision 1.86 2004/09/21 23:40:11 ksekar - mDNSResponder to return errors on NAT traversal failure +Revision 1.326 2007/04/16 20:49:39 cheshire +Fix compile errors for mDNSPosix build -Revision 1.85 2004/09/21 22:38:27 ksekar - PrimaryIP type uninitialized +Revision 1.325 2007/04/05 22:55:35 cheshire + Records are ending up in Lighthouse without expiry information -Revision 1.84 2004/09/18 00:30:39 cheshire - Infinite loop in CheckServiceRegistrations +Revision 1.324 2007/04/05 20:43:30 cheshire +Collapse sprawling code onto one line -- this is part of a bigger block of identical +code that has been copied-and-pasted into six different places in the same file. +This really needs to be turned into a subroutine. -Revision 1.83 2004/09/17 00:31:51 cheshire -For consistency with ipv6, renamed rdata field 'ip' to 'ipv4' +Revision 1.323 2007/04/04 21:48:52 cheshire + Combine unicast authoritative answer list with multicast list -Revision 1.82 2004/09/16 21:36:36 cheshire - Fix unsafe use of mDNSPlatformTimeNow() -Changes to add necessary locking calls around unicast DNS operations +Revision 1.322 2007/04/03 19:53:06 cheshire +Use mDNSSameIPPort (and similar) instead of accessing internal fields directly -Revision 1.81 2004/09/16 02:29:39 cheshire -Moved mDNS_Lock/mDNS_Unlock to DNSCommon.c; Added necessary locking around -uDNS_ReceiveMsg, uDNS_StartQuery, uDNS_UpdateRecord, uDNS_RegisterService +Revision 1.321 2007/04/02 23:44:09 cheshire +Minor code tidying -Revision 1.80 2004/09/16 01:58:21 cheshire -Fix compiler warnings +Revision 1.320 2007/03/31 01:26:13 cheshire +Take out GetAuthInfoForName syslog message -Revision 1.79 2004/09/16 00:24:48 cheshire - Fix unsafe use of mDNSPlatformTimeNow() +Revision 1.319 2007/03/31 01:10:53 cheshire +Add debugging -Revision 1.78 2004/09/15 01:16:57 ksekar - mDNSResponder printing too many messages +Revision 1.318 2007/03/31 00:17:11 cheshire +Remove some LogMsgs -Revision 1.77 2004/09/14 23:27:47 cheshire -Fix compile errors +Revision 1.317 2007/03/29 00:09:31 cheshire +Improve "uDNS_InitLongLivedQuery" log message -Revision 1.76 2004/09/14 22:22:00 ksekar - Legacy browses broken against some BIND versions +Revision 1.316 2007/03/28 21:16:27 cheshire +Remove DumpPacket() call now that OPT pseudo-RR rrclass bug is fixed -Revision 1.75 2004/09/03 19:23:05 ksekar -: Need retransmission mechanism for wide-area service registrations +Revision 1.315 2007/03/28 21:02:18 cheshire + Wide-Area Bonjour should work on multi-subnet private network -Revision 1.74 2004/09/02 17:49:04 ksekar -: 8A246: mDNSResponder crash while logging on restart -Fixed incorrect conversions, changed %s to %##s for all domain names. +Revision 1.314 2007/03/28 15:56:37 cheshire + Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output -Revision 1.73 2004/09/02 01:39:40 cheshire -For better readability, follow consistent convention that QR bit comes first, followed by OP bits +Revision 1.313 2007/03/28 01:27:32 cheshire + Unicast DNS polling server every three seconds +StartLLQPolling was using INIT_UCAST_POLL_INTERVAL instead of LLQ_POLL_INTERVAL for the retry interval -Revision 1.72 2004/09/01 03:59:29 ksekar -: Conditionally compile out uDNS code on Windows +Revision 1.312 2007/03/27 23:48:21 cheshire +Use mDNS_StopGetDomains(), not mDNS_StopQuery() -Revision 1.71 2004/08/27 17:51:53 ksekar -Replaced unnecessary LogMsg with debugf. +Revision 1.311 2007/03/27 22:47:51 cheshire +Remove unnecessary "*(long*)0 = 0;" to generate crash and stack trace -Revision 1.70 2004/08/25 00:37:27 ksekar -: Cleanup DynDNS hostname registration code +Revision 1.310 2007/03/24 01:24:13 cheshire +Add validator for uDNS data structures; fixed crash in RegisterSearchDomains() -Revision 1.69 2004/08/18 17:35:41 ksekar -: Feature #9586: Need support for Legacy NAT gateways +Revision 1.309 2007/03/24 00:47:53 cheshire + serviceRegistrationCallback: Locking Failure! mDNS_busy (1) != mDNS_reentrancy (2) +Locking in this file is all messed up. For now we'll just work around the issue. -Revision 1.68 2004/08/14 03:22:41 cheshire - Dynamic DNS UI <-> mDNSResponder glue -Add GetUserSpecifiedDDNSName() routine -Convert ServiceRegDomain to domainname instead of C string -Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs +Revision 1.308 2007/03/24 00:41:33 cheshire +Minor code cleanup (move variable declarations to minimum enclosing scope) -Revision 1.67 2004/08/13 23:46:58 cheshire -"asyncronous" -> "asynchronous" +Revision 1.307 2007/03/21 23:06:00 cheshire +Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields -Revision 1.66 2004/08/13 23:37:02 cheshire -Now that we do both uDNS and mDNS, global replace "uDNS_info.hostname" with -"uDNS_info.UnicastHostname" for clarity +Revision 1.306 2007/03/21 00:30:03 cheshire + Multiple errors in DNameList-related code -Revision 1.65 2004/08/13 23:12:32 cheshire -Don't use strcpy() and strlen() on "struct domainname" objects; -use AssignDomainName() and DomainNameLength() instead -(A "struct domainname" is a collection of packed pascal strings, not a C string.) +Revision 1.305 2007/03/20 17:07:15 cheshire +Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket" -Revision 1.64 2004/08/13 23:01:05 cheshire -Use platform-independent mDNSNULL instead of NULL +Revision 1.304 2007/03/17 00:02:11 cheshire + NAT-PMP: Lease TTL is being ignored -Revision 1.63 2004/08/12 00:32:36 ksekar -: LLQ Refreshes never terminate if unanswered +Revision 1.303 2007/03/10 03:26:44 cheshire + uDNS: LLQ refresh response packet causes cached records to be removed from cache -Revision 1.62 2004/08/10 23:19:14 ksekar -: DNS Extension daemon for Wide Area Service Discovery -Moved routines/constants to allow extern access for garbage collection daemon +Revision 1.302 2007/03/10 02:29:58 cheshire +Added comments about NAT-PMP response functions -Revision 1.61 2004/07/30 17:40:06 ksekar -: TXT Record updates not available for wide-area services +Revision 1.301 2007/03/10 02:02:58 cheshire + uDNS: LLQ refresh response packet causes cached records to be removed from cache +Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer -Revision 1.60 2004/07/29 19:40:05 ksekar -NAT-PMP Support - minor fixes and cleanup +Revision 1.300 2007/03/08 18:56:00 cheshire +Fixed typo: "&v4.ip.v4.b[0]" is always non-zero (ampersand should not be there) -Revision 1.59 2004/07/29 19:27:15 ksekar -NAT-PMP Support - minor fixes and cleanup +Revision 1.299 2007/02/28 01:45:47 cheshire + NAT-PMP: Port mapping refreshes should contain actual public port + Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c -Revision 1.58 2004/07/27 07:35:38 shersche -fix syntax error, variables declared in the middle of a block +Revision 1.298 2007/02/14 03:16:39 cheshire + Eliminate unnecessary malloc/free in mDNSCore code -Revision 1.57 2004/07/26 22:49:30 ksekar -: Feature #9516: Need support for NAT-PMP in client +Revision 1.297 2007/02/08 21:12:28 cheshire + Stop reading /etc/mDNSResponder.conf on every sleep/wake -Revision 1.56 2004/07/26 19:14:44 ksekar -: 8A210: mDNSResponder crashed in startLLQHandshakeCallback +Revision 1.296 2007/01/29 16:03:22 cheshire +Fix unused parameter warning -Revision 1.55 2004/07/15 19:01:33 ksekar -: Check for incorrect time comparisons +Revision 1.295 2007/01/27 03:34:27 cheshire +Made GetZoneData use standard queries (and cached results); +eliminated GetZoneData_Callback() packet response handler -Revision 1.54 2004/06/22 02:10:53 ksekar -: Lighthouse failure causes packet flood to DNS +Revision 1.294 2007/01/25 00:40:16 cheshire +Unified CNAME-following functionality into cache management code (which means CNAME-following +should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine. -Revision 1.53 2004/06/17 20:49:09 ksekar -: mDNSResponder crash while location cycling +Revision 1.293 2007/01/23 02:56:11 cheshire +Store negative results in the cache, instead of generating them out of pktResponseHndlr() -Revision 1.52 2004/06/17 01:13:11 ksekar -: polling interval too short +Revision 1.292 2007/01/20 01:32:40 cheshire +Update comments and debugging messages -Revision 1.51 2004/06/10 04:36:44 cheshire -Fix compiler warning +Revision 1.291 2007/01/20 00:07:02 cheshire +When we have credentials in the keychain for a domain, we attempt private queries, but +if the authoritative server is not set up for private queries (i.e. no _dns-query-tls +or _dns-llq-tls record) then we need to fall back to conventional non-private queries. -Revision 1.50 2004/06/10 00:55:13 ksekar -: crash on network reconnect +Revision 1.290 2007/01/19 23:41:45 cheshire +Need to clear m->rec.r.resrec.RecordType after calling GetLLQOptData() -Revision 1.49 2004/06/10 00:10:50 ksekar -: Infinite Loop in uDNS_Execute() +Revision 1.289 2007/01/19 23:32:07 cheshire +Eliminate pointless timenow variable -Revision 1.48 2004/06/09 20:03:37 ksekar -: Incorrect copying of resource record in deregistration +Revision 1.288 2007/01/19 23:26:08 cheshire +Right now tcpCallback does not run holding the lock, so no need to drop the lock before invoking callbacks -Revision 1.47 2004/06/09 03:48:28 ksekar -: nameserver address fails with prod. Lighthouse server +Revision 1.287 2007/01/19 22:55:41 cheshire +Eliminate redundant identical parameters to GetZoneData_StartQuery() -Revision 1.46 2004/06/09 01:44:30 ksekar - reworked Cache Record copy code +Revision 1.286 2007/01/19 21:17:33 cheshire +StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion -Revision 1.45 2004/06/08 18:54:47 ksekar -: mDNSResponder leaks after exploring in Printer Setup Utility +Revision 1.285 2007/01/19 18:39:11 cheshire +Fix a bunch of parameters that should have been declared "const" -Revision 1.44 2004/06/05 00:33:51 cheshire -: Check for incorrect time comparisons +Revision 1.284 2007/01/19 18:28:28 cheshire +Improved debugging messages -Revision 1.43 2004/06/05 00:14:44 cheshire -Fix signed/unsigned and other compiler warnings +Revision 1.283 2007/01/19 18:09:33 cheshire +Fixed getLLQAtIndex (now called GetLLQOptData): +1. It incorrectly assumed all EDNS0 OPT records are the same size (it ignored optlen) +2. It used inefficient memory copying instead of just returning a pointer -Revision 1.42 2004/06/04 22:36:16 ksekar -Properly set u->nextevent in uDNS_Execute +Revision 1.282 2007/01/17 22:06:01 cheshire +Replace duplicated literal constant "{ { 0 } }" with symbol "zeroIPPort" -Revision 1.41 2004/06/04 08:58:29 ksekar -: Keychain integration for secure dynamic update +Revision 1.281 2007/01/17 21:58:13 cheshire +For clarity, rename ntaContext field "isPrivate" to "ntaPrivate" -Revision 1.40 2004/06/03 03:09:58 ksekar -: Garbage Collection for Dynamic Updates +Revision 1.280 2007/01/17 21:46:02 cheshire +Remove redundant duplicated "isPrivate" field from LLQ_Info -Revision 1.39 2004/06/01 23:46:50 ksekar -: DynDNS: dynamically look up LLQ/Update ports +Revision 1.279 2007/01/17 21:35:31 cheshire +For clarity, rename zoneData_t field "isPrivate" to "zonePrivate" -Revision 1.38 2004/05/31 22:19:44 ksekar -: Feature: DNS server->client notification on -record changes (#7805) - revert to polling mode on setup errors +Revision 1.278 2007/01/16 03:04:16 cheshire + Add support for one-shot private queries as well as long-lived private queries +Don't cache result of ntaContextSRV(context) in a local variable -- +the macro evaluates to a different result after we clear "context->isPrivate" -Revision 1.37 2004/05/28 23:42:37 ksekar -: Feature: DNS server->client notification on record changes (#7805) +Revision 1.277 2007/01/10 22:51:58 cheshire + Add support for one-shot private queries as well as long-lived private queries -Revision 1.36 2004/05/18 23:51:25 cheshire -Tidy up all checkin comments to use consistent "" format for bug numbers +Revision 1.276 2007/01/10 02:09:30 cheshire +Better LogOperation record of keys read from System Keychain -Revision 1.35 2004/05/07 23:01:04 ksekar -Cleaned up list traversal in deriveGoodbyes - removed unnecessary -conditional assignment. +Revision 1.275 2007/01/09 22:37:18 cheshire +Provide ten-second grace period for deleted keys, to give mDNSResponder +time to delete host name before it gives up access to the required key. -Revision 1.34 2004/05/05 18:26:12 ksekar -Periodically re-transmit questions if the send() fails. Include -internal questions in retransmission. +Revision 1.274 2007/01/09 01:16:32 cheshire +Improve "ERROR m->CurrentQuestion already set" debugging messages -Revision 1.33 2004/05/05 17:40:06 ksekar -Removed prerequisite from deregistration update - it does not work for -shared records, and is unnecessary until we have more sophisticated -name conflict management. +Revision 1.273 2007/01/08 23:58:00 cheshire +Don't request regDomain and browseDomains in uDNS_SetupDNSConfig() -- it just ignores those results -Revision 1.32 2004/05/05 17:32:18 ksekar -Prevent registration of loopback interface caused by removal of -Multicast flag in interface structure. +Revision 1.272 2007/01/05 08:30:42 cheshire +Trim excessive "$Log" checkin history from before 2006 +(checkin history still available via "cvs log ..." of course) -Revision 1.31 2004/05/05 17:05:02 ksekar -Use LargeCacheRecord structs when pulling records off packets +Revision 1.271 2007/01/05 06:34:03 cheshire +Improve "ERROR m->CurrentQuestion already set" debugging messages -Revision 1.30 2004/04/16 21:33:27 ksekar -Fixed bug in processing GetZoneData responses that do not use BIND formatting. +Revision 1.270 2007/01/05 05:44:33 cheshire +Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c, +so that mDNSPosix embedded clients will compile again -Revision 1.29 2004/04/15 20:03:13 ksekar -Clarified log message when pulling bad resource records off packet. +Revision 1.269 2007/01/04 23:11:13 cheshire + uDNS: Need to start caching unicast records +When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries -Revision 1.28 2004/04/15 00:51:28 bradley -Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers. -Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers. +Revision 1.268 2007/01/04 22:06:38 cheshire +Fixed crash in LLQNatMapComplete() -Revision 1.27 2004/04/14 23:09:28 ksekar -Support for TSIG signed dynamic updates. +Revision 1.267 2007/01/04 21:45:20 cheshire +Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros, +to do additional lock sanity checking around callback invocations -Revision 1.26 2004/04/14 19:36:05 ksekar -Fixed memory corruption error in deriveGoodbyes. +Revision 1.266 2007/01/04 21:01:20 cheshire + mDNSResponder NXDOMAIN and CNAME support +Only return NXDOMAIN results to clients that request them using kDNSServiceFlagsReturnIntermediates -Revision 1.25 2004/04/14 04:07:11 ksekar -Fixed crash in IsActiveUnicastQuery(). Removed redundant checks in routine. +Revision 1.265 2007/01/04 20:47:17 cheshire +Fixed crash in CheckForUnreferencedLLQMapping() -Revision 1.24 2004/04/08 09:41:40 bradley -Added const to AuthRecord in deadvertiseIfCallback to match callback typedef. +Revision 1.264 2007/01/04 20:39:27 cheshire +Fix locking mismatch -Revision 1.23 2004/03/24 00:29:45 ksekar -Make it safe to call StopQuery in a unicast question callback +Revision 1.263 2007/01/04 02:39:53 cheshire + Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations -Revision 1.22 2004/03/19 10:11:09 bradley -Added AuthRecord * cast from umalloc for C++ builds. +Revision 1.262 2007/01/04 00:29:25 cheshire +Covert LogMsg() in GetAuthInfoForName to LogOperation() -Revision 1.21 2004/03/15 02:03:45 bradley -Added const to params where needed to match prototypes. Changed SetNewRData calls to use 0 instead -of -1 for unused size to fix warning. Disable assignment within conditional warnings with Visual C++. +Revision 1.261 2006/12/22 20:59:49 cheshire + Read *all* DNS keys from keychain, + not just key for the system-wide default registration domain -Revision 1.20 2004/03/13 02:07:26 ksekar -: DynDNS: Dynamic update of service records +Revision 1.260 2006/12/21 00:06:07 cheshire +Don't need to do mDNSPlatformMemZero() -- mDNS_SetupResourceRecord() does it for us -Revision 1.19 2004/03/13 01:57:33 ksekar -: DynDNS: Dynamic update of service records +Revision 1.259 2006/12/20 04:07:36 cheshire +Remove uDNS_info substructure from AuthRecord_struct -Revision 1.18 2004/02/21 08:34:15 bradley -Added casts from void * to specific type for C++ builds. Changed void * l-value cast -r-value cast to fix problems with VC++ builds. Removed empty switch to fix VC++ error. +Revision 1.258 2006/12/19 22:49:24 cheshire +Remove uDNS_info substructure from ServiceRecordSet_struct -Revision 1.17 2004/02/21 02:06:24 cheshire -Can't use anonymous unions -- they're non-standard and don't work on all compilers +Revision 1.257 2006/12/19 02:38:20 cheshire +Get rid of unnecessary duplicate query ID field from DNSQuestion_struct -Revision 1.16 2004/02/12 01:51:45 cheshire -Don't try to send uDNS queries unless we have at least one uDNS server available +Revision 1.256 2006/12/19 02:18:48 cheshire +Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct -Revision 1.15 2004/02/10 03:02:46 cheshire -Fix compiler warning +Revision 1.255 2006/12/16 01:58:31 cheshire + uDNS: Need to start caching unicast records -Revision 1.14 2004/02/06 23:04:19 ksekar -Basic Dynamic Update support via mDNS_Register (dissabled via -UNICAST_REGISTRATION #define) +Revision 1.254 2006/12/15 19:23:39 cheshire +Use new DomainNameLengthLimit() function, to be more defensive against malformed +data received from the network. -Revision 1.13 2004/02/03 22:15:01 ksekar -Fixed nameToAddr error check: don't abort state machine on nxdomain error. +Revision 1.253 2006/12/01 07:43:34 herscher +Fix byte ordering problem for one-shot TCP queries. +Iterate more intelligently over duplicates in uDNS_ReceiveMsg to avoid spin loops. -Revision 1.12 2004/02/03 19:47:36 ksekar -Added an asynchronous state machine mechanism to uDNS.c, including -calls to find the parent zone for a domain name. Changes include code -in repository previously dissabled via "#if 0 incomplete". Codepath -is currently unused, and will be called to create update records, etc. +Revision 1.252 2006/11/30 23:07:57 herscher + uDNS: Sync up with Lighthouse changes for Private DNS -Revision 1.11 2004/01/30 02:12:30 ksekar -Changed uDNS_ReceiveMsg() to correctly return void. +Revision 1.251 2006/11/28 21:42:11 mkrochma +Work around a crashing bug that was introduced by uDNS and mDNS code unification -Revision 1.10 2004/01/29 02:59:17 ksekar -Unicast DNS: Changed from a resource record oriented question/response -matching to packet based matching. New callback architecture allows -collections of records in a response to be processed differently -depending on the nature of the request, and allows the same structure -to be used for internal and client-driven queries with different processing needs. +Revision 1.250 2006/11/18 05:01:30 cheshire +Preliminary support for unifying the uDNS and mDNS code, +including caching of uDNS answers -Revision 1.9 2004/01/28 20:20:45 ksekar -Unified ActiveQueries and ActiveInternalQueries lists, using a flag to -demux them. Check-in includes work-in-progress code, #ifdef'd out. +Revision 1.249 2006/11/10 07:44:04 herscher + Fix Daemon locking failures while toggling BTMM -Revision 1.8 2004/01/28 02:30:07 ksekar -Added default Search Domains to unicast browsing, controlled via -Networking sharing prefs pane. Stopped sending unicast messages on -every interface. Fixed unicast resolving via mach-port API. +Revision 1.248 2006/11/08 04:26:53 cheshire +Fix typo in debugging message -Revision 1.7 2004/01/27 20:15:22 cheshire -: Time to prune obsolete code for listening on port 53 +Revision 1.247 2006/10/20 05:35:04 herscher + uDNS: Merge unicast active question list with multicast list. -Revision 1.6 2004/01/24 23:47:17 cheshire -Use mDNSOpaque16fromIntVal() instead of shifting and masking +Revision 1.246 2006/10/11 19:29:41 herscher + uDNS: mDNSResponder-111 using 100% CPU -Revision 1.5 2004/01/24 04:59:15 cheshire -Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again +Revision 1.245 2006/10/04 22:21:15 herscher +Tidy up references to mDNS_struct introduced when the embedded uDNS_info struct was removed. -Revision 1.4 2004/01/24 04:19:26 cheshire -Restore overwritten checkin 1.2 +Revision 1.244 2006/10/04 21:51:27 herscher +Replace calls to mDNSPlatformTimeNow(m) with m->timenow -Revision 1.3 2004/01/23 23:23:15 ksekar -Added TCP support for truncated unicast messages. +Revision 1.243 2006/10/04 21:38:59 herscher +Remove uDNS_info substructure from DNSQuestion_struct -Revision 1.2 2004/01/22 03:48:41 cheshire -Make sure uDNS client doesn't accidentally use query ID zero +Revision 1.242 2006/09/27 00:51:46 herscher +Fix compile error when _LEGACY_NAT_TRAVERSAL_ is not defined -Revision 1.1 2003/12/13 03:05:27 ksekar -: DynDNS: Unicast query of service records +Revision 1.241 2006/09/26 01:54:47 herscher + NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol) - */ +Revision 1.240 2006/09/15 21:20:15 cheshire +Remove uDNS_info substructure from mDNS_struct + +Revision 1.239 2006/08/16 02:52:56 mkrochma + Actually fix it this time + +Revision 1.238 2006/08/16 00:31:50 mkrochma + Get rid of NotAnInteger references + +Revision 1.237 2006/08/15 23:38:17 mkrochma + Requested Public Port field should be set to zero on mapping deletion + +Revision 1.236 2006/08/14 23:24:23 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + +Revision 1.235 2006/07/30 05:45:36 cheshire + Eliminate MIN_UCAST_PERIODIC_EXEC + +Revision 1.234 2006/07/22 02:58:36 cheshire +Code was clearing namehash twice instead of namehash and rdatahash + +Revision 1.233 2006/07/20 19:46:51 mkrochma + Add Private DNS client functionality to mDNSResponder +Fix Private DNS + +Revision 1.232 2006/07/15 02:01:29 cheshire + Add Private DNS client functionality to mDNSResponder +Fix broken "empty string" browsing + +Revision 1.231 2006/07/05 23:28:22 cheshire + Add Private DNS client functionality to mDNSResponder + +Revision 1.230 2006/06/29 03:02:44 cheshire + mDNSResponder NXDOMAIN and CNAME support + +Revision 1.229 2006/03/02 22:03:41 cheshire + Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use" +Refinement: m->rec.r.resrec.RecordType needs to be cleared *every* time around for loop, not just once at the end + +Revision 1.228 2006/02/26 00:54:42 cheshire +Fixes to avoid code generation warning/error on FreeBSD 7 + +Revision 1.227 2006/01/09 20:47:05 cheshire + Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use" + +*/ #include "uDNS.h" @@ -770,3832 +933,3270 @@ Revision 1.1 2003/12/13 03:05:27 ksekar #pragma warning(disable:4706) #endif -#define umalloc(x) mDNSPlatformMemAllocate(x) // short hands for common routines -#define ufree(x) mDNSPlatformMemFree(x) -#define ubzero(x,y) mDNSPlatformMemZero(x,y) -#define umemcpy(x, y, l) mDNSPlatformMemCopy(y, x, l) // uses memcpy(2) arg ordering - -// Asynchronous operation types - -typedef enum +typedef struct tcpInfo_t { - zoneDataResult - // other async. operation names go here - } AsyncOpResultType; - -typedef struct - { - domainname zoneName; - mDNSAddr primaryAddr; - mDNSu16 zoneClass; - mDNSIPPort llqPort; - mDNSIPPort updatePort; - } zoneData_t; - -// other async. result struct defs go here - -typedef struct - { - AsyncOpResultType type; - zoneData_t zoneData; - // other async result structs go here - } AsyncOpResult; - -typedef void AsyncOpCallback(mStatus err, mDNS *const m, void *info, const AsyncOpResult *result); - - -// Private Function Prototypes -// Note: In general, functions are ordered such that they do not require forward declarations. -// However, prototypes are used where cyclic call graphs exist (e.g. foo calls bar, and bar calls -// foo), or when they aid in the grouping or readability of code (e.g. state machine code that is easier -// read top-to-bottom.) - -mDNSlocal mDNSBool FreeNATInfo(mDNS *m, NATTraversalInfo *n); -mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question, const mDNSAddr *src, mDNS *m); -mDNSlocal mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdatePort, mDNSBool findLLQPort, AsyncOpCallback callback, void *callbackInfo); -mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID); -mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr); -mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs); -mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs); -mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srsPtr, const AsyncOpResult *result); -mDNSlocal void SuspendLLQs(mDNS *m, mDNSBool DeregisterActive); -mDNSlocal void RestartQueries(mDNS *m); -mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info, mDNSBool defer); -mDNSlocal void llqResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *context); - -// *************************************************************************** -#if COMPILER_LIKES_PRAGMA_MARK -#pragma mark - Temporary workaround -#endif - -// 17 Places in this file directly call mDNSPlatformTimeNow(), which is unsafe -// The platform function is now called mDNSPlatformRawTime(), and -// mDNSPlatformTimeNow() is defined here as a temporary workaround. -// This is a gross hack, and after this change has been tested for a while, -// all these calls should be replaced by simple references to m->timenow + mDNS *m; + TCPSocket *sock; + DNSMessage request; + int requestLen; + DNSQuestion *question; // For queries + ServiceRecordSet *srs; // For service record updates + AuthRecord *rr; // For record updates + mDNSAddr Addr; + mDNSIPPort Port; + DNSMessage *reply; + mDNSu16 replylen; + unsigned long nread; + int numReplies; + } tcpInfo_t; -mDNSlocal mDNSs32 mDNSPlatformTimeNow(mDNS *m) +typedef struct SearchListElem { - if (m->mDNS_busy && m->timenow) return(m->timenow); - LogMsg("ERROR: uDNS.c code executing without holding main mDNS lock"); - - // To get a quick and easy stack trace to find out *how* this routine - // is being called without holding main mDNS lock, uncomment the line below: - // *(long*)0=0; - - return(mDNS_TimeNow(m)); - } + struct SearchListElem *next; + domainname domain; + int flag; // -1 means delete, 0 means unchanged, +1 means newly added + DNSQuestion BrowseQ; + DNSQuestion DefBrowseQ; + DNSQuestion AutomaticBrowseQ; + DNSQuestion RegisterQ; + DNSQuestion DefRegisterQ; + ARListElem *AuthRecs; + } SearchListElem; + +// For domain enumeration and automatic browsing +// This is the user's DNS search list. +// In each of these domains we search for our special pointer records (lb._dns-sd._udp., etc.) +// to discover recommended domains for domain enumeration (browse, default browse, registration, +// default registration) and possibly one or more recommended automatic browsing domains. +static SearchListElem *SearchList = mDNSNULL; + +// Temporary workaround to make ServiceRecordSet list management safe. +// Ideally a ServiceRecordSet shouldn't be a special entity that's given special treatment by the uDNS code +// -- it should just be a grouping of records that are treated the same as any other registered records. +// In that case it may no longer be necessary to keep an explicit list of ServiceRecordSets, which in turn +// would avoid the perils of modifying that list cleanly while some other piece of code is iterating through it. +static ServiceRecordSet *CurrentServiceRecordSet = mDNSNULL; // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - General Utility Functions #endif -// CountLabels() returns number of labels in name, excluding final root label -// (e.g. for "apple.com." CountLabels returns 2.) -mDNSlocal int CountLabels(const domainname *d) - { - int count = 0; - const mDNSu8 *ptr; - - for (ptr = d->c; *ptr; ptr = ptr + ptr[0] + 1) count++; - return count; - } - -mDNSlocal mDNSOpaque16 newMessageID(uDNS_GlobalInfo *u) - { - static mDNSBool randomized = mDNSfalse; - - if (!randomized) { u->NextMessageID = (mDNSu16)mDNSRandom(0xFFFF); randomized = mDNStrue; } - if (u->NextMessageID == 0) u->NextMessageID++; - return mDNSOpaque16fromIntVal(u->NextMessageID++); - } - -// unlink an AuthRecord from a linked list -mDNSlocal mStatus unlinkAR(AuthRecord **list, AuthRecord *const rr) +// Unlink an AuthRecord from the m->ResourceRecords list. +// This seems risky. Probably some (or maybe all) of the places calling UnlinkAuthRecord to directly +// remove a record from the list should actually be using mDNS_Deregister/mDNS_Deregister_internal. +mDNSlocal mStatus UnlinkAuthRecord(mDNS *const m, AuthRecord *const rr) { + AuthRecord **list = &m->ResourceRecords; + if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next; + if (m->CurrentRecord == rr) m->CurrentRecord = rr->next; while (*list && *list != rr) list = &(*list)->next; + if (!*list) + { + list = &m->DuplicateRecords; + while (*list && *list != rr) list = &(*list)->next; + } if (*list) { *list = rr->next; rr->next = mDNSNULL; return(mStatus_NoError); } - LogMsg("ERROR: unlinkAR - no such active record %##s", rr->resrec.name->c); + LogMsg("ERROR: UnlinkAuthRecord - no such active record %##s", rr->resrec.name->c); return(mStatus_NoSuchRecord); } -mDNSlocal void unlinkSRS(mDNS *m, ServiceRecordSet *srs) +// unlinkSRS is an internal routine (i.e. must be called with the lock already held) +mDNSlocal void unlinkSRS(mDNS *const m, ServiceRecordSet *srs) { - uDNS_GlobalInfo *u = &m->uDNS_info; ServiceRecordSet **p; - NATTraversalInfo *n = u->NATTraversals; - // verify that no NAT objects reference this service - while (n) + if (srs->NATinfo.clientContext) { - if (n->reg.ServiceRegistration == srs) - { - NATTraversalInfo *tmp = n; - n = n->next; - LogMsg("ERROR: Unlinking service record set %##s still referenced by NAT traversal object!", srs->RR_SRV.resrec.name->c); - FreeNATInfo(m, tmp); - } - else n = n->next; + mDNS_StopNATOperation_internal(m, &srs->NATinfo); + srs->NATinfo.clientContext = mDNSNULL; } - - for (p = &u->ServiceRegistrations; *p; p = &(*p)->next) + + for (p = &m->ServiceRegistrations; *p; p = &(*p)->uDNS_next) if (*p == srs) { ExtraResourceRecord *e; - *p = srs->next; - srs->next = mDNSNULL; + *p = srs->uDNS_next; + if (CurrentServiceRecordSet == srs) + CurrentServiceRecordSet = srs->uDNS_next; + srs->uDNS_next = mDNSNULL; for (e=srs->Extras; e; e=e->next) - if (unlinkAR(&u->RecordRegistrations, &e->r)) + if (UnlinkAuthRecord(m, &e->r)) LogMsg("unlinkSRS: extra record %##s not found", e->r.resrec.name->c); return; } LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list %##s", srs->RR_SRV.resrec.name->c); } -mDNSlocal void LinkActiveQuestion(uDNS_GlobalInfo *u, DNSQuestion *q) - { - if (uDNS_IsActiveQuery(q, u)) - { LogMsg("LinkActiveQuestion - %##s (%d) already in list!", q->qname.c, q->qtype); return; } - - q->next = u->ActiveQueries; - u->ActiveQueries = q; - } - // set retry timestamp for record with exponential backoff // (for service record sets, use RR_SRV as representative for time checks mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mStatus SendErr) { - rr->LastAPTime = mDNSPlatformTimeNow(m); + rr->LastAPTime = m->timenow; if (SendErr == mStatus_TransientErr || rr->ThisAPInterval < INIT_UCAST_POLL_INTERVAL) rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL; else if (rr->ThisAPInterval*2 <= MAX_UCAST_POLL_INTERVAL) rr->ThisAPInterval *= 2; - else if (rr->ThisAPInterval != MAX_UCAST_POLL_INTERVAL) rr->ThisAPInterval = MAX_UCAST_POLL_INTERVAL; + else rr->ThisAPInterval = MAX_UCAST_POLL_INTERVAL; } - // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - Name Server List Management #endif -mDNSexport void mDNS_AddDNSServer(mDNS *const m, const mDNSAddr *addr, const domainname *d) - { - uDNS_GlobalInfo *u = &m->uDNS_info; - DNSServer *s, **p = &u->Servers; - - mDNS_Lock(m); - if (!d) d = (domainname *)""; +mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port) + { + DNSServer **p = &m->DNSServers; + + if (!d) d = (const domainname *)""; + + LogOperation("mDNS_AddDNSServer: Adding %#a for %##s", addr, d->c); + if (m->mDNS_busy != m->mDNS_reentrancy+1) + LogMsg("mDNS_AddDNSServer: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); - while (*p) // Check if we already have this {server,domain} pair registered + while (*p) // Check if we already have this {server,domain} pair registered { - if (mDNSSameAddress(&(*p)->addr, addr) && SameDomainName(&(*p)->domain, d)) - LogMsg("Note: DNS Server %#a for domain %##s registered more than once", addr, d->c); + if ((*p)->interface == interface && (*p)->teststate != DNSServer_Disabled && + mDNSSameAddress(&(*p)->addr, addr) && mDNSSameIPPort((*p)->port, port) && SameDomainName(&(*p)->domain, d)) + { + if (!(*p)->del) LogMsg("Note: DNS Server %#a for domain %##s registered more than once", addr, d->c); + (*p)->del = mDNSfalse; + return(*p); + } p=&(*p)->next; } // allocate, add to list - s = umalloc(sizeof(*s)); - if (!s) { LogMsg("Error: mDNS_AddDNSServer - malloc"); goto end; } - s->addr = *addr; - s->del = mDNSfalse; - s->teststate = DNSServer_Untested; - AssignDomainName(&s->domain, d); - s->next = mDNSNULL; - *p = s; - - end: - mDNS_Unlock(m); - } - -mDNSexport void mDNS_DeleteDNSServers(mDNS *const m) - { - DNSServer *s; - mDNS_Lock(m); - - s = m->uDNS_info.Servers; - m->uDNS_info.Servers = mDNSNULL; - while (s) + *p = mDNSPlatformMemAllocate(sizeof(**p)); + if (!*p) LogMsg("Error: mDNS_AddDNSServer - malloc"); + else { - DNSServer *tmp = s; - s = s->next; - ufree(tmp); + (*p)->interface = interface; + (*p)->addr = *addr; + (*p)->port = port; + (*p)->del = mDNSfalse; + (*p)->teststate = DNSServer_Untested; + (*p)->lasttest = m->timenow - INIT_UCAST_POLL_INTERVAL; + AssignDomainName(&(*p)->domain, d); + (*p)->next = mDNSNULL; } + return(*p); + } - mDNS_Unlock(m); - } - - // *************************************************************************** +// *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - authorization management #endif -mDNSlocal uDNS_AuthInfo *GetAuthInfoForName(const uDNS_GlobalInfo *u, const domainname *name) +mDNSlocal DomainAuthInfo *GetAuthInfoForName_direct(mDNS *m, const domainname *const name) { - uDNS_AuthInfo *ptr; - while (name->c[0]) + const domainname *n = name; + while (n->c[0]) { - for (ptr = u->AuthInfoList; ptr; ptr = ptr->next) - if (SameDomainName(&ptr->zone, name)) return(ptr); - name = (const domainname *)(name->c + 1 + name->c[0]); + DomainAuthInfo *ptr; + for (ptr = m->AuthInfoList; ptr; ptr = ptr->next) + if (SameDomainName(&ptr->domain, n)) + { + debugf("GetAuthInfoForName %##s Matched %##s Key name %##s", name->c, ptr->domain.c, ptr->keyname.c); + return(ptr); + } + n = (const domainname *)(n->c + 1 + n->c[0]); } + //LogOperation("GetAuthInfoForName none found for %##s", name->c); return mDNSNULL; } -mDNSlocal void DeleteAuthInfoForZone(uDNS_GlobalInfo *u, const domainname *zone) +// MUST be called with lock held +mDNSexport DomainAuthInfo *GetAuthInfoForName_internal(mDNS *m, const domainname *const name) { - uDNS_AuthInfo *ptr, *prev = mDNSNULL; + DomainAuthInfo **p = &m->AuthInfoList; + + if (m->mDNS_busy != m->mDNS_reentrancy+1) + LogMsg("GetAuthInfoForName_internal: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); - for (ptr = u->AuthInfoList; ptr; ptr = ptr->next) + // First purge any dead keys from the list + while (*p) { - if (SameDomainName(&ptr->zone, zone)) + if ((*p)->deltime && m->timenow - (*p)->deltime >= 0 && AutoTunnelUnregistered(*p)) { - if (prev) prev->next = ptr->next; - else u->AuthInfoList = ptr->next; - ufree(ptr); - return; + DNSQuestion *q; + DomainAuthInfo *info = *p; + LogOperation("GetAuthInfoForName_internal deleting expired key %##s %##s", info->domain.c, info->keyname.c); + *p = info->next; // Cut DomainAuthInfo from list *before* scanning our question list updating AuthInfo pointers + for (q = m->Questions; q; q=q->next) + if (q->AuthInfo == info) + { + q->AuthInfo = GetAuthInfoForName_direct(m, &q->qname); + debugf("GetAuthInfoForName_internal updated q->AuthInfo from %##s to %##s for %##s (%s)", + info->domain.c, q->AuthInfo ? q->AuthInfo->domain.c : mDNSNULL, q->qname.c, DNSTypeName(q->qtype)); + } + + // Probably not essential, but just to be safe, zero out the secret key data + // so we don't leave it hanging around in memory + // (where it could potentially get exposed via some other bug) + mDNSPlatformMemZero(info, sizeof(*info)); + mDNSPlatformMemFree(info); } - prev = ptr; + else + p = &(*p)->next; } + + return(GetAuthInfoForName_direct(m, name)); } -mDNSexport mStatus mDNS_SetSecretForZone(mDNS *m, const domainname *zone, const domainname *key, const char *sharedSecret) +mDNSexport DomainAuthInfo *GetAuthInfoForName(mDNS *m, const domainname *const name) { - uDNS_AuthInfo *info; - mDNSu8 keybuf[1024]; - mDNSs32 keylen; - uDNS_GlobalInfo *u = &m->uDNS_info; - mStatus status = mStatus_NoError; - + DomainAuthInfo *d; mDNS_Lock(m); - - if (GetAuthInfoForName(u, zone)) DeleteAuthInfoForZone(u, zone); - if (!key) goto exit; - - info = (uDNS_AuthInfo*)umalloc(sizeof(*info)); - if (!info) { LogMsg("ERROR: umalloc"); status = mStatus_NoMemoryErr; goto exit; } - ubzero(info, sizeof(*info)); - AssignDomainName(&info->zone, zone); - AssignDomainName(&info->keyname, key); - - keylen = DNSDigest_Base64ToBin(sharedSecret, keybuf, 1024); - if (keylen < 0) - { - LogMsg("ERROR: mDNS_SetSecretForZone - could not convert shared secret %s from base64", sharedSecret); - ufree(info); - status = mStatus_UnknownErr; - goto exit; - } - DNSDigest_ConstructHMACKey(info, keybuf, (mDNSu32)keylen); - - // link into list - info->next = m->uDNS_info.AuthInfoList; - m->uDNS_info.AuthInfoList = info; -exit: + d = GetAuthInfoForName_internal(m, name); mDNS_Unlock(m); - return status; + return(d); } - - // *************************************************************************** -#if COMPILER_LIKES_PRAGMA_MARK -#pragma mark - NAT Traversal -#endif -mDNSlocal mDNSBool DomainContainsLabelString(const domainname *d, const char *str) +// MUST be called with the lock held +mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info, + const domainname *domain, const domainname *keyname, const char *b64keydata, mDNSBool AutoTunnel) { - const domainlabel *l; - domainlabel buf; - - if (!MakeDomainLabelFromLiteralString(&buf, str)) return mDNSfalse; - - for (l = (const domainlabel *)d; l->c[0]; l = (const domainlabel *)(l->c + l->c[0]+1)) - if (SameDomainLabel(l->c, buf.c)) return mDNStrue; - return mDNSfalse; - } + DNSQuestion *q; + DomainAuthInfo **p = &m->AuthInfoList; + if (!info || !b64keydata) { LogMsg("mDNS_SetSecretForDomain: ERROR: info %p b64keydata %p", info, b64keydata); return(mStatus_BadParamErr); } -// allocate struct, link into global list, initialize -mDNSlocal NATTraversalInfo *AllocNATInfo(mDNS *const m, NATOp_t op, NATResponseHndlr callback) - { - uDNS_GlobalInfo *u = &m->uDNS_info; - NATTraversalInfo *info = umalloc(sizeof(NATTraversalInfo)); - if (!info) { LogMsg("ERROR: malloc"); return mDNSNULL; } - ubzero(info, sizeof(NATTraversalInfo)); - info->next = u->NATTraversals; - u->NATTraversals = info; - info->retry = mDNSPlatformTimeNow(m) + NATMAP_INIT_RETRY; - info->op = op; - info->state = NATState_Init; - info->ReceiveResponse = callback; - info->PublicPort.NotAnInteger = 0; - info->Router = u->Router; - return info; - } + LogOperation("mDNS_SetSecretForDomain: domain %##s key %##s%s", domain->c, keyname->c, AutoTunnel ? " AutoTunnel" : ""); -// unlink from list, deallocate -mDNSlocal mDNSBool FreeNATInfo(mDNS *m, NATTraversalInfo *n) - { - NATTraversalInfo *ptr, *prev = mDNSNULL; - ServiceRecordSet *s = m->uDNS_info.ServiceRegistrations; + info->AutoTunnel = AutoTunnel; + AssignDomainName(&info->domain, domain); + AssignDomainName(&info->keyname, keyname); + mDNS_snprintf(info->b64keydata, sizeof(info->b64keydata), "%s", b64keydata); - // Verify that object is not referenced by any services - while (s) + if (DNSDigest_ConstructHMACKeyfromBase64(info, b64keydata) < 0) { - if (s->uDNS_info.NATinfo == n) - { - LogMsg("Error: Freeing NAT info object still referenced by Service Record Set %##s!", s->RR_SRV.resrec.name->c); - s->uDNS_info.NATinfo = mDNSNULL; - } - s = s->next; + LogMsg("mDNS_SetSecretForDomain: ERROR: Could not convert shared secret from base64: domain %##s key %##s %s", + domain->c, keyname->c, LogAllOperations ? b64keydata : ""); + return(mStatus_BadParamErr); } - - if (n == m->uDNS_info.LLQNatInfo) m->uDNS_info.LLQNatInfo = mDNSNULL; - ptr = m->uDNS_info.NATTraversals; - while (ptr) + + // Don't clear deltime until after we've ascertained that b64keydata is valid + info->deltime = 0; + + while (*p && (*p) != info) p=&(*p)->next; + if (*p) return(mStatus_AlreadyRegistered); + + // Caution: Only zero AutoTunnelHostRecord.namestorage and AutoTunnelNAT.clientContext AFTER we've determined that this is a NEW DomainAuthInfo + // being added to the list. Otherwise we risk smashing our AutoTunnel host records and NATOperation that are already active and in use. + info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeUnregistered; + info->AutoTunnelHostRecord.namestorage.c[0] = 0; + info->AutoTunnelTarget .resrec.RecordType = kDNSRecordTypeUnregistered; + info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeUnregistered; + info->AutoTunnelService .resrec.RecordType = kDNSRecordTypeUnregistered; + info->AutoTunnelNAT.clientContext = mDNSNULL; + info->next = mDNSNULL; + *p = info; + + // Check to see if adding this new DomainAuthInfo has changed the credentials for any of our questions + for (q = m->Questions; q; q=q->next) { - if (ptr == n) + if (q->QuestionCallback != GetZoneData_QuestionCallback) { - if (prev) prev->next = ptr->next; - else m->uDNS_info.NATTraversals = ptr->next; - ufree(n); - return mDNStrue; + DomainAuthInfo *newinfo = GetAuthInfoForName_internal(m, &q->qname); + if (q->AuthInfo != newinfo) + { + debugf("mDNS_SetSecretForDomain updating q->AuthInfo from %##s to %##s for %##s (%s)", + q->AuthInfo ? q->AuthInfo->domain.c : mDNSNULL, + newinfo ? newinfo ->domain.c : mDNSNULL, q->qname.c, DNSTypeName(q->qtype)); + q->AuthInfo = newinfo; + } } - prev = ptr; - ptr = ptr->next; } - LogMsg("FreeNATInfo: NATTraversalInfo not found in list"); - return mDNSfalse; + + return(mStatus_NoError); } -mDNSlocal void SendNATMsg(NATTraversalInfo *info, mDNS *m) - { - mStatus err; - mDNSAddr dst; - mDNSIPPort dstport; - uDNS_GlobalInfo *u = &m->uDNS_info; +// *************************************************************************** +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - +#pragma mark - NAT Traversal +#endif - if (info->state != NATState_Request && info->state != NATState_Refresh) - { LogMsg("SendNATMsg: Bad state %d", info->state); return; } +mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info) + { + mStatus err = mStatus_NoError; - if (u->Router.ip.v4.NotAnInteger) + // send msg if we have a router and it is a private address + if (!mDNSIPv4AddressIsZero(m->Router.ip.v4) && mDNSv4AddrIsRFC1918(&m->Router.ip.v4)) { - // send msg if we have a router - const mDNSu8 *end = (mDNSu8 *)&info->request; - if (info->op == NATOp_AddrRequest) end += sizeof(NATAddrRequest); - else end += sizeof(NATPortMapRequest); + union { NATAddrRequest NATAddrReq; NATPortMapRequest NATPortReq; } u = { { NATMAP_VERS, NATOp_AddrRequest } } ; + const mDNSu8 *end = (mDNSu8 *)&u + sizeof(NATAddrRequest); + + if (info) // For NATOp_MapUDP and NATOp_MapTCP, fill in additional fields + { + mDNSu8 *p = (mDNSu8 *)&u.NATPortReq.NATReq_lease; + u.NATPortReq.opcode = info->Protocol; + u.NATPortReq.unused = zeroID; + u.NATPortReq.intport = info->IntPort; + u.NATPortReq.extport = info->RequestedPort; + p[0] = (mDNSu8)((info->NATLease >> 24) & 0xFF); + p[1] = (mDNSu8)((info->NATLease >> 16) & 0xFF); + p[2] = (mDNSu8)((info->NATLease >> 8) & 0xFF); + p[3] = (mDNSu8)( info->NATLease & 0xFF); + end = (mDNSu8 *)&u + sizeof(NATPortMapRequest); + } + + err = mDNSPlatformSendUDP(m, (mDNSu8 *)&u, end, 0, &m->Router, NATPMPPort); - dst.type = u->Router.type; - dst.ip.v4 = u->Router.ip.v4; - dstport = mDNSOpaque16fromIntVal(NATMAP_PORT); - err = mDNSPlatformSendUDP(m, &info->request, end, 0, &dst, dstport); - if (!err) (info->ntries++); // don't increment attempt counter if the send failed +#ifdef _LEGACY_NAT_TRAVERSAL_ + if (mDNSIPPortIsZero(m->UPnPSOAPPort)) LNT_SendDiscoveryMsg(m); + else if (info) err = LNT_MapPort(m, info); + else err = LNT_GetExternalAddress(m); +#endif // _LEGACY_NAT_TRAVERSAL_ } - - // set retry - if (info->RetryInterval < NATMAP_INIT_RETRY) info->RetryInterval = NATMAP_INIT_RETRY; - else if (info->RetryInterval * 2 > NATMAP_MAX_RETRY) info->RetryInterval = NATMAP_MAX_RETRY; - else info->RetryInterval *= 2; - info->retry = mDNSPlatformTimeNow(m) + info->RetryInterval; + return(err); } -mDNSlocal mDNSBool ReceiveNATAddrResponse(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len) +mDNSlocal void RecreateNATMappings(mDNS *const m) { - mStatus err = mStatus_NoError; - AuthRecord *rr = mDNSNULL; - NATAddrReply *response = (NATAddrReply *)pkt; - mDNSAddr addr; - - if (n->state != NATState_Request) - { - LogMsg("ReceiveNATAddrResponse: bad state %d", n->state); - return mDNSfalse; - } - - rr = n->reg.RecordRegistration; - if (!rr) + NATTraversalInfo *n; + for (n = m->NATTraversals; n; n=n->next) { - LogMsg("ReceiveNATAddrResponse: registration cancelled"); - return mDNSfalse; + n->ExpiryTime = 0; // Mark this mapping as expired + n->retryInterval = NATMAP_INIT_RETRY; + n->retryPortMap = m->timenow; +#ifdef _LEGACY_NAT_TRAVERSAL_ + if (n->tcpInfo.sock) { mDNSPlatformTCPCloseConnection(n->tcpInfo.sock); n->tcpInfo.sock = mDNSNULL; } +#endif // _LEGACY_NAT_TRAVERSAL_ } - addr.type = mDNSAddrType_IPv4; - addr.ip.v4 = rr->resrec.rdata->u.ipv4; + m->NextScheduledNATOp = m->timenow; // Need to send packets immediately + } - if (!pkt) // timeout - { #ifdef _LEGACY_NAT_TRAVERSAL_ - err = LNT_GetPublicIP(&addr.ip.v4); - if (err) goto end; - else n->state = NATState_Legacy; +mDNSlocal void ClearUPnPState(mDNS *const m) + { + if (m->tcpAddrInfo.sock) { mDNSPlatformTCPCloseConnection(m->tcpAddrInfo.sock); m->tcpAddrInfo.sock = mDNSNULL; } + if (m->tcpDeviceInfo.sock) { mDNSPlatformTCPCloseConnection(m->tcpDeviceInfo.sock); m->tcpDeviceInfo.sock = mDNSNULL; } + m->UPnPSOAPPort = m->UPnPRouterPort = zeroIPPort; // Reset UPnP ports + } #else - debugf("ReceiveNATAddrResponse: timeout"); - err = mStatus_NATTraversal; - goto end; +#define ClearUPnPState(X) #endif // _LEGACY_NAT_TRAVERSAL_ - } - else - { - if (len < sizeof(*response)) - { - LogMsg("ReceiveNATAddrResponse: response too short (%d bytes)", len); - return mDNSfalse; - } - if (response->vers != NATMAP_VERS) - { - LogMsg("ReceiveNATAddrResponse: received version %d (expect version %d)", pkt[0], NATMAP_VERS); - return mDNSfalse; - } - if (response->opcode != (NATOp_AddrRequest | NATMAP_RESPONSE_MASK)) - { - LogMsg("ReceiveNATAddrResponse: bad response code %d", response->opcode); - return mDNSfalse; - } - if (response->err.NotAnInteger) - { LogMsg("ReceiveAddrResponse: received error %d", mDNSVal16(response->err)); err = mStatus_NATTraversal; goto end; } - addr.ip.v4 = response->PubAddr; - n->state = NATState_Established; - } - - if (IsPrivateV4Addr(&addr)) - { - LogMsg("ReceiveNATAddrResponse: Double NAT"); - err = mStatus_DoubleNAT; - goto end; - } - - end: - if (err) +mDNSexport void natTraversalHandleAddressReply(mDNS *const m, mDNSu16 err, mDNSv4Addr ExtAddr) + { + if (err) LogMsg("Error getting external address %d", err); + else if (!mDNSSameIPv4Address(m->ExternalAddress, ExtAddr)) { - FreeNATInfo(m, n); - if (rr) - { - rr->uDNS_info.NATinfo = mDNSNULL; - rr->uDNS_info.state = regState_Unregistered; // note that rr is not yet in global list - rr->RecordCallback(m, rr, mStatus_NATTraversal); - // note - unsafe to touch rr after callback - } - return mDNStrue; + LogOperation("Received external IP address %.4a from NAT", &ExtAddr); + if (mDNSv4AddrIsRFC1918(&ExtAddr)) + LogMsg("Double NAT (external NAT gateway address %.4a is also a private RFC 1918 address)", &ExtAddr); + m->ExternalAddress = ExtAddr; + RecreateNATMappings(m); // Also sets NextScheduledNATOp for us } - else LogOperation("Received public IP address %d.%d.%d.%d from NAT.", addr.ip.v4.b[0], addr.ip.v4.b[1], addr.ip.v4.b[2], addr.ip.v4.b[3]); - rr->resrec.rdata->u.ipv4 = addr.ip.v4; // replace rdata w/ public address - uDNS_RegisterRecord(m, rr); - return mDNStrue; - } + if (err || mDNSIPv4AddressIsZero(ExtAddr)) m->retryIntervalGetAddr = NATMAP_INIT_RETRY * 32; // 8 seconds + else m->retryIntervalGetAddr = NATMAP_MAX_RETRY_INTERVAL; -mDNSlocal void StartGetPublicAddr(mDNS *m, AuthRecord *AddressRec) - { - NATAddrRequest *req; - uDNS_GlobalInfo *u = &m->uDNS_info; - - NATTraversalInfo *info = AllocNATInfo(m, NATOp_AddrRequest, ReceiveNATAddrResponse); - if (!info) { uDNS_RegisterRecord(m, AddressRec); return; } - AddressRec->uDNS_info.NATinfo = info; - info->reg.RecordRegistration = AddressRec; - info->state = NATState_Request; - - // format message - req = &info->request.AddrReq; - req->vers = NATMAP_VERS; - req->opcode = NATOp_AddrRequest; - - if (!u->Router.ip.v4.NotAnInteger) - { - debugf("No router. Will retry NAT traversal in %ld ticks", NATMAP_INIT_RETRY); - return; - } - - SendNATMsg(info, m); + m->retryGetAddr = m->timenow + m->retryIntervalGetAddr; + if (m->NextScheduledNATOp - m->retryIntervalGetAddr > 0) + m->NextScheduledNATOp = m->retryIntervalGetAddr; } - -mDNSlocal void RefreshNATMapping(NATTraversalInfo *n, mDNS *m) +// Both places that call NATSetNextRenewalTime() update m->NextScheduledNATOp correctly afterwards +mDNSlocal void NATSetNextRenewalTime(mDNS *const m, NATTraversalInfo *n) { - n->state = NATState_Refresh; - n->RetryInterval = NATMAP_INIT_RETRY; - n->ntries = 0; - SendNATMsg(n, m); + n->retryInterval = (n->ExpiryTime - m->timenow)/2; + if (n->retryInterval < NATMAP_MIN_RETRY_INTERVAL) // Min retry interval is 2 seconds + n->retryInterval = NATMAP_MIN_RETRY_INTERVAL; + n->retryPortMap = m->timenow + n->retryInterval; } -mDNSlocal void LLQNatMapComplete(mDNS *m) +// Note: When called from handleLNTPortMappingResponse() only pkt->err, pkt->extport and pkt->NATRep_lease fields are filled in +mDNSexport void natTraversalHandlePortMapReply(mDNS *const m, NATTraversalInfo *n, const mDNSInterfaceID InterfaceID, mDNSu16 err, mDNSIPPort extport, mDNSu32 lease) { - uDNS_GlobalInfo *u = &m->uDNS_info; - LLQ_Info *llqInfo; - NATTraversalInfo *n = u->LLQNatInfo; + n->NewResult = err; + if (err || lease == 0 || mDNSIPPortIsZero(extport)) + { + LogOperation("natTraversalHandlePortMapReply: received error making port mapping error %d port %d", err, mDNSVal16(extport)); + n->retryInterval = NATMAP_MAX_RETRY_INTERVAL; + n->retryPortMap = m->timenow + NATMAP_MAX_RETRY_INTERVAL; + // No need to set m->NextScheduledNATOp here, since we're only ever extending the m->retryPortMap time + if (err == NATErr_Refused) n->NewResult = mStatus_NATPortMappingDisabled; + else if (err > NATErr_None && err <= NATErr_Opcode) n->NewResult = mStatus_NATPortMappingUnsupported; + } + else + { + if (lease > 999999999UL / mDNSPlatformOneSecond) + lease = 999999999UL / mDNSPlatformOneSecond; + n->ExpiryTime = NonZeroTime(m->timenow + lease * mDNSPlatformOneSecond); - if (!n) { LogMsg("Error: LLQNatMapComplete called with NULL LLQNatInfo"); return; } - if (n->state != NATState_Established && n->state != NATState_Legacy && n->state != NATState_Error) - { LogMsg("LLQNatMapComplete - bad nat state %d", n->state); return; } + if (!mDNSSameIPPort(n->RequestedPort, extport)) + LogOperation("natTraversalHandlePortMapReply: public port changed from %d to %d", mDNSVal16(n->RequestedPort), mDNSVal16(extport)); - u->CurrentQuery = u->ActiveQueries; - while (u->CurrentQuery) - { - DNSQuestion *q = u->CurrentQuery; - u->CurrentQuery = u->CurrentQuery->next; - llqInfo = q->uDNS_info.llq; - if (q->LongLived && llqInfo->state == LLQ_NatMapWait) - { - if (n->state == NATState_Error) - { - llqInfo->NATMap = mDNSfalse; - llqInfo->question->uDNS_info.responseCallback = llqResponseHndlr; - llqInfo->state = LLQ_Poll; - llqInfo->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL); // trigger immediate poll - llqInfo->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL; - } - else { llqInfo->state = LLQ_GetZoneInfo; startLLQHandshake(m, llqInfo, mDNSfalse); } - } + n->InterfaceID = InterfaceID; + n->RequestedPort = extport; + + LogOperation("natTraversalHandlePortMapReply %p %s Internal Port %d External Port %d", n, + n->Protocol == NATOp_MapUDP ? "UDP Response" : + n->Protocol == NATOp_MapTCP ? "TCP Response" : "?", mDNSVal16(n->IntPort), mDNSVal16(n->RequestedPort)); + + NATSetNextRenewalTime(m, n); // Got our port mapping; now set timer to renew it at halfway point + m->NextScheduledNATOp = m->timenow; // May need to invoke client callback immediately } } -mDNSlocal mDNSBool ReceivePortMapReply(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len) +// Must be called with the mDNS_Lock held +mDNSexport mStatus mDNS_StartNATOperation_internal(mDNS *const m, NATTraversalInfo *traversal) { - ServiceRecordSet *srs = n->reg.ServiceRegistration; - mDNSIPPort priv = srs ? srs->RR_SRV.resrec.rdata->u.srv.port : m->UnicastPort4; - mDNSu32 lease; - mDNSBool deletion = !n->request.PortReq.lease.NotAnInteger; - NATPortMapReply *reply = (NATPortMapReply *)pkt; - mDNSu8 *service = srs ? srs->RR_SRV.resrec.name->c : (mDNSu8 *)"\016LLQ event port"; - - if (n->state != NATState_Request && n->state != NATState_Refresh) - { LogMsg("ReceivePortMapReply (%##s): bad state %d", service, n->state); return mDNSfalse; } - - if (!pkt && !deletion) // timeout - { -#ifdef _LEGACY_NAT_TRAVERSAL_ - mDNSIPPort pub; - int ntries = 0; - mStatus err; - mDNSBool tcp = (srs && DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp")); - - pub = priv; // initially request priv == pub - while (1) - { - err = LNT_MapPort(priv, pub, tcp); - if (!err) - { - n->PublicPort = pub; - n->state = NATState_Legacy; - goto end; - } - else if (err != mStatus_AlreadyRegistered || ++ntries > LEGACY_NATMAP_MAX_TRIES) - { - n->state = NATState_Error; - goto end; - } - else - { - // the mapping we want is taken - try a random port - mDNSu16 RandPort = mDNSRandom(DYN_PORT_MAX - DYN_PORT_MIN) + DYN_PORT_MIN; - pub = mDNSOpaque16fromIntVal(RandPort); - } - } -#else - goto end; -#endif // _LEGACY_NAT_TRAVERSAL_ - } + NATTraversalInfo **n; + + LogOperation("mDNS_StartNATOperation_internal %d %d %d %d", + traversal->Protocol, mDNSVal16(traversal->IntPort), mDNSVal16(traversal->RequestedPort), traversal->NATLease); + + // Note: It important that new traversal requests are appended at the *end* of the list, not prepended at the start + n = &m->NATTraversals; + while (*n && *n != traversal) n=&(*n)->next; + if (*n) { LogMsg("Error! Tried to add a NAT traversal that's already in the active list"); return(mStatus_AlreadyRegistered); } + + // Initialize necessary fields + traversal->next = mDNSNULL; + traversal->ExpiryTime = 0; + traversal->retryInterval = NATMAP_INIT_RETRY; + traversal->retryPortMap = m->timenow; + traversal->NewResult = mStatus_NoError; + traversal->ExternalAddress = onesIPv4Addr; + traversal->ExternalPort = zeroIPPort; + traversal->Lifetime = 0; + traversal->Result = mStatus_NoError; + + // set default lease if necessary + if (!traversal->NATLease) traversal->NATLease = NATMAP_DEFAULT_LEASE; - if (len < sizeof(*reply)) { LogMsg("ReceivePortMapReply: response too short (%d bytes)", len); return mDNSfalse; } - if (reply->vers != NATMAP_VERS) { LogMsg("ReceivePortMapReply: received version %d (expect version %d)", pkt[0], NATMAP_VERS); return mDNSfalse; } - if (reply->opcode != (n->op | NATMAP_RESPONSE_MASK)) { LogMsg("ReceivePortMapReply: bad response code %d", pkt[1]); return mDNSfalse; } - if (reply->err.NotAnInteger) { LogMsg("ReceivePortMapReply: received error %d", mDNSVal16(reply->err)); return mDNSfalse; } - if (priv.NotAnInteger != reply->priv.NotAnInteger) return mDNSfalse; // packet does not match this request +#ifdef _LEGACY_NAT_TRAVERSAL_ + mDNSPlatformMemZero(&traversal->tcpInfo, sizeof(traversal->tcpInfo)); +#endif _LEGACY_NAT_TRAVERSAL_ - if (!srs && n != m->uDNS_info.LLQNatInfo) + if (!m->NATTraversals) // If this is our first NAT request, kick off an address request too { - LogMsg("ReceivePortMapReply: registration cancelled"); //!!!KRS change to debugf before checkin - FreeNATInfo(m, n); - return mDNStrue; + m->retryGetAddr = m->timenow; + m->retryIntervalGetAddr = NATMAP_INIT_RETRY; } - if (deletion) { n->state = NATState_Deleted; return mDNStrue; } - - lease = (mDNSu32)mDNSVal32(reply->lease); - if (lease > 0x70000000UL / mDNSPlatformOneSecond) lease = 0x70000000UL / mDNSPlatformOneSecond; - - if (n->state == NATState_Refresh && reply->pub.NotAnInteger != n->PublicPort.NotAnInteger) - LogMsg("ReceivePortMapReply: NAT refresh changed public port from %d to %d", mDNSVal16(n->PublicPort), mDNSVal16(reply->pub)); - // this should never happen - // !!!KRS to be defensive, use SRVChanged flag on service and deregister here - - n->PublicPort = reply->pub; - if (reply->pub.NotAnInteger != n->request.PortReq.pub.NotAnInteger) n->request.PortReq.pub = reply->pub; // set message buffer for refreshes + m->NextScheduledNATOp = m->timenow; // This will always trigger sending the packet ASAP, and generate client callback if necessary - n->retry = mDNSPlatformTimeNow(m) + ((mDNSs32)lease * mDNSPlatformOneSecond / 2); // retry half way to expiration + *n = traversal; // Append new NATTraversalInfo to the end of our list - if (n->state == NATState_Refresh) { n->state = NATState_Established; return mDNStrue; } - n->state = NATState_Established; + return(mStatus_NoError); + } - end: - if (n->state != NATState_Established && n->state != NATState_Legacy) +// Must be called with the mDNS_Lock held +mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *traversal) + { + NATTraversalInfo **ptr = &m->NATTraversals; + + while (*ptr && *ptr != traversal) ptr=&(*ptr)->next; + if (*ptr) *ptr = (*ptr)->next; // If we found it, cut this NATTraversalInfo struct from our list + else { - LogMsg("NAT Port Mapping (%##s): timeout", service); - if (pkt) LogMsg("!!! timeout with non-null packet"); - n->state = NATState_Error; - if (srs) - { - uDNS_HostnameInfo *hi = m->uDNS_info.Hostnames; - while (hi) - { - if (hi->arv6 && (hi->arv6->uDNS_info.state == regState_Registered || hi->arv6->uDNS_info.state == regState_Refresh)) break; - else hi = hi->next; - } - - if (hi) - { - debugf("Port map failed for service %##s - using IPv6 service target", service); - srs->uDNS_info.NATinfo = mDNSNULL; - FreeNATInfo(m, n); - goto register_service; - } - else srs->uDNS_info.state = regState_NATError; - } - else LLQNatMapComplete(m); - return mDNStrue; + LogMsg("mDNS_StopNATOperation: NATTraversalInfo %p not found in list", traversal); + return(mStatus_BadReferenceErr); } - else LogOperation("Mapped private port %d to public port %d", mDNSVal16(priv), mDNSVal16(n->PublicPort)); - if (!srs) { LLQNatMapComplete(m); return mDNStrue; } + LogOperation("mDNS_StopNATOperation_internal %d %d %d %d", + traversal->Protocol, mDNSVal16(traversal->IntPort), mDNSVal16(traversal->RequestedPort), traversal->NATLease); - register_service: - if (srs->uDNS_info.ns.ip.v4.NotAnInteger) SendServiceRegistration(m, srs); // non-zero server address means we already have necessary zone data to send update - else + if (m->CurrentNATTraversal == traversal) + m->CurrentNATTraversal = m->CurrentNATTraversal->next; + + if (traversal->ExpiryTime) { - srs->uDNS_info.state = regState_FetchingZoneData; - startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs); + traversal->NATLease = 0; + traversal->retryInterval = 0; + uDNS_SendNATMsg(m, traversal); } - return mDNStrue; + // Even if we DIDN'T make a successful UPnP mapping yet, we might still have a partially-open TCP connection we need to clean up + #ifdef _LEGACY_NAT_TRAVERSAL_ + { + mStatus err = LNT_UnmapPort(m, traversal); + if (err) LogMsg("Legacy NAT Traversal - unmap request failed with error %ld", err); + } + #endif // _LEGACY_NAT_TRAVERSAL_ + return(mStatus_NoError); } -mDNSlocal void FormatPortMaprequest(NATTraversalInfo *info, mDNSIPPort port) +mDNSexport mStatus mDNS_StartNATOperation(mDNS *m, NATTraversalInfo *traversal) { - NATPortMapRequest *req = &info->request.PortReq; - - req->vers = NATMAP_VERS; - req->opcode = info->op; - req->unused.NotAnInteger = 0; - req->priv = port; - req->pub = port; - req->lease = mDNSOpaque32fromIntVal(NATMAP_DEFAULT_LEASE); + mStatus status; + mDNS_Lock(m); + status = mDNS_StartNATOperation_internal(m, traversal); + mDNS_Unlock(m); + return(status); } -mDNSlocal void SendInitialPMapReq(mDNS *m, NATTraversalInfo *info) +mDNSexport mStatus mDNS_StopNATOperation(mDNS *m, NATTraversalInfo *traversal) { - if (!m->uDNS_info.Router.ip.v4.NotAnInteger) - { - debugf("No router. Will retry NAT traversal in %ld seconds", NATMAP_INIT_RETRY); - info->retry = mDNSPlatformTimeNow(m) + NATMAP_INIT_RETRY; - info->RetryInterval = NATMAP_INIT_RETRY; - return; - } - SendNATMsg(info, m); - return; + mStatus status; + mDNS_Lock(m); + status = mDNS_StopNATOperation_internal(m, traversal); + mDNS_Unlock(m); + return(status); } -mDNSlocal void StartNATPortMap(mDNS *m, ServiceRecordSet *srs) +// *************************************************************************** +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - +#pragma mark - Long-Lived Queries +#endif + +mDNSlocal void StartLLQPolling(mDNS *const m, DNSQuestion *q) { - NATOp_t op; - NATTraversalInfo *info; - - if (DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp")) op = NATOp_MapTCP; - else if (DomainContainsLabelString(srs->RR_PTR.resrec.name, "_udp")) op = NATOp_MapUDP; - else { LogMsg("StartNATPortMap: could not determine transport protocol of service %##s", srs->RR_SRV.resrec.name->c); goto error; } - - if (srs->uDNS_info.NATinfo) { LogMsg("Error: StartNATPortMap - NAT info already initialized!"); FreeNATInfo(m, srs->uDNS_info.NATinfo); } - info = AllocNATInfo(m, op, ReceivePortMapReply); - srs->uDNS_info.NATinfo = info; - info->reg.ServiceRegistration = srs; - info->state = NATState_Request; - - FormatPortMaprequest(info, srs->RR_SRV.resrec.rdata->u.srv.port); - SendInitialPMapReq(m, info); - return; - - error: - startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs); + LogOperation("StartLLQPolling: %##s", q->qname.c); + q->state = LLQ_Poll; + q->ThisQInterval = LLQ_POLL_INTERVAL; + q->LastQTime = m->timenow - q->ThisQInterval; // trigger immediate poll + SetNextQueryTime(m, q); } -mDNSlocal void DeleteNATPortMapping(mDNS *m, NATTraversalInfo *nat, ServiceRecordSet *srs) +// Forward reference +mDNSlocal void LLQNatMapComplete(mDNS *m, NATTraversalInfo *n); + +mDNSlocal void StartLLQNatMap(mDNS *m, DNSQuestion *q) { - if (nat->state == NATState_Established) // let other edge-case states expire for simplicity - { - // zero lease - nat->request.PortReq.lease.NotAnInteger = 0; - nat->state = NATState_Request; - SendNATMsg(nat, m); - } -#ifdef _LEGACY_NAT_TRAVERSAL_ - else if (nat->state == NATState_Legacy) - { - mStatus err = mStatus_NoError; - mDNSBool tcp = srs ? DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp") : mDNSfalse; - err = LNT_UnmapPort(nat->PublicPort, tcp); - if (err) LogMsg("Legacy NAT Traversal - unmap request failed with error %ld", err); - } -#else - (void)srs; // unused -#endif // _LEGACY_NAT_TRAVERSAL_ + LogOperation("StartLLQNatMap: LLQ_NatMapWaitUDP"); + mDNSPlatformMemZero(&q->NATInfoUDP, sizeof(NATTraversalInfo)); + q->NATInfoUDP.IntPort = q->NATInfoUDP.RequestedPort = m->UnicastPort4; + q->NATInfoUDP.Protocol = NATOp_MapUDP; + q->NATInfoUDP.clientCallback = LLQNatMapComplete; + q->NATInfoUDP.clientContext = q; // Must be set non-null so we know this NATTraversalInfo object is in use + mDNS_StartNATOperation_internal(m, &q->NATInfoUDP); } -mDNSlocal void StartLLQNatMap(mDNS *m) +mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, const DNSQuestion *const question, const LLQOptData *const data, mDNSBool includeQuestion) { - NATTraversalInfo *info = AllocNATInfo(m, NATOp_MapUDP, ReceivePortMapReply); - uDNS_GlobalInfo *u = &m->uDNS_info; - - u->LLQNatInfo = info; + AuthRecord rr; + ResourceRecord *opt = &rr.resrec; + rdataOPT *optRD; - info->reg.RecordRegistration = mDNSNULL; - info->reg.ServiceRegistration = mDNSNULL; - info->state = NATState_Request; - FormatPortMaprequest(info, m->UnicastPort4); - SendInitialPMapReq(m, info); - return; - } + //!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section + if (includeQuestion) + { + ptr = putQuestion(msg, ptr, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass); + if (!ptr) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL; } + } + // locate OptRR if it exists, set pointer to end + // !!!KRS implement me -// if LLQ NAT context unreferenced, delete the mapping -mDNSlocal void CheckForUnreferencedLLQMapping(mDNS *m) - { - NATTraversalInfo *nat = m->uDNS_info.LLQNatInfo; - DNSQuestion *q; - - if (!nat) return; + // format opt rr (fields not specified are zero-valued) + mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL); + opt->rdlength = LLQ_OPT_RDLEN; + opt->rdestimate = LLQ_OPT_RDLEN; - for (q = m->uDNS_info.ActiveQueries; q; q = q->next) - if (q->LongLived && q->uDNS_info.llq->NATMap) return; + optRD = &rr.resrec.rdata->u.opt; + optRD->opt = kDNSOpt_LLQ; + optRD->optlen = LLQ_OPTLEN; + optRD->OptData.llq = *data; + ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.numAdditionals, opt, 0); + if (!ptr) { LogMsg("ERROR: putLLQ - PutResourceRecordTTLJumbo"); return mDNSNULL; } - //to avoid race condition if we need to recreate before this finishes, we do one-shot deregistration - if (nat->state == NATState_Established || nat->state == NATState_Legacy) - DeleteNATPortMapping(m, nat, mDNSNULL); // for simplicity we allow other states to expire - FreeNATInfo(m, nat); // note: this clears the global LLQNatInfo pointer + return ptr; } - // *************************************************************************** -#if COMPILER_LIKES_PRAGMA_MARK -#pragma mark - host name and interface management -#endif +mDNSlocal mStatus constructQueryMsg(DNSMessage *msg, mDNSu8 **endPtr, DNSQuestion *const question) + { + InitializeDNSMessage(&msg->h, question->TargetQID, uQueryFlags); -// if we ever want to refine support for multiple hostnames, we can add logic matching service names to a particular hostname -// for now, we grab the first registered DynDNS name, if any, or a static name we learned via a reverse-map query -mDNSlocal mDNSBool GetServiceTarget(uDNS_GlobalInfo *u, AuthRecord *srv, domainname *dst) + *endPtr = putQuestion(msg, msg->data, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass); + if (!*endPtr) + { + LogMsg("ERROR: Unicast query out of space in packet"); + return mStatus_UnknownErr; + } + return mStatus_NoError; + } + +// Normally called with llq set. +// May be called with llq NULL, when retransmitting a lost Challenge Response +mDNSlocal void sendChallengeResponse(mDNS *const m, DNSQuestion *const q, const LLQOptData *llq) { - uDNS_HostnameInfo *hi = u->Hostnames; - (void)srv; // unused + mDNSu8 *responsePtr = m->omsg.data; + mStatus err; + LLQOptData llqBuf; - dst->c[0] = 0; - while (hi) + if (q->ntries++ == kLLQ_MAX_TRIES) { - if (hi->arv4 && (hi->arv4->uDNS_info.state == regState_Registered || hi->arv4->uDNS_info.state == regState_Refresh)) - { - AssignDomainName(dst, hi->arv4->resrec.name); - return mDNStrue; - } - if (hi->arv6 && (hi->arv6->uDNS_info.state == regState_Registered || hi->arv6->uDNS_info.state == regState_Refresh)) - { - AssignDomainName(dst, hi->arv4->resrec.name); - return mDNStrue; - } - hi = hi->next; + LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s Will re-try in %d minutes", + kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60); + q->state = LLQ_Retry; + q->LastQTime = m->timenow; + q->ThisQInterval = (kLLQ_DEF_RETRY * mDNSPlatformOneSecond); + SetNextQueryTime(m, q); + // !!!KRS give a callback error in these cases? + return; } - if (u->StaticHostname.c[0]) { AssignDomainName(dst, &u->StaticHostname); return mDNStrue; } - return mDNSfalse; - } + if (!llq) // Retransmission: need to make a new LLQOptData + { + llqBuf.vers = kLLQ_Vers; + llqBuf.llqOp = kLLQOp_Setup; + llqBuf.err = LLQErr_NoError; + llqBuf.id = q->id; + llqBuf.llqlease = q->origLease; + llq = &llqBuf; + } -mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs) - { - uDNS_GlobalInfo *u = &m->uDNS_info; - ExtraResourceRecord *e; + q->LastQTime = m->timenow; + q->ThisQInterval = q->tcp ? 0 : (kLLQ_INIT_RESEND * q->ntries * mDNSPlatformOneSecond); // If using TCP, don't need to retransmit + SetNextQueryTime(m, q); - // Target change if: - // We have a target and were previously waiting for one, or - // We had a target and no longer do, or - // The target has changed + if (constructQueryMsg(&m->omsg, &responsePtr, q)) goto error; + responsePtr = putLLQ(&m->omsg, responsePtr, q, llq, mDNSfalse); + if (!responsePtr) { LogMsg("ERROR: sendChallengeResponse - putLLQ"); goto error; } - domainname newtarget; - domainname *curtarget = &srs->RR_SRV.resrec.rdata->u.srv.target; - mDNSBool HaveTarget = GetServiceTarget(u, &srs->RR_SRV, &newtarget); - mDNSBool TargetChanged = (HaveTarget && srs->uDNS_info.state == regState_NoTarget) || (curtarget->c[0] && !HaveTarget) || !SameDomainName(curtarget, &newtarget); - mDNSBool HaveZoneData = srs->uDNS_info.ns.ip.v4.NotAnInteger ? mDNStrue : mDNSfalse; - - // Nat state change if: - // We were behind a NAT, and now we are behind a new NAT, or - // We're not behind a NAT but our port was previously mapped to a different public port - // We were not behind a NAT and now we are - - NATTraversalInfo *nat = srs->uDNS_info.NATinfo; - mDNSIPPort port = srs->RR_SRV.resrec.rdata->u.srv.port; - mDNSBool NATChanged = mDNSfalse; - mDNSBool NowBehindNAT = port.NotAnInteger && IsPrivateV4Addr(&u->AdvertisedV4); - mDNSBool WereBehindNAT = nat != mDNSNULL; - mDNSBool NATRouterChanged = nat && nat->Router.ip.v4.NotAnInteger != u->Router.ip.v4.NotAnInteger; - mDNSBool PortWasMapped = nat && (nat->state == NATState_Established || nat->state == NATState_Legacy) && nat->PublicPort.NotAnInteger != port.NotAnInteger; - - if (WereBehindNAT && NowBehindNAT && NATRouterChanged) NATChanged = mDNStrue; - else if (!NowBehindNAT && PortWasMapped) NATChanged = mDNStrue; - else if (!WereBehindNAT && NowBehindNAT) NATChanged = mDNStrue; - - if (!TargetChanged && !NATChanged) return; + //LogOperation("sendChallengeResponse %#a:%d %d %p %d", &q->servAddr, mDNSVal16(q->servPort), q->tcp, q->AuthInfo, responsePtr - (mDNSu8 *)&m->omsg); + err = mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, q->AuthInfo); + if (err) debugf("ERROR: sendChallengeResponse - mDNSSendDNSMessage returned %ld", err); + // on error, we procede as normal and retry after the appropriate interval - debugf("UpdateSRV (%##s) HadZoneData=%d, TargetChanged=%d, HaveTarget=%d, NowBehindNAT=%d, WereBehindNAT=%d, NATRouterChanged=%d, PortWasMapped=%d", - srs->RR_SRV.resrec.name->c, HaveZoneData, TargetChanged, HaveTarget, NowBehindNAT, WereBehindNAT, NATRouterChanged, PortWasMapped); - - switch(srs->uDNS_info.state) - { - case regState_FetchingZoneData: - case regState_Cancelled: - case regState_DeregPending: - case regState_DeregDeferred: - case regState_Unregistered: - case regState_NATMap: - case regState_ExtraQueued: - // In these states, the SRV has either not yet been registered (it will get up-to-date information when it is) - // or is in the process of, or has already been, deregistered - return; - - case regState_Pending: - case regState_Refresh: - case regState_UpdatePending: - // let the in-flight operation complete before updating - srs->uDNS_info.SRVUpdateDeferred = mDNStrue; - return; - - case regState_NATError: - if (!NATChanged) return; - // if nat changed, register if we have a target (below) + return; - case regState_NoTarget: - if (HaveTarget) - { - debugf("UpdateSRV: %s service %##s", HaveZoneData ? (NATChanged && NowBehindNAT ? "Starting Port Map for" : "Registering") : "Getting Zone Data for", srs->RR_SRV.resrec.name->c); - if (!HaveZoneData) - { - srs->uDNS_info.state = regState_FetchingZoneData; - startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs); - } - else - { - if (nat && (NATChanged || !NowBehindNAT)) { srs->uDNS_info.NATinfo = mDNSNULL; FreeNATInfo(m, nat); } - if (NATChanged && NowBehindNAT) { srs->uDNS_info.state = regState_NATMap; StartNATPortMap(m, srs); } - else SendServiceRegistration(m, srs); - } - } - return; - - case regState_Registered: - // target or nat changed. deregister service. upon completion, we'll look for a new target - debugf("UpdateSRV: SRV record changed for service %##s - deregistering (will re-register with new SRV)", srs->RR_SRV.resrec.name->c); - for (e = srs->Extras; e; e = e->next) e->r.uDNS_info.state = regState_ExtraQueued; // extra will be re-registed if the service is re-registered - srs->uDNS_info.SRVChanged = mDNStrue; - SendServiceDeregistration(m, srs); - return; - } + error: + q->state = LLQ_Error; } -mDNSlocal void UpdateSRVRecords(mDNS *m) +mDNSlocal void recvSetupResponse(mDNS *const m, mDNSu8 rcode, DNSQuestion *const q, const rdataOPT *opt) { - ServiceRecordSet *srs; + mStatus err = mStatus_NoError; - for (srs = m->uDNS_info.ServiceRegistrations; srs; srs = srs->next) UpdateSRV(m, srs); - } + if (rcode && rcode != kDNSFlag1_RC_NXDomain) + { LogMsg("ERROR: recvSetupResponse %##s - rcode && rcode != kDNSFlag1_RC_NXDomain", q->qname.c); goto fail; } -mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result) - { - uDNS_HostnameInfo *hi = (uDNS_HostnameInfo *)rr->RecordContext; - - if (result == mStatus_MemFree) + if (opt->OptData.llq.llqOp != kLLQOp_Setup) + { LogMsg("ERROR: recvSetupResponse %##s - bad op %d", q->qname.c, opt->OptData.llq.llqOp); goto fail; } + + if (opt->OptData.llq.vers != kLLQ_Vers) + { LogMsg("ERROR: recvSetupResponse %##s - bad vers %d", q->qname.c, opt->OptData.llq.vers); goto fail; } + + if (q->state == LLQ_InitialRequest) { - if (hi) + const LLQOptData *const llq = &opt->OptData.llq; + //LogOperation("Got LLQ_InitialRequest"); + + switch(llq->err) { - if (hi->arv4 == rr) hi->arv4 = mDNSNULL; - else if (hi->arv4 == rr) hi->arv6 = mDNSNULL; - rr->RecordContext = mDNSNULL; - if (!hi->arv4 && !hi->arv6) ufree(hi); // free hi when both v4 and v6 AuthRecs deallocated + case LLQErr_NoError: break; + case LLQErr_ServFull: + LogMsg("recvSetupResponse - received ServFull from server for LLQ %##s Retry in %lu sec", q->qname.c, llq->llqlease); + q->LastQTime = m->timenow; + q->ThisQInterval = ((mDNSs32)llq->llqlease * mDNSPlatformOneSecond); + q->state = LLQ_Retry; + SetNextQueryTime(m, q); + case LLQErr_Static: + q->state = LLQ_Static; + q->ThisQInterval = 0; + LogMsg("LLQ %##s: static", q->qname.c); + goto exit; + case LLQErr_FormErr: + LogMsg("ERROR: recvSetupResponse - received FormErr from server for LLQ %##s", q->qname.c); + goto error; + case LLQErr_BadVers: + LogMsg("ERROR: recvSetupResponse - received BadVers from server"); + goto error; + case LLQErr_UnknownErr: + LogMsg("ERROR: recvSetupResponse - received UnknownErr from server for LLQ %##s", q->qname.c); + goto error; + default: + LogMsg("ERROR: recvSetupResponse - received invalid error %d for LLQ %##s", llq->err, q->qname.c); + goto error; } - ufree(rr); - return; - } - if (result) + if (q->origLease != llq->llqlease) + debugf("recvSetupResponse: requested lease %lu, granted lease %lu", q->origLease, llq->llqlease); + + // cache expiration in case we go to sleep before finishing setup + q->origLease = llq->llqlease; + q->expire = m->timenow + ((mDNSs32)llq->llqlease * mDNSPlatformOneSecond); + + // update state + q->state = LLQ_SecondaryRequest; + q->id = llq->id; + // if (q->ntries == 1) goto exit; // Test for simulating loss of challenge response packet + q->ntries = 0; // first attempt to send response + + sendChallengeResponse(m, q, llq); + goto exit; + + error: + q->state = LLQ_Error; + goto exit; + } + + if (q->state == LLQ_SecondaryRequest) { - // don't unlink or free - we can retry when we get a new address/router - if (rr->resrec.rrtype == kDNSType_A) - LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.4a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv4); - else - LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.16a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv6); - if (!hi) { ufree(rr); return; } - if (rr->uDNS_info.state != regState_Unregistered) LogMsg("Error: HostnameCallback invoked with error code for record not in regState_Unregistered!"); + //LogOperation("Got LLQ_SecondaryRequest"); - if ((!hi->arv4 || hi->arv4->uDNS_info.state == regState_Unregistered) && - (!hi->arv6 || hi->arv6->uDNS_info.state == regState_Unregistered)) + // Fix this immediately if not sooner. Copy the id from the LLQOptData into our DNSQuestion struct. This is only + // an issue for private LLQs, because we skip parts 2 and 3 of the handshake. This is related to a bigger + // problem of the current implementation of TCP LLQ setup: we're not handling state transitions correctly + // if the server sends back SERVFULL or STATIC. + if (q->AuthInfo) { - // only deliver status if both v4 and v6 fail - rr->RecordContext = (void *)hi->StatusContext; - if (hi->StatusCallback) - hi->StatusCallback(m, rr, result); // client may NOT make API calls here - rr->RecordContext = (void *)hi; + LogOperation("Private LLQ_SecondaryRequest; copying id %08X%08X", opt->OptData.llq.id.l[0], opt->OptData.llq.id.l[1]); + q->id = opt->OptData.llq.id; } - return; + + if (opt->OptData.llq.err) { LogMsg("ERROR: recvSetupResponse %##s code %d from server", q->qname.c, opt->OptData.llq.err); q->state = LLQ_Error; goto fail; } + if (!mDNSSameOpaque64(&q->id, &opt->OptData.llq.id)) + { LogMsg("recvSetupResponse - ID changed. discarding"); goto exit; } // this can happen rarely (on packet loss + reordering) + q->expire = m->timenow + ((mDNSs32)opt->OptData.llq.llqlease * mDNSPlatformOneSecond ); + q->LastQTime = m->timenow; + q->ThisQInterval = ((mDNSs32)opt->OptData.llq.llqlease * (mDNSPlatformOneSecond / 2)); + q->origLease = opt->OptData.llq.llqlease; + q->state = LLQ_Established; + SetNextQueryTime(m, q); + goto exit; } - // register any pending services that require a target - UpdateSRVRecords(m); - - // Deliver success to client - if (!hi) { LogMsg("HostnameCallback invoked with orphaned address record"); return; } - if (rr->resrec.rrtype == kDNSType_A) - LogMsg("Registered hostname %##s IP %.4a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv4); - else - LogMsg("Registered hostname %##s IP %.16a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv6); - rr->RecordContext = (void *)hi->StatusContext; - if (hi->StatusCallback) - hi->StatusCallback(m, rr, result); // client may NOT make API calls here - rr->RecordContext = (void *)hi; - } + if (q->state == LLQ_Established) goto exit; -// register record or begin NAT traversal -mDNSlocal void AdvertiseHostname(mDNS *m, uDNS_HostnameInfo *h) - { - uDNS_GlobalInfo *u = &m->uDNS_info; - - if (u->AdvertisedV4.ip.v4.NotAnInteger && h->arv4->uDNS_info.state == regState_Unregistered) - { - if (IsPrivateV4Addr(&u->AdvertisedV4)) - StartGetPublicAddr(m, h->arv4); - else - { - LogMsg("Advertising %##s IP %.4a", h->arv4->resrec.name->c, &u->AdvertisedV4.ip.v4); - uDNS_RegisterRecord(m, h->arv4); - } - } - if (u->AdvertisedV6.ip.v6.b[0] && h->arv6->uDNS_info.state == regState_Unregistered) + LogMsg("ERROR: recvSetupResponse %##s - bad state %d", q->qname.c, q->state); + +fail: + err = mStatus_UnknownErr; + +exit: + + if (err) { - LogMsg("Advertising %##s IP %.16a", h->arv4->resrec.name->c, &u->AdvertisedV6.ip.v6); - uDNS_RegisterRecord(m, h->arv6); + LogOperation("recvSetupResponse error %d ", err); + StartLLQPolling(m, q); } } -mDNSlocal void FoundStaticHostname(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) +// Returns mDNStrue if mDNSCoreReceiveResponse should treat this packet as a series of add/remove instructions (like an mDNS response) +// Returns mDNSfalse if mDNSCoreReceiveResponse should treat this as a single authoritative result (like a normal unicast DNS response) +mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport) { - const domainname *pktname = &answer->rdata->u.name; - domainname *storedname = &m->uDNS_info.StaticHostname; - uDNS_HostnameInfo *h = m->uDNS_info.Hostnames; - - (void)question; - - debugf("FoundStaticHostname: %##s -> %##s (%s)", question->qname.c, answer->rdata->u.name.c, AddRecord ? "added" : "removed"); - if (AddRecord && !SameDomainName(pktname, storedname)) + DNSQuestion pktQ, *q; + if (msg->h.numQuestions && getQuestion(msg, msg->data, end, 0, &pktQ)) { - AssignDomainName(storedname, pktname); - while (h) + const rdataOPT *opt = GetLLQOptData(m, msg, end); + if (opt) { - if ((h->arv4 && (h->arv4->uDNS_info.state == regState_FetchingZoneData || h->arv4->uDNS_info.state == regState_Pending || h->arv4->uDNS_info.state == regState_NATMap)) || - (h->arv6 && (h->arv6->uDNS_info.state == regState_FetchingZoneData || h->arv6->uDNS_info.state == regState_Pending))) + for (q = m->Questions; q; q = q->next) { - // if we're in the process of registering a dynamic hostname, delay SRV update so we don't have to reregister services if the dynamic name succeeds - m->uDNS_info.DelaySRVUpdate = mDNStrue; - m->uDNS_info.NextSRVUpdate = mDNSPlatformTimeNow(m) + (5 * mDNSPlatformOneSecond); - return; + if (q->LongLived && q->qtype == pktQ.qtype && q->qnamehash == pktQ.qnamehash && SameDomainName(&q->qname, &pktQ.qname)) + { + debugf("uDNS_recvLLQResponse found %##s (%s) %d %#a %#a %X %X %X %X %d", + q->qname.c, DNSTypeName(q->qtype), q->state, srcaddr, &q->servAddr, + opt->OptData.llq.id.l[0], opt->OptData.llq.id.l[1], q->id.l[0], q->id.l[1], opt->OptData.llq.llqOp); + if (q->state == LLQ_Poll) + { + m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it + return uDNS_LLQ_Poll; + } + else if (q->state == LLQ_Established || (q->state == LLQ_Refresh && msg->h.numAnswers)) + { + if (opt->OptData.llq.llqOp == kLLQOp_Event && mDNSSameOpaque64(&opt->OptData.llq.id, &q->id)) + { + mDNSu8 *ackEnd; + if (q->LongLived && q->state == LLQ_Poll && !mDNSIPPortIsZero(q->servPort)) q->ThisQInterval = LLQ_POLL_INTERVAL; + else if (q->ThisQInterval < MAX_UCAST_POLL_INTERVAL) q->ThisQInterval = MAX_UCAST_POLL_INTERVAL; + //debugf("Sending LLQ ack for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + InitializeDNSMessage(&m->omsg.h, msg->h.id, ResponseFlags); + ackEnd = putLLQ(&m->omsg, m->omsg.data, mDNSNULL, &opt->OptData.llq, mDNSfalse); + if (ackEnd) mDNSSendDNSMessage(m, &m->omsg, ackEnd, mDNSInterface_Any, srcaddr, srcport, mDNSNULL, mDNSNULL); + m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it + return uDNS_LLQ_Events; + } + } + if (mDNSSameOpaque16(msg->h.id, q->TargetQID)) + { + if (opt->OptData.llq.llqOp == kLLQOp_Refresh && q->state == LLQ_Refresh && msg->h.numAdditionals && !msg->h.numAnswers && mDNSSameOpaque64(&opt->OptData.llq.id, &q->id)) + { + if (opt->OptData.llq.err != LLQErr_NoError) LogMsg("recvRefreshReply: received error %d from server", opt->OptData.llq.err); + else + { + //LogOperation("Received refresh confirmation ntries %d for %##s (%s)", q->ntries, q->qname.c, DNSTypeName(q->qtype)); + GrantCacheExtensions(m, q, opt->OptData.llq.llqlease); + q->expire = q->LastQTime + ((mDNSs32)opt->OptData.llq.llqlease * mDNSPlatformOneSecond ); + q->ThisQInterval = ((mDNSs32)opt->OptData.llq.llqlease * (mDNSPlatformOneSecond/2)); + q->origLease = opt->OptData.llq.llqlease; + q->state = LLQ_Established; + } + m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it + return uDNS_LLQ_Events; + } + if (q->state < LLQ_Static) + { + if (mDNSSameAddress(srcaddr, &q->servAddr)) + { + LLQ_State oldstate = q->state; + recvSetupResponse(m, msg->h.flags.b[1] & kDNSFlag1_RC_Mask, q, opt); + m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it + //DumpPacket(m, msg, end); + // If this is our Ack+Answers packet resulting from a correct challenge response, then it's a full list + // of answers, and any cache answers we have that are not included in this packet need to be flushed + //LogMsg("uDNS_recvLLQResponse: recvSetupResponse state %d returning %d", oldstate, oldstate != LLQ_SecondaryRequest); + return (oldstate == LLQ_SecondaryRequest ? uDNS_LLQ_Setup : uDNS_LLQ_Events); + } + } + } + } } - h = h->next; + m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it + //LogMsg("uDNS_recvLLQResponse: returning 0"); } - UpdateSRVRecords(m); - } - else if (!AddRecord && SameDomainName(pktname, storedname)) - { - storedname->c[0] = 0; - UpdateSRVRecords(m); } + return uDNS_LLQ_Not; } -mDNSlocal void GetStaticHostname(mDNS *m) - { - char buf[MAX_ESCAPED_DOMAIN_NAME]; - DNSQuestion *q = &m->uDNS_info.ReverseMap; - mDNSu8 *ip = m->uDNS_info.AdvertisedV4.ip.v4.b; - mStatus err; - - if (m->uDNS_info.ReverseMapActive) - { - uDNS_StopQuery(m, q); - m->uDNS_info.ReverseMapActive = mDNSfalse; - } - - m->uDNS_info.StaticHostname.c[0] = 0; - if (!m->uDNS_info.AdvertisedV4.ip.v4.NotAnInteger) return; - ubzero(q, sizeof(*q)); - mDNS_snprintf(buf, MAX_ESCAPED_DOMAIN_NAME, "%d.%d.%d.%d.in-addr.arpa.", ip[3], ip[2], ip[1], ip[0]); - if (!MakeDomainNameFromDNSNameString(&q->qname, buf)) { LogMsg("Error: GetStaticHostname - bad name %s", buf); return; } +// Forward declaration +mDNSlocal void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease); - q->InterfaceID = mDNSInterface_Any; - q->Target = zeroAddr; - q->qtype = kDNSType_PTR; - q->qclass = kDNSClass_IN; - q->LongLived = mDNSfalse; - q->ExpectUnique = mDNSfalse; - q->ForceMCast = mDNSfalse; - q->QuestionCallback = FoundStaticHostname; - q->QuestionContext = mDNSNULL; - - err = uDNS_StartQuery(m, q); - if (err) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err); - else m->uDNS_info.ReverseMapActive = mDNStrue; - } +// Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.) +struct TCPSocket_struct { TCPSocketFlags flags; /* ... */ }; -mDNSlocal void AssignHostnameInfoAuthRecord(mDNS *m, uDNS_HostnameInfo *hi, int type) +// tcpCallback is called to handle events (e.g. connection opening and data reception) on TCP connections for +// Private DNS operations -- private queries, private LLQs, private record updates and private service updates +mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEstablished, mStatus err) { - AuthRecord **dst = (type == mDNSAddrType_IPv4 ? &hi->arv4 : &hi->arv6); - AuthRecord *ar = umalloc(sizeof(*ar)); - uDNS_GlobalInfo *u = &m->uDNS_info; - - if (type != mDNSAddrType_IPv4 && type != mDNSAddrType_IPv6) { LogMsg("ERROR: AssignHostnameInfoAuthRecord - bad type %d", type); return; } - if (!ar) { LogMsg("ERROR: AssignHostnameInfoAuthRecord - malloc"); return; } - - mDNS_SetupResourceRecord(ar, mDNSNULL, 0, type == mDNSAddrType_IPv4 ? kDNSType_A : kDNSType_AAAA, 1, kDNSRecordTypeKnownUnique, HostnameCallback, hi); - AssignDomainName(ar->resrec.name, &hi->fqdn); + tcpInfo_t *tcpInfo = (tcpInfo_t *)context; + mDNSBool closed = mDNSfalse; + mDNSu8 *end; + mDNS *m = tcpInfo->m; + DomainAuthInfo *AuthInfo = + tcpInfo->question ? tcpInfo->question->AuthInfo : + tcpInfo->srs ? GetAuthInfoForName(m, tcpInfo->srs->RR_SRV.resrec.name) : + tcpInfo->rr ? GetAuthInfoForName(m, tcpInfo->rr->resrec.name) : mDNSNULL; + + tcpInfo_t **backpointer = + tcpInfo->question ? &tcpInfo->question->tcp : + tcpInfo->srs ? &tcpInfo->srs->tcp : + tcpInfo->rr ? &tcpInfo->rr->tcp : mDNSNULL; + if (!backpointer) LogMsg("tcpCallback: Purpose of connection unidentified"); + else if (*backpointer != tcpInfo) + LogMsg("tcpCallback: %d backpointer %p incorrect tcpInfo %p question %p srs %p rr %p", + mDNSPlatformTCPGetFD(tcpInfo->sock), *backpointer, tcpInfo, tcpInfo->question, tcpInfo->srs, tcpInfo->rr); + + if (err) goto exit; - // only set RData if we have a valid IP - if (type == mDNSAddrType_IPv4 && u->AdvertisedV4.ip.v4.NotAnInteger) - { - if (u->MappedV4.ip.v4.NotAnInteger) ar->resrec.rdata->u.ipv4 = u->MappedV4.ip.v4; - else ar->resrec.rdata->u.ipv4 = u->AdvertisedV4.ip.v4; - } - else if (type == mDNSAddrType_IPv6 && u->AdvertisedV6.ip.v6.b[0]) - { - ar->resrec.rdata->u.ipv6 = u->AdvertisedV6.ip.v6; - } - - ar->uDNS_info.state = regState_Unregistered; - - if (*dst) + if (ConnectionEstablished) { - LogMsg("ERROR: AssignHostnameInfoAuthRecord - overwriting %s AuthRec", type == mDNSAddrType_IPv4 ? "IPv4" : "IPv6"); - unlinkAR(&u->RecordRegistrations, *dst); - (*dst)->RecordContext = mDNSNULL; // defensively clear backpointer to avoid doubly-referenced context - } - - *dst = ar; - } + // connection is established - send the message + if (tcpInfo->question && tcpInfo->question->LongLived && (tcpInfo->question->state == LLQ_Established || tcpInfo->question->state == LLQ_Refresh)) + { + //LogMsg("tcpCallback calling sendLLQRefresh %##s (%s)", tcpInfo->question->qname.c, DNSTypeName(tcpInfo->question->qtype)); + mDNS_Lock(m); + sendLLQRefresh(m, tcpInfo->question, tcpInfo->question->origLease); + mDNS_Unlock(m); + return; + } + else if (tcpInfo->question && tcpInfo->question->LongLived && tcpInfo->question->state != LLQ_Poll) + { + LLQOptData llqData; // set llq rdata + llqData.vers = kLLQ_Vers; + llqData.llqOp = kLLQOp_Setup; + llqData.err = LLQErr_NoError; + llqData.err = mDNSVal16(tcpInfo->question->eventPort); // Tell server our external NAT-mapped UDP port + if (llqData.err == 0) llqData.err = 5353; // If not using NAT, then we need events sent directly to 5353 + LogOperation("tcpCallback: eventPort %d", llqData.err); + llqData.id = zeroOpaque64; + llqData.llqlease = kLLQ_DefLease; + InitializeDNSMessage(&tcpInfo->request.h, tcpInfo->question->TargetQID, uQueryFlags); + //LogMsg("tcpCallback: putLLQ %p", AuthInfo); + end = putLLQ(&tcpInfo->request, tcpInfo->request.data, tcpInfo->question, &llqData, mDNStrue); + + if (!end) { LogMsg("ERROR: tcpCallback - putLLQ"); err = mStatus_UnknownErr; goto exit; } + } + else if (tcpInfo->question) + { + err = constructQueryMsg(&tcpInfo->request, &end, tcpInfo->question); + if (err) { LogMsg("ERROR: tcpCallback: constructQueryMsg - %ld", err); err = mStatus_UnknownErr; goto exit; } + } + else + end = ((mDNSu8*) &tcpInfo->request) + tcpInfo->requestLen; + err = mDNSSendDNSMessage(m, &tcpInfo->request, end, mDNSInterface_Any, &tcpInfo->Addr, tcpInfo->Port, sock, AuthInfo); -// Deregister hostnames and register new names for each host domain with the current global -// values for the hostlabel and primary IP address -mDNSlocal void UpdateHostnameRegistrations(mDNS *m) - { - uDNS_GlobalInfo *u = &m->uDNS_info; - uDNS_HostnameInfo *i; + if (err) { debugf("ERROR: tcpCallback: mDNSSendDNSMessage - %ld", err); err = mStatus_UnknownErr; goto exit; } - for (i = u->Hostnames; i; i = i->next) - { - if (i->arv4 && i->arv4->uDNS_info.state != regState_Unregistered && - i->arv4->resrec.rdata->u.ipv4.NotAnInteger != u->AdvertisedV4.ip.v4.NotAnInteger && - i->arv4->resrec.rdata->u.ipv4.NotAnInteger !=u->MappedV4.ip.v4.NotAnInteger) + // Record time we sent this question + if (tcpInfo->question) { - uDNS_DeregisterRecord(m, i->arv4); - i->arv4 = mDNSNULL; + mDNS_Lock(m); + tcpInfo->question->LastQTime = m->timenow; + tcpInfo->question->ThisQInterval = MAX_UCAST_POLL_INTERVAL; + SetNextQueryTime(m, tcpInfo->question); + mDNS_Unlock(m); } - if (i->arv6 && !mDNSPlatformMemSame(i->arv6->resrec.rdata->u.ipv6.b, u->AdvertisedV6.ip.v6.b, 16) && i->arv6->uDNS_info.state != regState_Unregistered) + } + else + { + long n; + if (tcpInfo->nread < 2) // First read the two-byte length preceeding the DNS message { - uDNS_DeregisterRecord(m, i->arv6); - i->arv6 = mDNSNULL; - } - - if (!i->arv4 && u->AdvertisedV4.ip.v4.NotAnInteger) AssignHostnameInfoAuthRecord(m, i, mDNSAddrType_IPv4); - else if (i->arv4 && i->arv4->uDNS_info.state == regState_Unregistered) i->arv4->resrec.rdata->u.ipv4 = u->AdvertisedV4.ip.v4; // simply overwrite unregistered - if (!i->arv6 && u->AdvertisedV6.ip.v6.b[0]) AssignHostnameInfoAuthRecord(m, i, mDNSAddrType_IPv6); - else if (i->arv6 &&i->arv6->uDNS_info.state == regState_Unregistered) i->arv6->resrec.rdata->u.ipv6 = u->AdvertisedV6.ip.v6; + mDNSu8 *lenptr = (mDNSu8 *)&tcpInfo->replylen; + n = mDNSPlatformReadTCP(sock, lenptr + tcpInfo->nread, 2 - tcpInfo->nread, &closed); + if (n < 0) { LogMsg("ERROR:tcpCallback - attempt to read message length failed (%d)", n); err = mStatus_ConnFailed; goto exit; } + else if (closed) + { + // It's perfectly fine for this socket to close after the first reply. The server might + // be sending gratuitous replies using UDP and doesn't have a need to leave the TCP socket open. + // We'll only log this event if we've never received a reply before. + // BIND 9 appears to close an idle connection after 30 seconds. + if (tcpInfo->numReplies == 0) LogMsg("ERROR: socket closed prematurely %d", tcpInfo->nread); + err = mStatus_ConnFailed; + goto exit; + } - AdvertiseHostname(m, i); - } - } + tcpInfo->nread += n; + if (tcpInfo->nread < 2) goto exit; -mDNSexport void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext) - { - uDNS_GlobalInfo *u = &m->uDNS_info; - uDNS_HostnameInfo *ptr, *new; + tcpInfo->replylen = (mDNSu16)((mDNSu16)lenptr[0] << 8 | lenptr[1]); + if (tcpInfo->replylen < sizeof(DNSMessageHeader)) + { LogMsg("ERROR: tcpCallback - length too short (%d bytes)", tcpInfo->replylen); err = mStatus_UnknownErr; goto exit; } - mDNS_Lock(m); + tcpInfo->reply = mDNSPlatformMemAllocate(tcpInfo->replylen); + if (!tcpInfo->reply) { LogMsg("ERROR: tcpCallback - malloc failed"); err = mStatus_NoMemoryErr; goto exit; } + } - // check if domain already registered - for (ptr = u->Hostnames; ptr; ptr = ptr->next) - { - if (SameDomainName(fqdn, &ptr->fqdn)) - { LogMsg("Host Domain %##s already in list", fqdn->c); goto exit; } - } + n = mDNSPlatformReadTCP(sock, ((char *)tcpInfo->reply) + (tcpInfo->nread - 2), tcpInfo->replylen - (tcpInfo->nread - 2), &closed); - // allocate and format new address record - new = umalloc(sizeof(*new)); - if (!new) { LogMsg("ERROR: mDNS_AddDynDNSHostname - malloc"); goto exit; } - ubzero(new, sizeof(*new)); - new->next = u->Hostnames; - u->Hostnames = new; - - AssignDomainName(&new->fqdn, fqdn); - new->StatusCallback = StatusCallback; - new->StatusContext = StatusContext; + if (n < 0) { LogMsg("ERROR: tcpCallback - read returned %d", n); err = mStatus_ConnFailed; goto exit; } + else if (closed) { LogMsg("ERROR: socket closed prematurely %d", tcpInfo->nread); err = mStatus_ConnFailed; goto exit; } - if (u->AdvertisedV4.ip.v4.NotAnInteger) AssignHostnameInfoAuthRecord(m, new, mDNSAddrType_IPv4); - else new->arv4 = mDNSNULL; - if (u->AdvertisedV6.ip.v6.b[0]) AssignHostnameInfoAuthRecord(m, new, mDNSAddrType_IPv6); - else new->arv6 = mDNSNULL; + tcpInfo->nread += n; + + if ((tcpInfo->nread - 2) == tcpInfo->replylen) + { + AuthRecord *rr = tcpInfo->rr; + DNSMessage *reply = tcpInfo->reply; + mDNSu8 *end = (mDNSu8 *)tcpInfo->reply + tcpInfo->replylen; + mDNSAddr Addr = tcpInfo->Addr; + mDNSIPPort Port = tcpInfo->Port; + tcpInfo->numReplies++; + tcpInfo->reply = mDNSNULL; // Detach reply buffer from tcpInfo_t, to make sure client callback can't cause it to be disposed + tcpInfo->nread = 0; + tcpInfo->replylen = 0; + + // If we're going to dispose this connection, do it FIRST, before calling client callback + if (!tcpInfo->question || !tcpInfo->question->LongLived) { *backpointer = mDNSNULL; DisposeTCPConn(tcpInfo); } + + if (rr && rr->resrec.RecordType == kDNSRecordTypeDeregistering) + { + mDNS_Lock(m); + LogOperation("tcpCallback: CompleteDeregistration %s", ARDisplayString(m, rr)); + CompleteDeregistration(m, rr); // Don't touch rr after this + mDNS_Unlock(m); + } + else + mDNSCoreReceive(m, reply, end, &Addr, Port, (sock->flags & kTCPSocketFlags_UseTLS) ? (mDNSAddr *)1 : mDNSNULL, zeroIPPort, 0); + // USE CAUTION HERE: Invoking mDNSCoreReceive may have caused the environment to change, including canceling this operation itself + + mDNSPlatformMemFree(reply); + return; + } + } - if (u->AdvertisedV6.ip.v6.b[0] || u->AdvertisedV4.ip.v4.NotAnInteger) AdvertiseHostname(m, new); - exit: - mDNS_Unlock(m); - } -mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn) - { - uDNS_GlobalInfo *u = &m->uDNS_info; - uDNS_HostnameInfo **ptr = &u->Hostnames; + if (err) + { + // Clear client backpointer FIRST -- that way if one of the callbacks cancels its operation + // we won't end up double-disposing our tcpInfo_t + *backpointer = mDNSNULL; - mDNS_Lock(m); + if (tcpInfo->question) + { + DNSQuestion *q = tcpInfo->question; + mDNS_Lock(m); // Need to grab the lock to get m->timenow + if (q->ThisQInterval == 0 || q->LastQTime + q->ThisQInterval - m->timenow > MAX_UCAST_POLL_INTERVAL) + { + q->LastQTime = m->timenow; + q->ThisQInterval = MAX_UCAST_POLL_INTERVAL; + SetNextQueryTime(m, q); + } + mDNS_Unlock(m); + // ConnFailed is actually okay. It just means that the server closed the connection but the LLQ is still okay. + // If the error isn't ConnFailed, then the LLQ is in bad shape. + if (err != mStatus_ConnFailed) tcpInfo->question->state = LLQ_Error; + } - while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next; - if (!*ptr) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn->c); - else - { - uDNS_HostnameInfo *hi = *ptr; - *ptr = (*ptr)->next; // unlink - if (hi->arv4) + if (tcpInfo->rr) { - hi->arv4->RecordContext = mDNSNULL; // about to free wrapper struct - if (hi->arv4->uDNS_info.state != regState_Unregistered) uDNS_DeregisterRecord(m, hi->arv4); - else { ufree(hi->arv4); hi->arv4 = mDNSNULL; } + mDNSBool deregPending = (tcpInfo->rr->state == regState_DeregPending) ? mDNStrue : mDNSfalse; + + UnlinkAuthRecord(m, tcpInfo->rr); + tcpInfo->rr->state = regState_Unregistered; + + if (!deregPending) + { + // Right now tcpCallback does not run holding the lock, so no need to drop the lock + //mDNS_DropLockBeforeCallback(); + if (tcpInfo->rr->RecordCallback) + tcpInfo->rr->RecordCallback(m, tcpInfo->rr, err); + //mDNS_ReclaimLockAfterCallback(); + // NOTE: not safe to touch any client structures here -- + // once we issue the callback, client is free to reuse or deallocate the srs memory + } } - if (hi->arv6) + + if (tcpInfo->srs) { - hi->arv6->RecordContext = mDNSNULL; // about to free wrapper struct - if (hi->arv6->uDNS_info.state != regState_Unregistered) uDNS_DeregisterRecord(m, hi->arv6); - else { ufree(hi->arv6); hi->arv6 = mDNSNULL; } + mDNSBool deregPending = (tcpInfo->srs->state == regState_DeregPending) ? mDNStrue : mDNSfalse; + + unlinkSRS(m, tcpInfo->srs); + tcpInfo->srs->state = regState_Unregistered; + + if (!deregPending) + { + // Right now tcpCallback does not run holding the lock, so no need to drop the lock + //mDNS_DropLockBeforeCallback(); + tcpInfo->srs->ServiceCallback(m, tcpInfo->srs, err); + //mDNS_ReclaimLockAfterCallback(); + // NOTE: not safe to touch any client structures here -- + // once we issue the callback, client is free to reuse or deallocate the srs memory + } } - ufree(hi); + + DisposeTCPConn(tcpInfo); } - UpdateSRVRecords(m); - mDNS_Unlock(m); } -mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router) +mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, + TCPSocketFlags flags, const mDNSAddr *const Addr, const mDNSIPPort Port, + DNSQuestion *const question, ServiceRecordSet *const srs, AuthRecord *const rr) { - uDNS_GlobalInfo *u = &m->uDNS_info; - mDNSBool v4Changed, v6Changed, RouterChanged; - - if (v4addr && v4addr->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo V4 address - incorrect type. Discarding."); return; } - if (v6addr && v6addr->type != mDNSAddrType_IPv6) { LogMsg("mDNS_SetPrimaryInterfaceInfo V6 address - incorrect type. Discarding."); return; } - if (router && router->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo passed non-V4 router. Discarding."); return; } + mStatus err; + mDNSIPPort srcport = zeroIPPort; + tcpInfo_t *info = (tcpInfo_t *)mDNSPlatformMemAllocate(sizeof(tcpInfo_t)); + if (!info) { LogMsg("ERROR: MakeTCP - memallocate failed"); return(mDNSNULL); } + + mDNSPlatformMemZero(info, sizeof(tcpInfo_t)); + info->m = m; + if (msg) + { + info->request = *msg; + info->requestLen = (int) (end - ((mDNSu8*)msg)); + } + info->question = question; + info->srs = srs; + info->rr = rr; + info->Addr = *Addr; + info->Port = Port; + + info->sock = mDNSPlatformTCPSocket(m, flags, &srcport); + if (!info->sock) { LogMsg("SendServiceRegistration: uanble to create TCP socket"); mDNSPlatformMemFree(info); return(mDNSNULL); } + err = mDNSPlatformTCPConnect(info->sock, Addr, Port, 0, tcpCallback, info); + + if (err == mStatus_ConnEstablished) { tcpCallback(info->sock, info, mDNStrue, mStatus_NoError); } + else if (err != mStatus_ConnPending ) { LogMsg("MakeTCPConnection: connection failed"); mDNSPlatformMemFree(info); return(mDNSNULL); } + return(info); + } - mDNS_Lock(m); +mDNSexport void DisposeTCPConn(struct tcpInfo_t *tcp) + { + mDNSPlatformTCPCloseConnection(tcp->sock); + if (tcp->reply) mDNSPlatformMemFree(tcp->reply); + mDNSPlatformMemFree(tcp); + } - v4Changed = (v4addr ? v4addr->ip.v4.NotAnInteger : 0) != u->AdvertisedV4.ip.v4.NotAnInteger; - v6Changed = v6addr ? !mDNSPlatformMemSame(v6addr, &u->AdvertisedV6, sizeof(*v6addr)) : (u->AdvertisedV6.ip.v6.b[0] != 0); - RouterChanged = (router ? router->ip.v4.NotAnInteger : 0) != u->Router.ip.v4.NotAnInteger; - -#if MDNS_DEBUGMSGS - if (v4addr && (v4Changed || RouterChanged)) - LogMsg("mDNS_SetPrimaryInterfaceInfo: address changed from %d.%d.%d.%d to %d.%d.%d.%d:%d", - u->AdvertisedV4.ip.v4.b[0], u->AdvertisedV4.ip.v4.b[1], u->AdvertisedV4.ip.v4.b[2], u->AdvertisedV4.ip.v4.b[3], - v4addr->ip.v4.b[0], v4addr->ip.v4.b[1], v4addr->ip.v4.b[2], v4addr->ip.v4.b[3]); -#endif // MDNS_DEBUGMSGS - - if ((v4Changed || RouterChanged) && u->MappedV4.ip.v4.NotAnInteger) u->MappedV4.ip.v4.NotAnInteger = 0; - if (v4addr) u->AdvertisedV4 = *v4addr; else u->AdvertisedV4.ip.v4.NotAnInteger = 0; - if (v6addr) u->AdvertisedV6 = *v6addr; else ubzero(u->AdvertisedV6.ip.v6.b, 16); - if (router) u->Router = *router; else u->Router.ip.v4.NotAnInteger = 0; - // setting router to zero indicates that nat mappings must be reestablished when router is reset - - if ((v4Changed || RouterChanged || v6Changed) && (v4addr && router)) +mDNSlocal void RemoveLLQNatMappings(mDNS *m, DNSQuestion *q) + { + if (q->NATInfoUDP.clientContext) { - // don't update these unless we've got V4 - UpdateHostnameRegistrations(m); - UpdateSRVRecords(m); - GetStaticHostname(m); // look up reverse map record to find any static hostnames for our IP address + mDNS_StopNATOperation_internal(m, &q->NATInfoUDP); + q->NATInfoUDP.clientContext = mDNSNULL; } - - mDNS_Unlock(m); } -// *************************************************************************** -#if COMPILER_LIKES_PRAGMA_MARK -#pragma mark - Incoming Message Processing -#endif - -mDNSlocal mDNSBool kaListContainsAnswer(DNSQuestion *question, CacheRecord *rr) +mDNSlocal void startLLQHandshake(mDNS *m, DNSQuestion *q) { - CacheRecord *ptr; - - for (ptr = question->uDNS_info.knownAnswers; ptr; ptr = ptr->next) - if (SameResourceRecord(&ptr->resrec, &rr->resrec)) return mDNStrue; + mStatus err = mStatus_NoError; + if (q->AuthInfo) + { + LogOperation("startLLQHandshakePrivate Addr %#a%s Server %#a:%d%s %##s (%s) eventport %d", + &m->AdvertisedV4, mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) ? " (RFC 1918)" : "", + &q->servAddr, mDNSVal16(q->servPort), mDNSAddrIsRFC1918(&q->servAddr) ? " (RFC 1918)" : "", + q->qname.c, DNSTypeName(q->qtype), mDNSVal16(q->eventPort)); - return mDNSfalse; - } + if (mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && !mDNSAddrIsRFC1918(&q->servAddr)) + if (q->state == LLQ_InitialRequest) + { + // start + if (!q->NATInfoUDP.clientContext) { q->state = LLQ_NatMapWaitUDP; StartLLQNatMap(m, q); goto exit; } + else + { + LogMsg("startLLQHandshake state == LLQ_InitialRequest but already have NATInfoUDP.clientContext %##s (%s)", + q->qname.c, DNSTypeName(q->qtype)); + err = mStatus_UnknownErr; + goto exit; + } + } + LogOperation("startLLQHandshake TCP %p %##s (%s)", q->tcp, q->qname.c, DNSTypeName(q->qtype)); + if (q->tcp) LogMsg("startLLQHandshake: Already have TCP connection for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + else q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, q, mDNSNULL, mDNSNULL); -mDNSlocal void removeKnownAnswer(DNSQuestion *question, CacheRecord *rr) - { - CacheRecord *ptr, *prev = mDNSNULL; + // update question state + //q->state = LLQ_InitialRequest; + q->state = LLQ_SecondaryRequest; // Right now, for private DNS, we skip the four-way LLQ handshake + q->origLease = kLLQ_DefLease; + q->ThisQInterval = 0; + q->LastQTime = m->timenow; + SetNextQueryTime(m, q); - for (ptr = question->uDNS_info.knownAnswers; ptr; ptr = ptr->next) + err = mStatus_NoError; + } + else { - if (SameResourceRecord(&ptr->resrec, &rr->resrec)) + mDNSu8 *end; + LLQOptData llqData; + + LogOperation("startLLQHandshake Addr %#a%s Server %#a:%d%s %##s (%s) RequestedPort %d", + &m->AdvertisedV4, mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) ? " (RFC 1918)" : "", + &q->servAddr, mDNSVal16(q->servPort), mDNSAddrIsRFC1918(&q->servAddr) ? " (RFC 1918)" : "", + q->qname.c, DNSTypeName(q->qtype), mDNSVal16(q->NATInfoUDP.RequestedPort)); + + if (mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && !mDNSAddrIsRFC1918(&q->servAddr)) { - if (prev) prev->next = ptr->next; - else question->uDNS_info.knownAnswers = ptr->next; - ufree(ptr); - return; + // start + if (!q->NATInfoUDP.clientContext) { q->state = LLQ_NatMapWaitUDP; StartLLQNatMap(m, q); } + else { err = mStatus_UnknownErr; goto exit; } } - prev = ptr; - } - LogMsg("removeKnownAnswer() called for record not in KA list"); - } + if (q->ntries++ >= kLLQ_MAX_TRIES) + { LogMsg("startLLQHandshake: %d failed attempts for LLQ %##s Polling.", kLLQ_MAX_TRIES, q->qname.c); err = mStatus_UnknownErr; goto exit; } -mDNSlocal void addKnownAnswer(DNSQuestion *question, const CacheRecord *rr) - { - CacheRecord *newCR = mDNSNULL; - mDNSu32 size; - - size = sizeof(CacheRecord) + rr->resrec.rdlength - InlineCacheRDSize; - newCR = (CacheRecord *)umalloc(size); - if (!newCR) { LogMsg("ERROR: addKnownAnswer - malloc"); return; } - umemcpy(newCR, rr, size); - newCR->resrec.rdata = (RData*)&newCR->rdatastorage; - newCR->resrec.rdata->MaxRDLength = rr->resrec.rdlength; - newCR->resrec.name = &question->qname; - newCR->next = question->uDNS_info.knownAnswers; - question->uDNS_info.knownAnswers = newCR; + // set llq rdata + llqData.vers = kLLQ_Vers; + llqData.llqOp = kLLQOp_Setup; + llqData.err = LLQErr_NoError; + llqData.id = zeroOpaque64; + llqData.llqlease = kLLQ_DefLease; + + InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags); + end = putLLQ(&m->omsg, m->omsg.data, q, &llqData, mDNStrue); + if (!end) { LogMsg("ERROR: startLLQHandshake - putLLQ"); q->state = LLQ_Error; return; } + + err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, &q->servAddr, q->servPort, mDNSNULL, mDNSNULL); + // on error, we procede as normal and retry after the appropriate interval + if (err) { debugf("ERROR: startLLQHandshake - mDNSSendDNSMessage returned %ld", err); err = mStatus_NoError; } + + // update question state + q->state = LLQ_InitialRequest; + q->origLease = kLLQ_DefLease; + q->ThisQInterval = (kLLQ_INIT_RESEND * mDNSPlatformOneSecond); + q->LastQTime = m->timenow - q->ThisQInterval; + SetNextQueryTime(m, q); + + err = mStatus_NoError; + } + +exit: + if (err) + { + LogOperation("startLLQHandshake error %d ", err); + StartLLQPolling(m, q); + } } -mDNSlocal void deriveGoodbyes(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question) +// Called in normal client context (lock not held) +mDNSlocal void LLQNatMapComplete(mDNS *m, NATTraversalInfo *n) { - const mDNSu8 *ptr; - int i; - CacheRecord *fptr, *ka, *cr, *answers = mDNSNULL, *prev = mDNSNULL; - LargeCacheRecord *lcr; - - if (question != m->uDNS_info.CurrentQuery) { LogMsg("ERROR: deriveGoodbyes called without CurrentQuery set!"); return; } + if (m->CurrentQuestion) + LogMsg("LLQNatMapComplete: ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); + m->CurrentQuestion = m->Questions; - ptr = LocateAnswers(msg, end); - if (!ptr) goto pkt_error; - - if (!msg->h.numAnswers) + while (m->CurrentQuestion) { - // delete the whole KA list - ka = question->uDNS_info.knownAnswers; - while (ka) + DNSQuestion *q = m->CurrentQuestion; + m->CurrentQuestion = m->CurrentQuestion->next; + if (q->LongLived) { - debugf("deriving goodbye for %##s", ka->resrec.name->c); - - m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback - question->QuestionCallback(m, question, &ka->resrec, mDNSfalse); - m->mDNS_reentrancy--; // Decrement to block mDNS API calls again - if (question != m->uDNS_info.CurrentQuery) + if (q->state == LLQ_NatMapWaitUDP) { - debugf("deriveGoodbyes - question removed via callback. returning."); - return; + if (!n->Result) + { + q->state = LLQ_GetZoneInfo; + q->eventPort = n->ExternalPort; + startLLQHandshake(m, q); + } + else + { + LogMsg("LLQNatMapComplete error %d Internal %d Requested %d External %d", n->Result, + mDNSVal16(q->NATInfoUDP.IntPort), mDNSVal16(q->NATInfoUDP.RequestedPort), mDNSVal16(q->NATInfoUDP.ExternalPort)); + RemoveLLQNatMappings(m, q); + StartLLQPolling(m, q); + } } - fptr = ka; - ka = ka->next; - ufree(fptr); - } - question->uDNS_info.knownAnswers = mDNSNULL; - return; - } - - // make a list of all the new answers - for (i = 0; i < msg->h.numAnswers; i++) - { - lcr = (LargeCacheRecord *)umalloc(sizeof(LargeCacheRecord)); - if (!lcr) goto malloc_error; - ubzero(lcr, sizeof(LargeCacheRecord)); - ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAns, lcr); - if (!ptr) goto pkt_error; - cr = &lcr->r; - if (ResourceRecordAnswersQuestion(&cr->resrec, question)) - { - cr->next = answers; - answers = cr; } - else ufree(cr); } - - // make sure every known answer is in the answer list - ka = question->uDNS_info.knownAnswers; - while (ka) + m->CurrentQuestion = mDNSNULL; + } + +// if we ever want to refine support for multiple hostnames, we can add logic matching service names to a particular hostname +// for now, we grab the first registered DynDNS name, if any, or a static name we learned via a reverse-map query +mDNSexport const domainname *GetServiceTarget(mDNS *m, ServiceRecordSet *srs) + { + LogOperation("GetServiceTarget %##s", srs->RR_SRV.resrec.name->c); + + if (!srs->RR_SRV.AutoTarget) // If not automatically tracking this host's current name, just return the existing target + return(&srs->RR_SRV.resrec.rdata->u.srv.target); + else { - for (cr = answers; cr; cr = cr->next) - { if (SameResourceRecord(&ka->resrec, &cr->resrec)) break; } - if (!cr) + HostnameInfo *hi = m->Hostnames; + +#if APPLE_OSX_mDNSResponder + DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name); + if (AuthInfo && AuthInfo->AutoTunnel) { - // record is in KA list but not answer list - remove from KA list - if (prev) prev->next = ka->next; - else question->uDNS_info.knownAnswers = ka->next; - debugf("deriving goodbye for %##s", ka->resrec.name->c); - m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback - question->QuestionCallback(m, question, &ka->resrec, mDNSfalse); - m->mDNS_reentrancy--; // Decrement to block mDNS API calls again - if (question != m->uDNS_info.CurrentQuery) + if (AuthInfo->AutoTunnelHostRecord.namestorage.c[0] == 0) { - debugf("deriveGoodbyes - question removed via callback. returning."); - return; + if (m->AutoTunnelHostAddr.b[0]) SetupLocalAutoTunnelInterface_internal(m); + return(mDNSNULL); } - fptr = ka; - ka = ka->next; - ufree(fptr); + return(&AuthInfo->AutoTunnelHostRecord.namestorage); } - else +#endif APPLE_OSX_mDNSResponder + + while (hi) { - prev = ka; - ka = ka->next; + if (hi->arv4.state == regState_Registered || hi->arv4.state == regState_Refresh) return(hi->arv4.resrec.name); + if (hi->arv6.state == regState_Registered || hi->arv6.state == regState_Refresh) return(hi->arv6.resrec.name); + hi = hi->next; } + if (m->StaticHostname.c[0]) return(&m->StaticHostname); + return(mDNSNULL); + } + } + +// Called with lock held +mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs) + { + mDNSu8 *ptr = m->omsg.data; + mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage); + mDNSOpaque16 id; + mStatus err = mStatus_NoError; + const domainname *target; + mDNSu32 i; + + if (m->mDNS_busy != m->mDNS_reentrancy+1) + LogMsg("SendServiceRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); + + if (mDNSIPv4AddressIsZero(srs->ns.ip.v4)) { LogMsg("SendServiceRegistration - NS not set!"); return; } + + id = mDNS_NewMessageID(m); + InitializeDNSMessage(&m->omsg.h, id, UpdateReqFlags); + + // setup resource records + SetNewRData(&srs->RR_PTR.resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash + SetNewRData(&srs->RR_TXT.resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash + + // replace port w/ NAT mapping if necessary + if (srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP && !mDNSIPPortIsZero(srs->NATinfo.ExternalPort)) + srs->RR_SRV.resrec.rdata->u.srv.port = srs->NATinfo.ExternalPort; + + // construct update packet + // set zone + ptr = putZone(&m->omsg, ptr, end, &srs->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass)); + if (!ptr) { err = mStatus_UnknownErr; goto exit; } + + if (srs->TestForSelfConflict) + { + // update w/ prereq that SRV already exist to make sure previous registration was ours, and delete any stale TXT records + if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numPrereqs, &srs->RR_SRV.resrec, 0))) { err = mStatus_UnknownErr; goto exit; } + if (!(ptr = putDeleteRRSet(&m->omsg, ptr, srs->RR_TXT.resrec.name, srs->RR_TXT.resrec.rrtype))) { err = mStatus_UnknownErr; goto exit; } } - // free temp answers list - cr = answers; - while (cr) { fptr = cr; cr = cr->next; ufree(fptr); } + else if (srs->state != regState_Refresh && srs->state != regState_UpdatePending) + { + // use SRV name for prereq + //ptr = putPrereqNameNotInUse(srs->RR_SRV.resrec.name, &m->omsg, ptr, end); - return; - - pkt_error: - LogMsg("ERROR: deriveGoodbyes - received malformed response to query for %##s (%d)", - question->qname.c, question->qtype); - return; + // For now, until we implement RFC 4701 (DHCID RR) to detect whether an existing record is someone else using the name, or just a + // stale echo of our own previous registration before we changed our host name, we just overwrite whatever may have already been there + ptr = putDeleteRRSet(&m->omsg, ptr, srs->RR_SRV.resrec.name, kDNSQType_ANY); + if (!ptr) { err = mStatus_UnknownErr; goto exit; } + } + + //!!!KRS Need to do bounds checking and use TCP if it won't fit!!! + if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_PTR.resrec, srs->RR_PTR.resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; } + + for (i = 0; i < srs->NumSubTypes; i++) + if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->SubTypes[i].resrec, srs->SubTypes[i].resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; } + + if (srs->state == regState_UpdatePending) // we're updating the txt record + { + AuthRecord *txt = &srs->RR_TXT; + // delete old RData + SetNewRData(&txt->resrec, txt->OrigRData, txt->OrigRDLen); + if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->RR_TXT.resrec))) { err = mStatus_UnknownErr; goto exit; } // delete old rdata + + // add new RData + SetNewRData(&txt->resrec, txt->InFlightRData, txt->InFlightRDLen); + if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; } + } + else + if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; } + + target = GetServiceTarget(m, srs); + if (!target) + { + debugf("SendServiceRegistration - no target for %##s", srs->RR_SRV.resrec.name->c); + srs->state = regState_NoTarget; + return; + } + + if (!SameDomainName(target, &srs->RR_SRV.resrec.rdata->u.srv.target)) + { + AssignDomainName(&srs->RR_SRV.resrec.rdata->u.srv.target, target); + SetNewRData(&srs->RR_SRV.resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash + } + + ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_SRV.resrec, srs->RR_SRV.resrec.rroriginalttl); + if (!ptr) { err = mStatus_UnknownErr; goto exit; } + + if (srs->srs_uselease) + { ptr = putUpdateLease(&m->omsg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) { err = mStatus_UnknownErr; goto exit; } } + + if (srs->state != regState_Refresh && srs->state != regState_DeregDeferred && srs->state != regState_UpdatePending) + srs->state = regState_Pending; + + srs->id = id; + + if (srs->Private) + { + LogOperation("SendServiceRegistration TCP %p %s", srs->tcp, ARDisplayString(m, &srs->RR_SRV)); + if (srs->tcp) LogMsg("SendServiceRegistration: Already have TCP connection for %s", ARDisplayString(m, &srs->RR_SRV)); + else srs->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &srs->ns, srs->SRSUpdatePort, mDNSNULL, srs, mDNSNULL); + srs->RR_SRV.LastAPTime = m->timenow; + srs->RR_SRV.ThisAPInterval = 0x3FFFFFFF; // TCP will handle any necessary retransmissions for us + } + else + { + err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, &srs->ns, srs->SRSUpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name)); + if (err) debugf("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %ld", err); + SetRecordRetry(m, &srs->RR_SRV, err); + } + + err = mStatus_NoError; + +exit: + + if (err) + { + LogMsg("SendServiceRegistration - Error formatting message %d", err); - malloc_error: - LogMsg("ERROR: Malloc"); + unlinkSRS(m, srs); + srs->state = regState_Unregistered; + + mDNS_DropLockBeforeCallback(); + srs->ServiceCallback(m, srs, err); + mDNS_ReclaimLockAfterCallback(); + // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function + // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. + } } -mDNSlocal void pktResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, mDNSBool llq) +mDNSlocal const domainname *PUBLIC_UPDATE_SERVICE_TYPE = (const domainname*)"\x0B_dns-update" "\x04_udp"; +mDNSlocal const domainname *PUBLIC_LLQ_SERVICE_TYPE = (const domainname*)"\x08_dns-llq" "\x04_udp"; + +mDNSlocal const domainname *PRIVATE_UPDATE_SERVICE_TYPE = (const domainname*)"\x0F_dns-update-tls" "\x04_tcp"; +mDNSlocal const domainname *PRIVATE_QUERY_SERVICE_TYPE = (const domainname*)"\x0E_dns-query-tls" "\x04_tcp"; +mDNSlocal const domainname *PRIVATE_LLQ_SERVICE_TYPE = (const domainname*)"\x0C_dns-llq-tls" "\x04_tcp"; + +#define ZoneDataSRV(X) (\ + (X)->ZoneService == ZoneServiceUpdate ? ((X)->ZonePrivate ? PRIVATE_UPDATE_SERVICE_TYPE : PUBLIC_UPDATE_SERVICE_TYPE) : \ + (X)->ZoneService == ZoneServiceQuery ? ((X)->ZonePrivate ? PRIVATE_QUERY_SERVICE_TYPE : (const domainname*)"" ) : \ + (X)->ZoneService == ZoneServiceLLQ ? ((X)->ZonePrivate ? PRIVATE_LLQ_SERVICE_TYPE : PUBLIC_LLQ_SERVICE_TYPE ) : (const domainname*)"") + +// Forward reference: GetZoneData_StartQuery references GetZoneData_QuestionCallback, and +// GetZoneData_QuestionCallback calls GetZoneData_StartQuery +mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qtype); + +// GetZoneData_QuestionCallback is called from normal client callback context (core API calls allowed) +mDNSexport void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) { - const mDNSu8 *ptr; - int i; - LargeCacheRecord lcr; - CacheRecord *cr = &lcr.r; - mDNSBool goodbye, inKAList, followedCName = mDNSfalse; - LLQ_Info *llqInfo = question->uDNS_info.llq; - domainname origname; - origname.c[0] = 0; - - if (question != m->uDNS_info.CurrentQuery) - { LogMsg("ERROR: pktResponseHdnlr called without CurrentQuery ptr set!"); return; } + ZoneData *zd = (ZoneData*)question->QuestionContext; - question->uDNS_info.Answered = mDNStrue; - - ptr = LocateAnswers(msg, end); - if (!ptr) goto pkt_error; + debugf("GetZoneData_QuestionCallback: %s %s", AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer)); + + if (!AddRecord) return; // Don't care about REMOVE events + if (AddRecord == QC_addnocache && answer->rdlength == 0) return; // Don't care about transient failure indications + if (answer->rrtype != question->qtype) return; // Don't care about CNAMEs - for (i = 0; i < msg->h.numAnswers; i++) + if (answer->rrtype == kDNSType_SOA) + { + debugf("GetZoneData GOT SOA %s", RRDisplayString(m, answer)); + mDNS_StopQuery(m, question); + if (answer->rdlength) + { + AssignDomainName(&zd->ZoneName, answer->name); + zd->ZoneClass = answer->rrclass; + AssignDomainName(&zd->question.qname, &zd->ZoneName); + GetZoneData_StartQuery(m, zd, kDNSType_SRV); + } + else if (zd->CurrentSOA->c[0]) + { + zd->CurrentSOA = (domainname *)(zd->CurrentSOA->c + zd->CurrentSOA->c[0]+1); + AssignDomainName(&zd->question.qname, zd->CurrentSOA); + GetZoneData_StartQuery(m, zd, kDNSType_SOA); + } + else + { + LogMsg("ERROR: GetZoneData_QuestionCallback - recursed to root label of %##s without finding SOA", zd->ChildName.c); + zd->ZoneDataCallback(m, mStatus_NoSuchNameErr, zd); + mDNSPlatformMemFree(zd); + } + } + else if (answer->rrtype == kDNSType_SRV) { - ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr); - if (!ptr) goto pkt_error; - if (ResourceRecordAnswersQuestion(&cr->resrec, question)) + debugf("GetZoneData GOT SRV %s", RRDisplayString(m, answer)); + mDNS_StopQuery(m, question); + if (!answer->rdlength && zd->ZonePrivate && zd->ZoneService != ZoneServiceQuery) + { + zd->ZonePrivate = mDNSfalse; // Causes ZoneDataSRV() to yield a different SRV name when building the query + GetZoneData_StartQuery(m, zd, kDNSType_SRV); // Try again, non-private this time + } + else { - if (cr->resrec.rrtype == kDNSType_CNAME) + if (answer->rdlength) { - if (followedCName) LogMsg("Error: multiple CNAME referals for question %##s", question->qname.c); - else - { - debugf("Following cname %##s -> %##s", question->qname.c, cr->resrec.rdata->u.name.c); - AssignDomainName(&origname, &question->qname); - AssignDomainName(&question->qname, &cr->resrec.rdata->u.name); - question->qnamehash = DomainNameHashValue(&question->qname); - followedCName = mDNStrue; - i = -1; // restart packet answer matching - ptr = LocateAnswers(msg, end); - continue; - } + AssignDomainName(&zd->Host, &answer->rdata->u.srv.target); + zd->Port = answer->rdata->u.srv.port; + AssignDomainName(&zd->question.qname, &zd->Host); + GetZoneData_StartQuery(m, zd, kDNSType_A); } - - goodbye = llq ? ((mDNSs32)cr->resrec.rroriginalttl == -1) : mDNSfalse; - inKAList = kaListContainsAnswer(question, cr); - - if ((goodbye && !inKAList) || (!goodbye && inKAList)) continue; // list up to date - if (!inKAList) addKnownAnswer(question, cr); - if (goodbye) removeKnownAnswer(question, cr); - m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback - question->QuestionCallback(m, question, &cr->resrec, !goodbye); - m->mDNS_reentrancy--; // Decrement to block mDNS API calls again - if (question != m->uDNS_info.CurrentQuery) + else { - debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning"); - return; + zd->ZonePrivate = mDNSfalse; + zd->Host.c[0] = 0; + zd->Port = zeroIPPort; + zd->Addr = zeroAddr; + zd->ZoneDataCallback(m, mStatus_NoError, zd); + mDNSPlatformMemFree(zd); } } - else if (!followedCName || !SameDomainName(cr->resrec.name, &origname)) - LogMsg("Question %##s %X (%s) %##s unexpected answer %##s %X (%s)", - question->qname.c, question->qnamehash, DNSTypeName(question->qtype), origname.c, - cr->resrec.name->c, cr->resrec.namehash, DNSTypeName(cr->resrec.rrtype)); } - - if (!llq || llqInfo->state == LLQ_Poll || llqInfo->deriveRemovesOnResume) + else if (answer->rrtype == kDNSType_A) { - deriveGoodbyes(m, msg, end,question); - if (llq && llqInfo->deriveRemovesOnResume) llqInfo->deriveRemovesOnResume = mDNSfalse; + debugf("GetZoneData GOT A %s", RRDisplayString(m, answer)); + mDNS_StopQuery(m, question); + zd->Addr.type = mDNSAddrType_IPv4; + zd->Addr.ip.v4 = (answer->rdlength == 4) ? answer->rdata->u.ipv4 : zerov4Addr; + zd->ZoneDataCallback(m, mStatus_NoError, zd); + mDNSPlatformMemFree(zd); } - - // Our interval may be set lower to recover from failures -- now that we have an answer, fully back off retry. - // If the server advertised an LLQ-specific port number then that implies that this zone - // *wants* to support LLQs, so if the setup fails (e.g. because we are behind a NAT) - // then we use a slightly faster polling rate to give slightly better user experience. - if (llq && llqInfo->state == LLQ_Poll && llqInfo->servPort.NotAnInteger) question->ThisQInterval = LLQ_POLL_INTERVAL; - else if (question->ThisQInterval < MAX_UCAST_POLL_INTERVAL) question->ThisQInterval = MAX_UCAST_POLL_INTERVAL; - return; - - pkt_error: - LogMsg("ERROR: pktResponseHndlr - received malformed response to query for %##s (%d)", - question->qname.c, question->qtype); - return; } -mDNSlocal void simpleResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *context) +// GetZoneData_StartQuery is called from normal client context (lock not held, or client callback) +mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qtype) { - (void)context; // unused - pktResponseHndlr(m, msg, end, question, mDNSfalse); + if (qtype == kDNSType_SRV) + { + LogOperation("lookupDNSPort %##s", ZoneDataSRV(zd)); + AssignDomainName(&zd->question.qname, ZoneDataSRV(zd)); + AppendDomainName(&zd->question.qname, &zd->ZoneName); + } + + zd->question.ThisQInterval = -1; // So that GetZoneData_QuestionCallback() knows whether to cancel this question (Is this necessary?) + zd->question.InterfaceID = mDNSInterface_Any; + zd->question.Target = zeroAddr; + //zd->question.qname.c[0] = 0; // Already set + zd->question.qtype = qtype; + zd->question.qclass = kDNSClass_IN; + zd->question.LongLived = mDNSfalse; + zd->question.ExpectUnique = mDNStrue; + zd->question.ForceMCast = mDNSfalse; + zd->question.ReturnIntermed = mDNStrue; + zd->question.QuestionCallback = GetZoneData_QuestionCallback; + zd->question.QuestionContext = zd; + + //LogMsg("GetZoneData_StartQuery %##s (%s) %p", zd->question.qname.c, DNSTypeName(zd->question.qtype), zd->question.Private); + return(mDNS_StartQuery(m, &zd->question)); } -mDNSlocal void llqResponseHndlr(mDNS * const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *context) +// StartGetZoneData is an internal routine (i.e. must be called with the lock already held) +mDNSexport ZoneData *StartGetZoneData(mDNS *const m, const domainname *const name, const ZoneService target, ZoneDataCallback callback, void *ZoneDataContext) { - (void)context; // unused - pktResponseHndlr(m, msg, end, question, mDNStrue); + DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, name); + int initialskip = (AuthInfo && AuthInfo->AutoTunnel) ? DomainNameLength(name) - DomainNameLength(&AuthInfo->domain) : 0; + ZoneData *zd = (ZoneData*)mDNSPlatformMemAllocate(sizeof(ZoneData)); + if (!zd) { LogMsg("ERROR: StartGetZoneData - mDNSPlatformMemAllocate failed"); return mDNSNULL; } + mDNSPlatformMemZero(zd, sizeof(ZoneData)); + AssignDomainName(&zd->ChildName, name); + zd->ZoneService = target; + zd->CurrentSOA = (domainname *)(&zd->ChildName.c[initialskip]); + zd->ZoneName.c[0] = 0; + zd->ZoneClass = 0; + zd->Host.c[0] = 0; + zd->Port = zeroIPPort; + zd->Addr = zeroAddr; + zd->ZonePrivate = AuthInfo ? mDNStrue : mDNSfalse; + zd->ZoneDataCallback = callback; + zd->ZoneDataContext = ZoneDataContext; + + zd->question.QuestionContext = zd; + AssignDomainName(&zd->question.qname, zd->CurrentSOA); + + mDNS_DropLockBeforeCallback(); // GetZoneData_StartQuery expects to be called from a normal callback, so we emulate that here + GetZoneData_StartQuery(m, zd, kDNSType_SOA); + mDNS_ReclaimLockAfterCallback(); + + return zd; } -mDNSlocal mStatus ParseTSIGError(mDNS *m, const DNSMessage *msg, const mDNSu8 *end, const domainname *displayname) +// if LLQ NAT context unreferenced, delete the mapping +mDNSlocal void CheckForUnreferencedLLQMapping(mDNS *m) { - LargeCacheRecord lcr; - const mDNSu8 *ptr; - mStatus err = mStatus_NoError; - int i; - - ptr = LocateAdditionals(msg, end); - if (!ptr) goto finish; - - for (i = 0; i < msg->h.numAdditionals; i++) + NATTraversalInfo *n = m->NATTraversals; + DNSQuestion *q; + + while (n) { - ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); - if (!ptr) goto finish; - if (lcr.r.resrec.rrtype == kDNSType_TSIG) + NATTraversalInfo *current = n; + n = n->next; + if (current->clientCallback == LLQNatMapComplete) { - mDNSu32 macsize; - mDNSu8 *rd = lcr.r.resrec.rdata->u.data; - mDNSu8 *rdend = rd + MaximumRDSize; - int alglen = DomainNameLength(&lcr.r.resrec.rdata->u.name); - - if (rd + alglen > rdend) goto finish; - rd += alglen; // algorithm name - if (rd + 6 > rdend) goto finish; - rd += 6; // 48-bit timestamp - if (rd + sizeof(mDNSOpaque16) > rdend) goto finish; - rd += sizeof(mDNSOpaque16); // fudge - if (rd + sizeof(mDNSOpaque16) > rdend) goto finish; - macsize = mDNSVal16(*(mDNSOpaque16 *)rd); - rd += sizeof(mDNSOpaque16); // MAC size - if (rd + macsize > rdend) goto finish; - rd += macsize; - if (rd + sizeof(mDNSOpaque16) > rdend) goto finish; - rd += sizeof(mDNSOpaque16); // orig id - if (rd + sizeof(mDNSOpaque16) > rdend) goto finish; - err = mDNSVal16(*(mDNSOpaque16 *)rd); // error code - - if (err == TSIG_ErrBadSig) { LogMsg("%##s: bad signature", displayname->c); err = mStatus_BadSig; } - else if (err == TSIG_ErrBadKey) { LogMsg("%##s: bad key", displayname->c); err = mStatus_BadKey; } - else if (err == TSIG_ErrBadTime) { LogMsg("%##s: bad time", displayname->c); err = mStatus_BadTime; } - else if (err) { LogMsg("%##s: unknown tsig error %d", displayname->c, err); err = mStatus_UnknownErr; } - goto finish; + for (q = m->Questions; q; q = q->next) if (&q->NATInfoUDP == current) break; + if (!q) mDNS_StopNATOperation_internal(m, current); } } - - finish: - return err; } -mDNSlocal mStatus checkUpdateResult(domainname *displayname, mDNSu8 rcode, mDNS *m, const DNSMessage *msg, const mDNSu8 *end) +// *************************************************************************** +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - host name and interface management +#endif + +// Called in normal client context (lock not held) +mDNSlocal void CompleteSRVNatMap(mDNS *m, NATTraversalInfo *n) { - (void)msg; // currently unused, needed for TSIG errors - if (!rcode) return mStatus_NoError; - else if (rcode == kDNSFlag1_RC_YXDomain) - { - debugf("name in use: %##s", displayname->c); - return mStatus_NameConflict; - } - else if (rcode == kDNSFlag1_RC_Refused) - { - LogMsg("Update %##s refused", displayname->c); - return mStatus_Refused; - } - else if (rcode == kDNSFlag1_RC_NXRRSet) - { - LogMsg("Reregister refused (NXRRSET): %##s", displayname->c); - return mStatus_NoSuchRecord; - } - else if (rcode == kDNSFlag1_RC_NotAuth) + ServiceRecordSet *srs = (ServiceRecordSet *)n->clientContext; + LogOperation("SRVNatMap complete %.4a %u %u TTL %u", &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort), n->NATLease); + + if (!srs) { LogMsg("CompleteSRVNatMap called with unknown ServiceRecordSet object"); return; } + if (!n->NATLease) return; + + if (n->Result) { - // TSIG errors should come with FmtErr as per RFC 2845, but BIND 9 sends them with NotAuth so we look here too - mStatus tsigerr = ParseTSIGError(m, msg, end, displayname); - if (!tsigerr) + HostnameInfo *hi = m->Hostnames; + while (hi) { - LogMsg("Permission denied (NOAUTH): %##s", displayname->c); - return mStatus_UnknownErr; + if (hi->arv6.state == regState_Registered || hi->arv6.state == regState_Refresh) break; + else hi = hi->next; } - else return tsigerr; - } - else if (rcode == kDNSFlag1_RC_FmtErr) - { - mStatus tsigerr = ParseTSIGError(m, msg, end, displayname); - if (!tsigerr) + + if (hi) { - LogMsg("Format Error: %##s", displayname->c); - return mStatus_UnknownErr; + debugf("Port map failed for service %##s - using IPv6 service target", srs->RR_SRV.resrec.name->c); + mDNS_StopNATOperation(m, &srs->NATinfo); + goto register_service; } - else return tsigerr; + else srs->state = regState_NATError; } + + register_service: + mDNS_Lock(m); + if (!mDNSIPv4AddressIsZero(srs->ns.ip.v4)) + SendServiceRegistration(m, srs); // non-zero server address means we already have necessary zone data to send update else { - LogMsg("Update %##s failed with rcode %d", displayname->c, rcode); - return mStatus_UnknownErr; + // SHOULD NEVER HAPPEN! + LogOperation("ERROR: CompleteSRVNatMap called but srs->ns.ip.v4 is zero!"); + srs->state = regState_FetchingZoneData; + if (srs->nta) CancelGetZoneData(m, srs->nta); // Make sure we cancel old one before we start a new one + srs->nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationZoneDataComplete, srs); } + mDNS_Unlock(m); } -mDNSlocal void hndlServiceUpdateReply(mDNS * const m, ServiceRecordSet *srs, mStatus err) +mDNSlocal void StartSRVNatMap(mDNS *m, ServiceRecordSet *srs) { - mDNSBool InvokeCallback = mDNSfalse; - uDNS_RegInfo *info = &srs->uDNS_info; - NATTraversalInfo *nat = srs->uDNS_info.NATinfo; - ExtraResourceRecord **e = &srs->Extras; - AuthRecord *txt = &srs->RR_TXT; - uDNS_RegInfo *txtInfo = &txt->uDNS_info; - switch (info->state) - { - case regState_Pending: - if (err == mStatus_NameConflict && !info->TestForSelfConflict) - { - info->TestForSelfConflict = mDNStrue; - debugf("checking for self-conflict of service %##s", srs->RR_SRV.resrec.name->c); - SendServiceRegistration(m, srs); - return; - } - else if (info->TestForSelfConflict) - { - info->TestForSelfConflict = mDNSfalse; - if (err == mStatus_NoSuchRecord) err = mStatus_NameConflict; // NoSuchRecord implies that our prereq was not met, so we actually have a name conflict - if (err) info->state = regState_Unregistered; - else info->state = regState_Registered; - InvokeCallback = mDNStrue; - break; - } - else if (err == mStatus_UnknownErr && info->lease) - { - LogMsg("Re-trying update of service %##s without lease option", srs->RR_SRV.resrec.name->c); - info->lease = mDNSfalse; - SendServiceRegistration(m, srs); - return; - } - else - { - if (err) { LogMsg("Error %ld for registration of service %##s", err, srs->RR_SRV.resrec.name->c); info->state = regState_Unregistered; } //!!!KRS make sure all structs will still get cleaned up when client calls DeregisterService with this state - else info->state = regState_Registered; - InvokeCallback = mDNStrue; - break; - } - case regState_Refresh: - if (err) - { - LogMsg("Error %ld for refresh of service %##s", err, srs->RR_SRV.resrec.name->c); - InvokeCallback = mDNStrue; - info->state = regState_Unregistered; - } - else info->state = regState_Registered; - break; - case regState_DeregPending: - if (err) LogMsg("Error %ld for deregistration of service %##s", err, srs->RR_SRV.resrec.name->c); - if (info->SRVChanged) - { - info->state = regState_NoTarget; // NoTarget will allow us to pick up new target OR nat traversal state - break; - } - err = mStatus_MemFree; - InvokeCallback = mDNStrue; - if (nat) - { - if (nat->state == NATState_Deleted) { info->NATinfo = mDNSNULL; FreeNATInfo(m, nat); } // deletion copmleted - else nat->reg.ServiceRegistration = mDNSNULL; // allow mapping deletion to continue - } - info->state = regState_Unregistered; - break; - case regState_DeregDeferred: - if (err) - { - debugf("Error %ld received prior to deferred derigstration of %##s", err, srs->RR_SRV.resrec.name->c); - err = mStatus_MemFree; - InvokeCallback = mDNStrue; - info->state = regState_Unregistered; - break; - } - else - { - debugf("Performing deferred deregistration of %##s", srs->RR_SRV.resrec.name->c); - info->state = regState_Registered; - SendServiceDeregistration(m, srs); - return; - } - case regState_UpdatePending: - if (err) - { - LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs->RR_SRV.resrec.name->c); - info->state = regState_Unregistered; - InvokeCallback = mDNStrue; - } - else - { - info->state = regState_Registered; - // deallocate old RData - if (txtInfo->UpdateRDCallback) txtInfo->UpdateRDCallback(m, txt, txtInfo->OrigRData); - SetNewRData(&txt->resrec, txtInfo->InFlightRData, txtInfo->InFlightRDLen); - txtInfo->OrigRData = mDNSNULL; - txtInfo->InFlightRData = mDNSNULL; - } - break; - case regState_FetchingZoneData: - case regState_Registered: - case regState_Cancelled: - case regState_Unregistered: - case regState_NATMap: - case regState_NoTarget: - case regState_ExtraQueued: - case regState_NATError: - LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %ld. Unlinking.", - srs->RR_SRV.resrec.name->c, info->state, err); - err = mStatus_UnknownErr; - } - - if ((info->SRVChanged || info->SRVUpdateDeferred) && (info->state == regState_NoTarget || info->state == regState_Registered)) - { - if (InvokeCallback) - { - info->ClientCallbackDeferred = mDNStrue; - info->DeferredStatus = err; - } - info->SRVChanged = mDNSfalse; - UpdateSRV(m, srs); - return; - } - - while (*e) - { - uDNS_RegInfo *einfo = &(*e)->r.uDNS_info; - if (einfo->state == regState_ExtraQueued) - { - if (info->state == regState_Registered && !err) - { - // extra resource record queued for this service - copy zone info and register - AssignDomainName(&einfo->zone, &info->zone); - einfo->ns = info->ns; - einfo->port = info->port; - einfo->lease = info->lease; - sendRecordRegistration(m, &(*e)->r); - e = &(*e)->next; - } - else if (err && einfo->state != regState_Unregistered) - { - // unlink extra from list - einfo->state = regState_Unregistered; - *e = (*e)->next; - } - else e = &(*e)->next; - } - else e = &(*e)->next; - } + mDNSu8 *p = srs->RR_PTR.resrec.name->c; + if (p[0]) p += 1 + p[0]; + + if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp")) srs->NATinfo.Protocol = NATOp_MapTCP; + else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp")) srs->NATinfo.Protocol = NATOp_MapUDP; + else { LogMsg("StartSRVNatMap: could not determine transport protocol of service %##s", srs->RR_SRV.resrec.name->c); goto error; } + srs->NATinfo.IntPort = srs->RR_SRV.resrec.rdata->u.srv.port; + srs->NATinfo.RequestedPort = srs->RR_SRV.resrec.rdata->u.srv.port; + srs->NATinfo.NATLease = 0; // Request default lease + srs->NATinfo.clientCallback = CompleteSRVNatMap; + srs->NATinfo.clientContext = srs; + mDNS_StartNATOperation_internal(m, &srs->NATinfo); + return; - srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL - 1; // reset retry delay for future refreshes, dereg, etc. - if (info->state == regState_Unregistered) unlinkSRS(m, srs); - else if (txtInfo->QueuedRData && info->state == regState_Registered) - { - if (InvokeCallback) - { - // if we were supposed to give a client callback, we'll do it after we update the primary txt record - info->ClientCallbackDeferred = mDNStrue; - info->DeferredStatus = err; - } - info->state = regState_UpdatePending; - txtInfo->InFlightRData = txtInfo->QueuedRData; - txtInfo->InFlightRDLen = txtInfo->QueuedRDLen; - info->OrigRData = txt->resrec.rdata; - info->OrigRDLen = txt->resrec.rdlength; - txtInfo->QueuedRData = mDNSNULL; - SendServiceRegistration(m, srs); - return; - } - - m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback - if (InvokeCallback) srs->ServiceCallback(m, srs, err); - else if (info->ClientCallbackDeferred) - { - info->ClientCallbackDeferred = mDNSfalse; - srs->ServiceCallback(m, srs, info->DeferredStatus); - } - m->mDNS_reentrancy--; // Decrement to block mDNS API calls again - // NOTE: do not touch structures after calling ServiceCallback + error: + if (srs->nta) CancelGetZoneData(m, srs->nta); // Make sure we cancel old one before we start a new one + srs->nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationZoneDataComplete, srs); } -mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err) +// Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1) +mDNSexport void ServiceRegistrationZoneDataComplete(mDNS *const m, mStatus err, const ZoneData *zoneData) { - uDNS_RegInfo *info = &rr->uDNS_info; - mDNSBool InvokeCallback = mDNStrue; + ServiceRecordSet *srs = (ServiceRecordSet *)zoneData->ZoneDataContext; - if (info->state == regState_UpdatePending) - { - if (err) - { - LogMsg("Update record failed for %##s (err %d)", rr->resrec.name->c, err); - info->state = regState_Unregistered; - } - else - { - debugf("Update record %##s - success", rr->resrec.name->c); - info->state = regState_Registered; - // deallocate old RData - if (info->UpdateRDCallback) info->UpdateRDCallback(m, rr, info->OrigRData); - SetNewRData(&rr->resrec, info->InFlightRData, info->InFlightRDLen); - info->OrigRData = mDNSNULL; - info->InFlightRData = mDNSNULL; - } - } + if (m->mDNS_busy != m->mDNS_reentrancy) + LogMsg("ServiceRegistrationZoneDataComplete: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); + + srs->nta = mDNSNULL; + + if (err) goto error; + if (!zoneData) { LogMsg("ERROR: ServiceRegistrationZoneDataComplete invoked with NULL result and no error"); goto error; } + + if (srs->RR_SRV.resrec.rrclass != zoneData->ZoneClass) + { LogMsg("Service %##s - class does not match zone", srs->RR_SRV.resrec.name->c); goto error; } - if (info->state == regState_DeregPending) + // cache zone data + AssignDomainName(&srs->zone, &zoneData->ZoneName); + srs->ns.type = mDNSAddrType_IPv4; + srs->ns = zoneData->Addr; + if (!mDNSIPPortIsZero(zoneData->Port)) { - debugf("Received reply for deregister record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype); - if (err) LogMsg("ERROR: Deregistration of record %##s type %d failed with error %ld", - rr->resrec.name->c, rr->resrec.rrtype, err); - err = mStatus_MemFree; - info->state = regState_Unregistered; + srs->SRSUpdatePort = zoneData->Port; + srs->Private = zoneData->ZonePrivate; } - - if (info->state == regState_DeregDeferred) + else { - if (err) - { - LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %ld", - rr->resrec.name->c, rr->resrec.rrtype, err); - info->state = regState_Unregistered; - } - debugf("Calling deferred deregistration of record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype); - info->state = regState_Registered; - uDNS_DeregisterRecord(m, rr); - return; + debugf("Update port not advertised via SRV - guessing port 53, no lease option"); + srs->SRSUpdatePort = UnicastDNSPort; + srs->srs_uselease = mDNSfalse; } - if (info->state == regState_Pending || info->state == regState_Refresh) + LogOperation("ServiceRegistrationZoneDataComplete %#a %d %#a %d", &m->AdvertisedV4, mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4), &srs->ns, mDNSAddrIsRFC1918(&srs->ns)); + + if (!mDNSIPPortIsZero(srs->RR_SRV.resrec.rdata->u.srv.port) && + mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && !mDNSAddrIsRFC1918(&srs->ns) && + srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP) { - if (!err) - { - info->state = regState_Registered; - if (info->state == regState_Refresh) InvokeCallback = mDNSfalse; - } - else - { - if (info->lease && err == mStatus_UnknownErr) - { - LogMsg("Re-trying update of record %##s without lease option", rr->resrec.name->c); - info->lease = mDNSfalse; - sendRecordRegistration(m, rr); - return; - } - LogMsg("Registration of record %##s type %d failed with error %ld", rr->resrec.name->c, rr->resrec.rrtype, err); - info->state = regState_Unregistered; - } - } - - if (info->state == regState_Unregistered) unlinkAR(&m->uDNS_info.RecordRegistrations, rr); - else rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL - 1; // reset retry delay for future refreshes, dereg, etc. - - if (info->QueuedRData && info->state == regState_Registered) - { - info->state = regState_UpdatePending; - info->InFlightRData = info->QueuedRData; - info->InFlightRDLen = info->QueuedRDLen; - info->OrigRData = rr->resrec.rdata; - info->OrigRDLen = rr->resrec.rdlength; - info->QueuedRData = mDNSNULL; - sendRecordRegistration(m, rr); - return; + srs->state = regState_NATMap; + LogOperation("ServiceRegistrationZoneDataComplete StartSRVNatMap"); + StartSRVNatMap(m, srs); } - - if (InvokeCallback) + else { - m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback - if (rr->RecordCallback) rr->RecordCallback(m, rr, err); - m->mDNS_reentrancy--; // Decrement to block mDNS API calls again + mDNS_Lock(m); + SendServiceRegistration(m, srs); + mDNS_Unlock(m); } - } + return; + +error: + unlinkSRS(m, srs); + srs->state = regState_Unregistered; + // Don't need to do the mDNS_DropLockBeforeCallback stuff here, because this code is + // *already* being invoked in the right callback context, with mDNS_reentrancy correctly incremented. + srs->ServiceCallback(m, srs, err); + // CAUTION: MUST NOT do anything more with rr after calling srs->ServiceCallback(), because the client's callback function + // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. + } -mDNSlocal void SetUpdateExpiration(mDNS *m, DNSMessage *msg, const mDNSu8 *end, uDNS_RegInfo *info) +mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs) { - LargeCacheRecord lcr; - const mDNSu8 *ptr; - int i; - mDNSu32 lease = 0; - mDNSs32 expire; - - ptr = LocateAdditionals(msg, end); + mDNSOpaque16 id; + mDNSu8 *ptr = m->omsg.data; + mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage); + mStatus err = mStatus_UnknownErr; + mDNSu32 i; - if (info->lease && (ptr = LocateAdditionals(msg, end))) + id = mDNS_NewMessageID(m); + InitializeDNSMessage(&m->omsg.h, id, UpdateReqFlags); + + // put zone + ptr = putZone(&m->omsg, ptr, end, &srs->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass)); + if (!ptr) { LogMsg("ERROR: SendServiceDeregistration - putZone"); err = mStatus_UnknownErr; goto exit; } + + if (!(ptr = putDeleteAllRRSets(&m->omsg, ptr, srs->RR_SRV.resrec.name))) { err = mStatus_UnknownErr; goto exit; } // this deletes SRV, TXT, and Extras + if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->RR_PTR.resrec))) { err = mStatus_UnknownErr; goto exit; } + for (i = 0; i < srs->NumSubTypes; i++) + if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->SubTypes[i].resrec))) { err = mStatus_UnknownErr; goto exit; } + + srs->id = id; + srs->state = regState_DeregPending; + + if (srs->Private) { - for (i = 0; i < msg->h.numAdditionals; i++) - { - ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); - if (!ptr) break; - if (lcr.r.resrec.rrtype == kDNSType_OPT) - { - if (lcr.r.resrec.rdlength < LEASE_OPT_RDLEN) continue; - if (lcr.r.resrec.rdata->u.opt.opt != kDNSOpt_Lease) continue; - lease = lcr.r.resrec.rdata->u.opt.OptData.lease; - break; - } - } + LogOperation("SendServiceDeregistration TCP %p %s", srs->tcp, ARDisplayString(m, &srs->RR_SRV)); + if (srs->tcp) LogMsg("SendServiceDeregistration: Already have TCP connection for %s", ARDisplayString(m, &srs->RR_SRV)); + else srs->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &srs->ns, srs->SRSUpdatePort, mDNSNULL, srs, mDNSNULL); + srs->RR_SRV.LastAPTime = m->timenow; + srs->RR_SRV.ThisAPInterval = 0x3FFFFFFF; // TCP will handle any necessary retransmissions for us } - - if (lease > 0) + else { - expire = (mDNSPlatformTimeNow(m) + (((mDNSs32)lease * mDNSPlatformOneSecond)) * 3/4); - if (info->state == regState_UpdatePending) - // if updating individual record, the service record set may expire sooner - { if (expire - info->expire < 0) info->expire = expire; } - else info->expire = expire; + err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, &srs->ns, srs->SRSUpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name)); + if (err && err != mStatus_TransientErr) { debugf("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %ld", err); goto exit; } + SetRecordRetry(m, &srs->RR_SRV, err); } - else info->lease = mDNSfalse; - } -mDNSexport void uDNS_ReceiveNATMap(mDNS *m, mDNSu8 *pkt, mDNSu16 len) - { - uDNS_GlobalInfo *u = &m->uDNS_info; - NATTraversalInfo *ptr = u->NATTraversals; - NATOp_t op; - - // check length, version, opcode - if (len < sizeof(NATPortMapReply) && len < sizeof(NATAddrReply)) { LogMsg("NAT Traversal message too short (%d bytes)", len); return; } - if (pkt[0] != NATMAP_VERS) { LogMsg("Received NAT Traversal response with version %d (expect version %d)", pkt[0], NATMAP_VERS); return; } - op = pkt[1]; - if (!(op & NATMAP_RESPONSE_MASK)) { LogMsg("Received NAT Traversal message that is not a response (opcode %d)", op); return; } + err = mStatus_NoError; + +exit: - while (ptr) + if (err) { - if ((ptr->state == NATState_Request || ptr->state == NATState_Refresh) && (ptr->op | NATMAP_RESPONSE_MASK) == op) - if (ptr->ReceiveResponse(ptr, m, pkt, len)) break; // note callback may invalidate ptr if it return value is non-zero - ptr = ptr->next; + unlinkSRS(m, srs); + srs->state = regState_Unregistered; } } -mDNSlocal const domainname *DNSRelayTestQuestion = (domainname*) - "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\xa" "dnsbugtest" - "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\x7" "in-addr" "\x4" "arpa"; - -// Returns mDNStrue if response was handled -mDNSlocal mDNSBool uDNS_ReceiveTestQuestionResponse(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end, - const mDNSAddr *const srcaddr, const mDNSInterfaceID InterfaceID) +// Called with lock held +mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs) { - const mDNSu8 *ptr = msg->data; - DNSQuestion q; - DNSServer *s; - mDNSu32 result = 0; - mDNSBool found = mDNSfalse; + ExtraResourceRecord *e; - // 1. Find out if this is an answer to one of our test questions - if (msg->h.numQuestions != 1) return(mDNSfalse); - ptr = getQuestion(msg, ptr, end, InterfaceID, &q); - if (!ptr) return(mDNSfalse); - if (q.qtype != kDNSType_PTR || q.qclass != kDNSClass_IN) return(mDNSfalse); - if (!SameDomainName(&q.qname, DNSRelayTestQuestion)) return(mDNSfalse); + // Target change if: + // We have a target and were previously waiting for one, or + // We had a target and no longer do, or + // The target has changed - // 2. If the DNS relay gave us a positive response, then it's got buggy firmware - // else, if the DNS relay gave us an error or no-answer response, it passed our test - if ((msg->h.flags.b[1] & kDNSFlag1_RC) == kDNSFlag1_RC_NoErr && msg->h.numAnswers > 0) - result = DNSServer_Failed; - else - result = DNSServer_Passed; + domainname *curtarget = &srs->RR_SRV.resrec.rdata->u.srv.target; + const domainname *const nt = GetServiceTarget(m, srs); + const domainname *const newtarget = nt ? nt : (domainname*)""; + mDNSBool TargetChanged = (newtarget->c[0] && srs->state == regState_NoTarget) || !SameDomainName(curtarget, newtarget); + mDNSBool HaveZoneData = !mDNSIPv4AddressIsZero(srs->ns.ip.v4); - // 3. Find occurrences of this server in our list, and mark them appropriately - for (s = m->uDNS_info.Servers; s; s = s->next) - if (mDNSSameAddress(srcaddr, &s->addr) && s->teststate != result) - { s->teststate = result; found = mDNStrue; } + // Nat state change if: + // We were behind a NAT, and now we are behind a new NAT, or + // We're not behind a NAT but our port was previously mapped to a different public port + // We were not behind a NAT and now we are - // 4. Assuming we found the server in question in our list (don't want to risk being victim of a deliberate DOS attack here) - // log a message to let the user know why Wide-Area Service Discovery isn't working - if (found && result == DNSServer_Failed) - LogMsg("NOTE: Wide-Area Service Discovery disabled to avoid crashing defective DNS relay %#a.", srcaddr); + mDNSIPPort port = srs->RR_SRV.resrec.rdata->u.srv.port; + mDNSBool NowBehindNAT = (!mDNSIPPortIsZero(port) && mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && !mDNSAddrIsRFC1918(&srs->ns)); + mDNSBool WereBehindNAT = (srs->NATinfo.clientContext != mDNSNULL); + mDNSBool PortWasMapped = (srs->NATinfo.clientContext && !mDNSSameIPPort(srs->NATinfo.RequestedPort, port)); // I think this is always false -- SC Sept 07 + mDNSBool NATChanged = (!WereBehindNAT && NowBehindNAT) || (!NowBehindNAT && PortWasMapped); - return(mDNStrue); // Return mDNStrue to tell uDNS_ReceiveMsg it doens't need to process this packet further - } + LogOperation("UpdateSRV %##s newtarget %##s TargetChanged %d HaveZoneData %d port %d NowBehindNAT %d WereBehindNAT %d PortWasMapped %d NATChanged %d", + srs->RR_SRV.resrec.name->c, newtarget, + TargetChanged, HaveZoneData, mDNSVal16(port), NowBehindNAT, WereBehindNAT, PortWasMapped, NATChanged); -mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end, - const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr, - const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID) - { - DNSQuestion *qptr; - AuthRecord *rptr; - ServiceRecordSet *sptr; - mStatus err = mStatus_NoError; - uDNS_GlobalInfo *u = &m->uDNS_info; - - mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery; - mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update; - mDNSu8 QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask); - mDNSu8 rcode = (mDNSu8)(msg->h.flags.b[1] & kDNSFlag1_RC); + if (m->mDNS_busy != m->mDNS_reentrancy+1) + LogMsg("UpdateSRV: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); - mDNSs32 timenow = mDNSPlatformTimeNow(m); - - // unused - (void)dstaddr; - (void)dstport; - (void)InterfaceID; - - if (QR_OP == StdR) + if (!TargetChanged && !NATChanged) return; + + switch(srs->state) { - // !!!KRS we should to a table lookup here to see if it answers an LLQ or a 1-shot - // LLQ Responses over TCP not currently supported - if (srcaddr && recvLLQResponse(m, msg, end, srcaddr, srcport, InterfaceID)) return; - - if (uDNS_ReceiveTestQuestionResponse(m, msg, end, srcaddr, InterfaceID)) return; - - for (qptr = u->ActiveQueries; qptr; qptr = qptr->next) - { - //!!!KRS we should have a hashtable, hashed on message id - if (qptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger) + case regState_FetchingZoneData: + case regState_DeregPending: + case regState_DeregDeferred: + case regState_Unregistered: + case regState_NATMap: + case regState_ExtraQueued: + // In these states, the SRV has either not yet been registered (it will get up-to-date information when it is) + // or is in the process of, or has already been, deregistered + return; + + case regState_Pending: + case regState_Refresh: + case regState_UpdatePending: + // let the in-flight operation complete before updating + srs->SRVUpdateDeferred = mDNStrue; + return; + + case regState_NATError: + if (!NATChanged) return; + // if nat changed, register if we have a target (below) + + case regState_NoTarget: + if (newtarget->c[0]) { - if (timenow - (qptr->LastQTime + RESPONSE_WINDOW) > 0) - { debugf("uDNS_ReceiveMsg - response received after maximum allowed window. Discarding"); return; } - if (msg->h.flags.b[0] & kDNSFlag0_TC) - { hndlTruncatedAnswer(qptr, srcaddr, m); return; } + debugf("UpdateSRV: %s service %##s", HaveZoneData ? (NATChanged && NowBehindNAT ? "Starting Port Map for" : "Registering") : "Getting Zone Data for", srs->RR_SRV.resrec.name->c); + if (!HaveZoneData) + { + srs->state = regState_FetchingZoneData; + if (srs->nta) CancelGetZoneData(m, srs->nta); // Make sure we cancel old one before we start a new one + srs->nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationZoneDataComplete, srs); + } else { - u->CurrentQuery = qptr; - qptr->uDNS_info.responseCallback(m, msg, end, qptr, qptr->uDNS_info.context); - u->CurrentQuery = mDNSNULL; - // Note: responseCallback can invalidate qptr - return; + if (srs->NATinfo.clientContext && (NATChanged || !NowBehindNAT)) + { + mDNS_StopNATOperation_internal(m, &srs->NATinfo); + srs->NATinfo.clientContext = mDNSNULL; + } + if (NATChanged && NowBehindNAT && srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP) + { srs->state = regState_NATMap; StartSRVNatMap(m, srs); } + else SendServiceRegistration(m, srs); } } + return; + + case regState_Registered: + // target or nat changed. deregister service. upon completion, we'll look for a new target + debugf("UpdateSRV: SRV record changed for service %##s - deregistering (will re-register with new SRV)", srs->RR_SRV.resrec.name->c); + for (e = srs->Extras; e; e = e->next) e->r.state = regState_ExtraQueued; // extra will be re-registed if the service is re-registered + srs->SRVChanged = mDNStrue; + SendServiceDeregistration(m, srs); + return; + + default: LogMsg("UpdateSRV: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c); + } + } + +// Called with lock held +mDNSlocal void UpdateSRVRecords(mDNS *m) + { + if (CurrentServiceRecordSet) + LogMsg("UpdateSRVRecords ERROR CurrentServiceRecordSet already set"); + CurrentServiceRecordSet = m->ServiceRegistrations; + + while (CurrentServiceRecordSet) + { + ServiceRecordSet *s = CurrentServiceRecordSet; + CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next; + UpdateSRV(m, s); + } + } + +// Forward reference: AdvertiseHostname references HostnameCallback, and HostnameCallback calls AdvertiseHostname +mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result); + +// Called in normal client context (lock not held) +mDNSlocal void hostnameGetPublicAddressCallback(mDNS *m, NATTraversalInfo *n) + { + HostnameInfo *h = (HostnameInfo *)n->clientContext; + + if (!h) { LogMsg("RegisterHostnameRecord: registration cancelled"); return; } + + if (!n->Result) + { + if (mDNSIPv4AddressIsZero(n->ExternalAddress) || mDNSv4AddrIsRFC1918(&n->ExternalAddress)) return; + + if (h->arv4.resrec.RecordType) + { + if (mDNSSameIPv4Address(h->arv4.resrec.rdata->u.ipv4, n->ExternalAddress)) return; // If address unchanged, do nothing + LogMsg("Updating hostname %##s IPv4 from %.4a to %.4a (NAT gateway's external address)", h->arv4.resrec.name->c, &h->arv4.resrec.rdata->u.ipv4, &n->ExternalAddress); + mDNS_Deregister(m, &h->arv4); // mStatus_MemFree callback will re-register with new address + } + else + { + LogMsg("Advertising hostname %##s IPv4 %.4a (NAT gateway's external address)", h->arv4.resrec.name->c, &n->ExternalAddress); + h->arv4.resrec.RecordType = kDNSRecordTypeKnownUnique; + h->arv4.resrec.rdata->u.ipv4 = n->ExternalAddress; + mDNS_Register(m, &h->arv4); } } - if (QR_OP == UpdateR) + } + +// register record or begin NAT traversal +mDNSlocal void AdvertiseHostname(mDNS *m, HostnameInfo *h) + { + if (!mDNSIPv4AddressIsZero(m->AdvertisedV4.ip.v4) && h->arv4.resrec.RecordType == kDNSRecordTypeUnregistered) { - for (sptr = u->ServiceRegistrations; sptr; sptr = sptr->next) + mDNS_SetupResourceRecord(&h->arv4, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnregistered, HostnameCallback, h); + AssignDomainName(&h->arv4.namestorage, &h->fqdn); + h->arv4.resrec.rdata->u.ipv4 = m->AdvertisedV4.ip.v4; + h->arv4.state = regState_Unregistered; + if (mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4)) { - if (sptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger) - { - err = checkUpdateResult(sptr->RR_SRV.resrec.name, rcode, m, msg, end); - if (!err) SetUpdateExpiration(m, msg, end, &sptr->uDNS_info); - hndlServiceUpdateReply(m, sptr, err); - return; - } + // If we already have a NAT query active, stop it and restart it to make sure we get another callback + if (h->natinfo.clientContext) mDNS_StopNATOperation_internal(m, &h->natinfo); + h->natinfo.Protocol = 0; + h->natinfo.IntPort = zeroIPPort; + h->natinfo.RequestedPort = zeroIPPort; + h->natinfo.NATLease = 0; + h->natinfo.clientCallback = hostnameGetPublicAddressCallback; + h->natinfo.clientContext = h; + mDNS_StartNATOperation_internal(m, &h->natinfo); } - for (rptr = u->RecordRegistrations; rptr; rptr = rptr->next) + else { - if (rptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger) - { - err = checkUpdateResult(rptr->resrec.name, rcode, m, msg, end); - if (!err) SetUpdateExpiration(m, msg, end, &rptr->uDNS_info); - hndlRecordUpdateReply(m, rptr, err); - return; - } + LogMsg("Advertising hostname %##s IPv4 %.4a", h->arv4.resrec.name->c, &m->AdvertisedV4.ip.v4); + h->arv4.resrec.RecordType = kDNSRecordTypeKnownUnique; + mDNS_Register_internal(m, &h->arv4); } } - debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg->h.id)); + + if (!mDNSIPv6AddressIsZero(m->AdvertisedV6.ip.v6) && h->arv6.resrec.RecordType == kDNSRecordTypeUnregistered) + { + mDNS_SetupResourceRecord(&h->arv6, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL, kDNSRecordTypeKnownUnique, HostnameCallback, h); + AssignDomainName(&h->arv6.namestorage, &h->fqdn); + h->arv6.resrec.rdata->u.ipv6 = m->AdvertisedV6.ip.v6; + h->arv6.state = regState_Unregistered; + LogMsg("Advertising hostname %##s IPv6 %.16a", h->arv6.resrec.name->c, &m->AdvertisedV6.ip.v6); + mDNS_Register_internal(m, &h->arv6); + } } -// lookup a DNS Server, matching by name in split-dns configurations. Result stored in addr parameter if successful -mDNSlocal DNSServer *GetServerForName(uDNS_GlobalInfo *u, const domainname *name) - { - DNSServer *curmatch = mDNSNULL, *p = u->Servers; - int i, curmatchlen = -1; - int ncount = name ? CountLabels(name) : 0; +mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus result) + { + HostnameInfo *hi = (HostnameInfo *)rr->RecordContext; - while (p) + if (result == mStatus_MemFree) { - int scount = CountLabels(&p->domain); - if (scount <= ncount && scount > curmatchlen) + if (hi) { - // only inspect if server's domain is longer than current best match and shorter than the name itself - const domainname *tail = name; - for (i = 0; i < ncount - scount; i++) - tail = (domainname *)(tail->c + 1 + tail->c[0]); // find "tail" (scount labels) of name - if (SameDomainName(tail, &p->domain)) { curmatch = p; curmatchlen = scount; } + // If we're still in the Hostnames list, update to new address + HostnameInfo *i; + LogOperation("HostnameCallback: Got mStatus_MemFree for %p %p %s", hi, rr, ARDisplayString(m, rr)); + for (i = m->Hostnames; i; i = i->next) + if (rr == &i->arv4 || rr == &i->arv6) + { mDNS_Lock(m); AdvertiseHostname(m, i); mDNS_Unlock(m); return; } + + // Else, we're not still in the Hostnames list, so free the memory + if (hi->arv4.resrec.RecordType == kDNSRecordTypeUnregistered && + hi->arv6.resrec.RecordType == kDNSRecordTypeUnregistered) + { + if (hi->natinfo.clientContext) mDNS_StopNATOperation_internal(m, &hi->natinfo); + hi->natinfo.clientContext = mDNSNULL; + mDNSPlatformMemFree(hi); // free hi when both v4 and v6 AuthRecs deallocated + } } - p = p->next; + return; } - return(curmatch); - } -// *************************************************************************** -#if COMPILER_LIKES_PRAGMA_MARK -#pragma mark - Query Routines -#endif + if (result) + { + // don't unlink or free - we can retry when we get a new address/router + if (rr->resrec.rrtype == kDNSType_A) + LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.4a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv4); + else + LogMsg("HostnameCallback: Error %ld for registration of %##s IP %.16a", result, rr->resrec.name->c, &rr->resrec.rdata->u.ipv6); + if (!hi) { mDNSPlatformMemFree(rr); return; } + if (rr->state != regState_Unregistered) LogMsg("Error: HostnameCallback invoked with error code for record not in regState_Unregistered!"); -#define sameID(x,y) mDNSPlatformMemSame(x,y,8) + if (hi->arv4.state == regState_Unregistered && + hi->arv6.state == regState_Unregistered) + { + // only deliver status if both v4 and v6 fail + rr->RecordContext = (void *)hi->StatusContext; + if (hi->StatusCallback) + hi->StatusCallback(m, rr, result); // client may NOT make API calls here + rr->RecordContext = (void *)hi; + } + return; + } -mDNSlocal void initializeQuery(DNSMessage *msg, DNSQuestion *question) - { - ubzero(msg, sizeof(msg)); - InitializeDNSMessage(&msg->h, question->uDNS_info.id, uQueryFlags); - } + // register any pending services that require a target + mDNS_Lock(m); + UpdateSRVRecords(m); + mDNS_Unlock(m); -mDNSlocal mStatus constructQueryMsg(DNSMessage *msg, mDNSu8 **endPtr, DNSQuestion *const question) - { - initializeQuery(msg, question); + // Deliver success to client + if (!hi) { LogMsg("HostnameCallback invoked with orphaned address record"); return; } + if (rr->resrec.rrtype == kDNSType_A) + LogMsg("Registered hostname %##s IP %.4a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv4); + else + LogMsg("Registered hostname %##s IP %.16a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv6); - *endPtr = putQuestion(msg, msg->data, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass); - if (!*endPtr) - { - LogMsg("ERROR: Unicast query out of space in packet"); - return mStatus_UnknownErr; - } - return mStatus_NoError; + rr->RecordContext = (void *)hi->StatusContext; + if (hi->StatusCallback) + hi->StatusCallback(m, rr, result); // client may NOT make API calls here + rr->RecordContext = (void *)hi; } -mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, DNSQuestion *question, LLQOptData *data, mDNSBool includeQuestion) +mDNSlocal void FoundStaticHostname(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) { - AuthRecord rr; - ResourceRecord *opt = &rr.resrec; - rdataOpt *optRD; - - //!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section - if (includeQuestion) + const domainname *pktname = &answer->rdata->u.name; + domainname *storedname = &m->StaticHostname; + HostnameInfo *h = m->Hostnames; + + (void)question; + + debugf("FoundStaticHostname: %##s -> %##s (%s)", question->qname.c, answer->rdata->u.name.c, AddRecord ? "added" : "removed"); + if (AddRecord && !SameDomainName(pktname, storedname)) { - ptr = putQuestion(msg, ptr, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass); - if (!ptr) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL; } + AssignDomainName(storedname, pktname); + while (h) + { + if (h->arv4.state == regState_FetchingZoneData || h->arv4.state == regState_Pending || h->arv4.state == regState_NATMap || + h->arv6.state == regState_FetchingZoneData || h->arv6.state == regState_Pending) + { + // if we're in the process of registering a dynamic hostname, delay SRV update so we don't have to reregister services if the dynamic name succeeds + m->NextSRVUpdate = NonZeroTime(m->timenow + (5 * mDNSPlatformOneSecond)); + return; + } + h = h->next; + } + mDNS_Lock(m); + UpdateSRVRecords(m); + mDNS_Unlock(m); } - // locate OptRR if it exists, set pointer to end - // !!!KRS implement me + else if (!AddRecord && SameDomainName(pktname, storedname)) + { + mDNS_Lock(m); + storedname->c[0] = 0; + UpdateSRVRecords(m); + mDNS_Unlock(m); + } + } - - // format opt rr (fields not specified are zero-valued) - ubzero(&rr, sizeof(AuthRecord)); - mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL); - opt->rdlength = LLQ_OPT_RDLEN; - opt->rdestimate = LLQ_OPT_RDLEN; +// Called with lock held +mDNSlocal void GetStaticHostname(mDNS *m) + { + char buf[MAX_REVERSE_MAPPING_NAME_V4]; + DNSQuestion *q = &m->ReverseMap; + mDNSu8 *ip = m->AdvertisedV4.ip.v4.b; + mStatus err; - optRD = &rr.resrec.rdata->u.opt; - optRD->opt = kDNSOpt_LLQ; - optRD->optlen = LLQ_OPTLEN; - umemcpy(&optRD->OptData.llq, data, sizeof(*data)); - ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.numAdditionals, opt, 0); - if (!ptr) { LogMsg("ERROR: putLLQ - PutResourceRecordTTLJumbo"); return mDNSNULL; } + if (m->ReverseMap.ThisQInterval != -1) mDNS_StopQuery_internal(m, q); - return ptr; - } + m->StaticHostname.c[0] = 0; + if (mDNSIPv4AddressIsZero(m->AdvertisedV4.ip.v4)) return; + mDNSPlatformMemZero(q, sizeof(*q)); + // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code + mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", ip[3], ip[2], ip[1], ip[0]); + if (!MakeDomainNameFromDNSNameString(&q->qname, buf)) { LogMsg("Error: GetStaticHostname - bad name %s", buf); return; } - -mDNSlocal mDNSBool getLLQAtIndex(mDNS *m, DNSMessage *msg, const mDNSu8 *end, LLQOptData *llq, int index) - { - LargeCacheRecord lcr; - int i; - const mDNSu8 *ptr; - - ubzero(&lcr, sizeof(lcr)); - - ptr = LocateAdditionals(msg, end); - if (!ptr) return mDNSfalse; - - // find the last additional - for (i = 0; i < msg->h.numAdditionals; i++) -// { ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); if (!ptr) return mDNSfalse; } -//!!!KRS workaround for LH server bug, which puts OPT as first additional - { ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); if (!ptr) return mDNSfalse; if (lcr.r.resrec.rrtype == kDNSType_OPT) break; } - if (lcr.r.resrec.rrtype != kDNSType_OPT) return mDNSfalse; - if (lcr.r.resrec.rdlength < (index + 1) * LLQ_OPT_RDLEN) return mDNSfalse; // rdata too small - umemcpy(llq, (mDNSu8 *)&lcr.r.resrec.rdata->u.opt.OptData.llq + (index * sizeof(*llq)), sizeof(*llq)); - return mDNStrue; + q->InterfaceID = mDNSInterface_Any; + q->Target = zeroAddr; + q->qtype = kDNSType_PTR; + q->qclass = kDNSClass_IN; + q->LongLived = mDNSfalse; + q->ExpectUnique = mDNSfalse; + q->ForceMCast = mDNSfalse; + q->ReturnIntermed = mDNStrue; + q->QuestionCallback = FoundStaticHostname; + q->QuestionContext = mDNSNULL; + + err = mDNS_StartQuery_internal(m, q); + if (err) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err); } -mDNSlocal void recvRefreshReply(mDNS *m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *q) - { - LLQ_Info *qInfo; - LLQOptData pktData; - - qInfo = q->uDNS_info.llq; - if (!getLLQAtIndex(m, msg, end, &pktData, 0)) { LogMsg("ERROR recvRefreshReply - getLLQAtIndex"); return; } - if (pktData.llqOp != kLLQOp_Refresh) return; - if (!sameID(pktData.id, qInfo->id)) { LogMsg("recvRefreshReply - ID mismatch. Discarding"); return; } - if (pktData.err != LLQErr_NoError) { LogMsg("recvRefreshReply: received error %d from server", pktData.err); return; } - - qInfo->expire = mDNSPlatformTimeNow(m) + ((mDNSs32)pktData.lease * mDNSPlatformOneSecond); - qInfo->retry = qInfo->expire - ((mDNSs32)pktData.lease * mDNSPlatformOneSecond/2); - - qInfo->origLease = pktData.lease; - qInfo->state = LLQ_Established; +mDNSexport void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext) + { + HostnameInfo **ptr = &m->Hostnames; + + LogOperation("mDNS_AddDynDNSHostName %##s", fqdn); + + while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next; + if (*ptr) { LogMsg("DynDNSHostName %##s already in list", fqdn->c); return; } + + // allocate and format new address record + *ptr = mDNSPlatformMemAllocate(sizeof(**ptr)); + if (!*ptr) { LogMsg("ERROR: mDNS_AddDynDNSHostName - malloc"); return; } + + mDNSPlatformMemZero(*ptr, sizeof(**ptr)); + AssignDomainName(&(*ptr)->fqdn, fqdn); + (*ptr)->arv4.state = regState_Unregistered; + (*ptr)->arv6.state = regState_Unregistered; + (*ptr)->StatusCallback = StatusCallback; + (*ptr)->StatusContext = StatusContext; + + AdvertiseHostname(m, *ptr); } -mDNSlocal void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease) +mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn) { - DNSMessage msg; - mDNSu8 *end; - LLQOptData llq; - LLQ_Info *info = q->uDNS_info.llq; - mStatus err; - mDNSs32 timenow; + HostnameInfo **ptr = &m->Hostnames; + + LogOperation("mDNS_RemoveDynDNSHostName %##s", fqdn); - timenow = mDNSPlatformTimeNow(m); - if ((info->state == LLQ_Refresh && info->ntries >= kLLQ_MAX_TRIES) || - info->expire - timenow < 0) + while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next; + if (!*ptr) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn->c); + else { - LogMsg("Unable to refresh LLQ %##s - will retry in %d minutes", q->qname.c, kLLQ_DEF_RETRY/60); - info->state = LLQ_Retry; - info->retry = mDNSPlatformTimeNow(m) + kLLQ_DEF_RETRY * mDNSPlatformOneSecond; - info->deriveRemovesOnResume = mDNStrue; - return; - //!!!KRS handle this - periodically try to re-establish + HostnameInfo *hi = *ptr; + // We do it this way because, if we have no active v6 record, the "mDNS_Deregister_internal(m, &hi->arv4);" + // below could free the memory, and we have to make sure we don't touch hi fields after that. + mDNSBool f4 = hi->arv4.resrec.RecordType != kDNSRecordTypeUnregistered && hi->arv4.state != regState_Unregistered; + mDNSBool f6 = hi->arv6.resrec.RecordType != kDNSRecordTypeUnregistered && hi->arv6.state != regState_Unregistered; + if (f4) LogOperation("mDNS_RemoveDynDNSHostName removing v4 %##s", fqdn); + if (f6) LogOperation("mDNS_RemoveDynDNSHostName removing v6 %##s", fqdn); + *ptr = (*ptr)->next; // unlink + if (f4) mDNS_Deregister_internal(m, &hi->arv4, mDNS_Dereg_normal); + if (f6) mDNS_Deregister_internal(m, &hi->arv6, mDNS_Dereg_normal); + // When both deregistrations complete we'll free the memory in the mStatus_MemFree callback } + UpdateSRVRecords(m); + } - llq.vers = kLLQ_Vers; - llq.llqOp = kLLQOp_Refresh; - llq.err = LLQErr_NoError; - umemcpy(llq.id, info->id, 8); - llq.lease = lease; +// Currently called without holding the lock +// Maybe we should change that? +mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router) + { + mDNSBool v4Changed, v6Changed, RouterChanged; - initializeQuery(&msg, q); - end = putLLQ(&msg, msg.data, q, &llq, mDNStrue); - if (!end) { LogMsg("ERROR: sendLLQRefresh - putLLQ"); return; } - - err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL); - if (err) debugf("ERROR: sendLLQRefresh - mDNSSendDNSMessage returned %ld", err); + if (m->mDNS_busy != m->mDNS_reentrancy) + LogMsg("mDNS_SetPrimaryInterfaceInfo: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); - if (info->state == LLQ_Established) info->ntries = 1; - else info->ntries++; - info->state = LLQ_Refresh; - q->LastQTime = timenow; - info->retry = (info->expire - q->LastQTime) / 2; - } + if (v4addr && v4addr->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo v4 address - incorrect type. Discarding. %#a", v4addr); return; } + if (v6addr && v6addr->type != mDNSAddrType_IPv6) { LogMsg("mDNS_SetPrimaryInterfaceInfo v6 address - incorrect type. Discarding. %#a", v6addr); return; } + if (router && router->type != mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo passed non-v4 router. Discarding. %#a", router); return; } -mDNSlocal mDNSBool recvLLQEvent(mDNS *m, DNSQuestion *q, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, mDNSInterfaceID InterfaceID) - { - DNSMessage ack; - mDNSu8 *ackEnd = ack.data; - mStatus err; - LLQOptData opt; + mDNS_Lock(m); + + if (v4addr && !mDNSv4AddressIsLinkLocal(&v4addr->ip.v4)) v6addr = mDNSNULL; + + v4Changed = !mDNSSameIPv4Address(m->AdvertisedV4.ip.v4, v4addr ? v4addr->ip.v4 : zerov4Addr); + v6Changed = !mDNSSameIPv6Address(m->AdvertisedV6.ip.v6, v6addr ? v6addr->ip.v6 : zerov6Addr); + RouterChanged = !mDNSSameIPv4Address(m->Router.ip.v4, router ? router->ip.v4 : zerov4Addr); + + if (v4addr && (v4Changed || RouterChanged)) + debugf("mDNS_SetPrimaryInterfaceInfo: address changed from %#a to %#a", &m->AdvertisedV4, v4addr); + + if (v4addr) m->AdvertisedV4 = *v4addr; else m->AdvertisedV4.ip.v4 = zerov4Addr; + if (v6addr) m->AdvertisedV6 = *v6addr; else m->AdvertisedV6.ip.v6 = zerov6Addr; + if (router) m->Router = *router; else m->Router .ip.v4 = zerov4Addr; + // setting router to zero indicates that nat mappings must be reestablished when router is reset + + if (v4Changed || RouterChanged || v6Changed) + { + HostnameInfo *i; + LogOperation("mDNS_SetPrimaryInterfaceInfo: %s%s%s%#a %#a %#a", + v4Changed ? "v4Changed " : "", + RouterChanged ? "RouterChanged " : "", + v6Changed ? "v6Changed " : "", v4addr, v6addr, router); + + for (i = m->Hostnames; i; i = i->next) + { + LogOperation("mDNS_SetPrimaryInterfaceInfo updating host name registrations for %##s", i->fqdn.c); - (void)InterfaceID; // unused - - // find Opt RR, verify correct ID - if (!getLLQAtIndex(m, msg, end, &opt, 0)) { debugf("Pkt does not contain LLQ Opt"); return mDNSfalse; } - if (!q->uDNS_info.llq) { LogMsg("Error: recvLLQEvent - question object does not contain LLQ metadata"); return mDNSfalse; } - if (!sameID(opt.id, q->uDNS_info.llq->id)) { return mDNSfalse; } - if (opt.llqOp != kLLQOp_Event) { if (!q->uDNS_info.llq->ntries) LogMsg("recvLLQEvent - Bad LLQ Opcode %d", opt.llqOp); return mDNSfalse; } - - // invoke response handler - m->uDNS_info.CurrentQuery = q; - q->uDNS_info.responseCallback(m, msg, end, q, q->uDNS_info.context); - if (m->uDNS_info.CurrentQuery != q) return mDNStrue; + if (i->arv4.resrec.RecordType > kDNSRecordTypeDeregistering && + !mDNSSameIPv4Address(i->arv4.resrec.rdata->u.ipv4, m->AdvertisedV4.ip.v4)) + { + LogOperation("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m, &i->arv4)); + mDNS_Deregister_internal(m, &i->arv4, mDNS_Dereg_normal); + } - // format and send ack - InitializeDNSMessage(&ack.h, msg->h.id, ResponseFlags); - ackEnd = putLLQ(&ack, ack.data, mDNSNULL, &opt, mDNSfalse); - if (!ackEnd) { LogMsg("ERROR: recvLLQEvent - putLLQ"); return mDNSfalse; } - err = mDNSSendDNSMessage(m, &ack, ackEnd, mDNSInterface_Any, srcaddr, srcport, -1, mDNSNULL); - if (err) debugf("ERROR: recvLLQEvent - mDNSSendDNSMessage returned %ld", err); - return mDNStrue; - } + if (i->arv6.resrec.RecordType > kDNSRecordTypeDeregistering && + !mDNSSameIPv6Address(i->arv6.resrec.rdata->u.ipv6, m->AdvertisedV6.ip.v6)) + { + LogOperation("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m, &i->arv6)); + mDNS_Deregister_internal(m, &i->arv6, mDNS_Dereg_normal); + } + // AdvertiseHostname will only register new address records. + // For records still in the process of deregistering it will ignore them, and let the mStatus_MemFree callback handle them. + AdvertiseHostname(m, i); + } + + if (v4Changed || RouterChanged) + { + m->ExternalAddress = zerov4Addr; + m->retryIntervalGetAddr = NATMAP_INIT_RETRY; + m->retryGetAddr = m->timenow; + m->NextScheduledNATOp = m->timenow; + ClearUPnPState(m); + } + UpdateSRVRecords(m); + GetStaticHostname(m); // look up reverse map record to find any static hostnames for our IP address + } -mDNSlocal void hndlChallengeResponseAck(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, LLQOptData *llq, DNSQuestion *q) + mDNS_Unlock(m); + } + +// *************************************************************************** +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - Incoming Message Processing +#endif + +mDNSlocal mStatus ParseTSIGError(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const domainname *const displayname) { - LLQ_Info *info = q->uDNS_info.llq; - - if (llq->err) { LogMsg("hndlChallengeResponseAck - received error %d from server", llq->err); goto error; } - if (!sameID(info->id, llq->id)) { LogMsg("hndlChallengeResponseAck - ID changed. discarding"); return; } // this can happen rarely (on packet loss + reordering) - info->expire = mDNSPlatformTimeNow(m) + ((mDNSs32)llq->lease * mDNSPlatformOneSecond); - info->retry = info->expire - ((mDNSs32)llq->lease * mDNSPlatformOneSecond / 2); - - info->origLease = llq->lease; - info->state = LLQ_Established; - - q->uDNS_info.responseCallback = llqResponseHndlr; - llqResponseHndlr(m, pktMsg, end, q, mDNSNULL); - return; + const mDNSu8 *ptr; + mStatus err = mStatus_NoError; + int i; - error: - info->state = LLQ_Error; + ptr = LocateAdditionals(msg, end); + if (!ptr) goto finish; + + for (i = 0; i < msg->h.numAdditionals; i++) + { + ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec); + if (!ptr) goto finish; + if (m->rec.r.resrec.rrtype == kDNSType_TSIG) + { + mDNSu32 macsize; + mDNSu8 *rd = m->rec.r.resrec.rdata->u.data; + mDNSu8 *rdend = rd + m->rec.r.resrec.rdlength; + int alglen = DomainNameLengthLimit(&m->rec.r.resrec.rdata->u.name, rdend); + if (alglen > MAX_DOMAIN_NAME) goto finish; + rd += alglen; // algorithm name + if (rd + 6 > rdend) goto finish; + rd += 6; // 48-bit timestamp + if (rd + sizeof(mDNSOpaque16) > rdend) goto finish; + rd += sizeof(mDNSOpaque16); // fudge + if (rd + sizeof(mDNSOpaque16) > rdend) goto finish; + macsize = mDNSVal16(*(mDNSOpaque16 *)rd); + rd += sizeof(mDNSOpaque16); // MAC size + if (rd + macsize > rdend) goto finish; + rd += macsize; + if (rd + sizeof(mDNSOpaque16) > rdend) goto finish; + rd += sizeof(mDNSOpaque16); // orig id + if (rd + sizeof(mDNSOpaque16) > rdend) goto finish; + err = mDNSVal16(*(mDNSOpaque16 *)rd); // error code + + if (err == TSIG_ErrBadSig) { LogMsg("%##s: bad signature", displayname->c); err = mStatus_BadSig; } + else if (err == TSIG_ErrBadKey) { LogMsg("%##s: bad key", displayname->c); err = mStatus_BadKey; } + else if (err == TSIG_ErrBadTime) { LogMsg("%##s: bad time", displayname->c); err = mStatus_BadTime; } + else if (err) { LogMsg("%##s: unknown tsig error %d", displayname->c, err); err = mStatus_UnknownErr; } + goto finish; + } + m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it + } + + finish: + m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it + return err; } -mDNSlocal void sendChallengeResponse(mDNS *m, DNSQuestion *q, LLQOptData *llq) +mDNSlocal mStatus checkUpdateResult(mDNS *const m, const domainname *const displayname, const mDNSu8 rcode, const DNSMessage *const msg, const mDNSu8 *const end) { - LLQ_Info *info = q->uDNS_info.llq; - DNSMessage response; - mDNSu8 *responsePtr = response.data; - mStatus err; - LLQOptData llqBuf; - mDNSs32 timenow = mDNSPlatformTimeNow(m); - - if (info->ntries++ == kLLQ_MAX_TRIES) + (void)msg; // currently unused, needed for TSIG errors + if (!rcode) return mStatus_NoError; + else if (rcode == kDNSFlag1_RC_YXDomain) { - LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s. Will re-try in %d minutes", - kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60); - info->state = LLQ_Retry; - info->retry = timenow + (kLLQ_DEF_RETRY * mDNSPlatformOneSecond); - // !!!KRS give a callback error in these cases? - return; + debugf("name in use: %##s", displayname->c); + return mStatus_NameConflict; } - - if (!llq) + else if (rcode == kDNSFlag1_RC_Refused) { - llq = &llqBuf; - llq->vers = kLLQ_Vers; - llq->llqOp = kLLQOp_Setup; - llq->err = LLQErr_NoError; - umemcpy(llq->id, info->id, 8); - llq->lease = info->origLease; + LogMsg("Update %##s refused", displayname->c); + return mStatus_Refused; } + else if (rcode == kDNSFlag1_RC_NXRRSet) + { + LogMsg("Reregister refused (NXRRSET): %##s", displayname->c); + return mStatus_NoSuchRecord; + } + else if (rcode == kDNSFlag1_RC_NotAuth) + { + // TSIG errors should come with FmtErr as per RFC 2845, but BIND 9 sends them with NotAuth so we look here too + mStatus tsigerr = ParseTSIGError(m, msg, end, displayname); + if (!tsigerr) + { + LogMsg("Permission denied (NOAUTH): %##s", displayname->c); + return mStatus_UnknownErr; + } + else return tsigerr; + } + else if (rcode == kDNSFlag1_RC_FmtErr) + { + mStatus tsigerr = ParseTSIGError(m, msg, end, displayname); + if (!tsigerr) + { + LogMsg("Format Error: %##s", displayname->c); + return mStatus_UnknownErr; + } + else return tsigerr; + } + else + { + LogMsg("Update %##s failed with rcode %d", displayname->c, rcode); + return mStatus_UnknownErr; + } + } - q->LastQTime = timenow; - info->retry = timenow + (kLLQ_INIT_RESEND * info->ntries * mDNSPlatformOneSecond); - - if (constructQueryMsg(&response, &responsePtr, q)) goto error; - responsePtr = putLLQ(&response, responsePtr, q, llq, mDNSfalse); - if (!responsePtr) { LogMsg("ERROR: sendChallengeResponse - putLLQ"); goto error; } - - err = mDNSSendDNSMessage(m, &response, responsePtr, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL); - if (err) debugf("ERROR: sendChallengeResponse - mDNSSendDNSMessage returned %ld", err); - // on error, we procede as normal and retry after the appropriate interval +// Called with lock held +mDNSlocal void SendRecordRegistration(mDNS *const m, AuthRecord *rr) + { + mDNSu8 *ptr = m->omsg.data; + mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage); + mStatus err = mStatus_UnknownErr; - return; + if (m->mDNS_busy != m->mDNS_reentrancy+1) + LogMsg("SendRecordRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); - error: - info->state = LLQ_Error; - } + rr->RequireGoodbye = mDNStrue; + rr->id = mDNS_NewMessageID(m); + InitializeDNSMessage(&m->omsg.h, rr->id, UpdateReqFlags); + // set zone + ptr = putZone(&m->omsg, ptr, end, &rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass)); + if (!ptr) { err = mStatus_UnknownErr; goto exit; } + if (rr->state == regState_UpdatePending) + { + // delete old RData + SetNewRData(&rr->resrec, rr->OrigRData, rr->OrigRDLen); + if (!(ptr = putDeletionRecord(&m->omsg, ptr, &rr->resrec))) { err = mStatus_UnknownErr; goto exit; } // delete old rdata -mDNSlocal void hndlRequestChallenge(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, LLQOptData *llq, DNSQuestion *q) - { - LLQ_Info *info = q->uDNS_info.llq; - mDNSs32 timenow = mDNSPlatformTimeNow(m); - switch(llq->err) - { - case LLQErr_NoError: break; - case LLQErr_ServFull: - LogMsg("hndlRequestChallenge - received ServFull from server for LLQ %##s. Retry in %lu sec", q->qname.c, llq->lease); - info->retry = timenow + ((mDNSs32)llq->lease * mDNSPlatformOneSecond); - info->state = LLQ_Retry; - simpleResponseHndlr(m, pktMsg, end, q, mDNSNULL); // get available answers - info->deriveRemovesOnResume = mDNStrue; - case LLQErr_Static: - info->state = LLQ_Static; - LogMsg("LLQ %##s: static", q->qname.c); - simpleResponseHndlr(m, pktMsg, end, q, mDNSNULL); - return; - case LLQErr_FormErr: - LogMsg("ERROR: hndlRequestChallenge - received FormErr from server for LLQ %##s", q->qname.c); - goto error; - case LLQErr_BadVers: - LogMsg("ERROR: hndlRequestChallenge - received BadVers from server"); - goto error; - case LLQErr_UnknownErr: - LogMsg("ERROR: hndlRequestChallenge - received UnknownErr from server for LLQ %##s", q->qname.c); - goto error; - default: - LogMsg("ERROR: hndlRequestChallenge - received invalid error %d for LLQ %##s", llq->err, q->qname.c); - goto error; + // add new RData + SetNewRData(&rr->resrec, rr->InFlightRData, rr->InFlightRDLen); + if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; } } - if (info->origLease != llq->lease) - debugf("hndlRequestChallenge: requested lease %lu, granted lease %lu", info->origLease, llq->lease); - - // cache expiration in case we go to sleep before finishing setup - info->origLease = llq->lease; - info->expire = timenow + ((mDNSs32)llq->lease * mDNSPlatformOneSecond); + else + { + if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique) + { + // KnownUnique: Delete any previous value + ptr = putDeleteRRSet(&m->omsg, ptr, rr->resrec.name, rr->resrec.rrtype); + if (!ptr) { err = mStatus_UnknownErr; goto exit; } + } - // update state - info->state = LLQ_SecondaryRequest; - umemcpy(info->id, llq->id, 8); - info->ntries = 0; // first attempt to send response + else if (rr->resrec.RecordType != kDNSRecordTypeShared) + { + ptr = putPrereqNameNotInUse(rr->resrec.name, &m->omsg, ptr, end); + if (!ptr) { err = mStatus_UnknownErr; goto exit; } + } - sendChallengeResponse(m, q, llq); - return; + ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl); + if (!ptr) { err = mStatus_UnknownErr; goto exit; } + } + if (rr->uselease) + { + ptr = putUpdateLease(&m->omsg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) { err = mStatus_UnknownErr; goto exit; } + } - error: - info->state = LLQ_Error; - } + if (rr->Private) + { + LogOperation("SendRecordRegistration TCP %p %s", rr->tcp, ARDisplayString(m, rr)); + if (rr->tcp) LogMsg("SendRecordRegistration: Already have TCP connection for %s", ARDisplayString(m, rr)); + else rr->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, mDNSNULL, rr); + rr->LastAPTime = m->timenow; + rr->ThisAPInterval = 0x3FFFFFFF; // TCP will handle any necessary retransmissions for us + } + else + { + err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name)); + if (err) debugf("ERROR: SendRecordRegistration - mDNSSendDNSMessage - %ld", err); + SetRecordRetry(m, rr, err); + } + if (rr->state != regState_Refresh && rr->state != regState_DeregDeferred && rr->state != regState_UpdatePending) + rr->state = regState_Pending; -// response handler for initial and secondary setup responses -mDNSlocal void recvSetupResponse(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end, DNSQuestion *q, void *clientContext) - { - DNSQuestion pktQuestion; - LLQOptData llq; - const mDNSu8 *ptr = pktMsg->data; - LLQ_Info *info = q->uDNS_info.llq; - mDNSu8 rcode = (mDNSu8)(pktMsg->h.flags.b[1] & kDNSFlag1_RC); + err = mStatus_NoError; - (void)clientContext; // unused - - if (rcode && rcode != kDNSFlag1_RC_NXDomain) goto poll; - - ptr = getQuestion(pktMsg, ptr, end, 0, &pktQuestion); - if (!ptr) { LogMsg("ERROR: recvSetupResponse - getQuestion"); goto poll; } - if (!SameDomainName(&q->qname, &pktQuestion.qname)) - { LogMsg("ERROR: recvSetupResponse - mismatched question in response for llq setup %##s", q->qname.c); goto poll; } - - if (!getLLQAtIndex(m, pktMsg, end, &llq, 0)) { debugf("recvSetupResponse - GetLLQAtIndex"); goto poll; } - if (llq.llqOp != kLLQOp_Setup) { LogMsg("ERROR: recvSetupResponse - bad op %d", llq.llqOp); goto poll; } - if (llq.vers != kLLQ_Vers) { LogMsg("ERROR: recvSetupResponse - bad vers %d", llq.vers); goto poll; } - - if (info->state == LLQ_InitialRequest) { hndlRequestChallenge(m, pktMsg, end, &llq, q); return; } - if (info->state == LLQ_SecondaryRequest) { hndlChallengeResponseAck(m, pktMsg, end, &llq, q); return; } - LogMsg("recvSetupResponse - bad state %d", info->state); - - poll: - info->state = LLQ_Poll; - q->uDNS_info.responseCallback = llqResponseHndlr; - info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL); // trigger immediate poll - info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL; - } +exit: -mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info, mDNSBool defer) - { - DNSMessage msg; - mDNSu8 *end; - LLQOptData llqData; - DNSQuestion *q = info->question; - mStatus err = mStatus_NoError; - mDNSs32 timenow = mDNSPlatformTimeNow(m); - uDNS_GlobalInfo *u = &m->uDNS_info; - - if (IsPrivateV4Addr(&u->AdvertisedV4)) + if (err) { - if (!u->LLQNatInfo) + LogMsg("SendRecordRegistration: Error formatting message %d", err); + + if (rr->state != regState_Unregistered) { - info->state = LLQ_NatMapWait; - StartLLQNatMap(m); - return; + UnlinkAuthRecord(m, rr); + rr->state = regState_Unregistered; } - if (u->LLQNatInfo->state == NATState_Error) goto poll; - if (u->LLQNatInfo->state != NATState_Established && u->LLQNatInfo->state != NATState_Legacy) - { info->state = LLQ_NatMapWait; info->NATMap = mDNStrue; return; } - info->NATMap = mDNStrue; // this llq references the global llq nat mapping - } - - if (info->ntries++ >= kLLQ_MAX_TRIES) - { - debugf("startLLQHandshake: %d failed attempts for LLQ %##s. Polling.", kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60); - goto poll; - } - - // set llq rdata - llqData.vers = kLLQ_Vers; - llqData.llqOp = kLLQOp_Setup; - llqData.err = LLQErr_NoError; - ubzero(llqData.id, 8); - llqData.lease = kLLQ_DefLease; - - initializeQuery(&msg, q); - end = putLLQ(&msg, msg.data, q, &llqData, mDNStrue); - if (!end) - { - LogMsg("ERROR: startLLQHandshake - putLLQ"); - info->state = LLQ_Error; - return; + + mDNS_DropLockBeforeCallback(); + if (rr->RecordCallback) + rr->RecordCallback(m, rr, err); + mDNS_ReclaimLockAfterCallback(); + // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function + // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. } + } + +// Called with lock held +mDNSlocal void hndlServiceUpdateReply(mDNS *const m, ServiceRecordSet *srs, mStatus err) + { + mDNSBool InvokeCallback = mDNSfalse; + ExtraResourceRecord **e = &srs->Extras; + AuthRecord *txt = &srs->RR_TXT; + + if (m->mDNS_busy != m->mDNS_reentrancy+1) + LogMsg("hndlServiceUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); - if (!defer) // if we are to defer, we simply set the retry timers so the request goes out in the future + switch (srs->state) { - err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &info->servAddr, info->servPort, -1, mDNSNULL); - if (err) debugf("ERROR: startLLQHandshake - mDNSSendDNSMessage returned %ld", err); - // on error, we procede as normal and retry after the appropriate interval + case regState_Pending: + if (err == mStatus_NameConflict && !srs->TestForSelfConflict) + { + srs->TestForSelfConflict = mDNStrue; + debugf("checking for self-conflict of service %##s", srs->RR_SRV.resrec.name->c); + SendServiceRegistration(m, srs); + return; + } + else if (srs->TestForSelfConflict) + { + srs->TestForSelfConflict = mDNSfalse; + if (err == mStatus_NoSuchRecord) err = mStatus_NameConflict; // NoSuchRecord implies that our prereq was not met, so we actually have a name conflict + if (err) srs->state = regState_Unregistered; + else srs->state = regState_Registered; + InvokeCallback = mDNStrue; + break; + } + else if (srs->srs_uselease && err == mStatus_UnknownErr && mDNSSameIPPort(srs->SRSUpdatePort, UnicastDNSPort)) + { + LogMsg("Re-trying update of service %##s without lease option", srs->RR_SRV.resrec.name->c); + srs->srs_uselease = mDNSfalse; + SendServiceRegistration(m, srs); + return; + } + else + { + //!!!KRS make sure all structs will still get cleaned up when client calls DeregisterService with this state + if (err) { LogMsg("Error %ld for registration of service %##s", err, srs->RR_SRV.resrec.name->c); srs->state = regState_Unregistered; } + else srs->state = regState_Registered; + InvokeCallback = mDNStrue; + break; + } + case regState_Refresh: + if (err) + { + LogMsg("Error %ld for refresh of service %##s", err, srs->RR_SRV.resrec.name->c); + InvokeCallback = mDNStrue; + srs->state = regState_Unregistered; + } + else srs->state = regState_Registered; + break; + case regState_DeregPending: + if (err) LogMsg("Error %ld for deregistration of service %##s", err, srs->RR_SRV.resrec.name->c); + if (srs->SRVChanged) + { + srs->state = regState_NoTarget; // NoTarget will allow us to pick up new target OR nat traversal state + break; + } + err = mStatus_MemFree; + InvokeCallback = mDNStrue; + if (srs->NATinfo.clientContext) + { + // deletion completed + mDNS_StopNATOperation_internal(m, &srs->NATinfo); + srs->NATinfo.clientContext = mDNSNULL; + } + srs->state = regState_Unregistered; + break; + case regState_DeregDeferred: + if (err) + { + debugf("Error %ld received prior to deferred derigstration of %##s", err, srs->RR_SRV.resrec.name->c); + err = mStatus_MemFree; + InvokeCallback = mDNStrue; + srs->state = regState_Unregistered; + break; + } + else + { + debugf("Performing deferred deregistration of %##s", srs->RR_SRV.resrec.name->c); + srs->state = regState_Registered; + SendServiceDeregistration(m, srs); + return; + } + case regState_UpdatePending: + if (err) + { + LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs->RR_SRV.resrec.name->c); + srs->state = regState_Unregistered; + InvokeCallback = mDNStrue; + } + else + { + srs->state = regState_Registered; + // deallocate old RData + if (txt->UpdateCallback) txt->UpdateCallback(m, txt, txt->OrigRData); + SetNewRData(&txt->resrec, txt->InFlightRData, txt->InFlightRDLen); + txt->OrigRData = mDNSNULL; + txt->InFlightRData = mDNSNULL; + } + break; + case regState_FetchingZoneData: + case regState_Registered: + case regState_Unregistered: + case regState_NATMap: + case regState_NoTarget: + case regState_ExtraQueued: + case regState_NATError: + LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %ld. Unlinking.", + srs->RR_SRV.resrec.name->c, srs->state, err); + err = mStatus_UnknownErr; + default: LogMsg("hndlServiceUpdateReply: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c); } - - // update question/info state - info->state = LLQ_InitialRequest; - info->origLease = kLLQ_DefLease; - info->retry = timenow + (kLLQ_INIT_RESEND * mDNSPlatformOneSecond); - q->LastQTime = timenow; - q->uDNS_info.responseCallback = recvSetupResponse; - q->uDNS_info.internal = mDNStrue; - return; - - poll: - info->question->uDNS_info.responseCallback = llqResponseHndlr; - info->state = LLQ_Poll; - info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL); // trigger immediate poll - info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL; - } -// wrapper for startLLQHandshake, invoked by async op callback -mDNSlocal void startLLQHandshakeCallback(mStatus err, mDNS *const m, void *llqInfo, const AsyncOpResult *result) - { - LLQ_Info *info = (LLQ_Info *)llqInfo; - const zoneData_t *zoneInfo = mDNSNULL; - - // check state first to make sure it is OK to touch question object - if (info->state == LLQ_Cancelled) + if ((srs->SRVChanged || srs->SRVUpdateDeferred) && (srs->state == regState_NoTarget || srs->state == regState_Registered)) { - // StopQuery was called while we were getting the zone info - debugf("startLLQHandshake - LLQ Cancelled."); - info->question = mDNSNULL; // question may be deallocated - ufree(info); + LogOperation("hndlServiceUpdateReply: SRVChanged %d SRVUpdateDeferred %d state %d", srs->SRVChanged, srs->SRVUpdateDeferred, srs->state); + if (InvokeCallback) + { + srs->ClientCallbackDeferred = mDNStrue; + srs->DeferredStatus = err; + } + srs->SRVChanged = srs->SRVUpdateDeferred = mDNSfalse; + UpdateSRV(m, srs); return; } - if (!info->question) - { LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL question"); goto error; } - - if (info->state != LLQ_GetZoneInfo) - { LogMsg("ERROR: startLLQHandshake - bad state %d", info->state); goto error; } - - if (err) - { LogMsg("ERROR: startLLQHandshakeCallback %##s invoked with error code %ld", info->question->qname.c, err); goto poll; } - - if (!result) - { LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL result and no error code"); goto error; } - - zoneInfo = &result->zoneData; - - if (!zoneInfo->llqPort.NotAnInteger) - { debugf("LLQ port lookup failed - reverting to polling"); info->servPort.NotAnInteger = 0; goto poll; } - - // cache necessary zone data - info->servAddr = zoneInfo->primaryAddr; - info->servPort = zoneInfo->llqPort; - info->ntries = 0; - - if (info->state == LLQ_SuspendDeferred) info->state = LLQ_Suspended; - else startLLQHandshake(m, info, mDNSfalse); - return; - - poll: - info->question->uDNS_info.responseCallback = llqResponseHndlr; - info->state = LLQ_Poll; - info->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL); // trigger immediate poll - info->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL; - return; - - error: - info->state = LLQ_Error; - } - -mDNSlocal mStatus startLLQ(mDNS *m, DNSQuestion *question) - { - LLQ_Info *info; - mStatus err = mStatus_NoError; - - // allocate / init info struct - info = umalloc(sizeof(LLQ_Info)); - if (!info) { LogMsg("ERROR: startLLQ - malloc"); return mStatus_NoMemoryErr; } - ubzero(info, sizeof(LLQ_Info)); - info->state = LLQ_GetZoneInfo; - - // link info/question - info->question = question; - question->uDNS_info.llq = info; - - question->uDNS_info.responseCallback = llqResponseHndlr; - - err = startGetZoneData(&question->qname, m, mDNSfalse, mDNStrue, startLLQHandshakeCallback, info); - if (err) + while (*e) { - LogMsg("ERROR: startLLQ - startGetZoneData returned %ld", err); - info->question = mDNSNULL; - ufree(info); - question->uDNS_info.llq = mDNSNULL; - return err; - } - - LinkActiveQuestion(&m->uDNS_info, question); - return err; - } - -mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID) - { - DNSQuestion pktQ, *q; - uDNS_GlobalInfo *u = &m->uDNS_info; - const mDNSu8 *ptr = msg->data; - LLQ_Info *llqInfo; - - if (!msg->h.numQuestions) return mDNSfalse; - - ptr = getQuestion(msg, ptr, end, 0, &pktQ); - if (!ptr) return mDNSfalse; - pktQ.uDNS_info.id = msg->h.id; - - q = u->ActiveQueries; - while (q) - { - llqInfo = q->uDNS_info.llq; - if (q->LongLived && - llqInfo && - q->qnamehash == pktQ.qnamehash && - q->qtype == pktQ.qtype && - SameDomainName(&q->qname, &pktQ.qname)) + if ((*e)->r.state == regState_ExtraQueued) { - u->CurrentQuery = q; - if (llqInfo->state == LLQ_Established || (llqInfo->state == LLQ_Refresh && msg->h.numAnswers)) - { if (recvLLQEvent(m, q, msg, end, srcaddr, srcport, InterfaceID)) return mDNStrue; } - else if (msg->h.id.NotAnInteger == q->uDNS_info.id.NotAnInteger) + if (srs->state == regState_Registered && !err) { - if (llqInfo->state == LLQ_Refresh && msg->h.numAdditionals && !msg->h.numAnswers) - { recvRefreshReply(m, msg, end, q); return mDNStrue; } - if (llqInfo->state < LLQ_Static) - { - if ((llqInfo->state != LLQ_InitialRequest && llqInfo->state != LLQ_SecondaryRequest) || mDNSSameAddress(srcaddr, &llqInfo->servAddr)) - { q->uDNS_info.responseCallback(m, msg, end, q, q->uDNS_info.context); return mDNStrue; } - } + // extra resource record queued for this service - copy zone srs and register + AssignDomainName(&(*e)->r.zone, &srs->zone); + (*e)->r.UpdateServer = srs->ns; + (*e)->r.UpdatePort = srs->SRSUpdatePort; + (*e)->r.uselease = srs->srs_uselease; + SendRecordRegistration(m, &(*e)->r); + e = &(*e)->next; + } + else if (err && (*e)->r.state != regState_Unregistered) + { + // unlink extra from list + (*e)->r.state = regState_Unregistered; + *e = (*e)->next; } + else e = &(*e)->next; } - q = q->next; + else e = &(*e)->next; } - return mDNSfalse; - } - -mDNSexport mDNSBool uDNS_IsActiveQuery(DNSQuestion *const question, uDNS_GlobalInfo *u) - { - DNSQuestion *q; - for (q = u->ActiveQueries; q; q = q->next) + srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL - 1; // reset retry delay for future refreshes, dereg, etc. + if (srs->state == regState_Unregistered) unlinkSRS(m, srs); + else if (txt->QueuedRData && srs->state == regState_Registered) { - if (q == question) + if (InvokeCallback) { - if (!question->uDNS_info.id.NotAnInteger || question->InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&question->qname)) - LogMsg("Warning: Question %##s in Active Unicast Query list with id %d, interfaceID %p", - question->qname.c, question->uDNS_info.id.NotAnInteger, question->InterfaceID); - return mDNStrue; + // if we were supposed to give a client callback, we'll do it after we update the primary txt record + srs->ClientCallbackDeferred = mDNStrue; + srs->DeferredStatus = err; } + srs->state = regState_UpdatePending; + txt->InFlightRData = txt->QueuedRData; + txt->InFlightRDLen = txt->QueuedRDLen; + txt->OrigRData = txt->resrec.rdata; + txt->OrigRDLen = txt->resrec.rdlength; + txt->QueuedRData = mDNSNULL; + SendServiceRegistration(m, srs); + return; } - return mDNSfalse; - } -// stopLLQ happens IN ADDITION to stopQuery -mDNSlocal void stopLLQ(mDNS *m, DNSQuestion *question) - { - LLQ_Info *info = question->uDNS_info.llq; - (void)m; // unused - - if (!question->LongLived) { LogMsg("ERROR: stopLLQ - LongLived flag not set"); return; } - if (!info) { LogMsg("ERROR: stopLLQ - llq info is NULL"); return; } - - switch (info->state) + mDNS_DropLockBeforeCallback(); + if (InvokeCallback) + srs->ServiceCallback(m, srs, err); + else if (srs->ClientCallbackDeferred) { - case LLQ_UnInit: - LogMsg("ERROR: stopLLQ - state LLQ_UnInit"); - //!!!KRS should we unlink info<->question here? - return; - case LLQ_GetZoneInfo: - case LLQ_SuspendDeferred: - info->question = mDNSNULL; // remove ref to question, as it may be freed when we get called back from async op - info->state = LLQ_Cancelled; - return; - case LLQ_Established: - case LLQ_Refresh: - // refresh w/ lease 0 - sendLLQRefresh(m, question, 0); - goto end; - default: - debugf("stopLLQ - silently discarding LLQ in state %d", info->state); - goto end; + srs->ClientCallbackDeferred = mDNSfalse; + srs->ServiceCallback(m, srs, srs->DeferredStatus); } - - end: - if (info->NATMap) info->NATMap = mDNSfalse; - CheckForUnreferencedLLQMapping(m); - info->question = mDNSNULL; - ufree(info); - question->uDNS_info.llq = mDNSNULL; - question->LongLived = mDNSfalse; + mDNS_ReclaimLockAfterCallback(); + // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function + // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. } -mDNSexport mStatus uDNS_StopQuery(mDNS *const m, DNSQuestion *const question) +// Called with lock held +mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err) { - uDNS_GlobalInfo *u = &m->uDNS_info; - DNSQuestion *qptr, *prev = mDNSNULL; - CacheRecord *ka; - - qptr = u->ActiveQueries; - while (qptr) - { - if (qptr == question) - { - if (question->LongLived && question->uDNS_info.llq) - stopLLQ(m, question); - if (m->uDNS_info.CurrentQuery == question) - m->uDNS_info.CurrentQuery = m->uDNS_info.CurrentQuery->next; - while (question->uDNS_info.knownAnswers) - { - ka = question->uDNS_info.knownAnswers; - question->uDNS_info.knownAnswers = question->uDNS_info.knownAnswers->next; - ufree(ka); - } - if (prev) prev->next = question->next; - else u->ActiveQueries = question->next; - return mStatus_NoError; - } - prev = qptr; - qptr = qptr->next; - } - LogMsg("uDNS_StopQuery: no such active query (%##s)", question->qname.c); - return mStatus_UnknownErr; - } - -mDNSlocal mStatus startQuery(mDNS *const m, DNSQuestion *const question, mDNSBool internal) - { - uDNS_GlobalInfo *u = &m->uDNS_info; - //!!!KRS we should check if the question is already in our activequestion list - if (!ValidateDomainName(&question->qname)) - { - LogMsg("Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); - return mStatus_Invalid; - } - - question->next = mDNSNULL; - question->qnamehash = DomainNameHashValue(&question->qname); // to do quick domain name comparisons - question->uDNS_info.id = newMessageID(u); - question->uDNS_info.Answered = mDNSfalse; - - // break here if its and LLQ - if (question->LongLived) return startLLQ(m, question); - - question->ThisQInterval = INIT_UCAST_POLL_INTERVAL / 2; - question->LastQTime = mDNSPlatformTimeNow(m) - question->ThisQInterval; - // store the question/id in active question list - question->uDNS_info.internal = internal; - LinkActiveQuestion(u, question); - question->uDNS_info.knownAnswers = mDNSNULL; - LogOperation("uDNS startQuery: %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); - - return mStatus_NoError; - } - -mDNSexport mStatus uDNS_StartQuery(mDNS *const m, DNSQuestion *const question) - { - ubzero(&question->uDNS_info, sizeof(uDNS_QuestionInfo)); - question->uDNS_info.responseCallback = simpleResponseHndlr; - question->uDNS_info.context = mDNSNULL; - //LogOperation("uDNS_StartQuery %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); - return startQuery(m, question, 0); - } - -// explicitly set response handler -mDNSlocal mStatus startInternalQuery(DNSQuestion *q, mDNS *m, InternalResponseHndlr callback, void *hndlrContext) - { - ubzero(&q->uDNS_info, sizeof(uDNS_QuestionInfo)); - q->QuestionContext = hndlrContext; - q->uDNS_info.responseCallback = callback; - q->uDNS_info.context = hndlrContext; - return startQuery(m, q, 1); - } - - - -// *************************************************************************** -#if COMPILER_LIKES_PRAGMA_MARK -#pragma mark - Domain -> Name Server Conversion -#endif - - -/* startGetZoneData - * - * Asynchronously find the address of the nameserver for the enclosing zone for a given domain name, - * i.e. the server to which update and LLQ requests will be sent for a given name. Once the address is - * derived, it will be passed to the callback, along with a context pointer. If the zone cannot - * be determined or if an error occurs, an all-zeros address will be passed and a message will be - * written to the syslog. - * - * If the FindUpdatePort arg is set, the port on which the server accepts dynamic updates is determined - * by querying for the _dns-update._udp.. SRV record. Likewise, if the FindLLQPort arg is set, - * the port on which the server accepts long lived queries is determined by querying for - * _dns-llq._udp.. record. If either of these queries fail, or flags are not specified, - * the llqPort and updatePort fields in the result structure are set to zero. - * - * Steps for deriving the zone name are as follows: - * - * Query for an SOA record for the required domain. If we don't get an answer (or an SOA in the Authority - * section), we strip the leading label from the name and repeat, until we get an answer. - * - * The name of the SOA record is our enclosing zone. The mname field in the SOA rdata is the domain - * name of the primary NS. - * - * We verify that there is an NS record with this zone for a name and the mname for its rdata. - * (!!!KRS this seems redundant, but BIND does this, and it should normally be zero-overhead since - * the NS query will get us address records in the additionals section, which we'd otherwise have to - * explicitly query for.) - * - * We then query for the address record for this nameserver (if it is not in the addionals section of - * the NS record response.) - */ - - -// state machine types and structs -// + mDNSBool InvokeCallback = mDNStrue; -// state machine states -typedef enum - { - init, - lookupSOA, - foundZone, - lookupNS, - foundNS, - lookupA, - foundA, - lookupPort, - foundPort, - complete - } ntaState; - -// state machine actions -typedef enum - { - smContinue, // continue immediately to next state - smBreak, // break until next packet/timeout - smError // terminal error - cleanup and abort - } smAction; - -typedef struct - { - domainname origName; // name we originally try to convert - domainname *curSOA; // name we have an outstanding SOA query for - ntaState state; // determines what we do upon receiving a packet - mDNS *m; - domainname zone; // left-hand-side of SOA record - mDNSu16 zoneClass; - domainname ns; // mname in SOA rdata, verified in confirmNS state - mDNSv4Addr addr; // address of nameserver - DNSQuestion question; // storage for any active question - DNSQuestion extraQuestion; // additional storage - mDNSBool questionActive; // if true, StopQuery() can be called on the question field - mDNSBool findUpdatePort; - mDNSBool findLLQPort; - mDNSIPPort updatePort; - mDNSIPPort llqPort; - AsyncOpCallback *callback; // caller specified function to be called upon completion - void *callbackInfo; - } ntaContext; - - -// function prototypes (for routines that must be used as fn pointers prior to their definitions, -// and allows states to be read top-to-bottom in logical order) -mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *contextPtr); -mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext *context); -mDNSlocal void processSOA(ntaContext *context, ResourceRecord *rr); -mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *context); -mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *context); -mDNSlocal smAction hndlLookupPorts(DNSMessage *msg, const mDNSu8 *end, ntaContext *context); - -// initialization -mDNSlocal mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdatePort, mDNSBool findLLQPort, - AsyncOpCallback callback, void *callbackInfo) - { - ntaContext *context = (ntaContext*)umalloc(sizeof(ntaContext)); - if (!context) { LogMsg("ERROR: startGetZoneData - umalloc failed"); return mStatus_NoMemoryErr; } - ubzero(context, sizeof(ntaContext)); - AssignDomainName(&context->origName, name); - context->state = init; - context->m = m; - context->callback = callback; - context->callbackInfo = callbackInfo; - context->findUpdatePort = findUpdatePort; - context->findLLQPort = findLLQPort; - getZoneData(m, mDNSNULL, mDNSNULL, mDNSNULL, context); - return mStatus_NoError; - } - -// state machine entry routine -mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DNSQuestion *question, void *contextPtr) - { - AsyncOpResult result; - ntaContext *context = (ntaContext*)contextPtr; - smAction action; - - // unused - (void)m; - (void)question; - - // stop any active question - if (context->questionActive) - { - uDNS_StopQuery(context->m, &context->question); - context->questionActive = mDNSfalse; - } + if (m->mDNS_busy != m->mDNS_reentrancy+1) + LogMsg("hndlRecordUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); - if (msg && msg->h.flags.b[2] >> 4 && msg->h.flags.b[2] >> 4 != kDNSFlag1_RC_NXDomain) - { - // rcode non-zero, non-nxdomain - LogMsg("ERROR: getZoneData - received response w/ rcode %d", msg->h.flags.b[2] >> 4); - goto error; - } - - switch (context->state) - { - case init: - case lookupSOA: - action = hndlLookupSOA(msg, end, context); - if (action == smError) goto error; - if (action == smBreak) return; - case foundZone: - case lookupNS: - action = confirmNS(msg, end, context); - if (action == smError) goto error; - if (action == smBreak) return; - case foundNS: - case lookupA: - action = lookupNSAddr(msg, end, context); - if (action == smError) goto error; - if (action == smBreak) return; - case foundA: - if (!context->findUpdatePort && !context->findLLQPort) - { - context->state = complete; - break; - } - case lookupPort: - action = hndlLookupPorts(msg, end, context); - if (action == smError) goto error; - if (action == smBreak) return; - if (action == smContinue) context->state = complete; - case foundPort: - case complete: break; - } - - if (context->state != complete) - { - LogMsg("ERROR: getZoneData - exited state machine with state %d", context->state); - goto error; - } - - result.type = zoneDataResult; - result.zoneData.primaryAddr.ip.v4 = context->addr; - result.zoneData.primaryAddr.type = mDNSAddrType_IPv4; - AssignDomainName(&result.zoneData.zoneName, &context->zone); - result.zoneData.zoneClass = context->zoneClass; - result.zoneData.llqPort = context->findLLQPort ? context->llqPort : zeroIPPort; - result.zoneData.updatePort = context->findUpdatePort ? context->updatePort : zeroIPPort; - context->callback(mStatus_NoError, context->m, context->callbackInfo, &result); - goto cleanup; - -error: - if (context && context->callback) - context->callback(mStatus_UnknownErr, context->m, context->callbackInfo, mDNSNULL); -cleanup: - if (context && context->questionActive) + if (rr->state == regState_UpdatePending) { - uDNS_StopQuery(context->m, &context->question); - context->questionActive = mDNSfalse; - } - if (context) ufree(context); - } - -mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext *context) - { - mStatus err; - LargeCacheRecord lcr; - ResourceRecord *rr = &lcr.r.resrec; - DNSQuestion *query = &context->question; - const mDNSu8 *ptr; - - if (msg) - { - // if msg contains SOA record in answer or authority sections, update context/state and return - int i; - ptr = LocateAnswers(msg, end); - for (i = 0; i < msg->h.numAnswers; i++) + if (err) { - ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr); - if (!ptr) { LogMsg("ERROR: hndlLookupSOA, Answers - GetLargeResourceRecord returned NULL"); return smError; } - if (rr->rrtype == kDNSType_SOA && SameDomainName(context->curSOA, rr->name)) - { - processSOA(context, rr); - return smContinue; - } + LogMsg("Update record failed for %##s (err %d)", rr->resrec.name->c, err); + rr->state = regState_Unregistered; } - ptr = LocateAuthorities(msg, end); - // SOA not in answers, check in authority - for (i = 0; i < msg->h.numAuthorities; i++) + else { - ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr); ///!!!KRS using type PacketAns for auth - if (!ptr) { LogMsg("ERROR: hndlLookupSOA, Authority - GetLargeResourceRecord returned NULL"); return smError; } - if (rr->rrtype == kDNSType_SOA) - { - processSOA(context, rr); - return smContinue; - } + debugf("Update record %##s - success", rr->resrec.name->c); + rr->state = regState_Registered; + // deallocate old RData + if (rr->UpdateCallback) rr->UpdateCallback(m, rr, rr->OrigRData); + SetNewRData(&rr->resrec, rr->InFlightRData, rr->InFlightRDLen); + rr->OrigRData = mDNSNULL; + rr->InFlightRData = mDNSNULL; } } - if (context->state != init && !context->curSOA->c[0]) - { - // we've gone down to the root and have not found an SOA - LogMsg("ERROR: hndlLookupSOA - recursed to root label of %##s without finding SOA", - context->origName.c); - return smError; - } - - ubzero(query, sizeof(DNSQuestion)); - // chop off leading label unless this is our first try - if (context->state == init) context->curSOA = &context->origName; - else context->curSOA = (domainname *)(context->curSOA->c + context->curSOA->c[0]+1); - - context->state = lookupSOA; - AssignDomainName(&query->qname, context->curSOA); - query->qtype = kDNSType_SOA; - query->qclass = kDNSClass_IN; - err = startInternalQuery(query, context->m, getZoneData, context); - context->questionActive = mDNStrue; - if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err); - - return smBreak; // break from state machine until we receive another packet - } - -mDNSlocal void processSOA(ntaContext *context, ResourceRecord *rr) - { - AssignDomainName(&context->zone, rr->name); - context->zoneClass = rr->rrclass; - AssignDomainName(&context->ns, &rr->rdata->u.soa.mname); - context->state = foundZone; - } - + if (rr->state == regState_DeregPending) + { + debugf("Received reply for deregister record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype); + if (err) LogMsg("ERROR: Deregistration of record %##s type %d failed with error %ld", + rr->resrec.name->c, rr->resrec.rrtype, err); + err = mStatus_MemFree; + rr->state = regState_Unregistered; + } -mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *context) - { - DNSQuestion *query = &context->question; - mStatus err; - LargeCacheRecord lcr; - const ResourceRecord *const rr = &lcr.r.resrec; - const mDNSu8 *ptr; - int i; - - if (context->state == foundZone) - { - // we've just learned the zone. confirm that an NS record exists - AssignDomainName(&query->qname, &context->zone); - query->qtype = kDNSType_NS; - query->qclass = kDNSClass_IN; - err = startInternalQuery(query, context->m, getZoneData, context); - context->questionActive = mDNStrue; - if (err) LogMsg("confirmNS: startInternalQuery returned error %ld (breaking until next periodic retransmission", err); - context->state = lookupNS; - return smBreak; // break from SM until we receive another packet - } - else if (context->state == lookupNS) - { - ptr = LocateAnswers(msg, end); - for (i = 0; i < msg->h.numAnswers; i++) + if (rr->state == regState_DeregDeferred) + { + if (err) { - ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr); - if (!ptr) { LogMsg("ERROR: confirmNS, Answers - GetLargeResourceRecord returned NULL"); return smError; } - if (rr->rrtype == kDNSType_NS && - SameDomainName(&context->zone, rr->name) && SameDomainName(&context->ns, &rr->rdata->u.name)) - { - context->state = foundNS; - return smContinue; // next routine will examine additionals section of A record - } + LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %ld", + rr->resrec.name->c, rr->resrec.rrtype, err); + rr->state = regState_Unregistered; } - debugf("ERROR: could not confirm existence of record %##s NS %##s", context->zone.c, context->ns.c); - return smError; + debugf("Calling deferred deregistration of record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype); + rr->state = regState_Registered; + mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); + return; } - else { LogMsg("ERROR: confirmNS - bad state %d", context->state); return smError; } - } - -mDNSlocal smAction queryNSAddr(ntaContext *context) - { - mStatus err; - DNSQuestion *query = &context->question; - - AssignDomainName(&query->qname, &context->ns); - query->qtype = kDNSType_A; - query->qclass = kDNSClass_IN; - err = startInternalQuery(query, context->m, getZoneData, context); - context->questionActive = mDNStrue; - if (err) LogMsg("confirmNS: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err); - context->state = lookupA; - return smBreak; - } -mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *context) - { - const mDNSu8 *ptr; - int i; - LargeCacheRecord lcr; - ResourceRecord *rr = &lcr.r.resrec; - - if (context->state == foundNS) + if (rr->state == regState_Pending || rr->state == regState_Refresh) { - // we just found the NS record - look for the corresponding A record in the Additionals section - if (!msg->h.numAdditionals) return queryNSAddr(context); - ptr = LocateAdditionals(msg, end); - if (!ptr) + if (!err) { - LogMsg("ERROR: lookupNSAddr - LocateAdditionals returned NULL, expected %d additionals", msg->h.numAdditionals); - return queryNSAddr(context); + rr->state = regState_Registered; + if (rr->state == regState_Refresh) InvokeCallback = mDNSfalse; } else { - for (i = 0; i < msg->h.numAdditionals; i++) + if (rr->uselease && err == mStatus_UnknownErr && mDNSSameIPPort(rr->UpdatePort, UnicastDNSPort)) { - ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr); - if (!ptr) - { - LogMsg("ERROR: lookupNSAddr, Additionals - GetLargeResourceRecord returned NULL"); - return queryNSAddr(context); - } - if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, rr->name)) - { - context->addr = rr->rdata->u.ipv4; - context->state = foundA; - return smContinue; - } + LogMsg("Re-trying update of record %##s without lease option", rr->resrec.name->c); + rr->uselease = mDNSfalse; + SendRecordRegistration(m, rr); + return; } + LogMsg("hndlRecordUpdateReply: Registration of record %##s type %d failed with error %ld", rr->resrec.name->c, rr->resrec.rrtype, err); + rr->state = regState_Unregistered; } - // no A record in Additionals - query the server - return queryNSAddr(context); } - else if (context->state == lookupA) + + if (rr->state == regState_Unregistered) UnlinkAuthRecord(m, rr); + else rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL - 1; // reset retry delay for future refreshes, dereg, etc. + + if (rr->QueuedRData && rr->state == regState_Registered) + { + rr->state = regState_UpdatePending; + rr->InFlightRData = rr->QueuedRData; + rr->InFlightRDLen = rr->QueuedRDLen; + rr->OrigRData = rr->resrec.rdata; + rr->OrigRDLen = rr->resrec.rdlength; + rr->QueuedRData = mDNSNULL; + SendRecordRegistration(m, rr); + return; + } + + if (InvokeCallback && rr->RecordCallback) { - ptr = LocateAnswers(msg, end); - if (!ptr) { LogMsg("ERROR: lookupNSAddr: LocateAnswers returned NULL"); return smError; } - for (i = 0; i < msg->h.numAnswers; i++) + mDNS_DropLockBeforeCallback(); + rr->RecordCallback(m, rr, err); + mDNS_ReclaimLockAfterCallback(); + } + // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function + // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. + } + +mDNSexport void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID InterfaceID, mDNSu8 *pkt, mDNSu16 len) + { + NATTraversalInfo *ptr; + NATAddrReply *AddrReply = (NATAddrReply *)pkt; + NATPortMapReply *PortMapReply = (NATPortMapReply *)pkt; + mDNSu32 nat_elapsed, our_elapsed; + + // Minimum packet is vers (1) opcode (1) err (2) upseconds (4) = 8 bytes + if (!AddrReply->err && len < 8) { LogMsg("NAT Traversal message too short (%d bytes)", len); return; } + if (AddrReply->vers != NATMAP_VERS) { LogMsg("Received NAT Traversal response with version %d (expected %d)", pkt[0], NATMAP_VERS); return; } + + // Read multi-byte numeric values (fields are identical in a NATPortMapReply) + AddrReply->err = (mDNSu16) ( (mDNSu16)pkt[2] << 8 | pkt[3]); + AddrReply->upseconds = (mDNSs32) ((mDNSs32)pkt[4] << 24 | (mDNSs32)pkt[5] << 16 | (mDNSs32)pkt[6] << 8 | pkt[7]); + + nat_elapsed = AddrReply->upseconds - m->LastNATupseconds; + our_elapsed = (m->timenow - m->LastNATReplyLocalTime) / mDNSPlatformOneSecond; + LogOperation("uDNS_ReceiveNATPMPPacket %X upseconds %u nat_elapsed %d our_elapsed %d", AddrReply->opcode, AddrReply->upseconds, nat_elapsed, our_elapsed); + + // We compute a conservative estimate of how much the NAT gateways's clock should have advanced + // 1. We subtract 12.5% from our own measured elapsed time, to allow for NAT gateways that have an inacurate clock that runs slowly + // 2. We add a two-second safety margin to allow for rounding errors: + // -- e.g. if NAT gateway sends a packet at t=2.00 seconds, then one at t=7.99, that's virtually 6 seconds, + // but based on the values in the packet (2,7) the apparent difference is only 5 seconds + // -- similarly, if we're slow handling packets and/or we have coarse clock granularity, we could over-estimate the true interval + // (e.g. t=1.99 seconds rounded to 1, and t=8.01 rounded to 8, gives an apparent difference of 7 seconds) + if (AddrReply->upseconds < m->LastNATupseconds || nat_elapsed + 2 < our_elapsed - our_elapsed/8) + { LogMsg("NAT gateway %#a rebooted", &m->Router); RecreateNATMappings(m); } + + m->LastNATupseconds = AddrReply->upseconds; + m->LastNATReplyLocalTime = m->timenow; + ClearUPnPState(m); // We know this is a NAT-PMP base station, so discard any prior UPnP state + + if (AddrReply->opcode == NATOp_AddrResponse) + { + if (!AddrReply->err && len < sizeof(NATAddrReply)) { LogMsg("NAT Traversal AddrResponse message too short (%d bytes)", len); return; } + natTraversalHandleAddressReply(m, AddrReply->err, AddrReply->ExtAddr); + } + else if (AddrReply->opcode == NATOp_MapUDPResponse || AddrReply->opcode == NATOp_MapTCPResponse) + { + mDNSu8 Protocol = AddrReply->opcode & 0x7F; + if (!PortMapReply->err) { - ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr); - if (!ptr) { LogMsg("ERROR: lookupNSAddr, Answers - GetLargeResourceRecord returned NULL"); break; } - if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, rr->name)) - { - context->addr = rr->rdata->u.ipv4; - context->state = foundA; - return smContinue; - } + if (len < sizeof(NATPortMapReply)) { LogMsg("NAT Traversal PortMapReply message too short (%d bytes)", len); return; } + PortMapReply->NATRep_lease = (mDNSu32) ((mDNSu32)pkt[12] << 24 | (mDNSu32)pkt[13] << 16 | (mDNSu32)pkt[14] << 8 | pkt[15]); } - LogMsg("ERROR: lookupNSAddr: Address record not found in answer section"); - return smError; + + for (ptr = m->NATTraversals; ptr; ptr=ptr->next) + if (ptr->Protocol == Protocol && mDNSSameIPPort(ptr->IntPort, PortMapReply->intport)) + natTraversalHandlePortMapReply(m, ptr, InterfaceID, PortMapReply->err, PortMapReply->extport, PortMapReply->NATRep_lease); } - else { LogMsg("ERROR: lookupNSAddr - bad state %d", context->state); return smError; } + else { LogMsg("Received NAT Traversal response with version unknown opcode 0x%X", AddrReply->opcode); return; } } - -mDNSlocal smAction lookupDNSPort(DNSMessage *msg, const mDNSu8 *end, ntaContext *context, char *portName, mDNSIPPort *port) + +// Shorten DNS-SD queries to avoid NAT bugs +// Add check to avoid crashing NAT gateways that have buggy DNS relay code +// +// We know of bugs in home NAT gateways that cause them to crash if they receive certain DNS queries. +// The DNS queries that make them crash are perfectly legal DNS queries, but even if they weren't, +// the gateway shouldn't crash -- in today's world of viruses and network attacks, software has to +// be written assuming that a malicious attacker could send them any packet, properly-formed or not. +// Still, we don't want to be crashing people's home gateways, so we go out of our way to avoid +// the queries that crash them. +// +// Some examples: +// +// 1. Any query where the name ends in ".in-addr.arpa." and the text before this is 32 or more bytes. +// The query type does not need to be PTR -- the gateway will crash for any query type. +// e.g. "ping long-name-crashes-the-buggy-router.in-addr.arpa" will crash one of these. +// +// 2. Any query that results in a large response with the TC bit set. +// +// 3. Any PTR query that doesn't begin with four decimal numbers. +// These gateways appear to assume that the only possible PTR query is a reverse-mapping query +// (e.g. "1.0.168.192.in-addr.arpa") and if they ever get a PTR query where the first four +// labels are not all decimal numbers in the range 0-255, they handle that by crashing. +// These gateways also ignore the remainder of the name following the four decimal numbers +// -- whether or not it actually says in-addr.arpa, they just make up an answer anyway. +// +// The challenge therefore is to craft a query that will discern whether the DNS server +// is one of these buggy ones, without crashing it. Furthermore we don't want our test +// queries making it all the way to the root name servers, putting extra load on those +// name servers and giving Apple a bad reputation. To this end we send this query: +// dig -t ptr 1.0.0.127.dnsbugtest.1.0.0.127.in-addr.arpa. +// +// The text preceding the ".in-addr.arpa." is under 32 bytes, so it won't cause crash (1). +// It will not yield a large response with the TC bit set, so it won't cause crash (2). +// It starts with four decimal numbers, so it won't cause crash (3). +// The name falls within the "1.0.0.127.in-addr.arpa." domain, the reverse-mapping name for the local +// loopback address, and therefore the query will black-hole at the first properly-configured DNS server +// it reaches, making it highly unlikely that this query will make it all the way to the root. +// +// Finally, the correct response to this query is NXDOMAIN or a similar error, but the +// gateways that ignore the remainder of the name following the four decimal numbers +// give themselves away by actually returning a result for this nonsense query. + +mDNSlocal const domainname *DNSRelayTestQuestion = (const domainname*) + "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\xa" "dnsbugtest" + "\x1" "1" "\x1" "0" "\x1" "0" "\x3" "127" "\x7" "in-addr" "\x4" "arpa"; + +// Returns mDNStrue if response was handled +mDNSlocal mDNSBool uDNS_ReceiveTestQuestionResponse(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end, + const mDNSAddr *const srcaddr, const mDNSIPPort srcport) { - int i; - LargeCacheRecord lcr; - const mDNSu8 *ptr; - DNSQuestion *q; - mStatus err; - - if (context->state == lookupPort) // we've already issued the query - { - if (!msg) { LogMsg("ERROR: hndlLookupUpdatePort - NULL message"); return smError; } - ptr = LocateAnswers(msg, end); - for (i = 0; i < msg->h.numAnswers; i++) + const mDNSu8 *ptr = msg->data; + DNSQuestion q; + DNSServer *s; + mDNSu32 result = 0; + + // 1. Find out if this is an answer to one of our test questions + if (msg->h.numQuestions != 1) return(mDNSfalse); + ptr = getQuestion(msg, ptr, end, mDNSInterface_Any, &q); + if (!ptr) return(mDNSfalse); + if (q.qtype != kDNSType_PTR || q.qclass != kDNSClass_IN) return(mDNSfalse); + if (!SameDomainName(&q.qname, DNSRelayTestQuestion)) return(mDNSfalse); + + // 2. If the DNS relay gave us a positive response, then it's got buggy firmware + // else, if the DNS relay gave us an error or no-answer response, it passed our test + if ((msg->h.flags.b[1] & kDNSFlag1_RC_Mask) == kDNSFlag1_RC_NoErr && msg->h.numAnswers > 0) + result = DNSServer_Failed; + else + result = DNSServer_Passed; + + // 3. Find occurrences of this server in our list, and mark them appropriately + for (s = m->DNSServers; s; s = s->next) + if (mDNSSameAddress(srcaddr, &s->addr) && mDNSSameIPPort(srcport, s->port) && s->teststate != result) { - ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr); - if (!ptr) { LogMsg("ERROR: hndlLookupUpdatePort - GetLargeResourceRecord returned NULL"); return smError; } - if (ResourceRecordAnswersQuestion(&lcr.r.resrec, &context->question)) + DNSQuestion *q; + if (s->teststate != result) { - *port = lcr.r.resrec.rdata->u.srv.port; - context->state = foundPort; - return smContinue; + s->teststate = result; + if (result == DNSServer_Passed) LogOperation("DNS Server %#a:%d passed", srcaddr, mDNSVal16(srcport)); + else LogMsg("NOTE: Wide-Area Service Discovery disabled to avoid crashing defective DNS relay %#a:%d", srcaddr, mDNSVal16(srcport)); } + if (result == DNSServer_Passed) // Unblock any questions that were waiting for this result + for (q = m->Questions; q; q=q->next) + if (q->qDNSServer == s) + { q->LastQTime = m->timenow - q->ThisQInterval; m->NextScheduledQuery = m->timenow; } } - debugf("hndlLookupUpdatePort - no answer for type %s", portName); - port->NotAnInteger = 0; - context->state = foundPort; - return smContinue; - } - - // query the server for the update port for the zone - context->state = lookupPort; - q = &context->question; - MakeDomainNameFromDNSNameString(&q->qname, portName); - AppendDomainName(&q->qname, &context->zone); - q->qtype = kDNSType_SRV; - q->qclass = kDNSClass_IN; - err = startInternalQuery(q, context->m, getZoneData, context); - context->questionActive = mDNStrue; - if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err); - return smBreak; // break from state machine until we receive another packet - } - -mDNSlocal smAction hndlLookupPorts(DNSMessage *msg, const mDNSu8 *end, ntaContext *context) - { - smAction action; - - if (context->findUpdatePort && !context->updatePort.NotAnInteger) - { - action = lookupDNSPort(msg, end, context, UPDATE_PORT_NAME, &context->updatePort); - if (action != smContinue) return action; - } - if (context->findLLQPort && !context->llqPort.NotAnInteger) - return lookupDNSPort(msg, end, context, LLQ_PORT_NAME, &context->llqPort); - return smContinue; + return(mDNStrue); // Return mDNStrue to tell uDNS_ReceiveMsg it doesn't need to process this packet further } +// Called from mDNSCoreReceive with the lock held +mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport) + { + DNSQuestion *qptr; + mStatus err = mStatus_NoError; -// *************************************************************************** -#if COMPILER_LIKES_PRAGMA_MARK -#pragma mark - Truncation Handling -#endif + mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery; + mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update; + mDNSu8 QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask); + mDNSu8 rcode = (mDNSu8)(msg->h.flags.b[1] & kDNSFlag1_RC_Mask); -typedef struct - { - DNSQuestion *question; - DNSMessage *reply; - mDNSu16 replylen; - int nread; - mDNS *m; - } tcpInfo_t; + (void)srcport; // Unused -// issue queries over a conected socket -mDNSlocal void conQueryCallback(int sd, void *context, mDNSBool ConnectionEstablished) - { - mStatus err = 0; - char msgbuf[356]; // 96 (hdr) + 256 (domain) + 4 (class/type) - DNSMessage *msg; - mDNSu8 *end; - tcpInfo_t *info = (tcpInfo_t *)context; - DNSQuestion *question = info->question; - int n; - mDNS *m = info->m; + debugf("uDNS_ReceiveMsg from %#-15a with " + "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s", + srcaddr, + msg->h.numQuestions, msg->h.numQuestions == 1 ? ", " : "s,", + msg->h.numAnswers, msg->h.numAnswers == 1 ? ", " : "s,", + msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,", + msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s"); - mDNS_Lock(m); - - if (ConnectionEstablished) + if (QR_OP == StdR) { - // connection is established - send the message - msg = (DNSMessage *)&msgbuf; - err = constructQueryMsg(msg, &end, question); - if (err) { LogMsg("ERROR: conQueryCallback: constructQueryMsg - %ld", err); goto error; } - err = mDNSSendDNSMessage(m, msg, end, mDNSInterface_Any, &zeroAddr, zeroIPPort, sd, mDNSNULL); - question->LastQTime = mDNSPlatformTimeNow(m); - if (err) { debugf("ERROR: conQueryCallback: mDNSSendDNSMessage_tcp - %ld", err); goto error; } + //if (srcaddr && recvLLQResponse(m, msg, end, srcaddr, srcport)) return; + if (uDNS_ReceiveTestQuestionResponse(m, msg, end, srcaddr, srcport)) return; + if (!mDNSOpaque16IsZero(msg->h.id)) + for (qptr = m->Questions; qptr; qptr = qptr->next) + if (msg->h.flags.b[0] & kDNSFlag0_TC && mDNSSameOpaque16(qptr->TargetQID, msg->h.id) && m->timenow - qptr->LastQTime < RESPONSE_WINDOW) + { + if (!srcaddr) LogMsg("uDNS_ReceiveMsg: TCP DNS response had TC bit set: ignoring"); + else if (qptr->tcp) + { + // There may be a race condition here, if the server decides to drop the connection just as we decide to reuse it + // For now it should not be serious because our normal retry logic (as used to handle UDP packet loss) + // should take care of it but later we may want to look at handling this case explicitly + LogOperation("uDNS_ReceiveMsg: Using existing TCP connection for %##s (%s)", qptr->qname.c, DNSTypeName(qptr->qtype)); + mDNS_DropLockBeforeCallback(); + tcpCallback(qptr->tcp->sock, qptr->tcp, mDNStrue, mStatus_NoError); + mDNS_ReclaimLockAfterCallback(); + } + else qptr->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_Zero, srcaddr, srcport, qptr, mDNSNULL, mDNSNULL); + } } - else + + if (QR_OP == UpdateR && !mDNSOpaque16IsZero(msg->h.id)) { - if (!info->nread) + mDNSu32 lease = GetPktLease(m, msg, end); + mDNSs32 expire = (m->timenow + (((mDNSs32)lease * mDNSPlatformOneSecond)) * 3/4); + + if (CurrentServiceRecordSet) + LogMsg("uDNS_ReceiveMsg ERROR CurrentServiceRecordSet already set"); + CurrentServiceRecordSet = m->ServiceRegistrations; + + while (CurrentServiceRecordSet) { - // read msg len - mDNSu8 lenbuf[2]; - n = mDNSPlatformReadTCP(sd, lenbuf, 2); - if (n != 2) + ServiceRecordSet *sptr = CurrentServiceRecordSet; + CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next; + + if (mDNSSameOpaque16(sptr->id, msg->h.id)) { - LogMsg("ERROR:conQueryCallback - attempt to read message length failed (read returned %d)", n); - goto error; + err = checkUpdateResult(m, sptr->RR_SRV.resrec.name, rcode, msg, end); + if (!err && sptr->srs_uselease && lease) + if (sptr->expire - expire >= 0 || sptr->state != regState_UpdatePending) + sptr->expire = expire; + hndlServiceUpdateReply(m, sptr, err); + CurrentServiceRecordSet = mDNSNULL; + return; } - info->replylen = (mDNSu16)((mDNSu16)lenbuf[0] << 8 | lenbuf[1]); - if (info->replylen < sizeof(DNSMessageHeader)) - { LogMsg("ERROR: conQueryCallback - length too short (%d bytes)", info->replylen); goto error; } - info->reply = umalloc(info->replylen); - if (!info->reply) { LogMsg("ERROR: conQueryCallback - malloc failed"); goto error; } } - n = mDNSPlatformReadTCP(sd, ((char *)info->reply) + info->nread, info->replylen - info->nread); - if (n < 0) { LogMsg("ERROR: conQueryCallback - read returned %d", n); goto error; } - info->nread += n; - if (info->nread == info->replylen) + + if (m->CurrentRecord) + LogMsg("uDNS_ReceiveMsg ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); + m->CurrentRecord = m->ResourceRecords; + while (m->CurrentRecord) { - // Finished reading message; convert the integer parts which are in IETF byte-order (MSB first, LSB second) - DNSMessage *msg = info->reply; - mDNSu8 *ptr = (mDNSu8 *)&msg->h.numQuestions; - msg->h.numQuestions = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); - msg->h.numAnswers = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]); - msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]); - msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]); - uDNS_ReceiveMsg(m, msg, (mDNSu8 *)msg + info->replylen, mDNSNULL, zeroIPPort, mDNSNULL, zeroIPPort, question->InterfaceID); - mDNSPlatformTCPCloseConnection(sd); - ufree(info->reply); - ufree(info); + AuthRecord *rptr = m->CurrentRecord; + m->CurrentRecord = m->CurrentRecord->next; + if (mDNSSameOpaque16(rptr->id, msg->h.id)) + { + err = checkUpdateResult(m, rptr->resrec.name, rcode, msg, end); + if (!err && rptr->uselease && lease) + if (rptr->expire - expire >= 0 || rptr->state != regState_UpdatePending) + rptr->expire = expire; + hndlRecordUpdateReply(m, rptr, err); + m->CurrentRecord = mDNSNULL; + return; + } } } - - mDNS_Unlock(m); - return; - - error: - mDNSPlatformTCPCloseConnection(sd); - if (info->reply) ufree(info->reply); - ufree(info); - mDNS_Unlock(m); - } - -mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question, const mDNSAddr *src, mDNS *m) - { - mStatus connectionStatus; - uDNS_QuestionInfo *info = &question->uDNS_info; - int sd; - tcpInfo_t *context; - - if (!src) { LogMsg("hndlTruncatedAnswer: TCP DNS response had TC bit set: ignoring"); return; } - - context = (tcpInfo_t *)umalloc(sizeof(tcpInfo_t)); - if (!context) { LogMsg("ERROR: hndlTruncatedAnswer - memallocate failed"); return; } - ubzero(context, sizeof(tcpInfo_t)); - context->question = question; - context->m = m; - info->id = newMessageID(&m->uDNS_info); - - connectionStatus = mDNSPlatformTCPConnect(src, UnicastDNSPort, question->InterfaceID, conQueryCallback, context, &sd); - if (connectionStatus == mStatus_ConnEstablished) // manually invoke callback if connection completes - { - conQueryCallback(sd, context, mDNStrue); - return; - } - if (connectionStatus == mStatus_ConnPending) return; // callback will be automatically invoked when connection completes - LogMsg("hndlTruncatedAnswer: connection failed"); - uDNS_StopQuery(m, question); //!!!KRS can we really call this here? + debugf("Received unexpected response: ID %d matches no active records", mDNSVal16(msg->h.id)); } - // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK -#pragma mark - Dynamic Updates +#pragma mark - Query Routines #endif -mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr) +mDNSlocal void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease) { - DNSMessage msg; - mDNSu8 *ptr = msg.data; - mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage); - uDNS_GlobalInfo *u = &m->uDNS_info; - mDNSOpaque16 id; - uDNS_RegInfo *regInfo = &rr->uDNS_info; - mStatus err = mStatus_UnknownErr; + mDNSu8 *end; + LLQOptData llq; + mStatus err; - id = newMessageID(u); - InitializeDNSMessage(&msg.h, id, UpdateReqFlags); - rr->uDNS_info.id = id; - - // set zone - ptr = putZone(&msg, ptr, end, ®Info->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass)); - if (!ptr) goto error; + // If this is supposed to be a private question and the server dropped the TCP connection, + // we don't want to cancel it with a clear-text UDP packet, and and it's not worth the expense of + // setting up a new TLS session just to cancel the outstanding LLQ, so we just let it expire naturally + if (lease == 0 && q->AuthInfo && !q->tcp) return; - if (regInfo->state == regState_UpdatePending) + if (q->AuthInfo && !q->tcp) { - // delete old RData - SetNewRData(&rr->resrec, regInfo->OrigRData, regInfo->OrigRDLen); - if (!(ptr = putDeletionRecord(&msg, ptr, &rr->resrec))) goto error; // delete old rdata - - // add new RData - SetNewRData(&rr->resrec, regInfo->InFlightRData, regInfo->InFlightRDLen); - if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl))) goto error; + //LogOperation("sendLLQRefresh setting up new TLS session %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, q, mDNSNULL, mDNSNULL); + q->LastQTime = m->timenow; + SetNextQueryTime(m, q); + return; } - else + if ((q->state == LLQ_Refresh && q->ntries >= kLLQ_MAX_TRIES) || q->expire - m->timenow < 0) { - if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique) - { - // KnownUnique: Delete any previous value - ptr = putDeleteRRSet(&msg, ptr, rr->resrec.name, rr->resrec.rrtype); - if (!ptr) goto error; - } - - else if (rr->resrec.RecordType != kDNSRecordTypeShared) - { - ptr = putPrereqNameNotInUse(rr->resrec.name, &msg, ptr, end); - if (!ptr) goto error; - } - - ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl); - if (!ptr) goto error; + LogMsg("Unable to refresh LLQ %##s (%s) - will retry in %d minutes", q->qname.c, DNSTypeName(q->qtype), kLLQ_DEF_RETRY/60); + q->state = LLQ_Retry; + q->LastQTime = m->timenow; + q->ThisQInterval = kLLQ_DEF_RETRY * mDNSPlatformOneSecond; + SetNextQueryTime(m, q); + return; + //!!!KRS handle this - periodically try to re-establish } - - if (rr->uDNS_info.lease) - { ptr = putUpdateLease(&msg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) goto error; } - err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, ®Info->ns, regInfo->port, -1, GetAuthInfoForName(u, rr->resrec.name)); - if (err) debugf("ERROR: sendRecordRegistration - mDNSSendDNSMessage - %ld", err); - - SetRecordRetry(m, rr, err); - - if (regInfo->state != regState_Refresh && regInfo->state != regState_DeregDeferred && regInfo->state != regState_UpdatePending) - regInfo->state = regState_Pending; + llq.vers = kLLQ_Vers; + llq.llqOp = kLLQOp_Refresh; + llq.err = LLQErr_NoError; + llq.id = q->id; + llq.llqlease = lease; - return; + InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags); + end = putLLQ(&m->omsg, m->omsg.data, q, &llq, mDNStrue); + if (!end) { LogMsg("ERROR: sendLLQRefresh - putLLQ"); return; } -error: - LogMsg("sendRecordRegistration: Error formatting message"); - if (rr->uDNS_info.state != regState_Unregistered) - { - unlinkAR(&u->RecordRegistrations, rr); - rr->uDNS_info.state = regState_Unregistered; - } - m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback - if (rr->RecordCallback) rr->RecordCallback(m, rr, err); - m->mDNS_reentrancy--; // Decrement to block mDNS API calls again - // NOTE: not safe to touch any client structures here + err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, q->AuthInfo); + if (err) debugf("ERROR: sendLLQRefresh - mDNSSendDNSMessage returned %ld", err); + + if (q->state == LLQ_Established) q->ntries = 1; + else q->ntries++; + + debugf("sendLLQRefresh ntries %d %##s (%s)", q->ntries, q->qname.c, DNSTypeName(q->qtype)); + + q->state = LLQ_Refresh; + q->LastQTime = m->timenow; + SetNextQueryTime(m, q); } -mDNSlocal void RecordRegistrationCallback(mStatus err, mDNS *const m, void *authPtr, const AsyncOpResult *result) +// wrapper for startLLQHandshake, invoked by async op callback +mDNSexport void startLLQHandshakeCallback(mDNS *const m, mStatus err, const ZoneData *zoneInfo) { - AuthRecord *newRR = (AuthRecord*)authPtr; - const zoneData_t *zoneData = mDNSNULL; - uDNS_GlobalInfo *u = &m->uDNS_info; - AuthRecord *ptr; - - // make sure record is still in list - for (ptr = u->RecordRegistrations; ptr; ptr = ptr->next) - if (ptr == newRR) break; - if (!ptr) { LogMsg("RecordRegistrationCallback - RR no longer in list. Discarding."); return; } + DNSQuestion *q = (DNSQuestion *)zoneInfo->ZoneDataContext; - // check error/result - if (err) { LogMsg("RecordRegistrationCallback: error %ld", err); goto error; } - if (!result) { LogMsg("ERROR: RecordRegistrationCallback invoked with NULL result and no error"); goto error; } - else zoneData = &result->zoneData; + // If we get here it means that the GetZoneData operation has completed, and is is about to cancel + // its question and free the ZoneData memory. We no longer need to hold onto our pointer (which + // we use for cleaning up if our LLQ is cancelled *before* the GetZoneData operation has completes). + q->nta = mDNSNULL; - if (newRR->uDNS_info.state == regState_Cancelled) + // check state first to make sure it is OK to touch question object + if (q->state == LLQ_Cancelled) { - //!!!KRS we should send a memfree callback here! - debugf("Registration of %##s type %d cancelled prior to update", - newRR->resrec.name->c, newRR->resrec.rrtype); - newRR->uDNS_info.state = regState_Unregistered; - unlinkAR(&u->RecordRegistrations, newRR); + // StopQuery was called while we were getting the zone info + debugf("startLLQHandshakeCallback - LLQ Cancelled."); return; } - - if (result->type != zoneDataResult) - { - LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result->type); - goto error; - } - if (newRR->resrec.rrclass != zoneData->zoneClass) + mDNS_Lock(m); + + if (q->state != LLQ_GetZoneInfo) { - LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)", - newRR->resrec.rrclass, zoneData->zoneClass); - goto error; + LogMsg("ERROR: startLLQHandshakeCallback - bad state %d", q->state); + err = mStatus_UnknownErr; + goto exit; } - - // Don't try to do updates to the root name server. - // We might be tempted also to block updates to any single-label name server (e.g. com, edu, net, etc.) but some - // organizations use their own private pseudo-TLD, like ".home", etc, and we don't want to block that. - if (zoneData->zoneName.c[0] == 0) + + if (err) { - LogMsg("ERROR: Only name server claiming responsibility for \"%##s\" is \"%##s\"!", - newRR->resrec.name->c, zoneData->zoneName.c); - err = mStatus_NoSuchNameErr; - goto error; + LogMsg("ERROR: startLLQHandshakeCallback %##s (%s) invoked with error code %ld", q->qname.c, DNSTypeName(q->qtype), err); + StartLLQPolling(m, q); + err = mStatus_NoError; + goto exit; } - // cache zone data - AssignDomainName(&newRR->uDNS_info.zone, &zoneData->zoneName); - newRR->uDNS_info.ns = zoneData->primaryAddr; - if (zoneData->updatePort.NotAnInteger) newRR->uDNS_info.port = zoneData->updatePort; - else + if (!zoneInfo) { - debugf("Update port not advertised via SRV - guessing port 53, no lease option"); - newRR->uDNS_info.port = UnicastDNSPort; - newRR->uDNS_info.lease = mDNSfalse; + LogMsg("ERROR: startLLQHandshakeCallback invoked with NULL result and no error code"); + err = mStatus_UnknownErr; + goto exit; } - sendRecordRegistration(m, newRR); - return; - -error: - if (newRR->uDNS_info.state != regState_Unregistered) + if (mDNSIPPortIsZero(zoneInfo->Port)) { - unlinkAR(&u->RecordRegistrations, newRR); - newRR->uDNS_info.state = regState_Unregistered; + LogOperation("LLQ port lookup failed - reverting to polling for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + q->servPort = zeroIPPort; + StartLLQPolling(m, q); + goto exit; } - m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback - if (newRR->RecordCallback) - newRR->RecordCallback(m, newRR, err); - m->mDNS_reentrancy--; // Decrement to block mDNS API calls again - // NOTE: not safe to touch any client structures here + + // cache necessary zone data + q->servAddr = zoneInfo->Addr; + q->servPort = zoneInfo->Port; + if (!zoneInfo->ZonePrivate) q->AuthInfo = mDNSNULL; + + q->ntries = 0; + + if (q->state == LLQ_SuspendDeferred) q->state = LLQ_Suspended; + else startLLQHandshake(m, q); + +exit: + + if (err && q) q->state = LLQ_Error; + + mDNS_Unlock(m); } -mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs) +// Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1) +mDNSlocal void startPrivateQueryCallback(mDNS *const m, mStatus err, const ZoneData *zoneInfo) { - DNSMessage msg; - mDNSu8 *ptr = msg.data; - mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage); - uDNS_GlobalInfo *u = &m->uDNS_info; - mDNSOpaque16 id; - uDNS_RegInfo *rInfo = &srs->uDNS_info; - mStatus err = mStatus_UnknownErr; - mDNSIPPort privport; - NATTraversalInfo *nat = srs->uDNS_info.NATinfo; - mDNSBool mapped = mDNSfalse; - domainname target; - AuthRecord *srv = &srs->RR_SRV; - mDNSu32 i; - - privport = zeroIPPort; - - if (!rInfo->ns.ip.v4.NotAnInteger) { LogMsg("SendServiceRegistration - NS not set!"); return; } + DNSQuestion *q = (DNSQuestion *) zoneInfo->ZoneDataContext; - id = newMessageID(u); - InitializeDNSMessage(&msg.h, id, UpdateReqFlags); + LogOperation("startPrivateQueryCallback %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); - // setup resource records - SetNewRData(&srs->RR_PTR.resrec, mDNSNULL, 0); - SetNewRData(&srs->RR_TXT.resrec, mDNSNULL, 0); - - // replace port w/ NAT mapping if necessary - if (nat && nat->PublicPort.NotAnInteger && - (nat->state == NATState_Established || nat->state == NATState_Refresh || nat->state == NATState_Legacy)) + // If we get here it means that the GetZoneData operation has completed, and is is about to cancel + // its question and free the ZoneData memory. We no longer need to hold onto our pointer (which + // we use for cleaning up if our LLQ is cancelled *before* the GetZoneData operation has completes). + q->nta = mDNSNULL; + + if (err) { - privport = srv->resrec.rdata->u.srv.port; - srv->resrec.rdata->u.srv.port = nat->PublicPort; - mapped = mDNStrue; + LogMsg("ERROR: startPrivateQueryCallback %##s (%s) invoked with error code %ld", q->qname.c, DNSTypeName(q->qtype), err); + goto exit; } - - // construct update packet - // set zone - ptr = putZone(&msg, ptr, end, &rInfo->zone, mDNSOpaque16fromIntVal(srv->resrec.rrclass)); - if (!ptr) goto error; - - if (srs->uDNS_info.TestForSelfConflict) + + if (!zoneInfo) { - // update w/ prereq that SRV already exist to make sure previous registration was ours, and delete any stale TXT records - if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numPrereqs, &srs->RR_SRV.resrec, 0))) goto error; - if (!(ptr = putDeleteRRSet(&msg, ptr, srs->RR_TXT.resrec.name, srs->RR_TXT.resrec.rrtype))) goto error; + LogMsg("ERROR: startPrivateQueryCallback invoked with NULL result and no error code"); + err = mStatus_UnknownErr; + goto exit; } - - else if (srs->uDNS_info.state != regState_Refresh && srs->uDNS_info.state != regState_UpdatePending) + + if (!zoneInfo->ZonePrivate) { - // use SRV name for prereq - ptr = putPrereqNameNotInUse(srv->resrec.name, &msg, ptr, end); - if (!ptr) goto error; + debugf("Private port lookup failed -- retrying without TLS -- %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + q->AuthInfo = mDNSNULL; // Clear AuthInfo so we try again non-private + q->ThisQInterval = InitialQuestionInterval; + q->LastQTime = m->timenow - q->ThisQInterval; + mDNS_Lock(m); + SetNextQueryTime(m, q); + mDNS_Unlock(m); + goto exit; + // Next call to uDNS_CheckCurrentQuestion() will do this as a non-private query } - - //!!!KRS Need to do bounds checking and use TCP if it won't fit!!! - if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_PTR.resrec, srs->RR_PTR.resrec.rroriginalttl))) goto error; - for (i = 0; i < srs->NumSubTypes; i++) - if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->SubTypes[i].resrec, srs->SubTypes[i].resrec.rroriginalttl))) goto error; - - if (rInfo->state == regState_UpdatePending) // we're updating the txt record + if (!q->AuthInfo) { - AuthRecord *txt = &srs->RR_TXT; - uDNS_RegInfo *txtInfo = &txt->uDNS_info; - // delete old RData - SetNewRData(&txt->resrec, txtInfo->OrigRData, txtInfo->OrigRDLen); - if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_TXT.resrec))) goto error; // delete old rdata - - // add new RData - SetNewRData(&txt->resrec, txtInfo->InFlightRData, txtInfo->InFlightRDLen); - if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) goto error; + LogMsg("ERROR: startPrivateQueryCallback: cannot find credentials for q %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + err = mStatus_UnknownErr; + goto exit; } - else - if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) goto error; - if (!GetServiceTarget(u, srv, &target)) + q->TargetQID = mDNS_NewMessageID(m); + if (q->tcp) { - debugf("Couldn't get target for service %##s", srv->resrec.name->c); - rInfo->state = regState_NoTarget; - return; + LogOperation("startPrivateQueryCallback: Already have TCP connection for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + tcpCallback(q->tcp->sock, q->tcp, mDNStrue, mStatus_NoError); } + else q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &zoneInfo->Addr, zoneInfo->Port, q, mDNSNULL, mDNSNULL); - if (!SameDomainName(&target, &srv->resrec.rdata->u.srv.target)) - { - AssignDomainName(&srv->resrec.rdata->u.srv.target, &target); - SetNewRData(&srv->resrec, mDNSNULL, 0); - } - - ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srv->resrec, srv->resrec.rroriginalttl); - if (!ptr) goto error; - - if (srs->uDNS_info.lease) - { ptr = putUpdateLease(&msg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) goto error; } - - err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rInfo->ns, rInfo->port, -1, GetAuthInfoForName(u, srs->RR_SRV.resrec.name)); - if (err) debugf("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %ld", err); - - if (rInfo->state != regState_Refresh && rInfo->state != regState_DeregDeferred && srs->uDNS_info.state != regState_UpdatePending) - rInfo->state = regState_Pending; - - SetRecordRetry(m, &srs->RR_SRV, err); - rInfo->id = id; - if (mapped) srv->resrec.rdata->u.srv.port = privport; - return; +exit: -error: - LogMsg("SendServiceRegistration - Error formatting message"); - if (mapped) srv->resrec.rdata->u.srv.port = privport; - unlinkSRS(m, srs); - rInfo->state = regState_Unregistered; - m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback - srs->ServiceCallback(m, srs, err); - m->mDNS_reentrancy--; // Decrement to block mDNS API calls again - //!!!KRS will mem still be free'd on error? - // NOTE: not safe to touch any client structures here + if (err) mDNS_StopQuery(m, q); } -mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srsPtr, const AsyncOpResult *result) +// uDNS_StopLongLivedQuery happens IN ADDITION to stopQuery +mDNSexport void uDNS_StopLongLivedQuery(mDNS *const m, DNSQuestion *const question) { - ServiceRecordSet *srs = (ServiceRecordSet *)srsPtr; - const zoneData_t *zoneData = mDNSNULL; - - if (err) goto error; - if (!result) { LogMsg("ERROR: serviceRegistrationCallback invoked with NULL result and no error"); goto error; } - else zoneData = &result->zoneData; - - if (result->type != zoneDataResult) - { - LogMsg("ERROR: buildUpdatePacket passed incorrect result type %d", result->type); - goto error; - } + LogOperation("uDNS_StopLongLivedQuery %##s (%s) state %d", question->qname.c, DNSTypeName(question->qtype), question->state); - if (srs->uDNS_info.state == regState_Cancelled) - { - // client cancelled registration while fetching zone data - srs->uDNS_info.state = regState_Unregistered; - unlinkSRS(m, srs); - m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback - srs->ServiceCallback(m, srs, mStatus_MemFree); - m->mDNS_reentrancy--; // Decrement to block mDNS API calls again - return; - } - - if (srs->RR_SRV.resrec.rrclass != zoneData->zoneClass) + switch (question->state) { - LogMsg("Service %##s - class does not match zone", srs->RR_SRV.resrec.name->c); - goto error; - } + case LLQ_UnInit: LogMsg("ERROR: uDNS_StopLongLivedQuery - state LLQ_UnInit"); return; //!!!KRS should we unlink info<->question here? - // cache zone data - AssignDomainName(&srs->uDNS_info.zone, &zoneData->zoneName); - srs->uDNS_info.ns.type = mDNSAddrType_IPv4; - srs->uDNS_info.ns = zoneData->primaryAddr; - if (zoneData->updatePort.NotAnInteger) srs->uDNS_info.port = zoneData->updatePort; - else - { - debugf("Update port not advertised via SRV - guessing port 53, no lease option"); - srs->uDNS_info.port = UnicastDNSPort; - srs->uDNS_info.lease = mDNSfalse; + case LLQ_GetZoneInfo: + case LLQ_SuspendDeferred: question->state = LLQ_Cancelled; return; + + case LLQ_Established: + case LLQ_Refresh: sendLLQRefresh(m, question, 0); break; + + default: debugf("uDNS_StopLongLivedQuery - silently discarding LLQ in state %d", question->state); break; } - if (srs->RR_SRV.resrec.rdata->u.srv.port.NotAnInteger && IsPrivateV4Addr(&m->uDNS_info.AdvertisedV4)) - { srs->uDNS_info.state = regState_NATMap; StartNATPortMap(m, srs); } - else SendServiceRegistration(m, srs); - return; - -error: - unlinkSRS(m, srs); - srs->uDNS_info.state = regState_Unregistered; - m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback - srs->ServiceCallback(m, srs, err); - m->mDNS_reentrancy--; // Decrement to block mDNS API calls again - // NOTE: not safe to touch any client structures here + RemoveLLQNatMappings(m, question); + CheckForUnreferencedLLQMapping(m); } -mDNSlocal mStatus SetupRecordRegistration(mDNS *m, AuthRecord *rr) +// *************************************************************************** +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - Dynamic Updates +#endif + +// Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1) +mDNSexport void RecordRegistrationCallback(mDNS *const m, mStatus err, const ZoneData *zoneData) { - domainname *target = GetRRDomainNameTarget(&rr->resrec); - AuthRecord *ptr = m->uDNS_info.RecordRegistrations; + AuthRecord *newRR = (AuthRecord*)zoneData->ZoneDataContext; + AuthRecord *ptr; - while (ptr && ptr != rr) ptr = ptr->next; - if (ptr) { LogMsg("Error: SetupRecordRegistration - record %##s already in list!", rr->resrec.name->c); return mStatus_AlreadyRegistered; } - - if (rr->uDNS_info.state == regState_FetchingZoneData || - rr->uDNS_info.state == regState_Pending || - rr->uDNS_info.state == regState_Registered) - { - LogMsg("Requested double-registration of physical record %##s type %d", - rr->resrec.name->c, rr->resrec.rrtype); - return mStatus_AlreadyRegistered; - } - - rr->resrec.rdlength = GetRDLength(&rr->resrec, mDNSfalse); - rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue); + if (m->mDNS_busy != m->mDNS_reentrancy) + LogMsg("RecordRegistrationCallback: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); + + newRR->nta = mDNSNULL; + + // make sure record is still in list (!!!) + for (ptr = m->ResourceRecords; ptr; ptr = ptr->next) if (ptr == newRR) break; + if (!ptr) { LogMsg("RecordRegistrationCallback - RR no longer in list. Discarding."); return; } - if (!ValidateDomainName(rr->resrec.name)) + // check error/result + if (err) { LogMsg("RecordRegistrationCallback: error %ld", err); goto error; } + if (!zoneData) { LogMsg("ERROR: RecordRegistrationCallback invoked with NULL result and no error"); goto error; } + + if (newRR->resrec.rrclass != zoneData->ZoneClass) { - LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr)); - return mStatus_Invalid; + LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)", + newRR->resrec.rrclass, zoneData->ZoneClass); + goto error; } - // Don't do this until *after* we've set rr->resrec.rdlength - if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata)) + // Don't try to do updates to the root name server. + // We might be tempted also to block updates to any single-label name server (e.g. com, edu, net, etc.) but some + // organizations use their own private pseudo-TLD, like ".home", etc, and we don't want to block that. + if (zoneData->ZoneName.c[0] == 0) { - LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr)); - return mStatus_Invalid; + LogMsg("RecordRegistrationCallback: Only name server claiming responsibility for \"%##s\" is \"%##s\"!", newRR->resrec.name->c, zoneData->ZoneName.c); + err = mStatus_NoSuchNameErr; + goto error; } - rr->resrec.namehash = DomainNameHashValue(rr->resrec.name); - rr->resrec.rdatahash = target ? DomainNameHashValue(target) : RDataHashValue(rr->resrec.rdlength, &rr->resrec.rdata->u); - - rr->uDNS_info.state = regState_FetchingZoneData; - rr->next = m->uDNS_info.RecordRegistrations; - m->uDNS_info.RecordRegistrations = rr; - rr->uDNS_info.lease = mDNStrue; - - return mStatus_NoError; - } - -mDNSexport mStatus uDNS_RegisterRecord(mDNS *const m, AuthRecord *const rr) - { - mStatus err = SetupRecordRegistration(m, rr); - if (err) return err; - else return startGetZoneData(rr->resrec.name, m, mDNStrue, mDNSfalse, RecordRegistrationCallback, rr); - } + // Store discovered zone data + AssignDomainName(&newRR->zone, &zoneData->ZoneName); + newRR->UpdateServer = zoneData->Addr; + newRR->UpdatePort = zoneData->Port; + newRR->Private = zoneData->ZonePrivate; + debugf("RecordRegistrationCallback: Set newRR->UpdateServer %##s %##s to %#a:%d", + newRR->resrec.name->c, zoneData->ZoneName.c, &newRR->UpdateServer, mDNSVal16(newRR->UpdatePort)); -mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr) - { - uDNS_GlobalInfo *u = &m->uDNS_info; - DNSMessage msg; - mDNSu8 *ptr = msg.data; - mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage); - mStatus err; - - InitializeDNSMessage(&msg.h, rr->uDNS_info.id, UpdateReqFlags); - - ptr = putZone(&msg, ptr, end, &rr->uDNS_info.zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass)); - if (!ptr) goto error; - if (!(ptr = putDeletionRecord(&msg, ptr, &rr->resrec))) goto error; + if (mDNSIPPortIsZero(zoneData->Port) || mDNSAddressIsZero(&zoneData->Addr)) + { + LogMsg("RecordRegistrationCallback: No _dns-update._udp service found for \"%##s\"!", newRR->resrec.name->c); + err = mStatus_NoSuchNameErr; + goto error; + } - err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rr->uDNS_info.ns, rr->uDNS_info.port, -1, GetAuthInfoForName(u, rr->resrec.name)); - if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %ld", err); - SetRecordRetry(m, rr, err); - rr->uDNS_info.state = regState_DeregPending; + mDNS_Lock(m); // SendRecordRegistration expects to be called with the lock held + SendRecordRegistration(m, newRR); + mDNS_Unlock(m); return; - error: - LogMsg("Error: SendRecordDeregistration - could not contruct deregistration packet"); - unlinkAR(&u->RecordRegistrations, rr); - rr->uDNS_info.state = regState_Unregistered; - } - - - -mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr) - { - uDNS_GlobalInfo *u = &m->uDNS_info; - NATTraversalInfo *n = rr->uDNS_info.NATinfo; - - switch (rr->uDNS_info.state) +error: + if (newRR->state != regState_Unregistered) { - case regState_NATMap: - // we're in the middle of a NAT traversal operation - rr->uDNS_info.NATinfo = mDNSNULL; - if (!n) LogMsg("uDNS_DeregisterRecord: no NAT info context"); - else FreeNATInfo(m, n); // cause response to outstanding request to be ignored. - // Note: normally here we're trying to determine our public address, - //in which case there is not state to be torn down. For simplicity, - //we allow other operations to expire. - rr->uDNS_info.state = regState_Unregistered; - break; - case regState_ExtraQueued: - rr->uDNS_info.state = regState_Unregistered; - break; - case regState_FetchingZoneData: - rr->uDNS_info.state = regState_Cancelled; - return mStatus_NoError; - case regState_Refresh: - case regState_Pending: - case regState_UpdatePending: - rr->uDNS_info.state = regState_DeregDeferred; - LogMsg("Deferring deregistration of record %##s until registration completes", rr->resrec.name->c); - return mStatus_NoError; - case regState_Registered: - case regState_DeregPending: - break; - case regState_DeregDeferred: - case regState_Cancelled: - LogMsg("Double deregistration of record %##s type %d", - rr->resrec.name->c, rr->resrec.rrtype); - return mStatus_UnknownErr; - case regState_Unregistered: - LogMsg("Requested deregistration of unregistered record %##s type %d", - rr->resrec.name->c, rr->resrec.rrtype); - return mStatus_UnknownErr; - case regState_NATError: - case regState_NoTarget: - LogMsg("ERROR: uDNS_DeregisterRecord called for record %##s with bad state %s", rr->resrec.name->c, rr->uDNS_info.state == regState_NoTarget ? "regState_NoTarget" : "regState_NATError"); - return mStatus_UnknownErr; + mDNS_Lock(m); + UnlinkAuthRecord(m, newRR); + newRR->state = regState_Unregistered; + mDNS_Unlock(m); } - if (rr->uDNS_info.state == regState_Unregistered) + // Don't need to do the mDNS_DropLockBeforeCallback stuff here, because this code is + // *already* being invoked in the right callback context, with mDNS_reentrancy correctly incremented. + if (newRR->RecordCallback) + newRR->RecordCallback(m, newRR, err); + // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function + // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc. + } + +mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr) + { + mDNSu8 *ptr = m->omsg.data; + mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage); + mStatus err = mStatus_NoError; + + InitializeDNSMessage(&m->omsg.h, rr->id, UpdateReqFlags); + + ptr = putZone(&m->omsg, ptr, end, &rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass)); + if (!ptr) { err = mStatus_UnknownErr; goto exit; } + if (!(ptr = putDeletionRecord(&m->omsg, ptr, &rr->resrec))) { err = mStatus_UnknownErr; goto exit; } + + rr->state = regState_DeregPending; + + if (rr->Private) { - // unlink and deliver memfree - - unlinkAR(&u->RecordRegistrations, rr); - m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback - if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_MemFree); - m->mDNS_reentrancy--; // Decrement to block mDNS API calls again - return mStatus_NoError; + LogOperation("SendRecordDeregistration TCP %p %s", rr->tcp, ARDisplayString(m, rr)); + if (rr->tcp) LogMsg("SendRecordDeregistration: ERROR: Already have TCP connection for %s", ARDisplayString(m, rr)); + else rr->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, mDNSNULL, rr); + rr->LastAPTime = m->timenow; + rr->ThisAPInterval = 0x3FFFFFFF; // TCP will handle any necessary retransmissions for us + } + else + { + err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name)); + if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %ld", err); + SetRecordRetry(m, rr, err); + CompleteDeregistration(m, rr); // Don't touch rr after this + return; } - rr->uDNS_info.NATinfo = mDNSNULL; - if (n) FreeNATInfo(m, n); - - SendRecordDeregistration(m, rr); - return mStatus_NoError; - } - -mDNSexport mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs) - { - mDNSu32 i; - domainname target; - uDNS_RegInfo *info = &srs->uDNS_info; - ServiceRecordSet **p = &m->uDNS_info.ServiceRegistrations; - while (*p && *p != srs) p=&(*p)->next; - if (*p) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs, srs->RR_SRV.resrec.name->c); return(mStatus_AlreadyRegistered); } - ubzero(info, sizeof(*info)); - *p = srs; - srs->next = mDNSNULL; - - srs->RR_SRV.resrec.rroriginalttl = kWideAreaTTL; - srs->RR_TXT.resrec.rroriginalttl = kWideAreaTTL; - srs->RR_PTR.resrec.rroriginalttl = kWideAreaTTL; - for (i = 0; i < srs->NumSubTypes;i++) srs->SubTypes[i].resrec.rroriginalttl = kWideAreaTTL; - - info->lease = mDNStrue; + err = mStatus_NoError; + +exit: - srs->RR_SRV.resrec.rdata->u.srv.target.c[0] = 0; - if (!GetServiceTarget(&m->uDNS_info, &srs->RR_SRV, &target)) + if (err) { - // defer registration until we've got a target - debugf("uDNS_RegisterService - no target for %##s", srs->RR_SRV.resrec.name->c); - info->state = regState_NoTarget; - return mStatus_NoError; + LogMsg("Error: SendRecordDeregistration - could not contruct deregistration packet"); + UnlinkAuthRecord(m, rr); + rr->state = regState_Unregistered; } - - info->state = regState_FetchingZoneData; - return startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs); } -mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs) +mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr) { - uDNS_RegInfo *info = &srs->uDNS_info; - uDNS_GlobalInfo *u = &m->uDNS_info; - DNSMessage msg; - mDNSOpaque16 id; - mDNSu8 *ptr = msg.data; - mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage); - mStatus err = mStatus_UnknownErr; - mDNSu32 i; - - id = newMessageID(u); - InitializeDNSMessage(&msg.h, id, UpdateReqFlags); - - // put zone - ptr = putZone(&msg, ptr, end, &info->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass)); - if (!ptr) { LogMsg("ERROR: SendServiceDeregistration - putZone"); goto error; } - - if (!(ptr = putDeleteAllRRSets(&msg, ptr, srs->RR_SRV.resrec.name))) goto error; // this deletes SRV, TXT, and Extras - if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_PTR.resrec))) goto error; - for (i = 0; i < srs->NumSubTypes; i++) - if (!(ptr = putDeletionRecord(&msg, ptr, &srs->SubTypes[i].resrec))) goto error; - - - err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &info->ns, info->port, -1, GetAuthInfoForName(u, srs->RR_SRV.resrec.name)); - if (err && err != mStatus_TransientErr) { debugf("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %ld", err); goto error; } + switch (rr->state) + { + case regState_NATMap: LogMsg("regState_NATMap %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError; + case regState_ExtraQueued: rr->state = regState_Unregistered; break; + case regState_Refresh: + case regState_Pending: + case regState_UpdatePending: + rr->state = regState_DeregDeferred; + LogMsg("Deferring deregistration of record %##s until registration completes", rr->resrec.name->c); + return mStatus_NoError; + case regState_FetchingZoneData: + case regState_Registered: break; + case regState_DeregPending: break; + case regState_DeregDeferred: LogMsg("regState_DeregDeferred %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError; + case regState_Unregistered: LogMsg("regState_Unregistered %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError; + case regState_NATError: LogMsg("regState_NATError %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError; + case regState_NoTarget: LogMsg("regState_NoTarget %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError; + default: LogMsg("uDNS_DeregisterRecord: State %d for %##s type %s", rr->state, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError; + } - SetRecordRetry(m, &srs->RR_SRV, err); - info->id = id; - info->state = regState_DeregPending; - - return; - - error: - unlinkSRS(m, srs); - info->state = regState_Unregistered; + if (rr->state != regState_Unregistered) SendRecordDeregistration(m, rr); + return mStatus_NoError; } +// Called with lock held mDNSexport mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs) { - NATTraversalInfo *nat = srs->uDNS_info.NATinfo; char *errmsg = "Unknown State"; - + + if (m->mDNS_busy != m->mDNS_reentrancy+1) + LogMsg("uDNS_DeregisterService: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); + // don't re-register with a new target following deregistration - srs->uDNS_info.SRVChanged = srs->uDNS_info.SRVUpdateDeferred = mDNSfalse; + srs->SRVChanged = srs->SRVUpdateDeferred = mDNSfalse; + + if (srs->nta) { CancelGetZoneData(m, srs->nta); srs->nta = mDNSNULL; } - if (nat) + if (srs->NATinfo.clientContext) { - if (nat->state == NATState_Established || nat->state == NATState_Refresh || nat->state == NATState_Legacy) - DeleteNATPortMapping(m, nat, srs); - nat->reg.ServiceRegistration = mDNSNULL; - srs->uDNS_info.NATinfo = mDNSNULL; - FreeNATInfo(m, nat); + mDNS_StopNATOperation_internal(m, &srs->NATinfo); + srs->NATinfo.clientContext = mDNSNULL; } - - switch (srs->uDNS_info.state) + + switch (srs->state) { case regState_Unregistered: debugf("uDNS_DeregisterService - service %##s not registered", srs->RR_SRV.resrec.name->c); return mStatus_BadReferenceErr; - case regState_FetchingZoneData: - // let the async op complete, then terminate - srs->uDNS_info.state = regState_Cancelled; - return mStatus_NoError; // deliver memfree upon completion of async op case regState_Pending: case regState_Refresh: case regState_UpdatePending: // deregister following completion of in-flight operation - srs->uDNS_info.state = regState_DeregDeferred; + srs->state = regState_DeregDeferred; return mStatus_NoError; case regState_DeregPending: case regState_DeregDeferred: - case regState_Cancelled: debugf("Double deregistration of service %##s", srs->RR_SRV.resrec.name->c); return mStatus_NoError; - case regState_NATError: // not registered - case regState_NATMap: // not registered - case regState_NoTarget: // not registered + case regState_NATError: // not registered + case regState_NATMap: // not registered + case regState_NoTarget: // not registered unlinkSRS(m, srs); - srs->uDNS_info.state = regState_Unregistered; - m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback + srs->state = regState_Unregistered; + mDNS_DropLockBeforeCallback(); srs->ServiceCallback(m, srs, mStatus_MemFree); - m->mDNS_reentrancy--; // Decrement to block mDNS API calls again + mDNS_ReclaimLockAfterCallback(); return mStatus_NoError; + case regState_FetchingZoneData: case regState_Registered: - srs->uDNS_info.state = regState_DeregPending; + srs->state = regState_DeregPending; SendServiceDeregistration(m, srs); return mStatus_NoError; case regState_ExtraQueued: // only for record registrations errmsg = "bad state (regState_ExtraQueued)"; goto error; + default: LogMsg("uDNS_DeregisterService: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c); } error: @@ -4603,94 +4204,70 @@ mDNSexport mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs) return mStatus_BadReferenceErr; } -mDNSexport mStatus uDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra) - { - mStatus err = mStatus_UnknownErr; - - extra->r.resrec.RecordType = kDNSRecordTypeShared; // don't want it to conflict with the service name - extra->r.RecordCallback = mDNSNULL; // don't generate callbacks for extra RRs - - if (sr->uDNS_info.state == regState_Registered || sr->uDNS_info.state == regState_Refresh) - err = uDNS_RegisterRecord(m, &extra->r); - else - { - err = SetupRecordRegistration(m, &extra->r); - extra->r.uDNS_info.state = regState_ExtraQueued; // %%% Is it okay to overwrite the previous uDNS_info.state? - } - - if (!err) - { - extra->next = sr->Extras; - sr->Extras = extra; - } - return err; - } - mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr) { - uDNS_GlobalInfo *u = &m->uDNS_info; ServiceRecordSet *parent = mDNSNULL; AuthRecord *rptr; - uDNS_RegInfo *info = &rr->uDNS_info; regState_t *stateptr = mDNSNULL; - + // find the record in registered service list - for (parent = u->ServiceRegistrations; parent; parent = parent->next) - if (&parent->RR_TXT == rr) { stateptr = &parent->uDNS_info.state; break; } + for (parent = m->ServiceRegistrations; parent; parent = parent->uDNS_next) + if (&parent->RR_TXT == rr) { stateptr = &parent->state; break; } if (!parent) { // record not part of a service - check individual record registrations - for (rptr = u->RecordRegistrations; rptr; rptr = rptr->next) - if (rptr == rr) { stateptr = &rr->uDNS_info.state; break; } + for (rptr = m->ResourceRecords; rptr; rptr = rptr->next) + if (rptr == rr) { stateptr = &rr->state; break; } if (!rptr) goto unreg_error; } - + switch(*stateptr) { case regState_DeregPending: case regState_DeregDeferred: - case regState_Cancelled: case regState_Unregistered: // not actively registered goto unreg_error; - + case regState_FetchingZoneData: case regState_NATMap: case regState_ExtraQueued: case regState_NoTarget: // change rdata directly since it hasn't been sent yet - if (info->UpdateRDCallback) info->UpdateRDCallback(m, rr, rr->resrec.rdata); + if (rr->UpdateCallback) rr->UpdateCallback(m, rr, rr->resrec.rdata); SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength); rr->NewRData = mDNSNULL; return mStatus_NoError; - + case regState_Pending: case regState_Refresh: case regState_UpdatePending: - // registration in-flight. queue rdata and return - if (info->QueuedRData && info->UpdateRDCallback) + // registration in-flight. queue rdata and return + if (rr->QueuedRData && rr->UpdateCallback) // if unsent rdata is already queued, free it before we replace it - info->UpdateRDCallback(m, rr, info->QueuedRData); - info->QueuedRData = rr->NewRData; - info->QueuedRDLen = rr->newrdlength; + rr->UpdateCallback(m, rr, rr->QueuedRData); + rr->QueuedRData = rr->NewRData; + rr->QueuedRDLen = rr->newrdlength; rr->NewRData = mDNSNULL; return mStatus_NoError; - + case regState_Registered: - info->OrigRData = rr->resrec.rdata; - info->OrigRDLen = rr->resrec.rdlength; - info->InFlightRData = rr->NewRData; - info->InFlightRDLen = rr->newrdlength; + rr->OrigRData = rr->resrec.rdata; + rr->OrigRDLen = rr->resrec.rdlength; + rr->InFlightRData = rr->NewRData; + rr->InFlightRDLen = rr->newrdlength; rr->NewRData = mDNSNULL; *stateptr = regState_UpdatePending; - if (parent) SendServiceRegistration(m, parent); - else sendRecordRegistration(m, rr); + if (parent) SendServiceRegistration(m, parent); + else SendRecordRegistration(m, rr); return mStatus_NoError; case regState_NATError: LogMsg("ERROR: uDNS_UpdateRecord called for record %##s with bad state regState_NATError", rr->resrec.name->c); - return mStatus_UnknownErr; // states for service records only + return mStatus_UnknownErr; // states for service records only + + default: LogMsg("uDNS_UpdateRecord: Unknown state %d for %##s", *stateptr, rr->resrec.name->c); } unreg_error: @@ -4699,252 +4276,360 @@ mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr) return mStatus_Invalid; } - // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - Periodic Execution Routines #endif +// See comments above for DNSRelayTestQuestion +// If this is the kind of query that has the risk of crashing buggy DNS servers, we do a test question first +mDNSlocal mDNSBool NoTestQuery(DNSQuestion *q) + { + int i; + mDNSu8 *p = q->qname.c; + if (q->AuthInfo) return(mDNStrue); // Don't need a test query for private queries sent directly to authoritative server over TLS/TCP + if (q->qtype != kDNSType_PTR) return(mDNStrue); // Don't need a test query for any non-PTR queries + for (i=0; i<4; i++) // If qname does not begin with num.num.num.num, can't skip the test query + { + if (p[0] < 1 || p[0] > 3) return(mDNSfalse); + if ( p[1] < '0' || p[1] > '9' ) return(mDNSfalse); + if (p[0] >= 2 && (p[2] < '0' || p[2] > '9')) return(mDNSfalse); + if (p[0] >= 3 && (p[3] < '0' || p[3] > '9')) return(mDNSfalse); + p += 1 + p[0]; + } + // If remainder of qname is ".in-addr.arpa.", this is a vanilla reverse-mapping query and + // we can safely do it without needing a test query first, otherwise we need the test query. + return(SameDomainName((domainname*)p, (const domainname*)"\x7" "in-addr" "\x4" "arpa")); + } -mDNSlocal mDNSs32 CheckNATMappings(mDNS *m, mDNSs32 timenow) +// The question to be checked is not passed in as an explicit parameter; +// instead it is implicit that the question to be checked is m->CurrentQuestion. +mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) { - NATTraversalInfo *ptr = m->uDNS_info.NATTraversals; - mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC; - - while (ptr) + DNSQuestion *q = m->CurrentQuestion; + mDNSs32 sendtime = q->LastQTime + q->ThisQInterval; + // Don't allow sendtime to be earlier than SuppressStdPort53Queries + if (!q->LongLived && m->SuppressStdPort53Queries && sendtime - m->SuppressStdPort53Queries < 0) + sendtime = m->SuppressStdPort53Queries; + if (m->timenow - sendtime < 0) return; + + if (q->LongLived && q->state != LLQ_Poll) + { + if (q->state >= LLQ_InitialRequest && q->state <= LLQ_Established) + { + // sanity check to avoid packet flood bugs + if (q->state == LLQ_Established || q->state == LLQ_Refresh) sendLLQRefresh(m, q, q->origLease); + else if (q->state == LLQ_InitialRequest ) startLLQHandshake(m, q); + else if (q->state == LLQ_SecondaryRequest ) sendChallengeResponse(m, q, mDNSNULL); + else if (q->state == LLQ_Retry ) { q->ntries = 0; startLLQHandshake(m, q); } + } + else + { + // This should never happen. Any LLQ not in states LLQ_InitialRequest to LLQ_Established should not have have ThisQInterval set. + // (uDNS_CheckCurrentQuestion() is only called for DNSQuestions with non-zero ThisQInterval) + LogMsg("uDNS_CheckCurrentQuestion: %##s (%s) state %d sendtime %d ThisQInterval %d", + q->qname.c, DNSTypeName(q->qtype), q->state, sendtime - m->timenow, q->ThisQInterval); + q->LastQTime = m->timenow; + q->ThisQInterval *= 2; + SetNextQueryTime(m, q); + } + } + + // We repeat the check above (rather than just making this the "else" case) because startLLQHandshake can change q->state to LLQ_Poll + if (!(q->LongLived && q->state != LLQ_Poll)) { - NATTraversalInfo *cur = ptr; - ptr = ptr->next; - if (cur->op != NATOp_AddrRequest || cur->state != NATState_Established) // no refresh necessary for established Add requests + if (q->qDNSServer && q->qDNSServer->teststate != DNSServer_Disabled) { - if (cur->retry - timenow < 0) + mDNSu8 *end = m->omsg.data; + mStatus err = mStatus_NoError; + DomainAuthInfo *private = mDNSNULL; + + if (q->qDNSServer->teststate != DNSServer_Untested || NoTestQuery(q)) + { + err = constructQueryMsg(&m->omsg, &end, q); + private = q->AuthInfo; + } + else if (m->timenow - q->qDNSServer->lasttest >= INIT_UCAST_POLL_INTERVAL) // Make sure at least three seconds has elapsed since last test query + { + LogOperation("Sending DNS test query to %#a:%d", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port)); + q->ThisQInterval = INIT_UCAST_POLL_INTERVAL; + q->qDNSServer->lasttest = m->timenow; + InitializeDNSMessage(&m->omsg.h, mDNS_NewMessageID(m), uQueryFlags); + end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, DNSRelayTestQuestion, kDNSType_PTR, kDNSClass_IN); + } + + if (err) LogMsg("Error: uDNS_CheckCurrentQuestion - constructQueryMsg. Skipping question %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + else { - if (cur->state == NATState_Established) RefreshNATMapping(cur, m); - else if (cur->state == NATState_Request || cur->state == NATState_Refresh) + if (end > m->omsg.data && (q->qDNSServer->teststate != DNSServer_Failed || NoTestQuery(q))) + { + //LogMsg("uDNS_CheckCurrentQuestion %d %p %##s (%s)", sendtime - m->timenow, private, q->qname.c, DNSTypeName(q->qtype)); + if (private) + { + if (q->nta) LogMsg("uDNS_CheckCurrentQuestion Error: GetZoneData already started for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + else q->nta = StartGetZoneData(m, &q->qname, q->LongLived ? ZoneServiceLLQ : ZoneServiceQuery, startPrivateQueryCallback, q); + q->ThisQInterval = 0; // Suspend this question until GetZoneData completes + } + else + { + err = mDNSSendDNSMessage(m, &m->omsg, end, q->qDNSServer->interface, &q->qDNSServer->addr, q->qDNSServer->port, mDNSNULL, mDNSNULL); + m->SuppressStdPort53Queries = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+99)/100); + } + } + + if (err) debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %ld", err); // surpress syslog messages if we have no network + else if (!q->LongLived && q->ThisQInterval < MAX_UCAST_POLL_INTERVAL) + { + q->ThisQInterval = q->ThisQInterval * QuestionIntervalStep; // Only increase interval if send succeeded + LogOperation("Adjusted ThisQInterval to %d for %##s (%s)", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype)); + } + else if (q->LongLived && q->state == LLQ_Poll) { - if (cur->ntries >= NATMAP_MAX_TRIES) cur->ReceiveResponse(cur, m, mDNSNULL, 0); // may invalidate "cur" - else SendNATMsg(cur, m); + // Bit of a hack here -- if we dropped the interval down to do the DNS test query, need to put + // it back or we'll poll every three seconds. The real solution is that the DNS test query + // should be a real query in its own right, which other queries are blocked on, rather than + // being shoehorned in here and borrowing another question's q->LastQTime and q->ThisQInterval + q->ThisQInterval = LLQ_POLL_INTERVAL; } } - else if (cur->retry - nextevent < 0) nextevent = cur->retry; + q->LastQTime = m->timenow; + SetNextQueryTime(m, q); + } + else + { + // If we have no server for this query, or the only server is a disabled one, then we deliver + // a transient failure indication to the client. This is important for things like iPhone + // where we want to return timely feedback to the user when no network is available. + // After calling MakeNegativeCacheRecord() we store the resulting record in the + // cache so that it will be visible to other clients asking the same question + + CacheRecord *rr; + const mDNSu32 slot = HashSlot(&q->qname); + CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); + if (cg) + for (rr = cg->members; rr; rr=rr->next) + if (SameNameRecordAnswersQuestion(&rr->resrec, q)) mDNS_PurgeCacheResourceRecord(m, rr); + + if (!q->qDNSServer) LogMsg("uDNS_CheckCurrentQuestion no DNS server for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + else LogMsg("uDNS_CheckCurrentQuestion DNS server %#a:%d for %##s is disabled", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qname.c); + + MakeNegativeCacheRecord(m, &q->qname, q->qnamehash, q->qtype, q->qclass, 60); + // Inactivate this question until the next change of DNS servers (do this before AnswerCurrentQuestionWithResourceRecord) + q->ThisQInterval = 0; + CreateNewCacheEntry(m, slot, cg); + m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it + // MUST NOT touch m->CurrentQuestion (or q) after this -- client callback could have deleted it } } - return nextevent; } -mDNSlocal mDNSs32 CheckQueries(mDNS *m, mDNSs32 timenow) +mDNSlocal void CheckNATMappings(mDNS *m) { - DNSQuestion *q; - uDNS_GlobalInfo *u = &m->uDNS_info; - LLQ_Info *llq; - mDNSs32 sendtime; - mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC; - DNSMessage msg; mStatus err = mStatus_NoError; - mDNSu8 *end; - uDNS_QuestionInfo *info; - - u->CurrentQuery = u->ActiveQueries; - while (u->CurrentQuery) + mDNSBool rfc1918 = mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4); + mDNSBool HaveRoutable = !rfc1918 && !mDNSIPv4AddressIsZero(m->AdvertisedV4.ip.v4); + m->NextScheduledNATOp = m->timenow + 0x3FFFFFFF; + + if (HaveRoutable) m->ExternalAddress = m->AdvertisedV4.ip.v4; + + if (m->NATTraversals && rfc1918) // Do we need to open NAT-PMP socket to receive multicast announcements from router? { - q = u->CurrentQuery; - info = &q->uDNS_info; - llq = info->llq; - - if (!info->internal && ((!q->LongLived && !info->Answered) || (llq && llq->state < LLQ_Established)) && - info->RestartTime + RESTART_GOODBYE_DELAY - timenow < 0) + if (m->NATMcastRecvskt == mDNSNULL) // If we are behind a NAT and the socket hasn't been opened yet, open it + { + m->NATMcastRecvskt = mDNSPlatformUDPSocket(m, NATPMPAnnouncementPort); + m->NATMcastRecvsk2 = mDNSPlatformUDPSocket(m, NATPMPPort); // For backwards compatibility with older base stations that announce on 5351 + if (!m->NATMcastRecvskt) LogMsg("CheckNATMappings: Failed to allocate port 5350 UDP multicast socket for NAT-PMP announcements"); + if (!m->NATMcastRecvsk2) LogOperation("CheckNATMappings: Failed to allocate port 5351 UDP multicast socket for NAT-PMP announcements"); + } + } + else // else, we don't want to listen for announcements, so close them if they're open + { + if (m->NATMcastRecvskt) { mDNSPlatformUDPClose(m->NATMcastRecvskt); m->NATMcastRecvskt = mDNSNULL; } + if (m->NATMcastRecvsk2) { mDNSPlatformUDPClose(m->NATMcastRecvsk2); m->NATMcastRecvsk2 = mDNSNULL; } + } + + if (m->NATTraversals) + { + if (m->timenow - m->retryGetAddr >= 0) { - // if we've been spinning on restart setup, and we have known answers, give goodbyes (they may be re-added later) - while (info->knownAnswers) + err = uDNS_SendNATMsg(m, mDNSNULL); // Will also do UPnP discovery for us, if necessary + if (!err) { - CacheRecord *cr = info->knownAnswers; - info->knownAnswers = info->knownAnswers->next; - - m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback - q->QuestionCallback(m, q, &cr->resrec, mDNSfalse); - m->mDNS_reentrancy--; // Decrement to block mDNS API calls again - ufree(cr); - if (q != u->CurrentQuery) { debugf("CheckQueries - question removed via callback."); break; } + if (m->retryIntervalGetAddr < NATMAP_INIT_RETRY) m->retryIntervalGetAddr = NATMAP_INIT_RETRY; + else if (m->retryIntervalGetAddr < NATMAP_MAX_RETRY_INTERVAL / 2) m->retryIntervalGetAddr *= 2; + else m->retryIntervalGetAddr = NATMAP_MAX_RETRY_INTERVAL; } + // Always update m->retryGetAddr, even if we fail to send the packet. Otherwise in cases where we can't send the packet + // (like when we have no active interfaces) we'll spin in an infinite loop repeatedly failing to send the packet + m->retryGetAddr = m->timenow + m->retryIntervalGetAddr; } - if (q != u->CurrentQuery) continue; - - if (q->LongLived && llq->state != LLQ_Poll) + // Even when we didn't send the GetAddr packet, still need to make sure NextScheduledNATOp is set correctly + if (m->NextScheduledNATOp - m->retryGetAddr > 0) + m->NextScheduledNATOp = m->retryGetAddr; + } + + if (m->CurrentNATTraversal) LogMsg("WARNING m->CurrentNATTraversal already in use"); + m->CurrentNATTraversal = m->NATTraversals; + + while (m->CurrentNATTraversal) + { + NATTraversalInfo *cur = m->CurrentNATTraversal; + m->CurrentNATTraversal = m->CurrentNATTraversal->next; + + if (HaveRoutable) // If not RFC 1918 address, our own address and port are effectively our external address and port + { + cur->ExpiryTime = 0; + cur->NewResult = mStatus_NoError; + } + else if (cur->Protocol) // Check if it's time to send port mapping packets { - if (llq->state >= LLQ_InitialRequest && llq->state <= LLQ_Established) + if (m->timenow - cur->retryPortMap >= 0) // Time to do something with this mapping { - if (llq->retry - timenow < 0) + if (cur->ExpiryTime && cur->ExpiryTime - m->timenow < 0) // Mapping has expired + { + cur->ExpiryTime = 0; + cur->retryInterval = NATMAP_INIT_RETRY; + } + + //LogMsg("uDNS_SendNATMsg"); + err = uDNS_SendNATMsg(m, cur); + + if (cur->ExpiryTime) // If have active mapping then set next renewal time halfway to expiry + NATSetNextRenewalTime(m, cur); + else // else no mapping; use exponential backoff sequence { - // sanity check to avoid packet flood bugs - if (!llq->retry) - LogMsg("ERROR: retry timer not set for LLQ %##s in state %d", q->qname.c, llq->state); - else if (llq->state == LLQ_Established || llq->state == LLQ_Refresh) - sendLLQRefresh(m, q, llq->origLease); - else if (llq->state == LLQ_InitialRequest) - startLLQHandshake(m, llq, mDNSfalse); - else if (llq->state == LLQ_SecondaryRequest) - sendChallengeResponse(m, q, mDNSNULL); - else if (llq->state == LLQ_Retry) - { llq->ntries = 0; startLLQHandshake(m, llq, mDNSfalse); } + if (cur->retryInterval < NATMAP_INIT_RETRY ) cur->retryInterval = NATMAP_INIT_RETRY; + else if (cur->retryInterval < NATMAP_MAX_RETRY_INTERVAL / 2) cur->retryInterval *= 2; + else cur->retryInterval = NATMAP_MAX_RETRY_INTERVAL; + cur->retryPortMap = m->timenow + cur->retryInterval; } - else if (llq->retry - nextevent < 0) nextevent = llq->retry; } + + if (m->NextScheduledNATOp - cur->retryPortMap > 0) + m->NextScheduledNATOp = cur->retryPortMap; } - else + + // Notify the client if necessary. We invoke the callback if: + // (1) we have an ExternalAddress, or we've tried and failed a couple of times to discover it + // and (2) the client doesn't want a mapping, or the client won't need a mapping, or the client has a successful mapping, or we've tried and failed a couple of times + // and (3) we have new data to give the client that's changed since the last callback + if (!mDNSIPv4AddressIsZero(m->ExternalAddress) || m->retryIntervalGetAddr > NATMAP_INIT_RETRY * 8) { - sendtime = q->LastQTime + q->ThisQInterval; - if (m->SuppressStdPort53Queries && - sendtime - m->SuppressStdPort53Queries < 0) // Don't allow sendtime to be earlier than SuppressStdPort53Queries - sendtime = m->SuppressStdPort53Queries; - if (sendtime - timenow < 0) - { - DNSServer *server = GetServerForName(&m->uDNS_info, &q->qname); - if (server) + const mDNSIPPort ExternalPort = HaveRoutable ? cur->IntPort : + !mDNSIPv4AddressIsZero(m->ExternalAddress) && cur->ExpiryTime ? cur->RequestedPort : zeroIPPort; + if (!cur->Protocol || HaveRoutable || cur->ExpiryTime || cur->retryInterval > NATMAP_INIT_RETRY * 8) + if (!mDNSSameIPv4Address(cur->ExternalAddress, m->ExternalAddress) || + !mDNSSameIPPort (cur->ExternalPort, ExternalPort) || + cur->Result != cur->NewResult) { - if (server->teststate == DNSServer_Untested) - { - InitializeDNSMessage(&msg.h, newMessageID(&m->uDNS_info), uQueryFlags); - end = putQuestion(&msg, msg.data, msg.data + AbsoluteMaxDNSMessageData, DNSRelayTestQuestion, kDNSType_PTR, kDNSClass_IN); - } - else - err = constructQueryMsg(&msg, &end, q); - if (err) LogMsg("Error: uDNS_Idle - constructQueryMsg. Skipping question %##s", q->qname.c); - else - { - if (server->teststate != DNSServer_Failed) - err = mDNSSendDNSMessage(m, &msg, end, mDNSInterface_Any, &server->addr, UnicastDNSPort, -1, mDNSNULL); - m->SuppressStdPort53Queries = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+99)/100); - q->LastQTime = timenow; - if (err) debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %ld", err); // surpress syslog messages if we have no network - else if (q->ThisQInterval < MAX_UCAST_POLL_INTERVAL) q->ThisQInterval = q->ThisQInterval * 2; // don't increase interval if send failed - } + //LogMsg("NAT callback %d %d %d", cur->Protocol, cur->ExpiryTime, cur->retryInterval); + if (cur->Protocol && mDNSIPPortIsZero(ExternalPort)) + LogMsg("Failed to obtain NAT port mapping from router %#a external address %.4a internal port %d", + &m->Router, &m->ExternalAddress, mDNSVal16(cur->IntPort)); + cur->ExternalAddress = m->ExternalAddress; + cur->ExternalPort = ExternalPort; + cur->Lifetime = cur->ExpiryTime && !mDNSIPPortIsZero(ExternalPort) ? + (cur->ExpiryTime - m->timenow + mDNSPlatformOneSecond/2) / mDNSPlatformOneSecond : 0; + cur->Result = cur->NewResult; + mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback + if (cur->clientCallback) + cur->clientCallback(m, cur); + mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again + // MUST NOT touch cur after invoking the callback } - } - else if (sendtime - nextevent < 0) nextevent = sendtime; } - u->CurrentQuery = u->CurrentQuery->next; } - return nextevent; } -mDNSlocal mDNSs32 CheckRecordRegistrations(mDNS *m, mDNSs32 timenow) +mDNSlocal mDNSs32 CheckRecordRegistrations(mDNS *m) { AuthRecord *rr; - uDNS_RegInfo *rInfo; - uDNS_GlobalInfo *u = &m->uDNS_info; - mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC; - - //!!!KRS list should be pre-sorted by expiration - for (rr = u->RecordRegistrations; rr; rr = rr->next) + mDNSs32 nextevent = m->timenow + 0x3FFFFFFF; + + for (rr = m->ResourceRecords; rr; rr = rr->next) { - rInfo = &rr->uDNS_info; - if (rInfo->state == regState_Pending || rInfo->state == regState_DeregPending || rInfo->state == regState_UpdatePending || rInfo->state == regState_DeregDeferred || rInfo->state == regState_Refresh) + if (rr->state == regState_Pending || rr->state == regState_DeregPending || rr->state == regState_UpdatePending || rr->state == regState_DeregDeferred || rr->state == regState_Refresh) { - if (rr->LastAPTime + rr->ThisAPInterval - timenow < 0) + if (rr->LastAPTime + rr->ThisAPInterval - m->timenow < 0) { -#if MDNS_DEBUGMSGS - char *op = "(unknown operation)"; - if (rInfo->state == regState_Pending) op = "registration"; - else if (rInfo->state == regState_DeregPending) op = "deregistration"; - else if (rInfo->state == regState_Refresh) op = "refresh"; - debugf("Retransmit record %s %##s", op, rr->resrec.name->c); -#endif - //LogMsg("Retransmit record %##s", rr->resrec.name->c); - if (rInfo->state == regState_DeregPending) SendRecordDeregistration(m, rr); - else sendRecordRegistration(m, rr); + if (rr->tcp) { rr->LastAPTime = m->timenow; rr->ThisAPInterval = 0x3FFFFFFF; } + else if (rr->state == regState_DeregPending) SendRecordDeregistration(m, rr); + else SendRecordRegistration(m, rr); } if (rr->LastAPTime + rr->ThisAPInterval - nextevent < 0) nextevent = rr->LastAPTime + rr->ThisAPInterval; } - if (rInfo->lease && rInfo->state == regState_Registered) - { - if (rInfo->expire - timenow < 0) - { - debugf("refreshing record %##s", rr->resrec.name->c); - rInfo->state = regState_Refresh; - sendRecordRegistration(m, rr); - } - if (rInfo->expire - nextevent < 0) nextevent = rInfo->expire; - } + if (rr->uselease && rr->state == regState_Registered) + { + if (rr->expire - m->timenow < 0) + { + debugf("refreshing record %##s", rr->resrec.name->c); + rr->state = regState_Refresh; + SendRecordRegistration(m, rr); + } + if (rr->expire - nextevent < 0) nextevent = rr->expire; + } } return nextevent; } -mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m, mDNSs32 timenow) +mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m) { - ServiceRecordSet *s = m->uDNS_info.ServiceRegistrations; - uDNS_RegInfo *rInfo; - mDNSs32 nextevent = timenow + MIN_UCAST_PERIODIC_EXEC; - + mDNSs32 nextevent = m->timenow + 0x3FFFFFFF; + + if (CurrentServiceRecordSet) + LogMsg("CheckServiceRegistrations ERROR CurrentServiceRecordSet already set"); + CurrentServiceRecordSet = m->ServiceRegistrations; + // Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery - while (s) + while (CurrentServiceRecordSet) { - ServiceRecordSet *srs = s; - // NOTE: Must advance s here -- SendServiceDeregistration may delete the object we're looking at, - // and then if we tried to do srs = srs->next at the end we'd be referencing a dead object - s = s->next; - - rInfo = &srs->uDNS_info; - if (rInfo->state == regState_Pending || rInfo->state == regState_DeregPending || rInfo->state == regState_DeregDeferred || rInfo->state == regState_Refresh || rInfo->state == regState_UpdatePending) + ServiceRecordSet *srs = CurrentServiceRecordSet; + CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next; + if (srs->state == regState_Pending || srs->state == regState_DeregPending || srs->state == regState_DeregDeferred || srs->state == regState_Refresh || srs->state == regState_UpdatePending) { - if (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval - timenow < 0) + if (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval - m->timenow < 0) { -#if MDNS_DEBUGMSGS - char *op = "unknown"; - if (rInfo->state == regState_Pending) op = "registration"; - else if (rInfo->state == regState_DeregPending) op = "deregistration"; - else if (rInfo->state == regState_Refresh) op = "refresh"; - else if (rInfo->state == regState_UpdatePending) op = "txt record update"; - debugf("Retransmit service %s %##s", op, srs->RR_SRV.resrec.name->c); -#endif - if (rInfo->state == regState_DeregPending) { SendServiceDeregistration(m, srs); continue; } - else SendServiceRegistration (m, srs); + if (srs->tcp) { srs->RR_SRV.LastAPTime = m->timenow; srs->RR_SRV.ThisAPInterval = 0x3FFFFFFF; } + else if (srs->state == regState_DeregPending) { SendServiceDeregistration(m, srs); continue; } + else SendServiceRegistration(m, srs); } if (nextevent - srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval > 0) nextevent = srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval; } - if (rInfo->lease && rInfo->state == regState_Registered) - { - if (rInfo->expire - timenow < 0) - { - debugf("refreshing service %##s", srs->RR_SRV.resrec.name->c); - rInfo->state = regState_Refresh; - SendServiceRegistration(m, srs); - } - if (rInfo->expire - nextevent < 0) nextevent = rInfo->expire; - } + if (srs->srs_uselease && srs->state == regState_Registered) + { + if (srs->expire - m->timenow < 0) + { + debugf("refreshing service %##s", srs->RR_SRV.resrec.name->c); + srs->state = regState_Refresh; + SendServiceRegistration(m, srs); + } + if (srs->expire - nextevent < 0) nextevent = srs->expire; + } } return nextevent; } mDNSexport void uDNS_Execute(mDNS *const m) { - uDNS_GlobalInfo *u = &m->uDNS_info; - mDNSs32 nexte, timenow = mDNSPlatformTimeNow(m); + mDNSs32 nexte; - u->nextevent = timenow + MIN_UCAST_PERIODIC_EXEC; + m->NextuDNSEvent = m->timenow + 0x3FFFFFFF; - if (u->DelaySRVUpdate && u->NextSRVUpdate - timenow < 0) - { - u->DelaySRVUpdate = mDNSfalse; - UpdateSRVRecords(m); - } - - nexte = CheckNATMappings(m, timenow); - if (nexte - u->nextevent < 0) u->nextevent = nexte; + if (m->NextSRVUpdate && m->NextSRVUpdate - m->timenow < 0) + { m->NextSRVUpdate = 0; UpdateSRVRecords(m); } - if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0) - m->SuppressStdPort53Queries = 0; // If suppression time has passed, clear it + CheckNATMappings(m); - nexte = CheckQueries(m, timenow); - if (nexte - u->nextevent < 0) u->nextevent = nexte; + if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0) + m->SuppressStdPort53Queries = 0; // If suppression time has passed, clear it - nexte = CheckRecordRegistrations(m, timenow); - if (nexte - u->nextevent < 0) u->nextevent = nexte; + nexte = CheckRecordRegistrations(m); + if (nexte - m->NextuDNSEvent < 0) m->NextuDNSEvent = nexte; - nexte = CheckServiceRegistrations(m, timenow); - if (nexte - u->nextevent < 0) u->nextevent = nexte; - + nexte = CheckServiceRegistrations(m); + if (nexte - m->NextuDNSEvent < 0) m->NextuDNSEvent = nexte; } // *************************************************************************** @@ -4952,34 +4637,44 @@ mDNSexport void uDNS_Execute(mDNS *const m) #pragma mark - Startup, Shutdown, and Sleep #endif -// DeregisterActive causes active LLQs to be removed from the server, e.g. before sleep. Pass false +// DeregisterActive causes active LLQs to be removed from the server, e.g. before sleep. Pass false // following a location change, as the server will reject deletions from a source address different // from the address on which the LLQ was created. mDNSlocal void SuspendLLQs(mDNS *m, mDNSBool DeregisterActive) { DNSQuestion *q; - LLQ_Info *llq; - for (q = m->uDNS_info.ActiveQueries; q; q = q->next) + + for (q = m->Questions; q; q = q->next) { - llq = q->uDNS_info.llq; - if (q->LongLived && llq) + if (q->LongLived) { - if (llq->state == LLQ_GetZoneInfo) + if (q->state == LLQ_GetZoneInfo) { debugf("Marking %##s suspend-deferred", q->qname.c); - llq->state = LLQ_SuspendDeferred; // suspend once we're done getting zone info + q->state = LLQ_SuspendDeferred; // suspend once we're done getting zone info } - else if (llq->state < LLQ_Suspended) + else if (q->state < LLQ_Suspended) { - if (DeregisterActive && (llq->state == LLQ_Established || llq->state == LLQ_Refresh)) - { debugf("Deleting LLQ %##s", q->qname.c); sendLLQRefresh(m, q, 0); } + if (DeregisterActive && (q->state == LLQ_Established || q->state == LLQ_Refresh)) + { + debugf("Deleting LLQ %##s", q->qname.c); + sendLLQRefresh(m, q, 0); + } debugf("Marking %##s suspended", q->qname.c); - llq->state = LLQ_Suspended; - ubzero(llq->id, 8); + q->state = LLQ_Suspended; + + if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; } + + q->id = zeroOpaque64; + } + else if (q->state == LLQ_Poll) + { + debugf("Marking %##s suspended-poll", q->qname.c); + q->state = LLQ_SuspendedPoll; } - else if (llq->state == LLQ_Poll) { debugf("Marking %##s suspended-poll", q->qname.c); llq->state = LLQ_SuspendedPoll; } - if (llq->NATMap) llq->NATMap = mDNSfalse; // may not need nat mapping if we restart with new route + + RemoveLLQNatMappings(m, q); // may not need nat mapping if we restart with new route } } CheckForUnreferencedLLQMapping(m); @@ -4987,53 +4682,48 @@ mDNSlocal void SuspendLLQs(mDNS *m, mDNSBool DeregisterActive) mDNSlocal void RestartQueries(mDNS *m) { - uDNS_GlobalInfo *u = &m->uDNS_info; - DNSQuestion *q; - LLQ_Info *llqInfo; - mDNSs32 timenow = mDNSPlatformTimeNow(m); - - u->CurrentQuery = u->ActiveQueries; - while (u->CurrentQuery) - { - q = u->CurrentQuery; - u->CurrentQuery = u->CurrentQuery->next; - llqInfo = q->uDNS_info.llq; - q->uDNS_info.RestartTime = timenow; - q->uDNS_info.Answered = mDNSfalse; - if (q->LongLived) + if (m->CurrentQuestion) + LogMsg("RestartQueries: ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); + m->CurrentQuestion = m->Questions; + while (m->CurrentQuestion) + { + DNSQuestion *q = m->CurrentQuestion; + m->CurrentQuestion = m->CurrentQuestion->next; + + if (!mDNSOpaque16IsZero(q->TargetQID) && !q->DuplicateOf) { - if (!llqInfo) { LogMsg("Error: RestartQueries - %##s long-lived with NULL info", q->qname.c); continue; } - if (llqInfo->state == LLQ_Suspended || llqInfo->state == LLQ_NatMapWait) + if (q->LongLived) { - llqInfo->ntries = -1; - llqInfo->deriveRemovesOnResume = mDNStrue; - startLLQHandshake(m, llqInfo, mDNStrue); // we set defer to true since several events that may generate restarts often arrive in rapid succession, and this cuts unnecessary packets + if (q->state == LLQ_Suspended || q->state == LLQ_NatMapWaitUDP) + { + q->ntries = -1; + startLLQHandshake(m, q); + } + else if (q->state == LLQ_SuspendDeferred) + q->state = LLQ_GetZoneInfo; // we never finished getting zone data - proceed as usual + else if (q->state == LLQ_SuspendedPoll) + { + // if we were polling, we may have had bad zone data due to firewall, etc. - refetch + q->ntries = 0; + q->state = LLQ_GetZoneInfo; + if (q->nta) CancelGetZoneData(m, q->nta); // Make sure we cancel old one before we start a new one + q->nta = StartGetZoneData(m, &q->qname, ZoneServiceLLQ, startLLQHandshakeCallback, q); + } } - else if (llqInfo->state == LLQ_SuspendDeferred) - llqInfo->state = LLQ_GetZoneInfo; // we never finished getting zone data - proceed as usual - else if (llqInfo->state == LLQ_SuspendedPoll) + else { - // if we were polling, we may have had bad zone data due to firewall, etc. - refetch - llqInfo->ntries = 0; - llqInfo->deriveRemovesOnResume = mDNStrue; - llqInfo->state = LLQ_GetZoneInfo; - startGetZoneData(&q->qname, m, mDNSfalse, mDNStrue, startLLQHandshakeCallback, llqInfo); + q->LastQTime = m->timenow; + q->ThisQInterval = INIT_UCAST_POLL_INTERVAL; // trigger poll in 3 seconds (to reduce packet rate when restarts come in rapid succession) + SetNextQueryTime(m, q); } } - else { q->LastQTime = timenow; q->ThisQInterval = INIT_UCAST_POLL_INTERVAL; } // trigger poll in 1 second (to reduce packet rate when restarts come in rapid succession) } + m->CurrentQuestion = mDNSNULL; } mDNSexport void mDNS_UpdateLLQs(mDNS *m) { - uDNS_GlobalInfo *u = &m->uDNS_info; - mDNS_Lock(m); - if (u->LLQNatInfo) - { - DeleteNATPortMapping(m, u->LLQNatInfo, mDNSNULL); - FreeNATInfo(m, u->LLQNatInfo); // routine clears u->LLQNatInfo ptr - } SuspendLLQs(m, mDNStrue); RestartQueries(m); mDNS_Unlock(m); @@ -5041,34 +4731,30 @@ mDNSexport void mDNS_UpdateLLQs(mDNS *m) // simplest sleep logic - rather than having sleep states that must be dealt with explicitly in all parts of // the code, we simply send a deregistration, and put the service in Refresh state, with a timeout far enough -// in the future that we'll sleep (or the sleep will be cancelled) before it is retransmitted. Then to wake, +// in the future that we'll sleep (or the sleep will be cancelled) before it is retransmitted. Then to wake, // we just move up the timers. - - mDNSlocal void SleepRecordRegistrations(mDNS *m) { - DNSMessage msg; - AuthRecord *rr = m->uDNS_info.RecordRegistrations; - mDNSs32 timenow = mDNSPlatformTimeNow(m); + AuthRecord *rr = m->ResourceRecords; while (rr) { - if (rr->uDNS_info.state == regState_Registered || - rr->uDNS_info.state == regState_Refresh) + if (rr->state == regState_Registered || + rr->state == regState_Refresh) { - mDNSu8 *ptr = msg.data, *end = (mDNSu8 *)&msg + sizeof(DNSMessage); - InitializeDNSMessage(&msg.h, newMessageID(&m->uDNS_info), UpdateReqFlags); - + mDNSu8 *ptr = m->omsg.data, *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage); + InitializeDNSMessage(&m->omsg.h, mDNS_NewMessageID(m), UpdateReqFlags); + // construct deletion update - ptr = putZone(&msg, ptr, end, &rr->uDNS_info.zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass)); + ptr = putZone(&m->omsg, ptr, end, &rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass)); if (!ptr) { LogMsg("Error: SleepRecordRegistrations - could not put zone"); return; } - ptr = putDeletionRecord(&msg, ptr, &rr->resrec); - if (!ptr) { LogMsg("Error: SleepRecordRegistrations - could not put deletion record"); return; } + ptr = putDeletionRecord(&m->omsg, ptr, &rr->resrec); + if (!ptr) { LogMsg("Error: SleepRecordRegistrations - could not put deletion record"); return; } - mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rr->uDNS_info.ns, rr->uDNS_info.port, -1, GetAuthInfoForName(&m->uDNS_info, rr->resrec.name)); - rr->uDNS_info.state = regState_Refresh; - rr->LastAPTime = timenow; + mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name)); + rr->state = regState_Refresh; + rr->LastAPTime = m->timenow; rr->ThisAPInterval = 300 * mDNSPlatformOneSecond; } rr = rr->next; @@ -5077,15 +4763,14 @@ mDNSlocal void SleepRecordRegistrations(mDNS *m) mDNSlocal void WakeRecordRegistrations(mDNS *m) { - mDNSs32 timenow = mDNSPlatformTimeNow(m); - AuthRecord *rr = m->uDNS_info.RecordRegistrations; + AuthRecord *rr = m->ResourceRecords; while (rr) { - if (rr->uDNS_info.state == regState_Refresh) + if (rr->state == regState_Refresh) { // trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets) - rr->LastAPTime = timenow; + rr->LastAPTime = m->timenow; rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL; } rr = rr->next; @@ -5094,69 +4779,258 @@ mDNSlocal void WakeRecordRegistrations(mDNS *m) mDNSlocal void SleepServiceRegistrations(mDNS *m) { - ServiceRecordSet *srs = m->uDNS_info.ServiceRegistrations; - while(srs) + ServiceRecordSet *srs = m->ServiceRegistrations; + while (srs) { - uDNS_RegInfo *info = &srs->uDNS_info; - NATTraversalInfo *nat = info->NATinfo; - - if (nat) + if (srs->nta) { CancelGetZoneData(m, srs->nta); srs->nta = mDNSNULL; } + + if (srs->NATinfo.clientContext) { - if (nat->state == NATState_Established || nat->state == NATState_Refresh || nat->state == NATState_Legacy) - DeleteNATPortMapping(m, nat, srs); - nat->reg.ServiceRegistration = mDNSNULL; - srs->uDNS_info.NATinfo = mDNSNULL; - FreeNATInfo(m, nat); + mDNS_StopNATOperation_internal(m, &srs->NATinfo); + srs->NATinfo.clientContext = mDNSNULL; } - if (info->state == regState_UpdatePending) + if (srs->state == regState_UpdatePending) { // act as if the update succeeded, since we're about to delete the name anyway AuthRecord *txt = &srs->RR_TXT; - uDNS_RegInfo *txtInfo = &txt->uDNS_info; - info->state = regState_Registered; + srs->state = regState_Registered; // deallocate old RData - if (txtInfo->UpdateRDCallback) txtInfo->UpdateRDCallback(m, txt, txtInfo->OrigRData); - SetNewRData(&txt->resrec, txtInfo->InFlightRData, txtInfo->InFlightRDLen); - txtInfo->OrigRData = mDNSNULL; - txtInfo->InFlightRData = mDNSNULL; + if (txt->UpdateCallback) txt->UpdateCallback(m, txt, txt->OrigRData); + SetNewRData(&txt->resrec, txt->InFlightRData, txt->InFlightRDLen); + txt->OrigRData = mDNSNULL; + txt->InFlightRData = mDNSNULL; } - if (info->state == regState_Registered || info->state == regState_Refresh) + if (srs->state == regState_Registered || srs->state == regState_Refresh) { - mDNSOpaque16 origid = srs->uDNS_info.id; - info->state = regState_DeregPending; // state expected by SendDereg() + mDNSOpaque16 origid = srs->id; + srs->state = regState_DeregPending; // state expected by SendDereg() SendServiceDeregistration(m, srs); - info->id = origid; - info->state = regState_NoTarget; // when we wake, we'll re-register (and optionally nat-map) once our address record completes + srs->id = origid; + srs->state = regState_NoTarget; // when we wake, we'll re-register (and optionally nat-map) once our address record completes srs->RR_SRV.resrec.rdata->u.srv.target.c[0] = 0; } - srs = srs->next; + srs = srs->uDNS_next; } } mDNSlocal void WakeServiceRegistrations(mDNS *m) { - mDNSs32 timenow = mDNSPlatformTimeNow(m); - ServiceRecordSet *srs = m->uDNS_info.ServiceRegistrations; - while(srs) + ServiceRecordSet *srs = m->ServiceRegistrations; + while (srs) { - if (srs->uDNS_info.state == regState_Refresh) + if (srs->state == regState_Refresh) { // trigger slightly delayed refresh (we usually get this message before kernel is ready to send packets) - srs->RR_SRV.LastAPTime = timenow; + srs->RR_SRV.LastAPTime = m->timenow; srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL; } - srs = srs->next; + srs = srs->uDNS_next; + } + } + +mDNSexport void mDNS_AddSearchDomain(const domainname *const domain) + { + SearchListElem **p; + + // Check to see if we already have this domain in our list + for (p = &SearchList; *p; p = &(*p)->next) + if (SameDomainName(&(*p)->domain, domain)) + { + // If domain is already in list, and marked for deletion, change it to "leave alone" + if ((*p)->flag == -1) (*p)->flag = 0; + LogOperation("mDNS_AddSearchDomain already in list %##s", domain->c); + return; + } + + // if domain not in list, add to list, mark as add (1) + *p = mDNSPlatformMemAllocate(sizeof(SearchListElem)); + if (!*p) { LogMsg("ERROR: mDNS_AddSearchDomain - malloc"); return; } + mDNSPlatformMemZero(*p, sizeof(SearchListElem)); + AssignDomainName(&(*p)->domain, domain); + (*p)->flag = 1; // add + (*p)->next = mDNSNULL; + LogOperation("mDNS_AddSearchDomain created new %##s", domain->c); + } + +mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result) + { + (void)m; // unused + if (result == mStatus_MemFree) mDNSPlatformMemFree(rr->RecordContext); + } + +mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) + { + SearchListElem *slElem = question->QuestionContext; + mStatus err; + + if (answer->rrtype != kDNSType_PTR) return; + if (answer->RecordType == kDNSRecordTypePacketNegative) return; + + if (AddRecord) + { + const char *name; + ARListElem *arElem = mDNSPlatformMemAllocate(sizeof(ARListElem)); + if (!arElem) { LogMsg("ERROR: malloc"); return; } + mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, FreeARElemCallback, arElem); + if (question == &slElem->BrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowse]; + else if (question == &slElem->DefBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault]; + else if (question == &slElem->AutomaticBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseAutomatic]; + else if (question == &slElem->RegisterQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistration]; + else if (question == &slElem->DefRegisterQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistrationDefault]; + else { LogMsg("FoundDomain - unknown question"); mDNSPlatformMemFree(arElem); return; } + + MakeDomainNameFromDNSNameString(&arElem->ar.namestorage, name); + AppendDNSNameString (&arElem->ar.namestorage, "local"); + AssignDomainName(&arElem->ar.resrec.rdata->u.name, &answer->rdata->u.name); + err = mDNS_Register(m, &arElem->ar); + if (err) { LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err); mDNSPlatformMemFree(arElem); return; } + arElem->next = slElem->AuthRecs; + slElem->AuthRecs = arElem; + } + else + { + ARListElem **ptr = &slElem->AuthRecs; + while (*ptr) + { + if (SameDomainName(&(*ptr)->ar.resrec.rdata->u.name, &answer->rdata->u.name)) + { + ARListElem *dereg = *ptr; + *ptr = (*ptr)->next; + debugf("Deregistering PTR %##s -> %##s", dereg->ar.resrec.name->c, dereg->ar.resrec.rdata->u.name.c); + err = mDNS_Deregister(m, &dereg->ar); + if (err) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err); + // Memory will be freed in the FreeARElemCallback + } + else + ptr = &(*ptr)->next; + } } } -mDNSexport void uDNS_Init(mDNS *const m) +#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING +mDNSexport void udns_validatelists(void *const v) + { + mDNS *const m = v; + + ServiceRecordSet *s; + for (s = m->ServiceRegistrations; s; s=s->uDNS_next) + if (s->uDNS_next == (ServiceRecordSet*)~0) + LogMemCorruption("m->ServiceRegistrations: %p is garbage (%lX)", s, s->uDNS_next); + + NATTraversalInfo *n; + for (n = m->NATTraversals; n; n=n->next) + if (n->next == (NATTraversalInfo *)~0 || n->clientCallback == (NATTraversalClientCallback)~0) + LogMemCorruption("m->NATTraversals: %p is garbage", n); + + DNSServer *d; + for (d = m->DNSServers; d; d=d->next) + if (d->next == (DNSServer *)~0 || d->teststate > DNSServer_Disabled) + LogMemCorruption("m->DNSServers: %p is garbage (%d)", d, d->teststate); + + DomainAuthInfo *info; + for (info = m->AuthInfoList; info; info = info->next) + if (info->next == (DomainAuthInfo *)~0 || info->AutoTunnel == (mDNSBool)~0) + LogMemCorruption("m->AuthInfoList: %p is garbage (%X)", info, info->AutoTunnel); + + HostnameInfo *hi; + for (hi = m->Hostnames; hi; hi = hi->next) + if (hi->next == (HostnameInfo *)~0 || hi->StatusCallback == (mDNSRecordCallback*)~0) + LogMemCorruption("m->Hostnames: %p is garbage", n); + + SearchListElem *ptr; + for (ptr = SearchList; ptr; ptr = ptr->next) + if (ptr->next == (SearchListElem *)~0 || ptr->AuthRecs == (void*)~0) + LogMemCorruption("SearchList: %p is garbage (%X)", ptr, ptr->AuthRecs); + } +#endif + +// This should probably move to the UDS daemon -- the concept of legacy clients and automatic registration / automatic browsing +// is really a UDS API issue, not something intrinsic to uDNS + +mDNSexport mStatus uDNS_RegisterSearchDomains(mDNS *const m) { - mDNSPlatformMemZero(&m->uDNS_info, sizeof(uDNS_GlobalInfo)); - m->uDNS_info.nextevent = m->timenow_last + 0x78000000; + SearchListElem **p = &SearchList, *ptr; + mStatus err; + + // step 1: mark each element for removal (-1) + for (ptr = SearchList; ptr; ptr = ptr->next) ptr->flag = -1; + + // Client has requested domain enumeration or automatic browse -- time to make sure we have the search domains from the platform layer + mDNS_Lock(m); + m->RegisterSearchDomains = mDNStrue; + mDNSPlatformSetDNSConfig(m, mDNSfalse, m->RegisterSearchDomains, mDNSNULL, mDNSNULL, mDNSNULL); + mDNS_Unlock(m); + + // delete elems marked for removal, do queries for elems marked add + while (*p) + { + ptr = *p; + debugf("RegisterSearchDomains %d %p %##s", ptr->flag, ptr->AuthRecs, ptr->domain.c); + if (ptr->flag == -1) // remove + { + ARListElem *arList = ptr->AuthRecs; + ptr->AuthRecs = mDNSNULL; + *p = ptr->next; + + mDNS_StopGetDomains(m, &ptr->BrowseQ); + mDNS_StopGetDomains(m, &ptr->RegisterQ); + mDNS_StopGetDomains(m, &ptr->DefBrowseQ); + mDNS_StopGetDomains(m, &ptr->DefRegisterQ); + mDNS_StopGetDomains(m, &ptr->AutomaticBrowseQ); + mDNSPlatformMemFree(ptr); + + // deregister records generated from answers to the query + while (arList) + { + ARListElem *dereg = arList; + arList = arList->next; + debugf("Deregistering PTR %##s -> %##s", dereg->ar.resrec.name->c, dereg->ar.resrec.rdata->u.name.c); + err = mDNS_Deregister(m, &dereg->ar); + if (err) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err); + // Memory will be freed in the FreeARElemCallback + } + continue; + } + + if (ptr->flag == 1) // add + { + mStatus err1, err2, err3, err4, err5; + err1 = mDNS_GetDomains(m, &ptr->BrowseQ, mDNS_DomainTypeBrowse, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr); + err2 = mDNS_GetDomains(m, &ptr->DefBrowseQ, mDNS_DomainTypeBrowseDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr); + err3 = mDNS_GetDomains(m, &ptr->RegisterQ, mDNS_DomainTypeRegistration, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr); + err4 = mDNS_GetDomains(m, &ptr->DefRegisterQ, mDNS_DomainTypeRegistrationDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr); + err5 = mDNS_GetDomains(m, &ptr->AutomaticBrowseQ, mDNS_DomainTypeBrowseAutomatic, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr); + if (err1 || err2 || err3 || err4 || err5) + LogMsg("GetDomains for domain %##s returned error(s):\n" + "%d (mDNS_DomainTypeBrowse)\n" + "%d (mDNS_DomainTypeBrowseDefault)\n" + "%d (mDNS_DomainTypeRegistration)\n" + "%d (mDNS_DomainTypeRegistrationDefault)" + "%d (mDNS_DomainTypeBrowseAutomatic)\n", + ptr->domain.c, err1, err2, err3, err4, err5); + ptr->flag = 0; + } + + if (ptr->flag) { LogMsg("RegisterSearchDomains - unknown flag %d. Skipping.", ptr->flag); } + + p = &ptr->next; + } + + return mStatus_NoError; } +// Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows: +// 1) query for b._dns-sd._udp.local on LocalOnly interface +// (.local manually generated via explicit callback) +// 2) for each search domain (from prefs pane), query for b._dns-sd._udp.. +// 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> +// 4) result above should generate a callback from question in (1). result added to global list +// 5) global list delivered to client via GetSearchDomainList() +// 6) client calls to enumerate domains now go over LocalOnly interface +// (!!!KRS may add outgoing interface in addition) + mDNSexport void uDNS_Sleep(mDNS *const m) { SuspendLLQs(m, mDNStrue); @@ -5170,3 +5044,12 @@ mDNSexport void uDNS_Wake(mDNS *const m) WakeServiceRegistrations(m); WakeRecordRegistrations(m); } + +struct CompileTimeAssertionChecks_uDNS + { + // 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. + char sizecheck_tcpInfo_t [(sizeof(tcpInfo_t) <= 9100) ? 1 : -1]; + char sizecheck_SearchListElem[(sizeof(SearchListElem) <= 3800) ? 1 : -1]; + }; diff --git a/mDNSCore/uDNS.h b/mDNSCore/uDNS.h index 76943f7..bf7918d 100755 --- a/mDNSCore/uDNS.h +++ b/mDNSCore/uDNS.h @@ -1,132 +1,177 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: uDNS.h,v $ -Revision 1.32 2005/07/29 19:46:10 ksekar - reduce polling period on failed LLQs to 15 minutes +Revision 1.79 2007/09/20 01:13:19 cheshire +Export CacheGroupForName so it's callable from other files + +Revision 1.78 2007/09/14 21:26:09 cheshire + BTMM: Need to manually avoid port conflicts when using UPnP gateways + +Revision 1.77 2007/09/12 23:03:08 cheshire + DNSServiceNATPortMappingCreate callback not giving correct interface index + +Revision 1.76 2007/09/12 19:22:19 cheshire +Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport +Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers + +Revision 1.75 2007/08/28 23:53:21 cheshire +Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete + +Revision 1.74 2007/08/24 00:15:20 cheshire +Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held + +Revision 1.73 2007/08/01 03:09:22 cheshire + BTMM: Create NAT port mapping for autotunnel port + +Revision 1.72 2007/08/01 00:04:13 cheshire + Crash in tcpKQSocketCallback +Half-open TCP connections were not being cancelled properly + +Revision 1.71 2007/07/30 23:31:26 cheshire +Code for respecting TTL received in uDNS responses should exclude LLQ-type responses + +Revision 1.70 2007/07/27 20:52:29 cheshire +Made uDNS_recvLLQResponse() return tri-state result: LLQ_Not, LLQ_First, or LLQ_Events + +Revision 1.69 2007/07/27 19:30:40 cheshire +Changed mDNSQuestionCallback parameter from mDNSBool to QC_result, +to properly reflect tri-state nature of the possible responses + +Revision 1.68 2007/07/27 18:38:56 cheshire +Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion" + +Revision 1.67 2007/07/20 23:11:12 cheshire +Fix code layout -Revision 1.31 2005/03/31 02:19:56 cheshire - Fix build warnings -Reviewed by: Scott Herscher +Revision 1.66 2007/07/16 23:54:48 cheshire + Crash when removing or changing DNS keys -Revision 1.30 2005/03/04 03:00:03 ksekar - Retransmissions happen too early, causing registrations to conflict with themselves +Revision 1.65 2007/07/16 20:14:22 vazquez + LegacyNATTraversal: Need complete rewrite -Revision 1.29 2005/01/11 22:50:53 ksekar -Fixed constant naming (was using kLLQ_DefLease for update leases) +Revision 1.64 2007/07/11 02:53:36 cheshire + Register IPv6-only hostname and don't create port mappings for AutoTunnel services +Add ServiceRecordSet parameter in GetServiceTarget -Revision 1.28 2004/12/22 00:13:49 ksekar - Change version, port, and polling interval for LLQ +Revision 1.63 2007/06/29 00:09:24 vazquez + Clean up NAT state machine (necessary for 6 other fixes) -Revision 1.27 2004/11/23 04:06:50 cheshire -Get rid of floating point constant -- in a small embedded device, bringing in all -the floating point libraries just to halve an integer value is a bit too heavyweight. +Revision 1.62 2007/05/14 23:53:00 cheshire +Export mDNS_StartQuery_internal and mDNS_StopQuery_internal so they can be called from uDNS.c -Revision 1.26 2004/11/22 17:49:15 ksekar -Changed INIT_REFRESH from fraction to decimal +Revision 1.61 2007/05/07 20:43:45 cheshire + Reduce the number of queries and announcements -Revision 1.25 2004/11/22 17:16:20 ksekar - Unicast services don't disappear when you disable all networking +Revision 1.60 2007/05/04 21:46:10 cheshire +Get rid of uDNS_Close (synonym for uDNS_Sleep) -Revision 1.24 2004/11/19 04:24:08 ksekar - Security: Enforce a "window" on one-shot wide-area queries +Revision 1.59 2007/05/03 22:40:38 cheshire + mDNSResponder ignores bogus null target in SRV record -Revision 1.23 2004/11/18 18:04:21 ksekar -Add INIT_REFRESH constant +Revision 1.58 2007/05/02 22:21:33 cheshire + RegisterRecord and RegisterService need to cancel StartGetZoneData -Revision 1.22 2004/11/15 20:09:24 ksekar - Wide Area support for Add/Remove record +Revision 1.57 2007/04/27 19:28:02 cheshire +Any code that calls StartGetZoneData needs to keep a handle to the structure, so +it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop +-- it would start a query and then quickly cancel it, and then when +StartGetZoneData completed, it had a dangling pointer and crashed.) -Revision 1.21 2004/11/11 20:14:55 ksekar - Wide-Area registrations not deregistered on sleep +Revision 1.56 2007/04/25 02:14:38 cheshire + uDNS: Identical client queries should reference a single shared core query +Additional fixes to make LLQs work properly -Revision 1.20 2004/10/16 00:16:59 cheshire - Replace IP TTL 255 check with local subnet source address check +Revision 1.55 2007/04/22 06:02:03 cheshire + Query should immediately return failure when no server -Revision 1.19 2004/09/17 01:08:49 cheshire -Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h - The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces - declared in that file are ONLY appropriate to single-address-space embedded applications. - For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used. +Revision 1.54 2007/04/04 21:48:53 cheshire + Combine unicast authoritative answer list with multicast list -Revision 1.18 2004/09/03 19:23:05 ksekar -: Need retransmission mechanism for wide-area service registrations +Revision 1.53 2007/03/28 15:56:37 cheshire + Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output -Revision 1.17 2004/09/01 03:59:29 ksekar -: Conditionally compile out uDNS code on Windows +Revision 1.52 2007/02/28 01:44:26 cheshire + Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c -Revision 1.16 2004/08/25 00:37:27 ksekar -: Cleanup DynDNS hostname registration code +Revision 1.51 2007/01/27 03:34:27 cheshire +Made GetZoneData use standard queries (and cached results); +eliminated GetZoneData_Callback() packet response handler -Revision 1.15 2004/07/30 17:40:06 ksekar -: TXT Record updates not available for wide-area services +Revision 1.50 2007/01/19 21:17:32 cheshire +StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion -Revision 1.14 2004/07/29 19:27:15 ksekar -NAT-PMP Support - minor fixes and cleanup +Revision 1.49 2007/01/17 21:35:31 cheshire +For clarity, rename zoneData_t field "isPrivate" to "zonePrivate" -Revision 1.13 2004/07/29 02:03:35 ksekar -Delete unused #define and structure field +Revision 1.48 2007/01/10 22:51:57 cheshire + Add support for one-shot private queries as well as long-lived private queries -Revision 1.12 2004/07/26 22:49:30 ksekar -: Feature #9516: Need support for NAT-PMP in client +Revision 1.47 2007/01/05 08:30:43 cheshire +Trim excessive "$Log" checkin history from before 2006 +(checkin history still available via "cvs log ..." of course) -Revision 1.11 2004/06/17 01:13:11 ksekar -: polling interval too short +Revision 1.46 2007/01/04 01:41:47 cheshire +Use _dns-update-tls/_dns-query-tls/_dns-llq-tls instead of creating a new "_tls" subdomain -Revision 1.10 2004/06/11 05:45:03 ksekar -: Change SRV names for LLQ/Update port lookups +Revision 1.45 2006/12/22 20:59:49 cheshire + Read *all* DNS keys from keychain, + not just key for the system-wide default registration domain -Revision 1.9 2004/06/01 23:46:50 ksekar -: DynDNS: dynamically look up LLQ/Update ports +Revision 1.44 2006/12/20 04:07:35 cheshire +Remove uDNS_info substructure from AuthRecord_struct -Revision 1.8 2004/05/28 23:42:37 ksekar -: Feature: DNS server->client notification on record changes (#7805) +Revision 1.43 2006/12/16 01:58:32 cheshire + uDNS: Need to start caching unicast records -Revision 1.7 2004/05/18 23:51:25 cheshire -Tidy up all checkin comments to use consistent "" format for bug numbers +Revision 1.42 2006/11/30 23:07:56 herscher + uDNS: Sync up with Lighthouse changes for Private DNS -Revision 1.6 2004/03/13 01:57:33 ksekar -: DynDNS: Dynamic update of service records +Revision 1.41 2006/11/18 05:01:30 cheshire +Preliminary support for unifying the uDNS and mDNS code, +including caching of uDNS answers -Revision 1.5 2004/02/21 08:56:58 bradley -Wrap prototypes with extern "C" for C++ builds. +Revision 1.40 2006/11/10 07:44:04 herscher + Fix Daemon locking failures while toggling BTMM -Revision 1.4 2004/02/06 23:04:19 ksekar -Basic Dynamic Update support via mDNS_Register (dissabled via -UNICAST_REGISTRATION #define) +Revision 1.39 2006/10/20 05:35:05 herscher + uDNS: Merge unicast active question list with multicast list. -Revision 1.3 2004/01/24 03:38:27 cheshire -Fix minor syntactic error: Headers should use "extern" declarations, not "mDNSexport" +Revision 1.38 2006/09/26 01:54:02 herscher + NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol) -Revision 1.2 2004/01/23 23:23:15 ksekar -Added TCP support for truncated unicast messages. +Revision 1.37 2006/09/15 21:20:15 cheshire +Remove uDNS_info substructure from mDNS_struct -Revision 1.1 2003/12/13 03:05:27 ksekar -: DynDNS: Unicast query of service records +Revision 1.36 2006/08/14 23:24:23 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 +Revision 1.35 2006/07/30 05:45:36 cheshire + Eliminate MIN_UCAST_PERIODIC_EXEC + +Revision 1.34 2006/07/15 02:01:29 cheshire + Add Private DNS client functionality to mDNSResponder +Fix broken "empty string" browsing + +Revision 1.33 2006/07/05 22:53:28 cheshire + Add Private DNS client functionality to mDNSResponder - */ +*/ #ifndef __UDNS_H_ #define __UDNS_H_ @@ -139,27 +184,29 @@ Revision 1.1 2003/12/13 03:05:27 ksekar #endif #define RESTART_GOODBYE_DELAY (6 * mDNSPlatformOneSecond) // delay after restarting LLQ before nuking previous known answers (avoids flutter if we restart before we have networking up) -#define MIN_UCAST_PERIODIC_EXEC (5 * mDNSPlatformOneSecond) #define INIT_UCAST_POLL_INTERVAL (3 * mDNSPlatformOneSecond) // this interval is used after send failures on network transitions // which typically heal quickly, so we start agressively and exponentially back off #define MAX_UCAST_POLL_INTERVAL (60 * 60 * mDNSPlatformOneSecond) +//#define MAX_UCAST_POLL_INTERVAL (1 * 60 * mDNSPlatformOneSecond) #define LLQ_POLL_INTERVAL (15 * 60 * mDNSPlatformOneSecond) // Polling interval for zones w/ an advertised LLQ port (ie not static zones) if LLQ fails due to NAT, etc. #define RESPONSE_WINDOW (60 * mDNSPlatformOneSecond) // require server responses within one minute of request -#define UPDATE_PORT_NAME "_dns-update._udp." -#define LLQ_PORT_NAME "_dns-llq._udp" + #define DEFAULT_UPDATE_LEASE 7200 - + +#define QuestionIntervalStep 3 +#define QuestionIntervalStep2 (QuestionIntervalStep*QuestionIntervalStep) +#define QuestionIntervalStep3 (QuestionIntervalStep*QuestionIntervalStep*QuestionIntervalStep) +#define InitialQuestionInterval ((mDNSPlatformOneSecond + QuestionIntervalStep-1) / QuestionIntervalStep) + // Entry points into unicast-specific routines -extern mStatus uDNS_StartQuery(mDNS *const m, DNSQuestion *const question); -extern mDNSBool uDNS_IsActiveQuery(DNSQuestion *const question, uDNS_GlobalInfo *u); // returns true if OK to call StopQuery -extern mStatus uDNS_StopQuery(mDNS *const m, DNSQuestion *const question); - -extern void uDNS_Init(mDNS *const m); +extern void startLLQHandshakeCallback(mDNS *const m, mStatus err, const ZoneData *zoneInfo); + +extern void uDNS_StopLongLivedQuery(mDNS *const m, DNSQuestion *const question); + extern void uDNS_Sleep(mDNS *const m); extern void uDNS_Wake(mDNS *const m); -#define uDNS_Close uDNS_Sleep - + // uDNS_UpdateRecord // following fields must be set, and the update validated, upon entry. // rr->NewRData @@ -168,24 +215,56 @@ extern void uDNS_Wake(mDNS *const m); extern mStatus uDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra); extern mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr); - -extern mStatus uDNS_RegisterRecord(mDNS *const m, AuthRecord *const rr); + +extern void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q); +extern CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name); +extern mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr); +// mDNS_Dereg_normal is used for most calls to mDNS_Deregister_internal +// mDNS_Dereg_conflict is used to indicate that this record is being forcibly deregistered because of a conflict +// mDNS_Dereg_repeat is used when cleaning up, for records that may have already been forcibly deregistered +typedef enum { mDNS_Dereg_normal, mDNS_Dereg_conflict, mDNS_Dereg_repeat } mDNS_Dereg_type; +extern mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt); +extern mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question); +extern mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question); +extern mStatus mDNS_StartNATOperation_internal(mDNS *const m, NATTraversalInfo *traversal); + +extern void RecordRegistrationCallback(mDNS *const m, mStatus err, const ZoneData *zoneData); +extern void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord); extern mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr); -extern mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs); +extern void ServiceRegistrationZoneDataComplete(mDNS *const m, mStatus err, const ZoneData *result); +extern const domainname *GetServiceTarget(mDNS *m, ServiceRecordSet *srs); extern mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs); +extern void uDNS_CheckCurrentQuestion(mDNS *const m); + // integer fields of msg header must be in HOST byte order before calling this routine extern void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end, - const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *const dstaddr, - const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID); + const mDNSAddr *const srcaddr, const mDNSIPPort srcport); -extern void uDNS_ReceiveNATMap(mDNS *m, mDNSu8 *pkt, mDNSu16 len); - // returns time of next scheduled event extern void uDNS_Execute(mDNS *const m); - +extern mStatus uDNS_SetupDNSConfig(mDNS *const m); +extern mStatus uDNS_RegisterSearchDomains(mDNS *const m); + +typedef enum + { + uDNS_LLQ_Not = 0, // Normal uDNS answer: Flush any stale records from cache, and respect record TTL + uDNS_LLQ_Poll, // LLQ Poll: Flush any stale records from cache, but assume TTL is 2 x poll interval + uDNS_LLQ_Setup, // LLQ Initial answer packet: Flush any stale records from cache; assume TTL is 2 x LLQ refresh interval + uDNS_LLQ_Events // LLQ event packet: don't flush cache; assume TTL is 2 x LLQ refresh interval + } uDNS_LLQType; + +extern uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport); +extern DomainAuthInfo *GetAuthInfoForName_internal(mDNS *m, const domainname *const name); +extern void DisposeTCPConn(struct tcpInfo_t *tcp); + +// NAT traversal +extern void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID InterfaceID, mDNSu8 *pkt, mDNSu16 len); // Called for each received NAT-PMP packet +extern void natTraversalHandleAddressReply(mDNS *const m, mDNSu16 err, mDNSv4Addr ExtAddr); +extern void natTraversalHandlePortMapReply(mDNS *const m, NATTraversalInfo *n, const mDNSInterfaceID InterfaceID, mDNSu16 err, mDNSIPPort extport, mDNSu32 lease); + #ifdef __cplusplus } #endif diff --git a/mDNSMacOS9/CarbonResource.r b/mDNSMacOS9/CarbonResource.r index 105a398..c7a49a0 100644 --- a/mDNSMacOS9/CarbonResource.r +++ b/mDNSMacOS9/CarbonResource.r @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: CarbonResource.r,v $ +Revision 1.6 2006/08/14 23:24:29 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.5 2003/08/12 19:56:24 cheshire Update to APSL 2.0 diff --git a/mDNSMacOS9/Mac OS Test Responder.c b/mDNSMacOS9/Mac OS Test Responder.c index 76a426c..cc14173 100644 --- a/mDNSMacOS9/Mac OS Test Responder.c +++ b/mDNSMacOS9/Mac OS Test Responder.c @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: Mac\040OS\040Test\040Responder.c,v $ +Revision 1.25 2006/08/14 23:24:29 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.24 2004/12/16 20:49:34 cheshire Cache memory management improvements diff --git a/mDNSMacOS9/Mac OS Test Searcher.c b/mDNSMacOS9/Mac OS Test Searcher.c index fd28def..4f282dc 100644 --- a/mDNSMacOS9/Mac OS Test Searcher.c +++ b/mDNSMacOS9/Mac OS Test Searcher.c @@ -1,28 +1,29 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: Mac\040OS\040Test\040Searcher.c,v $ +Revision 1.23 2007/07/27 19:30:40 cheshire +Changed mDNSQuestionCallback parameter from mDNSBool to QC_result, +to properly reflect tri-state nature of the possible responses + +Revision 1.22 2006/08/14 23:24:29 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.21 2004/12/16 20:49:34 cheshire Cache memory management improvements @@ -153,7 +154,7 @@ static void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query) // When a new named instance of a service is found, FoundInstance() is called. // In this sample code we turn around and immediately issue a query to resolve that service name to // find its address, port, and txtinfo, but a normal browing application would just display the name. -static void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) +static void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) { #pragma unused (question) SearcherServices *services = (SearcherServices *)question->QuestionContext; @@ -185,7 +186,7 @@ static void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRe } } -static void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) +static void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) { #pragma unused (m) #pragma unused (question) diff --git a/mDNSMacOS9/Responder.c b/mDNSMacOS9/Responder.c index 2e7135e..7a1993f 100644 --- a/mDNSMacOS9/Responder.c +++ b/mDNSMacOS9/Responder.c @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: Responder.c,v $ +Revision 1.3 2006/08/14 23:24:29 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.2 2004/05/20 18:38:31 cheshire Fix build broken by removal of 'kDNSServiceFlagsAutoRename' from dns_sd.h diff --git a/mDNSMacOS9/Searcher.c b/mDNSMacOS9/Searcher.c index a0a562f..9c49c8a 100644 --- a/mDNSMacOS9/Searcher.c +++ b/mDNSMacOS9/Searcher.c @@ -1,28 +1,28 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: Searcher.c,v $ +Revision 1.4 2006/12/19 22:43:54 cheshire +Fix compiler warnings + +Revision 1.3 2006/08/14 23:24:29 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.2 2004/05/27 06:30:21 cheshire Add code to test DNSServiceQueryRecord() @@ -135,7 +135,7 @@ static void FoundInstanceAddress(DNSServiceRef sdRef, DNSServiceFlags flags, uin static void FoundInstanceInfo(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t notAnIntPort, - uint16_t txtLen, const char *txtRecord, void *context) + uint16_t txtLen, const unsigned char *txtRecord, void *context) { linkedServiceInfo *info = (linkedServiceInfo *)context; SearcherServices *services = info->services; @@ -148,7 +148,7 @@ static void FoundInstanceInfo(DNSServiceRef sdRef, DNSServiceFlags flags, uint32 if (txtLen == 0) info->text[0] = 0; else { - strncpy(info->text, txtRecord+1, txtRecord[0]); + strncpy(info->text, (char *)txtRecord+1, txtRecord[0]); info->text[txtRecord[0]] = 0; } info->notAnIntPort.NotAnInteger = notAnIntPort; diff --git a/mDNSMacOS9/SubTypeTester.c b/mDNSMacOS9/SubTypeTester.c index 2206b22..d0eb613 100644 --- a/mDNSMacOS9/SubTypeTester.c +++ b/mDNSMacOS9/SubTypeTester.c @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: SubTypeTester.c,v $ +Revision 1.7 2006/08/14 23:24:29 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.6 2004/12/16 20:49:35 cheshire Cache memory management improvements diff --git a/mDNSMacOS9/mDNSLibrary.c b/mDNSMacOS9/mDNSLibrary.c index d385cb4..e54ab00 100644 --- a/mDNSMacOS9/mDNSLibrary.c +++ b/mDNSMacOS9/mDNSLibrary.c @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: mDNSLibrary.c,v $ +Revision 1.4 2006/08/14 23:24:29 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.3 2004/12/16 20:49:35 cheshire Cache memory management improvements diff --git a/mDNSMacOS9/mDNSLibraryLoader.c b/mDNSMacOS9/mDNSLibraryLoader.c index d671d77..f829f14 100644 --- a/mDNSMacOS9/mDNSLibraryLoader.c +++ b/mDNSMacOS9/mDNSLibraryLoader.c @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: mDNSLibraryLoader.c,v $ +Revision 1.2 2006/08/14 23:24:29 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.1 2004/03/12 21:30:26 cheshire Build a System-Context Shared Library from mDNSCore, for the benefit of developers like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code. diff --git a/mDNSMacOS9/mDNSLibraryResources.r b/mDNSMacOS9/mDNSLibraryResources.r index 82f764c..d7d0ea9 100644 --- a/mDNSMacOS9/mDNSLibraryResources.r +++ b/mDNSMacOS9/mDNSLibraryResources.r @@ -1,28 +1,85 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: mDNSLibraryResources.r,v $ +Revision 1.54 2007/06/27 21:59:08 cheshire +mDNSResponder-130 + +Revision 1.53 2007/05/29 23:47:57 cheshire +mDNSResponder-129 + +Revision 1.52 2007/05/25 23:45:39 jvidrine +Update version numbers to reflect the submission number. (Thanks, Marc!) + +Revision 1.51 2007/05/25 22:10:19 cheshire +mDNSResponder-127 + +Revision 1.50 2007/05/23 00:57:23 cheshire +mDNSResponder-126 + +Revision 1.49 2007/05/15 00:47:50 cheshire +mDNSResponder-125 + +Revision 1.48 2007/05/14 20:49:54 cheshire +mDNSResponder-124 + +Revision 1.47 2007/05/10 21:43:12 cheshire +mDNSResponder-123 + +Revision 1.46 2007/04/27 19:33:07 cheshire +mDNSResponder-122 + +Revision 1.45 2007/04/08 03:04:00 cheshire +mDNSResponder-121 + +Revision 1.44 2007/03/30 23:30:04 cheshire +mDNSResponder-120 + +Revision 1.43 2007/02/28 22:09:24 cheshire +mDNSResponder-119 + +Revision 1.42 2007/01/09 01:58:20 cheshire +mDNSResponder-116 + +Revision 1.41 2006/11/08 04:29:02 cheshire +mDNSResponder-115 + +Revision 1.40 2006/10/27 01:46:40 cheshire +mDNSResponder-114 + +Revision 1.39 2006/09/30 01:38:53 cheshire +mDNSResponder-113 + +Revision 1.38 2006/09/21 23:38:13 cheshire +mDNSResponder-112 + +Revision 1.37 2006/08/14 23:24:29 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + +Revision 1.36 2006/07/14 00:52:00 cheshire +mDNSResponder-111 + +Revision 1.35 2006/06/20 23:05:10 cheshire +mDNSResponder-110 + +Revision 1.34 2006/02/09 22:24:53 cheshire +mDNSResponder-109 + Revision 1.33 2005/12/12 17:48:36 cheshire mDNSResponder-108 @@ -140,15 +197,15 @@ like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code resource 'vers' (1, purgeable) { - 0x01, 0x00, alpha, 108, verUS, - "1.0a108", - "Multicast DNS & DNS Service Discovery 1.0a108" + 0x01, 0x00, alpha, 130, verUS, + "1.0a130", + "Multicast DNS & DNS Service Discovery 1.0a130" }; resource 'vers' (2, purgeable) { - 0x01, 0x00, alpha, 108, verUS, - "1.0a108", + 0x01, 0x00, alpha, 130, verUS, + "1.0a130", "developer.apple.com/darwin/projects/bonjour/" }; diff --git a/mDNSMacOS9/mDNSMacOS9.c b/mDNSMacOS9/mDNSMacOS9.c index 13cf72e..18c4da9 100644 --- a/mDNSMacOS9/mDNSMacOS9.c +++ b/mDNSMacOS9/mDNSMacOS9.c @@ -1,28 +1,43 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: mDNSMacOS9.c,v $ +Revision 1.51 2007/09/12 19:23:17 cheshire +Get rid of unnecessary mDNSPlatformTCPIsConnected() routine + +Revision 1.50 2007/04/05 20:40:37 cheshire +Remove unused mDNSPlatformTCPGetFlags() + +Revision 1.49 2007/03/22 18:31:48 cheshire +Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy + +Revision 1.48 2007/03/20 17:07:15 cheshire +Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket" + +Revision 1.47 2006/12/19 22:43:54 cheshire +Fix compiler warnings + +Revision 1.46 2006/08/14 23:24:29 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + +Revision 1.45 2006/03/19 02:00:14 cheshire + Improve logic for delaying packets after repeated interface transitions + Revision 1.44 2005/09/16 21:06:50 cheshire Use mDNS_TimeNow_NoLock macro, instead of writing "mDNSPlatformRawTime() + m->timenow_adjust" all over the place @@ -278,7 +293,7 @@ mDNSlocal OSStatus readpacket(mDNS *m) #if OTCARBONAPPLICATION // IP_RCVDSTADDR is known to fail on OS X Carbon, so we'll just assume the packet was probably multicast - destaddr.ip.v4 = AllDNSLinkGroupv4; + destaddr.ip.v4 = AllDNSLinkGroup_v4.ip.v4; #endif if (recvdata.opt.len) @@ -289,7 +304,7 @@ mDNSlocal OSStatus readpacket(mDNS *m) err = OTNextOption(recvdata.opt.buf, recvdata.opt.len, &c); if (err || !c) break; if (c->level == INET_IP && c->name == IP_RCVDSTADDR && c->len - kOTOptionHeaderSize == sizeof(destaddr.ip.v4)) - mDNSPlatformMemCopy(c->value, &destaddr.ip.v4, sizeof(destaddr.ip.v4)); + mDNSPlatformMemCopy(&destaddr.ip.v4, c->value, sizeof(destaddr.ip.v4)); } } @@ -302,39 +317,73 @@ mDNSlocal OSStatus readpacket(mDNS *m) return(err); } -mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID, - TCPConnectionCallback callback, void *context, int *descriptor) +mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS * const m, TCPSocketFlags flags, mDNSIPPort * port) { + (void)m; // Unused + (void)flags; // Unused + (void)port; // Unused + return NULL; + } + +mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int sd) + { + (void)flags; // Unused + (void)sd; // Unused + return NULL; + } + +mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock) + { + (void)sock; // Unused + return -1; + } + +mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr * dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID, + TCPConnectionCallback callback, void * context) + { + (void)sock; // Unused (void)dst; // Unused (void)dstport; // Unused (void)InterfaceID; // Unused (void)callback; // Unused (void)context; // Unused - (void)descriptor; // Unused return(mStatus_UnsupportedErr); } -mDNSexport void mDNSPlatformTCPCloseConnection(int sd) +mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sd) { (void)sd; // Unused } -mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen) +mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed) { - (void)sd; // Unused + (void)sock; // Unused (void)buf; // Unused (void)buflen; // Unused + (void)closed; // Unused return(0); } -mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len) +mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len) { - (void)sd; // Unused + (void)sock; // Unused (void)msg; // Unused (void)len; // Unused return(0); } +mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS * const m, mDNSIPPort port) + { + (void)m; // Unused + (void)port; // Unused + return NULL; + } + +mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock) + { + (void)sock; // Unused + } + mDNSlocal void mDNSOptionManagement(mDNS *const m) { OSStatus err; @@ -406,7 +455,7 @@ mDNSlocal pascal void mDNSNotifier(void *contextPtr, OTEventCode code, OTResult case mOT_Bind: OTBind(m->p->ep, (TBind*)&mDNSbindReq, NULL); break; case mOT_Ready: mDNSinitComplete(m, mStatus_NoError); // Can't do mDNS_RegisterInterface until *after* mDNSinitComplete has set m->mDNSPlatformStatus to mStatus_NoError - mDNS_RegisterInterface(m, &m->p->interface, 0); + mDNS_RegisterInterface(m, &m->p->interface, mDNSfalse); break; default: LogMsg("Unexpected m->p->mOTstate %d", m->p->mOTstate-1); } @@ -423,7 +472,7 @@ mDNSlocal pascal void mDNSNotifier(void *contextPtr, OTEventCode code, OTResult if (m->p->mOTstate == mOT_Ready) { m->p->mOTstate = mOT_Closed; - mDNS_DeregisterInterface(m, &m->p->interface); + mDNS_DeregisterInterface(m, &m->p->interface, mDNSfalse); } if (m->p->ep) { OTCloseProvider(m->p->ep); m->p->ep = NULL; } break; // Do we need to do anything? @@ -645,7 +694,7 @@ extern void mDNSPlatformClose (mDNS *const m) if (m->p->mOTstate == mOT_Ready) { m->p->mOTstate = mOT_Closed; - mDNS_DeregisterInterface(m, &m->p->interface); + mDNS_DeregisterInterface(m, &m->p->interface, mDNSfalse); } if (m->p->ep) { OTCloseProvider (m->p->ep); m->p->ep = NULL; } if (m->p->OTTimerTask) { OTDestroyTimerTask(m->p->OTTimerTask); m->p->OTTimerTask = 0; } @@ -727,11 +776,11 @@ mDNSexport void mDNSPlatformUnlock(const mDNS *const m) else OTLeaveNotifier(m->p->ep); } -mDNSexport void mDNSPlatformStrCopy(const void *src, void *dst) { OTStrCopy((char*)dst, (char*)src); } -mDNSexport UInt32 mDNSPlatformStrLen (const void *src) { return(OTStrLength((char*)src)); } -mDNSexport void mDNSPlatformMemCopy(const void *src, void *dst, UInt32 len) { OTMemcpy(dst, src, len); } -mDNSexport mDNSBool mDNSPlatformMemSame(const void *src, const void *dst, UInt32 len) { return(OTMemcmp(dst, src, len)); } -mDNSexport void mDNSPlatformMemZero( void *dst, UInt32 len) { OTMemzero(dst, len); } +mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { OTStrCopy((char*)dst, (char*)src); } +mDNSexport UInt32 mDNSPlatformStrLen ( const void *src) { return(OTStrLength((char*)src)); } +mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, UInt32 len) { OTMemcpy(dst, src, len); } +mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, UInt32 len) { return(OTMemcmp(dst, src, len)); } +mDNSexport void mDNSPlatformMemZero( void *dst, UInt32 len) { OTMemzero(dst, len); } mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(OTAllocMem(len)); } mDNSexport void mDNSPlatformMemFree(void *mem) { OTFreeMem(mem); } mDNSexport mDNSu32 mDNSPlatformRandomSeed(void) { return(TickCount()); } diff --git a/mDNSMacOS9/mDNSMacOS9.h b/mDNSMacOS9/mDNSMacOS9.h index c4fa310..149ec03 100755 --- a/mDNSMacOS9/mDNSMacOS9.h +++ b/mDNSMacOS9/mDNSMacOS9.h @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: mDNSMacOS9.h,v $ +Revision 1.11 2006/08/14 23:24:29 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.10 2004/03/12 21:30:26 cheshire Build a System-Context Shared Library from mDNSCore, for the benefit of developers like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code. diff --git a/mDNSMacOS9/mDNSPrefix.h b/mDNSMacOS9/mDNSPrefix.h index 80adab4..5cf83fb 100644 --- a/mDNSMacOS9/mDNSPrefix.h +++ b/mDNSMacOS9/mDNSPrefix.h @@ -1,28 +1,25 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: mDNSPrefix.h,v $ +Revision 1.4 2006/08/14 23:24:29 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.3 2004/06/11 00:03:28 cheshire Add code for testing avail/busy subtypes diff --git a/mDNSMacOSX/DNSServiceDiscovery.c b/mDNSMacOSX/DNSServiceDiscovery.c new file mode 100644 index 0000000..1f701f5 --- /dev/null +++ b/mDNSMacOSX/DNSServiceDiscovery.c @@ -0,0 +1,674 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Suppress "warning: 'DNSServiceDiscoveryMachPort' is deprecated" messages -- we already know this code is building the deprecated API +// Since we compile with all warnings treated as errors, we have to turn off the warnings here or the project won't compile +#include +#undef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED +#define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED +#undef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3 +#define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3 + +#include "DNSServiceDiscovery.h" +#include "DNSServiceDiscoveryDefines.h" +#include "DNSServiceDiscoveryReplyServer.h" + +#include +#include +#include +#include +#include +#include + +#include + +extern boolean_t DNSServiceDiscoveryReply_server( + mach_msg_header_t *InHeadP, + mach_msg_header_t *OutHeadP); + +extern +kern_return_t DNSServiceBrowserCreate_rpc +( + mach_port_t server, + mach_port_t client, + DNSCString regtype, + DNSCString domain +); + +extern +kern_return_t DNSServiceDomainEnumerationCreate_rpc +( + mach_port_t server, + mach_port_t client, + int registrationDomains +); + +extern +kern_return_t DNSServiceRegistrationCreate_rpc +( + mach_port_t server, + mach_port_t client, + DNSCString name, + DNSCString regtype, + DNSCString domain, + IPPort port, + DNSCString txtRecord +); + +extern +kern_return_t DNSServiceResolverResolve_rpc +( + mach_port_t server, + mach_port_t client, + DNSCString name, + DNSCString regtype, + DNSCString domain +); + +extern +kern_return_t DNSServiceRegistrationAddRecord_rpc +( + mach_port_t server, + mach_port_t client, + int type, + record_data_t data, + mach_msg_type_number_t record_dataCnt, + uint32_t ttl, + natural_t *reference +); + +extern +int DNSServiceRegistrationUpdateRecord_rpc +( + mach_port_t server, + mach_port_t client, + natural_t reference, + record_data_t data, + mach_msg_type_number_t record_dataCnt, + uint32_t ttl +); + +extern +kern_return_t DNSServiceRegistrationRemoveRecord_rpc +( + mach_port_t server, + mach_port_t client, + natural_t reference +); + +struct a_requests { + struct a_requests *next; + mach_port_t client_port; + union { + DNSServiceBrowserReply browserCallback; + DNSServiceDomainEnumerationReply enumCallback; + DNSServiceRegistrationReply regCallback; + DNSServiceResolverReply resolveCallback; + } callout; + void *context; +}; + +static struct a_requests *a_requests = NULL; +static pthread_mutex_t a_requests_lock = PTHREAD_MUTEX_INITIALIZER; + +typedef struct _dns_service_discovery_t { + mach_port_t port; +} dns_service_discovery_t; + +static mach_port_t DNSServiceDiscoveryLookupServer(void) +{ + static mach_port_t sndPort = MACH_PORT_NULL; + kern_return_t result; + + if (sndPort != MACH_PORT_NULL) { + return sndPort; + } + + result = bootstrap_look_up(bootstrap_port, DNS_SERVICE_DISCOVERY_SERVER, &sndPort); + if (result != KERN_SUCCESS) { + printf("%s(): {%s:%d} bootstrap_look_up() failed: $%x\n", __FUNCTION__, __FILE__, __LINE__, (int) result); + sndPort = MACH_PORT_NULL; + } + + + return sndPort; +} + +static void _increaseQueueLengthOnPort(mach_port_t port) +{ + mach_port_limits_t qlimits; + kern_return_t result; + + qlimits.mpl_qlimit = 16; + result = mach_port_set_attributes(mach_task_self(), port, MACH_PORT_LIMITS_INFO, (mach_port_info_t)&qlimits, MACH_PORT_LIMITS_INFO_COUNT); + + if (result != KERN_SUCCESS) { + printf("%s(): {%s:%d} mach_port_set_attributes() failed: $%x %s\n", __FUNCTION__, __FILE__, __LINE__, (int) result, mach_error_string(result)); + } +} + +dns_service_discovery_ref DNSServiceBrowserCreate (const char *regtype, const char *domain, DNSServiceBrowserReply callBack,void *context) +{ + mach_port_t serverPort = DNSServiceDiscoveryLookupServer(); + mach_port_t clientPort; + kern_return_t result; + dns_service_discovery_ref return_t; + struct a_requests *request; + + if (!serverPort) { + return NULL; + } + + result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort); + if (result != KERN_SUCCESS) { + printf("Mach port receive creation failed, %s\n", mach_error_string(result)); + return NULL; + } + result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND); + if (result != KERN_SUCCESS) { + printf("Mach port send creation failed, %s\n", mach_error_string(result)); + mach_port_destroy(mach_task_self(), clientPort); + return NULL; + } + _increaseQueueLengthOnPort(clientPort); + + return_t = malloc(sizeof(dns_service_discovery_t)); + return_t->port = clientPort; + + request = malloc(sizeof(struct a_requests)); + request->client_port = clientPort; + request->context = context; + request->callout.browserCallback = callBack; + + result = DNSServiceBrowserCreate_rpc(serverPort, clientPort, (char *)regtype, (char *)domain); + + if (result != KERN_SUCCESS) { + printf("There was an error creating a browser, %s\n", mach_error_string(result)); + free(request); + return NULL; + } + + pthread_mutex_lock(&a_requests_lock); + request->next = a_requests; + a_requests = request; + pthread_mutex_unlock(&a_requests_lock); + + return return_t; +} + +/* Service Enumeration */ + +dns_service_discovery_ref DNSServiceDomainEnumerationCreate (int registrationDomains, DNSServiceDomainEnumerationReply callBack, void *context) +{ + mach_port_t serverPort = DNSServiceDiscoveryLookupServer(); + mach_port_t clientPort; + kern_return_t result; + dns_service_discovery_ref return_t; + struct a_requests *request; + + if (!serverPort) { + return NULL; + } + + result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort); + if (result != KERN_SUCCESS) { + printf("Mach port receive creation failed, %s\n", mach_error_string(result)); + return NULL; + } + result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND); + if (result != KERN_SUCCESS) { + printf("Mach port send creation failed, %s\n", mach_error_string(result)); + mach_port_destroy(mach_task_self(), clientPort); + return NULL; + } + _increaseQueueLengthOnPort(clientPort); + + return_t = malloc(sizeof(dns_service_discovery_t)); + return_t->port = clientPort; + + request = malloc(sizeof(struct a_requests)); + request->client_port = clientPort; + request->context = context; + request->callout.enumCallback = callBack; + + result = DNSServiceDomainEnumerationCreate_rpc(serverPort, clientPort, registrationDomains); + + if (result != KERN_SUCCESS) { + printf("There was an error creating an enumerator, %s\n", mach_error_string(result)); + free(request); + return NULL; + } + + pthread_mutex_lock(&a_requests_lock); + request->next = a_requests; + a_requests = request; + pthread_mutex_unlock(&a_requests_lock); + + return return_t; +} + + +/* Service Registration */ + +dns_service_discovery_ref DNSServiceRegistrationCreate +(const char *name, const char *regtype, const char *domain, uint16_t port, const char *txtRecord, DNSServiceRegistrationReply callBack, void *context) +{ + mach_port_t serverPort = DNSServiceDiscoveryLookupServer(); + mach_port_t clientPort; + kern_return_t result; + dns_service_discovery_ref return_t; + struct a_requests *request; + IPPort IpPort; + char *portptr = (char *)&port; + + if (!serverPort) { + return NULL; + } + + if (!txtRecord) { + txtRecord = ""; + } + + result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort); + if (result != KERN_SUCCESS) { + printf("Mach port receive creation failed, %s\n", mach_error_string(result)); + return NULL; + } + result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND); + if (result != KERN_SUCCESS) { + printf("Mach port send creation failed, %s\n", mach_error_string(result)); + mach_port_destroy(mach_task_self(), clientPort); + return NULL; + } + _increaseQueueLengthOnPort(clientPort); + + return_t = malloc(sizeof(dns_service_discovery_t)); + return_t->port = clientPort; + + request = malloc(sizeof(struct a_requests)); + request->client_port = clientPort; + request->context = context; + request->callout.regCallback = callBack; + + // older versions of this code passed the port via mach IPC as an int. + // we continue to pass it as 4 bytes to maintain binary compatibility, + // but now ensure that the network byte order is preserved by using a struct + IpPort.bytes[0] = 0; + IpPort.bytes[1] = 0; + IpPort.bytes[2] = portptr[0]; + IpPort.bytes[3] = portptr[1]; + + result = DNSServiceRegistrationCreate_rpc(serverPort, clientPort, (char *)name, (char *)regtype, (char *)domain, IpPort, (char *)txtRecord); + + if (result != KERN_SUCCESS) { + printf("There was an error creating a resolve, %s\n", mach_error_string(result)); + free(request); + return NULL; + } + + pthread_mutex_lock(&a_requests_lock); + request->next = a_requests; + a_requests = request; + pthread_mutex_unlock(&a_requests_lock); + + return return_t; +} + +/* Resolver requests */ + +dns_service_discovery_ref DNSServiceResolverResolve(const char *name, const char *regtype, const char *domain, DNSServiceResolverReply callBack, void *context) +{ + mach_port_t serverPort = DNSServiceDiscoveryLookupServer(); + mach_port_t clientPort; + kern_return_t result; + dns_service_discovery_ref return_t; + struct a_requests *request; + + if (!serverPort) { + return NULL; + } + + result = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort); + if (result != KERN_SUCCESS) { + printf("Mach port receive creation failed, %s\n", mach_error_string(result)); + return NULL; + } + result = mach_port_insert_right(mach_task_self(), clientPort, clientPort, MACH_MSG_TYPE_MAKE_SEND); + if (result != KERN_SUCCESS) { + printf("Mach port send creation failed, %s\n", mach_error_string(result)); + mach_port_destroy(mach_task_self(), clientPort); + return NULL; + } + _increaseQueueLengthOnPort(clientPort); + + return_t = malloc(sizeof(dns_service_discovery_t)); + return_t->port = clientPort; + + request = malloc(sizeof(struct a_requests)); + request->client_port = clientPort; + request->context = context; + request->callout.resolveCallback = callBack; + + DNSServiceResolverResolve_rpc(serverPort, clientPort, (char *)name, (char *)regtype, (char *)domain); + + pthread_mutex_lock(&a_requests_lock); + request->next = a_requests; + a_requests = request; + pthread_mutex_unlock(&a_requests_lock); + + return return_t; +} + +DNSRecordReference DNSServiceRegistrationAddRecord(dns_service_discovery_ref ref, uint16_t rrtype, uint16_t rdlen, const char *rdata, uint32_t ttl) +{ + mach_port_t serverPort = DNSServiceDiscoveryLookupServer(); + mach_port_t clientPort; + natural_t reference = 0; + kern_return_t result = KERN_SUCCESS; + + if (!serverPort) { + return kDNSServiceDiscoveryUnknownErr; + } + + clientPort = DNSServiceDiscoveryMachPort(ref); + + if (!clientPort) { + return kDNSServiceDiscoveryUnknownErr; + } + + result = DNSServiceRegistrationAddRecord_rpc(serverPort, clientPort, rrtype, (record_data_t)rdata, rdlen, ttl, &reference); + + if (result != KERN_SUCCESS) { + printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result)); + } + + return reference; +} + +DNSServiceRegistrationReplyErrorType DNSServiceRegistrationUpdateRecord(dns_service_discovery_ref ref, DNSRecordReference reference, uint16_t rdlen, const char *rdata, uint32_t ttl) +{ + mach_port_t serverPort = DNSServiceDiscoveryLookupServer(); + mach_port_t clientPort; + kern_return_t result = KERN_SUCCESS; + + if (!serverPort) { + return kDNSServiceDiscoveryUnknownErr; + } + + clientPort = DNSServiceDiscoveryMachPort(ref); + + if (!clientPort) { + return kDNSServiceDiscoveryUnknownErr; + } + + result = DNSServiceRegistrationUpdateRecord_rpc(serverPort, clientPort, (natural_t)reference, (record_data_t)rdata, rdlen, ttl); + if (result != KERN_SUCCESS) { + printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result)); + return result; + } + + return kDNSServiceDiscoveryNoError; +} + + +DNSServiceRegistrationReplyErrorType DNSServiceRegistrationRemoveRecord(dns_service_discovery_ref ref, DNSRecordReference reference) +{ + mach_port_t serverPort = DNSServiceDiscoveryLookupServer(); + mach_port_t clientPort; + kern_return_t result = KERN_SUCCESS; + + if (!serverPort) { + return kDNSServiceDiscoveryUnknownErr; + } + + clientPort = DNSServiceDiscoveryMachPort(ref); + + if (!clientPort) { + return kDNSServiceDiscoveryUnknownErr; + } + + result = DNSServiceRegistrationRemoveRecord_rpc(serverPort, clientPort, (natural_t)reference); + + if (result != KERN_SUCCESS) { + printf("The result of the registration was not successful. Error %d, result %s\n", result, mach_error_string(result)); + return result; + } + + return kDNSServiceDiscoveryNoError; +} + +void DNSServiceDiscovery_handleReply(void *replyMsg) +{ + unsigned long result = 0xFFFFFFFF; + mach_msg_header_t * msgSendBufPtr; + mach_msg_header_t * receivedMessage; + unsigned msgSendBufLength; + + msgSendBufLength = internal_DNSServiceDiscoveryReply_subsystem.maxsize; + msgSendBufPtr = (mach_msg_header_t *) malloc(msgSendBufLength); + + + receivedMessage = ( mach_msg_header_t * ) replyMsg; + + // Call DNSServiceDiscoveryReply_server to change mig-generated message into a + // genuine mach message. It will then cause the callback to get called. + result = DNSServiceDiscoveryReply_server ( receivedMessage, msgSendBufPtr ); + ( void ) mach_msg_send ( msgSendBufPtr ); + free(msgSendBufPtr); +} + +mach_port_t DNSServiceDiscoveryMachPort(dns_service_discovery_ref dnsServiceDiscovery) +{ + return dnsServiceDiscovery->port; +} + +void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery) +{ + struct a_requests *request0, *request; + mach_port_t reply = dnsServiceDiscovery->port; + + if (dnsServiceDiscovery->port) { + pthread_mutex_lock(&a_requests_lock); + request0 = NULL; + request = a_requests; + while (request) { + if (request->client_port == reply) { + /* request info found, remove from list */ + if (request0) { + request0->next = request->next; + } else { + a_requests = request->next; + } + break; + } else { + /* not info for this request, skip to next */ + request0 = request; + request = request->next; + } + + } + pthread_mutex_unlock(&a_requests_lock); + + free(request); + + mach_port_destroy(mach_task_self(), dnsServiceDiscovery->port); + + free(dnsServiceDiscovery); + } + return; +} + +// reply functions, calls the users setup callbacks with function pointers + +kern_return_t internal_DNSServiceDomainEnumerationReply_rpc +( + mach_port_t reply, + int resultType, + DNSCString replyDomain, + int flags +) +{ + struct a_requests *request; + void *requestContext = NULL; + DNSServiceDomainEnumerationReply callback = NULL; + + pthread_mutex_lock(&a_requests_lock); + request = a_requests; + while (request) { + if (request->client_port == reply) { + break; + } + request = request->next; + } + + if (request != NULL) { + callback = (*request->callout.enumCallback); + requestContext = request->context; + } + pthread_mutex_unlock(&a_requests_lock); + + if (request != NULL) { + (callback)(resultType, replyDomain, flags, requestContext); + } + + return KERN_SUCCESS; + +} + +kern_return_t internal_DNSServiceBrowserReply_rpc +( + mach_port_t reply, + int resultType, + DNSCString replyName, + DNSCString replyType, + DNSCString replyDomain, + int flags +) +{ + struct a_requests *request; + void *requestContext = NULL; + DNSServiceBrowserReply callback = NULL; + + pthread_mutex_lock(&a_requests_lock); + request = a_requests; + while (request) { + if (request->client_port == reply) { + break; + } + request = request->next; + } + if (request != NULL) { + callback = (*request->callout.browserCallback); + requestContext = request->context; + } + + pthread_mutex_unlock(&a_requests_lock); + + if (request != NULL) { + (callback)(resultType, replyName, replyType, replyDomain, flags, requestContext); + } + + return KERN_SUCCESS; +} + + +kern_return_t internal_DNSServiceRegistrationReply_rpc +( + mach_port_t reply, + int resultType +) +{ + struct a_requests *request; + void *requestContext = NULL; + DNSServiceRegistrationReply callback = NULL; + + pthread_mutex_lock(&a_requests_lock); + request = a_requests; + while (request) { + if (request->client_port == reply) { + break; + } + request = request->next; + } + if (request != NULL) { + callback = (*request->callout.regCallback); + requestContext = request->context; + } + + pthread_mutex_unlock(&a_requests_lock); + if (request != NULL) { + (callback)(resultType, requestContext); + } + return KERN_SUCCESS; +} + + +kern_return_t internal_DNSServiceResolverReply_rpc +( + mach_port_t reply, + sockaddr_t interface, + sockaddr_t address, + DNSCString txtRecord, + int flags +) +{ + struct sockaddr *interface_storage = NULL; + struct sockaddr *address_storage = NULL; + struct a_requests *request; + void *requestContext = NULL; + DNSServiceResolverReply callback = NULL; + + if (interface) { + int len = ((struct sockaddr *)interface)->sa_len; + interface_storage = (struct sockaddr *)malloc(len); + bcopy(interface, interface_storage,len); + } + + if (address) { + int len = ((struct sockaddr *)address)->sa_len; + address_storage = (struct sockaddr *)malloc(len); + bcopy(address, address_storage, len); + } + + pthread_mutex_lock(&a_requests_lock); + request = a_requests; + while (request) { + if (request->client_port == reply) { + break; + } + request = request->next; + } + + if (request != NULL) { + callback = (*request->callout.resolveCallback); + requestContext = request->context; + } + pthread_mutex_unlock(&a_requests_lock); + + if (request != NULL) { + (callback)(interface_storage, address_storage, txtRecord, flags, requestContext); + } + + if (interface) { + free(interface_storage); + } + if (address) { + free(address_storage); + } + + return KERN_SUCCESS; +} diff --git a/mDNSWindows/DNSServices/DNSServiceDiscovery.h b/mDNSMacOSX/DNSServiceDiscovery.h similarity index 57% rename from mDNSWindows/DNSServices/DNSServiceDiscovery.h rename to mDNSMacOSX/DNSServiceDiscovery.h index 084b0b8..202d158 100644 --- a/mDNSWindows/DNSServices/DNSServiceDiscovery.h +++ b/mDNSMacOSX/DNSServiceDiscovery.h @@ -1,146 +1,111 @@ -/* - * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. +/* -*- Mode: C; tab-width: 4 -*- * - * @APPLE_LICENSE_HEADER_START@ + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ - - Change History (most recent first): - -$Log: DNSServiceDiscovery.h,v $ -Revision 1.4 2004/05/06 18:42:58 ksekar -General dns_sd.h API cleanup, including the following radars: -: Remove flags with zero value -: Passing in NULL causes a crash. - -Revision 1.3 2004/01/30 02:56:34 bradley -Updated to support full Unicode display. Added support for all services on www.dns-sd.org. - -Revision 1.2 2003/08/20 07:06:34 bradley -Update to APSL 2.0. Updated change history to match other mDNSResponder files. - -Revision 1.1 2003/08/20 06:04:45 bradley -Platform-neutral DNSServices-based emulation layer for the Mac OS X DNSServiceDiscovery API. - -*/ - -//--------------------------------------------------------------------------------------------------------------------------- -/*! @header DNSServiceDiscovery - - @abstract DNSServiceDiscovery emulation using DNSServices. -*/ - -#ifndef __DNS_SERVICE_DISCOVERY__ -#define __DNS_SERVICE_DISCOVERY__ - -#include - -#if( __MACH__ ) - - #include - - #include - #include - #include - - #include - -#elif( defined( __MWERKS__ ) ) + */ - #include - -#elif( defined( _MSC_VER ) ) +/*! @header DNS Service Discovery (Deprecated Mach-based API) + * + * @discussion This section describes the functions, callbacks, and data structures that + * make up the DNS Service Discovery API. + * + * The DNS Service Discovery API is part of Bonjour, Apple's implementation of + * zero-configuration networking (ZEROCONF). + * + * Bonjour allows you to register a network service, such as a + * printer or file server, so that it can be found by name or browsed + * for by service type and domain. Using Bonjour, applications can + * discover what services are available on the network, along with + * all necessary access information-such as name, IP address, and port + * number-for a given service. + * + * In effect, Bonjour combines the functions of a local DNS server + * and AppleTalk. Bonjour allows applications to provide user-friendly printer + * and server browsing, among other things, over standard IP networks. + * This behavior is a result of combining protocols such as multicast and DNS + * to add new functionality to the network (such as multicast DNS). + * + * Bonjour gives applications easy access to services over local IP + * networks without requiring the service or the application to support + * an AppleTalk or a Netbeui stack, and without requiring a DNS server + * for the local network. + * + * Note that this API was deprecated in Mac OS X 10.3, and replaced + * by the portable cross-platform /usr/include/dns_sd.h API. + */ - typedef signed char int8_t; // C99 stdint.h not supported in VC++/VS.NET yet. - typedef unsigned char uint8_t; // C99 stdint.h not supported in VC++/VS.NET yet. - typedef signed short int16_t; // C99 stdint.h not supported in VC++/VS.NET yet. - typedef unsigned short uint16_t; // C99 stdint.h not supported in VC++/VS.NET yet. - typedef signed long int32_t; // C99 stdint.h not supported in VC++/VS.NET yet. - typedef unsigned long uint32_t; // C99 stdint.h not supported in VC++/VS.NET yet. - -#endif +#ifndef __DNS_SERVICE_DISCOVERY_H +#define __DNS_SERVICE_DISCOVERY_H -#ifdef __cplusplus - extern "C" { -#endif +#include -// Note: The following is mostly copied from DNSServiceDiscovery.h. +#include +#include +#include -// Compatibility types. +#include -#if( !__MACH__ ) - typedef int mach_port_t; -#endif +#include -//--------------------------------------------------------------------------------------------------------------------------- -/*! @typedef dns_service_discovery_ref +__BEGIN_DECLS - @abstract Reference to a DNS Service Discovery object. -*/ +/* Opaque internal data type */ +typedef struct _dns_service_discovery_t * dns_service_discovery_ref; -typedef struct _dns_service_discovery_t * dns_service_discovery_ref; +/* possible reply flags values */ -//--------------------------------------------------------------------------------------------------------------------------- -/*! @enum DNSServiceRegistrationReplyErrorType +enum { + kDNSServiceDiscoveryNoFlags = 0, + kDNSServiceDiscoveryMoreRepliesImmediately = 1 << 0, +}; - @abstract Error codes. -*/ +/* possible error code values */ typedef enum { - kDNSServiceDiscoveryWaiting = 1, - kDNSServiceDiscoveryNoError = 0, - - // mDNS Error codes are in the range - // FFFE FF00 (-65792) to FFFE FFFF (-65537) - - kDNSServiceDiscoveryUnknownErr = -65537, // 0xFFFE FFFF - kDNSServiceDiscoveryNoSuchNameErr = -65538, - kDNSServiceDiscoveryNoMemoryErr = -65539, - kDNSServiceDiscoveryBadParamErr = -65540, - kDNSServiceDiscoveryBadReferenceErr = -65541, - kDNSServiceDiscoveryBadStateErr = -65542, - kDNSServiceDiscoveryBadFlagsErr = -65543, - kDNSServiceDiscoveryUnsupportedErr = -65544, - kDNSServiceDiscoveryNotInitializedErr = -65545, - kDNSServiceDiscoveryNoCache = -65546, - kDNSServiceDiscoveryAlreadyRegistered = -65547, - kDNSServiceDiscoveryNameConflict = -65548, - kDNSServiceDiscoveryInvalid = -65549, - kDNSServiceDiscoveryMemFree = -65792 // 0xFFFE FF00 - -} DNSServiceRegistrationReplyErrorType; + kDNSServiceDiscoveryWaiting = 1, + kDNSServiceDiscoveryNoError = 0, + // mDNS Error codes are in the range + // FFFE FF00 (-65792) to FFFE FFFF (-65537) + kDNSServiceDiscoveryUnknownErr = -65537, // 0xFFFE FFFF + kDNSServiceDiscoveryNoSuchNameErr = -65538, + kDNSServiceDiscoveryNoMemoryErr = -65539, + kDNSServiceDiscoveryBadParamErr = -65540, + kDNSServiceDiscoveryBadReferenceErr = -65541, + kDNSServiceDiscoveryBadStateErr = -65542, + kDNSServiceDiscoveryBadFlagsErr = -65543, + kDNSServiceDiscoveryUnsupportedErr = -65544, + kDNSServiceDiscoveryNotInitializedErr = -65545, + kDNSServiceDiscoveryNoCache = -65546, + kDNSServiceDiscoveryAlreadyRegistered = -65547, + kDNSServiceDiscoveryNameConflict = -65548, + kDNSServiceDiscoveryInvalid = -65549, + kDNSServiceDiscoveryMemFree = -65792 // 0xFFFE FF00 +} DNSServiceRegistrationReplyErrorType; typedef uint32_t DNSRecordReference; -//--------------------------------------------------------------------------------------------------------------------------- -/*! - @function DNSServiceResolver_handleReply - - @param replyMsg The Mach message. - - @description - - This function should be called with the Mach message sent to the port returned by the call to DNSServiceResolverResolve. - The reply message will be interpreted and will result in a call to the specified callout function. -*/ -void DNSServiceDiscovery_handleReply( void *replyMsg ); +/*! +@function DNSServiceResolver_handleReply + @discussion This function should be called with the Mach message sent + to the port returned by the call to DNSServiceResolverResolve. + The reply message will be interpreted and will result in a + call to the specified callout function. + @param replyMsg The Mach message. + */ +void DNSServiceDiscovery_handleReply(void *replyMsg); /* Service Registration */ @@ -151,7 +116,7 @@ typedef void (*DNSServiceRegistrationReply) ( /*! @function DNSServiceRegistrationCreate - @description Register a named service with DNS Service Discovery + @discussion Register a named service with DNS Service Discovery @param name The name of this service instance (e.g. "Steve's Printer") @param regtype The service type (e.g. "_printer._tcp." -- see RFC 2782 (DNS SRV) and ) @@ -171,7 +136,7 @@ dns_service_discovery_ref DNSServiceRegistrationCreate const char *txtRecord, DNSServiceRegistrationReply callBack, void *context -); +) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3; /***************************************************************************/ /* DNS Domain Enumeration */ @@ -185,6 +150,7 @@ typedef enum typedef enum { + DNSServiceDiscoverReplyFlagsFinished, DNSServiceDiscoverReplyFlagsMoreComing, } DNSServiceDiscoveryReplyFlags; @@ -197,7 +163,7 @@ typedef void (*DNSServiceDomainEnumerationReply) ( /*! @function DNSServiceDomainEnumerationCreate - @description Asynchronously create a DNS Domain Enumerator + @discussion Asynchronously create a DNS Domain Enumerator @param registrationDomains A boolean indicating whether you are looking for recommended registration domains (e.g. equivalent to the AppleTalk zone list in the AppleTalk Control Panel) @@ -212,7 +178,7 @@ dns_service_discovery_ref DNSServiceDomainEnumerationCreate int registrationDomains, DNSServiceDomainEnumerationReply callBack, void *context -); +) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3; /***************************************************************************/ /* DNS Service Browser */ @@ -234,7 +200,7 @@ typedef void (*DNSServiceBrowserReply) ( /*! @function DNSServiceBrowserCreate - @description Asynchronously create a DNS Service browser + @discussion Asynchronously create a DNS Service browser @param regtype The type of service @param domain The domain in which to find the service @param callBack The function to be called when service instances are found or removed @@ -247,13 +213,13 @@ dns_service_discovery_ref DNSServiceBrowserCreate const char *domain, DNSServiceBrowserReply callBack, void *context -); +) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3; /***************************************************************************/ /* Resolver requests */ typedef void (*DNSServiceResolverReply) ( - struct sockaddr *interfaceAddr, // Needed for scoped addresses like link-local + struct sockaddr *interface, // Needed for scoped addresses like link-local struct sockaddr *address, const char *txtRecord, DNSServiceDiscoveryReplyFlags flags, // DNS Service Discovery reply flags information @@ -262,7 +228,7 @@ typedef void (*DNSServiceResolverReply) ( /*! @function DNSServiceResolverResolve - @description Resolved a named instance of a service to its address, port, and + @discussion Resolved a named instance of a service to its address, port, and (optionally) other demultiplexing information contained in the TXT record. @param name The name of the service instance @param regtype The type of service @@ -280,14 +246,14 @@ dns_service_discovery_ref DNSServiceResolverResolve const char *domain, DNSServiceResolverReply callBack, void *context -); +) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3; /***************************************************************************/ /* Mach port accessor and deallocation */ /*! @function DNSServiceDiscoveryMachPort - @description Returns the mach port for a dns_service_discovery_ref + @discussion Returns the mach port for a dns_service_discovery_ref @param registration A dns_service_discovery_ref as returned from DNSServiceRegistrationCreate @result A mach reply port which will be sent messages as appropriate. These messages should be passed to the DNSServiceDiscovery_handleReply @@ -295,15 +261,15 @@ dns_service_discovery_ref DNSServiceResolverResolve specified or some other error occurred which prevented the resolution from being started. */ -mach_port_t DNSServiceDiscoveryMachPort(dns_service_discovery_ref dnsServiceDiscovery); +mach_port_t DNSServiceDiscoveryMachPort(dns_service_discovery_ref dnsServiceDiscovery) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3; /*! @function DNSServiceDiscoveryDeallocate - @description Deallocates the DNS Service Discovery type / closes the connection to the server + @discussion Deallocates the DNS Service Discovery type / closes the connection to the server @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a creation or enumeration call @result void */ -void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery); +void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3; /***************************************************************************/ /* Registration updating */ @@ -311,7 +277,7 @@ void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery /*! @function DNSServiceRegistrationAddRecord - @description Request that the mDNS Responder add the DNS Record of a specific type + @discussion Request that the mDNS Responder add the DNS Record of a specific type @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call @param rrtype A standard DNS Resource Record Type, from http://www.iana.org/assignments/dns-parameters @param rdlen Length of the data @@ -319,11 +285,11 @@ void DNSServiceDiscoveryDeallocate(dns_service_discovery_ref dnsServiceDiscovery @param ttl time to live for the added record. @result DNSRecordReference An opaque reference that can be passed to the update and remove record calls. If an error occurs, this value will be zero or negative */ -DNSRecordReference DNSServiceRegistrationAddRecord(dns_service_discovery_ref dnsServiceDiscovery, uint16_t rrtype, uint16_t rdlen, const char *rdata, uint32_t ttl); +DNSRecordReference DNSServiceRegistrationAddRecord(dns_service_discovery_ref dnsServiceDiscovery, uint16_t rrtype, uint16_t rdlen, const char *rdata, uint32_t ttl) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3; /*! @function DNSServiceRegistrationUpdateRecord - @description Request that the mDNS Responder add the DNS Record of a specific type + @discussion Request that the mDNS Responder add the DNS Record of a specific type @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call @param dnsRecordReference A dnsRecordReference as returned from a DNSServiceRegistrationAddRecord call @param rdlen Length of the data @@ -331,20 +297,18 @@ DNSRecordReference DNSServiceRegistrationAddRecord(dns_service_discovery_ref dns @param ttl time to live for the updated record. @result DNSServiceRegistrationReplyErrorType If an error occurs, this value will be non zero */ -DNSServiceRegistrationReplyErrorType DNSServiceRegistrationUpdateRecord(dns_service_discovery_ref ref, DNSRecordReference reference, uint16_t rdlen, const char *rdata, uint32_t ttl); +DNSServiceRegistrationReplyErrorType DNSServiceRegistrationUpdateRecord(dns_service_discovery_ref ref, DNSRecordReference reference, uint16_t rdlen, const char *rdata, uint32_t ttl) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3; /*! @function DNSServiceRegistrationRemoveRecord - @description Request that the mDNS Responder remove the DNS Record(s) of a specific type + @discussion Request that the mDNS Responder remove the DNS Record(s) of a specific type @param dnsServiceDiscovery A dns_service_discovery_ref as returned from a DNSServiceRegistrationCreate call @param dnsRecordReference A dnsRecordReference as returned from a DNSServiceRegistrationAddRecord call @result DNSServiceRegistrationReplyErrorType If an error occurs, this value will be non zero */ +DNSServiceRegistrationReplyErrorType DNSServiceRegistrationRemoveRecord(dns_service_discovery_ref ref, DNSRecordReference reference) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3; -DNSServiceRegistrationReplyErrorType DNSServiceRegistrationRemoveRecord(dns_service_discovery_ref ref, DNSRecordReference reference); -#ifdef __cplusplus - } -#endif +__END_DECLS -#endif // __DNS_SERVICE_DISCOVERY__ +#endif /* __DNS_SERVICE_DISCOVERY_H */ diff --git a/mDNSMacOSX/DNSServiceDiscoveryDefines.h b/mDNSMacOSX/DNSServiceDiscoveryDefines.h index c2f50c1..7dc7d62 100644 --- a/mDNSMacOSX/DNSServiceDiscoveryDefines.h +++ b/mDNSMacOSX/DNSServiceDiscoveryDefines.h @@ -1,28 +1,28 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: DNSServiceDiscoveryDefines.h,v $ +Revision 1.8 2006/10/27 00:35:36 cheshire +DNS_SERVICE_DISCOVERY_SERVER is now com.apple.mDNSResponder, not DNSServiceDiscoveryServer + +Revision 1.7 2006/08/14 23:24:39 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.6 2004/09/20 21:45:27 ksekar Mach IPC cleanup @@ -36,7 +36,7 @@ Update to APSL 2.0 #include -#define DNS_SERVICE_DISCOVERY_SERVER "DNSServiceDiscoveryServer" +#define DNS_SERVICE_DISCOVERY_SERVER "com.apple.mDNSResponder" typedef char DNSCString[1024]; typedef char sockaddr_t[128]; diff --git a/mDNSMacOSX/DNSServiceDiscoveryReply.defs b/mDNSMacOSX/DNSServiceDiscoveryReply.defs index 942fb6b..b918bee 100644 --- a/mDNSMacOSX/DNSServiceDiscoveryReply.defs +++ b/mDNSMacOSX/DNSServiceDiscoveryReply.defs @@ -1,24 +1,18 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ */ subsystem diff --git a/mDNSMacOSX/DNSServiceDiscoveryRequest.defs b/mDNSMacOSX/DNSServiceDiscoveryRequest.defs index b6d9cf8..ad06bdb 100644 --- a/mDNSMacOSX/DNSServiceDiscoveryRequest.defs +++ b/mDNSMacOSX/DNSServiceDiscoveryRequest.defs @@ -1,24 +1,18 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ */ subsystem diff --git a/mDNSMacOSX/LaunchDaemonInfo.dnsextd.plist b/mDNSMacOSX/LaunchDaemonInfo.dnsextd.plist new file mode 100644 index 0000000..37cb38d --- /dev/null +++ b/mDNSMacOSX/LaunchDaemonInfo.dnsextd.plist @@ -0,0 +1,19 @@ + + + + + Disabled + + Label + com.apple.dnsextd + OnDemand + + ProgramArguments + + /usr/sbin/dnsextd + -launchd + + ServiceIPC + + + diff --git a/mDNSMacOSX/LaunchDaemonInfo.helper.plist b/mDNSMacOSX/LaunchDaemonInfo.helper.plist new file mode 100644 index 0000000..5039775 --- /dev/null +++ b/mDNSMacOSX/LaunchDaemonInfo.helper.plist @@ -0,0 +1,21 @@ + + + + + Label + com.apple.mDNSResponderHelper + OnDemand + + ProgramArguments + + /usr/sbin/mDNSResponderHelper + + MachServices + + com.apple.mDNSResponderHelper + + + ServiceIPC + + + diff --git a/mDNSMacOSX/LaunchDaemonInfo.plist b/mDNSMacOSX/LaunchDaemonInfo.plist index e91b775..8f35709 100644 --- a/mDNSMacOSX/LaunchDaemonInfo.plist +++ b/mDNSMacOSX/LaunchDaemonInfo.plist @@ -6,12 +6,33 @@ com.apple.mDNSResponder OnDemand + UserName + _mdnsresponder + GroupName + _mdnsresponder ProgramArguments - /usr/sbin/mDNSResponder - -launchdaemon + /usr/sbin/mDNSResponder + -launchd + MachServices + + com.apple.mDNSResponder + + + Sockets + + Listeners + + SockFamily + Unix + SockPathName + /var/run/mDNSResponder + SockPathMode + 438 + + ServiceIPC - + diff --git a/mDNSMacOSX/LegacyNATTraversal.c b/mDNSMacOSX/LegacyNATTraversal.c index 2738e20..09db9ca 100644 --- a/mDNSMacOSX/LegacyNATTraversal.c +++ b/mDNSMacOSX/LegacyNATTraversal.c @@ -2,34 +2,107 @@ * * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: LegacyNATTraversal.c,v $ -Revision 1.14.2.2 2007/05/09 02:05:49 cheshire - Change sprintf and strcpy to their safer snprintf and strlcpy equivalents +Revision 1.40 2007/09/20 21:41:49 cheshire + Legacy NAT Traversal - unmap request failed with error -65549 + +Revision 1.39 2007/09/20 20:41:40 cheshire +Reordered functions in file, in preparation for following fix + +Revision 1.38 2007/09/18 21:42:30 cheshire +To reduce programming mistakes, renamed ExtPort to RequestedPort + +Revision 1.37 2007/09/14 21:26:09 cheshire + BTMM: Need to manually avoid port conflicts when using UPnP gateways + +Revision 1.36 2007/09/14 01:15:50 cheshire +Minor fixes for problems discovered in pre-submission testing + +Revision 1.35 2007/09/13 00:16:42 cheshire + Miscellaneous NAT Traversal improvements + +Revision 1.34 2007/09/12 23:03:08 cheshire + DNSServiceNATPortMappingCreate callback not giving correct interface index + +Revision 1.33 2007/09/12 19:22:20 cheshire +Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport +Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers + +Revision 1.32 2007/09/11 19:19:16 cheshire +Correct capitalization of "uPNP" to "UPnP" + +Revision 1.31 2007/09/10 22:14:16 cheshire +When constructing fake NATAddrReply or NATPortMapReply packet, need to calculate +plausible upseconds value or core logic will think NAT engine has been rebooted + +Revision 1.30 2007/09/05 20:46:17 cheshire +Tidied up alignment of code layout + +Revision 1.29 2007/08/03 20:18:01 vazquez + LegacyNATTraversal: reading out of bounds can lead to DoS -Revision 1.14.2.1 2005/12/12 17:38:40 cheshire -Put buffer overflow bug 4151514 back in by order of Program CCC: -"Program CCC Denied. This change does not meet the criteria for Chardonnay." +Revision 1.28 2007/07/31 02:28:36 vazquez + NAT-PMP: Detect public IP address changes and base station reboot + +Revision 1.27 2007/07/30 23:17:03 vazquez +Since lease times are meaningless in UPnP, return NATMAP_DEFAULT_LEASE in UPnP port mapping reply + +Revision 1.26 2007/07/27 22:50:08 vazquez +Allocate memory for UPnP request and reply buffers instead of using arrays + +Revision 1.25 2007/07/27 20:33:44 vazquez +Make sure we clean up previous port mapping requests before starting an unmap + +Revision 1.24 2007/07/27 00:57:48 vazquez +If a tcp connection is already established for doing a port mapping, don't start it again + +Revision 1.23 2007/07/26 21:19:26 vazquez +Retry port mapping with incremented port number (up to max) in order to handle +port mapping conflicts on UPnP gateways + +Revision 1.22 2007/07/25 21:41:00 vazquez +Make sure we clean up opened sockets when there are network transitions and when changing +port mappings + +Revision 1.21 2007/07/25 03:05:03 vazquez +Fixes for: + LegacyNATTraversal: UPnP heap overflow + LegacyNATTraversal: UPnP stack buffer overflow +and a myriad of other security problems + +Revision 1.20 2007/07/16 20:15:10 vazquez + LegacyNATTraversal: Need complete rewrite + +Revision 1.19 2007/06/21 16:37:43 jgraessley +Bug #: 5280520 +Reviewed by: Stuart Cheshire +Additional changes to get this compiling on the embedded platform. + +Revision 1.18 2007/05/09 01:43:32 cheshire + Change sprintf and strcpy to their safer snprintf and strlcpy equivalents + +Revision 1.17 2007/02/27 02:48:25 cheshire +Parameter to LNT_GetPublicIP function is IPv4 address, not anonymous "mDNSOpaque32" object + +Revision 1.16 2006/08/14 23:24:39 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + +Revision 1.15 2006/07/05 23:30:57 cheshire +Rename LegacyNATInit() -> LNT_Init() Revision 1.14 2005/12/08 03:00:33 cheshire Byte order bugs in Legacy NAT traversal code @@ -76,2972 +149,670 @@ Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h Revision 1.1 2004/08/18 17:35:41 ksekar : Feature #9586: Need support for Legacy NAT gateways +*/ +#ifdef _LEGACY_NAT_TRAVERSAL_ -*/ +#include "stdlib.h" // For strtol() +#include "string.h" // For strlcpy(), For strncpy(), strncasecmp() +#include // For inet_pton() #include "mDNSEmbeddedAPI.h" -#include "mDNSMacOSX.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include "memory.h" -#include -#include - -//#include "IPAddr.h" -//#include "upnp.h" -//#include "debug.h" - -// use error codes -//#include "netaddr.h" - -// TODO: remove later and do variable length -#define MAX_SOAPMSGSIZE 65536 - -// This code accidentally closes fd 0 all over the place -// To stop that messing up the mDNSResponder core, we trap it and prevent it -static int safe_close(int fd) - { - if (fd < 3) { /* LogMsg("safe_close: ERROR sd %d < 3", fd); */ return(-1); } - return(close(fd)); - } +#include "uDNS.h" // For natTraversalHandleAddressReply() etc. -#define close safe_close - -// This code uses fprintf(stderr, ...) and similar to log error messages -// We redirect all of them to syslog using our LogMsg mechanism -#define fprintf(file, ...) LogMsg(__VA_ARGS__) - -//////////////////////////////////////////////////////////////////////// -// NetAddr Functions -//////////////////////////////////////////////////////////////////////// - -// Return codes -#define NA_E_SUCCESS (0) -#define NA_E_INTERNAL_ERROR (-1) /* somewhere something wrong */ -#define NA_E_INVALID_PARAMETER (-2) /* bad params */ -#define NA_E_OPERATION_FAILED (-3) /* can't fulfill request */ -#define NA_E_TIMEOUT (-4) /* operation timed out */ -#define NA_E_THREAD_ERROR (-5) /* some error related to threads */ -#define NA_E_PARSE_ERROR (-6) /* a parsing error occured */ -#define NA_E_NOT_READY (-7) /* this op can't proceed yet */ -#define NA_E_NOT_FOUND (-8) /* resource/prereq not found */ -#define NA_E_NOT_AVAILABLE (-9) /* service not available */ -#define NA_E_EXISTS (-10) /* can't modify existing item */ -#define NA_E_AGAIN (-11) /* something wrong - try again */ -#define NA_E_NOT_SUPPORTED (-12) /* wait until next version */ -#define NA_E_ABORT (-14) /* operation aborted */ -#define NA_E_NET (-15) /* network layer problem */ - -// Logging flags - log types (increasing degree of detail) -#define NALOG_ERROR (1UL) /* error messages */ -#define NALOG_ALERT (2UL) /* useful warning/alerts */ -#define NALOG_INFO0 (4UL) /* info - potential problem */ -#define NALOG_INFO1 (8UL) /* extra info */ -#define NALOG_DUMP (16UL) /* data dumps */ - -#define NALOG_RSRV1 (32UL) /* reserved */ -#define NALOG_RSRV2 (64UL) /* reserved */ -#define NALOG_RSRV3 (128UL) /* reserved */ - -// Logging flags - component (not used for now) -#define NALOG_UPNP (256) /* UPnP */ - -// Default Logging levels -#define NALOG_LEVEL0 (0) -#define NALOG_LEVEL1 (NALOG_UPNP | NALOG_ERROR) -#define NALOG_LEVEL2 (NALOG_LEVEL1 | NALOG_ALERT) -#define NALOG_LEVEL3 (NALOG_LEVEL2 | NALOG_INFO0) -#define NALOG_LEVEL4 (NALOG_LEVEL3 | NALOG_INFO1) -#define NALOG_LEVEL5 (NALOG_LEVEL4 | NALOG_DUMP) -#define NALOG_DEFAULT_LEVEL (NALOG_LEVEL2) - -// Default timeout values (in m-seconds (milli)) -// 50 milliseconds for function timeout -#define NA_DEFAULT_FUNCTION_TIMEOUT (50) - -//////////////////////////////////////////////////////////////////////// -// GLOBAL Defines -//////////////////////////////////////////////////////////////////////// -#define SSDP_IP "239.255.255.250" -#define SSDP_PORT 1900 -#define SSDP_TTL 4 - -#define CRLF "\r\n" -#define H_CRLF "\r\n" -// SOAP message's CRLF: -//#define S_CRLF "\r\n" -#define S_CRLF - -// standard 200 ok msg -#define HTTP200OK "HTTP/1.1 200 OK\r\n\r\n" -#define HTTP200OKLEN (sizeof(HTTP200OK) - 1) - -// maximum time to wait for an event (in microseconds) -#define MAX_EXPECTEVENTTIME (10000) - -//////////////////////////////////////////////////////////////////////// -// GLOBAL Data Types -//////////////////////////////////////////////////////////////////////// -typedef struct tagProperty { - char *pszName; - char *pszValue; - char *pszType; -} Property, *PProperty; - -typedef struct tagHTTPResponse { - char *pszStatus; - char *pszReason; - int iNumHeaders; - Property aHeaders[30]; // assume at most this many headers - char *pszBody; - - // for admin use - int fFree; - char *buf; -} HTTPResponse, *PHTTPResponse, **PPHTTPResponse; - -//////////////////////////////////////////////////////////////////////// -// GLOBAL Constants -//////////////////////////////////////////////////////////////////////// -static const char szSSDPMsgDiscoverRoot[] = - "M-SEARCH * HTTP/1.1\r\n" - "Host:239.255.255.250:1900\r\n" - "ST:upnp:rootdevice\r\n" - "Man:\"ssdp:discover\"\r\n" - "MX:3\r\n" - "\r\n"; - -static const char szSSDPMsgDiscoverIGD[] = - "M-SEARCH * HTTP/1.1\r\n" - "Host:239.255.255.250:1900\r\n" - "ST:urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n" - "Man:\"ssdp:discover\"\r\n" - "MX:3\r\n" - "\r\n"; - -static const char szSSDPMsgDiscoverNAT[] = - "M-SEARCH * HTTP/1.1\r\n" - "Host:239.255.255.250:1900\r\n" - "ST:urn:schemas-upnp-org:service:WANIPConnection:1\r\n" - "Man:\"ssdp:discover\"\r\n" - "MX:3\r\n" - "\r\n"; - -//// Subscribe message -// 1$s: control URL -// 2$s: local's host/port ("host:port") -// 3$s: router's host/port ("host:port") -// 4$d: subscription timeout in seconds -static const char szEventMsgSubscribeFMT[] = - "SUBSCRIBE %1$s HTTP/1.1\r\n" - "NT: upnp:event\r\n" - "Callback: \r\n" - "Timeout: Second-%4$d\r\n" - "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n" - "Host: %3$s\r\n" - "Content-Length: 0\r\n" - "Pragma: no-cache\r\n" - "\r\n"; - -//// Unsubscribe message -// 1$s: control URL -// 2$s: SID (some uuid passed back during subscribe) -// 3$s: router's host ("host") -#if 0 -static const char szEventMsgUnsubscribeFMT[] = - "UNSUBSCRIBE %1$s HTTP/1.1\r\n" - "SID: %2$s\r\n" - "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n" - "Host: %3$s\r\n" - "Content-Length: 0\r\n" - "Pragma: no-cache\r\n" - "\r\n"; -#endif - -//// Generic SOAP Control:Action request messages -// 1$s: control URL -// 2$s: router's host/port ("host:port") -// 3$s: action (string) -// 4$d: content-length -static const char szSOAPMsgControlAHeaderFMT[] = - //"M-POST %1$s HTTP/1.1\r\n" - "POST %1$s HTTP/1.1\r\n" - "Content-Type: text/xml; charset=\"utf-8\"\r\n" - //"TEST: \"http://schemas.xmlsoap.org/soap/envelope/\"; ns=01\r\n" - //"Man: \"http://schemas.xmlsoap.org/soap/envelope/\"; ns=01\r\n" - //"01-SOAPAction: \"urn:schemas-upnp-org:service:WANIPConnection:1#%3$s\"\r\n" - "SOAPAction: \"urn:schemas-upnp-org:service:WANIPConnection:1#%3$s\"\r\n" - "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)\r\n" - "Host: %2$s\r\n" - "Content-Length: %4$d\r\n" - "Connection: close\r\n" -// "Connection: Keep-Alive\r\n" - "Pragma: no-cache\r\n" - "\r\n"; - -// 1$: action (string) -// 2$: argument list -static const char szSOAPMsgControlABodyFMT[] = - "" CRLF - "" S_CRLF - "" S_CRLF - "" S_CRLF - "%2$s" - "" S_CRLF - "" S_CRLF - "" S_CRLF -// CRLF -// "0" -// CRLF - CRLF; - -// 1$: argument name -// 2$: argument value -static const char szSOAPMsgControlAArgumentFMT[] = - "<%1$s>%2$s" S_CRLF; - -// 1$: argument name -// 2$: argument value -// 3$: argument type -static const char szSOAPMsgControlAArgumentFMT_t[] = - "<%1$s" - " xmlns:dt=\"urn:schemas-microsoft-com:datatypes\"" - " dt:dt=\"%3$s\">%2$s" S_CRLF; - -#if 0 -//// Generic SOAP Control:Query request messages -// 1$s: control URL -// 2$s: router's host/port ("host:port") -// 3$d: content-length -static const char szSOAPMsgControlQHeaderFMT[] = - "M-POST %1$s HTTP/1.1\r\n" - //"POST %1$s HTTP/1.1\r\n" - "Host: %2$s\r\n" - "Content-Length: %3$d\r\n" - "Content-Type: text/xml; charset-\"utf-8\"\r\n" - //"Man: \"http://schemas.xmlsoap.org/soap/envelope/\"; ns=01\r\n" - //"SOAPAction: \"urn:schemas-upnp-org:control-1-0#QueryStateVariable\"\r\n" - "01-SOAPAction: \"urn:schemas-upnp-org:control-1-0#QueryStateVariable\"\r\n" - "\r\n"; - -// 1$: variable name -static const char szSOAPMsgControlQBodyFMT[] = - "" S_CRLF - "" S_CRLF - "%s" S_CRLF - "" S_CRLF - "" S_CRLF - "" S_CRLF - "" S_CRLF; -#endif -// 1$: device description URL -// 2$: host/port -static const char szSSDPMsgDescribeDeviceFMT[] = - "GET %s HTTP/1.1\r\n" - "Accept: text/xml, application/xml\r\n" - "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n" - "Host: %s\r\n" - "Connection: close\r\n" -// "Connection: Keep-Alive\r\n" - "\r\n"; - -//////////////////////////////////////////////////////////////////////// -// GLOBAL Variables -//////////////////////////////////////////////////////////////////////// - -static int g_fFirstInit = TRUE; -static int g_fQuit = FALSE; -static FILE *g_log; -static int g_fLogging; - -// Globally-accessible UDP socket -static int g_sUDP = -1; -static int g_sUDPCancel = -1; - -// Globally-accessible TCP socket -static int g_sTCP = -1; -static int g_sTCPCancel = -1; - -// Event Vars -static int g_fEventEnabled = FALSE; -static unsigned short g_wEventPort; -static struct sockaddr_in g_saddrRouterEvent; -static char g_szRouterHostPortEvent[1024]; -static char g_szEventURL[1024]; - -// UPnP Router info -static char g_szFriendlyName[1024]; -static char g_szManufacturer[1024]; -static char g_szModelName[1024]; -static char g_szModelDescription[1024]; - -// URL base -static struct sockaddr_in g_saddrRouterBase; -static char g_szRouterHostPortBase[1024]; - -// the threads -static pthread_t g_UDPthread = NULL; -static pthread_t g_TCPthread = NULL; - -// Local IP -static unsigned long g_dwLocalIP = 0; - -// Globally accessible info about the router/UPnP -static int g_fUPnPEnabled = FALSE; -static char g_szUSN[1024]; - -static struct sockaddr_in g_saddrRouterDesc; -static char g_szRouterHostPortDesc[1024]; -static char g_szNATDevDescURL[1024]; - -static struct sockaddr_in g_saddrRouterSOAP; -static char g_szRouterHostPortSOAP[1024]; -static char g_szControlURL[1024]; -static int g_fControlURLSet = FALSE; - -// Lock/condvar for synchronous upnp calls -static pthread_mutex_t g_xUPnP; -static pthread_mutex_t g_xUPnPMsg; -static pthread_cond_t g_condUPnP; -static pthread_cond_t g_condUPnPControlURL; -static struct timeval g_tvUPnPInitTime; -static struct timeval g_tvLastUpdateTime; - -// timeout values in seconds -static int g_iFunctionTimeout = NA_DEFAULT_FUNCTION_TIMEOUT; - -static void GetDeviceDescription(void); -static void SetLocalIP(void); - -//////////////////////////////////////////////////////////////////////// -// IPAddr Functions -//////////////////////////////////////////////////////////////////////// - - -#define ISIPV6 0x01 -#define ISPPP 0x02 -#define IFNAMELEN 16 /* Interface Name Length */ -#define IPLEN 16 /* 16 bytes(128 bits) for IPv6 */ - -typedef struct tagIPINFO -{ - int iFlags; - char szIfName[IFNAMELEN]; /* Interface name */ - unsigned char abIP[IPLEN]; - unsigned short wPort; -} IPINFO, *PIPINFO, **PPIPINFO; - -typedef struct hostent HOSTENT, *PHOSTENT; - -static unsigned long GetNATIPNetmask(unsigned long dwIP) -{ - static const union { uint8_t b[4]; uint32_t l; } mask_10 = { { 255, 0, 0, 0 } }; // Mask for 10/8 - static const union { uint8_t b[4]; uint32_t l; } mask172 = { { 255, 240, 0, 0 } }; // Mask for 172.16/12 - static const union { uint8_t b[4]; uint32_t l; } mask192 = { { 255, 255, 0, 0 } }; // Mask for 192.168/16 - uint8_t *p = (uint8_t *)&dwIP; - if (p[0] == 10 ) return mask_10.l; - if (p[0] == 172 && (p[1] & 0xF0) == 16) return mask172.l; - if (p[0] == 192 && p[1] == 168 ) return mask192.l; - return 0; /* No NAT IP */ -} - -static int GetIPInfo(PPIPINFO ppIPInfo) -{ - int fd; - int iLastLen, iLen, iNum = 0, iMax = 0; - unsigned long dwIP; - char *pcBuf, *pcTemp; - PIPINFO pIPInfo = NULL; - struct ifconf ifc; - struct ifreq *ifr, ifrcopy; - - if (ppIPInfo == NULL) return 0; - - fd = socket(AF_INET, SOCK_DGRAM, 0); - - iLastLen = -1; - iLen = 100 * sizeof(struct ifreq); - - for (;;) +// used to format SOAP port mapping arguments +typedef struct Property_struct + { + char *name; + char *type; + char *value; + } Property; + +// All of the text parsing in this file is intentionally transparent so that we know exactly +// what's being done to the text, with an eye towards preventing security problems. + +// This is an evolving list of useful acronyms to know. Please add to it at will. +// ST Service Type +// NT Notification Type +// USN Unique Service Name +// UDN Unique Device Name +// UUID Universally Unique Identifier +// URN/urn Universal Resource Name + +// Forward declaration because of circular reference: +// SendPortMapRequest -> SendSOAPMsgControlAction -> MakeTCPConnection -> tcpConnectionCallback -> handleLNTPortMappingResponse +// In the event of a port conflict, handleLNTPortMappingResponse then increments tcpInfo->retries and calls back to SendPortMapRequest to try again +mDNSlocal mStatus SendPortMapRequest(mDNS *m, NATTraversalInfo *n); + +#define RequestedPortNum(n) (mDNSVal16(mDNSIPPortIsZero((n)->RequestedPort) ? (n)->IntPort : (n)->RequestedPort) + (n)->tcpInfo.retries) + +// This function parses the xml body of the device description response from the router. Basically, we look to make sure this is a response +// referencing a service we care about (WANIPConnection), look for the "controlURL" header immediately following, and copy the addressing and URL info we need +mDNSlocal void handleLNTDeviceDescriptionResponse(tcpLNTInfo *tcpInfo) { - pcBuf = (char *)malloc(iLen); - ifc.ifc_len = iLen; - ifc.ifc_buf = pcBuf; + mDNS *m = tcpInfo->m; + char *ptr = (char *)tcpInfo->Reply; + char *end = (char *)tcpInfo->Reply + tcpInfo->nread; - if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) + // find the service we care about + while (ptr && ptr != end) { - if (errno != EINVAL || iLastLen != -1) - { -// DbgPrint(ELL_ERROR, "ioctl failed(%d)\n", errno); - free(pcBuf); - close(fd); - return 0; - } + if (*ptr == 'W' && (strncasecmp(ptr, "WANIPConnection:1", 17) == 0)) break; // find the first 'W'; is this WANIPConnection? if not, keep looking + ptr++; } - else + if (ptr == mDNSNULL || ptr == end) { LogOperation("handleLNTDeviceDescriptionResponse: didn't find WANIPConnection:1 string"); return; } + + // find "controlURL", starting from where we left off + while (ptr && ptr != end) { - if (ifc.ifc_len == iLastLen) break; - iLastLen = ifc.ifc_len; + if (*ptr == 'c' && (strncasecmp(ptr, "controlURL", 10) == 0)) break; // find the first 'c'; is this controlURL? if not, keep looking + ptr++; } + if (ptr == mDNSNULL || ptr == end) { LogOperation("handleLNTDeviceDescriptionResponse: didn't find controlURL string"); return; } + ptr += 11; // skip over "controlURL>" + if (ptr >= end) { LogOperation("handleLNTDeviceDescriptionResponse: past end of buffer and no body!"); return; } // check ptr again in case we skipped over the end of the buffer - iLen += 10 * sizeof(struct ifreq); - free(pcBuf); - } - - for (pcTemp = pcBuf; pcTemp < pcBuf + ifc.ifc_len; ) - { - if (iNum >= iMax) + // is there an address string "http://"? starting from where we left off + if (strncasecmp(ptr, "http://", 7) == 0) { - PIPINFO pIPInfoNew; + int i; + char *addrPtr = mDNSNULL; + + ptr += 7; //skip over "http://" + if (ptr >= end) { LogOperation("handleLNTDeviceDescriptionResponse: past end of buffer and no URL!"); return; } + addrPtr = ptr; + for (i = 0; addrPtr && addrPtr != end; i++, addrPtr++) if (*addrPtr == '/') break; // first find the beginning of the URL and count the chars + if (addrPtr == mDNSNULL || addrPtr == end) { LogOperation("handleLNTDeviceDescriptionResponse: didn't find SOAP address string"); return; } + + // allocate the buffer (len i+1 so we have space to terminate the string) + if (m->UPnPSOAPAddressString != mDNSNULL) mDNSPlatformMemFree(m->UPnPSOAPAddressString); + if ((m->UPnPSOAPAddressString = (mDNSu8 *) mDNSPlatformMemAllocate(i+1)) == mDNSNULL) { LogMsg("can't allocate SOAP address string"); return; } + + strncpy((char *)m->UPnPSOAPAddressString, ptr, i); // copy the address string + m->UPnPSOAPAddressString[i] = '\0'; // terminate the string + } + + if (m->UPnPSOAPAddressString == mDNSNULL) m->UPnPSOAPAddressString = m->UPnPRouterAddressString; // just copy the pointer, don't allocate more memory + LogOperation("handleLNTDeviceDescriptionResponse: SOAP address string [%s]", m->UPnPSOAPAddressString); - iMax += 10; - pIPInfoNew = (PIPINFO)realloc(pIPInfo, sizeof(IPINFO) * iMax); - if (pIPInfoNew == NULL) + // find port and router URL, starting after the "http://" if it was there + while (ptr && ptr != end) + { + if (*ptr == ':') // found the port number { - free(pIPInfo); - free(pcBuf); - close(fd); - return 0; + int port; + ptr++; // skip over ':' + if (ptr == end) { LogOperation("handleLNTDeviceDescriptionResponse: reached end of buffer and no address!"); return; } + port = (int)strtol(ptr, (char **)mDNSNULL, 10); // get the port + m->UPnPSOAPPort = mDNSOpaque16fromIntVal(port); // store it properly converted } - else pIPInfo = pIPInfoNew; - - memset(pIPInfo + (iMax - 10), 0, sizeof(IPINFO) * 10); + else if (*ptr == '/') // found SOAP URL + { + int j; + char *urlPtr = mDNSNULL; + if (mDNSIPPortIsZero(m->UPnPSOAPPort)) m->UPnPSOAPPort = m->UPnPRouterPort; // fill in default port if we didn't find one before + + urlPtr = ptr; + for (j = 0; urlPtr && urlPtr != end; j++, urlPtr++) if (*urlPtr == '<') break; // first find the next '<' and count the chars + if (urlPtr == mDNSNULL || urlPtr == end) { LogOperation("handleLNTDeviceDescriptionResponse: didn't find SOAP URL string"); return; } + + // allocate the buffer (len j+2 because we're copying from the first '/' and so we have space to terminate the string) + if (m->UPnPSOAPURL != mDNSNULL) mDNSPlatformMemFree(m->UPnPSOAPURL); + if ((m->UPnPSOAPURL = (mDNSu8 *)mDNSPlatformMemAllocate(j+1)) == mDNSNULL) { LogMsg("can't mDNSPlatformMemAllocate SOAP URL"); return; } + + // now copy + strncpy((char *)m->UPnPSOAPURL, ptr, j); // this URL looks something like "/uuid:0013-108c-4b3f0000f3dc" + m->UPnPSOAPURL[j] = '\0'; // terminate the string + break; // we've got everything we need, so get out here + } + ptr++; // continue } - ifr = (struct ifreq *)pcTemp; - - pcTemp += sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len; - - /* discard invalid address families & loopback */ - if ((ifr->ifr_addr.sa_family != AF_INET && - ifr->ifr_addr.sa_family != AF_INET6) || - strncmp(ifr->ifr_name, "lo", 2) == 0) continue; - - ifrcopy = *ifr; - ioctl(fd, SIOCGIFFLAGS, &ifrcopy); - if ((ifrcopy.ifr_flags & IFF_UP) == 0) continue; - - switch (ifr->ifr_addr.sa_family) + // if we get to the end and haven't found the URL fill in the defaults + if (m->UPnPSOAPURL == mDNSNULL) { - case AF_INET: - memcpy(pIPInfo[iNum].szIfName, ifr->ifr_name, IFNAMELEN); - dwIP = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr; - memcpy(pIPInfo[iNum].abIP, &dwIP, sizeof(unsigned long)); - if (ifrcopy.ifr_flags & IFF_POINTOPOINT) - pIPInfo[iNum].iFlags |= ISPPP; - iNum++; - break; - - case AF_INET6: - memcpy(pIPInfo[iNum].szIfName, ifr->ifr_name, IFNAMELEN); - memcpy(pIPInfo[iNum].abIP, - ((struct sockaddr_in6 *)&(ifr->ifr_addr))-> sin6_addr.s6_addr, - 16); - pIPInfo[iNum].iFlags |= ISIPV6; - if (ifrcopy.ifr_flags & IFF_POINTOPOINT) - pIPInfo[iNum].iFlags |= ISPPP; - iNum++; - break; - - default: - break; + m->UPnPSOAPURL = m->UPnPRouterURL; // just copy the pointer, don't allocate more memory + m->UPnPSOAPPort = m->UPnPRouterPort; } + + LogOperation("handleLNTDeviceDescriptionResponse: SOAP URL [%s] port %d", m->UPnPSOAPURL, mDNSVal16(m->UPnPSOAPPort)); } - free(pcBuf); - close(fd); - - *ppIPInfo = pIPInfo; - - return iNum; -} - -static void FreeIPInfo(PIPINFO pIPInfo) -{ - if (pIPInfo != NULL) free(pIPInfo); -} - - -//////////////////////////////////////////////////////////////////////// -// Function Definitions -//////////////////////////////////////////////////////////////////////// - -static void SendDiscoveryMsg(); - -// SSDPListen -// Creates a UDP multicast socket and listens to the SSDP IP/PORT -// Returns -// -1 on error, or the socket descriptor if success -static int SSDPListen() -{ - char fLoop; - int iTTL; - struct ip_mreq mreq; - struct sockaddr_in saddr; - int sd; - - // IPPROTO_IP == 0; IPPROTO_TCP == 6; IPPROTO_UDP == 17; etc. - sd = socket(AF_INET, SOCK_DGRAM, 0); - if (sd == -1) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "Can't create socket! SSDPListen exiting\n"); - return NA_E_NET; - } - - // sock options values - fLoop = 0; // false - don't send copy to self - iTTL = SSDP_TTL; - - // bind to listen to ssdp multicast address - bzero(&saddr, sizeof(saddr)); - saddr.sin_len = sizeof(saddr); - saddr.sin_family = AF_INET; - //saddr.sin_addr.s_addr = inet_addr(SSDP_IP); - //saddr.sin_port = htons(SSDP_PORT); - saddr.sin_addr.s_addr = g_dwLocalIP; - saddr.sin_port = 0; - - // and set the multicast add_member structure - // (TODO: need to find interfaces later - ioctl, with: - // SIOCFIFCONF to find if's, SIOCGIFADDR to get addr, and SIOCFIFFLAGS - // to check for IFF_MULTICAST flag for multicast support on an if) - bzero(&mreq, sizeof(mreq)); - mreq.imr_interface.s_addr = g_dwLocalIP; - mreq.imr_multiaddr.s_addr = inet_addr(SSDP_IP); - - if ( - bind(sd, (struct sockaddr *)&saddr, sizeof(saddr)) //|| - //setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, &fLoop, sizeof(fLoop)) || - //setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL, &iTTL, sizeof(iTTL)) || - //setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) - ) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, - "bind/setsockopt for multicast failed... errno = %d\n", errno); - close(sd); - return NA_E_NET; - } - - return sd; -} - -static int EventListen() -{ - struct sockaddr_in saddr; - int sd; - - // try 5 ports before failing completely - for (g_wEventPort = 5000; g_wEventPort < 5005; g_wEventPort++) +mDNSlocal void handleLNTGetExternalAddressResponse(tcpLNTInfo *tcpInfo) { - sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sd == -1) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "Can't create socket! EventListen exiting\n"); - return NA_E_NET; - } + mDNS *m = tcpInfo->m; + mDNSu16 err = NATErr_None; + mDNSv4Addr ExtAddr; + char *addrPtr; + char *ptr = (char *)tcpInfo->Reply; + char *end = (char *)tcpInfo->Reply + tcpInfo->nread; - bzero(&saddr, sizeof(saddr)); - saddr.sin_len = sizeof(saddr); - saddr.sin_family = AF_INET; - saddr.sin_addr.s_addr = g_dwLocalIP; - saddr.sin_port = htons(g_wEventPort); +// LogOperation("handleLNTGetExternalAddressResponse: %s", ptr); - // return if okay - if (bind(sd, (struct sockaddr *)&saddr, sizeof(saddr)) == 0) + while (ptr && ptr < end) // Find "NewExternalIPAddress" { - listen(sd, 128); - ////TracePrint(ELL_TRACE, "UPnP: EventListen @%u\n", g_wEventPort); - return sd; + if (*ptr == 'N' && (strncasecmp(ptr, "NewExternalIPAddress", 20) == 0)) break; // find the first 'N'; is this NewExternalIPAddress? if not, keep looking + ptr++; } + if (ptr == mDNSNULL || ptr >= end) return; // bad or incomplete response + ptr+=21; // skip over "NewExternalIPAddress>" + if (ptr >= end) { LogOperation("handleLNTGetExternalAddressResponse: past end of buffer!"); return; } - // unsuccessful - close sd and try again - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, - "bind TCP port %u failed: errno = %d\n", g_wEventPort, errno); - close(sd); - } - - return NA_E_NET; -} + // find the end of the address and terminate the string so inet_pton() can convert it + for (addrPtr = ptr; addrPtr && addrPtr < end; addrPtr++) if (*addrPtr == '<') break; // first find the next '<' and count the chars + if (addrPtr == mDNSNULL || addrPtr >= end) { LogOperation("handleLNTGetExternalAddressResponse: didn't find SOAP URL string"); return; } + *addrPtr = '\0'; -static void *TCPProc(void *in); + if (inet_pton(AF_INET, ptr, &ExtAddr) <= 0) + { LogMsg("handleLNTGetExternalAddressResponse: Router returned bad address"); err = NATErr_NetFail; } + if (!err) LogOperation("handleLNTGetExternalAddressResponse: External IP address is %.4a", &ExtAddr); -static int EventInit() -{ - int iRet; - pthread_attr_t attr; + natTraversalHandleAddressReply(m, err, ExtAddr); + } - if (g_fEventEnabled == FALSE) +mDNSlocal void handleLNTPortMappingResponse(tcpLNTInfo *tcpInfo) { - // initialize TCP socket for Eventing - g_sTCP = EventListen(); - if (g_sTCP < 0) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "EventInit - Failed to init tcp socket.\n"); - return NA_E_INTERNAL_ERROR; - } + mDNS *m = tcpInfo->m; + mDNSIPPort extport = zeroIPPort; + char *ptr = (char *)tcpInfo->Reply; + char *end = (char *)tcpInfo->Reply + tcpInfo->nread; + NATTraversalInfo *natInfo; - // make TCP thread - pthread_attr_init(&attr); - iRet = pthread_create(&g_TCPthread, &attr, TCPProc, 0); - if (iRet != 0) { - close(g_sTCP); - g_sTCP = -1; - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "EventInit: TCPProc create failed(%d)\n", iRet); - return NA_E_THREAD_ERROR; - } - } + for (natInfo = m->NATTraversals; natInfo; natInfo=natInfo->next) { if (natInfo == tcpInfo->parentNATInfo) break; } + + if (!natInfo) { LogOperation("handleLNTPortMappingResponse: can't find matching tcpInfo in NATTraversals!"); return; } - g_fEventEnabled = TRUE; - - return NA_E_SUCCESS; -} - -static void DumpHex(char *buf, int len) -{ - int i; - int nexti; - int j; - int endj; - - if (g_fLogging & NALOG_DUMP) { - if (buf == NULL) return; - if (len <= 0) return; - - for (i = 0; i < len; i = nexti) { - fprintf(g_log, "%04x: ", i); - nexti = i + 16; - endj = (nexti > len) ? len : nexti; - for (j = i; j < endj; j++) - fprintf(g_log, "%02x %c ", buf[j] & 0xff, buf[j]); - if (j == len) { - if ((j % 16) != 0) { - char pad[3 * 16 + 1]; // don't need the last 3 bytes anyway - j = (16 - (j % 16)) * 3; - memset(pad, ' ', j); - pad[j] = '\0'; - fputs(pad, g_log); + // start from the beginning of the HTTP header; find "200 OK" status message; if the first characters after the + // space are not "200" then this is an error message or invalid in some other way + // if the error is "500" this is an internal server error + while (ptr && ptr != end) + { + if (*ptr == ' ') + { + ptr++; + if (ptr == end) { LogOperation("handleLNTPortMappingResponse: past end of buffer!"); return; } + if (strncasecmp(ptr, "200", 3) == 0) break; + else if (strncasecmp(ptr, "500", 3) == 0) + { + // now check to see if this was a port mapping conflict + while (ptr && ptr != end) + { + if ((*ptr == 'c' || *ptr == 'C') && strncasecmp(ptr, "Conflict", 8) == 0) + { + if (tcpInfo->retries < 100) + { tcpInfo->retries++; SendPortMapRequest(tcpInfo->m, natInfo); } + else + { + LogMsg("handleLNTPortMappingResponse too many conflict retries %d %d", mDNSVal16(natInfo->IntPort), mDNSVal16(natInfo->RequestedPort)); + natTraversalHandlePortMapReply(m, natInfo, m->UPnPInterfaceID, NATErr_Refused, zeroIPPort, 0); + } + return; + } + ptr++; + } + break; // out of HTTP status search } } - for (j = i; j < endj; j++) - isprint(buf[j]) ? fputc(buf[j], g_log) : fputc('.', g_log); - fputc('\n', g_log); + ptr++; } + if (ptr == mDNSNULL || ptr == end) return; + + LogOperation("handleLNTPortMappingResponse: got a valid response, sending reply to natTraversalHandlePortMapReply(internal %d external %d retries %d)", + mDNSVal16(natInfo->IntPort), RequestedPortNum(natInfo), tcpInfo->retries); - } -} - -// FindHTTPHeaderNewLine -// Returns a pointer to the beginning of a CRLF, that is not a -// part of LWS. (LWS is CRLF followed by a space or tab, and in -// HTTP, considered as equivalent to a single space) (LWS stands -// for "linear white space") -// Returns a pointer the beginning of CRLF, and sets the EOH flag to -// whether this is the last header in the HTTP header section. -// Also, if pbuf is NULL, or if there isn't any CRLF found in the -// string, or if the HTTP syntax is wrong, NULL is returned, and -// the EOH flag is not touched. -static char *FindHTTPHeaderNewLine(char *pbuf, int iBufSize, int *pfEOH) -{ - char *result; - int i = 0; - - if (pbuf == NULL) return NULL; - - for (;;) { - result = memchr(pbuf, '\r', iBufSize); - if (result == NULL) { - if (g_fLogging & NALOG_INFO0) { - fprintf(g_log, "FindHTTPHeaderNewLine: er @(%d/%d)\n", i, iBufSize); - fflush(g_log); - } - return NULL; - } - i++; // count chars - - // decrement iBufSize, and move pbuf forward - iBufSize -= (result - pbuf); - pbuf = result; - - ++pbuf; // now pointing right after "\r" - --iBufSize; - if (*pbuf == '\0') break; - if (*pbuf != '\n') continue; - - ++pbuf; // now pointing after "\r\n" - --iBufSize; - if (*pbuf == '\0') break; - if ((*pbuf == ' ') || (*pbuf == '\t')) continue; - - // at this point we know we're at the end of a header field, - // and there's more stuff coming... - - // just need to check if this is the last header - if ((pbuf[0] == '\r') && (pbuf[1] == '\n')) - *pfEOH = TRUE; - else - *pfEOH = FALSE; - - return result; - } - - return NULL; -} - -// NewHTTPResponse_sz -// Creates an HTTPResponse structure from a string (sz). Set -// fDestroyOriginal to TRUE if the buffer passed in can be overwritten. -// Otherwise, NewHTTPResponse_sz will duplicate the buffer. -// Returns the created HTTPResponse structure if successful, or if an -// error occured (out of memory, or bad http syntax), returns NULL. -// NOTE: ALWAYS call DeleteHTTPResponse after using the HTTPResponse structure. -// NOTE: The input is assumed to be correct. If there're HTTP syntax errors, -// and the pszHTTPResponse is not null-terminated, result may be undefined. -// (to be fixed next version) -static PHTTPResponse NewHTTPResponse_sz( - char *pszHTTPResponse, - int iBufferSize, - int fDestroyOriginal) -{ - PHTTPResponse pResponse; - int fEOH; - char *pszEOL; - int iNumHeaders; - char *pBuf; - - if ((pResponse = (PHTTPResponse)malloc(sizeof(HTTPResponse))) == NULL) { - if (g_fLogging & NALOG_INFO0) { - fprintf(g_log, "NewHTTPResponse_sz: er 1\n"); - fflush(g_log); - } - return NULL; - } - - // make copy of buffer now - if (fDestroyOriginal) { - pResponse->buf = NULL; - pBuf = pszHTTPResponse; - } - else { - int len = strlen(pszHTTPResponse); - if ((len+1) > iBufferSize) { - if (g_fLogging & NALOG_INFO0) - fprintf(g_log, "Length: %d > %d\n", len+1, iBufferSize); - iBufferSize = len+1; - } - if ((pResponse->buf = (char *)malloc(iBufferSize)) == NULL) { - free(pResponse); - if (g_fLogging & NALOG_INFO0) { - fprintf(g_log, "NewHTTPResponse_sz: er 2\n"); - fflush(g_log); - } - return NULL; - } - memcpy(pResponse->buf, pszHTTPResponse, iBufferSize); - pBuf = pResponse->buf; - } - - // get the first line - pszEOL = FindHTTPHeaderNewLine(pBuf, iBufferSize, &fEOH); - if (pszEOL == NULL) { - if (g_fLogging & NALOG_INFO0) { - fprintf(g_log, "NewHTTPResponse_sz: er 3\n"); - fflush(g_log); - } - goto cleanup; - } - - *pszEOL = '\0'; // terminate the status line - pszEOL += 2; // point to the rest of the buffer - - // set the status string first - pResponse->pszStatus = strchr(pBuf, ' '); - if (pResponse->pszStatus == NULL) { - if (g_fLogging & NALOG_INFO0) { - fprintf(g_log, "NewHTTPResponse_sz: er 4\n"); - fflush(g_log); - } - goto cleanup; // syntax error + // Make sure to compute extport *before* we zero tcpInfo->retries + extport = mDNSOpaque16fromIntVal(RequestedPortNum(natInfo)); + tcpInfo->retries = 0; + natTraversalHandlePortMapReply(m, natInfo, m->UPnPInterfaceID, mStatus_NoError, extport, NATMAP_DEFAULT_LEASE); } - pResponse->pszStatus++; // point to the actual status - - pResponse->pszReason = strchr(pResponse->pszStatus, ' '); - if (pResponse->pszReason == NULL) { - if (g_fLogging & NALOG_INFO0) { - fprintf(g_log, "NewHTTPResponse_sz: er 5\n"); - fflush(g_log); - } - goto cleanup; // syntax error +mDNSlocal void DisposeInfoFromUnmapList(mDNS *m, tcpLNTInfo *tcpInfo) + { + tcpLNTInfo **ptr = &m->tcpInfoUnmapList; + while (*ptr && *ptr != tcpInfo) ptr = &(*ptr)->next; + if (*ptr) { *ptr = (*ptr)->next; mDNSPlatformMemFree(tcpInfo); } // If we found it, cut it from our list and free the memory } - pResponse->pszReason[0] = '\0'; // terminate status string - pResponse->pszReason++; // point to the reason string - - iNumHeaders = 0; // initialize to 0 headers - - // parse header fields line by line (while not end of headers) - while (!fEOH) { - PProperty pHeader = &(pResponse->aHeaders[iNumHeaders]); - // point header field name to the first char of the line - pHeader->pszName = pszEOL; - - // search for the end of line - pszEOL = FindHTTPHeaderNewLine(pszEOL, - iBufferSize - (pszEOL - pBuf), // remainder size - &fEOH); - if (pszEOL == NULL) { - if (g_fLogging & NALOG_INFO0) { - fprintf(g_log, "NewHTTPResponse_sz: er reading header field %d @ %lu / %lu\n", - iNumHeaders, pHeader->pszName - pBuf, iBufferSize); - DumpHex(pszHTTPResponse, iBufferSize); - fflush(g_log); - } - goto cleanup; // syntax error - } - - *pszEOL = '\0'; // terminate this string - pszEOL += 2; // point to beginning of next line - - pHeader->pszValue = strchr(pHeader->pszName, ':'); - if (pHeader->pszValue == NULL) { - if (g_fLogging & NALOG_INFO0) { - fprintf(g_log, "NewHTTPResponse_sz: er 6\n"); - fflush(g_log); - } - goto cleanup; // syntax error (header field has no ":") - } - - pHeader->pszValue[0] = '\0'; // terminate the header name string - pHeader->pszValue++; // point after the ":" - // get rid of leading spaces for the value part - while ( - (pHeader->pszValue[0] == ' ') || - (pHeader->pszValue[0] == '\t') || - (pHeader->pszValue[0] == '\r') || - (pHeader->pszValue[0] == '\n') - ) { - pHeader->pszValue++; // skip the space - } +mDNSlocal void tcpConnectionCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEstablished, mStatus err) + { + mStatus status = mStatus_NoError; + tcpLNTInfo *tcpInfo = (tcpLNTInfo *)context; + mDNSBool closed = mDNSfalse; + long n = 0; + long nsent = 0; - iNumHeaders++; // added one more header - pHeader++; // point to the next header in pResponse->aHeaders - } + if (tcpInfo == mDNSNULL) { LogOperation("tcpConnectionCallback: no tcpInfo context"); status = mStatus_Invalid; goto exit; } - pResponse->iNumHeaders = iNumHeaders; // remember to set it in pResponse - - pResponse->pszBody = pszEOL + 2; // point after the empty line - - return pResponse; - -cleanup: - if (pResponse->buf != NULL) free(pResponse->buf); - free(pResponse); - return NULL; -} - -// DeleteHTTPResponse -// Deallocates stuff in the HTTPResponse structure, effectively returning -// memory to the system and destroying the structure. -// NOTE: The pointer pResponse WILL BE FREED, and will be unusable after -// the call to DeleteHTTPResponse. -static void DeleteHTTPResponse(PHTTPResponse pResponse) -{ -// int i; - - if (pResponse == NULL) return; - - // Current impl is just simple array - no need to free() - //for (i = 0; i < pResponse->iNumHeaders; i++) { - // free(pResponse->aHeaders[i]); - //} - - if (pResponse->buf != NULL) - free(pResponse->buf); - free(pResponse); -} - -//typedef struct tagHTTPResponse { -// char *pszStatus; -// char *pszReason; -// int iNumHeaders; -// Property aHeaders[30]; // assume at most this many headers -// char *pszBody; -// -// // for admin use -// int fFree; -// char *buf; -//} HTTPResponse, *PHTTPResponse, **PPHTTPResponse; - -static void PrintHTTPResponse(PHTTPResponse pResponse) -{ - int i; - - if (g_fLogging & (NALOG_INFO1)) { - if (pResponse == NULL) return; - fprintf(g_log, " *** HTTP response begin *** \n"); - fprintf(g_log, " * status = [%s], reason = [%s] *\n", - pResponse->pszStatus, pResponse->pszReason); - for (i = 0; i < pResponse->iNumHeaders; i++) { - fprintf(g_log, " * Header \"%s\" = [%s]\n", - pResponse->aHeaders[i].pszName, - pResponse->aHeaders[i].pszValue); - } - if (g_fLogging & NALOG_DUMP) - fprintf(g_log, " * body = [%s] *\n", pResponse->pszBody); - fprintf(g_log, " *** HTTP response end *** \n"); - } -} - -static int DiscoverRouter(PHTTPResponse pResponse) -{ - int i; - int fLocation = FALSE; - int fUSN = FALSE; - int fIsNATDevice = FALSE; - -#if 0 - if (strcmp(pResponse->pszStatus, "200") != 0) - return -1; -#endif - - if (pResponse == NULL) { - if (g_fLogging & NALOG_INFO0) - fprintf(g_log, "DiscoverRouter: pResponse == NULL\n"); - return -1; - } + // The handlers below expect to be called with the lock held + mDNS_Lock(tcpInfo->m); + + if (err) { LogOperation("tcpConnectionCallback: received error"); goto exit; } - // check to see if this is a relevant packet - for (i = 0; i < pResponse->iNumHeaders; i++) { - PProperty pHeader = &(pResponse->aHeaders[i]); - - if ((strcasecmp(pHeader->pszName, "ST") == 0) || - (strcasecmp(pHeader->pszName, "NT") == 0)) { - if ((strcmp(pHeader->pszValue, - "urn:schemas-upnp-org:service:WANIPConnection:1") == 0) || - (strcmp(pHeader->pszValue, - "urn:schemas-upnp-org:device:InternetGatewayDevice:1") == 0)) { - fIsNATDevice = TRUE; - } + if (ConnectionEstablished) // connection is established - send the message + { + LogOperation("tcpConnectionCallback: connection established, sending message"); + nsent = mDNSPlatformWriteTCP(sock, (char *)tcpInfo->Request, tcpInfo->requestLen); + if (nsent != (long)tcpInfo->requestLen) { LogMsg("tcpConnectionCallback: error writing"); status = mStatus_UnknownErr; goto exit; } } - } - - // leave the message alone if we don't need it - if (!fIsNATDevice) - return -1; - - // Now that we know we're looking at the message about the NAT device: - pthread_mutex_lock(&g_xUPnP); - - // set upnp to be unconfigured for now - g_fUPnPEnabled = FALSE; - - // loop through the headers - for (i = 0; i < pResponse->iNumHeaders; i++) { - PProperty pHeader = &(pResponse->aHeaders[i]); - - if (strcasecmp(pHeader->pszName, "Location") == 0) { - char *p; - char *q; - - if (g_fLogging & NALOG_INFO1) - fprintf(g_log, "Checking Location...\n"); - p = pHeader->pszValue; - if (strncmp(p, "http://", 7) != 0) - continue; // hope for another Location header to correct it - p += 7; // skip over "http://" - q = strchr(p, '/'); - - // set the control URL first - if (q == NULL) { - g_szNATDevDescURL[0] = '/'; - g_szNATDevDescURL[1] = '\0'; - } - else { - strncpy(g_szNATDevDescURL, q, sizeof(g_szNATDevDescURL) - 1); - g_szNATDevDescURL[sizeof(g_szNATDevDescURL) - 1] = '\0'; - // terminate the host/port string - *q = '\0'; - } - - if (g_fLogging & NALOG_INFO1) - fprintf(g_log, " Device Description URL set to[%s]...\n", - g_szNATDevDescURL); + else + { + n = mDNSPlatformReadTCP(sock, (char *)tcpInfo->Reply + tcpInfo->nread, tcpInfo->replyLen - tcpInfo->nread, &closed); + LogOperation("tcpConnectionCallback: mDNSPlatformReadTCP read %d bytes", n); - // see if port is specified - q = strchr(p, ':'); - if (q == NULL) { - snprintf(g_szRouterHostPortDesc, sizeof(g_szRouterHostPortDesc), "%s", p); + if (n < 0) { LogOperation("tcpConnectionCallback - read returned %d", n); status = mStatus_ConnFailed; goto exit; } + else if (closed) { LogOperation("tcpConnectionCallback: socket closed by remote end %d", tcpInfo->nread); status = mStatus_ConnFailed; goto exit; } - g_saddrRouterDesc.sin_addr.s_addr = inet_addr(p); - g_saddrRouterDesc.sin_port = htons(80); + tcpInfo->nread += n; + LogOperation("tcpConnectionCallback tcpInfo->nread %d", tcpInfo->nread); + if (tcpInfo->nread > LNT_MAXBUFSIZE) + { + LogOperation("result truncated..."); + tcpInfo->nread = LNT_MAXBUFSIZE; } - else { - // don't include the ":80" - HTTP is by default port 80 - if (atoi(q+1) == 80) *q = '\0'; - - strlcpy(g_szRouterHostPortDesc, p, sizeof(g_szRouterHostPortDesc)); - - // terminate the host part and point to it - *q = '\0'; - q++; - g_saddrRouterDesc.sin_addr.s_addr = inet_addr(p); - g_saddrRouterDesc.sin_port = htons(atoi(q)); + switch (tcpInfo->op) + { + case LNTDiscoveryOp: handleLNTDeviceDescriptionResponse (tcpInfo); break; + case LNTExternalAddrOp: handleLNTGetExternalAddressResponse(tcpInfo); break; + case LNTPortMapOp: handleLNTPortMappingResponse (tcpInfo); break; + case LNTPortMapDeleteOp: status = mStatus_ConfigChanged; break; + default: LogMsg("tcpConnectionCallback: bad tcp operation! %d", tcpInfo->op); status = mStatus_Invalid; break; } - - g_saddrRouterDesc.sin_family = AF_INET; - - if (g_fLogging & NALOG_INFO1) - fprintf(g_log, " Router Address set to[%s]...\n", - g_szRouterHostPortDesc); - fLocation = TRUE; } - else if (strcasecmp(pHeader->pszName, "USN") == 0) { - if (g_fLogging & NALOG_INFO1) - fprintf(g_log, "Checking USN...\n"); - strncpy(g_szUSN, pHeader->pszValue, sizeof(g_szUSN) - 1); - g_szUSN[sizeof(g_szUSN) - 1] = '\0'; - fUSN = TRUE; - } - else { - ; // do nothing for other headers for now - } - } - - // now check flags and set enabled if all set - if (fLocation && fUSN) { - if (g_fLogging & NALOG_INFO1) { - fprintf(g_log, - "Description Host/port string: [%s]\n" - "NATDevDescURL: [%s], USN: [%s]\n", - g_szRouterHostPortDesc, - g_szNATDevDescURL, g_szUSN); - if (g_fLogging & NALOG_INFO1) - fprintf(g_log, "Got router information\n"); - } - - g_fUPnPEnabled = TRUE; - pthread_cond_broadcast(&g_condUPnP); - } - - // remember to unlock before return - pthread_mutex_unlock(&g_xUPnP); - - return 0; -} - -// granularity is specified as: granularity = 1/nth seconds -#define UPNP_TIMEOUT_GRANULARITY (1000) -#define U_TOGRAN UPNP_TIMEOUT_GRANULARITY - -// result = a - b -static void TimevalSubtract( - struct timeval *result, - const struct timeval *a, - const struct timeval *b) -{ - result->tv_sec = a->tv_sec - b->tv_sec; - - if (b->tv_usec > a->tv_usec) { - result->tv_sec--; - result->tv_usec = 1000000 + a->tv_usec - b->tv_usec; - } - else - result->tv_usec = a->tv_usec - b->tv_usec; -} - -// elapsed = end - start -static void GetTimeElapsed( - const struct timeval *tv_start, - const struct timeval *tv_end, - struct timeval *tv_elapsed) -{ - TimevalSubtract(tv_elapsed, tv_end, tv_start); -#if 0 - tv_elapsed->tv_sec = tv_end->tv_sec - tv_start->tv_sec; - - if (tv_start->tv_usec > tv_end->tv_usec) { - tv_elapsed->tv_sec--; - tv_elapsed->tv_usec = 1000000 + tv_end->tv_usec - tv_start->tv_usec; - } - else - tv_elapsed->tv_usec = tv_end->tv_usec - tv_start->tv_usec; -#endif -} - -// returns +1, 0, or -1, if a>b, a==b, atv_sec == b->tv_sec) && - (a->tv_usec == b->tv_usec)) return 0; - - if (a->tv_sec > b->tv_sec) return 1; - else if (a->tv_sec < b->tv_sec) return -1; - - // if seconds are equal... - if (a->tv_usec > b->tv_usec) return 1; - else return -1; -} - -static int WaitControlURLSet(double timeout) -{ - struct timespec ts; - struct timeval tv; - struct timeval tv_start; - int iRet; - long to_sec = (int) (timeout / U_TOGRAN); - long to_usec = - (int) (((timeout / U_TOGRAN) - to_sec) * 1000000.0); - //long to_sec = (int) timeout; - //long to_usec = (int) ((timeout - to_sec) * 1000000.0); - struct timeval elapsed; - - // get function start time - gettimeofday(&tv_start, NULL); - - pthread_mutex_lock(&g_xUPnP); - -#if 0 - // if last update is too long ago then wait for it - GetTimeElapsed(&g_tvLastUpdateTime, &tv_start, &elapsed); - if ((elapsed.tv_sec + (elapsed.tv_usec / 1000000.0)) > - (((double) g_iUPnPTimeout) / U_TOGRAN)) - g_fControlURLSet = 0; -#endif - - while (!g_fControlURLSet) { - // get current time - gettimeofday(&tv, NULL); - -#if 0 -for now ignore device timeout - // see if we've past the device's timeout first - GetTimeElapsed(&g_tvUPnPInitTime, &tv, &elapsed); - if ((elapsed.tv_sec > g_timeout_sec) || - ( (elapsed.tv_sec == g_timeout_sec) && - (elapsed.tv_usec > g_timeout_usec) - )) +exit: + if (err || status) { - pthread_mutex_unlock(&g_xUPnP); - return FALSE; - } -#endif - - // calculate ts to sleep till - ts.tv_sec = tv.tv_sec + to_sec; - ts.tv_nsec = (tv.tv_usec + to_usec) * 1000; - if (ts.tv_nsec > 1000000000) { - ts.tv_nsec -= 1000000000; - ts.tv_sec += 1; - } - - // now get how long we've been in this function already and deduct - GetTimeElapsed(&tv_start, &tv, &elapsed); - ts.tv_sec -= elapsed.tv_sec; - if (ts.tv_nsec < (elapsed.tv_usec * 1000)) { - ts.tv_sec--; - ts.tv_nsec = 1000000000 + ts.tv_nsec - (elapsed.tv_usec * 1000); - } - else { - ts.tv_nsec -= (elapsed.tv_usec * 1000); + mDNSPlatformTCPCloseConnection(tcpInfo->sock); + tcpInfo->sock = mDNSNULL; + if (tcpInfo->Request) { mDNSPlatformMemFree(tcpInfo->Request); tcpInfo->Request = mDNSNULL; } + if (tcpInfo->Reply ) { mDNSPlatformMemFree(tcpInfo->Reply); tcpInfo->Reply = mDNSNULL; } } - iRet = pthread_cond_timedwait(&g_condUPnPControlURL, &g_xUPnP, &ts); + if (tcpInfo) mDNS_Unlock(tcpInfo->m); - // if timeout then return false - if (iRet != 0) - { - pthread_mutex_unlock(&g_xUPnP); - return FALSE; - } + if (status == mStatus_ConfigChanged) DisposeInfoFromUnmapList(tcpInfo->m, tcpInfo); } - pthread_mutex_unlock(&g_xUPnP); - - return TRUE; -} - -static int WaitUPnPFunction() -{ - struct timeval start; -// struct timeval end; - double wait2; -// struct timeval elapsed; - - gettimeofday(&start, NULL); - - wait2 = (double)g_iFunctionTimeout; - - WaitControlURLSet(wait2); -//gettimeofday(&end, NULL); -//GetTimeElapsed(&start, &end, &elapsed); -//fprintf(stderr, "== wait2: (%f) %d.%06d\n", -// wait2/U_TOGRAN, elapsed.tv_sec, elapsed.tv_usec); - - return g_fControlURLSet; -} - -static void SetLocalIP(); - -static int SendTCPMsg_saddr_parse( - char *msg, int iLen, - char *result, int resultSize, - struct sockaddr_in *saHost); - -static void *TCPProc(void *in) -{ - int iRet; - unsigned char buf[MAX_SOAPMSGSIZE]; - int iBufLen; - - (void)in; // unused - WaitUPnPFunction(); - //TracePrint(ELL_TRACE, "UPnP: Begin TCPProc\n"); - - // do the subscription +mDNSlocal mStatus MakeTCPConnection(mDNS *const m, tcpLNTInfo *info, const mDNSAddr *const Addr, const mDNSIPPort Port, LNTOp_t op) { - char callback[100]; - char response[2000]; - PHTTPResponse resp; - int n; - snprintf(callback, sizeof(callback), "%u.%u.%u.%u:%u", - ((uint8_t*)&g_dwLocalIP)[0], ((uint8_t*)&g_dwLocalIP)[1], - ((uint8_t*)&g_dwLocalIP)[2], ((uint8_t*)&g_dwLocalIP)[3], g_wEventPort); - - n = snprintf((char *)buf, sizeof(buf), - szEventMsgSubscribeFMT, - g_szEventURL, - callback, g_szRouterHostPortEvent, 1800); - - memset(response, 0, 2000); - n = SendTCPMsg_saddr_parse( - (char *)buf, n, - response, 2000, - &g_saddrRouterEvent); - if (n > 0) + mStatus err = mStatus_NoError; + mDNSIPPort srcport = zeroIPPort; + + if (mDNSIPv4AddressIsZero(Addr->ip.v4) || mDNSIPPortIsZero(Port)) + { LogMsg("LNT MakeTCPConnection: bad address/port %#a:%d", Addr, mDNSVal16(Port)); return(mStatus_Invalid); } + info->m = m; + info->Address = *Addr; + info->Port = Port; + info->op = op; + info->nread = 0; + info->replyLen = LNT_MAXBUFSIZE; + if (info->Reply != mDNSNULL) mDNSPlatformMemZero(info->Reply, LNT_MAXBUFSIZE); // reuse previously allocated buffer + else if ((info->Reply = (mDNSs8 *) mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogOperation("can't allocate reply buffer"); return (mStatus_NoMemoryErr); } + + if (info->sock) { LogOperation("MakeTCPConnection: closing previous open connection"); mDNSPlatformTCPCloseConnection(info->sock); info->sock = mDNSNULL; } + info->sock = mDNSPlatformTCPSocket(m, kTCPSocketFlags_Zero, &srcport); + if (!info->sock) { LogMsg("LNT MakeTCPConnection: unable to create TCP socket"); mDNSPlatformMemFree(info->Reply); info->Reply = mDNSNULL; return(mStatus_NoMemoryErr); } + LogOperation("MakeTCPConnection: connecting to %#a:%d", &info->Address, mDNSVal16(info->Port)); + err = mDNSPlatformTCPConnect(info->sock, Addr, Port, 0, tcpConnectionCallback, info); + + if (err == mStatus_ConnPending) err = mStatus_NoError; + else if (err == mStatus_ConnEstablished) { - response[n] = '\0'; - resp = NewHTTPResponse_sz((char *)response, n+1, TRUE); - if (NULL != resp) - { -////TracePrint(ELL_TRACE, "UPnP Subscribe returns %s/%d\n", resp->pszStatus, n); - } - else - { -////TracePrint(ELL_TRACE, "UPnP Subscribe not enough response (%d) \n[%s]\n", -// n, response); - } - DeleteHTTPResponse(resp); + mDNS_DropLockBeforeCallback(); + tcpConnectionCallback(info->sock, info, mDNStrue, mStatus_NoError); + mDNS_ReclaimLockAfterCallback(); + err = mStatus_NoError; } - else + else { -////TracePrint(ELL_TRACE, "UPnP Subscribe failed (%d)\n", n); - return NULL; + LogMsg("LNT MakeTCPConnection: connection failed"); + mDNSPlatformTCPCloseConnection(info->sock); // Dispose the socket we created with mDNSPlatformTCPSocket() above + info->sock = mDNSNULL; + mDNSPlatformMemFree(info->Reply); + info->Reply = mDNSNULL; } + return(err); } - //TracePrint(ELL_TRACE, "UPnP: TCPProc begin loop\n"); - - g_sTCPCancel = -1; - - for (;;) +mDNSlocal unsigned int AddSOAPArguments(char *buf, unsigned int maxlen, int numArgs, Property *a) { -// ssize_t n; - struct sockaddr_in recvaddr; - socklen_t recvaddrlen; - fd_set readfds; - struct timeval timeout; - int sEvent; - int fFirstRecv; - int sMax; - - // for after responding to long(?) TCP event - if (g_fQuit) - goto cleanup; - - if (g_sTCPCancel != -1) close(g_sTCPCancel); - sMax = g_sTCPCancel = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sMax < g_sTCP) sMax = g_sTCP; - - FD_ZERO(&readfds); - FD_SET(g_sTCP, &readfds); - FD_SET(g_sTCPCancel, &readfds); - iRet = select(sMax+1, &readfds, NULL, NULL, NULL); - if (iRet <= 0) { - if (EBADF == errno) - continue; - //TracePrint(ELL_TRACE, "UPnP Event select failed (%d)\n", errno); - continue; - } - - recvaddrlen = sizeof(recvaddr); - sEvent = accept(g_sTCP, (struct sockaddr *)&recvaddr, &recvaddrlen); - // not likely - (system's descriptor/file table full) - if (sEvent <= 0) continue; - - ////TracePrint(ELL_TRACE, "UPnP receiving event..\n"); - - // read all we could from this event - fFirstRecv = 1; - iBufLen = 0; - for (;;) + static const char f1[] = "<%s>%s"; + static const char f2[] = "<%s xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"%s\">%s"; + int i, len = 0; + *buf = 0; + for (i = 0; i < numArgs; i++) { - FD_ZERO(&readfds); - FD_SET(sEvent, &readfds); - timeout.tv_sec = 0; - timeout.tv_usec = 400000; // long cause we're dealing with input - iRet = select(sEvent+1, &readfds, NULL, NULL, &timeout); - if (iRet <= 0) { - if (g_fQuit) - { - close(sEvent); - goto cleanup; - } - break; - } - - // recv - iRet = recv(sEvent, buf + iBufLen, MAX_SOAPMSGSIZE - iBufLen, 0); - if (iRet < 0) - { - // something is wrong - break; - } - else if (iRet == 0) - { - break; - } - - iBufLen += iRet; - - if (fFirstRecv) - { - int iTemp; - iTemp = send(sEvent, HTTP200OK, HTTP200OKLEN, 0); - shutdown(sEvent, 1); - fFirstRecv = 0; - } + if (a[i].type) len += mDNS_snprintf(buf + len, maxlen - len, f2, a[i].name, a[i].type, a[i].value, a[i].name); + else len += mDNS_snprintf(buf + len, maxlen - len, f1, a[i].name, a[i].value, a[i].name); } + return(len); + } - // now send 200 OK and be done - close(sEvent); - - ////TracePrint(ELL_TRACE, "UPnP event (%d) received (%d)\n", g_fExpectEvent, iBufLen); - - // and parse the XML here. - if (iBufLen < MAX_SOAPMSGSIZE) +mDNSlocal mStatus SendSOAPMsgControlAction(mDNS *m, tcpLNTInfo *info, char *Action, int numArgs, Property *Arguments, LNTOp_t op) + { + // SOAP message header format - + // - control URL + // - action (string) + // - router's host/port ("host:port") + // - content-length + static const char header[] = + "POST %s HTTP/1.1\r\n" + "Content-Type: text/xml; charset=\"utf-8\"\r\n" + "SOAPAction: \"urn:schemas-upnp-org:service:WANIPConnection:1#%s\"\r\n" + "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)\r\n" + "Host: %s\r\n" + "Content-Length: %d\r\n" + "Connection: close\r\n" + "Pragma: no-cache\r\n" + "\r\n" + "%s\r\n"; + + static const char body1[] = + "\r\n" + "" + "" + ""; + + static const char body2[] = + "" + "" + "\r\n"; + + mStatus err; + char body[2048]; // Typically requires 1110-1122 bytes, so 2048 allows a generous safety margin + int bodyLen; + + if (m->UPnPSOAPURL == mDNSNULL || m->UPnPSOAPAddressString == mDNSNULL) // if no SOAP URL or address exists get out here + { LogOperation("SendSOAPMsgControlAction: no SOAP URL or address string"); return mStatus_Invalid; } + + // Create body + bodyLen = mDNS_snprintf (body, sizeof(body), body1, Action); + bodyLen += AddSOAPArguments(body + bodyLen, sizeof(body) - bodyLen, numArgs, Arguments); + bodyLen += mDNS_snprintf (body + bodyLen, sizeof(body) - bodyLen, body2, Action); + + // Create info->Request; the header needs to contain the bodyLen in the "Content-Length" field + if (!info->Request) info->Request = mDNSPlatformMemAllocate(LNT_MAXBUFSIZE); + if (!info->Request) { LogMsg("SendSOAPMsgControlAction: Can't allocate info->Request"); return mStatus_NoMemoryErr; } + info->requestLen = mDNS_snprintf((char *)info->Request, LNT_MAXBUFSIZE, header, m->UPnPSOAPURL, Action, m->UPnPSOAPAddressString, bodyLen, body); + + err = MakeTCPConnection(m, info, &m->Router, m->UPnPSOAPPort, op); + if (err) { mDNSPlatformMemFree(info->Request); info->Request = mDNSNULL; } + return err; + } + +// Build port mapping request with new port (up to max) and send it +mDNSlocal mStatus SendPortMapRequest(mDNS *m, NATTraversalInfo *n) + { + char externalPort[6]; + char internalPort[6]; + char localIPAddrString[30]; + char publicPortString[40]; + Property propArgs[8]; + mDNSu16 ReqPortNum = RequestedPortNum(n); + NATTraversalInfo *n2 = m->NATTraversals; + + // Scan our m->NATTraversals list to make sure the external port we're requesting is locally unique. + // UPnP gateways will report conflicts if different devices request the same external port, but if two + // clients on the same device request the same external port the second one just stomps over the first. + // One way this can happen is like this: + // 1. Client A binds local port 80 + // 2. Client A requests external port 80 -> internal port 80 + // 3. UPnP NAT gateway refuses external port 80 (some other client already has it) + // 4. Client A tries again, and successfully gets external port 80 -> internal port 81 + // 5. Client B on same machine tries to bind local port 80, and fails + // 6. Client B tries again, and successfully binds local port 81 + // 7. Client B now requests external port 81 -> internal port 81 + // 8. UPnP NAT gateway allows this, stomping over Client A's existing mapping + + while (n2) { - buf[iBufLen] = '\0'; - // for now do nothing - } + if (n2 == n || RequestedPortNum(n2) != ReqPortNum) n2=n2->next; else - { - buf[MAX_SOAPMSGSIZE - 1] = '\0'; - } - } - -cleanup: - //TracePrint(ELL_TRACE, "UPnP: TCPProc end\n"); - close(g_sTCP); - g_sTCP = -1; - g_fEventEnabled = FALSE; - if (g_sTCPCancel != -1) close(g_sTCPCancel); - g_sTCPCancel = -1; - return NULL; -} - -static void *UDPProc(void *in) -{ -// char fLoop = 0; // false - don't send copy to self -// int iTTL = SSDP_TTL; - int iRet; -// struct ip_mreq mreq; -// struct sockaddr_in saddr; - unsigned char buf[65536]; -// FILE *log = g_log; - static time_t last_getdevicedesc_t = 0; - - (void)in; // unused - pthread_mutex_lock(&g_xUPnP); - gettimeofday(&g_tvUPnPInitTime, NULL); - pthread_mutex_unlock(&g_xUPnP); - - for (;;) { - ssize_t n; - struct sockaddr_in recvaddr; - socklen_t recvaddrlen; - fd_set readfds; - //struct timeval timeout; - //int i; - int sMax; - - if (g_sUDPCancel < g_sUDP) sMax = g_sUDP; - else sMax = g_sUDPCancel; - - FD_ZERO(&readfds); - FD_SET(g_sUDP, &readfds); - FD_SET(g_sUDPCancel, &readfds); - iRet = select(sMax+1, &readfds, NULL, NULL, NULL); - - if (iRet <= 0) { - if (g_fQuit) - { - close(g_sUDP); - close(g_sUDPCancel); - g_sUDP = -1; - g_sUDPCancel = -1; - return NULL; - } - continue; - } - - if (!FD_ISSET(g_sUDP, &readfds)) continue; - recvaddrlen = sizeof(recvaddr); - n = recvfrom(g_sUDP, buf, sizeof(buf)-1, 0, - (struct sockaddr *)&recvaddr, &recvaddrlen); - if (n < 0) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "recv failed (%d)\n", errno); - close(g_sUDP); - close(g_sUDPCancel); - g_sUDP = -1; - g_sUDPCancel = -1; - return NULL; - } - buf[n] = '\0'; - if (strncmp((char *)buf, "HTTP/1.1", 8) == 0) { - PHTTPResponse pResponse = NewHTTPResponse_sz((char *)buf, n+1, TRUE); - PrintHTTPResponse(pResponse); - if (DiscoverRouter(pResponse) == 0) { - time_t now = time(NULL); - if (!g_fControlURLSet || - ((now - last_getdevicedesc_t) > 5)) + if (n->tcpInfo.retries < 100) { - GetDeviceDescription(); - SetLocalIP(); - last_getdevicedesc_t = now; + n->tcpInfo.retries++; + ReqPortNum = RequestedPortNum(n); // Pick a new port number + n2 = m->NATTraversals; // And re-scan the list looking for conflicts } - } - DeleteHTTPResponse(pResponse); - } - else if (strncmp((char *)buf, "NOTIFY * HTTP/1.1", 7) == 0) { - // temporarily use this to fudge - will have the exact same - // parsing, only status/reason set to "*" and "HTTP/1.1". - // TODO: add support for HTTP requests - PHTTPResponse pResponse = NewHTTPResponse_sz((char *)buf, n+1, TRUE); - if (DiscoverRouter(pResponse) == 0) - { - time_t now = time(NULL); - if (!g_fControlURLSet || - ((now - last_getdevicedesc_t) > 5)) + else { - GetDeviceDescription(); - SetLocalIP(); - last_getdevicedesc_t = now; + natTraversalHandlePortMapReply(m, n, m->UPnPInterfaceID, NATErr_Refused, zeroIPPort, 0); + return mStatus_NoError; } } - DeleteHTTPResponse(pResponse); } - else { - if (g_fLogging & NALOG_DUMP) - fprintf(g_log, "(%ld) Buffer: \n[%s]\n", time(NULL), buf); - fflush(g_log); - } - } - - close(g_sUDP); - g_sUDP = -1; -} - -static void SendUDPMsg(const char *msg) { - struct sockaddr_in saSendTo; - int iRet; - int iLen; - - bzero(&saSendTo, sizeof(saSendTo)); - saSendTo.sin_family = AF_INET; - saSendTo.sin_addr.s_addr = inet_addr(SSDP_IP); - saSendTo.sin_port = htons(SSDP_PORT); - - iLen = strlen(msg); - - if (g_fLogging & NALOG_DUMP) - fprintf(g_log, "SendUDP: [%s]\n", msg); - - iRet = sendto(g_sUDP, msg, iLen, 0, - (struct sockaddr *)&saSendTo, sizeof(saSendTo)); - - // sanity check - if (iRet != iLen) - if (g_fLogging & NALOG_ALERT) - fprintf(g_log, - "SendUDPMsg: iRet(%d) != strlen(msg)(%d)! (errno %d)\n", - iRet, iLen, errno); -} - -// strstr, case insensitive, and is limited by len -static char *strcasestr_n(const char *big, const char *little, int len) -{ - int bigLen; - int littleLen; - int i; - int end; - - if (little == NULL) return (char *)big; - if (big == NULL) return NULL; - - //bigLen = strlen(big); - bigLen = len; - littleLen = strlen(little); - - if (bigLen < littleLen) return NULL; - - end = bigLen - littleLen; - for (i = 0; i <= end; (i++), (big++)) { - if (strncasecmp(big, little, littleLen) == 0) - return (char *)big; - } - - return NULL; -} - -// this is strnstr, only portable -static char *strstr_n(const char *big, const char *little, int len) -{ - int iBigLen; - int iLittleLen; - - (void)len; // unused - - if ((big == NULL) || (little == NULL)) return NULL; - - iBigLen = strlen(big); - iLittleLen = strlen(little); - - // this part is basically strnstr, except this is portable - for (;;) { - if (iBigLen < iLittleLen) - return NULL; - if (strncmp(big, little, iLittleLen) == 0) - return (char *)big; - ++big; - --iBigLen; - } -} - -// returns -1 for "not found" -static int FindContentLength(char *pbuf, int iLen) -{ - // non reusable HTTP header parsing code: - // ---------------------------------------------- - char *p; - int iResult; - - // find content length header - p = strcasestr_n(pbuf, "\r\nContent-Length:", iLen); - if (p == NULL) return -1; - - p += sizeof("\r\nContent-Length:") - 1; // minus '\0' - - iResult = atoi(p); - - return iResult; - // ---------------------------------------------- -} - -// returns -1 for "not found" -static int FindBody(char *pbuf, int iLen) -{ - // non reusable HTTP header parsing code: - // ---------------------------------------------- - char *p; -// int iResult; - - // find the empty line - p = strstr_n(pbuf, "\r\n\r\n", iLen); - if (p == NULL) return -1; - - p += sizeof("\r\n\r\n") - 1; // minus '\0' - - return (p - pbuf); - // ---------------------------------------------- -} - -static int SendTCPMsg_saddr_2part( - char *msg, int iLen, - char *msg2, int iLen2, - char *result, int resultSize, - struct sockaddr_in *saHost) -{ - int s; - struct sockaddr_in saSendTo; - int iRet; - int iBufLen; - int fND; - int fcntl_flags; - int iRetcode; - struct timeval tv; - fd_set writefds; - - struct timeval tv_start; - struct timeval tv_end; - struct timeval tv_elapsed; - - int iContentLength = -1; - int iBodyOffset = -1; - - gettimeofday(&tv_start, NULL); - - if (g_fUPnPEnabled != TRUE) { -//TracePrint(ELL_TRACE, "UPnP not enabled\n"); - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "UPnP not enabled (no UPnP device found yet)\n"); - return NA_E_NOT_AVAILABLE; - } - - s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (s == -1) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "Can't get TCP socket (%d)\n", errno); - return NA_E_NET; - } - fND = 1; - if (setsockopt(s, IPPROTO_IP, TCP_NODELAY, &fND, sizeof(fND)) != 0) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "SendTCPMsg/2part: Can't set TCP_NODELAY option!\n"); - iRetcode = NA_E_NET; - goto cleanup; - } - - fcntl_flags = 0; - fcntl_flags = fcntl(s, F_GETFL, 0); - fcntl_flags |= O_NONBLOCK; - if (fcntl(s, F_SETFL, fcntl_flags) != 0) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "SendTCPMsg/2part: Can't set O_NONBLOCK option!\n"); - iRetcode = NA_E_NET; - goto cleanup; + // create strings to use in the message + mDNS_snprintf(externalPort, sizeof(externalPort), "%u", ReqPortNum); + mDNS_snprintf(internalPort, sizeof(internalPort), "%u", mDNSVal16(n->IntPort)); + mDNS_snprintf(publicPortString, sizeof(publicPortString), "iC%u", ReqPortNum); + mDNS_snprintf(localIPAddrString, sizeof(localIPAddrString), "%u.%u.%u.%u", + m->AdvertisedV4.ip.v4.b[0], m->AdvertisedV4.ip.v4.b[1], m->AdvertisedV4.ip.v4.b[2], m->AdvertisedV4.ip.v4.b[3]); + + // build the message + mDNSPlatformMemZero(propArgs, sizeof(propArgs)); + propArgs[0].name = "NewRemoteHost"; + propArgs[0].type = "string"; + propArgs[0].value = ""; + propArgs[1].name = "NewExternalPort"; + propArgs[1].type = "ui2"; + propArgs[1].value = externalPort; + propArgs[2].name = "NewProtocol"; + propArgs[2].type = "string"; + propArgs[2].value = (n->Protocol == NATOp_MapUDP) ? "UDP" : "TCP"; + propArgs[3].name = "NewInternalPort"; + propArgs[3].type = "ui2"; + propArgs[3].value = internalPort; + propArgs[4].name = "NewInternalClient"; + propArgs[4].type = "string"; + propArgs[4].value = localIPAddrString; + propArgs[5].name = "NewEnabled"; + propArgs[5].type = "boolean"; + propArgs[5].value = "1"; + propArgs[6].name = "NewPortMappingDescription"; + propArgs[6].type = "string"; + propArgs[6].value = publicPortString; + propArgs[7].name = "NewLeaseDuration"; + propArgs[7].type = "ui4"; + propArgs[7].value = "0"; + + LogOperation("SendPortMapRequest: internal %u external %u", mDNSVal16(n->IntPort), ReqPortNum); + return SendSOAPMsgControlAction(m, &n->tcpInfo, "AddPortMapping", 8, propArgs, LNTPortMapOp); + } + +mDNSexport mStatus LNT_MapPort(mDNS *m, NATTraversalInfo *n) + { + LogOperation("LNT_MapPort"); + if (n->tcpInfo.sock) return(mStatus_NoError); // If we already have a connection up don't make another request for the same thing + n->tcpInfo.parentNATInfo = n; + n->tcpInfo.retries = 0; + return SendPortMapRequest(m, n); } - if (saHost == NULL) - memcpy(&saSendTo, &g_saddrRouterDesc, sizeof(saSendTo)); - else - memcpy(&saSendTo, saHost, sizeof(saSendTo)); - - iRet = connect(s, (struct sockaddr *) &saSendTo, sizeof(saSendTo)); - if ((iRet < 0) && (errno != EINPROGRESS)) { -//TracePrint(ELL_TRACE, "UPnP connect failed\n"); - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "SendTCPMsg/2part: connect failed (%d)\n", errno); - iRetcode = NA_E_NET; - goto cleanup; - } +mDNSexport mStatus LNT_UnmapPort(mDNS *m, NATTraversalInfo *n) + { + char externalPort[10]; + Property propArgs[3]; + tcpLNTInfo *info; + tcpLNTInfo **infoPtr = &m->tcpInfoUnmapList; + mStatus err; + + // If no NAT gateway to talk to, no need to do all this work for nothing + if (!m->UPnPSOAPURL || !m->UPnPSOAPAddressString) return mStatus_NoError; + + mDNS_snprintf(externalPort, sizeof(externalPort), "%u", mDNSVal16(mDNSIPPortIsZero(n->RequestedPort) ? n->IntPort : n->RequestedPort)); + + mDNSPlatformMemZero(propArgs, sizeof(propArgs)); + propArgs[0].name = "NewRemoteHost"; + propArgs[0].type = "string"; + propArgs[0].value = ""; + propArgs[1].name = "NewExternalPort"; + propArgs[1].type = "ui2"; + propArgs[1].value = externalPort; + propArgs[2].name = "NewProtocol"; + propArgs[2].type = "string"; + propArgs[2].value = (n->Protocol == NATOp_MapUDP) ? "UDP" : "TCP"; + + n->tcpInfo.parentNATInfo = n; + + // clean up previous port mapping requests and allocations + if (n->tcpInfo.sock) LogOperation("LNT_UnmapPort: closing previous open connection"); + if (n->tcpInfo.sock ) { mDNSPlatformTCPCloseConnection(n->tcpInfo.sock); n->tcpInfo.sock = mDNSNULL; } + if (n->tcpInfo.Request) { mDNSPlatformMemFree(n->tcpInfo.Request); n->tcpInfo.Request = mDNSNULL; } + if (n->tcpInfo.Reply ) { mDNSPlatformMemFree(n->tcpInfo.Reply); n->tcpInfo.Reply = mDNSNULL; } + + // make a copy of the tcpInfo that we can clean up later (the one passed in will be destroyed by the client as soon as this returns) + if ((info = mDNSPlatformMemAllocate(sizeof(tcpLNTInfo))) == mDNSNULL) + { LogOperation("LNT_UnmapPort: can't allocate tcpInfo"); return(mStatus_NoMemoryErr); } + *info = n->tcpInfo; + + while (*infoPtr) infoPtr = &(*infoPtr)->next; // find the end of the list + *infoPtr = info; // append - if (g_fLogging & NALOG_INFO1) - fprintf(g_log, - "- Before Sending TCP Msg1: %d == %lu?\n", iLen, strlen(msg)); - if (g_fLogging & NALOG_DUMP) - fprintf(g_log, "Sending TCP msg part 1:\n[%s]\n", msg); - - tv.tv_sec = g_iFunctionTimeout / UPNP_TIMEOUT_GRANULARITY; - tv.tv_usec = (g_iFunctionTimeout % U_TOGRAN) * 1000000 / U_TOGRAN; - FD_ZERO(&writefds); - FD_SET(s, &writefds); - iRet = select(s+1, 0, &writefds, 0, &tv); - if (iRet < 0) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "SendTCPMsg/2part: select failed (%d)\n", errno); - iRetcode = NA_E_NET; - goto cleanup; - } - if (iRet == 0) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "SendTCPMsg/2part: select timed out\n"); - iRetcode = NA_E_TIMEOUT; -gettimeofday(&tv_end, NULL); -GetTimeElapsed(&tv_start, &tv_end, &tv_elapsed); -//TracePrint(ELL_TRACE, "UPnP 2part: timeout @1st after %lu.%06lu secs\n", -// tv_elapsed.tv_sec, tv_elapsed.tv_usec); - goto cleanup; + err = SendSOAPMsgControlAction(m, info, "DeletePortMapping", 3, propArgs, LNTPortMapDeleteOp); + if (err) DisposeInfoFromUnmapList(m, info); + return err; } - iRet = send(s, msg, iLen, 0); - // sanity check - if (iRet != iLen) - if (g_fLogging & NALOG_ALERT) - fprintf(g_log, "SendTCPMsg/2part: iRet(%d) != strlen(msg)(%d)!\n", - iRet, iLen); - -//TracePrint(ELL_TRACE, "UPnP 2part: 1st %d == %d (%d) (%d)?\n", iRet, iLen, strlen(msg), errno); - - tv.tv_sec = g_iFunctionTimeout / UPNP_TIMEOUT_GRANULARITY; - tv.tv_usec = (g_iFunctionTimeout % U_TOGRAN) * 1000000 / U_TOGRAN; - FD_ZERO(&writefds); - FD_SET(s, &writefds); - // calculate how much time elapsed - gettimeofday(&tv_end, NULL); - GetTimeElapsed(&tv_start, &tv_end, &tv_elapsed); - if (CompareTime(&tv_elapsed, &tv) > 0) { - close(s); - return NA_E_TIMEOUT; - //tv.tv_sec = 0; - //tv.tv_usec = 0; - } - else { - // subtract that from timeout accordingly - tv.tv_sec -= tv_elapsed.tv_sec; - if (tv.tv_usec < tv_elapsed.tv_usec) { - tv.tv_sec--; - tv.tv_usec = 1000000 + tv.tv_usec - tv_elapsed.tv_usec; - } - else - tv.tv_usec = tv.tv_usec - tv_elapsed.tv_usec; - } - iRet = select(s+1, 0, &writefds, 0, &tv); - if (iRet < 0) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "SendTCPMsg/2part: select2 failed (%d)\n", errno); - iRetcode = NA_E_NET; - goto cleanup; - } - if (iRet == 0) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "SendTCPMsg/2part: select2 timed out\n"); - iRetcode = NA_E_TIMEOUT; -gettimeofday(&tv_end, NULL); -GetTimeElapsed(&tv_start, &tv_end, &tv_elapsed); -//TracePrint(ELL_TRACE, "UPnP 2part: timeout @2nd after %lu.%06lu secs\n", -// tv_elapsed.tv_sec, tv_elapsed.tv_usec); - goto cleanup; +mDNSexport mStatus LNT_GetExternalAddress(mDNS *m) + { + return SendSOAPMsgControlAction(m, &m->tcpAddrInfo, "GetExternalIPAddress", 0, mDNSNULL, LNTExternalAddrOp); } - iRet = send(s, msg2, iLen2, 0); - if (g_fLogging & NALOG_INFO1) - fprintf(g_log, - "SendTCPMsg/parse: Before Sending TCP Msg2: %d == %lu?\n", - iLen2, strlen(msg2)); - if (g_fLogging & NALOG_DUMP) - fprintf(g_log, "Sending TCP msg part 2:\n[%s]\n", msg2); - -//TracePrint(ELL_TRACE, "UPnP 2part: 2nd %d == %d (%d) (%d)?\n", iRet, iLen2, strlen(msg2), errno); - - // sanity check - if (iRet != iLen2) - if (g_fLogging & NALOG_ALERT) - fprintf(g_log, "SendTCPMsg/2part: iRet(%d) != strlen(msg2)(%d)!\n", - iRet, iLen2); - - if (result == NULL) { // if caller just want to send/display msgs - if (g_fLogging & NALOG_DUMP) - fprintf(g_log, "TCP Buffer: ["); - } +mDNSlocal mStatus GetDeviceDescription(mDNS *m, tcpLNTInfo *info) + { + // Device description format - + // - device description URL + // - host/port + static const char szSSDPMsgDescribeDeviceFMT[] = + "GET %s HTTP/1.1\r\n" + "Accept: text/xml, application/xml\r\n" + "User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n" + "Host: %s\r\n" + "Connection: close\r\n" + "\r\n"; + + if (m->UPnPRouterURL == mDNSNULL || m->UPnPRouterAddressString == mDNSNULL) { LogOperation("GetDeviceDescription: no router URL or address string!"); return (mStatus_Invalid); } + + // build message + if (info->Request != mDNSNULL) mDNSPlatformMemZero(info->Request, LNT_MAXBUFSIZE); // reuse previously allocated buffer + else if ((info->Request = (mDNSs8 *) mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogOperation("can't allocate send buffer for discovery"); return (mStatus_NoMemoryErr); } + info->requestLen = mDNS_snprintf((char *)info->Request, LNT_MAXBUFSIZE, szSSDPMsgDescribeDeviceFMT, m->UPnPRouterURL, m->UPnPRouterAddressString); + LogOperation("Describe Device: [%s]", info->Request); + return MakeTCPConnection(m, info, &m->Router, m->UPnPRouterPort, LNTDiscoveryOp); + } + +// This function parses the response to our SSDP discovery message. Basically, we look to make sure this is a response +// referencing a service we care about (WANIPConnection), then look for the "Location:" header and copy the addressing and +// URL info we need. +mDNSexport void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID InterfaceID, mDNSu8 *data, mDNSu16 len) + { + char *ptr = (char *)data; + char *end = (char *)data + len; - if (g_fLogging & NALOG_INFO1) - fprintf(g_log, "start recv @%lu\n", time(NULL)); - - iBufLen = 0; - iContentLength = -1; - iBodyOffset = -1; - for (;;) { - fd_set readfds; - struct timeval timeout; - int i; - - FD_ZERO(&readfds); - FD_SET(s, &readfds); - - // In testing, the Linksys Wireless-G Broadband Router "WRT54GS" takes - // up to four seconds to respond, and even then only a partial response, - // with the remainder coming in a second TCP segment half a second later. - // Accordingly, we wait up to five seconds for the initial data, and then after that - // wait one second after subsequent TCP segments, in care more data is still coming. - timeout.tv_sec = iBufLen ? 1 : 5; - timeout.tv_usec = 0; - iRet = select(s+1, &readfds, NULL, NULL, &timeout); - if (iRet <= 0) + // The formatting of the HTTP header is not always the same when it comes to the placement of + // the service and location strings, so we just look for each of them from the beginning for every response + + // figure out if this is a message from a service we care about + while (ptr && ptr != end) { -//TracePrint(ELL_TRACE, "UPnP 2part: select timeout? (%d, %d)\n", -// iRet, errno); - break; + if (*ptr == 'W' && (strncasecmp(ptr, "WANIPConnection:1", 17) == 0)) break; // find the first 'W'; is this WANIPConnection? if not, keep looking + ptr++; } + if (ptr == mDNSNULL || ptr == end) return; // not a message we care about -//gettimeofday(&tv_end, NULL); -//GetTimeElapsed(&tv_start, &tv_end, &tv_elapsed); -//fprintf(stderr, "2 == loop: %d.%06d\n", tv_elapsed.tv_sec, tv_elapsed.tv_usec); - - // if only sending messages - if (result == NULL) { - char t[1000]; - i = recv(s, t, 1000-1, 0); // leave room for '\0' for dump - if (i== 0) break; - if (g_fLogging & NALOG_DUMP) { - t[i] = '\0'; - fprintf(g_log, "%s", t); - } - continue; - } - - // EO result buf: discard extra bytes - if (resultSize <= iBufLen) { - char t[1000]; - i = recv(s, &t, 1000, 0); - if (i== 0) break; - // Note that there's no dump here - prevents DoS attack from - // flooding the logs/diskspace - continue; - } - - i = recv(s, result + iBufLen, resultSize - iBufLen, 0); - if (i <= 0) { -//TracePrint(ELL_TRACE, "UPnP 2part: recv done %d (%d, %d)\n", -// iBufLen, i, errno); - break; - } - - iBufLen += i; - - // parse and see if we can find content-length to quit early - iContentLength = FindContentLength(result, iBufLen); - - // now if we're still in header, see if we can find body - iBodyOffset = FindBody(result, iBufLen); - - // now check if we can leave early. conditions are: - // past headers, and we've already recv'ed content-length of body - if ((iBodyOffset >= 0) && - (iContentLength >= 0) && - ((iBufLen - iBodyOffset) >= iContentLength)) + // find "Location:", starting from the beginning + ptr = (char *)data; + while (ptr && ptr != end) { -//TracePrint(ELL_TRACE, "UPnP 2part: read all specified %d (%d, %d) (%d, %d)\n", -// iBufLen, i, errno, iBodyOffset, iContentLength); - break; - } - } - -//fprintf(stderr, "2 -- \n"); - - if (g_fLogging & NALOG_INFO1) - fprintf(g_log, "SendTCPMsg_saddr_2part done recv %d @ %lu\n", iBufLen, time(NULL)); - - if (result == NULL) { // if caller just want to send/display msgs - if (g_fLogging & NALOG_DUMP) - fprintf(g_log, "]\n"); - } - - close(s); - return iBufLen; - -cleanup: - close(s); - return iRetcode; -} - -static int SendTCPMsg_saddr_parse( - char *msg, int iLen, - char *result, int resultSize, - struct sockaddr_in *saHost) -{ - int s; - struct sockaddr_in saSendTo; - int iRet; - int iBufLen; - int fcntl_flags; - fd_set writefds; - struct timeval tv; - - struct timeval tv_start; -// struct timeval tv_end; -// struct timeval tv_elapsed; - - // HTTP parsing vars - char *pszCurHdr; - int iContentLength; - int iBodyOffset; -// char prevChar; - - tv.tv_sec = 0; - tv.tv_usec = 25000; - select(0, NULL, NULL, NULL, &tv); - - pthread_mutex_lock(&g_xUPnPMsg); - - gettimeofday(&tv_start, NULL); - - if (g_fUPnPEnabled != TRUE) { -//TracePrint(ELL_TRACE, "UPnP not enabled\n"); - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "UPnP not enabled (no UPnP device found yet)\n"); - pthread_mutex_unlock(&g_xUPnPMsg); - return NA_E_NOT_AVAILABLE; - } - - s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (s == -1) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "Can't get TCP socket (%d)\n", errno); - pthread_mutex_unlock(&g_xUPnPMsg); - return NA_E_NET; - } - - fcntl_flags = 0; - fcntl_flags = fcntl(s, F_GETFL, 0); - fcntl_flags |= O_NONBLOCK; - if (fcntl(s, F_SETFL, fcntl_flags) != 0) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "SendTCPMsg/parse: Can't set O_NONBLOCK option!\n"); - close(s); - pthread_mutex_unlock(&g_xUPnPMsg); - return NA_E_NET; - } - - if (saHost == NULL) - memcpy(&saSendTo, &g_saddrRouterDesc, sizeof(saSendTo)); - else - memcpy(&saSendTo, saHost, sizeof(saSendTo)); - - iRet = connect(s, (struct sockaddr *) &saSendTo, sizeof(saSendTo)); - if ((iRet < 0) && (errno != EINPROGRESS)) { -//TracePrint(ELL_TRACE, "UPnP connect failed\n"); - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "SendTCPMsg/parse: connect failed (%d)\n", errno); - close(s); - pthread_mutex_unlock(&g_xUPnPMsg); - return NA_E_NET; - } - - if (g_fLogging & NALOG_INFO1) - fprintf(g_log, "SendTCPMsg_saddr_parse: Before Sending TCP Msg: %d == %lu?\n", - iLen, strlen(msg)); - if (g_fLogging & NALOG_DUMP) - fprintf(g_log,"Sending TCP msg:\n[%s]\n", msg); - - tv.tv_sec = g_iFunctionTimeout / UPNP_TIMEOUT_GRANULARITY; - tv.tv_usec = (g_iFunctionTimeout % U_TOGRAN) * 1000000 / U_TOGRAN; - FD_ZERO(&writefds); - FD_SET(s, &writefds); - iRet = select(s+1, 0, &writefds, 0, &tv); - if (iRet < 0) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "SendTCPMsg/parse: select failed (%d)\n", errno); - close(s); - pthread_mutex_unlock(&g_xUPnPMsg); - return NA_E_NET; - } - if (iRet == 0) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "SendTCPMsg/parse: select timed out\n"); - close(s); - pthread_mutex_unlock(&g_xUPnPMsg); - return NA_E_TIMEOUT; - } - - iRet = send(s, msg, iLen, 0); - - // sanity check - if (iRet != iLen) - if (g_fLogging & NALOG_ALERT) - fprintf(g_log, "SendTCPMsg: iRet (%d) != strlen(msg) (%d)!\n", - iRet, iLen); - - if (result == NULL) { // if caller just want to send/display msgs - if (g_fLogging & NALOG_DUMP) - fprintf(g_log, "TCP Buffer: ["); - } - - if (g_fLogging & NALOG_INFO1) - fprintf(g_log, "start recv @%lu\n", time(NULL)); - - iBufLen = 0; - pszCurHdr = result; - iContentLength = -1; - iBodyOffset = -1; - for (;;) { - fd_set readfds; - struct timeval timeout; - int i; - - FD_ZERO(&readfds); - FD_SET(s, &readfds); - - // In testing, the Linksys Wireless-G Broadband Router "WRT54GS" takes - // up to four seconds to respond, and even then only a partial response, - // with the remainder coming in a second TCP segment half a second later. - // Accordingly, we wait up to five seconds for the initial data, and then after that - // wait one second after subsequent TCP segments, in care more data is still coming. - timeout.tv_sec = iBufLen ? 1 : 5; - timeout.tv_usec = 0; - iRet = select(s+1, &readfds, NULL, NULL, &timeout); - if (iRet <= 0) { -//fprintf(stderr, "**********: select failed (%d/%d)\n", iRet, errno); - break; - } - -//gettimeofday(&tv_end, NULL); -//GetTimeElapsed(&tv_start, &tv_end, &tv_elapsed); -//fprintf(stderr, "p == loop: %d.%06d\n", tv_elapsed.tv_sec, tv_elapsed.tv_usec); - - // if only sending messages - if (result == NULL) { - char t[1000]; - i = recv(s, t, 1000-1, 0); // leave room for '\0' for dump - if (i== 0) break; - if (g_fLogging & NALOG_DUMP) { - t[i] = '\0'; - fprintf(g_log, "%s", t); - } - continue; - } - - // EO result buf: discard extra bytes - if (resultSize <= iBufLen) { - char t[1000]; - i = recv(s, &t, 1000, 0); - if (g_fLogging & NALOG_INFO1) - fprintf(g_log, "SendTCPMsg_saddr_parse discarding %d bytes\n", i); - if (i== 0) break; - // Note that there's no dump here - prevents DoS attack from - // flooding the logs/diskspace - continue; - } - - i = recv(s, result + iBufLen, resultSize - iBufLen, 0); - if (g_fLogging & NALOG_INFO1) - fprintf(g_log, "SendTCPMsg_saddr_parse read %d bytes (%d/%d)\n", i, iBufLen, resultSize); - if (0 == i) { - - break; - } - else if (i < 0) { - if (EAGAIN == errno) continue; - break; - } - - iBufLen += i; - - // parse and see if we can find content-length to quit early - iContentLength = FindContentLength(result, iBufLen); - - // now if we're still in header, see if we can find body - iBodyOffset = FindBody(result, iBufLen); - - } - -//fprintf(stderr, "p -- \n"); - - if (g_fLogging & NALOG_INFO1) - fprintf(g_log, "SendTCPMsg_saddr_parse done recv %d @ %lu\n", iBufLen, time(NULL)); - - if (result == NULL) { // if caller just want to send/display msgs - if (g_fLogging & NALOG_DUMP) - fprintf(g_log, "]\n"); - } - - close(s); - pthread_mutex_unlock(&g_xUPnPMsg); - return iBufLen; -} - - - -// szSOAPMsgControlAHeaderFMT - 4 args (ctrl_url, host/port, action, length) -// szSOAPMsgControlABodyFMT - 2 args (action, args string) -// szSOAPMsgControlAArgumentFMT - 2 args (name/value) -static PHTTPResponse SendSOAPMsgControlAction( - char *action, - int argc, - PProperty args, - int f2Part) -{ - //char outBuffer[65536]; - //char outBufferBody[65536]; - //char outBufferArgs[65536]; - char *outBuffer = NULL; - char *outBufferBody = NULL; - char *outBufferArgs = NULL; - char *inBuffer = NULL; - int iLen; - int iHeaderLen; - int iBodyLen; - int iArgsLen; - int iResultLen; - int i; - int n; - PHTTPResponse pResponse = NULL; - - - if (!WaitUPnPFunction()) - return NULL; - - if ((outBuffer = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "can't malloc for outBuffer\n"); - goto cleanup; - } - if ((outBufferBody = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "can't malloc for outBufferBody\n"); - goto cleanup; - } - if ((outBufferArgs = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "can't malloc for outBufferArgs\n"); - goto cleanup; - } - if ((inBuffer = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "can't malloc for inBuffer\n"); - goto cleanup; - } - - iArgsLen = 0; - if (args != NULL) - for (i=0; i 0) { - if (iResultLen > MAX_SOAPMSGSIZE) { - if (g_fLogging & NALOG_ALERT) - fprintf(g_log, "result truncated..\n"); - iResultLen = MAX_SOAPMSGSIZE; - } - pResponse = NewHTTPResponse_sz(inBuffer, iResultLen, FALSE); - if (pResponse != NULL) { - PrintHTTPResponse(pResponse); - //DeleteHTTPResponse(pResponse); - // - return response to caller - } - } - else { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "No TCP Response\n"); - //TracePrint(ELL_TRACE, "UPnP SendSOAPMsg got no TCP response (%d)\n", -// iResultLen); - } - -cleanup: - if (outBuffer != NULL) free(outBuffer); - if (outBufferBody != NULL) free(outBufferBody); - if (outBufferArgs != NULL) free(outBufferArgs); - if (inBuffer != NULL) free(inBuffer); - - return pResponse; -} - -static int FindURLBase(char *pbuf, int iLen, char *szURLBase) -{ - // non reusable XML parsing code: - // ---------------------------------------------- - char *p; - int i = 0; - - // now skip after end of this tag, then skip until controlURL tag - p = strstr_n(pbuf, "", iLen); - if (p == NULL) return -1; - - // skip to the actual stuff - p += sizeof("") - 1; // minus '\0' - - // skip white spaces (just in case) - while (isspace(*p)) - p++; - - // copy into szURLBase - while ((*p != '\0') && (*p != '<') && !isspace(*p)) { - if (i++ > 1000) break; - *szURLBase = *p; - szURLBase++; - p++; - } - *szURLBase = '\0'; - - return 0; - // ---------------------------------------------- -} - - -static int FindDescInfo( - char *pbuf, - int iLen, - const char *szParentName, - const char *szName, - char *szValue) -{ - char *p; - char szSearch[100]; - int iSearchLen; - int i = 0; - - // find the device within pbuf - p = strstr_n( - pbuf, - szParentName, - iLen); - if (p == NULL) - return -1; - - // adjust strlen - iLen -= (p - pbuf); - pbuf = p; - - // now skip after end of this tag, then skip until manufacturer tag - iSearchLen = snprintf(szSearch, sizeof(szSearch), "<%s>", szName); - p = strstr_n(pbuf, szSearch, iLen); - if (p == NULL) return -1; - p += iSearchLen; - - // skip white spaces (just in case) - while (isspace(*p)) - p++; - - // copy into szValue - while ((*p != '\0') && (*p != '<')) { - if (i++ > 1000) break; - *szValue = *p; - szValue++; - p++; - } - *szValue = '\0'; - - return 0; -} - -static int FindIGDInfo(char *pbuf, int iLen, const char *szName, char *szValue) -{ - return FindDescInfo( - pbuf, iLen, - "urn:schemas-upnp-org:device:InternetGatewayDevice:1", - szName, szValue); -} - -static int FindManufacturer(char *pbuf, int iLen, char *szManuf) -{ - return FindIGDInfo(pbuf, iLen, "manufacturer", szManuf); -} - -static int FindFriendlyName(char *pbuf, int iLen, char *szValue) -{ - return FindIGDInfo(pbuf, iLen, "friendlyName", szValue); -} - -static int FindModelName(char *pbuf, int iLen, char *szValue) -{ - return FindIGDInfo(pbuf, iLen, "modelName", szValue); -} - -static int FindModelDescription(char *pbuf, int iLen, char *szValue) -{ - return FindIGDInfo(pbuf, iLen, "modelDescription", szValue); -} - -static int FindWANIPInfo(char *pbuf, int iLen, const char *szName, char *szValue) -{ - return FindDescInfo( - pbuf, iLen, - "urn:schemas-upnp-org:service:WANIPConnection:1", - szName, szValue); -} - -static int FindControlURL(char *pbuf, int iLen, char *szControlURL) -{ - return FindWANIPInfo(pbuf, iLen, "controlURL", szControlURL); -} - -static int FindEventURL(char *pbuf, int iLen, char *szEventURL) -{ - return FindWANIPInfo(pbuf, iLen, "eventSubURL", szEventURL); -} - -static int FindRouterInfo(char *inBuffer, int iLen) -{ - if (FindManufacturer(inBuffer, iLen, g_szManufacturer) != 0) - g_szManufacturer[0] = '\0'; - - if (FindFriendlyName(inBuffer, iLen, g_szFriendlyName) != 0) - g_szFriendlyName[0] = '\0'; - - if (FindModelName(inBuffer, iLen, g_szModelName) != 0) - g_szModelName[0] = '\0'; - - if (FindModelDescription(inBuffer, iLen, g_szModelDescription) != 0) - g_szModelDescription[0] = '\0'; - -//TracePrint(ELL_TRACE, -// "UPnP Router Info:\n" -// " - manufacturer [%s]\n" -// " - friendly name [%s]\n" -// " - model name [%s]\n" -// " - model desc [%s]\n", -// g_szManufacturer, g_szFriendlyName, g_szModelName, g_szModelDescription); - - return 0; -} - -static void ParseURL( - const char *szBuf, - char *pszHostPort, int pszHostPort_size, - struct sockaddr_in *psaddr, - char *pszPath, int pszPath_size) -{ - char buf[1024]; - char *p; - char *q; - unsigned short port; - - strlcpy(buf, szBuf, sizeof(buf)); - - p = buf; - if (0 == strncmp(p, "http://", 7)) - p += 7; - - q = strchr(p, '/'); - - if (pszPath) { - if (NULL == q) { - pszPath[0] = '/'; - pszPath[1] = '\0'; - } - else { - strlcpy(pszPath, q, pszPath_size); - *q = '\0'; + if (*ptr == 'L' && (strncasecmp(ptr, "Location", 8) == 0)) break; // find the first 'L'; is this Location? if not, keep looking + ptr++; } - } - - // find the port separetor - q = strchr(p, ':'); - if (NULL == q) - port = 80; - else { - port = atoi(q + 1); - // HTTP's by default port 80, so don't have it in the "Host:" header - if (80 == port) *q = '\0'; - } - - if (pszHostPort) strlcpy(pszHostPort, p, pszHostPort_size); - - if (NULL != q) *q = '\0'; - - if (NULL != psaddr) { - psaddr->sin_family = AF_INET; - psaddr->sin_addr.s_addr = inet_addr(p); - psaddr->sin_port = htons(port); - } -#if 0 -//TracePrint(ELL_TRACE, "ParseURL [%s] -> [%s][%s] %lu.%lu.%lu.%lu:%u\n", - szBuf, - pszHostPort?pszHostPort:"", - pszPath?pszPath:"", - ((uint8_t*)&psaddr->sin_addr.s_addr)[0], ((uint8_t*)&psaddr->sin_addr.s_addr)[1], - ((uint8_t*)&psaddr->sin_addr.s_addr)[2], ((uint8_t*)&psaddr->sin_addr.s_addr)[3], - psaddr->sin_port); -#endif -} - -static void GetDeviceDescription(void) -{ - char *outBuffer = NULL; - char *inBuffer = NULL; - int iBufLen; - int iLen; - char szURLBase[1024]; - char szControlURL[1024]; - char szEventURL[1024]; - - if (!g_fUPnPEnabled) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "GetDeviceDescription: upnp not enabled\n"); - return; - } - - if ((outBuffer = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "can't malloc for outBuffer\n"); - goto cleanup; - } - if ((inBuffer = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "can't malloc for inBuffer\n"); - goto cleanup; - } - - iBufLen = snprintf(outBuffer, MAX_SOAPMSGSIZE, szSSDPMsgDescribeDeviceFMT, g_szNATDevDescURL, - g_szRouterHostPortDesc); - - if (g_fLogging & NALOG_INFO1) - fprintf(g_log, "Describe Device: [%s]\n", outBuffer); - iLen = SendTCPMsg_saddr_parse(outBuffer, iBufLen, inBuffer, MAX_SOAPMSGSIZE, - &g_saddrRouterDesc); - - if (iLen < 1) goto cleanup; - - g_fControlURLSet = FALSE; - - if (FindControlURL(inBuffer, iLen, szControlURL) != 0) { - if (g_fLogging & NALOG_ERROR) - fprintf(g_log, "GetDeviceDesc: can't find control URL\n"); - goto cleanup; - } - - // start modifying global - pthread_mutex_lock(&g_xUPnP); - - { - // now see if there's the URLBase - if (FindURLBase(inBuffer, iLen, szURLBase) != 0) { - // not there? try default numbers from device description - memcpy(&g_saddrRouterBase, &g_saddrRouterDesc, - sizeof(g_saddrRouterBase)); - strlcpy(g_szRouterHostPortBase, g_szRouterHostPortDesc, sizeof(g_szRouterHostPortBase)); - } - else { - ParseURL(szURLBase, - g_szRouterHostPortBase, sizeof(g_szRouterHostPortBase), - &g_saddrRouterBase, NULL, 0); - - if ((strlen(g_szRouterHostPortBase) == 0) || - (g_saddrRouterBase.sin_addr.s_addr == INADDR_NONE)) { - memcpy(&g_saddrRouterBase, &g_saddrRouterDesc, - sizeof(g_saddrRouterBase)); - strlcpy(g_szRouterHostPortBase, g_szRouterHostPortDesc, sizeof(g_szRouterHostPortBase)); - } - } - } - - ParseURL(szControlURL, - g_szRouterHostPortSOAP, sizeof(g_szRouterHostPortSOAP), &g_saddrRouterSOAP, g_szControlURL, sizeof(g_szControlURL)); - if ((strlen(g_szRouterHostPortSOAP) == 0) || - (g_saddrRouterSOAP.sin_addr.s_addr == INADDR_NONE)) { - memcpy(&g_saddrRouterSOAP, &g_saddrRouterBase, - sizeof(g_saddrRouterSOAP)); - strlcpy(g_szRouterHostPortSOAP, g_szRouterHostPortBase, sizeof(g_szRouterHostPortSOAP)); - } - - -////TracePrint(ELL_TRACE, "UPnP Control URL set to[%s][%s]...\n", -// g_szRouterHostPortSOAP, g_szControlURL); - - g_fControlURLSet = TRUE; - gettimeofday(&g_tvLastUpdateTime, NULL); - pthread_cond_broadcast(&g_condUPnPControlURL); - - if (g_fLogging & NALOG_INFO1) - fprintf(g_log, "Got Device Description\n"); - - // find router info - FindRouterInfo(inBuffer, iLen); - - if (FindEventURL(inBuffer, iLen, szEventURL) != 0) { - szEventURL[0] = '\0'; - } - else { - ParseURL(szEventURL, - g_szRouterHostPortEvent, sizeof(g_szRouterHostPortEvent), &g_saddrRouterEvent, g_szEventURL, sizeof(g_szEventURL)); - if ((strlen(g_szRouterHostPortEvent) == 0) || - (g_saddrRouterEvent.sin_addr.s_addr == INADDR_NONE)) { - memcpy(&g_saddrRouterEvent, &g_saddrRouterBase, - sizeof(g_saddrRouterEvent)); - strlcpy(g_szRouterHostPortEvent, g_szRouterHostPortBase, sizeof(g_szRouterHostPortEvent)); - } - - EventInit(); - } - - pthread_mutex_unlock(&g_xUPnP); - -cleanup: - if (outBuffer != NULL) free(outBuffer); - if (inBuffer != NULL) free(inBuffer); -} - - -static void GetIPByName(char *hostname, unsigned long *ip_ret) -{ - unsigned long ip; - - ip = inet_addr(hostname); - if (ip == INADDR_NONE) { - struct hostent *pHEnt; - pHEnt = gethostbyname(hostname); - if (pHEnt == NULL) { - if (g_fLogging & NALOG_ALERT) - fprintf(g_log, "Can't translate [%s] to IP...\n", hostname); - g_dwLocalIP = INADDR_ANY; - return; - } - ip = *(unsigned long *)(pHEnt->h_addr); - if (g_fLogging & NALOG_INFO1) - fprintf(g_log, "hostname [%s] to ip: %u.%u.%u.%u\n", hostname, - ((uint8_t*)&ip)[0], ((uint8_t*)&ip)[1], ((uint8_t*)&ip)[2], ((uint8_t*)&ip)[3]); - } - *ip_ret = ip; -} - -static void SetLocalIP() -{ - PIPINFO pIPInfo = NULL; - int count = GetIPInfo(&pIPInfo); - if (NULL != pIPInfo) - { - // choose first non IPV6 address - // iterate through array and set port information - int i; - unsigned long dwFirst = 0; - for(i = 0; i < count; i++) + if (ptr == mDNSNULL || ptr == end) return; // not a message we care about + + // find "http://", starting from where we left off + while (ptr && ptr != end) { - if (!(pIPInfo[i].iFlags & ISIPV6) && - (strncmp(pIPInfo[i].szIfName, "ppp", 3) != 0)) + if (*ptr == 'h' && (strncasecmp(ptr, "http://", 7) == 0)) // find the first 'h'; is this a URL? if not, keep looking { - unsigned long dwTemp; - - memcpy(&dwTemp, pIPInfo[i].abIP, sizeof(unsigned long)); - - if (0 != GetNATIPNetmask(dwTemp)) { - g_dwLocalIP = dwTemp; - break; - } - - if (0 == dwFirst) - dwFirst = dwTemp; + int i; + char *addrPtr = mDNSNULL; + + ptr += 7; //skip over "http://" + if (ptr >= end) { LogOperation("LNT_ConfigureRouterInfo: past end of buffer and no URL!"); return; } + addrPtr = ptr; + for (i = 0; addrPtr && addrPtr != end; i++, addrPtr++) if (*addrPtr == '/') break; // first find the beginning of the URL and count the chars + if (addrPtr == mDNSNULL || addrPtr == end) return; // not a valid message + + // allocate the buffer (len i+1 so we have space to terminate the string) + if (m->UPnPRouterAddressString != mDNSNULL) mDNSPlatformMemFree(m->UPnPRouterAddressString); + if ((m->UPnPRouterAddressString = (mDNSu8 *) mDNSPlatformMemAllocate(i+1)) == mDNSNULL) { LogMsg("can't mDNSPlatformMemAllocate router address string"); return; } + + strncpy((char *)m->UPnPRouterAddressString, ptr, i); // copy the address string + m->UPnPRouterAddressString[i] = '\0'; // terminate the string + LogOperation("LNT_ConfigureRouterInfo: router address string [%s]", m->UPnPRouterAddressString); + break; } + ptr++; // continue } - if (i == count) - g_dwLocalIP = dwFirst; - FreeIPInfo(pIPInfo); - } - -} - -static int FindTagContent(const char *text, const char *tagname, char *buf) -{ - char *p; - // parse the xml - p = strstr(text, tagname); - if (p == NULL) { - if (g_fLogging & NALOG_INFO0) - fprintf(g_log, "FindTagContent: can't find %s\n", tagname); - return NA_E_PARSE_ERROR; - } - - if (sscanf(p, "%*[^>]> %[^ <] <", buf) < 1) { - if (g_fLogging & NALOG_INFO0) - fprintf(g_log, "FindTagContent: Can't parse tag %s\n", tagname); - return NA_E_PARSE_ERROR; - } - - return NA_E_SUCCESS; -} - -mStatus LNT_UnmapPort(mDNSIPPort PubPort, mDNSBool tcp) -{ - //int iLen; - char szEPort[10]; - //char szRemoteHost[1024]; - //unsigned long dwIP; - Property propArgs[3]; - PHTTPResponse resp; - int protocol = tcp ? IPPROTO_TCP : IPPROTO_UDP; - snprintf(szEPort, sizeof(szEPort), "%u", mDNSVal16(PubPort)); - - bzero(propArgs, sizeof(propArgs)); - propArgs[0].pszName = "NewRemoteHost"; - propArgs[0].pszValue = ""; - propArgs[0].pszType = "string"; - propArgs[1].pszName = "NewExternalPort"; - propArgs[1].pszValue = szEPort; - propArgs[1].pszType = "ui2"; - propArgs[2].pszName = "NewProtocol"; - if (protocol == IPPROTO_TCP) { - propArgs[2].pszValue = "TCP"; - } - else if (protocol == IPPROTO_UDP) { - propArgs[2].pszValue = "UDP"; - } - else { - return -1; - } - propArgs[2].pszType = "string"; - - resp = SendSOAPMsgControlAction( - "DeletePortMapping", 3, propArgs, FALSE); - if (resp == NULL) { - return mStatus_NATTraversal; - } - - if (strcmp(resp->pszStatus, "200") != 0) { - DeleteHTTPResponse(resp); - return mStatus_NATTraversal; - } - - DeleteHTTPResponse(resp); - return mStatus_NoError; -} - - -static int GetMappingUnused(unsigned short eport, int protocol); - -extern mStatus LNT_MapPort(mDNSIPPort priv, mDNSIPPort pub, mDNSBool tcp) -{ - char szEPort[6]; - char szIPort[6]; - unsigned long dwIP; - char szLocalIP[30]; - char descr[40]; - Property propArgs[8]; - PHTTPResponse resp; - int protocol = tcp ? IPPROTO_TCP : IPPROTO_UDP; - - if (NA_E_EXISTS == GetMappingUnused(mDNSVal16(pub), protocol)) - return mStatus_AlreadyRegistered; - - //DeletePortMapping(eport, protocol); - - snprintf(szEPort, sizeof(szEPort), "%u", mDNSVal16(pub)); - snprintf(szIPort, sizeof(szIPort), "%u", mDNSVal16(priv)); - - dwIP = g_dwLocalIP; - snprintf(szLocalIP, sizeof(szLocalIP), "%u.%u.%u.%u", - ((uint8_t*)&dwIP)[0], ((uint8_t*)&dwIP)[1], ((uint8_t*)&dwIP)[2], ((uint8_t*)&dwIP)[3]); - - bzero(propArgs, sizeof(propArgs)); - propArgs[0].pszName = "NewRemoteHost"; - propArgs[0].pszValue = ""; - propArgs[0].pszType = "string"; - propArgs[1].pszName = "NewExternalPort"; - propArgs[1].pszValue = szEPort; - propArgs[1].pszType = "ui2"; - propArgs[2].pszName = "NewProtocol"; - if (protocol == IPPROTO_TCP) { - propArgs[2].pszValue = "TCP"; - } - else if (protocol == IPPROTO_UDP) { - propArgs[2].pszValue = "UDP"; - } - else { - return mStatus_BadParamErr; - } - propArgs[2].pszType = "string"; - propArgs[3].pszName = "NewInternalPort"; - propArgs[3].pszValue = szIPort; - propArgs[3].pszType = "ui2"; - propArgs[4].pszName = "NewInternalClient"; - propArgs[4].pszValue = szLocalIP; - propArgs[4].pszType = "string"; - propArgs[5].pszName = "NewEnabled"; - propArgs[5].pszValue = "1"; - propArgs[5].pszType = "boolean"; - propArgs[6].pszName = "NewPortMappingDescription"; - snprintf(descr, sizeof(descr), "iC%u", mDNSVal16(pub)); - //propArgs[6].pszValue = "V"; - propArgs[6].pszValue = descr; - propArgs[6].pszType = "string"; - propArgs[7].pszName = "NewLeaseDuration"; - propArgs[7].pszValue = "0"; - propArgs[7].pszType = "ui4"; - - if (g_fLogging & NALOG_INFO1) - fprintf(g_log, "Sending AddPortMapping priv %u pub %u\n", mDNSVal16(priv), mDNSVal16(pub)); - - resp = SendSOAPMsgControlAction( - "AddPortMapping", 8, propArgs, FALSE); - - if (g_fLogging & NALOG_INFO1) - fprintf(g_log, "AddPortMapping resp %p\n", resp); - - if (resp == NULL) { - return mStatus_NATTraversal; - } - - if (strcmp(resp->pszStatus, "200") != 0) { - DeleteHTTPResponse(resp); - return mStatus_NATTraversal; - } - - DeleteHTTPResponse(resp); - return mStatus_NoError; -} - -static int GetMappingUnused(unsigned short eport, int protocol) -{ - char buf[1024]; - char szPort[10]; - Property propArgs[3]; - PHTTPResponse resp; - unsigned long ip = 0; - - snprintf(szPort, sizeof(szPort), "%u", eport); - - bzero(&propArgs, sizeof(propArgs)); - propArgs[0].pszName = "NewRemoteHost"; - propArgs[0].pszValue = ""; - propArgs[0].pszType = "string"; - propArgs[1].pszName = "NewExternalPort"; - propArgs[1].pszValue = szPort; - propArgs[1].pszType = "ui2"; - propArgs[2].pszName = "NewProtocol"; - if (protocol == IPPROTO_TCP) { - propArgs[2].pszValue = "TCP"; - } - else if (protocol == IPPROTO_UDP) { - propArgs[2].pszValue = "UDP"; - } - else { - return NA_E_INVALID_PARAMETER; - } - propArgs[2].pszType = "string"; - resp = SendSOAPMsgControlAction( - "GetSpecificPortMappingEntry", 3, propArgs, FALSE); - if (resp != NULL) { - if ((strcmp(resp->pszStatus, "200") == 0) && - (FindTagContent(resp->pszBody, "NewInternalClient", buf) == 0)) + // find port and router URL, starting after the "http://" if it was there + while (ptr && ptr != end) { - GetIPByName(buf, &ip); - if (ip == g_dwLocalIP) { - // (perhaps we let it go?) - DeleteHTTPResponse(resp); - return NA_E_SUCCESS; + if (*ptr == ':') // found the port number + { + int port; + ptr++; // skip over ':' + if (ptr == end) { LogOperation("LNT_ConfigureRouterInfo: reached end of buffer and no address!"); return; } + port = (int)strtol(ptr, (char **)mDNSNULL, 10); // get the port + m->UPnPRouterPort = mDNSOpaque16fromIntVal(port); // store it properly converted } - else { - DeleteHTTPResponse(resp); - return NA_E_EXISTS; + else if (*ptr == '/') // found router URL + { + int j; + char *urlPtr; + m->UPnPInterfaceID = InterfaceID; + if (mDNSIPPortIsZero(m->UPnPRouterPort)) m->UPnPRouterPort = mDNSOpaque16fromIntVal(80); // fill in default port if we didn't find one before + + urlPtr = ptr; + for (j = 0; urlPtr && urlPtr != end; j++, urlPtr++) if (*urlPtr == '\r') break; // first find the end of the line and count the chars + if (urlPtr == mDNSNULL || urlPtr == end) return; // not a valid message + + // allocate the buffer (len j+1 so we have space to terminate the string) + if (m->UPnPRouterURL != mDNSNULL) mDNSPlatformMemFree(m->UPnPRouterURL); + if ((m->UPnPRouterURL = (mDNSu8 *) mDNSPlatformMemAllocate(j+1)) == mDNSNULL) { LogMsg("can't allocate router URL"); return; } + + // now copy everything to the end of the line + strncpy((char *)m->UPnPRouterURL, ptr, j); // this URL looks something like "/dyndev/uuid:0013-108c-4b3f0000f3dc" + m->UPnPRouterURL[j] = '\0'; // terminate the string + break; // we've got everything we need, so get out here } + ptr++; // continue } - DeleteHTTPResponse(resp); - } - - return NA_E_SUCCESS; -} - -mStatus LNT_GetPublicIP(mDNSv4Addr *IpPtr) -{ - char buf[1024]; - PHTTPResponse resp; - static struct timeval tvLastGoodIP = {0,0}; - static unsigned long dwLastGoodIP; - struct timeval tv; - unsigned long *ip = (unsigned long *)IpPtr; - if (ip == NULL) return mStatus_BadParamErr; - - gettimeofday(&tv, NULL); - GetTimeElapsed(&tvLastGoodIP, &tv, &tv); - if (tv.tv_sec < 4) - { - return dwLastGoodIP; - } - - resp = SendSOAPMsgControlAction( - "GetExternalIPAddress", 0, NULL, FALSE); - - if (resp == NULL) - return mStatus_NATTraversal; - - if (FindTagContent(resp->pszBody, "NewExternalIPAddress", buf) == 0) { - if (g_fLogging & NALOG_INFO1) - fprintf(g_log, "Mapped remote host = %s\n", buf); - *ip = inet_addr(buf); - DeleteHTTPResponse(resp); - gettimeofday(&tvLastGoodIP, NULL); - dwLastGoodIP = *ip; + if (ptr == mDNSNULL || ptr == end) return; // not a valid message + LogOperation("Router port %d, URL set to [%s]...", mDNSVal16(m->UPnPRouterPort), m->UPnPRouterURL); - return mStatus_NoError; + // now send message to get the device description + GetDeviceDescription(m, &m->tcpDeviceInfo); } - DeleteHTTPResponse(resp); - return mStatus_NATTraversal; -} - -static void SendDiscoveryMsg() -{ - // do it twice to avoid lost packet - //SendUDPMsg(szSSDPMsgDiscoverNAT); - SendUDPMsg(szSSDPMsgDiscoverRoot); - SendUDPMsg(szSSDPMsgDiscoverIGD); - SendUDPMsg(szSSDPMsgDiscoverNAT); -} - -// Set up threads for upnp responses, etc. -int LegacyNATInit(void) -{ - //pthread_t UDPthread; - pthread_attr_t attr; - int iRet; - //struct timeval tv; - LogOperation("LegacyNATInit"); - - static int fFirstInitLocks = TRUE; - FILE *log = NULL; - - g_fLogging = 0; - //g_fLogging = ~0; // Turns ALL logging on - g_log = stderr; - - SetLocalIP(); - - g_fQuit = FALSE; - - if (fFirstInitLocks) +mDNSexport void LNT_SendDiscoveryMsg(mDNS *m) { - // init locks - if (pthread_mutex_init(&g_xUPnP, NULL)) { - if (g_fLogging & NALOG_ERROR) - fprintf(log, "UpnpInit - mutex init failed\n"); - return NA_E_INTERNAL_ERROR; - } - if (pthread_cond_init(&g_condUPnP, NULL)) { - pthread_mutex_destroy(&g_xUPnP); - if (g_fLogging & NALOG_ERROR) - fprintf(log, "UpnpInit - cond init failed\n"); - return NA_E_INTERNAL_ERROR; - } - if (pthread_cond_init(&g_condUPnPControlURL, NULL)) { - pthread_mutex_destroy(&g_xUPnP); - pthread_cond_destroy(&g_condUPnP); - if (g_fLogging & NALOG_ERROR) - fprintf(log, "UpnpInit - cond init failed\n"); - return NA_E_INTERNAL_ERROR; - } - if (pthread_mutex_init(&g_xUPnPMsg, NULL)) { - pthread_mutex_destroy(&g_xUPnP); - pthread_cond_destroy(&g_condUPnP); - pthread_cond_destroy(&g_condUPnPControlURL); - if (g_fLogging & NALOG_ERROR) - fprintf(log, "UpnpInit - mutex init failed\n"); - return NA_E_INTERNAL_ERROR; - } - - fFirstInitLocks = FALSE; - } - - if (g_fFirstInit) - { - // initialize UDP socket for SSDP - g_sUDP = SSDPListen(); - g_sUDPCancel = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // sock to signal canccelation to UDP thread - if (g_sUDP < 0 || g_sUDPCancel < 0) { - if (g_fLogging & NALOG_ERROR) - fprintf(log, "UpnpInit - Failed to init multicast socket.\n"); - return NA_E_INTERNAL_ERROR; - } - - // make UDP thread - pthread_attr_init(&attr); - iRet = pthread_create(&g_UDPthread, &attr, UDPProc, log); - if (iRet != 0) { - g_fFirstInit = TRUE; // so we'll redo this part next time - close(g_sUDP); - g_sUDP = -1; - if (g_fLogging & NALOG_ERROR) - fprintf(log, "UpnpInit - pthread create failed (%d)\n", iRet); - return NA_E_THREAD_ERROR; - } - - // set this to FALSE only if first call succeeded - g_fFirstInit = FALSE; + static const mDNSu8 msg[] = + "M-SEARCH * HTTP/1.1\r\n" + "Host:239.255.255.250:1900\r\n" + "ST:urn:schemas-upnp-org:service:WANIPConnection:1\r\n" + "Man:\"ssdp:discover\"\r\n" + "MX:3\r\n\r\n"; - //TracePrint(ELL_TRACE, "UPnP init passed\n"); + LogOperation("LNT_SendDiscoveryMsg %.4a %.4a", &m->Router.ip.v4, &m->ExternalAddress); - //tv.tv_sec = 0; - //tv.tv_usec = 20000; // wait 20ms for thread/udp/multicast init - //select(0, 0, 0, 0, &tv); + if (!mDNSIPv4AddressIsZero(m->Router.ip.v4) && mDNSIPv4AddressIsZero(m->ExternalAddress)) + mDNSPlatformSendUDP(m, msg, msg + sizeof(msg), 0, &m->Router, SSDPPort); } - // send discovery message - SendDiscoveryMsg(); - - return NA_E_SUCCESS; -} - -int LegacyNATDestroy() -{ - void *UDPThreadRetVal; - g_fQuit = TRUE; - if (g_sTCPCancel >= 0) close(g_sTCPCancel); - if (g_sUDPCancel >= 0) close(g_sUDPCancel); - pthread_join(g_UDPthread, &UDPThreadRetVal); - g_sTCPCancel = -1; - g_sUDPCancel = -1; - g_fFirstInit = TRUE; - g_fUPnPEnabled = FALSE; - g_fControlURLSet = FALSE; - return NA_E_SUCCESS; -} +#endif /* _LEGACY_NAT_TRAVERSAL_ */ diff --git a/mDNSMacOSX/PreferencePane/BonjourPref.icns b/mDNSMacOSX/PreferencePane/BonjourPref.icns index 97b560f6e303dff0cf5b1151c411dd18d4eafae0..5ba4674ee10c023e982bef935a5899d38b3f8bdd 100644 GIT binary patch delta 2146 zcmb`{drVVT90%}w4mg`3&`E(R7F+tDU`wIz_O_)(gt=t{1cA-RL=s3RiW_@5T?QKt z$&|o;xQTIKwuolaO+g(GsoPk#5XH>!hlzu2nprYM>oWIXOSYYJT1@8_;}&w0^SkHX zd+z<++|T{)>%kp8Sm3SPRL5~03yuj4F=zrDF~-QgQv+M!nHXcl@xcmsKgNLGgl}Sa ze5wr=#X9hi7aotbW1kncsd@ad7sg_FeA){_p@Wu3g-%*_30?SfHH-@Fv;@*Jv9B6r z>3Zy|g4zdIX;?}QR>5F8E7ybPWJ`jV%nx3YtE1}%mY8UXien{tnUT(3h%?hBj>eIh z7yNNH`dFFBL>nv@S#W<1w292Pe;tg7Y{&-@@g~#@ws^8C51t~Eci~{X5e>q4ycP9B ze1Zj??0qDmU~a^st?xjWgvU)sU|iygc((gXkR;o2>i~EP7eZa~V!Y=IXiv7_j&m@Y zY{YM!h3kbD^f_p)S#$Pqc+*F)d9i`qzokeH{njYlHVVEX12%jBzgrccl}4j>;H5k| z0?$jGs1Z&`J(0UP)CJR0JC^r=NoGb{phjjut*~E~i8|pt**^$@;si)ak)UH>OEIJ4 zP{AicQ_5m=652|{a5^Okoq)6a0=ShTCa?MjuS16+!y$z=@>sMVHp*=Xpv#c}Lu6hL zqjD9hfLn4E7IniSg$gypQiU3=hZ=>RG}xsupp7u5(Bs5*n5#74^@HG0>dC@dr55XV zL#NWZu;{&s*Cz3m%iq<9jSZ9Bl}7kcDaUJ$gIJ}&>w3VYO2Xv_V3kUOm$$-;Dk)Ce z4Esn~-UvRG%r>v!<$;k4uV0>XVPs%SuE5X5*{WLlhR=*$oVavp;^Nqu;l5p!rfXcR zKv(c&eOuR|LtSn4-hvDPh*KRwvE`{ICbl(IPs9$VI;dErc2W>-b-37m0+(R6 z)0o)0wAmN?LlCZ7!^E!DuqO6uEL5y-nTa-Wzt$Qi_9d;2itW?#_xZZHombz0Z}W8I zTc%|Y`ggLG!nF)Bp&O~AbRD|Fd!)OqkkK8onExByETTedqinroY=i^05ZmunR;nFbt;X;f*_ydA$a zO~3jpH%0!KW^g&F*lH&gyVps@o^u+g*a#OBYjshv8(bl=>FS)y15HmKo@$upu61zu zE`9?p=2w)>{Mxgb--pYY-{-RL@SFR;{r<_#Y@?7JlNF>~;?^_D&2AdLLvA~zJnd$b zt)6ho$2^Sk4G*KN$zhZ?N_oWq#x1^ZzE-9wGcNAx_R8EBR#S%u`KzPebg1i?%U5SJdH-r-T>yq$9 zUI?C*BEr0MW%j=$@@?ugk@cn2_o`CryQP%+{1$hx)iiMV=K+8+7w7vF93j;KBo5)LX4C6MpMG}Wm{KM&% zX%>YrbjnZNI+=6J*fKTY%@@ET6Qc`pOf%wi23YF`WfaAkOb57Z&vOTkZDw`JXR=es|3`=6V>wt6W<;klVNaL=wG~2F7#DE<6RK)>-;eYVxO24hFmT}p z)FFZO;c2u#d>XE&uR?FQiEe}N2qWFp{8YrUnUeCWo$!I&g4llOm8VNI0pEZ;%8d5k z23ziYD34l%o*#g{QAV`X4c$?CRMHQ=TqFHGXiTYoPKv$(>ld-KAM9MNgjQ1^D*YPT zm$T^bAWWE4kfaEr?Z7K6^mW*zu+k-PLXjcaPf;+TFr$!5V2n1KT0=gOcVp8c=kSUYt(_q8vSy-p!@Og*$ z2*!=YG{{N0wm9bPnW{fDj7)@@$NfX6eq4Q|IOk<$fp85P>w3RY$Ts%n5@ zMvk_846iZ@RJaok;IY;T?MyTmvZku7>&jc#XI$xOd;Q57gH-4fqfZ!MeJGP_eOu^M|={yy&(lE=_RzcAO5o?Tq8G+Zwf%K((o- zvu(k8F_fRx0$Vm-V7npy(X+iJ>W$L~Y*%W`1g2ACB*T@RMs6ZNYnrC@H7!T9p43|W zvDWJ08tBhS##GfwX@94xfZ?P_{O~2ogsUYv_aV7%&K0=2jE4WjH5F6Ua)fFrUQ3{k z6R8e!0#(LLsID{MGtYP*vY& zdW#pB209izRykfV_U13t$UX{R(PkxL*I0?z16CsTqLn3L{n7=oTsjfEHhofTLSp9X zx{3`)N4AYoJ|~6#*{{1OLRP%xi1*I;_}G~5J&ItSV^b~K+uHm7U_kGQTG!=)(Yq7( zcK=#+uX19?IOVIQ2=OH=1mYWQe<7arzlr}wO?|q-CQTK!=h=0$aZ7hnl^*1F!>BYG z>g|CT{wcee6!u-aAm5NNU4DIrAb%u7ke`q#$S=)&gz_7*a5pnBl!aTI0bJODF6Jn; z-AfH__f|uhCZ1@=%{>``neE(X)H_2vAViB_2^=KkaHO?g%1I+RsLkQ&^YCqs9!EgB z*hC_*WU&#q_148=TTeycCf?iB%q%IHia<)xt806*ozODvu=LIlPuYZJw9}Po9tjc|J)(K|V=BWqvA7LR-F=1Xf7FJm3rD zI0?lCViH)Pu;)R4LFBa3o(~y?VK@zrLfZq1`+g!waqAo;2G2T340bu#ppGx9eL?#J z6w1)za~^Q3Fwz CO>Y4J diff --git a/mDNSMacOSX/PreferencePane/ConfigurationRights.h b/mDNSMacOSX/PreferencePane/ConfigurationRights.h index 85f441e..9e59fa5 100644 --- a/mDNSMacOSX/PreferencePane/ConfigurationRights.h +++ b/mDNSMacOSX/PreferencePane/ConfigurationRights.h @@ -45,7 +45,11 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Change History (most recent first): + $Log: ConfigurationRights.h,v $ +Revision 1.2 2006/08/14 23:15:47 cheshire +Tidy up Change History comment + Revision 1.1 2005/02/05 01:59:19 cheshire Add Preference Pane to facilitate testing of DDNS & wide-area features diff --git a/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.h b/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.h index 21f98f5..cf69c9c 100644 --- a/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.h +++ b/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.h @@ -41,7 +41,11 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Change History (most recent first): + $Log: DNSServiceDiscoveryPref.h,v $ +Revision 1.6 2006/08/14 23:15:47 cheshire +Tidy up Change History comment + Revision 1.5 2005/02/26 00:44:24 cheshire Restore default reg domain if user deletes text and clicks "apply" diff --git a/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m b/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m index e774498..8e66610 100644 --- a/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m +++ b/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m @@ -41,7 +41,20 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Change History (most recent first): + $Log: DNSServiceDiscoveryPref.m,v $ +Revision 1.10 2007/09/18 19:09:02 cheshire + mDNSResponderHelper (and other binaries) missing SCCS version strings + +Revision 1.9 2007/02/09 00:39:06 cheshire +Fix compile warnings + +Revision 1.8 2006/08/14 23:15:47 cheshire +Tidy up Change History comment + +Revision 1.7 2006/07/14 03:59:14 cheshire +Fix compile warnings: 'sortUsingFunction:context:' comparison function needs to return int + Revision 1.6 2005/02/26 00:44:24 cheshire Restore default reg domain if user deletes text and clicks "apply" @@ -70,16 +83,18 @@ Add Preference Pane to facilitate testing of DDNS & wide-area features @implementation DNSServiceDiscoveryPref -static CFComparisonResult +static int MyArrayCompareFunction(id val1, id val2, void *context) { + (void)context; // Unused return CFStringCompare((CFStringRef)val1, (CFStringRef)val2, kCFCompareCaseInsensitive); } -static CFComparisonResult +static int MyDomainArrayCompareFunction(id val1, id val2, void *context) { + (void)context; // Unused NSString *domain1 = [val1 objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY]; NSString *domain2 = [val2 objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY]; return CFStringCompare((CFStringRef)domain1, (CFStringRef)domain2, kCFCompareCaseInsensitive); @@ -116,6 +131,8 @@ GetNextLabel(const char *cstr, char label[64]) static void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context) { + (void)store; // Unused + (void)changedKeys; // Unused DNSServiceDiscoveryPref * me = (DNSServiceDiscoveryPref *)context; assert(me != NULL); @@ -126,6 +143,9 @@ static void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void 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; @@ -179,7 +199,7 @@ static void ServiceDomainEnumReply( DNSServiceRef sdRef, DNSServiceFlags flags, } -void +static void browseDomainReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *replyDomain, void *context) { @@ -187,7 +207,7 @@ browseDomainReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interface } -void +static void registrationDomainReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *replyDomain, void *context) { @@ -242,7 +262,7 @@ MySocketReadCallback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address -void +static void MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) { CFSocketNativeHandle sock; @@ -389,7 +409,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) if ([defaultBrowseDomainsArray count] > 0) { NSEnumerator * arrayEnumerator = [defaultBrowseDomainsArray objectEnumerator]; - while (domain = [arrayEnumerator nextObject]) { + while ((domain = [arrayEnumerator nextObject]) != NULL) { if ([self domainAlreadyInList:domain] == NO) break; } } @@ -412,6 +432,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) - (IBAction)removeBrowseDomainClicked:(id)sender; { + (void)sender; // Unused int selectedBrowseDomain = [browseDomainList selectedRow]; [browseDomainsArray removeObjectAtIndex:selectedBrowseDomain]; [browseDomainList reloadData]; @@ -437,6 +458,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) - (int)numberOfRowsInTableView:(NSTableView *)tableView; { + (void)tableView; // Unused int numberOfRows = 0; if (browseDomainsArray) { @@ -446,8 +468,10 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) } -- (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem; +- (void)tabView:(NSTabView *)xtabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem; { + (void)xtabView; // Unused + (void)tabViewItem; // Unused [browseDomainList deselectAll:self]; [mainWindow makeFirstResponder:nil]; } @@ -455,6 +479,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) - (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row; { + (void)tableView; // Unused NSDictionary *browseDomainDict; id value = nil; @@ -611,7 +636,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) NSDictionary *domainDict; NSString *domainName; NSEnumerator *arrayEnumerator = [browseDomainsArray objectEnumerator]; - while (domainDict = [arrayEnumerator nextObject]) { + while ((domainDict = [arrayEnumerator nextObject]) != NULL) { domainName = [domainDict objectForKey:(NSString *)SC_DYNDNS_DOMAIN_KEY]; if ([domainString caseInsensitiveCompare:domainName] == NSOrderedSame) return YES; } @@ -630,6 +655,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) - (void)addBrowseDomainSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo { + (void)contextInfo; // Unused [sheet orderOut:self]; [self enableControls]; @@ -673,7 +699,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) if ([sender isEqualTo:hostNameSharedSecretButton]) { if (hostNameSharedSecretValue) { [sharedSecretValue setStringValue:hostNameSharedSecretValue]; - } else if (keyName = [self sharedSecretKeyName:[hostName stringValue]]) { + } else if ((keyName = [self sharedSecretKeyName:[hostName stringValue]]) != NULL) { [sharedSecretName setStringValue:keyName]; [sharedSecretValue setStringValue:@"****************"]; } else { @@ -684,7 +710,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) } else { if (regSharedSecretValue) { [sharedSecretValue setStringValue:regSharedSecretValue]; - } else if (keyName = [self sharedSecretKeyName:[regDomainsComboBox stringValue]]) { + } else if ((keyName = [self sharedSecretKeyName:[regDomainsComboBox stringValue]]) != NULL) { [sharedSecretName setStringValue:keyName]; [sharedSecretValue setStringValue:@"****************"]; } else { @@ -738,6 +764,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) - (void)controlTextDidChange:(NSNotification *)notification; { + (void)notification; // Unused [self updateApplyButtonState]; } @@ -745,6 +772,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) - (IBAction)comboAction:(id)sender; { + (void)sender; // Unused [self updateApplyButtonState]; } @@ -849,6 +877,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) - (IBAction)applyClicked:(id)sender { + (void)sender; // Unused [self applyCurrentState]; } @@ -905,6 +934,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) - (void)savePanelWillClose:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo { + (void)sheet; // Unused DNSServiceDiscoveryPref * me = (DNSServiceDiscoveryPref *)contextInfo; if (returnCode == NSAlertDefaultReturn) { @@ -956,7 +986,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) SecKeychainAttributeInfo attrInfo; SecKeychainAttributeList *attrList = NULL; SecKeychainAttribute attribute; - int i; + unsigned int i; tags[0] = kSecAccountItemAttr; attrInfo.count = 1; @@ -1164,6 +1194,8 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) - (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(int)row; { + (void)row; // Unused + (void)tableView; // Unused return browseDomainListEnabled; } @@ -1191,14 +1223,30 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) - (void)authorizationViewDidAuthorize:(SFAuthorizationView *)view { + (void)view; // Unused [self enableControls]; } - (void)authorizationViewDidDeauthorize:(SFAuthorizationView *)view { + (void)view; // Unused [self disableControls]; } +@end + + +// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion +// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4" +// To expand "version" to its value before making the string, use STRINGIFY(version) instead +#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s +#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) + +// NOT static -- otherwise the compiler may optimize it out +// The "@(#) " pattern is a special prefix the "what" command looks for +const char VersionString_SCCS[] = "@(#) Bonjour Preference Pane " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")"; -@end \ No newline at end of file +// 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"); diff --git a/mDNSMacOSX/PreferencePane/English.lproj/InfoPlist.strings b/mDNSMacOSX/PreferencePane/English.lproj/InfoPlist.strings index e76e125fac018382ff1d61cbb81b481317e61551..e2dfa991dedc0e00bf59c0152f4d3104dd7b94d4 100644 GIT binary patch delta 33 ecmbQi@`QQ9!ig`7*o_zrfY5Am1mi>`wh;idK?vFa delta 67 zcmaFDJcDJzLc?H&42FD$B8C!%FoskhUCfXP^z2a1_cINAXZ{9WYA+U OnAp`hS(dR6i1h&|*$+ej diff --git a/mDNSMacOSX/PreferencePane/Info-PreferencePane.plist b/mDNSMacOSX/PreferencePane/Info-PreferencePane.plist new file mode 100644 index 0000000..e5cdb9f --- /dev/null +++ b/mDNSMacOSX/PreferencePane/Info-PreferencePane.plist @@ -0,0 +1,36 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + Bonjour + CFBundleGetInfoString + + CFBundleIconFile + BonjourPref + CFBundleIdentifier + com.apple.preference.bonjour + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSMainNibFile + DNSServiceDiscoveryPref + NSPrefPaneIconFile + BonjourPref.tiff + NSPrefPaneIconLabel + Bonjour + NSPrincipalClass + DNSServiceDiscoveryPref + + diff --git a/mDNSMacOSX/PreferencePane/PrivilegedOperations.c b/mDNSMacOSX/PreferencePane/PrivilegedOperations.c index 89b9736..13552f6 100644 --- a/mDNSMacOSX/PreferencePane/PrivilegedOperations.c +++ b/mDNSMacOSX/PreferencePane/PrivilegedOperations.c @@ -41,7 +41,20 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Change History (most recent first): + $Log: PrivilegedOperations.c,v $ +Revision 1.7 2007/02/09 00:39:06 cheshire +Fix compile warnings + +Revision 1.6 2006/08/14 23:15:47 cheshire +Tidy up Change History comment + +Revision 1.5 2006/06/10 02:07:11 mkrochma +Whoa. Make sure code compiles before checking it in. + +Revision 1.4 2006/05/27 02:32:38 mkrochma +Wait for installer script to exit before returning result + Revision 1.3 2005/06/04 04:50:00 cheshire ddnswriteconfig (Bonjour PreferencePane) vulnerability Use installtool instead of requiring ddnswriteconfig to self-install @@ -68,7 +81,7 @@ Add Preference Pane to facilitate testing of DDNS & wide-area features Boolean gToolApproved = false; -pid_t execTool(const char *args[]) +static pid_t execTool(const char *args[]) // fork/exec and return new pid { pid_t child; @@ -132,8 +145,18 @@ OSStatus EnsureToolInstalled(void) { char *installerargs[] = { toolSourcePath, NULL }; err = AuthorizationExecuteWithPrivileges(authRef, toolInstallerPath, 0, installerargs, (FILE**) NULL); - if (err == noErr) - gToolApproved = true; + if (err == noErr) { + int status; + int pid = wait(&status); + if (pid > 0 && WIFEXITED(status)) { + err = WEXITSTATUS(status); + if (err == noErr) { + gToolApproved = true; + } + } else { + err = -1; + } + } (void) AuthorizationFree(authRef, kAuthorizationFlagDestroyRights); } } diff --git a/mDNSMacOSX/PreferencePane/PrivilegedOperations.h b/mDNSMacOSX/PreferencePane/PrivilegedOperations.h index c5c68a0..e76cb68 100644 --- a/mDNSMacOSX/PreferencePane/PrivilegedOperations.h +++ b/mDNSMacOSX/PreferencePane/PrivilegedOperations.h @@ -41,7 +41,11 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Change History (most recent first): + $Log: PrivilegedOperations.h,v $ +Revision 1.5 2006/08/14 23:15:47 cheshire +Tidy up Change History comment + Revision 1.4 2005/06/04 04:50:00 cheshire ddnswriteconfig (Bonjour PreferencePane) vulnerability Use installtool instead of requiring ddnswriteconfig to self-install diff --git a/mDNSMacOSX/PreferencePane/ddnswriteconfig.m b/mDNSMacOSX/PreferencePane/ddnswriteconfig.m index ff3080e..3f2fbbf 100644 --- a/mDNSMacOSX/PreferencePane/ddnswriteconfig.m +++ b/mDNSMacOSX/PreferencePane/ddnswriteconfig.m @@ -43,7 +43,23 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Change History (most recent first): + $Log: ddnswriteconfig.m,v $ +Revision 1.9 2007/09/18 19:09:02 cheshire + mDNSResponderHelper (and other binaries) missing SCCS version strings + +Revision 1.8 2007/07/20 23:41:03 mkrochma + null deref in ddnswriteconfig + +Revision 1.7 2007/03/07 00:49:00 cheshire + Security: ddnswriteconfig does not verify that authorization blob is of correct size + +Revision 1.6 2007/02/09 00:39:06 cheshire +Fix compile warnings + +Revision 1.5 2006/08/14 23:15:47 cheshire +Tidy up Change History comment + Revision 1.4 2005/06/04 04:47:47 cheshire ddnswriteconfig (Bonjour PreferencePane) vulnerability Remove self-installing capability of ddnswriteconfig @@ -84,7 +100,7 @@ Add Preference Pane to facilitate testing of DDNS & wide-area features static AuthorizationRef gAuthRef = 0; -OSStatus +static OSStatus WriteArrayToDynDNS(CFStringRef arrayKey, CFArrayRef domainArray) { SCPreferencesRef store; @@ -141,8 +157,8 @@ 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; + ssize_t num, len; + u_int32_t tag; int result = 0; num = read(fd, &tag, sizeof tag); @@ -170,7 +186,7 @@ GetTagFailed: -int +static int SetAuthInfo( int fd) { int result = 0; @@ -179,6 +195,8 @@ SetAuthInfo( int fd) 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, kAuthorizationFlagDestroyRights); @@ -193,7 +211,7 @@ ReadParamsFailed: } -int +static int HandleWriteDomain(int fd, int domainType) { CFArrayRef domainArray; @@ -225,7 +243,7 @@ ReadParamsFailed: } -int +static int HandleWriteHostname(int fd) { CFArrayRef domainArray; @@ -252,7 +270,7 @@ ReadParamsFailed: } -SecAccessRef +static SecAccessRef MyMakeUidAccess(uid_t uid) { // make the "uid/gid" ACL subject @@ -263,10 +281,10 @@ MyMakeUidAccess(uid_t uid) uid, // uid to match 0 // gid (not matched here) }; - CSSM_LIST_ELEMENT subject2 = { NULL, 0 }; + 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 }; + 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) @@ -281,27 +299,27 @@ MyMakeUidAccess(uid_t uid) false }; // ACL entries (any number, just one here) - CSSM_ACL_ENTRY_INFO acls[] = { + CSSM_ACL_ENTRY_INFO acls = { - // prototype + // CSSM_ACL_ENTRY_PROTOTYPE { - // TypedSubject - { CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 }, - false, // Delegate - // rights for this entry - { sizeof(rights) / sizeof(rights[0]), rights }, - // rest is defaulted - } - } - }; + { 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 access = NULL; - (void) SecAccessCreateFromOwnerAndACL(&owner, sizeof(acls) / sizeof(acls[0]), acls, &access); + (void) SecAccessCreateFromOwnerAndACL(&owner, 1, &acls, &access); return access; } -OSStatus +static OSStatus MyAddDynamicDNSPassword(SecKeychainRef keychain, SecAccessRef access, UInt32 serviceNameLength, const char *serviceName, UInt32 accountNameLength, const char *accountName, UInt32 passwordLength, const void *passwordData) { @@ -327,7 +345,7 @@ MyAddDynamicDNSPassword(SecKeychainRef keychain, SecAccessRef access, UInt32 ser } -int +static int SetKeychainEntry(int fd) // Create a new entry in system keychain, or replace existing { @@ -407,7 +425,7 @@ int main( int argc, char **argv) if ( argc == 3 && 0 == strcmp( argv[2], "V")) return PRIV_OP_TOOL_VERS; - if ( argc >= 1) + if ( argc > 1) { commFD = strtol( argv[1], NULL, 0); lseek( commFD, 0, SEEK_SET); @@ -438,3 +456,17 @@ int main( int argc, char **argv) [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 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"); diff --git a/mDNSMacOSX/PreferencePane/installtool b/mDNSMacOSX/PreferencePane/installtool index 8fa79ad..6240d33 100755 --- a/mDNSMacOSX/PreferencePane/installtool +++ b/mDNSMacOSX/PreferencePane/installtool @@ -1,4 +1,5 @@ #!/usr/bin/perl +# Emacs settings: -*- tab-width: 4 -*- # # File: installtool # @@ -44,6 +45,12 @@ # Change History (most recent first): # # $Log: installtool,v $ +# Revision 1.3 2006/09/05 20:00:13 cheshire +# Moved Emacs settings to second line of file +# +# Revision 1.2 2006/08/14 23:15:14 cheshire +# Added "tab-width" emacs header line +# # Revision 1.1 2005/06/04 04:51:48 cheshire # ddnswriteconfig (Bonjour PreferencePane) vulnerability # Added separate "installtool" script instead of making ddnswriteconfig self-install diff --git a/mDNSMacOSX/README.privsep b/mDNSMacOSX/README.privsep new file mode 100644 index 0000000..d687d07 --- /dev/null +++ b/mDNSMacOSX/README.privsep @@ -0,0 +1,47 @@ +On Mac OS X, mDNSResponder now runs with user-ID and group-ID +"_mdnsresponder". In order to perform certain privileged operations, a +helper (unimagintively called mDNSResponderHelper) runs as root when +needed and handles requests from mDNSResponder. + + +* A new LaunchD job com.apple.mDNSResponderHelper starts + mDNSResponderHelper on demand. The helper exits after approximately + 10 seconds of idle time. + +* The com.apple.mDNSResponder LaunchD job specifies the account under + which to run, so that mDNSResponder starts as _mdnsresponder. When + run as root--- e.g. from the command line with `sudo'--- + mDNSResponder drops privileges itself. + +* A subdirectory named "mdns" and owned by _mdnsresponder has been + created in /var/run. The PID file and uDNS server socket has been + moved to that subdirectory. + +* There are currently six remote procedure calls handled by + mDNSResponderHelper: mDNSDynamicStoreSetConfig, + mDNSPreferencesSetName, mDNSKeychainGetSecrets, + mDNSAutoTunnelInterfaceUpDown, mDNSConfigureServer, and + mDNSAutoTunnelSetKeys + +* mDNSDynamicStoreSetConfig allows mDNSResponder to set the + MulticastDNS, PrivateDNS, or DynamicDNS configurations. + +* mDNSPreferencesSetName allows mDNSResponder to set the computer name + or local host name, and displays a notification if there was a + conflict. + +* mDNSKeychainGetSecrets causes mDNSResponderHelper to collect DNS + keys from the system keychain. SetDomainSecrets uses the result to + populate AuthInfoList. One could refactor this code further so that + mDNSResponderHelper performs all the cryptographic operations, with + the result that a compromise of mDNSResponder does not compromise + keys. But I think that may be more change than is advisable at this + point. + +* On the advice of the Security.framework team, I've used + SecKeychainSetPreferenceDomain to ensure that the system keychain is + references whenever a NULL SecKeychainRef is used. Wherever a + SecKeychainRef is needed, NULL is now specified. + +* mDNSAutoTunnelInterfaceUpDown, mDNSConfigureServer, and + mDNSAutoTunnelSetKeys do various setup and teardown for BTMM. diff --git a/mDNSMacOSX/SamplemDNSClient.c b/mDNSMacOSX/SamplemDNSClient.c index be60816..c44edc8 100644 --- a/mDNSMacOSX/SamplemDNSClient.c +++ b/mDNSMacOSX/SamplemDNSClient.c @@ -1,24 +1,18 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ * * Formatting notes: * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion @@ -33,53 +27,34 @@ * understand why variable y is not of type "char*" just proves the point that poor code * layout leads people to unfortunate misunderstandings about how the C language really works.) - Change History (most recent first): + Change History (most recent first): $Log: SamplemDNSClient.c,v $ -Revision 1.47 2006/01/10 02:29:22 cheshire - Cosmetic IPv6 address display problem in mDNS test tool - -Revision 1.46 2004/11/02 01:32:34 cheshire - Update code so it still compiles when DNSServiceDiscovery.h is deprecated - -Revision 1.45 2004/06/15 02:39:47 cheshire -When displaying error message, only show command name, not entire path - -Revision 1.44 2004/05/28 02:20:06 cheshire -If we allow dot or empty string for domain when resolving a service, -it should be a synonym for "local" - -Revision 1.43 2004/02/03 22:07:50 cheshire -: Widen columns to display non-local domains better +Revision 1.53 2007/09/18 19:09:02 cheshire + mDNSResponderHelper (and other binaries) missing SCCS version strings -Revision 1.42 2003/12/03 11:39:17 cheshire - Browse output misaligned in mDNS command-line tool -(Also fix it to add leading space when the hours part of the time is only one digit) +Revision 1.52 2007/03/06 22:45:52 cheshire -Revision 1.41 2003/10/30 22:52:57 cheshire - Browse output misaligned in mDNS command-line tool + argv buffer overflow issues -Revision 1.40 2003/09/26 01:07:06 cheshire -Added test case to test fix for +Revision 1.51 2007/02/13 18:56:45 cheshire + Mach mDNS tool inconsistent with UDS-based dns-sd tool +(missing domain should mean "system default(s)", not "local") -Revision 1.39 2003/08/18 19:05:45 cheshire - UpdateRecord not working right -Added "newrdlength" field to hold new length of updated rdata +Revision 1.50 2007/01/05 08:30:47 cheshire +Trim excessive "$Log" checkin history from before 2006 +(checkin history still available via "cvs log ..." of course) -Revision 1.38 2003/08/12 19:56:25 cheshire -Update to APSL 2.0 +Revision 1.49 2007/01/04 21:54:49 cheshire +Fix compile warnings related to the deprecated Mach-based API -Revision 1.37 2003/08/05 20:39:25 cheshire - mDNS buffered std out makes it impossible to use from another tool -Added "setlinebuf(stdout);" +Revision 1.48 2006/08/14 23:24:39 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 -Revision 1.36 2003/07/19 03:23:13 cheshire - mDNSResponder needs to receive and cache larger records - -Revision 1.35 2003/07/11 01:57:18 cheshire -Add checkin history header +Revision 1.47 2006/01/10 02:29:22 cheshire + Cosmetic IPv6 address display problem in mDNS test tool - */ +*/ #include #define BIND_8_COMPAT @@ -93,6 +68,9 @@ Add checkin history header #include #undef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED #define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED +#undef AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3 +#define AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_3 + #include //************************************************************************************************************* @@ -127,28 +105,28 @@ static char bigNULL[4096]; static void MyHandleMachMessage(CFMachPortRef port, void *msg, CFIndex size, void *info) { - (void)port; // Unused - (void)size; // Unused - (void)info; // Unused + (void)port; // Unused + (void)size; // Unused + (void)info; // Unused DNSServiceDiscovery_handleReply(msg); } static int AddDNSServiceClientToRunLoop(dns_service_discovery_ref client) - { + { mach_port_t port = DNSServiceDiscoveryMachPort(client); - if (!port) - return(-1); - else - { - CFMachPortContext context = { 0, 0, NULL, NULL, NULL }; - Boolean shouldFreeInfo; - CFMachPortRef cfMachPort = CFMachPortCreateWithPort(kCFAllocatorDefault, port, MyHandleMachMessage, &context, &shouldFreeInfo); - CFRunLoopSourceRef rls = CFMachPortCreateRunLoopSource(NULL, cfMachPort, 0); - CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); - CFRelease(rls); - return(0); - } - } + if (!port) + return(-1); + else + { + CFMachPortContext context = { 0, 0, NULL, NULL, NULL }; + Boolean shouldFreeInfo; + CFMachPortRef cfMachPort = CFMachPortCreateWithPort(kCFAllocatorDefault, port, MyHandleMachMessage, &context, &shouldFreeInfo); + CFRunLoopSourceRef rls = CFMachPortCreateRunLoopSource(NULL, cfMachPort, 0); + CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); + CFRelease(rls); + return(0); + } + } //************************************************************************************************************* // Sample callback functions for each of the operation types @@ -163,13 +141,13 @@ static void printtimestamp(void) } #define DomainMsg(X) ((X) == DNSServiceDomainEnumerationReplyAddDomain ? "Added" : \ - (X) == DNSServiceDomainEnumerationReplyAddDomainDefault ? "(Default)" : \ - (X) == DNSServiceDomainEnumerationReplyRemoveDomain ? "Removed" : "Unknown") + (X) == DNSServiceDomainEnumerationReplyAddDomainDefault ? "(Default)" : \ + (X) == DNSServiceDomainEnumerationReplyRemoveDomain ? "Removed" : "Unknown") static void regdom_reply(DNSServiceDomainEnumerationReplyResultType resultType, const char *replyDomain, - DNSServiceDiscoveryReplyFlags flags, void *context) + DNSServiceDiscoveryReplyFlags flags, void *context) { - (void)context; // Unused + (void)context; // Unused printtimestamp(); printf("Recommended Registration Domain %s %s", replyDomain, DomainMsg(resultType)); if (flags) printf(" Flags: %X", flags); @@ -177,9 +155,9 @@ static void regdom_reply(DNSServiceDomainEnumerationReplyResultType resultType, } static void browsedom_reply(DNSServiceDomainEnumerationReplyResultType resultType, const char *replyDomain, - DNSServiceDiscoveryReplyFlags flags, void *context) + DNSServiceDiscoveryReplyFlags flags, void *context) { - (void)context; // Unused + (void)context; // Unused printtimestamp(); printf("Recommended Browsing Domain %s %s", replyDomain, DomainMsg(resultType)); if (flags) printf(" Flags: %X", flags); @@ -187,10 +165,10 @@ static void browsedom_reply(DNSServiceDomainEnumerationReplyResultType resultTyp } static void browse_reply(DNSServiceBrowserReplyResultType resultType, - const char *replyName, const char *replyType, const char *replyDomain, DNSServiceDiscoveryReplyFlags flags, void *context) + const char *replyName, const char *replyType, const char *replyDomain, DNSServiceDiscoveryReplyFlags flags, void *context) { char *op = (resultType == DNSServiceBrowserReplyAddInstance) ? "Add" : "Rmv"; - (void)context; // Unused + (void)context; // Unused if (num_printed++ == 0) printf("Timestamp A/R Flags %-24s %-24s %s\n", "Domain", "Service Type", "Instance Name"); printtimestamp(); printf("%s%6X %-24s %-24s %s\n", op, flags, replyDomain, replyType, replyName); @@ -198,67 +176,67 @@ static void browse_reply(DNSServiceBrowserReplyResultType resultType, static void resolve_reply(struct sockaddr *interface, struct sockaddr *address, const char *txtRecord, DNSServiceDiscoveryReplyFlags flags, void *context) { - (void)interface; // Unused - (void)context; // Unused + (void)interface; // Unused + (void)context; // Unused if (address->sa_family != AF_INET && address->sa_family != AF_INET6) printf("Unknown address family %d\n", address->sa_family); else { - const char *src = txtRecord; - printtimestamp(); - - if (address->sa_family == AF_INET) - { - struct sockaddr_in *ip = (struct sockaddr_in *)address; - union { uint32_t l; u_char b[4]; } addr = { ip->sin_addr.s_addr }; - union { uint16_t s; u_char b[2]; } port = { ip->sin_port }; - uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1]; - char ipstring[16]; - sprintf(ipstring, "%d.%d.%d.%d", addr.b[0], addr.b[1], addr.b[2], addr.b[3]); - printf("Service can be reached at %-15s:%u", ipstring, PortAsNumber); - } - else if (address->sa_family == AF_INET6) - { - struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)address; - u_int8_t *b = ip6->sin6_addr.__u6_addr.__u6_addr8; - union { uint16_t s; u_char b[2]; } port = { ip6->sin6_port }; - uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1]; - char ipstring[40]; - char ifname[IF_NAMESIZE + 1] = ""; - sprintf(ipstring, "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X", + const char *src = txtRecord; + printtimestamp(); + + if (address->sa_family == AF_INET) + { + struct sockaddr_in *ip = (struct sockaddr_in *)address; + union { uint32_t l; u_char b[4]; } addr = { ip->sin_addr.s_addr }; + union { uint16_t s; u_char b[2]; } port = { ip->sin_port }; + uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1]; + char ipstring[16]; + sprintf(ipstring, "%d.%d.%d.%d", addr.b[0], addr.b[1], addr.b[2], addr.b[3]); + printf("Service can be reached at %-15s:%u", ipstring, PortAsNumber); + } + else if (address->sa_family == AF_INET6) + { + struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)address; + u_int8_t *b = ip6->sin6_addr.__u6_addr.__u6_addr8; + union { uint16_t s; u_char b[2]; } port = { ip6->sin6_port }; + uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1]; + char ipstring[40]; + char ifname[IF_NAMESIZE + 1] = ""; + sprintf(ipstring, "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X", b[0x0], b[0x1], b[0x2], b[0x3], b[0x4], b[0x5], b[0x6], b[0x7], b[0x8], b[0x9], b[0xA], b[0xB], b[0xC], b[0xD], b[0xE], b[0xF]); - if (ip6->sin6_scope_id) { ifname[0] = '%'; if_indextoname(ip6->sin6_scope_id, &ifname[1]); } - printf("%s%s:%u", ipstring, ifname, PortAsNumber); - } + if (ip6->sin6_scope_id) { ifname[0] = '%'; if_indextoname(ip6->sin6_scope_id, &ifname[1]); } + printf("%s%s:%u", ipstring, ifname, PortAsNumber); + } if (flags) printf(" Flags: %X", flags); - if (*src) - { - char txtInfo[64]; // Display at most first 64 characters of TXT record - char *dst = txtInfo; - const char *const lim = &txtInfo[sizeof(txtInfo)]; - while (*src && dst < lim-1) - { - if (*src == '\\') *dst++ = '\\'; // '\' displays as "\\" - if (*src >= ' ') *dst++ = *src++; // Display normal characters as-is - else - { - *dst++ = '\\'; // Display a backslash - if (*src == 1) *dst++ = ' '; // String boundary displayed as "\ " - else // Other chararacters displayed as "\0xHH" - { - static const char hexchars[16] = "0123456789ABCDEF"; - *dst++ = '0'; - *dst++ = 'x'; - *dst++ = hexchars[*src >> 4]; - *dst++ = hexchars[*src & 0xF]; - } + if (*src) + { + char txtInfo[64]; // Display at most first 64 characters of TXT record + char *dst = txtInfo; + const char *const lim = &txtInfo[sizeof(txtInfo)]; + while (*src && dst < lim-1) + { + if (*src == '\\') *dst++ = '\\'; // '\' displays as "\\" + if (*src >= ' ') *dst++ = *src++; // Display normal characters as-is + else + { + *dst++ = '\\'; // Display a backslash + if (*src == 1) *dst++ = ' '; // String boundary displayed as "\ " + else // Other chararacters displayed as "\0xHH" + { + static const char hexchars[16] = "0123456789ABCDEF"; + *dst++ = '0'; + *dst++ = 'x'; + *dst++ = hexchars[*src >> 4]; + *dst++ = hexchars[*src & 0xF]; + } src++; - } - } - *dst++ = 0; - printf(" TXT %s", txtInfo); - } + } + } + *dst++ = 0; + printf(" TXT %s", txtInfo); + } printf("\n"); } } @@ -267,69 +245,69 @@ static void myCFRunLoopTimerCallBack(CFRunLoopTimerRef timer, void *info) { (void)timer; // Parameter not used (void)info; // Parameter not used - - switch (operation) - { - case 'A': - { - switch (addtest) - { - case 0: printf("Adding Test HINFO record\n"); - record = DNSServiceRegistrationAddRecord(client, T_HINFO, sizeof(myhinfo9), &myhinfo9[0], 120); - addtest = 1; - break; - case 1: printf("Updating Test HINFO record\n"); - DNSServiceRegistrationUpdateRecord(client, record, sizeof(myhinfoX), &myhinfoX[0], 120); - addtest = 2; - break; - case 2: printf("Removing Test HINFO record\n"); - DNSServiceRegistrationRemoveRecord(client, record); - addtest = 0; - break; - } - } - break; - - case 'U': - { - if (updatetest[1] != 'Z') updatetest[1]++; - else updatetest[1] = 'A'; - updatetest[0] = 3 - updatetest[0]; - updatetest[2] = updatetest[1]; - printf("Updating Test TXT record to %c\n", updatetest[1]); - DNSServiceRegistrationUpdateRecord(client, 0, 1+updatetest[0], &updatetest[0], 120); - } - break; - - case 'N': - { - printf("Adding big NULL record\n"); - DNSServiceRegistrationAddRecord(client, T_NULL, sizeof(bigNULL), &bigNULL[0], 120); - CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode); - } - break; - } - } + + switch (operation) + { + case 'A': + { + switch (addtest) + { + case 0: printf("Adding Test HINFO record\n"); + record = DNSServiceRegistrationAddRecord(client, T_HINFO, sizeof(myhinfo9), &myhinfo9[0], 120); + addtest = 1; + break; + case 1: printf("Updating Test HINFO record\n"); + DNSServiceRegistrationUpdateRecord(client, record, sizeof(myhinfoX), &myhinfoX[0], 120); + addtest = 2; + break; + case 2: printf("Removing Test HINFO record\n"); + DNSServiceRegistrationRemoveRecord(client, record); + addtest = 0; + break; + } + } + break; + + case 'U': + { + if (updatetest[1] != 'Z') updatetest[1]++; + else updatetest[1] = 'A'; + updatetest[0] = 3 - updatetest[0]; + updatetest[2] = updatetest[1]; + printf("Updating Test TXT record to %c\n", updatetest[1]); + DNSServiceRegistrationUpdateRecord(client, 0, 1+updatetest[0], &updatetest[0], 120); + } + break; + + case 'N': + { + printf("Adding big NULL record\n"); + DNSServiceRegistrationAddRecord(client, T_NULL, sizeof(bigNULL), &bigNULL[0], 120); + CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode); + } + break; + } + } static void reg_reply(DNSServiceRegistrationReplyErrorType errorCode, void *context) { - (void)context; // Unused - printf("Got a reply from the server: "); - switch (errorCode) - { - case kDNSServiceDiscoveryNoError: printf("Name now registered and active\n"); break; - case kDNSServiceDiscoveryNameConflict: printf("Name in use, please choose another\n"); exit(-1); - default: printf("Error %d\n", errorCode); return; - } - - if (operation == 'A' || operation == 'U' || operation == 'N') - { - CFRunLoopTimerContext myCFRunLoopTimerContext = { 0, 0, NULL, NULL, NULL }; - CFRunLoopTimerRef timer = CFRunLoopTimerCreate(kCFAllocatorDefault, - CFAbsoluteTimeGetCurrent() + 5.0, 5.0, 0, 1, // Next fire time, periodic interval, flags, and order - myCFRunLoopTimerCallBack, &myCFRunLoopTimerContext); - CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode); - } + (void)context; // Unused + printf("Got a reply from the server: "); + switch (errorCode) + { + case kDNSServiceDiscoveryNoError: printf("Name now registered and active\n"); break; + case kDNSServiceDiscoveryNameConflict: printf("Name in use, please choose another\n"); exit(-1); + default: printf("Error %d\n", errorCode); return; + } + + if (operation == 'A' || operation == 'U' || operation == 'N') + { + CFRunLoopTimerContext myCFRunLoopTimerContext = { 0, 0, NULL, NULL, NULL }; + CFRunLoopTimerRef timer = CFRunLoopTimerCreate(kCFAllocatorDefault, + CFAbsoluteTimeGetCurrent() + 5.0, 5.0, 0, 1, // Next fire time, periodic interval, flags, and order + myCFRunLoopTimerCallBack, &myCFRunLoopTimerContext); + CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode); + } } //************************************************************************************************************* @@ -342,119 +320,121 @@ int main(int argc, char **argv) setlinebuf(stdout); // Want to see lines as they appear, not block buffered if (argc < 2) goto Fail; // Minimum command line is the command name and one argument - operation = getopt(argc, (char * const *)argv, "EFBLRAUNTMI"); + operation = getopt(argc, (char * const *)argv, "EFBLRAUNTMI"); if (operation == -1) goto Fail; - switch (operation) - { - case 'E': printf("Looking for recommended registration domains:\n"); - client = DNSServiceDomainEnumerationCreate(1, regdom_reply, nil); - break; - - case 'F': printf("Looking for recommended browsing domains:\n"); - client = DNSServiceDomainEnumerationCreate(0, browsedom_reply, nil); - break; - - case 'B': if (argc < optind+1) goto Fail; - dom = (argc < optind+2) ? "local" : argv[optind+1]; - if (dom[0] == '.' && dom[1] == 0) dom[0] = 0; // We allow '.' on the command line as a synonym for empty string - printf("Browsing for %s%s\n", argv[optind+0], dom); - client = DNSServiceBrowserCreate(argv[optind+0], dom, browse_reply, nil); - break; - - case 'L': if (argc < optind+2) goto Fail; - dom = (argc < optind+3) ? "" : argv[optind+2]; + switch (operation) + { + case 'E': printf("Looking for recommended registration domains:\n"); + client = DNSServiceDomainEnumerationCreate(1, regdom_reply, nil); + break; + + case 'F': printf("Looking for recommended browsing domains:\n"); + client = DNSServiceDomainEnumerationCreate(0, browsedom_reply, nil); + break; + + case 'B': if (argc < optind+1) goto Fail; + dom = (argc < optind+2) ? "" : argv[optind+1]; // Missing domain argument is the same as empty string i.e. use system default(s) + if (dom[0] == '.' && dom[1] == 0) dom[0] = 0; // We allow '.' on the command line as a synonym for empty string + printf("Browsing for %s%s\n", argv[optind+0], dom); + client = DNSServiceBrowserCreate(argv[optind+0], dom, browse_reply, nil); + break; + + case 'L': if (argc < optind+2) goto Fail; + dom = (argc < optind+3) ? "" : argv[optind+2]; if (dom[0] == '.' && dom[1] == 0) dom = "local"; // We allow '.' on the command line as a synonym for "local" - printf("Lookup %s.%s%s\n", argv[optind+0], argv[optind+1], dom); - client = DNSServiceResolverResolve(argv[optind+0], argv[optind+1], dom, resolve_reply, nil); - break; - - case 'R': if (argc < optind+4) goto Fail; - { - char *nam = argv[optind+0]; - char *typ = argv[optind+1]; - char *dom = argv[optind+2]; - uint16_t PortAsNumber = atoi(argv[optind+3]); - Opaque16 registerPort = { { PortAsNumber >> 8, PortAsNumber & 0xFF } }; - char txt[2048]; - char *ptr = txt; - int i; - - if (nam[0] == '.' && nam[1] == 0) nam[0] = 0; // We allow '.' on the command line as a synonym for empty string - if (dom[0] == '.' && dom[1] == 0) dom[0] = 0; // We allow '.' on the command line as a synonym for empty string - - // Copy all the TXT strings into one C string separated by ASCII-1 delimiters - for (i = optind+4; i < argc; i++) - { - strcpy(ptr, argv[i]); - ptr += strlen(argv[i]); - *ptr++ = 1; - } - if (ptr > txt) ptr--; - *ptr = 0; - - printf("Registering Service %s.%s%s port %s %s\n", nam, typ, dom, argv[optind+3], txt); - client = DNSServiceRegistrationCreate(nam, typ, dom, registerPort.NotAnInteger, txt, reg_reply, nil); - break; - } - - case 'A': - case 'U': - case 'N': { - Opaque16 registerPort = { { 0x12, 0x34 } }; - static const char TXT[] = "First String\001Second String\001Third String"; - printf("Registering Service Test._testupdate._tcp.local.\n"); - client = DNSServiceRegistrationCreate("Test", "_testupdate._tcp.", "", registerPort.NotAnInteger, TXT, reg_reply, nil); - break; - } - - case 'T': { - Opaque16 registerPort = { { 0x23, 0x45 } }; - char TXT[1000]; - unsigned int i; - for (i=0; i> 5); - TXT[i] = 0; - printf("Registering Service Test._testlargetxt._tcp.local.\n"); - client = DNSServiceRegistrationCreate("Test", "_testlargetxt._tcp.", "", registerPort.NotAnInteger, TXT, reg_reply, nil); - break; - } - - case 'M': { - pid_t pid = getpid(); - Opaque16 registerPort = { { pid >> 8, pid & 0xFF } }; - static const char TXT1[] = "First String\001Second String\001Third String"; - static const char TXT2[] = "\x0D" "Fourth String" "\x0C" "Fifth String" "\x0C" "Sixth String"; - printf("Registering Service Test._testdualtxt._tcp.local.\n"); - client = DNSServiceRegistrationCreate("", "_testdualtxt._tcp.", "", registerPort.NotAnInteger, TXT1, reg_reply, nil); - // use "sizeof(TXT2)-1" because we don't wan't the C compiler's null byte on the end of the string - record = DNSServiceRegistrationAddRecord(client, T_TXT, sizeof(TXT2)-1, TXT2, 120); - break; - } - - case 'I': { - pid_t pid = getpid(); - Opaque16 registerPort = { { pid >> 8, pid & 0xFF } }; - static const char TXT[] = "\x09" "Test Data"; - printf("Registering Service Test._testtxt._tcp.local.\n"); - client = DNSServiceRegistrationCreate("", "_testtxt._tcp.", "", registerPort.NotAnInteger, "", reg_reply, nil); - if (client) DNSServiceRegistrationUpdateRecord(client, 0, 1+TXT[0], &TXT[0], 120); - break; - } - - default: goto Exit; - } - - if (!client) { fprintf(stderr, "DNSService call failed\n"); return (-1); } - if (AddDNSServiceClientToRunLoop(client) != 0) { fprintf(stderr, "AddDNSServiceClientToRunLoop failed\n"); return (-1); } - printf("Talking to DNS SD Daemon at Mach port %d\n", DNSServiceDiscoveryMachPort(client)); + printf("Lookup %s.%s%s\n", argv[optind+0], argv[optind+1], dom); + client = DNSServiceResolverResolve(argv[optind+0], argv[optind+1], dom, resolve_reply, nil); + break; + + case 'R': if (argc < optind+4) goto Fail; + { + char *nam = argv[optind+0]; + char *typ = argv[optind+1]; + char *dom = argv[optind+2]; + uint16_t PortAsNumber = atoi(argv[optind+3]); + Opaque16 registerPort = { { PortAsNumber >> 8, PortAsNumber & 0xFF } }; + char txt[2048]; + char *ptr = txt; + int i; + + if (nam[0] == '.' && nam[1] == 0) nam[0] = 0; // We allow '.' on the command line as a synonym for empty string + if (dom[0] == '.' && dom[1] == 0) dom[0] = 0; // We allow '.' on the command line as a synonym for empty string + + // Copy all the TXT strings into one C string separated by ASCII-1 delimiters + for (i = optind+4; i < argc; i++) + { + int len = strlen(argv[i]); + if (len > 255 || ptr + len + 1 >= txt + sizeof(txt)) break; + strcpy(ptr, argv[i]); + ptr += len; + *ptr++ = 1; + } + if (ptr > txt) ptr--; + *ptr = 0; + + printf("Registering Service %s.%s%s port %s %s\n", nam, typ, dom, argv[optind+3], txt); + client = DNSServiceRegistrationCreate(nam, typ, dom, registerPort.NotAnInteger, txt, reg_reply, nil); + break; + } + + case 'A': + case 'U': + case 'N': { + Opaque16 registerPort = { { 0x12, 0x34 } }; + static const char TXT[] = "First String\001Second String\001Third String"; + printf("Registering Service Test._testupdate._tcp.local.\n"); + client = DNSServiceRegistrationCreate("Test", "_testupdate._tcp.", "", registerPort.NotAnInteger, TXT, reg_reply, nil); + break; + } + + case 'T': { + Opaque16 registerPort = { { 0x23, 0x45 } }; + char TXT[1000]; + unsigned int i; + for (i=0; i> 5); + TXT[i] = 0; + printf("Registering Service Test._testlargetxt._tcp.local.\n"); + client = DNSServiceRegistrationCreate("Test", "_testlargetxt._tcp.", "", registerPort.NotAnInteger, TXT, reg_reply, nil); + break; + } + + case 'M': { + pid_t pid = getpid(); + Opaque16 registerPort = { { pid >> 8, pid & 0xFF } }; + static const char TXT1[] = "First String\001Second String\001Third String"; + static const char TXT2[] = "\x0D" "Fourth String" "\x0C" "Fifth String" "\x0C" "Sixth String"; + printf("Registering Service Test._testdualtxt._tcp.local.\n"); + client = DNSServiceRegistrationCreate("", "_testdualtxt._tcp.", "", registerPort.NotAnInteger, TXT1, reg_reply, nil); + // use "sizeof(TXT2)-1" because we don't wan't the C compiler's null byte on the end of the string + record = DNSServiceRegistrationAddRecord(client, T_TXT, sizeof(TXT2)-1, TXT2, 120); + break; + } + + case 'I': { + pid_t pid = getpid(); + Opaque16 registerPort = { { pid >> 8, pid & 0xFF } }; + static const char TXT[] = "\x09" "Test Data"; + printf("Registering Service Test._testtxt._tcp.local.\n"); + client = DNSServiceRegistrationCreate("", "_testtxt._tcp.", "", registerPort.NotAnInteger, "", reg_reply, nil); + if (client) DNSServiceRegistrationUpdateRecord(client, 0, 1+TXT[0], &TXT[0], 120); + break; + } + + default: goto Exit; + } + + if (!client) { fprintf(stderr, "DNSService call failed\n"); return (-1); } + if (AddDNSServiceClientToRunLoop(client) != 0) { fprintf(stderr, "AddDNSServiceClientToRunLoop failed\n"); return (-1); } + printf("Talking to DNS SD Daemon at Mach port %d\n", DNSServiceDiscoveryMachPort(client)); CFRunLoopRun(); - - // Be sure to deallocate the dns_service_discovery_ref when you're finished - // Note: What other cleanup has to be done here? - // We should probably invalidate, remove and release our CFRunLoopSourceRef? - DNSServiceDiscoveryDeallocate(client); - + + // Be sure to deallocate the dns_service_discovery_ref when you're finished + // Note: What other cleanup has to be done here? + // We should probably invalidate, remove and release our CFRunLoopSourceRef? + DNSServiceDiscoveryDeallocate(client); + Exit: return 0; @@ -472,3 +452,17 @@ Fail: fprintf(stderr, "%s -I (Test registering and then immediately updating TXT record)\n", progname); return 0; } + +// 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[] = "@(#) mDNS " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")"; + +// 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"); diff --git a/mDNSMacOSX/daemon.c b/mDNSMacOSX/daemon.c index 7794479..714c431 100644 --- a/mDNSMacOSX/daemon.c +++ b/mDNSMacOSX/daemon.c @@ -1,24 +1,18 @@ -/* - * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. +/* -*- Mode: C; tab-width: 4 -*- * - * @APPLE_LICENSE_HEADER_START@ + * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ * * Formatting notes: * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion @@ -36,560 +30,284 @@ Change History (most recent first): $Log: daemon.c,v $ -Revision 1.255.2.1 2005/07/22 21:45:04 ksekar -Fix GCC 4.0/Intel compiler warnings - -Revision 1.255 2005/03/09 00:48:43 cheshire - QU packets getting sent too early on wake from sleep -Move "m->p->NetworkChanged = 0;" line from caller to callee - -Revision 1.254 2005/03/03 04:34:19 cheshire - Bonjour name conflict dialog appears during MacBuddy - -Revision 1.253 2005/03/03 03:55:09 cheshire - Name collision notifications should be localized - -Revision 1.252 2005/02/23 02:29:17 cheshire - "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed -Minor refinements, better variable names, improved comments - -Revision 1.251 2005/02/21 21:31:24 ksekar - changed LogMsg to debugf - -Revision 1.250 2005/02/19 01:25:04 cheshire - "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed -Further refinements - -Revision 1.249 2005/02/19 00:28:45 cheshire - "Local Hostname is already in use..." dialogue shows for only 60 seconds before being removed - -Revision 1.248 2005/02/19 00:18:34 cheshire -Confusing variable name -- alertMessage should be called alertHeader - -Revision 1.247 2005/02/15 02:13:49 cheshire -If we did registerBootstrapService() when starting, then we must do -destroyBootstrapService() before exiting, or Mach init will keep restarting us. - -Revision 1.246 2005/02/03 00:44:37 cheshire - DNSServiceUpdateRecord returns kDNSServiceErr_Invalid when rdlen=0, rdata=NULL - -Revision 1.245 2005/02/01 19:56:47 ksekar -Moved LogMsg from daemon.c to uds_daemon.c, cleaned up wording - -Revision 1.244 2005/01/28 00:34:49 cheshire -Turn off "Starting time value" log message - -Revision 1.243 2005/01/27 17:46:58 cheshire -Added comment about CFSocketInvalidate closing the underlying socket - -Revision 1.242 2005/01/27 00:10:58 cheshire - Name change log messages every time machine boots - -Revision 1.241 2005/01/25 17:28:06 ksekar - Should not return "local" twice for domain enumeration - -Revision 1.240 2005/01/21 02:39:18 cheshire -Rename FoundDomain() to DomainEnumFound() to avoid order-file symbol clash with other routine called FoundDomain() - -Revision 1.239 2005/01/20 00:25:01 cheshire -Improve validatelists() log message generation - -Revision 1.238 2005/01/19 19:15:35 ksekar -Refinement to - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer - -Revision 1.237 2005/01/19 03:33:09 cheshire - When changing Computer Name, we drop our own Goobye Packets - -Revision 1.236 2005/01/19 03:16:38 cheshire - CPU Spin in mDNSResponder -Improve detail of "Task Scheduling Error" diagnostic messages - -Revision 1.235 2005/01/15 00:56:41 ksekar - Unicast services don't disappear when logging -out of VPN - -Revision 1.234 2005/01/10 03:42:30 ksekar -Clarify debugf - -Revision 1.233 2004/12/18 00:53:46 cheshire -Use symbolic constant mDNSInterface_LocalOnly instead of (mDNSInterfaceID)~0 - -Revision 1.232 2004/12/17 23:37:48 cheshire - Guard against repeating wireless dissociation/re-association -(and other repetitive configuration changes) - -Revision 1.231 2004/12/17 04:13:38 cheshire -Removed debugging check - -Revision 1.230 2004/12/17 04:09:30 cheshire - Switch mDNSResponder to launchd - -Revision 1.229 2004/12/16 21:51:36 cheshire -Remove some startup messages - -Revision 1.228 2004/12/16 20:13:01 cheshire - Cache memory management improvements - -Revision 1.227 2004/12/10 13:52:57 cheshire - Turn off SIGPIPE signals - -Revision 1.226 2004/12/10 05:27:26 cheshire - Guard against multiple autoname services of the same type on the same machine - -Revision 1.225 2004/12/10 04:28:29 cheshire - User not notified of name changes for services using new UDS API - -Revision 1.224 2004/12/10 00:41:05 cheshire -Adjust alignment of log messages - -Revision 1.223 2004/12/07 20:42:34 cheshire -Add explicit context parameter to mDNS_RemoveRecordFromService() - -Revision 1.222 2004/12/06 21:15:23 ksekar - mDNSResponder crashed in CheckServiceRegistrations - -Revision 1.221 2004/11/30 03:24:04 cheshire - Defer processing network configuration changes until configuration has stabilized - -Revision 1.220 2004/11/29 23:34:31 cheshire -On platforms with coarse time resolutions, ORing time values with one to ensure they are non-zero -is crude, and effectively halves the time resolution. The more selective NonZeroTime() function -only nudges the time value to 1 if the interval calculation happens to result in the value zero. - -Revision 1.219 2004/11/25 01:00:56 cheshire -Checkin 1.217 not necessary - -Revision 1.218 2004/11/24 20:27:19 cheshire -Add missing "err" parameter in LogMsg() call - -Revision 1.217 2004/11/24 17:55:01 ksekar -Added log message clarifying For unicast operations, verify that service types are legal - -Revision 1.216 2004/11/24 00:10:44 cheshire - For unicast operations, verify that service types are legal - -Revision 1.215 2004/11/23 22:33:01 cheshire - Remove temporary workaround code for iChat +Revision 1.344 2007/09/29 01:06:17 mcguire + 9A564: mDNSResponder crash in mDNS_Execute -Revision 1.214 2004/11/23 22:13:59 cheshire - Subtype advertising broken for Mach API +Revision 1.343 2007/09/24 05:02:41 cheshire +Debugging: In SIGINFO output, indicate explicitly when a given section is empty -Revision 1.213 2004/11/23 06:12:55 cheshire - Update wording for name conflict dialogs +Revision 1.342 2007/09/18 19:09:02 cheshire + mDNSResponderHelper (and other binaries) missing SCCS version strings -Revision 1.212 2004/11/23 05:15:37 cheshire - Computer Name in use message garbled +Revision 1.341 2007/09/12 01:22:13 cheshire +Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0 -Revision 1.211 2004/11/23 05:00:41 cheshire - Name conflict log message should not have ".local" appended +Revision 1.340 2007/09/07 22:44:03 mcguire + Move CFUserNotification code to mDNSResponderHelper -Revision 1.210 2004/11/03 03:45:17 cheshire - mDNSResponder does not inform user of Computer Name collisions +Revision 1.339 2007/09/06 19:08:29 cheshire +LogAllOperations check needs to be "#if LogAllOperations || MDNS_DEBUGMSGS" -Revision 1.209 2004/11/03 02:25:50 cheshire - Conflict for Computer Name should update *all* empty string services, not just the one with the conflict +Revision 1.338 2007/09/05 23:34:27 mcguire +Revert logging change -Revision 1.208 2004/11/03 01:54:14 cheshire -Update debugging messages +Revision 1.337 2007/09/05 20:45:50 cheshire +Added list of KQSocketEventSources in SIGINFO output -Revision 1.207 2004/11/02 23:58:19 cheshire - mDNSResponder does not inform user of name collisions +Revision 1.336 2007/08/31 17:15:37 cheshire +Reordered startup log messages so that "mDNSResponder ... starting" is the first message -Revision 1.206 2004/10/28 02:40:47 cheshire -Add log message to confirm receipt of SIGUSR1 (simulate network configuration change event) +Revision 1.335 2007/08/31 02:00:16 cheshire +Added comment explaining use of zero-width non-breaking space character to tag literal strings -Revision 1.205 2004/10/28 02:21:01 cheshire - Improve mDNSResponder signal handling -Added SIGHUP as a way to do a forced restart of the daemon (better than kill -9) -Added SIGUSR1 to simulate a network change notification from System Configuration Framework +Revision 1.334 2007/08/24 23:40:24 cheshire +Added comment about FreeServiceInstance -Revision 1.204 2004/10/27 01:57:21 cheshire -Add check of m->p->InterfaceList +Revision 1.333 2007/08/23 21:02:35 cheshire +SecKeychainSetPreferenceDomain() call should be in platform-support layer, not daemon.c -Revision 1.203 2004/10/26 04:31:44 cheshire -Rename CountSubTypes() as ChopSubTypes() +Revision 1.332 2007/08/22 23:54:54 mcguire + BTMM: mDNSResponder should be able to run from the cmdline -Revision 1.202 2004/10/26 01:29:18 cheshire -Use "#if 0" instead of commenting out code +Revision 1.331 2007/08/18 01:02:03 mcguire + No Bonjour services are getting registered at boot -Revision 1.201 2004/10/25 21:41:39 ksekar - wide-area name conflicts can cause crash +Revision 1.330 2007/08/10 22:25:57 mkrochma + mDNSResponder continually complains about slow UDP packet reception -- about 400 msecs -Revision 1.200 2004/10/22 01:03:55 cheshire - select() says data is waiting; recvfrom() says there is no data -Log error message if attempt to remap stdin/stdout/stderr to /dev/null fails +Revision 1.329 2007/08/08 22:34:58 mcguire + Security: Run mDNSResponder as user id mdnsresponder instead of root -Revision 1.199 2004/10/19 21:33:19 cheshire - Cannot resolve non-local registrations using the mach API -Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name -doesn't force multicast unless you set this flag to indicate explicitly that this is what you want +Revision 1.328 2007/07/27 22:43:37 cheshire +Improved mallocL/freeL "suspiciously large" debugging messages -Revision 1.198 2004/10/15 23:00:18 ksekar - Need to update LLQs on location changes +Revision 1.327 2007/07/27 19:30:41 cheshire +Changed mDNSQuestionCallback parameter from mDNSBool to QC_result, +to properly reflect tri-state nature of the possible responses -Revision 1.197 2004/10/12 23:38:59 ksekar - remove unnecessary log message +Revision 1.326 2007/07/24 17:23:33 cheshire + Add list validation checks for debugging -Revision 1.196 2004/10/04 05:56:04 cheshire - mDNSResponder doesn't respond to certain AirPort changes +Revision 1.325 2007/07/11 23:43:43 cheshire +Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord -Revision 1.195 2004/09/30 00:24:59 ksekar - Dynamically update default registration domains on config change +Revision 1.324 2007/07/11 22:44:40 cheshire + SIGHUP should purge the cache -Revision 1.194 2004/09/26 23:20:35 ksekar - Allow default registrations in multiple wide-area domains +Revision 1.323 2007/07/11 03:01:50 cheshire + Register IPv6-only hostname and don't create port mappings for AutoTunnel services -Revision 1.193 2004/09/23 23:35:27 cheshire -Update error message +Revision 1.322 2007/07/06 18:58:16 cheshire +Check m->NextScheduledNATOp in ShowTaskSchedulingError() -Revision 1.192 2004/09/21 23:40:12 ksekar - mDNSResponder to return errors on NAT traversal failure +Revision 1.321 2007/07/02 21:54:20 cheshire +Fix compile error in MACOSX_MDNS_MALLOC_DEBUGGING checks -Revision 1.191 2004/09/21 21:05:12 cheshire -Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c, -into mDNSShared/uds_daemon.c +Revision 1.320 2007/06/28 21:16:27 cheshire +Rename "m->nextevent" as more informative "m->NextuDNSEvent" -Revision 1.190 2004/09/21 19:51:15 cheshire -Move "Starting time value" message from mDNS.c to mDNSMacOSX/daemon.c +Revision 1.319 2007/06/22 20:47:08 cheshire + DOS charset changes from CP932 to CP850 after Computer Name conflict +Made a "SafeSCPreferencesSetComputerName" routine to set the Computer Name without changing the machine's default character set -Revision 1.189 2004/09/21 18:17:23 cheshire - Add version info to mDNSResponder +Revision 1.318 2007/06/20 01:45:40 cheshire +When showing dormant interfaces, display last-seen IP address for that dormant interface -Revision 1.188 2004/09/20 21:45:27 ksekar -Mach IPC cleanup +Revision 1.317 2007/06/20 01:10:12 cheshire + Sync iPhone changes into main mDNSResponder code -Revision 1.187 2004/09/17 01:08:52 cheshire -Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h - The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces - declared in that file are ONLY appropriate to single-address-space embedded applications. - For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used. +Revision 1.316 2007/06/19 19:27:11 cheshire + Sandbox mDNSResponder +Weak-link sandbox_init, so mDNSResponder can be run on Tiger for regression testing -Revision 1.186 2004/09/16 00:24:49 cheshire - Fix unsafe use of mDNSPlatformTimeNow() +Revision 1.315 2007/06/15 21:54:51 cheshire + Add packet logging to help debugging private browsing over TLS -Revision 1.185 2004/08/25 02:01:45 cheshire - Need to be able to get status of Dynamic DNS Host Name Update +Revision 1.314 2007/06/15 19:23:17 cheshire + mDNSResponder renames my host without asking +Improve log messages, to distinguish user-initiated renames from automatic (name conflict) renames -Revision 1.184 2004/08/19 19:04:12 ksekar -: mDNSResponder crashes when adding a record to a service +Revision 1.313 2007/05/25 16:02:05 cheshire +When MACOSX_MDNS_MALLOC_DEBUGGING is enabled, log suspiciously large memory allocations -Revision 1.183 2004/08/14 03:22:42 cheshire - Dynamic DNS UI <-> mDNSResponder glue -Add GetUserSpecifiedDDNSName() routine -Convert ServiceRegDomain to domainname instead of C string -Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs +Revision 1.312 2007/05/22 19:07:21 cheshire +Add comment explaining RR_CACHE_SIZE calculation -Revision 1.182 2004/08/13 23:57:59 cheshire -Get rid of non-portable "_UNUSED" +Revision 1.311 2007/05/15 21:47:21 cheshire +Get rid of "#pragma unused(m)" -Revision 1.181 2004/08/11 02:02:26 cheshire -Remove "mDNS *globalInstance" parameter from udsserver_init(); -Move CheckForDuplicateRegistrations to uds_daemon.c +Revision 1.310 2007/05/08 00:56:17 cheshire + Share single socket instead of creating separate socket for each active interface -Revision 1.180 2004/07/13 21:24:25 rpantos -Fix for . +Revision 1.309 2007/04/30 21:33:38 cheshire +Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop +is iterating through the m->ServiceRegistrations list -Revision 1.179 2004/06/19 00:02:54 cheshire -Restore fix for Should not allow empty string for resolve domain +Revision 1.308 2007/04/28 01:31:59 cheshire +Improve debugging support for catching memory corruption problems -Revision 1.178 2004/06/18 19:10:00 cheshire - Current method of doing subtypes causes name collisions +Revision 1.307 2007/04/24 18:32:00 cheshire +Grab a copy of KQtask string pointer in case KQcallback deletes the task -Revision 1.177 2004/06/16 23:14:46 ksekar - Remove fix for Should not allow empty string for resolve domain +Revision 1.306 2007/04/22 19:11:51 cheshire +Some quirk of RemoveFromList (GenLinkedList.c) was corrupting the list and causing a crash +if the element being removed was not the last in the list. Fixed by removing GenLinkedList.c +from the project and just using simple vanilla C linked-list manipulation instead. -Revision 1.176 2004/06/11 20:27:42 cheshire -Rename "SocketRef" as "cfs" to avoid conflict with other plaforms +Revision 1.305 2007/04/22 06:02:03 cheshire + Query should immediately return failure when no server -Revision 1.175 2004/06/10 20:23:21 cheshire -Also list interfaces in SIGINFO output +Revision 1.304 2007/04/21 21:47:47 cheshire + Daemon: Add watchdog timer -Revision 1.174 2004/06/08 18:54:48 ksekar -: mDNSResponder leaks after exploring in Printer Setup Utility +Revision 1.303 2007/04/18 00:50:47 cheshire + Sandbox mDNSResponder -Revision 1.173 2004/06/08 17:35:12 cheshire - Detect and report if mDNSResponder uses too much CPU +Revision 1.302 2007/04/07 01:01:48 cheshire + mDNSResponder periodically blocks in SSLRead -Revision 1.172 2004/06/05 00:04:26 cheshire -: wide-area domains should be returned in reg. domain enumeration +Revision 1.301 2007/04/05 19:13:48 cheshire +Use better name in SCPreferencesCreate -Revision 1.171 2004/06/04 08:58:30 ksekar -: Keychain integration for secure dynamic update +Revision 1.300 2007/04/04 21:22:18 cheshire +Suppress "Local Hostname changed" syslog message when name has not actually changed -Revision 1.170 2004/05/30 20:01:50 ksekar -: wide-area default registrations should be in -.local too - fixed service registration when clients pass an explicit -domain (broken by previous checkin) +Revision 1.299 2007/04/03 19:19:33 cheshire +Use mDNSIPPortIsZero() instead of peeking into 'NotAnInteger' field -Revision 1.169 2004/05/30 01:30:16 ksekar -: wide-area default registrations should be in -.local too +Revision 1.298 2007/03/30 21:51:45 cheshire +Minor code tidying -Revision 1.168 2004/05/18 23:51:26 cheshire -Tidy up all checkin comments to use consistent "" format for bug numbers +Revision 1.297 2007/03/27 22:47:19 cheshire +On memory corruption, if ForceAlerts is set, force a crash to get a stack trace -Revision 1.167 2004/05/14 16:39:47 ksekar -Browse for iChat locally for now. +Revision 1.296 2007/03/24 01:23:29 cheshire +Call validator for uDNS data structures -Revision 1.166 2004/05/13 21:33:52 ksekar -Clean up non-local registration control via config file. Force iChat -registrations to be local for now. +Revision 1.295 2007/03/20 23:32:49 cheshire +Minor textual tidying -Revision 1.165 2004/05/13 04:54:20 ksekar -Unified list copy/free code. Added symetric list for +Revision 1.294 2007/03/07 02:50:50 cheshire + Name conflict dialog doesn't appear if Bonjour is persistantly unable to find an available hostname -Revision 1.164 2004/05/12 22:03:08 ksekar -Made GetSearchDomainList a true platform-layer call (declaration moved -from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local" -only on non-OSX platforms. Changed call to return a copy of the list -to avoid shared memory issues. Added a routine to free the list. +Revision 1.293 2007/03/06 22:59:01 cheshire + Security: Null dereference possible in daemon.c -Revision 1.163 2004/05/12 02:03:25 ksekar -Non-local domains will only be browsed by default, and show up in -_browse domain enumeration, if they contain an _browse._dns-sd ptr record. +Revision 1.292 2007/02/28 21:55:10 cheshire + UI: Name conflict notifications should be localized +Additional fix: We were not getting our NotificationCallBackDismissed messages +because we were scheduling our CFUserNotification RunLoopSource on the wrong runloop. +(We were incorrectly assuming CFRunLoopGetCurrent() would be the right runloop.) -Revision 1.162 2004/04/14 23:09:29 ksekar -Support for TSIG signed dynamic updates. +Revision 1.291 2007/02/28 03:51:24 cheshire + UI: Name conflict notifications should be localized +Moved curly quotes out of the literal text and into the localized text, so they +can be replaced with alternate characters as appropriate for other languages. -Revision 1.161 2004/04/07 01:20:04 cheshire -Hash slot value should be unsigned +Revision 1.290 2007/02/14 01:58:19 cheshire + Don't delete Unix Domain Socket on exit if we didn't create it on startup -Revision 1.160 2004/04/06 19:51:24 cheshire - mDNSResponder will not launch if "nobody" user doesn't exist. -After more discussion, we've decided to use userid -2 if "nobody" user doesn't exist. +Revision 1.289 2007/02/07 19:32:00 cheshire + All mDNSResponder components should contain version strings in SCCS-compatible format -Revision 1.159 2004/04/03 01:36:55 cheshire - mDNSResponder will not launch if "nobody" user doesn't exist. -If "nobody" user doesn't exist, log a message and continue as "root" +Revision 1.288 2007/02/07 01:01:24 cheshire + Need to go native with launchd +Additional refinements -- was unnecessarily calling launch_data_free() -Revision 1.158 2004/04/02 21:39:05 cheshire -Fix errors in comments +Revision 1.287 2007/02/06 19:06:48 cheshire + Need to go native with launchd -Revision 1.157 2004/03/19 18:49:10 ksekar -Increased size check in freeL() to account for LargeCacheRecord -structs larger than 8k +Revision 1.286 2007/01/06 01:00:33 cheshire +Improved SIGINFO output -Revision 1.156 2004/03/19 18:19:19 ksekar -Fixed daemon.c to compile with malloc debugging turned on. +Revision 1.285 2007/01/05 08:30:47 cheshire +Trim excessive "$Log" checkin history from before 2006 +(checkin history still available via "cvs log ..." of course) -Revision 1.155 2004/03/13 01:57:34 ksekar -: DynDNS: Dynamic update of service records +Revision 1.284 2007/01/05 05:44:35 cheshire +Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c, +so that mDNSPosix embedded clients will compile again -Revision 1.154 2004/03/12 08:42:47 cheshire -: Should not allow empty string for resolve domain +Revision 1.283 2007/01/04 23:11:14 cheshire + uDNS: Need to start caching unicast records +When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries -Revision 1.153 2004/03/12 08:08:51 cheshire -Update comments +Revision 1.282 2006/12/21 00:09:45 cheshire +Use mDNSPlatformMemZero instead of bzero -Revision 1.152 2004/02/05 19:39:29 cheshire -Move creation of /var/run/mDNSResponder.pid to uds_daemon.c, -so that all platforms get this functionality +Revision 1.281 2006/11/18 05:01:32 cheshire +Preliminary support for unifying the uDNS and mDNS code, +including caching of uDNS answers -Revision 1.151 2004/02/03 22:35:34 cheshire -: Should not allow empty string for resolve domain +Revision 1.280 2006/11/10 00:54:16 cheshire + Changing case of Computer Name doesn't work -Revision 1.150 2004/01/28 21:14:23 cheshire -Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode) +Revision 1.279 2006/11/02 17:44:01 cheshire +No longer have a separate uDNS ActiveQueries list -Revision 1.149 2004/01/28 02:30:08 ksekar -Added default Search Domains to unicast browsing, controlled via -Networking sharing prefs pane. Stopped sending unicast messages on -every interface. Fixed unicast resolving via mach-port API. +Revision 1.278 2006/10/05 04:04:24 herscher +Remove embedded uDNS_info struct from DNSQuestion_struct -Revision 1.148 2004/01/25 00:03:20 cheshire -Change to use mDNSVal16() instead of private PORT_AS_NUM() macro +Revision 1.277 2006/09/21 21:01:24 cheshire +Change 'autorename' to more accurate name 'renameonmemfree' -Revision 1.147 2004/01/19 19:51:46 cheshire -Fix compiler error (mixed declarations and code) on some versions of Linux +Revision 1.276 2006/09/17 19:12:02 cheshire +Further changes for removal of uDNS_info substructure from mDNS_struct -Revision 1.146 2003/12/08 21:00:46 rpantos -Changes to support mDNSResponder on Linux. +Revision 1.275 2006/09/15 21:20:16 cheshire +Remove uDNS_info substructure from mDNS_struct -Revision 1.145 2003/12/05 22:08:07 cheshire -Update version string to "mDNSResponder-61", including new mechanism to allow dots (e.g. 58.1) +Revision 1.274 2006/08/14 23:24:39 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 -Revision 1.144 2003/11/19 23:21:08 ksekar -: config change handler not called for dns-sd services +Revision 1.273 2006/07/30 05:43:19 cheshire + Convert mDNSResponder to use kqueue +Problems using KQueueFD with select() -- for now we'll stick to pure kevent() -Revision 1.143 2003/11/14 21:18:32 cheshire -: Security: Crashing bug in mDNSResponder -Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers. +Revision 1.272 2006/07/27 03:24:35 cheshire + Convert mDNSResponder to use kqueue +Further refinement: Declare KQueueEntry parameter "const" -Revision 1.142 2003/11/08 22:18:29 cheshire -: Don't need to show process ID in *every* mDNSResponder syslog message +Revision 1.271 2006/07/27 02:59:26 cheshire + Convert mDNSResponder to use kqueue +Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread +after releasing BigMutex, in case actions it took have resulted in new work for the +kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to +add new active interfaces to its list, and consequently schedule queries to be sent). -Revision 1.141 2003/11/07 02:30:57 cheshire -Also check per-slot cache use counts in SIGINFO state log +Revision 1.270 2006/07/25 17:16:36 mkrochma +Quick fix to solve kqueue related crashes and hangs -Revision 1.140 2003/10/21 19:58:26 cheshire - Syslog messages should show TTL as signed (for overdue records) +Revision 1.269 2006/07/22 06:11:37 cheshire + Convert mDNSResponder to use kqueue -Revision 1.139 2003/10/21 00:10:18 rpantos -: mDNSResponder should not run as root +Revision 1.268 2006/07/15 02:01:32 cheshire + Add Private DNS client functionality to mDNSResponder +Fix broken "empty string" browsing -Revision 1.138 2003/10/07 20:16:58 cheshire -Shorten syslog message a bit +Revision 1.267 2006/07/07 01:09:10 cheshire + Add Private DNS server functionality to dnsextd +Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd -Revision 1.137 2003/09/23 02:12:43 cheshire -Also include port number in list of services registered via new UDS API +Revision 1.266 2006/07/05 23:34:53 cheshire + Add Private DNS client functionality to mDNSResponder -Revision 1.136 2003/09/23 02:07:25 cheshire -Include port number in DNSServiceRegistration START/STOP messages +Revision 1.265 2006/06/29 07:32:08 cheshire +Added missing LogOperation logging for DNSServiceBrowse results -Revision 1.135 2003/09/23 01:34:02 cheshire -In SIGINFO state log, show remaining TTL on cache records, and port number on ServiceRegistrations +Revision 1.264 2006/06/29 05:33:30 cheshire + mDNSResponder conditional compilation options -Revision 1.134 2003/08/21 20:01:37 cheshire - Traffic reduction: Detect long-lived Resolve() calls, and report them in syslog +Revision 1.263 2006/06/08 23:23:48 cheshire +Fix errant indentation of curly brace at the end of provide_DNSServiceBrowserCreate_rpc() -Revision 1.133 2003/08/20 23:39:31 cheshire - Review syslog messages, and remove as appropriate +Revision 1.262 2006/03/18 21:49:11 cheshire +Added comment in ShowTaskSchedulingError(mDNS *const m) -Revision 1.132 2003/08/20 01:44:56 cheshire -Fix errors in LogOperation() calls (only used for debugging) +Revision 1.261 2006/01/06 01:22:28 cheshire + Reword "mach_absolute_time went backwards" dialog -Revision 1.131 2003/08/19 05:39:43 cheshire - SIGINFO dump should include resolves started by DNSServiceQueryRecord - -Revision 1.130 2003/08/16 03:39:01 cheshire - InterfaceID -1 indicates "local only" - -Revision 1.129 2003/08/15 20:16:03 cheshire - mDNSResponder takes too much RPRVT -We want to avoid touching the rdata pages, so we don't page them in. -1. RDLength was stored with the rdata, which meant touching the page just to find the length. - Moved this from the RData to the ResourceRecord object. -2. To avoid unnecessarily touching the rdata just to compare it, - compute a hash of the rdata and store the hash in the ResourceRecord object. - -Revision 1.128 2003/08/14 19:30:36 cheshire - Include list of cache records in SIGINFO output - -Revision 1.127 2003/08/14 02:18:21 cheshire - Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord - -Revision 1.126 2003/08/12 19:56:25 cheshire -Update to APSL 2.0 - -Revision 1.125 2003/08/08 18:36:04 cheshire - Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug - -Revision 1.124 2003/07/25 18:28:23 cheshire -Minor fix to error messages in syslog: Display string parameters with quotes - -Revision 1.123 2003/07/23 17:45:28 cheshire - mDNSResponder leaks a bit -Don't allocate memory for the reply until after we've verified that the reply is valid - -Revision 1.122 2003/07/23 00:00:04 cheshire -Add comments - -Revision 1.121 2003/07/20 03:38:51 ksekar - Completed support for Unix-domain socket based API. - -Revision 1.120 2003/07/18 00:30:00 cheshire - Remove mDNSResponder version from packet header and use HINFO record instead - -Revision 1.119 2003/07/17 19:08:58 cheshire - Remove calls to enable obsolete UDS code - -Revision 1.118 2003/07/15 21:12:28 cheshire -Added extra debugging checks in validatelists() (not used in final shipping version) - -Revision 1.117 2003/07/15 01:55:15 cheshire - Need to implement service registration with subtypes - -Revision 1.116 2003/07/02 21:19:51 cheshire - Update copyright notices, etc., in source code comments - -Revision 1.115 2003/07/02 02:41:24 cheshire - mDNSResponder needs to start with a smaller cache and then grow it as needed - -Revision 1.114 2003/07/01 21:10:20 cheshire -Reinstate checkin 1.111, inadvertently overwritten by checkin 1.112 - -Revision 1.113 2003/06/28 17:27:43 vlubet - Redirect standard input, standard output, and -standard error file descriptors to /dev/null just like any other -well behaved daemon - -Revision 1.112 2003/06/25 23:42:19 ksekar -: Feature: New DNS-SD APIs (#7875) -Reviewed by: Stuart Cheshire -Added files necessary to implement Unix domain sockets based enhanced -DNS-SD APIs, and integrated with existing Mach-port based daemon. - -Revision 1.111 2003/06/11 01:02:43 cheshire - mDNSResponder binary compatibility -Make single binary that can run on both Jaguar and Panther. - -Revision 1.110 2003/06/10 01:14:11 cheshire - New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call - -Revision 1.109 2003/06/06 19:53:43 cheshire -For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass -(Global search-and-replace; no functional change to code execution.) - -Revision 1.108 2003/06/06 14:08:06 cheshire -For clarity, pull body of main while() loop out into a separate function called mDNSDaemonIdle() - -Revision 1.107 2003/05/29 05:44:55 cheshire -Minor fixes to log messages - -Revision 1.106 2003/05/27 18:30:55 cheshire - Need a way to easily examine current mDNSResponder state -Dean Reece suggested SIGINFO is more appropriate than SIGHUP - -Revision 1.105 2003/05/26 03:21:29 cheshire -Tidy up address structure naming: -mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr) -mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4 -mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6 - -Revision 1.104 2003/05/26 00:42:06 cheshire - Temporarily include mDNSResponder version in packets - -Revision 1.103 2003/05/23 23:07:44 cheshire - Must not write to stderr when running as daemon - -Revision 1.102 2003/05/22 01:32:31 cheshire -Fix typo in Log message format string - -Revision 1.101 2003/05/22 00:26:55 cheshire - DNSServiceRegistrationCreate() should return error on dup -Modify error message to explain that this is technically legal, but may indicate a bug. - -Revision 1.100 2003/05/21 21:02:24 ksekar -: Service should be prefixed -Changed kmDNSBootstrapName to "com.apple.mDNSResponderRestart" since we're changing the main -Mach message port to "com.apple.mDNSResponder. - -Revision 1.99 2003/05/21 17:33:49 cheshire -Fix warnings (mainly printf format string warnings, like using "%d" where it should say "%lu", etc.) - -Revision 1.98 2003/05/20 00:33:07 cheshire - Need a way to easily examine current mDNSResponder state -SIGHUP now writes state summary to syslog - -Revision 1.97 2003/05/08 00:19:08 cheshire - Forgot to set "err = mStatus_BadParamErr" in a couple of places - -Revision 1.96 2003/05/07 22:10:46 cheshire - Add a few more error logging messages - -Revision 1.95 2003/05/07 19:20:17 cheshire - Add version number to mDNSResponder builds - -Revision 1.94 2003/05/07 00:28:18 cheshire - Need to make mDNSResponder more defensive against bad clients - -Revision 1.93 2003/05/06 00:00:49 cheshire - Rationalize naming of domainname manipulation functions - -Revision 1.92 2003/04/04 20:38:57 cheshire -Add $Log header - - */ +*/ #include #include @@ -598,20 +316,24 @@ Add $Log header #include #include #include +#include #include +#include +#include +#include #include #include "DNSServiceDiscoveryRequestServer.h" #include "DNSServiceDiscoveryReply.h" +#include "uDNS.h" #include "DNSCommon.h" #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform #include "uds_daemon.h" // Interface to the server side implementation of dns_sd.h -#include "GenLinkedList.h" - #include +#include "helper.h" //************************************************************************************************************* // Macros @@ -625,19 +347,23 @@ Add $Log header //************************************************************************************************************* // Globals -#define LOCAL_DEFAULT_REG 1 // empty string means register in the local domain -#define DEFAULT_REG_DOMAIN "apple.com." // used if the above flag is turned off static mDNS_PlatformSupport PlatformStorage; -// Start off with a default cache of 16K (about 100 records) +// Start off with a default cache of 16K (99 records) +// Each time we grow the cache we add another 99 records +// 99 * 164 = 16236 bytes. +// This fits in four 4kB pages, with 148 bytes spare for memory block headers and similar overhead #define RR_CACHE_SIZE ((16*1024) / sizeof(CacheRecord)) static CacheEntity rrcachestorage[RR_CACHE_SIZE]; static const char kmDNSBootstrapName[] = "com.apple.mDNSResponderRestart"; +static mach_port_t m_port = MACH_PORT_NULL; static mach_port_t client_death_port = MACH_PORT_NULL; static mach_port_t signal_port = MACH_PORT_NULL; static mach_port_t server_priv_port = MACH_PORT_NULL; +static dnssd_sock_t launchd_fd = dnssd_InvalidSocket; + // mDNS Mach Message Timeout, in milliseconds. // We need this to be short enough that we don't deadlock the mDNSResponder if a client // fails to service its mach message queue, but long enough to give a well-written @@ -646,11 +372,13 @@ static mach_port_t server_priv_port = MACH_PORT_NULL; // even extra-slow clients a fair chance before we cut them off. #define MDNS_MM_TIMEOUT 250 -static int restarting_via_mach_init = 0; -static int started_via_launchdaemon = 0; +static int restarting_via_mach_init = 0; // Used on Jaguar/Panther when daemon is started via mach_init mechanism +static int started_via_launchdaemon = 0; // Indicates we're running on Tiger or later, where daemon is managed by launchd static int OSXVers; +static CFRunLoopRef CFRunLoop; + //************************************************************************************************************* // Active client list structures @@ -709,7 +437,7 @@ typedef struct ServiceInstance struct ServiceInstance *next; mach_port_t ClientMachPort; mDNSBool autoname; // Set if this name is tied to the Computer Name - mDNSBool autorename; // Set if we just got a name conflict and now need to automatically pick a new name + mDNSBool renameonmemfree; // Set if we just got a name conflict and now need to automatically pick a new name domainlabel name; domainname domain; ServiceRecordSet srs; @@ -742,66 +470,126 @@ static DNSServiceBrowser *DNSServiceBrowserList = NULL; static DNSServiceResolver *DNSServiceResolverList = NULL; static DNSServiceRegistration *DNSServiceRegistrationList = NULL; +// We keep a list of client-supplied event sources in KQSocketEventSource records +typedef struct KQSocketEventSource + { + struct KQSocketEventSource *next; + int fd; + KQueueEntry kqs; + } KQSocketEventSource; + +static KQSocketEventSource *gEventSources; + //************************************************************************************************************* // General Utility Functions -#if MACOSX_MDNS_MALLOC_DEBUGGING +#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING char _malloc_options[] = "AXZ"; +mDNSexport void LogMemCorruption(const char *format, ...) + { + char buffer[512]; + va_list ptr; + va_start(ptr,format); + buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0; + va_end(ptr); + LogMsg("!!!! %s !!!!", buffer); + NotifyOfElusiveBug("Memory Corruption", buffer); +#if ForceAlerts + *(long*)0 = 0; // Trick to crash and get a stack trace right here, if that's what we want +#endif + } + mDNSlocal void validatelists(mDNS *const m) { - DNSServiceDomainEnumeration *e; - DNSServiceBrowser *b; - DNSServiceResolver *l; - DNSServiceRegistration *r; - AuthRecord *rr; - CacheGroup *cg; - CacheRecord *cr; - DNSQuestion *q; - mDNSu32 slot; - NetworkInterfaceInfoOSX *i; + // Check local lists + KQSocketEventSource *k; + for (k = gEventSources; k; k=k->next) + if (k->next == (KQSocketEventSource *)~0 || k->fd < 0) + LogMemCorruption("gEventSources: %p is garbage (%d)", k, k->fd); + // Check Mach client lists + DNSServiceDomainEnumeration *e; for (e = DNSServiceDomainEnumerationList; e; e=e->next) - if (e->ClientMachPort == 0 || e->ClientMachPort == (mach_port_t)~0) - LogMsg("!!!! DNSServiceDomainEnumerationList: %p is garbage (%X) !!!!", e, e->ClientMachPort); + if (e->next == (DNSServiceDomainEnumeration *)~0 || e->ClientMachPort == 0 || e->ClientMachPort == (mach_port_t)~0) + LogMemCorruption("DNSServiceDomainEnumerationList: %p is garbage (%X)", e, e->ClientMachPort); + DNSServiceBrowser *b; for (b = DNSServiceBrowserList; b; b=b->next) - if (b->ClientMachPort == 0 || b->ClientMachPort == (mach_port_t)~0) - LogMsg("!!!! DNSServiceBrowserList: %p is garbage (%X) !!!!", b, b->ClientMachPort); + if (b->next == (DNSServiceBrowser *)~0 || b->ClientMachPort == 0 || b->ClientMachPort == (mach_port_t)~0) + LogMemCorruption("DNSServiceBrowserList: %p is garbage (%X)", b, b->ClientMachPort); + DNSServiceResolver *l; for (l = DNSServiceResolverList; l; l=l->next) - if (l->ClientMachPort == 0 || l->ClientMachPort == (mach_port_t)~0) - LogMsg("!!!! DNSServiceResolverList: %p is garbage (%X) !!!!", l, l->ClientMachPort); + if (l->next == (DNSServiceResolver *)~0 || l->ClientMachPort == 0 || l->ClientMachPort == (mach_port_t)~0) + LogMemCorruption("DNSServiceResolverList: %p is garbage (%X)", l, l->ClientMachPort); + DNSServiceRegistration *r; for (r = DNSServiceRegistrationList; r; r=r->next) - if (r->ClientMachPort == 0 || r->ClientMachPort == (mach_port_t)~0) - LogMsg("!!!! DNSServiceRegistrationList: %p is garbage (%X) !!!!", r, r->ClientMachPort); + if (r->next == (DNSServiceRegistration *)~0 || r->ClientMachPort == 0 || r->ClientMachPort == (mach_port_t)~0) + LogMemCorruption("DNSServiceRegistrationList: %p is garbage (%X)", r, r->ClientMachPort); + + // Check Unix Domain Socket client lists (uds_daemon.c) + uds_validatelists(); + // Check core mDNS lists + AuthRecord *rr; for (rr = m->ResourceRecords; rr; rr=rr->next) { - if (rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF) - LogMsg("!!!! ResourceRecords list: %p is garbage (%X) !!!!", rr, rr->resrec.RecordType); + if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF) + LogMemCorruption("ResourceRecords list: %p is garbage (%X)", rr, rr->resrec.RecordType); if (rr->resrec.name != &rr->namestorage) - LogMsg("!!!! ResourceRecords list: %p name %p does not point to namestorage %p %##s", + LogMemCorruption("ResourceRecords list: %p name %p does not point to namestorage %p %##s", rr, rr->resrec.name->c, rr->namestorage.c, rr->namestorage.c); } for (rr = m->DuplicateRecords; rr; rr=rr->next) - if (rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF) - LogMsg("!!!! DuplicateRecords list: %p is garbage (%X) !!!!", rr, rr->resrec.RecordType); + if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF) + LogMemCorruption("DuplicateRecords list: %p is garbage (%X)", rr, rr->resrec.RecordType); + + rr = m->NewLocalRecords; + if (rr) + if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF) + LogMemCorruption("NewLocalRecords: %p is garbage (%X)", rr, rr->resrec.RecordType); + + rr = m->CurrentRecord; + if (rr) + if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF) + LogMemCorruption("CurrentRecord: %p is garbage (%X)", rr, rr->resrec.RecordType); + DNSQuestion *q; for (q = m->Questions; q; q=q->next) - if (q->ThisQInterval == (mDNSs32)~0) - LogMsg("!!!! Questions list: %p is garbage (%lX) !!!!", q, q->ThisQInterval); + if (q->next == (DNSQuestion*)~0 || q->ThisQInterval == (mDNSs32)~0) + LogMemCorruption("Questions list: %p is garbage (%lX %p)", q, q->ThisQInterval, q->next); + CacheGroup *cg; + CacheRecord *cr; + mDNSu32 slot; FORALL_CACHERECORDS(slot, cg, cr) + { if (cr->resrec.RecordType == 0 || cr->resrec.RecordType == 0xFF) - LogMsg("!!!! Cache slot %lu: %p is garbage (%X) !!!!", slot, rr, rr->resrec.RecordType); + LogMemCorruption("Cache slot %lu: %p is garbage (%X)", slot, cr, cr->resrec.RecordType); + if (cr->CRActiveQuestion) + { + for (q = m->Questions; q; q=q->next) if (q == cr->CRActiveQuestion) break; + if (!q) LogMemCorruption("Cache slot %lu: CRActiveQuestion %p not in m->Questions list %s", slot, cr->CRActiveQuestion, CRDisplayString(m, cr)); + } + } + // Check core uDNS lists + udns_validatelists(m); + + // Check platform-layer lists + NetworkInterfaceInfoOSX *i; for (i = m->p->InterfaceList; i; i = i->next) - if (!i->ifa_name) - LogMsg("!!!! InterfaceList: %p is garbage !!!!", i); + if (i->next == (NetworkInterfaceInfoOSX *)~0 || !i->ifa_name || i->ifa_name == (char *)~0) + LogMemCorruption("m->p->InterfaceList: %p is garbage (%p)", i, i->ifa_name); + + ClientTunnel *t; + for (t = m->TunnelClients; t; t=t->next) + if (t->next == (ClientTunnel *)~0 || t->dstname.c[0] > 63) + LogMemCorruption("m->TunnelClients: %p is garbage (%d)", t, t->dstname.c[0]); } void *mallocL(char *msg, unsigned int size) @@ -814,10 +602,11 @@ void *mallocL(char *msg, unsigned int size) } else { - LogMalloc("malloc( %s : %lu ) = %p", msg, size, &mem[2]); + if (size > 24000) LogMsg("malloc( %s : %lu ) = %p suspiciously large", msg, size, &mem[2]); + else if (MACOSX_MDNS_MALLOC_DEBUGGING >= 2) LogMsg("malloc( %s : %lu ) = %p", msg, size, &mem[2]); mem[0] = 0xDEAD1234; mem[1] = size; - //bzero(&mem[2], size); + //mDNSPlatformMemZero(&mem[2], size); memset(&mem[2], 0xFF, size); validatelists(&mDNSStorage); return(&mem[2]); @@ -831,12 +620,10 @@ void freeL(char *msg, void *x) else { unsigned long *mem = ((unsigned long *)x) - 2; - if (mem[0] != 0xDEAD1234) - { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg, &mem[2]); return; } - if (mem[1] > 24000) - { LogMsg("free( %s : %ld @ %p) too big!", msg, mem[1], &mem[2]); return; } - LogMalloc("free( %s : %ld @ %p)", msg, mem[1], &mem[2]); - //bzero(mem, mem[1]+8); + if (mem[0] != 0xDEAD1234) { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg, &mem[2]); return; } + if (mem[1] > 24000) LogMsg("free( %s : %ld @ %p) suspiciously large", msg, mem[1], &mem[2]); + else if (MACOSX_MDNS_MALLOC_DEBUGGING >= 2) LogMsg("free( %s : %ld @ %p)", msg, mem[1], &mem[2]); + //mDNSPlatformMemZero(mem, mem[1]+8); memset(mem, 0xFF, mem[1]+8); validatelists(&mDNSStorage); free(mem); @@ -848,12 +635,13 @@ void freeL(char *msg, void *x) //************************************************************************************************************* // Client Death Detection +// This gets called after ALL constituent records of the Service Record Set have been deregistered mDNSlocal void FreeServiceInstance(ServiceInstance *x) { ServiceRecordSet *s = &x->srs; ExtraResourceRecord *e = x->srs.Extras, *tmp; - while(e) + while (e) { e->r.RecordContext = e; tmp = e; @@ -862,7 +650,7 @@ mDNSlocal void FreeServiceInstance(ServiceInstance *x) } if (s->RR_TXT.resrec.rdata != &s->RR_TXT.rdatastorage) - freeL("TXT RData", s->RR_TXT.resrec.rdata); + freeL("TXT RData", s->RR_TXT.resrec.rdata); if (s->SubTypes) freeL("ServiceSubTypes", s->SubTypes); freeL("ServiceInstance", x); @@ -902,8 +690,8 @@ mDNSlocal void AbortClient(mach_port_t ClientMachPort, void *m) while (qptr) { if (m && m != x) - LogMsg("%5d: DNSServiceBrowser(%##s) STOP; WARNING m %p != x %p", ClientMachPort, qptr->q.qname.c, m, x); - else LogOperation("%5d: DNSServiceBrowser(%##s) STOP", ClientMachPort, qptr->q.qname.c); + LogMsg("%5d: DNSServiceBrowse(%##s) STOP; WARNING m %p != x %p", ClientMachPort, qptr->q.qname.c, m, x); + else LogOperation("%5d: DNSServiceBrowse(%##s) STOP", ClientMachPort, qptr->q.qname.c); mDNS_StopBrowse(&mDNSStorage, &qptr->q); freePtr = qptr; qptr = qptr->next; @@ -925,8 +713,8 @@ mDNSlocal void AbortClient(mach_port_t ClientMachPort, void *m) DNSServiceResolver *x = *l; *l = (*l)->next; if (m && m != x) - LogMsg("%5d: DNSServiceResolver(%##s) STOP; WARNING m %p != x %p", ClientMachPort, x->i.name.c, m, x); - else LogOperation("%5d: DNSServiceResolver(%##s) STOP", ClientMachPort, x->i.name.c); + LogMsg("%5d: DNSServiceResolve(%##s) STOP; WARNING m %p != x %p", ClientMachPort, x->i.name.c, m, x); + else LogOperation("%5d: DNSServiceResolve(%##s) STOP", ClientMachPort, x->i.name.c); mDNS_StopResolveService(&mDNSStorage, &x->q); freeL("DNSServiceResolver", x); return; @@ -944,8 +732,8 @@ mDNSlocal void AbortClient(mach_port_t ClientMachPort, void *m) { ServiceInstance *instance = si; si = si->next; - instance->autorename = mDNSfalse; - if (m && m != x) LogMsg("%5d: DNSServiceRegistration(%##s, %u) STOP; WARNING m %p != x %p", ClientMachPort, instance->srs.RR_SRV.resrec.name->c, SRS_PORT(&instance->srs), m, x); + instance->renameonmemfree = mDNSfalse; + if (m && m != x) LogMsg("%5d: DNSServiceRegistration(%##s, %u) STOP; WARNING m %p != x %p", ClientMachPort, instance->srs.RR_SRV.resrec.name->c, SRS_PORT(&instance->srs), m, x); else LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort, instance->srs.RR_SRV.resrec.name->c, SRS_PORT(&instance->srs)); // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list, @@ -954,7 +742,7 @@ mDNSlocal void AbortClient(mach_port_t ClientMachPort, void *m) // the list, so we should go ahead and free the memory right now if (mDNS_DeregisterService(&mDNSStorage, &instance->srs)) FreeServiceInstance(instance); // FreeServiceInstance invalidates pointer } - x->regs = NULL; + x->regs = NULL; freeL("DNSServiceRegistration", x); return; } @@ -976,19 +764,21 @@ mDNSlocal void AbortClientWithLogMessage(mach_port_t c, char *reason, char *msg, while (b && b->ClientMachPort != c) b = b->next; while (l && l->ClientMachPort != c) l = l->next; while (r && r->ClientMachPort != c) r = r->next; - if (e) LogMsg("%5d: DomainEnumeration(%##s) %s%s", c, e->dom.qname.c, reason, msg); + + if (e) LogMsg("%5d: DomainEnumeration(%##s) %s%s", c, e->dom.qname.c, reason, msg); else if (b) - { - for (qptr = b->qlist; qptr; qptr = qptr->next) - LogMsg("%5d: Browser(%##s) %s%s", c, qptr->q.qname.c, reason, msg); - } - else if (l) LogMsg("%5d: Resolver(%##s) %s%s", c, l->i.name.c, reason, msg); + { + for (qptr = b->qlist; qptr; qptr = qptr->next) + LogMsg("%5d: Browser(%##s) %s%s", c, qptr->q.qname.c, reason, msg); + } + else if (l) LogMsg("%5d: Resolver(%##s) %s%s", c, l->i.name.c, reason, msg); else if (r) - { - ServiceInstance *si; - for (si = r->regs; si; si = si->next) LogMsg("%5d: Registration(%##s) %s%s", c, si->srs.RR_SRV.resrec.name->c, reason, msg); - } - else LogMsg("%5d: (%s) %s, but no record of client can be found!", c, reason, msg); + { + ServiceInstance *si; + for (si = r->regs; si; si = si->next) + LogMsg("%5d: Registration(%##s) %s%s", c, si->srs.RR_SRV.resrec.name->c, reason, msg); + } + else LogMsg("%5d: (%s) %s, but no record of client can be found!", c, reason, msg); AbortClient(c, m); } @@ -1018,6 +808,7 @@ mDNSlocal mDNSBool CheckForExistingClient(mach_port_t c) mDNSlocal void ClientDeathCallback(CFMachPortRef unusedport, void *voidmsg, CFIndex size, void *info) { + KQueueLock(&mDNSStorage); mach_msg_header_t *msg = (mach_msg_header_t *)voidmsg; (void)unusedport; // Unused (void)size; // Unused @@ -1030,6 +821,7 @@ mDNSlocal void ClientDeathCallback(CFMachPortRef unusedport, void *voidmsg, CFIn /* Deallocate the send right that came in the dead name notification */ mach_port_destroy(mach_task_self(), deathMessage->not_port); } + KQueueUnlock(&mDNSStorage, "Mach AbortClient"); } mDNSlocal void EnableDeathNotificationForClient(mach_port_t ClientMachPort, void *m) @@ -1045,13 +837,13 @@ mDNSlocal void EnableDeathNotificationForClient(mach_port_t ClientMachPort, void //************************************************************************************************************* // Domain Enumeration -mDNSlocal void DomainEnumFound(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) +mDNSlocal void DomainEnumFound(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) { kern_return_t status; - #pragma unused(m) char buffer[MAX_ESCAPED_DOMAIN_NAME]; DNSServiceDomainEnumerationReplyResultType rt; DNSServiceDomainEnumeration *x = (DNSServiceDomainEnumeration *)question->QuestionContext; + (void)m; // Unused debugf("DomainEnumFound: %##s PTR %##s", answer->name->c, answer->rdata->u.name.c); if (answer->rrtype != kDNSType_PTR) return; @@ -1121,7 +913,7 @@ fail: //************************************************************************************************************* // Browse for services -mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) +mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) { (void)m; // Unused @@ -1151,6 +943,9 @@ mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const Resourc DNSServiceBrowserResult **p = &browser->results; while (*p) p = &(*p)->next; *p = x; + + LogOperation("%5d: DNSServiceBrowse(%##s, %s) RESULT %s %s", + browser->ClientMachPort, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer)); } mDNSlocal mStatus AddDomainToBrowser(DNSServiceBrowser *browser, const domainname *d) @@ -1175,11 +970,9 @@ mDNSlocal mStatus AddDomainToBrowser(DNSServiceBrowser *browser, const domainnam return err; } -mDNSexport void DefaultBrowseDomainChanged(const domainname *d, mDNSBool add) +mDNSexport void machserver_automatic_browse_domain_changed(const domainname *d, mDNSBool add) { DNSServiceBrowser *ptr; - - debugf("DefaultBrowseDomainChanged: %s default browse domain %##s", add ? "Adding" : "Removing", d->c); for (ptr = DNSServiceBrowserList; ptr; ptr = ptr->next) { if (ptr->DefaultDomain) @@ -1198,17 +991,10 @@ mDNSexport void DefaultBrowseDomainChanged(const domainname *d, mDNSBool add) { DNSServiceBrowserQuestion *remove = *q; *q = (*q)->next; - if (remove->q.LongLived) - { - // give goodbyes for known answers. note that since events are sent to client via udns_execute(), - // we don't need to worry about the question being cancelled mid-loop - CacheRecord *ka = remove->q.uDNS_info.knownAnswers; - while (ka) { remove->q.QuestionCallback(&mDNSStorage, &remove->q, &ka->resrec, mDNSfalse); ka = ka->next; } - } - mDNS_StopBrowse(&mDNSStorage, &remove->q); + mDNS_StopQueryWithRemoves(&mDNSStorage, &remove->q); freeL("DNSServiceBrowserQuestion", remove ); - return; - } + return; + } q = &(*q)->next; } LogMsg("Requested removal of default domain %##s not in client %5d's list", d->c, ptr->ClientMachPort); @@ -1224,7 +1010,6 @@ mDNSexport kern_return_t provide_DNSServiceBrowserCreate_rpc(mach_port_t unuseds (void)unusedserver; // Unused mStatus err = mStatus_NoError; const char *errormsg = "Unknown"; - DNameListElem *SearchDomains = NULL, *sdPtr; if (client == (mach_port_t)-1) { err = mStatus_Invalid; errormsg = "Client id -1 invalid"; goto fail; } if (CheckForExistingClient(client)) { err = mStatus_Invalid; errormsg = "Client id already in use"; goto fail; } @@ -1258,17 +1043,17 @@ mDNSexport kern_return_t provide_DNSServiceBrowserCreate_rpc(mach_port_t unuseds { // Start browser for an explicit domain x->DefaultDomain = mDNSfalse; - if (!MakeDomainNameFromDNSNameString(&d, domain)) { errormsg = "Illegal domain"; goto badparam; } + if (!MakeDomainNameFromDNSNameString(&d, domain)) { errormsg = "Illegal domain"; goto badparam; } err = AddDomainToBrowser(x, &d); if (err) { AbortClient(client, x); errormsg = "AddDomainToBrowser"; goto fail; } } else { + DNameListElem *sdPtr; // Start browser on all domains x->DefaultDomain = mDNStrue; - SearchDomains = mDNSPlatformGetSearchDomainList(); - if (!SearchDomains) { AbortClient(client, x); errormsg = "GetSearchDomainList"; goto fail; } - for (sdPtr = SearchDomains; sdPtr; sdPtr = sdPtr->next) + if (!AutoBrowseDomains) { AbortClient(client, x); errormsg = "GetSearchDomainList"; goto fail; } + for (sdPtr = AutoBrowseDomains; sdPtr; sdPtr = sdPtr->next) { err = AddDomainToBrowser(x, &sdPtr->name); if (err) @@ -1283,16 +1068,14 @@ mDNSexport kern_return_t provide_DNSServiceBrowserCreate_rpc(mach_port_t unuseds // Succeeded: Wrap up and return EnableDeathNotificationForClient(client, x); - mDNS_FreeDNameList(SearchDomains); return(mStatus_NoError); badparam: err = mStatus_BadParamErr; fail: LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", client, regtype, domain, errormsg, err); - if (SearchDomains) mDNS_FreeDNameList(SearchDomains); return(err); - } + } //************************************************************************************************************* // Resolve Service Info @@ -1313,8 +1096,8 @@ mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query) if (query->info->TXTlen > sizeof(cstring)) return; - bzero(&interface, sizeof(interface)); - bzero(&address, sizeof(address)); + mDNSPlatformMemZero(&interface, sizeof(interface)); + mDNSPlatformMemZero(&address, sizeof(address)); if (ifx && ifx->ifinfo.ip.type == mDNSAddrType_IPv4) { @@ -1331,7 +1114,7 @@ mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query) sin6->sin6_family = AF_INET6; sin6->sin6_flowinfo = 0; sin6->sin6_port = 0; - sin6->sin6_addr = *(struct in6_addr*)&ifx->ifinfo.ip.ip.v6; + sin6->sin6_addr = *(struct in6_addr*)&ifx->ifinfo.ip.ip.v6; sin6->sin6_scope_id = ifx->scope_id; } @@ -1350,7 +1133,7 @@ mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query) sin6->sin6_family = AF_INET6; sin6->sin6_port = query->info->port.NotAnInteger; sin6->sin6_flowinfo = 0; - sin6->sin6_addr = *(struct in6_addr*)&query->info->ip.ip.v6; + sin6->sin6_addr = *(struct in6_addr*)&query->info->ip.ip.v6; sin6->sin6_scope_id = ifx ? ifx->scope_id : 0; } @@ -1410,7 +1193,7 @@ mDNSexport kern_return_t provide_DNSServiceResolverResolve_rpc(mach_port_t unuse DNSServiceResolverList = x; // Do the operation - LogOperation("%5d: DNSServiceResolver(%##s) START", client, x->i.name.c); + LogOperation("%5d: DNSServiceResolve(%##s) START", client, x->i.name.c); err = mDNS_StartResolveService(&mDNSStorage, &x->q, &x->i, FoundInstanceInfo, x); if (err) { AbortClient(client, x); errormsg = "mDNS_StartResolveService"; goto fail; } @@ -1477,11 +1260,11 @@ mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus r else if (result == mStatus_MemFree) { - if (si->autorename) + if (si->renameonmemfree) // We intentionally terminated registration so we could re-register with new name { debugf("RegCallback renaming %#s to %#s", si->name.c, m->nicelabel.c); - si->autorename = mDNSfalse; - si->name = m->nicelabel; + si->renameonmemfree = mDNSfalse; + si->name = m->nicelabel; mDNS_RenameAndReregisterService(m, srs, &si->name); } else @@ -1490,18 +1273,11 @@ mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus r DNSServiceRegistration *r; for (r = DNSServiceRegistrationList; r; r = r->next) { - ServiceInstance *sp = r->regs, *prev = NULL; - while (sp) + ServiceInstance **sp = &r->regs; + while (*sp) { - if (sp == si) - { - LogMsg("RegCallback: %##s Still in DNSServiceRegistration list; removing now", srs->RR_SRV.resrec.name->c); - if (prev) prev->next = sp->next; - else r->regs = sp->next; - break; - } - prev = sp; - sp = sp->next; + if (*sp == si) { LogMsg("RegCallback: %##s Still in list; removing", srs->RR_SRV.resrec.name->c); *sp = (*sp)->next; break; } + sp = &(*sp)->next; } } // END SANITY CHECK @@ -1531,13 +1307,14 @@ mDNSlocal mStatus AddServiceInstance(DNSServiceRegistration *x, const domainname si = mallocL("ServiceInstance", sizeof(*si) - sizeof(RDataBody) + x->rdsize); if (!si) return mStatus_NoMemoryErr; - si->ClientMachPort = x->ClientMachPort; - si->autorename = mDNSfalse; - si->autoname = x->autoname; - si->name = x->autoname ? mDNSStorage.nicelabel : x->name; - si->domain = *domain; + si->ClientMachPort = x->ClientMachPort; + si->renameonmemfree = mDNSfalse; + si->autoname = x->autoname; + si->name = x->autoname ? mDNSStorage.nicelabel : x->name; + si->domain = *domain; - err = mDNS_RegisterService(&mDNSStorage, &si->srs, &si->name, &x->type, domain, NULL, x->port, x->txtinfo, x->txt_len, SubTypes, x->NumSubTypes, mDNSInterface_Any, RegCallback, si); + err = mDNS_RegisterService(&mDNSStorage, &si->srs, &si->name, &x->type, domain, NULL, + x->port, x->txtinfo, x->txt_len, SubTypes, x->NumSubTypes, mDNSInterface_Any, RegCallback, si); if (!err) { si->next = x->regs; @@ -1548,10 +1325,10 @@ mDNSlocal mStatus AddServiceInstance(DNSServiceRegistration *x, const domainname LogMsg("Error %d for registration of service in domain %##s", err, domain->c); freeL("ServiceInstance", si); } - return err; + return err; } -mDNSexport void DefaultRegDomainChanged(const domainname *d, mDNSBool add) +mDNSexport void machserver_automatic_registration_domain_changed(const domainname *d, mDNSBool add) { DNSServiceRegistration *reg; @@ -1560,27 +1337,23 @@ mDNSexport void DefaultRegDomainChanged(const domainname *d, mDNSBool add) if (reg->DefaultDomain) { if (add) - { AddServiceInstance(reg, d); - } else { - ServiceInstance *si = reg->regs, *prev = NULL; - while (si) + ServiceInstance **si = ®->regs; + while (*si) { - if (SameDomainName(&si->domain, d)) + if (SameDomainName(&(*si)->domain, d)) { - if (prev) prev->next = si->next; - else reg->regs = si->next; - if (mDNS_DeregisterService(&mDNSStorage, &si->srs)) - FreeServiceInstance(si); // only free memory synchronously on error + ServiceInstance *s = *si; + *si = (*si)->next; + if (mDNS_DeregisterService(&mDNSStorage, &s->srs)) FreeServiceInstance(s); // only free memory synchronously on error break; } - prev = si; - si = si->next; + si = &(*si)->next; } if (!si) debugf("Requested removal of default domain %##s not in client %5d's list", d, reg->ClientMachPort); // normal if registration failed - } + } } } } @@ -1652,7 +1425,7 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationCreate_rpc(mach_port_t un // Some clients use mDNS for lightweight copy protection, registering a pseudo-service with // a port number of zero. When two instances of the protected client are allowed to run on one // machine, we don't want to see misleading "Bogus client" messages in syslog and the console. - if (port.NotAnInteger) + if (!mDNSIPPortIsZero(port)) { int count = CountExistingRegistrations(&srv, port); if (count) @@ -1663,7 +1436,7 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationCreate_rpc(mach_port_t un // Allocate memory, and handle failure DNSServiceRegistration *x = mallocL("DNSServiceRegistration", sizeof(*x)); if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } - bzero(x, sizeof(*x)); + mDNSPlatformMemZero(x, sizeof(*x)); // Set up object, and link into list x->ClientMachPort = client; @@ -1676,7 +1449,7 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationCreate_rpc(mach_port_t un x->type = t; x->port = port; memcpy(x->txtinfo, txtinfo, 1024); - x->txt_len = data_len; + x->txt_len = data_len; x->NextRef = 0; x->regs = NULL; @@ -1691,11 +1464,10 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationCreate_rpc(mach_port_t un if (x->DefaultDomain) { - DNameListElem *ptr, *regdomains = mDNSPlatformGetRegDomainList(); - for (ptr = regdomains; ptr; ptr = ptr->next) + DNameListElem *ptr; + for (ptr = AutoRegistrationDomains; ptr; ptr = ptr->next) AddServiceInstance(x, &ptr->name); - mDNS_FreeDNameList(regdomains); - } + } // Succeeded: Wrap up and return EnableDeathNotificationForClient(client, x); @@ -1711,147 +1483,40 @@ fail: return(err); } -mDNSlocal CFUserNotificationRef gNotification = NULL; -mDNSlocal CFRunLoopSourceRef gNotificationRLS = NULL; -mDNSlocal domainlabel gNotificationPrefHostLabel; // The prefs as they were the last time we saw them -mDNSlocal domainlabel gNotificationPrefNiceLabel; -mDNSlocal domainlabel gNotificationUserHostLabel; // The prefs as they were the last time the user changed them -mDNSlocal domainlabel gNotificationUserNiceLabel; - -mDNSlocal void NotificationCallBackDismissed(CFUserNotificationRef userNotification, CFOptionFlags responseFlags) - { - (void)responseFlags; // Unused - if (userNotification != gNotification) LogMsg("NotificationCallBackDismissed: Wrong CFUserNotificationRef"); - if (gNotificationRLS) - { - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), gNotificationRLS, kCFRunLoopDefaultMode); - CFRelease(gNotificationRLS); - gNotificationRLS = NULL; - CFRelease(gNotification); - gNotification = NULL; - } - // By dismissing the alert, the user has conceptually acknowleged the rename. - // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".) - // If we get *another* conflict, the new alert should refer to the 'old'. - // name as now being "computer-2.local", not "computer.local" - gNotificationUserHostLabel = gNotificationPrefHostLabel; - gNotificationUserNiceLabel = gNotificationPrefNiceLabel; - } - -mDNSlocal void ShowNameConflictNotification(CFStringRef header, CFStringRef subtext) - { - CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (!dictionary) return; - CFDictionarySetValue(dictionary, kCFUserNotificationAlertHeaderKey, header); - CFDictionarySetValue(dictionary, kCFUserNotificationAlertMessageKey, subtext); - - CFURLRef urlRef = CFURLCreateWithFileSystemPath(NULL, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle, true); - if (urlRef) { CFDictionarySetValue(dictionary, kCFUserNotificationLocalizationURLKey, urlRef); CFRelease(urlRef); } - - if (gNotification) // If notification already on-screen, update it in place - CFUserNotificationUpdate(gNotification, 0, kCFUserNotificationCautionAlertLevel, dictionary); - else // else, we need to create it - { - SInt32 error; - gNotification = CFUserNotificationCreate(NULL, 0, kCFUserNotificationCautionAlertLevel, &error, dictionary); - if (!gNotification) { LogMsg("ShowNameConflictNotification: CFUserNotificationRef"); return; } - gNotificationRLS = CFUserNotificationCreateRunLoopSource(NULL, gNotification, NotificationCallBackDismissed, 0); - if (!gNotificationRLS) { LogMsg("ShowNameConflictNotification: RLS"); CFRelease(gNotification); gNotification = NULL; return; } - CFRunLoopAddSource(CFRunLoopGetCurrent(), gNotificationRLS, kCFRunLoopDefaultMode); - } - - CFRelease(dictionary); - } - -// This updates either the text of the field currently labelled "Local Hostname", -// or the text of the field currently labelled "Computer Name" -// in the Sharing Prefs Control Panel -mDNSlocal void RecordUpdatedName(const mDNS *const m, const domainlabel *const olddl, const domainlabel *const newdl, - const char *const msg, const char *const suffix, const CFStringRef subtext) - { - char oldname[MAX_DOMAIN_LABEL+1]; - char newname[MAX_DOMAIN_LABEL+1]; - ConvertDomainLabelToCString_unescaped(olddl, oldname); - ConvertDomainLabelToCString_unescaped(newdl, newname); - const CFStringRef cfoldname = CFStringCreateWithCString(NULL, oldname, kCFStringEncodingUTF8); - const CFStringRef cfnewname = CFStringCreateWithCString(NULL, newname, kCFStringEncodingUTF8); - const CFStringRef f1 = CFStringCreateWithCString(NULL, " “%@%s” ", kCFStringEncodingUTF8); - const CFStringRef f2 = CFStringCreateWithCString(NULL, " “%@%s” ", kCFStringEncodingUTF8); - const SCPreferencesRef session = SCPreferencesCreate(NULL, CFSTR("mDNSResponder"), NULL); - if (!cfoldname || !cfnewname || !f1 || !f2 || !session || !SCPreferencesLock(session, 0)) // If we can't get the lock don't wait - LogMsg("RecordUpdatedName: ERROR: Couldn't create SCPreferences session"); - else - { - const CFStringRef s0 = CFStringCreateWithCString(NULL, msg, kCFStringEncodingUTF8); - const CFStringRef s1 = CFStringCreateWithFormat(NULL, NULL, f1, cfoldname, suffix); - const CFStringRef s2 = CFStringCreateWithFormat(NULL, NULL, f2, cfnewname, suffix); - // On Tiger and later, if we pass an array instead of a string, CFUserNotification will translate each - // element of the array individually for us, and then concatenate the results to make the final message. - // This lets us have the relevant bits localized, but not the literal names, which should not be translated. - // On Panther this does not work, so we just build the string directly, and it will not be translated. - const CFMutableStringRef alertHeader = - (OSXVers < 8) ? CFStringCreateMutable(NULL, 0) : (CFMutableStringRef)CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - Boolean result; - if (newdl == &gNotificationPrefHostLabel) result = SCPreferencesSetLocalHostName(session, cfnewname); - else result = SCPreferencesSetComputerName(session, cfnewname, kCFStringEncodingUTF8); - if (!result || !SCPreferencesCommitChanges(session) || !SCPreferencesApplyChanges(session) || !s0 || !s1 || !s2 || !alertHeader) - LogMsg("RecordUpdatedName: ERROR: Couldn't update SCPreferences"); - else if (m->p->NotifyUser) - { - uid_t uid; - gid_t gid; - CFStringRef userName = SCDynamicStoreCopyConsoleUser(NULL, &uid, &gid); - if (userName) - { - CFRelease(userName); - typedef void CFStringAppendFN(CFMutableStringRef theString, CFStringRef appendedString); - CFStringAppendFN *const append = (OSXVers < 8) ? &CFStringAppend : (CFStringAppendFN*)&CFArrayAppendValue; - append(alertHeader, s0); - append(alertHeader, s1); - append(alertHeader, CFSTR("is already in use on this network.")); - append(alertHeader, CFSTR(" ")); - append(alertHeader, CFSTR("The name has been changed to")); - append(alertHeader, s2); - append(alertHeader, CFSTR("automatically.")); - ShowNameConflictNotification(alertHeader, subtext); - } - } - if (s0) CFRelease(s0); - if (s1) CFRelease(s1); - if (s2) CFRelease(s2); - if (alertHeader) CFRelease(alertHeader); - SCPreferencesUnlock(session); - } - if (cfoldname) CFRelease(cfoldname); - if (cfnewname) CFRelease(cfnewname); - if (f1) CFRelease(f1); - if (f2) CFRelease(f2); - if (session) CFRelease(session); - } - mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result) { (void)m; // Unused - if (result == mStatus_NoError) + if (result == mStatus_NoError) { + if (!SameDomainLabelCS(m->p->userhostlabel.c, m->hostlabel.c)) + LogOperation("Local Hostname changed from \"%#s.local\" to \"%#s.local\"", m->p->userhostlabel.c, m->hostlabel.c); // One second pause in case we get a Computer Name update too -- don't want to alert the user twice RecordUpdatedNiceLabel(m, mDNSPlatformOneSecond); } - else if (result == mStatus_ConfigChanged) + else if (result == mStatus_NameConflict) { - // If the user-specified hostlabel from System Configuration has changed since the last time - // we saw it, and *we* didn't change it, then that implies that the user has changed it, - // so we auto-dismiss the name conflict alert. - if (!SameDomainLabel(m->p->userhostlabel.c, gNotificationPrefHostLabel.c) || - !SameDomainLabel(m->p->usernicelabel.c, gNotificationPrefNiceLabel.c)) + LogOperation("Local Hostname conflict for \"%#s.local\"", m->hostlabel.c); + if (!m->p->HostNameConflict) m->p->HostNameConflict = NonZeroTime(m->timenow); + else if (m->timenow - m->p->HostNameConflict > 60 * mDNSPlatformOneSecond) { - gNotificationUserHostLabel = gNotificationPrefHostLabel = m->p->userhostlabel; - gNotificationUserNiceLabel = gNotificationPrefNiceLabel = m->p->usernicelabel; - // If we're showing a name conflict notification, and the user has manually edited - // the name to remedy the conflict, we should now remove the notification window. - if (gNotificationRLS) CFUserNotificationCancel(gNotification); + // Tell the helper we've given up + mDNSPreferencesSetName(kmDNSLocalHostName, &m->p->userhostlabel, NULL); } + } + else if (result == mStatus_GrowCache) + { + // Allocate another chunk of cache storage + CacheEntity *storage = mallocL("mStatus_GrowCache", sizeof(CacheEntity) * RR_CACHE_SIZE); + //LogOperation("GrowCache %d * %d = %d", sizeof(CacheEntity), RR_CACHE_SIZE, sizeof(CacheEntity) * RR_CACHE_SIZE); + if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE); + } + else if (result == mStatus_ConfigChanged) + { + // Tell the helper we've seen a change in the labels. It will dismiss the name conflict alert if needed. + mDNSPreferencesSetName(kmDNSComputerName, &m->p->usernicelabel, &m->nicelabel); + mDNSPreferencesSetName(kmDNSLocalHostName, &m->p->userhostlabel, &m->hostlabel); + // First we check our list of old Mach-based registered services, to see if any need to be updated to a new name DNSServiceRegistration *r; for (r = DNSServiceRegistrationList; r; r=r->next) if (r->autoname) @@ -1859,22 +1524,18 @@ mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result) ServiceInstance *si; for (si = r->regs; si; si = si->next) { - if (!SameDomainLabel(si->name.c, m->nicelabel.c)) + if (!SameDomainLabelCS(si->name.c, m->nicelabel.c)) { debugf("NetworkChanged renaming %##s to %#s", si->srs.RR_SRV.resrec.name->c, m->nicelabel.c); - si->autorename = mDNStrue; + si->renameonmemfree = mDNStrue; if (mDNS_DeregisterService(m, &si->srs)) // If service deregistered already, we can re-register immediately RegCallback(m, &si->srs, mStatus_MemFree); } } } - udsserver_handle_configchange(); - } - else if (result == mStatus_GrowCache) - { - // Allocate another chunk of cache storage - CacheEntity *storage = mallocL("mStatus_GrowCache", sizeof(CacheEntity) * RR_CACHE_SIZE); - if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE); + + // Then we call into the UDS daemon code, to let it do the same + udsserver_handle_configchange(m); } } @@ -1904,7 +1565,7 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t id = x->NextRef++; *reference = (natural_t)id; for (si = x->regs; si; si = si->next) - { + { // Allocate memory, and handle failure ExtraResourceRecord *extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size); if (!extra) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } @@ -1933,7 +1594,7 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t return mStatus_NoError; fail: - LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client, x->name.c, type, data_len, errormsg, err); + LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%ld)", client, x ? x->name.c : (mDNSu8*)"\x8""«NULL»", type, data_len, errormsg, err); return mStatus_UnknownErr; } @@ -1949,7 +1610,7 @@ mDNSlocal mStatus UpdateRecord(ServiceRecordSet *srs, mach_port_t client, AuthRe // Check client parameter mStatus err = mStatus_NoError; const char *errormsg = "Unknown"; - domainname *name = (domainname *)""; + const domainname *name = (const domainname *)""; name = srs->RR_SRV.resrec.name; @@ -1994,7 +1655,7 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationUpdateRecord_rpc(mach_por // Check client parameter mStatus err = mStatus_NoError; const char *errormsg = "Unknown"; - domainname *name = (domainname *)""; + const domainname *name = (const domainname *)""; ServiceInstance *si; (void)unusedserver; // unused @@ -2035,7 +1696,7 @@ fail: mDNSlocal mStatus RemoveRecord(ServiceRecordSet *srs, ExtraResourceRecord *extra, mach_port_t client) { - domainname *name = srs->RR_SRV.resrec.name; + const domainname *const name = srs->RR_SRV.resrec.name; mStatus err = mStatus_NoError; // Do the operation @@ -2095,6 +1756,8 @@ mDNSlocal void DNSserverCallback(CFMachPortRef port, void *msg, CFIndex size, vo (void)size; // Unused (void)info; // Unused + KQueueLock(&mDNSStorage); + /* allocate a reply buffer */ reply = CFAllocatorAllocate(NULL, provide_DNSServiceDiscoveryRequest_subsystem.maxsize, 0); @@ -2112,7 +1775,7 @@ mDNSlocal void DNSserverCallback(CFMachPortRef port, void *msg, CFIndex size, vo * user or the remote one, we pretend it's ok. */ CFAllocatorDeallocate(NULL, reply); - return; + goto done; } /* @@ -2129,7 +1792,7 @@ mDNSlocal void DNSserverCallback(CFMachPortRef port, void *msg, CFIndex size, vo if (reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) mach_msg_destroy(&reply->Head); CFAllocatorDeallocate(NULL, reply); - return; + goto done; } /* @@ -2171,6 +1834,9 @@ mDNSlocal void DNSserverCallback(CFMachPortRef port, void *msg, CFIndex size, vo } CFAllocatorDeallocate(NULL, reply); + +done: + KQueueUnlock(&mDNSStorage, "Mach client event"); } mDNSlocal kern_return_t registerBootstrapService() @@ -2235,10 +1901,11 @@ mDNSlocal kern_return_t destroyBootstrapService() mDNSlocal void ExitCallback(int signal) { + (void)signal; // Unused LogMsgIdent(mDNSResponderVersionString, "stopping"); debugf("ExitCallback"); - if (!mDNS_DebugMode && !started_via_launchdaemon && signal != SIGHUP) + if (!mDNS_DebugMode && !started_via_launchdaemon) destroyBootstrapService(); debugf("ExitCallback: Aborting MIG clients"); @@ -2253,7 +1920,7 @@ mDNSlocal void ExitCallback(int signal) debugf("ExitCallback: mDNS_Close"); mDNS_Close(&mDNSStorage); - if (udsserver_exit() < 0) LogMsg("ExitCallback: udsserver_exit failed"); + if (udsserver_exit(launchd_fd) < 0) LogMsg("ExitCallback: udsserver_exit failed"); exit(0); } @@ -2271,7 +1938,7 @@ mDNSlocal void HandleSIG(int signal) if (mach_msg_send(&header) != MACH_MSG_SUCCESS) { LogMsg("HandleSIG %d: mach_msg_send failed", signal); - if (signal == SIGHUP || signal == SIGTERM || signal == SIGINT) exit(-1); + if (signal == SIGTERM || signal == SIGINT) exit(-1); } } @@ -2283,47 +1950,89 @@ mDNSlocal void INFOCallback(void) DNSServiceResolver *l; DNSServiceRegistration *r; NetworkInterfaceInfoOSX *i; + DNSServer *s; LogMsgIdent(mDNSResponderVersionString, "---- BEGIN STATE LOG ----"); udsserver_info(&mDNSStorage); - for (e = DNSServiceDomainEnumerationList; e; e=e->next) - LogMsgNoIdent("%5d: Mach DomainEnumeration %##s", e->ClientMachPort, e->dom.qname.c); + LogMsgNoIdent("--------- Mach Clients ---------"); + if (!DNSServiceDomainEnumerationList && !DNSServiceBrowserList && !DNSServiceResolverList && !DNSServiceRegistrationList) + LogMsgNoIdent(""); + else + { + for (e = DNSServiceDomainEnumerationList; e; e=e->next) + LogMsgNoIdent("%5d: Mach DomainEnumeration %##s", e->ClientMachPort, e->dom.qname.c); + + for (b = DNSServiceBrowserList; b; b=b->next) + { + DNSServiceBrowserQuestion *qptr; + for (qptr = b->qlist; qptr; qptr = qptr->next) + LogMsgNoIdent("%5d: Mach ServiceBrowse %##s", b->ClientMachPort, qptr->q.qname.c); + } + for (l = DNSServiceResolverList; l; l=l->next) + LogMsgNoIdent("%5d: Mach ServiceResolve %##s", l->ClientMachPort, l->i.name.c); + + for (r = DNSServiceRegistrationList; r; r=r->next) + { + ServiceInstance *si; + for (si = r->regs; si; si = si->next) + LogMsgNoIdent("%5d: Mach ServiceInstance %##s %u", si->ClientMachPort, si->srs.RR_SRV.resrec.name->c, mDNSVal16(si->srs.RR_SRV.resrec.rdata->u.srv.port)); + } + } - for (b = DNSServiceBrowserList; b; b=b->next) + LogMsgNoIdent("----- KQSocketEventSources -----"); + if (!gEventSources) LogMsgNoIdent(""); + else { - DNSServiceBrowserQuestion *qptr; - for (qptr = b->qlist; qptr; qptr = qptr->next) - LogMsgNoIdent("%5d: Mach ServiceBrowse %##s", b->ClientMachPort, qptr->q.qname.c); + KQSocketEventSource *k; + for (k = gEventSources; k; k=k->next) + LogMsgNoIdent("%3d %s", k->fd, k->kqs.KQtask); } - for (l = DNSServiceResolverList; l; l=l->next) - LogMsgNoIdent("%5d: Mach ServiceResolve %##s", l->ClientMachPort, l->i.name.c); - for (r = DNSServiceRegistrationList; r; r=r->next) + LogMsgNoIdent("------ Network Interfaces ------"); + if (!mDNSStorage.p->InterfaceList) LogMsgNoIdent(""); + else { - ServiceInstance *si; - for (si = r->regs; si; si = si->next) - LogMsgNoIdent("%5d: Mach ServiceInstance %##s %u", si->ClientMachPort, si->srs.RR_SRV.resrec.name->c, mDNSVal16(si->srs.RR_SRV.resrec.rdata->u.srv.port)); + for (i = mDNSStorage.p->InterfaceList; i; i = i->next) + { + if (!i->Exists) + LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %#a dormant for %d seconds", + i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifa_name, i->scope_id, &i->BSSID, + &i->ifinfo.ip, utc - i->LastSeen); + else + LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %s %s %-15.4a %s InterfaceID %p %s %s %#a", + i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifa_name, i->scope_id, &i->BSSID, + i->ifinfo.InterfaceActive ? "Active" : " ", + i->ifinfo.IPv4Available ? "v4" : " ", + i->ifinfo.IPv4Available ? (mDNSv4Addr*)&i->ifa_v4addr : &zerov4Addr, + i->ifinfo.IPv6Available ? "v6" : " ", + i->ifinfo.InterfaceID, + i->ifinfo.Advertise ? "Adv" : " ", + i->ifinfo.McastTxRx ? "TxRx" : " ", + &i->ifinfo.ip); + } } - for (i = mDNSStorage.p->InterfaceList; i; i = i->next) + LogMsgNoIdent("--------- DNS Servers ----------"); + if (!mDNSStorage.DNSServers) LogMsgNoIdent(""); + else { - if (!i->Exists) - LogMsgNoIdent("Interface: %s %5s(%lu) %.6a DORMANT %d", - i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifa_name, i->scope_id, &i->BSSID, utc - i->LastSeen); - else - LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %s %s %2d %s %2d InterfaceID %p %s %s %#a", - i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifa_name, i->scope_id, &i->BSSID, - i->ifinfo.InterfaceActive ? "Active" : " ", - i->ifinfo.IPv4Available ? "v4" : " ", i->ss.sktv4, - i->ifinfo.IPv6Available ? "v6" : " ", i->ss.sktv6, - i->ifinfo.InterfaceID, - i->ifinfo.Advertise ? "Adv" : " ", - i->ifinfo.McastTxRx ? "TxRx" : " ", - &i->ifinfo.ip); + for (s = mDNSStorage.DNSServers; s; s = s->next) + { + NetworkInterfaceInfoOSX *ifx = (NetworkInterfaceInfoOSX *)s->interface; + LogMsgNoIdent("DNS Server %##s %s%s%#a:%d %s", + s->domain.c, ifx ? ifx->ifa_name : "", ifx ? " " : "", &s->addr, mDNSVal16(s->port), + s->teststate == DNSServer_Untested ? "(Untested)" : + s->teststate == DNSServer_Passed ? "" : + s->teststate == DNSServer_Failed ? "(Failed)" : + s->teststate == DNSServer_Disabled ? "(Disabled)" : "(Unknown state)"); + } } + mDNSs32 now = mDNS_TimeNow(&mDNSStorage); + LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now); + LogMsgIdent(mDNSResponderVersionString, "---- END STATE LOG ----"); } @@ -2332,17 +2041,27 @@ mDNSlocal void SignalCallback(CFMachPortRef port, void *msg, CFIndex size, void (void)port; // Unused (void)size; // Unused (void)info; // Unused - mach_msg_header_t *m = (mach_msg_header_t *)msg; - switch(m->msgh_id) + mach_msg_header_t *msg_header = (mach_msg_header_t *)msg; + KQueueLock(&mDNSStorage); + switch(msg_header->msgh_id) { - case SIGHUP: - case SIGINT: - case SIGTERM: ExitCallback(m->msgh_id); break; + case SIGHUP: { + mDNS *m = &mDNSStorage; + mDNSu32 slot; + CacheGroup *cg; + CacheRecord *rr; + LogMsg("SIGHUP: Purge cache"); + FORALL_CACHERECORDS(slot, cg, rr) mDNS_PurgeCacheResourceRecord(m, rr); + } break; + case SIGINT: + case SIGTERM: ExitCallback(msg_header->msgh_id); break; case SIGINFO: INFOCallback(); break; case SIGUSR1: LogMsg("SIGUSR1: Simulate Network Configuration Change Event"); mDNSMacOSXNetworkChanged(&mDNSStorage); break; - default: LogMsg("SignalCallback: Unknown signal %d", m->msgh_id); break; + case SIGUSR2: SigLogLevel(); break; + default: LogMsg("SignalCallback: Unknown signal %d", msg_header->msgh_id); break; } + KQueueUnlock(&mDNSStorage, "Unix Signal"); } // On 10.2 the MachServerName is DNSServiceDiscoveryServer @@ -2351,25 +2070,34 @@ mDNSlocal void SignalCallback(CFMachPortRef port, void *msg, CFIndex size, void mDNSlocal kern_return_t mDNSDaemonInitialize(void) { mStatus err; + CFMachPortRef s_port; + + // If launchd already created our Mach port for us, then use that, else we create a new one of our own + if (m_port != MACH_PORT_NULL) + s_port = CFMachPortCreateWithPort(NULL, m_port, DNSserverCallback, NULL, NULL); + else + { + s_port = CFMachPortCreate(NULL, DNSserverCallback, NULL, NULL); + m_port = CFMachPortGetPort(s_port); + char *MachServerName = OSXVers < 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder"; + kern_return_t status = bootstrap_register(bootstrap_port, MachServerName, m_port); + + if (status) + { + if (status == 1103) + LogMsg("Bootstrap_register failed(): A copy of the daemon is apparently already running"); + else + LogMsg("Bootstrap_register failed(): %s %d", mach_error_string(status), status); + return(status); + } + } + CFMachPortRef d_port = CFMachPortCreate(NULL, ClientDeathCallback, NULL, NULL); - CFMachPortRef s_port = CFMachPortCreate(NULL, DNSserverCallback, NULL, NULL); CFMachPortRef i_port = CFMachPortCreate(NULL, SignalCallback, NULL, NULL); - mach_port_t m_port = CFMachPortGetPort(s_port); - char *MachServerName = OSXVers < 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder"; - kern_return_t status = bootstrap_register(bootstrap_port, MachServerName, m_port); CFRunLoopSourceRef d_rls = CFMachPortCreateRunLoopSource(NULL, d_port, 0); CFRunLoopSourceRef s_rls = CFMachPortCreateRunLoopSource(NULL, s_port, 0); CFRunLoopSourceRef i_rls = CFMachPortCreateRunLoopSource(NULL, i_port, 0); - if (status) - { - if (status == 1103) - LogMsg("Bootstrap_register failed(): A copy of the daemon is apparently already running"); - else - LogMsg("Bootstrap_register failed(): %s %d", mach_error_string(status), status); - return(status); - } - err = mDNS_Init(&mDNSStorage, &PlatformStorage, rrcachestorage, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, @@ -2377,15 +2105,13 @@ mDNSlocal kern_return_t mDNSDaemonInitialize(void) if (err) { LogMsg("Daemon start: mDNS_Init failed %ld", err); return(err); } - gNotificationUserHostLabel = gNotificationPrefHostLabel = PlatformStorage.userhostlabel; - gNotificationUserNiceLabel = gNotificationPrefNiceLabel = PlatformStorage.usernicelabel; - client_death_port = CFMachPortGetPort(d_port); - signal_port = CFMachPortGetPort(i_port); + signal_port = CFMachPortGetPort(i_port); - CFRunLoopAddSource(CFRunLoopGetCurrent(), d_rls, kCFRunLoopDefaultMode); - CFRunLoopAddSource(CFRunLoopGetCurrent(), s_rls, kCFRunLoopDefaultMode); - CFRunLoopAddSource(CFRunLoopGetCurrent(), i_rls, kCFRunLoopDefaultMode); + CFRunLoop = CFRunLoopGetCurrent(); + CFRunLoopAddSource(CFRunLoop, d_rls, kCFRunLoopDefaultMode); + CFRunLoopAddSource(CFRunLoop, s_rls, kCFRunLoopDefaultMode); + CFRunLoopAddSource(CFRunLoop, i_rls, kCFRunLoopDefaultMode); CFRelease(d_rls); CFRelease(s_rls); CFRelease(i_rls); @@ -2471,23 +2197,18 @@ mDNSlocal mDNSs32 mDNSDaemonIdle(mDNS *const m) { if (m->p->NotifyUser - now < 0) { - if (!SameDomainLabel(m->p->usernicelabel.c, m->nicelabel.c)) + if (!SameDomainLabelCS(m->p->usernicelabel.c, m->nicelabel.c)) { - LogMsg("Updating Computer Name from \"%#s\" to \"%#s\"", m->p->usernicelabel.c, m->nicelabel.c); - gNotificationPrefNiceLabel = m->p->usernicelabel = m->nicelabel; - RecordUpdatedName(m, &gNotificationUserNiceLabel, &gNotificationPrefNiceLabel, "The name of your computer", "", - CFSTR("To change the name of your computer, open System Preferences and click Sharing. " - "Then type the name in the Computer Name field.")); - // Clear m->p->NotifyUser here -- even if the hostlabel has changed too, we don't want to bug the user with *two* alerts - m->p->NotifyUser = 0; + LogMsg("Name Conflict: Updated Computer Name from \"%#s\" to \"%#s\"", m->p->usernicelabel.c, m->nicelabel.c); + mDNSPreferencesSetName(kmDNSComputerName, &m->p->usernicelabel, &m->nicelabel); + m->p->usernicelabel = m->nicelabel; } - if (!SameDomainLabel(m->p->userhostlabel.c, m->hostlabel.c)) + if (!SameDomainLabelCS(m->p->userhostlabel.c, m->hostlabel.c)) { - LogMsg("Updating Local Hostname from \"%#s.local\" to \"%#s.local\"", m->p->userhostlabel.c, m->hostlabel.c); - gNotificationPrefHostLabel = m->p->userhostlabel = m->hostlabel; - RecordUpdatedName(m, &gNotificationUserHostLabel, &gNotificationPrefHostLabel, "This computer’s local hostname", ".local", - CFSTR("To change the local hostname, open System Preferences and click Sharing. " - "Then click Edit and type the name in the Local Hostname field.")); + LogMsg("Name Conflict: Updated Local Hostname from \"%#s.local\" to \"%#s.local\"", m->p->userhostlabel.c, m->hostlabel.c); + mDNSPreferencesSetName(kmDNSLocalHostName, &m->p->userhostlabel, &m->hostlabel); + m->p->HostNameConflict = 0; // Clear our indicator, now name change has been successful + m->p->userhostlabel = m->hostlabel; } m->p->NotifyUser = 0; } @@ -2505,6 +2226,8 @@ mDNSlocal void ShowTaskSchedulingError(mDNS *const m) LogMsg("Task Scheduling Error: Continuously busy for more than a second"); + // NOTE: To accurately diagnose *why* we're busy, the debugging code here to show needs to mirror the logic in GetNextScheduledEvent + if (m->NewQuestions && (!m->NewQuestions->DelayAnswering || m->timenow - m->NewQuestions->DelayAnswering >= 0)) LogMsg("Task Scheduling Error: NewQuestion %##s (%s)", m->NewQuestions->qname.c, DNSTypeName(m->NewQuestions->qtype)); @@ -2516,8 +2239,8 @@ mDNSlocal void ShowTaskSchedulingError(mDNS *const m) if (m->SuppressSending && m->timenow - m->SuppressSending >= 0) LogMsg("Task Scheduling Error: m->SuppressSending %d", m->timenow - m->SuppressSending); #ifndef UNICAST_DISABLED - if (m->timenow - m->uDNS_info.nextevent >= 0) - LogMsg("Task Scheduling Error: m->uDNS_info.nextevent %d", m->timenow - m->uDNS_info.nextevent); + if (m->timenow - m->NextuDNSEvent >= 0) + LogMsg("Task Scheduling Error: NextuDNSEvent %d", m->timenow - m->NextuDNSEvent); #endif if (m->timenow - m->NextCacheCheck >= 0) LogMsg("Task Scheduling Error: m->NextCacheCheck %d", m->timenow - m->NextCacheCheck); @@ -2527,27 +2250,253 @@ mDNSlocal void ShowTaskSchedulingError(mDNS *const m) LogMsg("Task Scheduling Error: m->NextScheduledProbe %d", m->timenow - m->NextScheduledProbe); if (m->timenow - m->NextScheduledResponse >= 0) LogMsg("Task Scheduling Error: m->NextScheduledResponse %d", m->timenow - m->NextScheduledResponse); + if (m->timenow - m->NextScheduledNATOp >= 0) + LogMsg("Task Scheduling Error: m->NextScheduledNATOp %d", m->timenow - m->NextScheduledNATOp); mDNS_Unlock(&mDNSStorage); } +mDNSlocal void KQWokenFlushBytes(int fd, __unused short filter, __unused void *context) + { + // Read all of the bytes so we won't wake again. + char buffer[100]; + ssize_t read = sizeof(buffer); + while (read > 0) read = recv(fd, buffer, sizeof(buffer), MSG_DONTWAIT); + } + +mDNSlocal void * KQueueLoop(void *m_param) + { + mDNS *m = m_param; + int numevents = 0; + +#if USE_SELECT_WITH_KQUEUEFD + fd_set readfds; + FD_ZERO(&readfds); + const int multiplier = 1000000 / mDNSPlatformOneSecond; +#else + const int multiplier = 1000000000 / mDNSPlatformOneSecond; +#endif + + pthread_mutex_lock(&PlatformStorage.BigMutex); + LogOperation("Starting time value 0x%08lX (%ld)", (mDNSu32)mDNSStorage.timenow_last, mDNSStorage.timenow_last); + + // This is the main work loop: + // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time + // (2) Then we make sure we've delivered all waiting browse messages to our clients + // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner + // (4) On wakeup we first process *all* events + // (5) then when no more events remain, we go back to (1) to finish off any deferred work and do it all again + for ( ; ; ) + { + #define kEventsToReadAtOnce 1 + struct kevent new_events[kEventsToReadAtOnce]; + + // Run mDNS_Execute to find out the time we next need to wake up + mDNSs32 start = mDNSPlatformRawTime(); + mDNSs32 nextTimerEvent = udsserver_idle(mDNSDaemonIdle(m)); + mDNSs32 end = mDNSPlatformRawTime(); + if (end - start >= WatchDogReportingThreshold) + LogOperation("WARNING: Idle task took %dms to complete", end - start); + + // Convert absolute wakeup time to a relative time from now + mDNSs32 ticks = nextTimerEvent - mDNS_TimeNow(m); + if (ticks < 1) ticks = 1; + + static mDNSs32 RepeatedBusy = 0; // Debugging sanity check, to guard against CPU spins + if (ticks > 1) + RepeatedBusy = 0; + else + { + ticks = 1; + if (++RepeatedBusy >= mDNSPlatformOneSecond) { ShowTaskSchedulingError(&mDNSStorage); RepeatedBusy = 0; } + } + + verbosedebugf("KQueueLoop: Handled %d events; now sleeping for %d ticks", numevents, ticks); + numevents = 0; + + // Release the lock, and sleep until: + // 1. Something interesting happens like a packet arriving, or + // 2. The other thread writes a byte to WakeKQueueLoopFD to poke us and make us wake up, or + // 3. The timeout expires + pthread_mutex_unlock(&PlatformStorage.BigMutex); + +#if USE_SELECT_WITH_KQUEUEFD + struct timeval timeout; + timeout.tv_sec = ticks / mDNSPlatformOneSecond; + timeout.tv_usec = (ticks % mDNSPlatformOneSecond) * multiplier; + FD_SET(KQueueFD, &readfds); + if (select(KQueueFD+1, &readfds, NULL, NULL, &timeout) < 0) + { LogMsg("select(%d) failed errno %d (%s)", KQueueFD, errno, strerror(errno)); sleep(1); } +#else + struct timespec timeout; + timeout.tv_sec = ticks / mDNSPlatformOneSecond; + timeout.tv_nsec = (ticks % mDNSPlatformOneSecond) * multiplier; + // In my opinion, you ought to be able to call kevent() with nevents set to zero, + // and have it work similarly to the way it does with nevents non-zero -- + // i.e. it waits until either an event happens or the timeout expires, and then wakes up. + // In fact, what happens if you do this is that it just returns immediately. So, we have + // to pass nevents set to one, and then we just ignore the event it gives back to us. -- SC + if (kevent(KQueueFD, NULL, 0, new_events, 1, &timeout) < 0) + { LogMsg("kevent(%d) failed errno %d (%s)", KQueueFD, errno, strerror(errno)); sleep(1); } +#endif + + pthread_mutex_lock(&PlatformStorage.BigMutex); + // We have to ignore the event we may have been told about above, because that + // was done without holding the lock, and between the time we woke up and the + // time we reclaimed the lock the other thread could have done something that + // makes the event no longer valid. Now we have the lock, we call kevent again + // and this time we can safely process the events it tells us about. + + static const struct timespec zero_timeout = { 0, 0 }; + int events_found; + while ((events_found = kevent(KQueueFD, NULL, 0, new_events, kEventsToReadAtOnce, &zero_timeout)) != 0) + { + if (events_found > kEventsToReadAtOnce || (events_found < 0 && errno != EINTR)) + { + // Not sure what to do here, our kqueue has failed us - this isn't ideal + LogMsg("ERROR: KQueueLoop - kevent failed errno %d (%s)", errno, strerror(errno)); + exit(errno); + } + + numevents += events_found; + + int i; + for (i = 0; i < events_found; i++) + { + const KQueueEntry *const kqentry = new_events[i].udata; + mDNSs32 start = mDNSPlatformRawTime(); +#if LogAllOperations || MDNS_DEBUGMSGS + const char *const KQtask = kqentry->KQtask; // Grab a copy in case KQcallback deletes the task +#endif + kqentry->KQcallback(new_events[i].ident, new_events[i].filter, kqentry->KQcontext); + mDNSs32 end = mDNSPlatformRawTime(); + if (end - start >= WatchDogReportingThreshold) + LogOperation("WARNING: %s took %dms to complete", KQtask, end - start); + } + } + } + + return NULL; + } + +mDNSlocal void LaunchdCheckin(void) + { + launch_data_t msg = launch_data_new_string(LAUNCH_KEY_CHECKIN); + launch_data_t resp = launch_msg(msg); + launch_data_free(msg); + if (!resp) { LogMsg("launch_msg returned NULL"); return; } + + if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO) + { + int err = launch_data_get_errno(resp); + // When running on Tiger with "ServiceIPC = false", we get "err == EACCES" to tell us there's no launchdata to fetch + if (err != EACCES) LogMsg("launch_msg returned %d", err); + else LogOperation("Launchd provided no launchdata; will open Mach port and Unix Domain Socket explicitly...", err); + } + else + { + launch_data_t skts = launch_data_dict_lookup(resp, LAUNCH_JOBKEY_SOCKETS); + if (!skts) LogMsg("launch_data_dict_lookup LAUNCH_JOBKEY_SOCKETS returned NULL"); + else + { + launch_data_t skt = launch_data_dict_lookup(skts, "Listeners"); + if (!skt) LogMsg("launch_data_dict_lookup Listeners returned NULL"); + else + { + launch_data_t s = launch_data_array_get_index(skt, 0); + if (!s) LogMsg("launch_data_array_get_index(skt, 0) returned NULL"); + else + { + launchd_fd = launch_data_get_fd(s); + LogOperation("Launchd Unix Domain Socket: %d", launchd_fd); + // In some early versions of 10.4.x, the permissions on the UDS were not set correctly, so we fix them here + chmod(MDNS_UDS_SERVERPATH, S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP | S_IROTH|S_IWOTH); + } + } + } + + launch_data_t ports = launch_data_dict_lookup(resp, "MachServices"); + if (!ports) LogMsg("launch_data_dict_lookup MachServices returned NULL"); + else + { + launch_data_t p = launch_data_dict_lookup(ports, "com.apple.mDNSResponder"); + if (!p) LogOperation("launch_data_array_get_index(ports, 0) returned NULL"); + else + { + m_port = launch_data_get_fd(p); + LogOperation("Launchd Mach Port: %d", m_port); + if (m_port == ~0U) m_port = MACH_PORT_NULL; + } + } + } + launch_data_free(resp); + } + +mDNSlocal void DropPrivileges(void) + { + static const char login[] = "_mdnsresponder"; + struct passwd *pwd = getpwnam(login); + if (NULL == pwd) + LogMsg("Could not find account name \"%s\". Running as root.", login); + else + { + uid_t uid = pwd->pw_uid; + gid_t gid = pwd->pw_gid; + + LogMsg("Started as root. Switching to userid \"%s\".", login); + + if (unlink(MDNS_UDS_SERVERPATH) < 0 && errno != ENOENT) LogMsg("DropPrivileges: Could not unlink \"%s\": (%d) %s", MDNS_UDS_SERVERPATH, errno, strerror(errno)); + else + { + static char path[] = "/var/run/mdns/mDNSResponder"; + char *p = strrchr(path, '/'); + *p = '\0'; + if (mkdir(path, 0755) < 0 && errno != EEXIST) LogMsg("DropPrivileges: Could not create directory \"%s\": (%d) %s", path, errno, strerror(errno)); + else if (chown(path, uid, gid) < 0) LogMsg("DropPrivileges: Could not chown directory \"%s\": (%d) %s", path, errno, strerror(errno)); + else + { + *p = '/'; + if (unlink(path) < 0 && errno != ENOENT) LogMsg("DropPrivileges: Could not unlink \"%s\": (%d) %s", path, errno, strerror(errno)); + else if (symlink(path, MDNS_UDS_SERVERPATH) < 0) LogMsg("DropPrivileges: Could not symlink \"%s\" -> \"%s\": (%d) %s", MDNS_UDS_SERVERPATH, path, errno, strerror(errno)); + else LogOperation("DropPrivileges: Created subdirectory and symlink"); + } + } + + if (0 != initgroups(login, gid)) LogMsg("initgroups(\"%s\", %lu) failed. Continuing.", login, (unsigned long)gid); + if (0 != setgid(gid)) LogMsg("setgid(%lu) failed. Continuing with group %lu privileges.", (unsigned long)getegid()); + if (0 != setuid(uid)) LogMsg("setuid(%lu) failed. Continuing as root after all.", (unsigned long)uid); + } + } + +extern int sandbox_init(const char *profile, uint64_t flags, char **errorbuf) __attribute__((weak_import)); + mDNSexport int main(int argc, char **argv) { int i; kern_return_t status; + pthread_t KQueueThread; + + LogMsgIdent(mDNSResponderVersionString, "starting"); + + if (0 == geteuid()) DropPrivileges(); for (i=1; ipw_uid); + i = pthread_mutex_init(&PlatformStorage.BigMutex, NULL); + if (i == -1) { LogMsg("pthread_mutex_init() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; } + + int fdpair[2] = {0, 0}; + i = socketpair(AF_UNIX, SOCK_STREAM, 0, fdpair); + if (i == -1) { LogMsg("socketpair() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; } + + // Socket pair returned us two identical sockets connected to each other + // We will use the first socket to send the second socket. The second socket + // will be added to the kqueue so it will wake when data is sent. + static const KQueueEntry wakeKQEntry = { KQWokenFlushBytes, NULL, "kqueue wakeup after CFRunLoop event" }; + PlatformStorage.WakeKQueueLoopFD = fdpair[0]; + KQueueSet(fdpair[1], EV_ADD, EVFILT_READ, &wakeKQEntry); + + // Invoke sandbox profile /usr/share/sandbox/mDNSResponder.sb +#if MDNS_NO_SANDBOX + LogMsg("Note: Compiled without Apple Sandbox support"); +#else + if (!sandbox_init) + LogMsg("Note: Running without Apple Sandbox support (not available on this OS)"); else - setuid(-2); // User "nobody" is -2; use that value if "nobody" does not appear in the password database + { + char *sandbox_msg; + int sandbox_err = sandbox_init("mDNSResponder", SANDBOX_NAMED, &sandbox_msg); + if (sandbox_err) { LogMsg("WARNING: sandbox_init error %s", sandbox_msg); sandbox_free_error(sandbox_msg); } + else LogOperation("Now running under Apple Sandbox restrictions"); + } #endif + OSXVers = mDNSMacOSXSystemBuildNumber(NULL); + status = mDNSDaemonInitialize(); + if (status) { LogMsg("Daemon start: mDNSDaemonInitialize failed"); goto exit; } + status = udsserver_init(launchd_fd); + if (status) { LogMsg("Daemon start: udsserver_init failed"); goto exit; } + + // Start the kqueue thread + i = pthread_create(&KQueueThread, NULL, KQueueLoop, &mDNSStorage); + if (i == -1) { LogMsg("pthread_create() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; } + if (status == 0) { - LogOperation("Starting time value 0x%08lX (%ld)", (mDNSu32)mDNSStorage.timenow_last, mDNSStorage.timenow_last); - int numevents = 0; - int RunLoopStatus = kCFRunLoopRunTimedOut; - - // This is the main work loop: - // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time - // (2) Then we make sure we've delivered all waiting browse messages to our clients - // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner - // (4) On wakeup we first process *all* events - // (5) then when no more events remain, we go back to (1) to finish off any deferred work and do it all again - while (RunLoopStatus == kCFRunLoopRunTimedOut) - { - // 1. Before going into a blocking wait call and letting our process to go sleep, - // call mDNSDaemonIdle to allow any deferred work to be completed. - mDNSs32 nextevent = mDNSDaemonIdle(&mDNSStorage); - nextevent = udsserver_idle(nextevent); - - // 2. Work out how long we expect to sleep before the next scheduled task - mDNSs32 ticks = nextevent - mDNS_TimeNow(&mDNSStorage); - static mDNSs32 RepeatedBusy = 0; // Debugging sanity check, to guard against CPU spins - if (ticks > 1) - RepeatedBusy = 0; - else - { - ticks = 1; - if (++RepeatedBusy >= mDNSPlatformOneSecond) { ShowTaskSchedulingError(&mDNSStorage); RepeatedBusy = 0; } - } - CFAbsoluteTime interval = (CFAbsoluteTime)ticks / (CFAbsoluteTime)mDNSPlatformOneSecond; - - // 3. Now do a blocking "CFRunLoopRunInMode" call so we sleep until - // (a) our next wakeup time, or (b) an event occurs. - // The 'true' parameter makes it return after handling any event that occurs - // This gives us chance to regain control so we can call mDNS_Execute() before sleeping again - verbosedebugf("main: Handled %d events; now sleeping for %d ticks", numevents, ticks); - numevents = 0; - RunLoopStatus = CFRunLoopRunInMode(kCFRunLoopDefaultMode, interval, true); - - // 4. Time to do some work? Handle all remaining events as quickly as we can, before returning to mDNSDaemonIdle() - while (RunLoopStatus == kCFRunLoopRunHandledSource) - { - numevents++; - RunLoopStatus = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0, true); - } - } - + CFRunLoopRun(); LogMsg("ERROR: CFRunLoopRun Exiting."); mDNS_Close(&mDNSStorage); } @@ -2643,94 +2572,48 @@ exit: return(status); } -// uds_daemon.c support routines ///////////////////////////////////////////// - -// We keep a list of client-supplied event sources in PosixEventSource records -struct CFSocketEventSource - { - udsEventCallback Callback; - void *Context; - int fd; - struct CFSocketEventSource *Next; - CFSocketRef cfs; - CFRunLoopSourceRef RLS; - }; -typedef struct CFSocketEventSource CFSocketEventSource; - -static GenLinkedList gEventSources; // linked list of CFSocketEventSource's - -mDNSlocal void cf_callback(CFSocketRef s, CFSocketCallBackType t, CFDataRef dr, const void *c, void *i) - // Called by CFSocket when data appears on socket - { - (void)s; // Unused - (void)t; // Unused - (void)dr; // Unused - (void)c; // Unused - CFSocketEventSource *source = (CFSocketEventSource*) i; - source->Callback(source->Context); - } +// uds_daemon.c support routines ///////////////////////////////////////////// +// Arrange things so that callback is called with context when data appears on fd mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context) - // Arrange things so that callback is called with context when data appears on fd { - CFSocketEventSource *newSource; - CFSocketContext cfContext = { 0, NULL, NULL, NULL, NULL }; - - if (gEventSources.LinkOffset == 0) - InitLinkedList(&gEventSources, offsetof(CFSocketEventSource, Next)); + KQSocketEventSource *newSource = (KQSocketEventSource*) mallocL("KQSocketEventSource", sizeof *newSource); + if (!newSource) return mStatus_NoMemoryErr; - if (fd >= FD_SETSIZE || fd < 0) - return mStatus_UnsupportedErr; - if (callback == NULL) - return mStatus_BadParamErr; - - newSource = (CFSocketEventSource*) calloc(1, sizeof *newSource); - if (NULL == newSource) - return mStatus_NoMemoryErr; - - newSource->Callback = callback; - newSource->Context = context; + mDNSPlatformMemZero(newSource, sizeof(*newSource)); newSource->fd = fd; + newSource->kqs.KQcallback = callback; + newSource->kqs.KQcontext = context; + newSource->kqs.KQtask = "UDS client"; - cfContext.info = newSource; - if ( NULL != (newSource->cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, - cf_callback, &cfContext)) && - NULL != (newSource->RLS = CFSocketCreateRunLoopSource(kCFAllocatorDefault, newSource->cfs, 0))) + if (KQueueSet(fd, EV_ADD, EVFILT_READ, &newSource->kqs) == 0) { - CFRunLoopAddSource(CFRunLoopGetCurrent(), newSource->RLS, kCFRunLoopDefaultMode); - AddToTail(&gEventSources, newSource); + KQSocketEventSource **p = &gEventSources; + while (*p) p = &(*p)->next; + *p = newSource; + return mStatus_NoError; } else { - if (newSource->cfs) - { - CFSocketInvalidate(newSource->cfs); // Note: Also closes the underlying socket - CFRelease(newSource->cfs); - } + close(fd); + free(newSource); return mStatus_NoMemoryErr; } - - return mStatus_NoError; } mStatus udsSupportRemoveFDFromEventLoop(int fd) // Note: This also CLOSES the file descriptor - // Reverse what was done in udsSupportAddFDToEventLoop(). { - CFSocketEventSource *iSource; - - for (iSource=(CFSocketEventSource*)gEventSources.Head; iSource; iSource = iSource->Next) + KQSocketEventSource **p = &gEventSources; + while (*p && (*p)->fd != fd) p = &(*p)->next; + if (*p) { - if (fd == iSource->fd) - { - RemoveFromList(&gEventSources, iSource); - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), iSource->RLS, kCFRunLoopDefaultMode); - CFRunLoopSourceInvalidate(iSource->RLS); - CFRelease(iSource->RLS); - CFSocketInvalidate(iSource->cfs); // Note: Also closes the underlying socket - CFRelease(iSource->cfs); - free(iSource); - return mStatus_NoError; - } + KQSocketEventSource *s = *p; + *p = (*p)->next; + // We don't have to explicitly do a kqueue EV_DELETE here because closing the fd + // causes the kernel to automatically remove any associated kevents + close(s->fd); + freeL("KQSocketEventSource", s); + return mStatus_NoError; } return mStatus_NoSuchNameErr; } @@ -2740,4 +2623,5 @@ const char *__crashreporter_info__ = mDNSResponderVersionString; asm(".desc ___crashreporter_info__, 0x10"); // For convenience when using the "strings" command, this is the last thing in the file -mDNSexport const char mDNSResponderVersionString[] = STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")"; +// The "@(#) " pattern is a special prefix the "what" command looks for +mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")"; diff --git a/mDNSMacOSX/helper-error.h b/mDNSMacOSX/helper-error.h new file mode 100644 index 0000000..767b167 --- /dev/null +++ b/mDNSMacOSX/helper-error.h @@ -0,0 +1,75 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2007 Apple Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + Change History (most recent first): + +$Log: helper-error.h,v $ +Revision 1.7 2007/09/12 00:42:47 mcguire + BTMM: Need to clean up security associations + +Revision 1.6 2007/09/04 22:32:58 mcguire + BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf + +Revision 1.5 2007/08/29 21:42:12 mcguire + BTMM: Duplicate Private DNS names are being added to DynamicStore + +Revision 1.4 2007/08/23 21:15:49 cheshire +Added $Log header + +Revision 1.3 2007/08/23 21:04:44 cheshire +Tidied up alignment of error message list + +Revision 1.2 2007/08/18 01:02:03 mcguire + No Bonjour services are getting registered at boot + +Revision 1.1 2007/08/08 22:34:58 mcguire + Security: Run mDNSResponder as user id mdnsresponder instead of root + + */ + +ERROR(kmDNSHelperCommunicationFailed, "Mach communication failed") +ERROR(kmDNSHelperNotAuthorized, "Not authorized") +ERROR(kmDNSHelperCreationFailed, "Object creation failed") +ERROR(kmDNSHelperInvalidPList, "Invalid property list") +ERROR(kmDNSHelperDynamicStoreFailed, "Could not create dynamic store session") +ERROR(kmDNSHelperDynamicStoreSetFailed, "Could not set dynamic store configuration") +ERROR(kmDNSHelperInvalidNameKey, "Invalid name key") +ERROR(kmDNSHelperInvalidConfigKey, "Invalid configuration key") +ERROR(kmDNSHelperTypeError, "Object was not of expected type") +ERROR(kmDNSHelperPreferencesFailed, "Could not create preferences session") +ERROR(kmDNSHelperPreferencesLockFailed, "Could not lock preferences") +ERROR(kmDNSHelperPreferencesSetFailed, "Could not update preferences") +ERROR(kmDNSHelperKeychainCopyDefaultFailed, "Could not copy keychain default") +ERROR(kmDNSHelperKeychainSearchCreationFailed, "Could not create keychain search") +ERROR(kmDNSHelperPListWriteFailed, "Could not write property list to stream") +ERROR(kmDNSHelperResultTooLarge, "Result too large") +ERROR(kmDNSHelperInterfaceCreationFailed, "Could not create auto-tunnel interface") +ERROR(kmDNSHelperInterfaceDeletionFailed, "Could not delete auto-tunnel interface") +ERROR(kmDNSHelperInvalidInterfaceState, "Invalid interface state requested") +ERROR(kmDNSHelperInvalidServerState, "Invalid server state requested") +ERROR(kmDNSHelperRacoonConfigCreationFailed, "Could not create racoon configuration file") +ERROR(kmDNSHelperRacoonStartFailed, "Could not start racoon") +ERROR(kmDNSHelperRacoonNotificationFailed, "Could not notify racoon") +ERROR(kmDNSHelperInvalidTunnelSetKeysOperation, "Invalid tunnel setkey operation requested") +ERROR(kmDNSHelperInvalidNetworkAddress, "Invalid network address") +ERROR(kmDNSHelperRouteAdditionFailed, "Could not add route") +ERROR(kmDNSHelperRouteDeletionFailed, "Could not remove route") +ERROR(kmDNSHelperRoutingSocketCreationFailed, "Could not create routing socket") +ERROR(kmDNSHelperDatagramSocketCreationFailed, "Could not create datagram socket") +ERROR(kmDNSHelperIPsecPolicyCreationFailed, "Could not create IPsec policy") +ERROR(kmDNSHelperIPsecPolicySetFailed, "Could not set IPsec policy") +ERROR(kmDNSHelperIPsecRemoveSAFailed, "Could not remove IPsec SA") +ERROR(kmDNSHelperIPsecPolicySocketCreationFailed, "Could not create IPsec policy socket") diff --git a/mDNSMacOSX/helper-main.c b/mDNSMacOSX/helper-main.c new file mode 100644 index 0000000..03efad4 --- /dev/null +++ b/mDNSMacOSX/helper-main.c @@ -0,0 +1,323 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2007 Apple Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + Change History (most recent first): + +$Log: helper-main.c,v $ +Revision 1.13 2007/09/21 16:13:14 cheshire +Additional Tiger compatibility fix: After bootstrap_check_in, we need to give +ourselves a Mach "send" right to the port, otherwise our ten-second idle timeout +mechanism is not able to send the "mDNSIdleExit" message to itself + +Revision 1.12 2007/09/20 22:26:20 cheshire +Add necessary bootstrap_check_in() in Tiger compatibility code (not used on Leopard) + +Revision 1.11 2007/09/18 19:09:02 cheshire + mDNSResponderHelper (and other binaries) missing SCCS version strings + +Revision 1.10 2007/09/09 02:21:17 mcguire + Leopard Server9A547(Insatll):mDNSResponderHelper crashing + +Revision 1.9 2007/09/07 22:44:03 mcguire + Move CFUserNotification code to mDNSResponderHelper + +Revision 1.8 2007/09/07 22:24:36 vazquez + Need to stop spewing mDNSResponderHelper logs + +Revision 1.7 2007/08/31 18:09:32 cheshire + Restore ability to run mDNSResponder on Tiger + +Revision 1.6 2007/08/31 17:45:13 cheshire +Allow maxidle time of zero, meaning "run indefinitely" + +Revision 1.5 2007/08/31 00:09:54 cheshire +Deleted extraneous whitespace (shortened code from 260 lines to 160) + +Revision 1.4 2007/08/28 00:33:04 jgraessley + Selective compilation options + +Revision 1.3 2007/08/23 23:21:24 cheshire +Tiger compatibility: Use old bootstrap_register() instead of Leopard-only bootstrap_register2() + +Revision 1.2 2007/08/23 21:36:17 cheshire +Made code layout style consistent with existing project style; added $Log header + +Revision 1.1 2007/08/08 22:34:58 mcguire + Security: Run mDNSResponder as user id mdnsresponder instead of root + */ + +#define _FORTIFY_SOURCE 2 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "helper.h" +#include "helper-server.h" +#include "helpermsg.h" +#include "helpermsgServer.h" + +#if TARGET_OS_EMBEDDED +#define NO_SECURITYFRAMEWORK 1 +#endif + +#ifndef LAUNCH_JOBKEY_MACHSERVICES +#define LAUNCH_JOBKEY_MACHSERVICES "MachServices" +#define LAUNCH_DATA_MACHPORT 10 +#define launch_data_get_machport launch_data_get_fd +#endif + +union max_msg_size + { + union __RequestUnion__proxy_helper_subsystem req; + union __ReplyUnion__proxy_helper_subsystem rep; + }; + +static const mach_msg_size_t MAX_MSG_SIZE = sizeof(union max_msg_size) + MAX_TRAILER_SIZE; +static aslclient logclient = NULL; +static int opt_debug; +static pthread_t idletimer_thread; + +unsigned long maxidle = 10; +unsigned long actualidle = 3600; + +CFRunLoopRef gRunLoop = NULL; +CFRunLoopTimerRef gTimer = NULL; + +static void helplogv(int level, const char *fmt, va_list ap) + { + if (NULL == logclient) { vfprintf(stderr, fmt, ap); fflush(stderr); } + else asl_vlog(logclient, NULL, level, fmt, ap); + } + +void helplog(int level, const char *fmt, ...) + { + va_list ap; + va_start(ap, fmt); + helplogv(level, fmt, ap); + va_end(ap); + } + +static void initialize_logging(void) + { + logclient = asl_open(NULL, kmDNSHelperServiceName, (opt_debug ? ASL_OPT_STDERR : 0)); + if (NULL == logclient) { fprintf(stderr, "Could not initialize ASL logging.\n"); fflush(stderr); return; } + if (opt_debug) asl_set_filter(logclient, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG)); + } + +static void initialize_id(void) + { + static char login[] = "_mdnsresponder"; + struct passwd *pwd = getpwnam(login); + + if (!pwd) { helplog(ASL_LEVEL_ERR, "Could not find account name `%s'. I will only help root.", login); return; } + mDNSResponderUID = pwd->pw_uid; + mDNSResponderGID = pwd->pw_gid; + } + +static void diediedie(CFRunLoopTimerRef timer, void *context) + { + debug("entry"); + assert(gTimer == timer); + if (maxidle) + (void)proxy_mDNSIdleExit((mach_port_t)context); + } + +void pause_idle_timer(void) + { + debug("entry"); + assert(gTimer); + assert(gRunLoop); + CFRunLoopRemoveTimer(gRunLoop, gTimer, kCFRunLoopDefaultMode); + } + +void unpause_idle_timer(void) + { + debug("entry"); + assert(gRunLoop); + assert(gTimer); + CFRunLoopAddTimer(gRunLoop, gTimer, kCFRunLoopDefaultMode); + } + +void update_idle_timer(void) + { + debug("entry"); + assert(gTimer); + CFRunLoopTimerSetNextFireDate(gTimer, CFAbsoluteTimeGetCurrent() + actualidle); + } + +static void *idletimer(void *context) + { + debug("entry context=%p", context); + gRunLoop = CFRunLoopGetCurrent(); + + unpause_idle_timer(); + + for (;;) + { + debug("Running CFRunLoop"); + CFRunLoopRun(); + sleep(1); + } + + return NULL; + } + +static void initialize_timer(mach_port_t port) + { + CFRunLoopTimerContext cxt = {0, (void *)port, NULL, NULL, NULL}; + gTimer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + actualidle, actualidle, 0, 0, diediedie, &cxt); + int err = 0; + + debug("entry port=%p", port); + if (0 != (err = pthread_create(&idletimer_thread, NULL, idletimer, (void *)port))) + helplog(ASL_LEVEL_ERR, "Could not start idletimer thread: %s", strerror(err)); + } + +static mach_port_t checkin(char *service_name) + { + kern_return_t kr = KERN_SUCCESS; + mach_port_t port = MACH_PORT_NULL; + launch_data_t msg = NULL, reply = NULL, datum = NULL; + + if (NULL == (msg = launch_data_new_string(LAUNCH_KEY_CHECKIN))) + { helplog(ASL_LEVEL_ERR, "Could not create checkin message for launchd."); goto fin; } + if (NULL == (reply = launch_msg(msg))) + { helplog(ASL_LEVEL_ERR, "Could not message launchd."); goto fin; } + if (LAUNCH_DATA_ERRNO == launch_data_get_type(reply)) + { + if (launch_data_get_errno(reply) == EACCES) { launch_data_free(msg); launch_data_free(reply); return(MACH_PORT_NULL); } + helplog(ASL_LEVEL_ERR, "Launchd checkin failed: %s.", strerror(launch_data_get_errno(reply))); goto fin; + } + if (NULL == (datum = launch_data_dict_lookup(reply, LAUNCH_JOBKEY_MACHSERVICES)) || LAUNCH_DATA_DICTIONARY != launch_data_get_type(datum)) + { helplog(ASL_LEVEL_ERR, "Launchd reply does not contain %s dictionary.", LAUNCH_JOBKEY_MACHSERVICES); goto fin; } + if (NULL == (datum = launch_data_dict_lookup(datum, service_name)) || LAUNCH_DATA_MACHPORT != launch_data_get_type(datum)) + { helplog(ASL_LEVEL_ERR, "Launchd reply does not contain %s Mach port.", service_name); goto fin; } + if (MACH_PORT_NULL == (port = launch_data_get_machport(datum))) + { helplog(ASL_LEVEL_ERR, "Launchd gave me a null Mach port."); goto fin; } + if (KERN_SUCCESS != (kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND))) + { helplog(ASL_LEVEL_ERR, "mach_port_insert_right: %s", mach_error_string(kr)); goto fin; } + +fin: + if (NULL != msg) launch_data_free(msg); + if (NULL != reply) launch_data_free(reply); + if (MACH_PORT_NULL == port) exit(EXIT_FAILURE); + return port; + } + +static mach_port_t register_service(const char *service_name) + { + mach_port_t port = MACH_PORT_NULL; + kern_return_t kr; + + if (KERN_SUCCESS == (kr = bootstrap_check_in(bootstrap_port, (char *)service_name, &port))) + { + if (KERN_SUCCESS != (kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND))) + helplog(ASL_LEVEL_ERR, "mach_port_insert_right: %s", mach_error_string(kr)); + else + return port; + } + if (KERN_SUCCESS != (kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port))) + { helplog(ASL_LEVEL_ERR, "mach_port_allocate: %s", mach_error_string(kr)); goto error; } + if (KERN_SUCCESS != (kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND))) + { helplog(ASL_LEVEL_ERR, "mach_port_insert_right: %s", mach_error_string(kr)); goto error; } + // XXX bootstrap_register does not modify its second argument, but the prototype does not include const. + if (KERN_SUCCESS != (kr = bootstrap_register(bootstrap_port, (char *)service_name, port))) + { helplog(ASL_LEVEL_ERR, "bootstrap_register failed: %s", mach_error_string(kr)); goto error; } + return port; +error: + if (MACH_PORT_NULL != port) mach_port_deallocate(mach_task_self(), port); + return MACH_PORT_NULL; + } + +int main(int ac, char *av[]) + { + char *p = NULL; + kern_return_t kr = KERN_FAILURE; + mach_port_t port = MACH_PORT_NULL; + long n; + int ch; + + while ((ch = getopt(ac, av, "dt:")) != -1) + switch (ch) + { + case 'd': opt_debug = 1; break; + case 't': + n = strtol(optarg, &p, 0); + if ('\0' == optarg[0] || '\0' != *p || n > LONG_MAX || n < 0) + { fprintf(stderr, "Invalid idle timeout: %s\n", optarg); exit(EXIT_FAILURE); } + maxidle = n; + break; + case '?': + default: + fprintf(stderr, "Usage: mDNSResponderHelper [-d] [-t maxidle]\n"); + exit(EXIT_FAILURE); + } + ac -= optind; + av += optind; + + initialize_logging(); + helplog(ASL_LEVEL_INFO, "Starting"); + initialize_id(); + +#ifndef NO_SECURITYFRAMEWORK + // We should normally be running as a system daemon. However, that might not be the case in some scenarios (e.g. debugging). + // Explicitly ensure that our Keychain operations utilize the system domain. + SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem); +#endif + if (!opt_debug) + { + port = checkin(kmDNSHelperServiceName); + if (!port) helplog(ASL_LEVEL_ERR, "Launchd provided no launchdata; will open Mach port explicitly"); + } + if (!port) port = register_service(kmDNSHelperServiceName); + + if (maxidle) actualidle = maxidle; + initialize_timer(port); + + kr = mach_msg_server(helper_server, MAX_MSG_SIZE, port, + MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)); + if (KERN_SUCCESS != kr) + { helplog(ASL_LEVEL_ERR, "mach_msg_server: %s\n", mach_error_string(kr)); exit(EXIT_FAILURE); } + exit(EXIT_SUCCESS); + } + +// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion +// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4" +// To expand "version" to its value before making the string, use STRINGIFY(version) instead +#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s +#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) + +// For convenience when using the "strings" command, this is the last thing in the file +// The "@(#) " pattern is a special prefix the "what" command looks for +const char VersionString_SCCS[] = "@(#) mDNSResponderHelper " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")"; + +// If 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"); diff --git a/mDNSMacOSX/helper-server.h b/mDNSMacOSX/helper-server.h new file mode 100644 index 0000000..defebe1 --- /dev/null +++ b/mDNSMacOSX/helper-server.h @@ -0,0 +1,43 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2007 Apple Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + Change History (most recent first): + +$Log: helper-server.h,v $ +Revision 1.3 2007/09/07 22:44:03 mcguire + Move CFUserNotification code to mDNSResponderHelper + +Revision 1.2 2007/08/23 21:39:01 cheshire +Made code layout style consistent with existing project style; added $Log header + +Revision 1.1 2007/08/08 22:34:58 mcguire + Security: Run mDNSResponder as user id mdnsresponder instead of root + */ + +#ifndef H_HELPER_SERVER_H +#define H_HELPER_SERVER_H + +extern void helplog(int, const char *, ...); +extern void pause_idle_timer(void); +extern void unpause_idle_timer(void); +extern void update_idle_timer(void); +extern uid_t mDNSResponderUID; +extern uid_t mDNSResponderGID; +extern CFRunLoopRef gRunLoop; +#define debug(...) debug_(__func__, __VA_ARGS__) +extern void debug_(const char *func, const char *fmt, ...); + +#endif /* H_HELPER_SERVER_H */ diff --git a/mDNSMacOSX/helper-stubs.c b/mDNSMacOSX/helper-stubs.c new file mode 100644 index 0000000..3d625ca --- /dev/null +++ b/mDNSMacOSX/helper-stubs.c @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2007 Apple Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + Change History (most recent first): + +$Log: helper-stubs.c,v $ +Revision 1.5 2007/09/07 22:44:03 mcguire + Move CFUserNotification code to mDNSResponderHelper + +Revision 1.4 2007/09/04 22:32:58 mcguire + BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf + +Revision 1.3 2007/08/23 21:44:55 cheshire +Made code layout style consistent with existing project style; added $Log header + +Revision 1.2 2007/08/18 01:02:03 mcguire + No Bonjour services are getting registered at boot + +Revision 1.1 2007/08/08 22:34:58 mcguire + Security: Run mDNSResponder as user id mdnsresponder instead of root + */ + +#include +#include +#include +#include +#include +#include "mDNSDebug.h" +#include "helper.h" +#include "helpermsg.h" + +#define ERROR(x, y) y, +static const char *errorstring[] = + { + #include "helper-error.h" + NULL + }; +#undef ERROR + +static mach_port_t +getHelperPort(int retry) + { + static mach_port_t port = MACH_PORT_NULL; + + if (retry) + port = MACH_PORT_NULL; + if (port == MACH_PORT_NULL && + BOOTSTRAP_SUCCESS != bootstrap_look_up(bootstrap_port, + kmDNSHelperServiceName, &port)) + LogMsg("%s: cannot contact helper", __func__); + return port; + } + +const char * +mDNSHelperError(int err) + { + const char *p = ""; + if (mDNSHelperErrorBase < err && mDNSHelperErrorEnd > err) + p = errorstring[err - mDNSHelperErrorBase - 1]; + return p; + } + + +/* Ugly but handy. */ +#define MACHRETRYLOOP_BEGIN(kr, retry, err, fin) for (;;) { + +#define MACHRETRYLOOP_END(kr, retry, err, fin) \ + if (KERN_SUCCESS == (kr)) break; \ + else if (MACH_SEND_INVALID_DEST == (kr) && 0 == (retry)++) continue; \ + else \ + { \ + (err) = kmDNSHelperCommunicationFailed; \ + LogMsg("%s: Mach communication failed: %s", __func__, mach_error_string(kr)); \ + goto fin; \ + } \ + } \ + if (0 != (err)) { LogMsg("%s: %s", __func__, mDNSHelperError((err))); goto fin; } + +int +mDNSPreferencesSetName(int key, domainlabel* old, domainlabel* new) + { + kern_return_t kr = KERN_FAILURE; + int retry = 0; + int err = 0; + char oldname[MAX_DOMAIN_LABEL+1] = {0}; + char newname[MAX_DOMAIN_LABEL+1] = {0}; + ConvertDomainLabelToCString_unescaped(old, oldname); + if (new) ConvertDomainLabelToCString_unescaped(new, newname); + + MACHRETRYLOOP_BEGIN(kr, retry, err, fin); + kr = proxy_mDNSPreferencesSetName(getHelperPort(retry), key, oldname, newname, &err); + MACHRETRYLOOP_END(kr, retry, err, fin); + +fin: + return err; + } + +int +mDNSDynamicStoreSetConfig(int key, CFPropertyListRef value) + { + CFWriteStreamRef stream = NULL; + CFDataRef bytes = NULL; + kern_return_t kr = KERN_FAILURE; + int retry = 0; + int err = 0; + + if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(NULL, + NULL))) + { + err = kmDNSHelperCreationFailed; + LogMsg("%s: CFWriteStreamCreateWithAllocatedBuffers failed", + __func__); + goto fin; + } + CFWriteStreamOpen(stream); + if (0 == CFPropertyListWriteToStream(value, stream, + kCFPropertyListBinaryFormat_v1_0, NULL)) + { + err = kmDNSHelperPListWriteFailed; + LogMsg("%s: CFPropertyListWriteToStream failed", __func__); + goto fin; + } + if (NULL == (bytes = CFWriteStreamCopyProperty(stream, + kCFStreamPropertyDataWritten))) + { + err = kmDNSHelperCreationFailed; + LogMsg("%s: CFWriteStreamCopyProperty failed", __func__); + goto fin; + } + CFWriteStreamClose(stream); + CFRelease(stream); + stream = NULL; + MACHRETRYLOOP_BEGIN(kr, retry, err, fin); + kr = proxy_mDNSDynamicStoreSetConfig(getHelperPort(retry), key, + (vm_offset_t)CFDataGetBytePtr(bytes), + CFDataGetLength(bytes), &err); + MACHRETRYLOOP_END(kr, retry, err, fin); + +fin: + if (NULL != stream) + { + CFWriteStreamClose(stream); + CFRelease(stream); + } + if (NULL != bytes) + CFRelease(bytes); + return err; + } + +int +mDNSKeychainGetSecrets(CFArrayRef *result) + { + CFPropertyListRef plist = NULL; + CFDataRef bytes = NULL; + kern_return_t kr = KERN_FAILURE; + unsigned int numsecrets = 0; + void *secrets = NULL; + mach_msg_type_number_t secretsCnt = 0; + int retry = 0; + int err = 0; + + + MACHRETRYLOOP_BEGIN(kr, retry, err, fin); + kr = proxy_mDNSKeychainGetSecrets(getHelperPort(retry), + &numsecrets, (vm_offset_t *)&secrets, &secretsCnt, &err); + MACHRETRYLOOP_END(kr, retry, err, fin); + if (0 == numsecrets) + goto fin; + if (NULL == (bytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, + secrets, secretsCnt, kCFAllocatorNull))) + { + err = kmDNSHelperCreationFailed; + LogMsg("%s: CFDataCreateWithBytesNoCopy failed", __func__); + goto fin; + } + if (NULL == (plist = CFPropertyListCreateFromXMLData( + kCFAllocatorDefault, bytes, kCFPropertyListImmutable, NULL))) + { + err = kmDNSHelperInvalidPList; + LogMsg("%s: CFPropertyListCreateFromXMLData failed", __func__); + goto fin; + } + if (CFArrayGetTypeID() != CFGetTypeID(plist)) + { + err = kmDNSHelperTypeError; + LogMsg("%s: Unexpected result type", __func__); + CFRelease(plist); + plist = NULL; + goto fin; + } + *result = (CFArrayRef)plist; + +fin: + if (NULL != bytes) + CFRelease(bytes); + if (NULL != secrets) + vm_deallocate(mach_task_self(), (vm_offset_t)secrets, + secretsCnt); + return err; + } + +int +mDNSAutoTunnelInterfaceUpDown(int updown, v6addr_t address) + { + kern_return_t kr = KERN_SUCCESS; + int retry = 0; + int err = 0; + + MACHRETRYLOOP_BEGIN(kr, retry, err, fin); + kr = proxy_mDNSAutoTunnelInterfaceUpDown(getHelperPort(retry), + updown, address, &err); + MACHRETRYLOOP_END(kr, retry, err, fin); + +fin: + return err; + } + +int +mDNSConfigureServer(int updown, const char *keydata) + { + kern_return_t kr = KERN_SUCCESS; + int retry = 0; + int err = 0; + + MACHRETRYLOOP_BEGIN(kr, retry, err, fin); + kr = proxy_mDNSConfigureServer(getHelperPort(retry), updown, keydata, &err); + MACHRETRYLOOP_END(kr, retry, err, fin); + +fin: + return err; + } + +int +mDNSAutoTunnelSetKeys(int replacedelete, v6addr_t local_inner, + v4addr_t local_outer, short local_port, v6addr_t remote_inner, + v4addr_t remote_outer, short remote_port, const char *keydata) + { + kern_return_t kr = KERN_SUCCESS; + const char *p = NULL; + int retry = 0; + int err = 0; + + if (kmDNSAutoTunnelSetKeysReplace == replacedelete) + p = keydata; + else + p = ""; + MACHRETRYLOOP_BEGIN(kr, retry, err, fin); + kr = proxy_mDNSAutoTunnelSetKeys(getHelperPort(retry), replacedelete, + local_inner, local_outer, local_port, remote_inner, remote_outer, + remote_port, keydata, &err); + MACHRETRYLOOP_END(kr, retry, err, fin); + +fin: + return err; + } diff --git a/mDNSMacOSX/helper.c b/mDNSMacOSX/helper.c new file mode 100644 index 0000000..7225742 --- /dev/null +++ b/mDNSMacOSX/helper.c @@ -0,0 +1,1778 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2007 Apple Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + Change History (most recent first): + +$Log: helper.c,v $ +Revision 1.20 2007/09/12 18:07:44 cheshire +Fix compile errors ("passing argument from incompatible pointer type") + +Revision 1.19 2007/09/12 00:42:47 mcguire + BTMM: Need to clean up security associations + +Revision 1.18 2007/09/12 00:40:16 mcguire + 9A547: Computer Name had incorrectly encoded unicode + +Revision 1.17 2007/09/09 02:21:17 mcguire + Leopard Server9A547(Insatll):mDNSResponderHelper crashing + +Revision 1.16 2007/09/07 22:44:03 mcguire + Move CFUserNotification code to mDNSResponderHelper + +Revision 1.15 2007/09/07 22:24:36 vazquez + Need to stop spewing mDNSResponderHelper logs + +Revision 1.14 2007/09/06 20:39:05 cheshire +Added comment explaining why we allow both "ddns" and "sndd" as valid item types +The Keychain APIs on Intel appear to store the four-character item type backwards (at least some of the time) + +Revision 1.13 2007/09/04 22:32:58 mcguire + BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf + +Revision 1.12 2007/08/29 21:42:12 mcguire + BTMM: Duplicate Private DNS names are being added to DynamicStore + +Revision 1.11 2007/08/28 00:33:04 jgraessley + Selective compilation options + +Revision 1.10 2007/08/27 22:16:38 mcguire + BTMM: MTU should be set to 1280 + +Revision 1.9 2007/08/27 22:13:59 mcguire + BTMM: IPSec security associations should have a shorter timeout + +Revision 1.8 2007/08/23 21:49:51 cheshire +Made code layout style consistent with existing project style; added $Log header + +Revision 1.7 2007/08/23 00:29:05 mcguire + BTMM: IPSec policy not installed in some situations - connections fail + +Revision 1.6 2007/08/18 01:02:03 mcguire + No Bonjour services are getting registered at boot + +Revision 1.5 2007/08/18 00:59:55 mcguire + Blocked: BTMM: Start racoon with '-e' parameter + +Revision 1.4 2007/08/16 01:00:06 mcguire + BTMM: Install generate IPsec policies to block non-BTMM traffic + +Revision 1.3 2007/08/15 23:20:28 mcguire + BTMM: racoon files can get corrupted if autotunnel is listening on port > 32767 + +Revision 1.2 2007/08/10 22:30:39 mcguire + BTMM: racoon config files are not always the correct mode + +Revision 1.1 2007/08/08 22:34:58 mcguire + Security: Run mDNSResponder as user id mdnsresponder instead of root + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mDNSEmbeddedAPI.h" +#include "dns_sd.h" +#include "dnssd_ipc.h" +#include "libpfkey.h" +#include "helper.h" +#include "helpermsgServer.h" +#include "helper-server.h" + +#if TARGET_OS_EMBEDDED +#define NO_SECURITYFRAMEWORK 1 +#endif + +typedef struct sadb_x_policy *ipsec_policy_t; + +uid_t mDNSResponderUID; +gid_t mDNSResponderGID; +static const char kTunnelAddressInterface[] = "lo0"; + +void +debug_(const char *func, const char *fmt, ...) + { + char buf[2048]; + va_list ap; + ssize_t n = snprintf(buf, sizeof(buf), "%s: ", func); + + if (n >= (int)sizeof(buf)) + return; + va_start(ap, fmt); + vsnprintf(&buf[n], sizeof(buf)-n, fmt, ap); + va_end(ap); + helplog(ASL_LEVEL_DEBUG, buf); + } + +static int +authorized(audit_token_t *token) + { + int ok = 0; + pid_t pid = (pid_t)-1; + uid_t euid = (uid_t)-1; + + audit_token_to_au32(*token, NULL, &euid, NULL, NULL, NULL, &pid, NULL, + NULL); + ok = (euid == mDNSResponderUID || euid == 0); + if (!ok) + helplog(ASL_LEVEL_NOTICE, + "Unauthorized access by euid=%lu pid=%lu", + (unsigned long)euid, (unsigned long)pid); + return ok; + } + +static void +closefds(int from) + { + int fd = 0; + struct dirent entry, *entryp = NULL; + DIR *dirp = opendir("/dev/fd"); + + if (dirp == NULL) + { + /* fall back to the erroneous getdtablesize method */ + for (fd = from; fd < getdtablesize(); ++fd) + close(fd); + return; + } + while (0 == readdir_r(dirp, &entry, &entryp) && NULL != entryp) + { + fd = atoi(entryp->d_name); + if (fd >= from && fd != dirfd(dirp)) + close(fd); + } + closedir(dirp); + } + +kern_return_t +do_mDNSIdleExit(__unused mach_port_t port, audit_token_t token) + { + debug("entry"); + if (!authorized(&token)) + goto fin; + helplog(ASL_LEVEL_INFO, "Idle exit"); + exit(0); + +fin: + debug("fin"); + return KERN_SUCCESS; + } + +kern_return_t +do_mDNSDynamicStoreSetConfig(__unused mach_port_t port, int key, + vm_offset_t value, mach_msg_type_number_t valueCnt, int *err, + audit_token_t token) + { + CFStringRef sckey = NULL; + CFDataRef bytes = NULL; + CFPropertyListRef plist = NULL; + SCDynamicStoreRef store = NULL; + + debug("entry"); + *err = 0; + if (!authorized(&token)) + { + *err = kmDNSHelperNotAuthorized; + goto fin; + } + switch ((enum mDNSDynamicStoreSetConfigKey)key) + { + case kmDNSMulticastConfig: + sckey = CFSTR("State:/Network/" kDNSServiceCompMulticastDNS); + break; + case kmDNSDynamicConfig: + sckey = CFSTR("State:/Network/DynamicDNS"); + break; + case kmDNSPrivateConfig: + sckey = CFSTR("State:/Network/" kDNSServiceCompPrivateDNS); + break; + case kmDNSBackToMyMacConfig: + sckey = CFSTR("State:/Network/BackToMyMac"); + break; + default: + debug("unrecognized key %d", key); + *err = kmDNSHelperInvalidConfigKey; + goto fin; + } + if (NULL == (bytes = CFDataCreateWithBytesNoCopy(NULL, (void *)value, + valueCnt, kCFAllocatorNull))) + { + debug("CFDataCreateWithBytesNoCopy of value failed"); + *err = kmDNSHelperCreationFailed; + goto fin; + } + if (NULL == (plist = CFPropertyListCreateFromXMLData(NULL, bytes, + kCFPropertyListImmutable, NULL))) + { + debug("CFPropertyListCreateFromXMLData of bytes failed"); + *err = kmDNSHelperInvalidPList; + goto fin; + } + CFRelease(bytes); + bytes = NULL; + if (NULL == (store = SCDynamicStoreCreate(NULL, + CFSTR(kmDNSHelperServiceName), NULL, NULL))) + { + debug("SCDynamicStoreCreate failed"); + *err = kmDNSHelperDynamicStoreFailed; + goto fin; + } + SCDynamicStoreSetValue(store, sckey, plist); + *err = 0; + debug("succeeded"); + +fin: + if (0 != *err) + debug("failed err=%d", *err); + if (NULL != bytes) + CFRelease(bytes); + if (NULL != plist) + CFRelease(plist); + if (NULL != store) + CFRelease(store); + vm_deallocate(mach_task_self(), value, valueCnt); + update_idle_timer(); + return KERN_SUCCESS; + } + +char usercompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name the user saw +char userhostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name the user saw +char lastcompname[MAX_DOMAIN_LABEL+1] = {0}; // the last computer name saved to preferences +char lasthostname[MAX_DOMAIN_LABEL+1] = {0}; // the last local host name saved to preferences + +static CFStringRef CFS_OQ = NULL; +static CFStringRef CFS_CQ = NULL; +static CFStringRef CFS_Format = NULL; +static CFStringRef CFS_ComputerName = NULL; +static CFStringRef CFS_ComputerNameMsg = NULL; +static CFStringRef CFS_LocalHostName = NULL; +static CFStringRef CFS_LocalHostNameMsg = NULL; +static CFStringRef CFS_Problem = NULL; + +static CFUserNotificationRef gNotification = NULL; +static CFRunLoopSourceRef gNotificationRLS = NULL; + +static void NotificationCallBackDismissed(CFUserNotificationRef userNotification, CFOptionFlags responseFlags) + { + debug("entry"); + (void)responseFlags; // Unused + if (userNotification != gNotification) helplog(ASL_LEVEL_ERR, "NotificationCallBackDismissed: Wrong CFUserNotificationRef"); + if (gNotificationRLS) + { + // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread. + // We need to explicitly specify the desired CFRunLoop from which we want to remove this event source. + CFRunLoopRemoveSource(gRunLoop, gNotificationRLS, kCFRunLoopDefaultMode); + CFRelease(gNotificationRLS); + gNotificationRLS = NULL; + CFRelease(gNotification); + gNotification = NULL; + } + // By dismissing the alert, the user has conceptually acknowleged the rename. + // (e.g. the machine's name is now officially "computer-2.local", not "computer.local".) + // If we get *another* conflict, the new alert should refer to the 'old' name + // as now being "computer-2.local", not "computer.local" + usercompname[0] = 0; + userhostname[0] = 0; + lastcompname[0] = 0; + lasthostname[0] = 0; + update_idle_timer(); + unpause_idle_timer(); + } + +static void ShowNameConflictNotification(CFMutableArrayRef header, CFStringRef subtext) + { + CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (!dictionary) return; + + debug("entry"); + + CFDictionarySetValue(dictionary, kCFUserNotificationAlertHeaderKey, header); + CFDictionarySetValue(dictionary, kCFUserNotificationAlertMessageKey, subtext); + + CFURLRef urlRef = CFURLCreateWithFileSystemPath(NULL, CFSTR("/System/Library/CoreServices/mDNSResponder.bundle"), kCFURLPOSIXPathStyle, true); + if (urlRef) { CFDictionarySetValue(dictionary, kCFUserNotificationLocalizationURLKey, urlRef); CFRelease(urlRef); } + + if (gNotification) // If notification already on-screen, update it in place + CFUserNotificationUpdate(gNotification, 0, kCFUserNotificationCautionAlertLevel, dictionary); + else // else, we need to create it + { + SInt32 error; + gNotification = CFUserNotificationCreate(NULL, 0, kCFUserNotificationCautionAlertLevel, &error, dictionary); + if (!gNotification || error) { helplog(ASL_LEVEL_ERR, "ShowNameConflictNotification: CFUserNotificationRef: Error %d", error); return; } + gNotificationRLS = CFUserNotificationCreateRunLoopSource(NULL, gNotification, NotificationCallBackDismissed, 0); + if (!gNotificationRLS) { helplog(ASL_LEVEL_ERR,"ShowNameConflictNotification: RLS"); CFRelease(gNotification); gNotification = NULL; return; } + // Caution: don't use CFRunLoopGetCurrent() here, because the currently executing thread may not be our "CFRunLoopRun" thread. + // We need to explicitly specify the desired CFRunLoop to which we want to add this event source. + CFRunLoopAddSource(gRunLoop, gNotificationRLS, kCFRunLoopDefaultMode); + debug("gRunLoop=%p gNotification=%p gNotificationRLS=%p", gRunLoop, gNotification, gNotificationRLS); + pause_idle_timer(); + } + + CFRelease(dictionary); + } + +static CFMutableArrayRef GetHeader(const char* oldname, const char* newname, const CFStringRef msg, const char* suffix) + { + CFMutableArrayRef alertHeader = NULL; + + const CFStringRef cfoldname = CFStringCreateWithCString(NULL, oldname, kCFStringEncodingUTF8); + // NULL newname means we've given up trying to construct a name that doesn't conflict + const CFStringRef cfnewname = newname ? CFStringCreateWithCString(NULL, newname, kCFStringEncodingUTF8) : NULL; + // We tag a zero-width non-breaking space at the end of the literal text to guarantee that, no matter what + // arbitrary computer name the user may choose, this exact text (with zero-width non-breaking space added) + // can never be one that occurs in the Localizable.strings translation file. + if (!cfoldname) + helplog(ASL_LEVEL_ERR,"Could not construct CFStrings for old=%s", newname); + else if (newname && !cfnewname) + helplog(ASL_LEVEL_ERR,"Could not construct CFStrings for new=%s", newname); + else + { + const CFStringRef s1 = CFStringCreateWithFormat(NULL, NULL, CFS_Format, cfoldname, suffix); + const CFStringRef s2 = cfnewname ? CFStringCreateWithFormat(NULL, NULL, CFS_Format, cfnewname, suffix) : NULL; + + alertHeader = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + + if (!s1) + helplog(ASL_LEVEL_ERR, "Could not construct secondary CFString for old=%s", oldname); + else if (cfnewname && !s2) + helplog(ASL_LEVEL_ERR, "Could not construct secondary CFString for new=%s", newname); + else if (!alertHeader) + helplog(ASL_LEVEL_ERR, "Could not construct CFArray for notification"); + else + { + // Make sure someone is logged in. We don't want this popping up over the login window + uid_t uid; + gid_t gid; + CFStringRef userName = SCDynamicStoreCopyConsoleUser(NULL, &uid, &gid); + if (userName) + { + CFRelease(userName); + CFArrayAppendValue(alertHeader, msg); // Opening phrase of message, provided by caller + CFArrayAppendValue(alertHeader, CFS_OQ); CFArrayAppendValue(alertHeader, s1); CFArrayAppendValue(alertHeader, CFS_CQ); + CFArrayAppendValue(alertHeader, CFSTR(" is already in use on this network. ")); + if (s2) + { + CFArrayAppendValue(alertHeader, CFSTR("The name has been changed to ")); + CFArrayAppendValue(alertHeader, CFS_OQ); CFArrayAppendValue(alertHeader, s2); CFArrayAppendValue(alertHeader, CFS_CQ); + CFArrayAppendValue(alertHeader, CFSTR(".")); + } + else + CFArrayAppendValue(alertHeader, CFSTR("All attempts to find an available name by adding a number to the name were also unsuccessful.")); + } + } + if (s1) CFRelease(s1); + if (s2) CFRelease(s2); + } + if (cfoldname) CFRelease(cfoldname); + if (cfnewname) CFRelease(cfnewname); + + return alertHeader; + } + +static void update_notification(void) + { + debug("entry ucn=%s, uhn=%s, lcn=%s, lhn=%s", usercompname, userhostname, lastcompname, lasthostname); + if (!CFS_OQ) + { + // Note: the "\xEF\xBB\xBF" byte sequence in the CFS_Format string is the UTF-8 encoding of the zero-width non-breaking space character. + // By appending this invisible character on the end of literal names, we ensure the these strings cannot inadvertently match any string + // in the localization file -- since we know for sure that none of our strings in the localization file contain the ZWNBS character. + CFS_OQ = CFStringCreateWithCString(NULL, "“", kCFStringEncodingUTF8); + CFS_CQ = CFStringCreateWithCString(NULL, "”", kCFStringEncodingUTF8); + CFS_Format = CFStringCreateWithCString(NULL, "%@%s\xEF\xBB\xBF", kCFStringEncodingUTF8); + CFS_ComputerName = CFStringCreateWithCString(NULL, "The name of your computer ", kCFStringEncodingUTF8); + CFS_ComputerNameMsg = CFStringCreateWithCString(NULL, "To change the name of your computer, " + "open System Preferences and click Sharing, then type the name in the Computer Name field.", kCFStringEncodingUTF8); + CFS_LocalHostName = CFStringCreateWithCString(NULL, "This computer’s local hostname ", kCFStringEncodingUTF8); + CFS_LocalHostNameMsg = CFStringCreateWithCString(NULL, "To change the local hostname, " + "open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field.", kCFStringEncodingUTF8); + CFS_Problem = CFStringCreateWithCString(NULL, "This may indicate a problem with the local network. " + "Please inform your network administrator.", kCFStringEncodingUTF8); + } + + if (!usercompname[0] && !userhostname[0]) + { + if (gNotificationRLS) + { + debug("canceling notification %p", gNotification); + CFUserNotificationCancel(gNotification); + unpause_idle_timer(); + } + } + else + { + CFMutableArrayRef header = NULL; + CFStringRef* subtext = NULL; + if (userhostname[0] && !lasthostname[0]) // we've given up trying to construct a name that doesn't conflict + { + header = GetHeader(userhostname, NULL, CFS_LocalHostName, ".local"); + subtext = &CFS_Problem; + } + else if (usercompname[0]) + { + header = GetHeader(usercompname, lastcompname, CFS_ComputerName, ""); + subtext = &CFS_ComputerNameMsg; + } + else + { + header = GetHeader(userhostname, lasthostname, CFS_LocalHostName, ".local"); + subtext = &CFS_LocalHostNameMsg; + } + ShowNameConflictNotification(header, *subtext); + CFRelease(header); + } + } + +kern_return_t +do_mDNSPreferencesSetName(__unused mach_port_t port, int key, const char* old, const char* new, int *err, audit_token_t token) + { + SCPreferencesRef session = NULL; + Boolean ok = FALSE; + Boolean locked = FALSE; + CFStringRef cfstr = NULL; + char* user = NULL; + char* last = NULL; + Boolean needUpdate = FALSE; + + debug("entry %s old=%s new=%s", key==kmDNSComputerName ? "ComputerName" : (key==kmDNSLocalHostName ? "LocalHostName" : "UNKNOWN"), old, new); + *err = 0; + if (!authorized(&token)) + { + *err = kmDNSHelperNotAuthorized; + goto fin; + } + switch ((enum mDNSPreferencesSetNameKey)key) + { + case kmDNSComputerName: + user = usercompname; + last = lastcompname; + break; + case kmDNSLocalHostName: + user = userhostname; + last = lasthostname; + break; + default: + debug("unrecognized key: %d", key); + *err = kmDNSHelperInvalidNameKey; + goto fin; + } + + if (!last) + { + helplog(ASL_LEVEL_ERR, "%s: no last ptr", __func__); + goto fin; + } + + if (!user) + { + helplog(ASL_LEVEL_ERR, "%s: no user ptr", __func__); + goto fin; + } + + if (0 == strncmp(old, new, MAX_DOMAIN_LABEL+1)) + { + // if we've changed the name, but now someone else has set it to something different, we no longer need the notification + if (last[0] && 0 != strncmp(last, new, MAX_DOMAIN_LABEL+1)) + { + last[0] = 0; + user[0] = 0; + needUpdate = TRUE; + } + goto fin; + } + else + { + if (strncmp(last, new, MAX_DOMAIN_LABEL+1)) + { + strncpy(last, new, MAX_DOMAIN_LABEL); + needUpdate = TRUE; + } + } + + if (!user[0]) + { + strncpy(user, old, MAX_DOMAIN_LABEL); + needUpdate = TRUE; + } + + if (!new[0]) // we've given up trying to construct a name that doesn't conflict + goto fin; + + cfstr = CFStringCreateWithCString(NULL, new, kCFStringEncodingUTF8); + + session = SCPreferencesCreate(NULL, CFSTR(kmDNSHelperServiceName), NULL); + + if (cfstr == NULL || session == NULL) + { + debug("SCPreferencesCreate failed"); + *err = kmDNSHelperPreferencesFailed; + goto fin; + } + if (!SCPreferencesLock(session, 0)) + { + debug("lock failed"); + *err = kmDNSHelperPreferencesLockFailed; + goto fin; + } + locked = TRUE; + + switch ((enum mDNSPreferencesSetNameKey)key) + { + case kmDNSComputerName: + { + // We want to write the new Computer Name to System Preferences, without disturbing the user-selected + // system-wide default character set used for things like AppleTalk NBP and NETBIOS service advertising. + // Note that this encoding is not used for the computer name, but since both are set by the same call, + // we need to take care to set the name without changing the character set. + CFStringEncoding encoding = kCFStringEncodingUTF8; + CFStringRef unused = SCDynamicStoreCopyComputerName(NULL, &encoding); + if (unused) { CFRelease(unused); unused = NULL; } + else encoding = kCFStringEncodingUTF8; + + ok = SCPreferencesSetComputerName(session, cfstr, encoding); + } + break; + case kmDNSLocalHostName: + ok = SCPreferencesSetLocalHostName(session, cfstr); + break; + default: + break; + } + + if (!ok || !SCPreferencesCommitChanges(session) || + !SCPreferencesApplyChanges(session)) + { + debug("SCPreferences update failed"); + *err = kmDNSHelperPreferencesSetFailed; + goto fin; + } + *err = 0; + debug("succeeded"); + +fin: + if (0 != *err) + debug("failed err=%d", *err); + if (NULL != cfstr) + CFRelease(cfstr); + if (NULL != session) + { + if (locked) + SCPreferencesUnlock(session); + CFRelease(session); + } + update_idle_timer(); + if (needUpdate) update_notification(); + return KERN_SUCCESS; + } + +enum DNSKeyFormat + { + formatNotDNSKey, formatDdnsTypeItem, formatDnsPrefixedServiceItem + }; + +// On Mac OS X on Intel, the four-character string seems to be stored backwards, at least sometimes. +// I suspect some overenthusiastic inexperienced engineer said, "On Intel everything's backwards, +// therefore I need to add some byte swapping in this API to make this four-character string backwards too." +// To cope with this we allow *both* "ddns" and "sndd" as valid item types. + +static const char dnsprefix[] = "dns:"; +static const char ddns[] = "ddns"; +static const char ddnsrev[] = "sndd"; + +#ifndef NO_SECURITYFRAMEWORK +static enum DNSKeyFormat +getDNSKeyFormat(SecKeychainItemRef item, SecKeychainAttributeList **attributesp) + { + static UInt32 tags[3] = + { + kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr + }; + static SecKeychainAttributeInfo attributeInfo = + { + sizeof(tags)/sizeof(tags[0]), tags, NULL + }; + SecKeychainAttributeList *attributes = NULL; + enum DNSKeyFormat format; + Boolean malformed = FALSE; + OSStatus status = noErr; + int i = 0; + + *attributesp = NULL; + if (noErr != (status = SecKeychainItemCopyAttributesAndData(item, + &attributeInfo, NULL, &attributes, NULL, NULL))) + { + debug("SecKeychainItemCopyAttributesAndData %d - skipping", + status); + goto skip; + } + if (attributeInfo.count != attributes->count) + malformed = TRUE; + for (i = 0; !malformed && i < (int)attributeInfo.count; ++i) + if (attributeInfo.tag[i] != attributes->attr[i].tag) + malformed = TRUE; + if (malformed) + { + debug( + "malformed result from SecKeychainItemCopyAttributesAndData - skipping"); + goto skip; + } + debug("entry (\"%.*s\", \"%.*s\", \"%.*s\")", + (int)attributes->attr[0].length, attributes->attr[0].data, + (int)attributes->attr[1].length, attributes->attr[1].data, + (int)attributes->attr[2].length, attributes->attr[2].data); + if (attributes->attr[1].length >= MAX_ESCAPED_DOMAIN_NAME + + sizeof(dnsprefix)-1) + { + debug("kSecServiceItemAttr too long (%u) - skipping", + (unsigned int)attributes->attr[1].length); + goto skip; + } + if (attributes->attr[2].length >= MAX_ESCAPED_DOMAIN_NAME) + { + debug("kSecAccountItemAttr too long (%u) - skipping", + (unsigned int)attributes->attr[2].length); + goto skip; + } + if (attributes->attr[1].length >= sizeof(dnsprefix)-1 && + 0 == strncasecmp(attributes->attr[1].data, dnsprefix, + sizeof(dnsprefix)-1)) + format = formatDnsPrefixedServiceItem; + else if (attributes->attr[0].length == sizeof(ddns)-1 && + 0 == strncasecmp(attributes->attr[0].data, ddns, sizeof(ddns)-1)) + format = formatDdnsTypeItem; + else if (attributes->attr[0].length == sizeof(ddnsrev)-1 && + 0 == strncasecmp(attributes->attr[0].data, ddnsrev, sizeof(ddnsrev)-1)) + format = formatDdnsTypeItem; + else + { + debug("uninterested in this entry"); + goto skip; + } + *attributesp = attributes; + debug("accepting this entry"); + return format; + +skip: + SecKeychainItemFreeAttributesAndData(attributes, NULL); + return formatNotDNSKey; + } + +static CFPropertyListRef +getKeychainItemInfo(SecKeychainItemRef item, + SecKeychainAttributeList *attributes, enum DNSKeyFormat format) + { + CFMutableArrayRef entry = NULL; + CFDataRef data = NULL; + OSStatus status = noErr; + UInt32 keylen = 0; + void *keyp = 0; + + if (NULL == (entry = CFArrayCreateMutable(NULL, 0, + &kCFTypeArrayCallBacks))) + { + debug("CFArrayCreateMutable failed"); + goto error; + } + switch ((enum DNSKeyFormat)format) + { + case formatDdnsTypeItem: + data = CFDataCreate(kCFAllocatorDefault, + attributes->attr[1].data, attributes->attr[1].length); + break; + case formatDnsPrefixedServiceItem: + data = CFDataCreate(kCFAllocatorDefault, + attributes->attr[1].data + sizeof(dnsprefix)-1, + attributes->attr[1].length - (sizeof(dnsprefix)-1)); + default: + assert("unknown DNSKeyFormat value"); + break; + } + if (NULL == data) + { + debug("CFDataCreate for attr[1] failed"); + goto error; + } + CFArrayAppendValue(entry, data); + CFRelease(data); + if (NULL == (data = CFDataCreate(kCFAllocatorDefault, + attributes->attr[2].data, attributes->attr[2].length))) + { + debug("CFDataCreate for attr[2] failed"); + goto error; + } + CFArrayAppendValue(entry, data); + CFRelease(data); + if (noErr != (status = SecKeychainItemCopyAttributesAndData(item, NULL, + NULL, NULL, &keylen, &keyp))) + { + debug("could not retrieve key for \"%.*s\": %d", + (int)attributes->attr[1].length, attributes->attr[1].data, + status); + goto error; + } + data = CFDataCreate(kCFAllocatorDefault, keyp, keylen); + SecKeychainItemFreeAttributesAndData(NULL, keyp); + if (NULL == data) + { + debug("CFDataCreate for keyp failed"); + goto error; + } + CFArrayAppendValue(entry, data); + CFRelease(data); + return entry; + +error: + if (NULL != entry) + CFRelease(entry); + return NULL; + } +#endif + +kern_return_t +do_mDNSKeychainGetSecrets(__unused mach_port_t port, __unused unsigned int *numsecrets, + __unused vm_offset_t *secrets, __unused mach_msg_type_number_t *secretsCnt, __unused int *err, + __unused audit_token_t token) + { +#ifndef NO_SECURITYFRAMEWORK + CFWriteStreamRef stream = NULL; + CFDataRef result = NULL; + CFPropertyListRef entry = NULL; + CFMutableArrayRef keys = NULL; + SecKeychainRef skc = NULL; + SecKeychainItemRef item = NULL; + SecKeychainSearchRef search = NULL; + SecKeychainAttributeList *attributes = NULL; + enum DNSKeyFormat format; + OSStatus status = 0; + + debug("entry"); + *err = 0; + *numsecrets = 0; + *secrets = (vm_offset_t)NULL; + if (!authorized(&token)) + { + *err = kmDNSHelperNotAuthorized; + goto fin; + } + if (NULL == (keys = CFArrayCreateMutable(NULL, 0, + &kCFTypeArrayCallBacks))) + { + debug("CFArrayCreateMutable failed"); + *err = kmDNSHelperCreationFailed; + goto fin; + } + if (noErr != (status = SecKeychainCopyDefault(&skc))) + { + *err = kmDNSHelperKeychainCopyDefaultFailed; + goto fin; + } + if (noErr != (status = SecKeychainSearchCreateFromAttributes(skc, kSecGenericPasswordItemClass, NULL, &search))) + { + *err = kmDNSHelperKeychainSearchCreationFailed; + goto fin; + } + for (status = SecKeychainSearchCopyNext(search, &item); + noErr == status; + status = SecKeychainSearchCopyNext(search, &item)) + { + if (formatNotDNSKey != (format = getDNSKeyFormat(item, + &attributes)) && + NULL != (entry = getKeychainItemInfo(item, attributes, + format))) + { + CFArrayAppendValue(keys, entry); + CFRelease(entry); + } + SecKeychainItemFreeAttributesAndData(attributes, NULL); + CFRelease(item); + } + if (errSecItemNotFound != status) + helplog(ASL_LEVEL_ERR, "%s: SecKeychainSearchCopyNext failed: %d", + __func__, status); + if (NULL == (stream = + CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorDefault, + kCFAllocatorDefault))) + { + *err = kmDNSHelperCreationFailed; + debug("CFWriteStreamCreateWithAllocatedBuffers failed"); + goto fin; + } + CFWriteStreamOpen(stream); + if (0 == CFPropertyListWriteToStream(keys, stream, + kCFPropertyListBinaryFormat_v1_0, NULL)) + { + *err = kmDNSHelperPListWriteFailed; + debug("CFPropertyListWriteToStream failed"); + goto fin; + } + result = CFWriteStreamCopyProperty(stream, + kCFStreamPropertyDataWritten); + if (KERN_SUCCESS != vm_allocate(mach_task_self(), secrets, + CFDataGetLength(result), VM_FLAGS_ANYWHERE)) + { + *err = kmDNSHelperCreationFailed; + debug("vm_allocate failed"); + goto fin; + } + CFDataGetBytes(result, CFRangeMake(0, CFDataGetLength(result)), + (void *)*secrets); + *secretsCnt = CFDataGetLength(result); + *numsecrets = CFArrayGetCount(keys); + debug("succeeded"); + +fin: + debug("returning %u secrets", *numsecrets); + if (NULL != stream) + { + CFWriteStreamClose(stream); + CFRelease(stream); + } + if (NULL != result) + CFRelease(result); + if (NULL != keys) + CFRelease(keys); + if (NULL != search) + CFRelease(search); + if (NULL != skc) + CFRelease(skc); + update_idle_timer(); + return KERN_SUCCESS; +#else + return KERN_FAILURE; +#endif + } + +typedef enum _mDNSTunnelPolicyWhich + { + kmDNSTunnelPolicySetup, + kmDNSTunnelPolicyTeardown, + kmDNSTunnelPolicyGenerate + } mDNSTunnelPolicyWhich; + +static const uint8_t kWholeV6Mask = 128; +static const uint8_t kZeroV6Mask = 0; + +static int +doTunnelPolicy(mDNSTunnelPolicyWhich which, + v6addr_t loc_inner, uint8_t loc_bits, + v4addr_t loc_outer, uint16_t loc_port, + v6addr_t rmt_inner, uint8_t rmt_bits, + v4addr_t rmt_outer, uint16_t rmt_port); + +static int +aliasTunnelAddress(v6addr_t address) + { + struct in6_aliasreq ifra_in6; + int err = 0; + int s = -1; + + if (0 > (s = socket(AF_INET6, SOCK_DGRAM, 0))) + { + helplog(ASL_LEVEL_ERR, "socket(AF_INET6, ...) failed: %s", + strerror(errno)); + err = kmDNSHelperDatagramSocketCreationFailed; + goto fin; + } + bzero(&ifra_in6, sizeof(ifra_in6)); + strlcpy(ifra_in6.ifra_name, kTunnelAddressInterface, + sizeof(ifra_in6.ifra_name)); + ifra_in6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; + ifra_in6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; + + ifra_in6.ifra_addr.sin6_family = AF_INET6; + ifra_in6.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); + memcpy(&(ifra_in6.ifra_addr.sin6_addr), address, + sizeof(ifra_in6.ifra_addr.sin6_addr)); + + ifra_in6.ifra_prefixmask.sin6_family = AF_INET6; + ifra_in6.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); + memset(&(ifra_in6.ifra_prefixmask.sin6_addr), 0xFF, + sizeof(ifra_in6.ifra_prefixmask.sin6_addr)); + + if (0 > ioctl(s, SIOCAIFADDR_IN6, &ifra_in6)) + { + helplog(ASL_LEVEL_ERR, + "ioctl(..., SIOCAIFADDR_IN6, ...) failed: %s", + strerror(errno)); + err = kmDNSHelperInterfaceCreationFailed; + goto fin; + } + + v6addr_t zero = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; + err = doTunnelPolicy(kmDNSTunnelPolicyGenerate, + address, kWholeV6Mask, NULL, 0, + zero, kZeroV6Mask, NULL, 0); + +fin: + if (0 <= s) + close(s); + return err; + } + +static int +unaliasTunnelAddress(v6addr_t address) + { + struct in6_ifreq ifr; + int err = 0; + int s = -1; + + if (0 > (s = socket(AF_INET6, SOCK_DGRAM, 0))) + { + helplog(ASL_LEVEL_ERR, "socket(AF_INET6, ...) failed: %s", + strerror(errno)); + err = kmDNSHelperDatagramSocketCreationFailed; + goto fin; + } + bzero(&ifr, sizeof(ifr)); + strlcpy(ifr.ifr_name, kTunnelAddressInterface, sizeof(ifr.ifr_name)); + ifr.ifr_ifru.ifru_addr.sin6_family = AF_INET6; + ifr.ifr_ifru.ifru_addr.sin6_len = sizeof(struct sockaddr_in6); + memcpy(&(ifr.ifr_ifru.ifru_addr.sin6_addr), address, + sizeof(ifr.ifr_ifru.ifru_addr.sin6_addr)); + + if (0 > ioctl(s, SIOCDIFADDR_IN6, &ifr)) + { + helplog(ASL_LEVEL_ERR, + "ioctl(..., SIOCDIFADDR_IN6, ...) failed: %s", + strerror(errno)); + err = kmDNSHelperInterfaceDeletionFailed; + goto fin; + } + + v6addr_t zero = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + err = doTunnelPolicy(kmDNSTunnelPolicyTeardown, + address, kWholeV6Mask, NULL, 0, + zero, kZeroV6Mask, NULL, 0); + +fin: + if (0 <= s) + close(s); + return err; + } + +int +do_mDNSAutoTunnelInterfaceUpDown(__unused mach_port_t port, int updown, + v6addr_t address, int *err, audit_token_t token) + { + debug("entry"); + *err = 0; + if (!authorized(&token)) + { + *err = kmDNSHelperNotAuthorized; + goto fin; + } + switch ((enum mDNSUpDown)updown) + { + case kmDNSUp: + *err = aliasTunnelAddress(address); + break; + case kmDNSDown: + *err = unaliasTunnelAddress(address); + break; + default: + *err = kmDNSHelperInvalidInterfaceState; + goto fin; + } + debug("succeeded"); + +fin: + update_idle_timer(); + return KERN_SUCCESS; + } + +static const char racoon_config_path[] = "/etc/racoon/remote/anonymous.conf"; +static const char racoon_config_path_orig[] = "/etc/racoon/remote/anonymous.conf.orig"; + +static const char configHeader[] = "# BackToMyMac\n"; + +static int IsFamiliarRacoonConfiguration() + { + int fd = open(racoon_config_path, O_RDONLY); + debug("entry"); + if (0 > fd) + { + helplog(ASL_LEVEL_NOTICE, "open \"%s\" failed: %s", racoon_config_path, strerror(errno)); + return 0; + } + else + { + char header[sizeof(configHeader)] = {0}; + ssize_t bytesRead = read(fd, header, sizeof(header)-1); + close(fd); + if (bytesRead != sizeof(header)-1) return 0; + return (0 == memcmp(header, configHeader, sizeof(header)-1)); + } + } + +static void +revertAnonymousRacoonConfiguration() + { + debug("entry"); + if (!IsFamiliarRacoonConfiguration()) + { + helplog(ASL_LEVEL_NOTICE, "\"%s\" does not look familiar, leaving in place", racoon_config_path); + return; + } + + if (0 > rename(racoon_config_path_orig, racoon_config_path)) + { + helplog(ASL_LEVEL_NOTICE, "rename \"%s\" \"%s\" failed: %s", racoon_config_path_orig, racoon_config_path, strerror(errno)); + helplog(ASL_LEVEL_NOTICE, "\"%s\" looks familiar, unlinking", racoon_config_path); + unlink(racoon_config_path); + } + } + +static int +createAnonymousRacoonConfiguration(const char *keydata) + { + static const char config1[] = + "remote anonymous {\n" + " exchange_mode aggressive;\n" + " doi ipsec_doi;\n" + " situation identity_only;\n" + " verify_identifier off;\n" + " generate_policy on;\n" + " shared_secret use \""; + static const char config2[] = + "\";\n" + " nonce_size 16;\n" + " lifetime time 5 min;\n" + " initial_contact on;\n" + " support_proxy on;\n" + " nat_traversal force;\n" + " proposal_check claim;\n" + " proposal {\n" + " encryption_algorithm aes;\n" + " hash_algorithm sha1;\n" + " authentication_method pre_shared_key;\n" + " dh_group 2;\n" + " lifetime time 5 min;\n" + " }\n" + "}\n\n" + "sainfo anonymous { \n" + " pfs_group 2;\n" + " lifetime time 10 min;\n" + " encryption_algorithm aes;\n" + " authentication_algorithm hmac_sha1;\n" + " compression_algorithm deflate;\n" + "}\n"; + char tmp_config_path[] = + "/etc/racoon/remote/tmp.XXXXXX"; + int fd = mkstemp(tmp_config_path); + + debug("entry"); + + if (0 > fd) + { + helplog(ASL_LEVEL_ERR, "mkstemp \"%s\" failed: %s", + tmp_config_path, strerror(errno)); + return -1; + } + write(fd, configHeader, sizeof(configHeader)-1); + write(fd, config1, sizeof(config1)-1); + write(fd, keydata, strlen(keydata)); + write(fd, config2, sizeof(config2)-1); + close(fd); + + if (IsFamiliarRacoonConfiguration()) + helplog(ASL_LEVEL_NOTICE, "\"%s\" looks familiar, will overwrite", racoon_config_path); + else if (0 > rename(racoon_config_path, racoon_config_path_orig)) // If we didn't write it, move it to the side so it can be reverted later + helplog(ASL_LEVEL_NOTICE, "rename \"%s\" \"%s\" failed: %s", racoon_config_path, racoon_config_path_orig, strerror(errno)); + else + debug("successfully renamed \"%s\" \"%s\"", racoon_config_path, racoon_config_path_orig); + + if (0 > rename(tmp_config_path, racoon_config_path)) + { + unlink(tmp_config_path); + helplog(ASL_LEVEL_ERR, "rename \"%s\" \"%s\" failed: %s", + tmp_config_path, racoon_config_path, strerror(errno)); + revertAnonymousRacoonConfiguration(); + return -1; + } + + debug("successfully renamed \"%s\" \"%s\"", tmp_config_path, racoon_config_path); + return 0; + } + +static int +notifyRacoon(void) + { + debug("entry"); + static const char racoon_pid_path[] = "/var/run/racoon.pid"; + char buf[] = "18446744073709551615"; /* largest 64-bit integer */ + char *p = NULL; + ssize_t n = 0; + unsigned long m = 0; + int fd = open(racoon_pid_path, O_RDONLY); + + if (0 > fd) + { + debug("open \"%s\" failed, and that's OK: %s", racoon_pid_path, + strerror(errno)); + return kmDNSHelperRacoonNotificationFailed; + } + n = read(fd, buf, sizeof(buf)-1); + close(fd); + if (1 > n) + { + debug("read of \"%s\" failed: %s", racoon_pid_path, + n == 0 ? "empty file" : strerror(errno)); + return kmDNSHelperRacoonNotificationFailed; + } + buf[n] = '\0'; + m = strtoul(buf, &p, 10); + if (*p != '\0' && !isspace(*p)) + { + debug("invalid PID \"%s\" (around '%c')", buf, *p); + return kmDNSHelperRacoonNotificationFailed; + } + if (2 > m) + { + debug("refusing to kill PID %lu", m); + return kmDNSHelperRacoonNotificationFailed; + } + if (0 != kill(m, SIGHUP)) + { + debug("Could not signal racoon (%lu): %s", m, strerror(errno)); + return kmDNSHelperRacoonNotificationFailed; + } + debug("Sent SIGHUP to racoon (%lu)", m); + return 0; + } + +static int +startRacoon(void) + { + debug("entry"); + char * const racoon_args[] = { "/usr/sbin/racoon", "-e", NULL }; + ssize_t n = 0; + pid_t pid = 0; + int status = 0; + + if (0 == (pid = fork())) + { + closefds(0); + execve(racoon_args[0], racoon_args, NULL); + helplog(ASL_LEVEL_ERR, "execve of \"%s\" failed: %s", + racoon_args[0], strerror(errno)); + exit(2); + } + helplog(ASL_LEVEL_NOTICE, "racoon (pid=%lu) started", + (unsigned long)pid); + n = waitpid(pid, &status, 0); + if (-1 == n) + { + helplog(ASL_LEVEL_ERR, "Unexpected waitpid failure: %s", + strerror(errno)); + return kmDNSHelperRacoonStartFailed; + } + else if (pid != n) + { + helplog(ASL_LEVEL_ERR, "Unexpected waitpid return value %d", + (int)n); + return kmDNSHelperRacoonStartFailed; + } + else if (WIFSIGNALED(status)) + { + helplog(ASL_LEVEL_ERR, + "racoon (pid=%lu) terminated due to signal %d", + (unsigned long)pid, WTERMSIG(status)); + return kmDNSHelperRacoonStartFailed; + } + else if (WIFSTOPPED(status)) + { + helplog(ASL_LEVEL_ERR, + "racoon (pid=%lu) has stopped due to signal %d", + (unsigned long)pid, WSTOPSIG(status)); + return kmDNSHelperRacoonStartFailed; + } + else if (0 != WEXITSTATUS(status)) + { + helplog(ASL_LEVEL_ERR, + "racoon (pid=%lu) exited with status %d", + (unsigned long)pid, WEXITSTATUS(status)); + return kmDNSHelperRacoonStartFailed; + } + debug("racoon (pid=%lu) daemonized normally", (unsigned long)pid); + return 0; + } + +static int +kickRacoon(void) + { + if ( 0 == notifyRacoon() ) + return 0; + return startRacoon(); + } + +int +do_mDNSConfigureServer(__unused mach_port_t port, int updown, const char *keydata, int *err, audit_token_t token) + { + debug("entry"); + *err = 0; + + if (!authorized(&token)) + { + *err = kmDNSHelperNotAuthorized; + goto fin; + } + + switch ((enum mDNSUpDown)updown) + { + case kmDNSUp: + if (0 != createAnonymousRacoonConfiguration(keydata)) + { + *err = kmDNSHelperRacoonConfigCreationFailed; + goto fin; + } + break; + case kmDNSDown: + revertAnonymousRacoonConfiguration(); + break; + default: + *err = kmDNSHelperInvalidServerState; + goto fin; + } + + if (0 != (*err = kickRacoon())) + goto fin; + debug("succeeded"); + +fin: + update_idle_timer(); + return KERN_SUCCESS; + } + +static unsigned int routeSeq = 1; + +static int +setupTunnelRoute(v6addr_t local, v6addr_t remote) + { + struct + { + struct rt_msghdr hdr; + struct sockaddr_in6 dst; + struct sockaddr_in6 gtwy; + } msg; + int err = 0; + int s = -1; + + if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET))) + { + helplog(ASL_LEVEL_ERR, "socket(PF_ROUTE, ...) failed: %s", + strerror(errno)); + err = kmDNSHelperRoutingSocketCreationFailed; + goto fin; + } + memset(&msg, 0, sizeof(msg)); + msg.hdr.rtm_msglen = sizeof(msg); + msg.hdr.rtm_type = RTM_ADD; + /* The following flags are set by `route add -inet6 -host ...` */ + msg.hdr.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_HOST | RTF_STATIC; + msg.hdr.rtm_version = RTM_VERSION; + msg.hdr.rtm_seq = routeSeq++; + msg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY; + msg.hdr.rtm_inits = RTV_MTU; + msg.hdr.rtm_rmx.rmx_mtu = 1280; + + msg.dst.sin6_len = sizeof(msg.dst); + msg.dst.sin6_family = AF_INET6; + memcpy(&msg.dst.sin6_addr, remote, sizeof(msg.dst.sin6_addr)); + + msg.gtwy.sin6_len = sizeof(msg.gtwy); + msg.gtwy.sin6_family = AF_INET6; + memcpy(&msg.gtwy.sin6_addr, local, sizeof(msg.gtwy.sin6_addr)); + + /* send message, ignore error when route already exists */ + if (0 > write(s, &msg, msg.hdr.rtm_msglen)) + { + int errno_ = errno; + + debug("write to routing socket failed: %s", strerror(errno_)); + if (EEXIST != errno_) + { + err = kmDNSHelperRouteAdditionFailed; + goto fin; + } + } + +fin: + if (0 <= s) + close(s); + return err; + } + +static int +teardownTunnelRoute(v6addr_t remote) + { + struct + { + struct rt_msghdr hdr; + struct sockaddr_in6 dst; + } msg; + int err = 0; + int s = -1; + + if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET))) + { + helplog(ASL_LEVEL_ERR, "socket(PF_ROUTE, ...) failed: %s", + strerror(errno)); + err = kmDNSHelperRoutingSocketCreationFailed; + goto fin; + } + memset(&msg, 0, sizeof(msg)); + + msg.hdr.rtm_msglen = sizeof(msg); + msg.hdr.rtm_type = RTM_DELETE; + msg.hdr.rtm_version = RTM_VERSION; + msg.hdr.rtm_seq = routeSeq++; + msg.hdr.rtm_addrs = RTA_DST; + + msg.dst.sin6_len = sizeof(msg.dst); + msg.dst.sin6_family = AF_INET6; + memcpy(&msg.dst.sin6_addr, remote, sizeof(msg.dst.sin6_addr)); + if (0 > write(s, &msg, msg.hdr.rtm_msglen)) + { + int errno_ = errno; + + debug("write to routing socket failed: %s", strerror(errno_)); + if (ESRCH != errno_) + { + err = kmDNSHelperRouteDeletionFailed; + goto fin; + } + } + +fin: + if (0 <= s) + close(s); + return err; + } + +static int +v4addr_to_string(v4addr_t addr, char *buf, size_t buflen) + { + if (NULL == inet_ntop(AF_INET, addr, buf, buflen)) + { + helplog(ASL_LEVEL_ERR, "inet_ntop failed: %s", + strerror(errno)); + return kmDNSHelperInvalidNetworkAddress; + } + else + return 0; + } + +static int +v6addr_to_string(v6addr_t addr, char *buf, size_t buflen) + { + if (NULL == inet_ntop(AF_INET6, addr, buf, buflen)) + { + helplog(ASL_LEVEL_ERR, "inet_ntop failed: %s", + strerror(errno)); + return kmDNSHelperInvalidNetworkAddress; + } + else + return 0; + } + +/* Caller owns object returned in `policy' */ +static int +generateTunnelPolicy(mDNSTunnelPolicyWhich which, int in, + v4addr_t src, uint16_t src_port, + v4addr_t dst, uint16_t dst_port, + ipsec_policy_t *policy, size_t *len) + { + char srcs[INET_ADDRSTRLEN], dsts[INET_ADDRSTRLEN]; + char buf[128]; + char *inOut = in ? "in" : "out"; + ssize_t n = 0; + int err = 0; + + *policy = NULL; + *len = 0; + + switch (which) + { + case kmDNSTunnelPolicySetup: + if (0 != (err = v4addr_to_string(src, srcs, sizeof(srcs)))) + goto fin; + if (0 != (err = v4addr_to_string(dst, dsts, sizeof(dsts)))) + goto fin; + n = snprintf(buf, sizeof(buf), + "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require", + inOut, srcs, src_port, dsts, dst_port); + break; + case kmDNSTunnelPolicyTeardown: + n = strlcpy(buf, inOut, sizeof(buf)); + break; + case kmDNSTunnelPolicyGenerate: + n = snprintf(buf, sizeof(buf), "%s generate", inOut); + break; + default: + err = kmDNSHelperIPsecPolicyCreationFailed; + goto fin; + } + + if (n >= (int)sizeof(buf)) + { + err = kmDNSHelperResultTooLarge; + goto fin; + } + + debug("policy=\"%s\"", buf); + if (NULL == (*policy = (ipsec_policy_t)ipsec_set_policy(buf, n))) + { + helplog(ASL_LEVEL_ERR, + "Could not create IPsec policy from \"%s\"", buf); + err = kmDNSHelperIPsecPolicyCreationFailed; + goto fin; + } + *len = ((ipsec_policy_t)(*policy))->sadb_x_policy_len * 8; + +fin: + return err; + } + +static int +sendPolicy(int s, int setup, + struct sockaddr *src, uint8_t src_bits, + struct sockaddr *dst, uint8_t dst_bits, + ipsec_policy_t policy, size_t len) + { + static unsigned int policySeq = 0; + int err = 0; + + debug("entry, setup=%d", setup); + if (setup) + err = pfkey_send_spdadd(s, src, src_bits, dst, dst_bits, -1, + (char *)policy, len, policySeq++); + else + err = pfkey_send_spddelete(s, src, src_bits, dst, dst_bits, -1, + (char *)policy, len, policySeq++); + if (0 > err) + { + helplog(ASL_LEVEL_ERR, "Could not set IPsec policy: %s", + ipsec_strerror()); + err = kmDNSHelperIPsecPolicySetFailed; + goto fin; + } + else + err = 0; + debug("succeeded"); + +fin: + return err; + } + +static int +removeSA(int s, struct sockaddr *src, struct sockaddr *dst) + { + int err = 0; + + debug("entry"); + err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, src, dst); + if (0 > err) + { + helplog(ASL_LEVEL_ERR, "Could not remove IPsec SA: %s", ipsec_strerror()); + err = kmDNSHelperIPsecRemoveSAFailed; + goto fin; + } + err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, dst, src); + if (0 > err) + { + helplog(ASL_LEVEL_ERR, "Could not remove IPsec SA: %s", ipsec_strerror()); + err = kmDNSHelperIPsecRemoveSAFailed; + goto fin; + } + else + err = 0; + + debug("succeeded"); + +fin: + return err; + } + +static int +doTunnelPolicy(mDNSTunnelPolicyWhich which, + v6addr_t loc_inner, uint8_t loc_bits, + v4addr_t loc_outer, uint16_t loc_port, + v6addr_t rmt_inner, uint8_t rmt_bits, + v4addr_t rmt_outer, uint16_t rmt_port) + { + struct sockaddr_in6 sin_loc; + struct sockaddr_in6 sin_rmt; + ipsec_policy_t policy = NULL; + size_t len = 0; + int s = -1; + int err = 0; + + debug("entry"); + if (0 > (s = pfkey_open())) + { + helplog(ASL_LEVEL_ERR, + "Could not create IPsec policy socket: %s", + ipsec_strerror()); + err = kmDNSHelperIPsecPolicySocketCreationFailed; + goto fin; + } + + memset(&sin_loc, 0, sizeof(sin_loc)); + sin_loc.sin6_len = sizeof(sin_loc); + sin_loc.sin6_family = AF_INET6; + sin_loc.sin6_port = htons(0); + memcpy(&sin_loc.sin6_addr, loc_inner, sizeof(sin_loc.sin6_addr)); + + memset(&sin_rmt, 0, sizeof(sin_rmt)); + sin_rmt.sin6_len = sizeof(sin_rmt); + sin_rmt.sin6_family = AF_INET6; + sin_rmt.sin6_port = htons(0); + memcpy(&sin_rmt.sin6_addr, rmt_inner, sizeof(sin_rmt.sin6_addr)); + + int setup = which != kmDNSTunnelPolicyTeardown; + + if (0 != (err = generateTunnelPolicy(which, 1, + rmt_outer, rmt_port, + loc_outer, loc_port, + &policy, &len))) + goto fin; + if (0 != (err = sendPolicy(s, setup, + (struct sockaddr *)&sin_rmt, rmt_bits, + (struct sockaddr *)&sin_loc, loc_bits, + policy, len))) + goto fin; + if (NULL != policy) + { + free(policy); + policy = NULL; + } + if (0 != (err = generateTunnelPolicy(which, 0, + loc_outer, loc_port, + rmt_outer, rmt_port, + &policy, &len))) + goto fin; + if (0 != (err = sendPolicy(s, setup, + (struct sockaddr *)&sin_loc, loc_bits, + (struct sockaddr *)&sin_rmt, rmt_bits, + policy, len))) + goto fin; + + if (which == kmDNSTunnelPolicyTeardown && loc_outer && rmt_outer) + { + struct sockaddr_in sin_loc; + struct sockaddr_in sin_rmt; + + memset(&sin_loc, 0, sizeof(sin_loc)); + sin_loc.sin_len = sizeof(sin_loc); + sin_loc.sin_family = AF_INET; + sin_loc.sin_port = htons(0); + memcpy(&sin_loc.sin_addr, loc_outer, sizeof(sin_loc.sin_addr)); + + memset(&sin_rmt, 0, sizeof(sin_rmt)); + sin_rmt.sin_len = sizeof(sin_rmt); + sin_rmt.sin_family = AF_INET; + sin_rmt.sin_port = htons(0); + memcpy(&sin_rmt.sin_addr, rmt_outer, sizeof(sin_rmt.sin_addr)); + + if (0 != (err = removeSA(s, (struct sockaddr *)&sin_loc, (struct sockaddr *)&sin_rmt))) + goto fin; + } + + debug("succeeded"); + +fin: + if (0 >= s) + close(s); + if (NULL != policy) + free(policy); + return err; + } + +int +do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete, + v6addr_t loc_inner, v4addr_t loc_outer, uint16_t loc_port, + v6addr_t rmt_inner, v4addr_t rmt_outer, uint16_t rmt_port, + const char *keydata, int *err, audit_token_t token) + { + static const char config[] = + "%s" + "remote %s [%u] {\n" + " exchange_mode aggressive;\n" + " doi ipsec_doi;\n" + " situation identity_only;\n" + " verify_identifier off;\n" + " generate_policy on;\n" + " shared_secret use \"%s\";\n" + " nonce_size 16;\n" + " lifetime time 5 min;\n" + " initial_contact on;\n" + " support_proxy on;\n" + " nat_traversal force;\n" + " proposal_check claim;\n" + " proposal {\n" + " encryption_algorithm aes;\n" + " hash_algorithm sha1;\n" + " authentication_method pre_shared_key;\n" + " dh_group 2;\n" + " lifetime time 5 min;\n" + " }\n" + "}\n\n" + "sainfo address %s any address %s any {\n" + " pfs_group 2;\n" + " lifetime time 10 min;\n" + " encryption_algorithm aes;\n" + " authentication_algorithm hmac_sha1;\n" + " compression_algorithm deflate;\n" + "}\n\n" + "sainfo address %s any address %s any {\n" + " pfs_group 2;\n" + " lifetime time 10 min;\n" + " encryption_algorithm aes;\n" + " authentication_algorithm hmac_sha1;\n" + " compression_algorithm deflate;\n" + "}\n"; + char path[PATH_MAX] = ""; + char li[INET6_ADDRSTRLEN], lo[INET_ADDRSTRLEN], + ri[INET6_ADDRSTRLEN], ro[INET_ADDRSTRLEN]; + FILE *fp = NULL; + int fd = -1; + char tmp_path[PATH_MAX] = ""; + + debug("entry"); + *err = 0; + if (!authorized(&token)) + { + *err = kmDNSHelperNotAuthorized; + goto fin; + } + switch ((enum mDNSAutoTunnelSetKeysReplaceDelete)replacedelete) + { + case kmDNSAutoTunnelSetKeysReplace: + case kmDNSAutoTunnelSetKeysDelete: + break; + default: + *err = kmDNSHelperInvalidTunnelSetKeysOperation; + goto fin; + } + if (0 != (*err = v6addr_to_string(loc_inner, li, sizeof(li)))) + goto fin; + if (0 != (*err = v6addr_to_string(rmt_inner, ri, sizeof(ri)))) + goto fin; + if (0 != (*err = v4addr_to_string(loc_outer, lo, sizeof(lo)))) + goto fin; + if (0 != (*err = v4addr_to_string(rmt_outer, ro, sizeof(ro)))) + goto fin; + debug("loc_inner=%s rmt_inner=%s", li, ri); + debug("loc_outer=%s loc_port=%u rmt_outer=%s rmt_port=%u", + lo, loc_port, ro, rmt_port); + + if ((int)sizeof(path) <= snprintf(path, sizeof(path), + "/etc/racoon/remote/%s.%u.conf", ro, + rmt_port)) + { + *err = kmDNSHelperResultTooLarge; + goto fin; + } + if (kmDNSAutoTunnelSetKeysReplace == replacedelete) + { + if ((int)sizeof(tmp_path) <= + snprintf(tmp_path, sizeof(tmp_path), "%s.XXXXXX", path)) + { + *err = kmDNSHelperResultTooLarge; + goto fin; + } + if (0 > (fd = mkstemp(tmp_path))) + { + helplog(ASL_LEVEL_ERR, "mktemp \"%s\" failed: %s", + tmp_path, strerror(errno)); + *err = kmDNSHelperRacoonConfigCreationFailed; + goto fin; + } + if (NULL == (fp = fdopen(fd, "w"))) + { + helplog(ASL_LEVEL_ERR, "fdopen: %s", + strerror(errno)); + *err = kmDNSHelperRacoonConfigCreationFailed; + goto fin; + } + fd = -1; + fprintf(fp, config, configHeader, ro, rmt_port, keydata, ri, li, li, ri); + fclose(fp); + fp = NULL; + if (0 > rename(tmp_path, path)) + { + helplog(ASL_LEVEL_ERR, + "rename \"%s\" \"%s\" failed: %s", + tmp_path, path, strerror(errno)); + *err = kmDNSHelperRacoonConfigCreationFailed; + goto fin; + } + if (0 != (*err = kickRacoon())) + goto fin; + } + else + { + if (0 != unlink(path)) + debug("unlink \"%s\" failed: %s", path, + strerror(errno)); + } + + if (0 != (*err = doTunnelPolicy(kmDNSTunnelPolicyTeardown, + loc_inner, kWholeV6Mask, loc_outer, loc_port, + rmt_inner, kWholeV6Mask, rmt_outer, rmt_port))) + goto fin; + if (kmDNSAutoTunnelSetKeysReplace == replacedelete && + 0 != (*err = doTunnelPolicy(kmDNSTunnelPolicySetup, + loc_inner, kWholeV6Mask, loc_outer, loc_port, + rmt_inner, kWholeV6Mask, rmt_outer, rmt_port))) + goto fin; + + if (0 != (*err = teardownTunnelRoute(rmt_inner))) + goto fin; + if (kmDNSAutoTunnelSetKeysReplace == replacedelete && + 0 != (*err = setupTunnelRoute(loc_inner, rmt_inner))) + goto fin; + + debug("succeeded"); + +fin: + if (NULL != fp) + fclose(fp); + if (0 <= fd) + close(fd); + unlink(tmp_path); + update_idle_timer(); + return KERN_SUCCESS; + } diff --git a/mDNSMacOSX/helper.h b/mDNSMacOSX/helper.h new file mode 100644 index 0000000..00d5289 --- /dev/null +++ b/mDNSMacOSX/helper.h @@ -0,0 +1,90 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2007 Apple Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + Change History (most recent first): + +$Log: helper.h,v $ +Revision 1.6 2007/09/20 22:33:17 cheshire +Tidied up inconsistent and error-prone naming -- used to be mDNSResponderHelper in +some places and mDNSResponder.helper in others; now mDNSResponderHelper everywhere + +Revision 1.5 2007/09/07 22:44:03 mcguire + Move CFUserNotification code to mDNSResponderHelper + +Revision 1.4 2007/09/04 22:32:58 mcguire + BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf + +Revision 1.3 2007/08/23 21:51:44 cheshire +Made code layout style consistent with existing project style; added $Log header + +Revision 1.1 2007/08/08 22:34:58 mcguire + Security: Run mDNSResponder as user id mdnsresponder instead of root + */ + +#ifndef H_HELPER_H +#define H_HELPER_H + +#define kmDNSHelperServiceName "com.apple.mDNSResponderHelper" + +enum mDNSDynamicStoreSetConfigKey + { + kmDNSMulticastConfig = 1, + kmDNSDynamicConfig, + kmDNSPrivateConfig, + kmDNSBackToMyMacConfig + }; + +enum mDNSPreferencesSetNameKey + { + kmDNSComputerName = 1, + kmDNSLocalHostName + }; + +enum mDNSUpDown + { + kmDNSUp = 1, + kmDNSDown + }; + +enum mDNSAutoTunnelSetKeysReplaceDelete + { + kmDNSAutoTunnelSetKeysReplace = 1, + kmDNSAutoTunnelSetKeysDelete + }; + +#define ERROR(x, y) x, +enum mDNSHelperErrors + { + mDNSHelperErrorBase = 2300, + #include "helper-error.h" + mDNSHelperErrorEnd + }; +#undef ERROR + +#include "mDNSEmbeddedAPI.h" +#include "helpermsg-types.h" + +extern const char *mDNSHelperError(int errornum); +extern int mDNSPreferencesSetName(int key, domainlabel* old, domainlabel* new); +extern int mDNSDynamicStoreSetConfig(int key, CFPropertyListRef value); +extern int mDNSKeychainGetSecrets(CFArrayRef *secrets); +extern int mDNSAutoTunnelInterfaceUpDown(int updown, v6addr_t addr); +extern int mDNSConfigureServer(int updown, const char *keydata); +extern int mDNSAutoTunnelSetKeys(int replacedelete, v6addr_t local_inner, + v4addr_t local_outer, short local_port, v6addr_t remote_inner, + v4addr_t remote_outer, short remote_port, const char *keydata); + +#endif /* H_HELPER_H */ diff --git a/mDNSMacOSX/helpermsg-types.h b/mDNSMacOSX/helpermsg-types.h new file mode 100644 index 0000000..1321692 --- /dev/null +++ b/mDNSMacOSX/helpermsg-types.h @@ -0,0 +1,35 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2007 Apple Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + Change History (most recent first): + +$Log: helpermsg-types.h,v $ +Revision 1.2 2007/08/23 21:52:19 cheshire +Added License header + +Revision 1.1 2007/08/08 22:34:58 mcguire + Security: Run mDNSResponder as user id mdnsresponder instead of root + */ + +#ifndef H_HELPERMSG_TYPES_H +#define H_HELPERMSG_TYPES_H + +#include +typedef uint8_t v6addr_t[16]; +typedef uint8_t v4addr_t[4]; +typedef const char *string_t; + +#endif /* H_HELPERMSG_TYPES_H */ diff --git a/mDNSMacOSX/helpermsg.defs b/mDNSMacOSX/helpermsg.defs new file mode 100644 index 0000000..03ae2da --- /dev/null +++ b/mDNSMacOSX/helpermsg.defs @@ -0,0 +1,103 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2007 Apple Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + Change History (most recent first): + +$Log: helpermsg.defs,v $ +Revision 1.6 2007/09/07 22:44:03 mcguire + Move CFUserNotification code to mDNSResponderHelper + +Revision 1.5 2007/09/04 22:32:58 mcguire + BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf + +Revision 1.4 2007/08/23 21:53:13 cheshire +Added $Log header + +Revision 1.3 2007/08/18 01:02:03 mcguire + No Bonjour services are getting registered at boot + +Revision 1.2 2007/08/15 23:20:28 mcguire + BTMM: racoon files can get corrupted if autotunnel is listening on port > 32767 + +Revision 1.1 2007/08/08 22:34:58 mcguire + Security: Run mDNSResponder as user id mdnsresponder instead of root + */ + +#include +#include + +import "helpermsg-types.h"; + +type v6addr_t = array [16] of uint8_t; +type v4addr_t = array [4] of uint8_t; +type string_t = c_string[*:1024]; + +subsystem helper 1833193043; +serverprefix do_; +userprefix proxy_; + +simpleroutine mDNSIdleExit( + port : mach_port_t; + ServerAuditToken token : audit_token_t); + +routine mDNSDynamicStoreSetConfig( + port : mach_port_t; + key : int; + value : pointer_t; + out err : int; + ServerAuditToken token : audit_token_t); + +routine mDNSPreferencesSetName( + port : mach_port_t; + key : int; + old : string_t; + new : string_t; + out err : int; + ServerAuditToken token : audit_token_t); + +routine mDNSKeychainGetSecrets( + port : mach_port_t; + out numsecrets : unsigned; + out secrets : pointer_t; + out err : int; + ServerAuditToken token : audit_token_t); + +routine mDNSAutoTunnelInterfaceUpDown( + port : mach_port_t; + updown : int; + address : v6addr_t; + out err : int; + ServerAuditToken token : audit_token_t); + +routine mDNSConfigureServer( + port : mach_port_t; + updown : int; + keydata : string_t; + out err : int; + ServerAuditToken token : audit_token_t); + +routine mDNSAutoTunnelSetKeys( + port : mach_port_t; + replacedelete : int; + local_inner : v6addr_t; + local_outer : v4addr_t; + local_port : uint16_t; + remote_inner : v6addr_t; + remote_outer : v4addr_t; + remote_port : uint16_t; + keydata : string_t; + out err : int; + ServerAuditToken token : audit_token_t); diff --git a/mDNSMacOSX/ipsec_strerror.h b/mDNSMacOSX/ipsec_strerror.h new file mode 100644 index 0000000..4104f85 --- /dev/null +++ b/mDNSMacOSX/ipsec_strerror.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2003-2007 Apple Computer, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* $FreeBSD: src/lib/libipsec/ipsec_strerror.h,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $ */ +/* $KAME: ipsec_strerror.h,v 1.8 2000/07/30 00:45:12 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +extern int __ipsec_errcode; +extern void __ipsec_set_strerror __P((const char *)); + +#define EIPSEC_NO_ERROR 0 /*success*/ +#define EIPSEC_NOT_SUPPORTED 1 /*not supported*/ +#define EIPSEC_INVAL_ARGUMENT 2 /*invalid argument*/ +#define EIPSEC_INVAL_SADBMSG 3 /*invalid sadb message*/ +#define EIPSEC_INVAL_VERSION 4 /*invalid version*/ +#define EIPSEC_INVAL_POLICY 5 /*invalid security policy*/ +#define EIPSEC_INVAL_ADDRESS 6 /*invalid address specification*/ +#define EIPSEC_INVAL_PROTO 7 /*invalid ipsec protocol*/ +#define EIPSEC_INVAL_MODE 8 /*Invalid ipsec mode*/ +#define EIPSEC_INVAL_LEVEL 9 /*invalid ipsec level*/ +#define EIPSEC_INVAL_SATYPE 10 /*invalid SA type*/ +#define EIPSEC_INVAL_MSGTYPE 11 /*invalid message type*/ +#define EIPSEC_INVAL_EXTTYPE 12 /*invalid extension type*/ +#define EIPSEC_INVAL_ALGS 13 /*Invalid algorithm type*/ +#define EIPSEC_INVAL_KEYLEN 14 /*invalid key length*/ +#define EIPSEC_INVAL_FAMILY 15 /*invalid address family*/ +#define EIPSEC_INVAL_PREFIXLEN 16 /*SPI range violation*/ +#define EIPSEC_INVAL_DIR 17 /*Invalid direciton*/ +#define EIPSEC_INVAL_SPI 18 /*invalid prefixlen*/ +#define EIPSEC_NO_PROTO 19 /*no protocol specified*/ +#define EIPSEC_NO_ALGS 20 /*No algorithm specified*/ +#define EIPSEC_NO_BUFS 21 /*no buffers available*/ +#define EIPSEC_DO_GET_SUPP_LIST 22 /*must get supported algorithm first*/ +#define EIPSEC_PROTO_MISMATCH 23 /*protocol mismatch*/ +#define EIPSEC_FAMILY_MISMATCH 24 /*family mismatch*/ +#define EIPSEC_FEW_ARGUMENTS 25 /*Too few arguments*/ +#define EIPSEC_SYSTEM_ERROR 26 /*system error*/ +#define EIPSEC_MAX 27 /*unknown error*/ diff --git a/mDNSMacOSX/libpfkey.h b/mDNSMacOSX/libpfkey.h new file mode 100644 index 0000000..077414b --- /dev/null +++ b/mDNSMacOSX/libpfkey.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2003-2007 Apple Computer, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* $FreeBSD: src/lib/libipsec/libpfkey.h,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $ */ +/* $KAME: libpfkey.h,v 1.6 2001/03/05 18:22:17 thorpej Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +struct sadb_msg; +extern void pfkey_sadump __P((struct sadb_msg *)); +extern void pfkey_spdump __P((struct sadb_msg *)); + +struct sockaddr; +struct sadb_alg; +int ipsec_check_keylen __P((u_int, u_int, u_int)); +int ipsec_check_keylen2 __P((u_int, u_int, u_int)); +int ipsec_get_keylen __P((u_int, u_int, struct sadb_alg *)); +u_int pfkey_set_softrate __P((u_int, u_int)); +u_int pfkey_get_softrate __P((u_int)); +int pfkey_send_getspi __P((int, u_int, u_int, struct sockaddr *, + struct sockaddr *, u_int32_t, u_int32_t, u_int32_t, u_int32_t)); +int pfkey_send_update __P((int, u_int, u_int, struct sockaddr *, + struct sockaddr *, u_int32_t, u_int32_t, u_int, + caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t, + u_int64_t, u_int64_t, u_int32_t)); +int pfkey_send_add __P((int, u_int, u_int, struct sockaddr *, + struct sockaddr *, u_int32_t, u_int32_t, u_int, + caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t, + u_int64_t, u_int64_t, u_int32_t)); +int pfkey_send_delete __P((int, u_int, u_int, + struct sockaddr *, struct sockaddr *, u_int32_t)); +int pfkey_send_delete_all __P((int, u_int, u_int, + struct sockaddr *, struct sockaddr *)); +int pfkey_send_get __P((int, u_int, u_int, + struct sockaddr *, struct sockaddr *, u_int32_t)); +int pfkey_send_register __P((int, u_int)); +int pfkey_recv_register __P((int)); +int pfkey_set_supported __P((struct sadb_msg *, int)); +int pfkey_send_flush __P((int, u_int)); +int pfkey_send_dump __P((int, u_int)); +int pfkey_send_promisc_toggle __P((int, int)); +int pfkey_send_spdadd __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); +int pfkey_send_spdadd2 __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t, + caddr_t, int, u_int32_t)); +int pfkey_send_spdupdate __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); +int pfkey_send_spdupdate2 __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t, + caddr_t, int, u_int32_t)); +int pfkey_send_spddelete __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); +int pfkey_send_spddelete2 __P((int, u_int32_t)); +int pfkey_send_spdget __P((int, u_int32_t)); +int pfkey_send_spdsetidx __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); +int pfkey_send_spdflush __P((int)); +int pfkey_send_spddump __P((int)); + +int pfkey_open __P((void)); +void pfkey_close __P((int)); +struct sadb_msg *pfkey_recv __P((int)); +int pfkey_send __P((int, struct sadb_msg *, int)); +int pfkey_align __P((struct sadb_msg *, caddr_t *)); +int pfkey_check __P((caddr_t *)); diff --git a/mDNSMacOSX/mDNSMacOSX.c b/mDNSMacOSX/mDNSMacOSX.c index c1bd30f..bf316b5 100644 --- a/mDNSMacOSX/mDNSMacOSX.c +++ b/mDNSMacOSX/mDNSMacOSX.c @@ -2,969 +2,599 @@ * * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: mDNSMacOSX.c,v $ -Revision 1.318.2.3 2007/07/18 20:35:42 cheshire -Bracket LegacyNATInit/LegacyNATDestroy calls with "#ifdef _LEGACY_NAT_TRAVERSAL_" - -Revision 1.318.2.2 2006/12/14 21:38:51 cheshire -Fix problem exposed by previous changes: kSecAccountItemAttr is not necessarily nul-terminated - -Revision 1.318.2.1 2006/10/31 02:37:04 cheshire - Stop creating HINFO records - -Revision 1.318 2005/10/20 00:10:34 cheshire - Add check to avoid crashing NAT gateways that have buggy DNS relay code - -Revision 1.317 2005/09/24 01:10:26 cheshire -Fix comment typos - -Revision 1.316 2005/07/29 18:04:22 ksekar - Hostname registration should register IPv6 AAAA record with DNS Update - -Revision 1.315 2005/07/22 21:50:55 ksekar -Fix GCC 4.0/Intel compiler warnings - -Revision 1.314 2005/07/11 02:12:09 cheshire - Be defensive against invalid UTF-8 in dynamic host names -Fix copy-and-paste error: "CFRelease(StatusVals[0]);" should be "CFRelease(StateVals[0]);" - -Revision 1.313 2005/07/04 23:52:25 cheshire - Things are showing up with a bogus interface index - -Revision 1.312 2005/07/04 22:24:36 cheshire -Export NotifyOfElusiveBug() so other files can call it - -Revision 1.311 2005/06/15 13:20:43 cheshire - Be defensive against invalid UTF-8 in dynamic host names - -Revision 1.310 2005/04/07 00:49:58 cheshire - PPP connection disables Bonjour ".local" lookups - -Revision 1.309 2005/03/23 05:53:29 cheshire -Fix %s where it should have been %##s in debugf & LogMsg calls - -Revision 1.308 2005/03/09 00:48:44 cheshire - QU packets getting sent too early on wake from sleep -Move "m->p->NetworkChanged = 0;" line from caller to callee - -Revision 1.307 2005/03/03 03:12:02 cheshire -Add comment about mDNSMacOSXSystemBuildNumber() - -Revision 1.306 2005/03/02 22:18:00 cheshire - mDNSResponder requires AppleInternal packages to build on Tiger - -Revision 1.305 2005/02/26 05:08:28 cheshire - mDNSResponder requires AppleInternal packages to build on Tiger -Added dnsinfo.h to project directory - -Revision 1.304 2005/02/25 23:51:22 cheshire - SendServiceRegistration fails on wake from sleep -Return mStatus_UnknownErr instead of -1 - -Revision 1.303 2005/02/25 17:47:45 ksekar - SendServiceRegistration fails on wake from sleep - -Revision 1.302 2005/02/25 02:34:14 cheshire - Should not indicate successful dynamic update if no network connection -Show status as 1 (in progress) while we're trying - -Revision 1.301 2005/02/24 21:55:57 ksekar - Should not indicate successful dynamic update if no network connection - -Revision 1.300 2005/02/15 20:03:13 ksekar - Crash when SCPreferences contains empty array - -Revision 1.299 2005/02/15 02:46:53 cheshire - Don't log ENETUNREACH errors for unicast destinations - -Revision 1.298 2005/02/10 00:41:59 cheshire -Fix compiler warning - -Revision 1.297 2005/02/09 23:38:51 ksekar - Reregister hostname when DNS server changes but IP address does not - -Revision 1.296 2005/02/01 21:06:52 ksekar -Avoid spurious log message - -Revision 1.295 2005/02/01 19:33:30 ksekar - Keychain format too restrictive - -Revision 1.294 2005/01/27 21:30:23 cheshire - "Can't assign requested address" message after AirPort turned off -Don't write syslog messages for EADDRNOTAVAIL if we know network configuration changes are happening - -Revision 1.293 2005/01/27 19:15:41 cheshire -Remove extraneous LogMsg() call - -Revision 1.292 2005/01/27 17:48:38 cheshire -Added comment about CFSocketInvalidate closing the underlying socket - -Revision 1.291 2005/01/27 00:10:58 cheshire - Name change log messages every time machine boots - -Revision 1.290 2005/01/25 23:18:30 ksekar -fix for requires that local-only ".local" registration record be created - -Revision 1.289 2005/01/25 18:08:31 ksekar -Removed redundant debug output - -Revision 1.288 2005/01/25 17:42:26 ksekar -Renamed FoundDefBrowseDomain -> FoundLegacyBrowseDomain, -cleaned up duplicate log messages when adding/removing browse domains - -Revision 1.287 2005/01/25 16:59:23 ksekar - sa_len not set checking reachability for TCP connections - -Revision 1.286 2005/01/25 02:02:37 cheshire - mDNSResponder leaks -GetSearchDomains() was not calling dns_configuration_free(). - -Revision 1.285 2005/01/22 00:07:54 ksekar - mDNSResponder should look at all browse domains in SCPreferences - -Revision 1.284 2005/01/21 23:07:17 ksekar - mDNSResponder causes Dial on Demand - -Revision 1.283 2005/01/19 21:16:16 cheshire -Make sure when we set NetworkChanged that we don't set it to zero - -Revision 1.282 2005/01/19 19:19:21 ksekar - Need a way to turn off domain discovery - -Revision 1.281 2005/01/18 18:10:55 ksekar - Use 10.4 resolver API to get search domains - -Revision 1.280 2005/01/17 22:48:52 ksekar -No longer need to call MarkSearchListElem for registration domain - -Revision 1.279 2005/01/17 20:40:34 ksekar -SCPreferences changes should remove exactly one browse and one legacy browse domain for each remove event - -Revision 1.278 2005/01/17 19:53:34 ksekar -Refinement to previous fix - register _legacy._browse records for SCPreference domains to achieve correct reference counting - -Revision 1.277 2005/01/12 00:17:50 ksekar - Update LLQs *after* setting DNS - -Revision 1.276 2005/01/10 17:39:10 ksekar -Refinement to 1.272 - avoid spurious warnings when registration and browse domains are set to same value and toggled on/off - -Revision 1.275 2005/01/10 04:02:22 ksekar -Refinement to - strip trailing dot before writing hostname status to dynamic store - -Revision 1.274 2005/01/10 03:41:36 ksekar -Correction to checkin 1.272 - check that registration domain is set -before trying to remove it as an implicit browse domain - -Revision 1.273 2005/01/08 00:42:18 ksekar - Clean up syslog messages - -Revision 1.272 2005/01/07 23:21:42 ksekar - Clean up SCPreferences format - -Revision 1.271 2004/12/20 23:18:12 cheshire - Guard against repeating wireless dissociation/re-association -One more refinement: When an interface with a v6LL address gets a v4 address too, that's not a flap - -Revision 1.270 2004/12/20 21:28:14 cheshire - Guard against repeating wireless dissociation/re-association -Additional refinements to handle sleep/wake better - -Revision 1.269 2004/12/20 20:48:11 cheshire -Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xxx) or later - -Revision 1.268 2004/12/18 03:19:04 cheshire -Show netmask in error log - -Revision 1.267 2004/12/18 00:51:52 cheshire -Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0 - -Revision 1.266 2004/12/17 23:49:38 cheshire - Computer Name change is slow -Also treat changes to "Setup:/Network/DynamicDNS" the same way - -Revision 1.265 2004/12/17 23:37:47 cheshire - Guard against repeating wireless dissociation/re-association -(and other repetitive configuration changes) - -Revision 1.264 2004/12/17 19:03:05 cheshire -Update debugging messages to show netmask a simple CIDR-style numeric value (0-128) - -Revision 1.263 2004/12/17 05:25:46 cheshire - Shorten DNS-SD queries to avoid NAT bugs - -Revision 1.262 2004/12/17 04:48:32 cheshire - Computer Name change is slow - -Revision 1.261 2004/12/17 02:40:08 cheshire -Undo last change -- it was too strict - -Revision 1.260 2004/12/16 22:17:16 cheshire -Only accept multicast packets on interfaces that have McastTxRx set +Revision 1.496 2007/10/04 20:33:05 mcguire + BTMM: Racoon configuration removed when network changes -Revision 1.259 2004/12/16 20:13:01 cheshire - Cache memory management improvements +Revision 1.495 2007/10/02 05:03:38 cheshire +Fix bugus indentation in mDNSPlatformDynDNSHostNameStatusChanged -Revision 1.258 2004/12/14 00:18:05 cheshire -Don't log dns_configuration_copy() failures in the first three minutes after boot +Revision 1.494 2007/09/29 20:40:19 cheshire + Crash in ReissueBlockedQuestions -Revision 1.257 2004/12/10 19:45:46 cheshire - Reduce egregious stack space usage -Reduced myCFSocketCallBack() stack frame from 9K to 512 bytes +Revision 1.493 2007/09/29 03:16:45 cheshire + BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal +When AutoTunnel information changes, wait for record deregistrations to complete before registering new data -Revision 1.256 2004/12/10 04:35:43 cheshire - Show "Note: Compiled without Apple-specific split DNS support" only once +Revision 1.492 2007/09/28 23:58:35 mcguire + BTMM: v6 address and security policies being setup too soon +Fix locking issue. -Revision 1.255 2004/12/10 04:12:54 ksekar - Need new DefaultBrowseDomain key +Revision 1.491 2007/09/27 23:28:53 mcguire + BTMM: Anonymous racoon configuration not always cleaned up correctly -Revision 1.254 2004/12/10 01:55:31 ksekar - Keychain lookups should be in lower case. +Revision 1.490 2007/09/26 23:01:21 mcguire + BTMM: v6 address and security policies being setup too soon -Revision 1.253 2004/12/09 03:15:41 ksekar - use _legacy instead of _default to find "empty string" browse domains +Revision 1.489 2007/09/26 22:58:16 mcguire + BTMM: Client tunnels being created to ::0 via 0.0.0.0 -Revision 1.252 2004/12/07 01:32:42 cheshire -Don't log dns_configuration_copy() failure when running on 10.3 +Revision 1.488 2007/09/26 00:32:45 cheshire +Rearrange struct TCPSocket_struct so "TCPSocketFlags flags" comes first (needed for debug logging) -Revision 1.251 2004/12/06 22:30:31 cheshire -Added debugging log message +Revision 1.487 2007/09/21 17:07:41 mcguire + BTMM: Need to modify IPSec tunnel setup files when shared secret changes (server-role) -Revision 1.250 2004/12/06 06:59:08 ksekar -RegisterSplitDNS should return Unsupported error when compiled on Panther +Revision 1.486 2007/09/19 23:17:38 cheshire + BTMM: Crash when switching .Mac accounts -Revision 1.249 2004/12/04 00:29:46 cheshire -Add "#ifdef MAC_OS_X_VERSION_10_4" around split-DNS code that can't be compiled on 10.3 systems -(When compiled on 10.3, code will not include split-DNS support.) +Revision 1.485 2007/09/19 21:44:29 cheshire +Improved "mDNSKeychainGetSecrets failed" error message -Revision 1.248 2004/12/01 20:57:20 ksekar - Wide Area Service Discovery must be split-DNS aware +Revision 1.484 2007/09/18 21:44:55 cheshire + Crash in GetAuthInfoForName_internal +Code was using n->ExtPort (now n->RequestedPort) when it should have been using n->ExternalPort -Revision 1.247 2004/12/01 03:26:58 cheshire -Remove unused variables +Revision 1.483 2007/09/17 22:19:39 mcguire + BTMM: Tunnel is getting configured too much which causes long delays +No need to configure a tunnel again if all the parameters are the same -- just remove the older duplicate tunnel from the list. -Revision 1.246 2004/12/01 01:51:34 cheshire -Move ReadDDNSSettingsFromConfFile() from mDNSMacOSX.c to PlatformCommon.c +Revision 1.482 2007/09/14 21:16:03 cheshire + mDNSResponder using 100% CPU spinning in tlsReadSock -Revision 1.245 2004/11/30 03:24:04 cheshire - Defer processing network configuration changes until configuration has stabilized +Revision 1.481 2007/09/14 21:14:56 mcguire + BTMM: Need to modify IPSec tunnel setup files when shared secret changes -Revision 1.244 2004/11/30 02:59:35 cheshire -For debugging diagnostics, added identifying strings in SCDynamicStoreCreate() calls +Revision 1.480 2007/09/13 00:16:42 cheshire + Miscellaneous NAT Traversal improvements -Revision 1.243 2004/11/29 19:17:29 ksekar - Unnecessary GetUserSpecifiedDDNSConfig log messages +Revision 1.479 2007/09/12 19:22:20 cheshire +Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport +Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers -Revision 1.242 2004/11/29 18:37:38 ksekar - Buffer overflow in GetConfigOption +Revision 1.478 2007/09/07 22:21:45 vazquez + BTMM: Connection stops working after connecting VPN -Revision 1.241 2004/11/25 01:37:04 ksekar - Config file and SCPreferences don't play well together +Revision 1.477 2007/09/07 21:22:30 cheshire + BTMM: SetupSocket 5351 failed; Can't allocate UDP multicast socket spew on wake from sleep with internet sharing on +Don't log failures binding to port 5351 -Revision 1.240 2004/11/25 01:29:42 ksekar -Remove unnecessary log messages +Revision 1.476 2007/09/06 20:38:08 cheshire + Only call SetDomainSecrets() for Keychain changes that are relevant to mDNSResponder -Revision 1.239 2004/11/25 01:27:19 ksekar - Don't try to advertise link-local IP addresses via dynamic update +Revision 1.475 2007/09/05 02:24:28 cheshire + mDNSResponder taking up 100% CPU in ReissueBlockedQuestions +In ReissueBlockedQuestions, only restart questions marked NoAnswer_Suspended, not those marked NoAnswer_Fail -Revision 1.238 2004/11/24 22:00:59 cheshire -Move definition of mDNSAddressIsAllDNSLinkGroup() from mDNSMacOSX.c to mDNSEmbeddedAPI.h +Revision 1.474 2007/09/04 22:32:58 mcguire + BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf -Revision 1.237 2004/11/24 21:54:44 cheshire - mDNSCore not receiving unicast responses properly +Revision 1.473 2007/08/31 19:53:15 cheshire + BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup +If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist -Revision 1.236 2004/11/23 03:39:46 cheshire -Let interface name/index mapping capability live directly in JNISupport.c, -instead of having to call through to the daemon via IPC to get this information. +Revision 1.472 2007/08/31 18:49:49 vazquez + BTMM: Need to properly deregister when stopping BTMM -Revision 1.235 2004/11/17 01:45:35 cheshire - mDNS buddy list frequently becomes empty if you let the machine sleep -Refresh our interface list on receiving kIOMessageSystemHasPoweredOn, -in case we get no System Configuration Framework "network changed" event. +Revision 1.471 2007/08/31 02:05:46 cheshire +Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName -Revision 1.234 2004/11/17 00:32:56 ksekar - mDNSResponder will not discover zones contained both in Search Domains and DHCP Domain option +Revision 1.470 2007/08/30 22:50:04 mcguire + BTMM: Tunneled services are registered when autotunnel can't be setup -Revision 1.233 2004/11/12 03:16:45 rpantos -rdar://problem/3809541 Add mDNSPlatformGetInterfaceByName, mDNSPlatformGetInterfaceName +Revision 1.469 2007/08/30 19:40:51 cheshire +Added syslog messages to report various initialization failures -Revision 1.232 2004/11/10 20:40:54 ksekar - LLQ mobility fragile on non-primary interface +Revision 1.468 2007/08/30 00:12:20 cheshire +Check error codes and log failures during AutoTunnel setup -Revision 1.231 2004/11/06 00:59:33 ksekar -Don't log ENETDOWN errors for unicast destinations (pollutes log on -wake from sleep) +Revision 1.467 2007/08/28 00:33:04 jgraessley + Selective compilation options -Revision 1.230 2004/11/05 01:04:10 ksekar - LegacyNATDestroy() called too enthusiastically +Revision 1.466 2007/08/24 23:25:55 cheshire +Debugging messages to help track down duplicate items being read from system keychain -Revision 1.229 2004/11/03 03:45:16 cheshire - mDNSResponder does not inform user of Computer Name collisions +Revision 1.465 2007/08/24 00:39:12 cheshire +Added comment explaining why we set info->AutoTunnelService.resrec.RecordType to kDNSRecordTypeUnregistered -Revision 1.228 2004/11/02 23:47:32 cheshire - Default hostname and Computer Name should be unique +Revision 1.464 2007/08/24 00:15:21 cheshire +Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held -Revision 1.227 2004/11/02 04:23:03 cheshire -Change to more informative name "GetUserSpecifiedLocalHostName()" +Revision 1.463 2007/08/23 21:02:35 cheshire +SecKeychainSetPreferenceDomain() call should be in platform-support layer, not daemon.c -Revision 1.226 2004/11/01 20:36:19 ksekar - mDNSResponder should not receive Keychain Notifications +Revision 1.462 2007/08/18 01:02:03 mcguire + No Bonjour services are getting registered at boot -Revision 1.225 2004/10/28 19:03:04 cheshire -Remove \n from LogMsg() calls +Revision 1.461 2007/08/10 22:25:57 mkrochma + mDNSResponder continually complains about slow UDP packet reception -- about 400 msecs -Revision 1.224 2004/10/28 17:47:34 cheshire -Oops. Forgot the %d in the log message. +Revision 1.460 2007/08/08 22:34:59 mcguire + Security: Run mDNSResponder as user id mdnsresponder instead of root -Revision 1.223 2004/10/28 17:24:28 cheshire -Updated "bad ifa_netmask" log message to give more information +Revision 1.459 2007/08/08 21:07:48 vazquez + BTMM: Need to advertise model information via wide-area bonjour -Revision 1.222 2004/10/28 03:36:34 cheshire - Share the same port for both multicast and unicast receiving +Revision 1.458 2007/08/03 02:18:41 mcguire + BTMM: Use port numbers in IPsec policies & configuration files -Revision 1.221 2004/10/28 03:24:41 cheshire -Rename m->CanReceiveUnicastOn as m->CanReceiveUnicastOn5353 +Revision 1.457 2007/08/02 16:48:45 mcguire + BTMM: Don't try to create tunnel back to same machine -Revision 1.220 2004/10/28 00:53:57 cheshire -Export mDNSMacOSXNetworkChanged() so it's callable from outside this mDNSMacOSX.c; -Add LogOperation() call to record when we get network change events +Revision 1.456 2007/08/02 03:28:30 vazquez +Make ExternalAddress and err unused to fix build warnings -Revision 1.219 2004/10/27 20:42:20 cheshire -Clean up debugging messages +Revision 1.455 2007/08/01 03:09:22 cheshire + BTMM: Create NAT port mapping for autotunnel port -Revision 1.218 2004/10/27 02:03:59 cheshire -Update debugging messages +Revision 1.454 2007/07/31 23:08:34 mcguire + BTMM: Make AutoTunnel mode work with multihoming -Revision 1.217 2004/10/26 20:48:21 cheshire -Improve logging messages +Revision 1.453 2007/07/31 19:13:58 mkrochma +No longer need to include "btmm" in hostname to avoid name conflicts -Revision 1.216 2004/10/26 01:02:37 cheshire -Update comment +Revision 1.452 2007/07/27 19:30:41 cheshire +Changed mDNSQuestionCallback parameter from mDNSBool to QC_result, +to properly reflect tri-state nature of the possible responses -Revision 1.215 2004/10/25 20:09:00 ksekar -Cleaned up config file parsing. +Revision 1.451 2007/07/25 22:25:45 cheshire + BTMM: Code not cleaning up old racoon files -Revision 1.214 2004/10/25 19:30:53 ksekar - Simplify dynamic host name structures +Revision 1.450 2007/07/25 21:19:10 cheshire + Fails to build with NO_SECURITYFRAMEWORK: 'IsTunnelModeDomain' defined but not used -Revision 1.213 2004/10/23 01:16:01 cheshire - uDNS operations not always reliable on multi-homed hosts +Revision 1.449 2007/07/25 01:36:09 mcguire + BTMM: Replace popen() `setkey` calls to setup/teardown ipsec policies -Revision 1.212 2004/10/22 20:52:08 ksekar - Create NAT port mappings for Long Lived Queries +Revision 1.448 2007/07/24 21:30:09 cheshire +Added "AutoTunnel server listening for connections..." diagnostic message -Revision 1.211 2004/10/22 01:07:11 cheshire - select() says data is waiting; recvfrom() says there is no data -Log error message if socket() ever returns file descriptors 0, 1 or 2 (stdin/stdout/stderr). -These are all supposed to be remapped to /dev/null +Revision 1.447 2007/07/24 20:24:18 cheshire +Only remove AutoTunnel address if we have created it. +Otherwise, we get "errno 49 (Can't assign requested address)" errors on exit. -Revision 1.210 2004/10/20 02:19:54 cheshire -Eliminate "SetupAddr invalid sa_family" warning from RegisterSearchDomains() +Revision 1.446 2007/07/24 03:00:09 cheshire +SetDomainSecrets() should call SetupLocalAutoTunnelInterface_internal(), not SetupLocalAutoTunnelInterface() -Revision 1.209 2004/10/16 00:17:00 cheshire - Replace IP TTL 255 check with local subnet source address check +Revision 1.445 2007/07/23 20:26:26 cheshire + Need separate SCPreferences for per-user .Mac settings +Move code that reads "Setup:/Network/BackToMyMac" preferences outside the check +for existence of "Setup:/Network/DynamicDNS" settings -Revision 1.208 2004/10/15 23:00:18 ksekar - Need to update LLQs on location changes +Revision 1.444 2007/07/21 00:54:49 cheshire + Delay IPv6 address callback until AutoTunnel route and policy is configured -Revision 1.207 2004/10/13 22:45:23 cheshire - Ten-second delay before kIOMessageSystemHasPoweredOn message +Revision 1.443 2007/07/20 23:23:11 cheshire +Rename out-of-date name "atq" (was AutoTunnelQuery) to simpler "tun" -Revision 1.206 2004/10/13 22:11:46 cheshire -Update debugging messages +Revision 1.442 2007/07/20 20:23:24 cheshire + Need separate SCPreferences for per-user .Mac settings +Fixed errors reading the Setup:/Network/BackToMyMac preferences -Revision 1.205 2004/10/12 21:10:11 cheshire - mach_absolute_time() not monotonically increasing -Do a NotifyOfElusiveBug() if we see mach_absolute_time() go backwards +Revision 1.441 2007/07/20 16:46:45 mcguire + BTMM: Replace system() `route` calls to setup/teardown routes -Revision 1.204 2004/10/12 03:20:52 ksekar - Incorrect LogMsg produces garbage on errors +Revision 1.440 2007/07/20 16:22:07 mcguire + BTMM: Replace system() `ifconfig` calls to setup/teardown IPv6 address -Revision 1.203 2004/10/08 04:29:25 ksekar - Allow default search domains to be set via hint from DHCP +Revision 1.439 2007/07/20 01:14:56 cheshire + Need separate SCPreferences for per-user .Mac settings +Cleaned up log messages -Revision 1.202 2004/10/04 05:56:04 cheshire - mDNSResponder doesn't respond to certain AirPort changes +Revision 1.438 2007/07/20 00:54:21 cheshire + Need separate SCPreferences for per-user .Mac settings -Revision 1.201 2004/09/30 00:24:59 ksekar - Dynamically update default registration domains on config change +Revision 1.437 2007/07/19 22:01:27 cheshire +Added "#pragma mark" sections headings to divide code into related function groups -Revision 1.200 2004/09/26 23:20:35 ksekar - Allow default registrations in multiple wide-area domains +Revision 1.436 2007/07/18 03:25:25 cheshire + Register IPSec tunnel with IPv4-only hostname and create NAT port mappings +Bring up server-side tunnel on demand, when necessary -Revision 1.199 2004/09/24 23:54:55 cheshire - Don't use kCFSocketCloseOnInvalidate +Revision 1.435 2007/07/18 01:05:08 cheshire + Automatically configure IPSec policy when resolving services +Add list of client tunnels so we can automatically reconfigure when local address changes -Revision 1.198 2004/09/24 23:47:49 cheshire -Correct comment and error message +Revision 1.434 2007/07/16 20:16:00 vazquez + LegacyNATTraversal: Need complete rewrite +Remove unnecessary LNT init code -Revision 1.197 2004/09/24 23:39:27 cheshire - Only IPv6 loopback address advertised on laptop w/no networking +Revision 1.433 2007/07/14 00:36:07 cheshire +Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working -Revision 1.196 2004/09/24 20:53:04 cheshire -Revise error message to say "Setsockopt SO_REUSEPORT failed" instead of "Flaw in Kernel" +Revision 1.432 2007/07/12 23:55:11 cheshire + Automatically configure IPSec policy when resolving services +Don't need two separate DNSQuestion structures when looking up tunnel endpoint -Revision 1.195 2004/09/24 19:21:45 cheshire - Report "Address already in use" errors +Revision 1.431 2007/07/12 23:34:48 cheshire +Removed 'LogOperation' message to reduce verbosity in syslog -Revision 1.194 2004/09/24 19:16:54 cheshire -Remove "mDNS *const m" parameter from NotifyOfElusiveBug(); -Refine error message to say "Flaw in Kernel (select/recvfrom mismatch)" +Revision 1.430 2007/07/12 22:16:46 cheshire +Improved "could not convert shared secret from base64" log message so it doesn't reveal key data in syslog -Revision 1.193 2004/09/22 00:41:59 cheshire -Move tcp connection status codes into the legal range allocated for mDNS use +Revision 1.429 2007/07/12 02:51:28 cheshire + Automatically configure IPSec policy when resolving services -Revision 1.192 2004/09/21 21:02:55 cheshire -Set up ifname before calling mDNS_RegisterInterface() +Revision 1.428 2007/07/11 23:17:31 cheshire + Register IPSec tunnel with IPv4-only hostname and create NAT port mappings +Improve log message to indicate if we're starting or restarting racoon -Revision 1.191 2004/09/21 19:19:36 cheshire - Combine WatchForDynDNSChanges() into WatchForNetworkChanges() +Revision 1.427 2007/07/11 22:50:30 cheshire + Register IPSec tunnel with IPv4-only hostname and create NAT port mappings +Write /etc/racoon/remote/anonymous.conf configuration file and start up /usr/sbin/racoon -Revision 1.190 2004/09/21 19:04:45 cheshire -Strip trailing white space from the ends of lines +Revision 1.426 2007/07/11 20:40:49 cheshire + Register IPSec tunnel with IPv4-only hostname and create NAT port mappings +In mDNSPlatformGetPrimaryInterface(), prefer routable IPv4 address to IPv4LL -Revision 1.189 2004/09/21 00:13:28 cheshire -Fix build failure (io_connect_t and io_object_t are integers, not pointers) +Revision 1.425 2007/07/11 19:24:19 cheshire + Register IPv6-only hostname and don't create port mappings for services +Configure internal AutoTunnel address +(For temporary testing we're faking up an IPv4LL address instead of IPv6 ULA, and we're +assigning it with "system(commandstring);" which probably isn't the most efficient way to do it) -Revision 1.188 2004/09/20 23:52:02 cheshire -CFSocket{Puma}.c renamed to mDNSMacOSX{Puma}.c +Revision 1.424 2007/07/11 19:00:27 cheshire +Only need to set up m->AutoTunnelHostAddr first time through UpdateInterfaceList() -Revision 1.187 2004/09/18 01:37:01 cheshire -Update comment +Revision 1.423 2007/07/11 03:00:59 cheshire + Register IPv6-only hostname and don't create port mappings for AutoTunnel services +Add AutoTunnel parameter to mDNS_SetSecretForDomain; Generate IPv6 ULA address for tunnel endpoint -Revision 1.186 2004/09/18 01:11:57 ksekar - Add a user's default domain to empty-string browse list +Revision 1.422 2007/07/10 01:21:20 cheshire +Added (commented out) line for displaying key data for debugging -Revision 1.185 2004/09/17 01:08:52 cheshire -Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h - The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces - declared in that file are ONLY appropriate to single-address-space embedded applications. - For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used. +Revision 1.421 2007/06/25 20:58:11 cheshire + Write the Multicast DNS domains to the DynamicStore +Additional refinement: Add mDNS domain list new new DynamicStore entity "State:/Network/MulticastDNS" -Revision 1.184 2004/09/17 00:19:10 cheshire -For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4 +Revision 1.420 2007/06/22 21:52:14 cheshire + Write the Multicast DNS domains to the DynamicStore -Revision 1.183 2004/09/17 00:15:56 cheshire -Rename mDNSPlatformInit_ReceiveUnicast to mDNSPlatformInit_CanReceiveUnicast +Revision 1.419 2007/06/22 21:32:00 cheshire + Use SecKeychainCopyDefault instead of SecKeychainOpen -Revision 1.182 2004/09/16 21:36:36 cheshire - Fix unsafe use of mDNSPlatformTimeNow() -Changes to add necessary locking calls around unicast DNS operations - -Revision 1.181 2004/09/16 02:03:42 cheshire - Change address to notify user of kernel flaw - -Revision 1.180 2004/09/16 01:58:22 cheshire -Fix compiler warnings - -Revision 1.179 2004/09/16 00:24:49 cheshire - Fix unsafe use of mDNSPlatformTimeNow() - -Revision 1.178 2004/09/15 21:51:34 cheshire - mDNSResponder should notify user of kernel flaw -Calling CFUserNotificationDisplayNotice too early in the boot process seems to kill -the machine, so make sure we don't do this until at least three minutes after boot. - -Revision 1.177 2004/09/15 01:16:29 cheshire - mDNSResponder should notify user of kernel flaw - -Revision 1.176 2004/09/14 23:42:36 cheshire - Need to seed random number generator from platform-layer data - -Revision 1.175 2004/09/14 21:35:46 cheshire -Minor code tidying, and added comments about CFRetainCounts - -Revision 1.174 2004/09/14 19:14:57 ksekar - DynDNS: Discovery of DynDNS Zones via Reverse-Map PTR - -Revision 1.173 2004/08/25 23:35:22 ksekar -: Error converting shared secret from base-64 to binary - -Revision 1.172 2004/08/25 02:01:45 cheshire - Need to be able to get status of Dynamic DNS Host Name Update - -Revision 1.171 2004/08/25 01:04:42 cheshire -Don't need to CFRelease name and array - -Revision 1.170 2004/08/25 00:37:28 ksekar -: Cleanup DynDNS hostname registration code - -Revision 1.169 2004/08/18 17:35:41 ksekar -: Feature #9586: Need support for Legacy NAT gateways - -Revision 1.168 2004/08/17 03:16:24 ksekar -Fixed checkin 1.166 - enumeration type changed for wrong invocation of mDNS_GetDomains - -Revision 1.167 2004/08/17 00:52:43 ksekar -Fix config file parse error, make semantics match SCPreferences -configuration input. - -Revision 1.166 2004/08/16 19:55:07 ksekar -Change enumeration type to BrowseDefault to construct empty-string -browse list as result of checking 1.161. - -Revision 1.165 2004/08/16 19:52:40 ksekar -Pass computer name + zone for FQDN after keychain notification, -setting global default service registration domain to the zone. - -Revision 1.164 2004/08/16 16:52:37 ksekar -Pass in zone read from keychain to mDNS_SetFQDNs. - -Revision 1.163 2004/08/14 03:22:42 cheshire - Dynamic DNS UI <-> mDNSResponder glue -Add GetUserSpecifiedDDNSName() routine -Convert ServiceRegDomain to domainname instead of C string -Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs - -Revision 1.162 2004/08/12 22:34:00 cheshire -All strings should be read as kCFStringEncodingUTF8, not kCFStringEncodingASCII - -Revision 1.161 2004/08/11 00:17:46 ksekar -: 8A227: Need Lighthouse configred machines to -set default bit for their domains - -Revision 1.160 2004/07/29 19:27:16 ksekar -NAT-PMP Support - minor fixes and cleanup - -Revision 1.159 2004/07/26 22:49:31 ksekar -: Feature #9516: Need support for NAT-PMP in client - -Revision 1.158 2004/07/13 21:24:24 rpantos -Fix for . - -Revision 1.157 2004/06/08 18:54:48 ksekar -: mDNSResponder leaks after exploring in Printer Setup Utility - -Revision 1.156 2004/06/05 00:04:26 cheshire -: wide-area domains should be returned in reg. domain enumeration - -Revision 1.155 2004/06/04 08:58:30 ksekar -: Keychain integration for secure dynamic update - -Revision 1.154 2004/05/31 22:22:28 ksekar -: wide-area domains should be returned in -reg. domain enumeration - -Revision 1.153 2004/05/26 17:06:33 cheshire -: Don't rely on CFSocketInvalidate() to remove RunLoopSource - -Revision 1.152 2004/05/18 23:51:26 cheshire -Tidy up all checkin comments to use consistent "" format for bug numbers - -Revision 1.151 2004/05/17 21:46:34 cheshire -: When interface is turned off, browse "remove" events are delivered with interface index zero -Take care to correctly update InterfaceIDs when a dormant interface comes back to life - -Revision 1.150 2004/05/13 04:54:20 ksekar -Unified list copy/free code. Added symetric list for - -Revision 1.149 2004/05/13 03:55:14 ksekar -Fixed list traversal bug in FoundDefSearchDomain. - -Revision 1.148 2004/05/12 22:03:08 ksekar -Made GetSearchDomainList a true platform-layer call (declaration moved -from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local" -only on non-OSX platforms. Changed call to return a copy of the list -to avoid shared memory issues. Added a routine to free the list. - -Revision 1.147 2004/05/12 02:03:25 ksekar -Non-local domains will only be browsed by default, and show up in -_browse domain enumeration, if they contain an _browse._dns-sd ptr record. - -Revision 1.146 2004/04/27 02:49:15 cheshire -: mDNSResponder leaks sockets on bind() error - -Revision 1.145 2004/04/21 03:08:03 cheshire -Rename 'alias' to more descriptive name 'primary' - -Revision 1.144 2004/04/21 03:04:35 cheshire -Minor cleanup for clarity - -Revision 1.143 2004/04/21 03:03:30 cheshire -Preparation work: AddInterfaceToList() should return pointer to structure it creates - -Revision 1.142 2004/04/21 02:49:11 cheshire -To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx' - -Revision 1.141 2004/04/21 02:20:47 cheshire -Rename interface field 'CurrentlyActive' to more descriptive 'Exists' - -Revision 1.140 2004/04/14 23:09:29 ksekar -Support for TSIG signed dynamic updates. - -Revision 1.139 2004/04/09 17:40:26 cheshire -Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing McastTxRx field +Revision 1.418 2007/06/21 16:37:43 jgraessley +Bug #: 5280520 +Reviewed by: Stuart Cheshire +Additional changes to get this compiling on the embedded platform. -Revision 1.138 2004/04/09 16:37:16 cheshire -Suggestion from Bob Bradley: -Move NumCacheRecordsForInterfaceID() to DNSCommon.c so it's available to all platform layers +Revision 1.417 2007/06/20 01:44:00 cheshire +More information in "Network Configuration Change" message -Revision 1.137 2004/04/08 00:59:55 cheshire - When interface turned off, browse "remove" events delivered with interface index zero -Unify use of the InterfaceID field, and make code that walks the list respect the 'Exists' flag +Revision 1.416 2007/06/20 01:10:12 cheshire + Sync iPhone changes into main mDNSResponder code -Revision 1.136 2004/04/07 01:08:57 cheshire - When interface turned off, browse "remove" events delivered with interface index zero +Revision 1.415 2007/06/15 19:23:38 cheshire + mDNSResponder renames my host without asking +Improve log messages, to distinguish user-initiated renames from automatic (name conflict) renames -Revision 1.135 2004/03/19 01:01:03 ksekar -Fixed config file parsing to chop newline +Revision 1.414 2007/05/17 22:00:59 cheshire + Lower network change delay from two seconds to one second -Revision 1.134 2004/03/13 01:57:34 ksekar -: DynDNS: Dynamic update of service records +Revision 1.413 2007/05/16 16:43:27 cheshire +Only log "bind" failures for our shared mDNS port and for binding to zero +-- other attempts to bind to a particular port may legitimately fail -Revision 1.133 2004/02/02 22:46:56 cheshire -Move "CFRelease(dict);" inside the "if (dict)" check +Revision 1.412 2007/05/15 21:49:21 cheshire +Get rid of "#pragma unused" -Revision 1.132 2004/01/28 02:30:08 ksekar -Added default Search Domains to unicast browsing, controlled via -Networking sharing prefs pane. Stopped sending unicast messages on -every interface. Fixed unicast resolving via mach-port API. +Revision 1.411 2007/05/14 23:54:55 cheshire +Instead of sprintf, use safer length-limited mDNS_snprintf -Revision 1.131 2004/01/27 22:57:48 cheshire -: Need separate socket for issuing unicast queries +Revision 1.410 2007/05/12 01:05:00 cheshire +Updated debugging messages -Revision 1.130 2004/01/27 22:28:40 cheshire -: Time to prune obsolete code for listening on port 53 -Additional lingering port 53 code deleted +Revision 1.409 2007/05/10 22:39:48 cheshire + Share single socket instead of creating separate socket for each active interface +Only define CountMaskBits for builds with debugging messages -Revision 1.129 2004/01/27 20:15:23 cheshire -: Time to prune obsolete code for listening on port 53 +Revision 1.408 2007/05/10 22:19:00 cheshire + Share single socket instead of creating separate socket for each active interface +Don't deliver multicast packets for which we can't find an associated InterfaceID -Revision 1.128 2004/01/24 23:58:17 cheshire -Change to use mDNSVal16() instead of shifting and ORing +Revision 1.407 2007/05/10 21:40:28 cheshire +Don't log unnecessary "Address already in use" errors when joining multicast groups -Revision 1.127 2004/01/24 04:59:16 cheshire -Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again +Revision 1.406 2007/05/08 00:56:17 cheshire + Share single socket instead of creating separate socket for each active interface -Revision 1.126 2004/01/23 23:23:15 ksekar -Added TCP support for truncated unicast messages. +Revision 1.405 2007/05/04 20:21:39 cheshire +Improve "connect failed" error message -Revision 1.125 2004/01/22 03:43:09 cheshire -Export constants like mDNSInterface_LocalOnly so that the client layers can use them +Revision 1.404 2007/05/02 19:41:53 cheshire +No need to alarm people with "Connection reset by peer" syslog message -Revision 1.124 2004/01/21 21:53:19 cheshire -: Don't try to receive unicast responses if we're not the first to bind to the UDP port +Revision 1.403 2007/04/28 01:31:59 cheshire +Improve debugging support for catching memory corruption problems -Revision 1.123 2004/01/20 03:18:25 cheshire -Removed "LogMsg("Hey There!");" that evidently got checked in my mistake +Revision 1.402 2007/04/26 22:54:57 cheshire +Debugging messages to help track down mDNSResponder takes 50%+ CPU -Revision 1.122 2003/12/17 20:43:59 cheshire -: Syslog messages saying "sendto failed" +Revision 1.401 2007/04/26 00:35:16 cheshire + uDNS: Domain discovery not working over VPN +Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server +inside the firewall may give answers where a public one gives none, and vice versa.) -Revision 1.121 2003/12/13 03:05:28 ksekar -: DynDNS: Unicast query of service records +Revision 1.400 2007/04/24 21:50:27 cheshire +Debugging: Show list of changedKeys in NetworkChanged callback -Revision 1.120 2003/12/08 21:00:46 rpantos -Changes to support mDNSResponder on Linux. +Revision 1.399 2007/04/23 22:28:47 cheshire +Allan Nathanson informs us we should only be looking at the search list for resolver[0], not all of them -Revision 1.119 2003/12/03 02:35:15 cheshire -Also report value of m->timenow when logging sendto() failure +Revision 1.398 2007/04/23 04:57:00 cheshire +Log messages for debugging IPv6 multicast not working properly -Revision 1.118 2003/11/14 20:59:09 cheshire -Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h. -Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file. +Revision 1.397 2007/04/22 06:02:03 cheshire + Query should immediately return failure when no server -Revision 1.117 2003/11/08 22:18:29 cheshire -: Don't need to show process ID in *every* mDNSResponder syslog message +Revision 1.396 2007/04/21 21:47:47 cheshire + Daemon: Add watchdog timer -Revision 1.116 2003/09/23 16:39:49 cheshire -When LogAllOperations is set, also report registration and deregistration of interfaces +Revision 1.395 2007/04/18 20:58:34 cheshire + Domain discovery not working over VPN +Needed different code to handle the case where there's only a single search domain -Revision 1.115 2003/09/10 00:45:55 cheshire - Don't log "sendto failed" errors during the first two minutes of startup +Revision 1.394 2007/04/17 23:05:50 cheshire + Shouldn't send domain queries when we have 169.254 or loopback address -Revision 1.114 2003/08/27 02:55:13 cheshire -: Bug: Don't report mDNSPlatformSendUDP sendto errno 64 (Host is down) +Revision 1.393 2007/04/17 19:21:29 cheshire + Domain discovery not working over VPN -Revision 1.113 2003/08/19 22:20:00 cheshire - Don't use IPv6 on interfaces that have a routable IPv4 address configured -More minor refinements +Revision 1.392 2007/04/17 17:15:09 cheshire +Change NO_CFUSERNOTIFICATION code so it still logs to syslog -Revision 1.112 2003/08/19 03:04:43 cheshire - Don't use IPv6 on interfaces that have a routable IPv4 address configured +Revision 1.391 2007/04/07 01:01:48 cheshire + mDNSResponder periodically blocks in SSLRead -Revision 1.111 2003/08/18 22:53:37 cheshire - mDNSResponder divide by zero in mDNSPlatformRawTime() +Revision 1.390 2007/04/06 18:45:02 cheshire +Fix SetupActiveInterfaces() -- accidentally changed SetupSocket parameter -Revision 1.110 2003/08/16 03:39:00 cheshire - InterfaceID -1 indicates "local only" +Revision 1.389 2007/04/05 21:39:49 cheshire +Debugging messages to help diagnose mDNSResponder periodically blocks in SSLRead -Revision 1.109 2003/08/15 02:19:49 cheshire - syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35 -Also limit number of messages to at most 100 +Revision 1.388 2007/04/05 21:09:52 cheshire +Condense sprawling code -Revision 1.108 2003/08/12 22:24:52 cheshire - syslog messages: myCFSocketCallBack recvfrom skt 6 error -1 errno 35 -This message indicates a kernel bug, but still we don't want to flood syslog. -Do a sleep(1) after writing this log message, to limit the rate. +Revision 1.387 2007/04/05 20:40:37 cheshire +Remove unused mDNSPlatformTCPGetFlags() -Revision 1.107 2003/08/12 19:56:25 cheshire -Update to APSL 2.0 +Revision 1.386 2007/04/05 19:50:56 cheshire +Fixed memory leak: GetCertChain() was not releasing cert returned by SecIdentityCopyCertificate() -Revision 1.106 2003/08/12 13:48:32 cheshire -Add comment explaining clockdivisor calculation +Revision 1.385 2007/04/03 19:39:19 cheshire +Fixed intel byte order bug in mDNSPlatformSetDNSServers() -Revision 1.105 2003/08/12 13:44:14 cheshire - mDNSResponder *VERY* unhappy if time goes backwards -Use mach_absolute_time() (which is guaranteed to always go forwards, resetting only on reboot) -instead of gettimeofday() (which can jump back if the user manually changes their time/date) +Revision 1.384 2007/03/31 01:10:53 cheshire +Add debugging -Revision 1.104 2003/08/12 13:12:07 cheshire -Textual search/replace: Indicate local functions using "mDNSlocal" instead of "static" +Revision 1.383 2007/03/31 00:13:48 cheshire +Remove LogMsg -Revision 1.103 2003/08/08 18:36:04 cheshire - Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug +Revision 1.382 2007/03/28 21:01:29 cheshire + Remove inappropriate use of IsPrivateV4Addr() -Revision 1.102 2003/08/06 00:14:52 cheshire - Need to check IP TTL on responses -Also add corresponding checks in the IPv6 code path +Revision 1.381 2007/03/28 15:56:37 cheshire + Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output -Revision 1.101 2003/08/05 22:20:16 cheshire - Need to check IP TTL on responses +Revision 1.380 2007/03/26 22:54:46 cheshire +Fix compile error -Revision 1.100 2003/08/05 21:18:50 cheshire - mDNSResponder should ignore 6to4 -Only use interfaces that are marked as multicast-capable (IFF_MULTICAST) +Revision 1.379 2007/03/22 18:31:48 cheshire +Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy -Revision 1.99 2003/08/05 20:13:52 cheshire - mDNSResponder using IPv6 interfaces before they are ready -Ignore interfaces with the IN6_IFF_NOTREADY flag set +Revision 1.378 2007/03/22 00:49:20 cheshire + Advertise model information via Bonjour -Revision 1.98 2003/07/20 03:38:51 ksekar - -Completed support for Unix-domain socket based API. +Revision 1.377 2007/03/21 00:30:05 cheshire + Multiple errors in DNameList-related code -Revision 1.97 2003/07/19 03:15:16 cheshire -Add generic MemAllocate/MemFree prototypes to mDNSPlatformFunctions.h, -and add the obvious trivial implementations to each platform support layer +Revision 1.376 2007/03/20 17:07:15 cheshire +Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket" -Revision 1.96 2003/07/18 00:30:00 cheshire - Remove mDNSResponder version from packet header and use HINFO record instead +Revision 1.375 2007/03/20 00:50:57 cheshire + Remove logic to disable IPv6 discovery on interfaces which have a routable IPv4 address -Revision 1.95 2003/07/12 03:15:20 cheshire - After SCDynamicStore notification, mDNSResponder updates -m->hostlabel even if user hasn't actually actually changed their dot-local hostname +Revision 1.374 2007/03/06 23:29:50 cheshire + Need to call IONotificationPortDestroy on shutdown -Revision 1.94 2003/07/03 00:51:54 cheshire - When select() and recvmgs() disagree, get more info from kernel about the socket state +Revision 1.373 2007/02/28 01:51:20 cheshire +Added comment about reverse-order IP address -Revision 1.93 2003/07/03 00:09:14 cheshire - New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call -Additional refinement suggested by Josh: Use info->scope_id instead of if_nametoindex(info->ifa_name); +Revision 1.372 2007/02/28 01:06:48 cheshire +Use %#a format code instead of %d.%d.%d.%d -Revision 1.92 2003/07/02 21:19:51 cheshire - Update copyright notices, etc., in source code comments +Revision 1.371 2007/02/08 21:12:28 cheshire + Stop reading /etc/mDNSResponder.conf on every sleep/wake -Revision 1.91 2003/06/24 01:53:51 cheshire -Minor update to comments +Revision 1.370 2007/01/16 22:59:58 cheshire +Error code ioErr is from wrong conceptual namespace; use errSSLClosedAbort instead -Revision 1.90 2003/06/24 01:51:47 cheshire - Oops: Double-dispose of sockets -Don't need to close sockets: CFSocketInvalidate() does that for us +Revision 1.369 2007/01/10 02:09:32 cheshire +Better LogOperation record of keys read from System Keychain -Revision 1.89 2003/06/21 18:12:47 cheshire - mDNSResponder cannot handle interfaces whose total name is >3 chars -One-line change: should say "IF_NAMESIZE", not sizeof(ifname) +Revision 1.368 2007/01/10 01:25:31 cheshire +Use symbol kDNSServiceCompPrivateDNS instead of fixed string "State:/Network/PrivateDNS" -Revision 1.88 2003/06/12 23:38:37 cheshire - mDNSResponder doesn't detect some configuration changes -Also check that scope_id matches before concluding that two interfaces are the same +Revision 1.367 2007/01/10 01:22:01 cheshire +Make sure c1, c2, c3 are initialized -Revision 1.87 2003/06/10 01:14:11 cheshire - New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call +Revision 1.366 2007/01/09 22:37:20 cheshire +Provide ten-second grace period for deleted keys, to give mDNSResponder +time to delete host name before it gives up access to the required key. -Revision 1.86 2003/05/28 02:41:52 cheshire - Time to remove Mac OS 9 UDP Port 53 legacy support +Revision 1.365 2007/01/09 21:09:20 cheshire +Need locking in KeychainChanged() -Revision 1.85 2003/05/28 02:39:47 cheshire -Minor change to debugging messages +Revision 1.364 2007/01/09 20:17:04 cheshire +mDNSPlatformGetDNSConfig() needs to initialize fields even when no "Setup:/Network/DynamicDNS" entity exists -Revision 1.84 2003/05/27 22:29:40 cheshire -Remove out-dated comment +Revision 1.363 2007/01/09 02:41:18 cheshire +uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer); +moved it to mDNS_Init() in mDNS.c (core code) -Revision 1.83 2003/05/26 03:21:29 cheshire -Tidy up address structure naming: -mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr) -mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4 -mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6 +Revision 1.362 2007/01/08 23:54:01 cheshire +Made mDNSPlatformGetDNSConfig() more selective -- only reads prefs for non-null parameters -Revision 1.82 2003/05/26 03:01:27 cheshire - sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead +Revision 1.361 2007/01/05 08:30:48 cheshire +Trim excessive "$Log" checkin history from before 2006 +(checkin history still available via "cvs log ..." of course) -Revision 1.81 2003/05/24 02:06:42 cheshire - IPv6 Multicast Loopback doesn't work -Tried setting IPV6_MULTICAST_LOOP; it doesn't help. -However, it is probably wise to have the code explicitly set this socket -option anyway, in case the default changes in later versions of Unix. +Revision 1.360 2007/01/04 00:12:24 cheshire + Read *all* DNS keys from keychain, + not just key for the system-wide default registration domain -Revision 1.80 2003/05/24 02:02:24 cheshire - if_indextoname consumes a lot of CPU -Fix error in myIfIndexToName; was returning prematurely +Revision 1.359 2006/12/22 21:14:37 cheshire +Added comment explaining why we allow both "ddns" and "sndd" as valid item types +The Keychain APIs on Intel appear to store the four-character item type backwards (at least some of the time) -Revision 1.79 2003/05/23 23:07:44 cheshire - Must not write to stderr when running as daemon +Revision 1.358 2006/12/22 20:59:50 cheshire + Read *all* DNS keys from keychain, + not just key for the system-wide default registration domain -Revision 1.78 2003/05/23 01:19:04 cheshire - mDNSResponder needs to signal type of service to AirPort -Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate +Revision 1.357 2006/12/21 00:09:45 cheshire +Use mDNSPlatformMemZero instead of bzero -Revision 1.77 2003/05/23 01:12:05 cheshire -Minor code tidying +Revision 1.356 2006/12/20 23:15:53 mkrochma +Fix the private domain list code so that it actually works -Revision 1.76 2003/05/22 01:26:01 cheshire -Tidy up log messages +Revision 1.355 2006/12/20 23:04:36 mkrochma +Fix crash when adding private domain list to Dynamic Store -Revision 1.75 2003/05/22 00:07:09 cheshire - myCFSocketCallBack recvfrom(5) error 1, errno 35 -Extra logging to determine whether there is a bug in CFSocket +Revision 1.354 2006/12/19 22:43:55 cheshire +Fix compiler warnings -Revision 1.74 2003/05/21 20:20:12 cheshire -Fix warnings (mainly printf format string warnings, like using "%d" where -it should say "%lu", etc.) and improve error logging (use strerror() -to include textual error message as well as numeric error in log messages). +Revision 1.353 2006/12/14 22:08:29 cheshire +Fixed memory leak: need to call SecKeychainItemFreeAttributesAndData() +to release data allocated by SecKeychainItemCopyAttributesAndData() -Revision 1.73 2003/05/21 17:56:29 ksekar -: mDNSResponder doesn't watch for IPv6 address changes +Revision 1.352 2006/12/14 02:33:26 cheshire + uDNS: Wide-area registrations sometimes fail -Revision 1.72 2003/05/14 18:48:41 cheshire - mDNSResponder should be smarter about reconfigurations -More minor refinements: -mDNSMacOSX.c needs to do *all* its mDNS_DeregisterInterface calls before freeing memory -mDNS_DeregisterInterface revalidates cache record when *any* representative of an interface goes away +Revision 1.351 2006/11/28 21:37:51 mkrochma +Tweak where the private DNS data is written -Revision 1.71 2003/05/14 07:08:37 cheshire - mDNSResponder should be smarter about reconfigurations -Previously, when there was any network configuration change, mDNSResponder -would tear down the entire list of active interfaces and start again. -That was very disruptive, and caused the entire cache to be flushed, -and caused lots of extra network traffic. Now it only removes interfaces -that have really gone, and only adds new ones that weren't there before. +Revision 1.350 2006/11/28 07:55:02 herscher + dnsextd has a slow memory leak -Revision 1.70 2003/05/07 18:30:24 cheshire -Fix signed/unsigned comparison warning +Revision 1.349 2006/11/28 07:45:58 herscher + Daemon: Need to write list of private domain names to the DynamicStore -Revision 1.69 2003/05/06 20:14:44 cheshire -Change "tp" to "tv" +Revision 1.348 2006/11/16 21:47:20 mkrochma + uDNS: Wide-area registrations sometimes fail -Revision 1.68 2003/05/06 00:00:49 cheshire - Rationalize naming of domainname manipulation functions +Revision 1.347 2006/11/10 00:54:16 cheshire + Changing case of Computer Name doesn't work -Revision 1.67 2003/04/29 00:43:44 cheshire -Fix compiler warnings +Revision 1.346 2006/10/31 02:34:58 cheshire + Stop creating HINFO records -Revision 1.66 2003/04/26 02:41:58 cheshire - Change timenow from a local variable to a structure member +Revision 1.345 2006/09/21 20:04:38 mkrochma +Accidently changed function name while checking in previous fix -Revision 1.65 2003/04/26 02:34:01 cheshire -Add missing mDNSexport +Revision 1.344 2006/09/21 19:04:13 mkrochma + uDNS: Update keychain format of DNS key to include prefix -Revision 1.64 2003/04/15 16:48:06 jgraessl - -Modified code in CFSocket notifier function to read all packets on the socket -instead of reading only one packet every time the notifier was called. +Revision 1.343 2006/09/15 21:20:16 cheshire +Remove uDNS_info substructure from mDNS_struct -Revision 1.63 2003/04/15 16:33:50 jgraessl - -Switched to our own copy of if_indextoname to improve performance. +Revision 1.342 2006/08/16 00:31:50 mkrochma + Get rid of NotAnInteger references -Revision 1.62 2003/03/28 01:55:44 cheshire -Minor improvements to debugging messages +Revision 1.341 2006/08/14 23:24:40 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 -Revision 1.61 2003/03/27 03:30:56 cheshire - Name conflicts not handled properly, resulting in memory corruption, and eventual crash -Problem was that HostNameCallback() was calling mDNS_DeregisterInterface(), which is not safe in a callback -Fixes: -1. Make mDNS_DeregisterInterface() safe to call from a callback -2. Make HostNameCallback() use mDNS_DeadvertiseInterface() instead - (it never really needed to deregister the interface at all) +Revision 1.340 2006/07/29 19:11:13 mkrochma +Change GetUserSpecifiedDDNSConfig LogMsg to debugf -Revision 1.60 2003/03/15 04:40:38 cheshire -Change type called "mDNSOpaqueID" to the more descriptive name "mDNSInterfaceID" +Revision 1.339 2006/07/27 03:24:35 cheshire + Convert mDNSResponder to use kqueue +Further refinement: Declare KQueueEntry parameter "const" -Revision 1.59 2003/03/11 01:23:26 cheshire - mDNSResponder socket problems +Revision 1.338 2006/07/27 02:59:25 cheshire + Convert mDNSResponder to use kqueue +Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread +after releasing BigMutex, in case actions it took have resulted in new work for the +kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to +add new active interfaces to its list, and consequently schedule queries to be sent). -Revision 1.58 2003/03/06 01:43:04 cheshire - Additional debugging code in mDNSResponder -Improve "LIST_ALL_INTERFACES" output +Revision 1.337 2006/07/22 06:11:37 cheshire + Convert mDNSResponder to use kqueue -Revision 1.57 2003/03/05 22:36:27 cheshire - Loopback doesn't work with mDNSResponder-27 -Temporary workaround: Skip loopback interface *only* if we found at least one v4 interface to use +Revision 1.336 2006/07/15 02:01:32 cheshire + Add Private DNS client functionality to mDNSResponder +Fix broken "empty string" browsing -Revision 1.56 2003/03/05 01:50:38 cheshire - Additional debugging code in mDNSResponder +Revision 1.335 2006/07/14 05:25:11 cheshire + Add Private DNS client functionality to mDNSResponder +Fixed crash in mDNSPlatformGetDNSConfig() reading BrowseDomains array -Revision 1.55 2003/02/21 01:54:09 cheshire - mDNSResponder needs performance improvements -Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt") +Revision 1.334 2006/07/05 23:42:00 cheshire + Add Private DNS client functionality to mDNSResponder -Revision 1.54 2003/02/20 06:48:35 cheshire - Xserve RAID needs to do interface-specific registrations -Reviewed by: Josh Graessley, Bob Bradley +Revision 1.333 2006/06/29 05:33:30 cheshire + mDNSResponder conditional compilation options -Revision 1.53 2003/01/29 02:21:23 cheshire -Return mStatus_Invalid if can't send packet because socket not available +Revision 1.332 2006/06/28 09:10:36 cheshire +Extra debugging messages -Revision 1.52 2003/01/28 19:39:43 jgraessl -Enabling AAAA over IPv4 support. +Revision 1.331 2006/06/21 22:29:42 cheshire +Make _CFCopySystemVersionDictionary() call more defensive on systems that have no build information set -Revision 1.51 2003/01/28 05:11:23 cheshire -Fixed backwards comparison in SearchForInterfaceByName +Revision 1.330 2006/06/20 23:06:00 cheshire +Fix some keychain API type mismatches (was mDNSu32 instead of UInt32) -Revision 1.50 2003/01/13 23:49:44 jgraessl -Merged changes for the following fixes in to top of tree: - computer name changes not handled properly - service name changes are not properly handled - announcements sent in pairs, failing chattiness test +Revision 1.329 2006/06/08 23:22:33 cheshire +Comment changes -Revision 1.49 2002/12/23 22:13:30 jgraessl -Reviewed by: Stuart Cheshire -Initial IPv6 support for mDNSResponder. +Revision 1.328 2006/03/19 03:27:49 cheshire + Suppress "interface flapping" logic for loopback -Revision 1.48 2002/11/22 01:37:52 cheshire - mDNSResponder is monitoring ServiceEntities instead of InterfaceEntities +Revision 1.327 2006/03/19 02:00:09 cheshire + Improve logic for delaying packets after repeated interface transitions -Revision 1.47 2002/09/21 20:44:51 zarzycki -Added APSL info +Revision 1.326 2006/03/08 22:42:23 cheshire +Fix spelling mistake: LocalReverseMapomain -> LocalReverseMapDomain -Revision 1.46 2002/09/19 21:25:35 cheshire -mDNS_snprintf() doesn't need to be in a separate file +Revision 1.325 2006/01/10 00:39:17 cheshire +Add comments explaining how IPv6 link-local addresses sometimes have an embedded scope_id -Revision 1.45 2002/09/17 01:45:13 cheshire -Add LIST_ALL_INTERFACES symbol for debugging +Revision 1.324 2006/01/09 19:28:59 cheshire + Cap number of "sendto failed" messages we allow mDNSResponder to log -Revision 1.44 2002/09/17 01:36:23 cheshire -Move Puma support to mDNSMacOSXPuma.c +Revision 1.323 2006/01/05 21:45:27 cheshire + Fix uninitialized structure member in IPv6 code -Revision 1.43 2002/09/17 01:05:28 cheshire -Change mDNS_AdvertiseLocalAddresses to be an Init parameter instead of a global +Revision 1.322 2006/01/05 21:41:50 cheshire + Reword "mach_absolute_time went backwards" dialog -Revision 1.42 2002/09/16 23:13:50 cheshire -Minor code tidying +Revision 1.321 2006/01/05 21:35:06 cheshire +Add (commented out) trigger value for testing "mach_absolute_time went backwards" notice - */ +*/ // *************************************************************************** // mDNSMacOSX.c: @@ -975,23 +605,31 @@ Minor code tidying // including ones that mDNSResponder chooses not to use. #define LIST_ALL_INTERFACES 0 -// For debugging, being able to identify software versions is useful. -// Some people are concerned that this information could be exploited by hackers. -// I'm not totally convinced by that argument, but we don't want to cause our users distress, -// so for shipping code, define "NO_HINFO" to suppress the generation of HINFO records. -- SC -#define NO_HINFO 1 - // For enabling AAAA records over IPv4. Setting this to 0 sends only // A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both // AAAA and A records over both IPv4 and IPv6. #define AAAA_OVER_V4 1 +// In Mac OS X 10.4 and earlier, to reduce traffic, we would send and receive using IPv6 only on interfaces that had no routable +// IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network, +// which means there's a good chance that most or all the other devices on that network should also have IPv4. +// By doing this we lost the ability to talk to true IPv6-only devices on that link, but we cut the packet rate in half. +// At that time, reducing the packet rate was more important than v6-only devices on a large configured network, +// so were willing to make that sacrifice. +// In Mac OS X 10.5, in 2007, two things have changed: +// 1. IPv6-only devices are starting to become more common, so we can't ignore them. +// 2. Other efficiency improvements in the code mean that crude hacks like this should no longer be necessary. + +#define USE_V6_ONLY_WHEN_NO_ROUTABLE_V4 0 + #include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above #include "DNSCommon.h" +#include "uDNS.h" #include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform #include "../mDNSShared/uds_daemon.h" // Defines communication interface from platform layer up to UDS daemon #include "PlatformCommon.h" + #include #include // For va_list support #include @@ -1001,10 +639,12 @@ Minor code tidying #include #include #include +#include #include #include #include // platform support for UTC time #include // for inet_aton +#include #include // For IP_RECVTTL #ifndef IP_RECVTTL @@ -1014,9 +654,18 @@ Minor code tidying #include // For n_long, required by below #include // For IPTOS_LOWDELAY etc. #include // For IN6_IFF_NOTREADY etc. +#include // For ND6_INFINITE_LIFETIME etc. +#if TARGET_OS_EMBEDDED +#define NO_SECURITYFRAMEWORK 1 +#endif + +#ifndef NO_SECURITYFRAMEWORK +#include #include +#endif /* NO_SECURITYFRAMEWORK */ +#include #include "dnsinfo.h" // Code contributed by Dave Heller: @@ -1031,115 +680,63 @@ Minor code tidying #include #include +#include +#include #include +#include "helper.h" -typedef struct SearchListElem - { - struct SearchListElem *next; - domainname domain; - int flag; - DNSQuestion BrowseQ; - DNSQuestion DefBrowseQ; - DNSQuestion LegacyBrowseQ; - DNSQuestion RegisterQ; - DNSQuestion DefRegisterQ; - ARListElem *AuthRecs; - } SearchListElem; - +#define kInterfaceSpecificOption "interface=" // *************************************************************************** // Globals -static mDNSu32 clockdivisor = 0; +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - Globals +#endif -// for domain enumeration and default browsing/registration -static SearchListElem *SearchList = NULL; // where we search for _browse domains -static DNSQuestion LegacyBrowseDomainQ; // our local enumeration query for _legacy._browse domains -static DNameListElem *DefBrowseList = NULL; // cache of answers to above query (where we search for empty string browses) -static DNameListElem *DefRegList = NULL; // manually generated list of domains where we register for empty string registrations -static ARListElem *SCPrefBrowseDomains = NULL; // manually generated local-only PTR records for browse domains we get from SCPreferences +static mDNSu32 clockdivisor = 0; -static domainname DynDNSRegDomain; // Default wide-area zone for service registration -static CFArrayRef DynDNSBrowseDomains = NULL; // Default wide-area zones for legacy ("empty string") browses -static domainname DynDNSHostname; +mDNSexport int KQueueFD; -static mDNSBool DomainDiscoveryDisabled = mDNSfalse; +#ifndef NO_SECURITYFRAMEWORK +static CFArrayRef ServerCerts; +#endif /* NO_SECURITYFRAMEWORK */ -#define CONFIG_FILE "/etc/mDNSResponder.conf" #define DYNDNS_KEYCHAIN_SERVICE "DynDNS Shared Secret" -#define SYS_KEYCHAIN_PATH "/Library/Keychains/System.keychain" -// Function Prototypes -mDNSlocal void SetSCPrefsBrowseDomain(mDNS *m, const domainname *d, mDNSBool add); +CFStringRef NetworkChangedKey_IPv4; +CFStringRef NetworkChangedKey_IPv6; +CFStringRef NetworkChangedKey_Hostnames; +CFStringRef NetworkChangedKey_Computername; +CFStringRef NetworkChangedKey_DNS; +CFStringRef NetworkChangedKey_DynamicDNS = CFSTR("Setup:/Network/DynamicDNS"); +CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac"); // *************************************************************************** // Functions -// routines to allow access to default domain lists from daemon layer - -mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void) - { - return mDNS_CopyDNameList(DefBrowseList); - } - -mDNSexport DNameListElem *mDNSPlatformGetRegDomainList(void) - { - return mDNS_CopyDNameList(DefRegList); - } - -// utility routines to manage registration domain lists - -mDNSlocal void AddDefRegDomain(domainname *d) - { - DNameListElem *newelem = NULL, *ptr; - - // make sure name not already in list - for (ptr = DefRegList; ptr; ptr = ptr->next) - { - if (SameDomainName(&ptr->name, d)) - { debugf("duplicate addition of default reg domain %##s", d->c); return; } - } - - newelem = mallocL("DNameListElem", sizeof(*newelem)); - if (!newelem) { LogMsg("Error - malloc"); return; } - AssignDomainName(&newelem->name, d); - newelem->next = DefRegList; - DefRegList = newelem; - - DefaultRegDomainChanged(d, mDNStrue); - udsserver_default_reg_domain_changed(d, mDNStrue); - } - -mDNSlocal void RemoveDefRegDomain(domainname *d) - { - DNameListElem *ptr = DefRegList, *prev = NULL; +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - +#pragma mark - Utility Functions +#endif - while (ptr) - { - if (SameDomainName(&ptr->name, d)) - { - if (prev) prev->next = ptr->next; - else DefRegList = ptr->next; - freeL("DNameListElem", ptr); - DefaultRegDomainChanged(d, mDNSfalse); - udsserver_default_reg_domain_changed(d, mDNSfalse); - return; - } - prev = ptr; - ptr = ptr->next; - } - debugf("Requested removal of default registration domain %##s not in contained in list", d->c); - } +// We only attempt to send and receive multicast packets on interfaces that are +// (a) flagged as multicast-capable +// (b) *not* flagged as point-to-point (e.g. modem) +// Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want +// to run up the user's bill sending multicast traffic over a link where there's only a single device at the +// other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway. +#define MulticastInterface(i) ((i->ifa_flags & IFF_MULTICAST) && !(i->ifa_flags & IFF_POINTOPOINT)) -mDNSexport void NotifyOfElusiveBug(const char *title, mDNSu32 radarid, const char *msg) +mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both strings are UTF-8 text { static int notifyCount = 0; if (notifyCount) return; - + // If we display our alert early in the boot process, then it vanishes once the desktop appears. // To avoid this, we don't try to display alerts in the first three minutes after boot. if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return; - + // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address #if !ForceAlerts { @@ -1153,26 +750,33 @@ mDNSexport void NotifyOfElusiveBug(const char *title, mDNSu32 radarid, const cha } #endif - // Send a notification to the user to contact coreos-networking + LogMsg("%s", title); + LogMsg("%s", msg); + // Display a notification to the user notifyCount++; - CFStringRef alertHeader = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8); - CFStringRef alertFormat = CFSTR("Congratulations, you've reproduced an elusive bug. Please contact the owner of . %s"); - CFStringRef alertMessage = CFStringCreateWithFormat(NULL, NULL, alertFormat, radarid, msg); + +#ifndef NO_CFUSERNOTIFICATION + static const char footer[] = "(Note: This message only appears on machines with 17.x.x.x IP addresses — i.e. at Apple — not on customer machines.)"; + CFStringRef alertHeader = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8); + CFStringRef alertBody = CFStringCreateWithCString(NULL, msg, kCFStringEncodingUTF8); + CFStringRef alertFooter = CFStringCreateWithCString(NULL, footer, kCFStringEncodingUTF8); + CFStringRef alertMessage = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@\r\r%@"), alertBody, alertFooter); CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, alertHeader, alertMessage, NULL); +#endif /* NO_CFUSERNOTIFICATION */ } -mDNSlocal struct ifaddrs* myGetIfAddrs(int refresh) +mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh) { static struct ifaddrs *ifa = NULL; - + if (refresh && ifa) { freeifaddrs(ifa); ifa = NULL; } - + if (ifa == NULL) getifaddrs(&ifa); - + return ifa; } @@ -1183,56 +787,77 @@ mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, const if (i->Exists && !strcmp(i->ifa_name, ifname) && ((AAAA_OVER_V4 ) || (type == AF_INET && i->ifinfo.ip.type == mDNSAddrType_IPv4) || - (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6) )) return(i); + (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i); return(NULL); } -mDNSlocal int myIfIndexToName(u_short index, char* name) +mDNSlocal int myIfIndexToName(u_short index, char *name) { struct ifaddrs *ifa; for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next) if (ifa->ifa_addr->sa_family == AF_LINK) if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == index) - { strncpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; } + { strlcpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; } return -1; } -mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS *const m, mDNSu32 index) +mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 index) { NetworkInterfaceInfoOSX *i; if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly); - if (index) - for (i = m->p->InterfaceList; i; i = i->next) - // Don't get tricked by inactive interfaces with no InterfaceID set - if (i->ifinfo.InterfaceID && i->scope_id == index) return(i->ifinfo.InterfaceID); + if (index == kDNSServiceInterfaceIndexAny ) return(mDNSNULL); + + // Don't get tricked by inactive interfaces with no InterfaceID set + for (i = m->p->InterfaceList; i; i = i->next) + if (i->ifinfo.InterfaceID && i->scope_id == index) return(i->ifinfo.InterfaceID); + + // Not found. Make sure our interface list is up to date, then try again. + LogOperation("InterfaceID for interface index %d not found; Updating interface list", index); + mDNSMacOSXNetworkChanged(m); + for (i = m->p->InterfaceList; i; i = i->next) + if (i->ifinfo.InterfaceID && i->scope_id == index) return(i->ifinfo.InterfaceID); + return(mDNSNULL); } -mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mDNSInterfaceID id) +mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id) { NetworkInterfaceInfoOSX *i; if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly); - if (id) - for (i = m->p->InterfaceList; i; i = i->next) - // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces, which have no InterfaceID set - if ((mDNSInterfaceID)i == id) return(i->scope_id); - return 0; + if (id == mDNSInterface_Any ) return(0); + + // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces, which have no InterfaceID set + for (i = m->p->InterfaceList; i; i = i->next) + if ((mDNSInterfaceID)i == id) return(i->scope_id); + + // Not found. Make sure our interface list is up to date, then try again. + LogOperation("Interface index for InterfaceID %p not found; Updating interface list", id); + mDNSMacOSXNetworkChanged(m); + for (i = m->p->InterfaceList; i; i = i->next) + if ((mDNSInterfaceID)i == id) return(i->scope_id); + + return(0); } +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - +#pragma mark - UDP & TCP send & receive +#endif + mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr) { mDNSBool result = mDNSfalse; SCNetworkConnectionFlags flags; SCNetworkReachabilityRef ReachRef = NULL; - ReachRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, addr); + ReachRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, addr); if (!ReachRef) { LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithAddress"); goto end; } if (!SCNetworkReachabilityGetFlags(ReachRef, &flags)) { LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags"); goto end; } result = flags & kSCNetworkFlagsConnectionRequired; end: if (ReachRef) CFRelease(ReachRef); - return result; + return result; } // NOTE: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket" @@ -1241,8 +866,6 @@ mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr) mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstPort) { - #pragma unused(m) - // Note: For this platform we've adopted the convention that InterfaceIDs are secretly pointers // to the NetworkInterfaceInfoOSX structure that holds the active sockets. The mDNSCore code // doesn't know that and doesn't need to know that -- it just treats InterfaceIDs as opaque identifiers. @@ -1250,17 +873,18 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms char *ifa_name = info ? info->ifa_name : "unicast"; struct sockaddr_storage to; int s = -1, err; + mStatus result = mStatus_NoError; // Sanity check: Make sure that if we're sending a query via unicast, we're sending it using our // anonymous socket created for this purpose, so that we'll receive the response. // If we use one of the many multicast sockets bound to port 5353 then we may not receive responses reliably. - if (info && !mDNSAddrIsDNSMulticast(dst)) + if (InterfaceID && !mDNSAddrIsDNSMulticast(dst)) { const DNSMessage *const m = (DNSMessage *)msg; if ((m->h.flags.b[0] & kDNSFlag0_QR_Mask) == kDNSFlag0_QR_Query) LogMsg("mDNSPlatformSendUDP: ERROR: Sending query OP from mDNS port to non-mDNS destination %#a:%d", dst, mDNSVal16(dstPort)); } - + if (dst->type == mDNSAddrType_IPv4) { struct sockaddr_in *sin_to = (struct sockaddr_in*)&to; @@ -1268,7 +892,30 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms sin_to->sin_family = AF_INET; sin_to->sin_port = dstPort.NotAnInteger; sin_to->sin_addr.s_addr = dst->ip.v4.NotAnInteger; - s = info ? info->ss.sktv4 : m->p->unicastsockets.sktv4; + s = m->p->permanentsockets.sktv4; + if (info) // Specify outgoing interface + { + if (!mDNSAddrIsDNSMulticast(dst)) + { + #ifdef IP_FORCE_OUT_IFP + setsockopt(s, IPPROTO_IP, IP_FORCE_OUT_IFP, ifa_name, strlen(ifa_name) + 1); + #else + { + static int displayed = 0; + if (!displayed) + { + displayed = 1; + LogOperation("IP_FORCE_OUT_IFP Socket option not defined -- cannot specify interface for unicast packets"); + } + } + #endif + } + else + { + err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr)); + if (err < 0) LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %ld errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno)); + } + } } else if (dst->type == mDNSAddrType_IPv6) { @@ -1279,7 +926,12 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms sin6_to->sin6_flowinfo = 0; sin6_to->sin6_addr = *(struct in6_addr*)&dst->ip.v6; sin6_to->sin6_scope_id = info ? info->scope_id : 0; - s = info ? info->ss.sktv6 : m->p->unicastsockets.sktv6; + s = m->p->permanentsockets.sktv6; + if (info && mDNSAddrIsDNSMulticast(dst)) // Specify outgoing interface + { + err = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &info->scope_id, sizeof(info->scope_id)); + if (err < 0) LogMsg("setsockopt - IPV6_MULTICAST_IF error %ld errno %d (%s)", err, errno, strerror(errno)); + } } else { @@ -1287,15 +939,15 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms return mStatus_BadParamErr; } - // Don't send if it would cause dial on demand connection initiation. As an optimization, - // don't bother consulting reachability API / routing table when sending Multicast DNS - // since we ignore PPP interfaces for mDNS traffic - if (!mDNSAddrIsDNSMulticast(dst) && AddrRequiresPPPConnection((struct sockaddr *)&to)) + // Don't send if it would cause dial-on-demand connection initiation. + // As an optimization, don't bother consulting reachability API / routing + // table when sending Multicast DNS since we ignore PPP interfaces for mDNS traffic. + if (!info && !mDNSAddrIsDNSMulticast(dst) && AddrRequiresPPPConnection((struct sockaddr *)&to)) { debugf("mDNSPlatformSendUDP: Surpressing sending to avoid dial-on-demand connection"); return mStatus_NoError; } - + if (s >= 0) verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d", InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s); @@ -1310,7 +962,8 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len); if (err < 0) { - // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations + static int MessageCount = 0; + // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations if (!mDNSAddressIsAllDNSLinkGroup(dst)) if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr); // Don't report EHOSTUNREACH in the first three minutes after boot @@ -1319,12 +972,21 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms if (errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(mStatus_TransientErr); // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change if (errno == EADDRNOTAVAIL && m->p->NetworkChanged) return(mStatus_TransientErr); - LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %5s/%ld to %#a:%d skt %d error %d errno %d (%s) %lu", - InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow)); - return(mStatus_UnknownErr); + if (MessageCount < 1000) + { + MessageCount++; + LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %5s/%ld to %#a:%d skt %d error %d errno %d (%s) %lu", + InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow)); + } + result = mStatus_UnknownErr; } - - return(mStatus_NoError); + +#ifdef IP_FORCE_OUT_IFP + if (dst->type == mDNSAddrType_IPv4 && info && !mDNSAddrIsDNSMulticast(dst)) + setsockopt(s, IPPROTO_IP, IP_FORCE_OUT_IFP, "", 1); +#endif + + return(result); } mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max, @@ -1347,7 +1009,7 @@ mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max, msg.msg_control = (caddr_t)&ancillary; msg.msg_controllen = sizeof(ancillary); msg.msg_flags = 0; - + // Receive the data n = recvmsg(s, &msg, 0); if (n<0) @@ -1357,8 +1019,8 @@ mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max, } if (msg.msg_controllen < (int)sizeof(struct cmsghdr)) { - if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_controllen %d < sizeof(struct cmsghdr) %lu", - s, msg.msg_controllen, sizeof(struct cmsghdr)); + if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu", + s, n, msg.msg_controllen, sizeof(struct cmsghdr)); return(-1); } if (msg.msg_flags & MSG_CTRUNC) @@ -1366,9 +1028,9 @@ mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max, if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s); return(-1); } - + *fromlen = msg.msg_namelen; - + // Parse each option out of the ancillary data. for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr)) { @@ -1376,22 +1038,20 @@ mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max, if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR) { dstaddr->type = mDNSAddrType_IPv4; - dstaddr->ip.v4.NotAnInteger = *(u_int32_t*)CMSG_DATA(cmPtr); + dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr); } if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF) { struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr); if (sdl->sdl_nlen < IF_NAMESIZE) { - mDNSPlatformMemCopy(sdl->sdl_data, ifname, sdl->sdl_nlen); + mDNSPlatformMemCopy(ifname, sdl->sdl_data, sdl->sdl_nlen); ifname[sdl->sdl_nlen] = 0; // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen); } } if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL) - { *ttl = *(u_char*)CMSG_DATA(cmPtr); - } if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO) { struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr); @@ -1400,42 +1060,30 @@ mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max, myIfIndexToName(ip6_info->ipi6_ifindex, ifname); } if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT) - { *ttl = *(int*)CMSG_DATA(cmPtr); - } } return(n); } -// On entry, context points to our CFSocketSet -// If ss->info is NULL, we received this packet on our anonymous unicast socket -// If ss->info is non-NULL, we received this packet on port 5353 on the indicated interface -mDNSlocal void myCFSocketCallBack(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context) +mDNSlocal void myKQSocketCallBack(int s1, short filter, void *context) { - const CFSocketSet *const ss = (const CFSocketSet *)context; + const KQSocketSet *const ss = (const KQSocketSet *)context; mDNS *const m = ss->m; - const int skt = CFSocketGetNative(cfs); - const int s1 = (cfs == ss->cfsv4) ? ss->sktv4 : (cfs == ss->cfsv6) ? ss->sktv6 : -1; int err, count = 0; - - (void)address; // Parameter not used - (void)data; // Parameter not used - - if (CallBackType != kCFSocketReadCallBack) - LogMsg("myCFSocketCallBack: Why is CallBackType %d not kCFSocketReadCallBack?", CallBackType); - if (s1 < 0 || s1 != skt) + if (filter != EVFILT_READ) + LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ); + + if (s1 != ss->sktv4 && s1 != ss->sktv6) { - LogMsg("myCFSocketCallBack: s1 %d native socket %d, cfs %p", s1, skt, cfs); - LogMsg("myCFSocketCallBack: cfsv4 %p, sktv4 %d", ss->cfsv4, ss->sktv4); - LogMsg("myCFSocketCallBack: cfsv6 %p, sktv6 %d", ss->cfsv6, ss->sktv6); - } + LogMsg("myKQSocketCallBack: native socket %d", s1); + LogMsg("myKQSocketCallBack: sktv4 %d", ss->sktv4); + LogMsg("myKQSocketCallBack: sktv6 %d", ss->sktv6); + } while (1) { - // NOTE: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet - mDNSInterfaceID InterfaceID = ss->info ? ss->info->ifinfo.InterfaceID : mDNSNULL; mDNSAddr senderAddr, destAddr; mDNSIPPort senderPort, destPort = MulticastDNSPort; struct sockaddr_storage from; @@ -1444,7 +1092,7 @@ mDNSlocal void myCFSocketCallBack(const CFSocketRef cfs, const CFSocketCallBackT mDNSu8 ttl; err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl); if (err < 0) break; - + count++; if (from.ss_family == AF_INET) { @@ -1452,6 +1100,7 @@ mDNSlocal void myCFSocketCallBack(const CFSocketRef cfs, const CFSocketCallBackT senderAddr.type = mDNSAddrType_IPv4; senderAddr.ip.v4.NotAnInteger = sin->sin_addr.s_addr; senderPort.NotAnInteger = sin->sin_port; + //LogOperation("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname); } else if (from.ss_family == AF_INET6) { @@ -1459,46 +1108,28 @@ mDNSlocal void myCFSocketCallBack(const CFSocketRef cfs, const CFSocketCallBackT senderAddr.type = mDNSAddrType_IPv6; senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr; senderPort.NotAnInteger = sin6->sin6_port; + //LogOperation("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname); } else { - LogMsg("myCFSocketCallBack from is unknown address family %d", from.ss_family); + LogMsg("myKQSocketCallBack from is unknown address family %d", from.ss_family); return; } - if (mDNSAddrIsDNSMulticast(&destAddr)) - { - // Even though we indicated a specific interface in the IP_ADD_MEMBERSHIP call, a weirdness of the - // sockets API means that even though this socket has only officially joined the multicast group - // on one specific interface, the kernel will still deliver multicast packets to it no matter which - // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug. - // To work around this weirdness, we use the IP_RECVIF option to find the name of the interface - // on which the packet arrived, and ignore the packet if it really arrived on some other interface. - if (!ss->info || !ss->info->Exists) - { - verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on unicast socket (Ignored)", &senderAddr, &destAddr); - return; - } - else if (strcmp(ss->info->ifa_name, packetifname)) - { - verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on interface %#a/%s (Ignored -- really arrived on interface %s)", - &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name, packetifname); - return; - } - else - verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on interface %#a/%s", - &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name); - } - else - { - // Note: Unicast packets are delivered to *one* of our listening sockets, - // not necessarily the one bound to the physical interface where the packet arrived. - // To sort this out we search our interface list and update InterfaceID to reference - // the mDNSCore interface object for the interface where the packet was actually received. - NetworkInterfaceInfo *intf = m->HostInterfaces; - while (intf && strcmp(intf->ifname, packetifname)) intf = intf->next; - if (intf) InterfaceID = intf->InterfaceID; - } + // NOTE: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet + mDNSInterfaceID InterfaceID = mDNSNULL; + NetworkInterfaceInfo *intf = m->HostInterfaces; + while (intf && strcmp(intf->ifname, packetifname)) intf = intf->next; + // When going to sleep we deregister all our interfaces, but if the machine + // takes a few seconds to sleep we may continue to receive multicasts + // during that time, which would confuse mDNSCoreReceive, because as far + // as it's concerned, we should have no active interfaces any more. + // Hence we ignore multicasts for which we can find no matching InterfaceID. + if (intf) InterfaceID = intf->InterfaceID; + else if (mDNSAddrIsDNSMulticast(&destAddr)) continue; + +// LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s", +// &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifa_name); mDNSCoreReceive(m, &m->imsg, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, destPort, InterfaceID); } @@ -1506,387 +1137,467 @@ mDNSlocal void myCFSocketCallBack(const CFSocketRef cfs, const CFSocketCallBackT if (err < 0 && (errno != EWOULDBLOCK || count == 0)) { // Something is busted here. - // CFSocket says there is a packet, but myrecvfrom says there is not. + // kqueue says there is a packet, but myrecvfrom says there is not. // Try calling select() to get another opinion. // Find out about other socket parameter that can help understand why select() says the socket is ready for read // All of this is racy, as data may have arrived after the call to select() + static unsigned int numLogMessages = 0; int save_errno = errno; int so_error = -1; int so_nread = -1; int fionread = -1; socklen_t solen = sizeof(int); fd_set readfds; + struct timeval timeout; + int selectresult; FD_ZERO(&readfds); FD_SET(s1, &readfds); - struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = 0; - int selectresult = select(s1+1, &readfds, NULL, NULL, &timeout); + selectresult = select(s1+1, &readfds, NULL, NULL, &timeout); if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1) - LogMsg("myCFSocketCallBack getsockopt(SO_ERROR) error %d", errno); + LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno); if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1) - LogMsg("myCFSocketCallBack getsockopt(SO_NREAD) error %d", errno); + LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno); if (ioctl(s1, FIONREAD, &fionread) == -1) - LogMsg("myCFSocketCallBack ioctl(FIONREAD) error %d", errno); - static unsigned int numLogMessages = 0; + LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno); if (numLogMessages++ < 100) - LogMsg("myCFSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d", + LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d", s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count); if (numLogMessages > 5) - NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)", 3375328, - "Alternatively, you can send email to radar-3387020@group.apple.com. " + NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)", + "Congratulations, you've reproduced an elusive bug.\r" + "Please contact the current assignee of .\r" + "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r" "If possible, please leave your machine undisturbed so that someone can come to investigate the problem."); sleep(1); // After logging this error, rate limit so we don't flood syslog } } -// TCP socket support for unicast DNS and Dynamic DNS Update +// TCP socket support -typedef struct +struct TCPSocket_struct { - TCPConnectionCallback callback; - void *context; - int connected; - } tcpInfo_t; + TCPSocketFlags flags; // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags + TCPConnectionCallback callback; + int fd; + KQueueEntry kqEntry; +#ifndef NO_SECURITYFRAMEWORK + SSLContextRef tlsContext; +#endif /* NO_SECURITYFRAMEWORK */ + void *context; + mDNSBool setup; + mDNSBool handshakecomplete; + mDNSBool connected; + }; + +#ifndef NO_SECURITYFRAMEWORK -mDNSlocal void tcpCFSocketCallback(CFSocketRef cfs, CFSocketCallBackType CallbackType, CFDataRef address, - const void *data, void *context) +mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength) { - #pragma unused(CallbackType, address, data) - mDNSBool connect = mDNSfalse; - - tcpInfo_t *info = context; - if (!info->connected) - { - connect = mDNStrue; - info->connected = mDNStrue; // prevent connected flag from being set in future callbacks - } - info->callback(CFSocketGetNative(cfs), info->context, connect); - // NOTE: the callback may call CloseConnection here, which frees the context structure! + int ret = send(((TCPSocket *)connection)->fd, data, *dataLength, 0); + if (ret >= 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); } + if (ret >= 0) { *dataLength = ret; return(noErr); } + *dataLength = 0; + if (errno == EAGAIN ) return(errSSLWouldBlock); + if (errno == ENOENT ) return(errSSLClosedGraceful); + if (errno == EPIPE || errno == ECONNRESET) return(errSSLClosedAbort); + LogMsg("ERROR: tlsWriteSock: error %d %s\n", errno, strerror(errno)); + return(errSSLClosedAbort); } -mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID, - TCPConnectionCallback callback, void *context, int *descriptor) +mDNSlocal OSStatus tlsReadSock(SSLConnectionRef connection, void *data, size_t *dataLength) { - int sd, on = 1; // "on" for setsockopt - struct sockaddr_in saddr; - CFSocketContext cfContext = { 0, NULL, 0, 0, 0 }; - tcpInfo_t *info; - CFSocketRef sr; - CFRunLoopSourceRef rls; - - (void)InterfaceID; //!!!KRS use this if non-zero!!! + int ret = recv(((TCPSocket *)connection)->fd, data, *dataLength, 0); + if (ret > 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); } + if (ret > 0) { *dataLength = ret; return(noErr); } + *dataLength = 0; + if (ret == 0 || errno == ENOENT ) return(errSSLClosedGraceful); + if ( errno == EAGAIN ) return(errSSLWouldBlock); + if ( errno == ECONNRESET) return(errSSLClosedAbort); + LogMsg("ERROR: tlsSockRead: error %d %s\n", errno, strerror(errno)); + return(errSSLClosedAbort); + } - *descriptor = 0; - if (dst->type != mDNSAddrType_IPv4) - { - LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: opperation not supported"); - return mStatus_UnknownErr; - } +mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, mDNSBool server) + { + mStatus err = SSLNewContext(server, &sock->tlsContext); + if (err) { LogMsg("ERROR: tlsSetupSock: SSLNewContext failed with error code: %d", err); return(err); } - bzero(&saddr, sizeof(saddr)); - saddr.sin_family = AF_INET; - saddr.sin_port = dstport.NotAnInteger; - saddr.sin_len = sizeof(saddr); - memcpy(&saddr.sin_addr, &dst->ip.v4.NotAnInteger, sizeof(saddr.sin_addr)); + err = SSLSetIOFuncs(sock->tlsContext, tlsReadSock, tlsWriteSock); + if (err) { LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err); return(err); } - // Don't send if it would cause dial on demand connection initiation. - if (AddrRequiresPPPConnection((struct sockaddr *)&saddr)) - { - debugf("mDNSPlatformTCPConnect: Surpressing sending to avoid dial-on-demand connection"); - return mStatus_UnknownErr; - } + err = SSLSetConnection(sock->tlsContext, (SSLConnectionRef) sock); + if (err) { LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err); return(err); } - sd = socket(AF_INET, SOCK_STREAM, 0); - if (sd < 3) { LogMsg("mDNSPlatformTCPConnect: socket error %d errno %d (%s)", sd, errno, strerror(errno)); return mStatus_UnknownErr; } + return(err); + } - // set non-blocking - if (fcntl(sd, F_SETFL, O_NONBLOCK) < 0) - { - LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno)); - return mStatus_UnknownErr; - } - - // receive interface identifiers - if (setsockopt(sd, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)) < 0) - { - LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); - return mStatus_UnknownErr; - } - // set up CF wrapper, add to Run Loop - info = mallocL("mDNSPlatformTCPConnect", sizeof(tcpInfo_t)); - info->callback = callback; - info->context = context; - cfContext.info = info; - sr = CFSocketCreateWithNative(kCFAllocatorDefault, sd, kCFSocketReadCallBack | kCFSocketConnectCallBack, - tcpCFSocketCallback, &cfContext); - if (!sr) - { - LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketRefCreateWithNative failed"); - freeL("mDNSPlatformTCPConnect", info); - return mStatus_UnknownErr; - } +mDNSlocal mDNSBool IsTunnelModeDomain(const domainname *d) + { + static const domainname *mmc = (const domainname*) "\x7" "members" "\x3" "mac" "\x3" "com"; + const domainname *d1 = mDNSNULL; // TLD + const domainname *d2 = mDNSNULL; // SLD + const domainname *d3 = mDNSNULL; + while (d->c[0]) { d3 = d2; d2 = d1; d1 = d; d = (const domainname*)(d->c + 1 + d->c[0]); } + return(d3 && SameDomainName(d3, mmc)); + } - rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sr, 0); - if (!rls) - { - LogMsg("ERROR: mDNSPlatformTCPConnect - CFSocketCreateRunLoopSource failed"); - freeL("mDNSPlatformTCPConnect", info); - return mStatus_UnknownErr; - } - - CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); - CFRelease(rls); - - // initiate connection wth peer - if (connect(sd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) +#endif /* NO_SECURITYFRAMEWORK */ + +mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context) + { + TCPSocket *sock = context; + mStatus err = mStatus_NoError; + + //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter); + //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter); + // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE + if (filter == EVFILT_WRITE) KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, &sock->kqEntry); + + if (sock->flags & kTCPSocketFlags_UseTLS) { - if (errno == EINPROGRESS) +#ifndef NO_SECURITYFRAMEWORK + if (!sock->setup) { sock->setup = mDNStrue; tlsSetupSock(sock, mDNSfalse); } + if (!sock->handshakecomplete) { - info->connected = 0; - *descriptor= sd; - return mStatus_ConnPending; + //LogMsg("tcpKQSocketCallback Starting SSLHandshake"); + err = SSLHandshake(sock->tlsContext); + //if (!err) LogMsg("tcpKQSocketCallback SSLHandshake complete"); + if (!err) sock->handshakecomplete = mDNStrue; + else if (err == errSSLWouldBlock) return; + else { LogMsg("KQ SSLHandshake failed: %d", err); SSLDisposeContext(sock->tlsContext); sock->tlsContext = NULL; } } - LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: %s", strerror(errno)); - freeL("mDNSPlatformTCPConnect", info); - CFSocketInvalidate(sr); // Note: Also closes the underlying socket - return mStatus_ConnFailed; +#else + err = mStatus_UnsupportedErr; +#endif /* NO_SECURITYFRAMEWORK */ } - info->connected = 1; - *descriptor = sd; - return mStatus_ConnEstablished; + + mDNSBool connect = !sock->connected; + sock->connected = mDNStrue; + sock->callback(sock, sock->context, connect, err); + // NOTE: the callback may call CloseConnection here, which frees the context structure! } -mDNSexport void mDNSPlatformTCPCloseConnection(int sd) +mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef) { - CFSocketContext cfContext; - tcpInfo_t *info; - CFSocketRef sr; + struct kevent new_event; + EV_SET(&new_event, fd, filter, flags, 0, 0, (void*)entryRef); + return (kevent(KQueueFD, &new_event, 1, NULL, 0, NULL) < 0) ? errno : 0; + } - if (sd < 3) LogMsg("mDNSPlatformTCPCloseConnection: ERROR sd %d < 3", sd); +mDNSexport void KQueueLock(mDNS *const m) + { + pthread_mutex_lock(&m->p->BigMutex); + m->p->BigMutexStartTime = mDNSPlatformRawTime(); + } - // Get the CFSocket for the descriptor - sr = CFSocketCreateWithNative(kCFAllocatorDefault, sd, kCFSocketNoCallBack, NULL, NULL); - if (!sr) { LogMsg("ERROR: mDNSPlatformTCPCloseConnection - CFSocketCreateWithNative returned NULL"); return; } +mDNSexport void KQueueUnlock(mDNS *const m, const char const *task) + { + mDNSs32 end = mDNSPlatformRawTime(); + (void)task; + if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold) + LogOperation("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime); - CFSocketGetContext(sr, &cfContext); - if (!cfContext.info) - { - LogMsg("ERROR: mDNSPlatformTCPCloseConnection - could not retreive tcpInfo from socket context"); - CFRelease(sr); - return; - } - CFRelease(sr); // this only releases the copy we allocated with CreateWithNative above - - info = cfContext.info; + pthread_mutex_unlock(&m->p->BigMutex); - // Note: MUST NOT close the underlying native BSD socket. - // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, - // because it first has to unhook the sockets from its select() call, before it can safely close them. - CFSocketInvalidate(sr); - CFRelease(sr); - freeL("mDNSPlatformTCPCloseConnection", info); + char wake = 1; + if (send(m->p->WakeKQueueLoopFD, &wake, sizeof(wake), 0) == -1) + LogMsg("ERROR: KQueueWake: send failed with error code: %d - %s", errno, strerror(errno)); } -mDNSexport int mDNSPlatformReadTCP(int sd, void *buf, int buflen) +mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port) { - int nread = recv(sd, buf, buflen, 0); - if (nread < 0) + (void) m; + + TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket)); + if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); } + + mDNSPlatformMemZero(sock, sizeof(TCPSocket)); + sock->callback = mDNSNULL; + sock->fd = socket(AF_INET, SOCK_STREAM, 0); + sock->kqEntry.KQcallback= tcpKQSocketCallback; + sock->kqEntry.KQcontext = sock; + sock->kqEntry.KQtask = "mDNSPlatformTCPSocket"; + sock->flags = flags; + sock->context = mDNSNULL; + sock->setup = mDNSfalse; + sock->handshakecomplete = mDNSfalse; + sock->connected = mDNSfalse; + + if (sock->fd == -1) { - if (errno == EAGAIN) return 0; // no data available (call would block) - LogMsg("ERROR: mDNSPlatformReadTCP - recv: %s", strerror(errno)); - return -1; + LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno)); + freeL("TCPSocket/mDNSPlatformTCPSocket", sock); + return(mDNSNULL); } - return nread; + + // Bind it + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = port->NotAnInteger; + if (bind(sock->fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) + { LogMsg("ERROR: bind %s", strerror(errno)); goto error; } + + // Receive interface identifiers + const int on = 1; // "on" for setsockopt + if (setsockopt(sock->fd, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)) < 0) + { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); goto error; } + + memset(&addr, 0, sizeof(addr)); + socklen_t len = sizeof(addr); + if (getsockname(sock->fd, (struct sockaddr*) &addr, &len) < 0) + { LogMsg("getsockname - %s", strerror(errno)); goto error; } + + port->NotAnInteger = addr.sin_port; + return sock; + +error: + close(sock->fd); + freeL("TCPSocket/mDNSPlatformTCPSocket", sock); + return(mDNSNULL); } -mDNSexport int mDNSPlatformWriteTCP(int sd, const char *msg, int len) +mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID, + TCPConnectionCallback callback, void *context) { - int nsent = send(sd, msg, len, 0); + struct sockaddr_in saddr; + mStatus err = mStatus_NoError; + + sock->callback = callback; + sock->context = context; + sock->setup = mDNSfalse; + sock->handshakecomplete = mDNSfalse; + sock->connected = mDNSfalse; - if (nsent < 0) + (void) InterfaceID; //!!!KRS use this if non-zero!!! + + if (dst->type != mDNSAddrType_IPv4) { - if (errno == EAGAIN) return 0; // blocked - LogMsg("ERROR: mDNSPlatformWriteTCP - sendL %s", strerror(errno)); - return -1; + LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: opperation not supported"); + return mStatus_UnknownErr; } - return nsent; - } -// This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel -mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel) - { - CFStringEncoding encoding = kCFStringEncodingUTF8; - CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding); - if (cfs) + mDNSPlatformMemZero(&saddr, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_port = dstport.NotAnInteger; + saddr.sin_len = sizeof(saddr); + saddr.sin_addr.s_addr = dst->ip.v4.NotAnInteger; + + // Don't send if it would cause dial-on-demand connection initiation. + if (AddrRequiresPPPConnection((struct sockaddr *)&saddr)) { - CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8); - CFRelease(cfs); + debugf("mDNSPlatformTCPConnect: Surpressing sending to avoid dial-on-demand connection"); + return mStatus_UnknownErr; + } + + sock->kqEntry.KQcallback = tcpKQSocketCallback; + sock->kqEntry.KQcontext = sock; + sock->kqEntry.KQtask = "Outgoing TCP"; + + // Watch for connect complete (write is ready) + // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE + if (KQueueSet(sock->fd, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, &sock->kqEntry)) + { + LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed"); + close(sock->fd); + return errno; + } + + // Watch for incoming data + if (KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry)) + { + LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed"); + close(sock->fd); // Closing the descriptor removes all filters from the kqueue + return errno; + } + + if (fcntl(sock->fd, F_SETFL, fcntl(sock->fd, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking + { + LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno)); + return mStatus_UnknownErr; + } + + // initiate connection wth peer + if (connect(sock->fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) + { + if (errno == EINPROGRESS) return mStatus_ConnPending; + LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d %s", sock->fd, errno, strerror(errno)); + close(sock->fd); + return mStatus_ConnFailed; } + + LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously"); + // kQueue should notify us, but this LogMsg is to help track down if it doesn't + return err; } -// This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel -mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel) +// Why doesn't mDNSPlatformTCPAccept actually call accept() ? +mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd) { - CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL); - if (cfs) + mStatus err = mStatus_NoError; + + TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket)); + if (!sock) return(mDNSNULL); + + memset(sock, 0, sizeof(*sock)); + sock->fd = fd; + sock->flags = flags; + + if (flags & kTCPSocketFlags_UseTLS) { - CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8); - CFRelease(cfs); +#ifndef NO_SECURITYFRAMEWORK + if (!ServerCerts) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err = mStatus_UnknownErr; goto exit; } + + err = tlsSetupSock(sock, mDNStrue); + if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err); goto exit; } + + err = SSLSetCertificate(sock->tlsContext, ServerCerts); + if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err); goto exit; } +#else + err = mStatus_UnsupportedErr; +#endif /* NO_SECURITYFRAMEWORK */ } +#ifndef NO_SECURITYFRAMEWORK +exit: +#endif + + if (err) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock); return(mDNSNULL); } + return(sock); } -mDNSlocal mDNSBool DDNSSettingEnabled(CFDictionaryRef dict) +mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock) { - mDNSs32 val; - CFNumberRef state = CFDictionaryGetValue(dict, CFSTR("Enabled")); - if (!state) return mDNSfalse; - if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val)) { LogMsg("ERROR: DDNSSettingEnabled - CFNumberGetValue"); return mDNSfalse; } - return val ? mDNStrue : mDNSfalse; + if (sock) + { +#ifndef NO_SECURITYFRAMEWORK + if (sock->tlsContext) + { + SSLClose(sock->tlsContext); + SSLDisposeContext(sock->tlsContext); + sock->tlsContext = NULL; + } +#endif /* NO_SECURITYFRAMEWORK */ + if (sock->fd != -1) + { + shutdown(sock->fd, 2); + close(sock->fd); + sock->fd = -1; + } + + freeL("mDNSPlatformTCPCloseConnection", sock); + } } -mDNSlocal void GetUserSpecifiedDDNSConfig(domainname *const fqdn, domainname *const regDomain, CFArrayRef *const browseDomains) +mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed) { - char buf[MAX_ESCAPED_DOMAIN_NAME]; + long nread = 0; + *closed = mDNSfalse; - fqdn->c[0] = 0; - regDomain->c[0] = 0; - buf[0] = 0; - *browseDomains = NULL; - - SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetUserSpecifiedDDNSConfig"), NULL, NULL); - if (store) + if (sock->flags & kTCPSocketFlags_UseTLS) { - CFDictionaryRef dict = SCDynamicStoreCopyValue(store, CFSTR("Setup:/Network/DynamicDNS")); - if (dict) +#ifndef NO_SECURITYFRAMEWORK + if (!sock->handshakecomplete) { - CFArrayRef fqdnArray = CFDictionaryGetValue(dict, CFSTR("HostNames")); - if (fqdnArray && CFArrayGetCount(fqdnArray) > 0) - { - CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0); // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list - if (fqdnDict && DDNSSettingEnabled(fqdnDict)) - { - CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain")); - if (name) - { - if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) || - !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0]) - LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)"); - else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf); - } - } - } + //LogMsg("mDNSPlatformReadTCP Starting SSLHandshake"); + mStatus err = SSLHandshake(sock->tlsContext); + //if (!err) LogMsg("mDNSPlatformReadTCP SSLHandshake complete"); + if (!err) sock->handshakecomplete = mDNStrue; + else if (err == errSSLWouldBlock) return(0); + else { LogMsg("Read SSLHandshake failed: %d", err); SSLDisposeContext(sock->tlsContext); sock->tlsContext = NULL; } + } - CFArrayRef regArray = CFDictionaryGetValue(dict, CFSTR("RegistrationDomains")); - if (regArray && CFArrayGetCount(regArray) > 0) - { - CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0); - if (regDict && DDNSSettingEnabled(regDict)) - { - CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain")); - if (name) - { - if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) || - !MakeDomainNameFromDNSNameString(regDomain, buf) || !regDomain->c[0]) - LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)"); - else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration zone: %s", buf); - } - } - } - CFArrayRef browseArray = CFDictionaryGetValue(dict, CFSTR("BrowseDomains")); - if (browseArray && CFArrayGetCount(browseArray) > 0) - { - CFRetain(browseArray); - *browseDomains = browseArray; - } - CFRelease(dict); + //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0)); + mStatus err = SSLRead(sock->tlsContext, buf, buflen, (size_t*)&nread); + //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen); + if (err == errSSLClosedGraceful) { nread = 0; *closed = mDNStrue; } + else if (err && err != errSSLWouldBlock) + { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err); nread = -1; *closed = mDNStrue; } +#else + nread = -1; + *closed = mDNStrue; +#endif /* NO_SECURITYFRAMEWORK */ + } + else + { + static int CLOSEDcount = 0; + static int EAGAINcount = 0; + nread = recv(sock->fd, buf, buflen, 0); + + if (nread > 0) { CLOSEDcount = 0; EAGAINcount = 0; } // On success, clear our error counters + else if (nread == 0) + { + *closed = mDNStrue; + if ((++CLOSEDcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock->fd, CLOSEDcount); sleep(1); } + } + // else nread is negative -- see what kind of error we got + else if (errno == ECONNRESET) { nread = 0; *closed = mDNStrue; } + else if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d %s", errno, strerror(errno)); nread = -1; } + else // errno is EAGAIN (EWOULDBLOCK) -- no data available + { + nread = 0; + if ((++EAGAINcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock->fd, EAGAINcount); sleep(1); } } - CFRelease(store); } + + return nread; } -mDNSlocal void SetDDNSNameStatus(domainname *const dname, mStatus status) +mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len) { - SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:SetDDNSNameStatus"), NULL, NULL); - if (store) - { - char uname[MAX_ESCAPED_DOMAIN_NAME]; - ConvertDomainNameToCString(dname, uname); - char *p = uname; + int nsent; - while (*p) - { - *p = tolower(*p); - if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot - p++; - } + if (sock->flags & kTCPSocketFlags_UseTLS) + { +#ifndef NO_SECURITYFRAMEWORK + size_t processed; + mStatus err = SSLWrite(sock->tlsContext, msg, len, &processed); - // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity. - // That single entity is a CFDictionary with name "HostNames". - // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN - // in question, and the corresponding value is a CFDictionary giving the state for that FQDN. - // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.) - // The CFDictionary for each FQDN holds (at present) a single name/value pair, - // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success). - - const CFStringRef StateKeys [1] = { CFSTR("HostNames") }; - const CFStringRef HostKeys [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) }; - const CFStringRef StatusKeys[1] = { CFSTR("Status") }; - if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname); - else + if (!err) nsent = (int) processed; + else if (err == errSSLWouldBlock) nsent = 0; + else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err); nsent = -1; } +#else + nsent = -1; +#endif /* NO_SECURITYFRAMEWORK */ + } + else + { + nsent = send(sock->fd, msg, len, 0); + if (nsent < 0) { - const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) }; - if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%ld) failed", status); - else - { - const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, NULL, NULL) }; - if (HostVals[0]) - { - const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, NULL, NULL) }; - if (StateVals[0]) - { - CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, NULL, NULL); - if (StateDict) - { - SCDynamicStoreSetValue(store, CFSTR("State:/Network/DynamicDNS"), StateDict); - CFRelease(StateDict); - } - CFRelease(StateVals[0]); - } - CFRelease(HostVals[0]); - } - CFRelease(StatusVals[0]); - } - CFRelease(HostKeys[0]); + if (errno == EAGAIN) nsent = 0; + else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno)); nsent = -1; } } - CFRelease(store); } + + return nsent; + } + +mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock) + { + return sock->fd; } // If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries -mDNSlocal mStatus SetupSocket(mDNS *const m, CFSocketSet *cp, mDNSBool mcast, const mDNSAddr *ifaddr, u_short sa_family) +mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family) { + const int ip_tosbits = IPTOS_LOWDELAY | IPTOS_THROUGHPUT; int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6; - CFSocketRef *c = (sa_family == AF_INET) ? &cp->cfsv4 : &cp->cfsv6; - CFRunLoopSourceRef *r = (sa_family == AF_INET) ? &cp->rlsv4 : &cp->rlsv6; + KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6; const int on = 1; const int twofivefive = 255; mStatus err = mStatus_NoError; char *errstr = mDNSNULL; - mDNSIPPort port = (mcast | m->CanReceiveUnicastOn5353) ? MulticastDNSPort : zeroIPPort; - - if (*s >= 0) { LogMsg("SetupSocket ERROR: socket %d is already set", *s); return(-1); } - if (*c) { LogMsg("SetupSocket ERROR: CFSocketRef %p is already set", *c); return(-1); } - - // Open the socket... int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP); - if (skt < 3) { LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno)); return(skt); } + if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno)); return(skt); } // ... with a shared UDP port, if it's for multicast receiving - if (port.NotAnInteger) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)); + if (mDNSSameIPPort(port, MulticastDNSPort)) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)); if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; } if (sa_family == AF_INET) @@ -1894,40 +1605,24 @@ mDNSlocal mStatus SetupSocket(mDNS *const m, CFSocketSet *cp, mDNSBool mcast, co // We want to receive destination addresses err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on)); if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; } - + // We want to receive interface identifiers err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)); if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; } - + // We want to receive packet TTL value so we can check it err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on)); // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it - - // Add multicast group membership on this interface, if it's for multicast receiving - if (mcast) - { - struct in_addr addr = { ifaddr->ip.v4.NotAnInteger }; - struct ip_mreq imr; - imr.imr_multiaddr.s_addr = AllDNSLinkGroupv4.NotAnInteger; - imr.imr_interface = addr; - err = setsockopt(skt, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr)); - if (err < 0) { errstr = "setsockopt - IP_ADD_MEMBERSHIP"; goto fail; } - - // Specify outgoing interface too - err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr)); - if (err < 0) { errstr = "setsockopt - IP_MULTICAST_IF"; goto fail; } - } - + // Send unicast packets with TTL 255 err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive)); if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; } - + // And multicast packets with TTL 255 too err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive)); if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; } // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate - const int ip_tosbits = IPTOS_LOWDELAY | IPTOS_THROUGHPUT; err = setsockopt(skt, IPPROTO_IP, IP_TOS, &ip_tosbits, sizeof(ip_tosbits)); if (err < 0) { errstr = "setsockopt - IP_TOS"; goto fail; } @@ -1944,39 +1639,24 @@ mDNSlocal mStatus SetupSocket(mDNS *const m, CFSocketSet *cp, mDNSBool mcast, co // We want to receive destination addresses and receive interface identifiers err = setsockopt(skt, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)); if (err < 0) { errstr = "setsockopt - IPV6_PKTINFO"; goto fail; } - + // We want to receive packet hop count value so we can check it err = setsockopt(skt, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on)); if (err < 0) { errstr = "setsockopt - IPV6_HOPLIMIT"; goto fail; } - - // We want to receive only IPv6 packets, without this option, we may - // get IPv4 addresses as mapped addresses. + + // We want to receive only IPv6 packets. Without this option we get IPv4 packets too, + // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; } - - if (mcast) - { - // Add multicast group membership on this interface, if it's for multicast receiving - int interface_id = if_nametoindex(cp->info->ifa_name); - struct ipv6_mreq i6mr; - i6mr.ipv6mr_interface = interface_id; - i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroupv6; - err = setsockopt(skt, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr)); - if (err < 0) { errstr = "setsockopt - IPV6_JOIN_GROUP"; goto fail; } - - // Specify outgoing interface too - err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_IF, &interface_id, sizeof(interface_id)); - if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_IF"; goto fail; } - } - + // Send unicast packets with TTL 255 err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive)); if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; } - + // And multicast packets with TTL 255 too err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive)); if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; } - + // Note: IPV6_TCLASS appears not to be implemented on OS X right now (or indeed on ANY version of Unix?) #ifdef IPV6_TCLASS // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to get maximum 802.11 multicast rate @@ -1984,43 +1664,241 @@ mDNSlocal mStatus SetupSocket(mDNS *const m, CFSocketSet *cp, mDNSBool mcast, co err = setsockopt(skt, IPPROTO_IPV6, IPV6_TCLASS, &tclass, sizeof(tclass)); if (err < 0) { errstr = "setsockopt - IPV6_TCLASS"; goto fail; } #endif - + // Want to receive our own packets err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on)); if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; } - + // And start listening for packets struct sockaddr_in6 listening_sockaddr6; - bzero(&listening_sockaddr6, sizeof(listening_sockaddr6)); + mDNSPlatformMemZero(&listening_sockaddr6, sizeof(listening_sockaddr6)); listening_sockaddr6.sin6_len = sizeof(listening_sockaddr6); listening_sockaddr6.sin6_family = AF_INET6; listening_sockaddr6.sin6_port = port.NotAnInteger; listening_sockaddr6.sin6_flowinfo = 0; -// listening_sockaddr6.sin6_addr = IN6ADDR_ANY_INIT; // Want to receive multicasts AND unicasts on this socket + listening_sockaddr6.sin6_addr = in6addr_any; // Want to receive multicasts AND unicasts on this socket listening_sockaddr6.sin6_scope_id = 0; err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6)); if (err) { errstr = "bind"; goto fail; } } - + fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking + fcntl(skt, F_SETFD, 1); // set close-on-exec *s = skt; - CFSocketContext myCFSocketContext = { 0, cp, NULL, NULL, NULL }; - *c = CFSocketCreateWithNative(kCFAllocatorDefault, *s, kCFSocketReadCallBack, myCFSocketCallBack, &myCFSocketContext); - *r = CFSocketCreateRunLoopSource(kCFAllocatorDefault, *c, 0); - CFRunLoopAddSource(CFRunLoopGetCurrent(), *r, kCFRunLoopDefaultMode); - + k->KQcallback = myKQSocketCallBack; + k->KQcontext = cp; + k->KQtask = "UDP packet reception"; + KQueueSet(*s, EV_ADD, EVFILT_READ, k); + return(err); -fail: - LogMsg("%s error %ld errno %d (%s)", errstr, err, errno, strerror(errno)); - if (!strcmp(errstr, "bind") && errno == EADDRINUSE) - NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed", 3814904, - "Alternatively, you can send email to radar-3387020@group.apple.com. " + fail: + // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero + if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port)) + LogMsg("%s error %ld errno %d (%s)", errstr, err, errno, strerror(errno)); + + // If we got a "bind" failure with an EADDRINUSE error for our shared mDNS port, display error alert + if (!strcmp(errstr, "bind") && mDNSSameIPPort(port, MulticastDNSPort) && errno == EADDRINUSE) + NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed", + "Congratulations, you've reproduced an elusive bug.\r" + "Please contact the current assignee of .\r" + "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r" "If possible, please leave your machine undisturbed so that someone can come to investigate the problem."); + close(skt); return(err); } +struct UDPSocket_struct + { + KQSocketSet ss; + }; + +mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort port) + { + mStatus err; + UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket)); + if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); } + memset(p, 0, sizeof(UDPSocket)); + p->ss.m = m; + p->ss.sktv4 = -1; + p->ss.sktv6 = -1; + err = SetupSocket(&p->ss, port, AF_INET); + if (err) + { + // In customer builds we don't want to log failures with port 5351, because this is a known issue + // of failing to bind to this port when Internet Sharing has already bound to it + if (mDNSSameIPPort(port, NATPMPPort)) + LogOperation("mDNSPlatformUDPSocket: SetupSocket %d failed", mDNSVal16(port)); + else LogMsg ("mDNSPlatformUDPSocket: SetupSocket %d failed", mDNSVal16(port)); + freeL("UDPSocket", p); + return(mDNSNULL); + } + return(p); + } + +mDNSlocal void CloseSocketSet(KQSocketSet *ss) + { + if (ss->sktv4 != -1) + { + close(ss->sktv4); + ss->sktv4 = -1; + } + if (ss->sktv6 != -1) + { + close(ss->sktv6); + ss->sktv6 = -1; + } + } + +mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock) + { + CloseSocketSet(&sock->ss); + freeL("UDPSocket", sock); + } + +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - +#pragma mark - Key Management +#endif + +#ifndef NO_SECURITYFRAMEWORK +mDNSlocal CFArrayRef GetCertChain(SecIdentityRef identity) + { + CFMutableArrayRef certChain = NULL; + if (!identity) { LogMsg("getCertChain: identity is NULL"); return(NULL); } + SecCertificateRef cert; + OSStatus err = SecIdentityCopyCertificate(identity, &cert); + if (err || !cert) LogMsg("getCertChain: SecIdentityCopyCertificate() returned %d", (int) err); + else + { + SecPolicySearchRef searchRef; + err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef); + if (err || !searchRef) LogMsg("getCertChain: SecPolicySearchCreate() returned %d", (int) err); + else + { + SecPolicyRef policy; + err = SecPolicySearchCopyNext(searchRef, &policy); + if (err || !policy) LogMsg("getCertChain: SecPolicySearchCopyNext() returned %d", (int) err); + else + { + CFArrayRef wrappedCert = CFArrayCreate(NULL, (const void**) &cert, 1, &kCFTypeArrayCallBacks); + if (!wrappedCert) LogMsg("getCertChain: wrappedCert is NULL"); + else + { + SecTrustRef trust; + err = SecTrustCreateWithCertificates(wrappedCert, policy, &trust); + if (err || !trust) LogMsg("getCertChain: SecTrustCreateWithCertificates() returned %d", (int) err); + else + { + err = SecTrustEvaluate(trust, NULL); + if (err) LogMsg("getCertChain: SecTrustEvaluate() returned %d", (int) err); + else + { + CFArrayRef rawCertChain; + CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL; + err = SecTrustGetResult(trust, NULL, &rawCertChain, &statusChain); + if (err || !rawCertChain || !statusChain) LogMsg("getCertChain: SecTrustGetResult() returned %d", (int) err); + else + { + certChain = CFArrayCreateMutableCopy(NULL, 0, rawCertChain); + if (!certChain) LogMsg("getCertChain: certChain is NULL"); + else + { + // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate: + // + CFArraySetValueAtIndex(certChain, 0, identity); + // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate + if (CFArrayGetCount(certChain) > 1) CFArrayRemoveValueAtIndex(certChain, CFArrayGetCount(certChain) - 1); + } + CFRelease(rawCertChain); + // Do not free statusChain: + // says: + // certChain: Call the CFRelease function to release this object when you are finished with it. + // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released... + } + } + CFRelease(trust); + } + CFRelease(wrappedCert); + } + CFRelease(policy); + } + CFRelease(searchRef); + } + CFRelease(cert); + } + return certChain; + } +#endif /* NO_SECURITYFRAMEWORK */ + +mDNSexport mStatus mDNSPlatformTLSSetupCerts(void) + { +#ifdef NO_SECURITYFRAMEWORK + return mStatus_UnsupportedErr; +#else + SecIdentityRef identity = nil; + SecIdentitySearchRef srchRef = nil; + OSStatus err; + + // search for "any" identity matching specified key use + // In this app, we expect there to be exactly one + err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_DECRYPT, &srchRef); + if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err); return err; } + + err = SecIdentitySearchCopyNext(srchRef, &identity); + if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err); return err; } + + if (CFGetTypeID(identity) != SecIdentityGetTypeID()) + { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr; } + + // Found one. Call getCertChain to create the correct certificate chain. + ServerCerts = GetCertChain(identity); + if (ServerCerts == nil) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: getCertChain error"); return mStatus_UnknownErr; } + + return mStatus_NoError; +#endif /* NO_SECURITYFRAMEWORK */ + } + +mDNSexport void mDNSPlatformTLSTearDownCerts(void) + { +#ifndef NO_SECURITYFRAMEWORK + if (ServerCerts) { CFRelease(ServerCerts); ServerCerts = NULL; } +#endif /* NO_SECURITYFRAMEWORK */ + } + +// This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel +mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel) + { + CFStringEncoding encoding = kCFStringEncodingUTF8; + CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding); + if (cfs) + { + CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8); + CFRelease(cfs); + } + } + +// This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel +mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel) + { + CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL); + if (cfs) + { + CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8); + CFRelease(cfs); + } + } + +mDNSlocal mDNSBool DDNSSettingEnabled(CFDictionaryRef dict) + { + mDNSs32 val; + CFNumberRef state = CFDictionaryGetValue(dict, CFSTR("Enabled")); + if (!state) return mDNSfalse; + if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val)) { LogMsg("ERROR: DDNSSettingEnabled - CFNumberGetValue"); return mDNSfalse; } + return val ? mDNStrue : mDNSfalse; + } + mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa) { if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); } @@ -2036,8 +1914,13 @@ mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa) if (sa->sa_family == AF_INET6) { struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa; - ip->type = mDNSAddrType_IPv6; + // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id + // value into the second word of the IPv6 link-local address, so they can just + // pass around IPv6 address structures instead of full sockaddr_in6 structures. + // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do. + // To work around this we always whack the second word of any IPv6 link-local address back to zero. if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0; + ip->type = mDNSAddrType_IPv6; ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr; return(mStatus_NoError); } @@ -2070,6 +1953,10 @@ mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name) return(eth); } +// Returns pointer to newly created NetworkInterfaceInfoOSX object, or +// pointer to already-existing NetworkInterfaceInfoOSX object found in list, or +// may return NULL if out of memory (unlikely) or parameters are invalid for some reason +// (e.g. sa_family not AF_INET or AF_INET6) mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa, mDNSs32 utc) { mDNSu32 scope_id = if_nametoindex(ifa->ifa_name); @@ -2085,53 +1972,435 @@ mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifad { debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, *p); (*p)->Exists = mDNStrue; + // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record + if ((*p)->LastSeen != utc) (*p)->AppearanceTime = utc; return(*p); } NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i)); debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i); if (!i) return(mDNSNULL); - bzero(i, sizeof(NetworkInterfaceInfoOSX)); + mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX)); i->ifa_name = (char *)mallocL("NetworkInterfaceInfoOSX name", strlen(ifa->ifa_name) + 1); if (!i->ifa_name) { freeL("NetworkInterfaceInfoOSX", i); return(mDNSNULL); } - strcpy(i->ifa_name, ifa->ifa_name); + strcpy(i->ifa_name, ifa->ifa_name); // This is safe because we know we allocated i->ifa_name with sufficient space i->ifinfo.InterfaceID = mDNSNULL; i->ifinfo.ip = ip; i->ifinfo.mask = mask; - strncpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname)); + strlcpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname)); i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0; i->ifinfo.Advertise = m->AdvertiseLocalAddresses; i->ifinfo.McastTxRx = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList - + i->next = mDNSNULL; i->Exists = mDNStrue; + i->AppearanceTime = utc; // Brand new interface; AppearanceTime is now i->LastSeen = utc; + i->Flashing = mDNSfalse; + i->Occulting = mDNSfalse; i->scope_id = scope_id; i->BSSID = bssid; i->sa_family = ifa->ifa_addr->sa_family; - i->Multicast = (ifa->ifa_flags & IFF_MULTICAST) && !(ifa->ifa_flags & IFF_POINTOPOINT); - - i->ss.m = m; - i->ss.info = i; - i->ss.sktv4 = i->ss.sktv6 = -1; - i->ss.cfsv4 = i->ss.cfsv6 = NULL; - i->ss.rlsv4 = i->ss.rlsv6 = NULL; + i->ifa_flags = ifa->ifa_flags; *p = i; return(i); } -mDNSlocal NetworkInterfaceInfoOSX *FindRoutableIPv4(mDNS *const m, mDNSu32 scope_id) +#if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4 +mDNSlocal NetworkInterfaceInfoOSX *FindRoutableIPv4(mDNS *const m, mDNSu32 scope_id) + { + NetworkInterfaceInfoOSX *i; + for (i = m->p->InterfaceList; i; i = i->next) + if (i->Exists && i->scope_id == scope_id && i->ifinfo.ip.type == mDNSAddrType_IPv4) + if (!mDNSv4AddressIsLinkLocal(&i->ifinfo.ip.ip.v4)) + return(i); + return(mDNSNULL); + } +#endif + +#if APPLE_OSX_mDNSResponder + +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - +#pragma mark - AutoTunnel +#endif + +#define kRacoonPort 4500 + +static mDNSBool AnonymousRacoonConfig = mDNSfalse; + +// MUST be called with lock held +mDNSlocal mDNSBool TunnelServers(mDNS *const m) + { + ServiceRecordSet *p; + for (p = m->ServiceRegistrations; p; p = p->uDNS_next) + { + DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, p->RR_SRV.resrec.name); + if (AuthInfo && AuthInfo->AutoTunnel && !AuthInfo->deltime) return(mDNStrue); + } + return(mDNSfalse); + } + +// MUST be called with lock held +mDNSlocal mDNSBool TunnelClients(mDNS *const m) + { + ClientTunnel *p; + for (p = m->TunnelClients; p; p = p->next) + if (p->q.ThisQInterval < 0) + return(mDNStrue); + return(mDNSfalse); + } + +mDNSlocal void RegisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info) + { + if (!info->AutoTunnelNAT.Result && !mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort) && AutoTunnelUnregistered(info)) + { + LogOperation("RegisterAutoTunnelRecords %##s", info->AutoTunnelService.namestorage.c); + mStatus err; + info->AutoTunnelService.resrec.rdata->u.srv.port = info->AutoTunnelNAT.ExternalPort; + info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeKnownUnique; + err = mDNS_Register(m, &info->AutoTunnelService); + if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c); + + info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeKnownUnique; + mDNS_Lock(m); + mDNS_AddDynDNSHostName(m, &info->AutoTunnelTarget.namestorage, mDNSNULL, info); + mDNS_Unlock(m); + + if (info->AutoTunnelHostRecord.namestorage.c[0] == 0) + { + AppendDomainLabel(&info->AutoTunnelHostRecord.namestorage, &m->hostlabel); + AppendDomainName (&info->AutoTunnelHostRecord.namestorage, &info->domain); + } + info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeKnownUnique; + err = mDNS_Register(m, &info->AutoTunnelHostRecord); + if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelHostRecord %##s", err, info->AutoTunnelHostRecord.namestorage.c); + + info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeKnownUnique; + err = mDNS_Register(m, &info->AutoTunnelDeviceInfo); + if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelDeviceInfo %##s", err, info->AutoTunnelDeviceInfo.namestorage.c); + + LogMsg("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]", + info->AutoTunnelTarget.namestorage.c, &m->AdvertisedV4.ip.v4, mDNSVal16(info->AutoTunnelNAT.IntPort), + info->AutoTunnelHostRecord.namestorage.c, &m->AutoTunnelHostAddr); + } + } + +mDNSlocal void DeregisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info) + { + LogOperation("DeregisterAutoTunnelRecords %##s", info->AutoTunnelService.namestorage.c); + if (info->AutoTunnelService.resrec.RecordType > kDNSRecordTypeDeregistering) + { + mStatus err = mDNS_Deregister(m, &info->AutoTunnelService); + if (err) + { + info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeUnregistered; + LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c); + } + + mDNS_Lock(m); + mDNS_RemoveDynDNSHostName(m, &info->AutoTunnelTarget.namestorage); + mDNS_Unlock(m); + } + + if (info->AutoTunnelHostRecord.resrec.RecordType > kDNSRecordTypeDeregistering) + { + mStatus err = mDNS_Deregister(m, &info->AutoTunnelHostRecord); + if (err) + { + info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeUnregistered; + LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelHostRecord %##s", err, info->AutoTunnelHostRecord.namestorage.c); + } + info->AutoTunnelHostRecord.namestorage.c[0] = 0; + } + + if (info->AutoTunnelDeviceInfo.resrec.RecordType > kDNSRecordTypeDeregistering) + { + mStatus err = mDNS_Deregister(m, &info->AutoTunnelDeviceInfo); + if (err) + { + info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeUnregistered; + LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelDeviceInfo %##s", err, info->AutoTunnelDeviceInfo.namestorage.c); + } + } + } + +mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result) + { + DomainAuthInfo *info = (DomainAuthInfo *)rr->RecordContext; + if (result == mStatus_MemFree) + { + LogOperation("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr)); + RegisterAutoTunnelRecords(m,info); + } + } + +mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n) + { + DomainAuthInfo *info = (DomainAuthInfo *)n->clientContext; + LogOperation("AutoTunnelNATCallback Result %d %.4a Internal %d External %d %##s", n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort), info->AutoTunnelService.namestorage.c); + + m->NextSRVUpdate = m->timenow; + DeregisterAutoTunnelRecords(m,info); + RegisterAutoTunnelRecords(m,info); + + // Determine whether we need racoon to accept incoming connections + for (info = m->AuthInfoList; info; info = info->next) + if (info->AutoTunnel && !info->deltime && !mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort)) + break; + mDNSBool needRacoonConfig = info != mDNSNULL; + if (needRacoonConfig != AnonymousRacoonConfig) + { + AnonymousRacoonConfig = needRacoonConfig; + // Create or revert configuration file, and start (or SIGHUP) Racoon + (void)mDNSConfigureServer(AnonymousRacoonConfig ? kmDNSUp : kmDNSDown, info ? info->b64keydata : ""); + } + } + +// Before SetupLocalAutoTunnelInterface_internal is called, +// m->AutoTunnelHostAddr.b[0] must be non-zero, and there must be at least one TunnelClient or TunnelServer +// Must be called with the lock held +mDNSexport void SetupLocalAutoTunnelInterface_internal(mDNS *const m) + { + LogOperation("SetupLocalAutoTunnelInterface"); + + // 1. Configure the local IPv6 address + if (!m->AutoTunnelHostAddrActive) + { + m->AutoTunnelHostAddrActive = mDNStrue; + LogMsg("Setting up AutoTunnel address %.16a", &m->AutoTunnelHostAddr); + (void)mDNSAutoTunnelInterfaceUpDown(kmDNSUp, m->AutoTunnelHostAddr.b); + } + + // 2. If we have at least one server (pending) listening, publish our records + if (TunnelServers(m)) + { + DomainAuthInfo *info; + for (info = m->AuthInfoList; info; info = info->next) + { + if (info->AutoTunnel && !info->deltime && !info->AutoTunnelNAT.clientContext) + { + // 1. Set up our address record for the internal tunnel address + // (User-visible user-friendly host name, used as target in AutoTunnel SRV records) + mDNS_SetupResourceRecord(&info->AutoTunnelHostRecord, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info); + info->AutoTunnelHostRecord.namestorage.c[0] = 0; + info->AutoTunnelHostRecord.resrec.rdata->u.ipv6 = m->AutoTunnelHostAddr; + + // 2. Set up device info record + mDNSu8 len = m->HIHardware.c[0] < 255 - 6 ? m->HIHardware.c[0] : 255 - 6; + mDNS_SetupResourceRecord(&info->AutoTunnelDeviceInfo, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info); + ConstructServiceName(&info->AutoTunnelDeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &info->domain); + mDNSPlatformMemCopy(info->AutoTunnelDeviceInfo.resrec.rdata->u.data + 1, "model=", 6); + mDNSPlatformMemCopy(info->AutoTunnelDeviceInfo.resrec.rdata->u.data + 7, m->HIHardware.c + 1, len); + info->AutoTunnelDeviceInfo.resrec.rdata->u.data[0] = 6 + len; // "model=" plus the device string + info->AutoTunnelDeviceInfo.resrec.rdlength = 7 + len; // One extra for the length byte at the start of the string + + // 3. Set up our address record for the external tunnel address + // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record) + mDNS_SetupResourceRecord(&info->AutoTunnelTarget, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info); + info->AutoTunnelTarget.namestorage.c[0] = 0; + AppendDomainLabel(&info->AutoTunnelTarget.namestorage, &m->AutoTunnelLabel); + AppendDomainName (&info->AutoTunnelTarget.namestorage, &info->domain); + + // 4. Set up IKE tunnel's SRV record: "AutoTunnelHostRecord SRV 0 0 port AutoTunnelTarget" + mDNS_SetupResourceRecord(&info->AutoTunnelService, mDNSNULL, mDNSInterface_Any, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info); + AssignDomainName(&info->AutoTunnelService.namestorage, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp"); + AppendDomainLabel(&info->AutoTunnelService.namestorage, &m->hostlabel); + AppendDomainName (&info->AutoTunnelService.namestorage, &info->domain); + info->AutoTunnelService.resrec.rdata->u.srv.priority = 0; + info->AutoTunnelService.resrec.rdata->u.srv.weight = 0; + AssignDomainName(&info->AutoTunnelService.resrec.rdata->u.srv.target, &info->AutoTunnelTarget.namestorage); + + // Try to get a NAT port mapping for the AutoTunnelService + info->AutoTunnelNAT.clientCallback = AutoTunnelNATCallback; + info->AutoTunnelNAT.clientContext = info; + info->AutoTunnelNAT.Protocol = NATOp_MapUDP; + info->AutoTunnelNAT.IntPort = mDNSOpaque16fromIntVal(kRacoonPort); + info->AutoTunnelNAT.RequestedPort = mDNSOpaque16fromIntVal(kRacoonPort); + info->AutoTunnelNAT.NATLease = 0; + mStatus err = mDNS_StartNATOperation_internal(m, &info->AutoTunnelNAT); + if (err) LogMsg("SetupLocalAutoTunnelInterface_internal error %d starting NAT mapping", err); + } + } + } + } + +mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew) + { + return(mDNSAutoTunnelSetKeys(AddNew ? kmDNSAutoTunnelSetKeysReplace : kmDNSAutoTunnelSetKeysDelete, tun->loc_inner.b, tun->loc_outer.b, kRacoonPort, tun->rmt_inner.b, tun->rmt_outer.b, mDNSVal16(tun->rmt_outer_port), tun->b64keydata)); + } + +// 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 ReissueBlockedQuestions(mDNS *const m, domainname *d, mDNSBool success) + { + DNSQuestion *q = m->Questions; + while (q) + { + if (q->NoAnswer == NoAnswer_Suspended && q->qtype == kDNSType_AAAA && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d)) + { + LogOperation("Restart %##s", q->qname.c); + mDNSQuestionCallback *tmp = q->QuestionCallback; + q->QuestionCallback = AutoTunnelCallback; // Set QuestionCallback to suppress another call back to AddNewClientTunnel + mDNS_StopQuery(m, q); + mDNS_StartQuery(m, q); + q->QuestionCallback = tmp; // Restore QuestionCallback back to the real value + if (!success) q->NoAnswer = NoAnswer_Fail; + // When we call mDNS_StopQuery, it's possible for other subbordinate questions like the GetZoneData query to be cancelled too. + // In general we have to assume that the question list might have changed in arbitrary ways. + // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is + // already in use. The safest solution is just to go back to the start of the list and start again. + // In principle this sounds like an n^2 algorithm, but in practice we almost always activate + // just one suspended question, so it's really a 2n algorithm. + q = m->Questions; + } + else + q = q->next; + } + } + +mDNSlocal void UnlinkAndReissueBlockedQuestions(mDNS *const m, ClientTunnel *tun, mDNSBool success) { - NetworkInterfaceInfoOSX *i; - for (i = m->p->InterfaceList; i; i = i->next) - if (i->Exists && i->scope_id == scope_id && i->ifinfo.ip.type == mDNSAddrType_IPv4) - if (!(i->ifinfo.ip.ip.v4.b[0] == 169 && i->ifinfo.ip.ip.v4.b[1] == 254)) - return(i); - return(mDNSNULL); + ClientTunnel **p = &m->TunnelClients; + while (*p != tun && *p) p = &(*p)->next; + if (*p) *p = tun->next; + ReissueBlockedQuestions(m, &tun->dstname, success); + freeL("ClientTunnel", tun); } +mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) + { + ClientTunnel *tun = (ClientTunnel *)question->QuestionContext; + LogOperation("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype); + + if (!AddRecord) return; + mDNS_StopQuery(m, question); + + if (!answer->rdlength) + { + LogOperation("AutoTunnelCallback NXDOMAIN %##s", question->qname.c); + UnlinkAndReissueBlockedQuestions(m, tun, mDNSfalse); + return; + } + + if (question->qtype == kDNSType_AAAA) + { + if (mDNSSameIPv6Address(answer->rdata->u.ipv6, m->AutoTunnelHostAddr)) + { + LogOperation("AutoTunnelCallback: supressing tunnel to self %.16a", &answer->rdata->u.ipv6); + UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue); + return; + } + + tun->rmt_inner = answer->rdata->u.ipv6; + LogOperation("AutoTunnelCallback: dst host %.16a", &tun->rmt_inner); + AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp"); + AppendDomainName(&question->qname, &tun->dstname); + question->qtype = kDNSType_SRV; + mDNS_StartQuery(m, &tun->q); + } + else if (question->qtype == kDNSType_SRV) + { + LogOperation("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c); + AssignDomainName(&tun->q.qname, &answer->rdata->u.srv.target); + tun->rmt_outer_port = answer->rdata->u.srv.port; + question->qtype = kDNSType_A; + mDNS_StartQuery(m, &tun->q); + } + else if (question->qtype == kDNSType_A) + { + ClientTunnel *old = mDNSNULL; + LogOperation("AutoTunnelCallback: SRV target addr %.4a", &answer->rdata->u.ipv4); + question->ThisQInterval = -1; // So we know this tunnel setup has completed + tun->rmt_outer = answer->rdata->u.ipv4; + tun->loc_inner = m->AutoTunnelHostAddr; + mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} }; + tmpDst.ip.v4 = tun->rmt_outer; + mDNSAddr tmpSrc = zeroAddr; + FindSourceAddrForIP(&tmpDst, &tmpSrc); + if (tmpSrc.type == mDNSAddrType_IPv4) tun->loc_outer = tmpSrc.ip.v4; + else tun->loc_outer = m->AdvertisedV4.ip.v4; + + ClientTunnel **p = &tun->next; + mDNSBool needSetKeys = mDNStrue; + while (*p) + { + if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next; + else + { + LogOperation("Found existing AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner); + old = *p; + *p = old->next; + if (old->q.ThisQInterval >= 0) mDNS_StopQuery(m, &old->q); + else if (!mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) || + !mDNSSameIPv4Address(old->loc_outer, tun->loc_outer) || + !mDNSSameIPv6Address(old->rmt_inner, tun->rmt_inner) || + !mDNSSameIPv4Address(old->rmt_outer, tun->rmt_outer) || + !mDNSSameIPPort(old->rmt_outer_port, tun->rmt_outer_port)) + { + LogOperation("Deleting existing AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner); + AutoTunnelSetKeys(old, mDNSfalse); + } + else needSetKeys = mDNSfalse; + + freeL("ClientTunnel", old); + } + } + + if (needSetKeys) LogOperation("New AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner); + + if (m->AutoTunnelHostAddr.b[0]) { mDNS_Lock(m); SetupLocalAutoTunnelInterface_internal(m); mDNS_Unlock(m); }; + + mStatus result = needSetKeys ? AutoTunnelSetKeys(tun, mDNStrue) : mStatus_NoError; + // Kick off any questions that were held pending this tunnel setup + ReissueBlockedQuestions(m, &tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse); + } + else + LogMsg("AutoTunnelCallback: Unknown question %p", question); + } + +// Must be called with the lock held +mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q) + { + ClientTunnel *p = mallocL("ClientTunnel", sizeof(ClientTunnel)); + if (!p) return; + AssignDomainName(&p->dstname, &q->qname); + p->markedForDeletion = mDNSfalse; + p->loc_inner = zerov6Addr; + p->loc_outer = zerov4Addr; + p->rmt_inner = zerov6Addr; + p->rmt_outer = zerov4Addr; + p->rmt_outer_port = zeroIPPort; + mDNS_snprintf(p->b64keydata, sizeof(p->b64keydata), "%s", q->AuthInfo->b64keydata); + p->next = m->TunnelClients; + m->TunnelClients = p; // Intentionally build list in reverse order + + p->q.InterfaceID = mDNSInterface_Any; + p->q.Target = zeroAddr; + AssignDomainName(&p->q.qname, &q->qname); + p->q.qtype = kDNSType_AAAA; + p->q.qclass = kDNSClass_IN; + p->q.LongLived = mDNSfalse; + p->q.ExpectUnique = mDNStrue; + p->q.ForceMCast = mDNSfalse; + p->q.ReturnIntermed = mDNStrue; + p->q.QuestionCallback = AutoTunnelCallback; + p->q.QuestionContext = p; + + LogOperation("AddNewClientTunnel start %##s (%s)%s", &p->q.qname.c, DNSTypeName(p->q.qtype), q->LongLived ? " LongLived" : ""); + mDNS_StartQuery_internal(m, &p->q); + } + +#endif // APPLE_OSX_mDNSResponder + +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - +#pragma mark - Power State & Configuration Change Management +#endif + mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc) { mDNSBool foundav4 = mDNSfalse; @@ -2141,8 +2410,10 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc) struct ifaddrs *v6Loopback = NULL; mDNSEthAddr PrimaryMAC = zeroEthAddr; char defaultname[32]; +#ifndef NO_IPV6 int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0); - if (InfoSocket < 3) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno)); + if (InfoSocket < 3 && errno != EAFNOSUPPORT) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno)); +#endif if (m->SleepState) ifa = NULL; while (ifa) @@ -2175,7 +2446,7 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc) { struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr; if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(PrimaryMAC) && mDNSSameEthAddress(&PrimaryMAC, &zeroEthAddr)) - mDNSPlatformMemCopy(sdl->sdl_data + sdl->sdl_nlen, PrimaryMAC.b, 6); + mDNSPlatformMemCopy(PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6); } if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr) @@ -2198,17 +2469,19 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc) else { int ifru_flags6 = 0; +#ifndef NO_IPV6 if (ifa->ifa_addr->sa_family == AF_INET6 && InfoSocket >= 0) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; struct in6_ifreq ifr6; - bzero((char *)&ifr6, sizeof(ifr6)); - strncpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name)); + mDNSPlatformMemZero((char *)&ifr6, sizeof(ifr6)); + strlcpy(ifr6.ifr_name, ifa->ifa_name, sizeof(ifr6.ifr_name)); ifr6.ifr_addr = *sin6; if (ioctl(InfoSocket, SIOCGIFAFLAG_IN6, &ifr6) != -1) ifru_flags6 = ifr6.ifr_ifru.ifru_flags6; verbosedebugf("%s %.16a %04X %04X", ifa->ifa_name, &sin6->sin6_addr, ifa->ifa_flags, ifru_flags6); } +#endif if (!(ifru_flags6 & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY))) { if (ifa->ifa_flags & IFF_LOOPBACK) @@ -2217,7 +2490,7 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc) else { NetworkInterfaceInfoOSX *i = AddInterfaceToList(m, ifa, utc); - if (i && i->Multicast) + if (i && MulticastInterface(i)) { if (ifa->ifa_addr->sa_family == AF_INET) foundav4 = mDNStrue; else foundav6 = mDNStrue; @@ -2229,32 +2502,59 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc) ifa = ifa->ifa_next; } - // For efficiency, we don't register a loopback interface when other interfaces of that family are available + // For efficiency, we don't register a loopback interface when other interfaces of that family are available if (!foundav4 && v4Loopback) AddInterfaceToList(m, v4Loopback, utc); if (!foundav6 && v6Loopback) AddInterfaceToList(m, v6Loopback, utc); // Now the list is complete, set the McastTxRx setting for each interface. - // We always send and receive using IPv4. - // To reduce traffic, we send and receive using IPv6 only on interfaces that have no routable IPv4 address. - // Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network, - // which means there's a good chance that most or all the other devices on that network should also have v4. - // By doing this we lose the ability to talk to true v6-only devices on that link, but we cut the packet rate in half. - // At this time, reducing the packet rate is more important than v6-only devices on a large configured network, - // so we are willing to make that sacrifice. NetworkInterfaceInfoOSX *i; for (i = m->p->InterfaceList; i; i = i->next) if (i->Exists) { - mDNSBool txrx = i->Multicast && ((i->ifinfo.ip.type == mDNSAddrType_IPv4) || !FindRoutableIPv4(m, i->scope_id)); + mDNSBool txrx = MulticastInterface(i); +#if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4 + txrx = txrx && ((i->ifinfo.ip.type == mDNSAddrType_IPv4) || !FindRoutableIPv4(m, i->scope_id)); +#endif if (i->ifinfo.McastTxRx != txrx) { i->ifinfo.McastTxRx = txrx; i->Exists = 2; // State change; need to deregister and reregister this interface } } + +#ifndef NO_IPV6 if (InfoSocket >= 0) close(InfoSocket); +#endif - mDNS_snprintf(defaultname, sizeof(defaultname), "Macintosh-%02X%02X%02X%02X%02X%02X", + // If we haven't set up AutoTunnelHostAddr yet, do it now + if (!mDNSSameEthAddress(&PrimaryMAC, &zeroEthAddr) && m->AutoTunnelHostAddr.b[0] == 0) + { + m->AutoTunnelHostAddr.b[0x0] = 0xFD; // Required prefix for "locally assigned" ULA (See RFC 4193) + m->AutoTunnelHostAddr.b[0x1] = mDNSRandom(255); + m->AutoTunnelHostAddr.b[0x2] = mDNSRandom(255); + m->AutoTunnelHostAddr.b[0x3] = mDNSRandom(255); + m->AutoTunnelHostAddr.b[0x4] = mDNSRandom(255); + m->AutoTunnelHostAddr.b[0x5] = mDNSRandom(255); + m->AutoTunnelHostAddr.b[0x6] = mDNSRandom(255); + m->AutoTunnelHostAddr.b[0x7] = mDNSRandom(255); + m->AutoTunnelHostAddr.b[0x8] = PrimaryMAC.b[0] ^ 0x02; // See RFC 3513, Appendix A for explanation + m->AutoTunnelHostAddr.b[0x9] = PrimaryMAC.b[1]; + m->AutoTunnelHostAddr.b[0xA] = PrimaryMAC.b[2]; + m->AutoTunnelHostAddr.b[0xB] = 0xFF; + m->AutoTunnelHostAddr.b[0xC] = 0xFE; + m->AutoTunnelHostAddr.b[0xD] = PrimaryMAC.b[3]; + m->AutoTunnelHostAddr.b[0xE] = PrimaryMAC.b[4]; + m->AutoTunnelHostAddr.b[0xF] = PrimaryMAC.b[5]; + m->AutoTunnelLabel.c[0] = mDNS_snprintf((char*)m->AutoTunnelLabel.c+1, 254, "AutoTunnel-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X", + m->AutoTunnelHostAddr.b[0x8], m->AutoTunnelHostAddr.b[0x9], m->AutoTunnelHostAddr.b[0xA], m->AutoTunnelHostAddr.b[0xB], + m->AutoTunnelHostAddr.b[0xC], m->AutoTunnelHostAddr.b[0xD], m->AutoTunnelHostAddr.b[0xE], m->AutoTunnelHostAddr.b[0xF]); + LogOperation("m->AutoTunnelLabel %#s", m->AutoTunnelLabel.c); + } + + #ifndef kDefaultLocalHostNamePrefix + #define kDefaultLocalHostNamePrefix "Macintosh" + #endif + mDNS_snprintf(defaultname, sizeof(defaultname), kDefaultLocalHostNamePrefix "-%02X%02X%02X%02X%02X%02X", PrimaryMAC.b[0], PrimaryMAC.b[1], PrimaryMAC.b[2], PrimaryMAC.b[3], PrimaryMAC.b[4], PrimaryMAC.b[5]); // Set up the nice label @@ -2277,19 +2577,23 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc) MakeDomainLabelFromLiteralString(&hostlabel, defaultname); } - if (SameDomainLabel(m->p->usernicelabel.c, nicelabel.c)) + // We use a case-sensitive comparison here because even though changing the capitalization + // of the name alone is not significant to DNS, it's still a change from the user's point of view + if (SameDomainLabelCS(m->p->usernicelabel.c, nicelabel.c)) debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m->p->usernicelabel.c, m->nicelabel.c); else { - debugf("Updating m->nicelabel to %#s", nicelabel.c); + if (m->p->usernicelabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot + LogMsg("User updated Computer Name from %#s to %#s", m->p->usernicelabel.c, nicelabel.c); m->p->usernicelabel = m->nicelabel = nicelabel; } - if (SameDomainLabel(m->p->userhostlabel.c, hostlabel.c)) + if (SameDomainLabelCS(m->p->userhostlabel.c, hostlabel.c)) debugf("Userhostlabel (%#s) unchanged since last time; not changing m->hostlabel (%#s)", m->p->userhostlabel.c, m->hostlabel.c); else { - debugf("Updating m->hostlabel to %#s", hostlabel.c); + if (m->p->userhostlabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot + LogMsg("User updated Local Hostname from %#s to %#s", m->p->userhostlabel.c, hostlabel.c); m->p->userhostlabel = m->hostlabel = hostlabel; mDNS_SetFQDN(m); } @@ -2297,6 +2601,9 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc) return(mStatus_NoError); } +#if LogAllOperations || MDNS_DEBUGMSGS +// Returns number of leading one-bits in mask: 0-32 for IPv4, 0-128 for IPv6 +// Returns -1 if all the one-bits are not contiguous mDNSlocal int CountMaskBits(mDNSAddr *mask) { int i = 0, bits = 0; @@ -2310,6 +2617,7 @@ mDNSlocal int CountMaskBits(mDNSAddr *mask) while (i < bytes) if (mask->ip.v6.b[i++]) return(-1); return(bits); } +#endif // returns count of non-link local V4 addresses registered mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc) @@ -2322,13 +2630,13 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc) NetworkInterfaceInfo *n = &i->ifinfo; NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, i->sa_family); if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifa_name); - + if (n->InterfaceID && n->InterfaceID != (mDNSInterfaceID)primary) // Sanity check { LogMsg("SetupActiveInterfaces ERROR! n->InterfaceID %p != primary %p", n->InterfaceID, primary); n->InterfaceID = mDNSNULL; } - + if (!n->InterfaceID) { // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface, @@ -2338,31 +2646,43 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc) // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away. // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds. // If the interface is an old one that went away and came back in less than a minute, then we're in a flapping scenario. - mDNSBool flapping = (utc - i->LastSeen > 0 && utc - i->LastSeen < 60); - mDNS_RegisterInterface(m, n, flapping ? mDNSPlatformOneSecond * 5 : 0); - if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && (i->ifinfo.ip.ip.v4.b[0] != 169 || i->ifinfo.ip.ip.v4.b[1] != 254)) count++; - LogOperation("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s", + i->Occulting = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->LastSeen > 0 && utc - i->LastSeen < 60); + mDNS_RegisterInterface(m, n, i->Flashing && i->Occulting); + if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++; + LogOperation("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s", i->ifa_name, i->scope_id, &i->BSSID, primary, &n->ip, CountMaskBits(&n->mask), - flapping ? " (Flapping)" : "", n->InterfaceActive ? " (Primary)" : ""); + i->Flashing ? " (Flashing)" : "", + i->Occulting ? " (Occulting)" : "", + n->InterfaceActive ? " (Primary)" : ""); } - + if (!n->McastTxRx) debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i->ifa_name, i->scope_id, &i->BSSID, primary, &n->ip); else { - if (i->sa_family == AF_INET && primary->ss.sktv4 == -1) + if (i->sa_family == AF_INET) { - mStatus err = SetupSocket(m, &primary->ss, mDNStrue, &i->ifinfo.ip, AF_INET); - if (err == 0) debugf("SetupActiveInterfaces: v4 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d", primary->ss.sktv4, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask)); - else LogMsg("SetupActiveInterfaces: v4 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d FAILED", primary->ss.sktv4, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask)); + struct ip_mreq imr; + primary->ifa_v4addr.s_addr = i->ifinfo.ip.ip.v4.NotAnInteger; + imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger; + imr.imr_interface = primary->ifa_v4addr; + mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr)); + // Joining same group twice can give "Address already in use" error -- no need to report that + if (err < 0 && errno != EADDRINUSE) + LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %ld errno %d (%s)", err, errno, strerror(errno)); } - - if (i->sa_family == AF_INET6 && primary->ss.sktv6 == -1) +#ifndef NO_IPV6 + if (i->sa_family == AF_INET6) { - mStatus err = SetupSocket(m, &primary->ss, mDNStrue, &i->ifinfo.ip, AF_INET6); - if (err == 0) debugf("SetupActiveInterfaces: v6 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d", primary->ss.sktv6, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask)); - else LogMsg("SetupActiveInterfaces: v6 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d FAILED", primary->ss.sktv6, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask)); + struct ipv6_mreq i6mr; + i6mr.ipv6mr_interface = primary->scope_id; + i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6; + mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr)); + // Joining same group twice can give "Address already in use" error -- no need to report that + if (err < 0 && errno != EADDRINUSE) + LogMsg("setsockopt - IPV6_JOIN_GROUP error %ld errno %d (%s)", err, errno, strerror(errno)); } +#endif } } return count; @@ -2378,28 +2698,6 @@ mDNSlocal void MarkAllInterfacesInactive(mDNS *const m, mDNSs32 utc) } } -mDNSlocal void CloseRunLoopSourceSocket(CFRunLoopSourceRef rls, CFSocketRef cfs) - { - // Note: CFSocketInvalidate also closes the underlying socket for us - // Comments show retain counts (obtained via CFGetRetainCount()) after each call. rls 3 cfs 3 - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); // rls 2 cfs 3 - CFRelease(rls); // rls ? cfs 3 - CFSocketInvalidate(cfs); // rls ? cfs 1 - CFRelease(cfs); // rls ? cfs ? - } - -mDNSlocal void CloseSocketSet(CFSocketSet *ss) - { - // Note: MUST NOT close the underlying native BSD sockets. - // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, - // because it first has to unhook the sockets from its select() call, before it can safely close them. - if (ss->cfsv4) CloseRunLoopSourceSocket(ss->rlsv4, ss->cfsv4); - if (ss->cfsv6) CloseRunLoopSourceSocket(ss->rlsv6, ss->cfsv6); - ss->sktv4 = ss->sktv6 = -1; - ss->cfsv4 = ss->cfsv6 = NULL; - ss->rlsv4 = ss->rlsv6 = NULL; - } - // returns count of non-link local V4 addresses deregistered mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc) { @@ -2414,16 +2712,20 @@ mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc) int count = 0; for (i = m->p->InterfaceList; i; i = i->next) { - // 1. If this interface is no longer active, or its InterfaceID is changing, deregister it + // If this interface is no longer active, or its InterfaceID is changing, deregister it NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, i->sa_family); if (i->ifinfo.InterfaceID) if (i->Exists == 0 || i->Exists == 2 || i->ifinfo.InterfaceID != (mDNSInterfaceID)primary) { - LogOperation("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a/%d%s", + i->Flashing = !(i->ifa_flags & IFF_LOOPBACK) && (utc - i->AppearanceTime < 60); + LogOperation("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s", i->ifa_name, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, - &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), i->ifinfo.InterfaceActive ? " (Primary)" : ""); - mDNS_DeregisterInterface(m, &i->ifinfo); - if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && (i->ifinfo.ip.ip.v4.b[0] != 169 || i->ifinfo.ip.ip.v4.b[1] != 254)) count++; + &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), + i->Flashing ? " (Flashing)" : "", + i->Occulting ? " (Occulting)" : "", + i->ifinfo.InterfaceActive ? " (Primary)" : ""); + mDNS_DeregisterInterface(m, &i->ifinfo, i->Flashing && i->Occulting); + if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++; i->ifinfo.InterfaceID = mDNSNULL; // NOTE: If n->InterfaceID 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. @@ -2437,10 +2739,7 @@ mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc) while (*p) { i = *p; - // 2. Close all our CFSockets. We'll recreate them later as necessary. - // (We may have previously had both v4 and v6, and we may not need both any more.) - CloseSocketSet(&i->ss); - // 3. If no longer active, delete interface from list and free memory + // If no longer active, delete interface from list and free memory if (!i->Exists) { if (i->LastSeen == utc) i->LastSeen = utc - 1; @@ -2462,684 +2761,431 @@ mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc) return count; } -mDNSlocal mStatus GetDNSConfig(void **result) +mDNSlocal void AppendDNameListElem(DNameListElem ***List, mDNSu32 uid, domainname *name) { -#if MDNS_NO_DNSINFO - static int MessageShown = 0; - if (!MessageShown) { MessageShown = 1; LogMsg("Note: Compiled without Apple-specific Split-DNS support"); } - *result = NULL; - return mStatus_UnsupportedErr; -#else - - *result = dns_configuration_copy(); - - if (!*result) + DNameListElem *dnle = (DNameListElem*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem)); + if (!dnle) LogMsg("ERROR: AppendDNameListElem: memory exhausted"); + else { - // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed - if (mDNSMacOSXSystemBuildNumber(NULL) < 8) return mStatus_UnsupportedErr; - - // On 10.4, calls to dns_configuration_copy() early in the boot process often fail. - // Apparently this is expected behaviour -- "not a bug". - // Accordingly, we suppress syslog messages for the first three minutes after boot. - // If we are still getting failures after three minutes, then we log them. - if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return mStatus_NoError; - - LogMsg("GetDNSConfig: Error: dns_configuration_copy returned NULL"); - return mStatus_UnknownErr; + dnle->next = mDNSNULL; + dnle->uid = uid; + AssignDomainName(&dnle->name, name); + **List = dnle; + *List = &dnle->next; } - return mStatus_NoError; -#endif // MDNS_NO_DNSINFO } -mDNSlocal mStatus RegisterSplitDNS(mDNS *m, int *nAdditions, int *nDeletions) +mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains) { - (void)m; // unused on 10.3 systems - void *v; - *nAdditions = *nDeletions = 0; - mStatus err = GetDNSConfig(&v); + int i; + char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL + domainname d; -#if !MDNS_NO_DNSINFO - if (!err && v) - { - int i; - DNSServer *p; - dns_config_t *config = v; // use void * to allow compilation on 10.3 systems - mDNS_Lock(m); - p = m->uDNS_info.Servers; - while (p) { p->del = mDNStrue; p = p->next; } // mark all for deletion - - LogOperation("RegisterSplitDNS: Registering %d resolvers", config->n_resolver); - for (i = 0; i < config->n_resolver; i++) - { - int j, n; - domainname d; - dns_resolver_t *r = config->resolver[i]; - if (r->port == MulticastDNSPort.NotAnInteger) continue; // ignore configurations for .local - if (r->search_order == DEFAULT_SEARCH_ORDER || !r->domain || !*r->domain) d.c[0] = 0; // we ignore domain for "default" resolver - else if (!MakeDomainNameFromDNSNameString(&d, r->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", r->domain); continue; } - - // check if this is the lowest-weighted server for the domain - for (j = 0; j < config->n_resolver; j++) - { - dns_resolver_t *p = config->resolver[j]; - if (p->port == MulticastDNSPort.NotAnInteger) continue; - if (p->search_order <= r->search_order) - { - domainname tmp; - if (p->search_order == DEFAULT_SEARCH_ORDER || !p->domain || !*p->domain) tmp.c[0] = '\0'; - else if (!MakeDomainNameFromDNSNameString(&tmp, p->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", p->domain); continue; } - if (SameDomainName(&d, &tmp)) - if (p->search_order < r->search_order || j < i) break; // if equal weights, pick first in list, otherwise pick lower-weight (p) - } - } - if (j < config->n_resolver) // found a lower-weighted resolver for this domain - { debugf("Rejecting DNS server in slot %d domain %##s (slot %d outranks)", i, d.c, j); continue; } - // we're using this resolver - find the first IPv4 address - for (n = 0; n < r->n_nameserver; n++) - { - if (r->nameserver[n]->sa_family == AF_INET && !AddrRequiresPPPConnection(r->nameserver[n])) - { - // %%% This should use mDNS_AddDNSServer() instead of duplicating functionality here - mDNSAddr saddr; - if (SetupAddr(&saddr, r->nameserver[n])) { LogMsg("RegisterSplitDNS: bad IP address"); continue; } - // mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 192, 168, 1, 1 } } } }; // for testing - debugf("Adding dns server from slot %d %d.%d.%d.%d for domain %##s", i, saddr.ip.v4.b[0], saddr.ip.v4.b[1], saddr.ip.v4.b[2], saddr.ip.v4.b[3], d.c); - p = m->uDNS_info.Servers; - while (p) - { - if (mDNSSameAddress(&p->addr, &saddr) && SameDomainName(&p->domain, &d)) { p->del = mDNSfalse; break; } - else p = p->next; - } - if (!p) - { - p = mallocL("DNSServer", sizeof(*p)); - if (!p) { LogMsg("Error: malloc"); mDNS_Unlock(m); return mStatus_UnknownErr; } - p->addr = saddr; - p->del = mDNSfalse; - p->teststate = DNSServer_Untested; - AssignDomainName(&p->domain, &d); - p->next = m->uDNS_info.Servers; - m->uDNS_info.Servers = p; - (*nAdditions)++; - } - break; // !!!KRS if we ever support round-robin servers, don't break here - } - } - } + // Need to set these here because we need to do this even if SCDynamicStoreCreate() or SCDynamicStoreCopyValue() below don't succeed + if (fqdn) fqdn->c[0] = 0; + if (RegDomains ) *RegDomains = NULL; + if (BrowseDomains) *BrowseDomains = NULL; + + LogOperation("mDNSPlatformSetDNSConfig%s%s%s%s%s", + setservers ? " setservers" : "", + setsearch ? " setsearch" : "", + fqdn ? " fqdn" : "", + RegDomains ? " RegDomains" : "", + BrowseDomains ? " BrowseDomains" : ""); - // remove all servers marked for deletion - DNSServer **s = &m->uDNS_info.Servers; - while (*s) + // Add the inferred address-based configuration discovery domains + // (should really be in core code I think, not platform-specific) + if (setsearch) + { + struct ifaddrs *ifa = myGetIfAddrs(1); + while (ifa) { - if ((*s)->del) + mDNSAddr a, n; + if (ifa->ifa_addr->sa_family == AF_INET && + ifa->ifa_netmask && + !(ifa->ifa_flags & IFF_LOOPBACK) && + !SetupAddr(&a, ifa->ifa_addr) && + !SetupAddr(&n, ifa->ifa_netmask) && + !mDNSv4AddressIsLinkLocal(&a.ip.v4) ) { - p = *s; - *s = (*s)->next; - freeL("DNSServer", p); - (*nDeletions)--; + // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code + mDNS_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa.", a.ip.v4.b[3] & n.ip.v4.b[3], + a.ip.v4.b[2] & n.ip.v4.b[2], + a.ip.v4.b[1] & n.ip.v4.b[1], + a.ip.v4.b[0] & n.ip.v4.b[0]); + mDNS_AddSearchDomain_CString(buf); } - else s = &(*s)->next; + ifa = ifa->ifa_next; } - mDNS_Unlock(m); - dns_configuration_free(config); } -#endif - - return err; - } - -mDNSlocal mStatus RegisterNameServers(mDNS *const m, CFDictionaryRef dict) - { - int i, count; - CFArrayRef values; - char buf[256]; - mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 0 } } } }; - CFStringRef s; - mDNS_DeleteDNSServers(m); // deregister orig list - values = CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses); - if (!values) return mStatus_NoError; - - count = CFArrayGetCount(values); - for (i = 0; i < count; i++) +#ifndef MDNS_NO_DNSINFO + if (setservers || setsearch) { - s = CFArrayGetValueAtIndex(values, i); - if (!s) { LogMsg("ERROR: RegisterNameServers - CFArrayGetValueAtIndex"); break; } - if (!CFStringGetCString(s, buf, 256, kCFStringEncodingUTF8)) - { - LogMsg("ERROR: RegisterNameServers - CFStringGetCString"); - continue; - } - if (!inet_aton(buf, (struct in_addr *)saddr.ip.v4.b)) - { - LogMsg("ERROR: RegisterNameServers - invalid address string %s", buf); - continue; - } - LogOperation("RegisterNameServers: Adding %#a", &saddr); - mDNS_AddDNSServer(m, &saddr, NULL); - } - return mStatus_NoError; - } - -mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result) - { - (void)m; // unused - ARListElem *elem = rr->RecordContext; - if (result == mStatus_MemFree) freeL("FreeARElemCallback", elem); - } - -mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) - { - SearchListElem *slElem = question->QuestionContext; - ARListElem *arElem, *ptr, *prev; - AuthRecord *dereg; - const char *name; - mStatus err; - - if (AddRecord) - { - arElem = mallocL("FoundDomain - arElem", sizeof(ARListElem)); - if (!arElem) { LogMsg("ERROR: malloc"); return; } - mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, FreeARElemCallback, arElem); - if (question == &slElem->BrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowse]; - else if (question == &slElem->DefBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault]; - else if (question == &slElem->LegacyBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseLegacy]; - else if (question == &slElem->RegisterQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistration]; - else if (question == &slElem->DefRegisterQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistrationDefault]; - else { LogMsg("FoundDomain - unknown question"); return; } - - MakeDomainNameFromDNSNameString(arElem->ar.resrec.name, name); - AppendDNSNameString (arElem->ar.resrec.name, "local"); - AssignDomainName(&arElem->ar.resrec.rdata->u.name, &answer->rdata->u.name); - err = mDNS_Register(m, &arElem->ar); - if (err) + dns_config_t *config = dns_configuration_copy(); + if (!config) { - LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err); - freeL("FoundDomain - arElem", arElem); - return; + // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed + // On 10.4, calls to dns_configuration_copy() early in the boot process often fail. + // Apparently this is expected behaviour -- "not a bug". + // Accordingly, we suppress syslog messages for the first three minutes after boot. + // If we are still getting failures after three minutes, then we log them. + if (mDNSMacOSXSystemBuildNumber(NULL) > 7 && (mDNSu32)mDNSPlatformRawTime() > (mDNSu32)(mDNSPlatformOneSecond * 180)) + LogMsg("GetDNSConfig: Error: dns_configuration_copy returned NULL"); } - arElem->next = slElem->AuthRecs; - slElem->AuthRecs = arElem; - } - else - { - ptr = slElem->AuthRecs; - prev = NULL; - while (ptr) + else { - if (SameDomainName(&ptr->ar.resrec.rdata->u.name, &answer->rdata->u.name)) + LogOperation("mDNSPlatformSetDNSConfig: Registering %d resolvers", config->n_resolver); + if (setservers) { - debugf("Deregistering PTR %##s -> %##s", ptr->ar.resrec.name->c, ptr->ar.resrec.rdata->u.name.c); - dereg = &ptr->ar; - if (prev) prev->next = ptr->next; - else slElem->AuthRecs = ptr->next; - ptr = ptr->next; - err = mDNS_Deregister(m, dereg); - if (err) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err); + for (i = 0; i < config->n_resolver; i++) + { + int j, n; + dns_resolver_t *r = config->resolver[i]; + // Ignore dnsinfo entries for mDNS domains (indicated by the fact that the resolver port is 5353, the mDNS port) + // Note: Unlike the BSD Sockets APIs (where TCP and UDP port numbers are universally in network byte order) + // in Apple's "dnsinfo.h" API the port number is declared to be a "uint16_t in host byte order" + if (r->port == 5353) continue; + if (r->search_order == DEFAULT_SEARCH_ORDER || !r->domain || !*r->domain) d.c[0] = 0; // we ignore domain for "default" resolver + else if (!MakeDomainNameFromDNSNameString(&d, r->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", r->domain); continue; } + + for (j = 0; j < config->n_resolver; j++) // check if this is the lowest-weighted server for the domain + { + dns_resolver_t *p = config->resolver[j]; + if (p->port == 5353) continue; // Note: dns_resolver_t port is defined to be "uint16_t in host byte order" + if (p->search_order <= r->search_order) + { + domainname tmp; + if (p->search_order == DEFAULT_SEARCH_ORDER || !p->domain || !*p->domain) tmp.c[0] = '\0'; + else if (!MakeDomainNameFromDNSNameString(&tmp, p->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", p->domain); continue; } + if (SameDomainName(&d, &tmp)) + if (p->search_order < r->search_order || j < i) break; // if equal weights, pick first in list, otherwise pick lower-weight (p) + } + } + if (j < config->n_resolver) // found a lower-weighted resolver for this domain + debugf("Rejecting DNS server in slot %d domain %##s (slot %d outranks)", i, d.c, j); + else + { + mDNSInterfaceID interface = mDNSInterface_Any; + int disabled = 0; + + // DNS server option parsing + if (r->options != NULL) + { + char *nextOption = r->options; + char *currentOption = NULL; + while ((currentOption = strsep(&nextOption, " ")) != NULL && currentOption[0] != 0) + { + // The option may be in the form of interface=xxx where xxx is an interface name. + if (strncmp(currentOption, kInterfaceSpecificOption, sizeof(kInterfaceSpecificOption) - 1) == 0) + { + NetworkInterfaceInfoOSX *i; + char ifname[IF_NAMESIZE+1]; + mDNSu32 ifindex = 0; + // If something goes wrong finding the interface, create the server entry anyhow but mark it as disabled. + // This allows us to block these special queries from going out on the wire. + strlcpy(ifname, currentOption + sizeof(kInterfaceSpecificOption)-1, sizeof(ifname)); + ifindex = if_nametoindex(ifname); + if (ifindex == 0) { disabled = 1; LogMsg("RegisterSplitDNS: interfaceSpecific - interface %s not found", ifname); continue; } + LogOperation("%s: Interface specific entry: %s on %s (%d)", __FUNCTION__, r->domain, ifname, ifindex); + // Find the interface, can't use mDNSPlatformInterfaceIDFromInterfaceIndex + // because that will call mDNSMacOSXNetworkChanged if the interface doesn't exist + for (i = m->p->InterfaceList; i; i = i->next) + if (i->ifinfo.InterfaceID && i->scope_id == ifindex) break; + if (i != NULL) interface = i->ifinfo.InterfaceID; + if (interface == mDNSNULL) { disabled = 1; LogMsg("RegisterSplitDNS: interfaceSpecific - index %d (%s) not found", ifindex, ifname); continue; } + } + } + } + for (n = 0; n < r->n_nameserver; n++) + if (r->nameserver[n]->sa_family == AF_INET && (interface || disabled || !AddrRequiresPPPConnection(r->nameserver[n]))) + { + mDNSAddr saddr; + // mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 192, 168, 1, 1 } } } }; // for testing + debugf("Adding dns server from slot %d %#a for domain %##s", i, &saddr, d.c); + if (SetupAddr(&saddr, r->nameserver[n])) LogMsg("RegisterSplitDNS: bad IP address"); + else + { + DNSServer *s = mDNS_AddDNSServer(m, &d, mDNSInterface_Any, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort); + if (s && disabled) s->teststate = DNSServer_Disabled; + } + } + } + } } - else + if (setsearch) { - prev = ptr; - ptr = ptr->next; + // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains + // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if + // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and + // instead use the search domain list as the sole authority for what domains to search and in what order + // (and the domain from the "domain" field will also appear somewhere in that list). + // Also, all search domains get added to the search list for resolver[0], so the domains and/or + // search lists for other resolvers in the list need to be ignored. + if (config->resolver[0]->n_search == 0) mDNS_AddSearchDomain_CString(config->resolver[0]->domain); + else for (i = 0; i < config->resolver[0]->n_search; i++) mDNS_AddSearchDomain_CString(config->resolver[0]->search[i]); } + dns_configuration_free(config); + setservers = mDNSfalse; // Done these now -- no need to fetch the same data from SCDynamicStore + setsearch = mDNSfalse; } } - } - -mDNSlocal void MarkSearchListElem(const char *d) - { - SearchListElem *new, *ptr; - domainname domain; - - if (!MakeDomainNameFromDNSNameString(&domain, d)) - { LogMsg("ERROR: MarkSearchListElem - bad domain %##s", d); return; } - - if (SameDomainName(&domain, &localdomain) || SameDomainName(&domain, &LocalReverseMapomain)) - { debugf("MarkSearchListElem - ignoring local domain %##s", domain.c); return; } - - // if domain is in list, mark as pre-existent (0) - for (ptr = SearchList; ptr; ptr = ptr->next) - if (SameDomainName(&ptr->domain, &domain)) - { - if (ptr->flag != 1) ptr->flag = 0; // gracefully handle duplicates - if it is already marked as add, don't bump down to preexistent - break; - } - - // if domain not in list, add to list, mark as add (1) - if (!ptr) - { - new = mallocL("MarkSearchListElem - SearchListElem", sizeof(SearchListElem)); - if (!new) { LogMsg("ERROR: MarkSearchListElem - malloc"); return; } - bzero(new, sizeof(SearchListElem)); - AssignDomainName(&new->domain, &domain); - new->flag = 1; // add - new->next = SearchList; - SearchList = new; - } - } - -// Get the search domains via OS X resolver routines. Returns mStatus_UnsupporterErr if compiled or run on 10.3 systems -mDNSlocal mStatus GetSearchDomains(void) - { - void *v; - mStatus err = GetDNSConfig(&v); - -#if !MDNS_NO_DNSINFO - if (!err && v) - { - int i; - dns_config_t *config = v; - if (!config->n_resolver) return err; - dns_resolver_t *resolv = config->resolver[0]; // use the first slot for search domains - - for (i = 0; i < resolv->n_search; i++) MarkSearchListElem(resolv->search[i]); - if (resolv->domain) MarkSearchListElem(resolv->domain); - dns_configuration_free(config); - } -#endif - - return err; - } - -// Get search domains from dynamic store - used as a fallback mechanism on 10.3 systems, if GetSearchDomains (above) fails. -mDNSlocal void GetDSSearchDomains(CFDictionaryRef dict) - { - char buf[MAX_ESCAPED_DOMAIN_NAME]; - int i, count; - - CFStringRef s; +#endif // MDNS_NO_DNSINFO - // get all the domains from "Search Domains" field of sharing prefs - if (dict) + SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformSetDNSConfig"), NULL, NULL); + if (store) { - CFArrayRef searchdomains = CFDictionaryGetValue(dict, kSCPropNetDNSSearchDomains); - if (searchdomains) + CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DynamicDNS); + if (dict) { - count = CFArrayGetCount(searchdomains); - for (i = 0; i < count; i++) + if (fqdn) { - s = CFArrayGetValueAtIndex(searchdomains, i); - if (!s) { LogMsg("ERROR: GetDSSearchDomains - CFArrayGetValueAtIndex"); break; } - if (!CFStringGetCString(s, buf, MAX_ESCAPED_DOMAIN_NAME, kCFStringEncodingUTF8)) + CFArrayRef fqdnArray = CFDictionaryGetValue(dict, CFSTR("HostNames")); + if (fqdnArray && CFArrayGetCount(fqdnArray) > 0) { - LogMsg("ERROR: GetDSSearchDomains - CFStringGetCString"); - continue; + // for now, we only look at the first array element. if we ever support multiple configurations, we will walk the list + CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0); + if (fqdnDict && DDNSSettingEnabled(fqdnDict)) + { + CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain")); + if (name) + { + if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) || + !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0]) + LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)"); + else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf); + } + } } - MarkSearchListElem(buf); } - } - - // get DHCP domain field - CFStringRef dname = CFDictionaryGetValue(dict, kSCPropNetDNSDomainName); - if (dname) - { - if (CFStringGetCString(dname, buf, MAX_ESCAPED_DOMAIN_NAME, kCFStringEncodingUTF8)) - MarkSearchListElem(buf); - else LogMsg("ERROR: GetDSSearchDomains - CFStringGetCString"); - } - } - } -mDNSlocal mStatus RegisterSearchDomains(mDNS *const m, CFDictionaryRef dict) - { - struct ifaddrs *ifa = NULL; - SearchListElem *ptr, *prev, *freeSLPtr; - ARListElem *arList; - mStatus err; - - if (DomainDiscoveryDisabled) return mStatus_NoError; - - // step 1: mark each elem for removal (-1), unless we aren't passed a dictionary in which case we mark as preexistent - for (ptr = SearchList; ptr; ptr = ptr->next) ptr->flag = dict ? -1 : 0; - - // Get search domains from resolver library (available in OS X 10.4 and later), reverting to dynamic store on 10.3 systems - if (GetSearchDomains() == mStatus_UnsupportedErr) GetDSSearchDomains(dict); - - // Construct reverse-map search domains - ifa = myGetIfAddrs(1); - while (ifa) - { - mDNSAddr addr; - if (ifa->ifa_addr->sa_family == AF_INET && !SetupAddr(&addr, ifa->ifa_addr) && !IsPrivateV4Addr(&addr) && !(ifa->ifa_flags & IFF_LOOPBACK) && ifa->ifa_netmask) - { - mDNSAddr netmask; - char buffer[256]; - if (!SetupAddr(&netmask, ifa->ifa_netmask)) - { - sprintf(buffer, "%d.%d.%d.%d.in-addr.arpa.", addr.ip.v4.b[3] & netmask.ip.v4.b[3], - addr.ip.v4.b[2] & netmask.ip.v4.b[2], - addr.ip.v4.b[1] & netmask.ip.v4.b[1], - addr.ip.v4.b[0] & netmask.ip.v4.b[0]); - MarkSearchListElem(buffer); - } - } - ifa = ifa->ifa_next; - } - - // delete elems marked for removal, do queries for elems marked add - prev = NULL; - ptr = SearchList; - while (ptr) - { - if (ptr->flag == -1) // remove - { - mDNS_StopQuery(m, &ptr->BrowseQ); - mDNS_StopQuery(m, &ptr->RegisterQ); - mDNS_StopQuery(m, &ptr->DefBrowseQ); - mDNS_StopQuery(m, &ptr->DefRegisterQ); - mDNS_StopQuery(m, &ptr->LegacyBrowseQ); - - // deregister records generated from answers to the query - arList = ptr->AuthRecs; - ptr->AuthRecs = NULL; - while (arList) + if (RegDomains) { - AuthRecord *dereg = &arList->ar; - arList = arList->next; - debugf("Deregistering PTR %##s -> %##s", dereg->resrec.name->c, dereg->resrec.rdata->u.name.c); - err = mDNS_Deregister(m, dereg); - if (err) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err); + CFArrayRef regArray = CFDictionaryGetValue(dict, CFSTR("RegistrationDomains")); + if (regArray && CFArrayGetCount(regArray) > 0) + { + CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0); + if (regDict && DDNSSettingEnabled(regDict)) + { + CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain")); + if (name) + { + if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) || + !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0]) + LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)"); + else + { + debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration domain: %s", buf); + AppendDNameListElem(&RegDomains, 0, &d); + } + } + } + } } - - // remove elem from list, delete - if (prev) prev->next = ptr->next; - else SearchList = ptr->next; - freeSLPtr = ptr; - ptr = ptr->next; - freeL("RegisterSearchDomains - freeSLPtr", freeSLPtr); - continue; - } - - if (ptr->flag == 1) // add - { - mStatus err1, err2, err3, err4, err5; - err1 = mDNS_GetDomains(m, &ptr->BrowseQ, mDNS_DomainTypeBrowse, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr); - err2 = mDNS_GetDomains(m, &ptr->DefBrowseQ, mDNS_DomainTypeBrowseDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr); - err3 = mDNS_GetDomains(m, &ptr->RegisterQ, mDNS_DomainTypeRegistration, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr); - err4 = mDNS_GetDomains(m, &ptr->DefRegisterQ, mDNS_DomainTypeRegistrationDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr); - err5 = mDNS_GetDomains(m, &ptr->LegacyBrowseQ, mDNS_DomainTypeBrowseLegacy, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr); - if (err1 || err2 || err3 || err4 || err5) - LogMsg("GetDomains for domain %##s returned error(s):\n" - "%d (mDNS_DomainTypeBrowse)\n" - "%d (mDNS_DomainTypeBrowseDefault)\n" - "%d (mDNS_DomainTypeRegistration)\n" - "%d (mDNS_DomainTypeRegistrationDefault)" - "%d (mDNS_DomainTypeBrowseLegacy)\n", - ptr->domain.c, err1, err2, err3, err4, err5); - ptr->flag = 0; - } - - if (ptr->flag) { LogMsg("RegisterSearchDomains - unknown flag %d. Skipping.", ptr->flag); } - - prev = ptr; - ptr = ptr->next; - } - - return mStatus_NoError; - } - -//!!!KRS here is where we will give success/failure notification to the UI -mDNSlocal void SCPrefsDynDNSCallback(mDNS *const m, AuthRecord *const rr, mStatus result) - { - (void)m; // unused - debugf("SCPrefsDynDNSCallback: result %d for registration of name %##s", result, rr->resrec.name->c); - SetDDNSNameStatus(rr->resrec.name, result); - } -mDNSlocal void SetSecretForDomain(mDNS *m, const domainname *domain) - { - OSStatus err = 0; - char dstring[MAX_ESCAPED_DOMAIN_NAME]; - mDNSu32 secretlen; - void *secret = NULL; - domainname *d, canon; - int i, dlen; - mDNSu32 type = 'ddns'; - mDNSu32 typelen = sizeof(type); - char *failedfn = "(none)"; - SecKeychainAttributeList *attrList = NULL; - SecKeychainItemRef itemRef = NULL; - - err = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem); - if (err) { failedfn = "SecKeychainSetPreferenceDomain"; goto cleanup; } - - // canonicalize name by converting to lower case (keychain and some name servers are case sensitive) - ConvertDomainNameToCString(domain, dstring); - dlen = strlen(dstring); - for (i = 0; i < dlen; i++) dstring[i] = tolower(dstring[i]); // canonicalize -> lower case - MakeDomainNameFromDNSNameString(&canon, dstring); - d = &canon; - - // find longest-match key, excluding last label (e.g. excluding ".com") - while (d->c[0] && *(d->c + d->c[0] + 1)) - { - if (!ConvertDomainNameToCString(d, dstring)) { LogMsg("SetSecretForDomain: bad domain %##s", d->c); return; } - dlen = strlen(dstring); - if (dstring[dlen-1] == '.') { dstring[dlen-1] = '\0'; dlen--; } // chop trailing dot - SecKeychainAttribute attrs[] = { { kSecServiceItemAttr, strlen(dstring), dstring }, - { kSecTypeItemAttr, typelen, (UInt32 *)&type } }; - SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs }; - SecKeychainSearchRef searchRef; - - err = SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attributes, &searchRef); - if (err) { failedfn = "SecKeychainSearchCreateFromAttributes"; goto cleanup; } - - err = SecKeychainSearchCopyNext(searchRef, &itemRef); - if (!err) - { - mDNSu32 tags[1]; - SecKeychainAttributeInfo attrInfo; - mDNSu32 i; - char keybuf[MAX_ESCAPED_DOMAIN_NAME+1]; - domainname keyname; - - tags[0] = kSecAccountItemAttr; - attrInfo.count = 1; - attrInfo.tag = tags; - attrInfo.format = NULL; - - err = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, &attrList, &secretlen, &secret); - if (err || !attrList) { failedfn = "SecKeychainItemCopyAttributesAndData"; goto cleanup; } - if (!secretlen || !secret) { LogMsg("SetSecretForDomain - bad shared secret"); return; } - if (((char *)secret)[secretlen-1]) { LogMsg("SetSecretForDomain - Shared secret not NULL-terminated"); goto cleanup; } - - for (i = 0; i < attrList->count; i++) + if (BrowseDomains) { - SecKeychainAttribute attr = attrList->attr[i]; - if (attr.tag == kSecAccountItemAttr) + CFArrayRef browseArray = CFDictionaryGetValue(dict, CFSTR("BrowseDomains")); + if (browseArray) { - if (!attr.length || attr.length > MAX_ESCAPED_DOMAIN_NAME) { LogMsg("SetSecretForDomain - Bad key length %d", attr.length); goto cleanup; } - memcpy(keybuf, attr.data, attr.length); - keybuf[attr.length] = 0; - if (!MakeDomainNameFromDNSNameString(&keyname, keybuf)) { LogMsg("SetSecretForDomain - bad key %s", keybuf); goto cleanup; } - debugf("Setting shared secret for zone %s with key %##s", dstring, keyname.c); - mDNS_SetSecretForZone(m, d, &keyname, secret); - break; + for (i = 0; i < CFArrayGetCount(browseArray); i++) + { + CFDictionaryRef browseDict = CFArrayGetValueAtIndex(browseArray, i); + if (browseDict && DDNSSettingEnabled(browseDict)) + { + CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain")); + if (name) + { + if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) || + !MakeDomainNameFromDNSNameString(&d, buf) || !d.c[0]) + LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browsing domain: %s", buf[0] ? buf : "(unknown)"); + else + { + debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browsing domain: %s", buf); + AppendDNameListElem(&BrowseDomains, 0, &d); + } + } + } + } } } - if (i == attrList->count) LogMsg("SetSecretForDomain - no key name set"); - goto cleanup; + CFRelease(dict); } - else if (err == errSecItemNotFound) d = (domainname *)(d->c + d->c[0] + 1); - else { failedfn = "SecKeychainSearchCopyNext"; goto cleanup; } - } - - cleanup: - if (err && err != errSecItemNotFound) LogMsg("Error: SetSecretForDomain - %s failed with error code %d", failedfn, err); - if (attrList) SecKeychainItemFreeAttributesAndData(attrList, secret); - if (itemRef) CFRelease(itemRef); - } -mDNSlocal void SetSCPrefsBrowseDomainsFromCFArray(mDNS *m, CFArrayRef browseDomains, mDNSBool add) - { - if (browseDomains) - { - CFIndex count = CFArrayGetCount(browseDomains); - CFDictionaryRef browseDict; - char buf[MAX_ESCAPED_DOMAIN_NAME]; - int i; - - for (i = 0; i < count; i++) + if (RegDomains) { - browseDict = (CFDictionaryRef)CFArrayGetValueAtIndex(browseDomains, i); - if (browseDict && DDNSSettingEnabled(browseDict)) + CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac); + if (btmm) { - CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain")); - if (name) + CFIndex size = CFDictionaryGetCount(btmm); + const void *key[size]; + const void *val[size]; + CFDictionaryGetKeysAndValues(btmm, key, val); + for (i = 0; i < size; i++) { - domainname BrowseDomain; - if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) || !MakeDomainNameFromDNSNameString(&BrowseDomain, buf) || !BrowseDomain.c[0]) - LogMsg("SetSCPrefsBrowseDomainsFromCFArray SCDynamicStore bad DDNS browse domain: %s", buf[0] ? buf : "(unknown)"); - else SetSCPrefsBrowseDomain(m, &BrowseDomain, add); + LogOperation("BackToMyMac %d", i); + if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8)) + LogMsg("Can't read BackToMyMac %d key %s", i, buf); + else + { + mDNSu32 uid = atoi(buf); + if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8)) + LogMsg("Can't read BackToMyMac %d val %s", i, buf); + else if (MakeDomainNameFromDNSNameString(&d, buf) && d.c[0]) + { + LogOperation("BackToMyMac %d %d %##s", i, uid, d.c); + AppendDNameListElem(&RegDomains, uid, &d); + } + } } + CFRelease(btmm); } } - } - } - - -mDNSlocal void DynDNSConfigChanged(mDNS *const m) - { -#ifdef _LEGACY_NAT_TRAVERSAL_ - static mDNSBool LegacyNATInitialized = mDNSfalse; -#endif _LEGACY_NAT_TRAVERSAL_ - uDNS_GlobalInfo *u = &m->uDNS_info; - CFDictionaryRef dict; - CFStringRef key; - domainname RegDomain, fqdn; - CFArrayRef NewBrowseDomains = NULL; - int nAdditions = 0, nDeletions = 0; - - // get fqdn, zone from SCPrefs - GetUserSpecifiedDDNSConfig(&fqdn, &RegDomain, &NewBrowseDomains); - ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, fqdn.c[0] ? NULL : &fqdn, RegDomain.c[0] ? NULL : &RegDomain, &DomainDiscoveryDisabled); - if (!SameDomainName(&RegDomain, &DynDNSRegDomain)) - { - if (DynDNSRegDomain.c[0]) - { - RemoveDefRegDomain(&DynDNSRegDomain); - SetSCPrefsBrowseDomain(m, &DynDNSRegDomain, mDNSfalse); // if we were automatically browsing in our registration domain, stop - } - AssignDomainName(&DynDNSRegDomain, &RegDomain); - if (DynDNSRegDomain.c[0]) + if (setservers || setsearch) { - SetSecretForDomain(m, &DynDNSRegDomain); - AddDefRegDomain(&DynDNSRegDomain); - SetSCPrefsBrowseDomain(m, &DynDNSRegDomain, mDNStrue); + CFStringRef key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS); + if (key) + { + CFDictionaryRef dict = SCDynamicStoreCopyValue(store, key); + if (dict) + { + if (setservers) + { + CFArrayRef values = CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses); + if (values) + { + for (i = 0; i < CFArrayGetCount(values); i++) + { + CFStringRef s = CFArrayGetValueAtIndex(values, i); + char buf[256]; + mDNSAddr addr = { mDNSAddrType_IPv4, { { { 0 } } } }; + if (s && CFStringGetCString(s, buf, 256, kCFStringEncodingUTF8) && + inet_aton(buf, (struct in_addr *) &addr.ip.v4)) + mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, &addr, UnicastDNSPort); + } + } + } + if (setsearch) + { + // Add the manual and/or DHCP-dicovered search domains + CFArrayRef searchDomains = CFDictionaryGetValue(dict, kSCPropNetDNSSearchDomains); + if (searchDomains) + { + for (i = 0; i < CFArrayGetCount(searchDomains); i++) + { + CFStringRef s = CFArrayGetValueAtIndex(searchDomains, i); + if (s && CFStringGetCString(s, buf, sizeof(buf), kCFStringEncodingUTF8)) + mDNS_AddSearchDomain_CString(buf); + } + } + else // No kSCPropNetDNSSearchDomains, so use kSCPropNetDNSDomainName + { + // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains + // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if + // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and + // instead use the search domain list as the sole authority for what domains to search and in what order + // (and the domain from the "domain" field will also appear somewhere in that list). + CFStringRef string = CFDictionaryGetValue(dict, kSCPropNetDNSDomainName); + if (string && CFStringGetCString(string, buf, sizeof(buf), kCFStringEncodingUTF8)) + mDNS_AddSearchDomain_CString(buf); + } + } + CFRelease(dict); + } + CFRelease(key); + } } + CFRelease(store); } + } - // Add new browse domains to internal list - if (NewBrowseDomains) SetSCPrefsBrowseDomainsFromCFArray(m, NewBrowseDomains, mDNStrue); - - // Remove old browse domains from internal list - if (DynDNSBrowseDomains) - { - SetSCPrefsBrowseDomainsFromCFArray(m, DynDNSBrowseDomains, mDNSfalse); - CFRelease(DynDNSBrowseDomains); - } +mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r) + { + SCDynamicStoreRef store = NULL; + CFDictionaryRef dict = NULL; + CFStringRef key = NULL; + CFStringRef string = NULL; + int nAdditions = 0; + int nDeletions = 0; + char buf[256]; + mStatus err = 0; - // Replace the old browse domains array with the new array - DynDNSBrowseDomains = NewBrowseDomains; - - if (!SameDomainName(&fqdn, &DynDNSHostname)) - { - if (DynDNSHostname.c[0]) mDNS_RemoveDynDNSHostName(m, &DynDNSHostname); - AssignDomainName(&DynDNSHostname, &fqdn); - if (DynDNSHostname.c[0]) - { - SetSecretForDomain(m, &fqdn); // no-op if "zone" secret, above, is to be used for hostname - SetDDNSNameStatus(&DynDNSHostname, 1); // Set status to 1 to indicate "in progress" - mDNS_AddDynDNSHostName(m, &DynDNSHostname, SCPrefsDynDNSCallback, NULL); - } - } + // get IPv4 settings - // get DNS settings - SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:DynDNSConfigChanged"), NULL, NULL); - if (!store) return; - - key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS); - if (!key) { LogMsg("ERROR: DNSConfigChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store); return; } - dict = SCDynamicStoreCopyValue(store, key); - CFRelease(key); + store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL, NULL); + require_action(store, exit, err = mStatus_UnknownErr); - // handle any changes to search domains and DNS server addresses - if (RegisterSplitDNS(m, &nAdditions, &nDeletions) != mStatus_NoError) - if (dict) RegisterNameServers(m, dict); // fall back to non-split DNS aware configuration on failure - RegisterSearchDomains(m, dict); // note that we register name servers *before* search domains - if (dict) CFRelease(dict); + key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4); + require_action(key, exit, err = mStatus_UnknownErr); - // get IPv4 settings - key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,kSCDynamicStoreDomainState, kSCEntNetIPv4); - if (!key) { LogMsg("ERROR: RouterChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store); return; } dict = SCDynamicStoreCopyValue(store, key); - CFRelease(key); - CFRelease(store); - if (!dict) // lost v4 - { - mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL); - if (DynDNSHostname.c[0]) SetDDNSNameStatus(&DynDNSHostname, 1); // Set status to 1 to indicate temporary failure - return; - } + require_action(dict, exit, err = mStatus_UnknownErr); // handle router changes - mDNSAddr r; - char buf[256]; - r.type = mDNSAddrType_IPv4; - r.ip.v4.NotAnInteger = 0; - CFStringRef router = CFDictionaryGetValue(dict, kSCPropNetIPv4Router); - if (router) + + r->type = mDNSAddrType_IPv4; + r->ip.v4 = zerov4Addr; + + string = CFDictionaryGetValue(dict, kSCPropNetIPv4Router); + + if (string) { struct sockaddr_in saddr; - - if (!CFStringGetCString(router, buf, 256, kCFStringEncodingUTF8)) + + if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8)) LogMsg("Could not convert router to CString"); else { saddr.sin_len = sizeof(saddr); saddr.sin_family = AF_INET; - saddr.sin_port = 0; + saddr.sin_port = 0; inet_aton(buf, &saddr.sin_addr); - if (AddrRequiresPPPConnection((struct sockaddr *)&saddr)) { debugf("Ignoring router %s (requires PPP connection)", buf); } - else *(in_addr_t *)&r.ip.v4 = saddr.sin_addr.s_addr; + + if (AddrRequiresPPPConnection((struct sockaddr *)&saddr)) debugf("Ignoring router %s (requires PPP connection)", buf); + else *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr; } } // handle primary interface changes // if we gained or lost DNS servers (e.g. logged into VPN) "toggle" primary address so it gets re-registered even if it is unchanged if (nAdditions || nDeletions) mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL); - CFStringRef primary = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface); - if (primary) + + string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface); + + if (string) { - mDNSAddr v4 = zeroAddr, v6 = zeroAddr; mDNSBool HavePrimaryGlobalv6 = mDNSfalse; // does the primary interface have a global v6 address? struct ifaddrs *ifa = myGetIfAddrs(1); - - if (!CFStringGetCString(primary, buf, 256, kCFStringEncodingUTF8)) - { LogMsg("Could not convert router to CString"); goto error; } + + *v4 = *v6 = zeroAddr; + + if (!CFStringGetCString(string, buf, 256, kCFStringEncodingUTF8)) { LogMsg("Could not convert router to CString"); goto exit; } // find primary interface in list - while (ifa && (!v4.ip.v4.NotAnInteger || !HavePrimaryGlobalv6)) + while (ifa && (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4) || !HavePrimaryGlobalv6)) { mDNSAddr tmp6 = zeroAddr; if (!strcmp(buf, ifa->ifa_name)) - { - if (ifa->ifa_addr->sa_family == AF_INET) SetupAddr(&v4, ifa->ifa_addr); - else if (ifa->ifa_addr->sa_family == AF_INET6) + { + if (ifa->ifa_addr->sa_family == AF_INET) + { + if (mDNSIPv4AddressIsZero(v4->ip.v4) || mDNSv4AddressIsLinkLocal(&v4->ip.v4)) SetupAddr(v4, ifa->ifa_addr); + } + else if (ifa->ifa_addr->sa_family == AF_INET6) { SetupAddr(&tmp6, ifa->ifa_addr); if (tmp6.ip.v6.b[0] >> 5 == 1) // global prefix: 001 - { HavePrimaryGlobalv6 = mDNStrue; v6 = tmp6; } + { HavePrimaryGlobalv6 = mDNStrue; *v6 = tmp6; } } } else { // We'll take a V6 address from the non-primary interface if the primary interface doesn't have a global V6 address - if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6.ip.v6.b[0]) + if (!HavePrimaryGlobalv6 && ifa->ifa_addr->sa_family == AF_INET6 && !v6->ip.v6.b[0]) { SetupAddr(&tmp6, ifa->ifa_addr); - if (tmp6.ip.v6.b[0] >> 5 == 1) v6 = tmp6; + if (tmp6.ip.v6.b[0] >> 5 == 1) *v6 = tmp6; } } ifa = ifa->ifa_next; @@ -3147,43 +3193,350 @@ mDNSlocal void DynDNSConfigChanged(mDNS *const m) // Note that while we advertise v6, we still require v4 (possibly NAT'd, but not link-local) because we must use // V4 to communicate w/ our DNS server - - if (v4.ip.v4.b[0] == 169 && v4.ip.v4.b[1] == 254) mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL); // primary IP is link-local + } + + exit: + if (dict) CFRelease(dict); + if (key) CFRelease(key); + if (store) CFRelease(store); + return err; + } + +mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status) + { + LogOperation("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status, dname->c); + char uname[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL + ConvertDomainNameToCString(dname, uname); + + char *p = uname; + while (*p) + { + *p = tolower(*p); + if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot + p++; + } + + // We need to make a CFDictionary called "State:/Network/DynamicDNS" containing (at present) a single entity. + // That single entity is a CFDictionary with name "HostNames". + // The "HostNames" CFDictionary contains a set of name/value pairs, where the each name is the FQDN + // in question, and the corresponding value is a CFDictionary giving the state for that FQDN. + // (At present we only support a single FQDN, so this dictionary holds just a single name/value pair.) + // The CFDictionary for each FQDN holds (at present) a single name/value pair, + // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success). + + const CFStringRef StateKeys [1] = { CFSTR("HostNames") }; + const CFStringRef HostKeys [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) }; + const CFStringRef StatusKeys[1] = { CFSTR("Status") }; + if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname); + else + { + const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) }; + if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%ld) failed", status); else { - if (v4.ip.v4.NotAnInteger != u->AdvertisedV4.ip.v4.NotAnInteger || - memcmp(v6.ip.v6.b, u->AdvertisedV6.ip.v6.b, 16) || - r.ip.v4.NotAnInteger != u->Router.ip.v4.NotAnInteger) + const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, NULL, NULL) }; + if (HostVals[0]) { -#ifdef _LEGACY_NAT_TRAVERSAL_ - if (LegacyNATInitialized) { LegacyNATDestroy(); LegacyNATInitialized = mDNSfalse; } - if (r.ip.v4.NotAnInteger && IsPrivateV4Addr(&v4)) + const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, NULL, NULL) }; + if (StateVals[0]) { - mStatus err = LegacyNATInit(); - if (err) LogMsg("ERROR: LegacyNATInit"); - else LegacyNATInitialized = mDNStrue; - } -#endif _LEGACY_NAT_TRAVERSAL_ - mDNS_SetPrimaryInterfaceInfo(m, &v4, v6.ip.v6.b[0] ? &v6 : NULL, r.ip.v4.NotAnInteger ? &r : NULL); + CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, NULL, NULL); + if (StateDict) + { + mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, StateDict); + CFRelease(StateDict); + } + CFRelease(StateVals[0]); + } + CFRelease(HostVals[0]); } + CFRelease(StatusVals[0]); } + CFRelease(HostKeys[0]); } - error: - CFRelease(dict); + } + +// MUST be called holding the lock -- this routine calls SetupLocalAutoTunnelInterface_internal() +mDNSlocal void SetDomainSecrets(mDNS *m) + { +#ifdef NO_SECURITYFRAMEWORK + (void)m; + LogMsg("Note: SetDomainSecrets: no keychain support"); +#else + mDNSBool haveAutoTunnels = mDNSfalse; + + LogOperation("SetDomainSecrets"); + + // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds. + // In the case where the user simultaneously removes their DDNS host name and the key + // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the + // server before it loses access to the necessary key. Otherwise, we'd leave orphaned + // address records behind that we no longer have permission to delete. + DomainAuthInfo *ptr; + for (ptr = m->AuthInfoList; ptr; ptr = ptr->next) + ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10); + +#if APPLE_OSX_mDNSResponder + { + // Mark all TunnelClients for deletion + ClientTunnel *client; + for (client = m->TunnelClients; client; client = client->next) + { + LogOperation("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c); + client->markedForDeletion = mDNStrue; + } + } +#endif APPLE_OSX_mDNSResponder + + CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + if (!sa) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; } + CFIndex i; + CFDataRef data = NULL; + const int itemsPerEntry = 3; // domain name, key name, key value + CFArrayRef secrets = NULL; + int err = mDNSKeychainGetSecrets(&secrets); + if (err || !secrets) + LogMsg("SetDomainSecrets: mDNSKeychainGetSecrets failed error %d CFArrayRef %p", err, secrets); + else + { + CFIndex ArrayCount = CFArrayGetCount(secrets); + // Iterate through the secrets + for (i = 0; i < ArrayCount; ++i) + { + int j; + CFArrayRef entry = CFArrayGetValueAtIndex(secrets, i); + if (CFArrayGetTypeID() != CFGetTypeID(entry) || itemsPerEntry != CFArrayGetCount(entry)) + { LogMsg("SetDomainSecrets: malformed entry"); continue; } + for (j = 0; j < CFArrayGetCount(entry); ++j) + if (CFDataGetTypeID() != CFGetTypeID(CFArrayGetValueAtIndex(entry, j))) + { LogMsg("SetDomainSecrets: malformed entry item"); continue; } + + // Validate that attributes are not too large + char dstring[MAX_ESCAPED_DOMAIN_NAME]; + char keynamebuf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL + // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness + data = CFArrayGetValueAtIndex(entry, 0); + if (CFDataGetLength(data) >= (int)sizeof(dstring)) + { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data)); continue; } + CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)dstring); + dstring[CFDataGetLength(data)] = '\0'; + data = CFArrayGetValueAtIndex(entry, 1); + if (CFDataGetLength(data) >= (int)sizeof(keynamebuf)) + { LogMsg("SetDomainSecrets: Bad kSecAccountItemAttr length %d", CFDataGetLength(data)); continue; } + CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), (UInt8 *)keynamebuf); + keynamebuf[CFDataGetLength(data)] = '\0'; + + domainname domain; + if (!MakeDomainNameFromDNSNameString(&domain, dstring)) { LogMsg("SetDomainSecrets: bad key domain %s", dstring); continue; } + + // Get DNS key name + domainname keyname; + if (!MakeDomainNameFromDNSNameString(&keyname, keynamebuf)) { LogMsg("SetDomainSecrets: bad key name %s", keynamebuf); continue; } + + // Get DNS key data + char keystring[1024]; + data = CFArrayGetValueAtIndex(entry, 2); + if (CFDataGetLength(data) >= (int)sizeof(keystring)) + { LogMsg("SetDomainSecrets: Shared secret too long: %d", CFDataGetLength(data)); continue; } + CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)keystring); + keystring[CFDataGetLength(data)] = '\0'; // mDNS_SetSecretForDomain requires NULL-terminated C string for key + + DomainAuthInfo *FoundInList; + for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next) + if (SameDomainName(&FoundInList->domain, &domain)) break; + +#if APPLE_OSX_mDNSResponder + if (FoundInList) + { + // If any client tunnel destination is in this domain, set deletion flag to false + ClientTunnel *client; + for (client = m->TunnelClients; client; client = client->next) + if (FoundInList == GetAuthInfoForName_internal(m, &client->dstname)) + { + LogOperation("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c); + client->markedForDeletion = mDNSfalse; + // If the key has changed, reconfigure the tunnel + if (strncmp(keystring, client->b64keydata, sizeof(client->b64keydata))) + { + mDNSBool queryNotInProgress = client->q.ThisQInterval < 0; + LogOperation("SetDomainSecrets: secret changed for tunnel %##s %s", client->dstname.c, queryNotInProgress ? "reconfiguring" : "query in progress"); + if (queryNotInProgress) AutoTunnelSetKeys(client, mDNSfalse); + mDNS_snprintf(client->b64keydata, sizeof(client->b64keydata), "%s", keystring); + if (queryNotInProgress) AutoTunnelSetKeys(client, mDNStrue); + } + } + } + + mDNSBool keyChanged = FoundInList && FoundInList->AutoTunnel ? strncmp(keystring, FoundInList->b64keydata, sizeof(FoundInList->b64keydata)) : mDNSfalse; + +#endif APPLE_OSX_mDNSResponder + + // Uncomment the line below to view the keys as they're read out of the system keychain + // DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE! + //LogOperation("SetDomainSecrets: %##s %##s %s", &domain.c, &keyname.c, keystring); + + // If didn't find desired domain in the list, make a new entry + ptr = FoundInList; + if (FoundInList && FoundInList->AutoTunnel && haveAutoTunnels == mDNSfalse) haveAutoTunnels = mDNStrue; + if (!FoundInList) + { + ptr = (DomainAuthInfo*)mallocL("DomainAuthInfo", sizeof(*ptr)); + if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; } + } + + LogOperation("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain); + if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, keystring, IsTunnelModeDomain(&domain)) == mStatus_BadParamErr) + { + if (!FoundInList) mDNSPlatformMemFree(ptr); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately + continue; + } + +#if APPLE_OSX_mDNSResponder + if (keyChanged && AnonymousRacoonConfig) + { + LogOperation("SetDomainSecrets: secret changed for %##s", &domain); + (void)mDNSConfigureServer(kmDNSUp, keystring); + } +#endif APPLE_OSX_mDNSResponder + + CFStringRef cfs = CFStringCreateWithCString(NULL, dstring, kCFStringEncodingUTF8); + if (cfs) { CFArrayAppendValue(sa, cfs); CFRelease(cfs); } + } + CFRelease(secrets); + } + mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, sa); + CFRelease(sa); + + #if APPLE_OSX_mDNSResponder + { + // clean up ClientTunnels + ClientTunnel **ptr = &m->TunnelClients; + while (*ptr) + { + if ((*ptr)->markedForDeletion) + { + ClientTunnel *cur = *ptr; + LogOperation("SetDomainSecrets: removing client %##s from list", cur->dstname.c); + if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q); + AutoTunnelSetKeys(cur, mDNSfalse); + *ptr = cur->next; + freeL("ClientTunnel", cur); + } + else + ptr = &(*ptr)->next; + } + + DomainAuthInfo *info = m->AuthInfoList; + while (info) + { + if (info->AutoTunnel && info->deltime && info->AutoTunnelNAT.clientContext) + { + // stop the NAT operation + mDNS_StopNATOperation_internal(m, &info->AutoTunnelNAT); + if (info->AutoTunnelHostRecord.namestorage.c[0] && info->AutoTunnelNAT.clientCallback) + { + // reset port and let the AutoTunnelNATCallback handle cleanup + info->AutoTunnelNAT.ExternalAddress = m->ExternalAddress; + info->AutoTunnelNAT.ExternalPort = zeroIPPort; + info->AutoTunnelNAT.Lifetime = 0; + info->AutoTunnelNAT.Result = mStatus_NoError; + mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback + info->AutoTunnelNAT.clientCallback(m, &info->AutoTunnelNAT); + mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again + } + info->AutoTunnelNAT.clientContext = mDNSNULL; + } + info = info->next; + } + + if (!haveAutoTunnels && !m->TunnelClients && m->AutoTunnelHostAddrActive) + { + // remove interface if no autotunnel servers and no more client tunnels + LogOperation("SetDomainSecrets: Bringing tunnel interface DOWN"); + m->AutoTunnelHostAddrActive = mDNSfalse; + (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown, m->AutoTunnelHostAddr.b); + memset(m->AutoTunnelHostAddr.b, 0, sizeof(m->AutoTunnelHostAddr.b)); + } + + if (!haveAutoTunnels && AnonymousRacoonConfig) + { + LogMsg("SetDomainSecrets: Resetting AnonymousRacoonConfig to false"); + AnonymousRacoonConfig = mDNSfalse; + (void)mDNSConfigureServer(kmDNSDown, ""); + } + + if (m->AutoTunnelHostAddr.b[0]) + if (TunnelClients(m) || TunnelServers(m)) + SetupLocalAutoTunnelInterface_internal(m); + } + #endif APPLE_OSX_mDNSResponder + +#endif /* NO_SECURITYFRAMEWORK */ + } + +mDNSlocal void SetLocalDomains(void) + { + CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + if (!sa) { LogMsg("SetLocalDomains: CFArrayCreateMutable failed"); return; } + + CFArrayAppendValue(sa, CFSTR("local")); + CFArrayAppendValue(sa, CFSTR("254.169.in-addr.arpa")); + CFArrayAppendValue(sa, CFSTR("8.e.f.ip6.arpa")); + CFArrayAppendValue(sa, CFSTR("9.e.f.ip6.arpa")); + CFArrayAppendValue(sa, CFSTR("a.e.f.ip6.arpa")); + CFArrayAppendValue(sa, CFSTR("b.e.f.ip6.arpa")); + + mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, sa); + CFRelease(sa); } mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m) - { - LogOperation("*** Network Configuration Change ***"); + { + LogOperation("*** Network Configuration Change *** (%d)%s", + m->p->NetworkChanged ? mDNS_TimeNow(m) - m->p->NetworkChanged : 0, + m->p->NetworkChanged ? "": " (no scheduled configuration change)"); m->p->NetworkChanged = 0; // If we received a network change event and deferred processing, we're now dealing with it mDNSs32 utc = mDNSPlatformUTC(); MarkAllInterfacesInactive(m, utc); UpdateInterfaceList(m, utc); int nDeletions = ClearInactiveInterfaces(m, utc); int nAdditions = SetupActiveInterfaces(m, utc); - DynDNSConfigChanged(m); // note - call DynDNSConfigChanged *before* mDNS_UpdateLLQs + + #if APPLE_OSX_mDNSResponder + { + if (m->AutoTunnelHostAddr.b[0]) + { + mDNS_Lock(m); + if (TunnelClients(m) || TunnelServers(m)) + SetupLocalAutoTunnelInterface_internal(m); + mDNS_Unlock(m); + } + + // Scan to find client tunnels whose questions have completed, + // but whose local inner/outer addresses have changed since the tunnel was set up + ClientTunnel *p; + for (p = m->TunnelClients; p; p = p->next) + if (p->q.ThisQInterval < 0) + { + mDNSAddr tmpSrc = zeroAddr; + mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} }; + tmpDst.ip.v4 = p->rmt_outer; + FindSourceAddrForIP(&tmpDst, &tmpSrc); + if (!mDNSSameIPv6Address(p->loc_inner, m->AutoTunnelHostAddr) || + !mDNSSameIPv4Address(p->loc_outer, tmpSrc.ip.v4)) + { + AutoTunnelSetKeys(p, mDNSfalse); + p->loc_inner = m->AutoTunnelHostAddr; + p->loc_outer = tmpSrc.ip.v4; + AutoTunnelSetKeys(p, mDNStrue); + } + } + } + #endif APPLE_OSX_mDNSResponder + + uDNS_SetupDNSConfig(m); // note - call DynDNSConfigChanged *before* mDNS_UpdateLLQs if (nDeletions || nAdditions) mDNS_UpdateLLQs(m); // so that LLQs are restarted against the up to date name servers - + if (m->MainCallback) m->MainCallback(m, mStatus_ConfigChanged); } @@ -3193,34 +3546,44 @@ mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, v (void)store; // Parameter not used (void)changedKeys; // Parameter not used mDNS *const m = (mDNS *const)context; + KQueueLock(m); mDNS_Lock(m); - mDNSs32 delay = mDNSPlatformOneSecond * 2; // Start off assuming a two-second delay + mDNSs32 delay = mDNSPlatformOneSecond; // Start off assuming a one-second delay - int c = CFArrayGetCount(changedKeys); // Count changes + int c = CFArrayGetCount(changedKeys); // Count changes CFRange range = { 0, c }; - CFStringRef k1 = SCDynamicStoreKeyCreateComputerName(NULL); - CFStringRef k2 = SCDynamicStoreKeyCreateHostNames(NULL); - if (k1 && k2) - { - int c1 = (CFArrayContainsValue(changedKeys, range, k1) != 0); // See if ComputerName changed - int c2 = (CFArrayContainsValue(changedKeys, range, k2) != 0); // See if Local Hostname changed - int c3 = (CFArrayContainsValue(changedKeys, range, CFSTR("Setup:/Network/DynamicDNS")) != 0); - if (c && c - c1 - c2 - c3 == 0) delay = mDNSPlatformOneSecond/10; // If these were the only changes, shorten delay - } - if (k1) CFRelease(k1); - if (k2) CFRelease(k2); + int c1 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Hostnames ) != 0); + int c2 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0); + int c3 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS ) != 0); + if (c && c - c1 - c2 - c3 == 0) delay = mDNSPlatformOneSecond/20; // If these were the only changes, shorten delay - LogOperation("*** NetworkChanged *** %d change%s, delay %d", c, c>1?"s":"", delay); +#if LogAllOperations + int i; + for (i=0; i1?"s":"", + c1 ? "(Local Hostname) " : "", + c2 ? "(Computer Name) " : "", + c3 ? "(DynamicDNS) " : "", + delay); +#endif if (!m->p->NetworkChanged || m->p->NetworkChanged - NonZeroTime(m->timenow + delay) < 0) m->p->NetworkChanged = NonZeroTime(m->timenow + delay); - + if (!m->SuppressSending || m->SuppressSending - m->p->NetworkChanged < 0) m->SuppressSending = m->p->NetworkChanged; + mDNS_Unlock(m); + KQueueUnlock(m, "NetworkChanged"); } mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m) @@ -3228,26 +3591,21 @@ mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m) mStatus err = -1; SCDynamicStoreContext context = { 0, m, NULL, NULL, NULL }; SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:WatchForNetworkChanges"), NetworkChanged, &context); - CFStringRef key1 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4); - CFStringRef key2 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6); - CFStringRef key3 = SCDynamicStoreKeyCreateComputerName(NULL); - CFStringRef key4 = SCDynamicStoreKeyCreateHostNames(NULL); - CFStringRef key5 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS); + CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); CFStringRef pattern1 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4); CFStringRef pattern2 = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6); - - CFMutableArrayRef keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); CFMutableArrayRef patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); if (!store) { LogMsg("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); goto error; } - if (!key1 || !key2 || !key3 || !key4 || !keys || !pattern1 || !pattern2 || !patterns) goto error; - - CFArrayAppendValue(keys, key1); - CFArrayAppendValue(keys, key2); - CFArrayAppendValue(keys, key3); - CFArrayAppendValue(keys, key4); - CFArrayAppendValue(keys, key5); - CFArrayAppendValue(keys, CFSTR("Setup:/Network/DynamicDNS")); + if (!keys || !pattern1 || !pattern2 || !patterns) goto error; + + CFArrayAppendValue(keys, NetworkChangedKey_IPv4); + CFArrayAppendValue(keys, NetworkChangedKey_IPv6); + CFArrayAppendValue(keys, NetworkChangedKey_Hostnames); + CFArrayAppendValue(keys, NetworkChangedKey_Computername); + CFArrayAppendValue(keys, NetworkChangedKey_DNS); + CFArrayAppendValue(keys, NetworkChangedKey_DynamicDNS); + CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac); CFArrayAppendValue(patterns, pattern1); CFArrayAppendValue(patterns, pattern2); CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort")); @@ -3262,26 +3620,70 @@ mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m) err = 0; goto exit; -error: + error: if (store) CFRelease(store); -exit: - if (key1) CFRelease(key1); - if (key2) CFRelease(key2); - if (key3) CFRelease(key3); - if (key4) CFRelease(key4); - if (key5) CFRelease(key5); - if (pattern1) CFRelease(pattern1); + exit: + if (patterns) CFRelease(patterns); if (pattern2) CFRelease(pattern2); + if (pattern1) CFRelease(pattern1); if (keys) CFRelease(keys); - if (patterns) CFRelease(patterns); - + return(err); } +#ifndef NO_SECURITYFRAMEWORK +mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void *context) + { + LogOperation("*** Keychain Changed ***"); + mDNS *const m = (mDNS *const)context; + SecKeychainRef skc; + OSStatus err = SecKeychainCopyDefault(&skc); + if (!err) + { + if (info->keychain == skc) + { + // For delete events, attempt to verify what item was deleted fail because the item is already gone, so we just assume they may be relevant + mDNSBool relevant = (keychainEvent == kSecDeleteEvent); + if (!relevant) + { + UInt32 tags[3] = { kSecTypeItemAttr, kSecServiceItemAttr, kSecAccountItemAttr }; + SecKeychainAttributeInfo attrInfo = { 3, tags, NULL }; // Count, array of tags, array of formats + SecKeychainAttributeList *a = NULL; + err = SecKeychainItemCopyAttributesAndData(info->item, &attrInfo, NULL, &a, NULL, NULL); + if (!err) + { + relevant = ((a->attr[0].length == 4 && (!strncasecmp(a->attr[0].data, "ddns", 4) || !strncasecmp(a->attr[0].data, "sndd", 4))) || + (a->attr[1].length >= 4 && (!strncasecmp(a->attr[1].data, "dns:", 4)))); + SecKeychainItemFreeAttributesAndData(a, NULL); + } + } + if (relevant) + { + LogMsg("*** Keychain Changed *** KeychainEvent=%d %s", + keychainEvent, + keychainEvent == kSecAddEvent ? "kSecAddEvent" : + keychainEvent == kSecDeleteEvent ? "kSecDeleteEvent" : + keychainEvent == kSecUpdateEvent ? "kSecUpdateEvent" : ""); + KQueueLock(m); + mDNS_Lock(m); + SetDomainSecrets(m); + mDNS_Unlock(m); + KQueueUnlock(m, "KeychainChanged"); + } + } + CFRelease(skc); + } + + return 0; + } +#endif + +#ifndef NO_IOPOWER mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument) { mDNS *const m = (mDNS *const)refcon; + KQueueLock(m); (void)service; // Parameter not used switch(messageType) { @@ -3307,20 +3709,14 @@ mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messag default: LogOperation("PowerChanged unknown message %X", messageType); break; } IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument); + KQueueUnlock(m, "Sleep/Wake"); } +#endif /* NO_IOPOWER */ -mDNSlocal mStatus WatchForPowerChanges(mDNS *const m) - { - IONotificationPortRef thePortRef; - m->p->PowerConnection = IORegisterForSystemPower(m, &thePortRef, PowerChanged, &m->p->PowerNotifier); - if (m->p->PowerConnection) - { - m->p->PowerRLS = IONotificationPortGetRunLoopSource(thePortRef); - CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->PowerRLS, kCFRunLoopDefaultMode); - return(mStatus_NoError); - } - return(-1); - } +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - +#pragma mark - Initialization & Teardown +#endif CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void); CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey; @@ -3333,7 +3729,7 @@ CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey; mDNSexport int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring) { int major = 0, minor = 0; - char letter = 0, prodname[256]="Mac OS X", prodvers[256]="", buildver[256]="?"; + char letter = 0, prodname[256]="", prodvers[256]="", buildver[256]=""; CFDictionaryRef vers = _CFCopySystemVersionDictionary(); if (vers) { @@ -3346,6 +3742,7 @@ mDNSexport int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring) sscanf(buildver, "%d%c%d", &major, &letter, &minor); CFRelease(vers); } + if (!major) { major=8; LogMsg("Note: No Major Build Version number found; assuming 8"); } if (HINFO_SWstring) mDNS_snprintf(HINFO_SWstring, 256, "%s %s (%s), %s", prodname, prodvers, buildver, mDNSResponderVersionString); return(major); } @@ -3374,108 +3771,6 @@ mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void) return(err == 0); } -// Callback for the _legacy._browse queries - add answer to list of domains to search for empty-string browses -mDNSlocal void FoundLegacyBrowseDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) - { - DNameListElem *ptr, *prev, *new; - (void)m; // unused; - (void)question; // unused - - LogMsg("%s browse domain %##s", AddRecord ? "Adding" : "Removing", answer->rdata->u.name.c); - - if (AddRecord) - { - new = mallocL("FoundLegacyBrowseDomain", sizeof(DNameListElem)); - if (!new) { LogMsg("ERROR: malloc"); return; } - AssignDomainName(&new->name, &answer->rdata->u.name); - new->next = DefBrowseList; - DefBrowseList = new; - DefaultBrowseDomainChanged(&new->name, mDNStrue); - udsserver_default_browse_domain_changed(&new->name, mDNStrue); - return; - } - else - { - ptr = DefBrowseList; - prev = NULL; - while (ptr) - { - if (SameDomainName(&ptr->name, &answer->rdata->u.name)) - { - DefaultBrowseDomainChanged(&ptr->name, mDNSfalse); - udsserver_default_browse_domain_changed(&ptr->name, mDNSfalse); - if (prev) prev->next = ptr->next; - else DefBrowseList = ptr->next; - freeL("FoundLegacyBrowseDomain", ptr); - return; - } - prev = ptr; - ptr = ptr->next; - } - LogMsg("FoundLegacyBrowseDomain: Got remove event for domain %##s not in list", answer->rdata->u.name.c); - } - } - -mDNSlocal void RegisterBrowseDomainPTR(mDNS *m, const domainname *d, int type) - { - // allocate/register legacy and non-legacy _browse PTR record - ARListElem *browse = mallocL("ARListElem", sizeof(*browse)); - mDNS_SetupResourceRecord(&browse->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, FreeARElemCallback, browse); - MakeDomainNameFromDNSNameString(browse->ar.resrec.name, mDNS_DomainTypeNames[type]); - AppendDNSNameString (browse->ar.resrec.name, "local"); - AssignDomainName(&browse->ar.resrec.rdata->u.name, d); - mStatus err = mDNS_Register(m, &browse->ar); - if (err) - { - LogMsg("SetSCPrefsBrowseDomain: mDNS_Register returned error %d", err); - freeL("ARListElem", browse); - } - else - { - browse->next = SCPrefBrowseDomains; - SCPrefBrowseDomains = browse; - } - } - -mDNSlocal void DeregisterBrowseDomainPTR(mDNS *m, const domainname *d, int type) - { - ARListElem *remove, **ptr = &SCPrefBrowseDomains; - domainname lhs; // left-hand side of PTR, for comparison - - MakeDomainNameFromDNSNameString(&lhs, mDNS_DomainTypeNames[type]); - AppendDNSNameString (&lhs, "local"); - - while (*ptr) - { - if (SameDomainName(&(*ptr)->ar.resrec.rdata->u.name, d) && SameDomainName((*ptr)->ar.resrec.name, &lhs)) - { - remove = *ptr; - *ptr = (*ptr)->next; - mDNS_Deregister(m, &remove->ar); - return; - } - else ptr = &(*ptr)->next; - } - } - -// Add or remove a user-specified domain to the list of empty-string browse domains -// Also register a non-legacy _browse PTR record so that the domain appears in enumeration lists -mDNSlocal void SetSCPrefsBrowseDomain(mDNS *m, const domainname *d, mDNSBool add) - { - debugf("SetSCPrefsBrowseDomain: %s default browse domain %##s", add ? "Adding" : "Removing", d->c); - - if (add) - { - RegisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowse); - RegisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowseLegacy); - } - else - { - DeregisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowse); - DeregisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowseLegacy); - } - } - // 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) @@ -3486,30 +3781,10 @@ mDNSlocal void SetSCPrefsBrowseDomain(mDNS *m, const domainname *d, mDNSBool add // 6) client calls to enumerate domains now go over LocalOnly interface // (!!!KRS may add outgoing interface in addition) -mDNSlocal mStatus InitDNSConfig(mDNS *const m) +mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m) { mStatus err; - static AuthRecord LocalRegPTR; - - // start query for domains to be used in default (empty string domain) browses - err = mDNS_GetDomains(m, &LegacyBrowseDomainQ, mDNS_DomainTypeBrowseLegacy, NULL, mDNSInterface_LocalOnly, FoundLegacyBrowseDomain, NULL); - - // provide browse domain "local" automatically - SetSCPrefsBrowseDomain(m, &localdomain, mDNStrue); - - // register registration domain "local" - mDNS_SetupResourceRecord(&LocalRegPTR, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, NULL, NULL); - MakeDomainNameFromDNSNameString(LocalRegPTR.resrec.name, mDNS_DomainTypeNames[mDNS_DomainTypeRegistration]); - AppendDNSNameString (LocalRegPTR.resrec.name, "local"); - AssignDomainName(&LocalRegPTR.resrec.rdata->u.name, &localdomain); - err = mDNS_Register(m, &LocalRegPTR); - if (err) LogMsg("ERROR: InitDNSConfig - mDNS_Register returned error %d", err); - - return mStatus_NoError; - } -mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m) - { // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up. // If we can't read the user's preferences, then we sleep a bit and try again, for up to five seconds before we give up. int i; @@ -3522,10 +3797,8 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m) usleep(50000); } - mStatus err; + m->hostlabel.c[0] = 0; - m->hostlabel.c[0] = 0; - char *HINFO_HWstring = "Macintosh"; char HINFO_HWstring_buffer[256]; int get_model[2] = { CTL_HW, HW_MODEL }; @@ -3537,61 +3810,95 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m) if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring) < 7) m->KnownBugs |= mDNS_KnownBug_PhantomInterfaces; if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue; -#ifndef NO_HINFO mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring); mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring); if (hlen + slen < 254) { m->HIHardware.c[0] = hlen; m->HISoftware.c[0] = slen; - mDNSPlatformMemCopy(HINFO_HWstring, &m->HIHardware.c[1], hlen); - mDNSPlatformMemCopy(HINFO_SWstring, &m->HISoftware.c[1], slen); + mDNSPlatformMemCopy(&m->HIHardware.c[1], HINFO_HWstring, hlen); + mDNSPlatformMemCopy(&m->HISoftware.c[1], HINFO_SWstring, slen); } -#endif /* NO_HINFO */ - m->p->unicastsockets.m = m; - m->p->unicastsockets.info = NULL; - m->p->unicastsockets.sktv4 = m->p->unicastsockets.sktv6 = -1; - m->p->unicastsockets.cfsv4 = m->p->unicastsockets.cfsv6 = NULL; - m->p->unicastsockets.rlsv4 = m->p->unicastsockets.rlsv6 = NULL; - - err = SetupSocket(m, &m->p->unicastsockets, mDNSfalse, &zeroAddr, AF_INET); - err = SetupSocket(m, &m->p->unicastsockets, mDNSfalse, &zeroAddr, AF_INET6); + m->p->permanentsockets.m = m; + m->p->permanentsockets.sktv4 = m->p->permanentsockets.sktv6 = -1; + m->p->permanentsockets.kqsv4.KQcallback = m->p->permanentsockets.kqsv6.KQcallback = myKQSocketCallBack; + m->p->permanentsockets.kqsv4.KQcontext = m->p->permanentsockets.kqsv6.KQcontext = &m->p->permanentsockets; + m->p->permanentsockets.kqsv4.KQtask = m->p->permanentsockets.kqsv6.KQtask = "UDP packet reception"; + + err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET); +#ifndef NO_IPV6 + err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET6); +#endif struct sockaddr_in s4; - struct sockaddr_in6 s6; socklen_t n4 = sizeof(s4); - socklen_t n6 = sizeof(s6); - if (getsockname(m->p->unicastsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0) LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno)); + if (getsockname(m->p->permanentsockets.sktv4, (struct sockaddr *)&s4, &n4) < 0) LogMsg("getsockname v4 error %d (%s)", errno, strerror(errno)); else m->UnicastPort4.NotAnInteger = s4.sin_port; - if (getsockname(m->p->unicastsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno)); - else m->UnicastPort6.NotAnInteger = s6.sin6_port; +#ifndef NO_IPV6 + if (m->p->permanentsockets.sktv6 >= 0) + { + struct sockaddr_in6 s6; + socklen_t n6 = sizeof(s6); + if (getsockname(m->p->permanentsockets.sktv6, (struct sockaddr *)&s6, &n6) < 0) LogMsg("getsockname v6 error %d (%s)", errno, strerror(errno)); + else m->UnicastPort6.NotAnInteger = s6.sin6_port; + } +#endif m->p->InterfaceList = mDNSNULL; m->p->userhostlabel.c[0] = 0; m->p->usernicelabel.c[0] = 0; m->p->NotifyUser = 0; + + m->AutoTunnelHostAddr.b[0] = 0; // Zero out AutoTunnelHostAddr so UpdateInterfaceList() know it has to set it up + mDNSs32 utc = mDNSPlatformUTC(); UpdateInterfaceList(m, utc); SetupActiveInterfaces(m, utc); + 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); + if (!NetworkChangedKey_IPv4 || !NetworkChangedKey_IPv6 || !NetworkChangedKey_Hostnames || !NetworkChangedKey_Computername || !NetworkChangedKey_DNS) + { LogMsg("SCDynamicStore string setup failed"); return(mStatus_NoMemoryErr); } + err = WatchForNetworkChanges(m); - if (err) return(err); - - err = WatchForPowerChanges(m); - if (err) return err; + if (err) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err); return(err); } + + // Explicitly ensure that our Keychain operations utilize the system domain. +#ifndef NO_SECURITYFRAMEWORK + SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem); +#endif + + mDNS_Lock(m); + SetDomainSecrets(m); + SetLocalDomains(); + mDNS_Unlock(m); + +#ifndef NO_SECURITYFRAMEWORK + err = SecKeychainAddCallback(KeychainChanged, kSecAddEventMask|kSecDeleteEventMask|kSecUpdateEventMask, m); + if (err) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err); return(err); } +#endif - DynDNSRegDomain.c[0] = '\0'; - DynDNSConfigChanged(m); // Get initial DNS configuration +#ifndef NO_IOPOWER + m->p->PowerConnection = IORegisterForSystemPower(m, &m->p->PowerPortRef, PowerChanged, &m->p->PowerNotifier); + if (!m->p->PowerConnection) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); } + else CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode); +#endif /* NO_IOPOWER */ - InitDNSConfig(m); - return(err); + return(mStatus_NoError); } mDNSexport mStatus mDNSPlatformInit(mDNS *const m) { +#if MDNS_NO_DNSINFO + LogMsg("Note: Compiled without Apple-specific Split-DNS support"); +#endif + mStatus result = mDNSPlatformInit_setup(m); - + // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately if (result == mStatus_NoError) mDNSCoreInitComplete(m, mStatus_NoError); @@ -3602,15 +3909,17 @@ mDNSexport void mDNSPlatformClose(mDNS *const m) { if (m->p->PowerConnection) { - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->PowerRLS, kCFRunLoopDefaultMode); - CFRunLoopSourceInvalidate(m->p->PowerRLS); - CFRelease(m->p->PowerRLS); + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode); +#ifndef NO_IOPOWER + // According to , a single call + // to IORegisterForSystemPower creates *three* objects that need to be disposed individually: IODeregisterForSystemPower(&m->p->PowerNotifier); + IOServiceClose ( m->p->PowerConnection); + IONotificationPortDestroy ( m->p->PowerPortRef); +#endif /* NO_IOPOWER */ m->p->PowerConnection = 0; - m->p->PowerNotifier = 0; - m->p->PowerRLS = NULL; } - + if (m->p->Store) { CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode); @@ -3620,13 +3929,27 @@ mDNSexport void mDNSPlatformClose(mDNS *const m) m->p->Store = NULL; m->p->StoreRLS = NULL; } - + mDNSs32 utc = mDNSPlatformUTC(); MarkAllInterfacesInactive(m, utc); ClearInactiveInterfaces(m, utc); - CloseSocketSet(&m->p->unicastsockets); + CloseSocketSet(&m->p->permanentsockets); + + #if APPLE_OSX_mDNSResponder + if (m->AutoTunnelHostAddrActive && m->AutoTunnelHostAddr.b[0]) + { + m->AutoTunnelHostAddrActive = mDNSfalse; + LogMsg("Removing AutoTunnel address %.16a", &m->AutoTunnelHostAddr); + (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown, m->AutoTunnelHostAddr.b); + } + #endif // APPLE_OSX_mDNSResponder } +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - +#pragma mark - General Platform Support Layer functions +#endif + mDNSexport mDNSu32 mDNSPlatformRandomSeed(void) { return(mach_absolute_time()); @@ -3665,6 +3988,7 @@ mDNSexport mDNSs32 mDNSPlatformRawTime(void) if (clockdivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); } static uint64_t last_mach_absolute_time = 0; + //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display uint64_t this_mach_absolute_time = mach_absolute_time(); if ((int64_t)this_mach_absolute_time - (int64_t)last_mach_absolute_time < 0) { @@ -3672,9 +3996,14 @@ mDNSexport mDNSs32 mDNSPlatformRawTime(void) LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time); // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug() last_mach_absolute_time = this_mach_absolute_time; - // Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xyyy) or later + // Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xyyy) or later. + // (This bug happens all the time on 10.3, and we know that's not going to be fixed.) if (mDNSMacOSXSystemBuildNumber(NULL) >= 8) - NotifyOfElusiveBug("mach_absolute_time went backwards!", 3438376, ""); + NotifyOfElusiveBug("mach_absolute_time went backwards!", + "This error occurs from time to time, often on newly released hardware, " + "and usually the exact cause is different in each instance.\r\r" + "Please file a new Radar bug report with the title “mach_absolute_time went backwards” " + "and assign it to Radar Component “Kernel” Version “X”."); } last_mach_absolute_time = this_mach_absolute_time; @@ -3689,10 +4018,12 @@ mDNSexport mDNSs32 mDNSPlatformUTC(void) // Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; } mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; } -mDNSexport void mDNSPlatformStrCopy(const void *src, void *dst) { strcpy((char *)dst, (char *)src); } -mDNSexport mDNSu32 mDNSPlatformStrLen (const void *src) { return(strlen((char*)src)); } -mDNSexport void mDNSPlatformMemCopy(const void *src, void *dst, mDNSu32 len) { memcpy(dst, src, len); } -mDNSexport mDNSBool mDNSPlatformMemSame(const void *src, const void *dst, mDNSu32 len) { return(memcmp(dst, src, len) == 0); } -mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) { bzero(dst, len); } +mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { strcpy((char *)dst, (char *)src); } +mDNSexport mDNSu32 mDNSPlatformStrLen ( const void *src) { return(strlen((char*)src)); } +mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, mDNSu32 len) { memcpy(dst, src, len); } +mDNSexport mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len) { return(memcmp(dst, src, len) == 0); } +mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) { bzero(dst, len); } +#if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING) mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); } +#endif mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); } diff --git a/mDNSMacOSX/mDNSMacOSX.h b/mDNSMacOSX/mDNSMacOSX.h index 7dd31be..6e8f12f 100644 --- a/mDNSMacOSX/mDNSMacOSX.h +++ b/mDNSMacOSX/mDNSMacOSX.h @@ -1,203 +1,92 @@ -/* +/* -*- Mode: C; tab-width: 4 -*- + * * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: mDNSMacOSX.h,v $ -Revision 1.51 2005/07/04 22:24:36 cheshire -Export NotifyOfElusiveBug() so other files can call it - -Revision 1.50 2005/02/19 00:04:18 cheshire -Add comments - -Revision 1.49 2004/12/17 23:37:47 cheshire - Guard against repeating wireless dissociation/re-association -(and other repetitive configuration changes) - -Revision 1.48 2004/12/07 01:31:31 cheshire -mDNSMacOSXSystemBuildNumber() returns int, not mDNSBool - -Revision 1.47 2004/11/30 03:24:03 cheshire - Defer processing network configuration changes until configuration has stabilized - -Revision 1.46 2004/11/03 03:45:16 cheshire - mDNSResponder does not inform user of Computer Name collisions - -Revision 1.45 2004/10/28 00:53:57 cheshire -Export mDNSMacOSXNetworkChanged() so it's callable from outside this mDNSMacOSX.c; -Add LogOperation() call to record when we get network change events - -Revision 1.44 2004/10/23 01:16:01 cheshire - uDNS operations not always reliable on multi-homed hosts - -Revision 1.43 2004/10/15 23:00:18 ksekar - Need to update LLQs on location changes - -Revision 1.42 2004/10/04 05:56:04 cheshire - mDNSResponder doesn't respond to certain AirPort changes - -Revision 1.41 2004/09/30 00:24:59 ksekar - Dynamically update default registration domains on config change - -Revision 1.40 2004/09/17 01:08:52 cheshire -Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h - The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces - declared in that file are ONLY appropriate to single-address-space embedded applications. - For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used. - -Revision 1.39 2004/08/18 17:35:41 ksekar -: Feature #9586: Need support for Legacy NAT gateways - -Revision 1.38 2004/07/13 21:24:25 rpantos -Fix for . - -Revision 1.37 2004/06/04 08:58:30 ksekar -: Keychain integration for secure dynamic update - -Revision 1.36 2004/05/26 17:06:33 cheshire -: Don't rely on CFSocketInvalidate() to remove RunLoopSource - -Revision 1.35 2004/05/18 23:51:26 cheshire -Tidy up all checkin comments to use consistent "" format for bug numbers - -Revision 1.34 2004/05/12 22:03:09 ksekar -Made GetSearchDomainList a true platform-layer call (declaration moved -from mDNSMacOSX.h to mDNSEmbeddedAPI.h), impelemted to return "local" -only on non-OSX platforms. Changed call to return a copy of the list -to avoid shared memory issues. Added a routine to free the list. - -Revision 1.33 2004/05/12 02:03:25 ksekar -Non-local domains will only be browsed by default, and show up in -_browse domain enumeration, if they contain an _browse._dns-sd ptr record. - -Revision 1.32 2004/04/21 02:20:47 cheshire -Rename interface field 'CurrentlyActive' to more descriptive 'Exists' +Revision 1.72 2007/08/01 16:09:14 cheshire +Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly -Revision 1.31 2004/04/09 17:40:26 cheshire -Remove unnecessary "Multicast" field -- it duplicates the semantics of the existing TxAndRx field +Revision 1.71 2007/07/27 23:57:23 cheshire +Added compile-time structure size checks -Revision 1.30 2004/01/28 02:30:08 ksekar -Added default Search Domains to unicast browsing, controlled via -Networking sharing prefs pane. Stopped sending unicast messages on -every interface. Fixed unicast resolving via mach-port API. +Revision 1.70 2007/07/11 02:55:50 cheshire + Register IPv6-only hostname and don't create port mappings for AutoTunnel services +Remove unused DefaultRegDomainChanged/DefaultBrowseDomainChanged -Revision 1.29 2004/01/27 22:57:48 cheshire -: Need separate socket for issuing unicast queries +Revision 1.69 2007/05/08 00:56:17 cheshire + Share single socket instead of creating separate socket for each active interface -Revision 1.28 2004/01/27 20:15:23 cheshire -: Time to prune obsolete code for listening on port 53 +Revision 1.68 2007/04/24 00:10:15 cheshire +Increase WatchDogReportingThreshold to 250ms for customer builds -Revision 1.27 2004/01/24 08:46:26 bradley -Added InterfaceID<->Index platform interfaces since they are now used by all platforms for the DNS-SD APIs. +Revision 1.67 2007/04/21 21:47:47 cheshire + Daemon: Add watchdog timer -Revision 1.26 2003/12/08 21:00:46 rpantos -Changes to support mDNSResponder on Linux. +Revision 1.66 2007/04/07 01:01:48 cheshire + mDNSResponder periodically blocks in SSLRead -Revision 1.25 2003/11/08 22:18:29 cheshire -: Don't need to show process ID in *every* mDNSResponder syslog message +Revision 1.65 2007/03/07 02:50:50 cheshire + Name conflict dialog doesn't appear if Bonjour is persistantly unable to find an available hostname -Revision 1.24 2003/11/08 22:13:00 cheshire -Move extern declarations inside '#ifdef __cplusplus extern "C" {' section +Revision 1.64 2007/03/06 23:29:50 cheshire + Need to call IONotificationPortDestroy on shutdown -Revision 1.23 2003/09/23 16:38:25 cheshire -When LogAllOperations is false, treat LogOperation() like debugf() -(i.e. show in debug builds), rather than unconditionally ignoring +Revision 1.63 2007/02/07 19:32:00 cheshire + All mDNSResponder components should contain version strings in SCCS-compatible format -Revision 1.22 2003/09/23 02:12:43 cheshire -Also include port number in list of services registered via new UDS API +Revision 1.62 2007/01/05 08:30:49 cheshire +Trim excessive "$Log" checkin history from before 2006 +(checkin history still available via "cvs log ..." of course) -Revision 1.21 2003/08/19 22:20:00 cheshire - Don't use IPv6 on interfaces that have a routable IPv4 address configured -More minor refinements +Revision 1.61 2006/08/14 23:24:40 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 -Revision 1.20 2003/08/19 05:39:43 cheshire - SIGINFO dump should include resolves started by DNSServiceQueryRecord +Revision 1.60 2006/07/27 03:24:35 cheshire + Convert mDNSResponder to use kqueue +Further refinement: Declare KQueueEntry parameter "const" -Revision 1.19 2003/08/19 05:36:45 cheshire -Add missing "extern" directives +Revision 1.59 2006/07/27 02:59:25 cheshire + Convert mDNSResponder to use kqueue +Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread +after releasing BigMutex, in case actions it took have resulted in new work for the +kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to +add new active interfaces to its list, and consequently schedule queries to be sent). -Revision 1.18 2003/08/19 03:04:43 cheshire - Don't use IPv6 on interfaces that have a routable IPv4 address configured +Revision 1.58 2006/07/22 06:08:29 cheshire + Convert mDNSResponder to use kqueue +Further changes -Revision 1.17 2003/08/12 19:56:25 cheshire -Update to APSL 2.0 +Revision 1.57 2006/07/22 03:43:26 cheshire + Convert mDNSResponder to use kqueue -Revision 1.16 2003/08/08 18:36:04 cheshire - Only need to revalidate on interface removal on platforms that have the PhantomInterfaces bug +Revision 1.56 2006/07/05 23:37:26 cheshire +Remove unused LegacyNATInit/LegacyNATDestroy declarations -Revision 1.15 2003/08/05 00:32:28 cheshire - Time to turn off MACOSX_MDNS_MALLOC_DEBUGGING +Revision 1.55 2006/06/29 05:33:30 cheshire + mDNSResponder conditional compilation options -Revision 1.14 2003/07/20 03:38:51 ksekar - Completed support for Unix-domain socket based API. +Revision 1.54 2006/03/19 03:27:49 cheshire + Suppress "interface flapping" logic for loopback -Revision 1.13 2003/07/18 00:30:00 cheshire - Remove mDNSResponder version from packet header and use HINFO record instead +Revision 1.53 2006/03/19 02:00:09 cheshire + Improve logic for delaying packets after repeated interface transitions -Revision 1.12 2003/07/12 03:15:20 cheshire - After SCDynamicStore notification, mDNSResponder updates -m->hostlabel even if user hasn't actually actually changed their dot-local hostname - -Revision 1.11 2003/07/02 21:19:51 cheshire - Update copyright notices, etc., in source code comments - -Revision 1.10 2003/06/25 23:42:19 ksekar -: Feature: New DNS-SD APIs (#7875) -Reviewed by: Stuart Cheshire -Added files necessary to implement Unix domain sockets based enhanced -DNS-SD APIs, and integrated with existing Mach-port based daemon. - -Revision 1.9 2003/06/10 01:14:11 cheshire - New APIs require a mDNSPlatformInterfaceIDfromInterfaceIndex() call - -Revision 1.8 2003/05/14 07:08:37 cheshire - mDNSResponder should be smarter about reconfigurations -Previously, when there was any network configuration change, mDNSResponder -would tear down the entire list of active interfaces and start again. -That was very disruptive, and caused the entire cache to be flushed, -and caused lots of extra network traffic. Now it only removes interfaces -that have really gone, and only adds new ones that weren't there before. - -Revision 1.7 2003/04/26 02:39:24 cheshire -Remove extern void LogMsg(const char *format, ...); - -Revision 1.6 2003/03/05 21:59:56 cheshire - Additional debugging code in mDNSResponder - -Revision 1.5 2003/03/05 01:50:38 cheshire - Additional debugging code in mDNSResponder - -Revision 1.4 2003/02/21 01:54:10 cheshire - mDNSResponder needs performance improvements -Switched to using new "mDNS_Execute" model (see "Implementer Notes.txt") - -Revision 1.3 2002/09/21 20:44:51 zarzycki -Added APSL info - -Revision 1.2 2002/09/19 04:20:44 cheshire -Remove high-ascii characters that confuse some systems - -Revision 1.1 2002/09/17 01:04:09 cheshire -Defines mDNS_PlatformSupport_struct for OS X +Revision 1.52 2006/01/05 21:41:49 cheshire + Reword "mach_absolute_time went backwards" dialog */ @@ -216,17 +105,22 @@ Defines mDNS_PlatformSupport_struct for OS X typedef struct NetworkInterfaceInfoOSX_struct NetworkInterfaceInfoOSX; +typedef void (*KQueueEventCallback)(int fd, short filter, void *context); +typedef struct + { + KQueueEventCallback KQcallback; + void *KQcontext; + const char const *KQtask; // For debugging messages + } KQueueEntry; + typedef struct { mDNS *m; - NetworkInterfaceInfoOSX *info; int sktv4; - CFSocketRef cfsv4; - CFRunLoopSourceRef rlsv4; + KQueueEntry kqsv4; int sktv6; - CFSocketRef cfsv6; - CFRunLoopSourceRef rlsv6; - } CFSocketSet; + KQueueEntry kqsv6; + } KQSocketSet; struct NetworkInterfaceInfoOSX_struct { @@ -234,44 +128,84 @@ struct NetworkInterfaceInfoOSX_struct NetworkInterfaceInfoOSX *next; mDNSu32 Exists; // 1 = currently exists in getifaddrs list; 0 = doesn't // 2 = exists, but McastTxRx state changed + mDNSs32 AppearanceTime; // Time this interface appeared most recently in getifaddrs list + // i.e. the first time an interface is seen, AppearanceTime is set. + // If an interface goes away temporarily and then comes back then + // AppearanceTime is updated to the time of the most recent appearance. mDNSs32 LastSeen; // If Exists==0, last time this interface appeared in getifaddrs list + mDNSBool Flashing; // Set if interface appeared for less than 60 seconds and then vanished + mDNSBool Occulting; // Set if interface vanished for less than 60 seconds and then came back char *ifa_name; // Memory for this is allocated using malloc + unsigned int ifa_flags; + struct in_addr ifa_v4addr; mDNSu32 scope_id; // interface index / IPv6 scope ID mDNSEthAddr BSSID; // BSSID of 802.11 base station, if applicable u_short sa_family; - mDNSBool Multicast; - CFSocketSet ss; }; struct mDNS_PlatformSupport_struct - { - NetworkInterfaceInfoOSX *InterfaceList; - CFSocketSet unicastsockets; - domainlabel userhostlabel; // The hostlabel as it was set in System Preferences the last time we looked - domainlabel usernicelabel; // The nicelabel as it was set in System Preferences the last time we looked - mDNSs32 NotifyUser; - mDNSs32 NetworkChanged; - SCDynamicStoreRef Store; - CFRunLoopSourceRef StoreRLS; - io_connect_t PowerConnection; - io_object_t PowerNotifier; - CFRunLoopSourceRef PowerRLS; - }; - -extern void NotifyOfElusiveBug(const char *title, mDNSu32 radarid, const char *msg); + { + NetworkInterfaceInfoOSX *InterfaceList; + KQSocketSet permanentsockets; + domainlabel userhostlabel; // The hostlabel as it was set in System Preferences the last time we looked + domainlabel usernicelabel; // The nicelabel as it was set in System Preferences the last time we looked + mDNSs32 NotifyUser; + mDNSs32 HostNameConflict; // Time we experienced conflict on our link-local host name + mDNSs32 NetworkChanged; + SCDynamicStoreRef Store; + CFRunLoopSourceRef StoreRLS; + IONotificationPortRef PowerPortRef; + io_connect_t PowerConnection; + io_object_t PowerNotifier; + pthread_mutex_t BigMutex; + mDNSs32 BigMutexStartTime; + int WakeKQueueLoopFD; + }; + +extern int KQueueFD; + +extern void NotifyOfElusiveBug(const char *title, const char *msg); // Both strings are UTF-8 text extern void mDNSMacOSXNetworkChanged(mDNS *const m); extern int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring); -extern const char mDNSResponderVersionString[]; +extern int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef); + +// 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 const *task); + +// If any event takes more than WatchDogReportingThreshold milliseconds to be processed, we log a warning message +// General event categories are: +// o Mach client request initiated / terminated +// o UDS client request +// o Handling UDP packets received from the network +// o Environmental change events: +// - network interface changes +// - sleep/wake +// - keychain changes +// o Name conflict dialog dismissal +// o Reception of Unix signal (e.g. SIGINFO) +// o Idle task processing +// If we find that we're getting warnings for any of these categories, and it's not evident +// what's causing the problem, we may need to subdivide some categories into finer-grained +// sub-categories (e.g. "Idle task processing" covers a pretty broad range of sub-tasks). + +#if LogAllOperations +#define WatchDogReportingThreshold 50 +#else +#define WatchDogReportingThreshold 250 +#endif -// Legacy NAT Traversal Support Setup/Teardown -extern int LegacyNATDestroy(void); -extern int LegacyNATInit(void); +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. + char sizecheck_NetworkInterfaceInfoOSX[(sizeof(NetworkInterfaceInfoOSX) <= 4100) ? 1 : -1]; + char sizecheck_mDNS_PlatformSupport [(sizeof(mDNS_PlatformSupport) <= 260) ? 1 : -1]; + }; -// Allow platform layer to tell daemon when default registration/browse domains -extern void DefaultRegDomainChanged(const domainname *d, mDNSBool add); -extern void DefaultBrowseDomainChanged(const domainname *d, mDNSBool add); - #ifdef __cplusplus } #endif diff --git a/mDNSMacOSX/mDNSMacOSXPuma.c b/mDNSMacOSX/mDNSMacOSXPuma.c deleted file mode 100644 index 7764e2a..0000000 --- a/mDNSMacOSX/mDNSMacOSXPuma.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - * - * This file is not normally used. - * It can be conditionally compiled in by defining RUN_ON_PUMA_WITHOUT_IFADDRS - * in mDNSMacOSX.c. It is included mainly as sample code for people building - * for other platforms that (like Puma) lack the getifaddrs() call. - * NOTE: YOU CANNOT use this code to build an mDNSResponder daemon for Puma - * that works just like the Jaguar one, because Puma lacks other necessary - * functionality (like the LibInfo support to receive MIG messages from clients). - - Change History (most recent first): - -$Log: mDNSMacOSXPuma.c,v $ -Revision 1.5 2004/09/20 23:52:02 cheshire -CFSocket{Puma}.c renamed to mDNSMacOSX{Puma}.c - -Revision 1.4 2003/08/12 19:56:25 cheshire -Update to APSL 2.0 - -Revision 1.3 2003/07/02 21:19:51 cheshire - Update copyright notices, etc., in source code comments - -Revision 1.2 2002/09/21 20:44:51 zarzycki -Added APSL info - -Revision 1.1 2002/09/17 01:36:23 cheshire -Move Puma support to mDNSMacOSXPuma.c - - */ - -#include -#include -#define ifaddrs ifa_info -#ifndef ifa_broadaddr -#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */ -#endif -#include - -/* Our own header for the programs that need interface configuration info. - Include this file, instead of "unp.h". */ - -#define IFA_NAME 16 /* same as IFNAMSIZ in */ -#define IFA_HADDR 8 /* allow for 64-bit EUI-64 in future */ - -struct ifa_info { - char ifa_name[IFA_NAME]; /* interface name, null terminated */ - u_char ifa_haddr[IFA_HADDR]; /* hardware address */ - u_short ifa_hlen; /* #bytes in hardware address: 0, 6, 8 */ - short ifa_flags; /* IFF_xxx constants from */ - short ifa_myflags; /* our own IFI_xxx flags */ - struct sockaddr *ifa_addr; /* primary address */ - struct sockaddr *ifa_brdaddr;/* broadcast address */ - struct sockaddr *ifa_dstaddr;/* destination address */ - struct ifa_info *ifa_next; /* next of these structures */ -}; - -#define IFI_ALIAS 1 /* ifa_addr is an alias */ - - /* function prototypes */ -struct ifa_info *get_ifa_info(int, int); -struct ifa_info *Get_ifa_info(int, int); -void free_ifa_info(struct ifa_info *); - -#define HAVE_SOCKADDR_SA_LEN 1 - -struct ifa_info * -get_ifa_info(int family, int doaliases) -{ - struct ifa_info *ifi, *ifihead, **ifipnext; - int sockfd, len, lastlen, flags, myflags; - char *ptr, *buf, lastname[IFNAMSIZ], *cptr; - struct ifconf ifc; - struct ifreq *ifr, ifrcopy; - struct sockaddr_in *sinptr; - - sockfd = socket(AF_INET, SOCK_DGRAM, 0); - - lastlen = 0; - len = 100 * sizeof(struct ifreq); /* initial buffer size guess */ - for ( ; ; ) { - buf = (char *) malloc(len); - ifc.ifc_len = len; - ifc.ifc_buf = buf; - if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { - if (errno != EINVAL || lastlen != 0) - debugf("ioctl error"); - } else { - if (ifc.ifc_len == lastlen) - break; /* success, len has not changed */ - lastlen = ifc.ifc_len; - } - len += 10 * sizeof(struct ifreq); /* increment */ - free(buf); - } - ifihead = NULL; - ifipnext = &ifihead; - lastname[0] = 0; -/* end get_ifa_info1 */ - -/* include get_ifa_info2 */ - for (ptr = buf; ptr < buf + ifc.ifc_len; ) { - ifr = (struct ifreq *) ptr; - -#ifdef HAVE_SOCKADDR_SA_LEN - len = MAX(sizeof(struct sockaddr), ifr->ifr_addr.sa_len); -#else - switch (ifr->ifr_addr.sa_family) { -#ifdef IPV6 - case AF_INET6: - len = sizeof(struct sockaddr_in6); - break; -#endif - case AF_INET: - default: - len = sizeof(struct sockaddr); - break; - } -#endif /* HAVE_SOCKADDR_SA_LEN */ - ptr += sizeof(ifr->ifr_name) + len; /* for next one in buffer */ - - if (ifr->ifr_addr.sa_family != family) - continue; /* ignore if not desired address family */ - - myflags = 0; - if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL) - *cptr = 0; /* replace colon will null */ - if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) { - if (doaliases == 0) - continue; /* already processed this interface */ - myflags = IFI_ALIAS; - } - memcpy(lastname, ifr->ifr_name, IFNAMSIZ); - - ifrcopy = *ifr; - ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy); - flags = ifrcopy.ifr_flags; - if ((flags & IFF_UP) == 0) - continue; /* ignore if interface not up */ - - ifi = (struct ifa_info *) calloc(1, sizeof(struct ifa_info)); - *ifipnext = ifi; /* prev points to this new one */ - ifipnext = &ifi->ifa_next; /* pointer to next one goes here */ - - ifi->ifa_flags = flags; /* IFF_xxx values */ - ifi->ifa_myflags = myflags; /* IFI_xxx values */ - memcpy(ifi->ifa_name, ifr->ifr_name, IFA_NAME); - ifi->ifa_name[IFA_NAME-1] = '\0'; -/* end get_ifa_info2 */ -/* include get_ifa_info3 */ - switch (ifr->ifr_addr.sa_family) { - case AF_INET: - sinptr = (struct sockaddr_in *) &ifr->ifr_addr; - if (ifi->ifa_addr == NULL) { - ifi->ifa_addr = (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in)); - memcpy(ifi->ifa_addr, sinptr, sizeof(struct sockaddr_in)); - -#ifdef SIOCGIFBRDADDR - if (flags & IFF_BROADCAST) { - ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy); - sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr; - ifi->ifa_brdaddr = (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in)); - memcpy(ifi->ifa_brdaddr, sinptr, sizeof(struct sockaddr_in)); - } -#endif - -#ifdef SIOCGIFDSTADDR - if (flags & IFF_POINTOPOINT) { - ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy); - sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr; - ifi->ifa_dstaddr = (struct sockaddr *) calloc(1, sizeof(struct sockaddr_in)); - memcpy(ifi->ifa_dstaddr, sinptr, sizeof(struct sockaddr_in)); - } -#endif - } - break; - - default: - break; - } - } - free(buf); - return(ifihead); /* pointer to first structure in linked list */ -} -/* end get_ifa_info3 */ - -/* include free_ifa_info */ -mDNSlocal void freeifaddrs(struct ifa_info *ifihead) -{ - struct ifa_info *ifi, *ifinext; - - for (ifi = ifihead; ifi != NULL; ifi = ifinext) { - if (ifi->ifa_addr != NULL) - free(ifi->ifa_addr); - if (ifi->ifa_brdaddr != NULL) - free(ifi->ifa_brdaddr); - if (ifi->ifa_dstaddr != NULL) - free(ifi->ifa_dstaddr); - ifinext = ifi->ifa_next; /* can't fetch ifa_next after free() */ - free(ifi); /* the ifa_info{} itself */ - } -} -/* end free_ifa_info */ - -struct ifa_info * -Get_ifa_info(int family, int doaliases) -{ - struct ifa_info *ifi; - - if ( (ifi = get_ifa_info(family, doaliases)) == NULL) - debugf("get_ifa_info error"); - return(ifi); -} - -mDNSlocal int getifaddrs(struct ifa_info **ifalist) - { - *ifalist = get_ifa_info(PF_INET, false); - if( ifalist == nil ) - return -1; - else - return(0); - } diff --git a/mDNSMacOSX/mDNSResponder-bundle/Resources/English.lproj/Localizable.strings b/mDNSMacOSX/mDNSResponder-bundle/Resources/English.lproj/Localizable.strings index bba4c2c..7b88ff9 100644 --- a/mDNSMacOSX/mDNSResponder-bundle/Resources/English.lproj/Localizable.strings +++ b/mDNSMacOSX/mDNSResponder-bundle/Resources/English.lproj/Localizable.strings @@ -1,10 +1,13 @@ -"The name of your computer" = "The name of your computer"; -"This computer’s local hostname" = "This computer’s local hostname"; -"is already in use on this network." = "is already in use on this network."; +"The name of your computer " = "The name of your computer "; +"This computer’s local hostname " = "This computer’s local hostname "; +"“" = "“"; +"”" = "”"; +" is already in use on this network. " = " is already in use on this network. "; +"The name has been changed to " = "The name has been changed to "; +"." = "."; -"The name has been changed to" = "The name has been changed to"; -"automatically." = "automatically."; +"To change the name of your computer, open System Preferences and click Sharing, then type the name in the Computer Name field." = "To change the name of your computer, open System Preferences and click Sharing, then type the name in the Computer Name field."; +"To change the local hostname, open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field." = "To change the local hostname, open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field."; -"To change the name of your computer, open System Preferences and click Sharing. Then type the name in the Computer Name field." = "To change the name of your computer, open System Preferences and click Sharing. Then type the name in the Computer Name field."; - -"To change the local hostname, open System Preferences and click Sharing. Then click Edit and type the name in the Local Hostname field." = "To change the local hostname, open System Preferences and click Sharing. Then click Edit and type the name in the Local Hostname field."; +"All attempts to find an available name by adding a number to the name were also unsuccessful." = "All attempts to find an available name by adding a number to the name were also unsuccessful."; +"This may indicate a problem with the local network. Please inform your network administrator." = "This may indicate a problem with the local network. Please inform your network administrator."; diff --git a/mDNSMacOSX/mDNSResponder-bundle/Resources/French.lproj/Localizable.strings b/mDNSMacOSX/mDNSResponder-bundle/Resources/French.lproj/Localizable.strings index be7a444..453d556 100644 --- a/mDNSMacOSX/mDNSResponder-bundle/Resources/French.lproj/Localizable.strings +++ b/mDNSMacOSX/mDNSResponder-bundle/Resources/French.lproj/Localizable.strings @@ -1,10 +1,13 @@ -"The name of your computer" = "Le nom de l’ordinateur"; -"This computer’s local hostname" = "Le nom d’hôte local de cet ordinateur"; -"is already in use on this network." = "est déjà utilié sur ce réseau."; +"The name of your computer " = "Le nom de l’ordinateur "; +"This computer’s local hostname " = "Le nom d’hôte local de cet ordinateur "; +"“" = "“"; +"”" = "”"; +" is already in use on this network. " = " est déjà utilié sur ce réseau. "; +"The name has been changed to " = "Le nom a été changé pa "; +"." = "."; -"The name has been changed to" = "Le non a été changé par"; -"automatically." = "automatiquement."; +"To change the name of your computer, open System Preferences and click Sharing, then type the name in the Computer Name field." = "Pour changer le nom de votre ordinateur, ouvrez Préférences Systèmes et cliquer Partage. Ensuite entrez le nom dans le champ Nom de l’ordinateur."; +"To change the local hostname, open System Preferences and click Sharing, then click “Edit” and type the name in the Local Hostname field." = "Pour changer le nom d’hôte local, ouvrez Préférences Systèmes et cliquer Partage. Ensuite cliquer Modifier et entrez le nom dans le champ Nom local de l’ordinateur."; -"To change the name of your computer, open System Preferences and click Sharing. Then type the name in the Computer Name field." = "Pour changer le nom de votre ordinateur, ouvrez Préférences Systèmes et cliquer Partage. Ensuite entrez le nom dans le champ Nom de l’ordinateur."; - -"To change the local hostname, open System Preferences and click Sharing. Then click Edit and type the name in the Local Hostname field." = "Pour changer le nom d’hôte local, ouvrez Préférences Systèmes et cliquer Partage. Ensuite cliquer Modifier et entrez le nom dans le champ Nom local de l’ordinateur."; +"All attempts to find an available name by adding a number to the name were also unsuccessful." = "Toutes les tentatives de trouver un nom disponible en ajoutant un nombre au nom étaient également non réussies."; +"This may indicate a problem with the local network. Please inform your network administrator." = "Ceci peut indiquer un problème avec le réseau local. Veuillez informer votre administrateur de réseau."; diff --git a/mDNSMacOSX/mDNSResponder.order b/mDNSMacOSX/mDNSResponder.order index 62c0240..a0cc39d 100644 --- a/mDNSMacOSX/mDNSResponder.order +++ b/mDNSMacOSX/mDNSResponder.order @@ -1,377 +1,367 @@ -no_module:start -no_module:__call_mod_init_funcs -no_module:__start -no_module:__dyld_func_lookup -no_module:dyld_stub_binding_helper -no_module:_main -no_module:_LogMsgIdent -no_module:_mDNS_vsnprintf -no_module:_WriteLogMsg -no_module:_mDNSDaemonInitialize -no_module:_mDNSMacOSXSystemBuildNumber -no_module:_mDNS_Init -no_module:_mDNSPlatformTimeInit -no_module:___udivdi3 -no_module:_mDNSRandom -no_module:_mDNSPlatformRandomSeed -no_module:_mDNSPlatformRawTime -no_module:_mDNS_GrowCache_internal -no_module:_LogMsg -no_module:_uDNS_Init -no_module:_mDNSPlatformMemZero -no_module:_mDNSPlatformInit -no_module:_mDNSPlatformInit_setup -no_module:_mDNS_snprintf -no_module:_mDNSPlatformInit_CanReceiveUnicast -no_module:_mDNSPlatformStrLen -no_module:_mDNSPlatformMemCopy -no_module:_SetupSocket -no_module:_mDNSPlatformUTC -no_module:_UpdateInterfaceList -no_module:_myGetIfAddrs -no_module:_AddInterfaceToList -no_module:_GetBSSID -no_module:_SetupAddr -no_module:_mallocL -no_module:_validatelists -no_module:_mDNSSameAddress -no_module:_FindRoutableIPv4 -no_module:_GetUserSpecifiedFriendlyComputerName -no_module:_GetUserSpecifiedLocalHostName -no_module:_SameDomainLabel -no_module:_mDNS_SetFQDN -no_module:_AppendDomainLabel -no_module:_DomainNameLength -no_module:_AppendLiteralLabelString -no_module:_SameDomainName -no_module:_mDNS_Lock -no_module:_mDNSPlatformLock -no_module:_mDNS_Unlock -no_module:_GetNextScheduledEvent -no_module:_mDNSPlatformUnlock -no_module:_SetupActiveInterfaces -no_module:_SearchForInterfaceByName -no_module:_mDNS_RegisterInterface -no_module:_AdvertiseInterface -no_module:_FindFirstAdvertisedInterface -no_module:_mDNS_SetupResourceRecord -no_module:_MakeDomainNameFromDNSNameString -no_module:_AppendDNSNameString -no_module:_mDNS_Register_internal -no_module:_IsLocalDomain -no_module:_InitializeLastAPTime -no_module:_SetNextAnnounceProbeTime -no_module:_GetRDLength -no_module:_ValidateRData -no_module:_DomainNameHashValue -no_module:_RDataHashValue -no_module:_SetTargetToHostName -no_module:_SetNewRData -no_module:_CompressedDomainNameLength -no_module:_AcknowledgeRecord -no_module:_IdenticalResourceRecord -no_module:_CountMaskBits -no_module:_SameRData -no_module:_mDNSPlatformMemSame -no_module:_WatchForNetworkChanges -no_module:_WatchForPowerChanges -no_module:_DynDNSConfigChanged -no_module:_GetUserSpecifiedDDNSConfig -no_module:_ReadDDNSSettingsFromConfFile -no_module:_RegisterSplitDNS -no_module:_GetDNSConfig -no_module:_RegisterSearchDomains -no_module:_GetSearchDomains -no_module:_GetDSSearchDomains -no_module:_IsPrivateV4Addr -no_module:_mDNS_SetPrimaryInterfaceInfo -no_module:_InitDNSConfig -no_module:_mDNS_GetDomains -no_module:_AppendDomainName -no_module:_mDNS_StartQuery -no_module:_mDNS_StartQuery_internal -no_module:_CheckForSoonToExpireRecords -no_module:_CacheGroupForName -no_module:_FindDuplicateQuestion -no_module:_SetSCPrefsBrowseDomain -no_module:_RegisterBrowseDomainPTR -no_module:_mDNS_Register -no_module:_FreeARElemCallback -no_module:_mDNSCoreInitComplete -no_module:_mDNS_StatusCallback -no_module:_RecordUpdatedNiceLabel -no_module:_udsserver_init -no_module:_udsSupportAddFDToEventLoop -no_module:_InitLinkedList -no_module:_AddToTail -no_module:_mDNSDaemonIdle -no_module:_mDNS_TimeNow -no_module:_mDNS_Execute -no_module:_AnswerNewLocalOnlyQuestion -no_module:_uDNS_Execute -no_module:_mDNSPlatformTimeNow -no_module:_CheckNATMappings -no_module:_CheckQueries -no_module:_CheckRecordRegistrations -no_module:_CheckServiceRegistrations -no_module:_udsserver_idle -no_module:_cf_callback -no_module:_connect_callback -no_module:_request_callback -no_module:_read_msg -no_module:_ConvertHeaderBytes -no_module:_validate_message -no_module:_handle_regservice_request -no_module:_get_long -no_module:_mDNSPlatformInterfaceIDfromInterfaceIndex -no_module:_get_string -no_module:_get_short -no_module:_get_rdata -no_module:_ChopSubTypes -no_module:_FindFirstSubType -no_module:_ConstructServiceName -no_module:_CountExistingRegistrations -no_module:_register_service_instance -no_module:_AllocateSubTypes -no_module:_mDNS_RegisterService -no_module:_ServiceCallback -no_module:_mDNSPlatformGetRegDomainList -no_module:_mDNS_CopyDNameList -no_module:_mDNS_FreeDNameList -no_module:_deliver_error -no_module:_dnssd_htonl -no_module:_put_long -no_module:_reset_connected_rstate -no_module:_freeL -no_module:_SendQueries -no_module:_GetFirstActiveInterface -no_module:_InitializeDNSMessage -no_module:_putQuestion -no_module:_putDomainNameAsLabels -no_module:_FindCompressionPointer -no_module:_GetNextActiveInterfaceID -no_module:_PutResourceRecordTTLWithLimit -no_module:_putRData -no_module:_mDNSSendDNSMessage -no_module:_mDNSPlatformSendUDP -no_module:_mDNSAddrIsDNSMulticast -no_module:_myCFSocketCallBack -no_module:_myrecvfrom -no_module:_mDNSCoreReceive -no_module:_mDNSCoreReceiveQuery -no_module:_ProcessQuery -no_module:_AddressIsLocalSubnet -no_module:_getQuestion -no_module:_getDomainName -no_module:_ResourceRecordAnswersQuestion -no_module:_ResolveSimultaneousProbe -no_module:_LocateAuthorities -no_module:_LocateAnswers -no_module:_skipQuestion -no_module:_skipDomainName -no_module:_GetLargeResourceRecord -no_module:_PacketRRConflict -no_module:_MatchDependentOn -no_module:_FindRRSet -no_module:_AddAdditionalsToResponseList -no_module:_NetworkChanged -no_module:_MakeDomainLabelFromLiteralString -no_module:_mDNSMacOSXNetworkChanged -no_module:_MarkAllInterfacesInactive -no_module:_ClearInactiveInterfaces -no_module:_mDNS_DeregisterInterface -no_module:_UpdateInterfaceProtocols -no_module:_DeadvertiseInterface -no_module:_mDNS_Deregister_internal -no_module:_mDNS_HostNameCallback -no_module:_CloseSocketSet -no_module:_CloseRunLoopSourceSocket -no_module:_NumCacheRecordsForInterfaceID -no_module:_RegisterNameServers -no_module:_mDNS_DeleteDNSServers -no_module:_mDNS_AddDNSServer -no_module:_mDNSPlatformMemAllocate -no_module:_MarkSearchListElem -no_module:_uDNS_StartQuery -no_module:_startQuery -no_module:_newMessageID -no_module:_constructQueryMsg -no_module:_initializeQuery -no_module:_LinkActiveQuestion -no_module:_uDNS_IsActiveQuery -no_module:_GetServerForName -no_module:_CountLabels -no_module:_UpdateHostnameRegistrations -no_module:_UpdateSRVRecords -no_module:_GetStaticHostname -no_module:_mDNS_UpdateLLQs -no_module:_SuspendLLQs -no_module:_CheckForUnreferencedLLQMapping -no_module:_RestartQueries -no_module:_udsserver_handle_configchange -no_module:_rename_service -no_module:_AnswerLocalQuestions -no_module:_AnswerLocalOnlyQuestionWithResourceRecord -no_module:_FoundDefBrowseDomain -no_module:_DefaultBrowseDomainChanged -no_module:_udsserver_default_browse_domain_changed -no_module:_SendResponses -no_module:_uDNS_ReceiveMsg -no_module:_recvLLQResponse -no_module:_simpleResponseHndlr -no_module:_pktResponseHndlr -no_module:_deriveGoodbyes -no_module:_mDNSCoreReceiveResponse -no_module:_kaListContainsAnswer -no_module:_addKnownAnswer -no_module:_FoundDomain -no_module:_SameResourceRecord -no_module:_mDNSPlatformMemFree -no_module:_FoundStaticHostname -no_module:_PacketRRMatchesSignature -no_module:_CacheGroupForRecord -no_module:_GetCacheGroup -no_module:_GetCacheEntity -no_module:_GetCacheRecord -no_module:_CacheRecordAdd -no_module:_SetNextCacheCheckTime -no_module:_SameResourceRecordSignature -no_module:_CacheRecordDeferredAdd -no_module:_regservice_callback -no_module:_process_service_registration -no_module:_gen_rr_response -no_module:_DeconstructServiceName -no_module:_ConvertDomainLabelToCString_withescape -no_module:_ConvertDomainNameToCString_withescape -no_module:_create_reply -no_module:_mDNSPlatformInterfaceIndexfromInterfaceID -no_module:_put_string -no_module:_send_msg -no_module:_CountPeerRegistrations -no_module:_CheckCacheExpiration -no_module:_FindIdenticalRecordInCache -no_module:_handle_browse_request -no_module:_mDNSPlatformGetSearchDomainList -no_module:_add_domain_to_browser -no_module:_mDNS_StartBrowse -no_module:_SetNextQueryTime -no_module:_startLLQ -no_module:_startGetZoneData -no_module:_getZoneData -no_module:_hndlLookupSOA -no_module:_startInternalQuery -no_module:_AnswerNewQuestion -no_module:_ExpireDupSuppressInfo -no_module:_SuppressOnThisInterface -no_module:_BuildQuestion -no_module:_uDNS_StopQuery -no_module:_processSOA -no_module:_confirmNS -no_module:_lookupNSAddr -no_module:_LocateAdditionals -no_module:_skipResourceRecord -no_module:_hndlLookupPorts -no_module:_lookupDNSPort -no_module:_startLLQHandshakeCallback -no_module:_mDNS_GrowCache -no_module:_AnswerQuestionWithResourceRecord -no_module:_browse_result_callback -no_module:_DNSTypeName -no_module:_GetRRDisplayString_rdb -no_module:_append_reply -no_module:_llqResponseHndlr -no_module:_AccelerateThisQuery -no_module:_ReconfirmAntecedents -no_module:_handle_enum_request -no_module:_format_enumeration_reply -no_module:_enum_result_callback -no_module:_ReleaseCacheRecord -no_module:_ReleaseCacheEntity -no_module:_AddRecordToResponseList -no_module:_ShouldSuppressKnownAnswer -no_module:_RecordDupSuppressInfo -no_module:_ReleaseCacheGroup -no_module:_CacheRecordRmv -no_module:_hndlTruncatedAnswer -no_module:_mDNSPlatformTCPConnect -no_module:_tcpCFSocketCallback -no_module:_conQueryCallback -no_module:_mDNSPlatformWriteTCP -no_module:_mDNSPlatformReadTCP -no_module:_mDNSPlatformTCPCloseConnection -no_module:_handle_add_request -no_module:_add_record_to_service -no_module:_mDNS_AddRecordToService -no_module:_handle_update_request -no_module:_update_record -no_module:_mDNS_Update -no_module:_handle_query_request -no_module:_question_result_callback -no_module:_put_short -no_module:_put_rdata -no_module:_abort_request -no_module:_question_termination_callback -no_module:_mDNS_StopQuery -no_module:_mDNS_StopQuery_internal -no_module:_UpdateQuestionDuplicates -no_module:_udsSupportRemoveFDFromEventLoop -no_module:_RemoveFromList -no_module:_unlink_request -no_module:_DNSserverCallback -no_module:_DNSServiceDiscoveryRequest_server -no_module:__XDNSServiceResolverResolve_rpc -no_module:___MIG_check__Request__DNSServiceResolverResolve_rpc_t -no_module:_provide_DNSServiceResolverResolve_rpc -no_module:_CheckForExistingClient -no_module:_mDNS_StartResolveService -no_module:_EnableDeathNotificationForClient -no_module:_FoundServiceInfoSRV -no_module:_MachineHasActiveIPv6 -no_module:_FoundServiceInfoTXT -no_module:_FoundServiceInfo -no_module:_FoundInstanceInfo -no_module:_DNSServiceResolverReply_rpc -no_module:_ExpireDupSuppressInfoOnInterface -no_module:_CompleteRDataUpdate -no_module:_update_callback -no_module:_GenerateUnicastResponse -no_module:_PutResourceRecordCappedTTL -no_module:_ClientDeathCallback -no_module:_AbortClient -no_module:_mDNS_StopResolveService -no_module:_mDNS_Reconfirm_internal -no_module:_browse_termination_callback -no_module:_stopLLQ -no_module:_GrantUpdateCredit -no_module:__XDNSServiceBrowserCreate_rpc -no_module:___MIG_check__Request__DNSServiceBrowserCreate_rpc_t -no_module:_provide_DNSServiceBrowserCreate_rpc -no_module:_AddDomainToBrowser -no_module:_FoundInstance -no_module:_DNSServiceBrowserReply_rpc -no_module:__XDNSServiceRegistrationCreate_rpc -no_module:___MIG_check__Request__DNSServiceRegistrationCreate_rpc_t -no_module:_provide_DNSServiceRegistrationCreate_rpc -no_module:_AddServiceInstance -no_module:_RegCallback -no_module:_DNSServiceRegistrationReply_rpc -no_module:_mDNS_DeregisterService -no_module:_CompleteDeregistration -no_module:_FreeServiceInstance -no_module:_PowerChanged -no_module:_mDNSCoreMachineSleep -no_module:_uDNS_Sleep -no_module:_SleepServiceRegistrations -no_module:_SleepRecordRegistrations -no_module:_PurgeCacheResourceRecord -no_module:_regservice_termination_callback -no_module:_free_service_instance -no_module:_FreeExtraRR -no_module:_mDNS_Deregister -no_module:_uDNS_Wake -no_module:_WakeServiceRegistrations -no_module:_WakeRecordRegistrations -no_module:_SendDelayedUnicastResponse -no_module:_mDNS_RenameAndReregisterService -no_module:_FindNextSubType -no_module:_handle_removerecord_request +start +_start +_dyld_func_lookup +main +LogMsg +mDNS_vsnprintf +WriteLogMsg +LogMsgIdent +KQueueSet +mDNSMacOSXSystemBuildNumber +mDNS_Init +mDNSPlatformTimeInit +mDNSRandom +mDNSPlatformRandomSeed +mDNSPlatformRawTime +mDNSPlatformInit +GetUserSpecifiedLocalHostName +mDNS_snprintf +SetupSocket +UpdateInterfaceList +myGetIfAddrs +AddInterfaceToList +SetupAddr +mDNSSameAddress +mDNS_SetFQDN +AppendDomainLabel +AppendLiteralLabelString +SameDomainNameCS +mDNS_Lock +mDNSPlatformLock +DomainNameLengthLimit +mDNSPlatformMemCopy +mDNS_Unlock +mDNSPlatformUnlock +SetupActiveInterfaces +mDNS_RegisterInterface +AdvertiseInterface +mDNS_SetupResourceRecord +MakeDomainNameFromDNSNameString +AppendDNSNameString +mDNS_Register_internal +InitializeLastAPTime +SetNextAnnounceProbeTime +GetRDLength +ValidateRData +DomainNameHashValue +RDataHashValue +SetTargetToHostName +SameDomainName +SetNewRData +CompressedDomainNameLength +AcknowledgeRecord +IdenticalResourceRecord +SetDomainSecrets +mDNSKeychainGetSecrets +getHelperPort +proxy_mDNSKeychainGetSecrets +mDNSDynamicStoreSetConfig +proxy_mDNSDynamicStoreSetConfig +mDNSCoreInitComplete +mDNS_StatusCallback +mDNSPlatformMemSame +uDNS_SetupDNSConfig +mDNSPlatformSetDNSConfig +dns_configuration_copy +_dns_configuration_server_port +shared_dns_infoGet +dns_configuration_free +mDNSPlatformGetPrimaryInterface +mDNS_SetPrimaryInterfaceInfo +udsserver_init +mDNSPlatformMemZero +mDNSPlatformStrCopy +udsSupportAddFDToEventLoop +mDNS_GetDomains +AppendDomainName +mDNS_StartQuery +mDNS_StartQuery_internal +CheckForSoonToExpireRecords +FindDuplicateQuestion +GetAuthInfoForName +RegisterLocalOnlyDomainEnumPTR +mDNSPlatformMemAllocate +mDNS_Register +AddAutoBrowseDomain +udsserver_automatic_browse_domain_changed +machserver_automatic_browse_domain_changed +udsserver_handle_configchange +UpdateDeviceInfoRecord +KQueueLoop +mDNS_TimeNow +mDNS_Execute +uDNS_Execute +mDNSv4AddrIsRFC1918 +udsserver_idle +NetworkChanged +KQueueLock +KQueueUnlock +KQWokenFlushBytes +connect_callback +NewRequest +request_callback +read_msg +ConvertHeaderBytes +handle_enum_request +get_uint32 +mDNSPlatformInterfaceIDfromInterfaceIndex +uDNS_RegisterSearchDomains +put_uint32 +send_all +mDNSMacOSXNetworkChanged +ClearInactiveInterfaces +GetFirstActiveInterface +InitializeDNSMessage +putQuestion +putDomainNameAsLabels +FindCompressionPointer +PutResourceRecordTTLWithLimit +putRData +mDNSSendDNSMessage +mDNSPlatformSendUDP +mDNSAddrIsDNSMulticast +myKQSocketCallBack +mDNSCoreReceive +AddressIsLocalSubnet +getQuestion +getDomainName +ResourceRecordAnswersQuestion +LocateAuthorities +GetLargeResourceRecord +PacketRRConflict +SameRData +SameRDataBody +AddAdditionalsToResponseList +SendResponses +mDNSCoreReceiveResponse +uDNS_recvLLQResponse +LocateAnswers +CreateNewCacheEntry +GetCacheEntity +SetNextCacheCheckTime +CacheRecordDeferredAdd +IdenticalSameNameRecord +mDNS_HostNameCallback +SameResourceRecordSignature +AnswerLocalQuestions +AnswerLocalOnlyQuestionWithResourceRecord +enum_result_callback +ConvertDomainNameToCString_withescape +ConvertDomainLabelToCString_withescape +create_reply +put_string +CheckCacheExpiration +AbortUnlinkAndFree +abort_request +enum_termination_callback +mDNS_StopQuery +mDNS_StopQuery_internal +udsSupportRemoveFDFromEventLoop +get_string +ChopSubTypes +add_domain_to_browser +mDNS_StartBrowse +ConstructServiceName +IsLocalDomain +GetNextActiveInterfaceID +ReconfirmAntecedents +mDNS_DeregisterInterface +DeadvertiseInterface +mDNS_Deregister_internal +NumCacheRecordsForInterfaceID +mDNS_UpdateLLQs +SuspendLLQs +RestartQueries +mDNS_AddSearchDomain +mDNS_NewMessageID +GetServerForName +ActivateUnicastQuery +AddrRequiresPPPConnection +mDNS_AddDNSServer +SetExternalAddress +UpdateSRVRecords +ReleaseCacheRecord +ReleaseCacheGroup +uDNS_CheckCurrentQuestion +NoTestQuery +uDNS_ReceiveMsg +GetLLQOptData +LocateLLQOptData +LocateAdditionals +AnswerCurrentQuestionWithResourceRecord +FoundInstance +GenerateNTDResponse +DeconstructServiceName +mDNSPlatformInterfaceIndexfromInterfaceID +get_uint16 +constructQueryMsg +skipResourceRecord +FoundDomain +FreeARElemCallback +SameNameRecordAnswersQuestion +queryrecord_result_callback +put_uint16 +queryrecord_termination_callback +FoundStaticHostname +AutomaticBrowseDomainChange +FindIdenticalRecordInCache +MakeDomainLabelFromLiteralString +register_service_instance +AllocateSubTypes +mDNS_RegisterService +ServiceCallback +regservice_callback +KeychainChanged +mDNS_SetSecretForDomain +DNSDigest_ConstructHMACKeyfromBase64 +StartGetZoneData +GetZoneData_StartQuery +AppendDNameListElem +SetPrefsBrowseDomains +udsserver_default_reg_domain_changed +machserver_automatic_registration_domain_changed +GetServiceTarget +SetupLocalAutoTunnelInterface_internal +mDNSAutoTunnelInterfaceUpDown +proxy_mDNSAutoTunnelInterfaceUpDown +mDNS_AddDynDNSHostName +AdvertiseHostname +mDNS_StartNATOperation_internal +mDNSConfigureServer +proxy_mDNSConfigureServer +mDNSPlatformUDPSocket +uDNS_SendNATMsg +LNT_SendDiscoveryMsg +uDNS_ReceiveNATPMPPacket +natTraversalHandleAddressReply +hostnameGetPublicAddressCallback +natTraversalHandlePortMapReply +AutoTunnelNATCallback +GetZoneData_QuestionCallback +startLLQHandshakeCallback +startLLQHandshake +StartLLQNatMap +mDNSPlatformMemFree +RecordRegistrationCallback +sendRecordRegistration +putZone +putDeleteRRSet +putUpdateLease +MakeTCPConn +mDNSPlatformTCPSocket +mDNSPlatformTCPConnect +tcpKQSocketCallback +tlsSetupSock +tlsWriteSock +tlsReadSock +LLQNatMapComplete +mDNS_GrowCache +tcpCallback +DNSDigest_SignMessage +MD5_Update +md5_block_host_order +mDNSPlatformUTC +MD5_Final +mDNSPlatformWriteTCP +putLLQ +serviceRegistrationCallback +SendServiceRegistration +putPrereqNameNotInUse +putEmptyResourceRecord +mDNSPlatformReadTCP +DisposeTCPConn +mDNSPlatformTCPCloseConnection +GetPktLease +LocateLeaseOptData +checkUpdateResult +GetRRDisplayString_rdb +startPrivateQueryCallback +HostnameCallback +UpdateSRV +SendServiceDeregistration +putDeleteAllRRSets +putDeletionRecord +StartSRVNatMap +SameDomainLabel +CompleteSRVNatMap +PowerChanged +mDNSCoreMachineSleep +uDNS_Sleep +sendLLQRefresh +mDNS_StopNATOperation_internal +mDNS_Reconfirm_internal +mDNSRandomFromFixedSeed +DeregisterLocalOnlyDomainEnumPTR +mDNS_Deregister +RmvAutoBrowseDomain +uDNS_Wake +uDNS_DeregisterRecord +MakeNegativeCacheRecord +CompleteDeregistration +mDNSPlatformUDPClose +CloseSocketSet +CancelGetZoneData +SendRecordDeregistration +mDNSPlatformStrLen +TruncateUTF8ToLength +get_rdata +mDNS_AddRecordToService +update_record +mDNS_Update +CompleteRDataUpdate +update_callback +ShouldSuppressKnownAnswer +handle_resolve_request +resolve_result_callback +put_rdata +resolve_termination_callback +regservice_termination_callback +mDNS_DeregisterService +browse_termination_callback +free_service_instance +FreeExtraRR +SetNextQueryTime +AddNewClientTunnel +AutoTunnelCallback +FindSourceAddrForIP +AutoTunnelSetKeys +mDNSAutoTunnelSetKeys +proxy_mDNSAutoTunnelSetKeys +ReissueBlockedQuestions +read_rr_from_ipc_msg +CountPeerRegistrations +RecordUpdatedNiceLabel +regrecord_callback +handle_port_mapping_request +mDNS_StartNATOperation +port_mapping_create_request_callback +DNSTypeName +mDNS_StopQueryWithRemoves +uDNS_StopLongLivedQuery +uDNS_ReceiveSSDPPacket +LNT_ConfigureRouterInfo +MakeTCPConnection +tcpConnectionCallback +LNT_GetExternalAddress +SendSOAPMsgControlAction +LNT_MapPort +LNT_UnmapPort +PutResourceRecordCappedTTL +connection_termination +uDNS_DeregisterService +SendServiceRemovalNotification +mDNS_RemoveDynDNSHostName +mDNS_StopNATOperation +unlinkSRS +DDNSSettingEnabled +sendChallengeResponse +mDNSPlatformDynDNSHostNameStatusChanged +UnlinkAuthRecord +DynDNSHostNameCallback +port_mapping_termination_callback +SendDelayedUnicastResponse +RecordProbeFailure +mDNS_RenameAndReregisterService +IncrementLabelSuffix +LabelContainsSuffix +AppendLabelSuffix diff --git a/mDNSMacOSX/mDNSResponder.pbproj/project.pbxproj b/mDNSMacOSX/mDNSResponder.pbproj/project.pbxproj index 648166b..3e7df11 100644 --- a/mDNSMacOSX/mDNSResponder.pbproj/project.pbxproj +++ b/mDNSMacOSX/mDNSResponder.pbproj/project.pbxproj @@ -22,11 +22,11 @@ buildSettings = { FRAMEWORK_SEARCH_PATHS = ""; GCC_TREAT_WARNINGS_AS_ERRORS = YES; - HEADER_SEARCH_PATHS = "../mDNSShared \"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers\" \"${OBJROOT}/mDNSResponder.build\""; - LIBRARY_SEARCH_PATHS = "\"${OBJROOT}/mDNSResponder.build\""; + HEADER_SEARCH_PATHS = "../mDNSShared \"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers\" \"${CONFIGURATION_TEMP_DIR}\""; + LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\""; MACOSX_DEPLOYMENT_TARGET = 10.2; OPTIMIZATION_CFLAGS = "-O0"; - OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -D__MACOSX__ -DmDNSResponderVersion=${MVERS} -DMDNS_DEBUGMSGS=1"; + OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -DmDNSResponderVersion=${MVERS} -DAPPLE_OSX_mDNSResponder=1 -D_LEGACY_NAT_TRAVERSAL_ -DMDNS_DEBUGMSGS=1"; OTHER_LDFLAGS = "-ldnsinfo"; OTHER_REZFLAGS = ""; PRODUCT_NAME = mDNSResponder.debug; @@ -75,6 +75,7 @@ F5E11B5E04A28126019798ED, FFCB6D75075D595E00B8AF62, 00AD62B0032D799A0CCA2C71, + 7FC8F9D606D14E66007E879D, 00AD62B1032D799A0CCA2C71, ); isa = PBXSourcesBuildPhase; @@ -198,6 +199,8 @@ buildRules = ( ); buildSettings = { + CONFIGURATION_BUILD_DIR = "${BUILD_DIR}"; + CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build"; MVERS = "\"mDNSResponder (Engineering Build)\""; }; isa = PBXBuildStyle; @@ -271,6 +274,7 @@ }; 08FB7795FE84155DC02AAC07 = { children = ( + 7FC8F9D406D14E66007E879D, 7F461DB5062DBF2900672BF3, F525E72804AA167501F1CF4D, F5E11B5A04A28126019798ED, @@ -291,8 +295,8 @@ 7F18A9F60587CEF6001880B3, 7F18A9F70587CEF6001880B3, FF25794606C9A8BF00376F7B, - FF25794C06C9A9D500376F7B, - FF25794F06C9AA8B00376F7B, + FF13FFEA0A5DA44A00897C81, + FF13FFEC0A5DA45500897C81, ); isa = PBXGroup; name = "mDNS Server Sources"; @@ -327,11 +331,11 @@ buildSettings = { FRAMEWORK_SEARCH_PATHS = ""; GCC_TREAT_WARNINGS_AS_ERRORS = YES; - HEADER_SEARCH_PATHS = "../mDNSShared \"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers\" \"${OBJROOT}/mDNSResponder.build\""; + HEADER_SEARCH_PATHS = "../mDNSShared \"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers\" \"${CONFIGURATION_TEMP_DIR}\""; INSTALL_PATH = /usr/sbin; - LIBRARY_SEARCH_PATHS = "\"${OBJROOT}/mDNSResponder.build\""; + LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\""; MACOSX_DEPLOYMENT_TARGET = 10.2; - OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -D__MACOSX__ -DmDNSResponderVersion=${MVERS}"; + OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -DmDNSResponderVersion=${MVERS} -DAPPLE_OSX_mDNSResponder=1 -D_LEGACY_NAT_TRAVERSAL_ -D__MigTypeCheck=1"; OTHER_LDFLAGS = "-ldnsinfo"; OTHER_REZFLAGS = ""; PRODUCT_NAME = mDNSResponder; @@ -372,6 +376,7 @@ F5E11B5C04A28126019798ED, FFCB6D74075D539900B8AF62, 6575FBED022EAF7200000109, + 7FC8F9D506D14E66007E879D, 6575FBEE022EAF7200000109, ); isa = PBXSourcesBuildPhase; @@ -620,7 +625,7 @@ GCC_TREAT_WARNINGS_AS_ERRORS = YES; INSTALL_PATH = /usr/bin; MACOSX_DEPLOYMENT_TARGET = 10.2; - OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -D__MACOSX__ -DmDNSResponderVersion=${MVERS}"; + OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic"; OTHER_LDFLAGS = ""; OTHER_REZFLAGS = ""; PRODUCT_NAME = mDNS; @@ -763,6 +768,24 @@ settings = { }; }; + 7FC8F9D406D14E66007E879D = { + fileEncoding = 4; + isa = PBXFileReference; + path = LegacyNATTraversal.c; + refType = 2; + }; + 7FC8F9D506D14E66007E879D = { + fileRef = 7FC8F9D406D14E66007E879D; + isa = PBXBuildFile; + settings = { + }; + }; + 7FC8F9D606D14E66007E879D = { + fileRef = 7FC8F9D406D14E66007E879D; + isa = PBXBuildFile; + settings = { + }; + }; //7F0 //7F1 //7F2 @@ -788,6 +811,8 @@ DB2CC44D0662DD1100335AB3, DB2CC44E0662DD1100335AB3, DB2CC44F0662DD1100335AB3, + FF2C5FB00A48B8680066DA11, + FF2C5FB20A48B86E0066DA11, ); isa = PBXGroup; name = "Java Support"; @@ -899,6 +924,8 @@ DB2CC45F0662DE4C00335AB3, DB2CC4600662DE4C00335AB3, DB2CC4610662DE4D00335AB3, + FF2C5FB10A48B8680066DA11, + FF2C5FB30A48B86E0066DA11, ); isa = PBXSourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -969,7 +996,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if [ -d ${OBJROOT}/mDNSResponder.build/${CONFIGURATION} ]; then BUILD_DIR=${OBJROOT}/mDNSResponder.build/${CONFIGURATION}; else BUILD_DIR=${OBJROOT}/mDNSResponder.build; fi\njavah -force -J-Xbootclasspath/p:${BUILD_DIR}/dns_sd.jar.build/JavaClasses -o ${BUILD_DIR}/dns_sd.jar.build/DNSSD.java.h com.apple.dnssd.AppleDNSSD com.apple.dnssd.AppleBrowser com.apple.dnssd.AppleResolver com.apple.dnssd.AppleRegistration com.apple.dnssd.AppleQuery com.apple.dnssd.AppleDomainEnum com.apple.dnssd.AppleService"; + shellScript = "javah -force -J-Xbootclasspath/p:${CONFIGURATION_TEMP_DIR}/dns_sd.jar.build/JavaClasses -o ${CONFIGURATION_TEMP_DIR}/dns_sd.jar.build/DNSSD.java.h com.apple.dnssd.AppleDNSSD com.apple.dnssd.AppleBrowser com.apple.dnssd.AppleResolver com.apple.dnssd.AppleRegistration com.apple.dnssd.AppleQuery com.apple.dnssd.AppleDomainEnum com.apple.dnssd.AppleService"; }; DB2CC4560662DE4500335AB3 = { fileRef = DB2CC4430662DD1100335AB3; @@ -1081,10 +1108,9 @@ DB2CC4650662DF5C00335AB3, ); buildSettings = { - DEBUGGING_SYMBOLS = NO; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; - HEADER_SEARCH_PATHS = "../mDNSShared \"${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/A/Headers\" \"${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/1.3.1/Headers\" \"${OBJROOT}/mDNSResponder.build/dns_sd.jar.build\" \"${OBJROOT}/mDNSResponder.build/${CONFIGURATION}/dns_sd.jar.build\""; + HEADER_SEARCH_PATHS = "../mDNSShared \"${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/A/Headers\" \"${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/1.3.1/Headers\" \"${CONFIGURATION_TEMP_DIR}/dns_sd.jar.build\""; INSTALL_PATH = /usr/lib/java; LIBRARY_STYLE = DYNAMIC; MACOSX_DEPLOYMENT_TARGET = 10.2; @@ -1282,6 +1308,48 @@ path = ../mDNSShared/mDNS.1; refType = 2; }; + FF13FFE90A5DA40200897C81 = { + fileRef = 6575FBEB022EAF7200000109; + isa = PBXBuildFile; + settings = { + }; + }; + FF13FFEA0A5DA44A00897C81 = { + fileEncoding = 4; + isa = PBXFileReference; + name = dnsextd_lexer.l; + path = ../mDNSShared/dnsextd_lexer.l; + refType = 2; + }; + FF13FFEB0A5DA44A00897C81 = { + fileRef = FF13FFEA0A5DA44A00897C81; + isa = PBXBuildFile; + settings = { + }; + }; + FF13FFEC0A5DA45500897C81 = { + fileEncoding = 4; + isa = PBXFileReference; + name = dnsextd_parser.y; + path = ../mDNSShared/dnsextd_parser.y; + refType = 2; + }; + FF13FFED0A5DA45500897C81 = { + fileRef = FF13FFEC0A5DA45500897C81; + isa = PBXBuildFile; + settings = { + }; + }; + FF13FFEE0A5DA52700897C81 = { + isa = PBXTargetDependency; + target = 08FB779FFE84155DC02AAC07; + }; + FF13FFEF0A5DA6FD00897C81 = { + fileRef = FFCB6D73075D539900B8AF62; + isa = PBXBuildFile; + settings = { + }; + }; FF16238F07023BD2001AB7D7 = { isa = PBXTargetDependency; target = FF1C919207021C84001048AB; @@ -1298,7 +1366,7 @@ GCC_TREAT_WARNINGS_AS_ERRORS = YES; INSTALL_PATH = /usr/bin; MACOSX_DEPLOYMENT_TARGET = 10.2; - OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -D__MACOSX__ -DmDNSResponderVersion=${MVERS} -I../mDNSShared"; + OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -I../mDNSShared"; OTHER_LDFLAGS = ""; OTHER_REZFLAGS = ""; PRODUCT_NAME = "dns-sd"; @@ -1396,20 +1464,24 @@ buildSettings = { FRAMEWORK_SEARCH_PATHS = ""; GCC_TREAT_WARNINGS_AS_ERRORS = YES; - HEADER_SEARCH_PATHS = "\"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers\""; + HEADER_SEARCH_PATHS = "\"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers\" \"${CONFIGURATION_TEMP_DIR}\""; INSTALL_PATH = /usr/sbin; - LIBRARY_SEARCH_PATHS = ""; + LEX = /usr/bin/flex; + LEXFLAGS = "-i"; + LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\""; MACOSX_DEPLOYMENT_TARGET = 10.2; - OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic -D__MACOSX__ -DmDNSResponderVersion=${MVERS}"; - OTHER_LDFLAGS = ""; + OTHER_CFLAGS = "-no-cpp-precomp -mdynamic-no-pic"; + OTHER_LDFLAGS = "-ldnsinfo"; OTHER_REZFLAGS = ""; PRODUCT_NAME = dnsextd; REZ_EXECUTABLE = YES; SECTORDER_FLAGS = ""; STRIPFLAGS = "-S"; WARNING_CFLAGS = "-W -Wall -Wmissing-prototypes -Wno-four-char-constants -Wno-unknown-pragmas"; + YACC = "/usr/bin/bison -y"; }; dependencies = ( + FF13FFEE0A5DA52700897C81, ); isa = PBXToolTarget; name = dnsextd; @@ -1421,7 +1493,6 @@ buildActionMask = 2147483647; files = ( FF25792B06C9A70800376F7B, - FF25792C06C9A70800376F7B, ); isa = PBXHeadersBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -1432,23 +1503,18 @@ settings = { }; }; - FF25792C06C9A70800376F7B = { - fileRef = F5E11B5B04A28126019798ED; - isa = PBXBuildFile; - settings = { - }; - }; FF25792D06C9A70800376F7B = { buildActionMask = 2147483647; files = ( FF25793606C9A70800376F7B, FF25793806C9A70800376F7B, FF25794706C9A8BF00376F7B, - FF25794906C9A97400376F7B, FF25794A06C9A98700376F7B, - FF25794D06C9A9D500376F7B, FF25794E06C9AA3000376F7B, - FF25795006C9AA8B00376F7B, + FF13FFE90A5DA40200897C81, + FF13FFEB0A5DA44A00897C81, + FF13FFED0A5DA45500897C81, + FF13FFEF0A5DA6FD00897C81, ); isa = PBXSourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -1526,7 +1592,7 @@ fileEncoding = 4; isa = PBXFileReference; name = dnsextd.c; - path = ../mDNSPosix/dnsextd.c; + path = ../mDNSShared/dnsextd.c; refType = 2; }; FF25794706C9A8BF00376F7B = { @@ -1535,50 +1601,18 @@ settings = { }; }; - FF25794906C9A97400376F7B = { - fileRef = 7F18A9F70587CEF6001880B3; - isa = PBXBuildFile; - settings = { - }; - }; FF25794A06C9A98700376F7B = { fileRef = DBAAFE29057E8F4D0085CAD0; isa = PBXBuildFile; settings = { }; }; - FF25794C06C9A9D500376F7B = { - fileEncoding = 4; - isa = PBXFileReference; - name = mDNSPosix.c; - path = ../mDNSPosix/mDNSPosix.c; - refType = 2; - }; - FF25794D06C9A9D500376F7B = { - fileRef = FF25794C06C9A9D500376F7B; - isa = PBXBuildFile; - settings = { - }; - }; FF25794E06C9AA3000376F7B = { fileRef = DBAAFE2C057E8F660085CAD0; isa = PBXBuildFile; settings = { }; }; - FF25794F06C9AA8B00376F7B = { - fileEncoding = 4; - isa = PBXFileReference; - name = mDNSUNP.c; - path = ../mDNSPosix/mDNSUNP.c; - refType = 2; - }; - FF25795006C9AA8B00376F7B = { - fileRef = FF25794F06C9AA8B00376F7B; - isa = PBXBuildFile; - settings = { - }; - }; FF25795106C9AB1D00376F7B = { isa = PBXTargetDependency; target = FF25792906C9A70800376F7B; @@ -1964,6 +1998,32 @@ isa = PBXTargetDependency; target = FF2609E107B440DD00CE10E5; }; + FF2C5FB00A48B8680066DA11 = { + fileEncoding = 4; + isa = PBXFileReference; + name = DNSSDRecordRegistrar.java; + path = ../mDNSShared/Java/DNSSDRecordRegistrar.java; + refType = 2; + }; + FF2C5FB10A48B8680066DA11 = { + fileRef = FF2C5FB00A48B8680066DA11; + isa = PBXBuildFile; + settings = { + }; + }; + FF2C5FB20A48B86E0066DA11 = { + fileEncoding = 4; + isa = PBXFileReference; + name = RegisterRecordListener.java; + path = ../mDNSShared/Java/RegisterRecordListener.java; + refType = 2; + }; + FF2C5FB30A48B86E0066DA11 = { + fileRef = FF2C5FB20A48B86E0066DA11; + isa = PBXBuildFile; + settings = { + }; + }; FF354EB108516C63007C00E1 = { fileEncoding = 4; isa = PBXExecutableFileReference; @@ -1988,7 +2048,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if [ -e /usr/local/include/dnsinfo.h ]\nthen\nrm -f \"${OBJROOT}/mDNSResponder.build/dnsinfo.h\"\nrm -f \"${OBJROOT}/mDNSResponder.build/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${OBJROOT}/mDNSResponder.build/dnsinfo.h\ntouch ${OBJROOT}/mDNSResponder.build/empty.c\ncc ${OBJROOT}/mDNSResponder.build/empty.c -c -o \"${OBJROOT}/mDNSResponder.build/libdnsinfo.a\"\nrm -f ${OBJROOT}/mDNSResponder.build/empty.c\nfi"; + shellScript = "if [ -e /usr/local/include/dnsinfo.h ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch ${CONFIGURATION_TEMP_DIR}/empty.c\ncc ${CONFIGURATION_TEMP_DIR}/empty.c -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f ${CONFIGURATION_TEMP_DIR}/empty.c\nfi"; }; FF485D5105632E0000130380 = { fileEncoding = 4; @@ -2070,7 +2130,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "rm -f ${BUILD_DIR}/${CONFIGURATION}/dns_sd"; + shellScript = "rm -f ${CONFIGURATION_BUILD_DIR}/dns_sd"; }; FFD41DDF06641BBB00F0C438 = { isa = PBXTargetDependency; @@ -2137,7 +2197,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if [ -e /usr/local/include/dnsinfo.h ]\nthen\nrm -f \"${OBJROOT}/mDNSResponder.build/dnsinfo.h\"\nrm -f \"${OBJROOT}/mDNSResponder.build/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${OBJROOT}/mDNSResponder.build/dnsinfo.h\ntouch ${OBJROOT}/mDNSResponder.build/empty.c\ncc ${OBJROOT}/mDNSResponder.build/empty.c -c -o \"${OBJROOT}/mDNSResponder.build/libdnsinfo.a\"\nrm -f ${OBJROOT}/mDNSResponder.build/empty.c\nfi"; + shellScript = "if [ -e /usr/local/include/dnsinfo.h ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch ${CONFIGURATION_TEMP_DIR}/empty.c\ncc ${CONFIGURATION_TEMP_DIR}/empty.c -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f ${CONFIGURATION_TEMP_DIR}/empty.c\nfi"; }; FFFB0DA407B43BED00B88D48 = { children = ( @@ -2195,6 +2255,7 @@ FFFB0DA807B43C9100B88D48, ); buildSettings = { + INSTALL_PATH = "/Library/Application Support/Bonjour"; MACOSX_DEPLOYMENT_TARGET = 10.2; OTHER_CFLAGS = ""; OTHER_LDFLAGS = ""; @@ -2209,7 +2270,7 @@ ); isa = PBXToolTarget; name = ddnswriteconfig; - productInstallPath = /usr/local/bin; + productInstallPath = "/Library/Application Support/Bonjour"; productName = ddnswriteconfig; productReference = FFFB0DAA07B43C9100B88D48; }; diff --git a/mDNSMacOSX/mDNSResponder.sb b/mDNSMacOSX/mDNSResponder.sb new file mode 100644 index 0000000..97ba7e1 --- /dev/null +++ b/mDNSMacOSX/mDNSResponder.sb @@ -0,0 +1,182 @@ +; -*- Mode: Scheme; tab-width: 4 -*- +; +; Copyright (c) 2007 Apple Inc. All rights reserved. +; +; Redistribution and use in source and binary forms, with or without +; modification, are permitted provided that the following conditions are met: +; +; 1. Redistributions of source code must retain the above copyright notice, +; this list of conditions and the following disclaimer. +; 2. Redistributions in binary form must reproduce the above copyright notice, +; this list of conditions and the following disclaimer in the documentation +; and/or other materials provided with the distribution. +; 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its +; contributors may be used to endorse or promote products derived from this +; software without specific prior written permission. +; +; THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY +; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +; DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY +; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +; +; $Log: mDNSResponder.sb,v $ +; Revision 1.24 2007/09/20 22:33:17 cheshire +; Tidied up inconsistent and error-prone naming -- used to be mDNSResponderHelper in +; some places and mDNSResponder.helper in others; now mDNSResponderHelper everywhere +; +; Revision 1.23 2007/09/04 22:26:18 mcguire +; Seatbelt: mDNSResponder needs to be allowed to access "/Library/Security/Trust Settings/" etc. +; +; Revision 1.22 2007/08/24 22:01:56 mcguire +; BTMM: Task: Change mDNSResponder Seatbelt settings to "deny default" instead of "signal FPE" just prior to GM candidate +; +; Revision 1.21 2007/08/18 01:02:03 mcguire +; No Bonjour services are getting registered at boot +; +; Revision 1.20 2007/08/08 22:34:59 mcguire +; Security: Run mDNSResponder as user id mdnsresponder instead of root +; +; Revision 1.19 2007/07/02 23:37:50 cheshire +; Need to list of allowed mach-lookup operations explicitly in mDNSResponder.sb +; +; Revision 1.18 2007/06/28 20:43:35 cheshire +; Seatbelt: mDNSResponder needs to be able to access /dev/autofs_nowait +; +; Revision 1.17 2007/06/28 20:34:45 cheshire +; Updated comments to reflect new seatbelt language syntax +; +; Revision 1.16 2007/05/29 23:32:46 cheshire +; Rearrange file so SPI warning isn't deleted when CVS history is trimmed from installed copy +; +; Revision 1.15 2007/05/25 22:45:17 jvidrine +; Update mDNSResponder.sb to Seatbelt Profile Language version 1 +; +; Revision 1.14 2007/05/23 17:40:08 cheshire +; Seatbelt killed mDNSResponder trying to read X509Anchors and X509Certificates +; +; Revision 1.13 2007/05/23 01:47:59 cheshire +; Need to list fs_read_data permission explicitly -- +; unlike fs_read/fs_write, fs_read_data does NOT automatically inherit from fs_write_data +; +; Revision 1.12 2007/05/21 23:52:27 cheshire +; Seatbelt killed mDNSResponder generating Module Directory Services cache +; +; Revision 1.11 2007/05/20 16:29:06 cheshire +; Seatbelt killed mDNSResponder trying to access /usr/share/icu/icudt36l.dat +; +; Revision 1.10 2007/05/15 00:21:39 cheshire +; Seatbelt killed mDNSResponder reading /private/var/root/Library/Preferences/com.apple.security.plist +; +; Revision 1.9 2007/05/14 22:08:26 cheshire +; Seatbelt: Need to escape literal dots in filename patterns +; +; Revision 1.8 2007/05/14 19:39:31 cheshire +; Seatbelt killed mDNSResponder in CFTimeZoneCopyDefault +; Seatbelt killed mDNSResponder in SecKeychainOpen +; +; Revision 1.7 2007/05/12 01:57:56 cheshire +; Seatbelt: mDNSResponder needs to be able to access preferences.plist-lock +; +; Revision 1.6 2007/05/10 21:12:14 cheshire +; Start using "debug deny" mode in Seatbelt +; +; Revision 1.5 2007/05/10 19:41:25 cheshire +; Have to use "deny mach_lookup_default" because "signal" doesn't work +; +; Revision 1.4 2007/04/27 20:46:31 cheshire +; Additional requirements: allow mDNSResponder to read /dev/random and /System/Library/Keychains/System.* +; +; Revision 1.3 2007/04/20 19:42:14 cheshire +; Condense rules a bit to bring file under Seatbelt's 4K limit +; +; Revision 1.2 2007/04/19 01:47:49 cheshire +; Refinements to sandbox profile, e.g. allow writing to /dev/console early in the boot process +; +; Revision 1.1 2007/04/18 00:50:47 cheshire +; Sandbox mDNSResponder +; +;############################################################################ + +; WARNING! SEATBELT CURRENTLY CAN'T HANDLE PROFILES LARGER THAN 16K +; MAKE SURE THE SIZE OF THIS FILE FROM "version" TO THE END DOESN'T EXCEED 16K + +(version 1) + +; WARNING: The sandbox rule capabilities and syntax used in this file are currently an +; Apple SPI (System Private Interface) and are subject to change at any time without notice. +; Apple may in future announce an official public supported sandbox API, but until then Developers +; are cautioned not to build products that use or depend on the sandbox facilities illustrated here. + +; Use "debug all" to log all operations examined by seatbelt, whether allowed or not. +; Use "debug deny" to log only operations that are denied by seatbelt +; to discover what specific attempted operation is causing an exception. + +;(debug all) +(debug deny) + +; To help debugging, "with send-signal SIGFPE" will trigger a fake floating-point exception, +; which will crash the process and show the call stack leading to the offending operation. +; For the shipping version "deny" is probably better because it vetoes the operation +; without killing the process. + +(deny default) +;(deny default (with send-signal SIGFPE)) + +; Special exception: "send-signal" command does not apply to the mach-* operations, +; so for those we have to use a plain unadorned "deny" instead +; (which means we may not get any notification of unintentional mach-* denials) +(deny mach-lookup) +(deny mach-priv-host-port) + +; Mach communications +; These are needed for things like getpwnam, hostname changes, & keychain +(allow mach-lookup (global-name + "com.apple.bsd.dirhelper" + "com.apple.distributed_notifications.2" + "com.apple.ocspd" + "com.apple.mDNSResponderHelper" + "com.apple.SecurityServer" + "com.apple.SystemConfiguration.configd" + "com.apple.system.DirectoryService.libinfo_v1" + "com.apple.system.notification_center")) + +; Rules to allow the operations mDNSResponder needs start here + +(allow network*) ; Allow networking, including Unix Domain Sockets +(allow sysctl-read) ; To get hardware model information +(allow file-read-metadata) ; Needed for dyld to work +(allow ipc-posix-shm) ; Needed for POSIX shared memory + +(allow file-read-data (regex "^/dev/random\$")) +(allow file-read-data file-write-data (regex "^/dev/console\$")) ; Needed for syslog early in the boot process +(allow file-read-data (regex "^/dev/autofs_nowait\$")) ; Used by CF to circumvent automount triggers + +; Allow us to read and write our socket +(allow file-read* file-write* (regex "^/private/var/run/mDNSResponder\$")) + +; Allow us to read system version, settings, and other miscellaneous necessary file system accesses +(allow file-read-data (regex "^/usr/sbin(/mDNSResponder)?\$")) ; Needed for CFCopyVersionDictionary() +(allow file-read-data (regex "^/usr/share/icu/.*\$")) +(allow file-read-data (regex "^/usr/share/zoneinfo/.*\$")) +(allow file-read-data (regex "^/System/Library/CoreServices/SystemVersion.*\$")) +(allow file-read-data (regex "^/Library/Preferences/(ByHost/)?\.GlobalPreferences.*\.plist\$")) +(allow file-read-data (regex "^/Library/Preferences/com\.apple\.security.*\.plist\$")) +(allow file-read-data (regex "^/Library/Preferences/com\.apple\.crypto\.plist\$")) +(allow file-read-data (regex "^/Library/Security/Trust Settings/Admin\.plist\$")) +(allow file-read-data (regex "^/System/Library/Preferences/com\.apple\.security.*\.plist\$")) +(allow file-read-data (regex "^/System/Library/Preferences/com\.apple\.crypto\.plist\$")) + +; Allow access to System Keychain +(allow file-read-data (regex "^/System/Library/Security\$")) +(allow file-read-data (regex "^/System/Library/Keychains/.*\$")) +(allow file-read-data (regex "^/Library/Keychains/System\.keychain\$")) +; Our Module Directory Services cache +(allow file-read-data (regex "^/private/var/tmp/mds/")) +(allow file-read* file-write* (regex "^/private/var/tmp/mds/[0-9]+(/|\$)")) + diff --git a/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj b/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj new file mode 100644 index 0000000..0454e3e --- /dev/null +++ b/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj @@ -0,0 +1,2269 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 42; + objects = { + +/* Begin PBXAggregateTarget section */ + 00AD62BB032D7A0C0CCA2C71 /* Build More */ = { + isa = PBXAggregateTarget; + buildConfigurationList = D284BE280ADD78180027CCDF /* Build configuration list for PBXAggregateTarget "Build More" */; + buildPhases = ( + ); + dependencies = ( + 03067D860C849CC30022BE1F /* PBXTargetDependency */, + D284BF2C0ADD815A0027CCDF /* PBXTargetDependency */, + D284BF2E0ADD81600027CCDF /* PBXTargetDependency */, + D284BF300ADD81630027CCDF /* PBXTargetDependency */, + D284BF260ADD814F0027CCDF /* PBXTargetDependency */, + D284BF2A0ADD81530027CCDF /* PBXTargetDependency */, + FFD41DDB0664169900F0C438 /* PBXTargetDependency */, + ); + name = "Build More"; + productName = "Build All"; + }; + 03067D640C83A3700022BE1F /* Build Some */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 03067D730C83A3CB0022BE1F /* Build configuration list for PBXAggregateTarget "Build Some" */; + buildPhases = ( + ); + dependencies = ( + 03067D680C83A3830022BE1F /* PBXTargetDependency */, + 03067D6A0C83A3890022BE1F /* PBXTargetDependency */, + 03067D6C0C83A3920022BE1F /* PBXTargetDependency */, + 03067D6E0C83A39C0022BE1F /* PBXTargetDependency */, + ); + name = "Build Some"; + productName = "Build Some"; + }; + FFA572650AF190F10055A0F1 /* SystemLibraries */ = { + isa = PBXAggregateTarget; + buildConfigurationList = FFA5726E0AF191200055A0F1 /* Build configuration list for PBXAggregateTarget "SystemLibraries" */; + buildPhases = ( + ); + dependencies = ( + FFA572690AF190FF0055A0F1 /* PBXTargetDependency */, + FFA5726B0AF191010055A0F1 /* PBXTargetDependency */, + FFA5726D0AF191020055A0F1 /* PBXTargetDependency */, + ); + name = SystemLibraries; + productName = SystemLibraries; + }; + FFB7657B0AEED96B00583A2C /* Build All */ = { + isa = PBXAggregateTarget; + buildConfigurationList = FFB7657E0AEED99D00583A2C /* Build configuration list for PBXAggregateTarget "Build All" */; + buildPhases = ( + ); + dependencies = ( + FFB7657D0AEED97F00583A2C /* PBXTargetDependency */, + FFA572710AF191230055A0F1 /* PBXTargetDependency */, + ); + name = "Build All"; + productName = "Build All"; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 2E0405F50C3195F700F13B59 /* helper.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405F40C3195F700F13B59 /* helper.c */; }; + 2E0405F60C31961100F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; settings = {ATTRIBUTES = (Server, Client, ); }; }; + 2E0406150C3197CB00F13B59 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E0406140C3197CB00F13B59 /* libbsm.dylib */; }; + 2E04061F0C3198B700F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; }; + 2E0406200C3198B700F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; }; + 2E04070A0C31EEEC00F13B59 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; }; + 2E04070B0C31EEEC00F13B59 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; }; + 2E3552900C3A95C100CA1CB7 /* helper-error.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E35528F0C3A95C100CA1CB7 /* helper-error.h */; }; + 2E3552910C3A95C100CA1CB7 /* helper-error.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E35528F0C3A95C100CA1CB7 /* helper-error.h */; }; + 2E3552920C3A95C100CA1CB7 /* helper-error.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E35528F0C3A95C100CA1CB7 /* helper-error.h */; }; + 2E35529D0C3A9E7600CA1CB7 /* helper-error.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E35528F0C3A95C100CA1CB7 /* helper-error.h */; }; + 2E35529E0C3A9E7600CA1CB7 /* helper-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */; }; + 2E35529F0C3A9E7600CA1CB7 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; }; + 2E4D9B050C38C19500480551 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; }; + 2E8165E80C5980E300485EB2 /* libpfkey.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A8202520C56C36500DDFD48 /* libpfkey.h */; }; + 2E8165E90C5980EE00485EB2 /* pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 4A8202530C56C36600DDFD48 /* pfkey.c */; }; + 2E8165EA0C5980F700485EB2 /* ipsec_strerror.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A8202510C56C36500DDFD48 /* ipsec_strerror.h */; }; + 2E8165F70C59835F00485EB2 /* libipsec.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E8165F60C59835F00485EB2 /* libipsec.dylib */; }; + 2E8165F90C59838100485EB2 /* libipsec.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E8165F60C59835F00485EB2 /* libipsec.dylib */; }; + 2E96A51D0C39BDAC0087C4D2 /* helper-main.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E0406CA0C31E9AD00F13B59 /* helper-main.c */; }; + 2E96A5260C39BE480087C4D2 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; }; + 2E96A5270C39BE480087C4D2 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; }; + 2E96A5300C39C1A50087C4D2 /* helper-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */; }; + 2E96A5320C39C1A50087C4D2 /* helper-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */; }; + 2EAE955A0C31F4D30021F738 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; }; + 2EC8F8EC0C39CCAC003C9C48 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; }; + 2ECC11A60C4FEC3800CB1885 /* helpermsg-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */; }; + 2ECC11A70C4FEC3800CB1885 /* helpermsg-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */; }; + 2ECC11A80C4FEC3800CB1885 /* helpermsg-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */; }; + 2EDC5E730C39EA640092701B /* helper-server.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EDC5E720C39EA640092701B /* helper-server.h */; }; + 2EDC5E740C39EA640092701B /* helper-server.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EDC5E720C39EA640092701B /* helper-server.h */; }; + 2EDC5E750C39EA640092701B /* helper-server.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EDC5E720C39EA640092701B /* helper-server.h */; }; + 4A8202650C56C4C900DDFD48 /* pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 4A8202530C56C36600DDFD48 /* pfkey.c */; }; + 4AAE0C9A0C68EA81003882A5 /* mDNSResponderHelper.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */; }; + D284BE530ADD80740027CCDF /* DNSServiceDiscoveryDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 6575FBFF022EAFBA00000109 /* DNSServiceDiscoveryDefines.h */; }; + D284BE540ADD80740027CCDF /* dnssd_ipc.h in Headers */ = {isa = PBXBuildFile; fileRef = F5E11B5B04A28126019798ED /* dnssd_ipc.h */; }; + D284BE560ADD80740027CCDF /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Client, ); }; }; + D284BE570ADD80740027CCDF /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; settings = {ATTRIBUTES = (Server, ); }; }; + D284BE580ADD80740027CCDF /* mDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBE9022EAF5A00000109 /* mDNS.c */; }; + D284BE590ADD80740027CCDF /* uDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F70587CEF6001880B3 /* uDNS.c */; }; + D284BE5A0ADD80740027CCDF /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; }; + D284BE5B0ADD80740027CCDF /* DNSDigest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F461DB5062DBF2900672BF3 /* DNSDigest.c */; }; + D284BE5D0ADD80740027CCDF /* mDNSDebug.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */; }; + D284BE5E0ADD80740027CCDF /* uds_daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = F525E72804AA167501F1CF4D /* uds_daemon.c */; }; + D284BE5F0ADD80740027CCDF /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; }; + D284BE600ADD80740027CCDF /* PlatformCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FFCB6D73075D539900B8AF62 /* PlatformCommon.c */; }; + D284BE610ADD80740027CCDF /* mDNSMacOSX.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */; }; + D284BE620ADD80740027CCDF /* LegacyNATTraversal.c in Sources */ = {isa = PBXBuildFile; fileRef = 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */; }; + D284BE630ADD80740027CCDF /* daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEC022EAF7200000109 /* daemon.c */; }; + D284BE650ADD80740027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; }; + D284BE660ADD80740027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; }; + D284BE670ADD80740027CCDF /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; }; + D284BE680ADD80740027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; }; + D284BE6B0ADD80740027CCDF /* mDNSResponder.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FF485D5105632E0000130380 /* mDNSResponder.8 */; }; + D284BE780ADD80800027CCDF /* DNSServiceDiscoveryDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 6575FBFF022EAFBA00000109 /* DNSServiceDiscoveryDefines.h */; }; + D284BE790ADD80800027CCDF /* dnssd_ipc.h in Headers */ = {isa = PBXBuildFile; fileRef = F5E11B5B04A28126019798ED /* dnssd_ipc.h */; }; + D284BE7A0ADD80800027CCDF /* mDNSEmbeddedAPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 654BE64F02B63B93000001D1 /* mDNSEmbeddedAPI.h */; }; + D284BE7B0ADD80800027CCDF /* mDNSDebug.h in Headers */ = {isa = PBXBuildFile; fileRef = 654BE65002B63B93000001D1 /* mDNSDebug.h */; }; + D284BE7C0ADD80800027CCDF /* mDNSMacOSX.h in Headers */ = {isa = PBXBuildFile; fileRef = 000753D303367C1C0CCA2C71 /* mDNSMacOSX.h */; }; + D284BE7E0ADD80800027CCDF /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Client, ); }; }; + D284BE7F0ADD80800027CCDF /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; settings = {ATTRIBUTES = (Server, ); }; }; + D284BE800ADD80800027CCDF /* mDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBE9022EAF5A00000109 /* mDNS.c */; }; + D284BE810ADD80800027CCDF /* uDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F70587CEF6001880B3 /* uDNS.c */; }; + D284BE820ADD80800027CCDF /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; }; + D284BE830ADD80800027CCDF /* DNSDigest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F461DB5062DBF2900672BF3 /* DNSDigest.c */; }; + D284BE850ADD80800027CCDF /* mDNSDebug.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */; }; + D284BE860ADD80800027CCDF /* uds_daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = F525E72804AA167501F1CF4D /* uds_daemon.c */; }; + D284BE870ADD80800027CCDF /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; }; + D284BE880ADD80800027CCDF /* PlatformCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FFCB6D73075D539900B8AF62 /* PlatformCommon.c */; }; + D284BE890ADD80800027CCDF /* mDNSMacOSX.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */; }; + D284BE8A0ADD80800027CCDF /* LegacyNATTraversal.c in Sources */ = {isa = PBXBuildFile; fileRef = 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */; }; + D284BE8B0ADD80800027CCDF /* daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEC022EAF7200000109 /* daemon.c */; }; + D284BE8D0ADD80800027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; }; + D284BE8E0ADD80800027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; }; + D284BE8F0ADD80800027CCDF /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; }; + D284BE900ADD80800027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; }; + D284BE9A0ADD808B0027CCDF /* SamplemDNSClient.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC20022EB7AA00000109 /* SamplemDNSClient.c */; }; + D284BE9C0ADD808B0027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; }; + D284BE9F0ADD808B0027CCDF /* mDNS.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FF0E0B5D065ADC7600FE4D9C /* mDNS.1 */; }; + D284BEA80ADD80920027CCDF /* dns-sd.c in Sources */ = {isa = PBXBuildFile; fileRef = FF1C919F07021E3F001048AB /* dns-sd.c */; }; + D284BEAC0ADD80920027CCDF /* dns-sd.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FF1C919D07021D77001048AB /* dns-sd.1 */; }; + D284BEB70ADD809A0027CCDF /* JNISupport.c in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC44B0662DD1100335AB3 /* JNISupport.c */; }; + D284BEB90ADD809A0027CCDF /* JavaVM.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB2CC4680662DFF500335AB3 /* JavaVM.framework */; }; + D284BEC50ADD80A20027CCDF /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; }; + D284BEC60ADD80A20027CCDF /* DNSDigest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F461DB5062DBF2900672BF3 /* DNSDigest.c */; }; + D284BEC70ADD80A20027CCDF /* dnsextd.c in Sources */ = {isa = PBXBuildFile; fileRef = FF25794606C9A8BF00376F7B /* dnsextd.c */; }; + D284BEC80ADD80A20027CCDF /* mDNSDebug.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */; }; + D284BEC90ADD80A20027CCDF /* GenLinkedList.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE2C057E8F660085CAD0 /* GenLinkedList.c */; }; + D284BECA0ADD80A20027CCDF /* mDNSMacOSX.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */; }; + D284BECB0ADD80A20027CCDF /* dnsextd_lexer.l in Sources */ = {isa = PBXBuildFile; fileRef = FF13FFEA0A5DA44A00897C81 /* dnsextd_lexer.l */; settings = {COMPILER_FLAGS = "-Wno-error"; }; }; + D284BECC0ADD80A20027CCDF /* dnsextd_parser.y in Sources */ = {isa = PBXBuildFile; fileRef = FF13FFEC0A5DA45500897C81 /* dnsextd_parser.y */; }; + D284BECD0ADD80A20027CCDF /* PlatformCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FFCB6D73075D539900B8AF62 /* PlatformCommon.c */; }; + D284BECF0ADD80A20027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; }; + D284BED00ADD80A20027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; }; + D284BED10ADD80A20027CCDF /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; }; + D284BED20ADD80A20027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; }; + D284BED50ADD80A20027CCDF /* dnsextd.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FFF4F63A06CFE4DD00459EFD /* dnsextd.8 */; }; + D284BEDE0ADD80A70027CCDF /* ddnswriteconfig.m in Sources */ = {isa = PBXBuildFile; fileRef = FFFB0DAF07B43CBA00B88D48 /* ddnswriteconfig.m */; }; + D284BEE00ADD80A70027CCDF /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FFFB0DB407B43D2700B88D48 /* Foundation.framework */; }; + D284BEE10ADD80A70027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; }; + D284BEE20ADD80A70027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; }; + D284BEE30ADD80A70027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; }; + D284BEEF0ADD80B00027CCDF /* remove_idle.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2407B4464B00CE10E5 /* remove_idle.tiff */; }; + D284BEF00ADD80B00027CCDF /* add_pressed.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2507B4464B00CE10E5 /* add_pressed.tiff */; }; + D284BEF10ADD80B00027CCDF /* remove_disabled.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2607B4464B00CE10E5 /* remove_disabled.tiff */; }; + D284BEF20ADD80B00027CCDF /* add_idle.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2707B4464B00CE10E5 /* add_idle.tiff */; }; + D284BEF30ADD80B00027CCDF /* success.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2807B4464B00CE10E5 /* success.tiff */; }; + D284BEF40ADD80B00027CCDF /* remove_pressed.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2907B4464B00CE10E5 /* remove_pressed.tiff */; }; + D284BEF50ADD80B00027CCDF /* failure.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2A07B4464B00CE10E5 /* failure.tiff */; }; + D284BEF60ADD80B00027CCDF /* BonjourPref.icns in Resources */ = {isa = PBXBuildFile; fileRef = FF260A3207B4466900CE10E5 /* BonjourPref.icns */; }; + D284BEF70ADD80B00027CCDF /* BonjourPref.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A3307B4466900CE10E5 /* BonjourPref.tiff */; }; + D284BEF80ADD80B00027CCDF /* DNSServiceDiscoveryPref.nib in Resources */ = {isa = PBXBuildFile; fileRef = FF260A4807B4475600CE10E5 /* DNSServiceDiscoveryPref.nib */; }; + D284BEF90ADD80B00027CCDF /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FF260A4B07B4477F00CE10E5 /* InfoPlist.strings */; }; + D284BEFB0ADD80B00027CCDF /* inprogress.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF08480607CEB8E800AE6769 /* inprogress.tiff */; }; + D284BEFC0ADD80B00027CCDF /* installtool in Resources */ = {isa = PBXBuildFile; fileRef = FF354EB108516C63007C00E1 /* installtool */; }; + D284BEFE0ADD80B00027CCDF /* DNSServiceDiscoveryPref.m in Sources */ = {isa = PBXBuildFile; fileRef = FFFB0DAC07B43CBA00B88D48 /* DNSServiceDiscoveryPref.m */; }; + D284BEFF0ADD80B00027CCDF /* PrivilegedOperations.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFB0DAD07B43CBA00B88D48 /* PrivilegedOperations.c */; }; + D284BF000ADD80B00027CCDF /* ConfigurationAuthority.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFB0DAE07B43CBA00B88D48 /* ConfigurationAuthority.c */; }; + D284BF020ADD80B00027CCDF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; }; + D284BF030ADD80B00027CCDF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; }; + D284BF040ADD80B00027CCDF /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF2609FA07B4433800CE10E5 /* Cocoa.framework */; }; + D284BF050ADD80B00027CCDF /* PreferencePanes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */; }; + D284BF060ADD80B00027CCDF /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; }; + D284C04E0ADD95D30027CCDF /* Info-PreferencePane.plist in Resources */ = {isa = PBXBuildFile; fileRef = D284C04D0ADD95D30027CCDF /* Info-PreferencePane.plist */; }; + DB2CC4560662DE4500335AB3 /* BaseListener.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC4430662DD1100335AB3 /* BaseListener.java */; }; + DB2CC4570662DE4600335AB3 /* BrowseListener.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC4440662DD1100335AB3 /* BrowseListener.java */; }; + DB2CC4580662DE4700335AB3 /* DNSRecord.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC4450662DD1100335AB3 /* DNSRecord.java */; }; + DB2CC4590662DE4700335AB3 /* DNSSD.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC4460662DD1100335AB3 /* DNSSD.java */; }; + DB2CC45A0662DE4800335AB3 /* DNSSDException.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC4470662DD1100335AB3 /* DNSSDException.java */; }; + DB2CC45B0662DE4900335AB3 /* DNSSDRegistration.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC4480662DD1100335AB3 /* DNSSDRegistration.java */; }; + DB2CC45C0662DE4900335AB3 /* DNSSDService.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC4490662DD1100335AB3 /* DNSSDService.java */; }; + DB2CC45D0662DE4A00335AB3 /* DomainListener.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC44A0662DD1100335AB3 /* DomainListener.java */; }; + DB2CC45E0662DE4B00335AB3 /* QueryListener.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC44C0662DD1100335AB3 /* QueryListener.java */; }; + DB2CC45F0662DE4C00335AB3 /* RegisterListener.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC44D0662DD1100335AB3 /* RegisterListener.java */; }; + DB2CC4600662DE4C00335AB3 /* ResolveListener.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC44E0662DD1100335AB3 /* ResolveListener.java */; }; + DB2CC4610662DE4D00335AB3 /* TXTRecord.java in Sources */ = {isa = PBXBuildFile; fileRef = DB2CC44F0662DD1100335AB3 /* TXTRecord.java */; }; + FF2C5FB10A48B8680066DA11 /* DNSSDRecordRegistrar.java in Sources */ = {isa = PBXBuildFile; fileRef = FF2C5FB00A48B8680066DA11 /* DNSSDRecordRegistrar.java */; }; + FF2C5FB30A48B86E0066DA11 /* RegisterRecordListener.java in Sources */ = {isa = PBXBuildFile; fileRef = FF2C5FB20A48B86E0066DA11 /* RegisterRecordListener.java */; }; + FFA572330AF18F1C0055A0F1 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; }; + FFA572340AF18F1C0055A0F1 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; }; + FFA572350AF18F1C0055A0F1 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; }; + FFA5723F0AF18F450055A0F1 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; }; + FFA572400AF18F450055A0F1 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; }; + FFA572410AF18F450055A0F1 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; }; + FFA572490AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; }; + FFA5724A0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; }; + FFA5724B0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; }; + FFA572610AF190940055A0F1 /* DNSServiceDiscovery.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = FFA572600AF1908D0055A0F1 /* DNSServiceDiscovery.h */; }; + FFA572640AF190C80055A0F1 /* dns_sd.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = FFA572630AF190C20055A0F1 /* dns_sd.h */; }; + FFC22AA20B00F42A00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; }; + FFC22AA30B00F42B00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; }; + FFC22AA40B00F42C00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; }; + FFC22AA50B00F43000BAB070 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; }; + FFC22AA60B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; }; + FFC22AA70B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; }; + FFFA38630AEEDB090065B80A /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; }; + FFFA38650AEEDB130065B80A /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; }; + FFFA38660AEEDB2B0065B80A /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; }; + FFFF8F810C3307C400722979 /* dnsextd.conf in CopyFiles */ = {isa = PBXBuildFile; fileRef = FFFF8F800C3307AC00722979 /* dnsextd.conf */; }; +/* End PBXBuildFile section */ + +/* Begin PBXBuildRule section */ + D284BF750ADD850C0027CCDF /* PBXBuildRule */ = { + isa = PBXBuildRule; + compilerSpec = com.apple.compilers.proxy.script; + fileType = sourcecode.yacc; + isEditable = 1; + outputFiles = ( + "$(DERIVED_FILE_DIR)/dnsextd_parser.h", + "$(DERIVED_FILE_DIR)/dnsextd_parser.c", + ); + script = "/usr/bin/bison -o ${DERIVED_FILE_DIR}/${INPUT_FILE_BASE}.c -d ${INPUT_FILE_PATH}"; + }; + D284BFB80ADD8E510027CCDF /* PBXBuildRule */ = { + isa = PBXBuildRule; + compilerSpec = com.apple.compilers.proxy.script; + fileType = sourcecode.lex; + isEditable = 1; + outputFiles = ( + "$(DERIVED_FILE_DIR)/dnsextd_lexer.c", + ); + script = "/usr/bin/flex -i -o${DERIVED_FILE_DIR}/${INPUT_FILE_BASE}.c ${INPUT_FILE_PATH}"; + }; +/* End PBXBuildRule section */ + +/* Begin PBXContainerItemProxy section */ + 03067D670C83A3830022BE1F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D284BE500ADD80740027CCDF /* mDNSResponder */; + remoteInfo = mDNSResponder; + }; + 03067D690C83A3890022BE1F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D284BE750ADD80800027CCDF /* mDNSResponder debug */; + remoteInfo = "mDNSResponder debug"; + }; + 03067D6B0C83A3920022BE1F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D284BEA50ADD80920027CCDF /* dns-sd tool */; + remoteInfo = "dns-sd tool"; + }; + 03067D6D0C83A39C0022BE1F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2E0405EF0C31955500F13B59 /* mDNSResponderHelper */; + remoteInfo = mDNSResponderHelper; + }; + 03067D850C849CC30022BE1F /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 03067D640C83A3700022BE1F /* Build Some */; + remoteInfo = "Build Some"; + }; + D284BDEA0ADD77F60027CCDF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DB2CC4530662DD6800335AB3; + remoteInfo = dns_sd.jar; + }; + D284BEB40ADD809A0027CCDF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = DB2CC4530662DD6800335AB3; + remoteInfo = dns_sd.jar; + }; + D284BF250ADD814F0027CCDF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D284BE970ADD808B0027CCDF; + remoteInfo = "mDNS command-line tool"; + }; + D284BF290ADD81530027CCDF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D284BEB20ADD809A0027CCDF; + remoteInfo = libjdns_sd.jnilib; + }; + D284BF2B0ADD815A0027CCDF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D284BEBF0ADD80A20027CCDF; + remoteInfo = dnsextd; + }; + D284BF2D0ADD81600027CCDF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D284BEDB0ADD80A70027CCDF; + remoteInfo = ddnswriteconfig; + }; + D284BF2F0ADD81630027CCDF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D284BEEA0ADD80B00027CCDF; + remoteInfo = PreferencePane; + }; + FFA572680AF190FF0055A0F1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FFB765830AEED9C700583A2C; + remoteInfo = libdns_sd; + }; + FFA5726A0AF191010055A0F1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FFA572300AF18F1C0055A0F1; + remoteInfo = "libdns_sd debug"; + }; + FFA5726C0AF191020055A0F1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FFA5723C0AF18F450055A0F1; + remoteInfo = "libdns_sd profile"; + }; + FFA572700AF191230055A0F1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FFA572650AF190F10055A0F1; + remoteInfo = SystemLibraries; + }; + FFB7657C0AEED97F00583A2C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 00AD62BB032D7A0C0CCA2C71; + remoteInfo = "Build Main"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 4AAE0C5A0C68E6EC003882A5 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man8; + dstSubfolderSpec = 0; + files = ( + 4AAE0C9A0C68EA81003882A5 /* mDNSResponderHelper.8 in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; + D284BE6A0ADD80740027CCDF /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man8; + dstSubfolderSpec = 0; + files = ( + D284BE6B0ADD80740027CCDF /* mDNSResponder.8 in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; + D284BE9E0ADD808B0027CCDF /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1; + dstSubfolderSpec = 0; + files = ( + D284BE9F0ADD808B0027CCDF /* mDNS.1 in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; + D284BEAB0ADD80920027CCDF /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1; + dstSubfolderSpec = 0; + files = ( + D284BEAC0ADD80920027CCDF /* dns-sd.1 in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; + D284BED40ADD80A20027CCDF /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man8; + dstSubfolderSpec = 0; + files = ( + D284BED50ADD80A20027CCDF /* dnsextd.8 in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; + FF93944E0AF193B900C5D655 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/include; + dstSubfolderSpec = 0; + files = ( + FFA572640AF190C80055A0F1 /* dns_sd.h in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; + FFA572500AF190070055A0F1 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/include/DNSServiceDiscovery; + dstSubfolderSpec = 0; + files = ( + FFA572610AF190940055A0F1 /* DNSServiceDiscovery.h in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; + FFFF8F770C32F0FD00722979 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /private/etc; + dstSubfolderSpec = 0; + files = ( + FFFF8F810C3307C400722979 /* dnsextd.conf in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 000753D303367C1C0CCA2C71 /* mDNSMacOSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mDNSMacOSX.h; sourceTree = ""; }; + 00CA213D02786FC30CCA2C71 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = ""; }; + 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = ""; }; + 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.mig; path = helpermsg.defs; sourceTree = ""; }; + 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 = ""; }; + 2E0406140C3197CB00F13B59 /* libbsm.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbsm.dylib; path = /usr/lib/libbsm.dylib; sourceTree = ""; }; + 2E0406CA0C31E9AD00F13B59 /* helper-main.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = "helper-main.c"; sourceTree = ""; }; + 2E35528F0C3A95C100CA1CB7 /* helper-error.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "helper-error.h"; sourceTree = ""; }; + 2E8165F60C59835F00485EB2 /* libipsec.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libipsec.dylib; path = /usr/lib/libipsec.dylib; sourceTree = ""; }; + 2E96A5250C39BE480087C4D2 /* helper.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = helper.h; sourceTree = ""; }; + 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "helper-stubs.c"; sourceTree = ""; }; + 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "helpermsg-types.h"; sourceTree = ""; }; + 2EDC5E720C39EA640092701B /* helper-server.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "helper-server.h"; sourceTree = ""; }; + 4A8202510C56C36500DDFD48 /* ipsec_strerror.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ipsec_strerror.h; sourceTree = ""; }; + 4A8202520C56C36500DDFD48 /* libpfkey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libpfkey.h; sourceTree = ""; }; + 4A8202530C56C36600DDFD48 /* pfkey.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pfkey.c; sourceTree = ""; }; + 4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mDNSResponderHelper.8; sourceTree = SOURCE_ROOT; }; + 654BE64F02B63B93000001D1 /* mDNSEmbeddedAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mDNSEmbeddedAPI.h; path = ../mDNSCore/mDNSEmbeddedAPI.h; sourceTree = ""; }; + 654BE65002B63B93000001D1 /* mDNSDebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mDNSDebug.h; path = ../mDNSCore/mDNSDebug.h; sourceTree = ""; }; + 65713D46025A293200000109 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = /System/Library/Frameworks/SystemConfiguration.framework; sourceTree = ""; }; + 6575FBE9022EAF5A00000109 /* mDNS.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = mDNS.c; path = ../mDNSCore/mDNS.c; sourceTree = ""; tabWidth = 4; usesTabs = 1; }; + 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = mDNSMacOSX.c; sourceTree = ""; tabWidth = 4; usesTabs = 1; }; + 6575FBEC022EAF7200000109 /* daemon.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = daemon.c; sourceTree = ""; tabWidth = 4; usesTabs = 1; }; + 6575FBFF022EAFBA00000109 /* DNSServiceDiscoveryDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNSServiceDiscoveryDefines.h; sourceTree = ""; }; + 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; path = DNSServiceDiscoveryReply.defs; sourceTree = ""; }; + 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; path = DNSServiceDiscoveryRequest.defs; sourceTree = ""; }; + 6575FC20022EB7AA00000109 /* SamplemDNSClient.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = SamplemDNSClient.c; sourceTree = SOURCE_ROOT; tabWidth = 4; usesTabs = 0; }; + 7F18A9F60587CEF6001880B3 /* DNSCommon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = DNSCommon.c; path = ../mDNSCore/DNSCommon.c; sourceTree = SOURCE_ROOT; }; + 7F18A9F70587CEF6001880B3 /* uDNS.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = uDNS.c; path = ../mDNSCore/uDNS.c; sourceTree = SOURCE_ROOT; }; + 7F461DB5062DBF2900672BF3 /* DNSDigest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = DNSDigest.c; path = ../mDNSCore/DNSDigest.c; sourceTree = SOURCE_ROOT; }; + 7F869685066EE02400D2A2DC /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = ""; }; + 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = LegacyNATTraversal.c; sourceTree = SOURCE_ROOT; }; + D284BE730ADD80740027CCDF /* mDNSResponder */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSResponder; sourceTree = BUILT_PRODUCTS_DIR; }; + D284BE950ADD80800027CCDF /* mDNSResponder.debug */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSResponder.debug; sourceTree = BUILT_PRODUCTS_DIR; }; + D284BEA30ADD808B0027CCDF /* mDNS */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNS; sourceTree = BUILT_PRODUCTS_DIR; }; + D284BEB00ADD80920027CCDF /* dns-sd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "dns-sd"; sourceTree = BUILT_PRODUCTS_DIR; }; + D284BEBE0ADD809A0027CCDF /* libjdns_sd.jnilib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libjdns_sd.jnilib; sourceTree = BUILT_PRODUCTS_DIR; }; + D284BED90ADD80A20027CCDF /* dnsextd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dnsextd; sourceTree = BUILT_PRODUCTS_DIR; }; + D284BEE80ADD80A70027CCDF /* ddnswriteconfig */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ddnswriteconfig; sourceTree = BUILT_PRODUCTS_DIR; }; + D284BF0C0ADD80B00027CCDF /* Bonjour.prefPane */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Bonjour.prefPane; sourceTree = BUILT_PRODUCTS_DIR; }; + D284C04D0ADD95D30027CCDF /* Info-PreferencePane.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = "Info-PreferencePane.plist"; path = "PreferencePane/Info-PreferencePane.plist"; sourceTree = ""; }; + DB2CC4430662DD1100335AB3 /* BaseListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = BaseListener.java; path = ../mDNSShared/Java/BaseListener.java; sourceTree = SOURCE_ROOT; }; + DB2CC4440662DD1100335AB3 /* BrowseListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = BrowseListener.java; path = ../mDNSShared/Java/BrowseListener.java; sourceTree = SOURCE_ROOT; }; + DB2CC4450662DD1100335AB3 /* DNSRecord.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSRecord.java; path = ../mDNSShared/Java/DNSRecord.java; sourceTree = SOURCE_ROOT; }; + DB2CC4460662DD1100335AB3 /* DNSSD.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSD.java; path = ../mDNSShared/Java/DNSSD.java; sourceTree = SOURCE_ROOT; }; + DB2CC4470662DD1100335AB3 /* DNSSDException.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSDException.java; path = ../mDNSShared/Java/DNSSDException.java; sourceTree = SOURCE_ROOT; }; + DB2CC4480662DD1100335AB3 /* DNSSDRegistration.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSDRegistration.java; path = ../mDNSShared/Java/DNSSDRegistration.java; sourceTree = SOURCE_ROOT; }; + DB2CC4490662DD1100335AB3 /* DNSSDService.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSDService.java; path = ../mDNSShared/Java/DNSSDService.java; sourceTree = SOURCE_ROOT; }; + DB2CC44A0662DD1100335AB3 /* DomainListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DomainListener.java; path = ../mDNSShared/Java/DomainListener.java; sourceTree = SOURCE_ROOT; }; + DB2CC44B0662DD1100335AB3 /* JNISupport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = JNISupport.c; path = ../mDNSShared/Java/JNISupport.c; sourceTree = SOURCE_ROOT; }; + DB2CC44C0662DD1100335AB3 /* QueryListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = QueryListener.java; path = ../mDNSShared/Java/QueryListener.java; sourceTree = SOURCE_ROOT; }; + DB2CC44D0662DD1100335AB3 /* RegisterListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = RegisterListener.java; path = ../mDNSShared/Java/RegisterListener.java; sourceTree = SOURCE_ROOT; }; + DB2CC44E0662DD1100335AB3 /* ResolveListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = ResolveListener.java; path = ../mDNSShared/Java/ResolveListener.java; sourceTree = SOURCE_ROOT; }; + DB2CC44F0662DD1100335AB3 /* TXTRecord.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = TXTRecord.java; path = ../mDNSShared/Java/TXTRecord.java; sourceTree = SOURCE_ROOT; }; + DB2CC4680662DFF500335AB3 /* JavaVM.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaVM.framework; path = /System/Library/Frameworks/JavaVM.framework; sourceTree = ""; }; + DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mDNSDebug.c; path = ../mDNSShared/mDNSDebug.c; sourceTree = SOURCE_ROOT; }; + DBAAFE2C057E8F660085CAD0 /* GenLinkedList.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = GenLinkedList.c; path = ../mDNSShared/GenLinkedList.c; sourceTree = SOURCE_ROOT; }; + F525E72804AA167501F1CF4D /* uds_daemon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = uds_daemon.c; path = ../mDNSShared/uds_daemon.c; sourceTree = SOURCE_ROOT; }; + F5E11B5A04A28126019798ED /* dnssd_ipc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssd_ipc.c; path = ../mDNSShared/dnssd_ipc.c; sourceTree = SOURCE_ROOT; }; + F5E11B5B04A28126019798ED /* dnssd_ipc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dnssd_ipc.h; path = ../mDNSShared/dnssd_ipc.h; sourceTree = SOURCE_ROOT; }; + FF08480607CEB8E800AE6769 /* inprogress.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = inprogress.tiff; path = PreferencePane/Artwork/inprogress.tiff; sourceTree = SOURCE_ROOT; }; + FF0E0B5D065ADC7600FE4D9C /* mDNS.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = mDNS.1; path = ../mDNSShared/mDNS.1; sourceTree = SOURCE_ROOT; }; + FF13FFEA0A5DA44A00897C81 /* dnsextd_lexer.l */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.lex; name = dnsextd_lexer.l; path = ../mDNSShared/dnsextd_lexer.l; sourceTree = SOURCE_ROOT; }; + FF13FFEC0A5DA45500897C81 /* dnsextd_parser.y */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.yacc; name = dnsextd_parser.y; path = ../mDNSShared/dnsextd_parser.y; sourceTree = SOURCE_ROOT; }; + FF1C919D07021D77001048AB /* dns-sd.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = "dns-sd.1"; path = "../mDNSShared/dns-sd.1"; sourceTree = SOURCE_ROOT; }; + FF1C919F07021E3F001048AB /* dns-sd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "dns-sd.c"; path = "../Clients/dns-sd.c"; sourceTree = SOURCE_ROOT; }; + FF25794606C9A8BF00376F7B /* dnsextd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnsextd.c; path = ../mDNSShared/dnsextd.c; sourceTree = SOURCE_ROOT; }; + FF2609FA07B4433800CE10E5 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; + FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PreferencePanes.framework; path = /System/Library/Frameworks/PreferencePanes.framework; sourceTree = ""; }; + FF260A2407B4464B00CE10E5 /* remove_idle.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = remove_idle.tiff; path = PreferencePane/Artwork/remove_idle.tiff; sourceTree = SOURCE_ROOT; }; + FF260A2507B4464B00CE10E5 /* add_pressed.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = add_pressed.tiff; path = PreferencePane/Artwork/add_pressed.tiff; sourceTree = SOURCE_ROOT; }; + FF260A2607B4464B00CE10E5 /* remove_disabled.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = remove_disabled.tiff; path = PreferencePane/Artwork/remove_disabled.tiff; sourceTree = SOURCE_ROOT; }; + FF260A2707B4464B00CE10E5 /* add_idle.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = add_idle.tiff; path = PreferencePane/Artwork/add_idle.tiff; sourceTree = SOURCE_ROOT; }; + FF260A2807B4464B00CE10E5 /* success.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = success.tiff; path = PreferencePane/Artwork/success.tiff; sourceTree = SOURCE_ROOT; }; + FF260A2907B4464B00CE10E5 /* remove_pressed.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = remove_pressed.tiff; path = PreferencePane/Artwork/remove_pressed.tiff; sourceTree = SOURCE_ROOT; }; + FF260A2A07B4464B00CE10E5 /* failure.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = failure.tiff; path = PreferencePane/Artwork/failure.tiff; sourceTree = SOURCE_ROOT; }; + FF260A3207B4466900CE10E5 /* BonjourPref.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = BonjourPref.icns; path = PreferencePane/BonjourPref.icns; sourceTree = SOURCE_ROOT; }; + FF260A3307B4466900CE10E5 /* BonjourPref.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = BonjourPref.tiff; path = PreferencePane/BonjourPref.tiff; sourceTree = SOURCE_ROOT; }; + FF260A4907B4475600CE10E5 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = PreferencePane/English.lproj/DNSServiceDiscoveryPref.nib; sourceTree = SOURCE_ROOT; }; + FF260A4C07B4477F00CE10E5 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = PreferencePane/English.lproj/InfoPlist.strings; sourceTree = SOURCE_ROOT; }; + FF2C5FB00A48B8680066DA11 /* DNSSDRecordRegistrar.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSDRecordRegistrar.java; path = ../mDNSShared/Java/DNSSDRecordRegistrar.java; sourceTree = SOURCE_ROOT; }; + FF2C5FB20A48B86E0066DA11 /* RegisterRecordListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = RegisterRecordListener.java; path = ../mDNSShared/Java/RegisterRecordListener.java; sourceTree = SOURCE_ROOT; }; + FF354EB108516C63007C00E1 /* installtool */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; name = installtool; path = PreferencePane/installtool; sourceTree = SOURCE_ROOT; }; + FF485D5105632E0000130380 /* mDNSResponder.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = mDNSResponder.8; path = ../mDNSShared/mDNSResponder.8; sourceTree = SOURCE_ROOT; }; + FF85880B0BD599F40080D89F /* mDNSResponder.sb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mDNSResponder.sb; sourceTree = SOURCE_ROOT; }; + FFA572390AF18F1C0055A0F1 /* libdns_sd_debug.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdns_sd_debug.a; sourceTree = BUILT_PRODUCTS_DIR; }; + FFA572450AF18F450055A0F1 /* libdns_sd_profile.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdns_sd_profile.a; sourceTree = BUILT_PRODUCTS_DIR; }; + FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = DNSServiceDiscovery.c; sourceTree = ""; }; + FFA572600AF1908D0055A0F1 /* DNSServiceDiscovery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNSServiceDiscovery.h; sourceTree = ""; }; + FFA572630AF190C20055A0F1 /* dns_sd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dns_sd.h; path = ../mDNSShared/dns_sd.h; sourceTree = SOURCE_ROOT; }; + FFB765840AEED9C700583A2C /* libdns_sd.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdns_sd.a; 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; }; + FFD41DDA0664157900F0C438 /* dns_sd.jar */ = {isa = PBXFileReference; explicitFileType = archive.jar; includeInIndex = 0; path = dns_sd.jar; sourceTree = BUILT_PRODUCTS_DIR; }; + 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 = ""; }; + FFFB0DAD07B43CBA00B88D48 /* PrivilegedOperations.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = PrivilegedOperations.c; sourceTree = ""; }; + FFFB0DAE07B43CBA00B88D48 /* ConfigurationAuthority.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ConfigurationAuthority.c; sourceTree = ""; }; + FFFB0DAF07B43CBA00B88D48 /* ddnswriteconfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ddnswriteconfig.m; sourceTree = ""; }; + FFFB0DB407B43D2700B88D48 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; + 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 */ + 2E0405EE0C31955500F13B59 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 2E0406150C3197CB00F13B59 /* libbsm.dylib in Frameworks */, + 2E04070A0C31EEEC00F13B59 /* CoreFoundation.framework in Frameworks */, + 2E04070B0C31EEEC00F13B59 /* SystemConfiguration.framework in Frameworks */, + 2E4D9B050C38C19500480551 /* Security.framework in Frameworks */, + 2E8165F70C59835F00485EB2 /* libipsec.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BE640ADD80740027CCDF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D284BE650ADD80740027CCDF /* CoreFoundation.framework in Frameworks */, + D284BE660ADD80740027CCDF /* SystemConfiguration.framework in Frameworks */, + D284BE670ADD80740027CCDF /* IOKit.framework in Frameworks */, + D284BE680ADD80740027CCDF /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BE8C0ADD80800027CCDF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D284BE8D0ADD80800027CCDF /* CoreFoundation.framework in Frameworks */, + D284BE8E0ADD80800027CCDF /* SystemConfiguration.framework in Frameworks */, + D284BE8F0ADD80800027CCDF /* IOKit.framework in Frameworks */, + D284BE900ADD80800027CCDF /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BE9B0ADD808B0027CCDF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D284BE9C0ADD808B0027CCDF /* CoreFoundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BEA90ADD80920027CCDF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BEB80ADD809A0027CCDF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D284BEB90ADD809A0027CCDF /* JavaVM.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BECE0ADD80A20027CCDF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D284BECF0ADD80A20027CCDF /* CoreFoundation.framework in Frameworks */, + D284BED00ADD80A20027CCDF /* SystemConfiguration.framework in Frameworks */, + D284BED10ADD80A20027CCDF /* IOKit.framework in Frameworks */, + D284BED20ADD80A20027CCDF /* Security.framework in Frameworks */, + 2E8165F90C59838100485EB2 /* libipsec.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BEDF0ADD80A70027CCDF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D284BEE00ADD80A70027CCDF /* Foundation.framework in Frameworks */, + D284BEE10ADD80A70027CCDF /* Security.framework in Frameworks */, + D284BEE20ADD80A70027CCDF /* SystemConfiguration.framework in Frameworks */, + D284BEE30ADD80A70027CCDF /* CoreFoundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BF010ADD80B00027CCDF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D284BF020ADD80B00027CCDF /* SystemConfiguration.framework in Frameworks */, + D284BF030ADD80B00027CCDF /* Security.framework in Frameworks */, + D284BF040ADD80B00027CCDF /* Cocoa.framework in Frameworks */, + D284BF050ADD80B00027CCDF /* PreferencePanes.framework in Frameworks */, + D284BF060ADD80B00027CCDF /* CoreFoundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DB2CC4520662DD6800335AB3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FFA572360AF18F1C0055A0F1 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FFA572420AF18F450055A0F1 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FFB765820AEED9C700583A2C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* mDNSResponder */ = { + isa = PBXGroup; + children = ( + 08FB7795FE84155DC02AAC07 /* mDNS Server Sources */, + 6575FC1F022EB78C00000109 /* Command-Line Clients */, + 6575FBFE022EAFA800000109 /* MIG files */, + DB2CC4420662DCE500335AB3 /* Java Support */, + FFFB0DA407B43BED00B88D48 /* PreferencePane */, + 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */, + 19C28FBDFE9D53C911CA2CBB /* Products */, + ); + name = mDNSResponder; + sourceTree = ""; + }; + 08FB7795FE84155DC02AAC07 /* mDNS Server Sources */ = { + isa = PBXGroup; + children = ( + 4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */, + 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */, + 2E35528F0C3A95C100CA1CB7 /* helper-error.h */, + 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */, + 2EDC5E720C39EA640092701B /* helper-server.h */, + 2E96A5250C39BE480087C4D2 /* helper.h */, + 2E0405F40C3195F700F13B59 /* helper.c */, + 2E0406CA0C31E9AD00F13B59 /* helper-main.c */, + 4A8202510C56C36500DDFD48 /* ipsec_strerror.h */, + 4A8202520C56C36500DDFD48 /* libpfkey.h */, + 4A8202530C56C36600DDFD48 /* pfkey.c */, + 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */, + 7F461DB5062DBF2900672BF3 /* DNSDigest.c */, + F525E72804AA167501F1CF4D /* uds_daemon.c */, + F5E11B5A04A28126019798ED /* dnssd_ipc.c */, + F5E11B5B04A28126019798ED /* dnssd_ipc.h */, + 6575FBEC022EAF7200000109 /* daemon.c */, + 6575FBE9022EAF5A00000109 /* mDNS.c */, + 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */, + 654BE64F02B63B93000001D1 /* mDNSEmbeddedAPI.h */, + 654BE65002B63B93000001D1 /* mDNSDebug.h */, + DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */, + 000753D303367C1C0CCA2C71 /* mDNSMacOSX.h */, + DBAAFE2C057E8F660085CAD0 /* GenLinkedList.c */, + FFCB6D73075D539900B8AF62 /* PlatformCommon.c */, + FF0E0B5D065ADC7600FE4D9C /* mDNS.1 */, + FF1C919D07021D77001048AB /* dns-sd.1 */, + FF485D5105632E0000130380 /* mDNSResponder.8 */, + FFF4F63A06CFE4DD00459EFD /* dnsextd.8 */, + FFFF8F800C3307AC00722979 /* dnsextd.conf */, + FF85880B0BD599F40080D89F /* mDNSResponder.sb */, + 7F18A9F60587CEF6001880B3 /* DNSCommon.c */, + 7F18A9F70587CEF6001880B3 /* uDNS.c */, + FF25794606C9A8BF00376F7B /* dnsextd.c */, + FF13FFEA0A5DA44A00897C81 /* dnsextd_lexer.l */, + FF13FFEC0A5DA45500897C81 /* dnsextd_parser.y */, + FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */, + FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */, + FFA572600AF1908D0055A0F1 /* DNSServiceDiscovery.h */, + FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */, + FFA572630AF190C20055A0F1 /* dns_sd.h */, + ); + name = "mDNS Server Sources"; + sourceTree = ""; + }; + 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + 2E8165F60C59835F00485EB2 /* libipsec.dylib */, + 65713D46025A293200000109 /* SystemConfiguration.framework */, + 2E0406140C3197CB00F13B59 /* libbsm.dylib */, + 7F869685066EE02400D2A2DC /* Security.framework */, + FFFB0DB407B43D2700B88D48 /* Foundation.framework */, + 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */, + 00CA213D02786FC30CCA2C71 /* IOKit.framework */, + DB2CC4680662DFF500335AB3 /* JavaVM.framework */, + FF2609FA07B4433800CE10E5 /* Cocoa.framework */, + FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */, + ); + name = "External Frameworks and Libraries"; + sourceTree = ""; + }; + 19C28FBDFE9D53C911CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + D284C04D0ADD95D30027CCDF /* Info-PreferencePane.plist */, + FFD41DDA0664157900F0C438 /* dns_sd.jar */, + D284BE730ADD80740027CCDF /* mDNSResponder */, + D284BE950ADD80800027CCDF /* mDNSResponder.debug */, + D284BEA30ADD808B0027CCDF /* mDNS */, + D284BEB00ADD80920027CCDF /* dns-sd */, + D284BEBE0ADD809A0027CCDF /* libjdns_sd.jnilib */, + D284BED90ADD80A20027CCDF /* dnsextd */, + D284BEE80ADD80A70027CCDF /* ddnswriteconfig */, + D284BF0C0ADD80B00027CCDF /* Bonjour.prefPane */, + FFB765840AEED9C700583A2C /* libdns_sd.a */, + FFA572390AF18F1C0055A0F1 /* libdns_sd_debug.a */, + FFA572450AF18F450055A0F1 /* libdns_sd_profile.a */, + 2E0405F00C31955500F13B59 /* mDNSResponderHelper */, + ); + name = Products; + sourceTree = ""; + }; + 6575FBFE022EAFA800000109 /* MIG files */ = { + isa = PBXGroup; + children = ( + 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */, + 6575FBFF022EAFBA00000109 /* DNSServiceDiscoveryDefines.h */, + 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */, + 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */, + ); + name = "MIG files"; + sourceTree = ""; + }; + 6575FC1F022EB78C00000109 /* Command-Line Clients */ = { + isa = PBXGroup; + children = ( + 6575FC20022EB7AA00000109 /* SamplemDNSClient.c */, + FF1C919F07021E3F001048AB /* dns-sd.c */, + ); + name = "Command-Line Clients"; + sourceTree = ""; + }; + DB2CC4420662DCE500335AB3 /* Java Support */ = { + isa = PBXGroup; + children = ( + DB2CC4430662DD1100335AB3 /* BaseListener.java */, + DB2CC4440662DD1100335AB3 /* BrowseListener.java */, + DB2CC4450662DD1100335AB3 /* DNSRecord.java */, + DB2CC4460662DD1100335AB3 /* DNSSD.java */, + DB2CC4470662DD1100335AB3 /* DNSSDException.java */, + DB2CC4480662DD1100335AB3 /* DNSSDRegistration.java */, + DB2CC4490662DD1100335AB3 /* DNSSDService.java */, + DB2CC44A0662DD1100335AB3 /* DomainListener.java */, + DB2CC44B0662DD1100335AB3 /* JNISupport.c */, + DB2CC44C0662DD1100335AB3 /* QueryListener.java */, + DB2CC44D0662DD1100335AB3 /* RegisterListener.java */, + DB2CC44E0662DD1100335AB3 /* ResolveListener.java */, + DB2CC44F0662DD1100335AB3 /* TXTRecord.java */, + FF2C5FB00A48B8680066DA11 /* DNSSDRecordRegistrar.java */, + FF2C5FB20A48B86E0066DA11 /* RegisterRecordListener.java */, + ); + name = "Java Support"; + sourceTree = ""; + }; + FF260A2307B4463400CE10E5 /* Resources */ = { + isa = PBXGroup; + children = ( + FF260A2407B4464B00CE10E5 /* remove_idle.tiff */, + FF260A2507B4464B00CE10E5 /* add_pressed.tiff */, + FF260A2607B4464B00CE10E5 /* remove_disabled.tiff */, + FF260A2707B4464B00CE10E5 /* add_idle.tiff */, + FF260A2907B4464B00CE10E5 /* remove_pressed.tiff */, + FF260A2807B4464B00CE10E5 /* success.tiff */, + FF08480607CEB8E800AE6769 /* inprogress.tiff */, + FF260A2A07B4464B00CE10E5 /* failure.tiff */, + FF260A3207B4466900CE10E5 /* BonjourPref.icns */, + FF260A3307B4466900CE10E5 /* BonjourPref.tiff */, + FF354EB108516C63007C00E1 /* installtool */, + FF260A4807B4475600CE10E5 /* DNSServiceDiscoveryPref.nib */, + FF260A4B07B4477F00CE10E5 /* InfoPlist.strings */, + ); + name = Resources; + sourceTree = ""; + }; + FFFB0DA407B43BED00B88D48 /* PreferencePane */ = { + isa = PBXGroup; + children = ( + FFE6935007C2CA7F00283007 /* ConfigurationAuthority.h */, + FFFB0DAE07B43CBA00B88D48 /* ConfigurationAuthority.c */, + FFE6935207C2CAA400283007 /* DNSServiceDiscoveryPref.h */, + FFFB0DAC07B43CBA00B88D48 /* DNSServiceDiscoveryPref.m */, + FFE6935407C2CABD00283007 /* PrivilegedOperations.h */, + FFFB0DAD07B43CBA00B88D48 /* PrivilegedOperations.c */, + FFFB0DAF07B43CBA00B88D48 /* ddnswriteconfig.m */, + FF260A2307B4463400CE10E5 /* Resources */, + ); + path = PreferencePane; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 2EC8F8ED0C39CCCA003C9C48 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 2EC8F8EC0C39CCAC003C9C48 /* helper.h in Headers */, + 2EDC5E730C39EA640092701B /* helper-server.h in Headers */, + 2E3552920C3A95C100CA1CB7 /* helper-error.h in Headers */, + 2ECC11A80C4FEC3800CB1885 /* helpermsg-types.h in Headers */, + 2E8165E80C5980E300485EB2 /* libpfkey.h in Headers */, + 2E8165EA0C5980F700485EB2 /* ipsec_strerror.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BE520ADD80740027CCDF /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + D284BE530ADD80740027CCDF /* DNSServiceDiscoveryDefines.h in Headers */, + D284BE540ADD80740027CCDF /* dnssd_ipc.h in Headers */, + 2E96A5260C39BE480087C4D2 /* helper.h in Headers */, + 2EDC5E750C39EA640092701B /* helper-server.h in Headers */, + 2E3552900C3A95C100CA1CB7 /* helper-error.h in Headers */, + 2ECC11A60C4FEC3800CB1885 /* helpermsg-types.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BE770ADD80800027CCDF /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + D284BE780ADD80800027CCDF /* DNSServiceDiscoveryDefines.h in Headers */, + D284BE790ADD80800027CCDF /* dnssd_ipc.h in Headers */, + D284BE7A0ADD80800027CCDF /* mDNSEmbeddedAPI.h in Headers */, + D284BE7B0ADD80800027CCDF /* mDNSDebug.h in Headers */, + D284BE7C0ADD80800027CCDF /* mDNSMacOSX.h in Headers */, + 2E96A5270C39BE480087C4D2 /* helper.h in Headers */, + 2EDC5E740C39EA640092701B /* helper-server.h in Headers */, + 2E3552910C3A95C100CA1CB7 /* helper-error.h in Headers */, + 2ECC11A70C4FEC3800CB1885 /* helpermsg-types.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BE980ADD808B0027CCDF /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BEA60ADD80920027CCDF /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BEB50ADD809A0027CCDF /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BEC20ADD80A20027CCDF /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 2E35529D0C3A9E7600CA1CB7 /* helper-error.h in Headers */, + 2E35529F0C3A9E7600CA1CB7 /* helper.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BEDC0ADD80A70027CCDF /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BEED0ADD80B00027CCDF /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FFA572310AF18F1C0055A0F1 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FFA5723D0AF18F450055A0F1 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FFB765800AEED9C700583A2C /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXJavaArchiveBuildPhase section */ + DB2CC4510662DD6800335AB3 /* JavaArchive */ = { + isa = PBXJavaArchiveBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXJavaArchiveBuildPhase section */ + +/* Begin PBXLibraryTarget section */ + DB2CC4530662DD6800335AB3 /* dns_sd.jar */ = { + isa = PBXLibraryTarget; + buildConfigurationList = D284BE1C0ADD78180027CCDF /* Build configuration list for PBXLibraryTarget "dns_sd.jar" */; + buildPhases = ( + DB2CC4500662DD6800335AB3 /* Sources */, + DB2CC4510662DD6800335AB3 /* JavaArchive */, + DB2CC4520662DD6800335AB3 /* Frameworks */, + DB2CC4550662DE1700335AB3 /* ShellScript */, + FFD41DDD06641B4200F0C438 /* ShellScript */, + ); + comments = "Multiplatform .jar file that implements Java interface to DNS-SD"; + dependencies = ( + ); + name = dns_sd.jar; + productInstallPath = /System/Library/Java/Extensions; + productName = dns_sd.jar; + productReference = FFD41DDA0664157900F0C438 /* dns_sd.jar */; + }; +/* End PBXLibraryTarget section */ + +/* Begin PBXNativeTarget section */ + 2E0405EF0C31955500F13B59 /* mDNSResponderHelper */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2E0405F30C31956600F13B59 /* Build configuration list for PBXNativeTarget "mDNSResponderHelper" */; + buildPhases = ( + 2EC8F8ED0C39CCCA003C9C48 /* Headers */, + 2E0405ED0C31955500F13B59 /* Sources */, + 2E0405EE0C31955500F13B59 /* Frameworks */, + 4AAE0C5A0C68E6EC003882A5 /* CopyFiles */, + FF045B6A0C7E4AA600448140 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = mDNSResponderHelper; + productName = mDNSResponderHelper; + productReference = 2E0405F00C31955500F13B59 /* mDNSResponderHelper */; + productType = "com.apple.product-type.tool"; + }; + D284BE500ADD80740027CCDF /* mDNSResponder */ = { + isa = PBXNativeTarget; + buildConfigurationList = D284BE6D0ADD80740027CCDF /* Build configuration list for PBXNativeTarget "mDNSResponder" */; + buildPhases = ( + D284BE510ADD80740027CCDF /* ShellScript */, + D284BE520ADD80740027CCDF /* Headers */, + D284BE550ADD80740027CCDF /* Sources */, + D284BE640ADD80740027CCDF /* Frameworks */, + D284BE690ADD80740027CCDF /* Rez */, + D284BE6A0ADD80740027CCDF /* CopyFiles */, + D284BE6C0ADD80740027CCDF /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = mDNSResponder; + productInstallPath = "${HOME}/bin"; + productName = mDNSResponder; + productReference = D284BE730ADD80740027CCDF /* mDNSResponder */; + productType = "com.apple.product-type.tool"; + }; + D284BE750ADD80800027CCDF /* mDNSResponder debug */ = { + isa = PBXNativeTarget; + buildConfigurationList = D284BE920ADD80800027CCDF /* Build configuration list for PBXNativeTarget "mDNSResponder debug" */; + buildPhases = ( + D284BE760ADD80800027CCDF /* ShellScript */, + D284BE770ADD80800027CCDF /* Headers */, + D284BE7D0ADD80800027CCDF /* Sources */, + D284BE8C0ADD80800027CCDF /* Frameworks */, + D284BE910ADD80800027CCDF /* Rez */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "mDNSResponder debug"; + productName = mDNSResponder; + productReference = D284BE950ADD80800027CCDF /* mDNSResponder.debug */; + productType = "com.apple.product-type.tool"; + }; + D284BE970ADD808B0027CCDF /* mDNS tool */ = { + isa = PBXNativeTarget; + buildConfigurationList = D284BEA00ADD808B0027CCDF /* Build configuration list for PBXNativeTarget "mDNS tool" */; + buildPhases = ( + D284BE980ADD808B0027CCDF /* Headers */, + D284BE990ADD808B0027CCDF /* Sources */, + D284BE9B0ADD808B0027CCDF /* Frameworks */, + D284BE9D0ADD808B0027CCDF /* Rez */, + D284BE9E0ADD808B0027CCDF /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "mDNS tool"; + productInstallPath = /usr/bin; + productName = "mDNS command-line tool"; + productReference = D284BEA30ADD808B0027CCDF /* mDNS */; + productType = "com.apple.product-type.tool"; + }; + D284BEA50ADD80920027CCDF /* dns-sd tool */ = { + isa = PBXNativeTarget; + buildConfigurationList = D284BEAD0ADD80920027CCDF /* Build configuration list for PBXNativeTarget "dns-sd tool" */; + buildPhases = ( + D284BEA60ADD80920027CCDF /* Headers */, + D284BEA70ADD80920027CCDF /* Sources */, + D284BEA90ADD80920027CCDF /* Frameworks */, + D284BEAA0ADD80920027CCDF /* Rez */, + D284BEAB0ADD80920027CCDF /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "dns-sd tool"; + productInstallPath = /usr/bin; + productName = "dns-sd command-line tool"; + productReference = D284BEB00ADD80920027CCDF /* dns-sd */; + productType = "com.apple.product-type.tool"; + }; + D284BEB20ADD809A0027CCDF /* libjdns_sd.jnilib */ = { + isa = PBXNativeTarget; + buildConfigurationList = D284BEBB0ADD809A0027CCDF /* Build configuration list for PBXNativeTarget "libjdns_sd.jnilib" */; + buildPhases = ( + D284BEB50ADD809A0027CCDF /* Headers */, + D284BEB60ADD809A0027CCDF /* Sources */, + D284BEB80ADD809A0027CCDF /* Frameworks */, + D284BEBA0ADD809A0027CCDF /* Rez */, + ); + buildRules = ( + ); + comments = "Platform-specific JNI library that bridges dns_sd.jar to ."; + dependencies = ( + D284BEB30ADD809A0027CCDF /* PBXTargetDependency */, + ); + name = libjdns_sd.jnilib; + productInstallPath = /usr/lib/java; + productName = libjdns_sd.jnilib; + productReference = D284BEBE0ADD809A0027CCDF /* libjdns_sd.jnilib */; + productType = "com.apple.product-type.library.dynamic"; + }; + D284BEBF0ADD80A20027CCDF /* dnsextd */ = { + isa = PBXNativeTarget; + buildConfigurationList = D284BED60ADD80A20027CCDF /* Build configuration list for PBXNativeTarget "dnsextd" */; + buildPhases = ( + D284BEC20ADD80A20027CCDF /* Headers */, + D284BEC40ADD80A20027CCDF /* Sources */, + D284BECE0ADD80A20027CCDF /* Frameworks */, + D284BED30ADD80A20027CCDF /* Rez */, + D284BED40ADD80A20027CCDF /* CopyFiles */, + FFFF8F770C32F0FD00722979 /* CopyFiles */, + FF37FAAD0BC581780044A5CF /* ShellScript */, + ); + buildRules = ( + D284BFB80ADD8E510027CCDF /* PBXBuildRule */, + D284BF750ADD850C0027CCDF /* PBXBuildRule */, + ); + dependencies = ( + ); + name = dnsextd; + productInstallPath = /usr/sbin; + productName = mDNSResponder; + productReference = D284BED90ADD80A20027CCDF /* dnsextd */; + productType = "com.apple.product-type.tool"; + }; + D284BEDB0ADD80A70027CCDF /* ddnswriteconfig */ = { + isa = PBXNativeTarget; + buildConfigurationList = D284BEE50ADD80A70027CCDF /* Build configuration list for PBXNativeTarget "ddnswriteconfig" */; + buildPhases = ( + D284BEDC0ADD80A70027CCDF /* Headers */, + D284BEDD0ADD80A70027CCDF /* Sources */, + D284BEDF0ADD80A70027CCDF /* Frameworks */, + D284BEE40ADD80A70027CCDF /* Rez */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ddnswriteconfig; + productInstallPath = "/Library/Application Support/Bonjour"; + productName = ddnswriteconfig; + productReference = D284BEE80ADD80A70027CCDF /* ddnswriteconfig */; + productType = "com.apple.product-type.tool"; + }; + D284BEEA0ADD80B00027CCDF /* PreferencePane */ = { + isa = PBXNativeTarget; + buildConfigurationList = D284BF080ADD80B00027CCDF /* Build configuration list for PBXNativeTarget "PreferencePane" */; + buildPhases = ( + D284BEED0ADD80B00027CCDF /* Headers */, + D284BEEE0ADD80B00027CCDF /* Resources */, + D284BEFD0ADD80B00027CCDF /* Sources */, + D284BF010ADD80B00027CCDF /* Frameworks */, + D284BF070ADD80B00027CCDF /* Rez */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = PreferencePane; + productInstallPath = "${SYSTEM_LIBRARY_DIR}/PreferencePanes"; + productName = PreferencePane; + productReference = D284BF0C0ADD80B00027CCDF /* Bonjour.prefPane */; + productType = "com.apple.product-type.bundle"; + }; + FFA572300AF18F1C0055A0F1 /* libdns_sd debug */ = { + isa = PBXNativeTarget; + buildConfigurationList = FFA572370AF18F1C0055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd debug" */; + buildPhases = ( + FFA572310AF18F1C0055A0F1 /* Headers */, + FFA572320AF18F1C0055A0F1 /* Sources */, + FFA572360AF18F1C0055A0F1 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "libdns_sd debug"; + productName = libdns_sd.a; + productReference = FFA572390AF18F1C0055A0F1 /* libdns_sd_debug.a */; + productType = "com.apple.product-type.library.static"; + }; + FFA5723C0AF18F450055A0F1 /* libdns_sd profile */ = { + isa = PBXNativeTarget; + buildConfigurationList = FFA572430AF18F450055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd profile" */; + buildPhases = ( + FFA5723D0AF18F450055A0F1 /* Headers */, + FFA5723E0AF18F450055A0F1 /* Sources */, + FFA572420AF18F450055A0F1 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "libdns_sd profile"; + productName = libdns_sd.a; + productReference = FFA572450AF18F450055A0F1 /* libdns_sd_profile.a */; + productType = "com.apple.product-type.library.static"; + }; + FFB765830AEED9C700583A2C /* libdns_sd */ = { + isa = PBXNativeTarget; + buildConfigurationList = FFB765890AEED9FB00583A2C /* Build configuration list for PBXNativeTarget "libdns_sd" */; + buildPhases = ( + FFB765800AEED9C700583A2C /* Headers */, + FFB765810AEED9C700583A2C /* Sources */, + FFB765820AEED9C700583A2C /* Frameworks */, + FFA572500AF190070055A0F1 /* CopyFiles */, + FF93944E0AF193B900C5D655 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = libdns_sd; + productName = libdns_sd.a; + productReference = FFB765840AEED9C700583A2C /* libdns_sd.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = D284BE2B0ADD78180027CCDF /* Build configuration list for PBXProject "mDNSResponder" */; + hasScannedForEncodings = 1; + mainGroup = 08FB7794FE84155DC02AAC07 /* mDNSResponder */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 00AD62BB032D7A0C0CCA2C71 /* Build More */, + 03067D640C83A3700022BE1F /* Build Some */, + FFB7657B0AEED96B00583A2C /* Build All */, + D284BE500ADD80740027CCDF /* mDNSResponder */, + D284BE750ADD80800027CCDF /* mDNSResponder debug */, + 2E0405EF0C31955500F13B59 /* mDNSResponderHelper */, + D284BE970ADD808B0027CCDF /* mDNS tool */, + D284BEA50ADD80920027CCDF /* dns-sd tool */, + DB2CC4530662DD6800335AB3 /* dns_sd.jar */, + D284BEB20ADD809A0027CCDF /* libjdns_sd.jnilib */, + D284BEBF0ADD80A20027CCDF /* dnsextd */, + D284BEDB0ADD80A70027CCDF /* ddnswriteconfig */, + D284BEEA0ADD80B00027CCDF /* PreferencePane */, + FFB765830AEED9C700583A2C /* libdns_sd */, + FFA572300AF18F1C0055A0F1 /* libdns_sd debug */, + FFA5723C0AF18F450055A0F1 /* libdns_sd profile */, + FFA572650AF190F10055A0F1 /* SystemLibraries */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 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 */, + D284C04E0ADD95D30027CCDF /* Info-PreferencePane.plist in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXRezBuildPhase section */ + D284BE690ADD80740027CCDF /* Rez */ = { + isa = PBXRezBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BE910ADD80800027CCDF /* Rez */ = { + isa = PBXRezBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BE9D0ADD808B0027CCDF /* Rez */ = { + isa = PBXRezBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BEAA0ADD80920027CCDF /* Rez */ = { + isa = PBXRezBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BEBA0ADD809A0027CCDF /* Rez */ = { + isa = PBXRezBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BED30ADD80A20027CCDF /* Rez */ = { + isa = PBXRezBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BEE40ADD80A70027CCDF /* Rez */ = { + isa = PBXRezBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BF070ADD80B00027CCDF /* Rez */ = { + isa = PBXRezBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXRezBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + D284BE510ADD80740027CCDF /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if [ -e /usr/local/include/dnsinfo.h ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch ${CONFIGURATION_TEMP_DIR}/empty.c\ncc -arch i386 -arch ppc ${CONFIGURATION_TEMP_DIR}/empty.c -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f ${CONFIGURATION_TEMP_DIR}/empty.c\nfi\n\nif [ -e /usr/include/sandbox.h ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > ${CONFIGURATION_TEMP_DIR}/sandbox.h\nfi\n"; + }; + D284BE6C0ADD80740027CCDF /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 8; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + shellPath = /bin/tcsh; + shellScript = "# Install plist to tell launchd to start mDNSResponder\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons\ncp ${SRCROOT}/LaunchDaemonInfo.plist ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponder.plist\n\n# Install mDNSResponder.bundle containing language localizations\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices\ncp -R ${SRCROOT}/mDNSResponder-bundle ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle\n\n# Remove unwanted CVS directories\nfind ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -depth -name CVS -exec rm -rf {} \\;\n\n# Expand UTF-8 files to UTF-16 (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, stripping initial license header to make the file fit in the ~16kB Sandbox profile limit\n(umask 022; mkdir -p -m 0755 ${DSTROOT}/usr/share/sandbox)\n(umask 222; awk '/^\\(version 1\\)$/,EOF' ${SRCROOT}/mDNSResponder.sb > ${DSTROOT}/usr/share/sandbox/mDNSResponder.sb)\n"; + }; + D284BE760ADD80800027CCDF /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if [ -e /usr/local/include/dnsinfo.h ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch ${CONFIGURATION_TEMP_DIR}/empty.c\ncc -arch i386 -arch ppc ${CONFIGURATION_TEMP_DIR}/empty.c -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f ${CONFIGURATION_TEMP_DIR}/empty.c\nfi\n\nif [ -e /usr/include/sandbox.h ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > ${CONFIGURATION_TEMP_DIR}/sandbox.h\nfi\n"; + }; + DB2CC4550662DE1700335AB3 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 12; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "javah -force -J-Xbootclasspath/p:${CONFIGURATION_TEMP_DIR}/dns_sd.jar.build/JavaClasses -o ${CONFIGURATION_TEMP_DIR}/dns_sd.jar.build/DNSSD.java.h com.apple.dnssd.AppleDNSSD com.apple.dnssd.AppleBrowser com.apple.dnssd.AppleResolver com.apple.dnssd.AppleRegistration com.apple.dnssd.AppleQuery com.apple.dnssd.AppleDomainEnum com.apple.dnssd.AppleService com.apple.dnssd.AppleDNSRecord com.apple.dnssd.AppleRecordRegistrar"; + }; + FF045B6A0C7E4AA600448140 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 8; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 1; + shellPath = /bin/tcsh; + shellScript = "# Install plist to tell launchd how to start mDNSResponderHelper\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons\ncp ${SRCROOT}/LaunchDaemonInfo.helper.plist ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponderHelper.plist\n"; + }; + FF37FAAD0BC581780044A5CF /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 8; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + shellPath = /bin/tcsh; + shellScript = "# Install plist to tell launchd how to start dnsextd\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons\ncp ${SRCROOT}/LaunchDaemonInfo.dnsextd.plist ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.dnsextd.plist\n"; + }; + FFD41DDD06641B4200F0C438 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "rm -f ${CONFIGURATION_BUILD_DIR}/dns_sd"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 2E0405ED0C31955500F13B59 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2E0405F50C3195F700F13B59 /* helper.c in Sources */, + 2E0405F60C31961100F13B59 /* helpermsg.defs in Sources */, + 2E96A51D0C39BDAC0087C4D2 /* helper-main.c in Sources */, + 2E8165E90C5980EE00485EB2 /* pfkey.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BE550ADD80740027CCDF /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D284BE560ADD80740027CCDF /* DNSServiceDiscoveryReply.defs in Sources */, + D284BE570ADD80740027CCDF /* DNSServiceDiscoveryRequest.defs in Sources */, + D284BE580ADD80740027CCDF /* mDNS.c in Sources */, + D284BE590ADD80740027CCDF /* uDNS.c in Sources */, + D284BE5A0ADD80740027CCDF /* DNSCommon.c in Sources */, + D284BE5B0ADD80740027CCDF /* DNSDigest.c in Sources */, + D284BE5D0ADD80740027CCDF /* mDNSDebug.c in Sources */, + D284BE5E0ADD80740027CCDF /* uds_daemon.c in Sources */, + D284BE5F0ADD80740027CCDF /* dnssd_ipc.c in Sources */, + D284BE600ADD80740027CCDF /* PlatformCommon.c in Sources */, + D284BE610ADD80740027CCDF /* mDNSMacOSX.c in Sources */, + D284BE620ADD80740027CCDF /* LegacyNATTraversal.c in Sources */, + D284BE630ADD80740027CCDF /* daemon.c in Sources */, + 2E04061F0C3198B700F13B59 /* helpermsg.defs in Sources */, + 2E96A5320C39C1A50087C4D2 /* helper-stubs.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BE7D0ADD80800027CCDF /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D284BE7E0ADD80800027CCDF /* DNSServiceDiscoveryReply.defs in Sources */, + D284BE7F0ADD80800027CCDF /* DNSServiceDiscoveryRequest.defs in Sources */, + D284BE800ADD80800027CCDF /* mDNS.c in Sources */, + D284BE810ADD80800027CCDF /* uDNS.c in Sources */, + D284BE820ADD80800027CCDF /* DNSCommon.c in Sources */, + D284BE830ADD80800027CCDF /* DNSDigest.c in Sources */, + D284BE850ADD80800027CCDF /* mDNSDebug.c in Sources */, + D284BE860ADD80800027CCDF /* uds_daemon.c in Sources */, + D284BE870ADD80800027CCDF /* dnssd_ipc.c in Sources */, + D284BE880ADD80800027CCDF /* PlatformCommon.c in Sources */, + D284BE890ADD80800027CCDF /* mDNSMacOSX.c in Sources */, + D284BE8A0ADD80800027CCDF /* LegacyNATTraversal.c in Sources */, + D284BE8B0ADD80800027CCDF /* daemon.c in Sources */, + 2E0406200C3198B700F13B59 /* helpermsg.defs in Sources */, + 2E96A5300C39C1A50087C4D2 /* helper-stubs.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BE990ADD808B0027CCDF /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D284BE9A0ADD808B0027CCDF /* SamplemDNSClient.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BEA70ADD80920027CCDF /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D284BEA80ADD80920027CCDF /* dns-sd.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BEB60ADD809A0027CCDF /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D284BEB70ADD809A0027CCDF /* JNISupport.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BEC40ADD80A20027CCDF /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D284BEC50ADD80A20027CCDF /* DNSCommon.c in Sources */, + D284BEC60ADD80A20027CCDF /* DNSDigest.c in Sources */, + D284BEC70ADD80A20027CCDF /* dnsextd.c in Sources */, + D284BEC80ADD80A20027CCDF /* mDNSDebug.c in Sources */, + D284BEC90ADD80A20027CCDF /* GenLinkedList.c in Sources */, + D284BECA0ADD80A20027CCDF /* mDNSMacOSX.c in Sources */, + D284BECC0ADD80A20027CCDF /* dnsextd_parser.y in Sources */, + D284BECB0ADD80A20027CCDF /* dnsextd_lexer.l in Sources */, + D284BECD0ADD80A20027CCDF /* PlatformCommon.c in Sources */, + 2EAE955A0C31F4D30021F738 /* helpermsg.defs in Sources */, + 2E35529E0C3A9E7600CA1CB7 /* helper-stubs.c in Sources */, + 4A8202650C56C4C900DDFD48 /* pfkey.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BEDD0ADD80A70027CCDF /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D284BEDE0ADD80A70027CCDF /* ddnswriteconfig.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D284BEFD0ADD80B00027CCDF /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D284BEFE0ADD80B00027CCDF /* DNSServiceDiscoveryPref.m in Sources */, + D284BEFF0ADD80B00027CCDF /* PrivilegedOperations.c in Sources */, + D284BF000ADD80B00027CCDF /* ConfigurationAuthority.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DB2CC4500662DD6800335AB3 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DB2CC4560662DE4500335AB3 /* BaseListener.java in Sources */, + DB2CC4570662DE4600335AB3 /* BrowseListener.java in Sources */, + DB2CC4580662DE4700335AB3 /* DNSRecord.java in Sources */, + DB2CC4590662DE4700335AB3 /* DNSSD.java in Sources */, + DB2CC45A0662DE4800335AB3 /* DNSSDException.java in Sources */, + DB2CC45B0662DE4900335AB3 /* DNSSDRegistration.java in Sources */, + DB2CC45C0662DE4900335AB3 /* DNSSDService.java in Sources */, + DB2CC45D0662DE4A00335AB3 /* DomainListener.java in Sources */, + DB2CC45E0662DE4B00335AB3 /* QueryListener.java in Sources */, + DB2CC45F0662DE4C00335AB3 /* RegisterListener.java in Sources */, + DB2CC4600662DE4C00335AB3 /* ResolveListener.java in Sources */, + DB2CC4610662DE4D00335AB3 /* TXTRecord.java in Sources */, + FF2C5FB10A48B8680066DA11 /* DNSSDRecordRegistrar.java in Sources */, + FF2C5FB30A48B86E0066DA11 /* RegisterRecordListener.java in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FFA572320AF18F1C0055A0F1 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FFA572330AF18F1C0055A0F1 /* dnssd_ipc.c in Sources */, + FFA572340AF18F1C0055A0F1 /* dnssd_clientlib.c in Sources */, + FFA572350AF18F1C0055A0F1 /* dnssd_clientstub.c in Sources */, + FFA5724A0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */, + FFC22AA40B00F42C00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */, + FFC22AA60B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FFA5723E0AF18F450055A0F1 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FFA5723F0AF18F450055A0F1 /* dnssd_ipc.c in Sources */, + FFA572400AF18F450055A0F1 /* dnssd_clientlib.c in Sources */, + FFA572410AF18F450055A0F1 /* dnssd_clientstub.c in Sources */, + FFA5724B0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */, + FFC22AA30B00F42B00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */, + FFC22AA70B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FFB765810AEED9C700583A2C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FFFA38660AEEDB2B0065B80A /* dnssd_ipc.c in Sources */, + FFFA38630AEEDB090065B80A /* dnssd_clientlib.c in Sources */, + FFFA38650AEEDB130065B80A /* dnssd_clientstub.c in Sources */, + FFA572490AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */, + FFC22AA20B00F42A00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */, + FFC22AA50B00F43000BAB070 /* DNSServiceDiscoveryReply.defs in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 03067D680C83A3830022BE1F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D284BE500ADD80740027CCDF /* mDNSResponder */; + targetProxy = 03067D670C83A3830022BE1F /* PBXContainerItemProxy */; + }; + 03067D6A0C83A3890022BE1F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D284BE750ADD80800027CCDF /* mDNSResponder debug */; + targetProxy = 03067D690C83A3890022BE1F /* PBXContainerItemProxy */; + }; + 03067D6C0C83A3920022BE1F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D284BEA50ADD80920027CCDF /* dns-sd tool */; + targetProxy = 03067D6B0C83A3920022BE1F /* PBXContainerItemProxy */; + }; + 03067D6E0C83A39C0022BE1F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 2E0405EF0C31955500F13B59 /* mDNSResponderHelper */; + targetProxy = 03067D6D0C83A39C0022BE1F /* PBXContainerItemProxy */; + }; + 03067D860C849CC30022BE1F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 03067D640C83A3700022BE1F /* Build Some */; + targetProxy = 03067D850C849CC30022BE1F /* PBXContainerItemProxy */; + }; + D284BEB30ADD809A0027CCDF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DB2CC4530662DD6800335AB3 /* dns_sd.jar */; + targetProxy = D284BEB40ADD809A0027CCDF /* PBXContainerItemProxy */; + }; + D284BF260ADD814F0027CCDF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D284BE970ADD808B0027CCDF /* mDNS tool */; + targetProxy = D284BF250ADD814F0027CCDF /* PBXContainerItemProxy */; + }; + D284BF2A0ADD81530027CCDF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D284BEB20ADD809A0027CCDF /* libjdns_sd.jnilib */; + targetProxy = D284BF290ADD81530027CCDF /* PBXContainerItemProxy */; + }; + D284BF2C0ADD815A0027CCDF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D284BEBF0ADD80A20027CCDF /* dnsextd */; + targetProxy = D284BF2B0ADD815A0027CCDF /* PBXContainerItemProxy */; + }; + D284BF2E0ADD81600027CCDF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D284BEDB0ADD80A70027CCDF /* ddnswriteconfig */; + targetProxy = D284BF2D0ADD81600027CCDF /* PBXContainerItemProxy */; + }; + D284BF300ADD81630027CCDF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D284BEEA0ADD80B00027CCDF /* PreferencePane */; + targetProxy = D284BF2F0ADD81630027CCDF /* PBXContainerItemProxy */; + }; + FFA572690AF190FF0055A0F1 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FFB765830AEED9C700583A2C /* libdns_sd */; + targetProxy = FFA572680AF190FF0055A0F1 /* PBXContainerItemProxy */; + }; + FFA5726B0AF191010055A0F1 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FFA572300AF18F1C0055A0F1 /* libdns_sd debug */; + targetProxy = FFA5726A0AF191010055A0F1 /* PBXContainerItemProxy */; + }; + FFA5726D0AF191020055A0F1 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FFA5723C0AF18F450055A0F1 /* libdns_sd profile */; + targetProxy = FFA5726C0AF191020055A0F1 /* PBXContainerItemProxy */; + }; + FFA572710AF191230055A0F1 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = FFA572650AF190F10055A0F1 /* SystemLibraries */; + targetProxy = FFA572700AF191230055A0F1 /* PBXContainerItemProxy */; + }; + FFB7657D0AEED97F00583A2C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 00AD62BB032D7A0C0CCA2C71 /* Build More */; + targetProxy = FFB7657C0AEED97F00583A2C /* PBXContainerItemProxy */; + }; + FFD41DDB0664169900F0C438 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DB2CC4530662DD6800335AB3 /* dns_sd.jar */; + targetProxy = D284BDEA0ADD77F60027CCDF /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + FF260A4807B4475600CE10E5 /* DNSServiceDiscoveryPref.nib */ = { + isa = PBXVariantGroup; + children = ( + FF260A4907B4475600CE10E5 /* English */, + ); + name = DNSServiceDiscoveryPref.nib; + path = PreferencePane; + sourceTree = SOURCE_ROOT; + }; + FF260A4B07B4477F00CE10E5 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + FF260A4C07B4477F00CE10E5 /* English */, + ); + name = InfoPlist.strings; + path = PreferencePane; + sourceTree = SOURCE_ROOT; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 03067D740C83A3CB0022BE1F /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + PRODUCT_NAME = "Build Some"; + }; + name = Development; + }; + 2E0405F20C31955500F13B59 /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)"; + CONFIGURATION_TEMP_DIR = "$(PROJECT_TEMP_DIR)"; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_WARN_CHECK_SWITCH_STATEMENTS = NO; + HEADER_SEARCH_PATHS = "${CONFIGURATION_TEMP_DIR}"; + INSTALL_PATH = /usr/sbin; + LD_MAP_FILE_PATH = "$(TARGET_TEMP_DIR)/$(PRODUCT_NAME)-LinkMap-$(CURRENT_VARIANT)-$(CURRENT_ARCH).txt"; + MACOSX_DEPLOYMENT_TARGET = 10.4; + PREBINDING = NO; + PRODUCT_NAME = mDNSResponderHelper; + }; + name = Development; + }; + D284BE1D0ADD78180027CCDF /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + CONFIGURATION_BUILD_DIR = "${BUILD_DIR}"; + CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build"; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + INSTALL_PATH = "${SYSTEM_LIBRARY_DIR}/Java/Extensions"; + JAVA_ARCHIVE_CLASSES = YES; + JAVA_ARCHIVE_COMPRESSION = YES; + JAVA_ARCHIVE_TYPE = JAR; + JAVA_COMPILER_DEBUGGING_SYMBOLS = NO; + JAVA_COMPILER_SOURCE_VERSION = 1.4; + JAVA_COMPILER_TARGET_VM_VERSION = 1.4; + JAVA_SOURCE_SUBDIR = .; + LIBRARY_STYLE = STATIC; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOL_FLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = dns_sd; + PURE_JAVA = YES; + REZ_EXECUTABLE = YES; + SECTORDER_FLAGS = ""; + STRIPFLAGS = "-S"; + }; + name = Development; + }; + D284BE290ADD78180027CCDF /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + CONFIGURATION_BUILD_DIR = "${BUILD_DIR}"; + CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build"; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = "Build All"; + SECTORDER_FLAGS = ""; + }; + name = Development; + }; + D284BE2C0ADD78180027CCDF /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = ( + "APPLE_OSX_mDNSResponder=1", + "__MigTypeCheck=1", + "mDNSResponderVersion=${MVERS}", + _LEGACY_NAT_TRAVERSAL_, + ); + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + MVERS = "\"(Engineering Build)\""; + PREBINDING = NO; + WARNING_CFLAGS = ( + "-W", + "-Wall", + "-Wmissing-prototypes", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + YACC_GENERATED_FILE_STEM = Standard; + }; + name = Development; + }; + D284BE6E0ADD80740027CCDF /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + CONFIGURATION_BUILD_DIR = "${BUILD_DIR}"; + CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build"; + FRAMEWORK_SEARCH_PATHS = ""; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + HEADER_SEARCH_PATHS = ( + ../mDNSShared, + "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers", + "${CONFIGURATION_TEMP_DIR}", + ); + INSTALL_PATH = /usr/sbin; + LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\""; + MACOSX_DEPLOYMENT_TARGET = 10.4; + OTHER_CFLAGS = ( + "$(inherited)", + "-no-cpp-precomp", + ); + OTHER_LDFLAGS = "-ldnsinfo"; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = mDNSResponder; + REZ_EXECUTABLE = YES; + SECTORDER_FLAGS = ( + "-sectorder", + __TEXT, + __text, + mDNSResponder.order, + ); + STRIPFLAGS = "-S"; + }; + name = Development; + }; + D284BE930ADD80800027CCDF /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + CONFIGURATION_BUILD_DIR = "${BUILD_DIR}"; + CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build"; + FRAMEWORK_SEARCH_PATHS = ""; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "MDNS_DEBUGMSGS=1", + ); + HEADER_SEARCH_PATHS = ( + ../mDNSShared, + "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers", + "${CONFIGURATION_TEMP_DIR}", + ); + LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\""; + MACOSX_DEPLOYMENT_TARGET = 10.4; + OTHER_CFLAGS = ( + "$(inherited)", + "-no-cpp-precomp", + ); + OTHER_LDFLAGS = "-ldnsinfo"; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = mDNSResponder.debug; + REZ_EXECUTABLE = YES; + SECTORDER_FLAGS = ( + "-sectorder", + __TEXT, + __text, + mDNSResponder.order, + ); + STRIPFLAGS = "-S"; + }; + name = Development; + }; + D284BEA10ADD808B0027CCDF /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + CONFIGURATION_BUILD_DIR = "${BUILD_DIR}"; + CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build"; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + INSTALL_PATH = /usr/bin; + MACOSX_DEPLOYMENT_TARGET = 10.2; + OTHER_CFLAGS = "-no-cpp-precomp"; + OTHER_LDFLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = mDNS; + REZ_EXECUTABLE = YES; + SECTORDER_FLAGS = ""; + STRIPFLAGS = "-S"; + }; + name = Development; + }; + D284BEAE0ADD80920027CCDF /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + CONFIGURATION_BUILD_DIR = "${BUILD_DIR}"; + CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build"; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + HEADER_SEARCH_PATHS = ../mDNSShared; + INSTALL_PATH = /usr/bin; + MACOSX_DEPLOYMENT_TARGET = 10.3; + OTHER_CFLAGS = "-no-cpp-precomp"; + OTHER_LDFLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = "dns-sd"; + REZ_EXECUTABLE = YES; + SECTORDER_FLAGS = ""; + STRIPFLAGS = "-S"; + }; + name = Development; + }; + D284BEBC0ADD809A0027CCDF /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + CONFIGURATION_BUILD_DIR = "${BUILD_DIR}"; + CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build"; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + EXECUTABLE_EXTENSION = jnilib; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + HEADER_SEARCH_PATHS = ( + ../mDNSShared, + "${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/A/Headers", + "${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/1.3.1/Headers", + "${CONFIGURATION_TEMP_DIR}/dns_sd.jar.build", + ); + INSTALL_PATH = /usr/lib/java; + LIBRARY_STYLE = DYNAMIC; + MACH_O_TYPE = mh_dylib; + OTHER_CFLAGS = ""; + OTHER_LIBTOOL_FLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = libjdns_sd; + REZ_EXECUTABLE = YES; + SECTORDER_FLAGS = ""; + STRIPFLAGS = "-S"; + }; + name = Development; + }; + D284BED70ADD80A20027CCDF /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + CONFIGURATION_BUILD_DIR = "${BUILD_DIR}"; + CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build"; + FRAMEWORK_SEARCH_PATHS = ""; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + HEADER_SEARCH_PATHS = ( + "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers", + "${CONFIGURATION_TEMP_DIR}", + ); + INSTALL_PATH = /usr/sbin; + LEX = /usr/bin/flex; + LEXFLAGS = ""; + LEX_CASE_INSENSITIVE_SCANNER = YES; + LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\""; + MACOSX_DEPLOYMENT_TARGET = 10.4; + OTHER_CFLAGS = ( + "-no-cpp-precomp", + "-UAPPLE_OSX_mDNSResponder", + ); + OTHER_LDFLAGS = "-ldnsinfo"; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = dnsextd; + REZ_EXECUTABLE = YES; + SECTORDER_FLAGS = ""; + STRIPFLAGS = "-S"; + YACC = "/usr/bin/bison -y"; + }; + name = Development; + }; + D284BEE60ADD80A70027CCDF /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + CONFIGURATION_BUILD_DIR = "${BUILD_DIR}"; + CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build"; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + INSTALL_PATH = "/Library/Application Support/Bonjour"; + MACOSX_DEPLOYMENT_TARGET = 10.3; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ""; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = ddnswriteconfig; + REZ_EXECUTABLE = YES; + SECTORDER_FLAGS = ""; + STRIPFLAGS = "-S"; + }; + name = Development; + }; + D284BF090ADD80B00027CCDF /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + CONFIGURATION_BUILD_DIR = "${BUILD_DIR}"; + CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build"; + EXPORTED_SYMBOLS_FILE = ""; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + INFOPLIST_FILE = "PreferencePane/Info-PreferencePane.plist"; + INSTALL_PATH = /AppleInternal/Library/PreferencePanes; + MACOSX_DEPLOYMENT_TARGET = 10.3; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = "-twolevel_namespace"; + OTHER_REZFLAGS = ""; + PRODUCT_NAME = Bonjour; + SECTORDER_FLAGS = ""; + STRIPFLAGS = "-S"; + WRAPPER_EXTENSION = prefPane; + }; + name = Development; + }; + FFA572380AF18F1C0055A0F1 /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + CONFIGURATION_BUILD_DIR = "${BUILD_DIR}"; + CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build"; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "__DARWIN_NON_CANCELABLE=1", + ); + INSTALL_PATH = /usr/local/lib/system; + PRODUCT_NAME = dns_sd_debug; + }; + name = Development; + }; + FFA572440AF18F450055A0F1 /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + CONFIGURATION_BUILD_DIR = "${BUILD_DIR}"; + CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build"; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "__DARWIN_NON_CANCELABLE=1", + ); + GENERATE_PROFILING_CODE = YES; + INSTALL_PATH = /usr/local/lib/system; + PRODUCT_NAME = dns_sd_profile; + }; + name = Development; + }; + FFA5726F0AF191200055A0F1 /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + PRODUCT_NAME = SystemLibraries; + }; + name = Development; + }; + FFB7657F0AEED99D00583A2C /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + CONFIGURATION_BUILD_DIR = "${BUILD_DIR}"; + CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build"; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + PRODUCT_NAME = "Build All"; + }; + name = Development; + }; + FFB7658A0AEED9FB00583A2C /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + CONFIGURATION_BUILD_DIR = "${BUILD_DIR}"; + CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build"; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "__DARWIN_NON_CANCELABLE=1", + ); + INSTALL_PATH = /usr/local/lib/system; + PRODUCT_NAME = dns_sd; + }; + name = Development; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 03067D730C83A3CB0022BE1F /* Build configuration list for PBXAggregateTarget "Build Some" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 03067D740C83A3CB0022BE1F /* Development */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Development; + }; + 2E0405F30C31956600F13B59 /* Build configuration list for PBXNativeTarget "mDNSResponderHelper" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2E0405F20C31955500F13B59 /* Development */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Development; + }; + D284BE1C0ADD78180027CCDF /* Build configuration list for PBXLibraryTarget "dns_sd.jar" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D284BE1D0ADD78180027CCDF /* Development */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Development; + }; + D284BE280ADD78180027CCDF /* Build configuration list for PBXAggregateTarget "Build More" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D284BE290ADD78180027CCDF /* Development */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Development; + }; + D284BE2B0ADD78180027CCDF /* Build configuration list for PBXProject "mDNSResponder" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D284BE2C0ADD78180027CCDF /* Development */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Development; + }; + D284BE6D0ADD80740027CCDF /* Build configuration list for PBXNativeTarget "mDNSResponder" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D284BE6E0ADD80740027CCDF /* Development */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Development; + }; + D284BE920ADD80800027CCDF /* Build configuration list for PBXNativeTarget "mDNSResponder debug" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D284BE930ADD80800027CCDF /* Development */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Development; + }; + D284BEA00ADD808B0027CCDF /* Build configuration list for PBXNativeTarget "mDNS tool" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D284BEA10ADD808B0027CCDF /* Development */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Development; + }; + D284BEAD0ADD80920027CCDF /* Build configuration list for PBXNativeTarget "dns-sd tool" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D284BEAE0ADD80920027CCDF /* Development */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Development; + }; + D284BEBB0ADD809A0027CCDF /* Build configuration list for PBXNativeTarget "libjdns_sd.jnilib" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D284BEBC0ADD809A0027CCDF /* Development */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Development; + }; + D284BED60ADD80A20027CCDF /* Build configuration list for PBXNativeTarget "dnsextd" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D284BED70ADD80A20027CCDF /* Development */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Development; + }; + D284BEE50ADD80A70027CCDF /* Build configuration list for PBXNativeTarget "ddnswriteconfig" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D284BEE60ADD80A70027CCDF /* Development */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Development; + }; + D284BF080ADD80B00027CCDF /* Build configuration list for PBXNativeTarget "PreferencePane" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D284BF090ADD80B00027CCDF /* Development */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Development; + }; + FFA572370AF18F1C0055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd debug" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FFA572380AF18F1C0055A0F1 /* Development */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Development; + }; + FFA572430AF18F450055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd profile" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FFA572440AF18F450055A0F1 /* Development */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Development; + }; + FFA5726E0AF191200055A0F1 /* Build configuration list for PBXAggregateTarget "SystemLibraries" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FFA5726F0AF191200055A0F1 /* Development */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Development; + }; + FFB7657E0AEED99D00583A2C /* Build configuration list for PBXAggregateTarget "Build All" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FFB7657F0AEED99D00583A2C /* Development */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Development; + }; + FFB765890AEED9FB00583A2C /* Build configuration list for PBXNativeTarget "libdns_sd" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FFB7658A0AEED9FB00583A2C /* Development */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Development; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/mDNSMacOSX/mDNSResponderHelper.8 b/mDNSMacOSX/mDNSResponderHelper.8 new file mode 100644 index 0000000..8bb2cf8 --- /dev/null +++ b/mDNSMacOSX/mDNSResponderHelper.8 @@ -0,0 +1,60 @@ +.\" -*- tab-width: 4 -*- +.\" +.\" Copyright (c) 2007 Apple Computer, Inc. All Rights Reserved. +.\" +.\" Licensed under the Apache License, Version 2.0 (the "License"); +.\" you may not use this file except in compliance with the License. +.\" You may obtain a copy of the License at +.\" +.\" http://www.apache.org/licenses/LICENSE-2.0 +.\" +.\" Unless required by applicable law or agreed to in writing, software +.\" distributed under the License is distributed on an "AS IS" BASIS, +.\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +.\" See the License for the specific language governing permissions and +.\" limitations under the License. +.\" +.\" $Log: mDNSResponderHelper.8,v $ +.\" Revision 1.1 2007/08/08 22:34:59 mcguire +.\" Security: Run mDNSResponder as user id mdnsresponder instead of root +.\" +.\" +.\" +.Dd August 2007 \" Date +.Dt mDNSResponderHelper 8 \" Document Title +.Os Darwin \" Operating System +.\" +.Sh NAME +.Nm mDNSResponderHelper +.Nd mDNS privilege separation helper \" Name Description for whatis database +.\" +.Sh SYNOPSIS +.Nm +.\" +.Sh DESCRIPTION +.Nm +is an executable invoked by +.Nm launchd +to provide privilege separation +to the +.Nm mDNSResponder +daemon. +.Pp +.Nm +has no user-specifiable command-line arguments, and users should not run +.Nm +manually. +.Sh FILES +.Pa /usr/sbin/mDNSResponderHelper \" Pathname +.\" +.Sh SEE ALSO +.Xr mDNSResponder 8 +.\" +.Sh BUGS +.Nm +bugs are tracked in Apple Radar component "mDNSResponder". +.\" +.Sh HISTORY +The +.Nm +first appeared in Mac OS X 10.5 (Leopard). diff --git a/mDNSMacOSX/mDNSResponderHelper.plist b/mDNSMacOSX/mDNSResponderHelper.plist new file mode 100644 index 0000000..22286d2 --- /dev/null +++ b/mDNSMacOSX/mDNSResponderHelper.plist @@ -0,0 +1,13 @@ + + + + + + ServiceName + com.apple.mDNSResponderHelper + Command + /usr/sbin/mDNSResponderHelper + OnDemand + + + diff --git a/mDNSMacOSX/pfkey.c b/mDNSMacOSX/pfkey.c new file mode 100644 index 0000000..b2a4d9d --- /dev/null +++ b/mDNSMacOSX/pfkey.c @@ -0,0 +1,2126 @@ +/* + * Copyright (c) 2003-2007 Apple Computer, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* $FreeBSD: src/lib/libipsec/pfkey.c,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $ */ +/* $KAME: pfkey.c,v 1.39 2001/03/05 18:22:17 thorpej Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ipsec_strerror.h" +#include "libpfkey.h" + +#define CALLOC(size, cast) (cast)calloc(1, (size)) + +static int findsupportedmap __P((int)); +static int setsupportedmap __P((struct sadb_supported *)); +static struct sadb_alg *findsupportedalg __P((u_int, u_int)); +static int pfkey_send_x1 __P((int, u_int, u_int, u_int, struct sockaddr *, + struct sockaddr *, u_int32_t, u_int32_t, u_int, caddr_t, + u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int32_t, + u_int32_t, u_int32_t, u_int32_t)); +static int pfkey_send_x2 __P((int, u_int, u_int, u_int, + struct sockaddr *, struct sockaddr *, u_int32_t)); +static int pfkey_send_x3 __P((int, u_int, u_int)); +static int pfkey_send_x4 __P((int, u_int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t, + char *, int, u_int32_t)); +static int pfkey_send_x5 __P((int, u_int, u_int32_t)); + +static caddr_t pfkey_setsadbmsg __P((caddr_t, caddr_t, u_int, u_int, + u_int, u_int32_t, pid_t)); +static caddr_t pfkey_setsadbsa __P((caddr_t, caddr_t, u_int32_t, u_int, + u_int, u_int, u_int32_t)); +static caddr_t pfkey_setsadbaddr __P((caddr_t, caddr_t, u_int, + struct sockaddr *, u_int, u_int)); +static caddr_t pfkey_setsadbkey __P((caddr_t, caddr_t, u_int, caddr_t, u_int)); +static caddr_t pfkey_setsadblifetime __P((caddr_t, caddr_t, u_int, u_int32_t, + u_int32_t, u_int32_t, u_int32_t)); +static caddr_t pfkey_setsadbxsa2 __P((caddr_t, caddr_t, u_int32_t, u_int32_t)); + +/* + * make and search supported algorithm structure. + */ +static struct sadb_supported *ipsec_supported[] = { NULL, NULL, NULL, }; + +static int supported_map[] = { + SADB_SATYPE_AH, + SADB_SATYPE_ESP, + SADB_X_SATYPE_IPCOMP, +}; + +static int +findsupportedmap(satype) + int satype; +{ + int i; + + for (i = 0; (unsigned int)i < sizeof(supported_map)/sizeof(supported_map[0]); i++) + if (supported_map[i] == satype) + return i; + return -1; +} + +static struct sadb_alg * +findsupportedalg(satype, alg_id) + u_int satype, alg_id; +{ + int algno; + int tlen; + caddr_t p; + + /* validity check */ + algno = findsupportedmap(satype); + if (algno == -1) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return NULL; + } + if (ipsec_supported[algno] == NULL) { + __ipsec_errcode = EIPSEC_DO_GET_SUPP_LIST; + return NULL; + } + + tlen = ipsec_supported[algno]->sadb_supported_len + - sizeof(struct sadb_supported); + p = (caddr_t)(ipsec_supported[algno] + 1); + while (tlen > 0) { + if ((unsigned int)tlen < sizeof(struct sadb_alg)) { + /* invalid format */ + break; + } + if (((struct sadb_alg *)p)->sadb_alg_id == alg_id) + return (struct sadb_alg *)p; + + tlen -= sizeof(struct sadb_alg); + p += sizeof(struct sadb_alg); + } + + __ipsec_errcode = EIPSEC_NOT_SUPPORTED; + return NULL; +} + +static int +setsupportedmap(sup) + struct sadb_supported *sup; +{ + struct sadb_supported **ipsup; + + switch (sup->sadb_supported_exttype) { + case SADB_EXT_SUPPORTED_AUTH: + ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_AH)]; + break; + case SADB_EXT_SUPPORTED_ENCRYPT: + ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_ESP)]; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + if (*ipsup) + free(*ipsup); + + *ipsup = malloc(sup->sadb_supported_len); + if (!*ipsup) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + memcpy(*ipsup, sup, sup->sadb_supported_len); + + return 0; +} + +/* + * check key length against algorithm specified. + * This function is called with SADB_EXT_SUPPORTED_{AUTH,ENCRYPT} as the + * augument, and only calls to ipsec_check_keylen2(); + * keylen is the unit of bit. + * OUT: + * -1: invalid. + * 0: valid. + */ +int +ipsec_check_keylen(supported, alg_id, keylen) + u_int supported; + u_int alg_id; + u_int keylen; +{ + int satype; + + /* validity check */ + switch (supported) { + case SADB_EXT_SUPPORTED_AUTH: + satype = SADB_SATYPE_AH; + break; + case SADB_EXT_SUPPORTED_ENCRYPT: + satype = SADB_SATYPE_ESP; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + return ipsec_check_keylen2(satype, alg_id, keylen); +} + +/* + * check key length against algorithm specified. + * satype is one of satype defined at pfkeyv2.h. + * keylen is the unit of bit. + * OUT: + * -1: invalid. + * 0: valid. + */ +int +ipsec_check_keylen2(satype, alg_id, keylen) + u_int satype; + u_int alg_id; + u_int keylen; +{ + struct sadb_alg *alg; + + alg = findsupportedalg(satype, alg_id); + if (!alg) + return -1; + + if (keylen < alg->sadb_alg_minbits || keylen > alg->sadb_alg_maxbits) { + __ipsec_errcode = EIPSEC_INVAL_KEYLEN; + return -1; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +/* + * get max/min key length against algorithm specified. + * satype is one of satype defined at pfkeyv2.h. + * keylen is the unit of bit. + * OUT: + * -1: invalid. + * 0: valid. + */ +int +ipsec_get_keylen(supported, alg_id, alg0) + u_int supported, alg_id; + struct sadb_alg *alg0; +{ + struct sadb_alg *alg; + u_int satype; + + /* validity check */ + if (!alg0) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + switch (supported) { + case SADB_EXT_SUPPORTED_AUTH: + satype = SADB_SATYPE_AH; + break; + case SADB_EXT_SUPPORTED_ENCRYPT: + satype = SADB_SATYPE_ESP; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + alg = findsupportedalg(satype, alg_id); + if (!alg) + return -1; + + memcpy(alg0, alg, sizeof(*alg0)); + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +/* + * set the rate for SOFT lifetime against HARD one. + * If rate is more than 100 or equal to zero, then set to 100. + */ +static u_int soft_lifetime_allocations_rate = PFKEY_SOFT_LIFETIME_RATE; +static u_int soft_lifetime_bytes_rate = PFKEY_SOFT_LIFETIME_RATE; +static u_int soft_lifetime_addtime_rate = PFKEY_SOFT_LIFETIME_RATE; +static u_int soft_lifetime_usetime_rate = PFKEY_SOFT_LIFETIME_RATE; + +u_int +pfkey_set_softrate(type, rate) + u_int type, rate; +{ + __ipsec_errcode = EIPSEC_NO_ERROR; + + if (rate > 100 || rate == 0) + rate = 100; + + switch (type) { + case SADB_X_LIFETIME_ALLOCATIONS: + soft_lifetime_allocations_rate = rate; + return 0; + case SADB_X_LIFETIME_BYTES: + soft_lifetime_bytes_rate = rate; + return 0; + case SADB_X_LIFETIME_ADDTIME: + soft_lifetime_addtime_rate = rate; + return 0; + case SADB_X_LIFETIME_USETIME: + soft_lifetime_usetime_rate = rate; + return 0; + } + + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return 1; +} + +/* + * get current rate for SOFT lifetime against HARD one. + * ATTENTION: ~0 is returned if invalid type was passed. + */ +u_int +pfkey_get_softrate(type) + u_int type; +{ + switch (type) { + case SADB_X_LIFETIME_ALLOCATIONS: + return soft_lifetime_allocations_rate; + case SADB_X_LIFETIME_BYTES: + return soft_lifetime_bytes_rate; + case SADB_X_LIFETIME_ADDTIME: + return soft_lifetime_addtime_rate; + case SADB_X_LIFETIME_USETIME: + return soft_lifetime_usetime_rate; + } + + return ~0; +} + +/* + * sending SADB_GETSPI message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; + u_int32_t min, max, reqid, seq; +{ + struct sadb_msg *newmsg; + caddr_t ep; + int len; + int need_spirange = 0; + caddr_t p; + int plen; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + if (min > max || (min > 0 && min <= 255)) { + __ipsec_errcode = EIPSEC_INVAL_SPI; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + /* create new sadb_msg to send. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_x_sa2) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(dst->sa_len); + + if (min > (u_int32_t)255 && max < (u_int32_t)~0) { + need_spirange++; + len += sizeof(struct sadb_spirange); + } + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_GETSPI, + len, satype, seq, getpid()); + if (!p) { + free(newmsg); + return -1; + } + + p = pfkey_setsadbxsa2(p, ep, mode, reqid); + if (!p) { + free(newmsg); + return -1; + } + + /* set sadb_address for source */ + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + + /* set sadb_address for destination */ + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + + /* proccessing spi range */ + if (need_spirange) { + struct sadb_spirange spirange; + + if (p + sizeof(spirange) > ep) { + free(newmsg); + return -1; + } + + memset(&spirange, 0, sizeof(spirange)); + spirange.sadb_spirange_len = PFKEY_UNIT64(sizeof(spirange)); + spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE; + spirange.sadb_spirange_min = min; + spirange.sadb_spirange_max = max; + + memcpy(p, &spirange, sizeof(spirange)); + + p += sizeof(spirange); + } + if (p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * sending SADB_UPDATE message to the kernel. + * The length of key material is a_keylen + e_keylen. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_update(so, satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq) + int so; + u_int satype, mode, wsize; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc; + u_int64_t l_bytes, l_addtime, l_usetime; + u_int32_t seq; +{ + int len; + if ((len = pfkey_send_x1(so, SADB_UPDATE, satype, mode, src, dst, spi, + reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_ADD message to the kernel. + * The length of key material is a_keylen + e_keylen. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_add(so, satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq) + int so; + u_int satype, mode, wsize; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc; + u_int64_t l_bytes, l_addtime, l_usetime; + u_int32_t seq; +{ + int len; + if ((len = pfkey_send_x1(so, SADB_ADD, satype, mode, src, dst, spi, + reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_DELETE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_delete(so, satype, mode, src, dst, spi) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi; +{ + int len; + if ((len = pfkey_send_x2(so, SADB_DELETE, satype, mode, src, dst, spi)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_DELETE without spi to the kernel. This is + * the "delete all" request (an extension also present in + * Solaris). + * + * OUT: + * positive: success and return length sent + * -1 : error occured, and set errno + */ +int +pfkey_send_delete_all(so, satype, mode, src, dst) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + int plen; + caddr_t ep; + + (void)mode; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(dst->sa_len); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_DELETE, len, satype, 0, + getpid()); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, + IPSEC_ULPROTO_ANY); + if (!p || p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * sending SADB_GET message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_get(so, satype, mode, src, dst, spi) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi; +{ + int len; + if ((len = pfkey_send_x2(so, SADB_GET, satype, mode, src, dst, spi)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_REGISTER message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_register(so, satype) + int so; + u_int satype; +{ + int len, algno; + + if (satype == PF_UNSPEC) { + for (algno = 0; + (unsigned int)algno < sizeof(supported_map)/sizeof(supported_map[0]); + algno++) { + if (ipsec_supported[algno]) { + free(ipsec_supported[algno]); + ipsec_supported[algno] = NULL; + } + } + } else { + algno = findsupportedmap(satype); + if (algno == -1) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + if (ipsec_supported[algno]) { + free(ipsec_supported[algno]); + ipsec_supported[algno] = NULL; + } + } + + if ((len = pfkey_send_x3(so, SADB_REGISTER, satype)) < 0) + return -1; + + return len; +} + +/* + * receiving SADB_REGISTER message from the kernel, and copy buffer for + * sadb_supported returned into ipsec_supported. + * OUT: + * 0: success and return length sent. + * -1: error occured, and set errno. + */ +int +pfkey_recv_register(so) + int so; +{ + pid_t pid = getpid(); + struct sadb_msg *newmsg; + int error = -1; + + /* receive message */ + do { + if ((newmsg = pfkey_recv(so)) == NULL) + return -1; + } while (newmsg->sadb_msg_type != SADB_REGISTER + || (pid_t)newmsg->sadb_msg_pid != pid); + + /* check and fix */ + newmsg->sadb_msg_len = PFKEY_UNUNIT64(newmsg->sadb_msg_len); + + error = pfkey_set_supported(newmsg, newmsg->sadb_msg_len); + free(newmsg); + + if (error == 0) + __ipsec_errcode = EIPSEC_NO_ERROR; + + return error; +} + +/* + * receiving SADB_REGISTER message from the kernel, and copy buffer for + * sadb_supported returned into ipsec_supported. + * NOTE: sadb_msg_len must be host order. + * IN: + * tlen: msg length, it's to makeing sure. + * OUT: + * 0: success and return length sent. + * -1: error occured, and set errno. + */ +int +pfkey_set_supported(msg, tlen) + struct sadb_msg *msg; + int tlen; +{ + struct sadb_supported *sup; + caddr_t p; + caddr_t ep; + + /* validity */ + if (msg->sadb_msg_len != tlen) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + p = (caddr_t)msg; + ep = p + tlen; + + p += sizeof(struct sadb_msg); + + while (p < ep) { + sup = (struct sadb_supported *)p; + if (ep < p + sizeof(*sup) || + (size_t)PFKEY_EXTLEN(sup) < sizeof(*sup) || + ep < p + sup->sadb_supported_len) { + /* invalid format */ + break; + } + + switch (sup->sadb_supported_exttype) { + case SADB_EXT_SUPPORTED_AUTH: + case SADB_EXT_SUPPORTED_ENCRYPT: + break; + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + /* fixed length */ + sup->sadb_supported_len = PFKEY_EXTLEN(sup); + + /* set supported map */ + if (setsupportedmap(sup) != 0) + return -1; + + p += sup->sadb_supported_len; + } + + if (p != ep) { + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + + return 0; +} + +/* + * sending SADB_FLUSH message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_flush(so, satype) + int so; + u_int satype; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_FLUSH, satype)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_DUMP message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_dump(so, satype) + int so; + u_int satype; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_DUMP, satype)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_PROMISC message to the kernel. + * NOTE that this function handles promisc mode toggle only. + * IN: + * flag: set promisc off if zero, set promisc on if non-zero. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + * 0 : error occured, and set errno. + * others: a pointer to new allocated buffer in which supported + * algorithms is. + */ +int +pfkey_send_promisc_toggle(so, flag) + int so; + int flag; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_X_PROMISC, (flag ? 1 : 0))) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDADD message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdadd(so, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if ((len = pfkey_send_x4(so, SADB_X_SPDADD, + src, prefs, dst, prefd, proto, + 0, 0, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDADD message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdadd2(so, src, prefs, dst, prefd, proto, ltime, vtime, + policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + u_int64_t ltime, vtime; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if ((len = pfkey_send_x4(so, SADB_X_SPDADD, + src, prefs, dst, prefd, proto, + ltime, vtime, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDUPDATE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdupdate(so, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE, + src, prefs, dst, prefd, proto, + 0, 0, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDUPDATE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdupdate2(so, src, prefs, dst, prefd, proto, ltime, vtime, + policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + u_int64_t ltime, vtime; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE, + src, prefs, dst, prefd, proto, + ltime, vtime, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDDELETE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spddelete(so, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if (policylen != sizeof(struct sadb_x_policy)) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + if ((len = pfkey_send_x4(so, SADB_X_SPDDELETE, + src, prefs, dst, prefd, proto, + 0, 0, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDDELETE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spddelete2(so, spid) + int so; + u_int32_t spid; +{ + int len; + + if ((len = pfkey_send_x5(so, SADB_X_SPDDELETE2, spid)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDGET message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdget(so, spid) + int so; + u_int32_t spid; +{ + int len; + + if ((len = pfkey_send_x5(so, SADB_X_SPDGET, spid)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDSETIDX message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdsetidx(so, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if (policylen != sizeof(struct sadb_x_policy)) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + if ((len = pfkey_send_x4(so, SADB_X_SPDSETIDX, + src, prefs, dst, prefd, proto, + 0, 0, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_SPDFLUSH message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdflush(so) + int so; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_X_SPDFLUSH, SADB_SATYPE_UNSPEC)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_SPDDUMP message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spddump(so) + int so; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_X_SPDDUMP, SADB_SATYPE_UNSPEC)) < 0) + return -1; + + return len; +} + +/* sending SADB_ADD or SADB_UPDATE message to the kernel */ +static int +pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq) + int so; + u_int type, satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + u_int wsize; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc, l_bytes, l_addtime, l_usetime, seq; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + int plen; + caddr_t ep; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + switch (satype) { + case SADB_SATYPE_ESP: + if (e_type == SADB_EALG_NONE) { + __ipsec_errcode = EIPSEC_NO_ALGS; + return -1; + } + break; + case SADB_SATYPE_AH: + if (e_type != SADB_EALG_NONE) { + __ipsec_errcode = EIPSEC_INVAL_ALGS; + return -1; + } + if (a_type == SADB_AALG_NONE) { + __ipsec_errcode = EIPSEC_NO_ALGS; + return -1; + } + break; + case SADB_X_SATYPE_IPCOMP: + if (e_type == SADB_X_CALG_NONE) { + __ipsec_errcode = EIPSEC_INVAL_ALGS; + return -1; + } + if (a_type != SADB_AALG_NONE) { + __ipsec_errcode = EIPSEC_NO_ALGS; + return -1; + } + break; + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_sa) + + sizeof(struct sadb_x_sa2) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(dst->sa_len) + + sizeof(struct sadb_lifetime) + + sizeof(struct sadb_lifetime); + + if (e_type != SADB_EALG_NONE) + len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(e_keylen)); + if (a_type != SADB_AALG_NONE) + len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(a_keylen)); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, + satype, seq, getpid()); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbsa(p, ep, spi, wsize, a_type, e_type, flags); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbxsa2(p, ep, mode, reqid); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + + if (e_type != SADB_EALG_NONE) { + p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_ENCRYPT, + keymat, e_keylen); + if (!p) { + free(newmsg); + return -1; + } + } + if (a_type != SADB_AALG_NONE) { + p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_AUTH, + keymat + e_keylen, a_keylen); + if (!p) { + free(newmsg); + return -1; + } + } + + /* set sadb_lifetime for destination */ + p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD, + l_alloc, l_bytes, l_addtime, l_usetime); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_SOFT, + l_alloc, l_bytes, l_addtime, l_usetime); + if (!p || p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* sending SADB_DELETE or SADB_GET message to the kernel */ +static int +pfkey_send_x2(so, type, satype, mode, src, dst, spi) + int so; + u_int type, satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + int plen; + caddr_t ep; + + (void)mode; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_sa) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(dst->sa_len); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0, + getpid()); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbsa(p, ep, spi, 0, 0, 0, 0); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, + IPSEC_ULPROTO_ANY); + if (!p || p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * sending SADB_REGISTER, SADB_FLUSH, SADB_DUMP or SADB_X_PROMISC message + * to the kernel + */ +static int +pfkey_send_x3(so, type, satype) + int so; + u_int type, satype; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + caddr_t ep; + + /* validity check */ + switch (type) { + case SADB_X_PROMISC: + if (satype != 0 && satype != 1) { + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + break; + default: + switch (satype) { + case SADB_SATYPE_UNSPEC: + case SADB_SATYPE_AH: + case SADB_SATYPE_ESP: + case SADB_X_SATYPE_IPCOMP: + break; + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + } + + /* create new sadb_msg to send. */ + len = sizeof(struct sadb_msg); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0, + getpid()); + if (!p || p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* sending SADB_X_SPDADD message to the kernel */ +static int +pfkey_send_x4(so, type, src, prefs, dst, prefd, proto, + ltime, vtime, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int type, prefs, prefd, proto; + u_int64_t ltime, vtime; + char *policy; + int policylen; + u_int32_t seq; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + int plen; + caddr_t ep; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + if (prefs > (u_int)plen || prefd > (u_int)plen) { + __ipsec_errcode = EIPSEC_INVAL_PREFIXLEN; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_lifetime) + + policylen; + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, + SADB_SATYPE_UNSPEC, seq, getpid()); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, prefs, proto); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, prefd, proto); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD, + 0, 0, ltime, vtime); + if (!p || p + policylen != ep) { + free(newmsg); + return -1; + } + memcpy(p, policy, policylen); + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* sending SADB_X_SPDGET or SADB_X_SPDDELETE message to the kernel */ +static int +pfkey_send_x5(so, type, spid) + int so; + u_int type; + u_int32_t spid; +{ + struct sadb_msg *newmsg; + struct sadb_x_policy xpl; + int len; + caddr_t p; + caddr_t ep; + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(xpl); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, + SADB_SATYPE_UNSPEC, 0, getpid()); + if (!p) { + free(newmsg); + return -1; + } + + if (p + sizeof(xpl) != ep) { + free(newmsg); + return -1; + } + memset(&xpl, 0, sizeof(xpl)); + xpl.sadb_x_policy_len = PFKEY_UNUNIT64(sizeof(xpl)); + xpl.sadb_x_policy_exttype = SADB_X_EXT_POLICY; + xpl.sadb_x_policy_id = spid; + memcpy(p, &xpl, sizeof(xpl)); + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * open a socket. + * OUT: + * -1: fail. + * others : success and return value of socket. + */ +int +pfkey_open() +{ + int so; + const int bufsiz = 128 * 1024; /*is 128K enough?*/ + + if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + + /* + * This is a temporary workaround for KAME PR 154. + * Don't really care even if it fails. + */ + (void)setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsiz, sizeof(bufsiz)); + (void)setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsiz, sizeof(bufsiz)); + + __ipsec_errcode = EIPSEC_NO_ERROR; + return so; +} + +/* + * close a socket. + * OUT: + * 0: success. + * -1: fail. + */ +void +pfkey_close(so) + int so; +{ + (void)close(so); + + __ipsec_errcode = EIPSEC_NO_ERROR; + return; +} + +/* + * receive sadb_msg data, and return pointer to new buffer allocated. + * Must free this buffer later. + * OUT: + * NULL : error occured. + * others : a pointer to sadb_msg structure. + * + * XXX should be rewritten to pass length explicitly + */ +struct sadb_msg * +pfkey_recv(so) + int so; +{ + struct sadb_msg buf, *newmsg; + int len, reallen; + + while ((len = recv(so, (caddr_t)&buf, sizeof(buf), MSG_PEEK)) < 0) { + if (errno == EINTR) + continue; + __ipsec_set_strerror(strerror(errno)); + return NULL; + } + + if ((size_t)len < sizeof(buf)) { + recv(so, (caddr_t)&buf, sizeof(buf), 0); + __ipsec_errcode = EIPSEC_MAX; + return NULL; + } + + /* read real message */ + reallen = PFKEY_UNUNIT64(buf.sadb_msg_len); + if ((newmsg = CALLOC(reallen, struct sadb_msg *)) == 0) { + __ipsec_set_strerror(strerror(errno)); + return NULL; + } + + while ((len = recv(so, (caddr_t)newmsg, reallen, 0)) < 0) { + if (errno == EINTR) + continue; + __ipsec_set_strerror(strerror(errno)); + free(newmsg); + return NULL; + } + + if (len != reallen) { + __ipsec_errcode = EIPSEC_SYSTEM_ERROR; + free(newmsg); + return NULL; + } + + /* don't trust what the kernel says, validate! */ + if (PFKEY_UNUNIT64(newmsg->sadb_msg_len) != len) { + __ipsec_errcode = EIPSEC_SYSTEM_ERROR; + free(newmsg); + return NULL; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return newmsg; +} + +/* + * send message to a socket. + * OUT: + * others: success and return length sent. + * -1 : fail. + */ +int +pfkey_send(so, msg, len) + int so; + struct sadb_msg *msg; + int len; +{ + if ((len = send(so, (caddr_t)msg, len, 0)) < 0) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * %%% Utilities + * NOTE: These functions are derived from netkey/key.c in KAME. + */ +/* + * set the pointer to each header in this message buffer. + * IN: msg: pointer to message buffer. + * mhp: pointer to the buffer initialized like below: + * caddr_t mhp[SADB_EXT_MAX + 1]; + * OUT: -1: invalid. + * 0: valid. + * + * XXX should be rewritten to obtain length explicitly + */ +int +pfkey_align(msg, mhp) + struct sadb_msg *msg; + caddr_t *mhp; +{ + struct sadb_ext *ext; + int i; + caddr_t p; + caddr_t ep; /* XXX should be passed from upper layer */ + + /* validity check */ + if (msg == NULL || mhp == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + /* initialize */ + for (i = 0; i < SADB_EXT_MAX + 1; i++) + mhp[i] = NULL; + + mhp[0] = (caddr_t)msg; + + /* initialize */ + p = (caddr_t) msg; + ep = p + PFKEY_UNUNIT64(msg->sadb_msg_len); + + /* skip base header */ + p += sizeof(struct sadb_msg); + + while (p < ep) { + ext = (struct sadb_ext *)p; + if (ep < p + sizeof(*ext) || (size_t)PFKEY_EXTLEN(ext) < sizeof(*ext) || + ep < p + PFKEY_EXTLEN(ext)) { + /* invalid format */ + break; + } + + /* duplicate check */ + /* XXX Are there duplication either KEY_AUTH or KEY_ENCRYPT ?*/ + if (mhp[ext->sadb_ext_type] != NULL) { + __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; + return -1; + } + + /* set pointer */ + switch (ext->sadb_ext_type) { + case SADB_EXT_SA: + case SADB_EXT_LIFETIME_CURRENT: + case SADB_EXT_LIFETIME_HARD: + case SADB_EXT_LIFETIME_SOFT: + case SADB_EXT_ADDRESS_SRC: + case SADB_EXT_ADDRESS_DST: + case SADB_EXT_ADDRESS_PROXY: + case SADB_EXT_KEY_AUTH: + /* XXX should to be check weak keys. */ + case SADB_EXT_KEY_ENCRYPT: + /* XXX should to be check weak keys. */ + case SADB_EXT_IDENTITY_SRC: + case SADB_EXT_IDENTITY_DST: + case SADB_EXT_SENSITIVITY: + case SADB_EXT_PROPOSAL: + case SADB_EXT_SUPPORTED_AUTH: + case SADB_EXT_SUPPORTED_ENCRYPT: + case SADB_EXT_SPIRANGE: + case SADB_X_EXT_POLICY: + case SADB_X_EXT_SA2: + mhp[ext->sadb_ext_type] = (caddr_t)ext; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; + return -1; + } + + p += PFKEY_EXTLEN(ext); + } + + if (p != ep) { + __ipsec_errcode = EIPSEC_INVAL_SADBMSG; + return -1; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +/* + * check basic usage for sadb_msg, + * NOTE: This routine is derived from netkey/key.c in KAME. + * IN: msg: pointer to message buffer. + * mhp: pointer to the buffer initialized like below: + * + * caddr_t mhp[SADB_EXT_MAX + 1]; + * + * OUT: -1: invalid. + * 0: valid. + */ +int +pfkey_check(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg; + + /* validity check */ + if (mhp == NULL || mhp[0] == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + msg = (struct sadb_msg *)mhp[0]; + + /* check version */ + if (msg->sadb_msg_version != PF_KEY_V2) { + __ipsec_errcode = EIPSEC_INVAL_VERSION; + return -1; + } + + /* check type */ + if (msg->sadb_msg_type > SADB_MAX) { + __ipsec_errcode = EIPSEC_INVAL_MSGTYPE; + return -1; + } + + /* check SA type */ + switch (msg->sadb_msg_satype) { + case SADB_SATYPE_UNSPEC: + switch (msg->sadb_msg_type) { + case SADB_GETSPI: + case SADB_UPDATE: + case SADB_ADD: + case SADB_DELETE: + case SADB_GET: + case SADB_ACQUIRE: + case SADB_EXPIRE: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + break; + case SADB_SATYPE_ESP: + case SADB_SATYPE_AH: + case SADB_X_SATYPE_IPCOMP: + switch (msg->sadb_msg_type) { + case SADB_X_SPDADD: + case SADB_X_SPDDELETE: + case SADB_X_SPDGET: + case SADB_X_SPDDUMP: + case SADB_X_SPDFLUSH: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + break; + case SADB_SATYPE_RSVP: + case SADB_SATYPE_OSPFV2: + case SADB_SATYPE_RIPV2: + case SADB_SATYPE_MIP: + __ipsec_errcode = EIPSEC_NOT_SUPPORTED; + return -1; + case 1: /* XXX: What does it do ? */ + if (msg->sadb_msg_type == SADB_X_PROMISC) + break; + /*FALLTHROUGH*/ + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + /* check field of upper layer protocol and address family */ + if (mhp[SADB_EXT_ADDRESS_SRC] != NULL + && mhp[SADB_EXT_ADDRESS_DST] != NULL) { + struct sadb_address *src0, *dst0; + + src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + + if (src0->sadb_address_proto != dst0->sadb_address_proto) { + __ipsec_errcode = EIPSEC_PROTO_MISMATCH; + return -1; + } + + if (PFKEY_ADDR_SADDR(src0)->sa_family + != PFKEY_ADDR_SADDR(dst0)->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + + switch (PFKEY_ADDR_SADDR(src0)->sa_family) { + case AF_INET: + case AF_INET6: + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + /* + * prefixlen == 0 is valid because there must be the case + * all addresses are matched. + */ + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +/* + * set data into sadb_msg. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +pfkey_setsadbmsg(buf, lim, type, tlen, satype, seq, pid) + caddr_t buf; + caddr_t lim; + u_int type, satype; + u_int tlen; + u_int32_t seq; + pid_t pid; +{ + struct sadb_msg *p; + u_int len; + + p = (struct sadb_msg *)buf; + len = sizeof(struct sadb_msg); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_msg_version = PF_KEY_V2; + p->sadb_msg_type = type; + p->sadb_msg_errno = 0; + p->sadb_msg_satype = satype; + p->sadb_msg_len = PFKEY_UNIT64(tlen); + p->sadb_msg_reserved = 0; + p->sadb_msg_seq = seq; + p->sadb_msg_pid = (u_int32_t)pid; + + return(buf + len); +} + +/* + * copy secasvar data into sadb_address. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +pfkey_setsadbsa(buf, lim, spi, wsize, auth, enc, flags) + caddr_t buf; + caddr_t lim; + u_int32_t spi, flags; + u_int wsize, auth, enc; +{ + struct sadb_sa *p; + u_int len; + + p = (struct sadb_sa *)buf; + len = sizeof(struct sadb_sa); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_sa_len = PFKEY_UNIT64(len); + p->sadb_sa_exttype = SADB_EXT_SA; + p->sadb_sa_spi = spi; + p->sadb_sa_replay = wsize; + p->sadb_sa_state = SADB_SASTATE_LARVAL; + p->sadb_sa_auth = auth; + p->sadb_sa_encrypt = enc; + p->sadb_sa_flags = flags; + + return(buf + len); +} + +/* + * set data into sadb_address. + * `buf' must has been allocated sufficiently. + * prefixlen is in bits. + */ +static caddr_t +pfkey_setsadbaddr(buf, lim, exttype, saddr, prefixlen, ul_proto) + caddr_t buf; + caddr_t lim; + u_int exttype; + struct sockaddr *saddr; + u_int prefixlen; + u_int ul_proto; +{ + struct sadb_address *p; + u_int len; + + p = (struct sadb_address *)buf; + len = sizeof(struct sadb_address) + PFKEY_ALIGN8(saddr->sa_len); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_address_len = PFKEY_UNIT64(len); + p->sadb_address_exttype = exttype & 0xffff; + p->sadb_address_proto = ul_proto & 0xff; + p->sadb_address_prefixlen = prefixlen; + p->sadb_address_reserved = 0; + + memcpy(p + 1, saddr, saddr->sa_len); + + return(buf + len); +} + +/* + * set sadb_key structure after clearing buffer with zero. + * OUT: the pointer of buf + len. + */ +static caddr_t +pfkey_setsadbkey(buf, lim, type, key, keylen) + caddr_t buf; + caddr_t lim; + caddr_t key; + u_int type, keylen; +{ + struct sadb_key *p; + u_int len; + + p = (struct sadb_key *)buf; + len = sizeof(struct sadb_key) + PFKEY_ALIGN8(keylen); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_key_len = PFKEY_UNIT64(len); + p->sadb_key_exttype = type; + p->sadb_key_bits = keylen << 3; + p->sadb_key_reserved = 0; + + memcpy(p + 1, key, keylen); + + return buf + len; +} + +/* + * set sadb_lifetime structure after clearing buffer with zero. + * OUT: the pointer of buf + len. + */ +static caddr_t +pfkey_setsadblifetime(buf, lim, type, l_alloc, l_bytes, l_addtime, l_usetime) + caddr_t buf; + caddr_t lim; + u_int type; + u_int32_t l_alloc, l_bytes, l_addtime, l_usetime; +{ + struct sadb_lifetime *p; + u_int len; + + p = (struct sadb_lifetime *)buf; + len = sizeof(struct sadb_lifetime); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_lifetime_len = PFKEY_UNIT64(len); + p->sadb_lifetime_exttype = type; + + switch (type) { + case SADB_EXT_LIFETIME_SOFT: + p->sadb_lifetime_allocations + = (l_alloc * soft_lifetime_allocations_rate) /100; + p->sadb_lifetime_bytes + = (l_bytes * soft_lifetime_bytes_rate) /100; + p->sadb_lifetime_addtime + = (l_addtime * soft_lifetime_addtime_rate) /100; + p->sadb_lifetime_usetime + = (l_usetime * soft_lifetime_usetime_rate) /100; + break; + case SADB_EXT_LIFETIME_HARD: + p->sadb_lifetime_allocations = l_alloc; + p->sadb_lifetime_bytes = l_bytes; + p->sadb_lifetime_addtime = l_addtime; + p->sadb_lifetime_usetime = l_usetime; + break; + } + + return buf + len; +} + +/* + * copy secasvar data into sadb_address. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +pfkey_setsadbxsa2(buf, lim, mode0, reqid) + caddr_t buf; + caddr_t lim; + u_int32_t mode0; + u_int32_t reqid; +{ + struct sadb_x_sa2 *p; + u_int8_t mode = mode0 & 0xff; + u_int len; + + p = (struct sadb_x_sa2 *)buf; + len = sizeof(struct sadb_x_sa2); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_x_sa2_len = PFKEY_UNIT64(len); + p->sadb_x_sa2_exttype = SADB_X_EXT_SA2; + p->sadb_x_sa2_mode = mode; + p->sadb_x_sa2_reqid = reqid; + + return(buf + len); +} diff --git a/mDNSPosix/Client.c b/mDNSPosix/Client.c index 6aafe37..6efffc3 100755 --- a/mDNSPosix/Client.c +++ b/mDNSPosix/Client.c @@ -2,28 +2,34 @@ * * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: Client.c,v $ +Revision 1.20 2007/07/27 19:30:41 cheshire +Changed mDNSQuestionCallback parameter from mDNSBool to QC_result, +to properly reflect tri-state nature of the possible responses + +Revision 1.19 2007/04/16 20:49:39 cheshire +Fix compile errors for mDNSPosix build + +Revision 1.18 2006/08/14 23:24:46 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + +Revision 1.17 2006/06/12 18:22:42 cheshire + mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux + Revision 1.16 2005/02/04 01:00:53 cheshire Add '-d' command-line option to specify domain to browse @@ -99,9 +105,11 @@ static mDNS_PlatformSupport PlatformStorage; // Stores this platform's globals #define RR_CACHE_SIZE 500 static CacheEntity gRRCache[RR_CACHE_SIZE]; -static const char *gProgramName = "mDNSResponderPosix"; +mDNSexport const char ProgramName[] = "mDNSClientPosix"; + +static const char *gProgramName = ProgramName; -static void BrowseCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) +static void BrowseCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) // A callback from the core mDNS code that indicates that we've received a // response to our query. Note that this code runs on the main thread // (in fact, there is only one thread!), so we can safely printf the results. @@ -281,7 +289,7 @@ int main(int argc, char **argv) result = 2; } if ( (result != 0) || (gMDNSPlatformPosixVerboseLevel > 0) ) { - fprintf(stderr, "%s: Finished with status %ld, result %d\n", gProgramName, status, result); + fprintf(stderr, "%s: Finished with status %d, result %d\n", gProgramName, (int)status, result); } return 0; diff --git a/mDNSPosix/ExampleClientApp.c b/mDNSPosix/ExampleClientApp.c index 17843af..15bb86a 100644 --- a/mDNSPosix/ExampleClientApp.c +++ b/mDNSPosix/ExampleClientApp.c @@ -2,28 +2,27 @@ * * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: ExampleClientApp.c,v $ +Revision 1.14 2006/08/14 23:24:46 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + +Revision 1.13 2006/02/23 23:38:43 cheshire + On FreeBSD 4 "arpa/inet.h" requires "netinet/in.h" be included first + Revision 1.12 2004/11/30 22:37:00 cheshire Update copyright dates and add "Mode: C; tab-width: 4" headers @@ -55,8 +54,8 @@ Add log header #include // For strlen() etc. #include // For select() #include // For errno, EINTR -#include // For inet_addr() #include // For INADDR_NONE +#include // For inet_addr() #include // For gethostbyname() #include // For SIGINT, etc. diff --git a/mDNSPosix/ExampleClientApp.h b/mDNSPosix/ExampleClientApp.h index fa9f0fc..3438260 100644 --- a/mDNSPosix/ExampleClientApp.h +++ b/mDNSPosix/ExampleClientApp.h @@ -2,28 +2,24 @@ * * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: ExampleClientApp.h,v $ +Revision 1.7 2006/08/14 23:24:46 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + Revision 1.6 2004/11/30 22:37:00 cheshire Update copyright dates and add "Mode: C; tab-width: 4" headers diff --git a/mDNSPosix/Identify.c b/mDNSPosix/Identify.c index c1724f2..ee88102 100644 --- a/mDNSPosix/Identify.c +++ b/mDNSPosix/Identify.c @@ -2,24 +2,17 @@ * * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ * * Formatting notes: * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion @@ -37,119 +30,33 @@ Change History (most recent first): $Log: Identify.c,v $ -Revision 1.34 2004/12/16 20:17:11 cheshire - Cache memory management improvements - -Revision 1.33 2004/11/30 22:37:00 cheshire -Update copyright dates and add "Mode: C; tab-width: 4" headers - -Revision 1.32 2004/10/19 21:33:21 cheshire - Cannot resolve non-local registrations using the mach API -Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name -doesn't force multicast unless you set this flag to indicate explicitly that this is what you want - -Revision 1.31 2004/10/16 00:17:00 cheshire - Replace IP TTL 255 check with local subnet source address check - -Revision 1.30 2004/09/21 23:29:51 cheshire - DNSServiceResolve should delay sending packets - -Revision 1.29 2004/09/17 01:08:53 cheshire -Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h - The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces - declared in that file are ONLY appropriate to single-address-space embedded applications. - For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used. - -Revision 1.28 2004/09/17 00:31:52 cheshire -For consistency with ipv6, renamed rdata field 'ip' to 'ipv4' - -Revision 1.27 2004/09/16 01:58:22 cheshire -Fix compiler warnings - -Revision 1.26 2004/08/24 21:55:07 cheshire -Don't try to build IPv6 code on systems that don't have IPv6 - -Revision 1.25 2004/07/20 23:42:37 cheshire -Update to use only "_services._dns-sd._udp.local." meta-query for service enumeration - -Revision 1.24 2004/06/15 02:39:47 cheshire -When displaying error message, only show command name, not entire path - -Revision 1.23 2004/05/18 23:51:26 cheshire -Tidy up all checkin comments to use consistent "" format for bug numbers - -Revision 1.22 2004/04/20 22:43:28 cheshire -Use _services._dns-sd._udp query, as documented in - - -Revision 1.21 2004/01/28 21:38:57 cheshire -Also ask target host for _services._mdns._udp.local. list - -Revision 1.20 2004/01/28 19:04:38 cheshire -Fix Ctrl-C handling when multiple targets are specified - -Revision 1.19 2004/01/28 03:49:30 cheshire -Enhanced mDNSIdentify to make use of new targeted-query capability - -Revision 1.18 2004/01/27 19:06:51 cheshire -Remove workaround for WWDC 2003 bug; no one has run that buggy build for a long time - -Revision 1.17 2004/01/22 03:57:00 cheshire -Use the new meta-interface mDNSInterface_ForceMCast. This restores mDNSIdentify's -ability to use multicast queries with non-link-local target addresses, like 17.x.x.x. - -Revision 1.16 2004/01/22 00:03:32 cheshire -Add while() loop so that a list of targets may be specified on the command line - -Revision 1.15 2004/01/21 21:55:06 cheshire -Don't need to wait for timeout once we've got the information we wanted - -Revision 1.14 2003/12/17 00:51:22 cheshire -Changed mDNSNetMonitor and mDNSIdentify to link the object files -instead of #including the "DNSCommon.c" "uDNS.c" and source files - -Revision 1.13 2003/12/13 03:05:28 ksekar -: DynDNS: Unicast query of service records - -Revision 1.12 2003/11/14 21:27:09 cheshire -: Security: Crashing bug in mDNSResponder -Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers. - -Revision 1.11 2003/10/30 19:26:38 cheshire -Fix warnings on certain compilers - -Revision 1.10 2003/09/02 20:38:57 cheshire -#include for Linux - -Revision 1.9 2003/08/14 23:57:46 cheshire -Report if there is no answer at all from the target host - -Revision 1.8 2003/08/14 02:19:55 cheshire - Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord +Revision 1.42 2007/07/27 19:30:41 cheshire +Changed mDNSQuestionCallback parameter from mDNSBool to QC_result, +to properly reflect tri-state nature of the possible responses -Revision 1.7 2003/08/12 19:56:26 cheshire -Update to APSL 2.0 +Revision 1.41 2007/04/16 20:49:39 cheshire +Fix compile errors for mDNSPosix build -Revision 1.6 2003/08/06 01:46:18 cheshire -Distinguish no answer from partial answer +Revision 1.40 2007/02/28 01:51:22 cheshire +Added comment about reverse-order IP address -Revision 1.5 2003/08/05 23:56:26 cheshire -Update code to compile with the new mDNSCoreReceive() function that requires a TTL -(Right now mDNSPosix.c just reports 255 -- we should fix this) +Revision 1.39 2007/01/05 08:30:51 cheshire +Trim excessive "$Log" checkin history from before 2006 +(checkin history still available via "cvs log ..." of course) -Revision 1.4 2003/08/04 17:24:48 cheshire -Combine the three separate A/AAAA/HINFO queries into a single qtype "ANY" query +Revision 1.38 2007/01/04 20:57:48 cheshire +Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates) -Revision 1.3 2003/08/04 17:14:08 cheshire -Do both AAAA queries in parallel +Revision 1.37 2006/10/27 01:32:08 cheshire +Set ReturnIntermed to mDNStrue -Revision 1.2 2003/08/02 02:25:13 cheshire -Multiple improvements: Now displays host's name, and all v4 and v6 addresses, as well as HINFO record +Revision 1.36 2006/08/14 23:24:46 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 -Revision 1.1 2003/08/01 02:20:02 cheshire -Add mDNSIdentify tool, used to discover what version of mDNSResponder a particular host is running +Revision 1.35 2006/06/12 18:22:42 cheshire + mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux - */ +*/ //************************************************************************************************************* // Incorporate mDNS.c functionality @@ -185,6 +92,7 @@ static mDNS mDNSStorage; // mDNS core uses this to store its globals static mDNS_PlatformSupport PlatformStorage; // Stores this platform's globals #define RR_CACHE_SIZE 500 static CacheEntity gRRCache[RR_CACHE_SIZE]; +mDNSexport const char ProgramName[] = "mDNSIdentify"; static volatile int StopNow; // 0 means running, 1 means stop because we got an answer, 2 means stop because of Ctrl-C static volatile int NumAnswers, NumAddr, NumAAAA, NumHINFO; @@ -226,7 +134,7 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS __MDNS__mDNSCoreReceive(m, msg, end, srcaddr, srcport, &AllDNSLinkGroup_v4, dstport, InterfaceID); } -static void NameCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) +static void NameCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) { (void)m; // Unused (void)question; // Unused @@ -240,7 +148,7 @@ static void NameCallback(mDNS *const m, DNSQuestion *question, const ResourceRec } } -static void InfoCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) +static void InfoCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) { (void)m; // Unused (void)question; // Unused @@ -282,7 +190,7 @@ static void InfoCallback(mDNS *const m, DNSQuestion *question, const ResourceRec if (NumHINFO && (NumAddr || NumAAAA)) StopNow = 1; } -static void ServicesCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) +static void ServicesCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) { (void)m; // Unused (void)question; // Unused @@ -338,6 +246,7 @@ mDNSlocal mStatus StartQuery(DNSQuestion *q, char *qname, mDNSu16 qtype, const m q->LongLived = mDNSfalse; q->ExpectUnique = mDNStrue; q->ForceMCast = mDNStrue; // Query via multicast, even for apparently uDNS names like 1.1.1.17.in-addr.arpa. + q->ReturnIntermed = mDNStrue; q->QuestionCallback = callback; q->QuestionContext = NULL; @@ -400,7 +309,7 @@ mDNSexport int main(int argc, char **argv) gRRCache, RR_CACHE_SIZE, mDNS_Init_DontAdvertiseLocalAddresses, mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext); - if (status) { fprintf(stderr, "Daemon start: mDNS_Init failed %ld\n", status); return(status); } + if (status) { fprintf(stderr, "Daemon start: mDNS_Init failed %d\n", (int)status); return(status); } signal(SIGINT, HandleSIG); // SIGINT is what you get for a Ctrl-C signal(SIGTERM, HandleSIG); @@ -418,6 +327,7 @@ mDNSexport int main(int argc, char **argv) if (inet_pton(AF_INET, arg, &s4) == 1) { mDNSu8 *p = (mDNSu8 *)&s4; + // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", p[3], p[2], p[1], p[0]); printf("%s\n", buffer); target.type = mDNSAddrType_IPv4; diff --git a/mDNSPosix/Makefile b/mDNSPosix/Makefile index f283913..91bc819 100755 --- a/mDNSPosix/Makefile +++ b/mDNSPosix/Makefile @@ -1,3 +1,5 @@ +# -*- tab-width: 4 -*- +# # Copyright (c) 2002-2004, Apple Computer, Inc. All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -23,7 +25,49 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # +# IMPORTANT NOTE: This is a Makefile for *GNU make* +# On some systems, a different program may be the default "make" command. +# If "make os=xxx" gives lots of errors like "Missing dependency operator", +# then try typing "gmake os=xxx" instead. +# # $Log: Makefile,v $ +# Revision 1.76 2007/07/31 23:39:02 mcguire +# Don't bail on errors in flex-generated .c files +# +# Revision 1.75 2006/08/24 22:41:23 herscher +# POSIX: dnsextd_parser doesn't compile on Linux +# +# Revision 1.74 2006/08/14 23:07:11 cheshire +# Added "tab-width" emacs header line +# +# Revision 1.73 2006/07/07 00:54:08 cheshire +# Add Private DNS server functionality to dnsextd +# Put intermediate files into "objects" folder instead of mDNSShared source code folder +# +# Revision 1.72 2006/07/05 23:53:58 cheshire +# Add Private DNS server functionality to dnsextd +# +# Revision 1.71 2006/06/20 23:07:04 rpantos +# Java needs to implement DNSServiceRegisterRecord equivalent +# +# Revision 1.70 2006/05/03 23:35:10 cheshire +# Add missing dependency: NetMonitor.c textually imports mDNS.c +# +# Revision 1.69 2006/02/26 23:18:50 cheshire +# FreeBSD 4 requires "-pthread" option to compile threaded code +# +# Revision 1.68 2006/02/26 01:36:54 cheshire +# Rename the poorly named "LIBFLAGS" as "LINKOPTS" +# +# Revision 1.67 2006/02/25 23:14:29 cheshire +# Add comment suggesting using "gmake" command +# +# Revision 1.66 2006/01/06 01:06:17 cheshire +# Compile library and client programs in one pass +# +# Revision 1.65 2005/12/21 21:15:57 cheshire +# Add missing dependency: Identify.c textually imports mDNS.c +# # Revision 1.64 2005/10/25 23:55:47 cheshire # Add tiger to list of target platforms # @@ -229,9 +273,10 @@ # Notes: # $@ means "The file name of the target of the rule" # $< means "The name of the first prerequisite" +# $* means "The stem with which an implicit rule matches" # $+ means "The names of all the prerequisites, with spaces between them, exactly as given" # For more magic automatic variables, see -# +# ############################################################################# @@ -242,12 +287,16 @@ SHAREDDIR = ../mDNSShared JDK = /usr/jdk CC = @cc +BISON = @bison +FLEX = @flex LD = ld -shared CP = cp RM = rm LN = ln -s -f -CFLAGS_COMMON = -I. -I$(COREDIR) -I$(SHAREDDIR) -W -Wall -DPID_FILE=\"/var/run/mdnsd.pid\" -DMDNS_UDS_SERVERPATH=\"/var/run/mdnsd\" -LIBFLAGS = +CFLAGS_COMMON = -I. -I$(COREDIR) -I$(SHAREDDIR) -I$(OBJDIR) -W -Wall -DPID_FILE=\"/var/run/mdnsd.pid\" -DMDNS_UDS_SERVERPATH=\"/var/run/mdnsd\" +CFLAGS_PTHREAD = +LINKOPTS = +LINKOPTS_PTHREAD = -lpthread LDSUFFIX = so JAVACFLAGS_OS = -fPIC -shared -ldns_sd @@ -274,7 +323,7 @@ CFLAGS_OS = -DNOT_HAVE_DAEMON -DNOT_HAVE_SA_LEN -DNOT_HAVE_SOCKLEN_T -DNOT_HAVE_ -DLOG_PERROR=0 -D_XPG4_2 -D__EXTENSIONS__ -DHAVE_BROKEN_RECVIF_NAME CC = gcc LD = gcc -shared -LIBFLAGS = -lsocket -lnsl -lresolv +LINKOPTS = -lsocket -lnsl -lresolv JAVACFLAGS_OS += -I$(JDK)/include/solaris ifneq ($(DEBUG),1) STRIP = strip @@ -282,7 +331,8 @@ endif else ifeq ($(os),linux) -CFLAGS_OS = -DNOT_HAVE_SA_LEN -DUSES_NETLINK -DHAVE_LINUX +CFLAGS_OS = -DNOT_HAVE_SA_LEN -DUSES_NETLINK -DHAVE_LINUX -DTARGET_OS_LINUX +FLEXFLAGS_OS = -l JAVACFLAGS_OS += -I$(JDK)/include/linux OPTIONALTARG = nss_mdns OPTINSTALL = InstalledNSS @@ -300,6 +350,14 @@ LOCALBASE?=/usr/local INSTBASE=$(LOCALBASE) STARTUPSCRIPTNAME=mdns.sh CFLAGS_OS = +# FreeBSD 4 requires threaded code to be compiled and linked using the "-pthread" option, +# and requires that the "-lpthread" link option NOT be used +# This appies only to FreeBSD -- "man cc" on FreeBSD says: +# FreeBSD SPECIFIC OPTIONS +# -pthread +# Link a user-threaded process against libc_r instead of libc. +CFLAGS_PTHREAD = -pthread -D_THREAD_SAFE +LINKOPTS_PTHREAD = -pthread JAVACFLAGS_OS += -I$(JDK)/include/freebsd LDCONFIG = ldconfig else @@ -312,7 +370,7 @@ else ifeq ($(os),jaguar) CFLAGS_OS = -DHAVE_IPV6 -no-cpp-precomp -Werror -DNOT_HAVE_SOCKLEN_T LD = libtool -dynamic -LIBFLAGS = -lSystem +LINKOPTS = -lSystem LDSUFFIX = dylib JDK = /System/Library/Frameworks/JavaVM.framework/Home JAVACFLAGS_OS = -dynamiclib -I/System/Library/Frameworks/JavaVM.framework/Headers -framework JavaVM @@ -321,7 +379,7 @@ else ifeq ($(os),panther) CFLAGS_OS = -DHAVE_IPV6 -no-cpp-precomp -Werror LD = libtool -dynamic -LIBFLAGS = -lSystem +LINKOPTS = -lSystem LDSUFFIX = dylib JDK = /System/Library/Frameworks/JavaVM.framework/Home JAVACFLAGS_OS = -dynamiclib -I/System/Library/Frameworks/JavaVM.framework/Headers -framework JavaVM @@ -331,7 +389,7 @@ ifeq ($(os),tiger) CFLAGS_OS = -DHAVE_IPV6 -no-cpp-precomp -Werror -Wdeclaration-after-statement #-Wunreachable-code CC = @gcc-4.0 LD = $(CC) -dynamiclib -LIBFLAGS = -lSystem +LINKOPTS = -lSystem LDSUFFIX = dylib JDK = /System/Library/Frameworks/JavaVM.framework/Home JAVACFLAGS_OS = -dynamiclib -I/System/Library/Frameworks/JavaVM.framework/Headers -framework JavaVM @@ -399,9 +457,9 @@ CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_OS) $(CFLAGS_DEBUG) ############################################################################# -all: setup Daemon libdns_sd Client Responder ProxyResponder Identify NetMonitor dnsextd $(OPTIONALTARG) +all: setup Daemon libdns_sd Clients SAClient SAResponder SAProxyResponder Identify NetMonitor dnsextd $(OPTIONALTARG) -install: setup InstalledDaemon InstalledLib InstalledStartup InstalledManPages $(OPTINSTALL) +install: setup InstalledDaemon InstalledStartup InstalledLib InstalledManPages InstalledClients $(OPTINSTALL) # 'setup' sets up the build directory structure the way we want setup: @@ -412,8 +470,9 @@ setup: # clean removes targets and objects clean: - if test -d $(OBJDIR) ; then rm -r $(OBJDIR) ; fi - if test -d $(BUILDDIR) ; then rm -r $(BUILDDIR) ; fi + @if test -d $(OBJDIR) ; then rm -r $(OBJDIR) ; fi + @if test -d $(BUILDDIR) ; then rm -r $(BUILDDIR) ; fi + @$(MAKE) -C ../Clients clean ############################################################################# @@ -422,11 +481,15 @@ DAEMONOBJS = $(OBJDIR)/PosixDaemon.c.o $(OBJDIR)/mDNSPosix.c.o $(OBJDIR)/mDNSUNP $(OBJDIR)/DNSDigest.c.o $(OBJDIR)/uDNS.c.o $(OBJDIR)/DNSCommon.c.o $(OBJDIR)/uds_daemon.c.o \ $(OBJDIR)/mDNSDebug.c.o $(OBJDIR)/dnssd_ipc.c.o $(OBJDIR)/GenLinkedList.c.o $(OBJDIR)/PlatformCommon.c.o +# dnsextd target build dnsextd +DNSEXTDOBJ = $(OBJDIR)/mDNSPosix.c.o $(OBJDIR)/mDNSUNP.c.o $(OBJDIR)/mDNSDebug.c.o $(OBJDIR)/GenLinkedList.c.o $(OBJDIR)/DNSDigest.c.o \ + $(OBJDIR)/DNSCommon.c.o $(OBJDIR)/PlatformCommon.c.o $(OBJDIR)/dnsextd_parser.y.o $(OBJDIR)/dnsextd_lexer.l.o + Daemon: setup $(BUILDDIR)/mdnsd @echo "Responder daemon done" $(BUILDDIR)/mdnsd: $(DAEMONOBJS) - $(CC) -o $@ $+ $(CFLAGS) $(LIBFLAGS) + $(CC) -o $@ $+ $(LINKOPTS) @$(STRIP) $@ # libdns_sd target builds the client library @@ -436,15 +499,21 @@ libdns_sd: setup $(BUILDDIR)/libdns_sd.$(LDSUFFIX) CLIENTLIBOBJS = $(OBJDIR)/dnssd_clientlib.c.so.o $(OBJDIR)/dnssd_clientstub.c.so.o $(OBJDIR)/dnssd_ipc.c.so.o $(BUILDDIR)/libdns_sd.$(LDSUFFIX): $(CLIENTLIBOBJS) - @$(LD) $(LIBFLAGS) -o $@ $+ + @$(LD) $(LINKOPTS) -o $@ $+ @$(STRIP) $@ +Clients: setup libdns_sd ../Clients/build/dns-sd + @echo "Clients done" + +../Clients/build/dns-sd: + @$(MAKE) -C ../Clients + # nss_mdns target builds the Name Service Switch module nss_mdns: setup $(BUILDDIR)/$(NSSLIBFILE) @echo "Name Service Switch module done" $(BUILDDIR)/$(NSSLIBFILE): $(CLIENTLIBOBJS) $(OBJDIR)/nss_mdns.c.so.o - @$(LD) $(LIBFLAGS) -o $@ $+ + @$(LD) $(LINKOPTS) -o $@ $+ @$(STRIP) $@ ############################################################################# @@ -459,13 +528,18 @@ InstalledLib: $(INSTBASE)/lib/libdns_sd.$(LDSUFFIX).$(LIBVERS) $(INSTBASE)/inclu InstalledStartup: $(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME) @echo $+ " installed" -InstalledNSS: $(NSSINSTPATH)/$(NSSLINKNAME) /etc/nss_mdns.conf $(MANPATH)/man5/nss_mdns.conf.5 $(MANPATH)/man8/libnss_mdns.8 +InstalledManPages: $(MANPATH)/man8/mdnsd.8 @echo $+ " installed" -InstalledManPages: $(MANPATH)/man8/mdnsd.8 +InstalledClients: $(INSTBASE)/bin/dns-sd @echo $+ " installed" +InstalledNSS: $(NSSINSTPATH)/$(NSSLINKNAME) /etc/nss_mdns.conf $(MANPATH)/man5/nss_mdns.conf.5 $(MANPATH)/man8/libnss_mdns.8 + @echo $+ " installed" + +# Note: If daemon already installed, we make sure it's stopped before overwriting it $(INSTBASE)/sbin/mdnsd: $(BUILDDIR)/mdnsd + @if test -x $@; then $(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME) stop; fi $(CP) $< $@ $(INSTBASE)/lib/libdns_sd.$(LDSUFFIX).$(LIBVERS): $(BUILDDIR)/libdns_sd.$(LDSUFFIX) @@ -479,9 +553,12 @@ endif $(INSTBASE)/include/dns_sd.h: $(SHAREDDIR)/dns_sd.h $(CP) $< $@ -$(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME): mdnsd.sh $(STARTUPSCRIPTDIR) +# We make this target dependent on $(INSTBASE)/sbin/mdnsd because we need to ensure +# that the daemon is installed *before* we try to execute the command to start it. +$(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME): mdnsd.sh $(STARTUPSCRIPTDIR) $(INSTBASE)/sbin/mdnsd $(CP) $< $@ chmod ugo+x $@ + $@ start ifdef RUNLEVELSCRIPTSDIR ifeq ($(wildcard $(RUNLEVELSCRIPTSDIR)/runlevels/default), $(RUNLEVELSCRIPTSDIR)/runlevels/default) $(LN) $@ $(RUNLEVELSCRIPTSDIR)/runlevels/default/mdns @@ -495,6 +572,21 @@ else endif endif +$(MANPATH)/man5/%.5: %.5 + cp $< $@ + chmod 444 $@ + +$(MANPATH)/man8/%.8: %.8 + cp $< $@ + chmod 444 $@ + +$(MANPATH)/man8/mdnsd.8: $(SHAREDDIR)/mDNSResponder.8 + cp $< $@ + chmod 444 $@ + +$(INSTBASE)/bin/dns-sd: ../Clients/build/dns-sd + $(CP) $< $@ + $(NSSINSTPATH)/$(NSSLINKNAME): $(NSSINSTPATH)/$(NSSLIBFILE) $(LN) $< $@ ldconfig @@ -511,18 +603,6 @@ $(NSSINSTPATH)/$(NSSLIBFILE): $(BUILDDIR)/$(NSSLIBFILE) cp -f /etc/nsswitch.conf /etc/nsswitch.conf.pre-mdns sed -e '/mdns/!s/^\(hosts:.*\)dns\(.*\)/\1mdns dns\2/' /etc/nsswitch.conf.pre-mdns > /etc/nsswitch.conf -$(MANPATH)/man5/%.5: %.5 - cp $< $@ - chmod 444 $@ - -$(MANPATH)/man8/%.8: %.8 - cp $< $@ - chmod 444 $@ - -$(MANPATH)/man8/mdnsd.8: $(SHAREDDIR)/mDNSResponder.8 - cp $< $@ - chmod 444 $@ - ############################################################################# # The following targets build Java wrappers for the dns-sd.h API. @@ -548,13 +628,15 @@ JARCONTENTS = $(OBJDIR)/com/apple/dnssd/DNSSDService.class \ $(OBJDIR)/com/apple/dnssd/RegisterListener.class \ $(OBJDIR)/com/apple/dnssd/QueryListener.class \ $(OBJDIR)/com/apple/dnssd/DomainListener.class \ + $(OBJDIR)/com/apple/dnssd/RegisterRecordListener.class \ + $(OBJDIR)/com/apple/dnssd/DNSSDRecordRegistrar.class \ $(OBJDIR)/com/apple/dnssd/DNSSD.class -$(BUILDDIR)/dns_sd.jar: $(JARCONTENTS) +$(BUILDDIR)/dns_sd.jar: $(JARCONTENTS) setup $(JAR) -cf $@ -C $(OBJDIR) com -$(BUILDDIR)/libjdns_sd.$(LDSUFFIX): $(JAVASRC)/JNISupport.c $(OBJDIR)/DNSSD.java.h - $(CC) -o $@ $< $(JAVACFLAGS) -I$(OBJDIR) +$(BUILDDIR)/libjdns_sd.$(LDSUFFIX): $(JAVASRC)/JNISupport.c $(OBJDIR)/DNSSD.java.h setup libdns_sd + $(CC) -o $@ $< $(JAVACFLAGS) -I$(OBJDIR) -L$(BUILDDIR) $(OBJDIR)/com/apple/dnssd/%.class: $(JAVASRC)/%.java $(JAVAC) -d $(OBJDIR) -classpath $(OBJDIR) $< @@ -573,7 +655,7 @@ $(OBJDIR)/DNSSD.java.h: $(OBJDIR)/com/apple/dnssd/DNSSD.class # The following target builds documentation for the Java wrappers. -JavaDoc: setup Java +JavaDoc: Java setup $(JAVADOC) $(JAVASRC)/*.java -classpath $(OBJDIR) -d $(BUILDDIR) -public ############################################################################# @@ -583,13 +665,13 @@ SPECIALOBJ = $(OBJDIR)/mDNSPosix.c.o $(OBJDIR)/mDNSUNP.c.o $(OBJDIR)/mDNSDebug.c COMMONOBJ = $(SPECIALOBJ) $(OBJDIR)/mDNS.c.o APPOBJ = $(COMMONOBJ) $(OBJDIR)/ExampleClientApp.c.o -Client: setup $(BUILDDIR)/mDNSClientPosix +SAClient: setup $(BUILDDIR)/mDNSClientPosix @echo "Embedded Standalone Client done" -Responder: setup $(BUILDDIR)/mDNSResponderPosix +SAResponder: setup $(BUILDDIR)/mDNSResponderPosix @echo "Embedded Standalone Responder done" -ProxyResponder: setup $(BUILDDIR)/mDNSProxyResponderPosix +SAProxyResponder: setup $(BUILDDIR)/mDNSProxyResponderPosix @echo "Embedded Standalone ProxyResponder done" Identify: setup $(BUILDDIR)/mDNSIdentify @@ -602,22 +684,26 @@ dnsextd: setup $(BUILDDIR)/dnsextd @echo "dnsextd done" $(BUILDDIR)/mDNSClientPosix: $(APPOBJ) $(OBJDIR)/Client.c.o - $(CC) $+ -o $@ $(LIBFLAGS) + $(CC) $+ -o $@ $(LINKOPTS) $(BUILDDIR)/mDNSResponderPosix: $(COMMONOBJ) $(OBJDIR)/Responder.c.o - $(CC) $+ -o $@ $(LIBFLAGS) + $(CC) $+ -o $@ $(LINKOPTS) $(BUILDDIR)/mDNSProxyResponderPosix: $(COMMONOBJ) $(OBJDIR)/ProxyResponder.c.o - $(CC) $+ -o $@ $(LIBFLAGS) + $(CC) $+ -o $@ $(LINKOPTS) $(BUILDDIR)/mDNSIdentify: $(SPECIALOBJ) $(OBJDIR)/Identify.c.o - $(CC) $+ -o $@ $(LIBFLAGS) + $(CC) $+ -o $@ $(LINKOPTS) + +$(OBJDIR)/Identify.c.o: $(COREDIR)/mDNS.c # Note: Identify.c textually imports mDNS.c $(BUILDDIR)/mDNSNetMonitor: $(SPECIALOBJ) $(OBJDIR)/NetMonitor.c.o - $(CC) $+ -o $@ $(LIBFLAGS) + $(CC) $+ -o $@ $(LINKOPTS) + +$(OBJDIR)/NetMonitor.c.o: $(COREDIR)/mDNS.c # Note: NetMonitor.c textually imports mDNS.c -$(BUILDDIR)/dnsextd: $(SPECIALOBJ) $(OBJDIR)/dnsextd.c.threadsafe.o - $(CC) $+ -o $@ $(LIBFLAGS) -lpthread +$(BUILDDIR)/dnsextd: $(DNSEXTDOBJ) $(OBJDIR)/dnsextd.c.threadsafe.o + $(CC) $+ -o $@ $(LINKOPTS) $(LINKOPTS_PTHREAD) ############################################################################# @@ -632,10 +718,21 @@ $(OBJDIR)/%.c.o: $(SHAREDDIR)/%.c $(CC) $(CFLAGS) -c -o $@ $< $(OBJDIR)/%.c.threadsafe.o: %.c - $(CC) $(CFLAGS) -D_REENTRANT -c -o $@ $< + $(CC) $(CFLAGS) $(CFLAGS_PTHREAD) -D_REENTRANT -c -o $@ $< + +$(OBJDIR)/%.c.threadsafe.o: $(SHAREDDIR)/%.c + $(CC) $(CFLAGS) $(CFLAGS_PTHREAD) -D_REENTRANT -c -o $@ $< $(OBJDIR)/%.c.so.o: %.c $(CC) $(CFLAGS) -c -fPIC -o $@ $< $(OBJDIR)/%.c.so.o: $(SHAREDDIR)/%.c $(CC) $(CFLAGS) -c -fPIC -o $@ $< + +$(OBJDIR)/%.y.o: $(SHAREDDIR)/%.y + $(BISON) -o $(OBJDIR)/$*.c -d $< + $(CC) $(CFLAGS) -c -o $@ $(OBJDIR)/$*.c + +$(OBJDIR)/%.l.o: $(SHAREDDIR)/%.l + $(FLEX) $(FLEXFLAGS_OS) -i -o$(OBJDIR)/$*.l.c $< + $(CC) $(CFLAGS) -Wno-error -c -o $@ $(OBJDIR)/$*.l.c diff --git a/mDNSPosix/NetMonitor.c b/mDNSPosix/NetMonitor.c index 320294f..9f26ea0 100644 --- a/mDNSPosix/NetMonitor.c +++ b/mDNSPosix/NetMonitor.c @@ -2,24 +2,17 @@ * * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ * * Formatting notes: * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion @@ -37,243 +30,56 @@ Change History (most recent first): $Log: NetMonitor.c,v $ -Revision 1.74 2005/12/02 20:08:39 cheshire -Update "No HINFO" message - -Revision 1.73 2005/12/02 19:19:53 cheshire - Include interface index and name in mDNSNetMonitor output - -Revision 1.72 2005/11/07 01:47:45 cheshire - Include interface index in mDNSNetMonitor output - -Revision 1.71 2004/12/16 20:17:11 cheshire - Cache memory management improvements - -Revision 1.70 2004/12/04 02:13:20 cheshire -Pass proper record type in GetLargeResourceRecord() calls - -Revision 1.69 2004/11/30 22:37:01 cheshire -Update copyright dates and add "Mode: C; tab-width: 4" headers - -Revision 1.68 2004/10/23 01:16:01 cheshire - uDNS operations not always reliable on multi-homed hosts - -Revision 1.67 2004/10/16 00:17:00 cheshire - Replace IP TTL 255 check with local subnet source address check - -Revision 1.66 2004/09/17 00:31:52 cheshire -For consistency with ipv6, renamed rdata field 'ip' to 'ipv4' - -Revision 1.65 2004/09/16 01:58:22 cheshire -Fix compiler warnings - -Revision 1.64 2004/06/15 02:39:47 cheshire -When displaying error message, only show command name, not entire path - -Revision 1.63 2004/05/18 23:51:26 cheshire -Tidy up all checkin comments to use consistent "" format for bug numbers - -Revision 1.62 2004/03/16 18:24:25 cheshire -If packet destination was not multicast, then display it - -Revision 1.61 2004/02/20 09:36:46 cheshire -Also show TTL in packet header, if it's not 255 - -Revision 1.60 2004/02/07 02:11:35 cheshire -Make mDNSNetMonitor smarter about sending targeted unicast HINFO queries - -Revision 1.59 2004/02/03 21:42:55 cheshire -Add constants kReportTopServices and kReportTopHosts - -Revision 1.58 2004/01/27 20:15:23 cheshire -: Time to prune obsolete code for listening on port 53 - -Revision 1.57 2004/01/24 23:59:42 cheshire -Change to use mDNSVal16() instead of shifting and ORing - -Revision 1.56 2004/01/24 05:25:34 cheshire -mDNSNetMonitor now uses the new ability to send unicast queries so that -it causes less perturbation of the network traffic it's monitoring. - -Revision 1.55 2003/12/23 00:21:31 cheshire -Send HINFO queries to determine the mDNSResponder version of each host - -Revision 1.54 2003/12/17 01:06:39 cheshire -Also show host name along with HINFO data - -Revision 1.53 2003/12/17 00:51:22 cheshire -Changed mDNSNetMonitor and mDNSIdentify to link the object files -instead of #including the "DNSCommon.c" "uDNS.c" and source files - -Revision 1.52 2003/12/17 00:21:51 cheshire -If we received one, display host's HINFO record in final summary - -Revision 1.51 2003/12/13 03:05:28 ksekar -: DynDNS: Unicast query of service records - -Revision 1.50 2003/12/08 20:47:02 rpantos -Add support for mDNSResponder on Linux. - -Revision 1.49 2003/10/30 19:38:56 cheshire -Fix warning on certain compilers - -Revision 1.48 2003/10/30 19:30:00 cheshire -Fix warnings on certain compilers - -Revision 1.47 2003/09/05 18:49:57 cheshire -Add total packet size to display - -Revision 1.46 2003/09/05 02:33:48 cheshire -Set output to be line buffered, so you can redirect to a file and "tail -f" the file in another window - -Revision 1.45 2003/09/04 00:16:20 cheshire -Only show count of unique source addresses seen on network if we're not filtering - -Revision 1.44 2003/09/02 22:13:28 cheshire -Show total host count in final summary table - -Revision 1.43 2003/09/02 21:42:52 cheshire -Improved alignment of final summary table with v6 addresses - -Revision 1.42 2003/09/02 20:59:24 cheshire -Use bcopy() instead of non-portable "__u6_addr.__u6_addr32" fields. - -Revision 1.41 2003/08/29 22:05:44 cheshire -Also count subsequent KA packets for the purposes of statistics counting - -Revision 1.40 2003/08/29 16:43:24 cheshire -Also display breakdown of Probe/Goodbye/BrowseQ etc. for each host - -Revision 1.39 2003/08/28 02:07:48 vlubet -Added "per hosts" statistics - -Revision 1.38 2003/08/20 22:41:42 cheshire -Also display total multicast packet count +Revision 1.89 2007/05/17 19:12:42 cheshire +Tidy up code layout -Revision 1.37 2003/08/20 22:32:08 cheshire -Error in DisplayQuery: Authorities come *after* Answers, not before +Revision 1.88 2007/04/22 20:16:25 cheshire +Fix compiler errors (const parameter declarations) -Revision 1.36 2003/08/18 23:20:10 cheshire -RDLength moved from the RData to the ResourceRecord object. +Revision 1.87 2007/04/16 20:49:39 cheshire +Fix compile errors for mDNSPosix build -Revision 1.35 2003/08/15 20:17:28 cheshire -"LargeResourceRecord" changed to "LargeCacheRecord" +Revision 1.86 2007/03/22 18:31:48 cheshire +Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy -Revision 1.34 2003/08/14 02:19:55 cheshire - Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord +Revision 1.85 2007/02/28 01:51:22 cheshire +Added comment about reverse-order IP address -Revision 1.33 2003/08/12 19:56:26 cheshire -Update to APSL 2.0 +Revision 1.84 2007/01/05 08:30:52 cheshire +Trim excessive "$Log" checkin history from before 2006 +(checkin history still available via "cvs log ..." of course) -Revision 1.32 2003/08/06 18:57:01 cheshire -Update comments +Revision 1.83 2006/11/18 05:01:32 cheshire +Preliminary support for unifying the uDNS and mDNS code, +including caching of uDNS answers -Revision 1.31 2003/08/06 02:05:12 cheshire -Add ability to give a list of hosts to monitor +Revision 1.82 2006/08/14 23:24:46 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 -Revision 1.30 2003/08/05 23:56:26 cheshire -Update code to compile with the new mDNSCoreReceive() function that requires a TTL -(Right now mDNSPosix.c just reports 255 -- we should fix this) +Revision 1.81 2006/07/06 00:01:44 cheshire + Add Private DNS client functionality to mDNSResponder +Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int" -Revision 1.29 2003/08/05 00:43:12 cheshire -Report errors encountered while processing authority section +Revision 1.80 2006/06/12 18:22:42 cheshire + mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux -Revision 1.28 2003/07/29 22:51:08 cheshire -Added hexdump for packets we can't decode, so we can find out *why* we couldn't decode them +Revision 1.79 2006/04/26 20:48:33 cheshire +Make final count of unique source addresses show IPv4 and IPv6 counts separately -Revision 1.27 2003/07/29 22:48:04 cheshire -Completed support for decoding packets containing oversized resource records +Revision 1.78 2006/04/25 00:42:24 cheshire +Add ability to specify a single interface index to capture on, +e.g. typically "-i 4" for Ethernet and "-i 5" for AirPort -Revision 1.26 2003/07/19 03:25:23 cheshire -Change to make use of new GetLargeResourceRecord() call, for handling larger records +Revision 1.77 2006/03/02 21:50:45 cheshire +Removed strange backslash at the end of a line -Revision 1.25 2003/07/18 00:13:23 cheshire -Remove erroneous trailing '\' from TXT record display +Revision 1.76 2006/02/23 23:38:43 cheshire + On FreeBSD 4 "arpa/inet.h" requires "netinet/in.h" be included first -Revision 1.24 2003/07/17 17:10:51 cheshire - Implement "unicast response" request, using top bit of qclass -Further work: distinguish between PM and PU +Revision 1.75 2006/01/05 22:33:58 cheshire +Use IFNAMSIZ (more portable) instead of IF_NAMESIZE -Revision 1.23 2003/07/16 22:20:23 cheshire - Implement "unicast response" request, using top bit of qclass -Made mDNSNetMonitor distinguish between QM and QU in its logging output - -Revision 1.22 2003/07/02 21:19:58 cheshire - Update copyright notices, etc., in source code comments - -Revision 1.21 2003/06/18 05:48:41 cheshire -Fix warnings - -Revision 1.20 2003/06/06 22:18:22 cheshire -Add extra space in Q output to line it up with RR output - -Revision 1.19 2003/06/06 21:05:04 cheshire -Display state of cache-flush bit on additional records - -Revision 1.18 2003/06/06 20:01:30 cheshire -For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass -(Global search-and-replace; no functional change to code execution.) - -Revision 1.17 2003/06/06 14:26:50 cheshire -Explicitly #include for the benefit of certain Linux distributions - -Revision 1.16 2003/05/29 21:56:36 cheshire -More improvements: -Distinguish modern multicast queries from legacy multicast queries -In addition to record counts, display packet counts of queries, legacy queries, and responses -Include TTL in RR display - -Revision 1.15 2003/05/29 20:03:57 cheshire -Various improvements: -Display start and end time, average rates in packets-per-minute, -show legacy queries as -LQ-, improve display of TXT and unknown records - -Revision 1.14 2003/05/26 04:45:42 cheshire -Limit line length when printing super-long TXT records - -Revision 1.13 2003/05/26 03:21:29 cheshire -Tidy up address structure naming: -mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr) -mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4 -mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6 - -Revision 1.12 2003/05/26 03:01:28 cheshire - sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead - -Revision 1.11 2003/05/26 00:48:13 cheshire -If mDNS packet contains a non-zero message ID, then display it. - -Revision 1.10 2003/05/22 01:10:32 cheshire -Indicate when the TC bit is set on a query packet - -Revision 1.9 2003/05/21 03:56:00 cheshire -Improve display of Probe queries - -Revision 1.8 2003/05/09 21:41:56 cheshire -Track deletion/goodbye packets as separate category - -Revision 1.7 2003/05/07 00:16:01 cheshire -More detailed decoding of Resource Records - -Revision 1.6 2003/05/05 21:16:16 cheshire - Change timenow from a local variable to a structure member - -Revision 1.5 2003/04/19 01:16:22 cheshire -Add filter option, to monitor only packets from a single specified source address - -Revision 1.4 2003/04/18 00:45:21 cheshire -Distinguish announcements (AN) from deletions (DE) - -Revision 1.3 2003/04/15 18:26:01 cheshire -Added timestamps and help information - -Revision 1.2 2003/04/04 20:42:02 cheshire -Fix broken statistics counting - -Revision 1.1 2003/04/04 01:37:14 cheshire -Added NetMonitor.c - - */ +*/ //************************************************************************************************************* // Incorporate mDNS.c functionality @@ -294,9 +100,9 @@ Added NetMonitor.c #include // For SIGINT, SIGTERM #include // For gethostbyname() #include // For AF_INET, AF_INET6, etc. -#include // For inet_addr() #include // For IF_NAMESIZE #include // For INADDR_NONE +#include // For inet_addr() #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform #include "ExampleClientApp.h" @@ -358,9 +164,10 @@ struct FilterList_struct static mDNS mDNSStorage; // mDNS core uses this to store its globals static mDNS_PlatformSupport PlatformStorage; // Stores this platform's globals +mDNSexport const char ProgramName[] = "mDNSNetMonitor"; struct timeval tv_start, tv_end, tv_interval; - +static int FilterInterface = 0; static FilterList *Filters; #define ExactlyOneFilter (Filters && !Filters->next) @@ -428,7 +235,7 @@ typedef struct static HostList IPv4HostList = { 0, 0, 0 }; static HostList IPv6HostList = { 0, 0, 0 }; -mDNSlocal HostEntry *FindHost(const mDNSAddr *addr, HostList* list) +mDNSlocal HostEntry *FindHost(const mDNSAddr *addr, HostList *list) { long i; @@ -442,7 +249,7 @@ mDNSlocal HostEntry *FindHost(const mDNSAddr *addr, HostList* list) return NULL; } -mDNSlocal HostEntry *AddHost(const mDNSAddr *addr, HostList* list) +mDNSlocal HostEntry *AddHost(const mDNSAddr *addr, HostList *list) { int i; HostEntry *entry; @@ -472,6 +279,7 @@ mDNSlocal HostEntry *AddHost(const mDNSAddr *addr, HostList* list) { mDNSv4Addr ip = entry->addr.ip.v4; char buffer[32]; + // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", ip.b[3], ip.b[2], ip.b[1], ip.b[0]); MakeDomainNameFromDNSNameString(&entry->revname, buffer); } @@ -521,8 +329,8 @@ mDNSlocal void RecordHostInfo(HostEntry *entry, const ResourceRecord *const pktr if (sw + 1 + sw[0] <= rdend) { AssignDomainName(&entry->hostname, pktrr->name); - mDNSPlatformMemCopy(hw, entry->HIHardware.c, 1 + (mDNSu32)hw[0]); - mDNSPlatformMemCopy(sw, entry->HISoftware.c, 1 + (mDNSu32)sw[0]); + mDNSPlatformMemCopy(entry->HIHardware.c, hw, 1 + (mDNSu32)hw[0]); + mDNSPlatformMemCopy(entry->HISoftware.c, sw, 1 + (mDNSu32)sw[0]); } } } @@ -551,10 +359,9 @@ mDNSlocal void SendUnicastQuery(mDNS *const m, HostEntry *entry, domainname *nam { //mprintf("%#a Q\n", target); InterfaceID = mDNSInterface_Any; // Send query from our unicast reply socket - m->ExpectUnicastResponse = m->timenow; } - mDNSSendDNSMessage(&mDNSStorage, &query, qptr, InterfaceID, target, MulticastDNSPort, -1, mDNSNULL); + mDNSSendDNSMessage(&mDNSStorage, &query, qptr, InterfaceID, target, MulticastDNSPort, mDNSNULL, mDNSNULL); } mDNSlocal void AnalyseHost(mDNS *const m, HostEntry *entry, const mDNSInterfaceID InterfaceID) @@ -605,7 +412,7 @@ mDNSlocal void ShowSortedHostList(HostList *list, int max) if (e->pkts[HostPkt_B]) mprintf("Bad: %8lu", e->pkts[HostPkt_B]); mprintf("\n"); if (!e->HISoftware.c[0] && e->NumQueries > 2) - mDNSPlatformMemCopy("\x27*** Unknown (Jaguar, Windows, etc.) ***", &e->HISoftware, 0x28); + mDNSPlatformMemCopy(&e->HISoftware, "\x27*** Unknown (Jaguar, Windows, etc.) ***", 0x28); if (e->hostname.c[0] || e->HIHardware.c[0] || e->HISoftware.c[0]) mprintf("%##-45s %#-14s %#s\n", e->hostname.c, e->HIHardware.c, e->HISoftware.c); } @@ -637,7 +444,7 @@ mDNSexport mDNSBool ExtractServiceType(const domainname *const fqdn, domainname return(mDNStrue); } -mDNSlocal void recordstat(HostEntry *entry, domainname *fqdn, int op, mDNSu16 rrtype) +mDNSlocal void recordstat(HostEntry *entry, const domainname *fqdn, int op, mDNSu16 rrtype) { ActivityStat **s = &stats; domainname srvtype; @@ -691,7 +498,7 @@ mDNSlocal void printstats(int max) } } -mDNSlocal const mDNSu8 *FindUpdate(mDNS *const m, const DNSMessage *const query, const mDNSu8 *ptr, const mDNSu8 *const end,\ +mDNSlocal const mDNSu8 *FindUpdate(mDNS *const m, const DNSMessage *const query, const mDNSu8 *ptr, const mDNSu8 *const end, DNSQuestion *q, LargeCacheRecord *pkt) { int i; @@ -713,7 +520,7 @@ mDNSlocal void DisplayPacketHeader(mDNS *const m, const DNSMessage *const msg, c struct timeval tv; struct tm tm; const mDNSu32 index = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID); - char if_name[IF_NAMESIZE]; + char if_name[IFNAMSIZ]; // Older Linux distributions don't define IF_NAMESIZE if_indextoname(index, if_name); gettimeofday(&tv, NULL); localtime_r((time_t*)&tv.tv_sec, &tm); @@ -984,6 +791,7 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS const mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery; const mDNSu8 QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask); mDNSu8 *ptr = (mDNSu8 *)&msg->h.numQuestions; + int goodinterface = (FilterInterface == 0); (void)dstaddr; // Unused (void)dstport; // Unused @@ -996,7 +804,8 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS // For now we're only interested in monitoring IPv4 traffic. // All IPv6 packets should just be duplicates of the v4 packets. - if (AddressMatchesFilterList(srcaddr)) + if (!goodinterface) goodinterface = (FilterInterface == (int)mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID)); + if (goodinterface && AddressMatchesFilterList(srcaddr)) { mDNS_Lock(m); if (!mDNSAddrIsDNSMulticast(dstaddr)) @@ -1072,7 +881,14 @@ mDNSlocal mStatus mDNSNetMonitor(void) localtime_r((time_t*)&tv_end.tv_sec, &tm); mprintf("End %3d:%02d:%02d.%06d\n", tm.tm_hour, tm.tm_min, tm.tm_sec, tv_end.tv_usec); mprintf("Captured for %3d:%02d:%02d.%06d\n", h, m, s, tv_interval.tv_usec); - if (!Filters) mprintf("Unique source addresses seen on network: %ld\n", IPv4HostList.num + IPv6HostList.num); + if (!Filters) + { + mprintf("Unique source addresses seen on network:"); + if (IPv4HostList.num) mprintf(" %ld (IPv4)", IPv4HostList.num); + if (IPv6HostList.num) mprintf(" %ld (IPv6)", IPv6HostList.num); + if (!IPv4HostList.num && !IPv6HostList.num) mprintf(" None"); + mprintf("\n"); + } mprintf("\n"); mprintf("Modern Query Packets: %7d (avg%5d/min)\n", NumPktQ, NumPktQ * mul / div); mprintf("Legacy Query Packets: %7d (avg%5d/min)\n", NumPktL, NumPktL * mul / div); @@ -1108,34 +924,43 @@ mDNSexport int main(int argc, char **argv) for (i=1; ih_addr; - else goto usage; + struct in_addr s4; + struct in6_addr s6; + FilterList *f; + mDNSAddr a; + a.type = mDNSAddrType_IPv4; + + if (inet_pton(AF_INET, argv[i], &s4) == 1) + a.ip.v4.NotAnInteger = s4.s_addr; + else if (inet_pton(AF_INET6, argv[i], &s6) == 1) + { + a.type = mDNSAddrType_IPv6; + bcopy(&s6, &a.ip.v6, sizeof(a.ip.v6)); + } + else + { + struct hostent *h = gethostbyname(argv[i]); + if (h) a.ip.v4.NotAnInteger = *(long*)h->h_addr; + else goto usage; + } + + f = malloc(sizeof(*f)); + f->FilterAddr = a; + f->next = Filters; + Filters = f; } - - f = malloc(sizeof(*f)); - f->FilterAddr = a; - f->next = Filters; - Filters = f; } status = mDNSNetMonitor(); - if (status) { fprintf(stderr, "%s: mDNSNetMonitor failed %ld\n", progname, status); return(status); } + if (status) { fprintf(stderr, "%s: mDNSNetMonitor failed %d\n", progname, (int)status); return(status); } return(0); usage: diff --git a/mDNSPosix/PosixDaemon.c b/mDNSPosix/PosixDaemon.c index 5963f20..741ca59 100644 --- a/mDNSPosix/PosixDaemon.c +++ b/mDNSPosix/PosixDaemon.c @@ -2,24 +2,17 @@ * * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ File: daemon.c @@ -28,97 +21,48 @@ Change History (most recent first): $Log: PosixDaemon.c,v $ -Revision 1.29 2005/08/04 03:37:45 mkrochma -Temporary workaround to fix posix after mDNS_SetPrimaryInterfaceInfo changed - -Revision 1.28 2005/07/19 11:21:09 cheshire - Unix Domain Socket leak in mdnsd - -Revision 1.27 2005/02/04 00:39:59 cheshire -Move ParseDNSServers() from PosixDaemon.c to mDNSPosix.c so all Posix client layers can use it - -Revision 1.26 2005/02/02 02:21:30 cheshire -Update references to "mDNSResponder" to say "mdnsd" instead - -Revision 1.25 2005/01/27 20:01:50 cheshire -udsSupportRemoveFDFromEventLoop() needs to close the file descriptor as well - -Revision 1.24 2005/01/19 19:20:49 ksekar - Need a way to turn off domain discovery - -Revision 1.23 2004/12/16 20:17:11 cheshire - Cache memory management improvements - -Revision 1.22 2004/12/10 13:12:08 cheshire -Create no-op function RecordUpdatedNiceLabel(), required by uds_daemon.c - -Revision 1.21 2004/12/01 20:57:20 ksekar - Wide Area Service Discovery must be split-DNS aware - -Revision 1.20 2004/12/01 04:28:43 cheshire - Darwin patches for Solaris and Suse -Use version of daemon() provided in mDNSUNP.c instead of local copy - -Revision 1.19 2004/12/01 03:30:29 cheshire - Add Unicast DNS support to mDNSPosix +Revision 1.42 2007/09/18 19:09:02 cheshire + mDNSResponderHelper (and other binaries) missing SCCS version strings -Revision 1.18 2004/11/30 22:45:59 cheshire -Minor code tidying +Revision 1.41 2007/09/04 17:02:25 cheshire + False positives in changed files list in nightly builds +Added MDNS_VERSIONSTR_NODTS option at the reqest of Rishi Srivatsavai (Sun) -Revision 1.17 2004/11/30 22:18:59 cheshire - Posix needs to read the list of unicast DNS servers and set server list +Revision 1.40 2007/07/31 23:08:34 mcguire + BTMM: Make AutoTunnel mode work with multihoming -Revision 1.16 2004/09/21 21:05:12 cheshire -Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c, -into mDNSShared/uds_daemon.c +Revision 1.39 2007/03/21 00:30:44 cheshire +Remove obsolete mDNS_DeleteDNSServers() call -Revision 1.15 2004/09/17 01:08:53 cheshire -Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h - The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces - declared in that file are ONLY appropriate to single-address-space embedded applications. - For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used. +Revision 1.38 2007/02/14 01:58:19 cheshire + Don't delete Unix Domain Socket on exit if we didn't create it on startup -Revision 1.14 2004/09/16 00:24:49 cheshire - Fix unsafe use of mDNSPlatformTimeNow() +Revision 1.37 2007/02/07 19:32:00 cheshire + All mDNSResponder components should contain version strings in SCCS-compatible format -Revision 1.13 2004/08/11 01:59:41 cheshire -Remove "mDNS *globalInstance" parameter from udsserver_init() +Revision 1.36 2007/02/06 19:06:48 cheshire + Need to go native with launchd -Revision 1.12 2004/06/28 23:19:19 cheshire -Fix "Daemon_Init declared but never defined" warning on Linux +Revision 1.35 2007/01/05 08:30:52 cheshire +Trim excessive "$Log" checkin history from before 2006 +(checkin history still available via "cvs log ..." of course) -Revision 1.11 2004/06/25 00:26:27 rpantos -Changes to fix the Posix build on Solaris. +Revision 1.34 2007/01/05 05:46:08 cheshire +Add mDNS *const m parameter to udsserver_handle_configchange() -Revision 1.10 2004/06/08 04:59:40 cheshire -Tidy up wording -- log messages are already prefixed with "mDNSResponder", so don't need to repeat it +Revision 1.33 2006/12/21 00:10:53 cheshire +Make mDNS_PlatformSupport PlatformStorage a static global instead of a stack variable -Revision 1.9 2004/05/29 00:14:20 rpantos - Runtime check to disable prod mdnsd on OS X. +Revision 1.32 2006/11/03 22:28:50 cheshire +PosixDaemon needs to handle mStatus_ConfigChanged and mStatus_GrowCache messages -Revision 1.8 2004/04/07 01:19:04 cheshire -Hash slot value should be unsigned +Revision 1.31 2006/08/14 23:24:46 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 -Revision 1.7 2004/02/14 06:34:57 cheshire -Use LogMsg instead of fprintf( stderr +Revision 1.30 2006/07/07 01:09:12 cheshire + Add Private DNS server functionality to dnsextd +Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd -Revision 1.6 2004/02/14 01:10:42 rpantos -Allow daemon to run if 'nobody' is not defined, with a warning. (For Roku HD1000.) - -Revision 1.5 2004/02/05 07:45:43 cheshire -Add Log header - -Revision 1.4 2004/01/28 21:14:23 cheshire -Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode) - -Revision 1.3 2004/01/19 19:51:46 cheshire -Fix compiler error (mixed declarations and code) on some versions of Linux - -Revision 1.2 2003/12/11 03:03:51 rpantos -Clean up mDNSPosix so that it builds on OS X again. - -Revision 1.1 2003/12/08 20:47:02 rpantos -Add support for mDNSResponder on Linux. */ #include @@ -143,24 +87,50 @@ static domainname DynDNSHostname; #define RR_CACHE_SIZE 500 static CacheEntity gRRCache[RR_CACHE_SIZE]; +static mDNS_PlatformSupport PlatformStorage; + +mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result) + { + (void)m; // Unused + if (result == mStatus_NoError) + { + // On successful registration of dot-local mDNS host name, daemon may want to check if + // any name conflict and automatic renaming took place, and if so, record the newly negotiated + // name in persistent storage for next time. It should also inform the user of the name change. + // On Mac OS X we store the current dot-local mDNS host name in the SCPreferences store, + // and notify the user with a CFUserNotification. + } + else if (result == mStatus_ConfigChanged) + { + udsserver_handle_configchange(m); + } + else if (result == mStatus_GrowCache) + { + // Allocate another chunk of cache storage + CacheEntity *storage = malloc(sizeof(CacheEntity) * RR_CACHE_SIZE); + if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE); + } + } -extern const char mDNSResponderVersionString[]; +// %%% Reconfigure() probably belongs in the platform support layer (mDNSPosix.c), not the daemon cde +// -- all client layers running on top of mDNSPosix.c need to handle network configuration changes, +// not only the Unix Domain Socket Daemon static void Reconfigure(mDNS *m) { mDNSAddr DynDNSIP; mDNS_SetPrimaryInterfaceInfo(m, NULL, NULL, NULL); - mDNS_DeleteDNSServers(m); if (ParseDNSServers(m, uDNS_SERVERS_FILE) < 0) LogMsg("Unable to parse DNS server list. Unicast DNS-SD unavailable"); ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, &DynDNSHostname, &DynDNSZone, NULL); - FindDefaultRouteIP(&DynDNSIP); + FindSourceAddrForIP(NULL, &DynDNSIP); if (DynDNSHostname.c[0]) mDNS_AddDynDNSHostName(m, &DynDNSHostname, NULL, NULL); if (DynDNSIP.type) mDNS_SetPrimaryInterfaceInfo(m, &DynDNSIP, NULL, NULL); + m->MainCallback(m, mStatus_ConfigChanged); } // Do appropriate things at startup with command line arguments. Calls exit() if unhappy. -static void ParseCmdLinArgs(int argc, char **argv) +mDNSlocal void ParseCmdLinArgs(int argc, char **argv) { if (argc > 1) { @@ -179,7 +149,7 @@ static void ParseCmdLinArgs(int argc, char **argv) } } -static void DumpStateLog(mDNS *const m) +mDNSlocal void DumpStateLog(mDNS *const m) // Dump a little log of what we've been up to. { LogMsgIdent(mDNSResponderVersionString, "---- BEGIN STATE LOG ----"); @@ -187,7 +157,7 @@ static void DumpStateLog(mDNS *const m) LogMsgIdent(mDNSResponderVersionString, "---- END STATE LOG ----"); } -static mStatus MainLoop(mDNS *m) // Loop until we quit. +mDNSlocal mStatus MainLoop(mDNS *m) // Loop until we quit. { sigset_t signals; mDNSBool gotData = mDNSfalse; @@ -229,26 +199,21 @@ static mStatus MainLoop(mDNS *m) // Loop until we quit. return EINTR; } -int main(int argc, char **argv) +int main(int argc, char **argv) { - #define mDNSRecord mDNSStorage - mDNS_PlatformSupport platformStorage; mStatus err; - bzero(&mDNSRecord, sizeof mDNSRecord); - bzero(&platformStorage, sizeof platformStorage); - ParseCmdLinArgs(argc, argv); LogMsgIdent(mDNSResponderVersionString, "starting"); - err = mDNS_Init(&mDNSRecord, &platformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, - mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext); + err = mDNS_Init(&mDNSStorage, &PlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, + mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext); if (mStatus_NoError == err) - err = udsserver_init(); + err = udsserver_init(dnssd_InvalidSocket); - Reconfigure(&mDNSRecord); + Reconfigure(&mDNSStorage); // Now that we're finished with anything privileged, switch over to running as "nobody" if (mStatus_NoError == err) @@ -261,13 +226,13 @@ int main(int argc, char **argv) } if (mStatus_NoError == err) - err = MainLoop(&mDNSRecord); + err = MainLoop(&mDNSStorage); LogMsgIdent(mDNSResponderVersionString, "stopping"); - mDNS_Close(&mDNSRecord); + mDNS_Close(&mDNSStorage); - if (udsserver_exit() < 0) + if (udsserver_exit(dnssd_InvalidSocket) < 0) LogMsg("ExitCallback: udsserver_exit failed"); #if MDNS_DEBUGMSGS > 0 @@ -279,12 +244,6 @@ int main(int argc, char **argv) // uds_daemon support //////////////////////////////////////////////////////////// -#if MDNS_MALLOC_DEBUGGING >= 2 -#define LogMalloc LogMsg -#else -#define LogMalloc(ARGS...) ((void)0) -#endif - mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context) /* Support routine for uds_daemon.c */ { @@ -306,52 +265,15 @@ mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay) // No-op, for now } -#if MACOSX_MDNS_MALLOC_DEBUGGING >= 1 - -void *mallocL(char *msg, unsigned int size) - { - unsigned long *mem = malloc(size+8); - if (!mem) - { - LogMsg("malloc( %s : %d ) failed", msg, size); - return(NULL); - } - else - { - LogMalloc("malloc( %s : %lu ) = %p", msg, size, &mem[2]); - mem[0] = 0xDEAD1234; - mem[1] = size; - //bzero(&mem[2], size); - memset(&mem[2], 0xFF, size); -// validatelists(&mDNSStorage); - return(&mem[2]); - } - } - -void freeL(char *msg, void *x) - { - if (!x) - LogMsg("free( %s @ NULL )!", msg); - else - { - unsigned long *mem = ((unsigned long *)x) - 2; - if (mem[0] != 0xDEAD1234) - { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg, &mem[2]); return; } - if (mem[1] > 8000) - { LogMsg("free( %s : %ld @ %p) too big!", msg, mem[1], &mem[2]); return; } - LogMalloc("free( %s : %ld @ %p)", msg, mem[1], &mem[2]); - //bzero(mem, mem[1]+8); - memset(mem, 0xDD, mem[1]+8); -// validatelists(&mDNSStorage); - free(mem); - } - } - -#endif // MACOSX_MDNS_MALLOC_DEBUGGING >= 1 +// If the process crashes, then this string will be magically included in the automatically-generated crash log +const char *__crashreporter_info__ = mDNSResponderVersionString_SCCS + 5; +asm(".desc ___crashreporter_info__, 0x10"); // For convenience when using the "strings" command, this is the last thing in the file #if mDNSResponderVersion > 1 -mDNSexport const char mDNSResponderVersionString[] = "mDNSResponder-" STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ") "; +mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder-" STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")"; +#elif MDNS_VERSIONSTR_NODTS +mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder (Engineering Build)"; #else -mDNSexport const char mDNSResponderVersionString[] = "mDNSResponder (Engineering Build) (" __DATE__ " " __TIME__ ") "; +mDNSexport const char mDNSResponderVersionString_SCCS[] = "@(#) mDNSResponder (Engineering Build) (" __DATE__ " " __TIME__ ")"; #endif diff --git a/mDNSPosix/ProxyResponder.c b/mDNSPosix/ProxyResponder.c index 293ee0a..5ae6809 100644 --- a/mDNSPosix/ProxyResponder.c +++ b/mDNSPosix/ProxyResponder.c @@ -2,28 +2,46 @@ * * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: ProxyResponder.c,v $ +Revision 1.44 2007/04/22 20:16:25 cheshire +Fix compiler errors (const parameter declarations) + +Revision 1.43 2007/04/16 20:49:39 cheshire +Fix compile errors for mDNSPosix build + +Revision 1.42 2007/03/06 22:45:53 cheshire + + argv buffer overflow issues + +Revision 1.41 2007/02/28 01:51:22 cheshire +Added comment about reverse-order IP address + +Revision 1.40 2007/01/05 04:32:13 cheshire +Change "(domainname *)" cast to "(const domainname *)" + +Revision 1.39 2006/08/14 23:24:46 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + +Revision 1.38 2006/06/12 18:22:42 cheshire + mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux + +Revision 1.37 2006/02/23 23:38:43 cheshire + On FreeBSD 4 "arpa/inet.h" requires "netinet/in.h" be included first + Revision 1.36 2005/08/04 03:12:47 mkrochma Register reverse PTR record using multicast @@ -118,8 +136,8 @@ Add "$Log" header #include // For select() #include // For SIGINT, SIGTERM #include // For errno, EINTR -#include // For inet_addr() #include // For INADDR_NONE +#include // For inet_addr() #include // For gethostbyname() #include "mDNSEmbeddedAPI.h" // Defines the interface to the client layer above @@ -135,6 +153,7 @@ Add "$Log" header // Globals static mDNS mDNSStorage; // mDNS core uses this to store its globals static mDNS_PlatformSupport PlatformStorage; // Stores this platform's globals +mDNSexport const char ProgramName[] = "mDNSProxyResponderPosix"; //************************************************************************************************************* // Proxy Host Registration @@ -168,12 +187,13 @@ mDNSlocal mStatus mDNS_RegisterProxyHost(mDNS *m, ProxyHost *p) mDNS_SetupResourceRecord(&p->RR_A, mDNSNULL, mDNSInterface_Any, kDNSType_A, 60, kDNSRecordTypeUnique, HostNameCallback, p); mDNS_SetupResourceRecord(&p->RR_PTR, mDNSNULL, mDNSInterface_Any, kDNSType_PTR, 60, kDNSRecordTypeKnownUnique, HostNameCallback, p); - p->RR_A.resrec.name->c[0] = 0; - AppendDomainLabel(p->RR_A.resrec.name, &p->hostlabel); - AppendLiteralLabelString(p->RR_A.resrec.name, "local"); + p->RR_A.namestorage.c[0] = 0; + AppendDomainLabel(&p->RR_A.namestorage, &p->hostlabel); + AppendLiteralLabelString(&p->RR_A.namestorage, "local"); + // Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", p->ip.b[3], p->ip.b[2], p->ip.b[1], p->ip.b[0]); - MakeDomainNameFromDNSNameString(p->RR_PTR.resrec.name, buffer); + MakeDomainNameFromDNSNameString(&p->RR_PTR.namestorage, buffer); p->RR_PTR.ForceMCast = mDNStrue; // This PTR points to our dot-local name, so don't ever try to write it into a uDNS server p->RR_A. resrec.rdata->u.ipv4 = p->ip; @@ -238,6 +258,7 @@ mDNSlocal void RegisterService(mDNS *m, ServiceRecordSet *recordset, while (argc) { int len = strlen(argv[0]); + if (len > 255 || bptr + 1 + len >= txtbuffer + sizeof(txtbuffer)) break; printf("STR: %s\n", argv[0]); bptr[0] = len; strcpy((char*)(bptr+1), argv[0]); @@ -268,7 +289,7 @@ mDNSlocal void RegisterService(mDNS *m, ServiceRecordSet *recordset, mDNSlocal void NoSuchServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus result) { - domainname *proxyhostname = (domainname *)rr->RecordContext; + const domainname *proxyhostname = (const domainname *)rr->RecordContext; switch (result) { case mStatus_NoError: debugf("Callback: %##s Name Registered", rr->resrec.name->c); break; @@ -326,7 +347,7 @@ mDNSexport int main(int argc, char **argv) mDNS_Init_NoCache, mDNS_Init_ZeroCacheSize, mDNS_Init_DontAdvertiseLocalAddresses, mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext); - if (status) { fprintf(stderr, "Daemon start: mDNS_Init failed %ld\n", status); return(status); } + if (status) { fprintf(stderr, "Daemon start: mDNS_Init failed %d\n", (int)status); return(status); } mDNSPosixListenForSignalInEventLoop(SIGINT); mDNSPosixListenForSignalInEventLoop(SIGTERM); diff --git a/mDNSPosix/ReadMe.txt b/mDNSPosix/ReadMe.txt index 80f8fa3..d4bff85 100755 --- a/mDNSPosix/ReadMe.txt +++ b/mDNSPosix/ReadMe.txt @@ -1,24 +1,31 @@ ReadMe About mDNSPosix ---------------------- -mDNSPosix is a port of Apple's core mDNS code to Posix platforms. +mDNSPosix is a port of Apple's Multicast DNS and DNS Service Discovery +code to Posix platforms. -mDNS is short for "multicast DNS", which is a technology that allows you -to register IP services and browse the network for those services. For -more information about mDNS, see the mDNS web site. +Multicast DNS and DNS Service Discovery are technologies that allow you +to register IP-based services and browse the network for those services. +For more information about mDNS, see the mDNS web site. -mDNS is part of a family of technologies resulting from the efforts of -the IETF zeroconf working group. For information about other zeroconf -technologies, see the zeroconf web site. +Multicast DNS is part of a family of technologies resulting from the +efforts of the IETF Zeroconf working group. For information about +other Zeroconf technologies, see the Zeroconf web site. Apple uses the trade mark "Bonjour" to describe our implementation of -zeroconf technologies. This sample is designed to show how easy it is +Zeroconf technologies. This sample is designed to show how easy it is to make a device "Bonjour compatible". +The "Bonjour" trade mark can also be licensed at no charge for +inclusion on your own products, packaging, manuals, promotional +materials, or web site. For details and licensing terms, see + + + The code in this sample was compiled and tested on Mac OS X (10.1.x, 10.2, 10.3), Solaris (SunOS 5.8), Linux (Redhat 2.4.9-21, Fedora Core 1), and OpenBSD (2.9). YMMV. @@ -79,26 +86,30 @@ o Standalone products for dedicated devices (printer, network camera, etc.) - mDNSResponderPosix - mDNSProxyResponderPosix -o Debugging tools +o Testing and Debugging tools + - dns-sd command-line tool (from the "Clients" folder) - mDNSNetMonitor - mDNSIdentify -As root type "make install" to install six things: +As root type "make install" to install eight things: o mdnsd (usually in /usr/sbin) o libmdns (usually in /usr/lib) o dns_sd.h (usually in /usr/include) o startup scripts (e.g. in /etc/rc.d) o manual pages (usually in /usr/share/man) +o dns-sd tool (usually in /usr/bin) o nss_mdns (usually in /lib) o nss configuration files (usually in /etc) -Once you've installed the files in their respective places, -you need to start the daemon running, either by rebooting, -or by running the startup script "/etc/init.d/mdns start" -(the exact path may be different on your system). -Then you can cd to the "Clients" folder and type "make". -This builds a test client showing how to exercise all the major -functionality of the daemon. +The "make install" concludes by executing the startup script +(usually "/etc/init.d/mdns start") to start the daemon running. +You shouldn't need to reboot unless you really want to. + +Once the daemon is running, you can use the dns-sd test tool +to exercise all the major functionality of the daemon. Running +"dns-sd" with no arguments gives a summary of the available options. +This test tool is also described in detail, with several examples, +in Chapter 6 of the O'Reilly "Zero Configuration Networking" book. How It Works @@ -243,17 +254,19 @@ Caveats ------- Currently the program uses a simple make file. -There are various problems with loopback-only self discovery. The code -will attempt service discovery on the loopback interface only if no -other interfaces are available. However, this exposes a number of -problems with the underlying network stack (at least on Mac OS X). +The Multicast DNS protocol can also operate locally over the loopback +interface, but this exposed some problems with the underlying network +stack in early versions of Mac OS X and may expose problems with other +network stacks too. -o On Mac OS X 10.1.x the code fails to start on the loopback interface +o On Mac OS X 10.1.x the code failed to start on the loopback interface because the IP_ADD_MEMBERSHIP option returns ENOBUFS. -o On Mac OS X 10.2 the loopback-only case fails because - mDNSPlatformSendUDP's call to "sendto" fails with error EHOSTUNREACH - [Radar ID 3016042]. +o On Mac OS X 10.2 the loopback-only case failed because + "sendto" calls fails with error EHOSTUNREACH. (3016042) + +Consequently, the code will attempt service discovery on the loopback +interface only if no other interfaces are available. I haven't been able to test the loopback-only case on other platforms because I don't have access to the physical machine. @@ -261,9 +274,7 @@ because I don't have access to the physical machine. Licencing --------- -This code is distributed under the Apple Public Source License. -Information about the licence is included at the top of each source file. - +This source code is Open Source; for details see the "LICENSE" file. Credits and Version History --------------------------- diff --git a/mDNSPosix/Responder.c b/mDNSPosix/Responder.c index 986333b..9a4d13a 100755 --- a/mDNSPosix/Responder.c +++ b/mDNSPosix/Responder.c @@ -2,28 +2,30 @@ * * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * 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 * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * http://www.apache.org/licenses/LICENSE-2.0 * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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. - * - * @APPLE_LICENSE_HEADER_END@ Change History (most recent first): $Log: Responder.c,v $ +Revision 1.33 2007/04/16 20:49:39 cheshire +Fix compile errors for mDNSPosix build + +Revision 1.32 2006/08/14 23:24:46 cheshire +Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 + +Revision 1.31 2006/06/12 18:22:42 cheshire + mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux + Revision 1.30 2005/10/26 22:21:16 cheshire Potential buffer overflow in mDNSResponderPosix @@ -141,7 +143,9 @@ First checkin static mDNS mDNSStorage; // mDNS core uses this to store its globals static mDNS_PlatformSupport PlatformStorage; // Stores this platform's globals -static const char *gProgramName = "mDNSResponderPosix"; +mDNSexport const char ProgramName[] = "mDNSResponderPosix"; + +static const char *gProgramName = ProgramName; #if COMPILER_LIKES_PRAGMA_MARK #pragma mark ***** Signals @@ -832,7 +836,7 @@ int main(int argc, char **argv) result = 2; } if ( (result != 0) || (gMDNSPlatformPosixVerboseLevel > 0) ) { - fprintf(stderr, "%s: Finished with status %ld, result %d\n", gProgramName, status, result); + fprintf(stderr, "%s: Finished with status %d, result %d\n", gProgramName, (int)status, result); } return result; diff --git a/mDNSPosix/dnsextd.c b/mDNSPosix/dnsextd.c deleted file mode 100644 index 6acf92e..0000000 --- a/mDNSPosix/dnsextd.c +++ /dev/null @@ -1,2122 +0,0 @@ -/* -*- Mode: C; tab-width: 4 -*- - * - * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - - Change History (most recent first): - -$Log: dnsextd.c,v $ -Revision 1.33.2.1 2005/08/05 21:14:00 ksekar - Long-lived queries not working on windows -Change constant names - -Revision 1.33 2005/03/11 19:09:02 ksekar -Fixed ZERO_LLQID macro - -Revision 1.32 2005/03/10 22:54:33 ksekar - dnsextd leaks memory/ports - -Revision 1.31 2005/02/24 02:37:57 ksekar - dnsextd memory management improvements - -Revision 1.30 2005/01/27 22:57:56 cheshire -Fix compile errors on gcc4 - -Revision 1.29 2004/12/22 00:13:50 ksekar - Change version, port, and polling interval for LLQ - -Revision 1.28 2004/12/17 00:30:00 ksekar - dnsextd memory leak - -Revision 1.27 2004/12/17 00:27:32 ksekar -Ignore SIGPIPE - -Revision 1.26 2004/12/17 00:21:33 ksekar -Fixes for new CacheRecord structure with indirect name pointer - -Revision 1.25 2004/12/16 20:13:02 cheshire - Cache memory management improvements - -Revision 1.24 2004/12/14 17:09:06 ksekar -fixed incorrect usage instructions - -Revision 1.23 2004/12/06 20:24:31 ksekar - dnsextd leaks sockets - -Revision 1.22 2004/12/03 20:20:29 ksekar - dnsextd: support delivery of large records via LLQ events - -Revision 1.21 2004/12/03 06:11:34 ksekar - clean up dnsextd arguments - -Revision 1.20 2004/12/01 04:27:28 cheshire - Darwin patches for Solaris and Suse -Don't use uint32_t, etc. -- they require stdint.h, which doesn't exist on FreeBSD 4.x, Solaris, etc. - -Revision 1.19 2004/12/01 01:16:29 cheshire -Solaris compatibility fixes - -Revision 1.18 2004/11/30 23:51:06 cheshire -Remove double semicolons - -Revision 1.17 2004/11/30 22:37:01 cheshire -Update copyright dates and add "Mode: C; tab-width: 4" headers - -Revision 1.16 2004/11/25 02:02:28 ksekar -Fixed verbose log message argument - -Revision 1.15 2004/11/19 02:35:02 ksekar - Wide Area Security: Add LLQ-ID to events - -Revision 1.14 2004/11/17 06:17:58 cheshire -Update comments to show correct SRV names: _dns-update._udp.. and _dns-llq._udp.. - -Revision 1.13 2004/11/13 02:22:36 ksekar - Refresh Acks from daemon malformatted - -Revision 1.12 2004/11/12 01:05:01 ksekar - dnsextd: daemon registers the SRV same record -twice at startup - -Revision 1.11 2004/11/12 01:03:31 ksekar - dnsextd: KnownAnswers (CacheRecords) leaked - -Revision 1.10 2004/11/12 00:35:28 ksekar - dnsextd: uninitialized pointer can cause crash - -Revision 1.9 2004/11/10 20:38:17 ksekar - dnsextd: allow a "fudge" in LLQ lease echo - -Revision 1.8 2004/11/01 17:48:14 cheshire -Changed SOA serial number back to signed. RFC 1035 may describe it as "unsigned", but -it's wrong. The SOA serial is a modular counter, as explained in "DNS & BIND", page -137. Since C doesn't have a modular type, we used signed, C's closest approximation. - -Revision 1.7 2004/10/30 00:06:58 ksekar - Support Long Lived Queries in DNS Extension daemon - -Revision 1.6 2004/09/17 01:08:54 cheshire -Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h - The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces - declared in that file are ONLY appropriate to single-address-space embedded applications. - For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used. - -Revision 1.5 2004/09/16 00:50:54 cheshire -Don't use MSG_WAITALL -- it returns "Invalid argument" on some Linux versions - -Revision 1.4 2004/09/14 23:27:48 cheshire -Fix compile errors - -Revision 1.3 2004/09/02 01:39:40 cheshire -For better readability, follow consistent convention that QR bit comes first, followed by OP bits - -Revision 1.2 2004/08/24 23:27:57 cheshire -Fixes for Linux compatibility: -Don't use strings.h -Don't assume SIGINFO -Don't try to set servaddr.sin_len on platforms that don't have sa_len - -Revision 1.1 2004/08/11 00:43:26 ksekar -: DNS Extension daemon for DNS Update Lease - -*/ - -#include "../mDNSCore/mDNSEmbeddedAPI.h" -#include "../mDNSCore/DNSCommon.h" -#include "../mDNSCore/mDNS.c" -//!!!KRS we #include mDNS.c for the various constants defined there - we should move these to DNSCommon.h - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Compatibility workaround -#ifndef AF_LOCAL -#define AF_LOCAL AF_UNIX -#endif - -// -// Constants -// - -#define LOOPBACK "127.0.0.1" -#define NS_PORT 53 -#define DAEMON_PORT 5352 // default, may be overridden via command line argument -#define LISTENQ 128 // tcp connection backlog -#define RECV_BUFLEN 9000 -#define LEASETABLE_INIT_NBUCKETS 256 // initial hashtable size (doubles as table fills) -#define LLQ_TABLESIZE 1024 // !!!KRS make this dynamically growable -#define EXPIRATION_INTERVAL 300 // check for expired records every 5 minutes -#define SRV_TTL 7200 // TTL For _dns-update SRV records - -// LLQ Lease bounds (seconds) -#define LLQ_MIN_LEASE (15 * 60) -#define LLQ_MAX_LEASE (120 * 60) -#define LLQ_LEASE_FUDGE 60 - -// LLQ SOA poll interval (microseconds) -#define LLQ_MONITOR_ERR_INTERVAL (60 * 1000000) -#define LLQ_MONITOR_INTERVAL 250000 -#ifdef SIGINFO -#define INFO_SIGNAL SIGINFO -#else -#define INFO_SIGNAL SIGUSR1 -#endif - -#define SAME_INADDR(x,y) (*((mDNSu32 *)&x) == *((mDNSu32 *)&y)) -#define ZERO_LLQID(x) (!memcmp(x, "\x0\x0\x0\x0\x0\x0\x0\x0", 8)) - -// -// Data Structures -// Structs/fields that must be locked for thread safety are explicitly commented -// - -typedef struct - { - struct sockaddr_in src; - size_t len; - DNSMessage msg; - // Note: extra storage for oversized (TCP) messages goes here - } PktMsg; - -// lease table entry -typedef struct RRTableElem - { - struct RRTableElem *next; - struct sockaddr_in cli; // client's source address - long expire; // expiration time, in seconds since epoch - domainname zone; // from zone field of update message - domainname name; // name of the record - CacheRecord rr; // last field in struct allows for allocation of oversized RRs - } RRTableElem; - -typedef enum - { - RequestReceived = 0, - ChallengeSent = 1, - Established = 2 - } LLQState; - -typedef struct AnswerListElem - { - struct AnswerListElem *next; - domainname name; - mDNSu16 type; - CacheRecord *KnownAnswers; // All valid answers delivered to client - CacheRecord *EventList; // New answers (adds/removes) to be sent to client - int refcount; - } AnswerListElem; - -// llq table entry -typedef struct LLQEntry - { - struct LLQEntry *next; - struct sockaddr_in cli; // clien'ts source address - domainname qname; - mDNSu16 qtype; - mDNSu8 id[8]; - LLQState state; - mDNSu32 lease; // original lease, in seconds - mDNSs32 expire; // expiration, absolute, in seconds since epoch - AnswerListElem *AnswerList; - } LLQEntry; - -// daemon-wide information -typedef struct - { - // server variables - read only after initialization (no locking) - struct in_addr saddr; // server address - domainname zone; // zone being updated - int tcpsd; // listening TCP socket - int udpsd; // listening UDP socket - - // daemon variables - read only after initialization (no locking) - uDNS_AuthInfo *AuthInfo; // linked list of keys for signing deletion updates - mDNSIPPort port; // listening port - - // lease table variables (locked via mutex after initialization) - RRTableElem **table; // hashtable for records with leases - pthread_mutex_t tablelock; // mutex for lease table - mDNSs32 nbuckets; // buckets allocated - mDNSs32 nelems; // elements in table - - // LLQ table variables - LLQEntry *LLQTable[LLQ_TABLESIZE]; // !!!KRS change this and RRTable to use a common data structure - AnswerListElem *AnswerTable[LLQ_TABLESIZE]; - int LLQEventListenSock; // Unix domain socket pair - polling thread writes to ServPollSock, which wakes - int LLQServPollSock; // the main thread listening on EventListenSock, indicating that the zone has changed - } DaemonInfo; - -// args passed to UDP request handler thread as void* -typedef struct - { - PktMsg pkt; - struct sockaddr_in cliaddr; - DaemonInfo *d; - } UDPRequestArgs; - -// args passed to TCP request handler thread as void* -typedef struct - { - int sd; // socket connected to client - struct sockaddr_in cliaddr; - DaemonInfo *d; - } TCPRequestArgs; - -// -// Global Variables -// - -// booleans to determine runtime output -// read-only after initialization (no mutex protection) -static mDNSBool foreground = 0; -static mDNSBool verbose = 0; - -// globals set via signal handler (accessed exclusively by main select loop and signal handler) -static mDNSBool terminate = 0; -static mDNSBool dumptable = 0; - -// -// Logging Routines -// Log messages are delivered to syslog unless -f option specified -// - -// common message logging subroutine -mDNSlocal void PrintLog(const char *buffer) - { - if (foreground) - { - fprintf(stderr,"%s\n", buffer); - fflush(stderr); - } - else - { - openlog("dnsextd", LOG_CONS | LOG_PERROR, LOG_DAEMON); - syslog(LOG_ERR, "%s", buffer); - closelog(); - } - } - -// Verbose Logging (conditional on -v option) -mDNSlocal void VLog(const char *format, ...) - { - char buffer[512]; - va_list ptr; - - if (!verbose) return; - va_start(ptr,format); - buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0; - va_end(ptr); - PrintLog(buffer); - } - -// Unconditional Logging -mDNSlocal void Log(const char *format, ...) - { - char buffer[512]; - va_list ptr; - - va_start(ptr,format); - buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0; - va_end(ptr); - PrintLog(buffer); - } - -// Error Logging -// prints message "dnsextd : - " -// must be compiled w/ -D_REENTRANT for thread-safe errno usage -mDNSlocal void LogErr(const char *fn, const char *operation) - { - char buf[512]; - snprintf(buf, sizeof(buf), "%s: %s - %s", fn, operation, strerror(errno)); - PrintLog(buf); - } - -// -// Networking Utility Routines -// - -// Convert DNS Message Header from Network to Host byte order -mDNSlocal void HdrNToH(PktMsg *pkt) - { - // Read the integer parts which are in IETF byte-order (MSB first, LSB second) - mDNSu8 *ptr = (mDNSu8 *)&pkt->msg.h.numQuestions; - pkt->msg.h.numQuestions = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); - pkt->msg.h.numAnswers = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]); - pkt->msg.h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]); - pkt->msg.h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]); - } - -// Convert DNS Message Header from Host to Network byte order -mDNSlocal void HdrHToN(PktMsg *pkt) - { - mDNSu16 numQuestions = pkt->msg.h.numQuestions; - mDNSu16 numAnswers = pkt->msg.h.numAnswers; - mDNSu16 numAuthorities = pkt->msg.h.numAuthorities; - mDNSu16 numAdditionals = pkt->msg.h.numAdditionals; - mDNSu8 *ptr = (mDNSu8 *)&pkt->msg.h.numQuestions; - - // Put all the integer values in IETF byte-order (MSB first, LSB second) - *ptr++ = (mDNSu8)(numQuestions >> 8); - *ptr++ = (mDNSu8)(numQuestions & 0xFF); - *ptr++ = (mDNSu8)(numAnswers >> 8); - *ptr++ = (mDNSu8)(numAnswers & 0xFF); - *ptr++ = (mDNSu8)(numAuthorities >> 8); - *ptr++ = (mDNSu8)(numAuthorities & 0xFF); - *ptr++ = (mDNSu8)(numAdditionals >> 8); - *ptr++ = (mDNSu8)(numAdditionals & 0xFF); - } - -// create a socket connected to nameserver -// caller terminates connection via close() -mDNSlocal int ConnectToServer(DaemonInfo *d) - { - struct sockaddr_in servaddr; - int sd; - - bzero(&servaddr, sizeof(servaddr)); - if (d->saddr.s_addr) servaddr.sin_addr = d->saddr; - else inet_pton(AF_INET, LOOPBACK, &d->saddr); // use loopback if server not explicitly specified - servaddr.sin_port = htons(NS_PORT); - servaddr.sin_family = AF_INET; -#ifndef NOT_HAVE_SA_LEN - servaddr.sin_len = sizeof(servaddr); -#endif - sd = socket(AF_INET, SOCK_STREAM, 0); - if (sd < 0) { LogErr("ConnectToServer", "socket"); return -1; } - if (connect(sd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) { LogErr("ConnectToServer", "connect"); return -1; } - return sd; - } - -// send an entire block of data over a connected socket, blocking if buffers are full -mDNSlocal int MySend(int sd, const void *msg, int len) - { - int n, nsent = 0; - - while (nsent < len) - { - n = send(sd, (char *)msg + nsent, len - nsent, 0); - if (n < 0) { LogErr("MySend", "send"); return -1; } - nsent += n; - } - return 0; - } - -// Transmit a DNS message, prefixed by its length, over TCP, blocking if necessary -mDNSlocal int SendTCPMsg(int sd, PktMsg *pkt) - { - // send the lenth, in network byte order - mDNSu16 len = htons((mDNSu16)pkt->len); - if (MySend(sd, &len, sizeof(len)) < 0) return -1; - - // send the message - return MySend(sd, &pkt->msg, pkt->len); - } - -// Receive len bytes, waiting until we have all of them. -// Returns number of bytes read (which should always be the number asked for). -static int my_recv(const int sd, void *const buf, const int len) - { - // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; - // use an explicit while() loop instead. - // Also, don't try to do '+=' arithmetic on the original "void *" pointer -- - // arithmetic on "void *" pointers is compiler-dependent. - int remaining = len; - char *ptr = (char *)buf; - while (remaining) - { - ssize_t num_read = recv(sd, ptr, remaining, 0); - if ((num_read == 0) || (num_read < 0) || (num_read > remaining)) return -1; - ptr += num_read; - remaining -= num_read; - } - return(len); - } - -// Return a DNS Message read off of a TCP socket, or NULL on failure -// If storage is non-null, result is placed in that buffer. Otherwise, -// returned value is allocated with Malloc, and contains sufficient extra -// storage for a Lease OPT RR - -mDNSlocal PktMsg *ReadTCPMsg(int sd, PktMsg *storage) - { - int nread, allocsize; - mDNSu16 msglen = 0; - PktMsg *pkt = NULL; - unsigned int srclen; - - nread = my_recv(sd, &msglen, sizeof(msglen)); - if (nread < 0) { LogErr("TCPRequestForkFn", "recv"); goto error; } - msglen = ntohs(msglen); - if (nread != sizeof(msglen)) { Log("Could not read length field of message"); goto error; } - - if (storage) - { - if (msglen > sizeof(storage->msg)) { Log("ReadTCPMsg: provided buffer too small."); goto error; } - pkt = storage; - } - else - { - // buffer extra space to add an OPT RR - if (msglen > sizeof(DNSMessage)) allocsize = sizeof(PktMsg) - sizeof(DNSMessage) + msglen; - else allocsize = sizeof(PktMsg); - pkt = malloc(allocsize); - if (!pkt) { LogErr("ReadTCPMsg", "malloc"); goto error; } - bzero(pkt, sizeof(*pkt)); - } - - pkt->len = msglen; - srclen = sizeof(pkt->src); - if (getpeername(sd, (struct sockaddr *)&pkt->src, &srclen) || - srclen != sizeof(pkt->src)) { LogErr("ReadTCPMsg", "getpeername"); bzero(&pkt->src, sizeof(pkt->src)); } - nread = my_recv(sd, &pkt->msg, msglen); - if (nread < 0) { LogErr("TCPRequestForkFn", "recv"); goto error; } - if (nread != msglen) { Log("Could not read entire message"); goto error; } - if (pkt->len < sizeof(DNSMessageHeader)) - { Log("ReadTCPMsg: Message too short (%d bytes)", pkt->len); goto error; } - HdrNToH(pkt); - return pkt; - //!!!KRS convert to HBO here? - error: - if (pkt && pkt != storage) free(pkt); - return NULL; - } - -// -// Dynamic Update Utility Routines -// - -// Get the lease life of records in a dynamic update -// returns -1 on error or if no lease present -mDNSlocal mDNSs32 GetPktLease(PktMsg *pkt) - { - mDNSs32 lease = -1; - const mDNSu8 *ptr = NULL, *end = (mDNSu8 *)&pkt->msg + pkt->len; - LargeCacheRecord lcr; - int i; - - HdrNToH(pkt); - ptr = LocateAdditionals(&pkt->msg, end); - if (ptr) - for (i = 0; i < pkt->msg.h.numAdditionals; i++) - { - ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); - if (!ptr) { Log("Unable to read additional record"); break; } - if (lcr.r.resrec.rrtype == kDNSType_OPT) - { - if (lcr.r.resrec.rdlength < LEASE_OPT_RDLEN) continue; - if (lcr.r.resrec.rdata->u.opt.opt != kDNSOpt_Lease) continue; - lease = (mDNSs32)lcr.r.resrec.rdata->u.opt.OptData.lease; - break; - } - } - - HdrHToN(pkt); - return lease; - } - -// check if a request and server response complete a successful dynamic update -mDNSlocal mDNSBool SuccessfulUpdateTransaction(PktMsg *request, PktMsg *reply) - { - char buf[32]; - char *vlogmsg = NULL; - - // check messages - if (!request || !reply) { vlogmsg = "NULL message"; goto failure; } - if (request->len < sizeof(DNSMessageHeader) || reply->len < sizeof(DNSMessageHeader)) { vlogmsg = "Malformatted message"; goto failure; } - - // check request operation - if ((request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask)) - { vlogmsg = "Request opcode not an update"; goto failure; } - - // check result - if ((reply->msg.h.flags.b[1] & kDNSFlag1_RC)) { vlogmsg = "Reply contains non-zero rcode"; goto failure; } - if ((reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (kDNSFlag0_OP_Update | kDNSFlag0_QR_Response)) - { vlogmsg = "Reply opcode not an update response"; goto failure; } - - VLog("Successful update from %s", inet_ntop(AF_INET, &request->src.sin_addr, buf, 32)); - return mDNStrue; - - failure: - VLog("Request %s: %s", inet_ntop(AF_INET, &request->src.sin_addr, buf, 32), vlogmsg); - return mDNSfalse; - } - -// Allocate an appropriately sized CacheRecord and copy data from original. -// Name pointer in CacheRecord object is set to point to the name specified -// -mDNSlocal CacheRecord *CopyCacheRecord(const CacheRecord *orig, domainname *name) - { - CacheRecord *cr; - size_t size = sizeof(*cr); - if (orig->resrec.rdlength > InlineCacheRDSize) size += orig->resrec.rdlength - InlineCacheRDSize; - cr = malloc(size); - if (!cr) { LogErr("CopyCacheRecord", "malloc"); return NULL; } - memcpy(cr, orig, size); - cr->resrec.rdata = (RData*)&cr->rdatastorage; - cr->resrec.name = name; - - return cr; - } - - -// -// Lease Hashtable Utility Routines -// - -// double hash table size -// caller must lock table prior to invocation -mDNSlocal void RehashTable(DaemonInfo *d) - { - RRTableElem *ptr, *tmp, **new; - int i, bucket, newnbuckets = d->nbuckets * 2; - - VLog("Rehashing lease table (new size %d buckets)", newnbuckets); - new = malloc(sizeof(RRTableElem *) * newnbuckets); - if (!new) { LogErr("RehashTable", "malloc"); return; } - bzero(new, newnbuckets * sizeof(RRTableElem *)); - - for (i = 0; i < d->nbuckets; i++) - { - ptr = d->table[i]; - while (ptr) - { - bucket = ptr->rr.resrec.namehash % newnbuckets; - tmp = ptr; - ptr = ptr->next; - tmp->next = new[bucket]; - new[bucket] = tmp; - } - } - d->nbuckets = newnbuckets; - free(d->table); - d->table = new; - } - -// print entire contents of hashtable, invoked via SIGINFO -mDNSlocal void PrintLeaseTable(DaemonInfo *d) - { - int i; - RRTableElem *ptr; - char rrbuf[80], addrbuf[16]; - struct timeval now; - int hr, min, sec; - - if (gettimeofday(&now, NULL)) { LogErr("PrintTable", "gettimeofday"); return; } - if (pthread_mutex_lock(&d->tablelock)) { LogErr("PrintTable", "pthread_mutex_lock"); return; } - - Log("Dumping Lease Table Contents (table contains %d resource records)", d->nelems); - for (i = 0; i < d->nbuckets; i++) - { - for (ptr = d->table[i]; ptr; ptr = ptr->next) - { - hr = ((ptr->expire - now.tv_sec) / 60) / 60; - min = ((ptr->expire - now.tv_sec) / 60) % 60; - sec = (ptr->expire - now.tv_sec) % 60; - Log("Update from %s, Expires in %d:%d:%d\n\t%s", inet_ntop(AF_INET, &ptr->cli.sin_addr, addrbuf, 16), hr, min, sec, - GetRRDisplayString_rdb(&ptr->rr.resrec, &ptr->rr.resrec.rdata->u, rrbuf)); - } - } - pthread_mutex_unlock(&d->tablelock); - } - -// -// Startup SRV Registration Routines -// Register _dns-update._udp/_tcp. SRV records indicating the port on which -// the daemon accepts requests -// - -// delete all RRS of a given name/type -mDNSlocal mDNSu8 *putRRSetDeletion(DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit, ResourceRecord *rr) - { - ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name); - if (!ptr || ptr + 10 >= limit) return NULL; // out of space - ptr[0] = (mDNSu8)(rr->rrtype >> 8); - ptr[1] = (mDNSu8)(rr->rrtype & 0xFF); - ptr[2] = (mDNSu8)((mDNSu16)kDNSQClass_ANY >> 8); - ptr[3] = (mDNSu8)((mDNSu16)kDNSQClass_ANY & 0xFF); - bzero(ptr+4, sizeof(rr->rroriginalttl) + sizeof(rr->rdlength)); // zero ttl/rdata - msg->h.mDNS_numUpdates++; - return ptr + 10; - } - -mDNSlocal mDNSu8 *PutUpdateSRV(DaemonInfo *d, PktMsg *pkt, mDNSu8 *ptr, char *regtype, mDNSBool registration) - { - AuthRecord rr; - char hostname[1024], buf[80]; - mDNSu8 *end = (mDNSu8 *)&pkt->msg + sizeof(DNSMessage); - - mDNS_SetupResourceRecord(&rr, NULL, 0, kDNSType_SRV, SRV_TTL, kDNSRecordTypeUnique, NULL, NULL); - rr.resrec.rrclass = kDNSClass_IN; - rr.resrec.rdata->u.srv.priority = 0; - rr.resrec.rdata->u.srv.weight = 0; - rr.resrec.rdata->u.srv.port.NotAnInteger = d->port.NotAnInteger; - if (!gethostname(hostname, 1024) < 0 || MakeDomainNameFromDNSNameString(&rr.resrec.rdata->u.srv.target, hostname)) - rr.resrec.rdata->u.srv.target.c[0] = '\0'; - - MakeDomainNameFromDNSNameString(rr.resrec.name, regtype); - AppendDomainName(rr.resrec.name, &d->zone); - VLog("%s %s", registration ? "Registering SRV record" : "Deleting existing RRSet", - GetRRDisplayString_rdb(&rr.resrec, &rr.resrec.rdata->u, buf)); - if (registration) ptr = PutResourceRecord(&pkt->msg, ptr, &pkt->msg.h.mDNS_numUpdates, &rr.resrec); - else ptr = putRRSetDeletion(&pkt->msg, ptr, end, &rr.resrec); - return ptr; - } - - -// perform dynamic update. -// specify deletion by passing false for the register parameter, otherwise register the records. -mDNSlocal int UpdateSRV(DaemonInfo *d, mDNSBool registration) - { - int sd = -1; - mDNSOpaque16 id; - PktMsg pkt; - mDNSu8 *ptr = pkt.msg.data; - mDNSu8 *end = (mDNSu8 *)&pkt.msg + sizeof(DNSMessage); - mDNSu16 nAdditHBO; // num additionas, in host byte order, required by message digest routine - PktMsg *reply = NULL; - - int result = -1; - - // Initialize message - id.NotAnInteger = 0; - InitializeDNSMessage(&pkt.msg.h, id, UpdateReqFlags); - pkt.src.sin_addr.s_addr = htonl(INADDR_ANY); // address field set solely for verbose logging in subroutines - pkt.src.sin_family = AF_INET; - - // format message body - ptr = putZone(&pkt.msg, ptr, end, &d->zone, mDNSOpaque16fromIntVal(kDNSClass_IN)); - if (!ptr) goto end; - - ptr = PutUpdateSRV(d, &pkt, ptr, "_dns-update._udp.", registration); if (!ptr) goto end; - ptr = PutUpdateSRV(d, &pkt, ptr, "_dns-update._tcp.", registration); if (!ptr) goto end; - ptr = PutUpdateSRV(d, &pkt, ptr, "_dns-llq._udp.", registration); if (!ptr) goto end; - - nAdditHBO = pkt.msg.h.numAdditionals; - HdrHToN(&pkt); - if (d->AuthInfo) - { - ptr = DNSDigest_SignMessage(&pkt.msg, &ptr, &nAdditHBO, d->AuthInfo); - if (!ptr) goto end; - } - pkt.len = ptr - (mDNSu8 *)&pkt.msg; - - // send message, receive reply - sd = ConnectToServer(d); - if (sd < 0) { Log("UpdateSRV: ConnectToServer failed"); goto end; } - if (SendTCPMsg(sd, &pkt)) { Log("UpdateSRV: SendTCPMsg failed"); } - reply = ReadTCPMsg(sd, NULL); - if (!SuccessfulUpdateTransaction(&pkt, reply)) - Log("SRV record registration failed with rcode %d", reply->msg.h.flags.b[1] & kDNSFlag1_RC); - else result = 0; - - end: - if (!ptr) { Log("UpdateSRV: Error constructing lease expiration update"); } - if (sd >= 0) close(sd); - if (reply) free(reply); - return result; - } - -// wrapper routines/macros -#define ClearUpdateSRV(d) UpdateSRV(d, 0) - -// clear any existing records prior to registration -mDNSlocal int SetUpdateSRV(DaemonInfo *d) - { - int err; - - err = ClearUpdateSRV(d); // clear any existing record - if (!err) err = UpdateSRV(d, 1); - return err; - } - -// -// Argument Parsing and Configuration -// - -// read authentication information for a zone from command line argument -// global optind corresponds to keyname argument on entry -mDNSlocal int ReadAuthKey(int argc, char *argv[], DaemonInfo *d) - { - uDNS_AuthInfo *auth = NULL; - unsigned char keybuf[512]; - mDNSs32 keylen; - - auth = malloc(sizeof(*auth)); - if (!auth) { perror("ReadAuthKey, malloc"); goto error; } - auth->next = NULL; - if (argc < optind + 1) return -1; // keyname + secret - if (!MakeDomainNameFromDNSNameString(&auth->keyname, optarg)) - { fprintf(stderr, "Bad key name %s", optarg); goto error; } - keylen = DNSDigest_Base64ToBin(argv[optind++], keybuf, 512); - if (keylen < 0) - { fprintf(stderr, "Bad shared secret %s (must be base-64 encoded string)", argv[optind-1]); goto error; } - DNSDigest_ConstructHMACKey(auth, keybuf, (mDNSu32)keylen); - d->AuthInfo = auth; - return 0; - - error: - if (auth) free(auth); - return -1; - } - -mDNSlocal int SetPort(DaemonInfo *d, char *PortAsString) - { - long l; - - l = strtol(PortAsString, NULL, 10); // convert string to long - if ((!l && errno == EINVAL) || l > 65535) return -1; // error check conversion - d->port.NotAnInteger = htons((mDNSu16)l); // set to network byte order - return 0; - } - -mDNSlocal void PrintUsage(void) - { - fprintf(stderr, "Usage: dnsextd -z [-vf] [ -s server ] [-k keyname secret] ...\n" - "Use \"dnsextd -h\" for help\n"); - } - -mDNSlocal void PrintHelp(void) - { - fprintf(stderr, "\n\n"); - PrintUsage(); - - fprintf(stderr, - "dnsextd is a daemon that implements DNS extensions supporting Dynamic DNS Update Leases\n" - "and Long Lived Queries, used in Wide-Area DNS Service Discovery, on behalf of name servers\n" - "that do not natively support these extensions. (See dns-sd.org for more info on DNS Service\n" - "Discovery, Update Leases, and Long Lived Queries.)\n\n" - - "dnsextd requires one argument,the zone, which is the domain for which Update Leases\n" - "and Long Lived Queries are to be administered. dnsextd communicates directly with the\n" - "primary master server for this zone.\n\n" - - "The options are as follows:\n\n" - - "-f Run daemon in foreground.\n\n" - - "-h Print help.\n\n" - - "-k Specify TSIG authentication key for dynamic updates from daemon to name server.\n" - " -k option is followed by the name of the key, and the shared secret as a base-64\n" - " encoded string. This key/secret are used by the daemon to delete resource records\n" - " from the server when leases expire. Clients are responsible for signing their\n" - " update requests.\n\n" - - "-s Specify address (IPv4 address in dotted-decimal notation) of the Primary Master\n" - " name server. Defaults to loopback (127.0.0.1), i.e. daemon and name server\n" - " running on the same machine.\n\n" - - "-v Verbose output.\n\n" - ); - } - -// Note: ProcessArgs called before process is daemonized, and therefore must open no descriptors -// returns 0 (success) if program is to continue execution -// output control arguments (-f, -v) do not affect this routine -mDNSlocal int ProcessArgs(int argc, char *argv[], DaemonInfo *d) - { - int opt; - - if (argc < 2) goto arg_error; - - d->port.NotAnInteger = htons(DAEMON_PORT); // default, may be overriden by command option - while ((opt = getopt(argc, argv, "z:p:hfvs:k:")) != -1) - { - switch(opt) - { - case 'p': if (SetPort(d, optarg) < 0) goto arg_error; - break; - - case 'h': PrintHelp(); return -1; - case 'f': foreground = 1; break; - case 'v': verbose = 1; break; - case 's': if (!inet_pton(AF_INET, optarg, &d->saddr)) goto arg_error; - break; - case 'k': if (ReadAuthKey(argc, argv, d) < 0) goto arg_error; - break; - case 'z': if (!MakeDomainNameFromDNSNameString(&d->zone, optarg)) - { - fprintf(stderr, "Bad zone %s", optarg); - goto arg_error; - } - break; - default: goto arg_error; - } - } - - if (!d->zone.c[0]) goto arg_error; // zone is the only required argument - if (d->AuthInfo) AssignDomainName(&d->AuthInfo->zone, &d->zone); // if we have a shared secret, use it for the entire zone - return 0; - - arg_error: - PrintUsage(); - return -1; - } - - -// -// Initialization Routines -// - -// Allocate memory, initialize locks and bookkeeping variables -mDNSlocal int InitLeaseTable(DaemonInfo *d) - { - if (pthread_mutex_init(&d->tablelock, NULL)) { LogErr("InitLeaseTable", "pthread_mutex_init"); return -1; } - d->nbuckets = LEASETABLE_INIT_NBUCKETS; - d->nelems = 0; - d->table = malloc(sizeof(RRTableElem *) * LEASETABLE_INIT_NBUCKETS); - if (!d->table) { LogErr("InitLeaseTable", "malloc"); return -1; } - bzero(d->table, sizeof(RRTableElem *) * LEASETABLE_INIT_NBUCKETS); - return 0; - } -mDNSlocal int SetupSockets(DaemonInfo *daemon) - { - struct sockaddr_in daddr; - int sockpair[2]; - - // set up sockets on which we receive requests - bzero(&daddr, sizeof(daddr)); - daddr.sin_family = AF_INET; - daddr.sin_addr.s_addr = htonl(INADDR_ANY); - - if (daemon->port.NotAnInteger) daddr.sin_port = daemon->port.NotAnInteger; - else daddr.sin_port = htons(DAEMON_PORT); - - daemon->tcpsd = socket(AF_INET, SOCK_STREAM, 0); - if (!daemon->tcpsd) { LogErr("SetupSockets", "socket"); return -1; } - if (bind(daemon->tcpsd, (struct sockaddr *)&daddr, sizeof(daddr)) < 0) { LogErr("SetupSockets", "bind"); return -1; } - if (listen(daemon->tcpsd, LISTENQ) < 0) { LogErr("SetupSockets", "listen"); return -1; } - - daemon->udpsd = socket(AF_INET, SOCK_DGRAM, 0); - if (!daemon->udpsd) { LogErr("SetupSockets", "socket"); return -1; } - if (bind(daemon->udpsd, (struct sockaddr *)&daddr, sizeof(daddr)) < 0) { LogErr("SetupSockets", "bind"); return -1; } - - // set up Unix domain socket pair for LLQ polling thread to signal main thread that a change to the zone occurred - if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockpair) < 0) { LogErr("SetupSockets", "socketpair"); return -1; } - daemon->LLQEventListenSock = sockpair[0]; - daemon->LLQServPollSock = sockpair[1]; - return 0; - } - -// -// periodic table updates -// - -// Delete a resource record from the nameserver via a dynamic update -mDNSlocal void DeleteRecord(DaemonInfo *d, CacheRecord *rr, domainname *zone) - { - int sd = -1; - mDNSOpaque16 id; - PktMsg pkt; - mDNSu8 *ptr = pkt.msg.data; - mDNSu8 *end = (mDNSu8 *)&pkt.msg + sizeof(DNSMessage); - mDNSu16 nAdditHBO; // num additionas, in host byte order, required by message digest routine - char buf[80]; - PktMsg *reply = NULL; - - VLog("Expiring record %s", GetRRDisplayString_rdb(&rr->resrec, &rr->resrec.rdata->u, buf)); - sd = ConnectToServer(d); - if (sd < 0) { Log("DeleteRecord: ConnectToServer failed"); goto end; } - - id.NotAnInteger = 0; - InitializeDNSMessage(&pkt.msg.h, id, UpdateReqFlags); - - ptr = putZone(&pkt.msg, ptr, end, zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass)); - if (!ptr) goto end; - ptr = putDeletionRecord(&pkt.msg, ptr, &rr->resrec); - if (!ptr) goto end; - - nAdditHBO = pkt.msg.h.numAdditionals; - HdrHToN(&pkt); - - if (d->AuthInfo) - { - ptr = DNSDigest_SignMessage(&pkt.msg, &ptr, &nAdditHBO, d->AuthInfo); - if (!ptr) goto end; - } - - pkt.len = ptr - (mDNSu8 *)&pkt.msg; - pkt.src.sin_addr.s_addr = htonl(INADDR_ANY); // address field set solely for verbose logging in subroutines - pkt.src.sin_family = AF_INET; - if (SendTCPMsg(sd, &pkt)) { Log("DeleteRecord: SendTCPMsg failed"); } - reply = ReadTCPMsg(sd, NULL); - if (!SuccessfulUpdateTransaction(&pkt, reply)) - Log("Expiration update failed with rcode %d", reply->msg.h.flags.b[1] & kDNSFlag1_RC); - - end: - if (!ptr) { Log("DeleteRecord: Error constructing lease expiration update"); } - if (sd >= 0) close(sd); - if (reply) free(reply); - } - -// iterate over table, deleting expired records -mDNSlocal void DeleteExpiredRecords(DaemonInfo *d) - { - int i; - RRTableElem *ptr, *prev, *fptr; - struct timeval now; - - if (gettimeofday(&now, NULL)) { LogErr("DeleteExpiredRecords ", "gettimeofday"); return; } - if (pthread_mutex_lock(&d->tablelock)) { LogErr("DeleteExpiredRecords", "pthread_mutex_lock"); return; } - for (i = 0; i < d->nbuckets; i++) - { - ptr = d->table[i]; - prev = NULL; - while (ptr) - { - if (ptr->expire - now.tv_sec < 0) - { - // delete record from server - DeleteRecord(d, &ptr->rr, &ptr->zone); - if (prev) prev->next = ptr->next; - else d->table[i] = ptr->next; - fptr = ptr; - ptr = ptr->next; - free(fptr); - d->nelems--; - } - else - { - prev = ptr; - ptr = ptr->next; - } - } - } - pthread_mutex_unlock(&d->tablelock); - } - -// -// main update request handling -// - -// Add, delete, or refresh records in table based on contents of a successfully completed dynamic update -mDNSlocal void UpdateLeaseTable(PktMsg *pkt, DaemonInfo *d, mDNSs32 lease) - { - RRTableElem **rptr, *tmp; - int i, allocsize, bucket; - LargeCacheRecord lcr; - ResourceRecord *rr = &lcr.r.resrec; - const mDNSu8 *ptr, *end; - struct timeval time; - DNSQuestion zone; - char buf[80]; - - if (pthread_mutex_lock(&d->tablelock)) { LogErr("UpdateLeaseTable", "pthread_mutex_lock"); return; } - HdrNToH(pkt); - ptr = pkt->msg.data; - end = (mDNSu8 *)&pkt->msg + pkt->len; - ptr = getQuestion(&pkt->msg, ptr, end, 0, &zone); - if (!ptr) { Log("UpdateLeaseTable: cannot read zone"); goto cleanup; } - ptr = LocateAuthorities(&pkt->msg, end); - if (!ptr) { Log("UpdateLeaseTable: Format error"); goto cleanup; } - - for (i = 0; i < pkt->msg.h.mDNS_numUpdates; i++) - { - mDNSBool DeleteAllRRSets = mDNSfalse, DeleteOneRRSet = mDNSfalse, DeleteOneRR = mDNSfalse; - - ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr); - if (!ptr) { Log("UpdateLeaseTable: GetLargeResourceRecord returned NULL"); goto cleanup; } - bucket = rr->namehash % d->nbuckets; - rptr = &d->table[bucket]; - - // handle deletions - if (rr->rrtype == kDNSQType_ANY && !rr->rroriginalttl && rr->rrclass == kDNSQClass_ANY && !rr->rdlength) - DeleteAllRRSets = mDNStrue; // delete all rrsets for a name - else if (!rr->rroriginalttl && rr->rrclass == kDNSQClass_ANY && !rr->rdlength) - DeleteOneRRSet = mDNStrue; - else if (!rr->rroriginalttl && rr->rrclass == kDNSClass_NONE) - DeleteOneRR = mDNStrue; - - if (DeleteAllRRSets || DeleteOneRRSet || DeleteOneRR) - { - while (*rptr) - { - if (SameDomainName((*rptr)->rr.resrec.name, rr->name) && - (DeleteAllRRSets || - (DeleteOneRRSet && (*rptr)->rr.resrec.rrtype == rr->rrtype) || - (DeleteOneRR && SameResourceRecord(&(*rptr)->rr.resrec, rr)))) - { - tmp = *rptr; - VLog("Received deletion update for %s", GetRRDisplayString_rdb(&tmp->rr.resrec, &tmp->rr.resrec.rdata->u, buf)); - *rptr = (*rptr)->next; - free(tmp); - d->nelems--; - } - else rptr = &(*rptr)->next; - } - } - else if (lease > 0) - { - // see if add or refresh - while (*rptr && !SameResourceRecord(&(*rptr)->rr.resrec, rr)) rptr = &(*rptr)->next; - if (*rptr) - { - // refresh - if (gettimeofday(&time, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; } - (*rptr)->expire = time.tv_sec + (unsigned)lease; - VLog("Refreshing lease for %s", GetRRDisplayString_rdb(&lcr.r.resrec, &lcr.r.resrec.rdata->u, buf)); - } - else - { - // New record - add to table - if (d->nelems > d->nbuckets) - { - RehashTable(d); - bucket = rr->namehash % d->nbuckets; - rptr = &d->table[bucket]; - } - if (gettimeofday(&time, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; } - allocsize = sizeof(RRTableElem); - if (rr->rdlength > InlineCacheRDSize) allocsize += (rr->rdlength - InlineCacheRDSize); - tmp = malloc(allocsize); - if (!tmp) { LogErr("UpdateLeaseTable", "malloc"); goto cleanup; } - memcpy(&tmp->rr, &lcr.r, sizeof(CacheRecord) + rr->rdlength - InlineCacheRDSize); - tmp->rr.resrec.rdata = (RData *)&tmp->rr.rdatastorage; - AssignDomainName(&tmp->name, rr->name); - tmp->rr.resrec.name = &tmp->name; - tmp->expire = time.tv_sec + (unsigned)lease; - tmp->cli.sin_addr = pkt->src.sin_addr; - AssignDomainName(&tmp->zone, &zone.qname); - tmp->next = d->table[bucket]; - d->table[bucket] = tmp; - d->nelems++; - VLog("Adding update for %s to lease table", GetRRDisplayString_rdb(&lcr.r.resrec, &lcr.r.resrec.rdata->u, buf)); - } - } - } - - cleanup: - pthread_mutex_unlock(&d->tablelock); - HdrHToN(pkt); - } - -// Given a successful reply from a server, create a new reply that contains lease information -// Replies are currently not signed !!!KRS change this -mDNSlocal PktMsg *FormatLeaseReply(DaemonInfo *d, PktMsg *orig, mDNSu32 lease) - { - PktMsg *reply; - mDNSu8 *ptr, *end; - mDNSOpaque16 flags; - - (void)d; //unused - reply = malloc(sizeof(*reply)); - if (!reply) { LogErr("FormatLeaseReply", "malloc"); return NULL; } - flags.b[0] = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update; - flags.b[1] = 0; - - InitializeDNSMessage(&reply->msg.h, orig->msg.h.id, flags); - reply->src.sin_addr.s_addr = htonl(INADDR_ANY); // unused except for log messages - reply->src.sin_family = AF_INET; - ptr = reply->msg.data; - end = (mDNSu8 *)&reply->msg + sizeof(DNSMessage); - ptr = putUpdateLease(&reply->msg, ptr, lease); - if (!ptr) { Log("FormatLeaseReply: putUpdateLease failed"); free(reply); return NULL; } - reply->len = ptr - (mDNSu8 *)&reply->msg; - return reply; - } - -// pkt is thread-local, not requiring locking -mDNSlocal PktMsg *HandleRequest(PktMsg *pkt, DaemonInfo *d) - { - int sd = -1; - PktMsg *reply = NULL, *LeaseReply; - mDNSs32 lease; - char buf[32]; - - // send msg to server, read reply - sd = ConnectToServer(d); - if (sd < 0) - { Log("Discarding request from %s due to connection errors", inet_ntop(AF_INET, &pkt->src.sin_addr, buf, 32)); goto cleanup; } - if (SendTCPMsg(sd, pkt) < 0) - { Log("Couldn't relay message from %s to server. Discarding.", inet_ntop(AF_INET, &pkt->src.sin_addr, buf, 32)); goto cleanup; } - reply = ReadTCPMsg(sd, NULL); - - // process reply - if (!SuccessfulUpdateTransaction(pkt, reply)) - { VLog("Message from %s not a successful update.", inet_ntop(AF_INET, &pkt->src.sin_addr, buf, 32)); goto cleanup; } - lease = GetPktLease(pkt); - UpdateLeaseTable(pkt, d, lease); - if (lease > 0) - { - LeaseReply = FormatLeaseReply(d, reply, lease); - if (!LeaseReply) Log("HandleRequest - unable to format lease reply"); - free(reply); - reply = LeaseReply; - } - cleanup: - if (sd >= 0) close(sd); - return reply; - } - - -// -// LLQ Support Routines -// - -// Set fields of an LLQ Opt Resource Record -mDNSlocal void FormatLLQOpt(AuthRecord *opt, int opcode, mDNSu8 *id, mDNSs32 lease) - { - bzero(opt, sizeof(*opt)); - mDNS_SetupResourceRecord(opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL); - opt->resrec.rdlength = LLQ_OPT_RDLEN; - opt->resrec.rdestimate = LLQ_OPT_RDLEN; - opt->resrec.rdata->u.opt.opt = kDNSOpt_LLQ; - opt->resrec.rdata->u.opt.optlen = sizeof(LLQOptData); - opt->resrec.rdata->u.opt.OptData.llq.vers = kLLQ_Vers; - opt->resrec.rdata->u.opt.OptData.llq.llqOp = opcode; - opt->resrec.rdata->u.opt.OptData.llq.err = LLQErr_NoError; - memcpy(opt->resrec.rdata->u.opt.OptData.llq.id, id, 8); - opt->resrec.rdata->u.opt.OptData.llq.lease = lease; - } - -// Calculate effective remaining lease of an LLQ -mDNSlocal mDNSu32 LLQLease(LLQEntry *e) - { - struct timeval t; - - gettimeofday(&t, NULL); - if (e->expire < t.tv_sec) return 0; - else return e->expire - t.tv_sec; - } - -mDNSlocal void DeleteLLQ(DaemonInfo *d, LLQEntry *e) - { - int bucket = DomainNameHashValue(&e->qname) % LLQ_TABLESIZE; - LLQEntry **ptr = &d->LLQTable[bucket]; - AnswerListElem *a = e->AnswerList; - char addr[32]; - - inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32); - VLog("Deleting LLQ table entry for %##s client %s", e->qname.c, addr); - - // free shared answer structure if ref count drops to zero - if (a && !(--a->refcount)) - { - CacheRecord *cr = a->KnownAnswers, *tmp; - AnswerListElem **tbl = &d->AnswerTable[bucket]; - - while (cr) - { - tmp = cr; - cr = cr->next; - free(tmp); - } - - while (*tbl && *tbl != a) tbl = &(*tbl)->next; - if (*tbl) { *tbl = (*tbl)->next; free(a); } - else Log("Error: DeleteLLQ - AnswerList not found in table"); - } - - // remove LLQ from table, free memory - while(*ptr && *ptr != e) ptr = &(*ptr)->next; - if (!*ptr) { Log("Error: DeleteLLQ - LLQ not in table"); return; } - *ptr = (*ptr)->next; - free(e); - } - -mDNSlocal int SendLLQ(DaemonInfo *d, PktMsg *pkt, struct sockaddr_in dst) - { - char addr[32]; - int err = -1; - - HdrHToN(pkt); - if (sendto(d->udpsd, &pkt->msg, pkt->len, 0, (struct sockaddr *)&dst, sizeof(dst)) != (int)pkt->len) - { - LogErr("DaemonInfo", "sendto"); - Log("Could not send response to client %s", inet_ntop(AF_INET, &dst.sin_addr, addr, 32)); - } - else err = 0; - HdrNToH(pkt); - return err; - } - -// if non-negative, sd is a TCP socket connected to the nameserver -// otherwise, this routine creates and closes its own socket -mDNSlocal CacheRecord *AnswerQuestion(DaemonInfo *d, AnswerListElem *e, int sd) - { - PktMsg q; - int i; - const mDNSu8 *ansptr; - mDNSu8 *end = q.msg.data; - mDNSOpaque16 id, flags = QueryFlags; - PktMsg *reply = NULL; - LargeCacheRecord lcr; - CacheRecord *AnswerList = NULL; - mDNSu8 rcode; - mDNSBool CloseSDOnExit = sd < 0; - - VLog("Querying server for %##s type %d", e->name.c, e->type); - - flags.b[0] |= kDNSFlag0_RD; // recursion desired - id.NotAnInteger = 0; - InitializeDNSMessage(&q.msg.h, id, flags); - - end = putQuestion(&q.msg, end, end + AbsoluteMaxDNSMessageData, &e->name, e->type, kDNSClass_IN); - if (!end) { Log("Error: AnswerQuestion - putQuestion returned NULL"); goto end; } - q.len = (int)(end - (mDNSu8 *)&q.msg); - - if (sd < 0) sd = ConnectToServer(d); - if (sd < 0) { Log("AnswerQuestion: ConnectToServer failed"); goto end; } - if (SendTCPMsg(sd, &q)) { Log("AnswerQuestion: SendTCPMsg failed"); close(sd); goto end; } - reply = ReadTCPMsg(sd, NULL); - - if ((reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery)) - { Log("AnswerQuestion: %##s type %d - Invalid response flags from server"); goto end; } - rcode = (mDNSu8)(reply->msg.h.flags.b[1] & kDNSFlag1_RC); - if (rcode && rcode != kDNSFlag1_RC_NXDomain) { Log("AnswerQuestion: %##s type %d - non-zero rcode %d from server", e->name.c, e->type, rcode); goto end; } - - end = (mDNSu8 *)&reply->msg + reply->len; - ansptr = LocateAnswers(&reply->msg, end); - if (!ansptr) { Log("Error: AnswerQuestion - LocateAnswers returned NULL"); goto end; } - - for (i = 0; i < reply->msg.h.numAnswers; i++) - { - ansptr = GetLargeResourceRecord(NULL, &reply->msg, ansptr, end, 0, kDNSRecordTypePacketAns, &lcr); - if (!ansptr) { Log("AnswerQuestions: GetLargeResourceRecord returned NULL"); goto end; } - if (lcr.r.resrec.rrtype != e->type || lcr.r.resrec.rrclass != kDNSClass_IN || !SameDomainName(lcr.r.resrec.name, &e->name)) - { - Log("AnswerQuestion: response %##s type #d does not answer question %##s type #d. Discarding", - lcr.r.resrec.name->c, lcr.r.resrec.rrtype, e->name.c, e->type); - } - else - { - CacheRecord *cr = CopyCacheRecord(&lcr.r, &e->name); - if (!cr) { Log("Error: AnswerQuestion - CopyCacheRecord returned NULL"); goto end; } - cr->next = AnswerList; - AnswerList = cr; - } - } - - end: - if (sd > -1 && CloseSDOnExit) close(sd); - if (reply) free(reply); - return AnswerList; - } - -// Routine sets EventList to contain Add/Remove events, and deletes any removes from the KnownAnswer list -mDNSlocal void UpdateAnswerList(DaemonInfo *d, AnswerListElem *a, int sd) - { - CacheRecord *cr, *NewAnswers, **na, **ka; // "new answer", "known answer" - - // get up to date answers - NewAnswers = AnswerQuestion(d, a, sd); - - // first pass - mark all answers for deletion - for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next) - (*ka)->resrec.rroriginalttl = (unsigned)-1; // -1 means delete - - // second pass - mark answers pre-existent - for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next) - { - for (na = &NewAnswers; *na; na = &(*na)->next) - { - if (SameResourceRecord(&(*ka)->resrec, &(*na)->resrec)) - { (*ka)->resrec.rroriginalttl = 0; break; } // 0 means no change - } - } - - // third pass - add new records to Event list - na = &NewAnswers; - while (*na) - { - for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next) - if (SameResourceRecord(&(*ka)->resrec, &(*na)->resrec)) break; - if (!*ka) - { - // answer is not in list - splice from NewAnswers list, add to Event list - cr = *na; - *na = (*na)->next; // splice from list - cr->next = a->EventList; // add spliced record to event list - a->EventList = cr; - cr->resrec.rroriginalttl = 1; // 1 means add - } - else na = &(*na)->next; - } - - // move all the removes from the answer list to the event list - ka = &a->KnownAnswers; - while (*ka) - { - if ((*ka)->resrec.rroriginalttl == (unsigned)-1) - { - cr = *ka; - *ka = (*ka)->next; - cr->next = a->EventList; - a->EventList = cr; - } - else ka = &(*ka)->next; - } - - // lastly, free the remaining records (known answers) in NewAnswers list - while (NewAnswers) - { - cr = NewAnswers; - NewAnswers = NewAnswers->next; - free(cr); - } - } - -mDNSlocal void SendEvents(DaemonInfo *d, LLQEntry *e) - { - PktMsg response; - CacheRecord *cr; - mDNSu8 *end = (mDNSu8 *)&response.msg.data; - mDNSOpaque16 msgID; - char rrbuf[80], addrbuf[32]; - AuthRecord opt; - - msgID.NotAnInteger = random(); - if (verbose) inet_ntop(AF_INET, &e->cli.sin_addr, addrbuf, 32); - InitializeDNSMessage(&response.msg.h, msgID, ResponseFlags); - end = putQuestion(&response.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN); - if (!end) { Log("Error: SendEvents - putQuestion returned NULL"); return; } - - // put adds/removes in packet - for (cr = e->AnswerList->EventList; cr; cr = cr->next) - { - if (verbose) GetRRDisplayString_rdb(&cr->resrec, &cr->resrec.rdata->u, rrbuf); - VLog("%s (%s): %s", addrbuf, (mDNSs32)cr->resrec.rroriginalttl < 0 ? "Remove": "Add", rrbuf); - end = PutResourceRecordTTLJumbo(&response.msg, end, &response.msg.h.numAnswers, &cr->resrec, cr->resrec.rroriginalttl); - if (!end) { Log("Error: SendEvents - UpdateAnswerList returned NULL"); return; } - } - - FormatLLQOpt(&opt, kLLQOp_Event, e->id, LLQLease(e)); - end = PutResourceRecordTTLJumbo(&response.msg, end, &response.msg.h.numAdditionals, &opt.resrec, 0); - if (!end) { Log("Error: SendEvents - PutResourceRecordTTLJumbo"); return; } - - response.len = (int)(end - (mDNSu8 *)&response.msg); - if (SendLLQ(d, &response, e->cli) < 0) LogMsg("Error: SendEvents - SendLLQ"); - } - -mDNSlocal void PrintLLQTable(DaemonInfo *d) - { - LLQEntry *e; - char addr[32]; - int i; - - Log("Printing LLQ table contents"); - - for (i = 0; i < LLQ_TABLESIZE; i++) - { - e = d->LLQTable[i]; - while(e) - { - inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32); - Log("LLQ from %##s type %d lease %d (%d remaining)", - addr, e->qname.c, e->qtype, e->lease, LLQLease(e)); - e = e->next; - } - } - } - -// Send events to clients as a result of a change in the zone -mDNSlocal void GenLLQEvents(DaemonInfo *d) - { - LLQEntry **e; - int i, sd; - struct timeval t; - - VLog("Generating LLQ Events"); - - gettimeofday(&t, NULL); - sd = ConnectToServer(d); - if (sd < 0) { Log("GenLLQEvents: ConnectToServer failed"); return; } - - // get all answers up to date - for (i = 0; i < LLQ_TABLESIZE; i++) - { - AnswerListElem *a = d->AnswerTable[i]; - while(a) - { - UpdateAnswerList(d, a, sd); - a = a->next; - } - } - - // for each established LLQ, send events - for (i = 0; i < LLQ_TABLESIZE; i++) - { - e = &d->LLQTable[i]; - while(*e) - { - if ((*e)->expire < t.tv_sec) DeleteLLQ(d, *e); - else - { - if ((*e)->state == Established && (*e)->AnswerList->EventList) SendEvents(d, *e); - e = &(*e)->next; - } - } - } - - // now that all LLQs are updated, we move Add events from the Event list to the Known Answer list, and free Removes - for (i = 0; i < LLQ_TABLESIZE; i++) - { - AnswerListElem *a = d->AnswerTable[i]; - while(a) - { - if (a->EventList) - { - CacheRecord *cr = a->EventList, *tmp; - while (cr) - { - tmp = cr; - cr = cr->next; - if ((signed)tmp->resrec.rroriginalttl < 0) free(tmp); - else - { - tmp->next = a->KnownAnswers; - a->KnownAnswers = tmp; - tmp->resrec.rroriginalttl = 0; - } - } - a->EventList = NULL; - } - a = a->next; - } - } - - close(sd); - } - -// Monitor zone for changes that may produce LLQ events -mDNSlocal void *LLQEventMonitor(void *DInfoPtr) - { - DaemonInfo *d = DInfoPtr; - PktMsg q; - mDNSu8 *end = q.msg.data; - const mDNSu8 *ptr; - mDNSOpaque16 id, flags = QueryFlags; - PktMsg reply; - mDNSs32 serial = 0; - mDNSBool SerialInitialized = mDNSfalse; - int sd; - LargeCacheRecord lcr; - ResourceRecord *rr = &lcr.r.resrec; - int i, sleeptime = 0; - domainname zone; - char pingmsg[4]; - - // create question - id.NotAnInteger = 0; - InitializeDNSMessage(&q.msg.h, id, flags); - AssignDomainName(&zone, &d->zone); - end = putQuestion(&q.msg, end, end + AbsoluteMaxDNSMessageData, &zone, kDNSType_SOA, kDNSClass_IN); - if (!end) { Log("Error: LLQEventMonitor - putQuestion returned NULL"); return NULL; } - q.len = (int)(end - (mDNSu8 *)&q.msg); - - sd = ConnectToServer(d); - if (sd < 0) { Log("LLQEventMonitor: ConnectToServer failed"); return NULL; } - - while(1) - { - usleep(sleeptime); - sleeptime = LLQ_MONITOR_ERR_INTERVAL; // if we bail on error below, rate limit retry - - // send message, receive response - if (SendTCPMsg(sd, &q)) { Log("LLQEventMonitor: SendTCPMsg failed"); continue; } - if (!ReadTCPMsg(sd, &reply)) { Log("LLQEventMonitor: ReadTCPMsg failed"); continue; } - end = (mDNSu8 *)&reply.msg + reply.len; - if (reply.msg.h.flags.b[1] & kDNSFlag1_RC) { Log("LLQEventMonitor - received non-zero rcode"); continue; } - - // find answer - ptr = LocateAnswers(&reply.msg, end); - if (!ptr) { Log("Error: LLQEventMonitor - LocateAnswers returned NULL"); continue; } - for (i = 0; i < reply.msg.h.numAnswers; i++) - { - ptr = GetLargeResourceRecord(NULL, &reply.msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr); - if (!ptr) { Log("Error: LLQEventMonitor - GetLargeResourceRecord returned NULL"); continue; } - if (rr->rrtype != kDNSType_SOA || rr->rrclass != kDNSClass_IN || !SameDomainName(rr->name, &zone)) continue; - if (!SerialInitialized) - { - // first time through loop - SerialInitialized = mDNStrue; - serial = rr->rdata->u.soa.serial; - sleeptime = LLQ_MONITOR_INTERVAL; - break; - } - else if (rr->rdata->u.soa.serial != serial) - { - // update serial, wake main thread - serial = rr->rdata->u.soa.serial; - VLog("LLQEventMonitor: zone changed. Signaling main thread."); - if (send(d->LLQServPollSock, pingmsg, sizeof(pingmsg), 0) != sizeof(pingmsg)) - { LogErr("LLQEventMonitor", "send"); break; } - } - sleeptime = LLQ_MONITOR_INTERVAL; - break; - } - if (!ptr) Log("LLQEventMonitor: response to query did not contain SOA"); - } - } - -mDNSlocal void SetAnswerList(DaemonInfo *d, LLQEntry *e) - { - int bucket = DomainNameHashValue(&e->qname) % LLQ_TABLESIZE; - AnswerListElem *a = d->AnswerTable[bucket]; - while (a && (a->type != e->qtype ||!SameDomainName(&a->name, &e->qname))) a = a->next; - if (!a) - { - a = malloc(sizeof(*a)); - if (!a) { LogErr("SetAnswerList", "malloc"); return; } - AssignDomainName(&a->name, &e->qname); - a->type = e->qtype; - a->refcount = 0; - a->KnownAnswers = NULL; - a->EventList = NULL; - a->next = d->AnswerTable[bucket]; - d->AnswerTable[bucket] = a; - - // to get initial answer list, call UpdateAnswerList and move cache records from EventList to KnownAnswers - UpdateAnswerList(d, a, -1); - a->KnownAnswers = a->EventList; - a->EventList = NULL; - } - - e->AnswerList = a; - a->refcount ++; - } - - // Allocate LLQ entry, insert into table -mDNSlocal LLQEntry *NewLLQ(DaemonInfo *d, struct sockaddr_in cli, domainname *qname, mDNSu16 qtype, mDNSu32 lease) - { - char addr[32]; - struct timeval t; - int bucket = DomainNameHashValue(qname) % LLQ_TABLESIZE; - LLQEntry *e; - - e = malloc(sizeof(*e)); - if (!e) { LogErr("NewLLQ", "malloc"); return NULL; } - - inet_ntop(AF_INET, &cli.sin_addr, addr, 32); - VLog("Allocating LLQ entry for client %s question %##s type %d", addr, qname->c, qtype); - - // initialize structure - e->cli = cli; - AssignDomainName(&e->qname, qname); - e->qtype = qtype; - memset(e->id, 0, 8); - e->state = RequestReceived; - e->AnswerList = NULL; - - if (lease < LLQ_MIN_LEASE) lease = LLQ_MIN_LEASE; - else if (lease > LLQ_MAX_LEASE) lease = LLQ_MIN_LEASE; - gettimeofday(&t, NULL); - e->expire = t.tv_sec + (int)lease; - e->lease = lease; - - // add to table - e->next = d->LLQTable[bucket]; - d->LLQTable[bucket] = e; - - return e; - } - -// Handle a refresh request from client -mDNSlocal void LLQRefresh(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID) - { - AuthRecord opt; - PktMsg ack; - mDNSu8 *end = (mDNSu8 *)&ack.msg.data; - char addr[32]; - - inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32); - VLog("%s LLQ for %##s from %s", llq->lease ? "Refreshing" : "Deleting", e->qname.c, addr); - - if (llq->lease) - { - if (llq->lease < LLQ_MIN_LEASE) llq->lease = LLQ_MIN_LEASE; - else if (llq->lease > LLQ_MAX_LEASE) llq->lease = LLQ_MIN_LEASE; - } - - ack.src.sin_addr.s_addr = 0; // unused - InitializeDNSMessage(&ack.msg.h, msgID, ResponseFlags); - end = putQuestion(&ack.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN); - if (!end) { Log("Error: putQuestion"); return; } - - FormatLLQOpt(&opt, kLLQOp_Refresh, e->id, llq->lease ? LLQLease(e) : 0); - end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAdditionals, &opt.resrec, 0); - if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; } - - ack.len = (int)(end - (mDNSu8 *)&ack.msg); - if (SendLLQ(d, &ack, e->cli)) Log("Error: LLQRefresh"); - - if (llq->lease) e->state = Established; - else DeleteLLQ(d, e); - } - -// Complete handshake with Ack an initial answers -mDNSlocal void LLQCompleteHandshake(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID) - { - char addr[32]; - CacheRecord *ptr; - AuthRecord opt; - PktMsg ack; - mDNSu8 *end = (mDNSu8 *)&ack.msg.data; - char rrbuf[80], addrbuf[32]; - - inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32); - - if (memcmp(llq->id, e->id, 8) || - llq->vers != kLLQ_Vers || - llq->llqOp != kLLQOp_Setup || - llq->err != LLQErr_NoError || - llq->lease > e->lease + LLQ_LEASE_FUDGE || - llq->lease < e->lease - LLQ_LEASE_FUDGE) - { Log("Incorrect challenge response from %s", addr); return; } - - if (e->state == Established) VLog("Retransmitting LLQ ack + answers for %##s", e->qname.c); - else VLog("Delivering LLQ ack + answers for %##s", e->qname.c); - - // format ack + answers - ack.src.sin_addr.s_addr = 0; // unused - InitializeDNSMessage(&ack.msg.h, msgID, ResponseFlags); - end = putQuestion(&ack.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN); - if (!end) { Log("Error: putQuestion"); return; } - - if (e->state != Established) { SetAnswerList(d, e); e->state = Established; } - - if (verbose) inet_ntop(AF_INET, &e->cli.sin_addr, addrbuf, 32); - for (ptr = e->AnswerList->KnownAnswers; ptr; ptr = ptr->next) - { - if (verbose) GetRRDisplayString_rdb(&ptr->resrec, &ptr->resrec.rdata->u, rrbuf); - VLog("%s Intitial Answer - %s", addr, rrbuf); - end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAnswers, &ptr->resrec, 1); - if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; } - } - - FormatLLQOpt(&opt, kLLQOp_Setup, e->id, LLQLease(e)); - end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAdditionals, &opt.resrec, 0); - if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; } - - ack.len = (int)(end - (mDNSu8 *)&ack.msg); - if (SendLLQ(d, &ack, e->cli)) Log("Error: LLQCompleteHandshake"); - } - -mDNSlocal void LLQSetupChallenge(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID) - { - struct timeval t; - mDNSu32 randval; - PktMsg challenge; - mDNSu8 *end = challenge.msg.data; - AuthRecord opt; - - if (e->state == ChallengeSent) VLog("Retransmitting LLQ setup challenge for %##s", e->qname.c); - else VLog("Sending LLQ setup challenge for %##s", e->qname.c); - - if (!ZERO_LLQID(llq->id)) { Log("Error: LLQSetupChallenge - nonzero ID"); return; } // server bug - if (llq->llqOp != kLLQOp_Setup) { Log("LLQSetupChallenge - incorrrect operation from client"); return; } // client error - - if (ZERO_LLQID(e->id)) // don't regenerate random ID for retransmissions - { - // construct ID