From 32bb7e43b766b4cf6c03ab11609bf9c164e40239 Mon Sep 17 00:00:00 2001 From: Apple Date: Thu, 23 Jul 2009 23:54:29 +0000 Subject: [PATCH] mDNSResponder-212.1.tar.gz --- ...ingResolveListener.java => ClientCommon.c} | 96 +- Clients/ClientCommon.h | 49 + Clients/DNS-SD.VisualStudio/DNS-SD.manifest | 12 + Clients/DNS-SD.VisualStudio/DNS-SD64.manifest | 12 + Clients/DNS-SD.VisualStudio/dns-sd.vcproj | 372 +- Clients/DNS-SD.xcodeproj/project.pbxproj | 6 +- .../DNSServiceBrowser.NET.csproj | 233 +- .../DNSServiceBrowser.cs | 312 +- .../DNSServiceBrowser.Designer.vb | 206 + .../DNSServiceBrowser.VB.vbproj | 116 + .../DNSServiceBrowser.resx | 120 + .../DNSServiceBrowser.VB/DNSServiceBrowser.vb | 111 + .../My Project/Application.Designer.vb | 38 + .../My Project/Application.myapp | 10 + .../My Project/AssemblyInfo.vb | 35 + .../My Project/Resources.Designer.vb | 62 + .../My Project/Resources.resx | 117 + .../My Project/Settings.Designer.vb | 73 + .../My Project/Settings.settings | 7 + Clients/ExplorerPlugin/About.cpp | 9 + Clients/ExplorerPlugin/ExplorerBar.cpp | 6 +- Clients/ExplorerPlugin/ExplorerBar.h | 6 +- Clients/ExplorerPlugin/ExplorerBarWindow.cpp | 12 +- Clients/ExplorerPlugin/ExplorerBarWindow.h | 6 +- Clients/ExplorerPlugin/ExplorerPlugin.cpp | 268 +- Clients/ExplorerPlugin/ExplorerPlugin.h | 21 + Clients/ExplorerPlugin/ExplorerPlugin.vcproj | 542 ++- .../ExplorerPlugin/ExplorerPluginLocRes.rc | 8 +- .../ExplorerPluginLocRes.vcproj | 450 +- .../ExplorerPlugin/ExplorerPluginRes.vcproj | 471 ++- .../res/ExplorerPlugin.manifest | 22 + .../res/ExplorerPlugin64.manifest | 22 + Clients/ExplorerPlugin/resource_dll.h | 1 + Clients/ExplorerPlugin/resource_loc_res.h | 1 + Clients/ExplorerPlugin/resource_res.h | 1 + Clients/Java/BrowserApp.java | 31 +- Clients/Java/JavaSamples.vcproj | 83 +- Clients/Java/nmakefile | 15 +- Clients/Makefile | 7 +- Clients/PrinterSetupWizard/Logger.cpp | 98 + Clients/PrinterSetupWizard/Logger.h | 71 + .../PrinterSetupWizard/PrinterSetupWizard.rc | 7 - .../PrinterSetupWizard.vcproj | 564 ++- .../PrinterSetupWizardApp.cpp | 10 + .../PrinterSetupWizardLocRes.rc | 6 +- .../PrinterSetupWizardLocRes.vcproj | 405 +- .../PrinterSetupWizardRes.vcproj | 432 +- .../PrinterSetupWizardSheet.cpp | 94 +- .../PrinterSetupWizardSheet.h | 16 +- Clients/PrinterSetupWizard/SecondPage.cpp | 29 +- Clients/PrinterSetupWizard/ThirdPage.cpp | 493 +-- Clients/PrinterSetupWizard/ThirdPage.h | 8 + Clients/PrinterSetupWizard/UtilTypes.h | 10 +- .../res/PrinterSetupWizard.manifest | 33 +- .../res/PrinterSetupWizard64.manifest | 17 + Clients/PrinterSetupWizard/resource_exe.h | 5 +- Clients/PrinterSetupWizard/resource_loc_res.h | 3 +- Clients/PrinterSetupWizard/resource_res.h | 5 +- Clients/SimpleChat.NET/SimpleChat.NET.csproj | 229 +- Clients/SimpleChat.NET/SimpleChat.cs | 759 ++-- Clients/SimpleChat.NET/SimpleChat.resx | 2 +- .../My Project/Application.Designer.vb | 38 + .../My Project/Application.myapp | 10 + .../SimpleChat.VB/My Project/AssemblyInfo.vb | 35 + .../My Project/Resources.Designer.vb | 62 + .../SimpleChat.VB/My Project/Resources.resx | 117 + .../My Project/Settings.Designer.vb | 73 + .../My Project/Settings.settings | 7 + Clients/SimpleChat.VB/SimpleChat.Designer.vb | 102 + Clients/SimpleChat.VB/SimpleChat.VB.vbproj | 116 + Clients/SimpleChat.VB/SimpleChat.resx | 120 + Clients/SimpleChat.VB/SimpleChat.vb | 121 + Clients/dns-sd.c | 230 +- Makefile | 2 +- PrivateDNS.txt | 2 +- buildResults.xml | 50 - mDNSCore/DNSCommon.c | 1283 +++--- mDNSCore/DNSCommon.h | 86 +- mDNSCore/DNSDigest.c | 5 +- mDNSCore/mDNS.c | 3608 ++++++++++++++--- mDNSCore/mDNSDebug.h | 159 +- mDNSCore/mDNSEmbeddedAPI.h | 1027 ++++- mDNSCore/uDNS.c | 906 +++-- mDNSCore/uDNS.h | 6 +- mDNSMacOS9/Mac OS Test Responder.c | 5 +- mDNSMacOS9/Mac OS Test Searcher.c | 5 +- mDNSMacOSX/DNSServiceDiscovery.c | 4 +- mDNSMacOSX/LaunchDaemonInfo.dnsextd.plist | 2 - mDNSMacOSX/LaunchDaemonInfo.helper.plist | 4 +- mDNSMacOSX/LaunchDaemonInfo.plist | 4 +- mDNSMacOSX/LegacyNATTraversal.c | 600 ++- .../PreferencePane/ConfigurationAuthority.c | 5 +- .../PreferencePane/DNSServiceDiscoveryPref.m | 68 +- .../PreferencePane/PrivilegedOperations.c | 5 +- mDNSMacOSX/PreferencePane/ddnswriteconfig.m | 27 +- mDNSMacOSX/SamplemDNSClient.c | 16 +- mDNSMacOSX/daemon.c | 823 +++- mDNSMacOSX/helper-main.c | 139 +- mDNSMacOSX/helper-server.h | 6 + mDNSMacOSX/helper-stubs.c | 253 +- mDNSMacOSX/helper.c | 875 +++- mDNSMacOSX/helper.h | 65 +- mDNSMacOSX/helpermsg-types.h | 8 +- mDNSMacOSX/helpermsg.defs | 161 +- mDNSMacOSX/mDNSMacOSX.c | 2747 ++++++++++--- mDNSMacOSX/mDNSMacOSX.h | 128 +- mDNSMacOSX/mDNSResponder.order | 682 ++-- mDNSMacOSX/mDNSResponder.sb | 103 +- .../mDNSResponder.xcodeproj/project.pbxproj | 245 +- mDNSMacOSX/safe_vproc.c | 92 + mDNSMacOSX/safe_vproc.h | 31 + mDNSPosix/Client.c | 5 +- mDNSPosix/Identify.c | 60 +- mDNSPosix/Makefile | 73 +- mDNSPosix/NetMonitor.c | 37 +- mDNSPosix/PosixDaemon.c | 37 +- mDNSPosix/ProxyResponder.c | 5 +- mDNSPosix/Responder.c | 22 +- mDNSPosix/mDNSPosix.c | 40 +- mDNSPosix/mDNSUNP.c | 22 +- mDNSPosix/nss_mdns.c | 6 +- mDNSResponder.sln | 235 +- mDNSShared/CommonServices.h | 46 +- mDNSShared/Java/DNSSD.java | 5 +- mDNSShared/PlatformCommon.c | 56 +- mDNSShared/dns_sd.h | 191 +- mDNSShared/dnsextd.c | 97 +- mDNSShared/dnsextd_lexer.l | 9 +- mDNSShared/dnsextd_parser.y | 7 +- mDNSShared/dnssd_clientlib.c | 91 +- mDNSShared/dnssd_clientstub.c | 354 +- mDNSShared/dnssd_ipc.c | 45 +- mDNSShared/dnssd_ipc.h | 33 +- mDNSShared/mDNSDebug.c | 89 +- mDNSShared/mDNSResponder.8 | 55 +- mDNSShared/uds_daemon.c | 1388 +++++-- mDNSShared/uds_daemon.h | 13 +- mDNSVxWorks/mDNSVxWorks.c | 16 +- mDNSVxWorks/mDNSVxWorksIPv4Only.c | 26 +- .../ControlPanel/ConfigPropertySheet.cpp | 12 +- .../ControlPanel/ConfigPropertySheet.h | 16 +- mDNSWindows/ControlPanel/ControlPanel.cpp | 6 +- mDNSWindows/ControlPanel/ControlPanel.rc | 10 + mDNSWindows/ControlPanel/ControlPanel.vcproj | 715 +++- mDNSWindows/ControlPanel/ControlPanelDll.rc | 9 - mDNSWindows/ControlPanel/ControlPanelExe.rc | 9 - .../ControlPanel/ControlPanelExe.vcproj | 664 ++- mDNSWindows/ControlPanel/FirstPage.cpp | 5 +- mDNSWindows/ControlPanel/FourthPage.cpp | 191 + mDNSWindows/ControlPanel/FourthPage.h | 93 + mDNSWindows/ControlPanel/SharedSecret.cpp | 146 +- mDNSWindows/ControlPanel/SharedSecret.h | 6 + .../ControlPanel/res/ControlPanel.manifest | 17 + .../ControlPanel/res/ControlPanel64.manifest | 17 + mDNSWindows/ControlPanel/resource.h | 4 +- mDNSWindows/DLL.NET/AssemblyInfo.cpp | 15 +- mDNSWindows/DLL.NET/Stdafx.h | 7 + mDNSWindows/DLL.NET/dnssd_NET.cpp | 6 +- mDNSWindows/DLL.NET/dnssd_NET.vcproj | 415 +- mDNSWindows/DLL/dnssd.def | 4 + mDNSWindows/DLL/dnssd.vcproj | 409 +- mDNSWindows/DLLStub/DLLStub.cpp | 693 ++++ mDNSWindows/DLLStub/DLLStub.h | 52 + mDNSWindows/DLLStub/DLLStub.vcproj | 318 ++ mDNSWindows/DLLX/DLLX.cpp | 120 + mDNSWindows/DLLX/DLLX.def | 33 + mDNSWindows/DLLX/DLLX.idl | 309 ++ mDNSWindows/DLLX/DLLX.rc | 126 + mDNSWindows/DLLX/DLLX.rgs | 11 + mDNSWindows/DLLX/DLLX.vcproj | 623 +++ mDNSWindows/DLLX/DNSSD.cpp | 892 ++++ mDNSWindows/DLLX/DNSSDEventManager.cpp | 31 + mDNSWindows/DLLX/DNSSDEventManager.h | 82 + mDNSWindows/DLLX/DNSSDEventManager.rgs | 27 + mDNSWindows/DLLX/DNSSDRecord.cpp | 66 + mDNSWindows/DLLX/DNSSDRecord.h | 108 + mDNSWindows/DLLX/DNSSDRecord.rgs | 27 + mDNSWindows/DLLX/DNSSDService.cpp | 1106 +++++ mDNSWindows/DLLX/DNSSDService.h | 273 ++ mDNSWindows/DLLX/DNSSDService.rgs | 27 + mDNSWindows/DLLX/StringServices.cpp | 196 + mDNSWindows/DLLX/StringServices.h | 67 + mDNSWindows/DLLX/TXTRecord.cpp | 206 + mDNSWindows/DLLX/TXTRecord.h | 117 + mDNSWindows/DLLX/TXTRecord.rgs | 27 + mDNSWindows/DLLX/_IDNSSDEvents_CP.h | 358 ++ mDNSWindows/DLLX/dlldatax.c | 41 + mDNSWindows/DLLX/dlldatax.h | 40 + mDNSWindows/DLLX/resource.h | 30 + mDNSWindows/DLLX/stdafx.h | 60 + .../Windows/Sources/AboutDialog.cpp | 7 +- .../Windows/Sources/AboutDialog.h | 5 +- .../Windows/Sources/ChooserDialog.cpp | 5 +- .../WindowsCE/Sources/BrowserDialog.cpp | 5 +- mDNSWindows/Java/Java.vcproj | 83 +- mDNSWindows/Java/makefile | 21 +- mDNSWindows/NSPTool/NSPTool.vcproj | 365 +- mDNSWindows/RegNames.h | 13 +- mDNSWindows/Secret.c | 348 ++ mDNSWindows/Secret.h | 53 + mDNSWindows/SystemService/Firewall.cpp | 153 +- mDNSWindows/SystemService/Firewall.h | 7 + mDNSWindows/SystemService/Service.c | 402 +- mDNSWindows/SystemService/Service.vcproj | 450 +- .../SystemService/res/mDNSResponder.manifest | 12 + .../res/mDNSResponder64.manifest | 12 + mDNSWindows/WinServices.cpp | 30 + mDNSWindows/WinServices.h | 6 +- mDNSWindows/WinVersRes.h | 28 +- mDNSWindows/isocode.h | 4 +- mDNSWindows/mDNSWin32.c | 1591 +++++--- mDNSWindows/mDNSWin32.h | 44 +- mDNSWindows/mdnsNSP/mdnsNSP.c | 54 +- mDNSWindows/mdnsNSP/mdnsNSP.vcproj | 414 +- 214 files changed, 30328 insertions(+), 8222 deletions(-) rename Clients/{Java/SwingResolveListener.java => ClientCommon.c} (58%) create mode 100644 Clients/ClientCommon.h create mode 100644 Clients/DNS-SD.VisualStudio/DNS-SD.manifest create mode 100644 Clients/DNS-SD.VisualStudio/DNS-SD64.manifest create mode 100644 Clients/DNSServiceBrowser.VB/DNSServiceBrowser.Designer.vb create mode 100644 Clients/DNSServiceBrowser.VB/DNSServiceBrowser.VB.vbproj create mode 100644 Clients/DNSServiceBrowser.VB/DNSServiceBrowser.resx create mode 100644 Clients/DNSServiceBrowser.VB/DNSServiceBrowser.vb create mode 100644 Clients/DNSServiceBrowser.VB/My Project/Application.Designer.vb create mode 100644 Clients/DNSServiceBrowser.VB/My Project/Application.myapp create mode 100644 Clients/DNSServiceBrowser.VB/My Project/AssemblyInfo.vb create mode 100644 Clients/DNSServiceBrowser.VB/My Project/Resources.Designer.vb create mode 100644 Clients/DNSServiceBrowser.VB/My Project/Resources.resx create mode 100644 Clients/DNSServiceBrowser.VB/My Project/Settings.Designer.vb create mode 100644 Clients/DNSServiceBrowser.VB/My Project/Settings.settings create mode 100644 Clients/ExplorerPlugin/res/ExplorerPlugin.manifest create mode 100644 Clients/ExplorerPlugin/res/ExplorerPlugin64.manifest create mode 100644 Clients/PrinterSetupWizard/Logger.cpp create mode 100644 Clients/PrinterSetupWizard/Logger.h create mode 100644 Clients/PrinterSetupWizard/res/PrinterSetupWizard64.manifest create mode 100644 Clients/SimpleChat.VB/My Project/Application.Designer.vb create mode 100644 Clients/SimpleChat.VB/My Project/Application.myapp create mode 100644 Clients/SimpleChat.VB/My Project/AssemblyInfo.vb create mode 100644 Clients/SimpleChat.VB/My Project/Resources.Designer.vb create mode 100644 Clients/SimpleChat.VB/My Project/Resources.resx create mode 100644 Clients/SimpleChat.VB/My Project/Settings.Designer.vb create mode 100644 Clients/SimpleChat.VB/My Project/Settings.settings create mode 100644 Clients/SimpleChat.VB/SimpleChat.Designer.vb create mode 100644 Clients/SimpleChat.VB/SimpleChat.VB.vbproj create mode 100644 Clients/SimpleChat.VB/SimpleChat.resx create mode 100644 Clients/SimpleChat.VB/SimpleChat.vb delete mode 100644 buildResults.xml create mode 100644 mDNSMacOSX/safe_vproc.c create mode 100644 mDNSMacOSX/safe_vproc.h create mode 100755 mDNSWindows/ControlPanel/FourthPage.cpp create mode 100755 mDNSWindows/ControlPanel/FourthPage.h create mode 100644 mDNSWindows/ControlPanel/res/ControlPanel.manifest create mode 100644 mDNSWindows/ControlPanel/res/ControlPanel64.manifest create mode 100755 mDNSWindows/DLLStub/DLLStub.cpp create mode 100755 mDNSWindows/DLLStub/DLLStub.h create mode 100755 mDNSWindows/DLLStub/DLLStub.vcproj create mode 100755 mDNSWindows/DLLX/DLLX.cpp create mode 100755 mDNSWindows/DLLX/DLLX.def create mode 100755 mDNSWindows/DLLX/DLLX.idl create mode 100755 mDNSWindows/DLLX/DLLX.rc create mode 100755 mDNSWindows/DLLX/DLLX.rgs create mode 100755 mDNSWindows/DLLX/DLLX.vcproj create mode 100755 mDNSWindows/DLLX/DNSSD.cpp create mode 100755 mDNSWindows/DLLX/DNSSDEventManager.cpp create mode 100755 mDNSWindows/DLLX/DNSSDEventManager.h create mode 100755 mDNSWindows/DLLX/DNSSDEventManager.rgs create mode 100755 mDNSWindows/DLLX/DNSSDRecord.cpp create mode 100755 mDNSWindows/DLLX/DNSSDRecord.h create mode 100755 mDNSWindows/DLLX/DNSSDRecord.rgs create mode 100755 mDNSWindows/DLLX/DNSSDService.cpp create mode 100755 mDNSWindows/DLLX/DNSSDService.h create mode 100755 mDNSWindows/DLLX/DNSSDService.rgs create mode 100755 mDNSWindows/DLLX/StringServices.cpp create mode 100755 mDNSWindows/DLLX/StringServices.h create mode 100755 mDNSWindows/DLLX/TXTRecord.cpp create mode 100755 mDNSWindows/DLLX/TXTRecord.h create mode 100755 mDNSWindows/DLLX/TXTRecord.rgs create mode 100755 mDNSWindows/DLLX/_IDNSSDEvents_CP.h create mode 100755 mDNSWindows/DLLX/dlldatax.c create mode 100755 mDNSWindows/DLLX/dlldatax.h create mode 100755 mDNSWindows/DLLX/resource.h create mode 100755 mDNSWindows/DLLX/stdafx.h create mode 100644 mDNSWindows/Secret.c create mode 100644 mDNSWindows/Secret.h create mode 100644 mDNSWindows/SystemService/res/mDNSResponder.manifest create mode 100644 mDNSWindows/SystemService/res/mDNSResponder64.manifest diff --git a/Clients/Java/SwingResolveListener.java b/Clients/ClientCommon.c similarity index 58% rename from Clients/Java/SwingResolveListener.java rename to Clients/ClientCommon.c index 19c1799..f25fbb6 100644 --- a/Clients/Java/SwingResolveListener.java +++ b/Clients/ClientCommon.c @@ -1,6 +1,6 @@ -/* -*- Mode: Java; tab-width: 4 -*- +/* -*- Mode: C; tab-width: 4 -*- * - * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple 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 @@ -36,71 +36,51 @@ * OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT * (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ + Change History (most recent first): -import javax.swing.*; -import com.apple.dnssd.*; +$Log: ClientCommon.c,v $ +Revision 1.2 2008/05/08 00:42:03 cheshire +Removed some unnecessary header files +Revision 1.1 2008/05/08 00:25:48 cheshire + GetNextLabel insufficiently defensive -/** Use this to schedule ResolveListener callbacks via SwingUtilities.invokeAndWait(). */ -public class SwingResolveListener implements Runnable, ResolveListener -{ - /** Create a listener for DNSSD that will call your listener on the Swing/AWT event thread. */ - public SwingResolveListener( ResolveListener listener) - { fListener = listener; } +*/ - public void operationFailed( DNSSDService service, int errorCode) - { - fResolver = service; - fErrorCode = errorCode; - this.schedule(); - } +#include +#include // For stdout, stderr - /** (Clients should not call this method directly.) */ - public void serviceResolved( DNSSDService resolver, int flags, int ifIndex, String fullName, - String hostName, int port, TXTRecord txtRecord) - { - fResolver = resolver; - fFlags = flags; - fIndex = ifIndex; - fFullName = fullName; - fHostName = hostName; - fPort = port; - fTXTRecord = txtRecord; - this.schedule(); - } +#include "ClientCommon.h" - /** (Clients should not call this method directly.) */ - public void run() +const char *GetNextLabel(const char *cstr, char label[64]) { - if ( fErrorCode != 0) - fListener.operationFailed( fResolver, fErrorCode); - else - fListener.serviceResolved( fResolver, fFlags, fIndex, fFullName, fHostName, fPort, fTXTRecord); - } - - protected void schedule() - { - try { - SwingUtilities.invokeAndWait( this); - } - catch ( Exception e) + char *ptr = label; + while (*cstr && *cstr != '.') // While we have characters in the label... { - e.printStackTrace(); + char c = *cstr++; + if (c == '\\' && *cstr) // If we have a backslash, and it's not the last character of the string + { + c = *cstr++; + if (isdigit(cstr[-1]) && isdigit(cstr[0]) && isdigit(cstr[1])) + { + int v0 = cstr[-1] - '0'; // then interpret as three-digit decimal + int v1 = cstr[ 0] - '0'; + int v2 = cstr[ 1] - '0'; + int val = v0 * 100 + v1 * 10 + v2; + // If valid three-digit decimal value, use it + // Note that although ascii nuls are possible in DNS labels + // we're building a C string here so we have no way to represent that + if (val == 0) val = '-'; + if (val <= 255) { c = (char)val; cstr += 2; } + } + } + *ptr++ = c; + if (ptr >= label+64) { label[63] = 0; return(NULL); } // Illegal label more than 63 bytes } + *ptr = 0; // Null-terminate label text + if (ptr == label) return(NULL); // Illegal empty label + if (*cstr) cstr++; // Skip over the trailing dot (if present) + return(cstr); } - - protected ResolveListener fListener; - - protected DNSSDService fResolver; - protected int fFlags; - protected int fIndex; - protected int fErrorCode; - protected String fFullName; - protected String fHostName; - protected int fPort; - protected TXTRecord fTXTRecord; -} - diff --git a/Clients/ClientCommon.h b/Clients/ClientCommon.h new file mode 100644 index 0000000..5c28307 --- /dev/null +++ b/Clients/ClientCommon.h @@ -0,0 +1,49 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2008 Apple Inc. All rights reserved. + * + * Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. + * ("Apple") in consideration of your agreement to the following terms, and your + * use, installation, modification or redistribution of this Apple software + * constitutes acceptance of these terms. If you do not agree with these terms, + * please do not use, install, modify or redistribute this Apple software. + * + * In consideration of your agreement to abide by the following terms, and subject + * to these terms, Apple grants you a personal, non-exclusive license, under Apple's + * copyrights in this original Apple software (the "Apple Software"), to use, + * reproduce, modify and redistribute the Apple Software, with or without + * modifications, in source and/or binary forms; provided that if you redistribute + * the Apple Software in its entirety and without modifications, you must retain + * this notice and the following text and disclaimers in all such redistributions of + * the Apple Software. Neither the name, trademarks, service marks or logos of + * Apple Computer, Inc. may be used to endorse or promote products derived from the + * Apple Software without specific prior written permission from Apple. Except as + * expressly stated in this notice, no other rights or licenses, express or implied, + * are granted by Apple herein, including but not limited to any patent rights that + * may be infringed by your derivative works or by other works in which the Apple + * Software may be incorporated. + * + * The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO + * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED + * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN + * COMBINATION WITH YOUR PRODUCTS. + * + * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION + * OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT + * (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Change History (most recent first): + +$Log: ClientCommon.h,v $ +Revision 1.1 2008/05/08 00:25:48 cheshire + GetNextLabel insufficiently defensive + + +*/ + +extern const char *GetNextLabel(const char *cstr, char label[64]); diff --git a/Clients/DNS-SD.VisualStudio/DNS-SD.manifest b/Clients/DNS-SD.VisualStudio/DNS-SD.manifest new file mode 100644 index 0000000..9e0b08a --- /dev/null +++ b/Clients/DNS-SD.VisualStudio/DNS-SD.manifest @@ -0,0 +1,12 @@ + + + + Command line utility. + + + + + + + + diff --git a/Clients/DNS-SD.VisualStudio/DNS-SD64.manifest b/Clients/DNS-SD.VisualStudio/DNS-SD64.manifest new file mode 100644 index 0000000..caa49df --- /dev/null +++ b/Clients/DNS-SD.VisualStudio/DNS-SD64.manifest @@ -0,0 +1,12 @@ + + + + Command Line Utility + + + + + + + + diff --git a/Clients/DNS-SD.VisualStudio/dns-sd.vcproj b/Clients/DNS-SD.VisualStudio/dns-sd.vcproj index 4c3a515..db1a499 100755 --- a/Clients/DNS-SD.VisualStudio/dns-sd.vcproj +++ b/Clients/DNS-SD.VisualStudio/dns-sd.vcproj @@ -1,119 +1,367 @@ + Keyword="Win32Proj" + > + Name="Win32" + /> + + + + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" + CharacterSet="2" + > + + + + + + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + /> + Name="VCManagedResourceCompilerTool" + /> + + + TargetMachine="1" + /> + + + + + + + + + + + + Name="VCCustomBuildTool" + /> + Name="VCXMLDataGeneratorTool" + /> + Name="VCWebServiceProxyGeneratorTool" + /> + Name="VCMIDLTool" + TargetEnvironment="3" + /> + + + AdditionalIncludeDirectories="../../mDNSWindows" + /> + + + Name="VCALinkTool" + /> + Name="VCManifestTool" + AdditionalManifestFiles="DNS-SD64.manifest" + /> + Name="VCXDCMakeTool" + /> + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + + + + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" + CharacterSet="2" + > + + + + + + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + /> + + + Name="VCPreLinkEventTool" + /> + TargetMachine="1" + /> + Name="VCALinkTool" + /> + Name="VCManifestTool" + AdditionalManifestFiles="DNS-SD.manifest" + /> + Name="VCXDCMakeTool" + /> + Name="VCBscMakeTool" + /> + + + + + + + + + + + + + + AdditionalIncludeDirectories="../../mDNSWindows" + /> + + + + + Name="VCXDCMakeTool" + /> + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + Name="VCWebDeploymentTool" + /> + @@ -121,23 +369,37 @@ + Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm" + > + + + RelativePath="..\dns-sd.c" + > + Filter="h;hpp;hxx;hm;inl;inc" + > + + + RelativePath="resource.h" + > + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" + > + RelativePath="dns-sd.rc" + > diff --git a/Clients/DNS-SD.xcodeproj/project.pbxproj b/Clients/DNS-SD.xcodeproj/project.pbxproj index 6ed5d53..f2d54f0 100644 --- a/Clients/DNS-SD.xcodeproj/project.pbxproj +++ b/Clients/DNS-SD.xcodeproj/project.pbxproj @@ -27,6 +27,7 @@ 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 */; }; + FF2704F90F12A60900299571 /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF2704F80F12A60900299571 /* ClientCommon.c */; }; 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 */; }; @@ -70,12 +71,13 @@ /* 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; }; + 8DD76F7E0486A8DE00D96B5E /* dns-sd */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "compiled.mach-o.executable"; 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 = ""; }; + FF2704F80F12A60900299571 /* ClientCommon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ClientCommon.c; 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 = ""; }; @@ -123,6 +125,7 @@ isa = PBXGroup; children = ( 08FB7796FE84155DC02AAC07 /* dns-sd.c */, + FF2704F80F12A60900299571 /* ClientCommon.c */, FF1B6914067114AF002304DD /* DNSServiceBrowser.m */, FF1E351B06711BCF003DD5BC /* DNSServiceReg.m */, ); @@ -293,6 +296,7 @@ buildActionMask = 2147483647; files = ( 8DD76F770486A8DE00D96B5E /* dns-sd.c in Sources */, + FF2704F90F12A60900299571 /* ClientCommon.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.NET.csproj b/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.NET.csproj index d43cf10..cbb7c30 100755 --- a/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.NET.csproj +++ b/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.NET.csproj @@ -1,117 +1,116 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + Local + 8.0.50727 + 2.0 + {DE8DB97E-37A3-43ED-9A5E-CCC5F6DE9CB4} + Debug + AnyCPU + + + + + DNSServiceBrowser_NET + + + JScript + Grid + IE50 + false + WinExe + DNSServiceBrowser_NET + + + + + + + + + bin\Debug\ + false + 285212672 + false + + + DEBUG;TRACE + + + true + 4096 + false + false + false + false + 4 + full + prompt + + + bin\Release\ + false + 285212672 + false + + + TRACE + + + false + 4096 + true + false + false + false + 4 + none + prompt + + + + System + + + System.Data + + + System.Drawing + + + System.Windows.Forms + + + System.XML + + + + + + Code + + + Form + + + DNSServiceBrowser.cs + Designer + + + + + {18FBED6D-F2B7-4EC8-A4A4-46282E635308} + 1 + 0 + 0 + tlbimp + False + + + + + + + + + + \ No newline at end of file diff --git a/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.cs b/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.cs index e279d18..c86b45e 100755 --- a/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.cs +++ b/Clients/DNSServiceBrowser.NET/DNSServiceBrowser.cs @@ -17,6 +17,9 @@ Change History (most recent first): $Log: DNSServiceBrowser.cs,v $ +Revision 1.8 2009/06/02 18:49:23 herscher + Update the .NET code to use the new Bonjour COM component + Revision 1.7 2006/08/14 23:23:58 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -50,7 +53,7 @@ using System.ComponentModel; using System.Windows.Forms; using System.Data; using System.Text; -using Apple.DNSSD; +using Bonjour; namespace DNSServiceBrowser_NET { @@ -61,24 +64,15 @@ namespace DNSServiceBrowser_NET { private System.Windows.Forms.ComboBox typeBox; private System.Windows.Forms.ListBox browseList; - private ServiceRef browser = null; - private ServiceRef resolver = null; + private Bonjour.DNSSDEventManager eventManager = null; + private Bonjour.DNSSDService service = null; + private Bonjour.DNSSDService browser = null; + private Bonjour.DNSSDService resolver = null; /// /// Required designer variable. /// private System.ComponentModel.Container components = null; - - // - // These delegates are invoked as a result of DNSService - // operation. - // - delegate void AddServiceCallback(BrowseData data); - delegate void RemoveServiceCallback(BrowseData data); - delegate void ResolveServiceCallback(ResolveData data); - - AddServiceCallback addServiceCallback; - RemoveServiceCallback removeServiceCallback; private System.Windows.Forms.Label label1; private System.Windows.Forms.Label label2; private System.Windows.Forms.Label label3; @@ -90,7 +84,6 @@ namespace DNSServiceBrowser_NET private System.Windows.Forms.TextBox portField; private System.Windows.Forms.Label label5; private System.Windows.Forms.ListBox serviceTextField; - ResolveServiceCallback resolveServiceCallback; public Form1() { @@ -99,19 +92,20 @@ namespace DNSServiceBrowser_NET // InitializeComponent(); - addServiceCallback = new AddServiceCallback(OnAddService); - removeServiceCallback = new RemoveServiceCallback(OnRemoveService); - resolveServiceCallback = new ResolveServiceCallback(OnResolveService); - this.Load += new System.EventHandler(this.Form1_Load); + + eventManager = new DNSSDEventManager(); + eventManager.ServiceFound += new _IDNSSDEvents_ServiceFoundEventHandler(this.ServiceFound); + eventManager.ServiceLost += new _IDNSSDEvents_ServiceLostEventHandler(this.ServiceLost); + eventManager.ServiceResolved += new _IDNSSDEvents_ServiceResolvedEventHandler(this.ServiceResolved); + eventManager.OperationFailed += new _IDNSSDEvents_OperationFailedEventHandler(this.OperationFailed); + + service = new DNSSDService(); } private void Form1_Load(object sender, EventArgs e) - { - - typeBox.SelectedItem = "_spike._tcp"; - + typeBox.SelectedItem = "_http._tcp"; } @@ -122,15 +116,30 @@ namespace DNSServiceBrowser_NET { if( disposing ) { - if (components != null) - { - components.Dispose(); - } + if (components != null) + { + components.Dispose(); + } - if (browser != null) - { - browser.Dispose(); - } + if (resolver != null) + { + resolver.Stop(); + } + + if (browser != null) + { + browser.Stop(); + } + + if (service != null) + { + service.Stop(); + } + + eventManager.ServiceFound -= new _IDNSSDEvents_ServiceFoundEventHandler(this.ServiceFound); + eventManager.ServiceLost -= new _IDNSSDEvents_ServiceLostEventHandler(this.ServiceLost); + eventManager.ServiceResolved -= new _IDNSSDEvents_ServiceResolvedEventHandler(this.ServiceResolved); + eventManager.OperationFailed -= new _IDNSSDEvents_OperationFailedEventHandler(this.OperationFailed); } base.Dispose( disposing ); } @@ -467,7 +476,7 @@ namespace DNSServiceBrowser_NET // public class BrowseData { - public int InterfaceIndex; + public uint InterfaceIndex; public String Name; public String Type; public String Domain; @@ -516,11 +525,11 @@ namespace DNSServiceBrowser_NET // public class ResolveData { - public int InterfaceIndex; - public String FullName; - public String HostName; - public int Port; - public Byte[] TxtRecord; + public uint InterfaceIndex; + public String FullName; + public String HostName; + public int Port; + public TXTRecord TxtRecord; public override String ToString() @@ -545,29 +554,30 @@ namespace DNSServiceBrowser_NET portField.Text = resolveData.Port.ToString(); serviceTextField.Items.Clear(); - - if (resolveData.TxtRecord != null) - { - for (int idx = 0; idx < TextRecord.GetCount(resolveData.TxtRecord); idx++) - { - String key; - Byte[] bytes; - - bytes = TextRecord.GetItemAtIndex(resolveData.TxtRecord, idx, out key); + + if (resolveData.TxtRecord != null) + { + for (uint idx = 0; idx < resolveData.TxtRecord.GetCount(); idx++) + { + String key; + Byte[] bytes; - if (key.Length > 0) - { - String val = ""; + key = resolveData.TxtRecord.GetKeyAtIndex(idx); + bytes = (Byte[])resolveData.TxtRecord.GetValueAtIndex(idx); - if (bytes != null) - { - val = Encoding.ASCII.GetString(bytes, 0, bytes.Length); - } + if (key.Length > 0) + { + String val = ""; - serviceTextField.Items.Add(key + "=" + val); - } - } - } + if (bytes != null) + { + val = Encoding.ASCII.GetString(bytes, 0, bytes.Length); + } + + serviceTextField.Items.Add(key + "=" + val); + } + } + } } // @@ -579,7 +589,7 @@ namespace DNSServiceBrowser_NET if (browser != null) { - browser.Dispose(); + browser.Stop(); } nameField.Text = ""; @@ -591,7 +601,7 @@ namespace DNSServiceBrowser_NET try { - browser = DNSService.Browse(0, 0, typeBox.SelectedItem.ToString(), null, new DNSService.BrowseReply(OnBrowseReply)); + browser = service.Browse( 0, 0, typeBox.SelectedItem.ToString(), null, eventManager ); } catch { @@ -604,7 +614,8 @@ namespace DNSServiceBrowser_NET { if (resolver != null) { - resolver.Dispose(); + resolver.Stop(); + resolver = null; } if (browseList.SelectedItem != null) @@ -613,7 +624,7 @@ namespace DNSServiceBrowser_NET { BrowseData data = (BrowseData) browseList.SelectedItem; - resolver = DNSService.Resolve(0, 0, data.Name, data.Type, data.Domain, new DNSService.ResolveReply(OnResolveReply)); + resolver = service.Resolve(0, data.InterfaceIndex, data.Name, data.Type, data.Domain, eventManager); } catch { @@ -624,125 +635,86 @@ namespace DNSServiceBrowser_NET } // - // OnAddService + // ServiceFound // - // This method is "Invoked" by OnBrowseReply. This call - // executes in the context of the main thread + // This call is invoked by the DNSService core. We create + // a BrowseData object and invoked the appropriate method + // in the GUI thread so we can update the UI // - private void OnAddService - ( - BrowseData data - ) + public void ServiceFound + ( + DNSSDService sref, + DNSSDFlags flags, + uint ifIndex, + String serviceName, + String regType, + String domain + ) { - browseList.Items.Add(data); - browseList.Invalidate(); - } + BrowseData data = new BrowseData(); - // - // OnRemoveService - // - // This method is "Invoked" by OnBrowseReply. This call - // executes in the context of the main thread - // - private void OnRemoveService - ( - BrowseData data - ) - { - browseList.Items.Remove(data); - browseList.Invalidate(); + data.InterfaceIndex = ifIndex; + data.Name = serviceName; + data.Type = regType; + data.Domain = domain; + + browseList.Items.Add(data); + browseList.Invalidate(); } - // - // OnResolveService - // - // This method is "Invoked" by OnResolveReply. This call - // executes in the context of the main thread - // - private void OnResolveService - ( - ResolveData data - ) + public void ServiceLost + ( + DNSSDService sref, + DNSSDFlags flags, + uint ifIndex, + String serviceName, + String regType, + String domain + ) + { + BrowseData data = new BrowseData(); + + data.InterfaceIndex = ifIndex; + data.Name = serviceName; + data.Type = regType; + data.Domain = domain; + + browseList.Items.Remove(data); + browseList.Invalidate(); + } + + public void ServiceResolved + ( + DNSSDService sref, + DNSSDFlags flags, + uint ifIndex, + String fullName, + String hostName, + ushort port, + TXTRecord txtRecord + ) { - resolver.Dispose(); + ResolveData data = new ResolveData(); + + data.InterfaceIndex = ifIndex; + data.FullName = fullName; + data.HostName = hostName; + data.Port = port; + data.TxtRecord = txtRecord; + + resolver.Stop(); resolver = null; Populate((BrowseData) browseList.SelectedItem, data); } - // - // OnBrowseReply - // - // This call is invoked by the DNSService core. It is - // executed in the context of a worker thread, not the - // main (GUI) thread. We create a BrowseData object - // and invoked the appropriate method in the GUI thread - // so we can update the UI - // - private void OnBrowseReply - ( - ServiceRef sdRef, - ServiceFlags flags, - int interfaceIndex, - ErrorCode errorCode, - String name, - String type, - String domain - ) - { - if (errorCode == ErrorCode.NoError) - { - BrowseData data = new BrowseData(); - - data.InterfaceIndex = interfaceIndex; - data.Name = name; - data.Type = type; - data.Domain = domain; - - if ((flags & ServiceFlags.Add) != 0) - { - Invoke(addServiceCallback, new Object[]{data}); - - } - else if ((flags == 0) || ((flags & ServiceFlags.MoreComing) != 0)) - { - Invoke(removeServiceCallback, new Object[]{data}); - } - } - else - { - MessageBox.Show("OnBrowseReply returned an error code: " + errorCode, "Error"); - } - } - - private void OnResolveReply - ( - ServiceRef sdRef, - ServiceFlags flags, - int interfaceIndex, - ErrorCode errorCode, - String fullName, - String hostName, - int port, - Byte[] txtRecord - ) - { - if (errorCode == ErrorCode.NoError) - { - ResolveData data = new ResolveData(); - - data.InterfaceIndex = interfaceIndex; - data.FullName = fullName; - data.HostName = hostName; - data.Port = port; - data.TxtRecord = txtRecord; - - Invoke(resolveServiceCallback, new Object[]{data}); - } - else - { - MessageBox.Show("OnResolveReply returned an error code: " + errorCode, "Error"); - } - } - } + public void OperationFailed + ( + DNSSDService sref, + DNSSDError error + ) + { + MessageBox.Show("Operation failed: error code: " + error, "Error"); + } + } } diff --git a/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.Designer.vb b/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.Designer.vb new file mode 100644 index 0000000..0c6280b --- /dev/null +++ b/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.Designer.vb @@ -0,0 +1,206 @@ + _ +Partial Class DNSServiceBrowser + Inherits System.Windows.Forms.Form + + 'Form overrides dispose to clean up the component list. + _ + Protected Overrides Sub Dispose(ByVal disposing As Boolean) + Try + If disposing AndAlso components IsNot Nothing Then + components.Dispose() + End If + Finally + MyBase.Dispose(disposing) + End Try + End Sub + + 'Required by the Windows Form Designer + Private components As System.ComponentModel.IContainer + + 'NOTE: The following procedure is required by the Windows Form Designer + 'It can be modified using the Windows Form Designer. + 'Do not modify it using the code editor. + _ + Private Sub InitializeComponent() + Me.ComboBox1 = New System.Windows.Forms.ComboBox + Me.ServiceNames = New System.Windows.Forms.ListBox + Me.Label1 = New System.Windows.Forms.Label + Me.Label2 = New System.Windows.Forms.Label + Me.Label3 = New System.Windows.Forms.Label + Me.Label4 = New System.Windows.Forms.Label + Me.Label5 = New System.Windows.Forms.Label + Me.NameField = New System.Windows.Forms.TextBox + Me.PortField = New System.Windows.Forms.TextBox + Me.HostField = New System.Windows.Forms.TextBox + Me.DomainField = New System.Windows.Forms.TextBox + Me.TypeField = New System.Windows.Forms.TextBox + Me.TextRecord = New System.Windows.Forms.ListBox + Me.SuspendLayout() + ' + 'ComboBox1 + ' + Me.ComboBox1.FormattingEnabled = True + Me.ComboBox1.Items.AddRange(New Object() {"_accessone._tcp", "_accountedge._tcp", "_actionitems._tcp", "_addressbook._tcp", "_aecoretech._tcp", "_afpovertcp._tcp", "_airport._tcp", "_animobserver._tcp", "_animolmd._tcp", "_apple-sasl._tcp", "_aquamon._tcp", "_async._tcp", "_auth._tcp", "_beep._tcp", "_bfagent._tcp", "_bootps._udp", "_bousg._tcp", "_bsqdea._tcp", "_cheat._tcp", "_chess._tcp", "_clipboard._tcp", "_collection._tcp", "_contactserver._tcp", "_cvspserver._tcp", "_cytv._tcp", "_daap._tcp", "_difi._tcp", "_distcc._tcp", "_dossier._tcp", "_dpap._tcp", "_earphoria._tcp", "_ebms._tcp", "_ebreg._tcp", "_ecbyesfsgksc._tcp", "_eheap._tcp", "_embrace._tcp", "_eppc._tcp", "_eventserver._tcp", "_exec._tcp", "_facespan._tcp", "_faxstfx._tcp", "_fish._tcp", "_fjork._tcp", "_fmpro-internal._tcp", "_ftp._tcp", "_ftpcroco._tcp", "_gbs-smp._tcp", "_gbs-stp._tcp", "_grillezvous._tcp", "_h323._tcp", "_hotwayd._tcp", "_http._tcp", "_hydra._tcp", "_ica-networking._tcp", "_ichalkboard._tcp", "_ichat._tcp", "_iconquer._tcp", "_ifolder._tcp", "_ilynx._tcp", "_imap._tcp", "_imidi._tcp", "_ipbroadcaster._tcp", "_ipp._tcp", "_ishare._tcp", "_isparx._tcp", "_ispq-vc._tcp", "_isticky._tcp", "_istorm._tcp", "_iwork._tcp", "_lan2p._tcp", "_ldap._tcp", "_liaison._tcp", "_login._tcp", "_lontalk._tcp", "_lonworks._tcp", "_macfoh-remote._tcp", "_macminder._tcp", "_moneyworks._tcp", "_mp3sushi._tcp", "_mttp._tcp", "_ncbroadcast._tcp", "_ncdirect._tcp", "_ncsyncserver._tcp", "_net-assistant._tcp", "_newton-dock._tcp", "_nfs._udp", "_nssocketport._tcp", "_odabsharing._tcp", "_omni-bookmark._tcp", "_openbase._tcp", "_p2pchat._udp", "_pdl-datastream._tcp", "_poch._tcp", "_pop3._tcp", "_postgresql._tcp", "_presence._tcp", "_printer._tcp", "_ptp._tcp", "_quinn._tcp", "_raop._tcp", "_rce._tcp", "_realplayfavs._tcp", "_rfb._tcp", "_riousbprint._tcp", "_rtsp._tcp", "_safarimenu._tcp", "_sallingclicker._tcp", "_scone._tcp", "_sdsharing._tcp", "_see._tcp", "_seeCard._tcp", "_serendipd._tcp", "_servermgr._tcp", "_sge-exec._tcp", "_sge-qmaster._tcp", "_shell._tcp", "_shout._tcp", "_shoutcast._tcp", "_soap._tcp", "_spike._tcp", "_spincrisis._tcp", "_spl-itunes._tcp", "_spr-itunes._tcp", "_ssh._tcp", "_ssscreenshare._tcp", "_stickynotes._tcp", "_strateges._tcp", "_sxqdea._tcp", "_sybase-tds._tcp", "_teamlist._tcp", "_teleport._udp", "_telnet._tcp", "_tftp._udp", "_ticonnectmgr._tcp", "_tinavigator._tcp", "_tryst._tcp", "_upnp._tcp", "_utest._tcp", "_vue4rendercow._tcp", "_webdav._tcp", "_whamb._tcp", "_wired._tcp", "_workgroup._tcp", "_workstation._tcp", "_wormhole._tcp", "_ws._tcp", "_xserveraid._tcp", "_xsync._tcp", "_xtshapro._tcp"}) + Me.ComboBox1.Location = New System.Drawing.Point(13, 13) + Me.ComboBox1.Name = "ComboBox1" + Me.ComboBox1.Size = New System.Drawing.Size(252, 21) + Me.ComboBox1.Sorted = True + Me.ComboBox1.TabIndex = 0 + ' + 'ServiceNames + ' + Me.ServiceNames.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _ + Or System.Windows.Forms.AnchorStyles.Left) _ + Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) + Me.ServiceNames.FormattingEnabled = True + Me.ServiceNames.Location = New System.Drawing.Point(13, 41) + Me.ServiceNames.Name = "ServiceNames" + Me.ServiceNames.Size = New System.Drawing.Size(662, 251) + Me.ServiceNames.Sorted = True + Me.ServiceNames.TabIndex = 1 + ' + 'Label1 + ' + Me.Label1.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles) + Me.Label1.AutoSize = True + Me.Label1.Location = New System.Drawing.Point(16, 311) + Me.Label1.Name = "Label1" + Me.Label1.Size = New System.Drawing.Size(38, 13) + Me.Label1.TabIndex = 2 + Me.Label1.Text = "Name:" + ' + 'Label2 + ' + Me.Label2.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles) + Me.Label2.AutoSize = True + Me.Label2.Location = New System.Drawing.Point(16, 439) + Me.Label2.Name = "Label2" + Me.Label2.Size = New System.Drawing.Size(29, 13) + Me.Label2.TabIndex = 3 + Me.Label2.Text = "Port:" + ' + 'Label3 + ' + Me.Label3.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles) + Me.Label3.AutoSize = True + Me.Label3.Location = New System.Drawing.Point(16, 407) + Me.Label3.Name = "Label3" + Me.Label3.Size = New System.Drawing.Size(32, 13) + Me.Label3.TabIndex = 4 + Me.Label3.Text = "Host:" + ' + 'Label4 + ' + Me.Label4.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles) + Me.Label4.AutoSize = True + Me.Label4.Location = New System.Drawing.Point(16, 374) + Me.Label4.Name = "Label4" + Me.Label4.Size = New System.Drawing.Size(46, 13) + Me.Label4.TabIndex = 5 + Me.Label4.Text = "Domain:" + ' + 'Label5 + ' + Me.Label5.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles) + Me.Label5.AutoSize = True + Me.Label5.Location = New System.Drawing.Point(16, 342) + Me.Label5.Name = "Label5" + Me.Label5.Size = New System.Drawing.Size(34, 13) + Me.Label5.TabIndex = 6 + Me.Label5.Text = "Type:" + ' + 'NameField + ' + Me.NameField.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles) + Me.NameField.Location = New System.Drawing.Point(69, 309) + Me.NameField.Name = "NameField" + Me.NameField.ReadOnly = True + Me.NameField.Size = New System.Drawing.Size(195, 20) + Me.NameField.TabIndex = 7 + ' + 'PortField + ' + Me.PortField.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles) + Me.PortField.Location = New System.Drawing.Point(69, 436) + Me.PortField.Name = "PortField" + Me.PortField.ReadOnly = True + Me.PortField.Size = New System.Drawing.Size(195, 20) + Me.PortField.TabIndex = 8 + ' + 'HostField + ' + Me.HostField.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles) + Me.HostField.Location = New System.Drawing.Point(69, 403) + Me.HostField.Name = "HostField" + Me.HostField.ReadOnly = True + Me.HostField.Size = New System.Drawing.Size(195, 20) + Me.HostField.TabIndex = 9 + ' + 'DomainField + ' + Me.DomainField.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles) + Me.DomainField.Location = New System.Drawing.Point(69, 371) + Me.DomainField.Name = "DomainField" + Me.DomainField.ReadOnly = True + Me.DomainField.Size = New System.Drawing.Size(195, 20) + Me.DomainField.TabIndex = 10 + ' + 'TypeField + ' + Me.TypeField.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles) + Me.TypeField.Location = New System.Drawing.Point(69, 340) + Me.TypeField.Name = "TypeField" + Me.TypeField.ReadOnly = True + Me.TypeField.Size = New System.Drawing.Size(195, 20) + Me.TypeField.TabIndex = 11 + ' + 'TextRecord + ' + Me.TextRecord.Anchor = CType(((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left) _ + Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) + Me.TextRecord.FormattingEnabled = True + Me.TextRecord.Location = New System.Drawing.Point(278, 309) + Me.TextRecord.Name = "TextRecord" + Me.TextRecord.SelectionMode = System.Windows.Forms.SelectionMode.None + Me.TextRecord.Size = New System.Drawing.Size(397, 147) + Me.TextRecord.TabIndex = 12 + ' + 'Form1 + ' + Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) + Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font + Me.ClientSize = New System.Drawing.Size(690, 480) + Me.Controls.Add(Me.TextRecord) + Me.Controls.Add(Me.TypeField) + Me.Controls.Add(Me.DomainField) + Me.Controls.Add(Me.HostField) + Me.Controls.Add(Me.PortField) + Me.Controls.Add(Me.NameField) + Me.Controls.Add(Me.Label5) + Me.Controls.Add(Me.Label4) + Me.Controls.Add(Me.Label3) + Me.Controls.Add(Me.Label2) + Me.Controls.Add(Me.Label1) + Me.Controls.Add(Me.ServiceNames) + Me.Controls.Add(Me.ComboBox1) + Me.Name = "Form1" + Me.Text = "Bonjour Browser" + Me.ResumeLayout(False) + Me.PerformLayout() + + End Sub + Friend WithEvents ComboBox1 As System.Windows.Forms.ComboBox + Friend WithEvents ServiceNames As System.Windows.Forms.ListBox + Friend WithEvents Label1 As System.Windows.Forms.Label + Friend WithEvents Label2 As System.Windows.Forms.Label + Friend WithEvents Label3 As System.Windows.Forms.Label + Friend WithEvents Label4 As System.Windows.Forms.Label + Friend WithEvents Label5 As System.Windows.Forms.Label + Friend WithEvents NameField As System.Windows.Forms.TextBox + Friend WithEvents PortField As System.Windows.Forms.TextBox + Friend WithEvents HostField As System.Windows.Forms.TextBox + Friend WithEvents DomainField As System.Windows.Forms.TextBox + Friend WithEvents TypeField As System.Windows.Forms.TextBox + Friend WithEvents TextRecord As System.Windows.Forms.ListBox + +End Class diff --git a/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.VB.vbproj b/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.VB.vbproj new file mode 100644 index 0000000..d4e59eb --- /dev/null +++ b/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.VB.vbproj @@ -0,0 +1,116 @@ + + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {FB79E297-5703-435C-A829-51AA51CD71C2} + WinExe + DNSServiceBrowser.VB.My.MyApplication + DNSServiceBrowser.VB + DNSServiceBrowser.VB + WindowsForms + + + true + full + true + true + bin\Debug\ + DNSServiceBrowser.VB.xml + 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022 + + + pdbonly + false + true + true + bin\Release\ + DNSServiceBrowser.VB.xml + 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022 + + + + + + + + + + + + + + + + + + + + + + Form + + + DNSServiceBrowser.vb + Form + + + + True + Application.myapp + + + True + True + Resources.resx + + + True + Settings.settings + True + + + + + Designer + DNSServiceBrowser.vb + + + VbMyResourcesResXFileCodeGenerator + Resources.Designer.vb + My.Resources + Designer + + + + + MyApplicationCodeGenerator + Application.Designer.vb + + + SettingsSingleFileGenerator + My + Settings.Designer.vb + + + + + {18FBED6D-F2B7-4EC8-A4A4-46282E635308} + 1 + 0 + 0 + tlbimp + False + + + + + \ No newline at end of file diff --git a/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.resx b/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.resx new file mode 100644 index 0000000..ff31a6d --- /dev/null +++ b/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.vb b/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.vb new file mode 100644 index 0000000..1e7a7ae --- /dev/null +++ b/Clients/DNSServiceBrowser.VB/DNSServiceBrowser.vb @@ -0,0 +1,111 @@ +Public Class DNSServiceBrowser + Public WithEvents MyEventManager As New Bonjour.DNSSDEventManager + + Private m_service As New Bonjour.DNSSDService + Private m_browser As Bonjour.DNSSDService + Private m_resolver As Bonjour.DNSSDService + + Public Sub New() + MyBase.New() + + 'This call is required by the Windows Form Designer. + InitializeComponent() + + ComboBox1.SelectedIndex = 0 + End Sub + Public Sub MyEventManager_ServiceFound(ByVal browser As Bonjour.DNSSDService, ByVal flags As Bonjour.DNSSDFlags, ByVal ifIndex As UInteger, ByVal serviceName As String, ByVal regtype As String, ByVal domain As String) Handles MyEventManager.ServiceFound + Dim browseData As New BrowseData + browseData.ServiceName = serviceName + browseData.RegType = regtype + browseData.Domain = domain + ServiceNames.Items.Add(browseData) + End Sub + Public Sub MyEventManager_ServiceLost(ByVal browser As Bonjour.DNSSDService, ByVal flags As Bonjour.DNSSDFlags, ByVal ifIndex As UInteger, ByVal serviceName As String, ByVal regtype As String, ByVal domain As String) Handles MyEventManager.ServiceLost + ServiceNames.Items.Remove(serviceName) + End Sub + Public Sub MyEventManager_ServiceResolved(ByVal resolver As Bonjour.DNSSDService, ByVal flags As Bonjour.DNSSDFlags, ByVal ifIndex As UInteger, ByVal fullname As String, ByVal hostname As String, ByVal port As UShort, ByVal record As Bonjour.TXTRecord) Handles MyEventManager.ServiceResolved + m_resolver.Stop() + m_resolver = Nothing + Dim browseData As BrowseData = ServiceNames.Items.Item(ServiceNames.SelectedIndex) + NameField.Text = browseData.ServiceName + TypeField.Text = browseData.RegType + DomainField.Text = browseData.Domain + HostField.Text = hostname + PortField.Text = port + + If record IsNot Nothing Then + For i As UInteger = 0 To record.GetCount() - 1 + Dim key As String = record.GetKeyAtIndex(i) + If key.Length() > 0 Then + TextRecord.Items.Add(key + "=" + System.Text.Encoding.ASCII.GetString(record.GetValueAtIndex(i))) + End If + Next i + End If + End Sub + Private Sub ClearServiceInfo() + TextRecord.Items.Clear() + NameField.Text = "" + TypeField.Text = "" + DomainField.Text = "" + HostField.Text = "" + PortField.Text = "" + End Sub + Private Sub ServiceNames_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ServiceNames.SelectedIndexChanged + If m_resolver IsNot Nothing Then + m_resolver.Stop() + End If + Me.ClearServiceInfo() + Dim browseData As BrowseData = ServiceNames.Items.Item(ServiceNames.SelectedIndex) + m_resolver = m_service.Resolve(0, 0, browseData.ServiceName, browseData.RegType, browseData.Domain, MyEventManager) + End Sub + Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged + If m_browser IsNot Nothing Then + m_browser.Stop() + End If + + ServiceNames.Items.Clear() + Me.ClearServiceInfo() + m_browser = m_service.Browse(0, 0, ComboBox1.Items.Item(ComboBox1.SelectedIndex), "", MyEventManager) + End Sub + + Private Sub ListBox2_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextRecord.SelectedIndexChanged + + End Sub +End Class +Public Class BrowseData + Private m_serviceName As String + Private m_regType As String + Private m_domain As String + + Property ServiceName() As String + Get + Return m_serviceName + End Get + Set(ByVal Value As String) + m_serviceName = Value + End Set + End Property + + Property RegType() As String + Get + Return m_regType + End Get + Set(ByVal Value As String) + m_regType = Value + End Set + End Property + + Property Domain() As String + Get + Return m_domain + End Get + Set(ByVal Value As String) + m_domain = Value + End Set + End Property + + Public Overrides Function ToString() As String + Return m_serviceName + End Function + +End Class diff --git a/Clients/DNSServiceBrowser.VB/My Project/Application.Designer.vb b/Clients/DNSServiceBrowser.VB/My Project/Application.Designer.vb new file mode 100644 index 0000000..ad73d2e --- /dev/null +++ b/Clients/DNSServiceBrowser.VB/My Project/Application.Designer.vb @@ -0,0 +1,38 @@ +'------------------------------------------------------------------------------ +' +' This code was generated by a tool. +' Runtime Version:2.0.50727.4918 +' +' Changes to this file may cause incorrect behavior and will be lost if +' the code is regenerated. +' +'------------------------------------------------------------------------------ + +Option Strict On +Option Explicit On + + +Namespace My + + 'NOTE: This file is auto-generated; do not modify it directly. To make changes, + ' or if you encounter build errors in this file, go to the Project Designer + ' (go to Project Properties or double-click the My Project node in + ' Solution Explorer), and make changes on the Application tab. + ' + Partial Friend Class MyApplication + + _ + Public Sub New() + MyBase.New(Global.Microsoft.VisualBasic.ApplicationServices.AuthenticationMode.Windows) + Me.IsSingleInstance = false + Me.EnableVisualStyles = true + Me.SaveMySettingsOnExit = true + Me.ShutDownStyle = Global.Microsoft.VisualBasic.ApplicationServices.ShutdownMode.AfterMainFormCloses + End Sub + + _ + Protected Overrides Sub OnCreateMainForm() + Me.MainForm = Global.DNSServiceBrowser.VB.DNSServiceBrowser + End Sub + End Class +End Namespace diff --git a/Clients/DNSServiceBrowser.VB/My Project/Application.myapp b/Clients/DNSServiceBrowser.VB/My Project/Application.myapp new file mode 100644 index 0000000..85cb2c9 --- /dev/null +++ b/Clients/DNSServiceBrowser.VB/My Project/Application.myapp @@ -0,0 +1,10 @@ + + + true + DNSServiceBrowser + false + 0 + true + 0 + true + \ No newline at end of file diff --git a/Clients/DNSServiceBrowser.VB/My Project/AssemblyInfo.vb b/Clients/DNSServiceBrowser.VB/My Project/AssemblyInfo.vb new file mode 100644 index 0000000..32fd3b7 --- /dev/null +++ b/Clients/DNSServiceBrowser.VB/My Project/AssemblyInfo.vb @@ -0,0 +1,35 @@ +Imports System +Imports System.Reflection +Imports System.Runtime.InteropServices + +' General Information about an assembly is controlled through the following +' set of attributes. Change these attribute values to modify the information +' associated with an assembly. + +' Review the values of the assembly attributes + + + + + + + + + + +'The following GUID is for the ID of the typelib if this project is exposed to COM + + +' Version information for an assembly consists of the following four values: +' +' Major Version +' Minor Version +' Build Number +' Revision +' +' You can specify all the values or you can default the Build and Revision Numbers +' by using the '*' as shown below: +' + + + diff --git a/Clients/DNSServiceBrowser.VB/My Project/Resources.Designer.vb b/Clients/DNSServiceBrowser.VB/My Project/Resources.Designer.vb new file mode 100644 index 0000000..1f3f960 --- /dev/null +++ b/Clients/DNSServiceBrowser.VB/My Project/Resources.Designer.vb @@ -0,0 +1,62 @@ +'------------------------------------------------------------------------------ +' +' This code was generated by a tool. +' Runtime Version:2.0.50727.3082 +' +' Changes to this file may cause incorrect behavior and will be lost if +' the code is regenerated. +' +'------------------------------------------------------------------------------ + +Option Strict On +Option Explicit On + + +Namespace My.Resources + + 'This class was auto-generated by the StronglyTypedResourceBuilder + 'class via a tool like ResGen or Visual Studio. + 'To add or remove a member, edit your .ResX file then rerun ResGen + 'with the /str option, or rebuild your VS project. + ' + ' A strongly-typed resource class, for looking up localized strings, etc. + ' + _ + Friend Module Resources + + Private resourceMan As Global.System.Resources.ResourceManager + + Private resourceCulture As Global.System.Globalization.CultureInfo + + ' + ' Returns the cached ResourceManager instance used by this class. + ' + _ + Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager + Get + If Object.ReferenceEquals(resourceMan, Nothing) Then + Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("VBTester.Resources", GetType(Resources).Assembly) + resourceMan = temp + End If + Return resourceMan + End Get + End Property + + ' + ' Overrides the current thread's CurrentUICulture property for all + ' resource lookups using this strongly typed resource class. + ' + _ + Friend Property Culture() As Global.System.Globalization.CultureInfo + Get + Return resourceCulture + End Get + Set(ByVal value As Global.System.Globalization.CultureInfo) + resourceCulture = value + End Set + End Property + End Module +End Namespace diff --git a/Clients/DNSServiceBrowser.VB/My Project/Resources.resx b/Clients/DNSServiceBrowser.VB/My Project/Resources.resx new file mode 100644 index 0000000..ffecec8 --- /dev/null +++ b/Clients/DNSServiceBrowser.VB/My Project/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Clients/DNSServiceBrowser.VB/My Project/Settings.Designer.vb b/Clients/DNSServiceBrowser.VB/My Project/Settings.Designer.vb new file mode 100644 index 0000000..a8c1536 --- /dev/null +++ b/Clients/DNSServiceBrowser.VB/My Project/Settings.Designer.vb @@ -0,0 +1,73 @@ +'------------------------------------------------------------------------------ +' +' This code was generated by a tool. +' Runtime Version:2.0.50727.3082 +' +' Changes to this file may cause incorrect behavior and will be lost if +' the code is regenerated. +' +'------------------------------------------------------------------------------ + +Option Strict On +Option Explicit On + + +Namespace My + + _ + Partial Friend NotInheritable Class MySettings + Inherits Global.System.Configuration.ApplicationSettingsBase + + Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings), MySettings) + +#Region "My.Settings Auto-Save Functionality" +#If _MyType = "WindowsForms" Then + Private Shared addedHandler As Boolean + + Private Shared addedHandlerLockObject As New Object + + _ + Private Shared Sub AutoSaveSettings(ByVal sender As Global.System.Object, ByVal e As Global.System.EventArgs) + If My.Application.SaveMySettingsOnExit Then + My.Settings.Save() + End If + End Sub +#End If +#End Region + + Public Shared ReadOnly Property [Default]() As MySettings + Get + +#If _MyType = "WindowsForms" Then + If Not addedHandler Then + SyncLock addedHandlerLockObject + If Not addedHandler Then + AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings + addedHandler = True + End If + End SyncLock + End If +#End If + Return defaultInstance + End Get + End Property + End Class +End Namespace + +Namespace My + + _ + Friend Module MySettingsProperty + + _ + Friend ReadOnly Property Settings() As Global.DNSServiceBrowser.VB.My.MySettings + Get + Return Global.DNSServiceBrowser.VB.My.MySettings.Default + End Get + End Property + End Module +End Namespace diff --git a/Clients/DNSServiceBrowser.VB/My Project/Settings.settings b/Clients/DNSServiceBrowser.VB/My Project/Settings.settings new file mode 100644 index 0000000..377f56d --- /dev/null +++ b/Clients/DNSServiceBrowser.VB/My Project/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Clients/ExplorerPlugin/About.cpp b/Clients/ExplorerPlugin/About.cpp index 783a9ce..4a63f2c 100644 --- a/Clients/ExplorerPlugin/About.cpp +++ b/Clients/ExplorerPlugin/About.cpp @@ -4,6 +4,7 @@ #include "stdafx.h" #include "ExplorerPlugin.h" #include "About.h" +#include "WinVersRes.h" #include @@ -48,6 +49,14 @@ CAbout::OnInitDialog() control->SetBitmap( ::LoadBitmap( GetNonLocalizedResources(), MAKEINTRESOURCE( IDB_ABOUT ) ) ); } + control = ( CStatic* ) GetDlgItem( IDC_COMPONENT_VERSION ); + check( control ); + + if ( control ) + { + control->SetWindowText( TEXT( MASTER_PROD_VERS_STR2 ) ); + } + return b; } diff --git a/Clients/ExplorerPlugin/ExplorerBar.cpp b/Clients/ExplorerPlugin/ExplorerBar.cpp index f09d983..3aea9a2 100644 --- a/Clients/ExplorerPlugin/ExplorerBar.cpp +++ b/Clients/ExplorerPlugin/ExplorerBar.cpp @@ -17,6 +17,10 @@ Change History (most recent first): $Log: ExplorerBar.cpp,v $ +Revision 1.5 2009/03/30 18:44:53 herscher + Current Bonjour code does not compile on Windows + Move build train to Visual Studio 2005 + Revision 1.4 2006/08/14 23:24:00 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -588,7 +592,7 @@ STDMETHODIMP ExplorerBar::QueryContextMenu(HMENU hShellContextMenu, UINT iConte //=========================================================================================================================== // Not called for explorer bars -STDMETHODIMP ExplorerBar::GetCommandString(UINT idCmd, UINT uType, UINT* pwReserved, LPSTR pszName, UINT cchMax) +STDMETHODIMP ExplorerBar::GetCommandString(UINT_PTR idCmd, UINT uType, UINT* pwReserved, LPSTR pszName, UINT cchMax) { DEBUG_UNUSED( idCmd ); DEBUG_UNUSED( uType ); diff --git a/Clients/ExplorerPlugin/ExplorerBar.h b/Clients/ExplorerPlugin/ExplorerBar.h index 5af86eb..988f8c3 100644 --- a/Clients/ExplorerPlugin/ExplorerBar.h +++ b/Clients/ExplorerPlugin/ExplorerBar.h @@ -17,6 +17,10 @@ Change History (most recent first): $Log: ExplorerBar.h,v $ +Revision 1.4 2009/03/30 18:46:13 herscher + Current Bonjour code does not compile on Windows + Move build train to Visual Studio 2005 + Revision 1.3 2006/08/14 23:24:00 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -108,7 +112,7 @@ class ExplorerBar : public IDeskBand, // IContextMenu methods STDMETHOD( QueryContextMenu )( HMENU hContextMenu, UINT iContextMenuFirstItem, UINT idCmdFirst, UINT idCmdLast, UINT uFlags ); - STDMETHOD( GetCommandString )( UINT idCmd, UINT uType, UINT* pwReserved, LPSTR pszName, UINT cchMax ); + STDMETHOD( GetCommandString )( UINT_PTR idCmd, UINT uType, UINT* pwReserved, LPSTR pszName, UINT cchMax ); STDMETHOD( InvokeCommand )( LPCMINVOKECOMMANDINFO lpici ); // Other diff --git a/Clients/ExplorerPlugin/ExplorerBarWindow.cpp b/Clients/ExplorerPlugin/ExplorerBarWindow.cpp index 88f4858..7b5b2ea 100644 --- a/Clients/ExplorerPlugin/ExplorerBarWindow.cpp +++ b/Clients/ExplorerPlugin/ExplorerBarWindow.cpp @@ -17,6 +17,10 @@ Change History (most recent first): $Log: ExplorerBarWindow.cpp,v $ +Revision 1.23 2009/03/30 18:47:40 herscher + Current Bonjour code does not compile on Windows + Move build train to Visual Studio 2005 + Revision 1.22 2006/08/14 23:24:00 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -381,7 +385,7 @@ exit: // OnServiceEvent //=========================================================================================================================== -LONG +LRESULT ExplorerBarWindow::OnServiceEvent(WPARAM inWParam, LPARAM inLParam) { if (WSAGETSELECTERROR(inLParam) && !(HIWORD(inLParam))) @@ -472,13 +476,13 @@ void DNSSD_API err = UTF8StringToStringObject( inName, service->displayName ); check_noerr( err ); - service->name = strdup( inName ); + service->name = _strdup( inName ); require_action( service->name, exit, err = kNoMemoryErr ); - service->type = strdup( inType ); + service->type = _strdup( inType ); require_action( service->type, exit, err = kNoMemoryErr ); - service->domain = strdup( inDomain ); + service->domain = _strdup( inDomain ); require_action( service->domain, exit, err = kNoMemoryErr ); service->ifi = inInterfaceIndex; diff --git a/Clients/ExplorerPlugin/ExplorerBarWindow.h b/Clients/ExplorerPlugin/ExplorerBarWindow.h index f035872..0bbbcae 100644 --- a/Clients/ExplorerPlugin/ExplorerBarWindow.h +++ b/Clients/ExplorerPlugin/ExplorerBarWindow.h @@ -17,6 +17,10 @@ Change History (most recent first): $Log: ExplorerBarWindow.h,v $ +Revision 1.9 2009/03/30 18:49:15 herscher + Current Bonjour code does not compile on Windows + Move build train to Visual Studio 2005 + Revision 1.8 2006/08/14 23:24:00 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -242,7 +246,7 @@ class ExplorerBarWindow : public CWnd afx_msg void OnDestroy( void ); afx_msg void OnSize( UINT inType, int inX, int inY ); afx_msg void OnDoubleClick( NMHDR *inNMHDR, LRESULT *outResult ); - afx_msg LONG OnServiceEvent( WPARAM inWParam, LPARAM inLParam ); + afx_msg LRESULT OnServiceEvent( WPARAM inWParam, LPARAM inLParam ); // Browsing diff --git a/Clients/ExplorerPlugin/ExplorerPlugin.cpp b/Clients/ExplorerPlugin/ExplorerPlugin.cpp index c2c661b..b83dac8 100644 --- a/Clients/ExplorerPlugin/ExplorerPlugin.cpp +++ b/Clients/ExplorerPlugin/ExplorerPlugin.cpp @@ -17,6 +17,10 @@ Change History (most recent first): $Log: ExplorerPlugin.cpp,v $ +Revision 1.10 2009/03/30 18:51:04 herscher + Current Bonjour code does not compile on Windows + Move build train to Visual Studio 2005 + Revision 1.9 2006/08/14 23:24:00 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -90,16 +94,6 @@ static char THIS_FILE[] = __FILE__; // Prototypes //=========================================================================================================================== -// DLL Exports - -extern "C" BOOL WINAPI DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved ); - -// MFC Support - -DEBUG_LOCAL OSStatus MFCDLLProcessAttach( HINSTANCE inInstance ); -DEBUG_LOCAL void MFCDLLProcessDetach( HINSTANCE inInstance ); -DEBUG_LOCAL void MFCDLLThreadDetach( HINSTANCE inInstance ); - // Utilities DEBUG_LOCAL OSStatus RegisterServer( HINSTANCE inInstance, CLSID inCLSID, LPCTSTR inName ); @@ -141,9 +135,9 @@ DEFINE_GUID(CLSID_CompCatCacheDaemon, // Globals //=========================================================================================================================== -HINSTANCE gInstance = NULL; -int gDLLRefCount = 0; -CWinApp gApp; +HINSTANCE gInstance = NULL; +int gDLLRefCount = 0; +CExplorerPluginApp gApp; #if 0 #pragma mark - @@ -151,53 +145,83 @@ CWinApp gApp; #endif //=========================================================================================================================== -// DllMain +// CExplorerPluginApp::CExplorerPluginApp //=========================================================================================================================== -BOOL WINAPI DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved ) +IMPLEMENT_DYNAMIC(CExplorerPluginApp, CWinApp); + +CExplorerPluginApp::CExplorerPluginApp() { - BOOL ok; - OSStatus err; - - DEBUG_UNUSED( inReserved ); - - ok = TRUE; - switch( inReason ) - { - case DLL_PROCESS_ATTACH: - gInstance = inInstance; - debug_initialize( kDebugOutputTypeWindowsEventLog, "DNSServices Bar", inInstance ); - debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelTrace ); - dlog( kDebugLevelTrace, "\nDllMain: process attach\n" ); - - err = MFCDLLProcessAttach( inInstance ); - ok = ( err == kNoErr ); - require_noerr( err, exit ); - break; - - case DLL_PROCESS_DETACH: - dlog( kDebugLevelTrace, "DllMain: process detach\n" ); - MFCDLLProcessDetach( inInstance ); - break; - - case DLL_THREAD_ATTACH: - dlog( kDebugLevelTrace, "DllMain: thread attach\n" ); - break; - - case DLL_THREAD_DETACH: - dlog( kDebugLevelTrace, "DllMain: thread detach\n" ); - MFCDLLThreadDetach( inInstance ); - break; - - default: - dlog( kDebugLevelTrace, "DllMain: unknown reason code (%d)\n",inReason ); - break; - } - +} + + +//=========================================================================================================================== +// CExplorerPluginApp::~CExplorerPluginApp +//=========================================================================================================================== + +CExplorerPluginApp::~CExplorerPluginApp() +{ +} + + +//=========================================================================================================================== +// CExplorerPluginApp::InitInstance +//=========================================================================================================================== + +BOOL +CExplorerPluginApp::InitInstance() +{ + wchar_t resource[MAX_PATH]; + OSStatus err; + int res; + HINSTANCE inInstance; + + inInstance = AfxGetInstanceHandle(); + gInstance = inInstance; + + debug_initialize( kDebugOutputTypeWindowsEventLog, "DNSServices Bar", inInstance ); + debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelTrace ); + dlog( kDebugLevelTrace, "\nCCPApp::InitInstance\n" ); + + res = PathForResource( inInstance, L"ExplorerPluginResources.dll", resource, MAX_PATH ); + + err = translate_errno( res != 0, kUnknownErr, kUnknownErr ); + require_noerr( err, exit ); + + g_nonLocalizedResources = LoadLibrary( resource ); + translate_errno( g_nonLocalizedResources, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + + g_nonLocalizedResourcesName = resource; + + res = PathForResource( inInstance, L"ExplorerPluginLocalized.dll", resource, MAX_PATH ); + err = translate_errno( res != 0, kUnknownErr, kUnknownErr ); + require_noerr( err, exit ); + + g_localizedResources = LoadLibrary( resource ); + translate_errno( g_localizedResources, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + + AfxSetResourceHandle( g_localizedResources ); + exit: - return( ok ); + + return TRUE; +} + + +//=========================================================================================================================== +// CExplorerPluginApp::ExitInstance +//=========================================================================================================================== + +int +CExplorerPluginApp::ExitInstance() +{ + return 0; } + + //=========================================================================================================================== // DllCanUnloadNow //=========================================================================================================================== @@ -305,142 +329,6 @@ exit: return( err ); } -#if 0 -#pragma mark - -#pragma mark == MFC Support == -#endif - -//=========================================================================================================================== -// MFCDLLProcessAttach -//=========================================================================================================================== - -DEBUG_LOCAL OSStatus MFCDLLProcessAttach( HINSTANCE inInstance ) -{ - wchar_t resource[MAX_PATH]; - OSStatus err; - _AFX_THREAD_STATE * threadState; - AFX_MODULE_STATE * previousModuleState; - BOOL ok; - int res; - CWinApp * app; - - app = NULL; - - // Simulate what is done in dllmodul.cpp. - - threadState = AfxGetThreadState(); - check( threadState ); - previousModuleState = threadState->m_pPrevModuleState; - - ok = AfxWinInit( inInstance, NULL, TEXT( "" ), 0 ); - require_action( ok, exit, err = kUnknownErr ); - - app = AfxGetApp(); - require_action( ok, exit, err = kNotInitializedErr ); - - // Before we load the resources, let's load the error string - - // errorMessage.LoadString( IDS_REINSTALL ); - // errorCaption.LoadString( IDS_REINSTALL_CAPTION ); - - // Load Resources - - res = PathForResource( inInstance, L"ExplorerPluginResources.dll", resource, MAX_PATH ); - - err = translate_errno( res != 0, kUnknownErr, kUnknownErr ); - require_noerr( err, exit ); - - g_nonLocalizedResources = LoadLibrary( resource ); - translate_errno( g_nonLocalizedResources, GetLastError(), kUnknownErr ); - require_noerr( err, exit ); - - g_nonLocalizedResourcesName = resource; - - res = PathForResource( inInstance, L"ExplorerPluginLocalized.dll", resource, MAX_PATH ); - err = translate_errno( res != 0, kUnknownErr, kUnknownErr ); - require_noerr( err, exit ); - - g_localizedResources = LoadLibrary( resource ); - translate_errno( g_localizedResources, GetLastError(), kUnknownErr ); - require_noerr( err, exit ); - - AfxSetResourceHandle( g_localizedResources ); - - ok = app->InitInstance(); - require_action( ok, exit, err = kUnknownErr ); - - threadState->m_pPrevModuleState = previousModuleState; - threadState = NULL; - AfxInitLocalData( inInstance ); - err = kNoErr; - -exit: - if( err ) - { - if( app ) - { - app->ExitInstance(); - } - AfxWinTerm(); - } - if( threadState ) - { - threadState->m_pPrevModuleState = previousModuleState; - } - return( err ); -} - -//=========================================================================================================================== -// MFCDLLProcessDetach -//=========================================================================================================================== - -DEBUG_LOCAL void MFCDLLProcessDetach( HINSTANCE inInstance ) -{ - CWinApp * app; - - // Simulate what is done in dllmodul.cpp. - - app = AfxGetApp(); - if( app ) - { - app->ExitInstance(); - } - -#if( DEBUG ) - if( AfxGetModuleThreadState()->m_nTempMapLock != 0 ) - { - dlog( kDebugLevelWarning, "Warning: Temp map lock count non-zero (%ld).\n", AfxGetModuleThreadState()->m_nTempMapLock ); - } -#endif - - AfxLockTempMaps(); - AfxUnlockTempMaps( -1 ); - - // Terminate the library before destructors are called. - - AfxWinTerm(); - AfxTermLocalData( inInstance, TRUE ); -} - -//=========================================================================================================================== -// MFCDLLFinalize -//=========================================================================================================================== - -DEBUG_LOCAL void MFCDLLThreadDetach( HINSTANCE inInstance ) -{ - // Simulate what is done in dllmodul.cpp. - -#if( DEBUG ) - if( AfxGetModuleThreadState()->m_nTempMapLock != 0 ) - { - dlog( kDebugLevelWarning, "Warning: Temp map lock count non-zero (%ld).\n", AfxGetModuleThreadState()->m_nTempMapLock ); - } -#endif - - AfxLockTempMaps(); - AfxUnlockTempMaps( -1 ); - AfxTermThread( inInstance ); -} #if 0 #pragma mark - diff --git a/Clients/ExplorerPlugin/ExplorerPlugin.h b/Clients/ExplorerPlugin/ExplorerPlugin.h index d14edd3..307c99a 100644 --- a/Clients/ExplorerPlugin/ExplorerPlugin.h +++ b/Clients/ExplorerPlugin/ExplorerPlugin.h @@ -17,6 +17,10 @@ Change History (most recent first): $Log: ExplorerPlugin.h,v $ +Revision 1.5 2009/03/30 18:52:02 herscher + Current Bonjour code does not compile on Windows + Move build train to Visual Studio 2005 + Revision 1.4 2006/08/14 23:24:00 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -34,6 +38,8 @@ Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within */ +#pragma once + //=========================================================================================================================== // Globals //=========================================================================================================================== @@ -47,3 +53,18 @@ extern int gDLLRefCount; extern HINSTANCE GetNonLocalizedResources(); extern HINSTANCE GetLocalizedResources(); + +class CExplorerPluginApp : public CWinApp +{ +public: + + CExplorerPluginApp(); + virtual ~CExplorerPluginApp(); + +protected: + + virtual BOOL InitInstance(); + virtual int ExitInstance(); + + DECLARE_DYNAMIC(CExplorerPluginApp); +}; diff --git a/Clients/ExplorerPlugin/ExplorerPlugin.vcproj b/Clients/ExplorerPlugin/ExplorerPlugin.vcproj index 6a5c4fc..78e7443 100644 --- a/Clients/ExplorerPlugin/ExplorerPlugin.vcproj +++ b/Clients/ExplorerPlugin/ExplorerPlugin.vcproj @@ -1,172 +1,462 @@ + > + Name="Win32" + /> + + + + ATLMinimizesCRunTimeLibraryUsage="false" + CharacterSet="1" + > + + + + + + CompileAs="0" + /> + Name="VCManagedResourceCompilerTool" + /> + + + ImportLibrary="$(OutDir)/$(ProjectName).lib" + /> + + + + + + + + + + + + + + - + MkTypLibCompatible="true" + SuppressStartupBanner="true" + TargetEnvironment="3" + TypeLibraryName="$(OutDir)/$(ProjectName).tlb" + /> + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows" + PreprocessorDefinitions="_USRDLL;WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0501;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1" + StringPooling="true" + BasicRuntimeChecks="3" + RuntimeLibrary="1" + BufferSecurityCheck="true" + ForceConformanceInForLoopScope="true" + UsePrecompiledHeader="0" + PrecompiledHeaderFile="" + AssemblerListingLocation="$(IntDir)\" + ObjectFile="$(IntDir)\" + ProgramDataBaseFileName="$(IntDir)\vc80.pdb" + BrowseInformation="1" + WarningLevel="4" + WarnAsError="false" + SuppressStartupBanner="true" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + CallingConvention="2" + CompileAs="0" + /> + Name="VCManagedResourceCompilerTool" + /> + AdditionalIncludeDirectories="../../mDNSWindows" + /> + + + + + + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + Name="VCWebDeploymentTool" + /> + Name="VCPostBuildEventTool" + /> + ATLMinimizesCRunTimeLibraryUsage="false" + CharacterSet="1" + > + + + + + + WarnAsError="false" + SuppressStartupBanner="true" + Detect64BitPortabilityProblems="true" + CompileAs="0" + /> + Name="VCManagedResourceCompilerTool" + /> + + + ImportLibrary="$(IntDir)/$(ProjectName).lib" + /> + + + + + + + + + + + + + + - + MkTypLibCompatible="true" + SuppressStartupBanner="true" + TargetEnvironment="3" + TypeLibraryName="$(OutDir)/$(ProjectName).tlb" + /> + Name="VCCLCompilerTool" + Optimization="2" + InlineFunctionExpansion="2" + FavorSizeOrSpeed="2" + OmitFramePointers="true" + AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows" + PreprocessorDefinitions="_USRDLL;WIN32;NDEBUG;_WINDOWS;WINVER=0x0501;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1" + StringPooling="true" + RuntimeLibrary="0" + BufferSecurityCheck="true" + EnableFunctionLevelLinking="false" + ForceConformanceInForLoopScope="true" + UsePrecompiledHeader="0" + PrecompiledHeaderFile="" + AssemblerListingLocation="$(IntDir)\" + ObjectFile="$(IntDir)\" + ProgramDataBaseFileName="$(IntDir)\vc80.pdb" + BrowseInformation="1" + WarningLevel="4" + WarnAsError="false" + SuppressStartupBanner="true" + Detect64BitPortabilityProblems="true" + CompileAs="0" + /> + Name="VCManagedResourceCompilerTool" + /> + AdditionalIncludeDirectories="../../mDNSWindows" + /> + + + + + + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + Name="VCWebDeploymentTool" + /> + Name="VCPostBuildEventTool" + CommandLine="if not "%RC_XBS%" == "YES" goto END if not exist "$(DSTROOT)\Program Files\Bonjour\$(PlatformName)" mkdir "$(DSTROOT)\Program Files\Bonjour\$(PlatformName)" xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\Program Files\Bonjour\$(PlatformName)" :END " + /> @@ -174,102 +464,132 @@ + > + RelativePath="..\..\mDNSShared\CommonServices.h" + > + RelativePath="..\..\mDNSShared\DebugServices.c" + > + RelativePath="..\..\mDNSShared\DebugServices.h" + > + RelativePath="..\..\mDNSWindows\isocode.h" + > + RelativePath="..\..\mDNSWindows\loclibrary.c" + > + RelativePath="..\..\mDNSWindows\loclibrary.h" + > + RelativePath="..\..\mDNSWindows\WinServices.cpp" + > + RelativePath="..\..\mDNSWindows\WinServices.h" + > + Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm" + > + RelativePath="About.cpp" + > + RelativePath="ClassFactory.cpp" + > + RelativePath="ExplorerBar.cpp" + > + RelativePath="ExplorerBarWindow.cpp" + > + RelativePath="ExplorerPlugin.cpp" + > + RelativePath="ExplorerPlugin.def" + > + RelativePath="LoginDialog.cpp" + > + RelativePath="StdAfx.cpp" + > + Filter="h;hpp;hxx;hm;inl;inc" + > + RelativePath=".\About.h" + > + RelativePath="ClassFactory.h" + > + RelativePath="ExplorerBar.h" + > + RelativePath="ExplorerBarWindow.h" + > + RelativePath="ExplorerPlugin.h" + > + RelativePath="LoginDialog.h" + > + RelativePath="Resource.h" + > + RelativePath="resource_dll.h" + > + RelativePath="StdAfx.h" + > + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest" + > + RelativePath="ExplorerPlugin.rc" + > + Value="ExplorerPlugin.rc" + /> diff --git a/Clients/ExplorerPlugin/ExplorerPluginLocRes.rc b/Clients/ExplorerPlugin/ExplorerPluginLocRes.rc index 4d74187..b17cf3b 100755 --- a/Clients/ExplorerPlugin/ExplorerPluginLocRes.rc +++ b/Clients/ExplorerPlugin/ExplorerPluginLocRes.rc @@ -126,9 +126,11 @@ FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN CONTROL "",IDC_ABOUT_BACKGROUND,"Static",SS_BITMAP | SS_REALSIZEIMAGE,0,0, 220,86 - CONTROL MASTER_PROD_VERS_STR3,IDC_COMPONENT,"Static", + CONTROL "Explorer Plugin",IDC_COMPONENT,"Static", SS_SIMPLE | WS_GROUP,92,10,122,8 - LTEXT "Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved. Apple and the Apple logo are trademarks of Apple Computer, Inc., registered in the U.S. and other countries.", + CONTROL "",IDC_COMPONENT_VERSION,"Static", + SS_SIMPLE | WS_GROUP,142,10,122,8 + LTEXT "Copyright (c) 2004-2007 Apple Inc. All rights reserved. Apple and the Apple logo are trademarks of Apple Inc., registered in the U.S. and other countries.", IDC_LEGAL,92,31,123,50,0,WS_EX_RTLREADING END @@ -181,7 +183,7 @@ BEGIN IDS_NAME "Bonjour" IDS_WEB_SITES "Web Sites" IDS_PRINTERS "Printers" - IDS_MDNSRESPONDER_NOT_AVAILABLE "Bonjour Service Not Available" + IDS_MDNSRESPONDER_NOT_AVAILABLE "Bonjour Service is not available." IDS_FIREWALL "Check firewall settings" END diff --git a/Clients/ExplorerPlugin/ExplorerPluginLocRes.vcproj b/Clients/ExplorerPlugin/ExplorerPluginLocRes.vcproj index 71e630e..54b0392 100755 --- a/Clients/ExplorerPlugin/ExplorerPluginLocRes.vcproj +++ b/Clients/ExplorerPlugin/ExplorerPluginLocRes.vcproj @@ -1,33 +1,61 @@ + ProjectGUID="{1643427B-F226-4AD6-B413-97DA64D5C6B4}" + RootNamespace="ExplorerPluginLocRes" + > + Name="Win32" + /> + + + + ATLMinimizesCRunTimeLibraryUsage="false" + CharacterSet="1" + > + + + + + + CompileAs="0" + /> + Name="VCManagedResourceCompilerTool" + /> + + + ResourceOnlyDLL="true" + ImportLibrary="$(OutDir)/$(ProjectName).lib" + /> + + + + + + + + + + + + + + + MkTypLibCompatible="true" + SuppressStartupBanner="true" + TargetEnvironment="3" + TypeLibraryName="$(OutDir)/$(ProjectName).tlb" + /> + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\..\mDNSWindows" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400" + StringPooling="true" + BasicRuntimeChecks="3" + RuntimeLibrary="1" + ForceConformanceInForLoopScope="true" + UsePrecompiledHeader="0" + PrecompiledHeaderFile="" + AssemblerListingLocation=".\Debug/" + ObjectFile=".\Debug/" + ProgramDataBaseFileName=".\Debug/" + BrowseInformation="1" + WarningLevel="4" + WarnAsError="false" + SuppressStartupBanner="true" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + CallingConvention="2" + CompileAs="0" + /> - + Name="VCManagedResourceCompilerTool" + /> + AdditionalIncludeDirectories="../../mDNSWindows" + /> + + + + + + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + Name="VCWebDeploymentTool" + /> + Name="VCPostBuildEventTool" + /> + ATLMinimizesCRunTimeLibraryUsage="false" + CharacterSet="1" + > + + + + + + WarnAsError="false" + SuppressStartupBanner="true" + Detect64BitPortabilityProblems="true" + CompileAs="0" + /> + Name="VCManagedResourceCompilerTool" + /> + + + ResourceOnlyDLL="true" + ImportLibrary="$(IntDir)/$(ProjectName).lib" + /> + + + + + + + + + + + + + + - + MkTypLibCompatible="true" + SuppressStartupBanner="true" + TargetEnvironment="3" + TypeLibraryName="$(OutDir)/$(ProjectName).tlb" + /> + Name="VCCLCompilerTool" + Optimization="2" + InlineFunctionExpansion="2" + FavorSizeOrSpeed="2" + OmitFramePointers="true" + AdditionalIncludeDirectories="..\..\mDNSWindows" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0400" + StringPooling="true" + RuntimeLibrary="0" + BufferSecurityCheck="false" + EnableFunctionLevelLinking="false" + ForceConformanceInForLoopScope="true" + UsePrecompiledHeader="0" + PrecompiledHeaderFile="" + AssemblerListingLocation=".\Release/" + ObjectFile=".\Release/" + ProgramDataBaseFileName=".\Release/" + BrowseInformation="1" + WarningLevel="4" + WarnAsError="false" + SuppressStartupBanner="true" + Detect64BitPortabilityProblems="true" + CompileAs="0" + /> + Name="VCManagedResourceCompilerTool" + /> + AdditionalIncludeDirectories="../../mDNSWindows" + /> + + + + + + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + Name="VCWebDeploymentTool" + /> + Name="VCPostBuildEventTool" + CommandLine="if not "%RC_XBS%" == "YES" goto END if not exist "$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\ExplorerPlugin.Resources\en.lproj" mkdir "$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\ExplorerPlugin.Resources\en.lproj" xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\ExplorerPlugin.Resources\en.lproj" :END" + /> @@ -180,22 +461,27 @@ if not exist "Release\ExplorerPlugin.Resources\en.lproj" mkdir "R + Filter="h;hpp;hxx;hm;inl;inc" + > + RelativePath="resource_loc_res.h" + > + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest" + > + RelativePath="ExplorerPluginLocRes.rc" + > + Value="ExplorerPluginLocRes.rc" + /> diff --git a/Clients/ExplorerPlugin/ExplorerPluginRes.vcproj b/Clients/ExplorerPlugin/ExplorerPluginRes.vcproj index a0b83bb..3c73311 100755 --- a/Clients/ExplorerPlugin/ExplorerPluginRes.vcproj +++ b/Clients/ExplorerPlugin/ExplorerPluginRes.vcproj @@ -1,33 +1,60 @@ + ProjectGUID="{871B1492-B4A4-4B57-9237-FA798484D7D7}" + > + Name="Win32" + /> + + + + ATLMinimizesCRunTimeLibraryUsage="false" + CharacterSet="1" + > + + + + + + CompileAs="0" + /> + Name="VCManagedResourceCompilerTool" + /> + + + ResourceOnlyDLL="true" + ImportLibrary="$(OutDir)/$(ProjectName).lib" + /> + + + + + + + + + + + + + + + MkTypLibCompatible="true" + SuppressStartupBanner="true" + TargetEnvironment="3" + TypeLibraryName="$(OutDir)/$(ProjectName).tlb" + /> - + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\..\mDNSWindows" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400" + StringPooling="true" + BasicRuntimeChecks="3" + RuntimeLibrary="1" + ForceConformanceInForLoopScope="true" + UsePrecompiledHeader="0" + PrecompiledHeaderFile="" + AssemblerListingLocation=".\Debug/" + ObjectFile=".\Debug/" + ProgramDataBaseFileName=".\Debug/" + BrowseInformation="1" + WarningLevel="4" + WarnAsError="false" + SuppressStartupBanner="true" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + CallingConvention="2" + CompileAs="0" + /> + Name="VCManagedResourceCompilerTool" + /> + AdditionalIncludeDirectories="../../mDNSWindows" + /> + + + + + + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + Name="VCWebDeploymentTool" + /> + Name="VCPostBuildEventTool" + /> + ATLMinimizesCRunTimeLibraryUsage="false" + CharacterSet="1" + > + + + + + + WarnAsError="false" + SuppressStartupBanner="true" + Detect64BitPortabilityProblems="true" + CompileAs="0" + /> + Name="VCManagedResourceCompilerTool" + /> + + + ResourceOnlyDLL="true" + ImportLibrary="$(IntDir)/$(ProjectName).lib" + /> + + + + + + + + + + + + + + - + MkTypLibCompatible="true" + SuppressStartupBanner="true" + TargetEnvironment="3" + TypeLibraryName="$(OutDir)/$(ProjectName).tlb" + /> + Name="VCCLCompilerTool" + Optimization="2" + InlineFunctionExpansion="2" + FavorSizeOrSpeed="2" + OmitFramePointers="true" + AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0400" + StringPooling="true" + RuntimeLibrary="0" + BufferSecurityCheck="false" + EnableFunctionLevelLinking="false" + ForceConformanceInForLoopScope="true" + UsePrecompiledHeader="0" + PrecompiledHeaderFile="" + AssemblerListingLocation=".\Release/" + ObjectFile=".\Release/" + ProgramDataBaseFileName=".\Release/" + BrowseInformation="1" + WarningLevel="4" + WarnAsError="false" + SuppressStartupBanner="true" + Detect64BitPortabilityProblems="true" + CompileAs="0" + /> + Name="VCManagedResourceCompilerTool" + /> + AdditionalIncludeDirectories="../../mDNSWindows" + /> + + + + + + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + Name="VCWebDeploymentTool" + /> + Name="VCPostBuildEventTool" + CommandLine="if not "%RC_XBS%" == "YES" goto END if not exist "$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\ExplorerPlugin.Resources" mkdir "$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\ExplorerPlugin.Resources" xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\ExplorerPlugin.Resources" :END" + /> @@ -175,49 +456,63 @@ if not exist "Release\ExplorerPlugin.Resources" mkdir "Release\Ex + Filter="h;hpp;hxx;hm;inl;inc" + > + RelativePath="resource_res.h" + > + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest" + > + RelativePath="res\about.bmp" + > + RelativePath=".\about.bmp" + > + RelativePath="res\button-2k.ico" + > + RelativePath="res\button-xp.ico" + > + RelativePath=".\res\cold.ico" + > + RelativePath="ExplorerPluginRes.rc" + > + RelativePath=".\hot.ico" + > + RelativePath="res\logo.bmp" + > + RelativePath=".\logo.bmp" + > + RelativePath="Web.ico" + > + Value="ExplorerPluginRes.rc" + /> diff --git a/Clients/ExplorerPlugin/res/ExplorerPlugin.manifest b/Clients/ExplorerPlugin/res/ExplorerPlugin.manifest new file mode 100644 index 0000000..90a067e --- /dev/null +++ b/Clients/ExplorerPlugin/res/ExplorerPlugin.manifest @@ -0,0 +1,22 @@ + + + +Your app description here + + + + + + diff --git a/Clients/ExplorerPlugin/res/ExplorerPlugin64.manifest b/Clients/ExplorerPlugin/res/ExplorerPlugin64.manifest new file mode 100644 index 0000000..ddc54b5 --- /dev/null +++ b/Clients/ExplorerPlugin/res/ExplorerPlugin64.manifest @@ -0,0 +1,22 @@ + + + +Your app description here + + + + + + diff --git a/Clients/ExplorerPlugin/resource_dll.h b/Clients/ExplorerPlugin/resource_dll.h index 6374ce2..0fd2c90 100755 --- a/Clients/ExplorerPlugin/resource_dll.h +++ b/Clients/ExplorerPlugin/resource_dll.h @@ -9,6 +9,7 @@ #define IDS_FIREWALL 111 #define IDC_COMPONENT 1001 #define IDC_LEGAL 1002 +#define IDC_COMPONENT_VERSION 1003 #define IDC_LOGIN_USERNAME_TEXT 1182 #define IDC_LOGIN_PASSWORD_TEXT 1183 #define ID_Menu 40001 diff --git a/Clients/ExplorerPlugin/resource_loc_res.h b/Clients/ExplorerPlugin/resource_loc_res.h index ea18e83..f2e86cd 100755 --- a/Clients/ExplorerPlugin/resource_loc_res.h +++ b/Clients/ExplorerPlugin/resource_loc_res.h @@ -15,6 +15,7 @@ #define IDS_ABOUT_URL 148 #define IDC_COMPONENT 1001 #define IDC_LEGAL 1002 +#define IDC_COMPONENT_VERSION 1003 #define IDC_LOGIN_USERNAME_TEXT 1182 #define IDC_LOGIN_PASSWORD_TEXT 1183 #define ID_Menu 40001 diff --git a/Clients/ExplorerPlugin/resource_res.h b/Clients/ExplorerPlugin/resource_res.h index c4aae0a..44062be 100755 --- a/Clients/ExplorerPlugin/resource_res.h +++ b/Clients/ExplorerPlugin/resource_res.h @@ -13,6 +13,7 @@ #define IDB_ABOUT 119 #define IDC_COMPONENT 1001 #define IDC_LEGAL 1002 +#define IDC_COMPONENT_VERSION 1003 #define IDC_LOGIN_USERNAME_TEXT 1182 #define IDC_LOGIN_PASSWORD_TEXT 1183 #define ID_Menu 40001 diff --git a/Clients/Java/BrowserApp.java b/Clients/Java/BrowserApp.java index cbdd200..8f51215 100644 --- a/Clients/Java/BrowserApp.java +++ b/Clients/Java/BrowserApp.java @@ -54,7 +54,7 @@ import javax.swing.event.*; import com.apple.dnssd.*; -class BrowserApp implements ListSelectionListener, ResolveListener +class BrowserApp implements ListSelectionListener, ResolveListener, Runnable { static BrowserApp app; JFrame frame; @@ -63,6 +63,8 @@ class BrowserApp implements ListSelectionListener, ResolveListener JList domainPane, servicesPane, servicePane; DNSSDService servicesBrowser, serviceBrowser, domainBrowser; JLabel hostLabel, portLabel; + String hostNameForUpdate; + int portForUpdate; public BrowserApp() { @@ -170,22 +172,43 @@ class BrowserApp implements ListSelectionListener, ResolveListener serviceList.getNthServiceName( newSel), serviceList.getNthRegType( newSel), serviceList.getNthDomain( newSel), - new SwingResolveListener( this)); + this); } } } catch ( Exception ex) { terminateWithException( ex); } } + public void run() + { + hostLabel.setText( hostNameForUpdate); + portLabel.setText( String.valueOf( portForUpdate)); + } + public void serviceResolved( DNSSDService resolver, int flags, int ifIndex, String fullName, String hostName, int port, TXTRecord txtRecord) { - hostLabel.setText( hostName); - portLabel.setText( String.valueOf( port)); + // We want to update GUI on the AWT event dispatching thread, but we can't stop + // the resolve from that thread, since stop() is synchronized with this callback. + // So, we stop the resolve on this thread, then invokeAndWait on the AWT event thread. + + resolver.stop(); + + hostNameForUpdate = hostName; + portForUpdate = port; + + try { + SwingUtilities.invokeAndWait(this); + } + catch ( Exception e) + { + e.printStackTrace(); + } } public void operationFailed( DNSSDService service, int errorCode) { + service.stop(); // handle failure here } diff --git a/Clients/Java/JavaSamples.vcproj b/Clients/Java/JavaSamples.vcproj index fe6c134..fbb6825 100755 --- a/Clients/Java/JavaSamples.vcproj +++ b/Clients/Java/JavaSamples.vcproj @@ -1,36 +1,105 @@ + Keyword="MakeFileProj" + > + Name="Win32" + /> + + + + ConfigurationType="0" + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" + > + CleanCommandLine="nmake /f nmakefile DEBUG=1 CLEAN" + Output="" + PreprocessorDefinitions="" + IncludeSearchPath="" + ForcedIncludes="" + AssemblySearchPath="" + ForcedUsingAssemblies="" + CompileAsManaged="" + /> + ConfigurationType="0" + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" + > + + + + + + + CleanCommandLine="nmake /f nmakefile CLEAN" + Output="" + PreprocessorDefinitions="" + IncludeSearchPath="" + ForcedIncludes="" + AssemblySearchPath="" + ForcedUsingAssemblies="" + CompileAsManaged="" + /> diff --git a/Clients/Java/nmakefile b/Clients/Java/nmakefile index 9b08ccb..89168e0 100644 --- a/Clients/Java/nmakefile +++ b/Clients/Java/nmakefile @@ -55,7 +55,7 @@ BAOBJ = $(OBJDIR)\BrowserApp ############################################################################# -all: setup Java +all: setup Java postbuild # 'setup' sets up the build directory structure the way we want setup: @@ -66,6 +66,16 @@ setup: @if not exist $(BAOBJ) mkdir $(BAOBJ) @if not exist $(BUILDDIR) mkdir $(BUILDDIR) +postbuild: + @if not "%RC_XBS%"=="YES" GOTO END + @if not exist "$(DSTROOT)\Program Files\Bonjour SDK\Samples\Java" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\Samples\Java" + @copy "nmakefile" "$(DSTROOT)\Program Files\Bonjour SDK\Samples\Java" + @copy "BrowserApp.java" "$(DSTROOT)\Program Files\Bonjour SDK\Samples\Java" + @copy "SimpleChat.java" "$(DSTROOT)\Program Files\Bonjour SDK\Samples\Java" + @copy "Swing*.java" "$(DSTROOT)\Program Files\Bonjour SDK\Samples\Java" + @copy "$(BUILDDIR)\*.jar" "$(DSTROOT)\Program Files\Bonjour SDK\Samples\Java" + @:END + # clean removes targets and objects clean: @if exist $(OBJDIR) $(RMDIR) $(OBJDIR) @@ -84,8 +94,7 @@ SIMPLECHATMAN = SimpleChat.manifest $(BUILDDIR)\SimpleChat.jar: $(SIMPLECHATOBJ) $(SIMPLECHATMAN) $(JAR) -cfm $@ $(SIMPLECHATMAN) -C $(SCOBJ) . -BROWSERAPPOBJ = $(BAOBJ)\SwingResolveListener.class \ - $(BAOBJ)\BrowserApp.class +BROWSERAPPOBJ = $(BAOBJ)\BrowserApp.class BROWSERAPPMAN = BrowserApp.manifest $(BUILDDIR)\BrowserApp.jar: $(BROWSERAPPOBJ) $(BROWSERAPPMAN) diff --git a/Clients/Makefile b/Clients/Makefile index 3fbb8df..9703ced 100755 --- a/Clients/Makefile +++ b/Clients/Makefile @@ -15,6 +15,9 @@ # limitations under the License. # # $Log: Makefile,v $ +# Revision 1.12 2008/09/05 17:37:08 cheshire +# Need to include ClientCommon.c when building dns-sd +# # Revision 1.11 2007/05/29 19:57:33 cheshire # Use "-Wall" for stricter compiler warnings # @@ -77,10 +80,10 @@ clean: build: mkdir build -build/dns-sd: build dns-sd.c +build/dns-sd: build dns-sd.c ClientCommon.c cc $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -Wall -o $@ -build/dns-sd64: build dns-sd.c +build/dns-sd64: build dns-sd.c ClientCommon.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 diff --git a/Clients/PrinterSetupWizard/Logger.cpp b/Clients/PrinterSetupWizard/Logger.cpp new file mode 100644 index 0000000..c5ffabf --- /dev/null +++ b/Clients/PrinterSetupWizard/Logger.cpp @@ -0,0 +1,98 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + Change History (most recent first): + +$Log: Logger.cpp,v $ +Revision 1.3 2009/06/11 23:32:12 herscher + Follow the app data folder naming convention of Safari/iTunes on Windows + +Revision 1.2 2009/06/11 23:11:53 herscher + Log to user's app data folder + +Revision 1.1 2009/06/11 22:27:14 herscher + Add comprehensive logging during printer installation process. + + */ + +#include "stdafx.h" +#include "Logger.h" +#include "DebugServices.h" +#include + + +Logger::Logger() +{ + std::string tmp; + char path[ MAX_PATH ]; + HRESULT err; + BOOL ok; + + err = SHGetFolderPathA( NULL, CSIDL_LOCAL_APPDATA, NULL, 0, path ); + require_noerr( err, exit ); + + tmp = path; + + // Create Logs subdir + tmp += "\\Apple"; + ok = CreateDirectoryA( tmp.c_str(), NULL ); + require_action( ( ok || ( GetLastError() == ERROR_ALREADY_EXISTS ) ), exit, err = -1 ); + + // Create Logs subdir + tmp += "\\Bonjour"; + ok = CreateDirectoryA( tmp.c_str(), NULL ); + require_action( ( ok || ( GetLastError() == ERROR_ALREADY_EXISTS ) ), exit, err = -1 ); + + // Create log file + tmp += "\\PrinterSetupLog.txt"; + open( tmp.c_str()); + + *this << currentTime() << " Log started" << std::endl; + +exit: + + return; +} + + +Logger::~Logger() +{ + *this << currentTime() << " Log finished" << std::endl; + flush(); +} + + +std::string +Logger::currentTime() +{ + time_t ltime; + struct tm now; + int err; + std::string ret; + + time( <ime ); + err = localtime_s( &now, <ime ); + + if ( !err ) + { + char temp[ 64 ]; + + strftime( temp, sizeof( temp ), "%m/%d/%y %I:%M:%S %p", &now ); + ret = temp; + } + + return ret; +} diff --git a/Clients/PrinterSetupWizard/Logger.h b/Clients/PrinterSetupWizard/Logger.h new file mode 100644 index 0000000..c74c315 --- /dev/null +++ b/Clients/PrinterSetupWizard/Logger.h @@ -0,0 +1,71 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + Change History (most recent first): + +$Log: Logger.h,v $ +Revision 1.1 2009/06/11 22:27:15 herscher + Add comprehensive logging during printer installation process. + + + */ + +#ifndef _Logger_h +#define _Logger_h + +#include +#include + + +class Logger : public std::ofstream +{ +public: + + Logger(); + ~Logger(); + + std::string + currentTime(); +}; + + +#define require_noerr_with_log( LOG, MESSAGE, ERR, LABEL ) \ + do \ + { \ + int_least32_t localErr; \ + localErr = (int_least32_t)( ERR ); \ + if( localErr != 0 ) \ + { \ + log << log.currentTime() << " [ERROR] " << MESSAGE << " returned " << ERR << std::endl; \ + log << log.currentTime() << " [WHERE] " << "\"" << __FILE__ << "\", \"" << __FUNCTION__ << "\", line " << __LINE__ << std::endl << std::endl; \ + goto LABEL; \ + } \ + } while( 0 ) + + +#define require_action_with_log( LOG, X, LABEL, ACTION ) \ + do \ + { \ + if( !( X ) ) \ + { \ + log << log.currentTime() << " [ERROR] " << #X << std::endl; \ + log << log.currentTime() << " [WHERE] " << "\"" << __FILE__ << "\", \"" << __FUNCTION__ << "\", line " << __LINE__ << std::endl << std::endl; \ + { ACTION; } \ + goto LABEL; \ + } \ + } while( 0 ) + +#endif diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizard.rc b/Clients/PrinterSetupWizard/PrinterSetupWizard.rc index 982b0f2..d57bed5 100644 --- a/Clients/PrinterSetupWizard/PrinterSetupWizard.rc +++ b/Clients/PrinterSetupWizard/PrinterSetupWizard.rc @@ -119,13 +119,6 @@ BEGIN END -///////////////////////////////////////////////////////////////////////////// -// -// RT_MANIFEST -// - -IDR_MANIFEST RT_MANIFEST "res\\PrinterSetupWizard.manifest" - ///////////////////////////////////////////////////////////////////////////// // // String Table diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj b/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj index a4b4135..65f5324 100644 --- a/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj +++ b/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj @@ -1,140 +1,409 @@ + Keyword="MFCProj" + > + Name="Win32" + /> + + + + CharacterSet="2" + > + + + + + + DisableSpecificWarnings="4702" + /> + + + Name="VCPreLinkEventTool" + /> + TargetMachine="1" + /> + + + + + + + + + + + + + + - + MkTypLibCompatible="false" + TargetEnvironment="3" + /> + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories=".;../../mDNSWindows;../../mDNSShared" + PreprocessorDefinitions="WIN32;_WINDOWS;_DEBUGS;DEBUG=1;WINVER=0x0501;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1" + StringPooling="true" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="1" + BufferSecurityCheck="true" + TreatWChar_tAsBuiltInType="true" + UsePrecompiledHeader="0" + AssemblerListingLocation="$(IntDir)\" + WarningLevel="4" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + CallingConvention="0" + DisableSpecificWarnings="4702" + /> + Name="VCManagedResourceCompilerTool" + /> + AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows" + /> + + + + + Name="VCXDCMakeTool" + /> + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + Name="VCWebDeploymentTool" + /> + + CharacterSet="2" + > + + + + + + DisableSpecificWarnings="4702" + /> + Name="VCManagedResourceCompilerTool" + /> + + + TargetMachine="1" + /> + + + + + + + + + + + + + + - + MkTypLibCompatible="false" + TargetEnvironment="3" + /> + Name="VCCLCompilerTool" + Optimization="2" + InlineFunctionExpansion="1" + OmitFramePointers="true" + AdditionalIncludeDirectories=".;../../mDNSWindows;../../mDNSShared" + PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;WINVER=0x0501;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1" + StringPooling="true" + MinimalRebuild="false" + RuntimeLibrary="0" + EnableFunctionLevelLinking="true" + TreatWChar_tAsBuiltInType="true" + UsePrecompiledHeader="0" + AssemblerListingLocation="$(IntDir)\" + WarningLevel="4" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + DisableSpecificWarnings="4702" + /> + Name="VCManagedResourceCompilerTool" + /> + AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows" + /> + + + + Name="VCManifestTool" + AdditionalManifestFiles="res\PrinterSetupWizard64.manifest" + /> + Name="VCXDCMakeTool" + /> + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + + @@ -142,147 +411,240 @@ + Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm" + > + RelativePath=".\About.cpp" + > + RelativePath="FirstPage.cpp" + > + RelativePath=".\FourthPage.cpp" + > + RelativePath="PrinterSetupWizardApp.cpp" + > + RelativePath="PrinterSetupWizardSheet.cpp" + > + RelativePath="SecondPage.cpp" + > + RelativePath="stdafx.cpp" + > + RelativePath=".\StdioFileEx.cpp" + > + RelativePath="ThirdPage.cpp" + > + Filter="h;hpp;hxx;hm;inl;inc" + > + RelativePath=".\About.h" + > + RelativePath="FirstPage.h" + > + RelativePath=".\FourthPage.h" + > + RelativePath="PrinterSetupWizardApp.h" + > + RelativePath="PrinterSetupWizardSheet.h" + > + RelativePath="resource.h" + > + RelativePath="resource_exe.h" + > + RelativePath="SecondPage.h" + > + RelativePath="stdafx.h" + > + RelativePath=".\StdioFileEx.h" + > + RelativePath="ThirdPage.h" + > + RelativePath=".\UtilTypes.h" + > + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest" + > + RelativePath="res\about.bmp" + > + RelativePath="res\banner_icon.bmp" + > + RelativePath="res\Info.ico" + > + RelativePath="res\NetworkPrinter.ico" + > + RelativePath="res\Print.ico" + > + RelativePath="res\PrinterSetupWizard.manifest" + > + + + + + + + + + + + + + RelativePath="PrinterSetupWizard.rc" + > + RelativePath="res\watermark.bmp" + > + > + RelativePath="..\..\mDNSShared\CommonServices.h" + > + RelativePath="..\..\mDNSShared\DebugServices.c" + > + RelativePath="..\..\mDNSShared\DebugServices.h" + > + RelativePath="..\..\mDNSShared\dns_sd.h" + > + RelativePath="..\..\mDNSWindows\isocode.h" + > + RelativePath="..\..\mDNSWindows\loclibrary.c" + > + Name="Debug|Win32" + > + DisableSpecificWarnings="4201" + /> + + + + + + + + RelativePath=".\Logger.h" + > + RelativePath="..\..\mDNSWindows\WinServices.cpp" + > + RelativePath="..\..\mDNSWindows\WinServices.h" + > + RelativePath="ReadMe.txt" + > + Value="PrinterSetupWizard.rc" + /> diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp b/Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp index e9e255f..c811e7e 100644 --- a/Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp +++ b/Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp @@ -17,6 +17,9 @@ Change History (most recent first): $Log: PrinterSetupWizardApp.cpp,v $ +Revision 1.10 2009/05/26 05:38:18 herscher + use HeapSetInformation(HeapEnableTerminationOnCorruption) in dns-sd.exe and PrinterWizard.exe + Revision 1.9 2006/08/14 23:24:09 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -59,6 +62,11 @@ First checked in #define new DEBUG_NEW #endif +#ifndef HeapEnableTerminationOnCorruption +# define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS) 1 +#endif + + // Stash away pointers to our resource DLLs static HINSTANCE g_nonLocalizedResources = NULL; @@ -110,6 +118,8 @@ BOOL CPrinterSetupWizardApp::InitInstance() int res; OSStatus err = kNoErr; + HeapSetInformation( NULL, HeapEnableTerminationOnCorruption, NULL, 0 ); + // // initialize the debugging framework // diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.rc b/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.rc index ea189ec..d535344 100755 --- a/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.rc +++ b/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.rc @@ -171,8 +171,8 @@ BEGIN LTEXT "",IDC_PRINTER_MODEL,172,104,113,8 LTEXT "",IDC_PRINTER_PROTOCOL,172,117,113,8 LTEXT "",IDC_PRINTER_DEFAULT,172,130,113,8 - LTEXT "To complete the installation, click Finish.",IDC_STATIC,116,187, - 171,8 + LTEXT "To complete the installation, click Finish.",IDC_STATIC,116,180,171,8 + LTEXT "To change these settings, click Back.",IDC_STATIC,116,190,171,8 END IDD_DIALOG1 DIALOGEX 0, 0, 265, 130 @@ -256,6 +256,8 @@ BEGIN IDS_INSTALL_ERROR_CAPTION "Error" IDS_INSTALL_ERROR_MESSAGE "You do not have sufficient access to your computer to connect to the selected printer." + IDS_BAD_INF_FILE "The specified location does not contain information about your printer" + IDS_BAD_INF_FILE_CAPTION "Select Device" IDS_MANUFACTURER_HEADING "Manufacturer" IDS_MODEL_HEADING "Model" IDS_NO_PRINTERS "No Bonjour Printers are available" diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.vcproj b/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.vcproj index b961304..0627786 100755 --- a/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.vcproj +++ b/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.vcproj @@ -1,149 +1,405 @@ + ProjectGUID="{967F5375-0176-43D3-ADA3-22EE25551C37}" + Keyword="MFCProj" + > + Name="Win32" + /> + + + + CharacterSet="2" + > + + + + + + DisableSpecificWarnings="4702" + /> + + Name="VCResourceCompilerTool" + PreprocessorDefinitions="_DEBUG" + Culture="1033" + AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows" + /> + + TargetMachine="1" + /> + + + + + + + + + + + + + + - + MkTypLibCompatible="false" + TargetEnvironment="3" + /> + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\..\mDNSWindows" + PreprocessorDefinitions="WIN32;_WINDOWS;_DEBUGS;DEBUG=1;WINVER=0x0400;UNICODE;_UNICODE" + StringPooling="true" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="1" + BufferSecurityCheck="true" + TreatWChar_tAsBuiltInType="true" + UsePrecompiledHeader="0" + WarningLevel="4" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + CallingConvention="0" + DisableSpecificWarnings="4702" + /> + Name="VCManagedResourceCompilerTool" + /> + AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows" + /> + + + + + + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + Name="VCWebDeploymentTool" + /> + Name="VCPostBuildEventTool" + /> + CharacterSet="2" + > + + + + + + DisableSpecificWarnings="4702" + /> + Name="VCManagedResourceCompilerTool" + /> + + + TargetMachine="1" + /> + + + + + + + + + + + + + + + MkTypLibCompatible="false" + TargetEnvironment="3" + /> - + Name="VCCLCompilerTool" + Optimization="2" + InlineFunctionExpansion="1" + OmitFramePointers="true" + AdditionalIncludeDirectories="..\..\mDNSWindows" + PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;WINVER=0x0400;UNICODE;_UNICODE" + StringPooling="true" + MinimalRebuild="false" + RuntimeLibrary="0" + EnableFunctionLevelLinking="true" + TreatWChar_tAsBuiltInType="true" + UsePrecompiledHeader="0" + WarningLevel="4" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + DisableSpecificWarnings="4702" + /> + Name="VCManagedResourceCompilerTool" + /> + AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows" + /> + + + + + + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + Name="VCWebDeploymentTool" + /> + Name="VCPostBuildEventTool" + CommandLine="if not "%RC_XBS%" == "YES" goto END if not exist "$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\PrinterWizard.Resources\en.lproj" mkdir "$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\PrinterWizard.Resources\en.lproj" xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\PrinterWizard.Resources\en.lproj" :END" + /> @@ -151,28 +407,35 @@ if not exist "Release\PrinterWizard.Resources\en.lproj" mkdir "Re + Filter="h;hpp;hxx;hm;inl;inc" + > + RelativePath="resource_loc_dll.h" + > + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest" + > + RelativePath="PrinterSetupWizardLocRes.rc" + > + RelativePath="res\PrinterSetupWizardLocRes.rc2" + > + RelativePath="ReadMe.txt" + > + Value="PrinterSetupWizardLocRes.rc" + /> diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardRes.vcproj b/Clients/PrinterSetupWizard/PrinterSetupWizardRes.vcproj index e23103d..31c30c6 100755 --- a/Clients/PrinterSetupWizard/PrinterSetupWizardRes.vcproj +++ b/Clients/PrinterSetupWizard/PrinterSetupWizardRes.vcproj @@ -1,146 +1,405 @@ + ProjectGUID="{CFCCB176-6CAA-472B-B0A2-90511C8E2E52}" + Keyword="MFCProj" + > + Name="Win32" + /> + + + + CharacterSet="2" + > + + + + + + DisableSpecificWarnings="4702" + /> + + Name="VCResourceCompilerTool" + PreprocessorDefinitions="_DEBUG" + Culture="1033" + AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows" + /> + + TargetMachine="1" + /> + + + + + + + + + + + + + + - + MkTypLibCompatible="false" + TargetEnvironment="3" + /> + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\..\mDNSWindows" + PreprocessorDefinitions="WIN32;_WINDOWS;_DEBUGS;DEBUG=1;WINVER=0x0400;UNICODE;_UNICODE" + StringPooling="true" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="1" + BufferSecurityCheck="true" + TreatWChar_tAsBuiltInType="true" + UsePrecompiledHeader="0" + WarningLevel="4" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + CallingConvention="0" + DisableSpecificWarnings="4702" + /> + Name="VCManagedResourceCompilerTool" + /> + AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows" + /> + + + + + + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + Name="VCWebDeploymentTool" + /> + Name="VCPostBuildEventTool" + /> + CharacterSet="2" + > + + + + + + DisableSpecificWarnings="4702" + /> + Name="VCManagedResourceCompilerTool" + /> + + + TargetMachine="1" + /> + + + + + + + + + + + + + + + MkTypLibCompatible="false" + TargetEnvironment="3" + /> - + Name="VCCLCompilerTool" + Optimization="2" + InlineFunctionExpansion="1" + OmitFramePointers="true" + AdditionalIncludeDirectories="..\..\mDNSWindows" + PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;WINVER=0x0400;UNICODE;_UNICODE" + StringPooling="true" + MinimalRebuild="false" + RuntimeLibrary="0" + EnableFunctionLevelLinking="true" + TreatWChar_tAsBuiltInType="true" + UsePrecompiledHeader="0" + WarningLevel="4" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + DisableSpecificWarnings="4702" + /> + Name="VCManagedResourceCompilerTool" + /> + AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows" + /> + + + + + + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + Name="VCWebDeploymentTool" + /> + Name="VCPostBuildEventTool" + CommandLine="if not "%RC_XBS%" == "YES" goto END if not exist "$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\PrinterWizard.Resources" mkdir "$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\PrinterWizard.Resources" xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\PrinterWizard.Resources" :END" + /> @@ -148,58 +407,75 @@ if not exist "Release\PrinterWizard.Resources" mkdir "Release\Pri + Filter="h;hpp;hxx;hm;inl;inc" + > + RelativePath="resource_dll.h" + > + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest" + > + RelativePath=".\res\about.bmp" + > + RelativePath="res\banner_icon.bmp" + > + RelativePath=".\res\Info.ico" + > + RelativePath=".\res\NetworkPrinter.ico" + > + RelativePath=".\res\Print.ico" + > + RelativePath=".\res\Printer.bmp" + > + RelativePath=".\res\Printer.ico" + > + RelativePath=".\res\Printer2.ico" + > + RelativePath="res\PrinterSetupWizard.ico" + > + RelativePath="PrinterSetupWizardRes.rc" + > + RelativePath="res\PrinterSetupWizardRes.rc2" + > + RelativePath="res\watermark.bmp" + > + RelativePath="ReadMe.txt" + > + Value="PrinterSetupWizardRes.rc" + /> diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp index e912716..565c6ea 100644 --- a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp +++ b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp @@ -17,6 +17,24 @@ Change History (most recent first): $Log: PrinterSetupWizardSheet.cpp,v $ +Revision 1.40 2009/06/18 18:05:50 herscher + Eliminate the first screen of Printer Wizard and maybe combine others ("I'm Feeling Lucky") + +Revision 1.39 2009/06/11 22:27:16 herscher + Add comprehensive logging during printer installation process. + +Revision 1.38 2009/05/27 04:49:02 herscher + Consider setting DoubleSpool for LPR queues to improve compatibility + +Revision 1.37 2009/03/30 19:17:37 herscher + Current Bonjour code does not compile on Windows + Printer Wizard crashes on launch when Bonjour Service isn't running + Buffer overflow in PrinterWizard when printer dns hostname is too long + Move build train to Visual Studio 2005 + +Revision 1.36 2008/10/23 22:33:23 cheshire +Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu + Revision 1.35 2006/08/14 23:24:09 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -279,7 +297,7 @@ exit: // // Installs a printer with Windows. // -// NOTE: this works one of two ways, depending on whether +// Note: this works one of two ways, depending on whether // there are drivers already installed for this printer. // If there are, then we can just create a port with XcvData, // and then call AddPrinter. If not, we use the printui.dll @@ -292,9 +310,10 @@ exit: OSStatus CPrinterSetupWizardSheet::InstallPrinter(Printer * printer) { + Logger log; Service * service; BOOL ok; - OSStatus err; + OSStatus err = 0; service = printer->services.front(); check( service ); @@ -316,7 +335,7 @@ CPrinterSetupWizardSheet::InstallPrinter(Printer * printer) // hThread = (HANDLE) _beginthreadex_compat( NULL, 0, InstallDriverThread, printer, 0, &threadID ); err = translate_errno( hThread, (OSStatus) GetLastError(), kUnknownErr ); - require_noerr( err, exit ); + require_noerr_with_log( log, "_beginthreadex_compat()", err, exit ); // // go modal @@ -329,18 +348,18 @@ CPrinterSetupWizardSheet::InstallPrinter(Printer * printer) TranslateMessage(&msg); DispatchMessage(&msg); } - + // // Wait until child process exits. // dwResult = WaitForSingleObject( hThread, INFINITE ); err = translate_errno( dwResult == WAIT_OBJECT_0, errno_compat(), err = kUnknownErr ); - require_noerr( err, exit ); + require_noerr_with_log( log, "WaitForSingleObject()", err, exit ); // // check the return value of thread // - require_noerr( m_driverThreadExitCode, exit ); + require_noerr_with_log( log, "thread exit code", m_driverThreadExitCode, exit ); // // now we know that the driver was successfully installed @@ -350,23 +369,22 @@ CPrinterSetupWizardSheet::InstallPrinter(Printer * printer) if ( service->type == kPDLServiceType ) { - err = InstallPrinterPDLAndLPR( printer, service, PROTOCOL_RAWTCP_TYPE ); - require_noerr( err, exit ); + err = InstallPrinterPDLAndLPR( printer, service, PROTOCOL_RAWTCP_TYPE, log ); + require_noerr_with_log( log, "InstallPrinterPDLAndLPR()", err, exit ); } else if ( service->type == kLPRServiceType ) { - err = InstallPrinterPDLAndLPR( printer, service, PROTOCOL_LPR_TYPE ); - require_noerr( err, exit ); + err = InstallPrinterPDLAndLPR( printer, service, PROTOCOL_LPR_TYPE, log ); + require_noerr_with_log( log, "InstallPrinterPDLAndLPR()", err, exit ); } else if ( service->type == kIPPServiceType ) { - err = InstallPrinterIPP( printer, service ); - require_noerr( err, exit ); + err = InstallPrinterIPP( printer, service, log ); + require_noerr_with_log( log, "InstallPrinterIPP()", err, exit ); } else { - err = kUnknownErr; - require_noerr( err, exit ); + require_action_with_log( log, ( service->type == kPDLServiceType ) || ( service->type == kLPRServiceType ) || ( service->type == kIPPServiceType ), exit, err = kUnknownErr ); } printer->installed = true; @@ -378,7 +396,7 @@ CPrinterSetupWizardSheet::InstallPrinter(Printer * printer) { ok = SetDefaultPrinter( printer->actualName ); err = translate_errno( ok, errno_compat(), err = kUnknownErr ); - require_noerr( err, exit ); + require_noerr_with_log( log, "SetDefaultPrinter()", err, exit ); } exit: @@ -388,7 +406,7 @@ exit: OSStatus -CPrinterSetupWizardSheet::InstallPrinterPDLAndLPR(Printer * printer, Service * service, DWORD protocol ) +CPrinterSetupWizardSheet::InstallPrinterPDLAndLPR(Printer * printer, Service * service, DWORD protocol, Logger & log ) { PRINTER_DEFAULTS printerDefaults = { NULL, NULL, SERVER_ACCESS_ADMINISTER }; DWORD dwStatus; @@ -411,7 +429,7 @@ CPrinterSetupWizardSheet::InstallPrinterPDLAndLPR(Printer * printer, Service * s ok = OpenPrinter(L",XcvMonitor Standard TCP/IP Port", &hXcv, &printerDefaults); err = translate_errno( ok, errno_compat(), kUnknownErr ); - require_noerr( err, exit ); + require_noerr_with_log( log, "OpenPrinter()", err, exit ); // // BUGBUG: MSDN said this is not required, but my experience shows it is required @@ -425,28 +443,33 @@ CPrinterSetupWizardSheet::InstallPrinterPDLAndLPR(Printer * printer, Service * s pOutputData = NULL; } - require_action( pOutputData, exit, err = kNoMemoryErr ); + require_action_with_log( log, pOutputData, exit, err = kNoMemoryErr ); // // setup the port // ZeroMemory(&portData, sizeof(PORT_DATA_1)); - wcscpy(portData.sztPortName, printer->portName); + + require_action_with_log( log, wcslen(printer->portName) < sizeof_array(portData.sztPortName), exit, err = kSizeErr ); + wcscpy_s(portData.sztPortName, printer->portName); portData.dwPortNumber = service->portNumber; portData.dwVersion = 1; + portData.dwDoubleSpool = 1; portData.dwProtocol = protocol; portData.cbSize = sizeof PORT_DATA_1; portData.dwReserved = 0L; - wcscpy(portData.sztQueue, q->name); - wcscpy(portData.sztIPAddress, service->hostname); - wcscpy(portData.sztHostAddress, service->hostname); + require_action_with_log( log, wcslen(q->name) < sizeof_array(portData.sztQueue), exit, err = kSizeErr ); + wcscpy_s(portData.sztQueue, q->name); + + require_action_with_log( log, wcslen( service->hostname ) < sizeof_array(portData.sztHostAddress), exit, err = kSizeErr ); + wcscpy_s( portData.sztHostAddress, service->hostname ); ok = XcvData(hXcv, L"AddPort", (PBYTE) &portData, sizeof(PORT_DATA_1), pOutputData, cbInputData, &cbOutputNeeded, &dwStatus); err = translate_errno( ok, errno_compat(), kUnknownErr ); - require_noerr( err, exit ); + require_noerr_with_log( log, "XcvData()", err, exit ); // // add the printer @@ -475,7 +498,7 @@ CPrinterSetupWizardSheet::InstallPrinterPDLAndLPR(Printer * printer, Service * s hPrinter = AddPrinter(NULL, 2, (LPBYTE) &pInfo); err = translate_errno( hPrinter, errno_compat(), kUnknownErr ); - require_noerr( err, exit ); + require_noerr_with_log( log, "AddPrinter()", err, exit ); exit: @@ -499,7 +522,7 @@ exit: OSStatus -CPrinterSetupWizardSheet::InstallPrinterIPP(Printer * printer, Service * service) +CPrinterSetupWizardSheet::InstallPrinterIPP(Printer * printer, Service * service, Logger & log) { DEBUG_UNUSED( service ); @@ -525,7 +548,7 @@ CPrinterSetupWizardSheet::InstallPrinterIPP(Printer * printer, Service * service hPrinter = AddPrinter(NULL, 2, (LPBYTE)&pInfo); err = translate_errno( hPrinter, errno_compat(), kUnknownErr ); - require_noerr( err, exit ); + require_noerr_with_log( log, "AddPrinter()", err, exit ); exit: @@ -596,12 +619,14 @@ exit: } else { - CPrinterSetupWizardSheet::WizardException exc; - - exc.text.LoadString( IDS_NO_MDNSRESPONDER_SERVICE_TEXT ); - exc.caption.LoadString( IDS_ERROR_CAPTION ); - - throw(exc); + CString text, caption; + + text.LoadString( IDS_NO_MDNSRESPONDER_SERVICE_TEXT ); + caption.LoadString( IDS_ERROR_CAPTION ); + + MessageBox(text, caption, MB_OK|MB_ICONEXCLAMATION); + + _exit( 0 ); } } @@ -676,7 +701,6 @@ CPrinterSetupWizardSheet::OnOK() void CPrinterSetupWizardSheet::Init(void) { - AddPage(&m_pgFirst); AddPage(&m_pgSecond); AddPage(&m_pgThird); AddPage(&m_pgFourth); @@ -693,7 +717,7 @@ void CPrinterSetupWizardSheet::Init(void) } -LONG +LRESULT CPrinterSetupWizardSheet::OnSocketEvent(WPARAM inWParam, LPARAM inLParam) { if (WSAGETSELECTERROR(inLParam) && !(HIWORD(inLParam))) @@ -726,7 +750,7 @@ CPrinterSetupWizardSheet::OnSocketEvent(WPARAM inWParam, LPARAM inLParam) } -LONG +LRESULT CPrinterSetupWizardSheet::OnProcessEvent(WPARAM inWParam, LPARAM inLParam) { DEBUG_UNUSED(inLParam); diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h index b9cc5ff..5e2306b 100644 --- a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h +++ b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h @@ -17,6 +17,13 @@ Change History (most recent first): $Log: PrinterSetupWizardSheet.h,v $ +Revision 1.14 2009/06/11 22:27:16 herscher + Add comprehensive logging during printer installation process. + +Revision 1.13 2009/03/30 19:18:49 herscher + Current Bonjour code does not compile on Windows + Move build train to Visual Studio 2005 + Revision 1.12 2006/08/14 23:24:09 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -67,6 +74,7 @@ First checked in #include "thirdpage.h" #include "fourthpage.h" #include "UtilTypes.h" +#include "Logger.h" #include "dns_sd.h" #include #include @@ -113,10 +121,10 @@ public: // // handles end of process event // - virtual LONG + virtual LRESULT OnProcessEvent(WPARAM inWParam, LPARAM inLParam); - virtual LONG + virtual LRESULT OnSocketEvent(WPARAM inWParam, LPARAM inLParam); virtual BOOL @@ -265,10 +273,10 @@ private: InstallPrinter(Printer * printer); OSStatus - InstallPrinterPDLAndLPR(Printer * printer, Service * service, DWORD protocol); + InstallPrinterPDLAndLPR(Printer * printer, Service * service, DWORD protocol, Logger & log); OSStatus - InstallPrinterIPP(Printer * printer, Service * service); + InstallPrinterIPP(Printer * printer, Service * service, Logger & log); static unsigned WINAPI InstallDriverThread( LPVOID inParam ); diff --git a/Clients/PrinterSetupWizard/SecondPage.cpp b/Clients/PrinterSetupWizard/SecondPage.cpp index 83e6685..4bed3f7 100644 --- a/Clients/PrinterSetupWizard/SecondPage.cpp +++ b/Clients/PrinterSetupWizard/SecondPage.cpp @@ -17,6 +17,9 @@ Change History (most recent first): $Log: SecondPage.cpp,v $ +Revision 1.20 2009/06/18 18:05:50 herscher + Eliminate the first screen of Printer Wizard and maybe combine others ("I'm Feeling Lucky") + Revision 1.19 2006/08/14 23:24:09 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -225,12 +228,20 @@ CSecondPage::OnSetActive() OnAddPrinter( *it, false ); } - // And if we hit 'Back' from page 3, then re-select printer - - if ( ( psheet->GetLastPage() == psheet->GetPage( 2 ) ) && printer ) + if ( ( !printer && ( psheet->m_printers.size() > 0 ) ) || ( printer != psheet->GetSelectedPrinter() ) ) { + if ( !printer ) + { + printer = psheet->m_printers.front(); + } + psheet->SetSelectedPrinter( printer ); - m_browseList.Select( printer->item, TVGN_FIRSTVISIBLE ); + } + + if ( printer ) + { + m_browseList.SelectItem( printer->item ); + ::SetFocus( m_browseList ); } exit: @@ -270,6 +281,7 @@ CSecondPage::OnAddPrinter( bool moreComing ) { CPrinterSetupWizardSheet * psheet; + Printer * selectedPrinter; OSStatus err = kNoErr; check( IsWindow( m_hWnd ) ); @@ -278,6 +290,8 @@ CSecondPage::OnAddPrinter( psheet = reinterpret_cast(GetParent()); require_quiet( psheet, exit ); + + selectedPrinter = psheet->GetSelectedPrinter(); printer->item = m_browseList.InsertItem(printer->displayName); @@ -301,6 +315,13 @@ CSecondPage::OnAddPrinter( m_browseList.EnableWindow(TRUE); } + if ( !selectedPrinter ) + { + psheet->SetSelectedPrinter( printer ); + m_browseList.SelectItem( printer->item ); + ::SetFocus( m_browseList ); + } + exit: if (!moreComing) diff --git a/Clients/PrinterSetupWizard/ThirdPage.cpp b/Clients/PrinterSetupWizard/ThirdPage.cpp index 4c156fd..f3d0432 100644 --- a/Clients/PrinterSetupWizard/ThirdPage.cpp +++ b/Clients/PrinterSetupWizard/ThirdPage.cpp @@ -17,6 +17,19 @@ Change History (most recent first): $Log: ThirdPage.cpp,v $ +Revision 1.41 2009/06/18 18:05:50 herscher + Eliminate the first screen of Printer Wizard and maybe combine others ("I'm Feeling Lucky") + +Revision 1.40 2009/05/29 20:43:36 herscher + Printer Wizard doesn't work correctly in Windows 7 64 bit + +Revision 1.39 2009/05/27 06:25:49 herscher + Need error dialog when selecting bad INF file + +Revision 1.38 2009/05/27 04:59:57 herscher + COMPATIBILITY WITH HP CLJ4700 + Compatibility with Samsung print driver files + Revision 1.37 2007/06/08 06:30:26 herscher Fix uninitialized pointers when detecting generic PCL and PS drivers @@ -150,6 +163,7 @@ First checked in #include #include #include +#include // local variable is initialize but not referenced #pragma warning(disable:4189) @@ -179,16 +193,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 -// -enum PrinterParsingState -{ - Looking, - ParsingManufacturers, - ParsingModels, - ParsingStrings -}; // CThirdPage dialog @@ -478,24 +482,6 @@ CThirdPage::AutoScroll( CListCtrl & list, int nIndex ) // ------------------------------------------------------ // LoadPrintDriverDefsFromFile // -// This function does all the heavy lifting in parsing inf -// files. It is called to parse both ntprint.inf, and driver -// files that might be shipped on a printer's installation -// disk -// -// The inf file is not totally parsed. I only want to determine -// the manufacturer and models that are involved. I leave it -// to printui.dll to actually copy the driver files to the -// right places. -// -// I was aiming to parse as little as I could so as not to -// duplicate the parsing code that is contained in Windows. There -// are no public APIs for parsing inf files. -// -// That part of the inf file that we're interested in has a fairly -// 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 // checkForDuplicateModels flag. The problem here is that ntprint.inf // doesn't contain duplicate models, and it has hundreds of models @@ -508,345 +494,193 @@ CThirdPage::AutoScroll( CListCtrl & list, int nIndex ) OSStatus CThirdPage::LoadPrintDriverDefsFromFile(Manufacturers & manufacturers, const CString & filename, bool checkForDuplicateModels ) { - PrinterParsingState state = Looking; - Manufacturers::iterator iter = manufacturers.end(); - CStdioFileEx file; - CFileException feError; - CString s; - OSStatus err; - BOOL ok; - - typedef std::map StringMap; + HINF handle = INVALID_HANDLE_VALUE; + const TCHAR * section = TEXT( "Manufacturer" ); + LONG sectionCount; + TCHAR line[ 1000 ]; + CString klass; + INFCONTEXT manufacturerContext; + BOOL ok; + OSStatus err = 0; + + // Make sure we can open the file + handle = SetupOpenInfFile( filename, NULL, INF_STYLE_WIN4, NULL ); + translate_errno( handle != INVALID_HANDLE_VALUE, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); - StringMap strings; - - ok = file.Open( filename, CFile::modeRead|CFile::typeText, &feError); - err = translate_errno( ok, errno_compat(), kUnknownErr ); + // Make sure it's a printer file + ok = SetupGetLineText( NULL, handle, TEXT( "Version" ), TEXT( "Class" ), line, sizeof( line ), NULL ); + translate_errno( ok, GetLastError(), kUnknownErr ); require_noerr( err, exit ); + klass = line; + require_action( klass == TEXT( "Printer" ), exit, err = kUnknownErr ); - check ( state == Looking ); - check ( iter == manufacturers.end() ); + sectionCount = SetupGetLineCount( handle, section ); + translate_errno( sectionCount != -1, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); - // - // first, parse the file looking for string sections - // - while (file.ReadString(s)) + memset( &manufacturerContext, 0, sizeof( manufacturerContext ) ); + + for ( LONG i = 0; i < sectionCount; i++ ) { - // - // check for comment - // - if (s.Find(';') == 0) + Manufacturers::iterator iter; + Manufacturer * manufacturer; + CString manufacturerName; + CString temp; + CStringList modelSectionNameDecl; + CString modelSectionName; + CString baseModelName; + CString model; + INFCONTEXT modelContext; + LONG modelCount; + POSITION p; + + if ( i == 0 ) { - continue; - } - - // - // check for tag - // - else if (s.Find('[') == 0) - { - // - // handle any capitalization issues here - // - CString tag = s; - - tag.MakeLower(); - - if (tag == L"[strings]") - { - state = ParsingStrings; - } - else - { - state = Looking; - } + ok = SetupFindFirstLine( handle, section, NULL, &manufacturerContext ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); } else { - switch (state) - { - case ParsingStrings: - { - int curPos = 0; - - if (s.GetLength() > 0) - { - CString key = s.Tokenize(L"=",curPos); - CString val = s.Tokenize(L"=",curPos); - - // - // get rid of all delimiters - // - key.Trim(); - val.Remove('"'); - - // - // and store it - // - strings[key] = val; - } - } - break; - } + ok = SetupFindNextLine( &manufacturerContext, &manufacturerContext ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); } - } - - file.Close(); - ok = file.Open( filename, CFile::modeRead|CFile::typeText, &feError); - err = translate_errno( ok, errno_compat(), kUnknownErr ); - require_noerr( err, exit ); - - state = Looking; + ok = SetupGetStringField( &manufacturerContext, 0, line, sizeof( line ), NULL ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + manufacturerName = line; - check ( iter == manufacturers.end() ); + ok = SetupGetLineText( &manufacturerContext, handle, NULL, NULL, line, sizeof( line ), NULL ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); - while (file.ReadString(s)) - { + // Try to find some model section name that has entries. Explanation of int file structure + // can be found at: // - // check for comment - // - if (s.Find(';') == 0) + // + Split( line, ',', modelSectionNameDecl ); + + p = modelSectionNameDecl.GetHeadPosition(); + modelSectionName = modelSectionNameDecl.GetNext( p ); + modelCount = SetupGetLineCount( handle, modelSectionName ); + baseModelName = modelSectionName; + + while ( modelCount <= 0 && p ) { - continue; + CString targetOSVersion; + + targetOSVersion = modelSectionNameDecl.GetNext( p ); + modelSectionName = baseModelName + TEXT( "." ) + targetOSVersion; + modelCount = SetupGetLineCount( handle, modelSectionName ); } - // - // check for tag - // - else if (s.Find('[') == 0) + if ( modelCount > 0 ) { - // - // handle any capitalization issues here - // - CString tag = s; + manufacturerName = NormalizeManufacturerName( manufacturerName ); - tag.MakeLower(); + iter = manufacturers.find( manufacturerName ); - if (tag == L"[manufacturer]") + if ( iter != manufacturers.end() ) { - state = ParsingManufacturers; + manufacturer = iter->second; + require_action( manufacturer, exit, err = kUnknownErr ); } 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( name ); - - if (iter != manufacturers.end()) + try { - state = ParsingModels; + manufacturer = new Manufacturer; } - else + catch (...) { - state = Looking; + manufacturer = NULL; } - } - } - // - // only look at this if the line isn't empty, or - // if it isn't a comment - // - else if ((s.GetLength() > 0) && (s.Find(';') != 0)) - { - switch (state) - { - // - // 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 - // delimited by either '"' (quotes) or '%' (percent sign). - // - // the tag is used further down the file when models are - // declared. this allows multiple manufacturers to exist - // in a single inf file. - // - case ParsingManufacturers: - { - Manufacturer * manufacturer; - int curPos = 0; - - CString key = s.Tokenize(L"=",curPos); - CString val = s.Tokenize(L"=",curPos); - - try - { - manufacturer = new Manufacturer; - } - catch (...) - { - manufacturer = NULL; - } - - require_action( manufacturer, exit, err = kNoMemoryErr ); - - // - // if it's a variable, look it up - // - if (key.Find('%') == 0) - { - StringMap::iterator it; - key.Remove('%'); - - it = strings.find(key); - - if (it != strings.end()) - { - key = it->second; - } - } - else - { - key.Remove('"'); - } - - val.TrimLeft(); - val.TrimRight(); - - // - // why is there no consistency in inf files? - // - if (val.GetLength() == 0) - { - val = key; - } + require_action( manufacturer, exit, err = kNoMemoryErr ); - // - // fix the manufacturer name if necessary - // - curPos = 0; - val = val.Tokenize(L",", curPos); + manufacturer->name = manufacturerName; + manufacturers[ manufacturerName ] = manufacturer; + } - for ( ;; ) - { - CString decoration; - - decoration = val.Tokenize( L",", curPos ); - - if ( decoration.GetLength() > 0 ) - { - manufacturer->decorations.push_back( decoration ); - } - else - { - break; - } - } + memset( &modelContext, 0, sizeof( modelContext ) ); - manufacturer->name = NormalizeManufacturerName( key ); - manufacturer->tag = val; + for ( LONG j = 0; j < modelCount; j++ ) + { + CString modelName; + Model * model; - manufacturers[val] = manufacturer; + if ( j == 0 ) + { + ok = SetupFindFirstLine( handle, modelSectionName, NULL, &modelContext ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); } - break; - - case ParsingModels: + else { - check( iter != manufacturers.end() ); - - Model * model; - int curPos = 0; - - CString name = s.Tokenize(L"=",curPos); - CString description = s.Tokenize(L"=",curPos); - - if (name.Find('%') == 0) - { - StringMap::iterator it; - - name.Remove('%'); + SetupFindNextLine( &modelContext, &modelContext ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + } - it = strings.find(name); + ok = SetupGetStringField( &modelContext, 0, line, sizeof( line ), NULL ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); - if (it != strings.end()) - { - name = it->second; - } - } - else - { - name.Remove('"'); - } + modelName = line; - name.Trim(); - description.Trim(); - - // - // If true, see if we've seen this guy before - // - if (checkForDuplicateModels == true) - { - if ( MatchModel( iter->second, ConvertToModelName( name ) ) != NULL ) - { - continue; - } - } - - // - // Stock Vista printer inf files embed guids in the model - // declarations for Epson printers. Let's ignore those. - // - if ( name.Find( L"{", 0 ) != -1 ) + if (checkForDuplicateModels == true) + { + if ( MatchModel( manufacturer, ConvertToModelName( modelName ) ) != NULL ) { continue; } + } - try - { - model = new Model; - } - catch (...) - { - model = NULL; - } - - require_action( model, exit, err = kNoMemoryErr ); - - model->infFileName = filename; - model->displayName = name; - model->name = name; - model->driverInstalled = false; - - iter->second->models.push_back(model); + // + // Stock Vista printer inf files embed guids in the model + // declarations for Epson printers. Let's ignore those. + // + if ( modelName.Find( TEXT( "{" ), 0 ) != -1 ) + { + continue; } - break; - default: + try + { + model = new Model; + } + catch (...) { - // pay no attention if we are in any other state + model = NULL; } - break; + + require_action( model, exit, err = kNoMemoryErr ); + + model->infFileName = filename; + model->displayName = modelName; + model->name = modelName; + model->driverInstalled = false; + + manufacturer->models.push_back(model); } } } exit: - file.Close(); + if ( handle != INVALID_HANDLE_VALUE ) + { + SetupCloseInfFile( handle ); + handle = NULL; + } - return (err); + return err; } + // ------------------------------------------------------- // LoadPrintDriverDefs // @@ -1622,9 +1456,14 @@ CThirdPage::OnSetActive() // and try and match the printer // - if ( psheet->GetLastPage() == psheet->GetPage(1) ) + if ( psheet->GetLastPage() == psheet->GetPage(0) ) { MatchPrinter( m_manufacturers, printer, service, true ); + + if ( ( m_manufacturerSelected != NULL ) && ( m_modelSelected != NULL ) ) + { + GetParent()->PostMessage(PSM_SETCURSEL, 2 ); + } } else { @@ -1816,6 +1655,16 @@ void CThirdPage::OnBnClickedHaveDisk() break; } + else + { + CString errorMessage; + CString errorCaption; + + errorMessage.LoadString( IDS_BAD_INF_FILE ); + errorCaption.LoadString( IDS_BAD_INF_FILE_CAPTION ); + + MessageBox( errorMessage, errorCaption, MB_OK ); + } } else { @@ -1827,3 +1676,21 @@ exit: return; } + + +void +CThirdPage::Split( const CString & string, TCHAR ch, CStringList & components ) +{ + CString temp; + int n; + + temp = string; + + while ( ( n = temp.Find( ch ) ) != -1 ) + { + components.AddTail( temp.Left( n ) ); + temp = temp.Right( temp.GetLength() - ( n + 1 ) ); + } + + components.AddTail( temp ); +} diff --git a/Clients/PrinterSetupWizard/ThirdPage.h b/Clients/PrinterSetupWizard/ThirdPage.h index 2ab62b1..cb929d4 100644 --- a/Clients/PrinterSetupWizard/ThirdPage.h +++ b/Clients/PrinterSetupWizard/ThirdPage.h @@ -17,6 +17,9 @@ Change History (most recent first): $Log: ThirdPage.h,v $ +Revision 1.10 2009/05/29 20:43:37 herscher + Printer Wizard doesn't work correctly in Windows 7 64 bit + Revision 1.9 2007/04/13 23:42:20 herscher mDNS: Printers added using Bonjour should be set as the default printer. @@ -179,7 +182,12 @@ public: afx_msg void OnLvnItemchangedPrinterModel(NMHDR *pNMHDR, LRESULT *pResult); afx_msg void OnBnClickedDefaultPrinter(); private: + + void + Split( const CString & string, TCHAR ch, CStringList & components ); + CButton m_defaultPrinterCtrl; + public: CStatic m_printerSelectionText; CStatic * m_printerImage; diff --git a/Clients/PrinterSetupWizard/UtilTypes.h b/Clients/PrinterSetupWizard/UtilTypes.h index c467f3d..41a3251 100644 --- a/Clients/PrinterSetupWizard/UtilTypes.h +++ b/Clients/PrinterSetupWizard/UtilTypes.h @@ -17,6 +17,13 @@ Change History (most recent first): $Log: UtilTypes.h,v $ +Revision 1.18 2009/05/29 20:43:37 herscher + Printer Wizard doesn't work correctly in Windows 7 64 bit + +Revision 1.17 2009/05/27 04:59:57 herscher + COMPATIBILITY WITH HP CLJ4700 + Compatibility with Samsung print driver files + 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 @@ -97,7 +104,6 @@ namespace PrinterSetupWizard typedef std::list Printers; typedef std::list Services; typedef std::list Models; - typedef std::list Decorations; struct Printer { @@ -218,9 +224,7 @@ namespace PrinterSetupWizard struct Manufacturer { CString name; - CString tag; Models models; - Decorations decorations; Model* find( const CString & name ); diff --git a/Clients/PrinterSetupWizard/res/PrinterSetupWizard.manifest b/Clients/PrinterSetupWizard/res/PrinterSetupWizard.manifest index 90a067e..a72bcca 100644 --- a/Clients/PrinterSetupWizard/res/PrinterSetupWizard.manifest +++ b/Clients/PrinterSetupWizard/res/PrinterSetupWizard.manifest @@ -1,22 +1,17 @@ - -Your app description here - - - - - + + Printer Setup Wizard + + + + + + + + + + + + diff --git a/Clients/PrinterSetupWizard/res/PrinterSetupWizard64.manifest b/Clients/PrinterSetupWizard/res/PrinterSetupWizard64.manifest new file mode 100644 index 0000000..f535d80 --- /dev/null +++ b/Clients/PrinterSetupWizard/res/PrinterSetupWizard64.manifest @@ -0,0 +1,17 @@ + + + + Printer Setup Wizard + + + + + + + + + + + + + diff --git a/Clients/PrinterSetupWizard/resource_exe.h b/Clients/PrinterSetupWizard/resource_exe.h index 46cd451..4a4f980 100755 --- a/Clients/PrinterSetupWizard/resource_exe.h +++ b/Clients/PrinterSetupWizard/resource_exe.h @@ -2,7 +2,6 @@ // Microsoft Visual C++ generated include file. // Used by PrinterSetupWizard.rc // -#define IDR_MANIFEST 1 #define IDM_ABOUTBOX 0x0010 #define IDD_ABOUTBOX 100 #define IDS_ABOUTBOX 101 @@ -48,6 +47,10 @@ #define IDI_PRINTER 141 #define IDS_REINSTALL 142 #define IDS_REINSTALL_CAPTION 143 +#define IDC_INFO 144 +#define IDS_PRINTER_UNAVAILABLE 145 +#define IDS_BAD_INF_FILE 150 +#define IDS_BAD_INF_FILE_CAPTION 151 #define IDC_BUTTON1 1000 #define IDC_LIST1 1000 #define IDC_BROWSE_LIST 1000 diff --git a/Clients/PrinterSetupWizard/resource_loc_res.h b/Clients/PrinterSetupWizard/resource_loc_res.h index b5a3bf9..951c54d 100755 --- a/Clients/PrinterSetupWizard/resource_loc_res.h +++ b/Clients/PrinterSetupWizard/resource_loc_res.h @@ -2,7 +2,6 @@ // Microsoft Visual C++ generated include file. // Used by PrinterSetupWizardLocRes.rc // -#define IDR_MANIFEST 1 #define IDM_ABOUTBOX 0x0010 #define IDD_ABOUTBOX 100 #define IDS_ABOUTBOX 101 @@ -51,6 +50,8 @@ #define IDS_REINSTALL_CAPTION 143 #define IDC_INFO 144 #define IDS_PRINTER_UNAVAILABLE 145 +#define IDS_BAD_INF_FILE 150 +#define IDS_BAD_INF_FILE_CAPTION 151 #define IDC_BUTTON1 1000 #define IDC_LIST1 1000 #define IDC_BROWSE_LIST 1000 diff --git a/Clients/PrinterSetupWizard/resource_res.h b/Clients/PrinterSetupWizard/resource_res.h index 46cd451..4a4f980 100755 --- a/Clients/PrinterSetupWizard/resource_res.h +++ b/Clients/PrinterSetupWizard/resource_res.h @@ -2,7 +2,6 @@ // Microsoft Visual C++ generated include file. // Used by PrinterSetupWizard.rc // -#define IDR_MANIFEST 1 #define IDM_ABOUTBOX 0x0010 #define IDD_ABOUTBOX 100 #define IDS_ABOUTBOX 101 @@ -48,6 +47,10 @@ #define IDI_PRINTER 141 #define IDS_REINSTALL 142 #define IDS_REINSTALL_CAPTION 143 +#define IDC_INFO 144 +#define IDS_PRINTER_UNAVAILABLE 145 +#define IDS_BAD_INF_FILE 150 +#define IDS_BAD_INF_FILE_CAPTION 151 #define IDC_BUTTON1 1000 #define IDC_LIST1 1000 #define IDC_BROWSE_LIST 1000 diff --git a/Clients/SimpleChat.NET/SimpleChat.NET.csproj b/Clients/SimpleChat.NET/SimpleChat.NET.csproj index 2165beb..a80011a 100755 --- a/Clients/SimpleChat.NET/SimpleChat.NET.csproj +++ b/Clients/SimpleChat.NET/SimpleChat.NET.csproj @@ -1,116 +1,113 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + Local + 8.0.50727 + 2.0 + {726DED99-34D0-45F3-9F4D-C7068DF4BCDA} + Debug + AnyCPU + App.ico + + + SimpleChat.NET + + + JScript + Grid + IE50 + false + WinExe + SimpleChat.NET + + + + + + + + + bin\Debug\ + false + 285212672 + false + + + DEBUG;TRACE + + + true + 4096 + false + false + false + false + 4 + full + prompt + + + bin\Release\ + false + 285212672 + false + + + TRACE + + + false + 4096 + true + false + false + false + 4 + none + prompt + + + + System + + + System.Data + + + System.Drawing + + + System.Windows.Forms + + + System.XML + + + + + + + Form + + + SimpleChat.cs + Designer + + + + + {18FBED6D-F2B7-4EC8-A4A4-46282E635308} + 1 + 0 + 0 + tlbimp + False + + + + + + + + + + \ No newline at end of file diff --git a/Clients/SimpleChat.NET/SimpleChat.cs b/Clients/SimpleChat.NET/SimpleChat.cs index e7f3b1e..cdfdad3 100755 --- a/Clients/SimpleChat.NET/SimpleChat.cs +++ b/Clients/SimpleChat.NET/SimpleChat.cs @@ -17,6 +17,9 @@ Change History (most recent first): $Log: SimpleChat.cs,v $ +Revision 1.7 2009/06/04 20:21:19 herscher + Update code to work with DNSSD COM component + Revision 1.6 2006/08/14 23:24:21 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -48,7 +51,7 @@ using System.Net; using System.Net.Sockets; using System.Data; using System.Text; -using Apple.DNSSD; +using Bonjour; namespace SimpleChat.NET { @@ -57,426 +60,226 @@ namespace SimpleChat.NET /// /// - // - // PeerData - // - // Holds onto the information associated with a peer on the network - // - public class PeerData - { - public int InterfaceIndex; - public String Name; - public String Type; - public String Domain; - public IPAddress Address; - public int Port; - - public override String - ToString() - { - return Name; - } - - public override bool - Equals(object other) - { - bool result = false; - - if (other != null) - { - if ((object) this == other) - { - result = true; - } - else if (other is PeerData) - { - PeerData otherPeerData = (PeerData) other; - - result = (this.Name == otherPeerData.Name); - } - } - - return result; - } - - public override int - GetHashCode() - { - return Name.GetHashCode(); - } - }; - - // - // ResolveData - // - // Holds onto the information associated with the resolution - // of a DNSService - // - public class ResolveData - { - public int InterfaceIndex; - public String FullName; - public String HostName; - public int Port; - public Byte[] TxtRecord; - - public override String - ToString() - { - return FullName; - } - }; - - - // - // SocketStateObject - // - // Holds onto the data associated with an asynchronous - // socket operation - // - class SocketStateObject + public class SimpleChat : System.Windows.Forms.Form { - public const int BUFFER_SIZE = 1024; - private Socket m_socket; - public byte[] m_buffer; - public bool m_complete; - public StringBuilder m_sb = new StringBuilder(); - - public SocketStateObject(Socket socket) - { - m_buffer = new byte[BUFFER_SIZE]; - m_complete = false; - m_socket = socket; - } - - public Socket - WorkSocket - { - get - { - return m_socket; - } - } - } - public class Form1 : System.Windows.Forms.Form - { - private System.Windows.Forms.ComboBox comboBox1; - private System.Windows.Forms.TextBox textBox2; - private System.Windows.Forms.Button button1; - private System.Windows.Forms.Label label1; - private ServiceRef registrar = null; - private ServiceRef browser = null; - private ServiceRef resolver = null; - private String myName; + private System.Windows.Forms.ComboBox comboBox1; + private System.Windows.Forms.TextBox textBox2; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Label label1; + private Bonjour.DNSSDEventManager m_eventManager = null; + private Bonjour.DNSSDService m_service = null; + private Bonjour.DNSSDService m_registrar = null; + private Bonjour.DNSSDService m_browser = null; + private Bonjour.DNSSDService m_resolver = null; + private String m_name; + private Socket m_socket = null; + private const int BUFFER_SIZE = 1024; + public byte[] m_buffer = new byte[BUFFER_SIZE]; + public bool m_complete = false; + public StringBuilder m_sb = new StringBuilder(); + delegate void ReadMessageCallback(String data); + ReadMessageCallback m_readMessageCallback; /// /// Required designer variable. /// private System.ComponentModel.Container components = null; - - // - // These all of our callbacks. These are invoked in the context - // of the main (GUI) thread. The DNSService callbacks Invoke() - // them - delegate void RegisterServiceCallback(String name); - delegate void AddPeerCallback(PeerData data); - delegate void RemovePeerCallback(PeerData data); - delegate void ResolveServiceCallback(ResolveData data); - delegate void ResolveAddressCallback(System.Net.IPAddress address); - delegate void ReadMessageCallback(String data); - - RegisterServiceCallback registerServiceCallback; - AddPeerCallback addPeerCallback; - RemovePeerCallback removePeerCallback; - ResolveServiceCallback resolveServiceCallback; - ResolveAddressCallback resolveAddressCallback; - ReadMessageCallback readMessageCallback; private System.Windows.Forms.RichTextBox richTextBox1; + // ServiceRegistered // - // The socket that we will be reading data from - // - Socket socket = null; - - // - // OnRegisterService - // - // The name that we are passed might be different than the - // name we called Register with. So we hold onto this name - // rather than the name we Register with. - // - // This is called (indirectly) from OnRegisterReply(). - // - private void - OnRegisterService - ( - String name - ) - { - myName = name; - } - - // - // OnAddPeer - // - // Called when DNSServices detects a new P2P Chat peer has - // joined. - // - // This is called (indirectly) from OnBrowseReply() - // - private void - OnAddPeer - ( - PeerData peer - ) - { - comboBox1.Items.Add(peer); - - if (comboBox1.Items.Count == 1) - { - comboBox1.SelectedIndex = 0; - } - } - - // - // OnRemovePeer - // - // Called when DNSServices detects a P2P peer has left - // the network - // - // This is called (indirectly) from OnBrowseReply() - // - private void - OnRemovePeer - ( - PeerData peer - ) - { - comboBox1.Items.Remove(peer); - } - - // - // OnResolveService - // - // Called when DNSServices has resolved a service. - // - // This is called (indirectly) from OnResolveService() - // - private void - OnResolveService - ( - ResolveData data - ) - { - resolver.Dispose(); - - PeerData peer = (PeerData) comboBox1.SelectedItem; - - peer.Port = data.Port; - - try - { - resolver = DNSService.QueryRecord(0, 0, data.HostName, /* ns_t_a */ 1, /* ns_t_c */ 1, new DNSService.QueryRecordReply(OnQueryRecordReply)); - } - catch - { - MessageBox.Show("QueryRecord Failed", "Error"); - Application.Exit(); - } - } - - // - // OnResolveAddress - // - // Called when DNSServices has finished a query operation - // - // This is called (indirectly) from OnQueryRecordReply() - // - private void - OnResolveAddress - ( - System.Net.IPAddress address - ) - { - resolver.Dispose(); - - PeerData peer = (PeerData) comboBox1.SelectedItem; - - peer.Address = address; - } - - // - // OnReadMessage - // - // Called when there is data to be read on a socket - // - // This is called (indirectly) from OnReadSocket() - // - private void - OnReadMessage - ( - String msg - ) - { - int rgb = 0; - - for (int i = 0; i < msg.Length && msg[i] != ':'; i++) - { - rgb = rgb ^ ((int) msg[i] << (i % 3 + 2) * 8); - } - - Color color = Color.FromArgb(rgb & 0x007F7FFF); - - richTextBox1.SelectionColor = color; - - richTextBox1.AppendText(msg + "\n"); - } - - // - // OnRegisterReply - // - // Called by DNSServices core as a result of DNSService.Register() + // Called by DNSServices core as a result of Register() // call - // - // This is called from a worker thread by DNSService core. - // - private void - OnRegisterReply - ( - ServiceRef sdRef, - ServiceFlags flags, - ErrorCode errorCode, - String name, - String regtype, - String domain) - { - if (errorCode == ErrorCode.NoError) - { - Invoke(registerServiceCallback, new Object[]{name}); - } - else - { - MessageBox.Show("OnRegisterReply returned an error code " + errorCode, "Error"); - } - } - - - // - // OnBrowseReply - // - // Called by DNSServices core as a result of DNSService.Browse() - // call - // - // This is called from a worker thread by DNSService core. - // - private void - OnBrowseReply - ( - ServiceRef sdRef, - ServiceFlags flags, - int interfaceIndex, - ErrorCode errorCode, - String name, - String type, - String domain) - { - if (errorCode == ErrorCode.NoError) - { - PeerData peer = new PeerData(); - - peer.InterfaceIndex = interfaceIndex; - peer.Name = name; - peer.Type = type; - peer.Domain = domain; - peer.Address = null; - - if ((flags & ServiceFlags.Add) != 0) - { - Invoke(addPeerCallback, new Object[]{peer}); - } - else if ((flags == 0) || ((flags & ServiceFlags.MoreComing) != 0)) - { - Invoke(removePeerCallback, new Object[]{peer}); - } - } - else - { - MessageBox.Show("OnBrowseReply returned an error code " + errorCode, "Error"); - } - } - - // - // OnResolveReply + // + + public void + ServiceRegistered + ( + DNSSDService service, + DNSSDFlags flags, + String name, + String regType, + String domain + ) + { + m_name = name; + + try + { + m_browser = m_service.Browse(0, 0, "_p2pchat._udp", null, m_eventManager); + } + catch + { + MessageBox.Show("Browse Failed", "Error"); + Application.Exit(); + } + } + + // + // ServiceFound + // + // Called by DNSServices core as a result of a Browse call + // + + public void + ServiceFound + ( + DNSSDService sref, + DNSSDFlags flags, + uint ifIndex, + String serviceName, + String regType, + String domain + ) + { + if (serviceName != m_name) + { + PeerData peer = new PeerData(); + + peer.InterfaceIndex = ifIndex; + peer.Name = serviceName; + peer.Type = regType; + peer.Domain = domain; + peer.Address = null; + + comboBox1.Items.Add(peer); + + if (comboBox1.Items.Count == 1) + { + comboBox1.SelectedIndex = 0; + } + } + } + + // + // ServiceLost + // + // Called by DNSServices core as a result of a Browse call + // + + public void + ServiceLost + ( + DNSSDService sref, + DNSSDFlags flags, + uint ifIndex, + String serviceName, + String regType, + String domain + ) + { + PeerData peer = new PeerData(); + + peer.InterfaceIndex = ifIndex; + peer.Name = serviceName; + peer.Type = regType; + peer.Domain = domain; + peer.Address = null; + + comboBox1.Items.Remove(peer); + } + + // + // ServiceResolved // // Called by DNSServices core as a result of DNSService.Resolve() // call // - // This is called from a worker thread by DNSService core. - // - private void - OnResolveReply - ( - ServiceRef sdRef, - ServiceFlags flags, - int interfaceIndex, - ErrorCode errorCode, - String fullName, - String hostName, - int port, - Byte[] txtRecord - ) - { - if (errorCode == ErrorCode.NoError) - { - ResolveData data = new ResolveData(); - - data.InterfaceIndex = interfaceIndex; - data.FullName = fullName; - data.HostName = hostName; - data.Port = port; - data.TxtRecord = txtRecord; - - Invoke(resolveServiceCallback, new Object[]{data}); - } - else - { - MessageBox.Show("OnResolveReply returned an error code: " + errorCode, "Error"); - } + + public void + ServiceResolved + ( + DNSSDService sref, + DNSSDFlags flags, + uint ifIndex, + String fullName, + String hostName, + ushort port, + TXTRecord txtRecord + ) + { + m_resolver.Stop(); + m_resolver = null; + + PeerData peer = (PeerData)comboBox1.SelectedItem; + + peer.Port = port; + + try + { + m_resolver = m_service.QueryRecord(0, ifIndex, hostName, DNSSDRRType.kDNSSDType_A, DNSSDRRClass.kDNSSDClass_IN, m_eventManager ); + } + catch + { + MessageBox.Show("QueryRecord Failed", "Error"); + Application.Exit(); + } } // - // OnQueryRecordReply + // QueryAnswered // // Called by DNSServices core as a result of DNSService.QueryRecord() // call // - // This is called from a worker thread by DNSService core. - // - private void - OnQueryRecordReply + + public void + QueryAnswered ( - ServiceRef sdRef, - ServiceFlags flags, - int interfaceIndex, - ErrorCode errorCode, - String fullName, - int rrtype, - int rrclass, - Byte[] rdata, - int ttl - ) - { - if (errorCode == ErrorCode.NoError) - { - uint bits = BitConverter.ToUInt32(rdata, 0); - System.Net.IPAddress data = new System.Net.IPAddress(bits); - - Invoke(resolveAddressCallback, new Object[]{data}); - } - else - { - MessageBox.Show("OnQueryRecordReply returned an error code: " + errorCode, "Error"); - } - } + DNSSDService service, + DNSSDFlags flags, + uint ifIndex, + String fullName, + DNSSDRRType rrtype, + DNSSDRRClass rrclass, + Object rdata, + uint ttl + ) + { + m_resolver.Stop(); + m_resolver = null; + + PeerData peer = (PeerData) comboBox1.SelectedItem; + + uint bits = BitConverter.ToUInt32( (Byte[])rdata, 0); + System.Net.IPAddress address = new System.Net.IPAddress(bits); + + peer.Address = address; + } + + public void + OperationFailed + ( + DNSSDService service, + DNSSDError error + ) + { + MessageBox.Show("Operation returned an error code " + error, "Error"); + } + + // + // OnReadMessage + // + // Called when there is data to be read on a socket + // + // This is called (indirectly) from OnReadSocket() + // + private void + OnReadMessage + ( + String msg + ) + { + int rgb = 0; + + for (int i = 0; i < msg.Length && msg[i] != ':'; i++) + { + rgb = rgb ^ ((int)msg[i] << (i % 3 + 2) * 8); + } + + Color color = Color.FromArgb(rgb & 0x007F7FFF); + richTextBox1.SelectionColor = color; + richTextBox1.AppendText(msg + Environment.NewLine); + } // // OnReadSocket @@ -491,26 +294,17 @@ namespace SimpleChat.NET IAsyncResult ar ) { - SocketStateObject so = (SocketStateObject) ar.AsyncState; - Socket s = so.WorkSocket; - try { - if (s == null) - { - return; - } - - int read = s.EndReceive(ar); + int read = m_socket.EndReceive(ar); if (read > 0) { - String msg = Encoding.UTF8.GetString(so.m_buffer, 0, read); - - Invoke(readMessageCallback, new Object[]{msg}); + String msg = Encoding.UTF8.GetString(m_buffer, 0, read); + Invoke(m_readMessageCallback, new Object[]{msg}); } - s.BeginReceive(so.m_buffer, 0, SocketStateObject.BUFFER_SIZE, 0, new AsyncCallback(OnReadSocket), so); + m_socket.BeginReceive(m_buffer, 0, BUFFER_SIZE, 0, new AsyncCallback(OnReadSocket), this); } catch { @@ -518,19 +312,32 @@ namespace SimpleChat.NET } - public Form1() + public SimpleChat() { // // Required for Windows Form Designer support // - InitializeComponent(); - - registerServiceCallback = new RegisterServiceCallback(OnRegisterService); - addPeerCallback = new AddPeerCallback(OnAddPeer); - removePeerCallback = new RemovePeerCallback(OnRemovePeer); - resolveServiceCallback = new ResolveServiceCallback(OnResolveService); - resolveAddressCallback = new ResolveAddressCallback(OnResolveAddress); - readMessageCallback = new ReadMessageCallback(OnReadMessage); + InitializeComponent(); + + try + { + m_service = new DNSSDService(); + } + catch + { + MessageBox.Show("Bonjour Service is not available", "Error"); + Application.Exit(); + } + + m_eventManager = new DNSSDEventManager(); + m_eventManager.ServiceRegistered += new _IDNSSDEvents_ServiceRegisteredEventHandler(this.ServiceRegistered); + m_eventManager.ServiceFound += new _IDNSSDEvents_ServiceFoundEventHandler(this.ServiceFound); + m_eventManager.ServiceLost += new _IDNSSDEvents_ServiceLostEventHandler(this.ServiceLost); + m_eventManager.ServiceResolved += new _IDNSSDEvents_ServiceResolvedEventHandler(this.ServiceResolved); + m_eventManager.QueryRecordAnswered += new _IDNSSDEvents_QueryRecordAnsweredEventHandler(this.QueryAnswered); + m_eventManager.OperationFailed += new _IDNSSDEvents_OperationFailedEventHandler(this.OperationFailed); + + m_readMessageCallback = new ReadMessageCallback(OnReadMessage); this.Load += new System.EventHandler(this.Form1_Load); @@ -550,15 +357,26 @@ namespace SimpleChat.NET components.Dispose(); } - if (registrar != null) + if (m_registrar != null) { - registrar.Dispose(); + m_registrar.Stop(); } - if (browser != null) + if (m_browser != null) { - browser.Dispose(); - } + m_browser.Stop(); + } + + if (m_resolver != null) + { + m_resolver.Stop(); + } + + m_eventManager.ServiceFound -= new _IDNSSDEvents_ServiceFoundEventHandler(this.ServiceFound); + m_eventManager.ServiceLost -= new _IDNSSDEvents_ServiceLostEventHandler(this.ServiceLost); + m_eventManager.ServiceResolved -= new _IDNSSDEvents_ServiceResolvedEventHandler(this.ServiceResolved); + m_eventManager.QueryRecordAnswered -= new _IDNSSDEvents_QueryRecordAnsweredEventHandler(this.QueryAnswered); + m_eventManager.OperationFailed -= new _IDNSSDEvents_OperationFailedEventHandler(this.OperationFailed); } base.Dispose( disposing ); } @@ -656,27 +474,25 @@ namespace SimpleChat.NET // // create the socket and bind to INADDR_ANY // - socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - socket.Bind(localEP); - localEP = (IPEndPoint) socket.LocalEndPoint; + m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + m_socket.Bind(localEP); + localEP = (IPEndPoint) m_socket.LocalEndPoint; // // start asynchronous read // - SocketStateObject so = new SocketStateObject(socket); - socket.BeginReceive(so.m_buffer, 0, SocketStateObject.BUFFER_SIZE, 0, new AsyncCallback(this.OnReadSocket), so); + m_socket.BeginReceive(m_buffer, 0, BUFFER_SIZE, 0, new AsyncCallback(this.OnReadSocket), this); try { // // start the register and browse operations // - registrar = DNSService.Register(0, 0, System.Environment.UserName, "_p2pchat._udp", null, null, localEP.Port, null, new DNSService.RegisterReply(OnRegisterReply)); - browser = DNSService.Browse(0, 0, "_p2pchat._udp", null, new DNSService.BrowseReply(OnBrowseReply)); + m_registrar = m_service.Register( 0, 0, System.Environment.UserName, "_p2pchat._udp", null, null, ( ushort ) localEP.Port, null, m_eventManager ); } catch { - MessageBox.Show("DNSServices Not Available", "Error"); + MessageBox.Show("Bonjour service is not available", "Error"); Application.Exit(); } } @@ -687,7 +503,7 @@ namespace SimpleChat.NET [STAThread] static void Main() { - Application.Run(new Form1()); + Application.Run(new SimpleChat()); } // @@ -697,13 +513,13 @@ namespace SimpleChat.NET { PeerData peer = (PeerData) comboBox1.SelectedItem; - String message = myName + ": " + textBox2.Text; + String message = m_name + ": " + textBox2.Text; Byte[] bytes = Encoding.UTF8.GetBytes(message); - - UdpClient udpSocket = new UdpClient(peer.Address.ToString(), peer.Port); - udpSocket.Send(bytes, bytes.Length); + IPEndPoint endPoint = new IPEndPoint( peer.Address, peer.Port ); + + m_socket.SendTo(bytes, endPoint); richTextBox1.SelectionColor = Color.Black; @@ -718,15 +534,7 @@ namespace SimpleChat.NET private void textBox2_TextChanged(object sender, System.EventArgs e) { PeerData peer = (PeerData) comboBox1.SelectedItem; - - if ((peer.Address != null) && (textBox2.Text.Length > 0)) - { - button1.Enabled = true; - } - else - { - button1.Enabled = false; - } + button1.Enabled = ((peer.Address != null) && (textBox2.Text.Length > 0)); } // @@ -742,7 +550,7 @@ namespace SimpleChat.NET try { - resolver = DNSService.Resolve(0, 0, peer.Name, peer.Type, peer.Domain, new DNSService.ResolveReply(OnResolveReply)); + m_resolver = m_service.Resolve(0, peer.InterfaceIndex, peer.Name, peer.Type, peer.Domain, m_eventManager); } catch { @@ -750,5 +558,54 @@ namespace SimpleChat.NET Application.Exit(); } } - } + } + + // + // PeerData + // + // Holds onto the information associated with a peer on the network + // + public class PeerData + { + public uint InterfaceIndex; + public String Name; + public String Type; + public String Domain; + public IPAddress Address; + public int Port; + + public override String + ToString() + { + return Name; + } + + public override bool + Equals(object other) + { + bool result = false; + + if (other != null) + { + if ((object)this == other) + { + result = true; + } + else if (other is PeerData) + { + PeerData otherPeerData = (PeerData)other; + + result = (this.Name == otherPeerData.Name); + } + } + + return result; + } + + public override int + GetHashCode() + { + return Name.GetHashCode(); + } + }; } diff --git a/Clients/SimpleChat.NET/SimpleChat.resx b/Clients/SimpleChat.NET/SimpleChat.resx index e5b5a11..5671818 100755 --- a/Clients/SimpleChat.NET/SimpleChat.resx +++ b/Clients/SimpleChat.NET/SimpleChat.resx @@ -97,6 +97,6 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - Form1 + SimpleChat.NET \ No newline at end of file diff --git a/Clients/SimpleChat.VB/My Project/Application.Designer.vb b/Clients/SimpleChat.VB/My Project/Application.Designer.vb new file mode 100644 index 0000000..8ec3666 --- /dev/null +++ b/Clients/SimpleChat.VB/My Project/Application.Designer.vb @@ -0,0 +1,38 @@ +'------------------------------------------------------------------------------ +' +' This code was generated by a tool. +' Runtime Version:2.0.50727.4918 +' +' Changes to this file may cause incorrect behavior and will be lost if +' the code is regenerated. +' +'------------------------------------------------------------------------------ + +Option Strict On +Option Explicit On + + +Namespace My + + 'NOTE: This file is auto-generated; do not modify it directly. To make changes, + ' or if you encounter build errors in this file, go to the Project Designer + ' (go to Project Properties or double-click the My Project node in + ' Solution Explorer), and make changes on the Application tab. + ' + Partial Friend Class MyApplication + + _ + Public Sub New() + MyBase.New(Global.Microsoft.VisualBasic.ApplicationServices.AuthenticationMode.Windows) + Me.IsSingleInstance = false + Me.EnableVisualStyles = true + Me.SaveMySettingsOnExit = true + Me.ShutDownStyle = Global.Microsoft.VisualBasic.ApplicationServices.ShutdownMode.AfterMainFormCloses + End Sub + + _ + Protected Overrides Sub OnCreateMainForm() + Me.MainForm = Global.SimpleChat.VB.SimpleChat + End Sub + End Class +End Namespace diff --git a/Clients/SimpleChat.VB/My Project/Application.myapp b/Clients/SimpleChat.VB/My Project/Application.myapp new file mode 100644 index 0000000..890288c --- /dev/null +++ b/Clients/SimpleChat.VB/My Project/Application.myapp @@ -0,0 +1,10 @@ + + + true + SimpleChat + false + 0 + true + 0 + true + \ No newline at end of file diff --git a/Clients/SimpleChat.VB/My Project/AssemblyInfo.vb b/Clients/SimpleChat.VB/My Project/AssemblyInfo.vb new file mode 100644 index 0000000..869313a --- /dev/null +++ b/Clients/SimpleChat.VB/My Project/AssemblyInfo.vb @@ -0,0 +1,35 @@ +Imports System +Imports System.Reflection +Imports System.Runtime.InteropServices + +' General Information about an assembly is controlled through the following +' set of attributes. Change these attribute values to modify the information +' associated with an assembly. + +' Review the values of the assembly attributes + + + + + + + + + + +'The following GUID is for the ID of the typelib if this project is exposed to COM + + +' Version information for an assembly consists of the following four values: +' +' Major Version +' Minor Version +' Build Number +' Revision +' +' You can specify all the values or you can default the Build and Revision Numbers +' by using the '*' as shown below: +' + + + diff --git a/Clients/SimpleChat.VB/My Project/Resources.Designer.vb b/Clients/SimpleChat.VB/My Project/Resources.Designer.vb new file mode 100644 index 0000000..babd06f --- /dev/null +++ b/Clients/SimpleChat.VB/My Project/Resources.Designer.vb @@ -0,0 +1,62 @@ +'------------------------------------------------------------------------------ +' +' This code was generated by a tool. +' Runtime Version:2.0.50727.4918 +' +' Changes to this file may cause incorrect behavior and will be lost if +' the code is regenerated. +' +'------------------------------------------------------------------------------ + +Option Strict On +Option Explicit On + + +Namespace My.Resources + + 'This class was auto-generated by the StronglyTypedResourceBuilder + 'class via a tool like ResGen or Visual Studio. + 'To add or remove a member, edit your .ResX file then rerun ResGen + 'with the /str option, or rebuild your VS project. + ' + ' A strongly-typed resource class, for looking up localized strings, etc. + ' + _ + Friend Module Resources + + Private resourceMan As Global.System.Resources.ResourceManager + + Private resourceCulture As Global.System.Globalization.CultureInfo + + ' + ' Returns the cached ResourceManager instance used by this class. + ' + _ + Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager + Get + If Object.ReferenceEquals(resourceMan, Nothing) Then + Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("SimpleChat.VB.Resources", GetType(Resources).Assembly) + resourceMan = temp + End If + Return resourceMan + End Get + End Property + + ' + ' Overrides the current thread's CurrentUICulture property for all + ' resource lookups using this strongly typed resource class. + ' + _ + Friend Property Culture() As Global.System.Globalization.CultureInfo + Get + Return resourceCulture + End Get + Set(ByVal value As Global.System.Globalization.CultureInfo) + resourceCulture = value + End Set + End Property + End Module +End Namespace diff --git a/Clients/SimpleChat.VB/My Project/Resources.resx b/Clients/SimpleChat.VB/My Project/Resources.resx new file mode 100644 index 0000000..ffecec8 --- /dev/null +++ b/Clients/SimpleChat.VB/My Project/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Clients/SimpleChat.VB/My Project/Settings.Designer.vb b/Clients/SimpleChat.VB/My Project/Settings.Designer.vb new file mode 100644 index 0000000..259ca35 --- /dev/null +++ b/Clients/SimpleChat.VB/My Project/Settings.Designer.vb @@ -0,0 +1,73 @@ +'------------------------------------------------------------------------------ +' +' This code was generated by a tool. +' Runtime Version:2.0.50727.4918 +' +' Changes to this file may cause incorrect behavior and will be lost if +' the code is regenerated. +' +'------------------------------------------------------------------------------ + +Option Strict On +Option Explicit On + + +Namespace My + + _ + Partial Friend NotInheritable Class MySettings + Inherits Global.System.Configuration.ApplicationSettingsBase + + Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings), MySettings) + +#Region "My.Settings Auto-Save Functionality" +#If _MyType = "WindowsForms" Then + Private Shared addedHandler As Boolean + + Private Shared addedHandlerLockObject As New Object + + _ + Private Shared Sub AutoSaveSettings(ByVal sender As Global.System.Object, ByVal e As Global.System.EventArgs) + If My.Application.SaveMySettingsOnExit Then + My.Settings.Save() + End If + End Sub +#End If +#End Region + + Public Shared ReadOnly Property [Default]() As MySettings + Get + +#If _MyType = "WindowsForms" Then + If Not addedHandler Then + SyncLock addedHandlerLockObject + If Not addedHandler Then + AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings + addedHandler = True + End If + End SyncLock + End If +#End If + Return defaultInstance + End Get + End Property + End Class +End Namespace + +Namespace My + + _ + Friend Module MySettingsProperty + + _ + Friend ReadOnly Property Settings() As Global.SimpleChat.VB.My.MySettings + Get + Return Global.SimpleChat.VB.My.MySettings.Default + End Get + End Property + End Module +End Namespace diff --git a/Clients/SimpleChat.VB/My Project/Settings.settings b/Clients/SimpleChat.VB/My Project/Settings.settings new file mode 100644 index 0000000..377f56d --- /dev/null +++ b/Clients/SimpleChat.VB/My Project/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Clients/SimpleChat.VB/SimpleChat.Designer.vb b/Clients/SimpleChat.VB/SimpleChat.Designer.vb new file mode 100644 index 0000000..4cdc2aa --- /dev/null +++ b/Clients/SimpleChat.VB/SimpleChat.Designer.vb @@ -0,0 +1,102 @@ + _ +Partial Class SimpleChat + Inherits System.Windows.Forms.Form + + 'Form overrides dispose to clean up the component list. + _ + Protected Overrides Sub Dispose(ByVal disposing As Boolean) + Try + If disposing AndAlso components IsNot Nothing Then + components.Dispose() + End If + Finally + MyBase.Dispose(disposing) + End Try + End Sub + + 'Required by the Windows Form Designer + Private components As System.ComponentModel.IContainer + + 'NOTE: The following procedure is required by the Windows Form Designer + 'It can be modified using the Windows Form Designer. + 'Do not modify it using the code editor. + _ + Private Sub InitializeComponent() + Me.TextBox1 = New System.Windows.Forms.TextBox + Me.TextBox2 = New System.Windows.Forms.TextBox + Me.TalkTo = New System.Windows.Forms.Label + Me.ComboBox1 = New System.Windows.Forms.ComboBox + Me.Button1 = New System.Windows.Forms.Button + Me.SuspendLayout() + ' + 'TextBox1 + ' + Me.TextBox1.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) + Me.TextBox1.Location = New System.Drawing.Point(12, 12) + Me.TextBox1.Multiline = True + Me.TextBox1.Name = "TextBox1" + Me.TextBox1.ReadOnly = True + Me.TextBox1.Size = New System.Drawing.Size(459, 362) + Me.TextBox1.TabIndex = 0 + ' + 'TextBox2 + ' + Me.TextBox2.Anchor = CType(((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left) _ + Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) + Me.TextBox2.Location = New System.Drawing.Point(13, 431) + Me.TextBox2.Name = "TextBox2" + Me.TextBox2.Size = New System.Drawing.Size(374, 20) + Me.TextBox2.TabIndex = 1 + ' + 'TalkTo + ' + Me.TalkTo.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles) + Me.TalkTo.AutoSize = True + Me.TalkTo.Location = New System.Drawing.Point(13, 395) + Me.TalkTo.Name = "TalkTo" + Me.TalkTo.Size = New System.Drawing.Size(43, 13) + Me.TalkTo.TabIndex = 2 + Me.TalkTo.Text = "Talk to:" + ' + 'ComboBox1 + ' + Me.ComboBox1.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left), System.Windows.Forms.AnchorStyles) + Me.ComboBox1.FormattingEnabled = True + Me.ComboBox1.Location = New System.Drawing.Point(63, 392) + Me.ComboBox1.Name = "ComboBox1" + Me.ComboBox1.Size = New System.Drawing.Size(324, 21) + Me.ComboBox1.TabIndex = 3 + ' + 'Button1 + ' + Me.Button1.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles) + Me.Button1.Location = New System.Drawing.Point(409, 430) + Me.Button1.Name = "Button1" + Me.Button1.Size = New System.Drawing.Size(59, 23) + Me.Button1.TabIndex = 4 + Me.Button1.Text = "Send" + Me.Button1.UseVisualStyleBackColor = True + ' + 'SimpleChat + ' + Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!) + Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font + Me.ClientSize = New System.Drawing.Size(483, 462) + Me.Controls.Add(Me.Button1) + Me.Controls.Add(Me.ComboBox1) + Me.Controls.Add(Me.TalkTo) + Me.Controls.Add(Me.TextBox2) + Me.Controls.Add(Me.TextBox1) + Me.Name = "SimpleChat" + Me.Text = "SimpleChat.VB" + Me.ResumeLayout(False) + Me.PerformLayout() + + End Sub + Friend WithEvents TextBox1 As System.Windows.Forms.TextBox + Friend WithEvents TextBox2 As System.Windows.Forms.TextBox + Friend WithEvents TalkTo As System.Windows.Forms.Label + Friend WithEvents ComboBox1 As System.Windows.Forms.ComboBox + Friend WithEvents Button1 As System.Windows.Forms.Button + +End Class diff --git a/Clients/SimpleChat.VB/SimpleChat.VB.vbproj b/Clients/SimpleChat.VB/SimpleChat.VB.vbproj new file mode 100644 index 0000000..1c1643d --- /dev/null +++ b/Clients/SimpleChat.VB/SimpleChat.VB.vbproj @@ -0,0 +1,116 @@ + + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {5ACED234-EB98-415E-9974-B54A70789821} + WinExe + SimpleChat.VB.My.MyApplication + SimpleChat.VB + SimpleChat.VB + WindowsForms + + + true + full + true + true + bin\Debug\ + SimpleChat.VB.xml + 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022 + + + pdbonly + false + true + true + bin\Release\ + SimpleChat.VB.xml + 42016,41999,42017,42018,42019,42032,42036,42020,42021,42022 + + + + + + + + + + + + + + + + + + + + + + Form + + + SimpleChat.vb + Form + + + + True + Application.myapp + + + True + True + Resources.resx + + + True + Settings.settings + True + + + + + Designer + SimpleChat.vb + + + VbMyResourcesResXFileCodeGenerator + Resources.Designer.vb + My.Resources + Designer + + + + + MyApplicationCodeGenerator + Application.Designer.vb + + + SettingsSingleFileGenerator + My + Settings.Designer.vb + + + + + {18FBED6D-F2B7-4EC8-A4A4-46282E635308} + 1 + 0 + 0 + tlbimp + False + + + + + \ No newline at end of file diff --git a/Clients/SimpleChat.VB/SimpleChat.resx b/Clients/SimpleChat.VB/SimpleChat.resx new file mode 100644 index 0000000..ff31a6d --- /dev/null +++ b/Clients/SimpleChat.VB/SimpleChat.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Clients/SimpleChat.VB/SimpleChat.vb b/Clients/SimpleChat.VB/SimpleChat.vb new file mode 100644 index 0000000..bcf5ef0 --- /dev/null +++ b/Clients/SimpleChat.VB/SimpleChat.vb @@ -0,0 +1,121 @@ + +Imports System.Net +Imports System.Net.Sockets +Imports System.Data +Imports System.Text + +Public Class SimpleChat + Public WithEvents MyEventManager As New Bonjour.DNSSDEventManager + Private m_service As New Bonjour.DNSSDService + Private m_registrar As Bonjour.DNSSDService + Private m_browser As Bonjour.DNSSDService + Private m_resolver As Bonjour.DNSSDService + Private m_socket As New Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp) + Private m_port As Integer + Private m_buffer(1024 * 32) As Byte + Private m_async As IAsyncResult + Public Delegate Sub SocketDelegate(ByVal msg As String) + Private m_socketDelegate As SocketDelegate + Private m_name As String + + Public Sub New() + MyBase.New() + + 'This call is required by the Windows Form Designer. + InitializeComponent() + + Button1.Enabled = False + + m_socketDelegate = New SocketDelegate(AddressOf MessageReceived) + + Dim endPoint As New IPEndPoint(IPAddress.Any, 0) + m_socket.Bind(endPoint) + endPoint = m_socket.LocalEndPoint + m_port = endPoint.Port + + Dim txtRecord As Bonjour.TXTRecord + m_async = m_socket.BeginReceive(m_buffer, 0, m_buffer.Length, SocketFlags.Partial, New AsyncCallback(AddressOf OnReceive), Me) + m_registrar = m_service.Register(0, 0, Environment.UserName, "_p2pchat._udp", vbNullString, vbNullString, m_port, txtRecord, MyEventManager) + End Sub + Public Sub MyEventManager_ServiceRegistered(ByVal registrar As Bonjour.DNSSDService, ByVal flags As Bonjour.DNSSDFlags, ByVal name As String, ByVal regType As String, ByVal domain As String) Handles MyEventManager.ServiceRegistered + m_name = name + m_browser = m_service.Browse(0, 0, regType, vbNullString, MyEventManager) + End Sub + Public Sub MyEventManager_ServiceFound(ByVal browser As Bonjour.DNSSDService, ByVal flags As Bonjour.DNSSDFlags, ByVal ifIndex As UInteger, ByVal serviceName As String, ByVal regtype As String, ByVal domain As String) Handles MyEventManager.ServiceFound + If (serviceName <> m_name) Then + Dim peer As PeerData = New PeerData + peer.InterfaceIndex = ifIndex + peer.Name = serviceName + peer.Type = regtype + peer.Domain = domain + ComboBox1.Items.Add(peer) + ComboBox1.SelectedIndex = 0 + End If + End Sub + Public Sub MyEventManager_ServiceLost(ByVal browser As Bonjour.DNSSDService, ByVal flags As Bonjour.DNSSDFlags, ByVal ifIndex As UInteger, ByVal serviceName As String, ByVal regtype As String, ByVal domain As String) Handles MyEventManager.ServiceLost + ComboBox1.Items.Remove(serviceName) + End Sub + Public Sub MyEventManager_ServiceResolved(ByVal resolver As Bonjour.DNSSDService, ByVal flags As Bonjour.DNSSDFlags, ByVal ifIndex As UInteger, ByVal fullname As String, ByVal hostname As String, ByVal port As UShort, ByVal record As Bonjour.TXTRecord) Handles MyEventManager.ServiceResolved + m_resolver.Stop() + Dim peer As PeerData = ComboBox1.SelectedItem + peer.Port = port + m_resolver = m_service.QueryRecord(0, ifIndex, hostname, Bonjour.DNSSDRRType.kDNSSDType_A, Bonjour.DNSSDRRClass.kDNSSDClass_IN, MyEventManager) + End Sub + Public Sub MyEventManager_QueryAnswered(ByVal resolver As Bonjour.DNSSDService, ByVal flags As Bonjour.DNSSDFlags, ByVal ifIndex As UInteger, ByVal fullName As String, ByVal rrtype As Bonjour.DNSSDRRType, ByVal rrclass As Bonjour.DNSSDRRClass, ByVal rdata As Object, ByVal ttl As UInteger) Handles MyEventManager.QueryRecordAnswered + m_resolver.Stop() + Dim peer As PeerData = ComboBox1.SelectedItem + Dim bits As UInteger = BitConverter.ToUInt32(rdata, 0) + Dim address As IPAddress = New System.Net.IPAddress(bits) + peer.Address = address + End Sub + Public Sub MyEventManager_OperationFailed(ByVal registrar As Bonjour.DNSSDService, ByVal errorCode As Bonjour.DNSSDError) Handles MyEventManager.OperationFailed + MessageBox.Show("Operation failed error code: " + errorCode) + End Sub + + Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click + Dim peer As PeerData = ComboBox1.SelectedItem + Dim message As String = m_name + ": " + TextBox2.Text + Dim bytes As Byte() = Encoding.UTF8.GetBytes(message) + Dim endPoint As IPEndPoint = New IPEndPoint(peer.Address, peer.Port) + m_socket.SendTo(bytes, 0, bytes.Length, 0, endPoint) + TextBox1.AppendText(TextBox2.Text + Environment.NewLine) + TextBox2.Text = "" + End Sub + + Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged + Dim peer As PeerData = ComboBox1.SelectedItem + m_resolver = m_service.Resolve(0, peer.InterfaceIndex, peer.Name, peer.Type, peer.Domain, MyEventManager) + End Sub + Private Sub TextBox2_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox2.TextChanged + Dim peer As PeerData = ComboBox1.SelectedItem + If ((peer.Address IsNot Nothing) And TextBox2.Text.Length > 0) Then + Button1.Enabled = True + Else + Button1.Enabled = False + End If + End Sub + Public Sub MessageReceived(ByVal msg As System.String) + TextBox1.AppendText(msg) + End Sub + Private Sub OnReceive(ByVal ar As IAsyncResult) + Dim bytesReceived As Integer = m_socket.EndReceive(ar) + If (bytesReceived > 0) Then + Dim msg As String = Encoding.UTF8.GetString(m_buffer, 0, bytesReceived) + Me.Invoke(m_socketDelegate, msg) + End If + m_async = m_socket.BeginReceive(m_buffer, 0, m_buffer.Length, SocketFlags.Partial, New AsyncCallback(AddressOf OnReceive), Me) + End Sub +End Class + +Public Class PeerData + Public InterfaceIndex As UInteger + Public Name As String + Public Type As String + Public Domain As String + Public Address As IPAddress + Public Port As UShort + + Overrides Function ToString() As String + Return Name + End Function +End Class diff --git a/Clients/dns-sd.c b/Clients/dns-sd.c index 497c5dc..993632d 100644 --- a/Clients/dns-sd.c +++ b/Clients/dns-sd.c @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 4 -*- * - * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002-2008 Apple 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 @@ -73,7 +73,7 @@ cl dns-sd.c -I../mDNSShared -DNOT_HAVE_GETOPT ws2_32.lib ..\mDNSWindows\DLL\Rele #include #include // For stdout, stderr #include // For exit() -#include // For strlen(), strcpy(), bzero() +#include // For strlen(), strcpy() #include // For errno, EINTR #include #include // For u_char @@ -81,12 +81,69 @@ cl dns-sd.c -I../mDNSShared -DNOT_HAVE_GETOPT ws2_32.lib ..\mDNSWindows\DLL\Rele #ifdef _WIN32 #include #include + #include #include typedef int pid_t; #define getpid _getpid #define strcasecmp _stricmp #define snprintf _snprintf static const char kFilePathSep = '\\'; + #ifndef HeapEnableTerminationOnCorruption + # define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS)1 + #endif + #if !defined(IFNAMSIZ) + #define IFNAMSIZ 16 + #endif + #define if_nametoindex if_nametoindex_win + #define if_indextoname if_indextoname_win + + typedef PCHAR (WINAPI * if_indextoname_funcptr_t)(ULONG index, PCHAR name); + typedef ULONG (WINAPI * if_nametoindex_funcptr_t)(PCSTR name); + + unsigned if_nametoindex_win(const char *ifname) + { + HMODULE library; + unsigned index = 0; + + // Try and load the IP helper library dll + if ((library = LoadLibrary(TEXT("Iphlpapi")) ) != NULL ) + { + if_nametoindex_funcptr_t if_nametoindex_funcptr; + + // On Vista and above there is a Posix like implementation of if_nametoindex + if ((if_nametoindex_funcptr = (if_nametoindex_funcptr_t) GetProcAddress(library, "if_nametoindex")) != NULL ) + { + index = if_nametoindex_funcptr(ifname); + } + + FreeLibrary(library); + } + + return index; + } + + char * if_indextoname_win( unsigned ifindex, char *ifname) + { + HMODULE library; + char * name = NULL; + + // Try and load the IP helper library dll + if ((library = LoadLibrary(TEXT("Iphlpapi")) ) != NULL ) + { + if_indextoname_funcptr_t if_indextoname_funcptr; + + // On Vista and above there is a Posix like implementation of if_indextoname + if ((if_indextoname_funcptr = (if_indextoname_funcptr_t) GetProcAddress(library, "if_indextoname")) != NULL ) + { + name = if_indextoname_funcptr(ifindex, ifname); + } + + FreeLibrary(library); + } + + return name; + } + #else #include // For getopt() and optind #include // For getaddrinfo() @@ -104,6 +161,8 @@ cl dns-sd.c -I../mDNSShared -DNOT_HAVE_GETOPT ws2_32.lib ..\mDNSWindows\DLL\Rele #include "dns_sd.h" +#include "ClientCommon.h" + #if TEST_NEW_CLIENTSTUB #include "../mDNSShared/dnssd_ipc.c" #include "../mDNSShared/dnssd_clientlib.c" @@ -135,7 +194,7 @@ 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[8200]; +static char bigNULL[8192]; // 8K is maximum rdata we support // Note: the select() implementation on Windows (Winsock2) fails with any timeout much larger than this #define LONG_TIME 100000000 @@ -239,31 +298,7 @@ static void printtimestamp(void) #define DomainMsg(X) (((X) & kDNSServiceFlagsDefault) ? "(Default)" : \ ((X) & kDNSServiceFlagsAdd) ? "Added" : "Removed") -static const char *GetNextLabel(const char *cstr, char label[64]) - { - char *ptr = label; - while (*cstr && *cstr != '.') // While we have characters in the label... - { - char c = *cstr++; - if (c == '\\') - { - c = *cstr++; - if (isdigit(cstr[-1]) && isdigit(cstr[0]) && isdigit(cstr[1])) - { - int v0 = cstr[-1] - '0'; // then interpret as three-digit decimal - int v1 = cstr[ 0] - '0'; - int v2 = cstr[ 1] - '0'; - int val = v0 * 100 + v1 * 10 + v2; - if (val <= 255) { c = (char)val; cstr += 2; } // If valid three-digit decimal value, use it - } - } - *ptr++ = c; - if (ptr >= label+64) return(NULL); - } - if (*cstr) cstr++; // Skip over the trailing dot (if present) - *ptr++ = 0; - return(cstr); - } +#define MAX_LABELS 128 static void DNSSD_API enum_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode, const char *replyDomain, void *context) @@ -271,7 +306,7 @@ static void DNSSD_API enum_reply(DNSServiceRef sdref, const DNSServiceFlags flag DNSServiceFlags partialflags = flags & ~(kDNSServiceFlagsMoreComing | kDNSServiceFlagsAdd | kDNSServiceFlagsDefault); int labels = 0, depth = 0, i, initial = 0; char text[64]; - const char *label[128]; + const char *label[MAX_LABELS]; (void)sdref; // Unused (void)ifIndex; // Unused @@ -292,7 +327,7 @@ static void DNSSD_API enum_reply(DNSServiceRef sdref, const DNSServiceFlags flag else printf(" "); // 2. Count the labels - while (*replyDomain) + while (replyDomain && *replyDomain && labels < MAX_LABELS) { label[labels++] = replyDomain; replyDomain = GetNextLabel(replyDomain, text); @@ -326,6 +361,97 @@ static void DNSSD_API enum_reply(DNSServiceRef sdref, const DNSServiceFlags flag if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout); } +static int CopyLabels(char *dst, const char *lim, const char **srcp, int labels) + { + const char *src = *srcp; + while (*src != '.' || --labels > 0) + { + if (*src == '\\') *dst++ = *src++; // Make sure "\." doesn't confuse us + if (!*src || dst >= lim) return -1; + *dst++ = *src++; + if (!*src || dst >= lim) return -1; + } + *dst++ = 0; + *srcp = src + 1; // skip over final dot + return 0; + } + +static void DNSSD_API zonedata_resolve(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 *txt, void *context) + { + union { uint16_t s; u_char b[2]; } port = { opaqueport }; + uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1]; + + const char *p = fullname; + char n[kDNSServiceMaxDomainName]; + char t[kDNSServiceMaxDomainName]; + + const unsigned char *max = txt + txtLen; + + (void)sdref; // Unused + (void)ifIndex; // Unused + (void)context; // Unused + + //if (!(flags & kDNSServiceFlagsAdd)) return; + if (errorCode) { printf("Error code %d\n", errorCode); return; } + + if (CopyLabels(n, n + kDNSServiceMaxDomainName, &p, 3)) return; // Fetch name+type + p = fullname; + if (CopyLabels(t, t + kDNSServiceMaxDomainName, &p, 1)) return; // Skip first label + if (CopyLabels(t, t + kDNSServiceMaxDomainName, &p, 2)) return; // Fetch next two labels (service type) + + if (num_printed++ == 0) + { + printf("\n"); + printf("; To direct clients to browse a different domain, substitute that domain in place of '@'\n"); + printf("%-47s PTR %s\n", "lb._dns-sd._udp", "@"); + printf("\n"); + printf("; In the list of services below, the SRV records will typically reference dot-local Multicast DNS names.\n"); + printf("; When transferring this zone file data to your unicast DNS server, you'll need to replace those dot-local\n"); + printf("; names with the correct fully-qualified (unicast) domain name of the target host offering the service.\n"); + } + + printf("\n"); + printf("%-47s PTR %s\n", t, n); + printf("%-47s SRV 0 0 %d %s ; Replace with unicast FQDN of target host\n", n, PortAsNumber, hosttarget); + printf("%-47s TXT ", n); + + while (txt < max) + { + const unsigned char *const end = txt + 1 + txt[0]; + txt++; // Skip over length byte + printf(" \""); + while (txt 1) { printf("\n"); ShowTXTRecord(txtLen, txtRecord); } @@ -824,7 +950,14 @@ int main(int argc, char **argv) const char *a0 = strrchr(argv[0], kFilePathSep) + 1; if (a0 == (const char *)1) a0 = argv[0]; +#if defined(_WIN32) + HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0); +#endif + +#if TEST_NEW_CLIENTSTUB + printf("Using embedded copy of dnssd_clientstub instead of system library\n"); if (sizeof(argv) == 8) printf("Running in 64-bit mode\n"); +#endif // Test code for TXTRecord functions //TXTRecordRef txtRecord; @@ -850,7 +983,7 @@ int main(int argc, char **argv) } if (argc < 2) goto Fail; // Minimum command line is the command name and one argument - operation = getfirstoption(argc, argv, "EFBLRPQCAUNTMISV" + operation = getfirstoption(argc, argv, "EFBZLRPQCAUNTMISV" #if HAS_NAT_PMP_API "X" #endif @@ -884,13 +1017,23 @@ int main(int argc, char **argv) err = DNSServiceBrowse(&client, 0, opinterface, typ, dom, browse_reply, NULL); break; + case 'Z': typ = (argc < opi+1) ? "" : argv[opi+0]; + dom = (argc < opi+2) ? "" : argv[opi+1]; // Missing domain argument is the same as empty string i.e. use system default(s) + typ = gettype(buffer, typ); + 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%s\n", typ, dom[0] ? "." : "", dom); + err = DNSServiceCreateConnection(&client); + sc1 = client; + err = DNSServiceBrowse(&sc1, kDNSServiceFlagsShareConnection, opinterface, typ, dom, zonedata_browse, NULL); + break; + case 'L': if (argc < opi+2) goto Fail; typ = (argc < opi+2) ? "" : argv[opi+1]; dom = (argc < opi+3) ? "local" : argv[opi+2]; typ = gettype(buffer, typ); 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[opi+0], typ, dom); - err = DNSServiceResolve(&client, 0, opinterface, argv[opi+0], typ, dom, (DNSServiceResolveReply)resolve_reply, NULL); + err = DNSServiceResolve(&client, 0, opinterface, argv[opi+0], typ, dom, resolve_reply, NULL); break; case 'R': if (argc < opi+4) goto Fail; @@ -907,7 +1050,7 @@ int main(int argc, char **argv) err = RegisterProxyAddressRecord(client_pa, argv[opi+4], argv[opi+5]); //err = RegisterProxyAddressRecord(client_pa, "two", argv[opi+5]); if (err) break; - err = RegisterService(&client, argv[opi+0], argv[opi+1], argv[opi+2], argv[opi+4], argv[opi+3], argc-(opi+6), argv+(opi+6)); + err = RegisterService(&client, argv[opi+0], gettype(buffer, argv[opi+1]), argv[opi+2], argv[opi+4], argv[opi+3], argc-(opi+6), argv+(opi+6)); //DNSServiceRemoveRecord(client_pa, record, 0); //DNSServiceRemoveRecord(client_pa, record, 0); break; @@ -995,6 +1138,10 @@ int main(int argc, char **argv) case 'S': { Opaque16 registerPort = { { 0x23, 0x45 } }; + unsigned char txtrec[16] = "\xF" "/path=test.html"; + DNSRecordRef rec; + unsigned char nulrec[4] = "1234"; + err = DNSServiceCreateConnection(&client); if (err) { fprintf(stderr, "DNSServiceCreateConnection failed %ld\n", (long int)err); return (-1); } @@ -1011,6 +1158,15 @@ int main(int argc, char **argv) "_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); } + err = DNSServiceUpdateRecord(sc3, NULL, 0, sizeof(txtrec), txtrec, 0); + if (err) { fprintf(stderr, "SharedConnection DNSServiceUpdateRecord failed %ld\n", (long int)err); return (-1); } + + err = DNSServiceAddRecord(sc3, &rec, 0, kDNSServiceType_NULL, sizeof(nulrec), nulrec, 0); + if (err) { fprintf(stderr, "SharedConnection DNSServiceAddRecord failed %ld\n", (long int)err); return (-1); } + + err = DNSServiceRemoveRecord(sc3, rec, 0); + if (err) { fprintf(stderr, "SharedConnection DNSServiceRemoveRecord failed %ld\n", (long int)err); return (-1); } + break; } @@ -1041,6 +1197,7 @@ Fail: 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 -Z (Output results in Zone File format)\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 @@ -1049,6 +1206,8 @@ Fail: #if HAS_ADDRINFO_API fprintf(stderr, "%s -G v4/v6/v4v6 (Get address information for hostname)\n", a0); #endif + fprintf(stderr, "%s -V (Get version of currently running daemon / system service)\n", a0); + 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); @@ -1056,7 +1215,6 @@ Fail: 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; } @@ -1070,6 +1228,8 @@ Fail: // The "@(#) " pattern is a special prefix the "what" command looks for const char VersionString_SCCS[] = "@(#) dns-sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")"; +#if _BUILDING_XCODE_PROJECT_ // If the process crashes, then this string will be magically included in the automatically-generated crash log const char *__crashreporter_info__ = VersionString_SCCS + 5; asm(".desc ___crashreporter_info__, 0x10"); +#endif diff --git a/Makefile b/Makefile index 73dd03e..1f62270 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ include /Developer/Makefiles/pb_makefiles/platform.make -MVERS = "mDNSResponder-176.3" +MVERS = "mDNSResponder-212.1" DDNSWRITECONFIG = "$(DSTROOT)/Library/Application Support/Bonjour/ddnswriteconfig" diff --git a/PrivateDNS.txt b/PrivateDNS.txt index 8d62907..e66bec8 100644 --- a/PrivateDNS.txt +++ b/PrivateDNS.txt @@ -76,7 +76,7 @@ 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 +of client machines, the server has the option of dropping the TLS 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 diff --git a/buildResults.xml b/buildResults.xml deleted file mode 100644 index b45ac9a..0000000 --- a/buildResults.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mDNSCore/DNSCommon.c b/mDNSCore/DNSCommon.c index deda1b9..b001a70 100644 --- a/mDNSCore/DNSCommon.c +++ b/mDNSCore/DNSCommon.c @@ -17,8 +17,179 @@ Change History (most recent first): $Log: DNSCommon.c,v $ -Revision 1.199.2.1 2008/07/25 07:25:08 mcguire -merge of to SUSB for +Revision 1.252 2009/06/27 00:27:03 cheshire + mDNSResponder taking up 13% CPU with 400 KBps incoming bonjour requests +Removed overly-complicate and ineffective multi-packet known-answer snooping code +(Bracketed it with "#if ENABLE_MULTI_PACKET_QUERY_SNOOPING" for now; will delete actual code later) + +Revision 1.251 2009/05/19 23:40:37 cheshire + Sleep Proxy: Retransmission logic not working reliably on quiet networks +Added m->NextScheduledSPRetry timer for scheduling Sleep Proxy registration retries + +Revision 1.250 2009/05/01 21:28:33 cheshire + AppleConnectAgent's reachability checks delay sleep by 30 seconds +No longer suspend network operations after we've acknowledged that the machine is going to sleep, +because other software may not have yet acknowledged the sleep event, and may be still trying +to do unicast DNS queries or other Bonjour operations. + +Revision 1.249 2009/04/24 00:29:20 cheshire + Return negative answers when host knows authoritatively that no answer exists +Added support for generating/parsing/displaying NSEC records + +Revision 1.248 2009/04/23 22:11:16 cheshire +Minor cleanup in debugging checks in GetLargeResourceRecord + +Revision 1.247 2009/04/21 23:36:25 cheshire + Remove unused kDNSType_MAC + +Revision 1.246 2009/04/21 01:00:19 cheshire +Fixed typo in previous checkin + +Revision 1.245 2009/04/21 00:57:23 cheshire + Off-by-one error in putDomainNameAsLabels() +If just writing one-byte root label, make sure we have space for that + +Revision 1.244 2009/04/11 00:19:30 jessic2 + Daemon: Should be able to turn on LogOperation dynamically + +Revision 1.243 2009/04/01 17:50:10 mcguire +cleanup mDNSRandom + +Revision 1.242 2009/03/26 04:01:55 jessic2 + MessageTracer: Log service types longer than 14 characters and service types with underscores + +Revision 1.241 2009/03/18 20:50:08 cheshire + uDNS: Reverse lookup of own IP address takes way too long, sometimes forever + +Revision 1.240 2009/03/18 20:41:04 cheshire +Added definition of the all-ones mDNSOpaque16 ID + +Revision 1.239 2009/03/06 23:51:50 mcguire +Fix broken build by defining DiscardPort + +Revision 1.238 2009/03/04 00:40:13 cheshire +Updated DNS server error codes to be more consistent with definitions at + + +Revision 1.237 2009/03/03 23:04:43 cheshire +For clarity, renamed "MAC" field to "HMAC" (Host MAC, as opposed to Interface MAC) + +Revision 1.236 2009/03/03 22:51:53 cheshire + Sleep Proxy: Waking on same network but different interface will cause conflicts + +Revision 1.235 2009/02/07 05:55:44 cheshire +Only pay attention to m->DelaySleep when it's nonzero + +Revision 1.234 2009/02/07 02:52:52 cheshire + Sleep Proxy: Need to adopt IOPMConnection +Pay attention to m->DelaySleep when computing next task time + +Revision 1.233 2009/01/30 23:50:31 cheshire +Added LastLabel() routine to get the last label of a domainname + +Revision 1.232 2009/01/15 00:22:48 mcguire + NAT-PMP: mDNSResponder needs to listen on 224.0.0.1:5350/UDP with REUSEPORT + +Revision 1.231 2008/12/12 01:24:06 cheshire +Updated GetNextScheduledEvent() to pay attention to m->SPSProxyListChanged + +Revision 1.230 2008/12/10 01:55:54 cheshire +Renamed "Max" macro to avoid conflict with another "Max" macro on ARMv5 + +Revision 1.229 2008/11/27 01:28:45 cheshire +For display purposes, show sleep sequence number as unsigned + +Revision 1.228 2008/11/26 20:57:37 cheshire +For consistency with other similar macros, renamed mdnsIsDigit/mdnsIsLetter/mdnsValidHostChar +to mDNSIsDigit/mDNSIsLetter/mDNSValidHostChar + +Revision 1.227 2008/11/26 20:28:05 cheshire +Added new SSHPort constant + +Revision 1.226 2008/11/16 16:55:51 cheshire +Updated debugging messages + +Revision 1.225 2008/11/14 21:56:31 cheshire +Moved debugging routine ShowTaskSchedulingError() from daemon.c into DNSCommon.c + +Revision 1.224 2008/11/14 02:20:03 cheshire +Include m->NextScheduledSPS in task scheduling calculations + +Revision 1.223 2008/11/14 01:19:03 cheshire +Initialize TimeRcvd and TimeExpire fields in AuthRecord_struct + +Revision 1.222 2008/11/14 00:00:53 cheshire +After client machine wakes up, Sleep Proxy machine need to remove any records +it was temporarily holding as proxy for that client + +Revision 1.221 2008/11/13 19:06:02 cheshire +Added code to put, get, and display rdataOPT properly + +Revision 1.220 2008/11/06 01:08:11 mcguire +Fix compiler warning about discarding const + +Revision 1.219 2008/11/04 23:06:50 cheshire +Split RDataBody union definition into RDataBody and RDataBody2, and removed +SOA from the normal RDataBody union definition, saving 270 bytes per AuthRecord + +Revision 1.218 2008/11/04 22:21:44 cheshire +Changed zone field of AuthRecord_struct from domainname to pointer, saving 252 bytes per AuthRecord + +Revision 1.217 2008/11/04 22:13:43 cheshire +Made RDataBody parameter to GetRRDisplayString_rdb "const" + +Revision 1.216 2008/11/04 20:06:19 cheshire + Change MAX_DOMAIN_NAME to 256 + +Revision 1.215 2008/10/23 23:54:35 cheshire +Added missing "const" in declaration + +Revision 1.214 2008/10/23 22:25:55 cheshire +Renamed field "id" to more descriptive "updateid" + +Revision 1.213 2008/10/22 01:01:52 cheshire +Added onesEthAddr constant, used for sending ARP broadcasts + +Revision 1.212 2008/10/14 21:52:18 cheshire +Added support for putting/getting/printing kDNSType_MAC + +Revision 1.211 2008/10/09 22:36:08 cheshire +Now that we have Sleep Proxy Server, can't suppress normal scheduling logic while going to sleep + +Revision 1.210 2008/10/08 01:03:52 cheshire +Change GetFirstActiveInterface() so the NetworkInterfaceInfo it returns is not "const" +Added mDNS_SetupQuestion() convenience function + +Revision 1.209 2008/09/23 04:13:30 cheshire + Remove "local" from the end of _services._dns-sd._udp PTR records +Removed old special-case Bonjour Browser hack that is no longer needed + +Revision 1.208 2008/09/23 02:33:56 cheshire + uDNS: Should not compress SRV rdata in uDNS packets + +Revision 1.207 2008/09/23 02:30:07 cheshire +Get rid of PutResourceRecordCappedTTL() + +Revision 1.206 2008/09/23 02:26:09 cheshire +Don't need to export putEmptyResourceRecord (it's only used from DNSCommon.c) + +Revision 1.205 2008/09/23 02:21:00 cheshire +Don't need to force setting of rrclass in PutResourceRecordTTLWithLimit() now that putLLQ() sets it correctly + +Revision 1.204 2008/08/29 19:03:05 cheshire + Off-by-one error in putDomainNameAsLabels() + +Revision 1.203 2008/08/13 00:47:53 mcguire +Handle failures when packet logging + +Revision 1.202 2008/08/13 00:32:48 mcguire +refactor to use SwapDNSHeaderBytes instead of swapping manually + +Revision 1.201 2008/07/24 20:23:03 cheshire + Should use randomized source ports and transaction IDs to avoid DNS cache poisoning + +Revision 1.200 2008/07/18 00:07:50 cheshire + Log a message for applications that register service types longer than 14 characters Revision 1.199 2008/03/14 19:58:38 mcguire BTMM: Need ability to identify version of mDNSResponder client @@ -416,6 +587,9 @@ 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 mDNSEthAddr onesEthAddr = { { 255, 255, 255, 255, 255, 255 } }; + +mDNSexport const OwnerOptData zeroOwner = { 0, 0, { { 0 } }, { { 0 } }, { { 0 } } }; mDNSexport const mDNSInterfaceID mDNSInterface_Any = 0; mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)1; @@ -428,38 +602,40 @@ mDNSexport const mDNSInterfaceID mDNSInterface_Unicast = (mDNSInterfaceID)2; // Uncomment the appropriate lines below to build a special Multicast DNS responder for testing interoperability // with Microsoft's LLMNR client code. +#define DiscardPortAsNumber 9 +#define SSHPortAsNumber 22 +#define UnicastDNSPortAsNumber 53 #define SSDPPortAsNumber 1900 - -#define UnicastDNSPortAsNumber 53 +#define NSIPCPortAsNumber 5030 // Port used for dnsextd to talk to local nameserver bound to loopback #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 DiscardPort = { { DiscardPortAsNumber >> 8, DiscardPortAsNumber & 0xFF } }; +mDNSexport const mDNSIPPort SSHPort = { { SSHPortAsNumber >> 8, SSHPortAsNumber & 0xFF } }; mDNSexport const mDNSIPPort UnicastDNSPort = { { UnicastDNSPortAsNumber >> 8, UnicastDNSPortAsNumber & 0xFF } }; +mDNSexport const mDNSIPPort SSDPPort = { { SSDPPortAsNumber >> 8, SSDPPortAsNumber & 0xFF } }; +mDNSexport const mDNSIPPort NSIPCPort = { { NSIPCPortAsNumber >> 8, NSIPCPortAsNumber & 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 mDNSv4Addr AllSystemsMcast = { { 224, 0, 0, 1 } }; // For NAT-PMP Annoucements 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 onesID = { { 255, 255 } }; 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 } }; @@ -482,7 +658,7 @@ mDNSexport mDNSBool mDNSv4AddrIsRFC1918(mDNSv4Addr *addr) (addr->b[0] == 192 && addr->b[1] == 168)); // 192.168/16 } -mDNSexport const NetworkInterfaceInfo *GetFirstActiveInterface(const NetworkInterfaceInfo *intf) +mDNSexport NetworkInterfaceInfo *GetFirstActiveInterface(NetworkInterfaceInfo *intf) { while (intf && !intf->InterfaceActive) intf = intf->next; return(intf); @@ -498,7 +674,7 @@ mDNSexport mDNSu32 NumCacheRecordsForInterfaceID(const mDNS *const m, mDNSInterf { mDNSu32 slot, used = 0; CacheGroup *cg; - CacheRecord *rr; + const CacheRecord *rr; FORALL_CACHERECORDS(slot, cg, rr) if (rr->resrec.InterfaceID == id) used++; return(used); @@ -519,6 +695,7 @@ mDNSexport char *DNSTypeName(mDNSu16 rrtype) case kDNSType_AAAA: return("AAAA"); case kDNSType_SRV: return("SRV"); case kDNSType_OPT: return("OPT"); + case kDNSType_NSEC: return("NSEC"); case kDNSType_TSIG: return("TSIG"); case kDNSQType_ANY: return("ANY"); default: { @@ -532,56 +709,88 @@ mDNSexport char *DNSTypeName(mDNSu16 rrtype) // Note slight bug: this code uses the rdlength from the ResourceRecord object, to display // the rdata from the RDataBody object. Sometimes this could be the wrong length -- but as // 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) +mDNSexport char *GetRRDisplayString_rdb(const ResourceRecord *const rr, const RDataBody *const rd1, char *const buffer) { - #define Max (MaxMsg-1) + const RDataBody2 *const rd = (RDataBody2 *)rd1; + #define RemSpc (MaxMsg-1-length) char *ptr = buffer; - mDNSu32 length = mDNS_snprintf(buffer, Max, "%4d %##s %s ", rr->rdlength, rr->name->c, DNSTypeName(rr->rrtype)); + mDNSu32 length = mDNS_snprintf(buffer, MaxMsg-1, "%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); } + if (!rr->rdlength) { mDNS_snprintf(buffer+length, RemSpc, "<< ZERO RDATA LENGTH >>"); return(buffer); } switch (rr->rrtype) { - case kDNSType_A: mDNS_snprintf(buffer+length, Max-length, "%.4a", &rd->ipv4); break; + case kDNSType_A: mDNS_snprintf(buffer+length, RemSpc, "%.4a", &rd->ipv4); break; case kDNSType_NS: // Same as PTR case kDNSType_CNAME:// Same as PTR - case kDNSType_PTR: mDNS_snprintf(buffer+length, Max-length, "%##s", rd->name.c); break; + case kDNSType_PTR: mDNS_snprintf(buffer+length, RemSpc, "%##s", rd->name.c); break; - case kDNSType_SOA: mDNS_snprintf(buffer+length, Max-length, "%##s %##s %d %d %d %d %d", + case kDNSType_SOA: mDNS_snprintf(buffer+length, RemSpc, "%##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 strings) case kDNSType_TXT: { - mDNSu8 *t = rd->txt.c; + const 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); + length += mDNS_snprintf(buffer+length, RemSpc, "%s%#s", t > rd->txt.c ? "¦" : "", t); t += 1 + t[0]; } } break; - 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", + case kDNSType_AAAA: mDNS_snprintf(buffer+length, RemSpc, "%.16a", &rd->ipv6); break; + case kDNSType_SRV: mDNS_snprintf(buffer+length, RemSpc, "%u %u %u %##s", rd->srv.priority, rd->srv.weight, mDNSVal16(rd->srv.port), rd->srv.target.c); 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) + + case kDNSType_OPT: { + const rdataOPT *opt; + const rdataOPT *const end = (const rdataOPT *)&rd->data[rr->rdlength]; + length += mDNS_snprintf(buffer+length, RemSpc, "Max %d", rr->rrclass); + for (opt = &rd->opt[0]; opt < end; opt++) { - 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); + switch(opt->opt) + { + case kDNSOpt_LLQ: + length += mDNS_snprintf(buffer+length, RemSpc, " Vers %d", opt->u.llq.vers); + length += mDNS_snprintf(buffer+length, RemSpc, " Op %d", opt->u.llq.llqOp); + length += mDNS_snprintf(buffer+length, RemSpc, " Err/Port %d", opt->u.llq.err); + length += mDNS_snprintf(buffer+length, RemSpc, " ID %08X%08X", opt->u.llq.id.l[0], opt->u.llq.id.l[1]); + length += mDNS_snprintf(buffer+length, RemSpc, " Lease %d", opt->u.llq.llqlease); + break; + case kDNSOpt_Lease: + length += mDNS_snprintf(buffer+length, RemSpc, " Lease %d", opt->u.updatelease); + break; + case kDNSOpt_Owner: + length += mDNS_snprintf(buffer+length, RemSpc, " Vers %d", opt->u.owner.vers); + length += mDNS_snprintf(buffer+length, RemSpc, " Seq %3d", (mDNSu8)opt->u.owner.seq); // Display as unsigned + length += mDNS_snprintf(buffer+length, RemSpc, " MAC %.6a", opt->u.owner.HMAC.b); + if (opt->optlen >= DNSOpt_OwnerData_ID_Wake_Space-4) + { + length += mDNS_snprintf(buffer+length, RemSpc, " I-MAC %.6a", opt->u.owner.IMAC.b); + if (opt->optlen > DNSOpt_OwnerData_ID_Wake_Space-4) + length += mDNS_snprintf(buffer+length, RemSpc, " Password %.6a", opt->u.owner.password.b); + } + break; + default: + length += mDNS_snprintf(buffer+length, RemSpc, " Unknown %d", opt->opt); + break; + } } - 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); + + case kDNSType_NSEC: { + int i; + for (i=0; i<255; i++) + if (rd->nsec.bitmap[i>>3] & (128 >> (i&7))) + length += mDNS_snprintf(buffer+length, RemSpc, "%s ", DNSTypeName(i)); + } + break; + + default: mDNS_snprintf(buffer+length, RemSpc, "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; @@ -589,46 +798,44 @@ mDNSexport char *GetRRDisplayString_rdb(const ResourceRecord *rr, RDataBody *rd, return(buffer); } -// Long-term we need to make this cross-platform, either by using our own embedded RC4 code -// to generate the pseudo-random sequence, or by adding another mDNSPlatformXXX() call. -// The former would be preferable because it makes our code self-contained, so it will run anywhere. -// The latter is less desirable because it increases the burden on people writing platform support layers -// to now implement one more function (and an important one at that, that needs to be cryptographically strong). -// For now, as a temporary fix, if we're building mDNSResponder for OS X we just use arc4random() directly here. +// See comments in mDNSEmbeddedAPI.h +#if _PLATFORM_HAS_STRONG_PRNG_ +#define mDNSRandomNumber mDNSPlatformRandomNumber +#else +mDNSlocal mDNSu32 mDNSRandomFromSeed(mDNSu32 seed) + { + return seed * 21 + 1; + } -#if _BUILDING_XCODE_PROJECT_ -#include -#endif +mDNSlocal mDNSu32 mDNSMixRandomSeed(mDNSu32 seed, mDNSu8 iteration) + { + return iteration ? mDNSMixRandomSeed(mDNSRandomFromSeed(seed), --iteration) : seed; + } -mDNSexport mDNSu32 mDNSRandom(mDNSu32 max) // Returns pseudo-random result from zero to max inclusive +mDNSlocal mDNSu32 mDNSRandomNumber() { + static mDNSBool seeded = mDNSfalse; static mDNSu32 seed = 0; - mDNSu32 mask = 1; - - if (!seed) + if (!seeded) { - int i; - seed = mDNSPlatformRandomSeed(); // Pick an initial seed - for (i=0; i<100; i++) seed = seed * 21 + 1; // And mix it up a bit + seed = mDNSMixRandomSeed(mDNSPlatformRandomSeed(), 100); + seeded = mDNStrue; } - while (mask < max) mask = (mask << 1) | 1; - -#if _BUILDING_XCODE_PROJECT_ - do seed = arc4random(); -#else - do seed = seed * 21 + 1; -#endif - while ((seed & mask) > max); - - return (seed & mask); + return (seed = mDNSRandomFromSeed(seed)); } - -mDNSexport mDNSu32 mDNSRandomFromFixedSeed(mDNSu32 seed, mDNSu32 max) +#endif // ! _PLATFORM_HAS_STRONG_PRNG_ + +mDNSexport mDNSu32 mDNSRandom(mDNSu32 max) // Returns pseudo-random result from zero to max inclusive { + mDNSu32 ret = 0; mDNSu32 mask = 1; + while (mask < max) mask = (mask << 1) | 1; - do seed = seed * 21 + 1; while ((seed & mask) > max); - return (seed & mask); + + do ret = mDNSRandomNumber() & mask; + while (ret > max); + + return ret; } mDNSexport mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2) @@ -690,7 +897,7 @@ mDNSexport mDNSBool SameDomainName(const domainname *const d1, const domainname while (*a || *b) { if (a + 1 + *a >= max) - { debugf("Malformed domain name (more than 255 characters)"); return(mDNSfalse); } + { debugf("Malformed domain name (more than 256 characters)"); return(mDNSfalse); } if (!SameDomainLabel(a, b)) return(mDNSfalse); a += 1 + *a; b += 1 + *b; @@ -734,11 +941,22 @@ mDNSexport mDNSBool IsLocalDomain(const domainname *d) return(mDNSfalse); } +mDNSexport const mDNSu8 *LastLabel(const domainname *d) + { + const mDNSu8 *p = d->c; + while (d->c[0]) + { + p = d->c; + d = (const domainname*)(d->c + 1 + d->c[0]); + } + return(p); + } + // Returns length of a domain name INCLUDING the byte for the final null label // 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 (MAX_DOMAIN_NAME+1) +// Legal results are 1 (just root label) to 256 (MAX_DOMAIN_NAME) +// If the given domainname is invalid, result is 257 (MAX_DOMAIN_NAME+1) mDNSexport mDNSu16 DomainNameLengthLimit(const domainname *const name, const mDNSu8 *limit) { const mDNSu8 *src = name->c; @@ -796,7 +1014,7 @@ mDNSexport const domainname *SkipLeadingLabels(const domainname *d, int skip) // 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). -// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes) +// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes) // AppendLiteralLabelString returns mDNSNULL. mDNSexport mDNSu8 *AppendLiteralLabelString(domainname *const name, const char *cstr) { @@ -818,7 +1036,7 @@ mDNSexport mDNSu8 *AppendLiteralLabelString(domainname *const name, const char * // 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). -// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes) +// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes) // AppendDNSNameString returns mDNSNULL. mDNSexport mDNSu8 *AppendDNSNameString(domainname *const name, const char *cstring) { @@ -835,7 +1053,7 @@ mDNSexport mDNSu8 *AppendDNSNameString(domainname *const name, const char *cstri if (c == '\\') // If escape character, check next character { c = (mDNSu8)*cstr++; // Assume we'll just take the next character - if (mdnsIsDigit(cstr[-1]) && mdnsIsDigit(cstr[0]) && mdnsIsDigit(cstr[1])) + if (mDNSIsDigit(cstr[-1]) && mDNSIsDigit(cstr[0]) && mDNSIsDigit(cstr[1])) { // If three decimal digits, int v0 = cstr[-1] - '0'; // then interpret as three-digit decimal int v1 = cstr[ 0] - '0'; @@ -860,7 +1078,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). -// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes) +// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes) // AppendDomainLabel returns mDNSNULL. mDNSexport mDNSu8 *AppendDomainLabel(domainname *const name, const domainlabel *const label) { @@ -914,7 +1132,7 @@ mDNSexport mDNSBool MakeDomainLabelFromLiteralString(domainlabel *const label, c // 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). -// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 255 bytes) +// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes) // MakeDomainNameFromDNSNameString returns mDNSNULL. mDNSexport mDNSu8 *MakeDomainNameFromDNSNameString(domainname *const name, const char *cstr) { @@ -949,10 +1167,10 @@ mDNSexport char *ConvertDomainLabelToCString_withescape(const domainlabel *const return(ptr); // and return } -// Note: To guarantee that there will be no possible overrun, cstr must be at least MAX_ESCAPED_DOMAIN_NAME (1005 bytes) +// Note: To guarantee that there will be no possible overrun, cstr must be at least MAX_ESCAPED_DOMAIN_NAME (1009 bytes) mDNSexport char *ConvertDomainNameToCString_withescape(const domainname *const name, char *ptr, char esc) { - const mDNSu8 *src = name->c; // Domain name we're reading + const mDNSu8 *src = name->c; // Domain name we're reading const mDNSu8 *const max = name->c + MAX_DOMAIN_NAME; // Maximum that's valid if (*src == 0) *ptr++ = '.'; // Special case: For root, just write a dot @@ -989,7 +1207,7 @@ mDNSexport void ConvertUTF8PstringToRFC1034HostLabel(const mDNSu8 UTF8Name[], do { src += 3; continue; } // Unicode curly apostrophe if (ptr < lim) { - if (mdnsValidHostChar(*src, (ptr > &hostlabel->c[1]), (src < end-1))) *ptr++ = *src; + if (mDNSValidHostChar(*src, (ptr > &hostlabel->c[1]), (src < end-1))) *ptr++ = *src; else if (ptr > &hostlabel->c[1] && ptr[-1] != '-') *ptr++ = '-'; } src++; @@ -1009,6 +1227,10 @@ mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn, mDNSu8 *dst = fqdn->c; const mDNSu8 *src; const char *errormsg; +#if APPLE_OSX_mDNSResponder + mDNSBool loggedUnderscore = mDNSfalse; + static char typeBuf[MAX_ESCAPED_DOMAIN_NAME]; +#endif // In the case where there is no name (and ONLY in that case), // a single-label subtype is allowed as the first label of a three-part "type" @@ -1052,21 +1274,44 @@ mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn, src = type->c; // Put the service type into the domain name len = *src; - if (len < 2 || len >= 0x40 || (len > 15 && !SameDomainName(domain, &localdomain))) + if (len < 2 || len > 15) { - errormsg = "Application protocol name must be underscore plus 1-14 characters. See "; - goto fail; + LogMsg("Bad service type in %#s.%##s%##s Application protocol name must be underscore plus 1-14 characters. " + "See ", name->c, type->c, domain->c); +#if APPLE_OSX_mDNSResponder + ConvertDomainNameToCString(type, typeBuf); + mDNSASLLog(mDNSNULL, "serviceType.nameTooLong", "noop", typeBuf, ""); +#endif } + if (len < 2 || len >= 0x40 || (len > 15 && !SameDomainName(domain, &localdomain))) return(mDNSNULL); if (src[1] != '_') { errormsg = "Application protocol name must begin with underscore"; goto fail; } for (i=2; i<=len; i++) { // Letters and digits are allowed anywhere - if (mdnsIsLetter(src[i]) || mdnsIsDigit(src[i])) continue; + 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; + if ((src[i] == '-' || src[i] == '_') && i > 2 && i < len) + { +#if APPLE_OSX_mDNSResponder + if (src[i] == '_' && loggedUnderscore == mDNSfalse) + { + ConvertDomainNameToCString(type, typeBuf); + mDNSASLLog(mDNSNULL, "serviceType.nameWithUnderscore", "noop", typeBuf, ""); + loggedUnderscore = mDNStrue; + } +#endif + continue; + } + errormsg = "Application protocol name must contain only letters, digits, and hyphens"; +#if APPLE_OSX_mDNSResponder + { + ConvertDomainNameToCString(type, typeBuf); + mDNSASLLog(mDNSNULL, "serviceType.nameWithIllegalCharacters", "noop", typeBuf, ""); + } +#endif + goto fail; } for (i=0; i<=len; i++) *dst++ = *src++; @@ -1117,9 +1362,8 @@ mDNSexport mDNSBool DeconstructServiceName(const domainname *const fqdn, len = *src; 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); } + 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 @@ -1187,17 +1431,17 @@ mDNSexport mDNSBool LabelContainsSuffix(const domainlabel *const name, const mDN { if (l < 4) return mDNSfalse; // Need at least " (2)" if (name->c[l--] != ')') return mDNSfalse; // Last char must be ')' - if (!mdnsIsDigit(name->c[l])) return mDNSfalse; // Preceeded by a digit + if (!mDNSIsDigit(name->c[l])) return mDNSfalse; // Preceeded by a digit l--; - while (l > 2 && mdnsIsDigit(name->c[l])) l--; // Strip off digits + while (l > 2 && mDNSIsDigit(name->c[l])) l--; // Strip off digits return (name->c[l] == '(' && name->c[l - 1] == ' '); } else { if (l < 2) return mDNSfalse; // Need at least "-2" - if (!mdnsIsDigit(name->c[l])) return mDNSfalse; // Last char must be a digit + if (!mDNSIsDigit(name->c[l])) return mDNSfalse; // Last char must be a digit l--; - while (l > 2 && mdnsIsDigit(name->c[l])) l--; // Strip off digits + while (l > 2 && mDNSIsDigit(name->c[l])) l--; // Strip off digits return (name->c[l] == '-'); } } @@ -1213,7 +1457,7 @@ mDNSexport mDNSu32 RemoveLabelSuffix(domainlabel *name, mDNSBool RichText) if (RichText && name->c[0] >= 1 && name->c[name->c[0]] == ')') name->c[0]--; // Get any existing numerical suffix off the name - while (mdnsIsDigit(name->c[name->c[0]])) + while (mDNSIsDigit(name->c[name->c[0]])) { val += (name->c[name->c[0]] - '0') * multiplier; multiplier *= 10; name->c[0]--; } // Chop opening parentheses or dash from suffix @@ -1322,6 +1566,11 @@ mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mD rr->AllowRemoteQuery = mDNSfalse; rr->ForceMCast = mDNSfalse; + rr->WakeUp = zeroOwner; + rr->AddressProxy = zeroAddr; + rr->TimeRcvd = 0; + rr->TimeExpire = 0; + // 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) @@ -1332,8 +1581,8 @@ mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mD rr->uselease = 0; rr->expire = 0; rr->Private = 0; - rr->id = zeroID; - rr->zone.c[0] = 0; + rr->updateid = zeroID; + rr->zone = rr->resrec.name; rr->UpdateServer = zeroAddr; rr->UpdatePort = zeroIPPort; rr->nta = mDNSNULL; @@ -1348,48 +1597,68 @@ mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mD rr->namestorage.c[0] = 0; // MUST be set by client before calling mDNS_Register() } +mDNSexport void mDNS_SetupQuestion(DNSQuestion *const q, const mDNSInterfaceID InterfaceID, const domainname *const name, + const mDNSu16 qtype, mDNSQuestionCallback *const callback, void *const context) + { + q->InterfaceID = InterfaceID; + q->Target = zeroAddr; + AssignDomainName(&q->qname, name); + q->qtype = qtype; + q->qclass = kDNSClass_IN; + q->LongLived = (qtype == kDNSType_PTR); + q->ExpectUnique = (qtype != kDNSType_PTR); + q->ForceMCast = mDNSfalse; + q->ReturnIntermed = mDNSfalse; + q->QuestionCallback = callback; + q->QuestionContext = context; + } + mDNSexport mDNSu32 RDataHashValue(const ResourceRecord *const rr) { + int len = rr->rdlength; + const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data; switch(rr->rrtype) { case kDNSType_NS: case kDNSType_CNAME: case kDNSType_PTR: - case kDNSType_DNAME: return DomainNameHashValue(&rr->rdata->u.name); + case kDNSType_DNAME: return DomainNameHashValue(&rdb->name); - case kDNSType_SOA: return rr->rdata->u.soa.serial + - rr->rdata->u.soa.refresh + - rr->rdata->u.soa.retry + - rr->rdata->u.soa.expire + - rr->rdata->u.soa.min + - DomainNameHashValue(&rr->rdata->u.soa.mname) + - DomainNameHashValue(&rr->rdata->u.soa.rname); + case kDNSType_SOA: return rdb->soa.serial + + rdb->soa.refresh + + rdb->soa.retry + + rdb->soa.expire + + rdb->soa.min + + DomainNameHashValue(&rdb->soa.mname) + + DomainNameHashValue(&rdb->soa.rname); case kDNSType_MX: case kDNSType_AFSDB: case kDNSType_RT: - case kDNSType_KX: return DomainNameHashValue(&rr->rdata->u.mx.exchange); + case kDNSType_KX: return DomainNameHashValue(&rdb->mx.exchange); + + case kDNSType_RP: return DomainNameHashValue(&rdb->rp.mbox) + DomainNameHashValue(&rdb->rp.txt); - case kDNSType_RP: return DomainNameHashValue(&rr->rdata->u.rp.mbox) + DomainNameHashValue(&rr->rdata->u.rp.txt); + case kDNSType_PX: return DomainNameHashValue(&rdb->px.map822) + DomainNameHashValue(&rdb->px.mapx400); - case kDNSType_PX: return DomainNameHashValue(&rr->rdata->u.px.map822) + DomainNameHashValue(&rr->rdata->u.px.mapx400); + case kDNSType_SRV: return DomainNameHashValue(&rdb->srv.target); - case kDNSType_SRV: return DomainNameHashValue(&rr->rdata->u.srv.target); + case kDNSType_OPT: return 0; // OPT is a pseudo-RR container structure; makes no sense to compare - case kDNSType_OPT: // Okay to use blind memory sum because there are no 'holes' in the in-memory representation + case kDNSType_NSEC: len = sizeof(rdataNSEC); // Use in-memory length of 32, and fall through default checksum computation below default: { mDNSu32 sum = 0; int i; - for (i=0; i+1 < rr->rdlength; i+=2) + for (i=0; i+1 < len; i+=2) { - sum += (((mDNSu32)(rr->rdata->u.data[i])) << 8) | rr->rdata->u.data[i+1]; + sum += (((mDNSu32)(rdb->data[i])) << 8) | rdb->data[i+1]; sum = (sum<<3) | (sum>>29); } - if (i < rr->rdlength) + if (i < len) { - sum += ((mDNSu32)(rr->rdata->u.data[i])) << 8; + sum += ((mDNSu32)(rdb->data[i])) << 8; } return(sum); } @@ -1400,42 +1669,46 @@ mDNSexport mDNSu32 RDataHashValue(const ResourceRecord *const rr) // r2 is just a bare RDataBody, which MUST be the same rrtype and rdlength as r1 mDNSexport mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2) { + const RDataBody2 *const b1 = (RDataBody2 *)r1->rdata->u.data; + const RDataBody2 *const b2 = (RDataBody2 *)r2; switch(r1->rrtype) { case kDNSType_NS: case kDNSType_CNAME: case kDNSType_PTR: - case kDNSType_DNAME:return(SameDomainName(&r1->rdata->u.name, &r2->name)); + case kDNSType_DNAME:return(SameDomainName(&b1->name, &b2->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_SOA: return(mDNSBool)( b1->soa.serial == b2->soa.serial && + b1->soa.refresh == b2->soa.refresh && + b1->soa.retry == b2->soa.retry && + b1->soa.expire == b2->soa.expire && + b1->soa.min == b2->soa.min && + SameDomainName(&b1->soa.mname, &b2->soa.mname) && + SameDomainName(&b1->soa.rname, &b2->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_KX: return(mDNSBool)( b1->mx.preference == b2->mx.preference && + SameDomainName(&b1->mx.exchange, &b2->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_RP: return(mDNSBool)( SameDomainName(&b1->rp.mbox, &b2->rp.mbox) && + SameDomainName(&b1->rp.txt, &b2->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_PX: return(mDNSBool)( b1->px.preference == b2->px.preference && + SameDomainName(&b1->px.map822, &b2->px.map822) && + SameDomainName(&b1->px.mapx400, &b2->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_SRV: return(mDNSBool)( b1->srv.priority == b2->srv.priority && + b1->srv.weight == b2->srv.weight && + mDNSSameIPPort(b1->srv.port, b2->srv.port) && + SameDomainName(&b1->srv.target, &b2->srv.target)); - case kDNSType_OPT: // Okay to use blind memory compare because there are no 'holes' in the in-memory representation + case kDNSType_OPT: return mDNSfalse; // OPT is a pseudo-RR container structure; makes no sense to compare - default: return(mDNSPlatformMemSame(r1->rdata->u.data, r2->data, r1->rdlength)); + case kDNSType_NSEC: return(mDNSPlatformMemSame(b1->data, b2->data, sizeof(rdataNSEC))); + + default: return(mDNSPlatformMemSame(b1->data, b2->data, r1->rdlength)); } } @@ -1456,8 +1729,8 @@ mDNSexport mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr 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 (!RRTypeAnswersQuestionType(rr,q->qtype)) return(mDNSfalse); + if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse); return(mDNStrue); } @@ -1472,14 +1745,29 @@ mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr 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 (!RRTypeAnswersQuestionType(rr,q->qtype)) return(mDNSfalse); + if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse); + + return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname)); + } + +mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(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); + + if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse); + return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname)); } mDNSexport mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate) { - const RDataBody *rd = &rr->rdata->u; + const RDataBody2 *const rd = (RDataBody2 *)rr->rdata->u.data; const domainname *const name = estimate ? rr->name : mDNSNULL; if (rr->rrclass == kDNSQClass_ANY) return(rr->rdlength); // Used in update packets to mean "Delete An RRset" (RFC 2136) else switch (rr->rrtype) @@ -1522,11 +1810,24 @@ mDNSexport mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate case kDNSType_OPT: return(rr->rdlength); + case kDNSType_NSEC: { + int i; + for (i=sizeof(rdataNSEC); i>0; i--) if (rd->nsec.bitmap[i-1]) break; + // For our simplified use of NSEC synthetic records: + // nextname is always the record's own name, + // the block number is always 0, + // the count byte is a value in the range 1-32, + // followed by the 1-32 data bytes + return((estimate ? 1 : DomainNameLength(rr->name)) + 2 + i); + } + default: debugf("Warning! Don't know how to get length of resource type %d", rr->rrtype); return(rr->rdlength); } } +// When a local client registers (or updates) a record, we use this routine to do some simple validation checks +// to help reduce the risk of bogus malformed data on the network mDNSexport mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd) { mDNSu16 len; @@ -1570,6 +1871,8 @@ mDNSexport mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, len = DomainNameLengthLimit(&rd->u.srv.target, rd->u.data + rdlength); return(len <= MAX_DOMAIN_NAME && rdlength == 6+len); + //case kDNSType_NSEC not checked + default: return(mDNStrue); // Allow all other types without checking } } @@ -1648,50 +1951,53 @@ 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); } + if (!ptr) { LogMsg("putDomainNameAsLabels %##s ptr is null", name->c); 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) // If just writing one-byte root label, make sure we have space for that { - if (*np > MAX_DOMAIN_LABEL) - { LogMsg("Malformed domain name %##s (label more than 63 bytes)", name->c); return(mDNSNULL); } - - // This check correctly allows for the final trailing root label: - // e.g. - // Suppose our domain name is exactly 255 bytes long, including the final trailing root label. - // Suppose np is now at name->c[248], and we're about to write our last non-null label ("local"). - // We know that max will be at name->c[255] - // That means that np + 1 + 5 == max - 1, so we (just) pass the "if" test below, write our - // six bytes, then exit the loop, write the final terminating root label, and the domain - // name we've written is exactly 255 bytes long, exactly at the correct legal limit. - // If the name is one byte longer, then we fail the "if" test below, and correctly bail out. - if (np + 1 + *np >= max) - { LogMsg("Malformed domain name %##s (more than 255 bytes)", name->c); return(mDNSNULL); } - - if (base) pointer = FindCompressionPointer(base, searchlimit, np); - if (pointer) // Use a compression pointer if we can - { - mDNSu16 offset = (mDNSu16)(pointer - base); - *ptr++ = (mDNSu8)(0xC0 | (offset >> 8)); - *ptr++ = (mDNSu8)( offset & 0xFF); - return(ptr); - } - else // Else copy one label and try again - { - int i; - mDNSu8 len = *np++; - if (ptr + 1 + len >= limit) return(mDNSNULL); - *ptr++ = len; - for (i=0; i= limit) return(mDNSNULL); } - - if (ptr < limit) // If we didn't run out of space + else // else, loop through writing labels and/or a compression offset { - *ptr++ = 0; // Put the final root label - return(ptr); // and return + do { + if (*np > MAX_DOMAIN_LABEL) + { LogMsg("Malformed domain name %##s (label more than 63 bytes)", name->c); return(mDNSNULL); } + + // This check correctly allows for the final trailing root label: + // e.g. + // Suppose our domain name is exactly 256 bytes long, including the final trailing root label. + // Suppose np is now at name->c[249], and we're about to write our last non-null label ("local"). + // We know that max will be at name->c[256] + // That means that np + 1 + 5 == max - 1, so we (just) pass the "if" test below, write our + // six bytes, then exit the loop, write the final terminating root label, and the domain + // name we've written is exactly 256 bytes long, exactly at the correct legal limit. + // If the name is one byte longer, then we fail the "if" test below, and correctly bail out. + if (np + 1 + *np >= max) + { LogMsg("Malformed domain name %##s (more than 256 bytes)", name->c); return(mDNSNULL); } + + if (base) pointer = FindCompressionPointer(base, searchlimit, np); + if (pointer) // Use a compression pointer if we can + { + const mDNSu16 offset = (mDNSu16)(pointer - base); + if (ptr+2 > limit) return(mDNSNULL); // If we don't have two bytes of space left, give up + *ptr++ = (mDNSu8)(0xC0 | (offset >> 8)); + *ptr++ = (mDNSu8)( offset & 0xFF); + return(ptr); + } + else // Else copy one label and try again + { + int i; + mDNSu8 len = *np++; + // If we don't at least have enough space for this label *plus* a terminating zero on the end, give up + if (ptr + 1 + len >= limit) return(mDNSNULL); + *ptr++ = len; + for (i=0; irdlength) - { - // check if space for opt/optlen - if (ptr + (2 * sizeof(mDNSu16)) > limit) goto space_err; - opt = (rdataOPT *)(rr->rdata->u.data + nput); - ptr = putVal16(ptr, opt->opt); - ptr = putVal16(ptr, opt->optlen); - nput += 2 * sizeof(mDNSu16); - if (opt->opt == kDNSOpt_LLQ) - { - if (ptr + LLQ_OPTLEN > limit) goto space_err; - ptr = putVal16(ptr, opt->OptData.llq.vers); - ptr = putVal16(ptr, opt->OptData.llq.llqOp); - ptr = putVal16(ptr, opt->OptData.llq.err); - mDNSPlatformMemCopy(ptr, opt->OptData.llq.id.b, 8); // 8-byte id - ptr += 8; - 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.updatelease); - nput += sizeof(mDNSs32); - } - else { LogMsg("putOptRData - unknown option %d", opt->opt); return mDNSNULL; } - } - - return ptr; - - space_err: - LogMsg("ERROR: putOptRData - out of space"); - return mDNSNULL; - } - -mDNSlocal mDNSu16 getVal16(const mDNSu8 **ptr) - { - mDNSu16 val = (mDNSu16)(((mDNSu16)(*ptr)[0]) << 8 | (*ptr)[1]); - *ptr += sizeof(mDNSOpaque16); - return val; - } - -mDNSlocal const mDNSu8 *getOptRdata(const mDNSu8 *ptr, const mDNSu8 *const limit, LargeCacheRecord *const cr, mDNSu16 pktRDLen) - { - int nread = 0; - ResourceRecord *const rr = &cr->r.resrec; - rdataOPT *opt = (rdataOPT *)rr->rdata->u.data; - - 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; - opt->opt = getVal16(&ptr); - opt->optlen = getVal16(&ptr); - nread += 2 * sizeof(mDNSu16); - if (opt->opt == kDNSOpt_LLQ) - { - if ((unsigned)(limit - ptr) < LLQ_OPTLEN) goto space_err; - opt->OptData.llq.vers = getVal16(&ptr); - opt->OptData.llq.llqOp = getVal16(&ptr); - opt->OptData.llq.err = getVal16(&ptr); - mDNSPlatformMemCopy(opt->OptData.llq.id.b, ptr, 8); - ptr += 8; - 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; - } - else if (opt->opt == kDNSOpt_Lease) - { - if ((unsigned)(limit - ptr) < sizeof(mDNSs32)) goto space_err; - - 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); - } - else { LogMsg("ERROR: getOptRdata - unknown opt %d", opt->opt); return mDNSNULL; } - opt++; // increment pointer into rdatabody - } - - rr->rdlength = pktRDLen; - return ptr; - - space_err: - LogMsg("ERROR: getLLQRdata - out of space"); - return mDNSNULL; - } - // 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) { + const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data; switch (rr->rrtype) { case kDNSType_A: if (rr->rdlength != 4) - { - debugf("putRData: Illegal length %d for kDNSType_A", rr->rdlength); - return(mDNSNULL); - } + { debugf("putRData: Illegal length %d for kDNSType_A", rr->rdlength); return(mDNSNULL); } if (ptr + 4 > limit) return(mDNSNULL); - *ptr++ = rr->rdata->u.ipv4.b[0]; - *ptr++ = rr->rdata->u.ipv4.b[1]; - *ptr++ = rr->rdata->u.ipv4.b[2]; - *ptr++ = rr->rdata->u.ipv4.b[3]; + *ptr++ = rdb->ipv4.b[0]; + *ptr++ = rdb->ipv4.b[1]; + *ptr++ = rdb->ipv4.b[2]; + *ptr++ = rdb->ipv4.b[3]; return(ptr); case kDNSType_NS: case kDNSType_CNAME: case kDNSType_PTR: - case kDNSType_DNAME:return(putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.name)); + case kDNSType_DNAME:return(putDomainNameAsLabels(msg, ptr, limit, &rdb->name)); - case kDNSType_SOA: ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.soa.mname); + case kDNSType_SOA: ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->soa.mname); if (!ptr) return(mDNSNULL); - ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.soa.rname); + ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->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); + ptr = putVal32(ptr, rdb->soa.serial); + ptr = putVal32(ptr, rdb->soa.refresh); + ptr = putVal32(ptr, rdb->soa.retry); + ptr = putVal32(ptr, rdb->soa.expire); + ptr = putVal32(ptr, rdb->soa.min); return(ptr); case kDNSType_NULL: @@ -1847,60 +2055,121 @@ mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNS case kDNSType_ISDN: case kDNSType_LOC: case kDNSType_DHCID:if (ptr + rr->rdlength > limit) return(mDNSNULL); - mDNSPlatformMemCopy(ptr, rr->rdata->u.data, rr->rdlength); + mDNSPlatformMemCopy(ptr, rdb->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)); + ptr = putVal16(ptr, rdb->mx.preference); + return(putDomainNameAsLabels(msg, ptr, limit, &rdb->mx.exchange)); - case kDNSType_RP: ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.rp.mbox); + case kDNSType_RP: ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->rp.mbox); if (!ptr) return(mDNSNULL); - ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.rp.txt); + ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->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); + ptr = putVal16(ptr, rdb->px.preference); + ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->px.map822); if (!ptr) return(mDNSNULL); - ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->rdata->u.px.mapx400); + ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->px.mapx400); return(ptr); - case kDNSType_AAAA: if (rr->rdlength != sizeof(rr->rdata->u.ipv6)) + case kDNSType_AAAA: if (rr->rdlength != sizeof(rdb->ipv6)) + { debugf("putRData: Illegal length %d for kDNSType_AAAA", rr->rdlength); return(mDNSNULL); } + if (ptr + sizeof(rdb->ipv6) > limit) return(mDNSNULL); + mDNSPlatformMemCopy(ptr, &rdb->ipv6, sizeof(rdb->ipv6)); + return(ptr + sizeof(rdb->ipv6)); + + case kDNSType_SRV: if (ptr + 7 > limit) return(mDNSNULL); + *ptr++ = (mDNSu8)(rdb->srv.priority >> 8); + *ptr++ = (mDNSu8)(rdb->srv.priority & 0xFF); + *ptr++ = (mDNSu8)(rdb->srv.weight >> 8); + *ptr++ = (mDNSu8)(rdb->srv.weight & 0xFF); + *ptr++ = rdb->srv.port.b[0]; + *ptr++ = rdb->srv.port.b[1]; + return(putDomainNameAsLabels(msg, ptr, limit, &rdb->srv.target)); + + case kDNSType_OPT: { + int len = 0; + const rdataOPT *opt; + const rdataOPT *const end = (const rdataOPT *)&rr->rdata->u.data[rr->rdlength]; + for (opt = &rr->rdata->u.opt[0]; opt < end; opt++) len += DNSOpt_Data_Space(opt); + if (ptr + len > limit) { LogMsg("ERROR: putOptRData - out of space"); return mDNSNULL; } + + for (opt = &rr->rdata->u.opt[0]; opt < end; opt++) { - debugf("putRData: Illegal length %d for kDNSType_AAAA", rr->rdlength); - return(mDNSNULL); + const int space = DNSOpt_Data_Space(opt); + ptr = putVal16(ptr, opt->opt); + ptr = putVal16(ptr, space - 4); + switch (opt->opt) + { + case kDNSOpt_LLQ: + ptr = putVal16(ptr, opt->u.llq.vers); + ptr = putVal16(ptr, opt->u.llq.llqOp); + ptr = putVal16(ptr, opt->u.llq.err); + mDNSPlatformMemCopy(ptr, opt->u.llq.id.b, 8); // 8-byte id + ptr += 8; + ptr = putVal32(ptr, opt->u.llq.llqlease); + break; + case kDNSOpt_Lease: + ptr = putVal32(ptr, opt->u.updatelease); + break; + case kDNSOpt_Owner: + *ptr++ = opt->u.owner.vers; + *ptr++ = opt->u.owner.seq; + mDNSPlatformMemCopy(ptr, opt->u.owner.HMAC.b, 6); // 6-byte Host identifier + ptr += 6; + if (space >= DNSOpt_OwnerData_ID_Wake_Space) + { + mDNSPlatformMemCopy(ptr, opt->u.owner.IMAC.b, 6); // 6-byte interface MAC + ptr += 6; + if (space > DNSOpt_OwnerData_ID_Wake_Space) + { + mDNSPlatformMemCopy(ptr, opt->u.owner.password.b, space - DNSOpt_OwnerData_ID_Wake_Space); + ptr += space - DNSOpt_OwnerData_ID_Wake_Space; + } + } + break; + } } - if (ptr + sizeof(rr->rdata->u.ipv6) > limit) return(mDNSNULL); - mDNSPlatformMemCopy(ptr, &rr->rdata->u.ipv6, sizeof(rr->rdata->u.ipv6)); - return(ptr + sizeof(rr->rdata->u.ipv6)); + return ptr; + } + + case kDNSType_NSEC: { + // For our simplified use of NSEC synthetic records: + // nextname is always the record's own name, + // the block number is always 0, + // the count byte is a value in the range 1-32, + // followed by the 1-32 data bytes + int i, j; + for (i=sizeof(rdataNSEC); i>0; i--) if (rdb->nsec.bitmap[i-1]) break; + ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name); + if (!ptr) return(mDNSNULL); + if (ptr + 2 + i > limit) return(mDNSNULL); + *ptr++ = 0; + *ptr++ = i; + for (j=0; jnsec.bitmap[j]; + return ptr; + } - 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); - *ptr++ = (mDNSu8)(rr->rdata->u.srv.weight & 0xFF); - *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); if (ptr + rr->rdlength > limit) return(mDNSNULL); - mDNSPlatformMemCopy(ptr, rr->rdata->u.data, rr->rdlength); + mDNSPlatformMemCopy(ptr, rdb->data, rr->rdlength); return(ptr + rr->rdlength); } } +#define IsUnicastUpdate(X) (!mDNSOpaque16IsZero((X)->h.id) && ((X)->h.flags.b[0] & kDNSFlag0_OP_Mask) == kDNSFlag0_OP_Update) + 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; + // When sending SRV to conventional DNS server (i.e. in DNS update requests) we should not do name compression on the rdata (RFC 2782) + const DNSMessage *const rdatacompressionbase = (IsUnicastUpdate(msg) && rr->rrtype == kDNSType_SRV) ? mDNSNULL : msg; if (rr->RecordType == kDNSRecordTypeUnregistered) { @@ -1914,13 +2183,13 @@ mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 * 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)(rrclass >> 8); - ptr[3] = (mDNSu8)(rrclass & 0xFF); + ptr[2] = (mDNSu8)(rr->rrclass >> 8); + ptr[3] = (mDNSu8)(rr->rrclass & 0xFF); ptr[4] = (mDNSu8)((ttl >> 24) & 0xFF); ptr[5] = (mDNSu8)((ttl >> 16) & 0xFF); ptr[6] = (mDNSu8)((ttl >> 8) & 0xFF); ptr[7] = (mDNSu8)( ttl & 0xFF); - endofrdata = putRData(msg, ptr+10, limit, rr); + endofrdata = putRData(rdatacompressionbase, ptr+10, limit, rr); if (!endofrdata) { verbosedebugf("Ran out of space in PutResourceRecord for %##s (%s)", rr->name->c, DNSTypeName(rr->rrtype)); return(mDNSNULL); } // Go back and fill in the actual number of data bytes we wrote @@ -1934,15 +2203,7 @@ mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 * return(endofrdata); } -mDNSexport mDNSu8 *PutResourceRecordCappedTTL(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 - maxttl) - { - if (maxttl > rr->rroriginalttl) maxttl = rr->rroriginalttl; - return(PutResourceRecordTTL(msg, ptr, count, rr, maxttl)); - } - -mDNSexport mDNSu8 *putEmptyResourceRecord(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, - mDNSu16 *count, const AuthRecord *rr) +mDNSlocal mDNSu8 *putEmptyResourceRecord(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, mDNSu16 *count, const AuthRecord *rr) { ptr = putDomainNameAsLabels(msg, ptr, limit, rr->resrec.name); if (!ptr || ptr + 10 > limit) return(mDNSNULL); // If we're out-of-space, return mDNSNULL @@ -2030,10 +2291,10 @@ mDNSexport mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domain ptr = putDomainNameAsLabels(msg, ptr, limit, name); if (!ptr || ptr + 10 >= limit) return mDNSNULL; // If we're out-of-space, return mDNSNULL - ptr[0] = (mDNSu8)(rrtype >> 8); - ptr[1] = (mDNSu8)(rrtype & 0xFF); - ptr[2] = (mDNSu8)(class >> 8); - ptr[3] = (mDNSu8)(class & 0xFF); + ptr[0] = (mDNSu8)(rrtype >> 8); + ptr[1] = (mDNSu8)(rrtype & 0xFF); + ptr[2] = (mDNSu8)(class >> 8); + ptr[3] = (mDNSu8)(class & 0xFF); ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0; // zero ttl ptr[8] = ptr[9] = 0; // zero rdlength/rdata @@ -2047,11 +2308,10 @@ mDNSexport mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease) AuthRecord rr; 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; + rr.resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record + rr.resrec.rdestimate = sizeof(rdataOPT); + rr.resrec.rdata->u.opt[0].opt = kDNSOpt_Lease; + rr.resrec.rdata->u.opt[0].u.updatelease = lease; end = PutResourceRecordTTLJumbo(msg, end, &msg->h.numAdditionals, &rr.resrec, 0); if (!end) { LogMsg("ERROR: putUpdateLease - PutResourceRecordTTL"); return mDNSNULL; } return end; @@ -2133,7 +2393,7 @@ mDNSexport const mDNSu8 *skipDomainName(const DNSMessage *const msg, const mDNSu case 0x00: if (ptr + len >= end) // Remember: expect at least one more byte for the root label { debugf("skipDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL); } if (total + 1 + len >= MAX_DOMAIN_NAME) // Remember: expect at least one more byte for the root label - { debugf("skipDomainName: Malformed domain name (more than 255 characters)"); return(mDNSNULL); } + { debugf("skipDomainName: Malformed domain name (more than 256 characters)"); return(mDNSNULL); } ptr += len; total += 1 + len; break; @@ -2170,7 +2430,7 @@ mDNSexport const mDNSu8 *getDomainName(const DNSMessage *const msg, const mDNSu8 case 0x00: if (ptr + len >= end) // Remember: expect at least one more byte for the root label { debugf("getDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL); } if (np + 1 + len >= limit) // Remember: expect at least one more byte for the root label - { debugf("getDomainName: Malformed domain name (more than 255 characters)"); return(mDNSNULL); } + { debugf("getDomainName: Malformed domain name (more than 256 characters)"); return(mDNSNULL); } *np++ = len; for (i=0; ir; + CacheRecord *const rr = &largecr->r; + RDataBody2 *const rdb = (RDataBody2 *)rr->smallrdatastorage.data; mDNSu16 pktrdlength; - if (largecr == &m->rec && largecr->r.resrec.RecordType) - LogMsg("GetLargeResourceRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &largecr->r)); + if (largecr == &m->rec && m->rec.r.resrec.RecordType) + { + LogMsg("GetLargeResourceRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &m->rec.r)); +#if ForceAlerts + *(long*)0 = 0; +#endif + } rr->next = mDNSNULL; rr->resrec.name = &largecr->namestorage; @@ -2231,10 +2504,12 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage rr->CRActiveQuestion = mDNSNULL; rr->UnansweredQueries = 0; rr->LastUnansweredTime= 0; +#if ENABLE_MULTI_PACKET_QUERY_SNOOPING rr->MPUnansweredQ = 0; rr->MPLastUnansweredQT= 0; rr->MPUnansweredKA = 0; rr->MPExpectingKA = mDNSfalse; +#endif rr->NextInCFList = mDNSNULL; rr->resrec.InterfaceID = InterfaceID; @@ -2261,7 +2536,7 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage 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; + rr->resrec.rdata = (RData*)&rr->smallrdatastorage; rr->resrec.rdata->MaxRDLength = MaximumRDSize; if (!RecordType) LogMsg("GetLargeResourceRecord: No RecordType for %##s", rr->resrec.name->c); @@ -2276,30 +2551,30 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage else switch (rr->resrec.rrtype) { 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]; + rdb->ipv4.b[0] = ptr[0]; + rdb->ipv4.b[1] = ptr[1]; + rdb->ipv4.b[2] = ptr[2]; + rdb->ipv4.b[3] = ptr[3]; break; case kDNSType_NS: case kDNSType_CNAME: case kDNSType_PTR: - case kDNSType_DNAME:ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.name); + case kDNSType_DNAME:ptr = getDomainName(msg, ptr, end, &rdb->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); + //debugf("%##s PTR %##s rdlen %d", rr->resrec.name.c, rdb->name.c, pktrdlength); break; - case kDNSType_SOA: ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.soa.mname); + case kDNSType_SOA: ptr = getDomainName(msg, ptr, end, &rdb->soa.mname); if (!ptr) { debugf("GetLargeResourceRecord: Malformed SOA RDATA mname"); return mDNSNULL; } - ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.soa.rname); + ptr = getDomainName(msg, ptr, end, &rdb->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]); + rdb->soa.serial = (mDNSs32) ((mDNSs32)ptr[0x00] << 24 | (mDNSs32)ptr[0x01] << 16 | (mDNSs32)ptr[0x02] << 8 | ptr[0x03]); + rdb->soa.refresh = (mDNSu32) ((mDNSu32)ptr[0x04] << 24 | (mDNSu32)ptr[0x05] << 16 | (mDNSu32)ptr[0x06] << 8 | ptr[0x07]); + rdb->soa.retry = (mDNSu32) ((mDNSu32)ptr[0x08] << 24 | (mDNSu32)ptr[0x09] << 16 | (mDNSu32)ptr[0x0A] << 8 | ptr[0x0B]); + rdb->soa.expire = (mDNSu32) ((mDNSu32)ptr[0x0C] << 24 | (mDNSu32)ptr[0x0D] << 16 | (mDNSu32)ptr[0x0E] << 8 | ptr[0x0F]); + rdb->soa.min = (mDNSu32) ((mDNSu32)ptr[0x10] << 24 | (mDNSu32)ptr[0x11] << 16 | (mDNSu32)ptr[0x12] << 8 | ptr[0x13]); break; case kDNSType_NULL: @@ -2316,49 +2591,111 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage return(mDNSNULL); } rr->resrec.rdlength = pktrdlength; - mDNSPlatformMemCopy(rr->resrec.rdata->u.data, ptr, pktrdlength); + mDNSPlatformMemCopy(rdb->data, ptr, pktrdlength); break; 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); + rdb->mx.preference = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); + ptr = getDomainName(msg, ptr+2, end, &rdb->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); + //debugf("%##s SRV %##s rdlen %d", rr->resrec.name.c, rdb->srv.target.c, pktrdlength); break; - case kDNSType_RP: ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.rp.mbox); // Domainname + domainname + case kDNSType_RP: ptr = getDomainName(msg, ptr, end, &rdb->rp.mbox); // Domainname + domainname if (!ptr) { debugf("GetLargeResourceRecord: Malformed RP mbox"); return mDNSNULL; } - ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.rp.txt); + ptr = getDomainName(msg, ptr, end, &rdb->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); + rdb->px.preference = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); + ptr = getDomainName(msg, ptr, end, &rdb->px.map822); if (!ptr) { debugf("GetLargeResourceRecord: Malformed PX map822"); return mDNSNULL; } - ptr = getDomainName(msg, ptr, end, &rr->resrec.rdata->u.px.mapx400); + ptr = getDomainName(msg, ptr, end, &rdb->px.mapx400); if (ptr != end) { debugf("GetLargeResourceRecord: Malformed PX mapx400"); return mDNSNULL; } break; case kDNSType_AAAA: if (pktrdlength != sizeof(mDNSv6Addr)) return(mDNSNULL); - mDNSPlatformMemCopy(&rr->resrec.rdata->u.ipv6, ptr, sizeof(rr->resrec.rdata->u.ipv6)); + mDNSPlatformMemCopy(&rdb->ipv6, ptr, sizeof(rdb->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]; - ptr = getDomainName(msg, ptr+6, end, &rr->resrec.rdata->u.srv.target); + rdb->srv.priority = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); + rdb->srv.weight = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]); + rdb->srv.port.b[0] = ptr[4]; + rdb->srv.port.b[1] = ptr[5]; + ptr = getDomainName(msg, ptr+6, end, &rdb->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); + //debugf("%##s SRV %##s rdlen %d", rr->resrec.name.c, rdb->srv.target.c, pktrdlength); break; - case kDNSType_OPT: ptr = getOptRdata(ptr, end, largecr, pktrdlength); break; + case kDNSType_OPT: { + rdataOPT *opt = rr->resrec.rdata->u.opt; + rr->resrec.rdlength = 0; + while (ptr < end && (mDNSu8 *)(opt+1) < &rr->resrec.rdata->u.data[MaximumRDSize]) + { + if (ptr + 4 > end) { LogMsg("GetLargeResourceRecord: OPT RDATA ptr + 4 > end"); return(mDNSNULL); } + opt->opt = getVal16(&ptr); + opt->optlen = getVal16(&ptr); + if (!ValidDNSOpt(opt)) { LogMsg("GetLargeResourceRecord: opt %d optlen %d wrong", opt->opt, opt->optlen); return(mDNSNULL); } + if (ptr + opt->optlen > end) { LogMsg("GetLargeResourceRecord: ptr + opt->optlen > end"); return(mDNSNULL); } + switch(opt->opt) + { + case kDNSOpt_LLQ: + opt->u.llq.vers = getVal16(&ptr); + opt->u.llq.llqOp = getVal16(&ptr); + opt->u.llq.err = getVal16(&ptr); + mDNSPlatformMemCopy(opt->u.llq.id.b, ptr, 8); + ptr += 8; + opt->u.llq.llqlease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]); + if (opt->u.llq.llqlease > 0x70000000UL / mDNSPlatformOneSecond) + opt->u.llq.llqlease = 0x70000000UL / mDNSPlatformOneSecond; + ptr += sizeof(mDNSOpaque32); + break; + case kDNSOpt_Lease: + opt->u.updatelease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]); + if (opt->u.updatelease > 0x70000000UL / mDNSPlatformOneSecond) + opt->u.updatelease = 0x70000000UL / mDNSPlatformOneSecond; + ptr += sizeof(mDNSs32); + break; + case kDNSOpt_Owner: + opt->u.owner.vers = ptr[0]; + opt->u.owner.seq = ptr[1]; + mDNSPlatformMemCopy(opt->u.owner.HMAC.b, ptr+2, 6); // 6-byte MAC address + mDNSPlatformMemCopy(opt->u.owner.IMAC.b, ptr+2, 6); // 6-byte MAC address + opt->u.owner.password = zeroEthAddr; + if (opt->optlen >= DNSOpt_OwnerData_ID_Wake_Space-4) + { + mDNSPlatformMemCopy(opt->u.owner.IMAC.b, ptr+8, 6); // 6-byte MAC address + if (opt->optlen > DNSOpt_OwnerData_ID_Wake_Space-4) + mDNSPlatformMemCopy(opt->u.owner.password.b, ptr+14, opt->optlen - (DNSOpt_OwnerData_ID_Wake_Space-4)); + } + ptr += opt->optlen; + break; + } + opt++; // increment pointer into rdatabody + } + rr->resrec.rdlength = (mDNSu8*)opt - rr->resrec.rdata->u.data; if (ptr != end) { LogMsg("GetLargeResourceRecord: Malformed OptRdata"); return(mDNSNULL); } + break; + } + + case kDNSType_NSEC: { + unsigned int i, j; + domainname d; + ptr = getDomainName(msg, ptr, end, &d); // Ignored for our simplified use of NSEC synthetic records + if (!ptr) { debugf("GetLargeResourceRecord: Malformed NSEC nextname"); return mDNSNULL; } + if (*ptr++ != 0) { debugf("GetLargeResourceRecord: We only handle block zero NSECs"); return mDNSNULL; } + i = *ptr++; + if (i < 1 || i > sizeof(rdataNSEC)) { debugf("GetLargeResourceRecord: invalid block length %d", i); return mDNSNULL; } + mDNSPlatformMemZero(rdb->nsec.bitmap, sizeof(rdb->nsec.bitmap)); + for (j=0; jnsec.bitmap[j] = *ptr++; + if (ptr != end) { LogMsg("GetLargeResourceRecord: Malformed NSEC"); return(mDNSNULL); } + break; + } default: if (pktrdlength > rr->resrec.rdata->MaxRDLength) { @@ -2374,7 +2711,7 @@ 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(rr->resrec.rdata->u.data, ptr, pktrdlength); + mDNSPlatformMemCopy(rdb->data, ptr, pktrdlength); break; } @@ -2399,6 +2736,7 @@ mDNSexport const mDNSu8 *getQuestion(const DNSMessage *msg, const mDNSu8 *ptr, c { mDNSPlatformMemZero(question, sizeof(*question)); question->InterfaceID = InterfaceID; + if (!InterfaceID) question->TargetQID = onesID; // In DNSQuestions we use TargetQID as the indicator of whether it's unicast or multicast ptr = getDomainName(msg, ptr, end, &question->qname); if (!ptr) { debugf("Malformed domain name in DNS question section"); return(mDNSNULL); } if (ptr+4 > end) { debugf("Malformed DNS question section -- no query type and class!"); return(mDNSNULL); } @@ -2433,7 +2771,7 @@ mDNSexport const mDNSu8 *LocateAdditionals(const DNSMessage *const msg, const mD return (ptr); } -mDNSexport const mDNSu8 *LocateLLQOptData(const DNSMessage *const msg, const mDNSu8 *const end) +mDNSexport const mDNSu8 *LocateOptRR(const DNSMessage *const msg, const mDNSu8 *const end, int minsize) { int i; const mDNSu8 *ptr = LocateAdditionals(msg, end); @@ -2444,11 +2782,11 @@ mDNSexport const mDNSu8 *LocateLLQOptData(const DNSMessage *const msg, const mDN // 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) + if (ptr + DNSOpt_Header_Space + minsize <= end && // Make sure we have 11+minsize 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)minsize) return(ptr); else ptr = skipResourceRecord(msg, ptr, end); @@ -2457,39 +2795,16 @@ mDNSexport const mDNSu8 *LocateLLQOptData(const DNSMessage *const msg, const mDN } // On success, GetLLQOptData returns pointer to storage within shared "m->rec"; -// it is callers responsibilty to clear m->rec.r.resrec.RecordType after use +// it is caller's 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); + const mDNSu8 *ptr = LocateOptRR(msg, end, DNSOpt_LLQData_Space); 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); + if (ptr) return(&m->rec.r.resrec.rdata->u.opt[0]); } return(mDNSNULL); } @@ -2499,10 +2814,10 @@ mDNSexport const mDNSu8 *LocateLeaseOptData(const DNSMessage *const msg, const m mDNSexport mDNSu32 GetPktLease(mDNS *m, DNSMessage *msg, const mDNSu8 *end) { mDNSu32 result = 0; - const mDNSu8 *ptr = LocateLeaseOptData(msg, end); + const mDNSu8 *ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space); if (ptr) ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec); - if (ptr && m->rec.r.resrec.rdlength >= LEASE_OPT_RDLEN && m->rec.r.resrec.rdata->u.opt.opt == kDNSOpt_Lease) - result = m->rec.r.resrec.rdata->u.opt.OptData.updatelease; + if (ptr && m->rec.r.resrec.rdlength >= DNSOpt_LeaseData_Space && m->rec.r.resrec.rdata->u.opt[0].opt == kDNSOpt_Lease) + result = m->rec.r.resrec.rdata->u.opt[0].u.updatelease; m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it return(result); } @@ -2534,8 +2849,8 @@ mDNSlocal const mDNSu8 *DumpRecords(mDNS *const m, const DNSMessage *const msg, #define DNS_RC_Name(X) ( \ (X) == kDNSFlag1_RC_NoErr ? "NoErr" : \ - (X) == kDNSFlag1_RC_FmtErr ? "FmtErr" : \ - (X) == kDNSFlag1_RC_SrvErr ? "SrvErr" : \ + (X) == kDNSFlag1_RC_FormErr ? "FormErr" : \ + (X) == kDNSFlag1_RC_ServFail ? "ServFail" : \ (X) == kDNSFlag1_RC_NXDomain ? "NXDomain" : \ (X) == kDNSFlag1_RC_NotImpl ? "NotImpl" : \ (X) == kDNSFlag1_RC_Refused ? "Refused" : \ @@ -2546,7 +2861,7 @@ mDNSlocal const mDNSu8 *DumpRecords(mDNS *const m, const DNSMessage *const msg, (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, +mDNSexport void DumpPacket(mDNS *const m, mStatus status, mDNSBool sent, char *transport, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end) { @@ -2554,14 +2869,16 @@ mDNSexport void DumpPacket(mDNS *const m, mDNSBool sent, char *transport, const mDNSu8 *ptr = msg->data; int i; DNSQuestion q; - char sbuffer[64], dbuffer[64] = ""; + char tbuffer[64], sbuffer[64], dbuffer[64] = ""; + if (!status) tbuffer[mDNS_snprintf(tbuffer, sizeof(tbuffer), sent ? "Sent" : "Received" )] = 0; + else tbuffer[mDNS_snprintf(tbuffer, sizeof(tbuffer), "ERROR %d %sing", status, sent ? "Send" : "Receiv")] = 0; if (sent) sbuffer[mDNS_snprintf(sbuffer, sizeof(sbuffer), "port " )] = 0; else sbuffer[mDNS_snprintf(sbuffer, sizeof(sbuffer), "%#a:", srcaddr)] = 0; if (dstaddr || !mDNSIPPortIsZero(dstport)) dbuffer[mDNS_snprintf(dbuffer, sizeof(dbuffer), " to %#a:%d", dstaddr, mDNSVal16(dstport))] = 0; LogMsg("-- %s %s DNS %s%s (flags %02X%02X) RCODE: %s (%d) %s%s%s%s%s%sID: %d %d bytes from %s%d%s%s --", - sent ? "Sent" : "Received", transport, + tbuffer, 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], @@ -2611,71 +2928,52 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo) { mStatus status = mStatus_NoError; - const mDNSu16 numQuestions = msg->h.numQuestions; - const mDNSu16 numAnswers = msg->h.numAnswers; - const mDNSu16 numAuthorities = msg->h.numAuthorities; const mDNSu16 numAdditionals = msg->h.numAdditionals; - mDNSu16 tmpNumAdditionals = numAdditionals; - mDNSu8 *ptr = (mDNSu8 *)&msg->h.numQuestions; + mDNSu8 *newend; - if (end <= msg->data || end - msg->data > AbsoluteMaxDNSMessageData) + // Zero-length message data is okay (e.g. for a DNS Update ack, where all we need is an ID and an error code + if (end < msg->data || end - msg->data > AbsoluteMaxDNSMessageData) { LogMsg("mDNSSendDNSMessage: invalid message %p %p %d", msg->data, end, end - msg->data); return mStatus_BadParamErr; } - end = putHINFO(m, msg, end, authInfo); - if (!end) { LogMsg("mDNSSendDNSMessage: putHINFO failed"); status = mStatus_NoMemoryErr; } - else - { - tmpNumAdditionals = msg->h.numAdditionals; + newend = putHINFO(m, msg, end, authInfo); + if (!newend) LogMsg("mDNSSendDNSMessage: putHINFO failed"); // Not fatal + else end = newend; - // 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)(tmpNumAdditionals >> 8); - *ptr++ = (mDNSu8)(tmpNumAdditionals & 0xFF); + // Put all the integer values in IETF byte-order (MSB first, LSB second) + SwapDNSHeaderBytes(msg); - if (authInfo) DNSDigest_SignMessage(msg, &end, authInfo, 0); // DNSDigest_SignMessage operates on message in network byte order - if (!end) { LogMsg("mDNSSendDNSMessage: DNSDigest_SignMessage failed"); status = mStatus_NoMemoryErr; } + if (authInfo) DNSDigest_SignMessage(msg, &end, authInfo, 0); // DNSDigest_SignMessage operates on message in network byte order + if (!end) { LogMsg("mDNSSendDNSMessage: DNSDigest_SignMessage failed"); status = mStatus_NoMemoryErr; } + else + { + // Send the packet on the wire + if (!sock) + status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, src, dst, dstport); else { - // Send the packet on the wire - if (!sock) - status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, src, dst, dstport); + mDNSu16 msglen = (mDNSu16)(end - (mDNSu8 *)msg); + mDNSu8 lenbuf[2] = { (mDNSu8)(msglen >> 8), (mDNSu8)(msglen & 0xFF) }; + long nsent = mDNSPlatformWriteTCP(sock, (char*)lenbuf, 2); // Should do scatter/gather here -- this is probably going out as two packets + if (nsent != 2) { LogMsg("mDNSSendDNSMessage: write msg length failed %d/%d", nsent, 2); status = mStatus_ConnFailed; } else { - mDNSu16 msglen = (mDNSu16)(end - (mDNSu8 *)msg); - mDNSu8 lenbuf[2] = { (mDNSu8)(msglen >> 8), (mDNSu8)(msglen & 0xFF) }; - long nsent = mDNSPlatformWriteTCP(sock, (char*)lenbuf, 2); // Should do scatter/gather here -- this is probably going out as two packets - if (nsent != 2) { LogMsg("mDNSSendDNSMessage: write msg length failed %d/%d", nsent, 2); status = mStatus_ConnFailed; } - else - { - nsent = mDNSPlatformWriteTCP(sock, (char *)msg, msglen); - if (nsent != msglen) { LogMsg("mDNSSendDNSMessage: write msg body failed %d/%d", nsent, msglen); status = mStatus_ConnFailed; } - } + nsent = mDNSPlatformWriteTCP(sock, (char *)msg, msglen); + if (nsent != msglen) { LogMsg("mDNSSendDNSMessage: write msg body failed %d/%d", nsent, msglen); status = mStatus_ConnFailed; } } } } - // Put all the integer values back the way they were before we return - msg->h.numQuestions = numQuestions; - msg->h.numAnswers = numAnswers; - msg->h.numAuthorities = numAuthorities; + // Swap the integer values back the way they were (remember that numAdditionals may have been changed by putHINFO and/or SignMessage) + SwapDNSHeaderBytes(msg); // Dump the packet with the HINFO and TSIG - if (mDNS_LogLevel >= MDNS_LOG_VERBOSE_DEBUG && !mDNSOpaque16IsZero(msg->h.id)) - { - ptr = (mDNSu8 *)&msg->h.numAdditionals; - msg->h.numAdditionals = (mDNSu16)ptr[0] << 8 | (mDNSu16)ptr[1]; - DumpPacket(m, mDNStrue, sock && (sock->flags & kTCPSocketFlags_UseTLS) ? "TLS" : sock ? "TCP" : "UDP", mDNSNULL, src ? src->port : MulticastDNSPort, dst, dstport, msg, end); - } + if (mDNS_PacketLoggingEnabled && !mDNSOpaque16IsZero(msg->h.id)) + DumpPacket(m, status, mDNStrue, sock && (sock->flags & kTCPSocketFlags_UseTLS) ? "TLS" : sock ? "TCP" : "UDP", mDNSNULL, src ? src->port : MulticastDNSPort, dst, dstport, msg, end); - // put the final integer value back the way it was + // put the number of additionals back the way it was msg->h.numAdditionals = numAdditionals; return(status); @@ -2743,28 +3041,77 @@ mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m) } if (m->NewLocalOnlyQuestions) return(m->timenow); if (m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords)) return(m->timenow); + if (m->SPSProxyListChanged) return(m->timenow); #ifndef UNICAST_DISABLED if (e - m->NextuDNSEvent > 0) e = m->NextuDNSEvent; if (e - m->NextScheduledNATOp > 0) e = m->NextScheduledNATOp; #endif if (e - m->NextCacheCheck > 0) e = m->NextCacheCheck; + if (e - m->NextScheduledSPS > 0) e = m->NextScheduledSPS; + if (m->SleepLimit && e - m->NextScheduledSPRetry > 0) e = m->NextScheduledSPRetry; + if (m->DelaySleep && e - m->DelaySleep > 0) e = m->DelaySleep; - if (!m->SleepState) + if (m->SuppressSending) { - if (m->SuppressSending) - { - if (e - m->SuppressSending > 0) e = m->SuppressSending; - } - else - { - 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->SuppressSending > 0) e = m->SuppressSending; } + else + { + if (e - m->NextScheduledQuery > 0) e = m->NextScheduledQuery; + if (e - m->NextScheduledProbe > 0) e = m->NextScheduledProbe; + if (e - m->NextScheduledResponse > 0) e = m->NextScheduledResponse; + } + return(e); } +mDNSexport void ShowTaskSchedulingError(mDNS *const m) + { + mDNS_Lock(m); + + LogMsg("Task Scheduling Error: Continuously busy for more than a second"); + + // Note: To accurately diagnose *why* we're busy, the debugging code here needs to mirror the logic in GetNextScheduledEvent above + + 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)); + + if (m->NewLocalOnlyQuestions) + LogMsg("Task Scheduling Error: NewLocalOnlyQuestions %##s (%s)", + m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype)); + + if (m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords)) + LogMsg("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m, m->NewLocalRecords)); + + if (m->timenow - m->NextScheduledEvent >= 0) + LogMsg("Task Scheduling Error: m->NextScheduledEvent %d", m->timenow - m->NextScheduledEvent); + if (m->SuppressSending && m->timenow - m->SuppressSending >= 0) + LogMsg("Task Scheduling Error: m->SuppressSending %d", m->timenow - m->SuppressSending); + if (m->timenow - m->NextCacheCheck >= 0) + LogMsg("Task Scheduling Error: m->NextCacheCheck %d", m->timenow - m->NextCacheCheck); + if (m->timenow - m->NextScheduledQuery >= 0) + LogMsg("Task Scheduling Error: m->NextScheduledQuery %d", m->timenow - m->NextScheduledQuery); + if (m->timenow - m->NextScheduledProbe >= 0) + 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); + if (m->timenow - m->NextScheduledSPS >= 0) + LogMsg("Task Scheduling Error: m->NextScheduledSPS %d", m->timenow - m->NextScheduledSPS); + if (m->SleepLimit && m->timenow - m->NextScheduledSPRetry >= 0) + LogMsg("Task Scheduling Error: m->NextScheduledSPRetry %d", m->timenow - m->NextScheduledSPRetry); + if (m->DelaySleep && m->timenow - m->DelaySleep >= 0) + LogMsg("Task Scheduling Error: m->DelaySleep %d", m->timenow - m->DelaySleep); +#ifndef UNICAST_DISABLED + if (m->timenow - m->NextuDNSEvent >= 0) + LogMsg("Task Scheduling Error: NextuDNSEvent %d", m->timenow - m->NextuDNSEvent); +#endif + + mDNS_Unlock(m); + } + mDNSexport void mDNS_Unlock_(mDNS *const m) { // Decrement mDNS_busy diff --git a/mDNSCore/DNSCommon.h b/mDNSCore/DNSCommon.h index 52169de..95d4e30 100644 --- a/mDNSCore/DNSCommon.h +++ b/mDNSCore/DNSCommon.h @@ -17,6 +17,48 @@ Change History (most recent first): $Log: DNSCommon.h,v $ +Revision 1.73 2009/04/24 00:28:05 cheshire + Return negative answers when host knows authoritatively that no answer exists +Added definitions for RRTypeAnswersQuestionType/RRAssertsNonexistence/AnyTypeRecordAnswersQuestion + +Revision 1.72 2009/04/01 21:12:56 herscher + Current Bonjour code does not compile on Windows + +Revision 1.71 2009/04/01 17:50:10 mcguire +cleanup mDNSRandom + +Revision 1.70 2009/03/04 00:40:12 cheshire +Updated DNS server error codes to be more consistent with definitions at + + +Revision 1.69 2008/11/26 20:57:37 cheshire +For consistency with other similar macros, renamed mdnsIsDigit/mdnsIsLetter/mdnsValidHostChar +to mDNSIsDigit/mDNSIsLetter/mDNSValidHostChar + +Revision 1.68 2008/11/14 21:56:31 cheshire +Moved debugging routine ShowTaskSchedulingError() from daemon.c into DNSCommon.c + +Revision 1.67 2008/11/13 19:05:09 cheshire +Added definition of LocateOptRR() + +Revision 1.66 2008/10/22 19:56:54 cheshire +Removed unused SameRData() macro -- it duplicates the functionality of IdenticalSameNameRecord() + +Revision 1.65 2008/10/20 15:39:20 cheshire +Group "#define PutResourceRecord ..." with related definitions + +Revision 1.64 2008/10/08 01:03:33 cheshire +Change GetFirstActiveInterface() so the NetworkInterfaceInfo it returns is not "const" + +Revision 1.63 2008/09/23 02:30:07 cheshire +Get rid of PutResourceRecordCappedTTL() + +Revision 1.62 2008/09/23 02:26:09 cheshire +Don't need to export putEmptyResourceRecord (it's only used from DNSCommon.c) + +Revision 1.61 2008/08/13 00:47:53 mcguire +Handle failures when packet logging + Revision 1.60 2008/07/24 20:23:03 cheshire Should use randomized source ports and transaction IDs to avoid DNS cache poisoning @@ -162,8 +204,8 @@ typedef enum kDNSFlag1_RC_Mask = 0x0F, // Response code kDNSFlag1_RC_NoErr = 0x00, - kDNSFlag1_RC_FmtErr = 0x01, - kDNSFlag1_RC_SrvErr = 0x02, + kDNSFlag1_RC_FormErr = 0x01, + kDNSFlag1_RC_ServFail = 0x02, kDNSFlag1_RC_NXDomain = 0x03, kDNSFlag1_RC_NotImpl = 0x04, kDNSFlag1_RC_Refused = 0x05, @@ -187,11 +229,10 @@ typedef enum #pragma mark - General Utility Functions #endif -extern const NetworkInterfaceInfo *GetFirstActiveInterface(const NetworkInterfaceInfo *intf); +extern NetworkInterfaceInfo *GetFirstActiveInterface(NetworkInterfaceInfo *intf); extern mDNSInterfaceID GetNextActiveInterfaceID(const NetworkInterfaceInfo *intf); 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 @@ -199,12 +240,12 @@ extern mDNSu32 mDNSRandomFromFixedSeed(mDNSu32 seed, mDNSu32 max); #pragma mark - Domain Name Utility Functions #endif -#define mdnsIsDigit(X) ((X) >= '0' && (X) <= '9') +#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 mDNSIsLetter(X) (mDNSIsUpperCase(X) || mDNSIsLowerCase(X)) -#define mdnsValidHostChar(X, notfirst, notlast) (mdnsIsLetter(X) || mdnsIsDigit(X) || ((notfirst) && (notlast) && (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); @@ -252,11 +293,16 @@ extern void AppendLabelSuffix(domainlabel *name, mDNSu32 val, mDNSBool RichText) (r1)->rdatahash == (r2)->rdatahash && \ SameRDataBody((r1), &(r2)->rdata->u)) +// A given RRType answers a QuestionType if RRType is CNAME, or types match, or QuestionType is ANY, +// or the RRType is NSEC and positively asserts the nonexistence of the type being requested +#define RRTypeAnswersQuestionType(R,T) ((R)->rrtype == kDNSType_CNAME || (R)->rrtype == (T) || (T) == kDNSQType_ANY || RRAssertsNonexistence((R),(T))) +#define RRAssertsNonexistence(R,T) ((R)->rrtype == kDNSType_NSEC && (T) < kDNSQType_ANY && !((R)->rdata->u.nsec.bitmap[(T)>>3] & (128 >> ((T)&7)))) + extern mDNSu32 RDataHashValue(const ResourceRecord *const rr); extern mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2); -#define SameRData(r1,r2) ((r1)->rrtype == (r2)->rrtype && (r1)->rdlength == (r2)->rdlength && (r1)->rdatahash == (r2)->rdatahash && SameRDataBody((r1), &(r2)->rdata->u)) -extern mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q); extern mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q); +extern mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q); +extern mDNSBool AnyTypeRecordAnswersQuestion (const ResourceRecord *const rr, const DNSQuestion *const q); extern mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate); extern mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd); @@ -281,12 +327,13 @@ extern mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 * // 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 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), \ + +#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); +#define PutResourceRecordTTLJumbo(msg, ptr, count, rr, ttl) \ + PutResourceRecordTTLWithLimit((msg), (ptr), (count), (rr), (ttl), (msg)->data + AbsoluteMaxDNSMessageData) +#define PutResourceRecord(MSG, P, C, RR) PutResourceRecordTTL((MSG), (P), (C), (RR), (RR)->rroriginalttl) 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); @@ -295,7 +342,6 @@ extern mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *r 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) extern mDNSu8 *putHINFO(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end, DomainAuthInfo *authInfo); @@ -320,11 +366,10 @@ extern const mDNSu8 *getQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const 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 mDNSu8 *LocateOptRR(const DNSMessage *const msg, const mDNSu8 *const end, int minsize); extern const rdataOPT *GetLLQOptData(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end); -extern 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 *transport, +extern void DumpPacket(mDNS *const m, mStatus status, mDNSBool sent, char *transport, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end); @@ -343,9 +388,14 @@ extern mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 * #pragma mark - RR List Management & Task Management #endif +extern void ShowTaskSchedulingError(mDNS *const m); extern void mDNS_Lock_(mDNS *const m); extern void mDNS_Unlock_(mDNS *const m); +#if defined(_WIN32) + #define __func__ __FUNCTION__ +#endif + #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) diff --git a/mDNSCore/DNSDigest.c b/mDNSCore/DNSDigest.c index 09ff7c7..d83e635 100644 --- a/mDNSCore/DNSDigest.c +++ b/mDNSCore/DNSDigest.c @@ -17,6 +17,9 @@ Change History (most recent first): $Log: DNSDigest.c,v $ +Revision 1.26 2008/10/10 23:21:51 mcguire +fixed typo in original MD5 source reference + Revision 1.25 2007/12/17 23:48:29 cheshire DNSDigest_SignMessage doesn't need to return a result -- it already updates the 'end' parameter @@ -153,7 +156,7 @@ mDNSlocal mDNSu32 NToH32(mDNSu8 * bytes) * Note: machine archetecure specific conditionals from the original sources are turned off, but are left in the code * to aid in platform-specific optimizations and debugging. * Sources originally distributed under the following license headers: - * CommonDigest.c - APSL + * CommonDigest.h - APSL * * md32_Common.h * ==================================================================== diff --git a/mDNSCore/mDNS.c b/mDNSCore/mDNS.c index 2578911..c267896 100755 --- a/mDNSCore/mDNS.c +++ b/mDNSCore/mDNS.c @@ -38,23 +38,632 @@ Change History (most recent first): $Log: mDNS.c,v $ -Revision 1.777.4.5 2008/09/30 18:03:01 mcguire +Revision 1.969.2.1 2009/07/23 23:41:25 cheshire + Sleep Proxy: Ten-second maintenance wake not long enough to reliably get network connectivity + +Revision 1.969 2009/06/30 21:18:19 cheshire + Plugging and unplugging the power cable shouldn't cause a network change event +Additional fixes: +1. Made mDNS_ActivateNetWake_internal and mDNS_DeactivateNetWake_internal more defensive against bad parameters +2. mDNS_DeactivateNetWake_internal also needs to stop any outstanding Sleep Proxy resolve operations + +Revision 1.968 2009/06/29 23:51:09 cheshire + Can't bind to Active Directory + +Revision 1.967 2009/06/27 00:25:27 cheshire + mDNSResponder taking up 13% CPU with 400 KBps incoming bonjour requests +Removed overly-complicate and ineffective multi-packet known-answer snooping code +(Bracketed it with "#if ENABLE_MULTI_PACKET_QUERY_SNOOPING" for now; will delete actual code later) + +Revision 1.966 2009/06/26 01:55:55 cheshire + mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour +Additional refinements -- except for the case of explicit queries for record types we don't have (for names we own), +add additional NSEC records only when there's space to do that without having to generate an additional packet + +Revision 1.965 2009/06/24 22:14:21 cheshire + Plugging and unplugging the power cable shouldn't cause a network change event + +Revision 1.964 2009/06/03 23:07:13 cheshire + mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour +Large records were not being added in cases where an NSEC record was also required + +Revision 1.963 2009/05/28 00:39:19 cheshire + Sleep is delayed by 10 seconds if BTMM is on +After receiving confirmation of wide-area record deletion, need to schedule another evaluation of whether we're ready to sleep yet + +Revision 1.962 2009/05/19 23:40:37 cheshire + Sleep Proxy: Retransmission logic not working reliably on quiet networks +Added m->NextScheduledSPRetry timer for scheduling Sleep Proxy registration retries + +Revision 1.961 2009/05/19 23:00:43 cheshire +Improved comments and debugging messages + +Revision 1.960 2009/05/13 17:25:33 mkrochma + Should not schedule maintenance wake when machine has no advertised services +Sleep proxy client should only look for services being advertised via Multicast + +Revision 1.959 2009/05/12 23:10:31 cheshire + Should not schedule maintenance wake when machine has no advertised services +Make new routine mDNSCoreHaveAdvertisedServices so daemon.c can tell whether it needs to schedule a maintenance wake + +Revision 1.958 2009/05/12 19:19:20 cheshire + Sleep Proxy delays sleep by ten seconds when logged in to VPN + +Revision 1.957 2009/05/07 23:56:25 cheshire + Retransmit and retry Sleep Proxy Server requests +To get negative answers for our AAAA query we need to set the ReturnIntermed flag on the NetWakeResolve question + +Revision 1.956 2009/05/07 23:46:27 cheshire + Retransmit and retry Sleep Proxy Server requests + +Revision 1.955 2009/05/07 23:40:54 cheshire +Minor code rearrangement in preparation for upcoming changes + +Revision 1.954 2009/05/01 21:28:34 cheshire + AppleConnectAgent's reachability checks delay sleep by 30 seconds +No longer suspend network operations after we've acknowledged that the machine is going to sleep, +because other software may not have yet acknowledged the sleep event, and may be still trying +to do unicast DNS queries or other Bonjour operations. + +Revision 1.953 2009/05/01 19:17:35 cheshire + Sleep Proxy: Reduce the frequency of maintenance wakes: ODD, fans, power + +Revision 1.952 2009/05/01 19:16:45 mcguire + Crash: mDNS_vsnprintf + 1844 + +Revision 1.951 2009/04/28 23:48:19 jessic2 + regservice_callback: instance->request is NULL 0 + +Revision 1.950 2009/04/25 01:17:10 mcguire +Fix spurious TCP connect failures uncovered by PPP doesn't automatically reconnect on wake from sleep + +Revision 1.949 2009/04/25 01:11:02 mcguire +Refactor: create separate function: RestartRecordGetZoneData + +Revision 1.948 2009/04/24 21:25:16 cheshire + Special case Net Assistant port so Apple Remote Desktop doesn't wake up every machine on the network + +Revision 1.947 2009/04/24 19:41:12 mcguire + 4 second delay in DNS response + +Revision 1.946 2009/04/24 19:28:39 mcguire + 4 second delay in DNS response + +Revision 1.945 2009/04/24 00:30:30 cheshire + Return negative answers when host knows authoritatively that no answer exists +Added code to generate and process NSEC records + +Revision 1.944 2009/04/23 22:06:29 cheshire +Added CacheRecord and InterfaceID parameters to MakeNegativeCacheRecord, in preparation for: + Return negative answers when host knows authoritatively that no answer exists + +Revision 1.943 2009/04/22 01:19:56 jessic2 + Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32 + +Revision 1.942 2009/04/21 02:13:29 cheshire + Local hostname changed even though there really isn't a name conflict +Made code less susceptible to being tricked by stale packets echoed back from the network. + +Revision 1.941 2009/04/15 22:22:23 mcguire + uDNS: Treat RCODE 5 (Refused) responses as failures +Additional fix: protect against deref of NULL + +Revision 1.940 2009/04/15 20:42:51 mcguire + uDNS: Treat RCODE 5 (Refused) responses as failures + +Revision 1.939 2009/04/11 00:19:32 jessic2 + Daemon: Should be able to turn on LogOperation dynamically + +Revision 1.938 2009/04/06 23:44:57 cheshire + mDNSResponder thrashing kernel lock in the UDP close path, hurting SPECweb performance + +Revision 1.937 2009/04/04 00:14:49 mcguire +fix logging in BeginSleepProcessing + +Revision 1.936 2009/04/04 00:10:59 mcguire +don't ignore m->SystemWakeOnLANEnabled when going to sleep + +Revision 1.935 2009/04/01 17:50:11 mcguire +cleanup mDNSRandom + +Revision 1.934 2009/03/27 17:17:58 cheshire +Improved "Ignoring suspect uDNS response" debugging message + +Revision 1.933 2009/03/21 02:40:21 cheshire + uDNS: Need to create negative cache entries for "local" SOA + +Revision 1.932 2009/03/20 23:53:03 jessic2 + SIGHUP should restart all in-progress queries + +Revision 1.931 2009/03/18 19:08:15 cheshire +Show old/new sleep sequence numbers in logical order + +Revision 1.930 2009/03/17 23:40:45 cheshire +For now only try the highest-ranked Sleep Proxy; fixed come compiler warnings + +Revision 1.929 2009/03/17 21:55:56 cheshire +Fixed mistake in logic for decided when we're ready to go to sleep + +Revision 1.928 2009/03/17 19:48:12 cheshire + Don't cache negative unicast answers for Multicast DNS names + +Revision 1.927 2009/03/17 01:22:56 cheshire + Sleep Proxy: Retransmit and retry Sleep Proxy Server requests +Initial support for resolving up to three Sleep Proxies in parallel + +Revision 1.926 2009/03/17 01:05:07 mcguire + Reachability fixes on DNS config change + +Revision 1.925 2009/03/13 01:35:36 mcguire + Reachability fixes on DNS config change + +Revision 1.924 2009/03/10 23:45:20 cheshire +Added comments explaining usage of SetSPSProxyListChanged() + +Revision 1.923 2009/03/09 21:53:02 cheshire + Sleep Proxy: Need to stop proxying when it sees an ARP probe from the client + +Revision 1.922 2009/03/09 21:30:17 cheshire +Improved some LogSPS messages; made RestartProbing() subroutine + +Revision 1.921 2009/03/06 22:53:31 cheshire +Don't bother registering with Sleep Proxy if we have no advertised services + +Revision 1.920 2009/03/06 20:08:55 cheshire + Sleep Proxy: Return error responses to clients + +Revision 1.919 2009/03/05 21:54:43 cheshire +Improved "Sleep Proxy Server started / stopped" message + +Revision 1.918 2009/03/04 01:37:14 cheshire + Limit maximum number of records that a Sleep Proxy Server will accept + +Revision 1.917 2009/03/03 23:14:25 cheshire +Got rid of code duplication by making subroutine "SetupOwnerOpt" + +Revision 1.916 2009/03/03 23:04:43 cheshire +For clarity, renamed "MAC" field to "HMAC" (Host MAC, as opposed to Interface MAC) + +Revision 1.915 2009/03/03 22:51:53 cheshire + Sleep Proxy: Waking on same network but different interface will cause conflicts + +Revision 1.914 2009/03/03 00:46:09 cheshire +Additional debugging information in ResolveSimultaneousProbe + +Revision 1.913 2009/02/27 03:08:47 cheshire + Crash while shutting down when "local" is in the user's DNS searchlist + +Revision 1.912 2009/02/27 02:31:28 cheshire +Improved "Record not found in list" debugging message + +Revision 1.911 2009/02/21 01:42:11 cheshire +Updated log messages + +Revision 1.910 2009/02/19 01:50:53 cheshire +Converted some LogInfo messages to LogSPS + +Revision 1.909 2009/02/14 00:04:59 cheshire +Left-justify interface names + +Revision 1.908 2009/02/13 19:40:07 cheshire +Improved alignment of LogSPS messages + +Revision 1.907 2009/02/13 18:16:05 cheshire +Fixed some compile warnings + +Revision 1.906 2009/02/13 06:10:17 cheshire +Convert LogOperation messages to LogInfo + +Revision 1.905 2009/02/12 20:57:24 cheshire +Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch + +Revision 1.904 2009/02/11 02:37:29 cheshire +m->p->SystemWakeForNetworkAccessEnabled renamed to m->SystemWakeOnLANEnabled +Moved code to send goodbye packets from mDNSCoreMachineSleep into BeginSleepProcessing, +so that it happens correctly even when we delay re-sleep due to a very short wakeup. + +Revision 1.903 2009/02/09 23:34:31 cheshire +Additional logging for debugging unknown packets + +Revision 1.902 2009/02/07 05:57:01 cheshire +Fixed debugging log message + +Revision 1.901 2009/02/07 02:57:31 cheshire + Sleep Proxy: Need to adopt IOPMConnection + +Revision 1.900 2009/02/02 21:29:24 cheshire + Implement logic to determine when to send dot-local lookups via Unicast +If Negative response for our special Microsoft Active Directory "local SOA" check has no +SOA record in the authority section, assume we should cache the negative result for 24 hours + +Revision 1.899 2009/01/31 00:37:50 cheshire +When marking cache records for deletion in response to a uDNS response, +make sure InterfaceID matches (i.e. it should be NULL for a uDNS cache record) + +Revision 1.898 2009/01/30 23:49:20 cheshire +Exclude mDNSInterface_Unicast from "InterfaceID ... not currently found" test + +Revision 1.897 2009/01/30 22:04:49 cheshire +Workaround to reduce load on root name servers when caching the SOA record for "." + +Revision 1.896 2009/01/30 22:00:05 cheshire +Made mDNS_StartQuery_internal pay attention to mDNSInterface_Unicast + +Revision 1.895 2009/01/30 17:46:39 cheshire +Improved debugging messages for working out why spurious name conflicts are happening + +Revision 1.894 2009/01/30 00:22:09 cheshire + No announcement after probing & no conflict notice + +Revision 1.893 2009/01/29 22:27:03 mcguire + Cleanup: Logs about Unknown DNS packet type 5450 + +Revision 1.892 2009/01/24 01:38:23 cheshire +Fixed error in logic for targeted queries + +Revision 1.891 2009/01/22 02:14:25 cheshire + Sleep Proxy: Set correct target MAC address, instead of all zeroes + +Revision 1.890 2009/01/22 00:45:02 cheshire +Improved SPS debugging log messages; we are eligible to start answering ARP requests +after we send our first announcement, not after we send our last probe + +Revision 1.889 2009/01/21 03:43:56 mcguire + BTMM: Add support for setting kDNSServiceErr_NATPortMappingDisabled in DynamicStore + +Revision 1.888 2009/01/20 00:27:43 mcguire + when removing a uDNS record, if a dup exists, copy information to it + +Revision 1.887 2009/01/17 05:14:37 cheshire +Convert SendQueries Probe messages to LogSPS messages + +Revision 1.886 2009/01/17 03:43:09 cheshire +Added SPSLogging switch to facilitate Sleep Proxy Server debugging + +Revision 1.885 2009/01/16 22:44:18 cheshire + Sleep Proxy: Begin ARP Announcements sooner + +Revision 1.884 2009/01/16 21:43:52 cheshire +Let InitializeLastAPTime compute the correct interval, instead of having it passed in as a parameter + +Revision 1.883 2009/01/16 21:11:18 cheshire +When purging expired Sleep Proxy records, need to check DuplicateRecords list too + +Revision 1.882 2009/01/16 19:54:28 cheshire +Use symbols "SleepProxyServiceType" and "localdomain" instead of literal strings + +Revision 1.881 2009/01/14 01:38:38 mcguire + Write out DynamicStore per-interface SleepProxyServer info + +Revision 1.880 2009/01/10 01:51:19 cheshire +q->CurrentAnswers not being incremented/decremented when answering a question with a local AuthRecord + +Revision 1.879 2009/01/10 01:43:52 cheshire +Changed misleading function name 'AnsweredLOQ' to more informative 'AnsweredLocalQ' + +Revision 1.878 2009/01/10 01:38:10 cheshire +Changed misleading function name 'AnswerLocalOnlyQuestionWithResourceRecord' to more informative 'AnswerLocalQuestionWithLocalAuthRecord' + +Revision 1.877 2009/01/10 01:36:08 cheshire +Changed misleading function name 'AnswerLocalOnlyQuestions' to more informative 'AnswerAllLocalQuestionsWithLocalAuthRecord' + +Revision 1.876 2009/01/09 22:56:06 cheshire +Don't touch rr after calling mDNS_Deregister_internal -- the memory may have been free'd + +Revision 1.875 2009/01/09 22:54:46 cheshire +When tranferring record from DuplicateRecords list to ResourceRecords list, +need to copy across state of 'Answered Local-Only-Questions' flag + +Revision 1.874 2009/01/07 23:07:24 cheshire + SPS Client not canceling outstanding resolve call before sleeping + +Revision 1.873 2008/12/17 00:18:59 mkrochma +Change some LogMsg to LogOperation before submitting + +Revision 1.872 2008/12/12 01:30:40 cheshire +Update platform-layer BPF filters when we add or remove AddressProxy records + +Revision 1.871 2008/12/10 02:25:31 cheshire +Minor fixes to use of LogClientOperations symbol + +Revision 1.870 2008/12/10 02:11:41 cheshire +ARMv5 compiler doesn't like uncommented stuff after #endif + +Revision 1.869 2008/12/05 02:35:24 mcguire + Write to the DynamicStore when a Sleep Proxy server is available on the network + +Revision 1.868 2008/12/04 21:08:51 mcguire + mDNS: Provide mechanism to disable Multicast advertisements + +Revision 1.867 2008/11/26 21:19:36 cheshire + Sleeping Server should choose the best Sleep Proxy by using advertised metrics + +Revision 1.866 2008/11/26 20:32:46 cheshire + Sleep Proxy: Advertise BSP metrics in service name +Update advertised name when Sleep Proxy "intent" metric changes + +Revision 1.865 2008/11/26 19:49:25 cheshire +Record originally-requested port in sr->NATinfo.IntPort + +Revision 1.864 2008/11/26 19:02:37 cheshire +Don't answer ARP Probes from owner machine as it wakes up and rejoins the network + +Revision 1.863 2008/11/26 03:59:03 cheshire +Wait 30 seconds before starting ARP Announcements + +Revision 1.862 2008/11/25 23:43:07 cheshire + Crashes at ServiceRegistrationGotZoneData + 397 +Made code more defensive to guard against ServiceRegistrationGotZoneData being called with invalid ServiceRecordSet object + +Revision 1.861 2008/11/25 22:46:30 cheshire +For ease of code searching, renamed ZoneData field of ServiceRecordSet_struct from "nta" to "srs_nta" + +Revision 1.860 2008/11/25 05:07:15 cheshire + Advertise Sleep Proxy metrics in service name + +Revision 1.859 2008/11/20 02:07:56 cheshire + Refresh our NAT mappings on wake from sleep + +Revision 1.858 2008/11/20 01:38:36 cheshire +For consistency with other parts of the code, changed code to only check +that the first 4 bytes of MAC address are zero, not the whole 6 bytes. + +Revision 1.857 2008/11/14 22:55:18 cheshire +Fixed log messages + +Revision 1.856 2008/11/14 21:08:28 cheshire +Only put owner option in query packet if we have a non-zero MAC address to put +Only process owner options in received query packets if the MAC address in the option is non-zero + +Revision 1.855 2008/11/14 02:29:54 cheshire +If Sleep Proxy client fails to renew proxy records before they expire, remove them from our m->ResourceRecords list + +Revision 1.854 2008/11/14 00:00:53 cheshire +After client machine wakes up, Sleep Proxy machine need to remove any records +it was temporarily holding as proxy for that client + +Revision 1.853 2008/11/13 19:07:30 cheshire +Added code to put OPT record, containing owner and lease lifetime, into SPS registration packet + +Revision 1.852 2008/11/12 23:23:11 cheshire +Before waking a host, check to see if it has an SRV record advertising +a service on the port in question, and if not, don't bother waking it. + +Revision 1.851 2008/11/12 01:54:15 cheshire + Add domain back to end of _services._dns-sd._udp PTR records +It turns out it is beneficial to have the domain on the end, because it allows better name compression + +Revision 1.850 2008/11/11 01:56:57 cheshire +Improved name conflict log messages + +Revision 1.849 2008/11/06 23:50:43 cheshire +Allow plain (non-SYN) ssh data packets to wake sleeping host + +Revision 1.848 2008/11/05 02:40:28 mkrochma +Change mDNS_SetFQDN syslog mesage to debugf + +Revision 1.847 2008/11/04 23:06:50 cheshire +Split RDataBody union definition into RDataBody and RDataBody2, and removed +SOA from the normal RDataBody union definition, saving 270 bytes per AuthRecord + +Revision 1.846 2008/11/04 22:21:44 cheshire +Changed zone field of AuthRecord_struct from domainname to pointer, saving 252 bytes per AuthRecord + +Revision 1.845 2008/11/03 23:52:05 cheshire +Improved ARP debugging messages to differentiate ARP Announcements from Requests + +Revision 1.844 2008/10/31 23:43:51 cheshire +Fixed compile error in Posix build + +Revision 1.843 2008/10/31 22:55:04 cheshire +Initial support for structured SPS names + +Revision 1.842 2008/10/30 00:12:07 cheshire +Fixed spin when PutSPSRec fails to put a record because it's too big to fit + +Revision 1.841 2008/10/29 23:23:38 cheshire +Refined cache size reporting to go in steps of 1000 when number is above 1000 + +Revision 1.840 2008/10/29 21:34:10 cheshire +Removed some old debugging messages + +Revision 1.839 2008/10/29 21:31:32 cheshire +Five seconds not always enough time for machine to go to sleep -- increased to ten seconds + +Revision 1.838 2008/10/28 18:30:37 cheshire +Added debugging message in mDNSCoreReceiveRawPacket + +Revision 1.837 2008/10/24 23:58:05 cheshire +Wake up for Back to My Mac IPSEC packets, except NAT keepalive packets + +Revision 1.836 2008/10/24 23:18:18 cheshire +If we have a Sleep Proxy Server, don't remove service registrations from the DNS server + +Revision 1.835 2008/10/24 23:07:59 cheshire +Wake SPS client if we receive conflicting mDNS respoonse (record with same name as one of our unique records, but different rdata) + +Revision 1.834 2008/10/24 23:03:24 cheshire +Wake SPS client if we receive a conflicting ARP (some other machine claiming to own that IP address) + +Revision 1.833 2008/10/24 23:01:26 cheshire +To reduce spurious wakeups for now, we'll only wake for incoming TCP SYN packets + +Revision 1.832 2008/10/24 22:58:24 cheshire +For now, since we don't get IPv6 ND or data packets, don't advertise AAAA records for our SPS clients + +Revision 1.831 2008/10/24 22:50:41 cheshire +When waking SPS client, include interface name in syslog message + +Revision 1.830 2008/10/24 20:50:34 cheshire +Use "#if USE_SEPARATE_UDNS_SERVICE_LIST" instead of "#if defined(USE_SEPARATE_UDNS_SERVICE_LIST)" + +Revision 1.829 2008/10/23 23:55:57 cheshire +Fixed some missing "const" declarations + +Revision 1.828 2008/10/23 22:25:56 cheshire +Renamed field "id" to more descriptive "updateid" + +Revision 1.827 2008/10/23 03:06:25 cheshire +Fixed "Waking host" log message + +Revision 1.826 2008/10/22 23:21:30 cheshire +Make sure we have enough bytes before reading into the transport-level header + +Revision 1.825 2008/10/22 22:31:53 cheshire +Log SYN/FIN/RST bits from TCP header, and don't wake for FIN/RST + +Revision 1.824 2008/10/22 20:00:31 cheshire +If we ourselves go to sleep, stop advertising sleep proxy service, then re-advertise after we wake up + +Revision 1.823 2008/10/22 19:55:35 cheshire +Miscellaneous fixes; renamed FindFirstAnswerInCache to FindSPSInCache + +Revision 1.822 2008/10/22 01:41:39 cheshire +Set question->ThisQInterval back to -1 after we cancel our NetWakeResolve + +Revision 1.821 2008/10/22 01:12:53 cheshire +Answer ARP Requests for any IP address we're proxying for + +Revision 1.820 2008/10/21 01:11:11 cheshire +Added mDNSCoreReceiveRawPacket for handling raw packets received by platform layer + +Revision 1.819 2008/10/20 22:16:27 cheshire +Updated comments; increased cache shedding threshold from 3000 to 4000 + +Revision 1.818 2008/10/16 22:01:54 cheshire +Fix last checkin: Should be "ar->resrec.rdata->u.data", not "ar->resrec.rdata.u.data" + +Revision 1.817 2008/10/16 21:40:49 cheshire +Need to set ar->resrec.rdlength correctly before calling mDNS_Register_internal() + +Revision 1.816 2008/10/15 23:12:36 cheshire +On receiving SPS registration from client, broadcast ARP Announcements claiming ownership of that IP address + +Revision 1.815 2008/10/15 20:46:38 cheshire +When transferring records to SPS, include Lease Option + +Revision 1.814 2008/10/15 19:51:27 cheshire +Change "NOTE:" to "Note:" so that BBEdit 9 stops putting those lines into the funtion popup menu + +Revision 1.813 2008/10/15 00:09:23 cheshire +When acting as Sleep Proxy Server, handle DNS Updates received from SPS clients on the network + +Revision 1.812 2008/10/15 00:01:40 cheshire +When going to sleep, discover and resolve SPS, and if successful, transfer records to it + +Revision 1.811 2008/10/14 23:51:57 cheshire +Created new routine GetRDLengthMem() to compute the in-memory storage requirements for particular rdata + +Revision 1.810 2008/10/14 21:37:55 cheshire +Removed unnecessary m->BeSleepProxyServer variable + +Revision 1.809 2008/10/10 23:45:48 cheshire +For ForceMCast records, SetTargetToHostName should use the dot-local multicast hostname, +not a wide-area unicast hostname + +Revision 1.808 2008/10/09 18:59:19 cheshire +Added NetWakeResolve code, removed unused m->SendDeregistrations and m->SendImmediateAnswers + +Revision 1.807 2008/10/07 15:56:58 cheshire +Fixed "unused variable" warnings in non-debug builds + +Revision 1.806 2008/10/04 00:53:37 cheshire +On interfaces that support Wake-On-LAN, browse to discover Sleep Proxy Servers + +Revision 1.805 2008/10/03 18:17:28 cheshire + Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service +Update advertised Sleep Proxy Server name if user changes computer name + +Revision 1.804 2008/10/03 01:26:06 mcguire + mDNS_FinalExit failed to send goodbye for duplicate uDNS records +Put back Duplicate Record check + +Revision 1.803 2008/10/02 23:38:56 mcguire + mDNS_FinalExit failed to send goodbye for duplicate uDNS records + +Revision 1.802 2008/10/02 23:13:48 cheshire + Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service +Need to drop lock before calling "mDNSCoreBeSleepProxyServer(m, mDNSfalse);" + +Revision 1.801 2008/10/02 22:51:04 cheshire + Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service +Added mDNSCoreBeSleepProxyServer() routine to start and stop Sleep Proxy Service + +Revision 1.800 2008/10/02 22:13:15 cheshire + 100ms delay on shutdown +Additional refinement: Also need to clear m->SuppressSending + +Revision 1.799 2008/09/29 20:12:37 cheshire +Rename 'AnswerLocalQuestions' to more descriptive 'AnswerLocalOnlyQuestions' and 'AnsweredLocalQ' to 'AnsweredLOQ' + +Revision 1.798 2008/09/26 19:53:14 cheshire +Fixed locking error: should not call mDNS_Deregister_internal within "mDNS_DropLock" section + +Revision 1.797 2008/09/25 20:40:59 cheshire + Stop using separate m->ServiceRegistrations list +In mDNS_SetFQDN, need to update all AutoTarget SRV records, even if m->MulticastHostname hasn't changed + +Revision 1.796 2008/09/25 20:17:10 cheshire + Stop using separate m->ServiceRegistrations list +Added defensive code to make sure *all* records of a ServiceRecordSet have +completed deregistering before we pass on the mStatus_MemFree message + +Revision 1.795 2008/09/25 00:30:11 cheshire + Stop using separate m->ServiceRegistrations list + +Revision 1.794 2008/09/24 23:48:05 cheshire +Don't need to pass whole ServiceRecordSet reference to GetServiceTarget; +it only needs to access the embedded SRV member of the set + +Revision 1.793 2008/09/23 04:11:53 cheshire + Remove "local" from the end of _services._dns-sd._udp PTR records + +Revision 1.792 2008/09/23 02:30:07 cheshire +Get rid of PutResourceRecordCappedTTL() + +Revision 1.791 2008/09/20 00:34:21 mcguire BTMM: Add support for WANPPPConnection -Revision 1.777.4.4 2008/08/14 20:43:59 cheshire - Back to My Mac not working with Time Capsule shared volume +Revision 1.790 2008/09/18 22:46:34 cheshire + 100ms delay on shutdown + +Revision 1.789 2008/09/18 06:15:06 mkrochma + Cleanup: mDNSResponder logging debugging information to console + +Revision 1.788 2008/09/16 21:11:41 cheshire + mDNS: Duplicate TXT record queries being produced by iPhone Remote + +Revision 1.787 2008/09/05 22:53:24 cheshire +Improve "How is rr->resrec.rroriginalttl <= SecsSinceRcvd" debugging message + +Revision 1.786 2008/09/05 22:23:28 cheshire +Moved initialization of "question->LocalSocket" to more logical place + +Revision 1.785 2008/08/14 19:20:55 cheshire + Negative responses over TCP incorrectly rejected -Revision 1.777.4.3 2008/07/29 20:46:05 mcguire - Should use randomized source ports and transaction IDs to avoid DNS cache poisoning -merge r1.782 & r1.783 from +Revision 1.784 2008/08/13 00:47:53 mcguire +Handle failures when packet logging -Revision 1.777.4.2 2008/07/29 20:13:52 mcguire - BTMM: alternate SSDP queries between multicast & unicast -merged r1.781 for +Revision 1.783 2008/07/25 07:09:51 mcguire + Should use randomized source ports and transaction IDs to avoid DNS cache poisoning -Revision 1.777.4.1 2008/07/29 19:17:55 mcguire - Only trigger reconfirm on hostname if both A and AAAA query fail to elicit a response -merge r1.779, r.1780 from +Revision 1.782 2008/07/24 20:23:03 cheshire + Should use randomized source ports and transaction IDs to avoid DNS cache poisoning + +Revision 1.781 2008/07/18 21:37:35 mcguire + BTMM: alternate SSDP queries between multicast & unicast + +Revision 1.780 2008/07/18 02:24:36 cheshire + Only trigger reconfirm on hostname if both A and AAAA query fail to elicit a response +Additional fix: Don't want to do the ReconfirmAntecedents() stuff if q->RequestUnicast is set (that indicates +we're still on our first or second query after an interface registration or wake from sleep). + +Revision 1.779 2008/07/18 01:05:23 cheshire + Only trigger reconfirm on hostname if both A and AAAA query fail to elicit a response + +Revision 1.778 2008/06/26 17:24:11 mkrochma + BTMM: Stop listening on UDP 5351 for NAT Status Announcements Revision 1.777 2008/06/19 01:20:48 mcguire Use all configured DNS servers @@ -352,7 +961,7 @@ Revision 1.691 2007/09/05 22:25:01 vazquez 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 +Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance code 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. @@ -635,7 +1244,7 @@ Revision 1.609 2007/04/20 21:17:24 cheshire For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative Revision 1.608 2007/04/20 19:45:31 cheshire -In LogAllOperations mode, dump out unknown DNS packets in their entirety +In LogClientOperations mode, dump out unknown DNS packets in their entirety Revision 1.607 2007/04/19 23:56:25 cheshire Don't do cache-flush processing for LLQ answers @@ -898,6 +1507,10 @@ Fixes to avoid code generation warning/error on FreeBSD 7 #pragma warning(disable:4706) #endif +// Forward declarations +mDNSlocal void BeginSleepProcessing(mDNS *const m); +mDNSlocal void RetrySPSRegistrations(mDNS *const m); + // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - Program Constants @@ -1000,26 +1613,43 @@ mDNSlocal mDNSBool AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID Int return(mDNSfalse); } +mDNSlocal NetworkInterfaceInfo *FirstInterfaceForID(mDNS *const m, const mDNSInterfaceID InterfaceID) + { + NetworkInterfaceInfo *intf = m->HostInterfaces; + while (intf && intf->InterfaceID != InterfaceID) intf = intf->next; + return(intf); + } + +mDNSlocal char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID) + { + NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID); + return(intf ? intf->ifname : ""); + } + // 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, QC_result AddRecord) +// Used by AnswerAllLocalQuestionsWithLocalAuthRecord() and AnswerNewLocalOnlyQuestion() +mDNSlocal void AnswerLocalQuestionWithLocalAuthRecord(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->AnsweredLocalQ = mDNStrue; mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback if (q->QuestionCallback && !q->NoAnswer) + { + q->CurrentAnswers += AddRecord ? 1 : -1; q->QuestionCallback(m, q, &rr->resrec, AddRecord); + } 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, AnswerAllLocalQuestionsWithLocalAuthRecord() runs though +// all our local questions (both LocalOnlyQuestions and mDNSInterface_Any questions) 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, QC_result AddRecord) +mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord) { if (m->CurrentQuestion) - LogMsg("AnswerLocalQuestions ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); + LogMsg("AnswerAllLocalQuestionsWithLocalAuthRecord 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) @@ -1027,7 +1657,7 @@ mDNSlocal void AnswerLocalQuestions(mDNS *const m, AuthRecord *rr, QC_result Add DNSQuestion *q = m->CurrentQuestion; m->CurrentQuestion = q->next; if (ResourceRecordAnswersQuestion(&rr->resrec, q)) - AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, AddRecord); // MUST NOT dereference q again + AnswerLocalQuestionWithLocalAuthRecord(m, q, rr, AddRecord); // MUST NOT dereference q again } // If this AuthRecord is marked LocalOnly, then we want to deliver it to all local 'mDNSInterface_Any' questions @@ -1039,7 +1669,7 @@ mDNSlocal void AnswerLocalQuestions(mDNS *const m, AuthRecord *rr, QC_result Add DNSQuestion *q = m->CurrentQuestion; m->CurrentQuestion = q->next; if (ResourceRecordAnswersQuestion(&rr->resrec, q)) - AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, AddRecord); // MUST NOT dereference q again + AnswerLocalQuestionWithLocalAuthRecord(m, q, rr, AddRecord); // MUST NOT dereference q again } } @@ -1094,7 +1724,11 @@ mDNSlocal void AnswerLocalQuestions(mDNS *const m, AuthRecord *rr, QC_result Add // 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 AuthRecord *const r1, const AuthRecord *const r2) +// SameResourceRecordNameClassInterface is functionally the same as SameResourceRecordSignature, except rrtype does not have to match + +#define SameResourceRecordSignature(A,B) (A)->resrec.rrtype == (B)->resrec.rrtype && SameResourceRecordNameClassInterface((A),(B)) + +mDNSlocal mDNSBool SameResourceRecordNameClassInterface(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); } @@ -1102,7 +1736,6 @@ mDNSlocal mDNSBool SameResourceRecordSignature(const AuthRecord *const r1, const 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)); @@ -1113,6 +1746,9 @@ mDNSlocal mDNSBool SameResourceRecordSignature(const AuthRecord *const r1, const // complete ownership of *all* types for this name, so *any* record type with the same name is a conflict. // In addition, when probing we send our questions with the wildcard type kDNSQType_ANY, // so a response of any type should match, even if it is not actually the type the client plans to use. + +// For now, to make it easier to avoid false conflicts, we treat SPS Proxy records like shared records, +// and require the rrtypes to match for the rdata to be considered potentially conflicting mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, const AuthRecord *const authrr) { if (!pktrr) { LogMsg("PacketRRMatchesSignature ERROR: pktrr is NULL"); return(mDNSfalse); } @@ -1120,7 +1756,8 @@ mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, cons if (pktrr->resrec.InterfaceID && authrr->resrec.InterfaceID && pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse); - if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) && pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse); + if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) || authrr->WakeUp.HMAC.l[0]) + if (pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse); return(mDNSBool)( pktrr->resrec.rrclass == authrr->resrec.rrclass && pktrr->resrec.namehash == authrr->resrec.namehash && @@ -1155,8 +1792,7 @@ 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); } @@ -1167,9 +1803,10 @@ mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const r } } -mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr, mDNSs32 interval) +mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr) { - rr->ThisAPInterval = interval; + // For reverse-mapping Sleep Proxy PTR records, probe interval is one second + rr->ThisAPInterval = rr->AddressProxy.type ? mDNSPlatformOneSecond : DefaultAPIntervalForRecordType(rr->resrec.RecordType); // To allow us to aggregate probes when a group of services are registered together, // the first probe is delayed 1/4 second. This means the common-case behaviour is: @@ -1193,7 +1830,7 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr, mDNSs32 } } - rr->LastAPTime = m->SuppressProbes - interval; + 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) rr->LastMCTime = m->timenow; @@ -1206,12 +1843,25 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr, mDNSs32 // delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete. // When the probing is complete and those records begin to announce, these records will also be picked up and accelerated, // because they will meet the criterion of being at least half-way to their scheduled announcement time. + if (rr->resrec.RecordType != kDNSRecordTypeUnique) + rr->LastAPTime += DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2; + // The exception is unique records that have already been verified and are just being updated // via mDNS_Update() -- for these we want to announce the new value immediately, without delay. if (rr->resrec.RecordType == kDNSRecordTypeVerified) - rr->LastAPTime = m->timenow - interval; - else if (rr->resrec.RecordType != kDNSRecordTypeUnique) - rr->LastAPTime += DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + interval / 2; + rr->LastAPTime = m->timenow - rr->ThisAPInterval; + + // For reverse-mapping Sleep Proxy PTR records we don't want to start probing instantly -- we + // wait one second to give the client a chance to go to sleep, and then start our ARP/NDP probing. + // After three probes one second apart with no answer, we conclude the client is now sleeping + // and we can begin broadcasting our announcements to take over ownership of that IP address. + // If we don't wait for the client to go to sleep, then when the client sees our ARP Announcements there's a risk + // (depending on the OS and networking stack it's using) that it might interpret it as a conflict and change its IP address. + if (rr->AddressProxy.type) rr->LastAPTime = m->timenow; + + // For now, since we don't yet handle IPv6 ND or data packets, we send deletions for our SPS clients' AAAA records + if (rr->WakeUp.HMAC.l[0] && rr->resrec.rrtype == kDNSType_AAAA) + rr->LastAPTime = m->timenow - rr->ThisAPInterval + mDNSPlatformOneSecond * 10; SetNextAnnounceProbeTime(m, rr); } @@ -1220,16 +1870,23 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr, mDNSs32 // Eventually we should unify this with GetServiceTarget() in uDNS.c mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr) { - domainname *target = GetRRDomainNameTarget(&rr->resrec); + domainname *const target = GetRRDomainNameTarget(&rr->resrec); + const domainname *newname = &m->MulticastHostname; if (!target) debugf("SetTargetToHostName: Don't know how to set the target of rrtype %d", rr->resrec.rrtype); - if (target && SameDomainName(target, &m->MulticastHostname)) + if (!(rr->ForceMCast || rr->resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&rr->namestorage))) + { + const domainname *const n = GetServiceTarget(m, rr); + if (n) newname = n; + } + + if (target && SameDomainName(target, newname)) debugf("SetTargetToHostName: Target of %##s is already %##s", rr->resrec.name->c, target->c); - if (target && !SameDomainName(target, &m->MulticastHostname)) + if (target && !SameDomainName(target, newname)) { - AssignDomainName(target, &m->MulticastHostname); + AssignDomainName(target, newname); SetNewRData(&rr->resrec, mDNSNULL, 0); // Update rdlength, rdestimate, rdatahash // If we're in the middle of probing this record, we need to start again, @@ -1246,7 +1903,7 @@ mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr) rr->AnnounceCount = InitialAnnounceCount; rr->RequireGoodbye = mDNSfalse; - InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType)); + InitializeLastAPTime(m, rr); } } @@ -1293,6 +1950,22 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) if (!rr->resrec.RecordType) { LogMsg("mDNS_Register_internal: RecordType must be non-zero %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); } + if (m->ShutdownTime) + { LogMsg("mDNS_Register_internal: Shutting down, can't register %s", ARDisplayString(m, rr)); return(mStatus_ServiceNotRunning); } + + if (m->DivertMulticastAdvertisements && !AuthRecord_uDNS(rr)) + { + mDNSInterfaceID previousID = rr->resrec.InterfaceID; + if (rr->resrec.InterfaceID == mDNSInterface_Any) rr->resrec.InterfaceID = mDNSInterface_LocalOnly; + if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly) + { + NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID); + if (intf && !intf->Advertise) rr->resrec.InterfaceID = mDNSInterface_LocalOnly; + } + if (rr->resrec.InterfaceID != previousID) + LogInfo("mDNS_Register_internal: Diverting record to local-only %s", ARDisplayString(m, rr)); + } + while (*p && *p != rr) p=&(*p)->next; while (*d && *d != rr) d=&(*d)->next; if (*d || *p) @@ -1323,9 +1996,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) // If this resource record is referencing a specific interface, make sure it exists if (rr->resrec.InterfaceID && rr->resrec.InterfaceID != mDNSInterface_LocalOnly) { - NetworkInterfaceInfo *intf; - for (intf = m->HostInterfaces; intf; intf = intf->next) - if (intf->InterfaceID == rr->resrec.InterfaceID) break; + NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID); if (!intf) { debugf("mDNS_Register_internal: Bogus InterfaceID %p in resource record", rr->resrec.InterfaceID); @@ -1358,8 +2029,9 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) rr->RequireGoodbye = mDNSfalse; rr->AnsweredLocalQ = mDNSfalse; rr->IncludeInProbe = mDNSfalse; - rr->ImmedAnswer = mDNSNULL; rr->ImmedUnicast = mDNSfalse; + rr->SendNSECNow = mDNSNULL; + rr->ImmedAnswer = mDNSNULL; rr->ImmedAdditional = mDNSNULL; rr->SendRNow = mDNSNULL; rr->v4Requester = zerov4Addr; @@ -1367,7 +2039,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) rr->NextResponse = mDNSNULL; rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; - if (!rr->AutoTarget) InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType)); + 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() @@ -1378,13 +2050,16 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) rr->NextUpdateCredit = 0; rr->UpdateBlocked = 0; + // For records we're holding as proxy (except reverse-mapping PTR records) two announcements is sufficient + if (rr->WakeUp.HMAC.l[0] && !rr->AddressProxy.type) rr->AnnounceCount = 2; + // 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->updateid = zeroID; + rr->zone = rr->resrec.name; rr->UpdateServer = zeroAddr; rr->UpdatePort = zeroIPPort; rr->nta = mDNSNULL; @@ -1397,7 +2072,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr) rr->QueuedRDLen = 0; // rr->resrec.interface = already set in mDNS_SetupResourceRecord -// rr->resrec.name->c = MUST be set by client +// rr->resrec.name->c = MUST be set by client // rr->resrec.rrtype = already set in mDNS_SetupResourceRecord // rr->resrec.rrclass = already set in mDNS_SetupResourceRecord // rr->resrec.rroriginalttl = already set in mDNS_SetupResourceRecord @@ -1435,7 +2110,7 @@ mDNSexport 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, rr) && !SameRData(&r->resrec, &rr->resrec)) + if (s1 != s2 && SameResourceRecordSignature(r, rr) && !IdenticalSameNameRecord(&r->resrec, &rr->resrec)) break; } if (r) // If we found a conflict, set RecordType = kDNSRecordTypeDeregistering so we'll deliver the callback @@ -1515,7 +2190,7 @@ mDNSlocal void CompleteRDataUpdate(mDNS *const m, AuthRecord *const rr) rr->UpdateCallback(m, rr, OldRData); // ... and let the client know } -// NOTE: mDNS_Deregister_internal can call a user callback, which may change the record list and/or question list. +// 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. // Exported so uDNS.c can call this mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt) @@ -1553,6 +2228,7 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, dup->ProbeCount = rr->ProbeCount; dup->AnnounceCount = rr->AnnounceCount; dup->RequireGoodbye = rr->RequireGoodbye; + dup->AnsweredLocalQ = rr->AnsweredLocalQ; dup->ImmedAnswer = rr->ImmedAnswer; dup->ImmedUnicast = rr->ImmedUnicast; dup->ImmedAdditional = rr->ImmedAdditional; @@ -1562,7 +2238,12 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, dup->LastAPTime = rr->LastAPTime; dup->LastMCTime = rr->LastMCTime; dup->LastMCInterface = rr->LastMCInterface; + dup->UpdateServer = rr->UpdateServer; + dup->UpdatePort = rr->UpdatePort; + dup->Private = rr->Private; + dup->state = rr->state; rr->RequireGoodbye = mDNSfalse; + rr->AnsweredLocalQ = mDNSfalse; } } } @@ -1581,17 +2262,16 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, { // 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 not found in list %s", rr, ARDisplayString(m,rr)); 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 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" + // If this is a record (including mDNSInterface_LocalOnly records) for which we've given local-only answers then + // it's tempting to just do "AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse)" here, but that would not not be safe. + // The AnswerAllLocalQuestionsWithLocalAuthRecord 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. @@ -1612,7 +2292,7 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, // process and will complete asynchronously. Either way we don't need to do anything more here. return(mStatus_NoError); } -#endif UNICAST_DISABLED +#endif // UNICAST_DISABLED if (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->AnsweredLocalQ)) { @@ -1655,17 +2335,20 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, // 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. - mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback if (drt != mDNS_Dereg_conflict) { + mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_MemFree); // MUST NOT touch rr after this + mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again } else { RecordProbeFailure(m, rr); + mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_NameConflict); // MUST NOT touch rr after this + mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again // 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. @@ -1676,7 +2359,6 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, else { mDNS_Deregister_internal(m, r2, mDNS_Dereg_conflict); r2 = m->DuplicateRecords; } } } - mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again } return(mStatus_NoError); } @@ -1824,11 +2506,11 @@ mDNSexport void CompleteDeregistration(mDNS *const m, AuthRecord *rr) // it should go ahead and immediately dispose of this registration rr->resrec.RecordType = kDNSRecordTypeShared; rr->RequireGoodbye = mDNSfalse; - if (rr->AnsweredLocalQ) { AnswerLocalQuestions(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; } + if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; } mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); // Don't touch rr after this } -// NOTE: DiscardDeregistrations calls mDNS_Deregister_internal which can call a user callback, which may change +// Note: DiscardDeregistrations 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. mDNSlocal void DiscardDeregistrations(mDNS *const m) @@ -1847,39 +2529,163 @@ mDNSlocal void DiscardDeregistrations(mDNS *const m) } } -mDNSlocal void GrantUpdateCredit(AuthRecord *rr) +mDNSlocal mStatus GetLabelDecimalValue(const mDNSu8 *const src, mDNSu8 *dst) { - if (++rr->UpdateCredits >= kMaxUpdateCredits) rr->NextUpdateCredit = 0; - else rr->NextUpdateCredit = NonZeroTime(rr->NextUpdateCredit + kUpdateCreditRefreshInterval); + int i, val = 0; + if (src[0] < 1 || src[0] > 3) return(mStatus_Invalid); + for (i=1; i<=src[0]; i++) + { + if (src[i] < '0' || src[i] > '9') return(mStatus_Invalid); + val = val * 10 + src[i] - '0'; + } + if (val > 255) return(mStatus_Invalid); + *dst = val; + return(mStatus_NoError); } -// Note about acceleration of announcements to facilitate automatic coalescing of -// multiple independent threads of announcements into a single synchronized thread: -// The announcements in the packet may be at different stages of maturity; -// One-second interval, two-second interval, four-second interval, and so on. -// After we've put in all the announcements that are due, we then consider -// whether there are other nearly-due announcements that are worth accelerating. -// To be eligible for acceleration, a record MUST NOT be older (further along -// its timeline) than the most mature record we've already put in the packet. -// In other words, younger records can have their timelines accelerated to catch up -// with their elder bretheren; this narrows the age gap and helps them eventually get in sync. -// Older records cannot have their timelines accelerated; this would just widen -// the gap between them and their younger bretheren and get them even more out of sync. +mDNSlocal mStatus GetIPv4FromName(mDNSAddr *const a, const domainname *const name) + { + int skip = CountLabels(name) - 6; + if (skip < 0) { LogMsg("GetIPFromName: Need six labels in IPv4 reverse mapping name %##s", name); return mStatus_Invalid; } + if (GetLabelDecimalValue(SkipLeadingLabels(name, skip+3)->c, &a->ip.v4.b[0]) || + GetLabelDecimalValue(SkipLeadingLabels(name, skip+2)->c, &a->ip.v4.b[1]) || + GetLabelDecimalValue(SkipLeadingLabels(name, skip+1)->c, &a->ip.v4.b[2]) || + GetLabelDecimalValue(SkipLeadingLabels(name, skip+0)->c, &a->ip.v4.b[3])) return mStatus_Invalid; + a->type = mDNSAddrType_IPv4; + return(mStatus_NoError); + } -// NOTE: SendResponses 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. -mDNSlocal void SendResponses(mDNS *const m) +#define HexVal(X) ( ((X) >= '0' && (X) <= '9') ? ((X) - '0' ) : \ + ((X) >= 'A' && (X) <= 'F') ? ((X) - 'A' + 10) : \ + ((X) >= 'a' && (X) <= 'f') ? ((X) - 'a' + 10) : -1) + +mDNSlocal mStatus GetIPv6FromName(mDNSAddr *const a, const domainname *const name) { - int pktcount = 0; - AuthRecord *rr, *r2; - mDNSs32 maxExistingAnnounceInterval = 0; - const NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces); + int i, h, l; + const domainname *n; - m->NextScheduledResponse = m->timenow + 0x78000000; + int skip = CountLabels(name) - 34; + if (skip < 0) { LogMsg("GetIPFromName: Need 34 labels in IPv6 reverse mapping name %##s", name); return mStatus_Invalid; } - for (rr = m->ResourceRecords; rr; rr=rr->next) - if (rr->ImmedUnicast) + n = SkipLeadingLabels(name, skip); + for (i=0; i<16; i++) + { + if (n->c[0] != 1) return mStatus_Invalid; + l = HexVal(n->c[1]); + n = (const domainname *)(n->c + 2); + + if (n->c[0] != 1) return mStatus_Invalid; + h = HexVal(n->c[1]); + n = (const domainname *)(n->c + 2); + + if (l<0 || h<0) return mStatus_Invalid; + a->ip.v6.b[15-i] = (h << 4) | l; + } + + a->type = mDNSAddrType_IPv6; + return(mStatus_NoError); + } + +mDNSlocal mDNSs32 ReverseMapDomainType(const domainname *const name) + { + int skip = CountLabels(name) - 2; + if (skip >= 0) + { + const domainname *suffix = SkipLeadingLabels(name, skip); + if (SameDomainName(suffix, (const domainname*)"\x7" "in-addr" "\x4" "arpa")) return mDNSAddrType_IPv4; + if (SameDomainName(suffix, (const domainname*)"\x3" "ip6" "\x4" "arpa")) return mDNSAddrType_IPv6; + } + return(mDNSAddrType_None); + } + +mDNSlocal void SendARP(mDNS *const m, const mDNSu8 op, const AuthRecord *const rr, + const mDNSu8 *const spa, const mDNSu8 *const tha, const mDNSu8 *const tpa, const mDNSu8 *const dst) + { + int i; + mDNSu8 *ptr = m->omsg.data; + NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID); + if (!intf) { LogMsg("SendARP: No interface with InterfaceID %p found %s", rr->resrec.InterfaceID, ARDisplayString(m,rr)); return; } + + // 0x00 Destination address + for (i=0; i<6; i++) *ptr++ = dst[i]; + + // 0x06 Source address (we just use zero -- driver/hardware will fill in real interface address) + for (i=0; i<6; i++) *ptr++ = 0x0; + + // 0x0C ARP Ethertype (0x0806) + *ptr++ = 0x08; *ptr++ = 0x06; + + // 0x0E ARP header + *ptr++ = 0x00; *ptr++ = 0x01; // Hardware address space; Ethernet = 1 + *ptr++ = 0x08; *ptr++ = 0x00; // Protocol address space; IP = 0x0800 + *ptr++ = 6; // Hardware address length + *ptr++ = 4; // Protocol address length + *ptr++ = 0x00; *ptr++ = op; // opcode; Request = 1, Response = 2 + + // 0x16 Sender hardware address (our MAC address) + for (i=0; i<6; i++) *ptr++ = intf->MAC.b[i]; + + // 0x1C Sender protocol address + for (i=0; i<4; i++) *ptr++ = spa[i]; + + // 0x20 Target hardware address + for (i=0; i<6; i++) *ptr++ = tha[i]; + + // 0x26 Target protocol address + for (i=0; i<4; i++) *ptr++ = tpa[i]; + + // 0x2A Total ARP Packet length 42 bytes + mDNSPlatformSendRawPacket(m->omsg.data, ptr, rr->resrec.InterfaceID); + } + +mDNSlocal void SetupOwnerOpt(const mDNS *const m, const NetworkInterfaceInfo *const intf, rdataOPT *const owner) + { + owner->u.owner.vers = 0; + owner->u.owner.seq = m->SleepSeqNum; + owner->u.owner.HMAC = m->PrimaryMAC; + owner->u.owner.IMAC = intf->MAC; + owner->u.owner.password = zeroEthAddr; + + // Don't try to compute the optlen until *after* we've set up the data fields + owner->opt = kDNSOpt_Owner; + owner->optlen = DNSOpt_Owner_Space(owner) - 4; + } + +mDNSlocal void GrantUpdateCredit(AuthRecord *rr) + { + if (++rr->UpdateCredits >= kMaxUpdateCredits) rr->NextUpdateCredit = 0; + else rr->NextUpdateCredit = NonZeroTime(rr->NextUpdateCredit + kUpdateCreditRefreshInterval); + } + +// Note about acceleration of announcements to facilitate automatic coalescing of +// multiple independent threads of announcements into a single synchronized thread: +// The announcements in the packet may be at different stages of maturity; +// One-second interval, two-second interval, four-second interval, and so on. +// After we've put in all the announcements that are due, we then consider +// whether there are other nearly-due announcements that are worth accelerating. +// To be eligible for acceleration, a record MUST NOT be older (further along +// its timeline) than the most mature record we've already put in the packet. +// In other words, younger records can have their timelines accelerated to catch up +// with their elder bretheren; this narrows the age gap and helps them eventually get in sync. +// Older records cannot have their timelines accelerated; this would just widen +// the gap between them and their younger bretheren and get them even more out of sync. + +// Note: SendResponses 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. +mDNSlocal void SendResponses(mDNS *const m) + { + int pktcount = 0; + AuthRecord *rr, *r2; + mDNSs32 maxExistingAnnounceInterval = 0; + const NetworkInterfaceInfo *intf = GetFirstActiveInterface(m->HostInterfaces); + + m->NextScheduledResponse = m->timenow + 0x78000000; + + if (m->SleepState == SleepState_Transferring) RetrySPSRegistrations(m); + + for (rr = m->ResourceRecords; rr; rr=rr->next) + if (rr->ImmedUnicast) { mDNSAddr v4 = { mDNSAddrType_IPv4, {{{0}}} }; mDNSAddr v6 = { mDNSAddrType_IPv6, {{{0}}} }; @@ -1904,10 +2710,29 @@ mDNSlocal void SendResponses(mDNS *const m) while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr); if (TimeToAnnounceThisRecord(rr, m->timenow) && ResourceRecordIsValidAnswer(rr)) { - rr->ImmedAnswer = mDNSInterfaceMark; // Send on all interfaces - if (maxExistingAnnounceInterval < rr->ThisAPInterval) - maxExistingAnnounceInterval = rr->ThisAPInterval; - if (rr->UpdateBlocked) rr->UpdateBlocked = 0; + if (rr->AddressProxy.type) + { + rr->AnnounceCount--; + rr->ThisAPInterval *= 2; + rr->LastAPTime = m->timenow; + if (rr->AddressProxy.type == mDNSAddrType_IPv4) + { + LogSPS("ARP Announcement %d Capturing traffic for H-MAC %.6a I-MAC %.6a %s", rr->AnnounceCount, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m,rr)); + SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b); + } + else if (rr->AddressProxy.type == mDNSAddrType_IPv6) + { + //LogSPS("NDP Announcement %d %s", rr->AnnounceCount, ARDisplayString(m,rr)); + //SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b); + } + } + else + { + rr->ImmedAnswer = mDNSInterfaceMark; // Send on all interfaces + if (maxExistingAnnounceInterval < rr->ThisAPInterval) + maxExistingAnnounceInterval = rr->ThisAPInterval; + if (rr->UpdateBlocked) rr->UpdateBlocked = 0; + } } } @@ -1917,11 +2742,12 @@ mDNSlocal void SendResponses(mDNS *const m) if ((rr->resrec.InterfaceID && rr->ImmedAnswer) || (rr->ThisAPInterval <= maxExistingAnnounceInterval && TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2) && + !rr->AddressProxy.type && // Don't include ARP Annoucements when considering which records to accelerate ResourceRecordIsValidAnswer(rr))) rr->ImmedAnswer = mDNSInterfaceMark; // Send on all interfaces // When sending SRV records (particularly when announcing a new service) automatically add related Address record(s) as additionals - // NOTE: Currently all address records are interface-specific, so it's safe to set ImmedAdditional to their InterfaceID, + // Note: Currently all address records are interface-specific, so it's safe to set ImmedAdditional to their InterfaceID, // 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) @@ -1961,7 +2787,7 @@ mDNSlocal void SendResponses(mDNS *const m) if (ResourceRecordIsValidAnswer(r2)) if (r2->ImmedAnswer != mDNSInterfaceMark && r2->ImmedAnswer != rr->ImmedAnswer && SameResourceRecordSignature(r2, rr)) - r2->ImmedAnswer = rr->ImmedAnswer; + r2->ImmedAnswer = !r2->ImmedAnswer ? rr->ImmedAnswer : mDNSInterfaceMark; } else if (rr->ImmedAdditional) // If we're sending this as additional, see that its whole RRSet is similarly marked { @@ -2018,18 +2844,15 @@ mDNSlocal void SendResponses(mDNS *const m) // 1. Deregistering records that need to send their goodbye packet // 2. Updated records that need to retract their old data // 3. Answers and announcements we need to send - // In all cases, if we fail, and we've put at least one answer, we break out of the for loop so we can - // send this packet and then try again. - // If we have not put even one answer, then we don't bail out. We pretend we succeeded anyway, - // because otherwise we'll end up in an infinite loop trying to send a record that will never fit. for (rr = m->ResourceRecords; rr; rr=rr->next) + { if (rr->SendRNow == intf->InterfaceID) { + newptr = mDNSNULL; if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) { newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0); 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 { @@ -2040,7 +2863,6 @@ mDNSlocal void SendResponses(mDNS *const m) { newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0); 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); @@ -2053,24 +2875,33 @@ mDNSlocal void SendResponses(mDNS *const m) } else { + mDNSu8 active = (m->SleepState != SleepState_Sleeping || intf->SPSAddr[0].type || intf->SPSAddr[1].type || intf->SPSAddr[2].type); if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) 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); + newptr = PutResourceRecordTTL(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, active ? rr->resrec.rroriginalttl : 0); rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state if (newptr) { responseptr = newptr; - rr->RequireGoodbye = (mDNSu8) (!m->SleepState); + rr->RequireGoodbye = active; if (rr->LastAPTime == m->timenow) numAnnounce++; else numAnswer++; } - else if (m->omsg.h.numAnswers) break; + + // The first time through (pktcount==0), if this record is verified unique + // (i.e. typically A, AAAA, SRV and TXT), set the flag to add an NSEC too. + if (!pktcount && active && rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->SendNSECNow) rr->SendNSECNow = (mDNSInterfaceID)1; + } + + if (newptr) // If succeeded in sending, advance to next interface + { + // If sending on all interfaces, go to next interface; else we're finished now + if (rr->ImmedAnswer == mDNSInterfaceMark && rr->resrec.InterfaceID == mDNSInterface_Any) + rr->SendRNow = GetNextActiveInterfaceID(intf); + else + rr->SendRNow = mDNSNULL; } - // If sending on all interfaces, go to next interface; else we're finished now - if (rr->ImmedAnswer == mDNSInterfaceMark && rr->resrec.InterfaceID == mDNSInterface_Any) - rr->SendRNow = GetNextActiveInterfaceID(intf); - else - rr->SendRNow = mDNSNULL; } + } // Second Pass. Add additional records, if there's space. newptr = responseptr; @@ -2096,6 +2927,10 @@ mDNSlocal void SendResponses(mDNS *const m) rr->ImmedAdditional = mDNSNULL; // then cancel its ImmedAdditional field else if (newptr) // Else, try to add it if we can { + // The first time through (pktcount==0), if this record is verified unique + // (i.e. typically A, AAAA, SRV and TXT), set the flag to add an NSEC too. + if (!pktcount && rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->SendNSECNow) rr->SendNSECNow = (mDNSInterfaceID)1; + if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it newptr = PutResourceRecord(&m->omsg, newptr, &m->omsg.h.numAdditionals, &rr->resrec); @@ -2114,13 +2949,48 @@ mDNSlocal void SendResponses(mDNS *const m) } } } - + + // Third Pass. Add NSEC records, if there's space. + for (rr = m->ResourceRecords; rr; rr=rr->next) + if (rr->SendNSECNow == (mDNSInterfaceID)1 || rr->SendNSECNow == intf->InterfaceID) + { + AuthRecord nsec; + mDNS_SetupResourceRecord(&nsec, mDNSNULL, mDNSInterface_Any, kDNSType_NSEC, rr->resrec.rroriginalttl, kDNSRecordTypeUnique, mDNSNULL, mDNSNULL); + nsec.resrec.rrclass |= kDNSClass_UniqueRRSet; + AssignDomainName(&nsec.namestorage, rr->resrec.name); + mDNSPlatformMemZero(nsec.rdatastorage.u.nsec.bitmap, sizeof(nsec.rdatastorage.u.nsec.bitmap)); + for (r2 = m->ResourceRecords; r2; r2=r2->next) + if (ResourceRecordIsValidAnswer(r2) && SameResourceRecordNameClassInterface(r2, rr)) + { + if (r2->resrec.rrtype >= kDNSQType_ANY) { LogMsg("Can't create NSEC for record %s", ARDisplayString(m, r2)); break; } + else nsec.rdatastorage.u.nsec.bitmap[r2->resrec.rrtype >> 3] |= 128 >> (r2->resrec.rrtype & 7); + } + newptr = responseptr; + if (!r2) // If we successfully built our NSEC record, add it to the packet now + { + newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &nsec.resrec); + if (newptr) responseptr = newptr; + } + + // If we successfully put the NSEC record, clear the SendNSECNow flag + // If we consider this NSEC optional, then we unconditionally clear the SendNSECNow flag, even if we fail to put this additional record + if (newptr || rr->SendNSECNow == (mDNSInterfaceID)1) + { + rr->SendNSECNow = mDNSNULL; + // Run through remainder of list clearing SendNSECNow flag for all other records which would generate the same NSEC + for (r2 = rr->next; r2; r2=r2->next) + if (SameResourceRecordNameClassInterface(r2, rr)) + if (r2->SendNSECNow == (mDNSInterfaceID)1 || r2->SendNSECNow == intf->InterfaceID) + r2->SendNSECNow = mDNSNULL; + } + } + if (m->omsg.h.numAnswers > 0 || m->omsg.h.numAdditionals) { debugf("SendResponses: Sending %d Deregistration%s, %d Announcement%s, %d Answer%s, %d Additional%s on %p", - numDereg, numDereg == 1 ? "" : "s", - numAnnounce, numAnnounce == 1 ? "" : "s", - numAnswer, numAnswer == 1 ? "" : "s", + numDereg, numDereg == 1 ? "" : "s", + 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, mDNSNULL, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL); if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL); @@ -2136,6 +3006,7 @@ mDNSlocal void SendResponses(mDNS *const m) debugf(msg, intf, next); #endif intf = next; + pktcount = 0; // When we move to a new interface, reset packet count back to zero -- NSEC generation logic uses it } } @@ -2244,7 +3115,7 @@ mDNSlocal mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr, // 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); + interval += m->RandomReconfirmDelay % ((interval/3) + 1); rr->TimeRcvd = m->timenow - (mDNSs32)interval * 3; rr->resrec.rroriginalttl = (interval * 4 + mDNSPlatformOneSecond - 1) / mDNSPlatformOneSecond; SetNextCacheCheckTime(m, rr); @@ -2354,7 +3225,7 @@ mDNSlocal void ReconfirmAntecedents(mDNS *const m, const domainname *const name, domainname *crtarget = GetRRDomainNameTarget(&cr->resrec); if (crtarget && cr->resrec.rdatahash == namehash && SameDomainName(crtarget, name)) { - LogOperation("ReconfirmAntecedents: Reconfirming (depth=%d) %s", depth, CRDisplayString(m, cr)); + LogInfo("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); } @@ -2365,14 +3236,39 @@ mDNSlocal void ReconfirmAntecedents(mDNS *const m, const domainname *const name, // we check if we have an address record for the same name. If we do have an IPv4 address for a given // name but not an IPv6 address, that's okay (it just means the device doesn't do IPv6) so the failure // to get a AAAA response is not grounds to doubt the PTR/SRV chain that lead us to that name. -mDNSlocal CacheRecord *CacheHasAddressTypeForName(mDNS *const m, const domainname *const name, const mDNSu32 namehash) +mDNSlocal const CacheRecord *CacheHasAddressTypeForName(mDNS *const m, const domainname *const name, const mDNSu32 namehash) { CacheGroup *const cg = CacheGroupForName(m, HashSlot(name), namehash, name); - CacheRecord *cr = cg ? cg->members : mDNSNULL; + const CacheRecord *cr = cg ? cg->members : mDNSNULL; while (cr && !RRTypeIsAddressType(cr->resrec.rrtype)) cr=cr->next; return(cr); } +mDNSlocal const CacheRecord *FindSPSInCache1(mDNS *const m, const DNSQuestion *const q, const CacheRecord *const c0, const CacheRecord *const c1) + { + CacheGroup *const cg = CacheGroupForName(m, HashSlot(&q->qname), q->qnamehash, &q->qname); + const CacheRecord *cr, *bestcr = mDNSNULL; + mDNSu32 bestmetric = 1000000; + for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next) + if (cr->resrec.rrtype == kDNSType_PTR && cr->resrec.rdlength >= 6) // If record is PTR type, with long enough name, + if (cr != c0 && cr != c1) // that's not one we've seen before, + if (SameNameRecordAnswersQuestion(&cr->resrec, q)) // and answers our browse query, + if (!IdenticalSameNameRecord(&cr->resrec, &m->SPSRecords.RR_PTR.resrec)) // and is not our own advertised service... + { + mDNSu32 metric = SPSMetric(cr->resrec.rdata->u.name.c); + if (bestmetric > metric) { bestmetric = metric; bestcr = cr; } + } + return(bestcr); + } + +// Finds the three best Sleep Proxies we currently have in our cache +mDNSexport void FindSPSInCache(mDNS *const m, const DNSQuestion *const q, const CacheRecord *sps[3]) + { + sps[0] = FindSPSInCache1(m, q, mDNSNULL, mDNSNULL); + sps[1] = !sps[0] ? mDNSNULL : FindSPSInCache1(m, q, sps[0], mDNSNULL); + sps[2] = !sps[1] ? mDNSNULL : FindSPSInCache1(m, q, sps[0], sps[1]); + } + // Only DupSuppressInfos newer than the specified 'time' are allowed to remain active mDNSlocal void ExpireDupSuppressInfo(DupSuppressInfo ds[DupSuppressInfoSize], mDNSs32 time) { @@ -2438,7 +3334,7 @@ mDNSlocal mDNSBool AccelerateThisQuery(mDNS *const m, DNSQuestion *q) mDNSu32 forecast = (mDNSu32)DomainNameLength(&q->qname) + 4; const mDNSu32 slot = HashSlot(&q->qname); const CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname); - CacheRecord *rr; + const CacheRecord *rr; for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // If we have a resource record in our cache, if (rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet SameNameRecordAnswersQuestion(&rr->resrec, q) && // which answers our question @@ -2491,7 +3387,7 @@ 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)); + debugf("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); // For uDNS queries (TargetQID non-zero) we adjust LastQTime, @@ -2520,10 +3416,16 @@ mDNSlocal void SendQueries(mDNS *const m) { 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->LocalSocket, &q->Target, q->TargetPort, mDNSNULL, mDNSNULL); - q->ThisQInterval *= QuestionIntervalStep; + + // If we fail to get a new on-demand socket (should only happen cases of the most extreme resource exhaustion), we'll try again next time + if (!q->LocalSocket) q->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort); + if (q->LocalSocket) + { + 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->LocalSocket, &q->Target, q->TargetPort, mDNSNULL, mDNSNULL); + q->ThisQInterval *= QuestionIntervalStep; + } if (q->ThisQInterval > MaxQuestionInterval) q->ThisQInterval = MaxQuestionInterval; q->LastQTime = m->timenow; @@ -2534,7 +3436,7 @@ mDNSlocal void SendQueries(mDNS *const m) } 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)); + //LogInfo("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; @@ -2563,7 +3465,7 @@ mDNSlocal void SendQueries(mDNS *const m) // 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)); + //LogInfo("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 debugf("SendQueries: %##s (%s) next interval %d seconds RequestUnicast = %d", q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval / InitialQuestionInterval, q->RequestUnicast); @@ -2628,9 +3530,23 @@ mDNSlocal void SendQueries(mDNS *const m) // 2. else, if it has reached its probe time, mark it for sending and then update m->NextScheduledProbe correctly else if (rr->ProbeCount) { + if (rr->AddressProxy.type == mDNSAddrType_IPv4) + { + LogSPS("SendQueries ARP Probe %d %s %s", rr->ProbeCount, InterfaceNameForID(m, rr->resrec.InterfaceID), ARDisplayString(m,rr)); + SendARP(m, 1, rr, zerov4Addr.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, rr->WakeUp.IMAC.b); + } + else if (rr->AddressProxy.type == mDNSAddrType_IPv6) + { + //LogSPS("SendQueries NDP Probe %d %s", rr->ProbeCount, ARDisplayString(m,rr)); + //SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b); + } // Mark for sending. (If no active interfaces, then don't even try.) - rr->SendRNow = !intf ? mDNSNULL : (rr->resrec.InterfaceID) ? rr->resrec.InterfaceID : intf->InterfaceID; + rr->SendRNow = (!intf || rr->WakeUp.HMAC.l[0]) ? mDNSNULL : rr->resrec.InterfaceID ? rr->resrec.InterfaceID : intf->InterfaceID; rr->LastAPTime = m->timenow; + // When we have a late conflict that resets a record to probing state we use a special marker value greater + // than DefaultProbeCountForTypeUnique. Here we detect that state and reset rr->ProbeCount back to the right value. + if (rr->ProbeCount > DefaultProbeCountForTypeUnique) + rr->ProbeCount = DefaultProbeCountForTypeUnique; rr->ProbeCount--; SetNextAnnounceProbeTime(m, rr); if (rr->ProbeCount == 0) @@ -2678,8 +3594,11 @@ mDNSlocal void SendQueries(mDNS *const m) // go through our interface list sending the appropriate queries on each interface while (intf) { + const int os = !intf->MAC.l[0] ? 0 : DNSOpt_Header_Space + mDNSSameEthAddress(&m->PrimaryMAC, &intf->MAC) ? DNSOpt_OwnerData_ID_Space : DNSOpt_OwnerData_ID_Wake_Space; + int OwnerRecordSpace = 0; AuthRecord *rr; mDNSu8 *queryptr = m->omsg.data; + mDNSu8 *limit = m->omsg.data + AbsoluteMaxDNSMessageData; InitializeDNSMessage(&m->omsg.h, zeroID, QueryFlags); if (KnownAnswerList) verbosedebugf("SendQueries: KnownAnswerList set... Will continue from previous packet"); if (!KnownAnswerList) @@ -2696,10 +3615,14 @@ mDNSlocal void SendQueries(mDNS *const m) debugf("SendQueries: %s question for %##s (%s) at %d forecast total %d", SuppressOnThisInterface(q->DupSuppress, intf) ? "Suppressing" : "Putting ", q->qname.c, DNSTypeName(q->qtype), queryptr - m->omsg.data, queryptr + answerforecast - m->omsg.data); + // If we're suppressing this question, or we successfully put it, update its SendQNow state if (SuppressOnThisInterface(q->DupSuppress, intf) || BuildQuestion(m, &m->omsg, &queryptr, q, &kalistptr, &answerforecast)) - q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf); + q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf); + + // Once we've put at least one question, cut back our limit to the normal single-packet size + if (m->omsg.h.numQuestions) limit = m->omsg.data + NormalMaxDNSMessageData; } } @@ -2709,14 +3632,15 @@ mDNSlocal void SendQueries(mDNS *const m) { mDNSBool ucast = (rr->ProbeCount >= DefaultProbeCountForTypeUnique-1) && m->CanReceiveUnicastOn5353; mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0); - const mDNSu8 *const limit = m->omsg.data + ((m->omsg.h.numQuestions) ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData); mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit, rr->resrec.name, kDNSQType_ANY, (mDNSu16)(rr->resrec.rrclass | ucbit)); // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n) mDNSu32 forecast = answerforecast + 12 + rr->resrec.rdestimate; - if (newptr && newptr + forecast < limit) + if (newptr && newptr + forecast + os < limit) { - queryptr = newptr; - answerforecast = forecast; + queryptr = newptr; + limit = m->omsg.data + NormalMaxDNSMessageData; + answerforecast = forecast; + OwnerRecordSpace = os; rr->SendRNow = (rr->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf); rr->IncludeInProbe = mDNStrue; verbosedebugf("SendQueries: Put Question %##s (%s) probecount %d", @@ -2724,24 +3648,26 @@ mDNSlocal void SendQueries(mDNS *const m) } 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--; } } - } + } + + if (m->omsg.h.numQuestions) limit = m->omsg.data + NormalMaxDNSMessageData - OwnerRecordSpace; // Put our known answer list (either new one from this question or questions, or remainder of old one from last time) while (KnownAnswerList) { CacheRecord *ka = KnownAnswerList; mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - ka->TimeRcvd)) / mDNSPlatformOneSecond; - mDNSu8 *newptr = PutResourceRecordTTL(&m->omsg, queryptr, &m->omsg.h.numAnswers, &ka->resrec, ka->resrec.rroriginalttl - SecsSinceRcvd); + mDNSu8 *newptr = PutResourceRecordTTLWithLimit(&m->omsg, queryptr, &m->omsg.h.numAnswers, &ka->resrec, ka->resrec.rroriginalttl - SecsSinceRcvd, limit); if (newptr) { verbosedebugf("SendQueries: Put %##s (%s) at %d - %d", ka->resrec.name->c, DNSTypeName(ka->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data); queryptr = newptr; + limit = m->omsg.data + NormalMaxDNSMessageData - OwnerRecordSpace; KnownAnswerList = ka->NextInKAList; ka->NextInKAList = mDNSNULL; } @@ -2762,10 +3688,25 @@ mDNSlocal void SendQueries(mDNS *const m) mDNSu8 *newptr = PutResourceRecord(&m->omsg, queryptr, &m->omsg.h.numAuthorities, &rr->resrec); rr->IncludeInProbe = mDNSfalse; if (newptr) queryptr = newptr; - else LogMsg("SendQueries: How did we fail to have space for the Update record %##s (%s)?", - rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); + else LogMsg("SendQueries: How did we fail to have space for the Update record %s", ARDisplayString(m,rr)); } - + + if (OwnerRecordSpace) + { + AuthRecord opt; + mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL); + opt.resrec.rrclass = NormalMaxDNSMessageData; + opt.resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record + opt.resrec.rdestimate = sizeof(rdataOPT); + SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[0]); + LogSPS("SendQueries putting %s", ARDisplayString(m, &opt)); + queryptr = PutResourceRecordTTLWithLimit(&m->omsg, queryptr, &m->omsg.h.numAdditionals, + &opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData); + if (!queryptr) + LogMsg("SendQueries: How did we fail to have space for the OPT record (%d/%d/%d/%d) %s", + m->omsg.h.numQuestions, m->omsg.h.numAnswers, m->omsg.h.numAuthorities, m->omsg.h.numAdditionals, ARDisplayString(m, &opt)); + } + if (queryptr > m->omsg.data) { if ((m->omsg.h.flags.b[0] & kDNSFlag0_TC) && m->omsg.h.numQuestions > 1) @@ -2828,13 +3769,50 @@ mDNSlocal void SendQueries(mDNS *const m) } } +mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password) + { + int i, j; + mDNSu8 *ptr = m->omsg.data; + + if (!InterfaceID) { LogMsg("SendWakeup: No InterfaceID specified"); return; } + + // 0x00 Destination address + for (i=0; i<6; i++) *ptr++ = EthAddr->b[i]; + + // 0x06 Source address (we just use zero -- BPF will fill in real interface address) + for (i=0; i<6; i++) *ptr++ = 0x0; + + // 0x0C Ethertype (0x0842) + *ptr++ = 0x08; + *ptr++ = 0x42; + + // 0x0E Wakeup sync sequence + for (i=0; i<6; i++) *ptr++ = 0xFF; + + // 0x14 Wakeup data + for (j=0; j<16; j++) for (i=0; i<6; i++) *ptr++ = EthAddr->b[i]; + + // 0x74 Password + for (i=0; i<6; i++) *ptr++ = password->b[i]; + + mDNSPlatformSendRawPacket(m->omsg.data, ptr, InterfaceID); + + // For Ethernet switches that don't flood-foward packets with unknown unicast destination MAC addresses, + // broadcast is the only reliable way to get a wakeup packet to the intended target machine. + // For 802.11 WPA networks, where a sleeping target machine may have missed a broadcast/multicast + // key rotation, unicast is the only way to get a wakeup packet to the intended target machine. + // So, we send one of each, unicast first, then broadcast second. + for (i=0; i<6; i++) m->omsg.data[i] = 0xFF; + mDNSPlatformSendRawPacket(m->omsg.data, ptr, InterfaceID); + } + // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - #pragma mark - RR List Management & Task Management #endif -// NOTE: AnswerCurrentQuestionWithResourceRecord can call a user callback, which may change the record list and/or question list. +// 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. @@ -2880,26 +3858,34 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco if (rr->DelayDelivery) return; // We'll come back later when CacheRecordDeferredAdd() calls us // Only deliver negative answers if client has explicitly requested them - if (rr->resrec.RecordType == kDNSRecordTypePacketNegative && (!AddRecord || !q->ReturnIntermed)) return; + if (rr->resrec.RecordType == kDNSRecordTypePacketNegative || (q->qtype != kDNSType_NSEC && RRAssertsNonexistence(&rr->resrec, q->qtype))) + if (!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); + if (q->qtype != kDNSType_NSEC && RRAssertsNonexistence(&rr->resrec, q->qtype)) + { + CacheRecord neg; + MakeNegativeCacheRecord(m, &neg, &q->qname, q->qnamehash, q->qtype, q->qclass, 1, rr->resrec.InterfaceID); + q->QuestionCallback(m, q, &neg.resrec, AddRecord); + } + else + q->QuestionCallback(m, q, &rr->resrec, AddRecord); 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, + // 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, + // and track CNAMEs coming and going, we should really create a subordinate 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)); + LogInfo("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 @@ -2931,7 +3917,7 @@ mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *c const mDNSs32 start = m->timenow - 0x10000000; mDNSs32 delay = start; CacheGroup *cg = CacheGroupForName(m, slot, namehash, name); - CacheRecord *rr; + const CacheRecord *rr; for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) 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 @@ -2945,7 +3931,7 @@ 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 AnswerCurrentQuestionWithResourceRecord 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) @@ -3021,7 +4007,7 @@ 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 AnswerCurrentQuestionWithResourceRecord 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) @@ -3049,7 +4035,7 @@ 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 AnswerCurrentQuestionWithResourceRecord 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) @@ -3081,7 +4067,7 @@ mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr) { if (q->CurrentAnswers == 0) { - LogOperation("CacheRecordRmv: Last answer for %##s (%s) expired from cache; will reconfirm antecedents", + LogInfo("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); } @@ -3122,7 +4108,7 @@ 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); + if (r->resrec.rdata && r->resrec.rdata != (RData*)&r->smallrdatastorage) mDNSPlatformMemFree(r->resrec.rdata); r->resrec.rdata = mDNSNULL; ReleaseCacheEntity(m, (CacheEntity *)r); } @@ -3212,7 +4198,7 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m) 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); + MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any); q->NoAnswer = NoAnswer_Normal; // Temporarily turn off answer suppression AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache); q->NoAnswer = NoAnswer_Fail; // Restore NoAnswer state @@ -3232,7 +4218,7 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m) if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly) if (ResourceRecordAnswersQuestion(&rr->resrec, q)) { - AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, mDNStrue); + AnswerLocalQuestionWithLocalAuthRecord(m, q, rr, mDNStrue); if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here } } @@ -3251,8 +4237,8 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m) 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); + LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %s %d %d", + rr->resrec.rroriginalttl, SecsSinceRcvd, CRDisplayString(m, rr), m->timenow, rr->TimeRcvd); continue; // Go to next one in loop } @@ -3267,8 +4253,7 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m) 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; + ShouldQueryImmediately = mDNSfalse; } if (m->CurrentQuestion != q) debugf("AnswerNewQuestion: question deleted while giving cache answers"); @@ -3295,7 +4280,7 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m) } // 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 +// appropriate answers, stopping if it reaches a NewLocalRecord -- these will be handled by AnswerAllLocalQuestionsWithLocalAuthRecord mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m) { DNSQuestion *q = m->NewLocalOnlyQuestions; // Grab the question we're going to answer @@ -3317,7 +4302,7 @@ mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m) m->CurrentRecord = rr->next; if (ResourceRecordAnswersQuestion(&rr->resrec, q)) { - AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, mDNStrue); + AnswerLocalQuestionWithLocalAuthRecord(m, q, rr, mDNStrue); if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here } } @@ -3345,8 +4330,8 @@ mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const Pre // 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", + if (m->rrcache_size > 5000 && m->rrcache_size / 32 > m->rrcache_active) + LogInfo("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu", m->rrcache_size, m->rrcache_active); else { @@ -3360,9 +4345,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 LogAllOperations || MDNS_DEBUGMSGS mDNSu32 oldtotalused = m->rrcache_totalused; - #endif mDNSu32 slot; for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) { @@ -3390,7 +4373,7 @@ mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const Pre else ReleaseCacheGroup(m, cp); } } - LogOperation("GetCacheEntity recycled %d records to reduce cache from %d to %d", + LogInfo("GetCacheEntity recycled %d records to reduce cache from %d to %d", oldtotalused - m->rrcache_totalused, oldtotalused, m->rrcache_totalused); } @@ -3400,9 +4383,10 @@ mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const Pre m->rrcache_free = e->next; if (++m->rrcache_totalused >= m->rrcache_report) { - LogOperation("RR Cache now using %ld objects", m->rrcache_totalused); - if (m->rrcache_report < 100) m->rrcache_report += 10; - else m->rrcache_report += 100; + LogInfo("RR Cache now using %ld objects", m->rrcache_totalused); + if (m->rrcache_report < 100) m->rrcache_report += 10; + else if (m->rrcache_report < 1000) m->rrcache_report += 100; + else m->rrcache_report += 1000; } mDNSPlatformMemZero(e, sizeof(*e)); } @@ -3417,7 +4401,7 @@ mDNSlocal CacheRecord *GetCacheRecord(mDNS *const m, CacheGroup *cg, mDNSu16 RDL CacheRecord *r = (CacheRecord *)GetCacheEntity(m, cg); if (r) { - r->resrec.rdata = (RData*)&r->rdatastorage; // By default, assume we're usually going to be using local storage + r->resrec.rdata = (RData*)&r->smallrdatastorage; // By default, assume we're usually going to be using local storage if (RDLength > InlineCacheRDSize) // If RDLength is too big, allocate extra storage { r->resrec.rdata = (RData*)mDNSPlatformMemAllocate(sizeofRDataHeader + RDLength); @@ -3458,6 +4442,8 @@ mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const Res mDNSexport void mDNS_PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr) { + if (m->mDNS_busy != m->mDNS_reentrancy+1) + LogMsg("mDNS_PurgeCacheResourceRecord: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); // 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). // We don't want to clear CRActiveQuestion here, because that would leave the record subject to @@ -3485,6 +4471,43 @@ mDNSexport mDNSs32 mDNS_TimeNow(const mDNS *const m) return(time); } +// To avoid pointless CPU thrash, we use SetSPSProxyListChanged(X) to record the last interface that +// had its Sleep Proxy client list change, and defer to actual BPF reconfiguration to mDNS_Execute(). +// (GetNextScheduledEvent() returns "now" when m->SPSProxyListChanged is set) +#define SetSPSProxyListChanged(X) do { \ + if (m->SPSProxyListChanged && m->SPSProxyListChanged != (X)) mDNSPlatformUpdateProxyList(m, m->SPSProxyListChanged); \ + m->SPSProxyListChanged = (X); } while(0) + +// Called from mDNS_Execute() to expire stale proxy records +mDNSlocal void CheckProxyRecords(mDNS *const m, AuthRecord *list) + { + m->CurrentRecord = list; + while (m->CurrentRecord) + { + AuthRecord *rr = m->CurrentRecord; + if (rr->WakeUp.HMAC.l[0]) + { + if (m->timenow - rr->TimeExpire < 0) // If proxy record not expired yet, update m->NextScheduledSPS + { + if (m->NextScheduledSPS - rr->TimeExpire > 0) + m->NextScheduledSPS = rr->TimeExpire; + } + else // else proxy record expired, so remove it + { + LogSPS("mDNS_Execute: Removing %d H-MAC %.6a I-MAC %.6a %d %s", + m->ProxyRecords, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, rr->WakeUp.seq, ARDisplayString(m, rr)); + SetSPSProxyListChanged(rr->resrec.InterfaceID); + mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); + // Don't touch rr after this -- memory may have been free'd + } + } + // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, + // because the list may have been changed in that call. + if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now + m->CurrentRecord = rr->next; + } + } + mDNSexport mDNSs32 mDNS_Execute(mDNS *const m) { mDNS_Lock(m); // Must grab lock before trying to read m->timenow @@ -3520,6 +4543,25 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m) } } + if (m->timenow - m->NextScheduledSPS >= 0) + { + m->NextScheduledSPS = m->timenow + 0x3FFFFFFF; + CheckProxyRecords(m, m->DuplicateRecords); // Clear m->DuplicateRecords first, then m->ResourceRecords + CheckProxyRecords(m, m->ResourceRecords); + } + + SetSPSProxyListChanged(mDNSNULL); // Perform any deferred BPF reconfiguration now + + if (m->DelaySleep && m->timenow - m->DelaySleep >= 0) + { + m->DelaySleep = 0; + if (m->SleepState == SleepState_Transferring) + { + LogSPS("Re-sleep delay passed; now checking for Sleep Proxy Servers"); + BeginSleepProcessing(m); + } + } + // 4. See if we can answer any of our new local questions from the cache for (i=0; m->NewQuestions && i<1000; i++) { @@ -3535,13 +4577,14 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m) { AuthRecord *rr = m->NewLocalRecords; m->NewLocalRecords = m->NewLocalRecords->next; - AnswerLocalQuestions(m, rr, mDNStrue); + AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue); } if (i >= 1000) LogMsg("mDNS_Execute: AnswerForNewLocalRecords exceeded loop limit"); // 5. See what packets we need to send - if (m->mDNSPlatformStatus != mStatus_NoError || m->SleepState) DiscardDeregistrations(m); - else if (m->SuppressSending == 0 || m->timenow - m->SuppressSending >= 0) + if (m->mDNSPlatformStatus != mStatus_NoError || (m->SleepState == SleepState_Sleeping)) + DiscardDeregistrations(m); + if (m->mDNSPlatformStatus == mStatus_NoError && (m->SuppressSending == 0 || m->timenow - m->SuppressSending >= 0)) { // If the platform code is ready, and we're not suppressing packet generation right now // then send our responses, probes, and questions. @@ -3645,7 +4688,7 @@ mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question, if (!question->DuplicateOf) { - LogOperation("ActivateUnicastQuery: %##s %s%s%s", + debugf("ActivateUnicastQuery: %##s %s%s%s", question->qname.c, DNSTypeName(question->qtype), question->AuthInfo ? " (Private)" : "", ScheduleImmediately ? " ScheduleImmediately" : ""); if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; } if (question->LongLived) @@ -3664,107 +4707,527 @@ mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question, } } -// Call mDNSCoreMachineSleep(m, mDNStrue) when the machine is about to go to sleep. -// Call mDNSCoreMachineSleep(m, mDNSfalse) when the machine is has just woken up. -// Normally, the platform support layer below mDNSCore should call this, not the client layer above. -// Note that sleep/wake calls do not have to be paired one-for-one; it is acceptable to call -// mDNSCoreMachineSleep(m, mDNSfalse) any time there is reason to believe that the machine may have just -// found itself in a new network environment. For example, if the Ethernet hardware indicates that the -// cable has just been connected, the platform support layer should call mDNSCoreMachineSleep(m, mDNSfalse) -// to make mDNSCore re-issue its outstanding queries, probe for record uniqueness, etc. -// While it is safe to call mDNSCoreMachineSleep(m, mDNSfalse) at any time, it does cause extra network -// traffic, so it should only be called when there is legitimate reason to believe the machine -// may have become attached to a new network. -mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate) +mDNSexport void mDNSCoreRestartQueries(mDNS *const m) { - AuthRecord *rr; - - mDNS_Lock(m); - - m->SleepState = sleepstate; - LogOperation("%s at %ld", sleepstate ? "Sleeping" : "Waking", m->timenow); + DNSQuestion *q; - if (sleepstate) - { #ifndef UNICAST_DISABLED - SuspendLLQs(m); - SleepServiceRegistrations(m); - SleepRecordRegistrations(m); -#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) - rr->ImmedAnswer = mDNSInterfaceMark; - SendResponses(m); - } - else + // Retrigger all our uDNS questions + if (m->CurrentQuestion) + LogMsg("mDNSCoreRestartQueries: ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype)); + m->CurrentQuestion = m->Questions; + while (m->CurrentQuestion) { - DNSQuestion *q; - mDNSu32 slot; - CacheGroup *cg; - CacheRecord *cr; + q = m->CurrentQuestion; + m->CurrentQuestion = m->CurrentQuestion->next; + if (!mDNSOpaque16IsZero(q->TargetQID)) ActivateUnicastQuery(m, q, mDNStrue); + } +#endif -#ifndef UNICAST_DISABLED - // On wake, retrigger all our uDNS questions - 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) + // Retrigger all our mDNS questions + for (q = m->Questions; q; q=q->next) // Scan our list of questions + if (mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q)) { - q = m->CurrentQuestion; - m->CurrentQuestion = m->CurrentQuestion->next; - if (!mDNSOpaque16IsZero(q->TargetQID)) ActivateUnicastQuery(m, q, mDNStrue); + q->ThisQInterval = InitialQuestionInterval; // 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; + q->RecentAnswerPkts = 0; + ExpireDupSuppressInfo(q->DupSuppress, m->timenow); + m->NextScheduledQuery = m->timenow; } - // and reactivtate service registrations - m->NextSRVUpdate = NonZeroTime(m->timenow + mDNSPlatformOneSecond); - LogOperation("WakeServiceRegistrations %d %d", m->timenow, m->NextSRVUpdate); + } + +// *************************************************************************** +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - +#pragma mark - Power Management (Sleep/Wake) #endif - // 1. Retrigger all our mDNS questions - for (q = m->Questions; q; q=q->next) // Scan our list of questions - 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 - q->LastQTime = m->timenow - q->ThisQInterval; - q->RecentAnswerPkts = 0; - ExpireDupSuppressInfo(q->DupSuppress, m->timenow); - m->NextScheduledQuery = m->timenow; - } - // 2. Re-validate our cache records - m->NextCacheCheck = m->timenow; - FORALL_CACHERECORDS(slot, cg, cr) - mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForWake); +mDNSlocal void SendSPSRegistration(mDNS *const m, NetworkInterfaceInfo *intf, const mDNSOpaque16 id) + { + const int ownerspace = mDNSSameEthAddress(&m->PrimaryMAC, &intf->MAC) ? DNSOpt_OwnerData_ID_Space : DNSOpt_OwnerData_ID_Wake_Space; + const int optspace = DNSOpt_Header_Space + DNSOpt_LeaseData_Space + ownerspace; + const int sps = intf->NextSPSAttempt / 3; + AuthRecord *rr; - // 3. Retrigger probing and announcing for all our authoritative records + if (!intf->SPSAddr[sps].type) + { + intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond; + if (m->NextScheduledSPRetry - intf->NextSPSAttemptTime > 0) + m->NextScheduledSPRetry = intf->NextSPSAttemptTime; + LogSPS("SendSPSRegistration: %s SPS %d (%d) %##s not yet resolved", intf->ifname, intf->NextSPSAttempt, sps, intf->NetWakeResolve[sps].qname.c); + goto exit; + } + + // Mark our mDNS records (not unicast records) for transfer to SPS + if (mDNSOpaque16IsZero(id)) for (rr = m->ResourceRecords; rr; rr=rr->next) - if (AuthRecord_uDNS(rr)) + if (rr->resrec.RecordType > kDNSRecordTypeDeregistering) + if (rr->resrec.InterfaceID == intf->InterfaceID || (!rr->resrec.InterfaceID && (rr->ForceMCast || IsLocalDomain(rr->resrec.name)))) + rr->SendRNow = mDNSInterfaceMark; // mark it now + + while (1) + { + mDNSu8 *p = m->omsg.data; + // To comply with RFC 2782, PutResourceRecord suppresses name compression for SRV records in unicast updates. + // For now we follow that same logic for SPS registrations too. + // If we decide to compress SRV records in SPS registrations in the future, we can achieve that by creating our + // initial DNSMessage with h.flags set to zero, and then update it to UpdateReqFlags right before sending the packet. + InitializeDNSMessage(&m->omsg.h, mDNSOpaque16IsZero(id) ? mDNS_NewMessageID(m) : id, UpdateReqFlags); + + for (rr = m->ResourceRecords; rr; rr=rr->next) + if (rr->SendRNow || (!mDNSOpaque16IsZero(id) && !AuthRecord_uDNS(rr) && mDNSSameOpaque16(rr->updateid, id) && m->timenow - (rr->LastAPTime + rr->ThisAPInterval) >= 0)) { - ActivateUnicastRegistration(m, rr); + mDNSu8 *newptr; + const mDNSu8 *const limit = m->omsg.data + (m->omsg.h.mDNS_numUpdates ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData) - optspace; + if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) + rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the 'unique' bit so PutResourceRecord will set it + newptr = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit); + rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear 'unique' bit back to normal state + if (!newptr) + LogSPS("SendSPSRegistration put %s FAILED %d/%d %s", intf->ifname, p - m->omsg.data, limit - m->omsg.data, ARDisplayString(m, rr)); + else + { + LogSPS("SendSPSRegistration put %s %s", intf->ifname, ARDisplayString(m, rr)); + rr->SendRNow = mDNSNULL; + rr->ThisAPInterval = mDNSPlatformOneSecond; + rr->LastAPTime = m->timenow; + rr->updateid = m->omsg.h.id; + if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0) + m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval); + p = newptr; + } } + + if (!m->omsg.h.mDNS_numUpdates) break; + else + { + AuthRecord opt; + mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL); + opt.resrec.rrclass = NormalMaxDNSMessageData; + opt.resrec.rdlength = sizeof(rdataOPT) * 2; // Two options in this OPT record + opt.resrec.rdestimate = sizeof(rdataOPT) * 2; + opt.resrec.rdata->u.opt[0].opt = kDNSOpt_Lease; + opt.resrec.rdata->u.opt[0].optlen = DNSOpt_LeaseData_Space - 4; + opt.resrec.rdata->u.opt[0].u.updatelease = DEFAULT_UPDATE_LEASE; + SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[1]); + LogSPS("SendSPSRegistration put %s %s", intf->ifname, ARDisplayString(m, &opt)); + p = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.numAdditionals, &opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData); + if (!p) + LogMsg("SendSPSRegistration: Failed to put OPT record (%d updates) %s", m->omsg.h.mDNS_numUpdates, ARDisplayString(m, &opt)); else { - if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique; - rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); - rr->AnnounceCount = InitialAnnounceCount; - InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType)); + mStatus err; + LogSPS("SendSPSRegistration: Sending Update %s %d (%d) id %5d with %d records %d bytes to %#a:%d", intf->ifname, intf->NextSPSAttempt, sps, + mDNSVal16(m->omsg.h.id), m->omsg.h.mDNS_numUpdates, p - m->omsg.data, &intf->SPSAddr[sps], mDNSVal16(intf->SPSPort[sps])); + // if (intf->NextSPSAttempt < 5) m->omsg.h.flags = zeroID; // For simulating packet loss + err = mDNSSendDNSMessage(m, &m->omsg, p, intf->InterfaceID, mDNSNULL, &intf->SPSAddr[sps], intf->SPSPort[sps], mDNSNULL, mDNSNULL); + if (err) LogSPS("SendSPSRegistration: mDNSSendDNSMessage err %d", err); + if (err && intf->SPSAddr[sps].type == mDNSAddrType_IPv6 && intf->NetWakeResolve[sps].ThisQInterval == -1) + { + LogSPS("SendSPSRegistration %d %##s failed to send to IPv6 address; will try IPv4 instead", sps, intf->NetWakeResolve[sps].qname.c); + intf->NetWakeResolve[sps].qtype = kDNSType_A; + mDNS_StartQuery_internal(m, &intf->NetWakeResolve[sps]); + return; + } } + } } - mDNS_Unlock(m); + intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond * 10; // If successful, update NextSPSAttemptTime + +exit: + if (mDNSOpaque16IsZero(id) && intf->NextSPSAttempt < 8) intf->NextSPSAttempt++; } -// *************************************************************************** -#if COMPILER_LIKES_PRAGMA_MARK -#pragma mark - -#pragma mark - Packet Reception Functions -#endif +// RetrySPSRegistrations is called from SendResponses, with the lock held +mDNSlocal void RetrySPSRegistrations(mDNS *const m) + { + AuthRecord *rr; + NetworkInterfaceInfo *intf; -#define MustSendRecord(RR) ((RR)->NR_AnswerTo || (RR)->NR_AdditionalTo) + // First make sure none of our interfaces' NextSPSAttemptTimes are inadvertently set to m->timenow + mDNSPlatformOneSecond * 10 + for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) + if (intf->NextSPSAttempt && intf->NextSPSAttemptTime == m->timenow + mDNSPlatformOneSecond * 10) + intf->NextSPSAttemptTime++; -mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const mDNSu8 *const end, - const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, DNSMessage *const response, AuthRecord *ResponseRecords) - { + // Retry any record registrations that are due + for (rr = m->ResourceRecords; rr; rr=rr->next) + if (!AuthRecord_uDNS(rr) && !mDNSOpaque16IsZero(rr->updateid) && m->timenow - (rr->LastAPTime + rr->ThisAPInterval) >= 0) + for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) + if (!rr->resrec.InterfaceID || rr->resrec.InterfaceID == intf->InterfaceID) + { + LogSPS("RetrySPSRegistrations: %s", ARDisplayString(m, rr)); + SendSPSRegistration(m, intf, rr->updateid); + } + + // For interfaces where we did an SPS registration attempt, increment intf->NextSPSAttempt + for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) + if (intf->NextSPSAttempt && intf->NextSPSAttemptTime == m->timenow + mDNSPlatformOneSecond * 10 && intf->NextSPSAttempt < 8) + intf->NextSPSAttempt++; + } + +mDNSlocal void NetWakeResolve(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) + { + NetworkInterfaceInfo *intf = (NetworkInterfaceInfo *)question->QuestionContext; + int sps = question - intf->NetWakeResolve; + (void)m; // Unused + LogSPS("NetWakeResolve: SPS: %d Add: %d %s", sps, AddRecord, RRDisplayString(m, answer)); + + if (!AddRecord) return; // Don't care about REMOVE events + if (answer->rrtype != question->qtype) return; // Don't care about CNAMEs + + mDNS_StopQuery(m, question); + question->ThisQInterval = -1; + + if (answer->rrtype == kDNSType_SRV) + { + intf->SPSPort[sps] = answer->rdata->u.srv.port; + AssignDomainName(&question->qname, &answer->rdata->u.srv.target); + question->qtype = kDNSType_AAAA; + mDNS_StartQuery(m, question); + } + else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == sizeof(mDNSv6Addr) && mDNSv6AddressIsLinkLocal(&answer->rdata->u.ipv6)) + { + intf->SPSAddr[sps].type = mDNSAddrType_IPv6; + intf->SPSAddr[sps].ip.v6 = answer->rdata->u.ipv6; + mDNS_Lock(m); + if (sps == intf->NextSPSAttempt/3) SendSPSRegistration(m, intf, zeroID); // If we're ready for this result, use it now + mDNS_Unlock(m); + } + else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == 0) // If negative answer for IPv6, look for IPv4 addresses instead + { + LogSPS("NetWakeResolve: SPS %d %##s has no IPv6 address, will try IPv4 instead", sps, question->qname.c); + question->qtype = kDNSType_A; + mDNS_StartQuery(m, question); + } + else if (answer->rrtype == kDNSType_A && answer->rdlength == sizeof(mDNSv4Addr)) + { + intf->SPSAddr[sps].type = mDNSAddrType_IPv4; + intf->SPSAddr[sps].ip.v4 = answer->rdata->u.ipv4; + mDNS_Lock(m); + if (sps == intf->NextSPSAttempt/3) SendSPSRegistration(m, intf, zeroID); // If we're ready for this result, use it now + mDNS_Unlock(m); + } + } + +mDNSexport mDNSBool mDNSCoreHaveAdvertisedMulticastServices(mDNS *const m) + { + AuthRecord *rr; + for (rr = m->ResourceRecords; rr; rr=rr->next) + if (rr->resrec.rrtype == kDNSType_SRV && !AuthRecord_uDNS(rr) && !mDNSSameIPPort(rr->resrec.rdata->u.srv.port, DiscardPort)) + return mDNStrue; + return mDNSfalse; + } + +// BeginSleepProcessing is called, with the lock held, from either mDNS_Execute or mDNSCoreMachineSleep +mDNSlocal void BeginSleepProcessing(mDNS *const m) + { + const CacheRecord *sps[3] = { mDNSNULL }; + + m->NextScheduledSPRetry = m->timenow; + + if (!m->SystemWakeOnLANEnabled) LogSPS("BeginSleepProcessing: m->SystemWakeOnLANEnabled is false"); + else if (!mDNSCoreHaveAdvertisedMulticastServices(m)) LogSPS("BeginSleepProcessing: No advertised services"); + else // If we have at least one advertised service + { + NetworkInterfaceInfo *intf; + for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) + { + if (!intf->NetWake) LogSPS("BeginSleepProcessing: %-6s not capable of magic packet wakeup", intf->ifname); + else + { + FindSPSInCache(m, &intf->NetWakeBrowse, sps); + if (!sps[0]) LogSPS("BeginSleepProcessing: %-6s %#a No Sleep Proxy Server found %d", intf->ifname, &intf->ip, intf->NetWakeBrowse.ThisQInterval); + else + { + int i; + intf->NextSPSAttempt = 0; + intf->NextSPSAttemptTime = m->timenow + mDNSPlatformOneSecond; + // Don't need to set m->NextScheduledSPRetry here because we already set "m->NextScheduledSPRetry = m->timenow" above + for (i=0; i<3; i++) + { +#if ForceAlerts + if (intf->SPSAddr[i].type) + { LogMsg("BeginSleepProcessing: %s %d intf->SPSAddr[i].type %d", intf->ifname, i, intf->SPSAddr[i].type); *(long*)0 = 0; } + if (intf->NetWakeResolve[i].ThisQInterval >= 0) + { LogMsg("BeginSleepProcessing: %s %d intf->NetWakeResolve[i].ThisQInterval %d", intf->ifname, i, intf->NetWakeResolve[i].ThisQInterval); *(long*)0 = 0; } +#endif + intf->SPSAddr[i].type = mDNSAddrType_None; + if (intf->NetWakeResolve[i].ThisQInterval >= 0) mDNS_StopQuery(m, &intf->NetWakeResolve[i]); + intf->NetWakeResolve[i].ThisQInterval = -1; + if (sps[i]) + { + LogSPS("BeginSleepProcessing: %-6s Found Sleep Proxy Server %d TTL %d %s", intf->ifname, i, sps[i]->resrec.rroriginalttl, CRDisplayString(m, sps[i])); + mDNS_SetupQuestion(&intf->NetWakeResolve[i], intf->InterfaceID, &sps[i]->resrec.rdata->u.name, kDNSType_SRV, NetWakeResolve, intf); + intf->NetWakeResolve[i].ReturnIntermed = mDNStrue; + mDNS_StartQuery_internal(m, &intf->NetWakeResolve[i]); + } + } + } + } + } + } + + if (!sps[0]) // If we didn't find even one Sleep Proxy + { + AuthRecord *rr; + LogSPS("BeginSleepProcessing: Not registering with Sleep Proxy Server"); + m->SleepState = SleepState_Sleeping; + +#ifndef UNICAST_DISABLED + SleepServiceRegistrations(m); + SleepRecordRegistrations(m); // If we have no SPS, need to deregister our uDNS records +#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) + rr->ImmedAnswer = mDNSInterfaceMark; + SendResponses(m); + } + } + +// Call mDNSCoreMachineSleep(m, mDNStrue) when the machine is about to go to sleep. +// Call mDNSCoreMachineSleep(m, mDNSfalse) when the machine is has just woken up. +// Normally, the platform support layer below mDNSCore should call this, not the client layer above. +mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep) + { + AuthRecord *rr; + + mDNS_Lock(m); + + LogSPS("%s (old state %d) at %ld", sleep ? "Sleeping" : "Waking", m->SleepState, m->timenow); + + if (sleep && !m->SleepState) // Going to sleep + { + // If we're going to sleep, need to stop advertising that we're a Sleep Proxy Server + if (m->SPSSocket) + { + mDNSu8 oldstate = m->SPSState; + mDNS_DropLockBeforeCallback(); // mDNS_DeregisterService expects to be called without the lock held, so we emulate that here + m->SPSState = 2; + if (oldstate == 1) mDNS_DeregisterService(m, &m->SPSRecords); + mDNS_ReclaimLockAfterCallback(); + } + + m->SleepState = SleepState_Transferring; + if (m->SystemWakeOnLANEnabled && m->DelaySleep) + { + // If we just woke up moments ago, allow ten seconds for networking to stabilize before going back to sleep + LogSPS("mDNSCoreMachineSleep: Re-sleeping immediately after waking; will delay for %d ticks", m->DelaySleep - m->timenow); + m->SleepLimit = m->DelaySleep + mDNSPlatformOneSecond * 10; + } + else + { + m->DelaySleep = 0; + m->SleepLimit = m->timenow + mDNSPlatformOneSecond * 10; + BeginSleepProcessing(m); + } + +#ifndef UNICAST_DISABLED + SuspendLLQs(m); +#endif + LogSPS("mDNSCoreMachineSleep: m->SleepState %d (%s) seq %d", m->SleepState, + m->SleepState == SleepState_Transferring ? "Transferring" : + m->SleepState == SleepState_Sleeping ? "Sleeping" : "?", m->SleepSeqNum); + } + else if (!sleep) // Waking up + { + mDNSu32 slot; + CacheGroup *cg; + CacheRecord *cr; + NetworkInterfaceInfo *intf; + + // If we were previously sleeping, but now we're not, increment m->SleepSeqNum to indicate that we're entering a new period of wakefulness + if (m->SleepState != SleepState_Awake) + { + m->SleepState = SleepState_Awake; + m->SleepSeqNum++; + // If the machine wakes and then immediately tries to sleep again (e.g. a maintenance wake) + // then we enforce a minimum delay of 16 seconds before we begin sleep processing. + // This is to allow time for the Ethernet link to come up, DHCP to get an address, mDNS to issue queries, etc., + // before we make our determination of whether there's a Sleep Proxy out there we should register with. + m->DelaySleep = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 16); + } + + if (m->SPSState == 3) + { + mDNS_DropLockBeforeCallback(); // mDNS_DeregisterService expects to be called without the lock held, so we emulate that here + m->SPSState = 0; + mDNSCoreBeSleepProxyServer(m, m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower); + mDNS_ReclaimLockAfterCallback(); + } + + // In case we gave up waiting and went to sleep before we got an ack from the Sleep Proxy, + // on wake we go through our record list and clear updateid back to zero + for (rr = m->ResourceRecords; rr; rr=rr->next) rr->updateid = zeroID; + + // ... and the same for NextSPSAttempt + for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) intf->NextSPSAttempt = -1; + + // Restart unicast and multicast queries + mDNSCoreRestartQueries(m); + + // and reactivtate service registrations + m->NextSRVUpdate = NonZeroTime(m->timenow + mDNSPlatformOneSecond); + LogInfo("WakeServiceRegistrations %d %d", m->timenow, m->NextSRVUpdate); + + // 2. Re-validate our cache records + m->NextCacheCheck = m->timenow; + FORALL_CACHERECORDS(slot, cg, cr) + mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForWake); + + // 3. Retrigger probing and announcing for all our authoritative records + for (rr = m->ResourceRecords; rr; rr=rr->next) + if (AuthRecord_uDNS(rr)) + { + ActivateUnicastRegistration(m, rr); + } + else + { + if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique; + rr->ProbeCount = DefaultProbeCountForRecordType(rr->resrec.RecordType); + rr->AnnounceCount = InitialAnnounceCount; + InitializeLastAPTime(m, rr); + } + + // 4. Refresh NAT mappings + // We don't want to have to assume that all hardware can necessarily keep accurate + // track of passage of time while asleep, so on wake we refresh our NAT mappings + m->retryIntervalGetAddr = NATMAP_INIT_RETRY; + m->retryGetAddr = m->timenow; + RecreateNATMappings(m); + } + + mDNS_Unlock(m); + } + +mDNSexport mDNSBool mDNSCoreReadyForSleep(mDNS *m) + { + DNSQuestion *q; + AuthRecord *rr; + ServiceRecordSet *srs; + NetworkInterfaceInfo *intf; + + mDNS_Lock(m); + + if (m->NextScheduledSPRetry - m->timenow > 0) goto notready; + + m->NextScheduledSPRetry = m->timenow + 0x40000000UL; + + if (m->DelaySleep) goto notready; + + // See if we might need to retransmit any lost Sleep Proxy Registrations + for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) + if (intf->NextSPSAttempt >= 0) + { + if (m->timenow - intf->NextSPSAttemptTime >= 0) + { + LogSPS("ReadyForSleep retrying SPS %s %d", intf->ifname, intf->NextSPSAttempt); + SendSPSRegistration(m, intf, zeroID); + } + else + if (m->NextScheduledSPRetry - intf->NextSPSAttemptTime > 0) + m->NextScheduledSPRetry = intf->NextSPSAttemptTime; + } + + // Scan list of private LLQs, and make sure they've all completed their handshake with the server + for (q = m->Questions; q; q = q->next) + if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->ReqLease == 0 && q->tcp) + { + LogSPS("ReadyForSleep waiting for LLQ %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + goto notready; + } + + // Scan list of interfaces + for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) + if (intf->NetWakeResolve[0].ThisQInterval >= 0) + { + LogSPS("ReadyForSleep waiting for SPS Resolve %s %##s (%s)", intf->ifname, intf->NetWakeResolve[0].qname.c, DNSTypeName(intf->NetWakeResolve[0].qtype)); + goto notready; + } + + // Scan list of registered records + for (rr = m->ResourceRecords; rr; rr = rr->next) + { + if (AuthRecord_uDNS(rr)) + { + if (rr->state == regState_Refresh && rr->tcp) + { LogSPS("ReadyForSleep waiting for Record Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto notready; } + } + else + { + if (!mDNSOpaque16IsZero(rr->updateid)) + { LogSPS("ReadyForSleep waiting for SPS Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto notready; } + } + } + + // Scan list of registered services + for (srs = m->ServiceRegistrations; srs; srs = srs->uDNS_next) + if (srs->state == regState_NoTarget && srs->tcp) goto notready; + + mDNS_Unlock(m); + return mDNStrue; + +notready: + mDNS_Unlock(m); + return mDNSfalse; + } + +mDNSexport mDNSs32 mDNSCoreIntervalToNextWake(mDNS *const m, mDNSs32 now) + { + AuthRecord *ar; + + // Even when we have no wake-on-LAN-capable interfaces, or we failed to find a sleep proxy, or we have other + // failure scenarios, we still want to wake up in at most 120 minutes, to see if the network environment has changed. + // E.g. we might wake up and find no wireless network because the base station got rebooted just at that moment, + // and if that happens we don't want to just give up and go back to sleep and never try again. + mDNSs32 e = now + (120 * 60 * mDNSPlatformOneSecond); // Sleep for at most 120 minutes + + NATTraversalInfo *nat; + for (nat = m->NATTraversals; nat; nat=nat->next) + if (nat->Protocol && nat->ExpiryTime && nat->ExpiryTime - now > mDNSPlatformOneSecond*4) + { + mDNSs32 t = nat->ExpiryTime - (nat->ExpiryTime - now) / 10; // Wake up when 90% of the way to the expiry time + if (e - t > 0) e = t; + LogSPS("ComputeWakeTime: %p %s Int %5d Ext %5d Err %d Retry %5d Interval %5d Expire %5d Wake %5d", + nat, nat->Protocol == NATOp_MapTCP ? "TCP" : "UDP", + mDNSVal16(nat->IntPort), mDNSVal16(nat->ExternalPort), nat->Result, + nat->retryPortMap ? (nat->retryPortMap - now) / mDNSPlatformOneSecond : 0, + nat->retryInterval / mDNSPlatformOneSecond, + nat->ExpiryTime ? (nat->ExpiryTime - now) / mDNSPlatformOneSecond : 0, + (t - now) / mDNSPlatformOneSecond); + } + + // This loop checks both the time we need to renew wide-area registrations, + // and the time we need to renew Sleep Proxy registrations + for (ar = m->ResourceRecords; ar; ar = ar->next) + if (ar->expire && ar->expire - now > mDNSPlatformOneSecond*4) + { + mDNSs32 t = ar->expire - (ar->expire - now) / 10; // Wake up when 90% of the way to the expiry time + if (e - t > 0) e = t; + LogSPS("ComputeWakeTime: %p Int %7d Next %7d Expire %7d Wake %7d %s", + ar, ar->ThisAPInterval / mDNSPlatformOneSecond, + (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond, + ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0, + (t - now) / mDNSPlatformOneSecond, ARDisplayString(m, ar)); + } + + return(e - now); + } + +// *************************************************************************** +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - +#pragma mark - Packet Reception Functions +#endif + +#define MustSendRecord(RR) ((RR)->NR_AnswerTo || (RR)->NR_AdditionalTo) + +mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const mDNSu8 *const end, + const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, DNSMessage *const response, AuthRecord *ResponseRecords) + { mDNSu8 *responseptr = response->data; const mDNSu8 *const limit = response->data + sizeof(response->data); const mDNSu8 *ptr = query->data; @@ -3807,7 +5270,8 @@ mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const m for (rr=ResponseRecords; rr; rr=rr->NextResponse) if (rr->NR_AnswerTo) { - mDNSu8 *p = PutResourceRecordCappedTTL(response, responseptr, &response->h.numAnswers, &rr->resrec, maxttl); + mDNSu8 *p = PutResourceRecordTTL(response, responseptr, &response->h.numAnswers, &rr->resrec, + maxttl < rr->resrec.rroriginalttl ? maxttl : rr->resrec.rroriginalttl); if (p) responseptr = p; else { debugf("GenerateUnicastResponse: Ran out of space for answers!"); response->h.flags.b[0] |= kDNSFlag0_TC; } } @@ -3818,7 +5282,8 @@ mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const m for (rr=ResponseRecords; rr; rr=rr->NextResponse) if (rr->NR_AdditionalTo && !rr->NR_AnswerTo) { - mDNSu8 *p = PutResourceRecordCappedTTL(response, responseptr, &response->h.numAdditionals, &rr->resrec, maxttl); + mDNSu8 *p = PutResourceRecordTTL(response, responseptr, &response->h.numAdditionals, &rr->resrec, + maxttl < rr->resrec.rroriginalttl ? maxttl : rr->resrec.rroriginalttl); if (p) responseptr = p; else debugf("GenerateUnicastResponse: No more space for additionals"); } @@ -3831,7 +5296,7 @@ mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const m // Returns 0 if there is no conflict // Returns +1 if there was a conflict and we won // Returns -1 if there was a conflict and we lost and have to rename -mDNSlocal int CompareRData(AuthRecord *our, CacheRecord *pkt) +mDNSlocal int CompareRData(const AuthRecord *const our, const CacheRecord *const pkt) { mDNSu8 ourdata[256], *ourptr = ourdata, *ourend; mDNSu8 pktdata[256], *pktptr = pktdata, *pktend; @@ -3914,22 +5379,29 @@ mDNSlocal const AuthRecord *FindRRSet(const mDNS *const m, const CacheRecord *co // are members of the same RRSet, then this is not a conflict. mDNSlocal mDNSBool PacketRRConflict(const mDNS *const m, const AuthRecord *const our, const CacheRecord *const pktrr) { - const AuthRecord *ourset = our->RRSet ? our->RRSet : our; - // If not supposed to be unique, not a conflict if (!(our->resrec.RecordType & kDNSRecordTypeUniqueMask)) return(mDNSfalse); // If a dependent record, not a conflict if (our->DependentOn || MatchDependentOn(m, pktrr, our)) return(mDNSfalse); + else + { + // If the pktrr matches a member of ourset, not a conflict + const AuthRecord *ourset = our->RRSet ? our->RRSet : our; + const AuthRecord *pktset = FindRRSet(m, pktrr); + if (pktset == ourset) return(mDNSfalse); - // If the pktrr matches a member of ourset, not a conflict - if (FindRRSet(m, pktrr) == ourset) return(mDNSfalse); + // For records we're proxying, where we don't know the full + // relationship between the records, having any matching record + // in our AuthRecords list is sufficient evidence of non-conflict + if (our->WakeUp.HMAC.l[0] && pktset) return(mDNSfalse); + } // Okay, this is a conflict return(mDNStrue); } -// NOTE: ResolveSimultaneousProbe calls mDNS_Deregister_internal which can call a user callback, which may change +// Note: ResolveSimultaneousProbe 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. mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const query, const mDNSu8 *const end, @@ -3951,20 +5423,36 @@ mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const q int result = (int)our->resrec.rrclass - (int)m->rec.r.resrec.rrclass; if (!result) result = (int)our->resrec.rrtype - (int)m->rec.r.resrec.rrtype; if (!result) result = CompareRData(our, &m->rec.r); - if (result > 0) - LogOperation("ResolveSimultaneousProbe: %##s (%s): We won", our->resrec.name->c, DNSTypeName(our->resrec.rrtype)); - else if (result < 0) + if (result) { - LogOperation("ResolveSimultaneousProbe: %##s (%s): We lost", our->resrec.name->c, DNSTypeName(our->resrec.rrtype)); - mDNS_Deregister_internal(m, our, mDNS_Dereg_conflict); + const char *const msg = (result < 0) ? "lost:" : (result > 0) ? "won: " : "tie: "; + LogMsg("ResolveSimultaneousProbe: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r)); + LogMsg("ResolveSimultaneousProbe: Our Record %d %s %08lX %s", our->ProbeCount, msg, our->resrec.rdatahash, ARDisplayString(m, our)); + } + // If we lost the tie-break for simultaneous probes, we don't immediately give up, because we might be seeing stale packets on the network. + // Instead we pause for one second, to give the other host (if real) a change to establish its name, and then try probing again. + // If there really is another live host out there with the same name, it will answer our probes and we'll then rename. + if (result < 0) + { + m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond); + our->ProbeCount = DefaultProbeCountForTypeUnique; + our->AnnounceCount = InitialAnnounceCount; + InitializeLastAPTime(m, our); goto exit; } } +#if 0 + else + { + LogMsg("ResolveSimultaneousProbe: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r)); + LogMsg("ResolveSimultaneousProbe: Our Record ign: %08lX %s", our->resrec.rdatahash, ARDisplayString(m, our)); + } +#endif } m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it } if (!FoundUpdate) - LogOperation("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our->resrec.name->c, DNSTypeName(our->resrec.rrtype)); + LogInfo("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 } @@ -3979,6 +5467,28 @@ mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, const Res return(rr); } +// Called from ProcessQuery when we get an mDNS packet with an owner record in it +mDNSlocal void ClearProxyRecords(mDNS *const m, const OwnerOptData *const owner, AuthRecord *const thelist) + { + m->CurrentRecord = thelist; + while (m->CurrentRecord) + { + AuthRecord *const rr = m->CurrentRecord; + if (m->rec.r.resrec.InterfaceID == rr->resrec.InterfaceID && mDNSSameEthAddress(&owner->HMAC, &rr->WakeUp.HMAC)) + if (owner->seq != rr->WakeUp.seq || m->timenow - rr->TimeRcvd > mDNSPlatformOneSecond * 60) + { + LogSPS("ClearProxyRecords: Removing %3d H-MAC %.6a I-MAC %.6a %d %d %s", + m->ProxyRecords, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, rr->WakeUp.seq, owner->seq, ARDisplayString(m, rr)); + mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); + SetSPSProxyListChanged(m->rec.r.resrec.InterfaceID); + } + // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, + // because the list may have been changed in that call. + if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now + m->CurrentRecord = rr->next; + } + } + // 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, @@ -3993,18 +5503,43 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con DNSQuestion **dqp = &DupQuestions; mDNSs32 delayresponse = 0; mDNSBool SendLegacyResponse = mDNSfalse; - const mDNSu8 *ptr = query->data; + const mDNSu8 *ptr; mDNSu8 *responseptr = mDNSNULL; AuthRecord *rr; int i; // *** - // *** 1. Parse Question Section and mark potential answers + // *** 1. Look in Additional Section for an OPT record + // *** + ptr = LocateOptRR(query, end, DNSOpt_OwnerData_ID_Space); + if (ptr) + { + ptr = GetLargeResourceRecord(m, query, ptr, end, InterfaceID, kDNSRecordTypePacketAdd, &m->rec); + if (m->rec.r.resrec.rrtype == kDNSType_OPT) + { + const rdataOPT *opt; + const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength]; + // Find owner sub-option(s). We verify that the MAC is non-zero, otherwise we could inadvertently + // delete all our own AuthRecords (which are identified by having zero MAC tags on them). + for (opt = &m->rec.r.resrec.rdata->u.opt[0]; opt < e; opt++) + if (opt->opt == kDNSOpt_Owner && opt->u.owner.vers == 0 && opt->u.owner.HMAC.l[0]) + { + ClearProxyRecords(m, &opt->u.owner, m->DuplicateRecords); + ClearProxyRecords(m, &opt->u.owner, m->ResourceRecords); + } + } + m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it + } + + // *** + // *** 2. Parse Question Section and mark potential answers // *** + ptr = query->data; for (i=0; ih.numQuestions; i++) // For each question... { mDNSBool QuestionNeedsMulticastResponse; int NumAnswersForThisQuestion = 0; + AuthRecord *NSECAnswer = mDNSNULL; DNSQuestion pktq, *q; ptr = getQuestion(query, ptr, end, InterfaceID, &pktq); // get the question... if (!ptr) goto exit; @@ -4034,42 +5569,67 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con { rr = m->CurrentRecord; m->CurrentRecord = rr->next; - if (ResourceRecordAnswersQuestion(&rr->resrec, &pktq) && (QueryWasMulticast || QueryWasLocalUnicast || rr->AllowRemoteQuery)) + if (AnyTypeRecordAnswersQuestion(&rr->resrec, &pktq) && (QueryWasMulticast || QueryWasLocalUnicast || rr->AllowRemoteQuery)) { - if (rr->resrec.RecordType == kDNSRecordTypeUnique) - ResolveSimultaneousProbe(m, query, end, &pktq, rr); - else if (ResourceRecordIsValidAnswer(rr)) + if (RRTypeAnswersQuestionType(&rr->resrec, pktq.qtype)) { - NumAnswersForThisQuestion++; - // Notes: - // NR_AnswerTo pointing into query packet means "answer via immediate legacy unicast" (may *also* choose to multicast) - // NR_AnswerTo == (mDNSu8*)~1 means "answer via delayed unicast" (to modern querier; may promote to multicast instead) - // NR_AnswerTo == (mDNSu8*)~0 means "definitely answer via multicast" (can't downgrade to unicast later) - // If we're not multicasting this record because the kDNSQClass_UnicastResponse bit was set, - // but the multicast querier is not on a matching subnet (e.g. because of overalyed subnets on one link) - // then we'll multicast it anyway (if we unicast, the receiver will ignore it because it has an apparently non-local source) - if (QuestionNeedsMulticastResponse || (!FromLocalSubnet && QueryWasMulticast && !LegacyQuery)) + if (rr->resrec.RecordType == kDNSRecordTypeUnique) + ResolveSimultaneousProbe(m, query, end, &pktq, rr); + else if (ResourceRecordIsValidAnswer(rr)) { - // We only mark this question for sending if it is at least one second since the last time we multicast it - // on this interface. If it is more than a second, or LastMCInterface is different, then we may multicast it. - // This is to guard against the case where someone blasts us with queries as fast as they can. - if (m->timenow - (rr->LastMCTime + mDNSPlatformOneSecond) >= 0 || - (rr->LastMCInterface != mDNSInterfaceMark && rr->LastMCInterface != InterfaceID)) - rr->NR_AnswerTo = (mDNSu8*)~0; + NumAnswersForThisQuestion++; + // Note: We should check here if this is a probe-type query, and if so, generate an immediate + // unicast answer back to the source, because timeliness in answering probes is important. + + // Notes: + // NR_AnswerTo pointing into query packet means "answer via immediate legacy unicast" (may *also* choose to multicast) + // NR_AnswerTo == (mDNSu8*)~1 means "answer via delayed unicast" (to modern querier; may promote to multicast instead) + // NR_AnswerTo == (mDNSu8*)~0 means "definitely answer via multicast" (can't downgrade to unicast later) + // If we're not multicasting this record because the kDNSQClass_UnicastResponse bit was set, + // but the multicast querier is not on a matching subnet (e.g. because of overlaid subnets on one link) + // then we'll multicast it anyway (if we unicast, the receiver will ignore it because it has an apparently non-local source) + if (QuestionNeedsMulticastResponse || (!FromLocalSubnet && QueryWasMulticast && !LegacyQuery)) + { + // We only mark this question for sending if it is at least one second since the last time we multicast it + // on this interface. If it is more than a second, or LastMCInterface is different, then we may multicast it. + // This is to guard against the case where someone blasts us with queries as fast as they can. + if (m->timenow - (rr->LastMCTime + mDNSPlatformOneSecond) >= 0 || + (rr->LastMCInterface != mDNSInterfaceMark && rr->LastMCInterface != InterfaceID)) + rr->NR_AnswerTo = (mDNSu8*)~0; + } + else if (!rr->NR_AnswerTo) rr->NR_AnswerTo = LegacyQuery ? ptr : (mDNSu8*)~1; } - else if (!rr->NR_AnswerTo) rr->NR_AnswerTo = LegacyQuery ? ptr : (mDNSu8*)~1; + } + else if (rr->resrec.RecordType == kDNSRecordTypeVerified) + { + // If we don't have any answers for this question, but we do own another record with the same name, + // then mark it to generate an NSEC record on this interface + if (!NSECAnswer) NSECAnswer = rr; } } } + if (NumAnswersForThisQuestion == 0 && NSECAnswer) + { + NumAnswersForThisQuestion++; + NSECAnswer->SendNSECNow = InterfaceID; + m->NextScheduledResponse = m->timenow; + } + // If we couldn't answer this question, someone else might be able to, // so use random delay on response to reduce collisions if (NumAnswersForThisQuestion == 0) delayresponse = mDNSPlatformOneSecond; // Divided by 50 = 20ms - // We only do the following accelerated cache expiration processing and duplicate question suppression processing - // for multicast queries with multicast responses. - // For any query generating a unicast response we don't do this because we can't assume we will see the response +#if ENABLE_MULTI_PACKET_QUERY_SNOOPING if (QuestionNeedsMulticastResponse) +#else + // We only do the following accelerated cache expiration and duplicate question suppression processing + // for non-truncated multicast queries with multicast responses. + // For any query generating a unicast response we don't do this because we can't assume we will see the response. + // For truncated queries we don't do this because a response we're expecting might be suppressed by a subsequent + // known-answer packet, and when there's packet loss we can't safely assume we'll receive *all* known-answer packets. + if (QuestionNeedsMulticastResponse && !(query->h.flags.b[0] & kDNSFlag0_TC)) +#endif { const mDNSu32 slot = HashSlot(&pktq.qname); CacheGroup *cg = CacheGroupForName(m, slot, pktq.qnamehash, &pktq.qname); @@ -4077,28 +5637,35 @@ 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 (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next) - if (SameNameRecordAnswersQuestion(&cr->resrec, &pktq) && cr->resrec.rdlength <= SmallRecordLimit) - if (!cr->NextInKAList && eap != &cr->NextInKAList) - { - *eap = cr; - eap = &cr->NextInKAList; - if (cr->MPUnansweredQ == 0 || m->timenow - cr->MPLastUnansweredQT >= mDNSPlatformOneSecond) +#if ENABLE_MULTI_PACKET_QUERY_SNOOPING + if (!(query->h.flags.b[0] & kDNSFlag0_TC)) +#endif + for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next) + if (SameNameRecordAnswersQuestion(&cr->resrec, &pktq) && cr->resrec.rdlength <= SmallRecordLimit) + if (!cr->NextInKAList && eap != &cr->NextInKAList) { - // Although MPUnansweredQ is only really used for multi-packet query processing, - // we increment it for both single-packet and multi-packet queries, so that it stays in sync - // with the MPUnansweredKA value, which by necessity is incremented for both query types. - cr->MPUnansweredQ++; - cr->MPLastUnansweredQT = m->timenow; - cr->MPExpectingKA = mDNStrue; + *eap = cr; + eap = &cr->NextInKAList; +#if ENABLE_MULTI_PACKET_QUERY_SNOOPING + if (cr->MPUnansweredQ == 0 || m->timenow - cr->MPLastUnansweredQT >= mDNSPlatformOneSecond) + { + // Although MPUnansweredQ is only really used for multi-packet query processing, + // we increment it for both single-packet and multi-packet queries, so that it stays in sync + // with the MPUnansweredKA value, which by necessity is incremented for both query types. + cr->MPUnansweredQ++; + cr->MPLastUnansweredQT = m->timenow; + cr->MPExpectingKA = mDNStrue; + } +#endif } - } // Check if this question is the same as any of mine. // We only do this for non-truncated queries. Right now it would be too complicated to try // to keep track of duplicate suppression state between multiple packets, especially when we // can't guarantee to receive all of the Known Answer packets that go with a particular query. +#if ENABLE_MULTI_PACKET_QUERY_SNOOPING if (!(query->h.flags.b[0] & kDNSFlag0_TC)) +#endif for (q = m->Questions; q; q=q->next) if (!q->Target.type && ActiveQuestion(q) && m->timenow - q->LastQTxTime > mDNSPlatformOneSecond / 4) if (!q->InterfaceID || q->InterfaceID == InterfaceID) @@ -4111,19 +5678,19 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con } // *** - // *** 2. Now we can safely build the list of marked answers + // *** 3. Now we can safely build the list of marked answers // *** for (rr = m->ResourceRecords; rr; rr=rr->next) // Now build our list of potential answers if (rr->NR_AnswerTo) // If we marked the record... AddRecordToResponseList(&nrp, rr, mDNSNULL); // ... add it to the list // *** - // *** 3. Add additional records + // *** 4. Add additional records // *** AddAdditionalsToResponseList(m, ResponseRecords, &nrp, InterfaceID); // *** - // *** 4. Parse Answer Section and cancel any records disallowed by Known-Answer list + // *** 5. Parse Answer Section and cancel any records disallowed by Known-Answer list // *** for (i=0; ih.numAnswers; i++) // For each record in the query's answer section... { @@ -4162,18 +5729,20 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con } } + ourcacherr = FindIdenticalRecordInCache(m, &m->rec.r.resrec); + +#if ENABLE_MULTI_PACKET_QUERY_SNOOPING // See if this Known-Answer suppresses any answers we were expecting for our cache records. We do this always, // even if the TC bit is not set (the TC bit will *not* be set in the *last* packet of a multi-packet KA list). - ourcacherr = FindIdenticalRecordInCache(m, &m->rec.r.resrec); if (ourcacherr && ourcacherr->MPExpectingKA && m->timenow - ourcacherr->MPLastUnansweredQT < mDNSPlatformOneSecond) { ourcacherr->MPUnansweredKA++; ourcacherr->MPExpectingKA = mDNSfalse; } +#endif - // Having built our ExpectedAnswers list from the questions in this packet, we can definitively - // remove from our ExpectedAnswers list any records that are suppressed in the very same packet. - // For answers that are suppressed in subsequent KA list packets, we rely on the MPQ/MPKA counting to track them. + // Having built our ExpectedAnswers list from the questions in this packet, we then remove + // any records that are suppressed by the Known Answer list in this packet. eap = &ExpectedAnswers; while (*eap) { @@ -4199,14 +5768,14 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con } // *** - // *** 5. Cancel any additionals that were added because of now-deleted records + // *** 6. Cancel any additionals that were added because of now-deleted records // *** for (rr=ResponseRecords; rr; rr=rr->NextResponse) if (rr->NR_AdditionalTo && !MustSendRecord(rr->NR_AdditionalTo)) { rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; } // *** - // *** 6. Mark the send flags on the records we plan to send + // *** 7. Mark the send flags on the records we plan to send // *** for (rr=ResponseRecords; rr; rr=rr->NextResponse) { @@ -4274,7 +5843,7 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con } // *** - // *** 7. If we think other machines are likely to answer these questions, set our packet suppression timer + // *** 8. If we think other machines are likely to answer these questions, set our packet suppression timer // *** if (delayresponse && (!m->SuppressSending || (m->SuppressSending - m->timenow) < (delayresponse + 49) / 50)) { @@ -4305,7 +5874,7 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con } // *** - // *** 8. If query is from a legacy client, or from a new client requesting a unicast reply, then generate a unicast response too + // *** 9. If query is from a legacy client, or from a new client requesting a unicast reply, then generate a unicast response too // *** if (SendLegacyResponse) responseptr = GenerateUnicastResponse(query, end, InterfaceID, LegacyQuery, response, ResponseRecords); @@ -4314,7 +5883,7 @@ exit: m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it // *** - // *** 9. Finally, clear our link chains ready for use next time + // *** 10. Finally, clear our link chains ready for use next time // *** while (ResponseRecords) { @@ -4338,9 +5907,11 @@ exit: { cr->UnansweredQueries++; cr->LastUnansweredTime = m->timenow; +#if ENABLE_MULTI_PACKET_QUERY_SNOOPING if (cr->UnansweredQueries > 1) debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s", cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr)); +#endif SetNextCacheCheckTime(m, cr); } @@ -4348,12 +5919,15 @@ exit: // then mark it to expire in five seconds if we don't get a response by then. if (cr->UnansweredQueries >= MaxUnansweredQueries) { +#if ENABLE_MULTI_PACKET_QUERY_SNOOPING // Only show debugging message if this record was not about to expire anyway if (RRExpireTime(cr) - m->timenow > 4 * mDNSPlatformOneSecond) debugf("ProcessQuery: (Max) UAQ %lu MPQ %lu MPKA %lu mDNS_Reconfirm() for %s", cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr)); +#endif mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); } +#if ENABLE_MULTI_PACKET_QUERY_SNOOPING // Make a guess, based on the multi-packet query / known answer counts, whether we think we // should have seen an answer for this. (We multiply MPQ by 4 and MPKA by 5, to allow for // possible packet loss of up to 20% of the additional KA packets.) @@ -4384,6 +5958,7 @@ exit: remain = kDefaultReconfirmTimeForNoAnswer; mDNS_Reconfirm_internal(m, cr, remain); } +#endif } while (DupQuestions) @@ -4458,15 +6033,16 @@ struct UDPSocket_struct mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port }; -mDNSlocal const DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m, const mDNSIPPort port, const mDNSOpaque16 id, const DNSQuestion *const question) +mDNSlocal DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m, const mDNSIPPort port, const mDNSOpaque16 id, const DNSQuestion *const question) { DNSQuestion *q; for (q = m->Questions; q; q=q->next) - if (mDNSSameIPPort(q->LocalSocket ? q->LocalSocket->port : MulticastDNSPort, port) && - mDNSSameOpaque16(q->TargetQID, id) && - q->qtype == question->qtype && - q->qclass == question->qclass && - q->qnamehash == question->qnamehash && + if (q->LocalSocket && + mDNSSameIPPort (q->LocalSocket->port, port) && + 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); @@ -4478,19 +6054,19 @@ mDNSlocal mDNSBool ExpectingUnicastResponseForRecord(mDNS *const m, const mDNSAd (void)id; (void)srcaddr; for (q = m->Questions; q; q=q->next) - if (ResourceRecordAnswersQuestion(&rr->resrec, q)) + if (!q->DuplicateOf && ResourceRecordAnswersQuestion(&rr->resrec, q)) { if (!mDNSOpaque16IsZero(q->TargetQID)) { debugf("ExpectingUnicastResponseForRecord msg->h.id %d q->TargetQID %d for %s", mDNSVal16(id), mDNSVal16(q->TargetQID), CRDisplayString(m, rr)); if (mDNSSameOpaque16(q->TargetQID, id)) { - if (mDNSSameIPPort(q->LocalSocket ? q->LocalSocket->port : MulticastDNSPort, port)) return(mDNStrue); + if (q->LocalSocket && mDNSSameIPPort(q->LocalSocket->port, port)) return(mDNStrue); // if (mDNSSameAddress(srcaddr, &q->Target)) 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) [q->Target %#a] from %#a: %s", - q->qname.c, DNSTypeName(q->qtype), &q->Target, srcaddr, CRDisplayString(m, rr)); + LogInfo("WARNING: Ignoring suspect uDNS response for %##s (%s) [q->Target %#a:%d] from %#a:%d %s", + q->qname.c, DNSTypeName(q->qtype), &q->Target, mDNSVal16(q->LocalSocket ? q->LocalSocket->port : zeroIPPort), srcaddr, mDNSVal16(port), CRDisplayString(m, rr)); return(mDNSfalse); } } @@ -4503,26 +6079,31 @@ mDNSlocal mDNSBool ExpectingUnicastResponseForRecord(mDNS *const m, const mDNSAd return(mDNSfalse); } -mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, CacheGroup *cg) +// 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. +// In addition, NSEC currently requires less space for in-memory storage than its in-packet representation. +mDNSlocal mDNSu16 GetRDLengthMem(const ResourceRecord *const rr) { - 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) + switch (rr->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; + case kDNSType_SOA: return sizeof(rdataSOA); + case kDNSType_RP: return sizeof(rdataRP); + case kDNSType_PX: return sizeof(rdataPX); + case kDNSType_NSEC:return sizeof(rdataNSEC); + default: return rr->rdlength; } + } + +mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, CacheGroup *cg) + { + CacheRecord *rr = mDNSNULL; + mDNSu16 RDLength = GetRDLengthMem(&m->rec.r.resrec); if (!m->rec.r.resrec.InterfaceID) debugf("CreateNewCacheEntry %s", CRDisplayString(m, &m->rec.r)); //if (RDLength > InlineCacheRDSize) - // LogOperation("Rdata len %4d > InlineCacheRDSize %d %s", RDLength, InlineCacheRDSize, CRDisplayString(m, &m->rec.r)); + // LogInfo("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 @@ -4535,9 +6116,9 @@ mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, C 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) + if (rr->resrec.rdata == (RData*)&rr->smallrdatastorage && 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) + else if (rr->resrec.rdata != (RData*)&rr->smallrdatastorage && 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); @@ -4553,7 +6134,7 @@ mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, C else rr->DelayDelivery = CheckForSoonToExpireRecords(m, rr->resrec.name, rr->resrec.namehash, slot); - CacheRecordAdd(m, rr); // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us + CacheRecordAdd(m, rr); // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us } return(rr); } @@ -4563,9 +6144,11 @@ mDNSlocal void RefreshCacheRecord(mDNS *const m, CacheRecord *rr, mDNSu32 ttl) rr->TimeRcvd = m->timenow; rr->resrec.rroriginalttl = ttl; rr->UnansweredQueries = 0; +#if ENABLE_MULTI_PACKET_QUERY_SNOOPING rr->MPUnansweredQ = 0; rr->MPUnansweredKA = 0; rr->MPExpectingKA = mDNSfalse; +#endif SetNextCacheCheckTime(m, rr); } @@ -4577,7 +6160,7 @@ mDNSexport void GrantCacheExtensions(mDNS *const m, DNSQuestion *q, mDNSu32 leas for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) if (rr->CRActiveQuestion == q) { - //LogOperation("GrantCacheExtensions: new lease %d / %s", lease, CRDisplayString(m, rr)); + //LogInfo("GrantCacheExtensions: new lease %d / %s", lease, CRDisplayString(m, rr)); RefreshCacheRecord(m, rr, lease); } } @@ -4618,9 +6201,12 @@ mDNSlocal mDNSu32 GetEffectiveTTL(const uDNS_LLQType LLQType, mDNSu32 ttl) // T return ttl; } -// NOTE: mDNSCoreReceiveResponse calls mDNS_Deregister_internal which can call a user callback, which may change +// Note: mDNSCoreReceiveResponse 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. +// InterfaceID non-NULL tells us the interface this multicast response was received on +// InterfaceID NULL tells us this was a unicast response +// dstaddr NULL tells us we received this over an outgoing TCP connection we made mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, const DNSMessage *const response, const mDNSu8 *end, const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport, @@ -4643,11 +6229,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, int firstauthority = response->h.numAnswers; int firstadditional = firstauthority + response->h.numAuthorities; int totalrecords = firstadditional + response->h.numAdditionals; - const mDNSu8 *ptr = response->data; - - // Currently used only for display in debugging message - (void)srcport; - (void)dstport; + const mDNSu8 *ptr = response->data; 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", @@ -4657,6 +6239,21 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, response->h.numAuthorities, response->h.numAuthorities == 1 ? "y, " : "ies,", response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s", LLQType); + // According to RFC 2181 + // When a DNS client receives a reply with TC + // set, it should ignore that response, and query again, using a + // mechanism, such as a TCP connection, that will permit larger replies. + // It feels wrong to be throwing away data after the network went to all the trouble of delivering it to us, but + // delivering some records of the RRSet first and then the remainder a couple of milliseconds later was causing + // failures in our Microsoft Active Directory client, which expects to get the entire set of answers at once. + // Can't bind to Active Directory + // In addition, if the client immediately canceled its query after getting the initial partial response, then we'll + // abort our TCP connection, and not complete the operation, and end up with an incomplete RRSet in our cache. + // Next time there's a query for this RRSet we'll see answers in our cache, and assume we have the whole RRSet already, + // and not even do the TCP query. + // Accordingly, if we get a uDNS reply with kDNSFlag0_TC set, we bail out and wait for the TCP response containing the entire RRSet. + if (!InterfaceID && (response->h.flags.b[0] & kDNSFlag0_TC)) return; + if (LLQType == uDNS_LLQ_Ignore) return; // 1. We ignore questions (if any) in mDNS response packets @@ -4671,6 +6268,9 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, // in this response packet are immediately deemed to be invalid. else { + mDNSu8 rcode = (mDNSu8)(response->h.flags.b[1] & kDNSFlag1_RC_Mask); + mDNSBool failure = !(rcode == kDNSFlag1_RC_NoErr || rcode == kDNSFlag1_RC_NXDomain || rcode == kDNSFlag1_RC_NotAuth); + mDNSBool returnEarly = mDNSfalse; // 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 @@ -4679,23 +6279,46 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, // packet number, then we deduce they are old and delete them for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++) { - DNSQuestion q; + DNSQuestion q, *qptr = mDNSNULL; ptr = getQuestion(response, ptr, end, InterfaceID, &q); - if (ptr && (!dstaddr || ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q))) + if (ptr && (!dstaddr || (qptr = ExpectingUnicastResponseForQuestion(m, dstport, 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)) + if (!failure) + { + 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 (q.InterfaceID == rr->resrec.InterfaceID && SameNameRecordAnswersQuestion(&rr->resrec, &q)) + { + debugf("uDNS marking %p %##s (%s) %p %s", q.InterfaceID, q.qname.c, DNSTypeName(q.qtype), + rr->resrec.InterfaceID, 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 - TicksTTL(rr) - 1; + rr->UnansweredQueries = MaxUnansweredQueries; + } + } + else + { + if (qptr) { - //LogMsg("uDNS marking %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 - TicksTTL(rr) - 1; - rr->UnansweredQueries = MaxUnansweredQueries; + LogInfo("Server %p responded with code %d to query %##s (%s)", qptr->qDNSServer, rcode, q.qname.c, DNSTypeName(q.qtype)); + PushDNSServerToEnd(m, qptr); } + returnEarly = mDNStrue; + } } } + if (returnEarly) + { + LogInfo("Ignoring %2d Answer%s %2d Authorit%s %2d Additional%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"); + // not goto exit because we won't have any CacheFlushRecords and we do not want to + // generate negative cache entries (we want to query the next server) + return; + } } for (i = 0; i < totalrecords && ptr && ptr < end; i++) @@ -4727,7 +6350,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, if (!AcceptableResponse) AcceptableResponse = ExpectingUnicastResponseForRecord(m, srcaddr, ResponseSrcLocal, dstport, response->h.id, &m->rec.r); // 1. Check that this packet resource record does not conflict with any of ours - if (mDNSOpaque16IsZero(response->h.id)) + if (mDNSOpaque16IsZero(response->h.id) && m->rec.r.resrec.rrtype != kDNSType_NSEC) { if (m->CurrentRecord) LogMsg("mDNSCoreReceiveResponse ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); @@ -4740,10 +6363,11 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, // 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... { // ... 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 (IdenticalSameNameRecord(&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) @@ -4760,44 +6384,54 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, // 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)); + LogInfo("mDNSCoreReceiveResponse: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r)); + LogInfo("mDNSCoreReceiveResponse: Our Record: %08lX %s", rr-> resrec.rdatahash, ARDisplayString(m, rr)); // 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 (rr->DependentOn) + { + while (rr->DependentOn) rr = rr->DependentOn; + LogInfo("mDNSCoreReceiveResponse: Dep Record: %08lX %s", rr-> resrec.rdatahash, ARDisplayString(m, rr)); + } // If we've just whacked this record's ProbeCount, don't need to do it again - if (rr->ProbeCount <= DefaultProbeCountForTypeUnique) + if (rr->ProbeCount > DefaultProbeCountForTypeUnique) + LogInfo("mDNSCoreReceiveResponse: Already reset to Probing: %s", ARDisplayString(m, rr)); + else if (rr->ProbeCount == DefaultProbeCountForTypeUnique) + LogMsg("mDNSCoreReceiveResponse: Ignoring response received before we even began probing: %s", ARDisplayString(m, rr)); + else { + LogMsg("mDNSCoreReceiveResponse: Received from %#a:%d %s", srcaddr, mDNSVal16(srcport), CRDisplayString(m, &m->rec.r)); // 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)); + LogMsg("mDNSCoreReceiveResponse: Reseting to Probing: %s", ARDisplayString(m, rr)); rr->resrec.RecordType = kDNSRecordTypeUnique; + // We set ProbeCount to one more than the usual value so we know we've already touched this record. + // This is because our single probe for "example-name.local" could yield a response with (say) two A records and + // three AAAA records in it, and we don't want to call RecordProbeFailure() five times and count that as five conflicts. + // This special value is recognised and reset to DefaultProbeCountForTypeUnique in SendQueries(). rr->ProbeCount = DefaultProbeCountForTypeUnique + 1; - InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(kDNSRecordTypeUnique)); + rr->AnnounceCount = InitialAnnounceCount; + 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)); + LogMsg("mDNSCoreReceiveResponse: ProbeCount %d; will rename %s", rr->ProbeCount, ARDisplayString(m, rr)); 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. + // 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)); + LogMsg("mDNSCoreReceiveResponse: Unexpected conflict discarding %s", ARDisplayString(m, rr)); 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)); + LogMsg("mDNSCoreReceiveResponse: Unexpected record type %X %s", rr->resrec.RecordType, ARDisplayString(m, rr)); } } // Else, matching signature, different type or rdata, but not a considered a conflict. @@ -4813,7 +6447,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, if (!AcceptableResponse) { - CacheRecord *cr; + const CacheRecord *cr; for (cr = CacheFlushRecords; cr != (CacheRecord*)1; cr = cr->NextInCFList) { domainname *target = GetRRDomainNameTarget(&cr->resrec); @@ -4831,6 +6465,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m, const mDNSu32 slot = HashSlot(m->rec.r.resrec.name); CacheGroup *cg = CacheGroupForRecord(m, slot, &m->rec.r.resrec); CacheRecord *rr; + // 2a. Check if this packet resource record is already in our cache for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) { @@ -4951,7 +6586,7 @@ exit: { if (!(r2->resrec.rroriginalttl == 240 && r1->resrec.rroriginalttl == 60 && r2->resrec.rrtype == kDNSType_TXT) && mDNSOpaque16IsZero(response->h.id)) - LogOperation("Correcting TTL from %4d to %4d for %s", + LogInfo("Correcting TTL from %4d to %4d for %s", r2->resrec.rroriginalttl, r1->resrec.rroriginalttl, CRDisplayString(m, r2)); r2->resrec.rroriginalttl = r1->resrec.rroriginalttl; } @@ -5012,122 +6647,356 @@ exit: ptr = getQuestion(response, ptr, end, InterfaceID, &q); if (ptr && (!dstaddr || ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q))) { - CacheRecord *rr, *neg = mDNSNULL; - 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 - if (rr->TimeRcvd + TicksTTL(rr) - m->timenow > 0) break; - // 2. If we already had a negative entry, keep track of it so we can resurrect it instead of creating a new one - if (rr->resrec.RecordType == kDNSRecordTypePacketNegative) neg = rr; - } - - if (!rr) + // When we're doing parallel unicast and multicast queries for dot-local names (for supporting Microsoft + // Active Directory sites) we don't want to waste memory making negative cache entries for all the unicast answers. + // Otherwise we just fill up our cache with negative entries for just about every single multicast name we ever look up + // (since the Microsoft Active Directory server is going to assert that pretty much every single multicast name doesn't exist). + // This is not only a waste of memory, but there's also the problem of those negative entries confusing us later -- e.g. we + // suppress sending our mDNS query packet because we think we already have a valid (negative) answer to that query in our cache. + // The one exception is that we *DO* want to make a negative cache entry for "local. SOA", for the (common) case where we're + // *not* on a Microsoft Active Directory network, and there is no authoritative server for "local". Note that this is not + // in conflict with the mDNS spec, because that spec says, "Multicast DNS Zones have no SOA record," so it's okay to cache + // negative answers for "local. SOA" from a uDNS server, because the mDNS spec already says that such records do not exist :-) + if (!InterfaceID && q.qtype != kDNSType_SOA && IsLocalDomain(&q.qname)) + LogInfo("Not generating negative cache entry for %##s (%s)", q.qname.c, DNSTypeName(q.qtype)); + else { - // 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) + CacheRecord *rr, *neg = mDNSNULL; + 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)) { - 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; + // 1. If we got a fresh answer to this query, then don't need to generate a negative entry + if (rr->TimeRcvd + TicksTTL(rr) - m->timenow > 0) break; + // 2. If we already had a negative entry, keep track of it so we can resurrect it instead of creating a new one + if (rr->resrec.RecordType == kDNSRecordTypePacketNegative) neg = rr; + } + + if (!rr) + { + // 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; - // 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) + // Special case for our special Microsoft Active Directory "local SOA" check. + // Some cheap home gateways don't include an SOA record in the authority section when + // they send negative responses, so we don't know how long to cache the negative result. + // Because we don't want to keep hitting the root name servers with our query to find + // if we're on a network using Microsoft Active Directory using "local" as a private + // internal top-level domain, we make sure to cache the negative result for at least one day. + if (q.qtype == kDNSType_SOA && SameDomainName(&q.qname, &localdomain)) negttl = 60 * 60 * 24; + + // 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) { - 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; + const rdataSOA *const soa = (const rdataSOA *)m->rec.r.resrec.rdata->u.data; + mDNSu32 ttl_s = soa->min; + // We use the lesser of the SOA.MIN field and the SOA record's TTL, *except* + // for the SOA record for ".", where the record is reported as non-cacheable + // (TTL zero) for some reason, so in this case we just take the SOA record's TTL as-is + if (ttl_s > m->rec.r.resrec.rroriginalttl && m->rec.r.resrec.name->c[0]) + ttl_s = m->rec.r.resrec.rroriginalttl; + 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 (neg) + { + if (negttl < neg->resrec.rroriginalttl * 2) + negttl = neg->resrec.rroriginalttl * 2; + if (negttl > 3600) + negttl = 3600; + } + + negttl = GetEffectiveTTL(LLQType, negttl); // Add 25% grace period if necessary + + // If we already had a negative cache entry just update it, else make one or more new negative cache entries + if (neg) + { + debugf("Renewing negative TTL from %d to %d %s", neg->resrec.rroriginalttl, negttl, CRDisplayString(m, neg)); + RefreshCacheRecord(m, neg, negttl); + } + else while (1) + { + debugf("mDNSCoreReceiveResponse making negative cache entry TTL %d for %##s (%s)", negttl, name->c, DNSTypeName(q.qtype)); + MakeNegativeCacheRecord(m, &m->rec.r, name, hash, q.qtype, q.qclass, negttl, mDNSInterface_Any); + 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); } - 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 (neg) - { - if (negttl < neg->resrec.rroriginalttl * 2) - negttl = neg->resrec.rroriginalttl * 2; - if (negttl > 3600) - negttl = 3600; - } +mDNSlocal void SPSRecordCallback(mDNS *const m, AuthRecord *const ar, mStatus result) + { + if (result && result != mStatus_MemFree) + LogInfo("SPS Callback %d %s", result, ARDisplayString(m, ar)); - negttl = GetEffectiveTTL(LLQType, negttl); // Add 25% grace period if necessary + if (result == mStatus_NameConflict) + { + LogMsg("Received Conflicting mDNS -- waking %s %.6a %s", + InterfaceNameForID(m, ar->resrec.InterfaceID), &ar->WakeUp.HMAC, ARDisplayString(m, ar)); + SendWakeup(m, ar->resrec.InterfaceID, &ar->WakeUp.IMAC, &ar->WakeUp.password); + } + else if (result == mStatus_MemFree) + { + m->ProxyRecords--; + mDNSPlatformMemFree(ar); + } + } - // If we already had a negative cache entry just update it, else make one or more new negative cache entries - if (neg) - { - LogOperation("Renewing negative TTL from %d to %d %s", neg->resrec.rroriginalttl, negttl, CRDisplayString(m, neg)); - RefreshCacheRecord(m, neg, negttl); - } - else while (1) +mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m, + const DNSMessage *const msg, const mDNSu8 *end, + const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport, + const mDNSInterfaceID InterfaceID) + { + int i; + AuthRecord opt; + mDNSu8 *p = m->omsg.data; + OwnerOptData owner; + mDNSu32 updatelease = 0; + const mDNSu8 *ptr; + + LogSPS("Received Update 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,", + msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y, " : "ies,", + msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s"); + + if (!InterfaceID || !m->SPSSocket || !mDNSSameIPPort(dstport, m->SPSSocket->port)) return; + + if (mDNS_PacketLoggingEnabled) + DumpPacket(m, mStatus_NoError, mDNSfalse, "UDP", srcaddr, srcport, dstaddr, dstport, msg, end); + + ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space + DNSOpt_OwnerData_ID_Space); + if (ptr) + { + ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec); + if (ptr && m->rec.r.resrec.rrtype == kDNSType_OPT) + { + const rdataOPT *o; + const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength]; + for (o = &m->rec.r.resrec.rdata->u.opt[0]; o < e; o++) + { + if (o->opt == kDNSOpt_Lease) updatelease = o->u.updatelease; + else if (o->opt == kDNSOpt_Owner && o->u.owner.vers == 0) owner = o->u.owner; + } + } + m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it + } + + InitializeDNSMessage(&m->omsg.h, msg->h.id, UpdateRespFlags); + + if (!updatelease || !owner.HMAC.l[0]) + { + static int msgs = 0; + if (msgs < 100) + { + msgs++; + LogMsg("Refusing sleep proxy registration from %#a:%d:%s%s", srcaddr, mDNSVal16(srcport), + !updatelease ? " No lease" : "", !owner.HMAC.l[0] ? " No owner" : ""); + } + m->omsg.h.flags.b[1] |= kDNSFlag1_RC_FormErr; + } + else if (m->ProxyRecords + msg->h.mDNS_numUpdates > MAX_PROXY_RECORDS) + { + static int msgs = 0; + if (msgs < 100) + { + msgs++; + LogMsg("Refusing sleep proxy registration from %#a:%d: Too many records %d + %d = %d > %d", srcaddr, mDNSVal16(srcport), + m->ProxyRecords, msg->h.mDNS_numUpdates, m->ProxyRecords + msg->h.mDNS_numUpdates, MAX_PROXY_RECORDS); + } + m->omsg.h.flags.b[1] |= kDNSFlag1_RC_Refused; + } + else + { + LogSPS("Received Update for H-MAC %.6a I-MAC %.6a Password %.6a seq %d", &owner.HMAC, &owner.IMAC, &owner.password, owner.seq); + + if (updatelease > 24 * 60 * 60) + updatelease = 24 * 60 * 60; + + if (updatelease > 0x40000000UL / mDNSPlatformOneSecond) + updatelease = 0x40000000UL / mDNSPlatformOneSecond; + + ptr = LocateAuthorities(msg, end); + for (i = 0; i < msg->h.mDNS_numUpdates && ptr && ptr < end; i++) + { + ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &m->rec); + if (ptr) + { + mDNSu16 RDLengthMem = GetRDLengthMem(&m->rec.r.resrec); + AuthRecord *ar = mDNSPlatformMemAllocate(sizeof(AuthRecord) - sizeof(RDataBody) + RDLengthMem); + if (!ar) { m->omsg.h.flags.b[1] |= kDNSFlag1_RC_Refused; break; } + else { - LogOperation("mDNSCoreReceiveResponse 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); + mDNSu8 RecordType = m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask ? kDNSRecordTypeUnique : kDNSRecordTypeShared; + m->rec.r.resrec.rrclass &= ~kDNSClass_UniqueRRSet; + mDNS_SetupResourceRecord(ar, mDNSNULL, InterfaceID, m->rec.r.resrec.rrtype, m->rec.r.resrec.rroriginalttl, RecordType, SPSRecordCallback, ar); + AssignDomainName(&ar->namestorage, m->rec.r.resrec.name); + ar->resrec.rdlength = GetRDLength(&m->rec.r.resrec, mDNSfalse); + ar->resrec.rdata->MaxRDLength = RDLengthMem; + mDNSPlatformMemCopy(ar->resrec.rdata->u.data, m->rec.r.resrec.rdata->u.data, RDLengthMem); + ar->WakeUp = owner; + if (m->rec.r.resrec.rrtype == kDNSType_PTR) + { + mDNSs32 t = ReverseMapDomainType(m->rec.r.resrec.name); + if (t == mDNSAddrType_IPv4) GetIPv4FromName(&ar->AddressProxy, m->rec.r.resrec.name); + else if (t == mDNSAddrType_IPv6) GetIPv6FromName(&ar->AddressProxy, m->rec.r.resrec.name); + debugf("mDNSCoreReceiveUpdate: PTR %d %d %#a %s", t, ar->AddressProxy.type, &ar->AddressProxy, ARDisplayString(m, ar)); + if (ar->AddressProxy.type) SetSPSProxyListChanged(InterfaceID); + } + ar->TimeRcvd = m->timenow; + ar->TimeExpire = m->timenow + updatelease * mDNSPlatformOneSecond; + if (m->NextScheduledSPS - ar->TimeExpire > 0) + m->NextScheduledSPS = ar->TimeExpire; + mDNS_Register_internal(m, ar); + // For now, since we don't get IPv6 ND or data packets, we don't advertise AAAA records for our SPS clients + if (ar->resrec.rrtype == kDNSType_AAAA) ar->resrec.rroriginalttl = 0; + m->ProxyRecords++; + LogSPS("SPS Registered %4d %X %s", m->ProxyRecords, RecordType, ARDisplayString(m,ar)); } } + m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it + } + + if (m->omsg.h.flags.b[1] & kDNSFlag1_RC_Mask) + { + LogMsg("Refusing sleep proxy registration from %#a:%d: Out of memory", srcaddr, mDNSVal16(srcport)); + ClearProxyRecords(m, &owner, m->DuplicateRecords); + ClearProxyRecords(m, &owner, m->ResourceRecords); + } + else + { + mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL); + opt.resrec.rrclass = NormalMaxDNSMessageData; + opt.resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record + opt.resrec.rdestimate = sizeof(rdataOPT); + opt.resrec.rdata->u.opt[0].opt = kDNSOpt_Lease; + opt.resrec.rdata->u.opt[0].u.updatelease = updatelease; + p = PutResourceRecordTTLWithLimit(&m->omsg, p, &m->omsg.h.numAdditionals, &opt.resrec, opt.resrec.rroriginalttl, m->omsg.data + AbsoluteMaxDNSMessageData); } } - } -mDNSexport void MakeNegativeCacheRecord(mDNS *const m, const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds) - { + if (p) mDNSSendDNSMessage(m, &m->omsg, p, InterfaceID, m->SPSSocket, srcaddr, srcport, mDNSNULL, mDNSNULL); + } + +mDNSlocal void mDNSCoreReceiveUpdateR(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *end, const mDNSInterfaceID InterfaceID) + { + if (InterfaceID) + { + AuthRecord *rr; + mDNSu32 updatelease = 60 * 60; // If SPS fails to indicate lease time, assume one hour + const mDNSu8 *ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space); + if (ptr) + { + ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec); + if (ptr && m->rec.r.resrec.rrtype == kDNSType_OPT) + { + const rdataOPT *o; + const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength]; + for (o = &m->rec.r.resrec.rdata->u.opt[0]; o < e; o++) + if (o->opt == kDNSOpt_Lease) + { + updatelease = o->u.updatelease; + LogSPS("Sleep Proxy granted lease time %4d seconds", updatelease); + } + } + m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it + } + + for (rr = m->ResourceRecords; rr; rr=rr->next) + if (rr->resrec.InterfaceID == InterfaceID || (!rr->resrec.InterfaceID && (rr->ForceMCast || IsLocalDomain(rr->resrec.name)))) + if (mDNSSameOpaque16(rr->updateid, msg->h.id)) + { + rr->updateid = zeroID; + rr->expire = NonZeroTime(m->timenow + updatelease * mDNSPlatformOneSecond); + LogSPS("Sleep Proxy registered record %5d %s", updatelease, ARDisplayString(m,rr)); + } + + } + // If we were waiting to go to sleep, then this SPS registration or wide-area record deletion + // may have been the thing we were waiting for, so schedule another check to see if we can sleep now. + if (m->SleepLimit) m->NextScheduledSPRetry = m->timenow; + } + +mDNSexport void MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr, + const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds, mDNSInterfaceID InterfaceID) + { + if (cr == &m->rec.r && m->rec.r.resrec.RecordType) + { + LogMsg("MakeNegativeCacheRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &m->rec.r)); +#if ForceAlerts + *(long*)0 = 0; +#endif + } + // 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; + cr->resrec.RecordType = kDNSRecordTypePacketNegative; + cr->resrec.InterfaceID = InterfaceID; + cr->resrec.name = name; // Will be updated to point to cg->name when we call CreateNewCacheEntry + cr->resrec.rrtype = rrtype; + cr->resrec.rrclass = rrclass; + cr->resrec.rroriginalttl = ttl_seconds; + cr->resrec.rdlength = 0; + cr->resrec.rdestimate = 0; + cr->resrec.namehash = namehash; + cr->resrec.rdatahash = 0; + cr->resrec.rdata = (RData*)&cr->smallrdatastorage; + cr->resrec.rdata->MaxRDLength = 0; + + cr->NextInKAList = mDNSNULL; + cr->TimeRcvd = m->timenow; + cr->DelayDelivery = 0; + cr->NextRequiredQuery = m->timenow; + cr->LastUsed = m->timenow; + cr->CRActiveQuestion = mDNSNULL; + cr->UnansweredQueries = 0; + cr->LastUnansweredTime = 0; +#if ENABLE_MULTI_PACKET_QUERY_SNOOPING + cr->MPUnansweredQ = 0; + cr->MPLastUnansweredQT = 0; + cr->MPUnansweredKA = 0; + cr->MPExpectingKA = mDNSfalse; +#endif + cr->NextInCFList = mDNSNULL; } mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *const end, @@ -5138,6 +7007,7 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *co DNSMessage *msg = (DNSMessage *)pkt; const mDNSu8 StdQ = kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery; const mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery; + const mDNSu8 UpdQ = kDNSFlag0_QR_Query | kDNSFlag0_OP_Update; const mDNSu8 UpdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update; mDNSu8 QR_OP; mDNSu8 *ptr = mDNSNULL; @@ -5164,6 +7034,10 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *co return; } } +#ifdef _LEGACY_NAT_TRAVERSAL_ + else if (m->SSDPSocket && mDNSSameIPPort(dstport, m->SSDPSocket->port)) { debugf("Ignoring SSDP response from %#a:%d", srcaddr, mDNSVal16(srcport)); return; } +#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); @@ -5187,18 +7061,31 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *co if (!mDNSOpaque16IsZero(msg->h.id)) // uDNS_ReceiveMsg only needs to get real uDNS responses, not "QU" mDNS responses { ifid = mDNSInterface_Any; - if (mDNS_LogLevel >= MDNS_LOG_VERBOSE_DEBUG) - DumpPacket(m, mDNSfalse, TLS ? "TLS" : !dstaddr ? "TCP" : "UDP", srcaddr, srcport, dstaddr, dstport, msg, end); + if (mDNS_PacketLoggingEnabled) + DumpPacket(m, mStatus_NoError, mDNSfalse, TLS ? "TLS" : !dstaddr ? "TCP" : "UDP", srcaddr, srcport, dstaddr, dstport, 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, ifid); else if (QR_OP == StdR) mDNSCoreReceiveResponse(m, msg, end, srcaddr, srcport, dstaddr, dstport, ifid); - else if (QR_OP != UpdR) + else if (QR_OP == UpdQ) mDNSCoreReceiveUpdate (m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID); + else if (QR_OP == UpdR) mDNSCoreReceiveUpdateR (m, msg, end, InterfaceID); + else { - 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); + LogMsg("Unknown DNS packet type %02X%02X from %#-15a:%-5d to %#-15a:%-5d length %d on %p (ignored)", + msg->h.flags.b[0], msg->h.flags.b[1], srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), end-(mDNSu8 *)pkt, InterfaceID); + if (mDNS_LoggingEnabled) + { + int i = 0; + while (iLongLived && !mDNSOpaque16IsZero((Q)->TargetQID)) + mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuestion *const question) { DNSQuestion *q; @@ -5238,7 +7131,7 @@ mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuest SameQTarget(q, question) && // and same unicast/multicast target settings q->qtype == question->qtype && // type, q->qclass == question->qclass && // class, - q->LongLived == question->LongLived && // and long-lived status matches + IsLLQ(q) == IsLLQ(question) && // and long-lived status matches (!q->AuthInfo || question->AuthInfo) && // to avoid deadlock, don't make public query dup of a private one q->qnamehash == question->qnamehash && SameDomainName(&q->qname, &question->qname)) // and name @@ -5285,20 +7178,20 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const questi // question->tcp = mDNSNULL; if (q->LocalSocket) - LogOperation("UpdateQuestionDuplicates transferred LocalSocket pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + debugf("UpdateQuestionDuplicates transferred LocalSocket pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); if (q->nta) { - LogOperation("UpdateQuestionDuplicates transferred nta pointer for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + LogInfo("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"); + if (question->tcp) LogInfo("UpdateQuestionDuplicates did not transfer tcp pointer"); if (question->state == LLQ_Established) { - LogOperation("UpdateQuestionDuplicates transferred LLQ state for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + LogInfo("UpdateQuestionDuplicates transferred LLQ state for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); question->state = 0; // Must zero question->state, or mDNS_StopQuery_internal will clean up and cancel our LLQ from the server } @@ -5331,7 +7224,7 @@ mDNSlocal void LLQNATCallback(mDNS *m, NATTraversalInfo *n) DNSQuestion *q; (void)n; // Unused mDNS_Lock(m); - LogOperation("LLQNATCallback external address:port %.4a:%u", &n->ExternalAddress, mDNSVal16(n->ExternalPort)); + LogInfo("LLQNATCallback external address:port %.4a:%u", &n->ExternalAddress, mDNSVal16(n->ExternalPort)); for (q = m->Questions; q; q=q->next) if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID) && q->LongLived) startLLQHandshake(m, q); // If ExternalPort is zero, will do StartLLQPolling instead @@ -5350,15 +7243,13 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu question->Target.type = mDNSAddrType_None; } - if (!question->Target.type) // No question->Target specified, so clear TargetPort and TargetQID - { - question->TargetPort = zeroIPPort; - question->TargetQID = zeroID; - } + if (!question->Target.type) question->TargetPort = zeroIPPort; // If question->Target specified clear TargetPort question->TargetQID = #ifndef UNICAST_DISABLED - (question->InterfaceID != mDNSInterface_LocalOnly && !question->ForceMCast && !IsLocalDomain(&question->qname)) ? mDNS_NewMessageID(m) : + (question->Target.type || (question->InterfaceID == mDNSInterface_Unicast) || + (question->InterfaceID != mDNSInterface_LocalOnly && !question->ForceMCast && !IsLocalDomain(&question->qname))) + ? mDNS_NewMessageID(m) : #endif // UNICAST_DISABLED zeroID; @@ -5384,19 +7275,17 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu if (*q) { - LogMsg("Error! Tried to add a question %##s (%s) that's already in the active list", - question->qname.c, DNSTypeName(question->qtype)); + LogMsg("Error! Tried to add a question %##s (%s) %p that's already in the active list", + question->qname.c, DNSTypeName(question->qtype), question); return(mStatus_AlreadyRegistered); } *q = question; // If this question is referencing a specific interface, verify it exists - if (question->InterfaceID && question->InterfaceID != mDNSInterface_LocalOnly) + if (question->InterfaceID && question->InterfaceID != mDNSInterface_LocalOnly && question->InterfaceID != mDNSInterface_Unicast) { - NetworkInterfaceInfo *intf; - for (intf = m->HostInterfaces; intf; intf = intf->next) - if (intf->InterfaceID == question->InterfaceID) break; + NetworkInterfaceInfo *intf = FirstInterfaceForID(m, question->InterfaceID); if (!intf) LogMsg("Note: InterfaceID %p for question %##s (%s) not currently found in active interface list", question->InterfaceID, question->qname.c, DNSTypeName(question->qtype)); @@ -5429,6 +7318,11 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu question->LastQTxTime = m->timenow; question->CNAMEReferrals = 0; + // We'll create our question->LocalSocket on demand, if needed. + // We won't need one for duplicate questions, or from questions answered immediately out of the cache. + // We also don't need one for LLQs because (when we're using NAT) we want them all to share a single + // NAT mapping for receiving inbound add/remove events. + question->LocalSocket = mDNSNULL; question->qDNSServer = mDNSNULL; question->unansweredQueries = 0; question->nta = mDNSNULL; @@ -5443,8 +7337,6 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu question->ntries = 0; question->id = zeroOpaque64; - question->LocalSocket = mDNSNULL; - if (question->DuplicateOf) question->AuthInfo = question->DuplicateOf->AuthInfo; for (i=0; iTargetQID)) { - // We don't want to make a separate UDP socket for LLQs because (when we're using NAT) - // they all share a single NAT mapping for receiving inbound add/remove events. - if (!question->DuplicateOf && !question->LongLived) - { - question->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort); - debugf("mDNS_StartQuery_internal: dup %p %##s (%s) port %d", - question->DuplicateOf, question->qname.c, DNSTypeName(question->qtype), question->LocalSocket ? mDNSVal16(question->LocalSocket->port) : -1); - // If we fail to get a new on-demand socket (should only happen cases of the most extreme resource exhaustion) - // then we don't fail the query; we just let it use our pre-canned permanent socket, which is okay (it should - // never happen in normal operation, and even if it does we still have our cryptographically strong transaction ID). - } - question->qDNSServer = GetServerForName(m, &question->qname); ActivateUnicastQuery(m, question, mDNSfalse); @@ -5514,7 +7394,7 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu // 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)); + debugf("CancelGetZoneData %##s (%s)", nta->question.qname.c, DNSTypeName(nta->question.qtype)); mDNS_StopQuery_internal(m, &nta->question); mDNSPlatformMemFree(nta); } @@ -5526,7 +7406,7 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que CacheRecord *rr; DNSQuestion **qp = &m->Questions; - //LogOperation("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); + //LogInfo("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); if (question->InterfaceID == mDNSInterface_LocalOnly) qp = &m->LocalOnlyQuestions; while (*qp && *qp != question) qp=&(*qp)->next; @@ -5608,7 +7488,7 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que LogMsg("mDNS_StopQuery ERROR LLQNAT.clientContext NULL"); else { - LogOperation("Stopping LLQNAT"); + LogInfo("Stopping LLQNAT"); mDNS_StopNATOperation_internal(m, &m->LLQNAT); m->LLQNAT.clientContext = mDNSNULL; // Means LLQ NAT Traversal not running } @@ -5671,10 +7551,10 @@ mDNSexport mStatus mDNS_StopQueryWithRemoves(mDNS *const m, DNSQuestion *const q status = mDNS_StopQuery_internal(m, question); if (status == mStatus_NoError && !qq) { - CacheRecord *rr; + const 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)); + LogInfo("Generating terminal removes for %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) if (rr->resrec.RecordType != kDNSRecordTypePacketNegative && SameNameRecordAnswersQuestion(&rr->resrec, question)) { @@ -5710,7 +7590,7 @@ mDNSexport mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr return(status); } -mDNSexport mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question, +mDNSlocal mStatus mDNS_StartBrowse_internal(mDNS *const m, DNSQuestion *const question, const domainname *const srv, const domainname *const domain, const mDNSInterfaceID InterfaceID, mDNSBool ForceMCast, mDNSQuestionCallback *Callback, void *Context) { @@ -5734,7 +7614,18 @@ mDNSexport mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question, question->LastQTime = m->timenow - question->ThisQInterval; } #endif // UNICAST_DISABLED - return(mDNS_StartQuery(m, question)); + return(mDNS_StartQuery_internal(m, question)); + } + +mDNSexport mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question, + const domainname *const srv, const domainname *const domain, + const mDNSInterfaceID InterfaceID, mDNSBool ForceMCast, mDNSQuestionCallback *Callback, void *Context) + { + mStatus status; + mDNS_Lock(m); + status = mDNS_StartBrowse_internal(m, question, srv, domain, InterfaceID, ForceMCast, Callback, Context); + mDNS_Unlock(m); + return(status); } mDNSlocal mDNSBool MachineHasActiveIPv6(mDNS *const m) @@ -5834,7 +7725,7 @@ mDNSlocal void FoundServiceInfoTXT(mDNS *const m, DNSQuestion *question, const R 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)); + //LogInfo("FoundServiceInfo %d %s", AddRecord, RRDisplayString(m, answer)); if (!AddRecord) return; if (answer->rrtype == kDNSType_A) @@ -6054,7 +7945,7 @@ mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newt // even though there's no actual semantic change, so the mDNSPlatformMemSame() check doesn't help us. // To work around this, we simply unilaterally limit all legacy _ichat-type updates to a single announcement. if (SameDomainLabel(type.c, (mDNSu8*)"\x6_ichat")) rr->AnnounceCount = 1; - InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType)); + InitializeLastAPTime(m, rr); while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr); if (!rr->UpdateBlocked && rr->UpdateCredits) rr->UpdateCredits--; if (!rr->NextUpdateCredit) rr->NextUpdateCredit = NonZeroTime(m->timenow + kUpdateCreditRefreshInterval); @@ -6075,7 +7966,7 @@ mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newt return(mStatus_NoError); } -// NOTE: mDNS_Deregister calls mDNS_Deregister_internal which can call a user callback, which may change +// Note: mDNS_Deregister 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 mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr) @@ -6197,21 +8088,24 @@ 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 (SameDomainNameCS(&m->MulticastHostname, &newmname)) { LogMsg("mDNS_SetFQDN - hostname unchanged"); return; } mDNS_Lock(m); - 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); - - // 2. Start advertising our address records using the new name - for (intf = m->HostInterfaces; intf; intf = intf->next) - if (intf->Advertise) AdvertiseInterface(m, intf); + if (SameDomainNameCS(&m->MulticastHostname, &newmname)) debugf("mDNS_SetFQDN - hostname unchanged"); + else + { + 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); + + // 2. Start advertising our address records using the new name + for (intf = m->HostInterfaces; intf; intf = intf->next) + if (intf->Advertise) AdvertiseInterface(m, intf); + } - // 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 + // 3. Make sure that any AutoTarget SRV records (and the like) get updated 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); @@ -6246,9 +8140,9 @@ mDNSlocal void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatu m->MainCallback(m, mStatus_NameConflict); // 2. If the client callback didn't do it, add (or increment) an index ourselves - // This needs to be case-insensitive compare, because we need to know that the name has been changed so as to + // 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)) + if (SameDomainLabel(m->hostlabel.c, oldlabel.c)) IncrementLabelSuffix(&m->hostlabel, mDNSfalse); // 3. Generate the FQDNs from the hostlabel, @@ -6263,7 +8157,7 @@ mDNSlocal void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatu debugf("mDNS_HostNameCallback: MemFree (ignored)"); } else - LogMsg("mDNS_HostNameCallback: Unknown error %ld for registration of record %s", result, rr->resrec.name->c); + LogMsg("mDNS_HostNameCallback: Unknown error %d for registration of record %s", result, rr->resrec.name->c); } mDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *active) @@ -6279,10 +8173,80 @@ mDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *act } } -mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping) +mDNSlocal void RestartRecordGetZoneData(mDNS * const m) { AuthRecord *rr; ServiceRecordSet *s; + + for (rr = m->ResourceRecords; rr; rr=rr->next) + if (AuthRecord_uDNS(rr)) + { + debugf("RestartRecordGetZoneData: StartGetZoneData for %##s", rr->resrec.name->c); + if (rr->nta) CancelGetZoneData(m, rr->nta); + rr->nta = StartGetZoneData(m, rr->resrec.name, ZoneServiceUpdate, RecordRegistrationGotZoneData, rr); + } + + for (s = m->ServiceRegistrations; s; s = s->uDNS_next) + { + debugf("RestartRecordGetZoneData: StartGetZoneData for %##s", s->RR_SRV.resrec.name->c); + if (s->srs_nta) CancelGetZoneData(m, s->srs_nta); + s->srs_nta = StartGetZoneData(m, s->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, s); + } + } + +mDNSlocal void InitializeNetWakeState(mDNS *const m, NetworkInterfaceInfo *set) + { + int i; + set->NetWakeBrowse.ThisQInterval = -1; + for (i=0; i<3; i++) + { + set->NetWakeResolve[i].ThisQInterval = -1; + set->SPSAddr[i].type = mDNSAddrType_None; + } + set->NextSPSAttempt = -1; + set->NextSPSAttemptTime = m->timenow; + } + +mDNSexport void mDNS_ActivateNetWake_internal(mDNS *const m, NetworkInterfaceInfo *set) + { + NetworkInterfaceInfo *p = m->HostInterfaces; + while (p && p != set) p=p->next; + if (!p) { LogMsg("mDNS_ActivateNetWake_internal: NetworkInterfaceInfo %p not found in active list", set); return; } + + if (set->InterfaceActive) + { + LogSPS("ActivateNetWake for %s (%#a)", set->ifname, &set->ip); + mDNS_StartBrowse_internal(m, &set->NetWakeBrowse, &SleepProxyServiceType, &localdomain, set->InterfaceID, mDNSfalse, m->SPSBrowseCallback, set); + } + } + +mDNSexport void mDNS_DeactivateNetWake_internal(mDNS *const m, NetworkInterfaceInfo *set) + { + NetworkInterfaceInfo *p = m->HostInterfaces; + while (p && p != set) p=p->next; + if (!p) { LogMsg("mDNS_DeactivateNetWake_internal: NetworkInterfaceInfo %p not found in active list", set); return; } + + if (set->NetWakeBrowse.ThisQInterval >= 0) + { + int i; + LogSPS("DeactivateNetWake for %s (%#a)", set->ifname, &set->ip); + + // Stop our browse and resolve operations + mDNS_StopQuery_internal(m, &set->NetWakeBrowse); + for (i=0; i<3; i++) if (set->NetWakeResolve[i].ThisQInterval >= 0) mDNS_StopQuery_internal(m, &set->NetWakeResolve[i]); + + // Make special call to the browse callback to let it know it can to remove all records for this interface + if (m->SPSBrowseCallback) m->SPSBrowseCallback(m, &set->NetWakeBrowse, mDNSNULL, mDNSfalse); + + // Reset our variables back to initial state, so we're ready for when NetWake is turned back on + // (includes resetting NetWakeBrowse.ThisQInterval back to -1) + InitializeNetWakeState(m, set); + } + } + +mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping) + { + AuthRecord *rr; mDNSBool FirstOfType = mDNStrue; NetworkInterfaceInfo **p = &m->HostInterfaces; @@ -6298,6 +8262,8 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s set->InterfaceActive = mDNStrue; set->IPv4Available = (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx); set->IPv6Available = (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx); + + InitializeNetWakeState(m, set); // Scan list to see if this InterfaceID is already represented while (*p) @@ -6327,11 +8293,13 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s if (set->Advertise) AdvertiseInterface(m, set); - LogOperation("mDNS_RegisterInterface: InterfaceID %p %s (%#a) %s", set->InterfaceID, set->ifname, &set->ip, + LogInfo("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"); + if (set->NetWake) mDNS_ActivateNetWake_internal(m, set); + // 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, @@ -6342,16 +8310,25 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s // 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; + mDNSs32 newSS = 0; // Use a small amount of randomness: // In the case of a network administrator turning on an Ethernet hub so that all the // connected machines establish link at exactly the same time, we don't want them all // to go and hit the network with identical queries at exactly the same moment. - if (!m->SuppressSending) m->SuppressSending = m->timenow + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval); + newSS = m->timenow + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval); +#if APPLE_OSX_mDNSResponder + // We set this to at least 2 seconds, because the MacOSX platform layer typically gets lots + // of network change notifications in a row, and we don't know when we're done getting notified. + // Note that this will not be set if the interface doesn't do multicast (set->McastTxRx). + newSS += mDNSPlatformOneSecond * 2; +#endif + if (!m->SuppressSending || newSS - m->SuppressSending < 0) m->SuppressSending = newSS; if (flapping) { - LogMsg("Note: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect", set->ifname, &set->ip); + LogMsg("Note: RegisterInterface: 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); @@ -6364,7 +8341,7 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s 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 expired for %##s (%s); okay to delay questions a little", q->qname.c, DNSTypeName(q->qtype)); + if (dodelay) LogInfo("No cache records expired for %##s (%s); okay to delay questions a little", q->qname.c, DNSTypeName(q->qtype)); if (!q->ThisQInterval || q->ThisQInterval > initial) { @@ -6385,30 +8362,17 @@ 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); if (rr->AnnounceCount < announce) rr->AnnounceCount = announce; - InitializeLastAPTime(m, rr, DefaultAPIntervalForRecordType(rr->resrec.RecordType)); + InitializeLastAPTime(m, rr); } } - for (rr = m->ResourceRecords; rr; rr=rr->next) - if (AuthRecord_uDNS(rr)) - { - LogOperation("mDNS_RegisterInterface: StartGetZoneData for %##s", rr->resrec.name->c); - if (rr->nta) CancelGetZoneData(m, rr->nta); - rr->nta = StartGetZoneData(m, rr->resrec.name, ZoneServiceUpdate, RecordRegistrationGotZoneData, rr); - } - - for (s = m->ServiceRegistrations; s; s = s->uDNS_next) - { - LogOperation("mDNS_RegisterInterface: StartGetZoneData for %##s", s->RR_SRV.resrec.name->c); - if (s->nta) CancelGetZoneData(m, s->nta); - s->nta = StartGetZoneData(m, s->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, s); - } + RestartRecordGetZoneData(m); mDNS_Unlock(m); return(mStatus_NoError); } -// NOTE: mDNS_DeregisterInterface calls mDNS_Deregister_internal which can call a user callback, which may change +// Note: mDNS_DeregisterInterface calls mDNS_Deregister_internal which can call a user callback, which may change // the record list and/or question list. // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this. mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping) @@ -6427,6 +8391,8 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se while (*p && *p != set) p=&(*p)->next; if (!*p) { debugf("mDNS_DeregisterInterface: NetworkInterfaceInfo not found in list"); mDNS_Unlock(m); return; } + mDNS_DeactivateNetWake_internal(m, set); + // Unlink this record from our list *p = (*p)->next; set->next = mDNSNULL; @@ -6441,16 +8407,17 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se } else { - NetworkInterfaceInfo *intf; - for (intf = m->HostInterfaces; intf; intf = intf->next) - if (intf->InterfaceID == set->InterfaceID) - break; + NetworkInterfaceInfo *intf = FirstInterfaceForID(m, set->InterfaceID); if (intf) { - LogOperation("mDNS_DeregisterInterface: Another representative of InterfaceID %p %s (%#a) exists;" + LogInfo("mDNS_DeregisterInterface: Another representative of InterfaceID %p %s (%#a) exists;" " making it active", set->InterfaceID, set->ifname, &set->ip); + if (intf->InterfaceActive) + LogMsg("mDNS_DeregisterInterface: ERROR intf->InterfaceActive already set for %s (%#a)", set->ifname, &set->ip); intf->InterfaceActive = mDNStrue; UpdateInterfaceProtocols(m, intf); + + if (intf->NetWake) mDNS_ActivateNetWake_internal(m, intf); // See if another representative *of the same type* exists. If not, we mave have gone from // dual-stack to v6-only (or v4-only) so we need to reconfirm which records are still valid. @@ -6467,11 +8434,11 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se DNSQuestion *q; DNSServer *s; - LogOperation("mDNS_DeregisterInterface: Last representative of InterfaceID %p %s (%#a) deregistered;" + LogInfo("mDNS_DeregisterInterface: Last representative of InterfaceID %p %s (%#a) deregistered;" " marking questions etc. dormant", set->InterfaceID, set->ifname, &set->ip); if (flapping) - LogMsg("Note: Frequent transitions for interface %s (%#a); network traffic reduction measures in effect", + LogMsg("Note: DeregisterInterface: 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 @@ -6546,7 +8513,7 @@ mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus resu if (result == mStatus_NoError) msg = "Name Registered"; else if (result == mStatus_NameConflict) msg = "Name Conflict"; else if (result == mStatus_MemFree) msg = "Memory Free"; - debugf("ServiceCallback: %##s (%s) %s (%ld)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result); + debugf("ServiceCallback: %##s (%s) %s (%d)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result); } #endif @@ -6563,15 +8530,26 @@ mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus resu if (result == mStatus_MemFree) { - // If the PTR record or any of the subtype PTR records are still in the process of deregistering, - // don't pass on the NameConflict/MemFree message until every record is finished cleaning up. + // If the SRV/TXT/PTR records, or the _services._dns-sd._udp record, or any of the subtype PTR records, + // are still in the process of deregistering, don't pass on the NameConflict/MemFree message until + // every record is finished cleaning up. mDNSu32 i; + if (sr->RR_SRV.resrec.RecordType != kDNSRecordTypeUnregistered) return; + if (sr->RR_TXT.resrec.RecordType != kDNSRecordTypeUnregistered) return; if (sr->RR_PTR.resrec.RecordType != kDNSRecordTypeUnregistered) return; + if (sr->RR_ADV.resrec.RecordType != kDNSRecordTypeUnregistered) return; for (i=0; iNumSubTypes; i++) if (sr->SubTypes[i].resrec.RecordType != kDNSRecordTypeUnregistered) return; // If this ServiceRecordSet was forcibly deregistered, and now its memory is ready for reuse, // then we can now report the NameConflict to the client if (sr->Conflict) result = mStatus_NameConflict; + + if (sr->srs_nta) + { + LogMsg("ServiceCallback ERROR Got mStatus_MemFree with srs_nta still set for %s", ARDisplayString(m, &sr->RR_SRV)); + CancelGetZoneData(m, sr->srs_nta); + sr->srs_nta = mDNSNULL; + } } // CAUTION: MUST NOT do anything more with sr after calling sr->Callback(), because the client's callback @@ -6587,6 +8565,7 @@ mDNSlocal void NSSCallback(mDNS *const m, AuthRecord *const rr, mStatus result) sr->ServiceCallback(m, sr, result); } +#if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST mDNSlocal mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs) { mDNSu32 i; @@ -6613,20 +8592,19 @@ mDNSlocal mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs) if (!AuthInfo || !AuthInfo->AutoTunnel) srs->RR_SRV.AutoTarget = Target_AutoHostAndNATMAP; } - if (!GetServiceTarget(m, srs)) + if (!GetServiceTarget(m, &srs->RR_SRV)) { // defer registration until we've got a target - LogOperation("uDNS_RegisterService - no target for %##s", srs->RR_SRV.resrec.name->c); - srs->state = regState_NoTarget; - srs->nta = mDNSNULL; + LogInfo("uDNS_RegisterService - no target for %##s", srs->RR_SRV.resrec.name->c); + srs->state = regState_NoTarget; return mStatus_NoError; } ActivateUnicastRegistration(m, &srs->RR_SRV); srs->state = regState_FetchingZoneData; - srs->nta = mDNSNULL; return mStatus_NoError; } +#endif // Note: // Name is first label of domain name (any dots in the name are actual dots, not label separators) @@ -6655,6 +8633,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr, sr->SRSUpdateServer = zeroAddr; sr->SRSUpdatePort = zeroIPPort; mDNSPlatformMemZero(&sr->NATinfo, sizeof(sr->NATinfo)); + sr->NATinfo.IntPort = port; // Record originally-requested port sr->ClientCallbackDeferred = 0; sr->DeferredStatus = 0; sr->SRVUpdateDeferred = 0; @@ -6739,7 +8718,9 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr, } sr->RR_TXT.DependentOn = &sr->RR_SRV; -#ifndef UNICAST_DISABLED + sr->srs_nta = mDNSNULL; + +#if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST // 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.namestorage))) @@ -6757,6 +8738,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr, return(status); } #endif + mDNS_Lock(m); err = mDNS_Register_internal(m, &sr->RR_SRV); if (!err) err = mDNS_Register_internal(m, &sr->RR_TXT); @@ -6780,7 +8762,7 @@ 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)); + LogInfo("DummyCallback %d %s", result, ARDisplayString(m, rr)); } mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, @@ -6851,7 +8833,7 @@ mDNSexport mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordSet *const sr, const domainlabel *newname) { - // NOTE: Don't need to use mDNS_Lock(m) here, because this code is just using public routines + // Note: Don't need to use mDNS_Lock(m) here, because this code is just using public routines // mDNS_RegisterService() and mDNS_AddRecordToService(), which do the right locking internally. domainlabel name1, name2; domainname type, domain; @@ -6868,8 +8850,8 @@ mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordS } 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); + debugf("%##s service renamed from \"%#s\" to \"%#s\"", type.c, name1.c, newname->c); + else debugf("%##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, @@ -6889,7 +8871,7 @@ mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordS return(err); } -// NOTE: mDNS_DeregisterService calls mDNS_Deregister_internal which can call a user callback, +// Note: mDNS_DeregisterService 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 mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr) @@ -6897,7 +8879,7 @@ mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr) // If port number is zero, that means this was actually registered using mDNS_RegisterNoSuchService() if (mDNSIPPortIsZero(sr->RR_SRV.resrec.rdata->u.srv.port)) return(mDNS_DeregisterNoSuchService(m, &sr->RR_SRV)); -#ifndef UNICAST_DISABLED +#if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name))) { mStatus status; @@ -7005,7 +8987,7 @@ mDNSexport mDNSOpaque16 mDNS_NewMessageID(mDNS * const m) AuthRecord *r; DNSQuestion *q; id = mDNSOpaque16fromIntVal(1 + mDNSRandom(0xFFFE)); - for (r = m->ResourceRecords; r; r=r->next) if (mDNSSameOpaque16(id, r->id )) continue; + for (r = m->ResourceRecords; r; r=r->next) if (mDNSSameOpaque16(id, r->updateid )) continue; for (q = m->Questions; q; q=q->next) if (mDNSSameOpaque16(id, q->TargetQID)) continue; break; } @@ -7013,6 +8995,267 @@ mDNSexport mDNSOpaque16 mDNS_NewMessageID(mDNS * const m) return id; } +// *************************************************************************** +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - +#pragma mark - Sleep Proxy Server +#endif + +mDNSlocal void RestartProbing(mDNS *const m, AuthRecord *const rr) + { + // We reset ProbeCount, so we'll suppress our own answers for a while, to avoid generating ARP conflicts with a waking machine. + // If the machine does wake properly then we'll discard our records when we see the first new mDNS probe from that machine. + // If it does not wake (perhaps we just picked up a stray delayed packet sent before it went to sleep) + // then we'll transition out of probing state and start answering ARPs again. + rr->resrec.RecordType = kDNSRecordTypeUnique; + rr->ProbeCount = DefaultProbeCountForTypeUnique; + rr->AnnounceCount = InitialAnnounceCount; + InitializeLastAPTime(m, rr); + } + +mDNSexport void mDNSCoreReceiveRawPacket(mDNS *const m, const mDNSu8 *const p, const mDNSu8 *const end, const mDNSInterfaceID InterfaceID) + { + static const mDNSOpaque16 Ethertype_IP = { { 0x08, 0x00 } }; + static const mDNSOpaque32 ARP_EthIP_h0 = { { 0x08, 0x06, 0x00, 0x01 } }; // Ethertype (ARP = 0x0806), Hardware address space (Ethernet = 1) + static const mDNSOpaque32 ARP_EthIP_h1 = { { 0x08, 0x00, 0x06, 0x04 } }; // Protocol address space (IP = 0x0800), hlen, plen + static const mDNSOpaque16 ARP_op_request = { { 0, 1 } }; + const EthernetHeader *const eth = (const EthernetHeader *)p; + const ARP_EthIP *const arp = (const ARP_EthIP *)(eth+1); + const IPv4Header *const v4 = (const IPv4Header *)(eth+1); + const IPv6Header *const v6 = (const IPv6Header *)(eth+1); + if (end >= p+42 && *(mDNSu32*)(p+12) == ARP_EthIP_h0.NotAnInteger && *(mDNSu32*)(p+16) == ARP_EthIP_h1.NotAnInteger) + { + AuthRecord *rr; + NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID); + if (!intf) return; + + debugf("Got ARP from %.4a/%.6a for %.4a", &arp->spa, &arp->sha, &arp->tpa); + + mDNS_Lock(m); + + // Pass 1: + // Process ARP Requests and Probes (but not Announcements), and generate an ARP Reply if necessary. + // We also process and answer ARPs from our own kernel (no special treatment for localhost). + // We ignore ARP Announcements here -- Announcements are not questions, they're assertions, so we don't need to answer them. + // The only time we might need to respond to an ARP Announcement is if it's a conflict -- and we check for that in Pass 2 below. + if (mDNSSameOpaque16(arp->op, ARP_op_request) && !mDNSSameIPv4Address(arp->spa, arp->tpa)) + for (rr = m->ResourceRecords; rr; rr=rr->next) + if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, arp->tpa)) + { + static const char msg1[] = "ARP Req from owner -- re-probing"; + static const char msg2[] = "Ignoring ARP Request from "; + static const char msg3[] = "Creating Local ARP Cache entry "; + static const char msg4[] = "Answering ARP Request from "; + const char *const msg = mDNSSameEthAddress(&arp->sha, &rr->WakeUp.IMAC) ? msg1 : + (rr->AnnounceCount == InitialAnnounceCount) ? msg2 : + mDNSSameEthAddress(&arp->sha, &intf->MAC) ? msg3 : msg4; + LogSPS("%-7s %s %.6a %.4a for %.4a -- H-MAC %.6a I-MAC %.6a %s", + InterfaceNameForID(m, InterfaceID), msg, &arp->sha, &arp->spa, &arp->tpa, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr)); + if (msg == msg1) RestartProbing(m, rr); + else if (msg == msg3) mDNSPlatformSetLocalARP(&arp->tpa, &rr->WakeUp.IMAC, InterfaceID); + else if (msg == msg4) SendARP(m, 2, rr, arp->tpa.b, arp->sha.b, arp->spa.b, arp->sha.b); + } + + // Pass 2: + // For all types of ARP packet we check the Sender IP address to make sure it doesn't conflict with any AddressProxy record we're holding. + // (Strictly speaking we're only checking Announcement/Request/Reply packets, since ARP Probes have zero Sender IP address, + // so by definition (and by design) they can never conflict with any real (i.e. non-zero) IP address). + // We ignore ARPs we sent ourselves (Sender MAC address is our MAC address) because our own proxy ARPs do not constitute a conflict that we need to handle. + // If we see an apparently conflicting ARP, we check the sender hardware address: + // If the sender hardware address is the original owner this is benign, so we just suppress our own proxy answering for a while longer. + // If the sender hardware address is *not* the original owner, then this is a conflict, and we need to wake the sleeping machine to handle it. + if (mDNSSameEthAddress(&arp->sha, &intf->MAC)) + debugf("ARP from self for %.4a", &arp->tpa); + else + { + if (!mDNSSameIPv4Address(arp->spa, zerov4Addr)) + for (rr = m->ResourceRecords; rr; rr=rr->next) + if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, arp->spa)) + { + RestartProbing(m, rr); + if (mDNSSameEthAddress(&arp->sha, &rr->WakeUp.IMAC)) + LogSPS("%-7s ARP %s from owner %.6a %.4a for %-15.4a -- re-starting probing for %s", + InterfaceNameForID(m, InterfaceID), + mDNSSameIPv4Address(arp->spa, arp->tpa) ? "Announcement" : mDNSSameOpaque16(arp->op, ARP_op_request) ? "Request " : "Response ", + &arp->sha, &arp->spa, &arp->tpa, ARDisplayString(m, rr)); + else + { + LogMsg("%-7s Conflicting ARP from %.6a %.4a for %.4a -- waking H-MAC %.6a I-MAC %.6a %s", + InterfaceNameForID(m, InterfaceID), &arp->sha, &arp->spa, &arp->tpa, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr)); + SendWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.IMAC, &rr->WakeUp.password); + } + } + } + + mDNS_Unlock(m); + } + else if (end >= p+34 && mDNSSameOpaque16(eth->ethertype, Ethertype_IP) && (v4->flagsfrags.b[0] & 0x1F) == 0 && v4->flagsfrags.b[1] == 0) + { + const mDNSu8 *const trans = p + 14 + (v4->vlen & 0xF) * 4; + const mDNSu8 *const required = trans + (v4->protocol == 1 ? 4 : v4->protocol == 6 ? 20 : v4->protocol == 17 ? 8 : 0); + debugf("Got IPv4 from %.4a to %.4a", &v4->src, &v4->dst); + if (end >= required) + { + #define SSH_AsNumber 22 + #define ARD_AsNumber 3283 + #define IPSEC_AsNumber 4500 + static const mDNSIPPort SSH = { { SSH_AsNumber >> 8, SSH_AsNumber & 0xFF } }; + static const mDNSIPPort ARD = { { ARD_AsNumber >> 8, ARD_AsNumber & 0xFF } }; + static const mDNSIPPort IPSEC = { { IPSEC_AsNumber >> 8, IPSEC_AsNumber & 0xFF } }; + + mDNSBool wake = mDNSfalse; + mDNSIPPort port = zeroIPPort; + + switch (v4->protocol) + { + #define XX wake ? "Received" : "Ignoring", end-p + case 1: LogSPS("%s %d-byte ICMP from %.4a to %.4a", XX, &v4->src, &v4->dst); + break; + + case 6: { + const TCPHeader *const tcp = (const TCPHeader *)trans; + port = tcp->dst; + + // Plan to wake if + // (a) RST is not set, AND + // (b) packet is SYN, SYN+FIN, or plain data packet (no SYN or FIN). We won't wake for FIN alone. + wake = (!(tcp->flags & 4) && (tcp->flags & 3) != 1); + + // For now, to reduce spurious wakeups, we wake only for TCP SYN, + // except for ssh connections, where we'll wake for plain data packets too + if (!mDNSSameIPPort(port, SSH) && !(tcp->flags & 2)) wake = mDNSfalse; + + LogSPS("%s %d-byte TCP from %.4a:%d to %.4a:%d%s%s%s", XX, + &v4->src, mDNSVal16(tcp->src), &v4->dst, mDNSVal16(port), + (tcp->flags & 2) ? " SYN" : "", + (tcp->flags & 1) ? " FIN" : "", + (tcp->flags & 4) ? " RST" : ""); + } + break; + + case 17: { + const UDPHeader *const udp = (const UDPHeader *)trans; + mDNSu16 len = (mDNSu16)((mDNSu16)trans[4] << 8 | trans[5]); + port = udp->dst; + wake = mDNStrue; + + // For Back to My Mac UDP port 4500 (IPSEC) packets, we specially ignore NAT keepalive packets + if (mDNSSameIPPort(port, IPSEC)) wake = (len != 9 || end < trans + 9 || trans[8] != 0xFF); + + // For now, because we haven't yet worked out a clean elegant way to do this, we just special-case the + // Apple Remote Desktop port number -- we ignore all packets to UDP 3283 (the "Net Assistant" port), + // except for Apple Remote Desktop's explicit manual wakeup packet, which looks like this: + // UDP header (8 bytes) 13 88 00 6a 41 4e 41 20 (8 bytes) ffffffffffff (6 bytes) 16xMAC (96 bytes) = 118 bytes total + if (mDNSSameIPPort(port, ARD)) wake = (len >= 118 && end >= trans+10 && trans[8] == 0x13 && trans[9] == 0x88); + + LogSPS("%s %d-byte UDP from %.4a:%d to %.4a:%d", XX, &v4->src, mDNSVal16(udp->src), &v4->dst, mDNSVal16(port)); + } + break; + + default: LogSPS("%s %d-byte IP packet unknown protocol %d from %.4a to %.4a", XX, v4->protocol, &v4->src, &v4->dst); + break; + } + + if (wake) + { + AuthRecord *rr, *r2; + + mDNS_Lock(m); + for (rr = m->ResourceRecords; rr; rr=rr->next) + if (rr->resrec.InterfaceID == InterfaceID && + rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, v4->dst)) + { + const mDNSu8 *const tp = (v4->protocol == 6) ? (mDNSu8 *)"\x4_tcp" : (mDNSu8 *)"\x4_udp"; + for (r2 = m->ResourceRecords; r2; r2=r2->next) + if (r2->resrec.InterfaceID == InterfaceID && mDNSSameEthAddress(&r2->WakeUp.HMAC, &rr->WakeUp.HMAC) && + r2->resrec.rrtype == kDNSType_SRV && mDNSSameIPPort(r2->resrec.rdata->u.srv.port, port) && + SameDomainLabel(SkipLeadingLabels(r2->resrec.name, 2)->c, tp)) + break; + if (!r2 && mDNSSameIPPort(port, IPSEC)) r2 = rr; // So that we wake for BTMM IPSEC packets, even without a matching SRV record + if (r2) + { + rr->AnnounceCount = 0; + LogMsg("Waking host at %s %.4a H-MAC %.6a I-MAC %.6a for %s", + InterfaceNameForID(m, rr->resrec.InterfaceID), &v4->dst, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, r2)); + SendWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.IMAC, &rr->WakeUp.password); + } + else + LogSPS("Sleeping host at %s %.4a %.6a has no service on %#s %d", + InterfaceNameForID(m, rr->resrec.InterfaceID), &v4->dst, &rr->WakeUp.HMAC, tp, mDNSVal16(port)); + } + mDNS_Unlock(m); + } + } + } + else if (end >= p+34 && mDNSSameOpaque16(eth->ethertype, Ethertype_IP) && (v4->flagsfrags.b[0] & 0x1F) == 0 && v4->flagsfrags.b[1] == 0) + { + debugf("Got IPv6 from %.16a to %.16a", &v4->src, &v6->dst); + (void)v6; + } + } + +mDNSlocal void ConstructSleepProxyServerName(mDNS *const m, domainlabel *name) + { + name->c[0] = mDNS_snprintf((char*)name->c+1, 62, "%d-%d-%d-%d %#s", + m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower, &m->nicelabel); + } + +mDNSlocal void SleepProxyServerCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus result) + { + if (result == mStatus_NameConflict) + mDNS_RenameAndReregisterService(m, srs, mDNSNULL); + else if (result == mStatus_MemFree) + { + if (m->SleepState) + m->SPSState = 3; + else + { + m->SPSState = (m->SPSSocket != mDNSNULL); + if (m->SPSState) + { + domainlabel name; + ConstructSleepProxyServerName(m, &name); + mDNS_RegisterService(m, srs, + &name, &SleepProxyServiceType, &localdomain, + mDNSNULL, m->SPSSocket->port, // Host, port + (mDNSu8 *)"", 1, // TXT data, length + mDNSNULL, 0, // Subtypes (none) + mDNSInterface_Any, // Interface ID + SleepProxyServerCallback, mDNSNULL); // Callback and context + } + LogSPS("Sleep Proxy Server %#s %s", srs->RR_SRV.resrec.name->c, m->SPSState ? "started" : "stopped"); + } + } + } + +mDNSexport void mDNSCoreBeSleepProxyServer(mDNS *const m, mDNSu8 sps, mDNSu8 port, mDNSu8 marginalpower, mDNSu8 totpower) + { + // If turning off SPS, close our socket + // (Do this first, BEFORE calling mDNS_DeregisterService below) + if (!sps && m->SPSSocket) { mDNSPlatformUDPClose(m->SPSSocket); m->SPSSocket = mDNSNULL; } + + // If turning off, or changing type, deregister old name + if (m->SPSState == 1 && sps != m->SPSType) + { m->SPSState = 2; mDNS_DeregisterService(m, &m->SPSRecords); } + + // Record our new SPS parameters + m->SPSType = sps; + m->SPSPortability = port; + m->SPSMarginalPower = marginalpower; + m->SPSTotalPower = totpower; + + // If turning on, open socket and advertise service + if (sps) + { + if (!m->SPSSocket) + { + m->SPSSocket = mDNSPlatformUDPSocket(m, zeroIPPort); + if (!m->SPSSocket) { LogMsg("mDNSCoreBeSleepProxyServer: Failed to allocate SPSSocket"); return; } + } + if (m->SPSState == 0) SleepProxyServerCallback(m, &m->SPSRecords, mStatus_MemFree); + } + } + // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - @@ -7049,16 +9292,18 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, if (!rrcachestorage) rrcachesize = 0; - m->p = p; - m->KnownBugs = 0; - 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; - m->UnicastPort6 = zeroIPPort; - m->MainCallback = Callback; - m->MainContext = Context; - m->rec.r.resrec.RecordType = 0; + m->p = p; + m->KnownBugs = 0; + m->CanReceiveUnicastOn5353 = mDNSfalse; // Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise + m->AdvertiseLocalAddresses = AdvertiseLocalAddresses; + m->DivertMulticastAdvertisements = mDNSfalse; + m->mDNSPlatformStatus = mStatus_Waiting; + m->UnicastPort4 = zeroIPPort; + m->UnicastPort6 = zeroIPPort; + m->PrimaryMAC = zeroEthAddr; + m->MainCallback = Callback; + m->MainContext = Context; + m->rec.r.resrec.RecordType = 0; // For debugging: To catch and report locking failures m->mDNS_busy = 0; @@ -7083,12 +9328,15 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, m->NextScheduledProbe = timenow + 0x78000000; m->NextScheduledResponse = timenow + 0x78000000; m->NextScheduledNATOp = timenow + 0x78000000; + m->NextScheduledSPS = timenow + 0x78000000; m->RandomQueryDelay = 0; m->RandomReconfirmDelay = 0; m->PktNum = 0; - m->SendDeregistrations = mDNSfalse; - m->SendImmediateAnswers = mDNSfalse; - m->SleepState = mDNSfalse; + m->SleepState = SleepState_Awake; + m->SleepSeqNum = 0; + m->SystemWakeOnLANEnabled = mDNSfalse; + m->DelaySleep = 0; + m->SleepLimit = 0; // These fields only required for mDNS Searcher... m->Questions = mDNSNULL; @@ -7153,9 +9401,9 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, m->ExternalAddress = zerov4Addr; m->NATMcastRecvskt = mDNSNULL; - m->NATMcastRecvsk2 = mDNSNULL; m->LastNATupseconds = 0; m->LastNATReplyLocalTime = timenow; + m->LastNATMapResultCode = NATErr_None; m->UPnPInterfaceID = 0; m->SSDPSocket = mDNSNULL; @@ -7167,6 +9415,16 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, m->UPnPSOAPURL = mDNSNULL; m->UPnPRouterAddressString = mDNSNULL; m->UPnPSOAPAddressString = mDNSNULL; + m->SPSType = 0; + m->SPSPortability = 0; + m->SPSMarginalPower = 0; + m->SPSTotalPower = 0; + m->SPSState = 0; + m->SPSProxyListChanged = mDNSNULL; + m->SPSSocket = mDNSNULL; + m->SPSBrowseCallback = mDNSNULL; + m->ProxyRecords = 0; + #endif #if APPLE_OSX_mDNSResponder @@ -7184,6 +9442,28 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p, return(result); } +mDNSexport void mDNS_ConfigChanged(mDNS *const m) + { + if (m->SPSState == 1) + { + domainlabel name, newname; + domainname type, domain; + DeconstructServiceName(m->SPSRecords.RR_SRV.resrec.name, &name, &type, &domain); + ConstructSleepProxyServerName(m, &newname); + if (!SameDomainLabelCS(name.c, newname.c)) + { + LogSPS("Renaming SPS from “%#s” to “%#s”", name.c, newname.c); + // When SleepProxyServerCallback gets the mStatus_MemFree message, + // it will reregister the service under the new name + m->SPSState = 2; + mDNS_DeregisterService(m, &m->SPSRecords); + } + } + + if (m->MainCallback) + m->MainCallback(m, mStatus_ConfigChanged); + } + mDNSlocal void DynDNSHostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result) { (void)m; // unused @@ -7191,6 +9471,21 @@ mDNSlocal void DynDNSHostNameCallback(mDNS *const m, AuthRecord *const rr, mStat mDNSPlatformDynDNSHostNameStatusChanged(rr->resrec.name, result); } +mDNSlocal void PurgeOrReconfirmCacheRecord(mDNS *const m, CacheRecord *cr, const DNSServer * const ptr, mDNSBool lameduck) + { + mDNSBool purge = cr->resrec.RecordType == kDNSRecordTypePacketNegative || + cr->resrec.rrtype == kDNSType_A || + cr->resrec.rrtype == kDNSType_AAAA || + cr->resrec.rrtype == kDNSType_SRV; + + (void) lameduck; + (void) ptr; + debugf("uDNS_SetupDNSConfig: %s cache record due to %s server %p %#a:%d (%##s): %s", purge ? "purging" : "reconfirming", lameduck ? "lame duck" : "new", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c, CRDisplayString(m, cr)); + + if (purge) mDNS_PurgeCacheResourceRecord(m, cr); + else mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); + } + mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) { mDNSu32 slot; @@ -7202,6 +9497,8 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) DNSServer *ptr, **p = &m->DNSServers; const DNSServer *oldServers = m->DNSServers; DNSQuestion *q; + + debugf("uDNS_SetupDNSConfig: entry"); if (m->RegisterSearchDomains) uDNS_RegisterSearchDomains(m); @@ -7223,7 +9520,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) if (t != s) { // If DNS Server for this question has changed, reactivate it - LogOperation("Updating DNS Server from %p %#a:%d (%##s) to %p %#a:%d (%##s) for %##s (%s)", + debugf("uDNS_SetupDNSConfig: Updating DNS Server from %p %#a:%d (%##s) to %p %#a:%d (%##s) for %##s (%s)", t, t ? &t->addr : mDNSNULL, mDNSVal16(t ? t->port : zeroIPPort), t ? t->domain.c : (mDNSu8*)"", s, s ? &s->addr : mDNSNULL, mDNSVal16(s ? s->port : zeroIPPort), s ? s->domain.c : (mDNSu8*)"", q->qname.c, DNSTypeName(q->qtype)); @@ -7238,12 +9535,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) { ptr = GetServerForName(m, cr->resrec.name); if (ptr && (ptr->flags & DNSServer_FlagNew) && !cr->resrec.InterfaceID) - { - if (cr->resrec.RecordType == kDNSRecordTypePacketNegative) - mDNS_PurgeCacheResourceRecord(m, cr); - else - mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer); - } + PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNSfalse); } while (*p) @@ -7257,8 +9549,9 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) ptr->flags &= ~DNSServer_FlagDelete; // 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); + PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNStrue); *p = (*p)->next; + debugf("uDNS_SetupDNSConfig: Deleting server %p %#a:%d (%##s)", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c); mDNSPlatformMemFree(ptr); } else @@ -7276,10 +9569,14 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m) { int count = 0; FORALL_CACHERECORDS(slot, cg, cr) if (!cr->resrec.InterfaceID) { mDNS_PurgeCacheResourceRecord(m, cr); count++; } - LogOperation("uDNS_SetupDNSConfig: %s available; purged %d unicast DNS records from cache", + LogInfo("uDNS_SetupDNSConfig: %s available; purged %d unicast DNS records from cache", m->DNSServers ? "DNS server became" : "No DNS servers", count); } + // If we no longer have any DNS servers, we need to force anything that needs to get zone data + // to get that information again (which will fail, since we have no more DNS servers) + if ((m->DNSServers == mDNSNULL) && (oldServers != mDNSNULL)) RestartRecordGetZoneData(m); + // Did our FQDN change? if (!SameDomainName(&fqdn, &m->FQDN)) { @@ -7331,6 +9628,24 @@ mDNSexport void mDNSCoreInitComplete(mDNS *const m, mStatus result) extern ServiceRecordSet *CurrentServiceRecordSet; +mDNSlocal void DeregLoop(mDNS *const m, AuthRecord *const start) + { + m->CurrentRecord = start; + while (m->CurrentRecord) + { + AuthRecord *rr = m->CurrentRecord; + if (rr->resrec.RecordType != kDNSRecordTypeDeregistering) + { + LogInfo("DeregLoop: Deregistering %p %02X %s", rr, rr->resrec.RecordType, ARDisplayString(m, rr)); + mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); + } + // Note: We mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because + // the list may have been changed in that call. + if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now + m->CurrentRecord = rr->next; + } + } + mDNSexport void mDNS_StartExit(mDNS *const m) { NetworkInterfaceInfo *intf; @@ -7340,11 +9655,29 @@ mDNSexport void mDNS_StartExit(mDNS *const m) m->ShutdownTime = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5); + mDNS_DropLockBeforeCallback(); // mDNSCoreBeSleepProxyServer expects to be called without the lock held, so we emulate that here + mDNSCoreBeSleepProxyServer(m, 0, 0, 0, 0); + mDNS_ReclaimLockAfterCallback(); + #ifndef UNICAST_DISABLED + { + SearchListElem *s; SuspendLLQs(m); // Don't need to do SleepRecordRegistrations() or SleepServiceRegistrations() here, // because we deregister all records and services later in this routine while (m->Hostnames) mDNS_RemoveDynDNSHostName(m, &m->Hostnames->fqdn); + + // For each member of our SearchList, deregister any records it may have created, and cut them from the list. + // Otherwise they'll be forcibly deregistered for us (without being cut them from the appropriate list) + // and we may crash because the list still contains dangling pointers. + for (s = SearchList; s; s = s->next) + while (s->AuthRecs) + { + ARListElem *dereg = s->AuthRecs; + s->AuthRecs = s->AuthRecs->next; + mDNS_Deregister_internal(m, &dereg->ar, mDNS_Dereg_normal); // Memory will be freed in the FreeARElemCallback + } + } #endif for (intf = m->HostInterfaces; intf; intf = intf->next) @@ -7370,63 +9703,52 @@ mDNSexport void mDNS_StartExit(mDNS *const m) // Make sure there are nothing but deregistering records remaining in the list if (m->CurrentRecord) - LogMsg("mDNS_StartExit 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, - // because the freeing of the memory is triggered off the mStatus_MemFree for the PTR record. - m->CurrentRecord = m->ResourceRecords; - while (m->CurrentRecord) - { - rr = m->CurrentRecord; - if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask) - mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); - // Note: We mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because when - // we have records on the DuplicateRecords list, the duplicate gets inserted in place of the record - // we're removing, and if we've already advanced to rr->next we'll miss the newly activated duplicate - if (m->CurrentRecord == rr) // If m->CurrentRecord was not auto-advanced, do it ourselves now - m->CurrentRecord = rr->next; - } - - // Now deregister any remaining records we didn't get the first time through - m->CurrentRecord = m->ResourceRecords; - while (m->CurrentRecord) + LogMsg("mDNS_StartExit: ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord)); + + // We're in the process of shutting down, so queries, etc. are no longer available. + // Consequently, determining certain information, e.g. the uDNS update server's IP + // address, will not be possible. The records on the main list are more likely to + // already contain such information, so we deregister the duplicate records first. + LogInfo("mDNS_StartExit: Deregistering duplicate resource records"); + DeregLoop(m, m->DuplicateRecords); + LogInfo("mDNS_StartExit: Deregistering resource records"); + DeregLoop(m, m->ResourceRecords); + + // If we scheduled a response to send goodbye packets, we set NextScheduledResponse to now. Normally when deregistering records, + // we allow up to 100ms delay (to help improve record grouping) but when shutting down we don't want any such delay. + if (m->NextScheduledResponse - m->timenow < mDNSPlatformOneSecond) { - rr = m->CurrentRecord; - if (rr->resrec.RecordType != kDNSRecordTypeDeregistering) - { - //LogOperation("mDNS_StartExit: Deregistering %s", ARDisplayString(m, rr)); - mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); - } - // Note: We mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because when - // we have records on the DuplicateRecords list, the duplicate gets inserted in place of the record - // we're removing, and if we've already advanced to rr->next we'll miss the newly activated duplicate - if (m->CurrentRecord == rr) // If m->CurrentRecord was not auto-advanced, do it ourselves now - m->CurrentRecord = rr->next; + m->NextScheduledResponse = m->timenow; + m->SuppressSending = 0; } +#if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST CurrentServiceRecordSet = m->ServiceRegistrations; while (CurrentServiceRecordSet) { ServiceRecordSet *srs = CurrentServiceRecordSet; - LogOperation("mDNS_StartExit: Deregistering %##s", srs->RR_SRV.resrec.name->c); + LogInfo("mDNS_StartExit: Deregistering uDNS service %##s", srs->RR_SRV.resrec.name->c); uDNS_DeregisterService(m, srs); if (CurrentServiceRecordSet == srs) CurrentServiceRecordSet = srs->uDNS_next; } +#endif + + if (m->ResourceRecords) LogInfo("mDNS_StartExit: Sending final record deregistrations"); + else LogInfo("mDNS_StartExit: No deregistering records remain"); - if (m->ResourceRecords) LogOperation("mDNS_StartExit: Sending final record deregistrations"); - else LogOperation("mDNS_StartExit: No deregistering records remain"); + if (m->ServiceRegistrations) LogInfo("mDNS_StartExit: Sending final uDNS service deregistrations"); + else LogInfo("mDNS_StartExit: No deregistering uDNS services remain"); - if (m->ServiceRegistrations) LogOperation("mDNS_StartExit: Sending final service deregistrations"); - else LogOperation("mDNS_StartExit: No deregistering services remain"); + for (rr = m->DuplicateRecords; rr; rr = rr->next) + LogMsg("mDNS_StartExit: Should not still have Duplicate Records remaining: %02X %s", rr->resrec.RecordType, ARDisplayString(m, rr)); // If any deregistering records remain, send their deregistration announcements before we exit if (m->mDNSPlatformStatus != mStatus_NoError) DiscardDeregistrations(m); mDNS_Unlock(m); - LogOperation("mDNS_StartExit: done"); + LogInfo("mDNS_StartExit: done"); } mDNSexport void mDNS_FinalExit(mDNS *const m) @@ -7437,7 +9759,7 @@ mDNSexport void mDNS_FinalExit(mDNS *const m) AuthRecord *rr; ServiceRecordSet *srs; - LogOperation("mDNS_FinalExit: mDNSPlatformClose"); + LogInfo("mDNS_FinalExit: mDNSPlatformClose"); mDNSPlatformClose(m); rrcache_totalused = m->rrcache_totalused; @@ -7457,15 +9779,15 @@ mDNSexport void mDNS_FinalExit(mDNS *const m) ReleaseCacheGroup(m, &m->rrcache_hash[slot]); } } - debugf("mDNS_StartExit: RR Cache was using %ld records, %lu active", rrcache_totalused, rrcache_active); + debugf("mDNS_FinalExit: RR Cache was using %ld records, %lu active", rrcache_totalused, rrcache_active); if (rrcache_active != m->rrcache_active) LogMsg("*** ERROR *** rrcache_active %lu != m->rrcache_active %lu", rrcache_active, m->rrcache_active); for (rr = m->ResourceRecords; rr; rr = rr->next) - LogMsg("mDNS_FinalExit failed to send goodbye for: %02X %s", rr->resrec.RecordType, ARDisplayString(m, rr)); + LogMsg("mDNS_FinalExit failed to send goodbye for: %p %02X %s", rr, rr->resrec.RecordType, ARDisplayString(m, rr)); for (srs = m->ServiceRegistrations; srs; srs = srs->uDNS_next) - LogMsg("mDNS_FinalExit failed to deregister service: %##s", srs->RR_SRV.resrec.name->c); + LogMsg("mDNS_FinalExit failed to deregister service: %p %##s", srs, srs->RR_SRV.resrec.name->c); - LogOperation("mDNS_FinalExit: done"); + LogInfo("mDNS_FinalExit: done"); } diff --git a/mDNSCore/mDNSDebug.h b/mDNSCore/mDNSDebug.h index 7301087..36cbc43 100755 --- a/mDNSCore/mDNSDebug.h +++ b/mDNSCore/mDNSDebug.h @@ -17,6 +17,45 @@ Change History (most recent first): $Log: mDNSDebug.h,v $ +Revision 1.51 2009/06/25 23:36:59 cheshire +To facilitate testing, added command-line switch "-OfferSleepProxyService" +to re-enable the previously-supported mode of operation where we offer +sleep proxy service on desktop Macs that are set to never sleep. + +Revision 1.50 2009/05/19 23:34:06 cheshire +Updated comment to show correct metric of 80 for a low-priority sleep proxy + +Revision 1.49 2009/04/24 23:32:28 cheshire +To facilitate testing, put back code to be a sleep proxy when set to never sleep, compiled out by compile-time switch + +Revision 1.48 2009/04/11 01:43:27 jessic2 + Daemon: Should be able to turn on LogOperation dynamically + +Revision 1.47 2009/04/11 00:19:41 jessic2 + Daemon: Should be able to turn on LogOperation dynamically + +Revision 1.46 2009/02/13 06:36:50 cheshire +Update LogSPS definition + +Revision 1.45 2009/02/13 06:03:12 cheshire +Added LogInfo for informational message logging + +Revision 1.44 2009/02/12 20:57:25 cheshire +Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch + +Revision 1.43 2008/12/10 02:27:14 cheshire +Commented out definitions of LogClientOperations, LogTimeStamps, ForceAlerts and MACOSX_MDNS_MALLOC_DEBUGGING +to allow overriding values to be easily defined in a Makefile or similar build environment + +Revision 1.42 2008/11/02 21:22:05 cheshire +Changed mallocL size parameter back to "unsigned int" + +Revision 1.41 2008/11/02 21:14:58 cheshire +Fixes to make mallocL/freeL debugging checks work on 64-bit + +Revision 1.40 2008/10/24 20:53:37 cheshire +For now, define USE_SEPARATE_UDNS_SERVICE_LIST, so that we use the old service list code for this submission + Revision 1.39 2008/02/26 21:17:11 cheshire Grouped all user settings together near the start of the file; added LogTimeStamps option @@ -142,26 +181,24 @@ Merge in license terms from Quinn's copy, in preparation for Darwin release 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 + MDNS_LOG_MSG, + MDNS_LOG_OPERATION, + MDNS_LOG_SPS, + MDNS_LOG_INFO, + MDNS_LOG_DEBUG, + } mDNSLogLevel_t; // Set this symbol to 1 to answer remote queries for our Address, reverse mapping PTR, and HINFO records #define ANSWER_REMOTE_HOSTNAME_QUERIES 0 // Set this symbol to 1 to do extra debug checks on malloc() and free() // Set this symbol to 2 to write a log message for every malloc() and free() -#define MACOSX_MDNS_MALLOC_DEBUGGING 0 +//#define MACOSX_MDNS_MALLOC_DEBUGGING 1 + +//#define ForceAlerts 1 +//#define LogTimeStamps 1 -#define LogAllOperations 0 -#define LogTimeStamps 0 -#define ForceAlerts 0 +#define USE_SEPARATE_UDNS_SERVICE_LIST 1 // Developer-settings section ends here @@ -171,7 +208,7 @@ typedef enum #define IS_A_PRINTF_STYLE_FUNCTION(F,A) #endif -#ifdef __cplusplus +#ifdef __cplusplus extern "C" { #endif @@ -179,62 +216,78 @@ typedef enum #if (defined(__GNUC__)) #if ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 2))) - #define MDNS_C99_VA_ARGS 1 - #define MDNS_GNU_VA_ARGS 0 + #define MDNS_C99_VA_ARGS 1 + #define MDNS_GNU_VA_ARGS 0 #else - #define MDNS_C99_VA_ARGS 0 - #define MDNS_GNU_VA_ARGS 1 + #define MDNS_C99_VA_ARGS 0 + #define MDNS_GNU_VA_ARGS 1 #endif - #define MDNS_HAS_VA_ARG_MACROS 1 + #define MDNS_HAS_VA_ARG_MACROS 1 #elif (_MSC_VER >= 1400) // Visual Studio 2005 and later - #define MDNS_C99_VA_ARGS 1 - #define MDNS_GNU_VA_ARGS 0 - #define MDNS_HAS_VA_ARG_MACROS 1 + #define MDNS_C99_VA_ARGS 1 + #define MDNS_GNU_VA_ARGS 0 + #define MDNS_HAS_VA_ARG_MACROS 1 #elif (defined(__MWERKS__)) - #define MDNS_C99_VA_ARGS 1 - #define MDNS_GNU_VA_ARGS 0 - #define MDNS_HAS_VA_ARG_MACROS 1 + #define MDNS_C99_VA_ARGS 1 + #define MDNS_GNU_VA_ARGS 0 + #define MDNS_HAS_VA_ARG_MACROS 1 #else - #define MDNS_C99_VA_ARGS 0 - #define MDNS_GNU_VA_ARGS 0 - #define MDNS_HAS_VA_ARG_MACROS 0 + #define MDNS_C99_VA_ARGS 0 + #define MDNS_GNU_VA_ARGS 0 + #define MDNS_HAS_VA_ARG_MACROS 0 #endif -#if MDNS_DEBUGMSGS -#define debugf debugf_ -extern void debugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); -#else // If debug breaks are off, use a preprocessor trick to optimize those calls out of the code +#if (MDNS_HAS_VA_ARG_MACROS) #if (MDNS_C99_VA_ARGS) - #define debugf( ... ) ((void)0) + #define debug_noop( ... ) ((void)0) + #define LogMsg( ... ) LogMsgWithLevel(MDNS_LOG_MSG, __VA_ARGS__) + #define LogOperation( ... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_OPERATION, __VA_ARGS__); } while (0) + #define LogSPS( ... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_SPS, __VA_ARGS__); } while (0) + #define LogInfo( ... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_INFO, __VA_ARGS__); } while (0) #elif (MDNS_GNU_VA_ARGS) - #define debugf( ARGS... ) ((void)0) + #define debug_noop( ARGS... ) ((void)0) + #define LogMsg( ARGS... ) LogMsgWithLevel(MDNS_LOG_MSG, ARGS) + #define LogOperation( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_OPERATION, ARGS); } while (0) + #define LogSPS( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_SPS, ARGS); } while (0) + #define LogInfo( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_INFO, ARGS); } while (0) #else - #define debugf 1 ? ((void)0) : (void) + #error Unknown variadic macros #endif +#else + // If your platform does not support variadic macros, you need to define the following variadic functions. + // See mDNSShared/mDNSDebug.c for sample implementation + extern void debug_noop(const char *format, ...); + #define LogMsg LogMsg_ + #define LogOperation mDNS_LoggingEnabled == 0 ? ((void)0) : LogOperation_ + #define LogSPS mDNS_LoggingEnabled == 0 ? ((void)0) : LogSPS_ + #define LogInfo mDNS_LoggingEnabled == 0 ? ((void)0) : LogInfo_ + extern void LogMsg_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); + extern void LogOperation_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); + extern void LogSPS_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); + extern void LogInfo_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); +#endif + +#if MDNS_DEBUGMSGS +#define debugf debugf_ +extern void debugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); +#else +#define debugf debug_noop #endif #if MDNS_DEBUGMSGS > 1 #define verbosedebugf verbosedebugf_ extern void verbosedebugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2); #else - #if (MDNS_C99_VA_ARGS) - #define verbosedebugf( ... ) ((void)0) - #elif (MDNS_GNU_VA_ARGS) - #define verbosedebugf( ARGS... ) ((void)0) - #else - #define verbosedebugf 1 ? ((void)0) : (void) - #endif +#define verbosedebugf debug_noop #endif -// LogMsg is used even in shipping code, to write truly serious error messages to syslog (or equivalent) -extern LogLevel_t mDNS_LogLevel; +extern int mDNS_LoggingEnabled; +extern int mDNS_PacketLoggingEnabled; 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 const char ProgramName[]; -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); +extern void LogMsgWithLevel(mDNSLogLevel_t logLevel, const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(2,3); +#define LogMsgNoIdent LogMsg #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1 extern void *mallocL(char *msg, unsigned int size); @@ -247,13 +300,7 @@ extern void udns_validatelists(void *const v); #define freeL(X,Y) free(Y) #endif -#if LogAllOperations -#define LogOperation LogMsg -#else -#define LogOperation debugf -#endif - -#ifdef __cplusplus +#ifdef __cplusplus } #endif diff --git a/mDNSCore/mDNSEmbeddedAPI.h b/mDNSCore/mDNSEmbeddedAPI.h index 8b46b3b..c02cea4 100755 --- a/mDNSCore/mDNSEmbeddedAPI.h +++ b/mDNSCore/mDNSEmbeddedAPI.h @@ -54,20 +54,337 @@ Change History (most recent first): $Log: mDNSEmbeddedAPI.h,v $ -Revision 1.468.2.4 2008/09/30 18:03:02 mcguire +Revision 1.573 2009/06/30 18:17:45 herscher +Add to 64 bit macro check for 64 bit Windows OSes + +Revision 1.572 2009/06/27 00:52:27 cheshire + mDNSResponder taking up 13% CPU with 400 KBps incoming bonjour requests +Removed overly-complicate and ineffective multi-packet known-answer snooping code +(Bracketed it with "#if ENABLE_MULTI_PACKET_QUERY_SNOOPING" for now; will delete actual code later) + +Revision 1.571 2009/06/26 01:55:54 cheshire + mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour +Additional refinements -- except for the case of explicit queries for record types we don't have (for names we own), +add additional NSEC records only when there's space to do that without having to generate an additional packet + +Revision 1.570 2009/06/24 22:14:21 cheshire + Plugging and unplugging the power cable shouldn't cause a network change event + +Revision 1.569 2009/06/03 23:07:12 cheshire + mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour +Large records were not being added in cases where an NSEC record was also required + +Revision 1.568 2009/05/19 22:37:04 cheshire + Sleep Proxy: Retransmission logic not working reliably on quiet networks +Added NextScheduledSPRetry field + +Revision 1.567 2009/05/13 17:25:33 mkrochma + Should not schedule maintenance wake when machine has no advertised services +Sleep proxy client should only look for services being advertised via Multicast + +Revision 1.566 2009/05/12 23:09:24 cheshire + Should not schedule maintenance wake when machine has no advertised services +Declare mDNSCoreHaveAdvertisedServices routine so it can be called from daemon.c + +Revision 1.565 2009/05/09 00:10:58 jessic2 +Change expected size of NetworkInterfaceInfo to fix build failure + +Revision 1.564 2009/05/07 23:31:26 cheshire + Sleep Proxy: Retransmit and retry Sleep Proxy Server requests +Added NextSPSAttempt and NextSPSAttemptTime fields to NetworkInterfaceInfo_struct + +Revision 1.563 2009/04/24 21:06:38 cheshire +Added comment about UDP length field (includes UDP header, so minimum value is 8 bytes) + +Revision 1.562 2009/04/24 00:22:23 cheshire + Return negative answers when host knows authoritatively that no answer exists +Added definition of rdataNSEC + +Revision 1.561 2009/04/23 22:06:29 cheshire +Added CacheRecord and InterfaceID parameters to MakeNegativeCacheRecord, in preparation for: + Return negative answers when host knows authoritatively that no answer exists + +Revision 1.560 2009/04/23 21:54:50 cheshire +Updated comments + +Revision 1.559 2009/04/22 00:37:38 cheshire + Remove unused kDNSType_MAC + +Revision 1.558 2009/04/21 23:36:25 cheshire + Remove unused kDNSType_MAC + +Revision 1.557 2009/04/15 20:42:51 mcguire + uDNS: Treat RCODE 5 (Refused) responses as failures + +Revision 1.556 2009/04/11 00:19:43 jessic2 + Daemon: Should be able to turn on LogOperation dynamically + +Revision 1.555 2009/04/01 21:12:27 herscher + Current Bonjour code does not compile on Windows. + +Revision 1.554 2009/04/01 17:50:11 mcguire +cleanup mDNSRandom + +Revision 1.553 2009/03/26 03:59:00 jessic2 +Changes for + +Revision 1.552 2009/03/20 23:53:03 jessic2 + SIGHUP should restart all in-progress queries + +Revision 1.551 2009/03/18 20:41:04 cheshire +Added definition of the all-ones mDNSOpaque16 ID + +Revision 1.550 2009/03/17 19:10:29 mcguire +Fix sizechecks for x86_64 + +Revision 1.549 2009/03/17 01:22:56 cheshire + Sleep Proxy: Retransmit and retry Sleep Proxy Server requests +Initial support for resolving up to three Sleep Proxies in parallel + +Revision 1.548 2009/03/14 01:42:56 mcguire + BTMM: Fix issues with multiple .Mac accounts on the same machine + +Revision 1.547 2009/03/10 01:14:30 cheshire +Sleep Proxies with invalid names need to be ignored (score 10000), +not treated as "Sleep Proxy of last resort" (score 9999) + +Revision 1.546 2009/03/06 23:51:51 mcguire +Fix broken build by defining DiscardPort + +Revision 1.545 2009/03/06 22:39:23 cheshire + Ignore prototype base stations when picking Sleep Proxy to register with + +Revision 1.544 2009/03/04 01:33:30 cheshire +Add m->ProxyRecords counter + +Revision 1.543 2009/03/03 23:04:43 cheshire +For clarity, renamed "MAC" field to "HMAC" (Host MAC, as opposed to Interface MAC) + +Revision 1.542 2009/03/03 22:51:53 cheshire + Sleep Proxy: Waking on same network but different interface will cause conflicts + +Revision 1.541 2009/03/03 00:45:19 cheshire +Added m->PrimaryMAC field + +Revision 1.540 2009/02/27 02:56:57 cheshire +Moved struct SearchListElem definition from uDNS.c into mDNSEmbeddedAPI.h + +Revision 1.539 2009/02/17 23:29:01 cheshire +Throttle logging to a slower rate when running on SnowLeopard + +Revision 1.538 2009/02/11 02:31:57 cheshire +Moved SystemWakeOnLANEnabled from mDNSMacOSX.h, so it's accessible to mDNSCore routines + +Revision 1.537 2009/02/07 02:51:48 cheshire + Sleep Proxy: Need to adopt IOPMConnection +Added new functions and timing variables + +Revision 1.536 2009/01/30 23:50:31 cheshire +Added LastLabel() routine to get the last label of a domainname + +Revision 1.535 2009/01/23 00:38:36 mcguire + BTMM: Doesn't work with Linksys WRT54GS firmware 4.71.1 + +Revision 1.534 2009/01/22 02:14:25 cheshire + Sleep Proxy: Set correct target MAC address, instead of all zeroes + +Revision 1.533 2009/01/21 03:43:57 mcguire + BTMM: Add support for setting kDNSServiceErr_NATPortMappingDisabled in DynamicStore + +Revision 1.532 2009/01/16 19:50:36 cheshire +Oops. Fixed definition of SleepProxyServiceType. + +Revision 1.531 2009/01/16 19:48:09 cheshire +Added definition of SleepProxyServiceType + +Revision 1.530 2009/01/15 00:22:49 mcguire + NAT-PMP: mDNSResponder needs to listen on 224.0.0.1:5350/UDP with REUSEPORT + +Revision 1.529 2009/01/13 00:31:44 cheshire +Fixed off-by-one error in computing the implicit limit pointer in the "DomainNameLength(name)" macro + +Revision 1.528 2009/01/10 01:43:52 cheshire +Changed misleading function name 'AnsweredLOQ' to more informative 'AnsweredLocalQ' + +Revision 1.527 2008/12/12 01:23:19 cheshire +Added m->SPSProxyListChanged state variable to flag when we need to update our BPF filter program + +Revision 1.526 2008/12/12 00:51:14 cheshire +Added structure definitions for IPv6Header, etc. + +Revision 1.525 2008/12/10 02:18:31 cheshire +Increased MaxMsg to 160 for showing longer TXT records in SIGINFO output + +Revision 1.524 2008/12/10 01:49:39 cheshire +Fixes for alignment issues on ARMv5 + +Revision 1.523 2008/12/05 02:35:24 mcguire + Write to the DynamicStore when a Sleep Proxy server is available on the network + +Revision 1.522 2008/12/04 21:08:51 mcguire + mDNS: Provide mechanism to disable Multicast advertisements + +Revision 1.521 2008/12/04 02:19:24 cheshire +Updated comment + +Revision 1.520 2008/11/26 20:28:05 cheshire +Added new SSHPort constant + +Revision 1.519 2008/11/25 22:46:30 cheshire +For ease of code searching, renamed ZoneData field of ServiceRecordSet_struct from "nta" to "srs_nta" + +Revision 1.518 2008/11/25 05:07:15 cheshire + Advertise Sleep Proxy metrics in service name + +Revision 1.517 2008/11/20 01:51:19 cheshire +Exported RecreateNATMappings so it's callable from other files + +Revision 1.516 2008/11/16 16:49:25 cheshire + LLQs broken in mDNSResponder-184 +DNSOpt_LLQData_Space was incorrectly defined to be 18 instead of 22 + +Revision 1.515 2008/11/14 20:59:41 cheshire +Added mDNSEthAddressIsZero(A) macro + +Revision 1.514 2008/11/14 02:17:41 cheshire +Added NextScheduledSPS task scheduling variable + +Revision 1.513 2008/11/14 00:47:19 cheshire +Added TimeRcvd and TimeExpire fields to AuthRecord_struct + +Revision 1.512 2008/11/14 00:00:53 cheshire +After client machine wakes up, Sleep Proxy machine need to remove any records +it was temporarily holding as proxy for that client + +Revision 1.511 2008/11/13 19:04:44 cheshire +Added definition of OwnerOptData + +Revision 1.510 2008/11/06 23:48:32 cheshire +Changed SleepProxyServerType to mDNSu8 + +Revision 1.509 2008/11/04 23:06:50 cheshire +Split RDataBody union definition into RDataBody and RDataBody2, and removed +SOA from the normal RDataBody union definition, saving 270 bytes per AuthRecord + +Revision 1.508 2008/11/04 22:21:43 cheshire +Changed zone field of AuthRecord_struct from domainname to pointer, saving 252 bytes per AuthRecord + +Revision 1.507 2008/11/04 22:13:43 cheshire +Made RDataBody parameter to GetRRDisplayString_rdb "const" + +Revision 1.506 2008/11/04 20:06:19 cheshire + Change MAX_DOMAIN_NAME to 256 + +Revision 1.505 2008/11/03 23:49:47 mkrochma +Increase NATMAP_DEFAULT_LEASE to 2 hours so we do maintenance wake less often + +Revision 1.504 2008/10/31 22:55:04 cheshire +Initial support for structured SPS names + +Revision 1.503 2008/10/24 23:58:47 cheshire +Ports should be mDNSIPPort, not mDNSOpaque16 + +Revision 1.502 2008/10/23 22:25:56 cheshire +Renamed field "id" to more descriptive "updateid" + +Revision 1.501 2008/10/22 22:22:27 cheshire +Added packet structure definitions + +Revision 1.500 2008/10/22 19:55:35 cheshire +Miscellaneous fixes; renamed FindFirstAnswerInCache to FindSPSInCache + +Revision 1.499 2008/10/22 17:15:47 cheshire +Updated definitions of mDNSIPv4AddressIsZero/mDNSIPv4AddressIsOnes, etc. + +Revision 1.498 2008/10/22 01:01:52 cheshire +Added onesEthAddr constant, used for sending ARP broadcasts + +Revision 1.497 2008/10/21 00:51:11 cheshire +Added declaration of mDNSPlatformSetBPF(), used by uds_daemon.c to pass BPF fd to mDNSMacOSX.c + +Revision 1.496 2008/10/16 22:38:52 cheshire +Added declaration of mDNSCoreReceiveRawPacket() + +Revision 1.495 2008/10/15 22:53:51 cheshire +Removed unused "#define LocalReverseMapDomain" + +Revision 1.494 2008/10/15 20:37:17 cheshire +Added "#define DNSOpt_Lease_Space 19" + +Revision 1.493 2008/10/14 21:37:56 cheshire +Removed unnecessary m->BeSleepProxyServer variable + +Revision 1.492 2008/10/14 20:26:36 cheshire +Added definition of a new kDNSType_MAC rdata type + +Revision 1.491 2008/10/09 22:29:04 cheshire +Added "mDNSEthAddr MAC" to NetworkInterfaceInfo_struct + +Revision 1.490 2008/10/09 21:39:20 cheshire +Update list of DNS types + +Revision 1.489 2008/10/09 18:59:19 cheshire +Added NetWakeResolve code, removed unused m->SendDeregistrations and m->SendImmediateAnswers + +Revision 1.488 2008/10/08 01:02:03 cheshire +Added mDNS_SetupQuestion() convenience function + +Revision 1.487 2008/10/07 21:41:57 mcguire +Increase sizecheck limits to account for DNSQuestion added to NetworkInterfaceInfo_struct in 64bit builds + +Revision 1.486 2008/10/07 15:56:24 cheshire +Increase sizecheck limits to account for DNSQuestion added to NetworkInterfaceInfo_struct + +Revision 1.485 2008/10/04 00:48:37 cheshire +Added DNSQuestion to NetworkInterfaceInfo_struct, used for browsing for Sleep Proxy Servers + +Revision 1.484 2008/10/04 00:01:45 cheshire +Move NetworkInterfaceInfo_struct further down in file (we'll need to add a DNSQuestion to it later) + +Revision 1.483 2008/10/03 23:28:41 cheshire +Added declaration of mDNSPlatformSendRawPacket + +Revision 1.482 2008/10/03 17:30:05 cheshire +Added declaration of mDNS_ConfigChanged(mDNS *const m); + +Revision 1.481 2008/10/02 22:38:58 cheshire +Added SleepProxyServer fields, and mDNSCoreBeSleepProxyServer() call for turning SleepProxyServer on and off + +Revision 1.480 2008/10/01 21:22:17 cheshire +Added NetWake field to NetworkInterfaceInfo structure, to signal when Wake-On-Magic-Packet is enabled for that interface + +Revision 1.479 2008/09/29 20:12:37 cheshire +Rename 'AnswerLocalQuestions' to more descriptive 'AnswerLocalOnlyQuestions' and 'AnsweredLocalQ' to 'AnsweredLOQ' + +Revision 1.478 2008/09/23 02:37:10 cheshire +Added FirstLabel/SecondLabel macros + +Revision 1.477 2008/09/20 00:34:22 mcguire BTMM: Add support for WANPPPConnection -Revision 1.468.2.3 2008/07/29 20:46:57 mcguire - Should use randomized source ports and transaction IDs to avoid DNS cache poisoning -merge r1.474 from +Revision 1.476 2008/09/05 22:22:01 cheshire +Move "UDPSocket *LocalSocket" field to more logical place in DNSQuestion_struct + +Revision 1.475 2008/07/25 22:34:11 mcguire +fix sizecheck issues for 64bit -Revision 1.468.2.2 2008/07/29 19:44:38 mcguire - BTMM: alternate SSDP queries between multicast & unicast -merge r1.472, r1.473 for +Revision 1.474 2008/07/24 20:23:03 cheshire + Should use randomized source ports and transaction IDs to avoid DNS cache poisoning -Revision 1.468.2.1 2008/07/29 19:10:53 mcguire - Use all configured DNS servers -merege 1.470 from +Revision 1.473 2008/07/18 21:37:42 mcguire + BTMM: alternate SSDP queries between multicast & unicast + +Revision 1.472 2008/07/01 01:39:59 mcguire + 64-bit fixes + +Revision 1.471 2008/06/26 17:24:11 mkrochma + BTMM: Stop listening on UDP 5351 for NAT Status Announcements + +Revision 1.470 2008/06/19 01:20:49 mcguire + Use all configured DNS servers + +Revision 1.469 2008/03/07 18:56:02 cheshire + dnsbugtest query every three seconds when source IP address of response doesn't match Revision 1.468 2008/03/06 02:48:34 mcguire write status to the DS @@ -195,7 +512,7 @@ Add new symbol "NATPMPAnnouncementPort" (5350) 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 +Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance code 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. @@ -679,6 +996,9 @@ Fixes to avoid code generation warning/error on FreeBSD 7 #endif #include "mDNSDebug.h" +#if APPLE_OSX_mDNSResponder +#include +#endif #ifdef __cplusplus extern "C" { @@ -767,51 +1087,62 @@ typedef enum // From RFC 1035 kDNSType_MINFO, // 14 Mailbox information kDNSType_MX, // 15 Mail Exchanger kDNSType_TXT, // 16 Arbitrary text string - 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_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_SINK, // 40 Kitchen sink (experimental) 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_NSEC, // 47 Denial of Existence kDNSType_DNSKEY, // 48 DNSKEY - kDNSType_DHCID, // 49 DHCID + kDNSType_DHCID, // 49 DHCP Client Identifier + kDNSType_NSEC3, // 50 Hashed Authenticated Denial of Existence + kDNSType_NSEC3PARAM, // 51 Hashed Authenticated Denial of Existence + + kDNSType_HIP = 55, // 55 Host Identity Protocol + + kDNSType_SPF = 99, // 99 Sender Policy Framework for E-Mail + kDNSType_UINFO, // 100 IANA-Reserved + kDNSType_UID, // 101 IANA-Reserved + kDNSType_GID, // 102 IANA-Reserved + kDNSType_UNSPEC, // 103 IANA-Reserved 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. + 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; // *************************************************************************** #if 0 +#pragma mark - #pragma mark - Simple types #endif @@ -856,11 +1187,17 @@ typedef struct mDNSInterfaceID_dummystruct { void *dummy; } *mDNSInterfaceID; // less than, add, multiply, increment, decrement, etc., are undefined for opaque identifiers, // and if you make the mistake of trying to do those using the NotAnInteger field, then you'll // find you get code that doesn't work consistently on big-endian and little-endian machines. -typedef packedunion { mDNSu8 b[ 2]; mDNSu16 NotAnInteger; } mDNSOpaque16; -typedef packedunion { mDNSu8 b[ 4]; mDNSu32 NotAnInteger; } mDNSOpaque32; +#if defined(_WIN32) + #pragma pack(push,2) +#endif +typedef union { mDNSu8 b[ 2]; mDNSu16 NotAnInteger; } mDNSOpaque16; +typedef union { 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 union { mDNSu8 b[ 8]; mDNSu16 w[4]; mDNSu32 l[2]; } mDNSOpaque64; +typedef union { mDNSu8 b[16]; mDNSu16 w[8]; mDNSu32 l[4]; } mDNSOpaque128; +#if defined(_WIN32) + #pragma pack(pop) +#endif typedef mDNSOpaque16 mDNSIPPort; // An IP port is a two-byte opaque identifier (not an integer) typedef mDNSOpaque32 mDNSv4Addr; // An IP address is a four-byte opaque identifier (not an integer) @@ -946,26 +1283,26 @@ typedef mDNSs32 mStatus; #define MAX_DOMAIN_LABEL 63 typedef struct { mDNSu8 c[ 64]; } domainlabel; // One label: length byte and up to 63 characters -// RFC 1034/1035 specify that a domain name, including length bytes, data bytes, and terminating zero, may be up to 255 bytes long -#define MAX_DOMAIN_NAME 255 -typedef struct { mDNSu8 c[256]; } domainname; // Up to 255 bytes of length-prefixed domainlabels +// RFC 1034/1035/2181 specify that a domain name, including length bytes, data bytes, and terminating zero, may be up to 256 bytes long +#define MAX_DOMAIN_NAME 256 +typedef struct { mDNSu8 c[256]; } domainname; // Up to 256 bytes of length-prefixed domainlabels typedef struct { mDNSu8 c[256]; } UTF8str255; // Null-terminated C string -// The longest legal textual form of a DNS name is 1005 bytes, including the C-string terminating NULL at the end. +// The longest legal textual form of a DNS name is 1009 bytes, including the C-string terminating NULL at the end. // Explanation: // When a native domainname object is converted to printable textual form using ConvertDomainNameToCString(), // non-printing characters are represented in the conventional DNS way, as '\ddd', where ddd is a three-digit decimal number. -// The longest legal domain name is 255 bytes, in the form of four labels as shown below: -// Length byte, 63 data bytes, length byte, 63 data bytes, length byte, 63 data bytes, length byte, 61 data bytes, zero byte. +// The longest legal domain name is 256 bytes, in the form of four labels as shown below: +// Length byte, 63 data bytes, length byte, 63 data bytes, length byte, 63 data bytes, length byte, 62 data bytes, zero byte. // Each label is encoded textually as characters followed by a trailing dot. // If every character has to be represented as a four-byte escape sequence, then this makes the maximum textual form four labels // plus the C-string terminating NULL as shown below: -// 63*4+1 + 63*4+1 + 63*4+1 + 61*4+1 + 1 = 1005. +// 63*4+1 + 63*4+1 + 63*4+1 + 62*4+1 + 1 = 1009. // Note that MAX_ESCAPED_DOMAIN_LABEL is not normally used: If you're only decoding a single label, escaping is usually not required. // It is for domain names, where dots are used as label separators, that proper escaping is vital. #define MAX_ESCAPED_DOMAIN_LABEL 254 -#define MAX_ESCAPED_DOMAIN_NAME 1005 +#define MAX_ESCAPED_DOMAIN_NAME 1009 // MAX_REVERSE_MAPPING_NAME // For IPv4: "123.123.123.123.in-addr.arpa." 30 bytes including terminating NUL @@ -996,12 +1333,13 @@ typedef struct mDNS_PlatformSupport_struct mDNS_PlatformSupport; typedef struct NATTraversalInfo_struct NATTraversalInfo; // 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 +// The actual definition of these structures appear in the appropriate platform support code typedef struct TCPSocket_struct TCPSocket; typedef struct UDPSocket_struct UDPSocket; // *************************************************************************** #if 0 +#pragma mark - #pragma mark - DNS Message structures #endif @@ -1049,6 +1387,87 @@ typedef struct tcpInfo_t // *************************************************************************** #if 0 +#pragma mark - +#pragma mark - Other Packet Format Structures +#endif + +typedef packedstruct + { + mDNSEthAddr dst; + mDNSEthAddr src; + mDNSOpaque16 ethertype; + } EthernetHeader; // 14 bytes + +typedef packedstruct + { + mDNSOpaque16 hrd; + mDNSOpaque16 pro; + mDNSu8 hln; + mDNSu8 pln; + mDNSOpaque16 op; + mDNSEthAddr sha; + mDNSv4Addr spa; + mDNSEthAddr tha; + mDNSv4Addr tpa; + } ARP_EthIP; // 28 bytes + +typedef packedstruct + { + mDNSu8 vlen; + mDNSu8 tos; + mDNSu16 totlen; + mDNSOpaque16 id; + mDNSOpaque16 flagsfrags; + mDNSu8 ttl; + mDNSu8 protocol; + mDNSu16 checksum; + mDNSv4Addr src; + mDNSv4Addr dst; + } IPv4Header; // 20 bytes + +typedef packedstruct + { + mDNSu32 vcf; // Version, Traffic Class, Flow Label + mDNSu16 len; // Payload Length + mDNSu8 protocol; // Type of next header: 0x06 = TCP, 0x11 = UDP, 0x3A = ICMPv6 + mDNSu8 ttl; // Hop Limit + mDNSv6Addr src; + mDNSv6Addr dst; + } IPv6Header; // 40 bytes + +typedef packedstruct + { + mDNSu8 type; // 0x87 == Neighbor Solicitation, 0x88 == Neighbor Advertisement + mDNSu8 code; + mDNSu16 checksum; + mDNSu32 reserved; + mDNSv6Addr target; + } IPv6ND; // 24 bytes + +typedef packedstruct + { + mDNSIPPort src; + mDNSIPPort dst; + mDNSu16 len; // Length including UDP header (ie. minimum value is 8 bytes) + mDNSu16 checksum; + } UDPHeader; // 8 bytes + +typedef packedstruct + { + mDNSIPPort src; + mDNSIPPort dst; + mDNSu32 seq; + mDNSu32 ack; + mDNSu8 offset; + mDNSu8 flags; + mDNSu16 window; + mDNSu16 checksum; + mDNSu16 urgent; + } TCPHeader; // 20 bytes + +// *************************************************************************** +#if 0 +#pragma mark - #pragma mark - Resource Record structures #endif @@ -1149,30 +1568,82 @@ typedef packedstruct mDNSu32 min; // Nominally the minimum record TTL for this zone, in seconds; also used for negative caching. } rdataSOA; -typedef packedstruct +// EDNS Option Code registrations are recorded in the "DNS EDNS0 Options" section of +// + +#define kDNSOpt_LLQ 1 +#define kDNSOpt_Lease 2 +#define kDNSOpt_NSID 3 +#define kDNSOpt_Owner 4 + +typedef struct { mDNSu16 vers; mDNSu16 llqOp; mDNSu16 err; // Or UDP reply port, in setup request + // Note: In the in-memory form, there's typically a two-byte space here, so that the following 64-bit id is word-aligned 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)) - -// NOTE: rdataOPT format may be repeated an arbitrary number of times in a single resource record +typedef struct + { + mDNSu8 vers; // Version number of this Owner OPT record + mDNSs8 seq; // Sleep/wake epoch + mDNSEthAddr HMAC; // Host's primary identifier (e.g. MAC of on-board Ethernet) + mDNSEthAddr IMAC; // Interface's MAC address (if different to primary MAC) + mDNSOpaque48 password; // Optional password + } OwnerOptData; + +// 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 updatelease; } OptData; + union { LLQOptData llq; mDNSu32 updatelease; OwnerOptData owner; } u; } rdataOPT; +// Space needed to put OPT records into a packet: +// Header 11 bytes (name 1, type 2, class 2, TTL 4, length 2) +// LLQ rdata 18 bytes (opt 2, len 2, vers 2, op 2, err 2, id 8, lease 4) +// Lease rdata 8 bytes (opt 2, len 2, lease 4) +// Owner rdata 12-24 (opt 2, len 2, owner 8-20) + +#define DNSOpt_Header_Space 11 +#define DNSOpt_LLQData_Space (4 + 2 + 2 + 2 + 8 + 4) +#define DNSOpt_LeaseData_Space (4 + 4) +#define DNSOpt_OwnerData_ID_Space (4 + 2 + 6) +#define DNSOpt_OwnerData_ID_Wake_Space (4 + 2 + 6 + 6) +#define DNSOpt_OwnerData_ID_Wake_PW4_Space (4 + 2 + 6 + 6 + 4) +#define DNSOpt_OwnerData_ID_Wake_PW6_Space (4 + 2 + 6 + 6 + 6) + +#define ValidOwnerLength(X) ( (X) == DNSOpt_OwnerData_ID_Space - 4 || \ + (X) == DNSOpt_OwnerData_ID_Wake_Space - 4 || \ + (X) == DNSOpt_OwnerData_ID_Wake_PW4_Space - 4 || \ + (X) == DNSOpt_OwnerData_ID_Wake_PW6_Space - 4 ) + +#define ValidDNSOpt(O) (((O)->opt == kDNSOpt_LLQ && (O)->optlen == DNSOpt_LLQData_Space - 4) || \ + ((O)->opt == kDNSOpt_Lease && (O)->optlen == DNSOpt_LeaseData_Space - 4) || \ + ((O)->opt == kDNSOpt_Owner && ValidOwnerLength((O)->optlen) ) ) + +#define DNSOpt_Owner_Space(O) (mDNSSameEthAddress(&(O)->u.owner.HMAC, &(O)->u.owner.IMAC) ? DNSOpt_OwnerData_ID_Space : DNSOpt_OwnerData_ID_Wake_Space) + +#define DNSOpt_Data_Space(O) ( \ + (O)->opt == kDNSOpt_LLQ ? DNSOpt_LLQData_Space : \ + (O)->opt == kDNSOpt_Lease ? DNSOpt_LeaseData_Space : \ + (O)->opt == kDNSOpt_Owner ? DNSOpt_Owner_Space(O) : 0x10000) + +// A maximal NSEC record is: +// 256 bytes domainname 'nextname' +// + 256 * 34 = 8704 bytes of bitmap data +// = 8960 bytes total +// For now we only support NSEC records encoding DNS types 0-255 and ignore the nextname (we always set it to be the same as the rrname), +// which gives us a fixed in-memory size of 32 bytes (256 bits) +typedef struct + { + mDNSu8 bitmap[32]; + } rdataNSEC; + // 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 @@ -1192,30 +1663,70 @@ typedef packedstruct // have them both be the same size. Making one smaller without making the other smaller won't actually save any memory. #define InlineCacheRDSize 68 -#define InlineCacheGroupNameSize 144 +// On 64-bit, the pointers in a CacheRecord are bigger, and that creates 8 bytes more space for the name in a CacheGroup +#if ENABLE_MULTI_PACKET_QUERY_SNOOPING + #if defined(_ILP64) || defined(__ILP64__) || defined(_LP64) || defined(__LP64__) || defined(_WIN64) + #define InlineCacheGroupNameSize 152 + #else + #define InlineCacheGroupNameSize 144 + #endif +#else + #if defined(_ILP64) || defined(__ILP64__) || defined(_LP64) || defined(__LP64__) || defined(_WIN64) + #define InlineCacheGroupNameSize 136 + #else + #define InlineCacheGroupNameSize 128 + #endif +#endif +// The RDataBody union defines the common rdata types that fit into our 264-byte limit 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 rdataSRV srv; - rdataOPT opt; // For EDNS0 OPT record; RDataBody may contain multiple variable-length rdataOPT objects packed together + rdataOPT opt[2]; // For EDNS0 OPT record; RDataBody may contain multiple variable-length rdataOPT objects packed together + rdataNSEC nsec; } RDataBody; +// The RDataBody2 union is the same as above, except it includes fields for the larger types like soa, rp, px +typedef union + { + mDNSu8 data[StandardAuthRDSize]; + mDNSv4Addr ipv4; // For 'A' record + domainname name; // For PTR, NS, CNAME, DNAME + rdataSOA soa; // This is large; not included in the normal RDataBody definition + UTF8str255 txt; + rdataMX mx; + rdataRP rp; // This is large; not included in the normal RDataBody definition + rdataPX px; // This is large; not included in the normal RDataBody definition + mDNSv6Addr ipv6; // For 'AAAA' record + rdataSRV srv; + rdataOPT opt[2]; // For EDNS0 OPT record; RDataBody may contain multiple variable-length rdataOPT objects packed together + rdataNSEC nsec; + } RDataBody2; + typedef struct { mDNSu16 MaxRDLength; // Amount of storage allocated for rdata (usually sizeof(RDataBody)) + mDNSu16 padding; // So that RDataBody is aligned on 32-bit boundary RDataBody u; } RData; + +// sizeofRDataHeader should be 4 bytes #define sizeofRDataHeader (sizeof(RData) - sizeof(RDataBody)) +// RData_small is a smaller version of the RData object, used for inline data storage embedded in a CacheRecord_struct +typedef struct + { + mDNSu16 MaxRDLength; // Storage allocated for data (may be greater than InlineCacheRDSize if additional storage follows this object) + mDNSu16 padding; // So that data is aligned on 32-bit boundary + mDNSu8 data[InlineCacheRDSize]; + } RData_small; + // Note: Within an mDNSRecordCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute() typedef void mDNSRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result); @@ -1227,13 +1738,14 @@ typedef void mDNSRecordUpdateCallback(mDNS *const m, AuthRecord *const rr, RData // *************************************************************************** #if 0 +#pragma mark - #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_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 * 2) // 2 hour lease life in seconds #define NATMAP_VERS 0 typedef enum @@ -1361,26 +1873,22 @@ struct NATTraversalInfo_struct // 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 + mDNSIPPort RequestedPort; // Requested external port; may be updated with actual value assigned by gateway mDNSu32 NATLease; // Requested lifetime in seconds (doesn't change) NATTraversalClientCallback clientCallback; void *clientContext; }; -typedef struct +typedef struct // Size is 36 bytes when compiling for 32-bit; 48 when compiling for 64-bit { 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) - 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 + // (In-memory storage may be larger, for structures containing 'holes', like SOA, + // or smaller, for NSEC where we don't bother storing the nextname field) + mDNSu16 rdestimate; // Upper bound on on-the-wire 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 @@ -1388,6 +1896,13 @@ typedef struct // ReconfirmAntecedents(), etc., use rdatahash as a pre-flight check to see // whether it's worth doing a full SameDomainName() call. If the rdatahash // is not a correct case-insensitive name hash, they'll get false negatives. + + // Grouping pointers together at the end of the structure improves the memory layout efficiency + 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) + const domainname *name; RData *rdata; // Pointer to storage for this rdata } ResourceRecord; @@ -1425,11 +1940,11 @@ struct AuthRecord_struct AuthRecord *next; // Next in list; first element of structure for efficiency reasons // Field Group 1: Common ResourceRecord fields - ResourceRecord resrec; + ResourceRecord resrec; // 36 bytes when compiling for 32-bit; 48 when compiling for 64-bit // Field Group 2: Persistent metadata for Authoritative Records 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 *Additional2; // Another additional (e.g. TXT for PTR 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 @@ -1438,15 +1953,22 @@ struct AuthRecord_struct 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 + OwnerOptData WakeUp; // Fpr Sleep Proxy records, MAC address of original owner (so we can wake it) + mDNSAddr AddressProxy; // For reverse-mapping Sleep Proxy PTR records, address in question + mDNSs32 TimeRcvd; // In platform time units + mDNSs32 TimeExpire; // In platform time units + + // Field Group 3: Transient state for Authoritative Records mDNSu8 Acknowledged; // Set if we've given the success callback to the client mDNSu8 ProbeCount; // Number of probes remaining before this record is valid (kDNSRecordTypeUnique) mDNSu8 AnnounceCount; // Number of announcements remaining (kDNSRecordTypeShared) mDNSu8 RequireGoodbye; // Set if this RR has been announced on the wire and will require a goodbye packet - mDNSu8 AnsweredLocalQ; // Set if this RR has been delivered to LocalOnly questions + mDNSu8 AnsweredLocalQ; // Set if this AuthRecord has been delivered to any local question (LocalOnly or mDNSInterface_Any) mDNSu8 IncludeInProbe; // Set if this RR is being put into a probe right now - mDNSInterfaceID ImmedAnswer; // Someone on this interface issued a query we need to answer (all-ones for all interfaces) mDNSu8 ImmedUnicast; // Set if we may send our response directly via unicast to the requester + mDNSInterfaceID SendNSECNow; // Set if we need to generate associated NSEC data for this rrname + mDNSInterfaceID ImmedAnswer; // Someone on this interface issued a query we need to answer (all-ones for all interfaces) #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES mDNSs32 ImmedAnswerMarkTime; #endif @@ -1474,10 +1996,10 @@ struct AuthRecord_struct // 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) + mDNSs32 expire; // In platform time units: 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 + mDNSOpaque16 updateid; // Identifier to match update request and response -- also used when transferring records to Sleep Proxy + const 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 @@ -1487,12 +2009,12 @@ struct AuthRecord_struct // 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 + RData *OrigRData; + RData *InFlightRData; + RData *QueuedRData; // Field Group 5: Large data objects go at the end domainname namestorage; @@ -1519,13 +2041,14 @@ struct CacheGroup_struct // Header object for a list of CacheRecords with the CacheRecord *members; // List of CacheRecords with this same name CacheRecord **rrcache_tail; // Tail end of that list domainname *name; // Common name for all CacheRecords in this list + // Size to here is 20 bytes when compiling 32-bit; 40 bytes when compiling 64-bit mDNSu8 namestorage[InlineCacheGroupNameSize]; }; struct CacheRecord_struct { CacheRecord *next; // Next in list; first element of structure for efficiency reasons - ResourceRecord resrec; + ResourceRecord resrec; // 36 bytes when compiling for 32-bit; 48 when compiling for 64-bit // Transient state for Cache Records CacheRecord *NextInKAList; // Link to the next element in the chain of known answers to send @@ -1536,16 +2059,19 @@ struct CacheRecord_struct DNSQuestion *CRActiveQuestion; // Points to an active question referencing this answer mDNSu32 UnansweredQueries; // Number of times we've issued a query for this record without getting an answer mDNSs32 LastUnansweredTime; // In platform time units; last time we incremented UnansweredQueries +#if ENABLE_MULTI_PACKET_QUERY_SNOOPING mDNSu32 MPUnansweredQ; // Multi-packet query handling: Number of times we've seen a query for this record mDNSs32 MPLastUnansweredQT; // Multi-packet query handling: Last time we incremented MPUnansweredQ mDNSu32 MPUnansweredKA; // Multi-packet query handling: Number of times we've seen this record in a KA list mDNSBool MPExpectingKA; // Multi-packet query handling: Set when we increment MPUnansweredQ; allows one KA +#endif CacheRecord *NextInCFList; // Set if this is in the list of records we just received with the cache flush bit set - - struct { mDNSu16 MaxRDLength; mDNSu8 data[InlineCacheRDSize]; } rdatastorage; // Storage for small records is right here + // Size to here is 76 bytes when compiling 32-bit; 104 bytes when compiling 64-bit + RData_small smallrdatastorage; // Storage for small records is right here (4 bytes header + 68 bytes data = 72 bytes) }; // Storage sufficient to hold either a CacheGroup header or a CacheRecord +// -- for best efficiency (to avoid wasted unused storage) they should be the same size typedef union CacheEntity_union CacheEntity; union CacheEntity_union { CacheEntity *next; CacheGroup cg; CacheRecord cr; }; @@ -1587,46 +2113,13 @@ typedef struct DNSServer mDNSInterfaceID interface; // For specialized uses; we can have DNS servers reachable over specific interfaces mDNSAddr addr; mDNSIPPort port; + mDNSOpaque16 testid; mDNSu32 flags; // 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; - -// A NetworkInterfaceInfo_struct serves two purposes: -// 1. It holds the address, PTR and HINFO records to advertise a given IP address on a given physical interface -// 2. It tells mDNSCore which physical interfaces are available; each physical interface has its own unique InterfaceID. -// Since there may be multiple IP addresses on a single physical interface, -// there may be multiple NetworkInterfaceInfo_structs with the same InterfaceID. -// In this case, to avoid sending the same packet n times, when there's more than one -// struct with the same InterfaceID, mDNSCore picks one member of the set to be the -// active representative of the set; all others have the 'InterfaceActive' flag unset. - -struct NetworkInterfaceInfo_struct - { - // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them. - NetworkInterfaceInfo *next; - - mDNSBool InterfaceActive; // Set if interface is sending & receiving packets (see comment above) - mDNSBool IPv4Available; // If InterfaceActive, set if v4 available on this InterfaceID - mDNSBool IPv6Available; // If InterfaceActive, set if v6 available on this InterfaceID - - // Standard AuthRecords that every Responder host should have (one per active IP address) - AuthRecord RR_A; // 'A' or 'AAAA' (address) record for our ".local" name - AuthRecord RR_PTR; // PTR (reverse lookup) record - AuthRecord RR_HINFO; - - // Client API fields: The client must set up these fields *before* calling mDNS_RegisterInterface() - mDNSInterfaceID InterfaceID; // Identifies physical interface; MUST NOT be 0, -1, or -2 - mDNSAddr ip; // The IPv4 or IPv6 address to advertise - mDNSAddr mask; - char ifname[64]; // Windows uses a GUID string for the interface name, which doesn't fit in 16 bytes - mDNSBool Advertise; // False if you are only searching on this interface - mDNSBool McastTxRx; // Send/Receive multicast on this { InterfaceID, address family } ? - }; - typedef struct ExtraResourceRecord_struct ExtraResourceRecord; struct ExtraResourceRecord_struct { @@ -1659,9 +2152,9 @@ struct ServiceRecordSet_struct // all required data is passed as parameters to that function. // Begin uDNS info **************** - // Hopefully much of this stuff can be simplified or eliminated + // All of these fields should be eliminated - // NOTE: The current uDNS code keeps an explicit list of registered services, and handles them + // 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. @@ -1670,7 +2163,7 @@ struct ServiceRecordSet_struct mDNSBool srs_uselease; // dynamic update contains (should contain) lease option 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; + ZoneData *srs_nta; mDNSOpaque16 id; domainname zone; // the zone that is updated mDNSAddr SRSUpdateServer; // primary name server for the record's zone !!!KRS not technically correct to cache longer than TTL @@ -1701,6 +2194,7 @@ struct ServiceRecordSet_struct // *************************************************************************** #if 0 +#pragma mark - #pragma mark - Question structures #endif @@ -1726,8 +2220,6 @@ typedef enum } LLQ_State; // LLQ constants -#define kDNSOpt_LLQ 1 -#define kDNSOpt_Lease 2 #define kLLQ_Vers 1 #define kLLQ_DefLease 7200 // 2 hours #define kLLQ_MAX_TRIES 3 // retry an operation 3 times max @@ -1737,9 +2229,6 @@ typedef enum #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)) - // LLQ Errror Codes enum { @@ -1815,6 +2304,7 @@ struct DNSQuestion_struct mDNSu32 CNAMEReferrals; // Count of how many CNAME redirections we've done // Wide Area fields. These are used internally by the uDNS core + UDPSocket *LocalSocket; DNSServer *qDNSServer; // Caching server for this query (in the absence of an SRV saying otherwise) mDNSu8 unansweredQueries;// The number of unanswered queries to this server @@ -1826,7 +2316,7 @@ struct DNSQuestion_struct // LLQ-specific fields. These fields are only meaningful when LongLived flag is set LLQ_State state; - mDNSu32 ReqLease; // seconds (relative) + mDNSu32 ReqLease; // seconds (relative) mDNSs32 expire; // ticks (absolute) mDNSs16 ntries; mDNSOpaque64 id; @@ -1836,7 +2326,6 @@ struct DNSQuestion_struct mDNSAddr Target; // Non-zero if you want to direct queries to a specific unicast target address mDNSIPPort TargetPort; // Must be set if Target is set mDNSOpaque16 TargetQID; // Must be set if Target is set - UDPSocket *LocalSocket; domainname qname; mDNSu16 qtype; mDNSu16 qclass; @@ -1925,13 +2414,82 @@ typedef struct ClientTunnel mDNSv6Addr rmt_inner; mDNSv4Addr rmt_outer; mDNSIPPort rmt_outer_port; - char b64keydata[32]; DNSQuestion q; } ClientTunnel; #endif // *************************************************************************** #if 0 +#pragma mark - +#pragma mark - NetworkInterfaceInfo_struct +#endif + +typedef struct NetworkInterfaceInfo_struct NetworkInterfaceInfo; + +// A NetworkInterfaceInfo_struct serves two purposes: +// 1. It holds the address, PTR and HINFO records to advertise a given IP address on a given physical interface +// 2. It tells mDNSCore which physical interfaces are available; each physical interface has its own unique InterfaceID. +// Since there may be multiple IP addresses on a single physical interface, +// there may be multiple NetworkInterfaceInfo_structs with the same InterfaceID. +// In this case, to avoid sending the same packet n times, when there's more than one +// struct with the same InterfaceID, mDNSCore picks one member of the set to be the +// active representative of the set; all others have the 'InterfaceActive' flag unset. + +struct NetworkInterfaceInfo_struct + { + // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them. + NetworkInterfaceInfo *next; + + mDNSu8 InterfaceActive; // Set if interface is sending & receiving packets (see comment above) + mDNSu8 IPv4Available; // If InterfaceActive, set if v4 available on this InterfaceID + mDNSu8 IPv6Available; // If InterfaceActive, set if v6 available on this InterfaceID + + DNSQuestion NetWakeBrowse; + DNSQuestion NetWakeResolve[3]; // For fault-tolerance, we try up to three Sleep Proxies + mDNSAddr SPSAddr[3]; + mDNSIPPort SPSPort[3]; + mDNSs32 NextSPSAttempt; // -1 if we're not currently attempting to register with any Sleep Proxy + mDNSs32 NextSPSAttemptTime; + + // Standard AuthRecords that every Responder host should have (one per active IP address) + AuthRecord RR_A; // 'A' or 'AAAA' (address) record for our ".local" name + AuthRecord RR_PTR; // PTR (reverse lookup) record + AuthRecord RR_HINFO; + + // Client API fields: The client must set up these fields *before* calling mDNS_RegisterInterface() + mDNSInterfaceID InterfaceID; // Identifies physical interface; MUST NOT be 0, -1, or -2 + mDNSAddr ip; // The IPv4 or IPv6 address to advertise + mDNSAddr mask; + mDNSEthAddr MAC; + char ifname[64]; // Windows uses a GUID string for the interface name, which doesn't fit in 16 bytes + mDNSu8 Advertise; // False if you are only searching on this interface + mDNSu8 McastTxRx; // Send/Receive multicast on this { InterfaceID, address family } ? + mDNSu8 NetWake; // Set if Wake-On-Magic-Packet is enabled on this interface + }; + +typedef struct SearchListElem + { + 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. +extern SearchListElem *SearchList; // This really ought to be part of mDNS_struct -- SC + +// *************************************************************************** +#if 0 +#pragma mark - #pragma mark - Main mDNS object, used to hold all the mDNS state #endif @@ -1941,7 +2499,15 @@ typedef void mDNSCallback(mDNS *const m, mStatus result); enum { - mDNS_KnownBug_PhantomInterfaces = 1 + mDNS_KnownBug_PhantomInterfaces = 1, + mDNS_KnownBug_LossySyslog = 2 // + }; + +enum + { + SleepState_Awake = 0, + SleepState_Transferring = 1, + SleepState_Sleeping = 2 }; struct mDNS_struct @@ -1955,9 +2521,11 @@ struct mDNS_struct mDNSu32 KnownBugs; mDNSBool CanReceiveUnicastOn5353; mDNSBool AdvertiseLocalAddresses; + mDNSBool DivertMulticastAdvertisements; // from interfaces that do not advertise local addresses to local-only mStatus mDNSPlatformStatus; mDNSIPPort UnicastPort4; mDNSIPPort UnicastPort6; + mDNSEthAddr PrimaryMAC; // Used as unique host ID mDNSCallback *MainCallback; void *MainContext; @@ -1967,7 +2535,9 @@ struct mDNS_struct mDNSu8 lock_rrcache; // For debugging: Set at times when these lists may not be modified mDNSu8 lock_Questions; mDNSu8 lock_Records; - #define MaxMsg 120 +#ifndef MaxMsg + #define MaxMsg 160 +#endif char MsgBuffer[MaxMsg]; // Temp storage used while building error log messages // Task Scheduling variables @@ -1975,19 +2545,24 @@ struct mDNS_struct mDNSs32 timenow; // The time that this particular activation of the mDNS code started mDNSs32 timenow_last; // The time the last time we ran mDNSs32 NextScheduledEvent; // Derived from values below - mDNSs32 ShutdownTime; // Set when we're shutting down, allows us to skip some unnecessary steps + mDNSs32 ShutdownTime; // Set when we're shutting down; allows us to skip some unnecessary steps mDNSs32 SuppressSending; // Don't send *any* packets during this time mDNSs32 NextCacheCheck; // Next time to refresh cache record before it expires 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 NextScheduledNATOp; // Next time to send NAT-traversal packets + mDNSs32 NextScheduledSPS; // Next time to purge expiring Sleep Proxy records 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) - mDNSBool SleepState; // Set if we're sleeping (send no more packets) + mDNSu8 SleepState; // Set if we're sleeping + mDNSu8 SleepSeqNum; // "Epoch number" of our current period of wakefulness + mDNSu8 SystemWakeOnLANEnabled; // Set if we want to register with a Sleep Proxy before going to sleep + mDNSs32 DelaySleep; // To inhibit re-sleeping too quickly right after wake + mDNSs32 SleepLimit; // Time window to allow deregistrations, etc., + // during which underying platform layer should inhibit system sleep + mDNSs32 NextScheduledSPRetry; // Time next sleep proxy registration action is required. Only valid if SleepLimit is nonzero. // These fields only required for mDNS Searcher... DNSQuestion *Questions; // List of all registered questions, active and inactive @@ -2018,7 +2593,7 @@ struct mDNS_struct mDNSu32 NumFailedProbes; mDNSs32 SuppressProbes; - // unicast-specific data + // Unicast-specific data 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 @@ -2043,7 +2618,7 @@ struct mDNS_struct mDNSBool RegisterSearchDomains; - // NAT traversal fields + // NAT-Traversal fields NATTraversalInfo LLQNAT; // Single shared NAT Traversal to receive inbound LLQ notifications NATTraversalInfo *NATTraversals; NATTraversalInfo *CurrentNATTraversal; @@ -2052,9 +2627,9 @@ struct mDNS_struct 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 + mDNSu16 LastNATMapResultCode; // Most recent error code for mappings tcpLNTInfo tcpAddrInfo; // legacy NAT traversal TCP connection info for external address tcpLNTInfo tcpDeviceInfo; // legacy NAT traversal TCP connection info for device info @@ -2070,12 +2645,27 @@ struct mDNS_struct mDNSu8 *UPnPRouterAddressString; // holds both the router's address and port mDNSu8 *UPnPSOAPAddressString; // holds both address and port for SOAP messages + // Sleep Proxy Server fields + mDNSu8 SPSType; // 0 = off, 10-99 encodes desirability metric + mDNSu8 SPSPortability; // 10-99 + mDNSu8 SPSMarginalPower; // 10-99 + mDNSu8 SPSTotalPower; // 10-99 + mDNSu8 SPSState; // 0 = off, 1 = running, 2 = shutting down, 3 = suspended during sleep + mDNSInterfaceID SPSProxyListChanged; + UDPSocket *SPSSocket; + ServiceRecordSet SPSRecords; + mDNSQuestionCallback *SPSBrowseCallback; // So the platform layer can do something useful with SPS browse results + int ProxyRecords; // Total number of records we're holding as proxy + #define MAX_PROXY_RECORDS 10000 /* DOS protection: 400 machines at 25 records each */ + #if APPLE_OSX_mDNSResponder ClientTunnel *TunnelClients; + uuid_t asl_uuid; // uuid for ASL logging #endif // Fixed storage, to avoid creating large objects on the stack - DNSMessage imsg; // Incoming message received from wire + // The imsg is declared as a union with a pointer type to enforce CPU-appropriate alignment + union { DNSMessage m; void *p; } imsg; // Incoming message received from wire DNSMessage omsg; // Outgoing message we're building LargeCacheRecord rec; // Resource Record extracted from received message }; @@ -2087,6 +2677,7 @@ struct mDNS_struct // *************************************************************************** #if 0 +#pragma mark - #pragma mark - Useful Static Constants #endif @@ -2096,29 +2687,34 @@ extern const mDNSv6Addr zerov6Addr; extern const mDNSEthAddr zeroEthAddr; extern const mDNSv4Addr onesIPv4Addr; extern const mDNSv6Addr onesIPv6Addr; +extern const mDNSEthAddr onesEthAddr; extern const mDNSAddr zeroAddr; +extern const OwnerOptData zeroOwner; + extern const mDNSInterfaceID mDNSInterface_Any; // Zero extern const mDNSInterfaceID mDNSInterface_LocalOnly; // Special value extern const mDNSInterfaceID mDNSInterface_Unicast; // Special value -extern const mDNSIPPort SSDPPort; - +extern const mDNSIPPort DiscardPort; +extern const mDNSIPPort SSHPort; extern const mDNSIPPort UnicastDNSPort; +extern const mDNSIPPort SSDPPort; +extern const mDNSIPPort NSIPCPort; 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 mDNSv4Addr AllSystemsMcast; extern const mDNSAddr AllDNSLinkGroup_v4; extern const mDNSAddr AllDNSLinkGroup_v6; extern const mDNSOpaque16 zeroID; +extern const mDNSOpaque16 onesID; extern const mDNSOpaque16 QueryFlags; extern const mDNSOpaque16 uQueryFlags; extern const mDNSOpaque16 ResponseFlags; @@ -2127,12 +2723,13 @@ extern const mDNSOpaque16 UpdateRespFlags; 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") +#define localdomain (*(const domainname *)"\x5" "local") +#define DeviceInfoName (*(const domainname *)"\xC" "_device-info" "\x4" "_tcp") +#define SleepProxyServiceType (*(const domainname *)"\xC" "_sleep-proxy" "\x4" "_udp") // *************************************************************************** #if 0 +#pragma mark - #pragma mark - Inline functions #endif @@ -2173,6 +2770,7 @@ mDNSinline mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v) // *************************************************************************** #if 0 +#pragma mark - #pragma mark - Main Client Functions #endif @@ -2197,6 +2795,10 @@ mDNSinline mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v) // In principle, a proxy-like registration service could manually create address records for its own machine too, // but this would be pointless extra effort when using mDNS_Init_AdvertiseLocalAddresses does that for you. // +// Note that a client-only device that wishes to prohibit multicast advertisements (e.g. from +// higher-layer API calls) must also set DivertMulticastAdvertisements in the mDNS structure and +// advertise local address(es) on a loopback interface. +// // When mDNS has finished setting up the client's callback is called // A client can also spin and poll the mDNSPlatformStatus field to see when it changes from mStatus_Waiting to mStatus_NoError // @@ -2235,6 +2837,7 @@ extern mStatus mDNS_Init (mDNS *const m, mDNS_PlatformSupport *const p, #define mDNS_Init_NoInitCallback mDNSNULL #define mDNS_Init_NoInitCallbackContext mDNSNULL +extern void mDNS_ConfigChanged(mDNS *const m); extern void mDNS_GrowCache (mDNS *const m, CacheEntity *storage, mDNSu32 numrecords); extern void mDNS_StartExit (mDNS *const m); extern void mDNS_FinalExit (mDNS *const m); @@ -2264,6 +2867,7 @@ extern DomainAuthInfo *GetAuthInfoForName(mDNS *m, const domainname *const name) // *************************************************************************** #if 0 +#pragma mark - #pragma mark - Platform support functions that are accessible to the client layer too #endif @@ -2271,6 +2875,7 @@ extern mDNSs32 mDNSPlatformOneSecond; // *************************************************************************** #if 0 +#pragma mark - #pragma mark - General utility and helper functions #endif @@ -2315,6 +2920,9 @@ extern mStatus mDNS_RegisterNoSuchService(mDNS *const m, AuthRecord *const rr, const mDNSInterfaceID InterfaceID, mDNSRecordCallback Callback, void *Context); #define mDNS_DeregisterNoSuchService mDNS_Deregister +extern void mDNS_SetupQuestion(DNSQuestion *const q, const mDNSInterfaceID InterfaceID, const domainname *const name, + const mDNSu16 qtype, mDNSQuestionCallback *const callback, void *const context); + extern mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question, const domainname *const srv, const domainname *const domain, const mDNSInterfaceID InterfaceID, mDNSBool ForceMCast, mDNSQuestionCallback *Callback, void *Context); @@ -2348,6 +2956,7 @@ extern DNSServer *GetServerForName(mDNS *m, const domainname *name); // *************************************************************************** #if 0 +#pragma mark - #pragma mark - DNS name utility functions #endif @@ -2370,10 +2979,14 @@ extern mDNSBool SameDomainName(const domainname *const d1, const domainname *con 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 +#define FirstLabel(X) ((const domainlabel *)(X)) +#define SecondLabel(X) ((const domainlabel *)&(X)->c[1 + (X)->c[0]]) +extern const mDNSu8 *LastLabel(const domainname *d); + // 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 DomainNameLengthLimit(const domainname *const name, const mDNSu8 *limit); -#define DomainNameLength(name) DomainNameLengthLimit((name), (name)->c + MAX_DOMAIN_NAME + 1) +#define DomainNameLength(name) DomainNameLengthLimit((name), (name)->c + MAX_DOMAIN_NAME) // 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. @@ -2398,7 +3011,7 @@ extern mDNSu8 *MakeDomainNameFromDNSNameString (domainname *const name, const // When using ConvertDomainLabelToCString, the target buffer must be MAX_ESCAPED_DOMAIN_LABEL (254) bytes long // to guarantee there will be no buffer overrun. It is only safe to use a buffer shorter than this in rare cases // where the label is known to be constrained somehow (for example, if the label is known to be either "_tcp" or "_udp"). -// Similarly, when using ConvertDomainNameToCString, the target buffer must be MAX_ESCAPED_DOMAIN_NAME (1005) bytes long. +// Similarly, when using ConvertDomainNameToCString, the target buffer must be MAX_ESCAPED_DOMAIN_NAME (1009) bytes long. // See definitions of MAX_ESCAPED_DOMAIN_LABEL and MAX_ESCAPED_DOMAIN_NAME for more detailed explanation. extern char *ConvertDomainLabelToCString_withescape(const domainlabel *const name, char *cstr, char esc); #define ConvertDomainLabelToCString_unescaped(D,C) ConvertDomainLabelToCString_withescape((D), (C), 0) @@ -2425,6 +3038,7 @@ extern mDNSBool DeconstructServiceName(const domainname *const fqdn, domainlabel // *************************************************************************** #if 0 +#pragma mark - #pragma mark - Other utility functions and macros #endif @@ -2437,7 +3051,7 @@ extern mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va extern mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...) IS_A_PRINTF_STYLE_FUNCTION(3,4); extern mDNSu32 NumCacheRecordsForInterfaceID(const mDNS *const m, mDNSInterfaceID id); extern char *DNSTypeName(mDNSu16 rrtype); -extern char *GetRRDisplayString_rdb(const ResourceRecord *rr, RDataBody *rd, char *buffer); +extern char *GetRRDisplayString_rdb(const ResourceRecord *const rr, const RDataBody *const rd1, char *const buffer); #define RRDisplayString(m, rr) GetRRDisplayString_rdb(rr, &(rr)->rdata->u, (m)->MsgBuffer) #define ARDisplayString(m, rr) GetRRDisplayString_rdb(&(rr)->resrec, &(rr)->resrec.rdata->u, (m)->MsgBuffer) #define CRDisplayString(m, rr) GetRRDisplayString_rdb(&(rr)->resrec, &(rr)->resrec.rdata->u, (m)->MsgBuffer) @@ -2448,20 +3062,22 @@ extern mDNSBool mDNSv4AddrIsRFC1918(mDNSv4Addr *addr); // returns true for RFC1 #define mDNSSameIPPort(A,B) ((A).NotAnInteger == (B).NotAnInteger) #define mDNSSameOpaque16(A,B) ((A).NotAnInteger == (B).NotAnInteger) +#define mDNSSameOpaque32(A,B) ((A).NotAnInteger == (B).NotAnInteger) +#define mDNSSameOpaque64(A,B) ((A)->l[0] == (B)->l[0] && (A)->l[1] == (B)->l[1]) + #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 mDNSIPPortIsZero(A) ((A).NotAnInteger == 0) +#define mDNSOpaque16IsZero(A) ((A).NotAnInteger == 0) +#define mDNSOpaque64IsZero(A) (((A)->l[0] | (A)->l[1] ) == 0) +#define mDNSIPv4AddressIsZero(A) ((A).NotAnInteger == 0) +#define mDNSIPv6AddressIsZero(A) (((A).l[0] | (A).l[1] | (A).l[2] | (A).l[3]) == 0) +#define mDNSEthAddressIsZero(A) (((A).w[0] | (A).w[1] | (A).w[2] ) == 0) -#define mDNSIPv4AddressIsOnes(A) mDNSSameIPv4Address((A), onesIPv4Addr) -#define mDNSIPv6AddressIsOnes(A) mDNSSameIPv6Address((A), onesIPv6Addr) +#define mDNSIPv4AddressIsOnes(A) ((A).NotAnInteger == 0xFFFFFFFF) +#define mDNSIPv6AddressIsOnes(A) (((A).l[0] & (A).l[1] & (A).l[2] & (A).l[3]) == 0xFFFFFFFF) #define mDNSAddressIsAllDNSLinkGroup(X) ( \ ((X)->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address((X)->ip.v4, AllDNSLinkGroup_v4.ip.v4)) || \ @@ -2492,6 +3108,7 @@ extern mDNSBool mDNSv4AddrIsRFC1918(mDNSv4Addr *addr); // returns true for RFC1 // *************************************************************************** #if 0 +#pragma mark - #pragma mark - Authentication Support #endif @@ -2507,6 +3124,8 @@ extern mDNSBool mDNSv4AddrIsRFC1918(mDNSv4Addr *addr); // returns true for RFC1 extern mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info, const domainname *domain, const domainname *keyname, const char *b64keydata, mDNSBool AutoTunnel); +extern void RecreateNATMappings(mDNS *const m); + // Hostname/Unicast Interface Configuration // All hostnames advertised point to one IPv4 address and/or one IPv6 address, set via SetPrimaryInterfaceInfo. Invoking this routine @@ -2528,6 +3147,7 @@ extern void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCa extern void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn); extern void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router); extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port); +extern void PushDNSServerToEnd(mDNS *const m, DNSQuestion *q); extern void mDNS_AddSearchDomain(const domainname *const domain); // We use ((void *)0) here instead of mDNSNULL to avoid compile warnings on gcc 4.2 @@ -2563,6 +3183,7 @@ extern mDNSBool DNSDigest_VerifyMessage(DNSMessage *msg, mDNSu8 *end, LargeCache // *************************************************************************** #if 0 +#pragma mark - #pragma mark - PlatformSupport interface #endif @@ -2581,7 +3202,7 @@ extern mDNSBool DNSDigest_VerifyMessage(DNSMessage *msg, mDNSu8 *end, LargeCache // Note: mDNSPlatformMemAllocate/mDNSPlatformMemFree are only required for handling oversized resource records and unicast DNS. // If your target platform has a well-defined specialized application, and you know that all the records it uses // are InlineCacheRDSize or less, then you can just make a simple mDNSPlatformMemAllocate() stub that always returns -// NULL. InlineCacheRDSize is a compile-time constant, which is set by default to 64. If you need to handle records +// NULL. InlineCacheRDSize is a compile-time constant, which is set by default to 68. If you need to handle records // a little larger than this and you don't want to have to implement run-time allocation and freeing, then you // can raise the value of this constant to a suitable value (at the expense of increased memory usage). // @@ -2614,7 +3235,19 @@ extern void mDNSPlatformMemZero ( void *dst, mDNSu extern void * mDNSPlatformMemAllocate (mDNSu32 len); #endif extern void mDNSPlatformMemFree (void *mem); + +// If the platform doesn't have a strong PRNG, we define a naive multiply-and-add based on a seed +// from the platform layer. Long-term, we should embed an arc4 implementation, but the strength +// will still depend on the randomness of the seed. +#if !defined(_PLATFORM_HAS_STRONG_PRNG_) && (_BUILDING_XCODE_PROJECT_ || defined(_WIN32)) +#define _PLATFORM_HAS_STRONG_PRNG_ 1 +#endif +#if _PLATFORM_HAS_STRONG_PRNG_ +extern mDNSu32 mDNSPlatformRandomNumber(void); +#else extern mDNSu32 mDNSPlatformRandomSeed (void); +#endif // _PLATFORM_HAS_STRONG_PRNG_ + extern mStatus mDNSPlatformTimeInit (void); extern mDNSs32 mDNSPlatformRawTime (void); extern mDNSs32 mDNSPlatformUTC (void); @@ -2623,7 +3256,12 @@ extern mDNSs32 mDNSPlatformUTC (void); #if MDNS_DEBUGMSGS extern void mDNSPlatformWriteDebugMsg(const char *msg); #endif -extern void mDNSPlatformWriteLogMsg(const char *ident, const char *msg, int flags); +extern void mDNSPlatformWriteLogMsg(const char *ident, const char *msg, mDNSLogLevel_t loglevel); + +#if APPLE_OSX_mDNSResponder +// Utility function for ASL logging +mDNSexport void mDNSASLLog(uuid_t *uuid, const char *subdomain, const char *result, const char *signature, const char *fmt, ...); +#endif // 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 @@ -2665,6 +3303,10 @@ extern long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long extern long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len); extern UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport); extern void mDNSPlatformUDPClose(UDPSocket *sock); +extern void mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd); +extern void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID); +extern void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID); +extern void mDNSPlatformSetLocalARP(const mDNSv4Addr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID); extern void mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst); // mDNSPlatformTLSSetupCerts/mDNSPlatformTLSTearDownCerts used by dnsextd @@ -2685,6 +3327,7 @@ extern void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID Interface extern mStatus LNT_GetExternalAddress(mDNS *m); extern mStatus LNT_MapPort(mDNS *m, NATTraversalInfo *n); extern mStatus LNT_UnmapPort(mDNS *m, NATTraversalInfo *n); +extern void LNT_ClearState(mDNS *const m); #endif // _LEGACY_NAT_TRAVERSAL_ // The core mDNS code provides these functions, for the platform support code to call at appropriate times @@ -2723,20 +3366,37 @@ extern mStatus LNT_UnmapPort(mDNS *m, NATTraversalInfo *n); // not lightweight second-by-second CPU power management modes.) extern void mDNS_SetFQDN(mDNS *const m); +extern void mDNS_ActivateNetWake_internal (mDNS *const m, NetworkInterfaceInfo *set); +extern void mDNS_DeactivateNetWake_internal(mDNS *const m, NetworkInterfaceInfo *set); extern mStatus mDNS_RegisterInterface (mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping); extern void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping); 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, const mDNSAddr *const dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID); +extern void mDNSCoreRestartQueries(mDNS *const m); +extern mDNSBool mDNSCoreHaveAdvertisedMulticastServices(mDNS *const m); extern void mDNSCoreMachineSleep(mDNS *const m, mDNSBool wake); +extern mDNSBool mDNSCoreReadyForSleep(mDNS *m); +extern mDNSs32 mDNSCoreIntervalToNextWake(mDNS *const m, mDNSs32 now); + +extern void mDNSCoreBeSleepProxyServer(mDNS *const m, mDNSu8 sps, mDNSu8 port, mDNSu8 marginalpower, mDNSu8 totpower); +extern void mDNSCoreReceiveRawPacket (mDNS *const m, const mDNSu8 *const p, const mDNSu8 *const end, const mDNSInterfaceID InterfaceID); 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 MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr, + const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds, mDNSInterfaceID InterfaceID); extern void CompleteDeregistration(mDNS *const m, AuthRecord *rr); +extern void FindSPSInCache(mDNS *const m, const DNSQuestion *const q, const CacheRecord *sps[3]); +#define PrototypeSPSName(X) ((X)[0] >= 11 && (X)[3] == '-' && (X)[ 4] == '9' && (X)[ 5] == '9' && \ + (X)[6] == '-' && (X)[ 7] == '9' && (X)[ 8] == '9' && \ + (X)[9] == '-' && (X)[10] == '9' && (X)[11] == '9' ) +#define ValidSPSName(X) ((X)[0] >= 5 && mDNSIsDigit((X)[1]) && mDNSIsDigit((X)[2]) && mDNSIsDigit((X)[4]) && mDNSIsDigit((X)[5])) +#define SPSMetric(X) (!ValidSPSName(X) || PrototypeSPSName(X) ? 1000000 : \ + ((X)[1]-'0') * 100000 + ((X)[2]-'0') * 10000 + ((X)[4]-'0') * 1000 + ((X)[5]-'0') * 100 + ((X)[7]-'0') * 10 + ((X)[8]-'0')) extern void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheRecord *const rr, const QC_result AddRecord); // For now this AutoTunnel stuff is specific to Mac OS X. @@ -2750,6 +3410,7 @@ extern void UpdateAutoTunnelDomainStatuses(const mDNS *const m); // *************************************************************************** #if 0 +#pragma mark - #pragma mark - Compile-Time assertion checks #endif @@ -2775,28 +3436,36 @@ struct CompileTimeAssertionChecks_mDNS char assert9[(sizeof(mDNSOpaque16) == 2 ) ? 1 : -1]; char assertA[(sizeof(mDNSOpaque32) == 4 ) ? 1 : -1]; char assertB[(sizeof(mDNSOpaque128) == 16 ) ? 1 : -1]; - char assertC[(sizeof(CacheRecord ) >= sizeof(CacheGroup) ) ? 1 : -1]; + char assertC[(sizeof(CacheRecord ) == sizeof(CacheGroup) ) ? 1 : -1]; char assertD[(sizeof(int) >= 4 ) ? 1 : -1]; char assertE[(StandardAuthRDSize >= 256 ) ? 1 : -1]; + char assertF[(sizeof(EthernetHeader) == 14 ) ? 1 : -1]; + char assertG[(sizeof(ARP_EthIP ) == 28 ) ? 1 : -1]; + char assertH[(sizeof(IPv4Header ) == 20 ) ? 1 : -1]; + char assertI[(sizeof(IPv6Header ) == 40 ) ? 1 : -1]; + char assertJ[(sizeof(IPv6ND ) == 24 ) ? 1 : -1]; + char assertK[(sizeof(UDPHeader ) == 8 ) ? 1 : -1]; + char assertL[(sizeof(TCPHeader ) == 20 ) ? 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_RDataBody [(sizeof(RDataBody) == 264) ? 1 : -1]; char sizecheck_ResourceRecord [(sizeof(ResourceRecord) <= 56) ? 1 : -1]; - char sizecheck_AuthRecord [(sizeof(AuthRecord) <= 1416) ? 1 : -1]; - char sizecheck_CacheRecord [(sizeof(CacheRecord) <= 200) ? 1 : -1]; - char sizecheck_CacheGroup [(sizeof(CacheGroup) <= 184) ? 1 : -1]; - char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 720) ? 1 : -1]; - char sizecheck_ZoneData [(sizeof(ZoneData) <= 1552) ? 1 : -1]; + char sizecheck_AuthRecord [(sizeof(AuthRecord) <= 1000) ? 1 : -1]; + char sizecheck_CacheRecord [(sizeof(CacheRecord) <= 176) ? 1 : -1]; + char sizecheck_CacheGroup [(sizeof(CacheGroup) <= 176) ? 1 : -1]; + char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 728) ? 1 : -1]; + char sizecheck_ZoneData [(sizeof(ZoneData) <= 1560) ? 1 : -1]; char sizecheck_NATTraversalInfo [(sizeof(NATTraversalInfo) <= 192) ? 1 : -1]; - char sizecheck_HostnameInfo [(sizeof(HostnameInfo) <= 3304) ? 1 : -1]; + char sizecheck_HostnameInfo [(sizeof(HostnameInfo) <= 2800) ? 1 : -1]; char sizecheck_DNSServer [(sizeof(DNSServer) <= 312) ? 1 : -1]; - char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 4392) ? 1 : -1]; - char sizecheck_ServiceRecordSet [(sizeof(ServiceRecordSet) <= 6248) ? 1 : -1]; - char sizecheck_DomainAuthInfo [(sizeof(DomainAuthInfo) <= 6544) ? 1 : -1]; - char sizecheck_ServiceInfoQuery [(sizeof(ServiceInfoQuery) <= 2912) ? 1 : -1]; + char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 5968) ? 1 : -1]; + char sizecheck_ServiceRecordSet [(sizeof(ServiceRecordSet) <= 5500) ? 1 : -1]; + char sizecheck_DomainAuthInfo [(sizeof(DomainAuthInfo) <= 5500) ? 1 : -1]; + char sizecheck_ServiceInfoQuery [(sizeof(ServiceInfoQuery) <= 2944) ? 1 : -1]; #if APPLE_OSX_mDNSResponder - char sizecheck_ClientTunnel [(sizeof(ClientTunnel) <= 1064) ? 1 : -1]; + char sizecheck_ClientTunnel [(sizeof(ClientTunnel) <= 1072) ? 1 : -1]; #endif }; diff --git a/mDNSCore/uDNS.c b/mDNSCore/uDNS.c index d649f19..962c536 100755 --- a/mDNSCore/uDNS.c +++ b/mDNSCore/uDNS.c @@ -22,22 +22,209 @@ Change History (most recent first): $Log: uDNS.c,v $ -Revision 1.553.2.4 2008/07/29 20:47:44 mcguire - Should use randomized source ports and transaction IDs to avoid DNS cache poisoning -merge r1.567 & r1.568 from +Revision 1.617 2009/06/30 20:51:02 cheshire +Improved "Error! Tried to add a NAT traversal that's already in the active list" debugging message -Revision 1.553.2.3 2008/07/29 19:09:21 mcguire - Use all configured DNS servers -merge r1.558-r1.565 from +Revision 1.616 2009/05/27 20:29:36 cheshire + Sleep is delayed by 10 seconds if BTMM is on +After receiving confirmation of LLQ deletion, need to schedule another evaluation of whether we're ready to sleep yet -Revision 1.553.2.2 2008/07/29 18:50:09 mcguire - LLQ refresh randomization not working properly -merge r1.555 & r1.556 from +Revision 1.615 2009/05/05 01:32:50 jessic2 + regservice_callback: instance->request is NULL 0 -- Clean up spurious logs resulting from fixing this bug. -Revision 1.553.2.1 2008/03/14 20:11:25 mcguire +Revision 1.614 2009/04/24 02:17:57 mcguire + uDNS: Not always respecting preference order of DNS servers + +Revision 1.613 2009/04/23 22:06:29 cheshire +Added CacheRecord and InterfaceID parameters to MakeNegativeCacheRecord, in preparation for: + Return negative answers when host knows authoritatively that no answer exists + +Revision 1.612 2009/04/22 01:19:57 jessic2 + Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32 + +Revision 1.611 2009/04/15 20:42:51 mcguire + uDNS: Treat RCODE 5 (Refused) responses as failures + +Revision 1.610 2009/04/15 01:10:39 jessic2 + BTMM: Add support for setting kDNSServiceErr_NoSuchRecord in DynamicStore + +Revision 1.609 2009/04/11 00:19:45 jessic2 + Daemon: Should be able to turn on LogOperation dynamically + +Revision 1.608 2009/04/06 23:44:59 cheshire + mDNSResponder thrashing kernel lock in the UDP close path, hurting SPECweb performance + +Revision 1.607 2009/04/02 22:36:34 jessic2 +Fix crash when calling debugf with null opt + +Revision 1.606 2009/03/26 03:59:00 jessic2 +Changes for + +Revision 1.605 2009/03/04 00:40:14 cheshire +Updated DNS server error codes to be more consistent with definitions at + + +Revision 1.604 2009/02/27 03:08:47 cheshire + Crash while shutting down when "local" is in the user's DNS searchlist + +Revision 1.603 2009/02/27 02:56:57 cheshire +Moved struct SearchListElem definition from uDNS.c into mDNSEmbeddedAPI.h + +Revision 1.602 2009/02/13 06:29:54 cheshire +Converted LogOperation messages to LogInfo + +Revision 1.601 2009/02/12 20:57:25 cheshire +Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch + +Revision 1.600 2009/01/31 21:05:12 cheshire +Improved "Failed to obtain NAT port mapping" debugging log message + +Revision 1.599 2009/01/23 00:38:36 mcguire + BTMM: Doesn't work with Linksys WRT54GS firmware 4.71.1 + +Revision 1.598 2009/01/21 03:43:57 mcguire + BTMM: Add support for setting kDNSServiceErr_NATPortMappingDisabled in DynamicStore + +Revision 1.597 2009/01/10 01:55:49 cheshire +Added LogOperation message showing when domains are added and removed in FoundDomain + +Revision 1.596 2008/12/19 20:23:33 mcguire + Lots of duplicate log messages about failure to bind to NAT-PMP Announcement port + +Revision 1.595 2008/12/18 23:32:19 mcguire + BTMM: Include the question in the LLQ notification acknowledgment + +Revision 1.594 2008/12/10 02:25:31 cheshire +Minor fixes to use of LogClientOperations symbol + +Revision 1.593 2008/12/10 02:11:42 cheshire +ARMv5 compiler doesn't like uncommented stuff after #endif + +Revision 1.592 2008/12/06 01:42:55 mcguire + Need to exponentially back-off after failure to get public address + +Revision 1.591 2008/12/06 00:17:11 cheshire + mDNS_StopNATOperation doesn't handle duplicate NAT mapping requests properly +Refinement: For duplicate ssh mappings we want to suppress the syslog warning message, but not the "unmap = mDNSfalse" + +Revision 1.590 2008/12/04 20:57:36 mcguire +fix build + +Revision 1.589 2008/12/04 02:24:09 cheshire +Improved NAT-PMP debugging messages + +Revision 1.588 2008/11/26 20:38:08 cheshire +Changed some "LogOperation" debugging messages to "debugf" + +Revision 1.587 2008/11/26 19:53:26 cheshire +Don't overwrite srs->NATinfo.IntPort in StartSRVNatMap() + +Revision 1.586 2008/11/25 23:43:07 cheshire + Crashes at ServiceRegistrationGotZoneData + 397 +Made code more defensive to guard against ServiceRegistrationGotZoneData being called with invalid ServiceRecordSet object + +Revision 1.585 2008/11/25 22:46:30 cheshire +For ease of code searching, renamed ZoneData field of ServiceRecordSet_struct from "nta" to "srs_nta" + +Revision 1.584 2008/11/24 19:46:40 cheshire +When sending query over TCP, don't include LLQ option when we're talking to a conventional DNS server or cache + +Revision 1.583 2008/11/21 00:34:58 cheshire + mDNS_StopNATOperation doesn't handle duplicate NAT mapping requests properly + +Revision 1.582 2008/11/20 02:23:37 mcguire + need to handle URLBase + +Revision 1.581 2008/11/20 01:51:19 cheshire +Exported RecreateNATMappings so it's callable from other files + +Revision 1.580 2008/11/13 19:08:45 cheshire +Fixed code to handle rdataOPT properly + +Revision 1.579 2008/11/07 00:18:01 mcguire + uDNS: Supress reverse DNS query until required + +Revision 1.578 2008/11/04 22:21:46 cheshire +Changed zone field of AuthRecord_struct from domainname to pointer, saving 252 bytes per AuthRecord + +Revision 1.577 2008/10/29 21:37:01 cheshire +Removed some old debugging messages + +Revision 1.576 2008/10/23 22:25:57 cheshire +Renamed field "id" to more descriptive "updateid" + +Revision 1.575 2008/10/20 02:07:49 mkrochma + Remove Note: DNS Server for domain registered more than once + +Revision 1.574 2008/10/14 19:06:45 cheshire +In uDNS_ReceiveMsg(), only do checkUpdateResult() for uDNS records + +Revision 1.573 2008/09/25 20:43:44 cheshire + Stop using separate m->ServiceRegistrations list +In UpdateSRVRecords, call mDNS_SetFQDN(m) to update AutoTarget SRV records on the main m->ResourceRecords list + +Revision 1.572 2008/09/24 23:48:05 cheshire +Don't need to pass whole ServiceRecordSet reference to GetServiceTarget; +it only needs to access the embedded SRV member of the set + +Revision 1.571 2008/09/23 22:56:53 cheshire + Remove dnsbugtest query + +Revision 1.570 2008/09/23 01:30:18 cheshire +The putLLQ() routine was not setting the OPT record's rrclass to NormalMaxDNSMessageData + +Revision 1.569 2008/07/25 22:34:11 mcguire +fix sizecheck issues for 64bit + +Revision 1.568 2008/07/24 20:23:03 cheshire + Should use randomized source ports and transaction IDs to avoid DNS cache poisoning + +Revision 1.567 2008/07/01 01:40:00 mcguire + 64-bit fixes + +Revision 1.566 2008/06/26 17:24:11 mkrochma + BTMM: Stop listening on UDP 5351 for NAT Status Announcements + +Revision 1.565 2008/06/21 19:06:58 mcguire + Use all configured DNS servers + +Revision 1.564 2008/06/19 23:42:03 mcguire + Use all configured DNS servers + +Revision 1.563 2008/06/19 17:46:14 mcguire + Use all configured DNS servers +Don't do extra work for log messages if we're not going to log + +Revision 1.562 2008/06/19 17:35:19 mcguire + Use all configured DNS servers +cleanup log messages +check for null pointers + +Revision 1.561 2008/06/19 01:20:49 mcguire + Use all configured DNS servers + +Revision 1.560 2008/05/31 01:51:09 mcguire +fixed typo in log message + +Revision 1.559 2008/04/15 22:37:58 mkrochma +Change LogMsg to LogOperation + +Revision 1.558 2008/03/17 18:02:35 mkrochma +Add space to log message for consistency + +Revision 1.557 2008/03/14 19:58:38 mcguire BTMM: Need ability to identify version of mDNSResponder client Make sure we add the record when sending LLQ refreshes +Revision 1.556 2008/03/07 23:55:05 cheshire + LLQ refresh randomization not working properly + +Revision 1.555 2008/03/07 23:25:56 cheshire +Improved debugging messages + +Revision 1.554 2008/03/07 18:56:03 cheshire + dnsbugtest query every three seconds when source IP address of response doesn't match + Revision 1.553 2008/03/06 02:48:34 mcguire write status to the DS @@ -361,7 +548,7 @@ Fixed minor error introduced in 1.379 (an "if" statement was deleted but the "el 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 +Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance code 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. @@ -1144,25 +1331,12 @@ Revision 1.227 2006/01/09 20:47:05 cheshire #pragma warning(disable:4706) #endif -typedef struct SearchListElem - { - 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; +mDNSexport 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 @@ -1233,7 +1407,7 @@ mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mStatus SendErr) // Code for stress-testing registration renewal code if (rr->expire && rr->expire - m->timenow > mDNSPlatformOneSecond * 120) { - LogOperation("Adjusting expiry from %d to 120 seconds for %s", + LogInfo("Adjusting expiry from %d to 120 seconds for %s", (rr->expire - m->timenow) / mDNSPlatformOneSecond, ARDisplayString(m, rr)); rr->expire = m->timenow + mDNSPlatformOneSecond * 120; } @@ -1243,10 +1417,8 @@ mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mStatus SendErr) { mDNSs32 remaining = rr->expire - m->timenow; rr->ThisAPInterval = remaining/2 + mDNSRandom(remaining/10); - LogOperation("SetRecordRetry refresh in %4d of %4d for %s", - rr->ThisAPInterval / mDNSPlatformOneSecond, - (rr->expire - m->timenow) / mDNSPlatformOneSecond, - ARDisplayString(m, rr)); + debugf("SetRecordRetry refresh in %4d of %4d for %s", + rr->ThisAPInterval / mDNSPlatformOneSecond, (rr->expire - m->timenow) / mDNSPlatformOneSecond, ARDisplayString(m, rr)); return; } @@ -1262,7 +1434,7 @@ mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mStatus SendErr) if (rr->ThisAPInterval > 30 * 60 * mDNSPlatformOneSecond) rr->ThisAPInterval = 30 * 60 * mDNSPlatformOneSecond; - LogOperation("SetRecordRetry retry in %4d for %s", rr->ThisAPInterval / mDNSPlatformOneSecond, ARDisplayString(m, rr)); + LogInfo("SetRecordRetry retry in %4d for %s", rr->ThisAPInterval / mDNSPlatformOneSecond, ARDisplayString(m, rr)); } // *************************************************************************** @@ -1273,44 +1445,53 @@ mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mStatus SendErr) mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port) { DNSServer **p = &m->DNSServers; - + DNSServer *tmp = mDNSNULL; + if (!d) d = (const domainname *)""; - LogOperation("mDNS_AddDNSServer: Adding %#a for %##s", addr, d->c); + LogInfo("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 {interface,address,port,domain} tuple registered { if ((*p)->interface == interface && (*p)->teststate != DNSServer_Disabled && mDNSSameAddress(&(*p)->addr, addr) && mDNSSameIPPort((*p)->port, port) && SameDomainName(&(*p)->domain, d)) { - if (!((*p)->flags & DNSServer_FlagDelete)) LogMsg("Note: DNS Server %#a for domain %##s registered more than once", addr, d->c); + if (!((*p)->flags & DNSServer_FlagDelete)) debugf("Note: DNS Server %#a:%d for domain %##s (%p) registered more than once", addr, mDNSVal16(port), d->c, interface); (*p)->flags &= ~DNSServer_FlagDelete; - return(*p); + tmp = *p; + *p = tmp->next; + tmp->next = mDNSNULL; } - p=&(*p)->next; + else + p=&(*p)->next; } - // allocate, add to list - *p = mDNSPlatformMemAllocate(sizeof(**p)); - if (!*p) LogMsg("Error: mDNS_AddDNSServer - malloc"); + if (tmp) *p = tmp; // move to end of list, to ensure ordering from platform layer else { - (*p)->interface = interface; - (*p)->addr = *addr; - (*p)->port = port; - (*p)->flags = DNSServer_FlagNew; - (*p)->teststate = DNSServer_Untested; - (*p)->lasttest = m->timenow - INIT_UCAST_POLL_INTERVAL; - AssignDomainName(&(*p)->domain, d); - (*p)->next = mDNSNULL; + // allocate, add to list + *p = mDNSPlatformMemAllocate(sizeof(**p)); + if (!*p) LogMsg("Error: mDNS_AddDNSServer - malloc"); + else + { + (*p)->interface = interface; + (*p)->addr = *addr; + (*p)->port = port; + (*p)->flags = DNSServer_FlagNew; + (*p)->teststate = /* DNSServer_Untested */ DNSServer_Passed; + (*p)->lasttest = m->timenow - INIT_UCAST_POLL_INTERVAL; + AssignDomainName(&(*p)->domain, d); + (*p)->next = mDNSNULL; + } } return(*p); } -mDNSlocal void PushDNSServerToEnd(mDNS *const m, DNSQuestion *q) +mDNSexport void PushDNSServerToEnd(mDNS *const m, DNSQuestion *q) { + DNSServer *orig = q->qDNSServer; DNSServer **p = &m->DNSServers; if (m->mDNS_busy != m->mDNS_reentrancy+1) @@ -1319,10 +1500,11 @@ mDNSlocal void PushDNSServerToEnd(mDNS *const m, DNSQuestion *q) if (!q->qDNSServer) { LogMsg("PushDNSServerToEnd: Null DNS server for %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), q->unansweredQueries); - return; + goto end; } - LogOperation("PushDNSServerToEnd: Pushing DNS server %#a:%d (%##s) due to %d unanswered queries for %##s (%s)", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c, q->unansweredQueries, q->qname.c, DNSTypeName(q->qtype)); + LogInfo("PushDNSServerToEnd: Pushing DNS server %#a:%d (%##s) due to %d unanswered queries for %##s (%s)", + &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c, q->unansweredQueries, q->qname.c, DNSTypeName(q->qtype)); while (*p) { @@ -1331,7 +1513,17 @@ mDNSlocal void PushDNSServerToEnd(mDNS *const m, DNSQuestion *q) } *p = q->qDNSServer; - q->qDNSServer->next = mDNSNULL; + q->qDNSServer->next = mDNSNULL; + +end: + q->qDNSServer = GetServerForName(m, &q->qname); + + if (q->qDNSServer != orig) + { + if (q->qDNSServer) LogInfo("PushDNSServerToEnd: Server for %##s (%s) changed to %#a:%d (%##s)", q->qname.c, DNSTypeName(q->qtype), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c); + else LogInfo("PushDNSServerToEnd: Server for %##s (%s) changed to ", q->qname.c, DNSTypeName(q->qtype)); + q->ThisQInterval = q->ThisQInterval / QuestionIntervalStep; // Decrease interval one step so we don't quickly bounce between servers for queries that will not be answered. + } } // *************************************************************************** @@ -1353,7 +1545,7 @@ mDNSlocal DomainAuthInfo *GetAuthInfoForName_direct(mDNS *m, const domainname *c } n = (const domainname *)(n->c + 1 + n->c[0]); } - //LogOperation("GetAuthInfoForName none found for %##s", name->c); + //LogInfo("GetAuthInfoForName none found for %##s", name->c); return mDNSNULL; } @@ -1372,7 +1564,7 @@ mDNSexport DomainAuthInfo *GetAuthInfoForName_internal(mDNS *m, const domainname { DNSQuestion *q; DomainAuthInfo *info = *p; - LogOperation("GetAuthInfoForName_internal deleting expired key %##s %##s", info->domain.c, info->keyname.c); + LogInfo("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) @@ -1412,7 +1604,7 @@ mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info, DomainAuthInfo **p = &m->AuthInfoList; if (!info || !b64keydata) { LogMsg("mDNS_SetSecretForDomain: ERROR: info %p b64keydata %p", info, b64keydata); return(mStatus_BadParamErr); } - LogOperation("mDNS_SetSecretForDomain: domain %##s key %##s%s", domain->c, keyname->c, AutoTunnel ? " AutoTunnel" : ""); + LogInfo("mDNS_SetSecretForDomain: domain %##s key %##s%s", domain->c, keyname->c, AutoTunnel ? " AutoTunnel" : ""); info->AutoTunnel = AutoTunnel; AssignDomainName(&info->domain, domain); @@ -1421,8 +1613,7 @@ mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info, if (DNSDigest_ConstructHMACKeyfromBase64(info, b64keydata) < 0) { - LogMsg("mDNS_SetSecretForDomain: ERROR: Could not convert shared secret from base64: domain %##s key %##s %s", - domain->c, keyname->c, LogAllOperations ? b64keydata : ""); + LogMsg("mDNS_SetSecretForDomain: ERROR: Could not convert shared secret from base64: domain %##s key %##s %s", domain->c, keyname->c, mDNS_LoggingEnabled ? b64keydata : ""); return(mStatus_BadParamErr); } @@ -1492,7 +1683,7 @@ mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info) err = mDNSPlatformSendUDP(m, (mDNSu8 *)&u, end, 0, mDNSNULL, &m->Router, NATPMPPort); #ifdef _LEGACY_NAT_TRAVERSAL_ - if (mDNSIPPortIsZero(m->UPnPSOAPPort)) LNT_SendDiscoveryMsg(m); + if (mDNSIPPortIsZero(m->UPnPRouterPort) || mDNSIPPortIsZero(m->UPnPSOAPPort)) LNT_SendDiscoveryMsg(m); else if (info) err = LNT_MapPort(m, info); else err = LNT_GetExternalAddress(m); #endif // _LEGACY_NAT_TRAVERSAL_ @@ -1500,7 +1691,7 @@ mDNSlocal mStatus uDNS_SendNATMsg(mDNS *m, NATTraversalInfo *info) return(err); } -mDNSlocal void RecreateNATMappings(mDNS *const m) +mDNSexport void RecreateNATMappings(mDNS *const m) { NATTraversalInfo *n; for (n = m->NATTraversals; n; n=n->next) @@ -1516,35 +1707,35 @@ mDNSlocal void RecreateNATMappings(mDNS *const m) m->NextScheduledNATOp = m->timenow; // Need to send packets immediately } -#ifdef _LEGACY_NAT_TRAVERSAL_ -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 -#define ClearUPnPState(X) -#endif // _LEGACY_NAT_TRAVERSAL_ - mDNSexport void natTraversalHandleAddressReply(mDNS *const m, mDNSu16 err, mDNSv4Addr ExtAddr) { - static mDNSu16 last_err; + static mDNSu16 last_err = 0; + if (err) { if (err != last_err) LogMsg("Error getting external address %d", err); + ExtAddr = zerov4Addr; } - else if (!mDNSSameIPv4Address(m->ExternalAddress, ExtAddr)) + else { - LogOperation("Received external IP address %.4a from NAT", &ExtAddr); + LogInfo("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); + if (mDNSIPv4AddressIsZero(ExtAddr)) + err = NATErr_NetFail; // fake error to handle routers that pathologically report success with the zero address + } + + if (!mDNSSameIPv4Address(m->ExternalAddress, ExtAddr)) + { m->ExternalAddress = ExtAddr; RecreateNATMappings(m); // Also sets NextScheduledNATOp for us } - if (err || mDNSIPv4AddressIsZero(ExtAddr)) m->retryIntervalGetAddr = NATMAP_INIT_RETRY * 32; // 8 seconds - else m->retryIntervalGetAddr = NATMAP_MAX_RETRY_INTERVAL; + if (!err) // Success, back-off to maximum interval + m->retryIntervalGetAddr = NATMAP_MAX_RETRY_INTERVAL; + else if (!last_err) // Failure after success, retry quickly (then back-off exponentially) + m->retryIntervalGetAddr = NATMAP_INIT_RETRY; + // else back-off normally in case of pathological failures m->retryGetAddr = m->timenow + m->retryIntervalGetAddr; if (m->NextScheduledNATOp - m->retryIntervalGetAddr > 0) @@ -1565,10 +1756,13 @@ mDNSlocal void NATSetNextRenewalTime(mDNS *const m, NATTraversalInfo *n) // 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) { + const char *prot = n->Protocol == NATOp_MapUDP ? "UDP" : n->Protocol == NATOp_MapTCP ? "TCP" : "?"; + (void)prot; n->NewResult = err; if (err || lease == 0 || mDNSIPPortIsZero(extport)) { - LogOperation("natTraversalHandlePortMapReply: received error making port mapping error %d port %d", err, mDNSVal16(extport)); + LogInfo("natTraversalHandlePortMapReply: %p Response %s Port %5d External Port %5d lease %d error %d", + n, prot, mDNSVal16(n->IntPort), mDNSVal16(extport), lease, err); 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 @@ -1582,14 +1776,14 @@ mDNSexport void natTraversalHandlePortMapReply(mDNS *const m, NATTraversalInfo * n->ExpiryTime = NonZeroTime(m->timenow + lease * mDNSPlatformOneSecond); if (!mDNSSameIPPort(n->RequestedPort, extport)) - LogOperation("natTraversalHandlePortMapReply: public port changed from %d to %d", mDNSVal16(n->RequestedPort), mDNSVal16(extport)); + LogInfo("natTraversalHandlePortMapReply: %p Response %s Port %5d External Port %5d changed to %5d", + n, prot, mDNSVal16(n->IntPort), mDNSVal16(n->RequestedPort), mDNSVal16(extport)); 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)); + LogInfo("natTraversalHandlePortMapReply: %p Response %s Port %5d External Port %5d lease %d", + n, prot, mDNSVal16(n->IntPort), mDNSVal16(extport), lease); 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 @@ -1601,13 +1795,25 @@ mDNSexport mStatus mDNS_StartNATOperation_internal(mDNS *const m, NATTraversalIn { NATTraversalInfo **n; - LogOperation("mDNS_StartNATOperation_internal %d %d %d %d", + LogInfo("mDNS_StartNATOperation_internal Protocol %d IntPort %d RequestedPort %d NATLease %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); } + for (n = &m->NATTraversals; *n; n=&(*n)->next) + { + if (traversal == *n) + { + LogMsg("Error! Tried to add a NAT traversal that's already in the active list: request %p Prot %d Int %d TTL %d", + traversal, traversal->Protocol, mDNSVal16(traversal->IntPort), traversal->NATLease); + return(mStatus_AlreadyRegistered); + } + if (traversal->Protocol && traversal->Protocol == (*n)->Protocol && mDNSSameIPPort(traversal->IntPort, (*n)->IntPort) && + !mDNSSameIPPort(traversal->IntPort, SSHPort)) + LogMsg("Warning: Created port mapping request %p Prot %d Int %d TTL %d " + "duplicates existing port mapping request %p Prot %d Int %d TTL %d", + traversal, traversal->Protocol, mDNSVal16(traversal->IntPort), traversal->NATLease, + *n, (*n) ->Protocol, mDNSVal16((*n) ->IntPort), (*n) ->NATLease); + } // Initialize necessary fields traversal->next = mDNSNULL; @@ -1625,7 +1831,7 @@ mDNSexport mStatus mDNS_StartNATOperation_internal(mDNS *const m, NATTraversalIn #ifdef _LEGACY_NAT_TRAVERSAL_ mDNSPlatformMemZero(&traversal->tcpInfo, sizeof(traversal->tcpInfo)); -#endif _LEGACY_NAT_TRAVERSAL_ +#endif // _LEGACY_NAT_TRAVERSAL_ if (!m->NATTraversals) // If this is our first NAT request, kick off an address request too { @@ -1643,8 +1849,10 @@ mDNSexport mStatus mDNS_StartNATOperation_internal(mDNS *const m, NATTraversalIn // Must be called with the mDNS_Lock held mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *traversal) { + mDNSBool unmap = mDNStrue; + NATTraversalInfo *p; 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 @@ -1653,25 +1861,39 @@ mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *tra return(mStatus_BadReferenceErr); } - LogOperation("mDNS_StopNATOperation_internal %d %d %d %d", + LogInfo("mDNS_StopNATOperation_internal %d %d %d %d", traversal->Protocol, mDNSVal16(traversal->IntPort), mDNSVal16(traversal->RequestedPort), traversal->NATLease); if (m->CurrentNATTraversal == traversal) m->CurrentNATTraversal = m->CurrentNATTraversal->next; - if (traversal->ExpiryTime) + if (traversal->Protocol) + for (p = m->NATTraversals; p; p=p->next) + if (traversal->Protocol == p->Protocol && mDNSSameIPPort(traversal->IntPort, p->IntPort)) + { + if (!mDNSSameIPPort(traversal->IntPort, SSHPort)) + LogMsg("Warning: Removed port mapping request %p Prot %d Int %d TTL %d " + "duplicates existing port mapping request %p Prot %d Int %d TTL %d", + traversal, traversal->Protocol, mDNSVal16(traversal->IntPort), traversal->NATLease, + p, p ->Protocol, mDNSVal16(p ->IntPort), p ->NATLease); + unmap = mDNSfalse; + } + + if (traversal->ExpiryTime && unmap) { traversal->NATLease = 0; traversal->retryInterval = 0; uDNS_SendNATMsg(m, traversal); } + // 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); + if (err) LogMsg("Legacy NAT Traversal - unmap request failed with error %d", err); } #endif // _LEGACY_NAT_TRAVERSAL_ + return(mStatus_NoError); } @@ -1702,7 +1924,7 @@ mDNSexport mStatus mDNS_StopNATOperation(mDNS *m, NATTraversalInfo *traversal) // Lock must be held -- otherwise m->timenow is undefined mDNSlocal void StartLLQPolling(mDNS *const m, DNSQuestion *q) { - LogOperation("StartLLQPolling: %##s", q->qname.c); + debugf("StartLLQPolling: %##s", q->qname.c); q->state = LLQ_Poll; q->ThisQInterval = INIT_UCAST_POLL_INTERVAL; // We want to send our poll query ASAP, but the "+ 1" is because if we set the time to now, @@ -1714,30 +1936,28 @@ mDNSlocal void StartLLQPolling(mDNS *const m, DNSQuestion *q) #endif } -mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, const DNSQuestion *const question, const LLQOptData *const data, mDNSBool includeQuestion) +mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, const DNSQuestion *const question, const LLQOptData *const data) { 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) - { - ptr = putQuestion(msg, ptr, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass); - if (!ptr) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL; } - } + 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 // 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; + opt->rrclass = NormalMaxDNSMessageData; + opt->rdlength = sizeof(rdataOPT); // One option in this OPT record + opt->rdestimate = sizeof(rdataOPT); - optRD = &rr.resrec.rdata->u.opt; + optRD = &rr.resrec.rdata->u.opt[0]; optRD->opt = kDNSOpt_LLQ; - optRD->optlen = LLQ_OPTLEN; - optRD->OptData.llq = *data; + optRD->u.llq = *data; ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.numAdditionals, opt, 0); if (!ptr) { LogMsg("ERROR: putLLQ - PutResourceRecordTTLJumbo"); return mDNSNULL; } @@ -1792,8 +2012,7 @@ mDNSlocal void sendChallengeResponse(mDNS *const m, DNSQuestion *const q, const //if (q->ntries == 1) return; InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags); - responsePtr = putQuestion(&m->omsg, responsePtr, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass); - if (responsePtr) responsePtr = putLLQ(&m->omsg, responsePtr, q, llq, mDNSfalse); + responsePtr = putLLQ(&m->omsg, responsePtr, q, llq); if (responsePtr) { mStatus err = mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, q->AuthInfo); @@ -1830,7 +2049,7 @@ mDNSlocal void recvSetupResponse(mDNS *const m, mDNSu8 rcode, DNSQuestion *const if (q->state == LLQ_InitialRequest) { - //LogOperation("Got LLQ_InitialRequest"); + //LogInfo("Got LLQ_InitialRequest"); if (llq->err) { LogMsg("recvSetupResponse - received llq->err %d from server", llq->err); StartLLQPolling(m,q); return; } @@ -1849,7 +2068,7 @@ mDNSlocal void recvSetupResponse(mDNS *const m, mDNSu8 rcode, DNSQuestion *const } else if (q->state == LLQ_SecondaryRequest) { - //LogOperation("Got LLQ_SecondaryRequest"); + //LogInfo("Got LLQ_SecondaryRequest"); // 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 @@ -1857,7 +2076,7 @@ mDNSlocal void recvSetupResponse(mDNS *const m, mDNSu8 rcode, DNSQuestion *const // if the server sends back SERVFULL or STATIC. if (q->AuthInfo) { - LogOperation("Private LLQ_SecondaryRequest; copying id %08X%08X", llq->id.l[0], llq->id.l[1]); + LogInfo("Private LLQ_SecondaryRequest; copying id %08X%08X", llq->id.l[0], llq->id.l[1]); q->id = llq->id; } @@ -1886,12 +2105,12 @@ mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *co { 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); + opt ? opt->u.llq.id.l[0] : 0, opt ? opt->u.llq.id.l[1] : 0, q->id.l[0], q->id.l[1], opt ? opt->u.llq.llqOp : 0); if (q->state == LLQ_Poll) debugf("uDNS_LLQ_Events: q->state == LLQ_Poll msg->h.id %d q->TargetQID %d", mDNSVal16(msg->h.id), mDNSVal16(q->TargetQID)); if (q->state == LLQ_Poll && mDNSSameOpaque16(msg->h.id, q->TargetQID)) { m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it - LogOperation("uDNS_recvLLQResponse got poll response; moving to LLQ_InitialRequest for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + debugf("uDNS_recvLLQResponse got poll response; moving to LLQ_InitialRequest for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); q->state = LLQ_InitialRequest; q->servPort = zeroIPPort; // Clear servPort so that startLLQHandshake will retry the GetZoneData processing q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10); // Retry LLQ setup in approx 15 minutes @@ -1900,12 +2119,12 @@ mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *co return uDNS_LLQ_Entire; // uDNS_LLQ_Entire means flush stale records; assume a large effective TTL } // Note: In LLQ Event packets, the msg->h.id does not match our q->TargetQID, because in that case the msg->h.id nonce is selected by the server - else if (opt && q->state == LLQ_Established && opt->OptData.llq.llqOp == kLLQOp_Event && mDNSSameOpaque64(&opt->OptData.llq.id, &q->id)) + else if (opt && q->state == LLQ_Established && opt->u.llq.llqOp == kLLQOp_Event && mDNSSameOpaque64(&opt->u.llq.id, &q->id)) { mDNSu8 *ackEnd; //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); + ackEnd = putLLQ(&m->omsg, m->omsg.data, q, &opt->u.llq); if (ackEnd) mDNSSendDNSMessage(m, &m->omsg, ackEnd, mDNSInterface_Any, q->LocalSocket, srcaddr, srcport, mDNSNULL, mDNSNULL); m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it debugf("uDNS_LLQ_Events: q->state == LLQ_Established msg->h.id %d q->TargetQID %d", mDNSVal16(msg->h.id), mDNSVal16(q->TargetQID)); @@ -1913,14 +2132,17 @@ mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *co } if (opt && mDNSSameOpaque16(msg->h.id, q->TargetQID)) { - if (q->state == LLQ_Established && opt->OptData.llq.llqOp == kLLQOp_Refresh && mDNSSameOpaque64(&opt->OptData.llq.id, &q->id) && msg->h.numAdditionals && !msg->h.numAnswers) + if (q->state == LLQ_Established && opt->u.llq.llqOp == kLLQOp_Refresh && mDNSSameOpaque64(&opt->u.llq.id, &q->id) && msg->h.numAdditionals && !msg->h.numAnswers) { - if (opt->OptData.llq.err != LLQErr_NoError) LogMsg("recvRefreshReply: received error %d from server", opt->OptData.llq.err); + if (opt->u.llq.err != LLQErr_NoError) LogMsg("recvRefreshReply: received error %d from server", opt->u.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); - SetLLQTimer(m, q, &opt->OptData.llq); + //LogInfo("Received refresh confirmation ntries %d for %##s (%s)", q->ntries, q->qname.c, DNSTypeName(q->qtype)); + // If we're waiting to go to sleep, then this LLQ deletion may have been the thing + // we were waiting for, so schedule another check to see if we can sleep now. + if (opt->u.llq.llqlease == 0 && m->SleepLimit) m->NextScheduledSPRetry = m->timenow; + GrantCacheExtensions(m, q, opt->u.llq.llqlease); + SetLLQTimer(m, q, &opt->u.llq); q->ntries = 0; } m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it @@ -1929,10 +2151,10 @@ mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *co if (q->state < LLQ_Established && mDNSSameAddress(srcaddr, &q->servAddr)) { LLQ_State oldstate = q->state; - recvSetupResponse(m, msg->h.flags.b[1] & kDNSFlag1_RC_Mask, q, &opt->OptData.llq); + recvSetupResponse(m, msg->h.flags.b[1] & kDNSFlag1_RC_Mask, q, &opt->u.llq); m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it // We have a protocol anomaly here in the LLQ definition. - // Both the challenge packet from the server and the ack+answers packet have opt->OptData.llq.llqOp == kLLQOp_Setup. + // Both the challenge packet from the server and the ack+answers packet have opt->u.llq.llqOp == kLLQOp_Setup. // However, we need to treat them differently: // The challenge packet has no answers in it, and tells us nothing about whether our cache entries // are still valid, so this packet should not cause us to do anything that messes with our cache. @@ -1993,7 +2215,7 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs { end = ((mDNSu8*) &tcpInfo->request) + tcpInfo->requestLen; } - else if (q && q->LongLived && q->state != LLQ_Poll && !mDNSIPPortIsZero(m->LLQNAT.ExternalPort)) + else if (q && q->LongLived && q->state != LLQ_Poll && !mDNSIPPortIsZero(m->LLQNAT.ExternalPort) && !mDNSIPPortIsZero(q->servPort)) { // Notes: // If we have a NAT port mapping, ExternalPort is the external port @@ -2003,11 +2225,11 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs llqData.vers = kLLQ_Vers; llqData.llqOp = kLLQOp_Setup; llqData.err = GetLLQEventPort(m, &tcpInfo->Addr); // We're using TCP; tell server what UDP port to send notifications to - LogOperation("tcpCallback: eventPort %d", llqData.err); + LogInfo("tcpCallback: eventPort %d", llqData.err); llqData.id = zeroOpaque64; llqData.llqlease = kLLQ_DefLease; InitializeDNSMessage(&tcpInfo->request.h, q->TargetQID, uQueryFlags); - end = putLLQ(&tcpInfo->request, tcpInfo->request.data, q, &llqData, mDNStrue); + end = putLLQ(&tcpInfo->request, tcpInfo->request.data, q, &llqData); if (!end) { LogMsg("ERROR: tcpCallback - putLLQ"); err = mStatus_UnknownErr; goto exit; } AuthInfo = q->AuthInfo; // Need to add TSIG to this message } @@ -2019,7 +2241,7 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs } err = mDNSSendDNSMessage(m, &tcpInfo->request, end, mDNSInterface_Any, mDNSNULL, &tcpInfo->Addr, tcpInfo->Port, sock, AuthInfo); - if (err) { debugf("ERROR: tcpCallback: mDNSSendDNSMessage - %ld", err); err = mStatus_UnknownErr; goto exit; } + if (err) { debugf("ERROR: tcpCallback: mDNSSendDNSMessage - %d", err); err = mStatus_UnknownErr; goto exit; } // Record time we sent this question if (q) @@ -2091,7 +2313,7 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs if (rr && rr->resrec.RecordType == kDNSRecordTypeDeregistering) { mDNS_Lock(m); - LogOperation("tcpCallback: CompleteDeregistration %s", ARDisplayString(m, rr)); + LogInfo("tcpCallback: CompleteDeregistration %s", ARDisplayString(m, rr)); CompleteDeregistration(m, rr); // Don't touch rr after this mDNS_Unlock(m); } @@ -2180,7 +2402,7 @@ mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, con // Don't need to log "connection failed" in customer builds -- it happens quite often during sleep, wake, configuration changes, etc. if (err == mStatus_ConnEstablished) { tcpCallback(info->sock, info, mDNStrue, mStatus_NoError); } - else if (err != mStatus_ConnPending ) { LogOperation("MakeTCPConnection: connection failed"); DisposeTCPConn(info); return(mDNSNULL); } + else if (err != mStatus_ConnPending ) { LogInfo("MakeTCPConnection: connection failed"); DisposeTCPConn(info); return(mDNSNULL); } return(info); } @@ -2196,7 +2418,7 @@ mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q) { if (mDNSIPv4AddressIsOnes(m->LLQNAT.ExternalAddress)) { - LogOperation("startLLQHandshake: waiting for NAT status for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + LogInfo("startLLQHandshake: waiting for NAT status for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10); // Retry in approx 15 minutes q->LastQTime = m->timenow; SetNextQueryTime(m, q); @@ -2205,19 +2427,19 @@ mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q) if (mDNSIPPortIsZero(m->LLQNAT.ExternalPort)) { - LogOperation("startLLQHandshake: Cannot receive inbound packets; will poll for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + LogInfo("startLLQHandshake: Cannot receive inbound packets; will poll for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); StartLLQPolling(m, q); return; } if (mDNSIPPortIsZero(q->servPort)) { - LogOperation("startLLQHandshake: StartGetZoneData for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + debugf("startLLQHandshake: StartGetZoneData for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10); // Retry in approx 15 minutes q->LastQTime = m->timenow; SetNextQueryTime(m, q); q->servAddr = zeroAddr; - q->servPort = zeroIPPort; + // We know q->servPort is zero because of check above if (q->nta) CancelGetZoneData(m, q->nta); q->nta = StartGetZoneData(m, &q->qname, ZoneServiceLLQ, LLQGotZoneData, q); return; @@ -2225,7 +2447,7 @@ mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q) if (q->AuthInfo) { - if (q->tcp) LogOperation("startLLQHandshake: Disposing existing TCP connection for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + if (q->tcp) LogInfo("startLLQHandshake: Disposing existing TCP connection for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); if (q->tcp) DisposeTCPConn(q->tcp); q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, q, mDNSNULL, mDNSNULL); if (!q->tcp) @@ -2241,7 +2463,7 @@ mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q) } else { - LogOperation("startLLQHandshake m->AdvertisedV4 %#a%s Server %#a:%d%s %##s (%s)", + debugf("startLLQHandshake: m->AdvertisedV4 %#a%s Server %#a:%d%s %##s (%s)", &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)); @@ -2264,7 +2486,7 @@ mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q) llqData.llqlease = kLLQ_DefLease; InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags); - end = putLLQ(&m->omsg, m->omsg.data, q, &llqData, mDNStrue); + end = putLLQ(&m->omsg, m->omsg.data, q, &llqData); if (!end) { LogMsg("ERROR: startLLQHandshake - putLLQ"); StartLLQPolling(m,q); return; } mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, mDNSNULL, mDNSNULL); @@ -2279,16 +2501,19 @@ mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q) } } -mDNSexport const domainname *GetServiceTarget(mDNS *m, ServiceRecordSet *srs) +// forward declaration so GetServiceTarget can do reverse lookup if needed +mDNSlocal void GetStaticHostname(mDNS *m); + +mDNSexport const domainname *GetServiceTarget(mDNS *m, AuthRecord *const rr) { - LogOperation("GetServiceTarget %##s", srs->RR_SRV.resrec.name->c); + debugf("GetServiceTarget %##s", rr->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); + if (!rr->AutoTarget) // If not automatically tracking this host's current name, just return the existing target + return(&rr->resrec.rdata->u.srv.target); else { #if APPLE_OSX_mDNSResponder - DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name); + DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name); if (AuthInfo && AuthInfo->AutoTunnel) { // If this AutoTunnel is not yet active, start it now (which entails activating its NAT Traversal request, @@ -2299,9 +2524,9 @@ mDNSexport const domainname *GetServiceTarget(mDNS *m, ServiceRecordSet *srs) return(&AuthInfo->AutoTunnelHostRecord.namestorage); } else -#endif APPLE_OSX_mDNSResponder +#endif // APPLE_OSX_mDNSResponder { - const int srvcount = CountLabels(srs->RR_SRV.resrec.name); + const int srvcount = CountLabels(rr->resrec.name); HostnameInfo *besthi = mDNSNULL, *hi; int best = 0; for (hi = m->Hostnames; hi; hi = hi->next) @@ -2310,13 +2535,14 @@ mDNSexport const domainname *GetServiceTarget(mDNS *m, ServiceRecordSet *srs) { int x, hostcount = CountLabels(&hi->fqdn); for (x = hostcount < srvcount ? hostcount : srvcount; x > 0 && x > best; x--) - if (SameDomainName(SkipLeadingLabels(srs->RR_SRV.resrec.name, srvcount - x), SkipLeadingLabels(&hi->fqdn, hostcount - x))) + if (SameDomainName(SkipLeadingLabels(rr->resrec.name, srvcount - x), SkipLeadingLabels(&hi->fqdn, hostcount - x))) { best = x; besthi = hi; } } if (besthi) return(&besthi->fqdn); } if (m->StaticHostname.c[0]) return(&m->StaticHostname); + else GetStaticHostname(m); // asynchronously do reverse lookup for primary IPv4 address return(mDNSNULL); } } @@ -2398,10 +2624,10 @@ mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs) 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); + target = GetServiceTarget(m, &srs->RR_SRV); if (!target || target->c[0] == 0) { - LogOperation("SendServiceRegistration - no target for %##s", srs->RR_SRV.resrec.name->c); + debugf("SendServiceRegistration - no target for %##s", srs->RR_SRV.resrec.name->c); srs->state = regState_NoTarget; return; } @@ -2425,7 +2651,7 @@ mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs) if (srs->Private) { - if (srs->tcp) LogOperation("SendServiceRegistration: Disposing existing TCP connection for %s", ARDisplayString(m, &srs->RR_SRV)); + if (srs->tcp) LogInfo("SendServiceRegistration: Disposing existing TCP connection for %s", ARDisplayString(m, &srs->RR_SRV)); if (srs->tcp) DisposeTCPConn(srs->tcp); srs->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, srs, mDNSNULL); if (!srs->tcp) srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5; // If failed to make TCP connection, try again in ten seconds (5*2) @@ -2434,7 +2660,7 @@ mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs) else { err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name)); - if (err) debugf("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %ld", err); + if (err) debugf("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %d", err); } SetRecordRetry(m, &srs->RR_SRV, err); @@ -2501,7 +2727,7 @@ mDNSlocal void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question } else { - LogOperation("GetZoneData recursed to root label of %##s without finding SOA", zd->ChildName.c); + LogInfo("GetZoneData recursed to root label of %##s without finding SOA", zd->ChildName.c); zd->ZoneDataCallback(m, mStatus_NoSuchNameErr, zd); mDNSPlatformMemFree(zd); } @@ -2568,7 +2794,7 @@ mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qt { AssignDomainName(&zd->question.qname, ZoneDataSRV(zd)); AppendDomainName(&zd->question.qname, &zd->ZoneName); - LogOperation("lookupDNSPort %##s", zd->question.qname.c); + debugf("lookupDNSPort %##s", zd->question.qname.c); } zd->question.ThisQInterval = -1; // So that GetZoneData_QuestionCallback() knows whether to cancel this question (Is this necessary?) @@ -2639,7 +2865,7 @@ mDNSexport DomainAuthInfo *GetAuthInfoForQuestion(mDNS *m, const DNSQuestion *co mDNSlocal void CompleteSRVNatMap(mDNS *m, NATTraversalInfo *n) { ServiceRecordSet *srs = (ServiceRecordSet *)n->clientContext; - LogOperation("SRVNatMap complete %.4a %u %u TTL %u", &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort), n->NATLease); + debugf("SRVNatMap complete %.4a IntPort %u ExternalPort %u NATLease %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; @@ -2650,10 +2876,10 @@ mDNSlocal void CompleteSRVNatMap(mDNS *m, NATTraversalInfo *n) else { // SHOULD NEVER HAPPEN! - LogOperation("ERROR: CompleteSRVNatMap called but srs->SRSUpdateServer.ip.v4 is zero!"); + LogInfo("ERROR: CompleteSRVNatMap called but srs->SRSUpdateServer.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, ServiceRegistrationGotZoneData, srs); + if (srs->srs_nta) CancelGetZoneData(m, srs->srs_nta); // Make sure we cancel old one before we start a new one + srs->srs_nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, srs); } mDNS_Unlock(m); } @@ -2667,7 +2893,9 @@ mDNSlocal void StartSRVNatMap(mDNS *m, ServiceRecordSet *srs) else { LogMsg("StartSRVNatMap: could not determine transport protocol of service %##s", srs->RR_SRV.resrec.name->c); return; } if (srs->NATinfo.clientContext) mDNS_StopNATOperation_internal(m, &srs->NATinfo); - srs->NATinfo.IntPort = srs->RR_SRV.resrec.rdata->u.srv.port; + // Don't try to set IntPort here -- + // SendServiceRegistration overwrites srs->RR_SRV.resrec.rdata->u.srv.port with external (mapped) port number + //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; @@ -2683,7 +2911,10 @@ mDNSexport void ServiceRegistrationGotZoneData(mDNS *const m, mStatus err, const if (m->mDNS_busy != m->mDNS_reentrancy) LogMsg("ServiceRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); - srs->nta = mDNSNULL; + if (!srs->RR_SRV.resrec.rdata) + { LogMsg("ServiceRegistrationGotZoneData: ERROR: srs->RR_SRV.resrec.rdata is NULL"); return; } + + srs->srs_nta = mDNSNULL; // Start off assuming we're going to use a lease // If we get an error from the server, and the update port as given in the SRV record is 53, then we'll retry without the lease option @@ -2703,17 +2934,21 @@ mDNSexport void ServiceRegistrationGotZoneData(mDNS *const m, mStatus err, const srs->RR_SRV.LastAPTime = m->timenow; srs->RR_SRV.ThisAPInterval = 0; - LogOperation("ServiceRegistrationGotZoneData My IPv4 %#a%s Server %#a:%d%s for %##s", + debugf("ServiceRegistrationGotZoneData My IPv4 %#a%s Server %#a:%d%s for %##s", &m->AdvertisedV4, mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) ? " (RFC1918)" : "", &srs->SRSUpdateServer, mDNSVal16(srs->SRSUpdatePort), mDNSAddrIsRFC1918(&srs->SRSUpdateServer) ? " (RFC1918)" : "", srs->RR_SRV.resrec.name->c); + // If we have non-zero service port (always?) + // and a private address, and update server is non-private + // and this service is AutoTarget + // then initiate a NAT mapping request. On completion it will do SendServiceRegistration() for us if (!mDNSIPPortIsZero(srs->RR_SRV.resrec.rdata->u.srv.port) && mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && !mDNSAddrIsRFC1918(&srs->SRSUpdateServer) && srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP) { srs->state = regState_NATMap; - LogOperation("ServiceRegistrationGotZoneData StartSRVNatMap"); + debugf("ServiceRegistrationGotZoneData StartSRVNatMap"); StartSRVNatMap(m, srs); } else @@ -2758,8 +2993,8 @@ mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs) if (srs->Private) { - LogOperation("SendServiceDeregistration TCP %p %s", srs->tcp, ARDisplayString(m, &srs->RR_SRV)); - if (srs->tcp) LogOperation("SendServiceDeregistration: Disposing existing TCP connection for %s", ARDisplayString(m, &srs->RR_SRV)); + LogInfo("SendServiceDeregistration TCP %p %s", srs->tcp, ARDisplayString(m, &srs->RR_SRV)); + if (srs->tcp) LogInfo("SendServiceDeregistration: Disposing existing TCP connection for %s", ARDisplayString(m, &srs->RR_SRV)); if (srs->tcp) DisposeTCPConn(srs->tcp); srs->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, srs, mDNSNULL); if (!srs->tcp) srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5; // If failed to make TCP connection, try again in ten seconds (5*2) @@ -2768,7 +3003,7 @@ mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs) else { err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name)); - if (err && err != mStatus_TransientErr) { debugf("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %ld", err); goto exit; } + if (err && err != mStatus_TransientErr) { debugf("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %d", err); goto exit; } } SetRecordRetry(m, &srs->RR_SRV, err); @@ -2794,14 +3029,14 @@ mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs) // The target has changed domainname *curtarget = &srs->RR_SRV.resrec.rdata->u.srv.target; - const domainname *const nt = GetServiceTarget(m, srs); + const domainname *const nt = GetServiceTarget(m, &srs->RR_SRV); const domainname *const newtarget = nt ? nt : (domainname*)""; mDNSBool TargetChanged = (newtarget->c[0] && srs->state == regState_NoTarget) || !SameDomainName(curtarget, newtarget); mDNSBool HaveZoneData = !mDNSIPv4AddressIsZero(srs->SRSUpdateServer.ip.v4); // 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're not behind a NAT but our port was previously mapped to a different external port // We were not behind a NAT and now we are mDNSIPPort port = srs->RR_SRV.resrec.rdata->u.srv.port; @@ -2810,7 +3045,7 @@ mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs) mDNSBool PortWasMapped = (srs->NATinfo.clientContext && !mDNSSameIPPort(srs->NATinfo.RequestedPort, port)); // I think this is always false -- SC Sept 07 mDNSBool NATChanged = (!WereBehindNAT && NowNeedNATMAP) || (!NowNeedNATMAP && PortWasMapped); - LogOperation("UpdateSRV %##s newtarget %##s TargetChanged %d HaveZoneData %d port %d NowNeedNATMAP %d WereBehindNAT %d PortWasMapped %d NATChanged %d", + debugf("UpdateSRV %##s newtarget %##s TargetChanged %d HaveZoneData %d port %d NowNeedNATMAP %d WereBehindNAT %d PortWasMapped %d NATChanged %d", srs->RR_SRV.resrec.name->c, newtarget, TargetChanged, HaveZoneData, mDNSVal16(port), NowNeedNATMAP, WereBehindNAT, PortWasMapped, NATChanged); @@ -2849,8 +3084,8 @@ mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs) 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, ServiceRegistrationGotZoneData, srs); + if (srs->srs_nta) CancelGetZoneData(m, srs->srs_nta); // Make sure we cancel old one before we start a new one + srs->srs_nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, srs); } else { @@ -2881,7 +3116,7 @@ mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs) // Called with lock held mDNSlocal void UpdateSRVRecords(mDNS *m) { - LogOperation("UpdateSRVRecords%s", m->SleepState ? " (ignored due to SleepState)" : ""); + debugf("UpdateSRVRecords%s", m->SleepState ? " (ignored due to SleepState)" : ""); if (m->SleepState) return; if (CurrentServiceRecordSet) @@ -2894,6 +3129,10 @@ mDNSlocal void UpdateSRVRecords(mDNS *m) CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next; UpdateSRV(m, s); } + + mDNS_DropLockBeforeCallback(); // mDNS_SetFQDN expects to be called without the lock held, so we emulate that here + mDNS_SetFQDN(m); + mDNS_ReclaimLockAfterCallback(); } // Forward reference: AdvertiseHostname references HostnameCallback, and HostnameCallback calls AdvertiseHostname @@ -2913,12 +3152,13 @@ mDNSlocal void hostnameGetPublicAddressCallback(mDNS *m, NATTraversalInfo *n) if (h->arv4.resrec.RecordType) { if (mDNSSameIPv4Address(h->arv4.resrec.rdata->u.ipv4, n->ExternalAddress)) return; // If address unchanged, do nothing - LogOperation("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); + LogInfo("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 { - LogOperation("Advertising hostname %##s IPv4 %.4a (NAT gateway's external address)", h->arv4.resrec.name->c, &n->ExternalAddress); + LogInfo("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); @@ -2949,7 +3189,7 @@ mDNSlocal void AdvertiseHostname(mDNS *m, HostnameInfo *h) } else { - LogOperation("Advertising hostname %##s IPv4 %.4a", h->arv4.resrec.name->c, &m->AdvertisedV4.ip.v4); + LogInfo("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); } @@ -2961,7 +3201,7 @@ mDNSlocal void AdvertiseHostname(mDNS *m, HostnameInfo *h) AssignDomainName(&h->arv6.namestorage, &h->fqdn); h->arv6.resrec.rdata->u.ipv6 = m->AdvertisedV6.ip.v6; h->arv6.state = regState_Unregistered; - LogOperation("Advertising hostname %##s IPv6 %.16a", h->arv6.resrec.name->c, &m->AdvertisedV6.ip.v6); + LogInfo("Advertising hostname %##s IPv6 %.16a", h->arv6.resrec.name->c, &m->AdvertisedV6.ip.v6); mDNS_Register_internal(m, &h->arv6); } } @@ -2976,7 +3216,7 @@ mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus res { // 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)); + LogInfo("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; } @@ -2997,9 +3237,9 @@ mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus res { // 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); + LogMsg("HostnameCallback: Error %d 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); + LogMsg("HostnameCallback: Error %d 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!"); @@ -3023,9 +3263,9 @@ mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus res // Deliver success to client if (!hi) { LogMsg("HostnameCallback invoked with orphaned address record"); return; } if (rr->resrec.rrtype == kDNSType_A) - LogOperation("Registered hostname %##s IP %.4a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv4); + LogInfo("Registered hostname %##s IP %.4a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv4); else - LogOperation("Registered hostname %##s IP %.16a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv6); + LogInfo("Registered hostname %##s IP %.16a", rr->resrec.name->c, &rr->resrec.rdata->u.ipv6); rr->RecordContext = (void *)hi->StatusContext; if (hi->StatusCallback) @@ -3077,10 +3317,9 @@ mDNSlocal void GetStaticHostname(mDNS *m) mDNSu8 *ip = m->AdvertisedV4.ip.v4.b; mStatus err; - if (m->ReverseMap.ThisQInterval != -1) mDNS_StopQuery_internal(m, q); - - m->StaticHostname.c[0] = 0; + if (m->ReverseMap.ThisQInterval != -1) return; // already running 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]); @@ -3097,6 +3336,7 @@ mDNSlocal void GetStaticHostname(mDNS *m) q->QuestionCallback = FoundStaticHostname; q->QuestionContext = mDNSNULL; + LogInfo("GetStaticHostname: %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); err = mDNS_StartQuery_internal(m, q); if (err) LogMsg("Error: GetStaticHostname - StartQuery returned error %d", err); } @@ -3105,7 +3345,7 @@ mDNSexport void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSReco { HostnameInfo **ptr = &m->Hostnames; - LogOperation("mDNS_AddDynDNSHostName %##s", fqdn); + LogInfo("mDNS_AddDynDNSHostName %##s", fqdn); while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next; if (*ptr) { LogMsg("DynDNSHostName %##s already in list", fqdn->c); return; } @@ -3128,7 +3368,7 @@ mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn) { HostnameInfo **ptr = &m->Hostnames; - LogOperation("mDNS_RemoveDynDNSHostName %##s", fqdn); + LogInfo("mDNS_RemoveDynDNSHostName %##s", fqdn); while (*ptr && !SameDomainName(fqdn, &(*ptr)->fqdn)) ptr = &(*ptr)->next; if (!*ptr) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn->c); @@ -3139,8 +3379,8 @@ mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn) // 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); + if (f4) LogInfo("mDNS_RemoveDynDNSHostName removing v4 %##s", fqdn); + if (f6) LogInfo("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); @@ -3181,26 +3421,26 @@ mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, co if (v4Changed || RouterChanged || v6Changed) { HostnameInfo *i; - LogOperation("mDNS_SetPrimaryInterfaceInfo: %s%s%s%#a %#a %#a", + LogInfo("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); + LogInfo("mDNS_SetPrimaryInterfaceInfo updating host name registrations for %##s", i->fqdn.c); 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)); + LogInfo("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m, &i->arv4)); mDNS_Deregister_internal(m, &i->arv4, mDNS_Dereg_normal); } 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)); + LogInfo("mDNS_SetPrimaryInterfaceInfo deregistering %s", ARDisplayString(m, &i->arv6)); mDNS_Deregister_internal(m, &i->arv6, mDNS_Dereg_normal); } @@ -3215,12 +3455,19 @@ mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, co m->retryIntervalGetAddr = NATMAP_INIT_RETRY; m->retryGetAddr = m->timenow; m->NextScheduledNATOp = m->timenow; - ClearUPnPState(m); + m->LastNATMapResultCode = NATErr_None; +#ifdef _LEGACY_NAT_TRAVERSAL_ + LNT_ClearState(m); +#endif // _LEGACY_NAT_TRAVERSAL_ } - UpdateSRVRecords(m); - GetStaticHostname(m); // look up reverse map record to find any static hostnames for our IP address + if (m->ReverseMap.ThisQInterval != -1) mDNS_StopQuery_internal(m, &m->ReverseMap); + m->StaticHostname.c[0] = 0; + + UpdateSRVRecords(m); // Will call GetStaticHostname if needed + #if APPLE_OSX_mDNSResponder + if (RouterChanged) uuid_generate(m->asl_uuid); UpdateAutoTunnelDomainStatuses(m); #endif } @@ -3303,7 +3550,7 @@ mDNSlocal mStatus checkUpdateResult(mDNS *const m, const domainname *const displ } 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 + // TSIG errors should come with FormErr 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) { @@ -3312,7 +3559,7 @@ mDNSlocal mStatus checkUpdateResult(mDNS *const m, const domainname *const displ } else return tsigerr; } - else if (rcode == kDNSFlag1_RC_FmtErr) + else if (rcode == kDNSFlag1_RC_FormErr) { mStatus tsigerr = ParseTSIGError(m, msg, end, displayname); if (!tsigerr) @@ -3348,11 +3595,11 @@ mDNSlocal void SendRecordRegistration(mDNS *const m, AuthRecord *rr) } rr->RequireGoodbye = mDNStrue; - rr->id = mDNS_NewMessageID(m); - InitializeDNSMessage(&m->omsg.h, rr->id, UpdateReqFlags); + rr->updateid = mDNS_NewMessageID(m); + InitializeDNSMessage(&m->omsg.h, rr->updateid, UpdateReqFlags); // set zone - ptr = putZone(&m->omsg, ptr, end, &rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass)); + ptr = putZone(&m->omsg, ptr, end, rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass)); if (!ptr) { err = mStatus_UnknownErr; goto exit; } if (rr->state == regState_UpdatePending) @@ -3377,7 +3624,8 @@ mDNSlocal void SendRecordRegistration(mDNS *const m, AuthRecord *rr) else if (rr->resrec.RecordType != kDNSRecordTypeShared) { - ptr = putPrereqNameNotInUse(rr->resrec.name, &m->omsg, ptr, end); + // For now don't do this, until we have the logic for intelligent grouping of individual recors into logical service record sets + //ptr = putPrereqNameNotInUse(rr->resrec.name, &m->omsg, ptr, end); if (!ptr) { err = mStatus_UnknownErr; goto exit; } } @@ -3392,8 +3640,8 @@ mDNSlocal void SendRecordRegistration(mDNS *const m, AuthRecord *rr) if (rr->Private) { - LogOperation("SendRecordRegistration TCP %p %s", rr->tcp, ARDisplayString(m, rr)); - if (rr->tcp) LogOperation("SendRecordRegistration: Disposing existing TCP connection for %s", ARDisplayString(m, rr)); + LogInfo("SendRecordRegistration TCP %p %s", rr->tcp, ARDisplayString(m, rr)); + if (rr->tcp) LogInfo("SendRecordRegistration: Disposing existing TCP connection for %s", ARDisplayString(m, rr)); if (rr->tcp) DisposeTCPConn(rr->tcp); rr->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, mDNSNULL, rr); if (!rr->tcp) rr->ThisAPInterval = mDNSPlatformOneSecond * 5; // If failed to make TCP connection, try again in ten seconds (5*2) @@ -3402,7 +3650,7 @@ mDNSlocal void SendRecordRegistration(mDNS *const m, AuthRecord *rr) else { err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name)); - if (err) debugf("ERROR: SendRecordRegistration - mDNSSendDNSMessage - %ld", err); + if (err) debugf("ERROR: SendRecordRegistration - mDNSSendDNSMessage - %d", err); } SetRecordRetry(m, rr, err); @@ -3426,7 +3674,7 @@ mDNSlocal void hndlServiceUpdateReply(mDNS *const m, ServiceRecordSet *srs, mSt 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); - LogOperation("hndlServiceUpdateReply: err %d state %d %##s", err, srs->state, srs->RR_SRV.resrec.name->c); + debugf("hndlServiceUpdateReply: err %d state %d %##s", err, srs->state, srs->RR_SRV.resrec.name->c); SetRecordRetry(m, &srs->RR_SRV, mStatus_NoError); @@ -3458,7 +3706,7 @@ mDNSlocal void hndlServiceUpdateReply(mDNS *const m, ServiceRecordSet *srs, mSt 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); + if (err) LogMsg("Error %d for registration of service %##s", err, srs->RR_SRV.resrec.name->c); else srs->state = regState_Registered; InvokeCallback = mDNStrue; break; @@ -3466,13 +3714,13 @@ mDNSlocal void hndlServiceUpdateReply(mDNS *const m, ServiceRecordSet *srs, mSt case regState_Refresh: if (err) { - LogMsg("Error %ld for refresh of service %##s", err, srs->RR_SRV.resrec.name->c); + LogMsg("Error %d for refresh of service %##s", err, srs->RR_SRV.resrec.name->c); InvokeCallback = mDNStrue; } 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 (err) LogMsg("Error %d 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 @@ -3491,7 +3739,7 @@ mDNSlocal void hndlServiceUpdateReply(mDNS *const m, ServiceRecordSet *srs, mSt case regState_DeregDeferred: if (err) { - debugf("Error %ld received prior to deferred derigstration of %##s", err, srs->RR_SRV.resrec.name->c); + debugf("Error %d received prior to deferred deregistration of %##s", err, srs->RR_SRV.resrec.name->c); err = mStatus_MemFree; InvokeCallback = mDNStrue; srs->state = regState_Unregistered; @@ -3529,7 +3777,7 @@ mDNSlocal void hndlServiceUpdateReply(mDNS *const m, ServiceRecordSet *srs, mSt case regState_NATMap: case regState_ExtraQueued: case regState_NATError: - LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %ld. Unlinking.", + LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %d. 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); @@ -3537,7 +3785,7 @@ mDNSlocal void hndlServiceUpdateReply(mDNS *const m, ServiceRecordSet *srs, mSt if ((srs->SRVChanged || srs->SRVUpdateDeferred) && (srs->state == regState_NoTarget || srs->state == regState_Registered)) { - LogOperation("hndlServiceUpdateReply: SRVChanged %d SRVUpdateDeferred %d state %d", srs->SRVChanged, srs->SRVUpdateDeferred, srs->state); + debugf("hndlServiceUpdateReply: SRVChanged %d SRVUpdateDeferred %d state %d", srs->SRVChanged, srs->SRVUpdateDeferred, srs->state); if (InvokeCallback) { srs->ClientCallbackDeferred = mDNStrue; @@ -3555,7 +3803,7 @@ mDNSlocal void hndlServiceUpdateReply(mDNS *const m, ServiceRecordSet *srs, mSt if (srs->state == regState_Registered && !err) { // extra resource record queued for this service - copy zone srs and register - AssignDomainName(&(*e)->r.zone, &srs->zone); + (*e)->r.zone = &srs->zone; (*e)->r.UpdateServer = srs->SRSUpdateServer; (*e)->r.UpdatePort = srs->SRSUpdatePort; (*e)->r.uselease = srs->srs_uselease; @@ -3619,7 +3867,7 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err) 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); - LogOperation("hndlRecordUpdateReply: err %d state %d %s", err, rr->state, ARDisplayString(m, rr)); + LogInfo("hndlRecordUpdateReply: err %d state %d %s", err, rr->state, ARDisplayString(m, rr)); if (m->SleepState) return; // If we just sent a deregister on going to sleep, no further action required @@ -3639,7 +3887,7 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err) 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", + if (err) LogMsg("ERROR: Deregistration of record %##s type %d failed with error %d", rr->resrec.name->c, rr->resrec.rrtype, err); err = mStatus_MemFree; rr->state = regState_Unregistered; @@ -3649,7 +3897,7 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err) { if (err) { - LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %ld", + LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %d", rr->resrec.name->c, rr->resrec.rrtype, err); rr->state = regState_Unregistered; } @@ -3675,7 +3923,7 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err) SendRecordRegistration(m, rr); return; } - LogMsg("hndlRecordUpdateReply: Registration of record %##s type %d failed with error %ld", rr->resrec.name->c, rr->resrec.rrtype, err); + LogMsg("hndlRecordUpdateReply: Registration of record %##s type %d failed with error %d", rr->resrec.name->c, rr->resrec.rrtype, err); return; } } @@ -3725,7 +3973,7 @@ mDNSexport void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID Interfac 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); + debugf("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 @@ -3739,22 +3987,39 @@ mDNSexport void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID Interfac 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 +#ifdef _LEGACY_NAT_TRAVERSAL_ + LNT_ClearState(m); +#endif // _LEGACY_NAT_TRAVERSAL_ if (AddrReply->opcode == NATOp_AddrResponse) { +#if APPLE_OSX_mDNSResponder + static char msgbuf[16]; + mDNS_snprintf(msgbuf, sizeof(msgbuf), "%d", AddrReply->err); + mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.natpmp.AddressRequest", AddrReply->err ? "failure" : "success", msgbuf, ""); +#endif 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 APPLE_OSX_mDNSResponder + static char msgbuf[16]; + mDNS_snprintf(msgbuf, sizeof(msgbuf), "%s - %d", AddrReply->opcode == NATOp_MapUDPResponse ? "UDP" : "TCP", PortMapReply->err); + mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.natpmp.PortMapRequest", PortMapReply->err ? "failure" : "success", msgbuf, ""); +#endif if (!PortMapReply->err) { 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]); } + // Since some NAT-PMP server implementations don't return the requested internal port in + // the reply, we can't associate this reply with a particular NATTraversalInfo structure. + // We globally keep track of the most recent error code for mappings. + m->LastNATMapResultCode = PortMapReply->err; + 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); @@ -3762,7 +4027,7 @@ mDNSexport void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID Interfac else { LogMsg("Received NAT Traversal response with version unknown opcode 0x%X", AddrReply->opcode); return; } // Don't need an SSDP socket if we get a NAT-PMP packet - if (m->SSDPSocket) { LogOperation("uDNS_ReceiveNATPMPPacket destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; } + if (m->SSDPSocket) { debugf("uDNS_ReceiveNATPMPPacket destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; } } // Shorten DNS-SD queries to avoid NAT bugs @@ -3857,12 +4122,25 @@ mDNSlocal mDNSBool uDNS_ReceiveTestQuestionResponse(mDNS *const m, DNSMessage *c // 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) + { + mDNSBool matchaddr = (s->teststate != result && mDNSSameAddress(srcaddr, &s->addr) && mDNSSameIPPort(srcport, s->port)); + mDNSBool matchid = (s->teststate == DNSServer_Untested && mDNSSameOpaque16(msg->h.id, s->testid)); + if (matchaddr || matchid) { DNSQuestion *q; 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) + { + LogInfo("DNS Server %#a:%d (%#a:%d) %d passed%s", + &s->addr, mDNSVal16(s->port), srcaddr, mDNSVal16(srcport), mDNSVal16(s->testid), + matchaddr ? "" : " NOTE: Reply did not come from address to which query was sent"); + } + else + { + LogMsg("NOTE: Wide-Area Service Discovery disabled to avoid crashing defective DNS relay %#a:%d (%#a:%d) %d%s", + &s->addr, mDNSVal16(s->port), srcaddr, mDNSVal16(srcport), mDNSVal16(s->testid), + matchaddr ? "" : " NOTE: Reply did not come from address to which query was sent"); + } // If this server has just changed state from DNSServer_Untested to DNSServer_Passed, then retrigger any waiting questions. // We use the NoTestQuery() test so that we only retrigger questions that were actually blocked waiting for this test to complete. @@ -3876,6 +4154,7 @@ mDNSlocal mDNSBool uDNS_ReceiveTestQuestionResponse(mDNS *const m, DNSMessage *c m->NextScheduledQuery = m->timenow; } } + } return(mDNStrue); // Return mDNStrue to tell uDNS_ReceiveMsg it doesn't need to process this packet further } @@ -3914,7 +4193,7 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS // 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)); + LogInfo("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(); @@ -3928,7 +4207,7 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS mDNSu32 lease = GetPktLease(m, msg, end); mDNSs32 expire = m->timenow + (mDNSs32)lease * mDNSPlatformOneSecond; - //rcode = kDNSFlag1_RC_SrvErr; // Simulate server failure (rcode 2) + //rcode = kDNSFlag1_RC_ServFail; // Simulate server failure (rcode 2) if (CurrentServiceRecordSet) LogMsg("uDNS_ReceiveMsg ERROR CurrentServiceRecordSet already set"); @@ -3958,7 +4237,7 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS { AuthRecord *rptr = m->CurrentRecord; m->CurrentRecord = m->CurrentRecord->next; - if (mDNSSameOpaque16(rptr->id, msg->h.id)) + if (AuthRecord_uDNS(rptr) && mDNSSameOpaque16(rptr->updateid, msg->h.id)) { err = checkUpdateResult(m, rptr->resrec.name, rcode, msg, end); if (!err && rptr->uselease && lease) @@ -3998,7 +4277,7 @@ mDNSexport void sendLLQRefresh(mDNS *m, DNSQuestion *q) llq.llqlease = q->ReqLease; InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags); - end = putLLQ(&m->omsg, m->omsg.data, q, &llq, mDNStrue); + end = putLLQ(&m->omsg, m->omsg.data, q, &llq); if (!end) { LogMsg("sendLLQRefresh: putLLQ failed %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; } // Note that we (conditionally) add HINFO and TSIG here, since the question might be going away, @@ -4014,7 +4293,7 @@ mDNSexport void sendLLQRefresh(mDNS *m, DNSQuestion *q) if (q->AuthInfo && !q->tcp) { - LogOperation("sendLLQRefresh setting up new TLS session %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + LogInfo("sendLLQRefresh setting up new TLS session %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); q->tcp = MakeTCPConn(m, &m->omsg, end, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, q, mDNSNULL, mDNSNULL); } else @@ -4054,11 +4333,19 @@ mDNSexport void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneI q->servPort = zoneInfo->Port; q->AuthInfo = zoneInfo->ZonePrivate ? GetAuthInfoForName_internal(m, &q->qname) : mDNSNULL; q->ntries = 0; - LogOperation("LLQGotZoneData %#a:%d", &q->servAddr, mDNSVal16(q->servPort)); + debugf("LLQGotZoneData %#a:%d", &q->servAddr, mDNSVal16(q->servPort)); startLLQHandshake(m, q); } else + { StartLLQPolling(m,q); + if (err == mStatus_NoSuchNameErr) + { + // this actually failed, so mark it by setting address to all ones + q->servAddr.type = mDNSAddrType_IPv4; + q->servAddr.ip.v4 = onesIPv4Addr; + } + } mDNS_Unlock(m); } @@ -4068,7 +4355,7 @@ mDNSlocal void PrivateQueryGotZoneData(mDNS *const m, mStatus err, const ZoneDat { DNSQuestion *q = (DNSQuestion *) zoneInfo->ZoneDataContext; - LogOperation("PrivateQueryGotZoneData %##s (%s) err %d Zone %##s Private %d", q->qname.c, DNSTypeName(q->qtype), err, zoneInfo->ZoneName.c, zoneInfo->ZonePrivate); + LogInfo("PrivateQueryGotZoneData %##s (%s) err %d Zone %##s Private %d", q->qname.c, DNSTypeName(q->qtype), err, zoneInfo->ZoneName.c, zoneInfo->ZonePrivate); // 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 @@ -4077,7 +4364,7 @@ mDNSlocal void PrivateQueryGotZoneData(mDNS *const m, mStatus err, const ZoneDat if (err || !zoneInfo || mDNSAddressIsZero(&zoneInfo->Addr) || mDNSIPPortIsZero(zoneInfo->Port)) { - LogOperation("ERROR: PrivateQueryGotZoneData %##s (%s) invoked with error code %ld %p %#a:%d", + LogInfo("ERROR: PrivateQueryGotZoneData %##s (%s) invoked with error code %d %p %#a:%d", q->qname.c, DNSTypeName(q->qtype), err, zoneInfo, zoneInfo ? &zoneInfo->Addr : mDNSNULL, zoneInfo ? mDNSVal16(zoneInfo->Port) : 0); @@ -4118,6 +4405,7 @@ mDNSexport void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const { AuthRecord *newRR = (AuthRecord*)zoneData->ZoneDataContext; AuthRecord *ptr; + int c1, c2; if (m->mDNS_busy != m->mDNS_reentrancy) LogMsg("RecordRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy); @@ -4135,7 +4423,7 @@ mDNSexport void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const // check error/result if (err) { - if (err != mStatus_NoSuchNameErr) LogMsg("RecordRegistrationGotZoneData: error %ld", err); + if (err != mStatus_NoSuchNameErr) LogMsg("RecordRegistrationGotZoneData: error %d", err); return; } @@ -4152,12 +4440,24 @@ mDNSexport void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const // organizations use their own private pseudo-TLD, like ".home", etc, and we don't want to block that. if (zoneData->ZoneName.c[0] == 0) { - LogOperation("RecordRegistrationGotZoneData: No name server found claiming responsibility for \"%##s\"!", newRR->resrec.name->c); + LogInfo("RecordRegistrationGotZoneData: No name server found claiming responsibility for \"%##s\"!", newRR->resrec.name->c); return; } // Store discovered zone data - AssignDomainName(&newRR->zone, &zoneData->ZoneName); + c1 = CountLabels(newRR->resrec.name); + c2 = CountLabels(&zoneData->ZoneName); + if (c2 > c1) + { + LogMsg("RecordRegistrationGotZoneData: Zone \"%##s\" is longer than \"%##s\"", zoneData->ZoneName.c, newRR->resrec.name->c); + return; + } + newRR->zone = SkipLeadingLabels(newRR->resrec.name, c1-c2); + if (!SameDomainName(newRR->zone, &zoneData->ZoneName)) + { + LogMsg("RecordRegistrationGotZoneData: Zone \"%##s\" does not match \"%##s\" for \"%##s\"", newRR->zone->c, zoneData->ZoneName.c, newRR->resrec.name->c); + return; + } newRR->UpdateServer = zoneData->Addr; newRR->UpdatePort = zoneData->Port; newRR->Private = zoneData->ZonePrivate; @@ -4166,7 +4466,7 @@ mDNSexport void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const if (mDNSIPPortIsZero(zoneData->Port) || mDNSAddressIsZero(&zoneData->Addr)) { - LogOperation("RecordRegistrationGotZoneData: No _dns-update._udp service found for \"%##s\"!", newRR->resrec.name->c); + LogInfo("RecordRegistrationGotZoneData: No _dns-update._udp service found for \"%##s\"!", newRR->resrec.name->c); return; } @@ -4190,9 +4490,9 @@ mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr) return; } - InitializeDNSMessage(&m->omsg.h, rr->id, UpdateReqFlags); + InitializeDNSMessage(&m->omsg.h, rr->updateid, UpdateReqFlags); - ptr = putZone(&m->omsg, ptr, end, &rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass)); + ptr = putZone(&m->omsg, ptr, end, rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass)); if (ptr) ptr = putDeletionRecord(&m->omsg, ptr, &rr->resrec); if (!ptr) { @@ -4204,8 +4504,8 @@ mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr) rr->expire = 0; // Indicate that we have no active registration any more if (rr->Private) { - LogOperation("SendRecordDeregistration TCP %p %s", rr->tcp, ARDisplayString(m, rr)); - if (rr->tcp) LogOperation("SendRecordDeregistration: Disposing existing TCP connection for %s", ARDisplayString(m, rr)); + LogInfo("SendRecordDeregistration TCP %p %s", rr->tcp, ARDisplayString(m, rr)); + if (rr->tcp) LogInfo("SendRecordDeregistration: Disposing existing TCP connection for %s", ARDisplayString(m, rr)); if (rr->tcp) DisposeTCPConn(rr->tcp); rr->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, mDNSNULL, rr); if (!rr->tcp) rr->ThisAPInterval = mDNSPlatformOneSecond * 5; // If failed to make TCP connection, try again in ten seconds (5*2) @@ -4215,7 +4515,7 @@ mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr) else { mStatus err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name)); - if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %ld", err); + if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %d", err); if (rr->state == regState_DeregPending) CompleteDeregistration(m, rr); // Don't touch rr after this } } @@ -4255,7 +4555,7 @@ mDNSexport mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs) // don't re-register with a new target following deregistration srs->SRVChanged = srs->SRVUpdateDeferred = mDNSfalse; - if (srs->nta) { CancelGetZoneData(m, srs->nta); srs->nta = mDNSNULL; } + if (srs->srs_nta) { CancelGetZoneData(m, srs->srs_nta); srs->srs_nta = mDNSNULL; } if (srs->NATinfo.clientContext) { @@ -4405,26 +4705,9 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) if (q->unansweredQueries >= MAX_UCAST_UNANSWERED_QUERIES) { DNSServer *orig = q->qDNSServer; - -#if LogAllOperations || MDNS_DEBUGMSGS - char buffer[1024]; - - mDNS_snprintf(buffer, sizeof(buffer), orig ? "%#a:%d (%##s)" : "null", &orig->addr, mDNSVal16(orig->port), orig->domain.c); - LogOperation("Sent %d unanswered queries for %##s (%s) to %s", q->unansweredQueries, q->qname.c, DNSTypeName(q->qtype), buffer); -#endif + if (orig) LogInfo("Sent %d unanswered queries for %##s (%s) to %#a:%d (%##s)", q->unansweredQueries, q->qname.c, DNSTypeName(q->qtype), &orig->addr, mDNSVal16(orig->port), orig->domain.c); PushDNSServerToEnd(m, q); - q->qDNSServer = GetServerForName(m, &q->qname); - - if (q->qDNSServer != orig) - { -#if LogAllOperations || MDNS_DEBUGMSGS - mDNS_snprintf(buffer, sizeof(buffer), q->qDNSServer ? "%#a:%d (%##s)" : "null", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c); - LogOperation("Server for %##s (%s) changed to %s", q->qname.c, DNSTypeName(q->qtype), buffer); -#endif - q->ThisQInterval = q->ThisQInterval / QuestionIntervalStep; // Decrease interval one step so we don't quickly bounce between servers for queries that will not be answered. - } - q->unansweredQueries = 0; } @@ -4443,10 +4726,11 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) } 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)); + LogInfo("Sending DNS test query to %#a:%d", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port)); q->ThisQInterval = INIT_UCAST_POLL_INTERVAL / QuestionIntervalStep; q->qDNSServer->lasttest = m->timenow; end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, DNSRelayTestQuestion, kDNSType_PTR, kDNSClass_IN); + q->qDNSServer->testid = m->omsg.h.id; } if (end > m->omsg.data && (q->qDNSServer->teststate != DNSServer_Failed || NoTestQuery(q))) @@ -4460,19 +4744,21 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) } else { - err = mDNSSendDNSMessage(m, &m->omsg, end, q->qDNSServer->interface, q->LocalSocket, &q->qDNSServer->addr, q->qDNSServer->port, mDNSNULL, mDNSNULL); + if (!q->LocalSocket) q->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort); + if (!q->LocalSocket) err = mStatus_NoMemoryErr; // If failed to make socket (should be very rare), we'll try again next time + else err = mDNSSendDNSMessage(m, &m->omsg, end, q->qDNSServer->interface, q->LocalSocket, &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 + if (err) debugf("ERROR: uDNS_idle - mDNSSendDNSMessage - %d", err); // surpress syslog messages if we have no network else { q->ThisQInterval = q->ThisQInterval * QuestionIntervalStep; // Only increase interval if send succeeded q->unansweredQueries++; if (q->ThisQInterval > MAX_UCAST_POLL_INTERVAL) q->ThisQInterval = MAX_UCAST_POLL_INTERVAL; - LogOperation("Increased ThisQInterval to %d for %##s (%s)", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype)); + debugf("Increased ThisQInterval to %d for %##s (%s)", q->ThisQInterval, q->qname.c, DNSTypeName(q->qtype)); } q->LastQTime = m->timenow; SetNextQueryTime(m, q); @@ -4495,10 +4781,10 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m) for (rr = cg->members; rr; rr=rr->next) if (SameNameRecordAnswersQuestion(&rr->resrec, q)) mDNS_PurgeCacheResourceRecord(m, rr); - if (!q->qDNSServer) LogOperation("uDNS_CheckCurrentQuestion no DNS server for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + if (!q->qDNSServer) debugf("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); + MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any); // Inactivate this question until the next change of DNS servers (do this before AnswerCurrentQuestionWithResourceRecord) q->ThisQInterval = 0; q->unansweredQueries = 0; @@ -4522,17 +4808,25 @@ mDNSlocal void CheckNATMappings(mDNS *m) { if (m->NATMcastRecvskt == mDNSNULL) // If we are behind a NAT and the socket hasn't been opened yet, open it { + // we need to log a message if we can't get our socket, but only the first time (after success) + static mDNSBool needLog = mDNStrue; m->NATMcastRecvskt = mDNSPlatformUDPSocket(m, NATPMPAnnouncementPort); - m->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"); + if (!m->NATMcastRecvskt) + { + if (needLog) + { + LogMsg("CheckNATMappings: Failed to allocate port 5350 UDP multicast socket for NAT-PMP announcements"); + needLog = mDNSfalse; + } + } + else + needLog = mDNStrue; } } 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->SSDPSocket) { LogOperation("CheckNATMappings destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; } + if (m->SSDPSocket) { debugf("CheckNATMappings destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; } } if (m->NATTraversals) @@ -4612,8 +4906,14 @@ mDNSlocal void CheckNATMappings(mDNS *m) { //LogMsg("NAT callback %d %d %d", cur->Protocol, cur->ExpiryTime, cur->retryInterval); if (cur->Protocol && mDNSIPPortIsZero(ExternalPort) && !mDNSIPv4AddressIsZero(m->Router.ip.v4)) - LogMsg("Failed to obtain NAT port mapping %p from router %#a external address %.4a internal port %d error %d", - cur, &m->Router, &m->ExternalAddress, mDNSVal16(cur->IntPort), EffectiveResult); + { + if (!EffectiveResult) + LogInfo("Failed to obtain NAT port mapping %p from router %#a external address %.4a internal port %5d interval %d error %d", + cur, &m->Router, &m->ExternalAddress, mDNSVal16(cur->IntPort), cur->retryInterval, EffectiveResult); + else + LogMsg("Failed to obtain NAT port mapping %p from router %#a external address %.4a internal port %5d interval %d error %d", + cur, &m->Router, &m->ExternalAddress, mDNSVal16(cur->IntPort), cur->retryInterval, EffectiveResult); + } cur->ExternalAddress = m->ExternalAddress; cur->ExternalPort = ExternalPort; @@ -4682,8 +4982,8 @@ mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m) if (srs->tcp) { DisposeTCPConn(srs->tcp); srs->tcp = mDNSNULL; } if (srs->state == regState_FetchingZoneData) { - if (srs->nta) CancelGetZoneData(m, srs->nta); - srs->nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, srs); + if (srs->srs_nta) CancelGetZoneData(m, srs->srs_nta); + srs->srs_nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, srs); SetRecordRetry(m, &srs->RR_SRV, mStatus_NoError); } else if (srs->state == regState_DeregPending) SendServiceDeregistration(m, srs); @@ -4747,8 +5047,8 @@ mDNSexport void SleepServiceRegistrations(mDNS *m) ServiceRecordSet *srs = m->ServiceRegistrations; while (srs) { - LogOperation("SleepServiceRegistrations: state %d %s", srs->state, ARDisplayString(m, &srs->RR_SRV)); - if (srs->nta) { CancelGetZoneData(m, srs->nta); srs->nta = mDNSNULL; } + LogInfo("SleepServiceRegistrations: state %d %s", srs->state, ARDisplayString(m, &srs->RR_SRV)); + if (srs->srs_nta) { CancelGetZoneData(m, srs->srs_nta); srs->srs_nta = mDNSNULL; } if (srs->NATinfo.clientContext) { @@ -4790,7 +5090,7 @@ mDNSexport void mDNS_AddSearchDomain(const domainname *const 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); + LogInfo("mDNS_AddSearchDomain already in list %##s", domain->c); return; } @@ -4801,7 +5101,7 @@ mDNSexport void mDNS_AddSearchDomain(const domainname *const domain) AssignDomainName(&(*p)->domain, domain); (*p)->flag = 1; // add (*p)->next = mDNSNULL; - LogOperation("mDNS_AddSearchDomain created new %##s", domain->c); + LogInfo("mDNS_AddSearchDomain created new %##s", domain->c); } mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result) @@ -4814,26 +5114,30 @@ mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceR { SearchListElem *slElem = question->QuestionContext; mStatus err; + const char *name; if (answer->rrtype != kDNSType_PTR) return; if (answer->RecordType == kDNSRecordTypePacketNegative) return; + if (answer->InterfaceID == mDNSInterface_LocalOnly) return; + + 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"); return; } + + LogInfo("FoundDomain: %p %s %s Q %##s A %s", answer->InterfaceID, AddRecord ? "Add" : "Rmv", name, question->qname.c, RRDisplayString(m, answer)); if (AddRecord) { - const char *name; ARListElem *arElem = mDNSPlatformMemAllocate(sizeof(ARListElem)); - if (!arElem) { LogMsg("ERROR: malloc"); return; } + if (!arElem) { LogMsg("ERROR: FoundDomain out of memory"); 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); + LogInfo("FoundDomain: Registering %s", ARDisplayString(m, &arElem->ar)); err = mDNS_Register(m, &arElem->ar); if (err) { LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err); mDNSPlatformMemFree(arElem); return; } arElem->next = slElem->AuthRecs; @@ -4848,7 +5152,7 @@ mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceR { ARListElem *dereg = *ptr; *ptr = (*ptr)->next; - debugf("Deregistering PTR %##s -> %##s", dereg->ar.resrec.name->c, dereg->ar.resrec.rdata->u.name.c); + LogInfo("FoundDomain: Deregistering %s", ARDisplayString(m, &dereg->ar)); err = mDNS_Deregister(m, &dereg->ar); if (err) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err); // Memory will be freed in the FreeARElemCallback @@ -4917,18 +5221,22 @@ mDNSexport mStatus uDNS_RegisterSearchDomains(mDNS *const m) while (*p) { ptr = *p; - debugf("RegisterSearchDomains %d %p %##s", ptr->flag, ptr->AuthRecs, ptr->domain.c); + LogInfo("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); + // If the user has "local" in their DNS searchlist, we ignore that for the purposes of domain enumeration queries + if (!SameDomainName(&ptr->domain, &localdomain)) + { + 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 @@ -4946,20 +5254,24 @@ mDNSexport mStatus uDNS_RegisterSearchDomains(mDNS *const m) 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); + // If the user has "local" in their DNS searchlist, we ignore that for the purposes of domain enumeration queries + if (!SameDomainName(&ptr->domain, &localdomain)) + { + 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; } @@ -4987,5 +5299,5 @@ struct CompileTimeAssertionChecks_uDNS // 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) <= 9056) ? 1 : -1]; - char sizecheck_SearchListElem[(sizeof(SearchListElem) <= 3880) ? 1 : -1]; + char sizecheck_SearchListElem[(sizeof(SearchListElem) <= 3920) ? 1 : -1]; }; diff --git a/mDNSCore/uDNS.h b/mDNSCore/uDNS.h index 3a66ab6..71f4097 100755 --- a/mDNSCore/uDNS.h +++ b/mDNSCore/uDNS.h @@ -17,6 +17,10 @@ Change History (most recent first): $Log: uDNS.h,v $ +Revision 1.93 2008/09/24 23:48:05 cheshire +Don't need to pass whole ServiceRecordSet reference to GetServiceTarget; +it only needs to access the embedded SRV member of the set + Revision 1.92 2008/06/19 23:42:03 mcguire Use all configured DNS servers @@ -274,7 +278,7 @@ extern void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const Zone extern mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr); extern void ServiceRegistrationGotZoneData(mDNS *const m, mStatus err, const ZoneData *result); -extern const domainname *GetServiceTarget(mDNS *m, ServiceRecordSet *srs); +extern const domainname *GetServiceTarget(mDNS *m, AuthRecord *const rr); extern mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs); extern void uDNS_CheckCurrentQuestion(mDNS *const m); diff --git a/mDNSMacOS9/Mac OS Test Responder.c b/mDNSMacOS9/Mac OS Test Responder.c index cc14173..1cf014c 100644 --- a/mDNSMacOS9/Mac OS Test Responder.c +++ b/mDNSMacOS9/Mac OS Test Responder.c @@ -17,6 +17,9 @@ Change History (most recent first): $Log: Mac\040OS\040Test\040Responder.c,v $ +Revision 1.26 2008/11/04 19:43:35 cheshire +Updated comment about MAX_ESCAPED_DOMAIN_NAME size (should be 1009, not 1005) + Revision 1.25 2006/08/14 23:24:29 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -45,7 +48,7 @@ Change to use mDNSOpaque16fromIntVal/mDNSVal16 instead of shifting and masking Revision 1.18 2003/11/14 21:27:08 cheshire : Security: Crashing bug in mDNSResponder -Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers. +Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1009) instead of 256-byte buffers. Revision 1.17 2003/08/14 02:19:54 cheshire Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord diff --git a/mDNSMacOS9/Mac OS Test Searcher.c b/mDNSMacOS9/Mac OS Test Searcher.c index 4f282dc..ca37051 100644 --- a/mDNSMacOS9/Mac OS Test Searcher.c +++ b/mDNSMacOS9/Mac OS Test Searcher.c @@ -17,6 +17,9 @@ Change History (most recent first): $Log: Mac\040OS\040Test\040Searcher.c,v $ +Revision 1.24 2008/11/04 19:43:35 cheshire +Updated comment about MAX_ESCAPED_DOMAIN_NAME size (should be 1009, not 1005) + 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 @@ -53,7 +56,7 @@ Change to use mDNSOpaque16fromIntVal/mDNSVal16 instead of shifting and masking Revision 1.14 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. +Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1009) instead of 256-byte buffers. Revision 1.13 2003/08/14 02:19:54 cheshire Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord diff --git a/mDNSMacOSX/DNSServiceDiscovery.c b/mDNSMacOSX/DNSServiceDiscovery.c index 1f701f5..1dea7f9 100644 --- a/mDNSMacOSX/DNSServiceDiscovery.c +++ b/mDNSMacOSX/DNSServiceDiscovery.c @@ -635,13 +635,13 @@ kern_return_t internal_DNSServiceResolverReply_rpc if (interface) { int len = ((struct sockaddr *)interface)->sa_len; interface_storage = (struct sockaddr *)malloc(len); - bcopy(interface, interface_storage,len); + memcpy(interface_storage, interface, len); } if (address) { int len = ((struct sockaddr *)address)->sa_len; address_storage = (struct sockaddr *)malloc(len); - bcopy(address, address_storage, len); + memcpy(address_storage, address, len); } pthread_mutex_lock(&a_requests_lock); diff --git a/mDNSMacOSX/LaunchDaemonInfo.dnsextd.plist b/mDNSMacOSX/LaunchDaemonInfo.dnsextd.plist index 37cb38d..e31b391 100644 --- a/mDNSMacOSX/LaunchDaemonInfo.dnsextd.plist +++ b/mDNSMacOSX/LaunchDaemonInfo.dnsextd.plist @@ -13,7 +13,5 @@ /usr/sbin/dnsextd -launchd - ServiceIPC - diff --git a/mDNSMacOSX/LaunchDaemonInfo.helper.plist b/mDNSMacOSX/LaunchDaemonInfo.helper.plist index cb01007..edf5d06 100644 --- a/mDNSMacOSX/LaunchDaemonInfo.helper.plist +++ b/mDNSMacOSX/LaunchDaemonInfo.helper.plist @@ -6,8 +6,6 @@ com.apple.mDNSResponderHelper OnDemand - HopefullyExitsLast - ProgramArguments /usr/sbin/mDNSResponderHelper @@ -17,7 +15,7 @@ com.apple.mDNSResponderHelper - ServiceIPC + EnableTransactions diff --git a/mDNSMacOSX/LaunchDaemonInfo.plist b/mDNSMacOSX/LaunchDaemonInfo.plist index a36f31d..c81682f 100644 --- a/mDNSMacOSX/LaunchDaemonInfo.plist +++ b/mDNSMacOSX/LaunchDaemonInfo.plist @@ -6,8 +6,6 @@ com.apple.mDNSResponder OnDemand - HopefullyExitsFirst - UserName _mdnsresponder GroupName @@ -34,7 +32,7 @@ 438 - ServiceIPC + EnableTransactions diff --git a/mDNSMacOSX/LegacyNATTraversal.c b/mDNSMacOSX/LegacyNATTraversal.c index d833ca9..5cf1ae1 100644 --- a/mDNSMacOSX/LegacyNATTraversal.c +++ b/mDNSMacOSX/LegacyNATTraversal.c @@ -17,9 +17,60 @@ Change History (most recent first): $Log: LegacyNATTraversal.c,v $ -Revision 1.48.2.1 2008/09/30 18:03:03 mcguire +Revision 1.65 2009/07/03 03:16:07 jessic2 + BTMM: UPnP works in Leopard but doesn't work in SnowLeopard (URLBase is empty) Made changes to support the case where the URLBase tag exists but there isn't a valid URL + +Revision 1.64 2009/06/25 21:07:44 herscher + B4W should support UPnP + +Revision 1.63 2009/03/26 03:59:00 jessic2 +Changes for + +Revision 1.62 2009/02/13 06:31:09 cheshire +Converted LogOperation messages to LogInfo + +Revision 1.61 2009/01/23 19:25:43 mcguire + UPnP: Should not use NATErr_Refused when too many conflict retries + +Revision 1.60 2009/01/23 00:38:36 mcguire + BTMM: Doesn't work with Linksys WRT54GS firmware 4.71.1 + +Revision 1.59 2009/01/22 20:32:17 mcguire + BTMM: pref pane reports enabled but negotiation failed +Make sure we push the pointer out past the LF if we read it. + +Revision 1.58 2009/01/22 01:15:58 mcguire + BTMM: pref pane reports enabled but negotiation failed + +Revision 1.57 2008/12/19 21:09:22 mcguire + UPnP: error messages when canceling seemingly unrelated browse + +Revision 1.56 2008/12/06 01:42:57 mcguire + Need to exponentially back-off after failure to get public address + +Revision 1.55 2008/12/01 19:43:48 mcguire + UPnP: Handle errorCode 718 as a conflict when requesting a port mapping + +Revision 1.54 2008/11/26 20:57:37 cheshire +For consistency with other similar macros, renamed mdnsIsDigit/mdnsIsLetter/mdnsValidHostChar +to mDNSIsDigit/mDNSIsLetter/mDNSValidHostChar + +Revision 1.53 2008/11/26 20:34:04 cheshire +Changed "destroying SSDPSocket" LogOperation debugging messages to debugf + +Revision 1.52 2008/11/26 19:54:03 cheshire +Changed some "LogOperation" debugging messages to "debugf" + +Revision 1.51 2008/11/20 02:23:38 mcguire + need to handle URLBase + +Revision 1.50 2008/09/20 00:34:22 mcguire BTMM: Add support for WANPPPConnection +Revision 1.49 2008/08/07 21:51:13 mcguire + UPnP: Possible memory corruption bug + UPnP: Combine URL parsing code + Revision 1.48 2008/07/24 20:23:04 cheshire Should use randomized source ports and transaction IDs to avoid DNS cache poisoning @@ -183,7 +234,34 @@ Revision 1.1 2004/08/18 17:35:41 ksekar #include "stdlib.h" // For strtol() #include "string.h" // For strlcpy(), For strncpy(), strncasecmp() -#include // For inet_pton() + +#if defined( WIN32 ) +# include +# include +# define strcasecmp _stricmp +# define strncasecmp _strnicmp +# define mDNSASLLog( UUID, SUBDOMAIN, RESULT, SIGNATURE, FORMAT, ... ) ; + +static int +inet_pton( int family, const char * addr, void * dst ) + { + struct sockaddr_storage ss; + int sslen = sizeof( ss ); + + ZeroMemory( &ss, sizeof( ss ) ); + ss.ss_family = family; + + if ( WSAStringToAddressA( addr, family, NULL, ( struct sockaddr* ) &ss, &sslen ) == 0 ) + { + if ( family == AF_INET ) { memcpy( dst, &( ( struct sockaddr_in* ) &ss)->sin_addr, sizeof( IN_ADDR ) ); return 1; } + else if ( family == AF_INET6 ) { memcpy( dst, &( ( struct sockaddr_in6* ) &ss)->sin6_addr, sizeof( IN6_ADDR ) ); return 1; } + else return 0; + } + else return 0; + } +#else +# include // For inet_pton() +#endif #include "mDNSEmbeddedAPI.h" #include "uDNS.h" // For natTraversalHandleAddressReply() etc. @@ -214,6 +292,116 @@ mDNSlocal mStatus SendPortMapRequest(mDNS *m, NATTraversalInfo *n); #define RequestedPortNum(n) (mDNSVal16(mDNSIPPortIsZero((n)->RequestedPort) ? (n)->IntPort : (n)->RequestedPort) + (n)->tcpInfo.retries) +// Note that this function assumes src is already NULL terminated +mDNSlocal void AllocAndCopy(mDNSu8** dst, mDNSu8* src) + { + if (src == mDNSNULL) return; + if ((*dst = (mDNSu8 *) mDNSPlatformMemAllocate(strlen((char*)src) + 1)) == mDNSNULL) { LogMsg("AllocAndCopy: can't allocate string"); return; } + strcpy((char *)*dst, (char*)src); + } + +// This function does a simple parse of an HTTP URL that may include a hostname, port, and path +// If found in the URL, addressAndPort and path out params will point to newly allocated space (and will leak if they were previously pointing at allocated space) +mDNSlocal mStatus ParseHttpUrl(char* ptr, char* end, mDNSu8** addressAndPort, mDNSIPPort* port, mDNSu8** path) + { + // if the data begins with "http://", we assume there is a hostname and possibly a port number + if (end - ptr >= 7 && strncasecmp(ptr, "http://", 7) == 0) + { + int i; + char* stop = end; + char* addrPtr = mDNSNULL; + + ptr += 7; //skip over "http://" + if (ptr >= end) { LogInfo("ParseHttpUrl: past end of buffer parsing host:port"); return mStatus_BadParamErr; } + + // find the end of the host:port + addrPtr = ptr; + for (i = 0; addrPtr && addrPtr != end; i++, addrPtr++) if (*addrPtr == '/') break; + + // allocate the buffer (len i+1 so we have space to terminate the string) + if ((*addressAndPort = (mDNSu8 *) mDNSPlatformMemAllocate(i+1)) == mDNSNULL) { LogMsg("ParseHttpUrl: can't allocate address string"); return mStatus_NoMemoryErr; } + strncpy((char *)*addressAndPort, ptr, i); + (*addressAndPort)[i] = '\0'; + + // find the port number in the string, by looking backwards for the ':' + stop = ptr; // can't go back farther than the original start + ptr = addrPtr; // move ptr to the path part + + for (addrPtr--;addrPtr>stop;addrPtr--) + { + if (*addrPtr == ':') + { + int tmpport; + addrPtr++; // skip over ':' + tmpport = (int)strtol(addrPtr, mDNSNULL, 10); + *port = mDNSOpaque16fromIntVal(tmpport); // store it properly converted + break; + } + } + } + + // ptr should now point to the first character we haven't yet processed + // everything that remains is the path + if (path && ptr < end) + { + if ((*path = (mDNSu8 *)mDNSPlatformMemAllocate(end - ptr + 1)) == mDNSNULL) { LogMsg("ParseHttpUrl: can't mDNSPlatformMemAllocate path"); return mStatus_NoMemoryErr; } + strncpy((char *)*path, ptr, end - ptr); + (*path)[end - ptr] = '\0'; + } + + return mStatus_NoError; + } + +enum + { + HTTPCode_NeedMoreData = -1, // No code found in stream + HTTPCode_Other = -2, // Valid code other than those below found in stream + HTTPCode_Bad = -3, + HTTPCode_200 = 200, + HTTPCode_404 = 404, + HTTPCode_500 = 500, + }; + +mDNSlocal mDNSs16 ParseHTTPResponseCode(mDNSu8** data, mDNSu8* end) + { + mDNSu8* ptr = *data; + char * code; + + if (end - ptr < 5) return HTTPCode_NeedMoreData; + if (strncasecmp((char*)ptr, "HTTP/", 5) != 0) return HTTPCode_Bad; + ptr += 5; + // should we care about the HTTP protocol version? + + // look for first space, which must come before first LF + while (ptr && ptr != end) + { + if (*ptr == '\n') return HTTPCode_Bad; + if (*ptr == ' ') break; + ptr++; + } + if (ptr == end) return HTTPCode_NeedMoreData; + ptr++; + + if (end - ptr < 3) return HTTPCode_NeedMoreData; + + code = (char*)ptr; + ptr += 3; + while (ptr && ptr != end) + { + if (*ptr == '\n') break; + ptr++; + } + if (ptr == end) return HTTPCode_NeedMoreData; + *data = ++ptr; + + if (memcmp(code, "200", 3) == 0) return HTTPCode_200; + if (memcmp(code, "404", 3) == 0) return HTTPCode_404; + if (memcmp(code, "500", 3) == 0) return HTTPCode_500; + + LogInfo("ParseHTTPResponseCode found unexpected result code: %c%c%c", code[0], code[1], code[2]); + return HTTPCode_Other; + } + // This function parses the xml body of the device description response from the router. Basically, we look to make sure this is a response // referencing a service we care about (WANIPConnection or WANPPPConnection), look for the "controlURL" header immediately following, and copy the addressing and URL info we need mDNSlocal void handleLNTDeviceDescriptionResponse(tcpLNTInfo *tcpInfo) @@ -222,12 +410,23 @@ mDNSlocal void handleLNTDeviceDescriptionResponse(tcpLNTInfo *tcpInfo) char *ptr = (char *)tcpInfo->Reply; char *end = (char *)tcpInfo->Reply + tcpInfo->nread; char *stop = mDNSNULL; + mDNSs16 http_result; + + if (!mDNSIPPortIsZero(m->UPnPSOAPPort)) return; // already have the info we need + + http_result = ParseHTTPResponseCode((mDNSu8**)&ptr, (mDNSu8*)end); // Note: modifies ptr + if (http_result == HTTPCode_404) LNT_ClearState(m); + if (http_result != HTTPCode_200) + { + mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "noop", "HTTP Result", "HTTP code: %d", http_result); + return; + } // Always reset our flag to use WANIPConnection. We'll use WANPPPConnection if we find it and don't find WANIPConnection. m->UPnPWANPPPConnection = mDNSfalse; // find either service we care about - while (ptr && ptr != end) + while (ptr && ptr < end) { if (*ptr == 'W' && (strncasecmp(ptr, "WANIPConnection:1", 17) == 0)) break; ptr++; @@ -235,7 +434,7 @@ mDNSlocal void handleLNTDeviceDescriptionResponse(tcpLNTInfo *tcpInfo) if (ptr == end) { ptr = (char *)tcpInfo->Reply; - while (ptr && ptr != end) + while (ptr && ptr < end) { if (*ptr == 'W' && (strncasecmp(ptr, "WANPPPConnection:1", 18) == 0)) { @@ -245,79 +444,69 @@ mDNSlocal void handleLNTDeviceDescriptionResponse(tcpLNTInfo *tcpInfo) ptr++; } } - if (ptr == mDNSNULL || ptr == end) { LogOperation("handleLNTDeviceDescriptionResponse: didn't find WANIPConnection:1 or WANPPPConnection:1 string"); return; } + if (ptr == mDNSNULL || ptr == end) { LogInfo("handleLNTDeviceDescriptionResponse: didn't find WANIPConnection:1 or WANPPPConnection:1 string"); return; } // find "controlURL", starting from where we left off - while (ptr && ptr != end) + while (ptr && ptr < end) { 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; } + if (ptr == mDNSNULL || ptr == end) { LogInfo("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 + if (ptr >= end) { LogInfo("handleLNTDeviceDescriptionResponse: past end of buffer and no body!"); return; } // check ptr again in case we skipped over the end of the buffer // find the end of the controlURL element - for (stop = ptr; stop != end; stop++) { if (*stop == '<') { end = stop; break; } } + for (stop = ptr; stop < end; stop++) { if (*stop == '<') { end = stop; break; } } // fill in default port m->UPnPSOAPPort = m->UPnPRouterPort; - // is there an address string "http://"? - if (strncasecmp(ptr, "http://", 7) == 0) + // free string pointers and set to NULL + if (m->UPnPSOAPAddressString != mDNSNULL) { - 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; } + mDNSPlatformMemFree(m->UPnPSOAPAddressString); + m->UPnPSOAPAddressString = mDNSNULL; + } + if (m->UPnPSOAPURL != mDNSNULL) + { + mDNSPlatformMemFree(m->UPnPSOAPURL); + m->UPnPSOAPURL = mDNSNULL; + } + + if (ParseHttpUrl(ptr, end, &m->UPnPSOAPAddressString, &m->UPnPSOAPPort, &m->UPnPSOAPURL) != mStatus_NoError) return; + // the SOAPURL should look something like "/uuid:0013-108c-4b3f0000f3dc" - // 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 - - stop = ptr; // remember where to stop (just after "http://") - ptr = addrPtr; // move ptr past the rest of what we just processed - - // find the port number in the string - for (addrPtr--;addrPtr>stop;addrPtr--) + if (m->UPnPSOAPAddressString == mDNSNULL) + { + ptr = (char *)tcpInfo->Reply; + while (ptr && ptr < end) { - if (*addrPtr == ':') + if (*ptr == 'U' && (strncasecmp(ptr, "URLBase", 7) == 0)) break; + ptr++; + } + + if (ptr < end) // found URLBase + { + LogInfo("handleLNTDeviceDescriptionResponse: found URLBase"); + ptr += 8; // skip over "URLBase>" + // find the end of the URLBase element + for (stop = ptr; stop < end; stop++) { if (*stop == '<') { end = stop; break; } } + if (ParseHttpUrl(ptr, end, &m->UPnPSOAPAddressString, &m->UPnPSOAPPort, mDNSNULL) != mStatus_NoError) { - int port; - addrPtr++; // skip over ':' - port = (int)strtol(addrPtr, mDNSNULL, 10); - m->UPnPSOAPPort = mDNSOpaque16fromIntVal(port); // store it properly converted - break; + LogInfo("handleLNTDeviceDescriptionResponse: failed to parse URLBase"); } } - } - - 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); - - // ptr should now point to the first character we haven't yet processed - if (ptr != end) - { - // allocate the buffer - if (m->UPnPSOAPURL != mDNSNULL) mDNSPlatformMemFree(m->UPnPSOAPURL); - if ((m->UPnPSOAPURL = (mDNSu8 *)mDNSPlatformMemAllocate(end - ptr + 1)) == mDNSNULL) { LogMsg("can't mDNSPlatformMemAllocate SOAP URL"); return; } - // now copy - strncpy((char *)m->UPnPSOAPURL, ptr, end - ptr); // this URL looks something like "/uuid:0013-108c-4b3f0000f3dc" - m->UPnPSOAPURL[end - ptr] = '\0'; // terminate the string + // if all else fails, use the router address string + if (m->UPnPSOAPAddressString == mDNSNULL) AllocAndCopy(&m->UPnPSOAPAddressString, m->UPnPRouterAddressString); } + if (m->UPnPSOAPAddressString == mDNSNULL) LogMsg("handleLNTDeviceDescriptionResponse: UPnPSOAPAddressString is NULL"); + else LogInfo("handleLNTDeviceDescriptionResponse: SOAP address string [%s]", m->UPnPSOAPAddressString); - // if we get to the end and haven't found the URL fill in the defaults - if (m->UPnPSOAPURL == mDNSNULL) m->UPnPSOAPURL = m->UPnPRouterURL; // just copy the pointer, don't allocate more memory - - LogOperation("handleLNTDeviceDescriptionResponse: SOAP URL [%s] port %d", m->UPnPSOAPURL, mDNSVal16(m->UPnPSOAPPort)); + if (m->UPnPSOAPURL == mDNSNULL) AllocAndCopy(&m->UPnPSOAPURL, m->UPnPRouterURL); + if (m->UPnPSOAPURL == mDNSNULL) LogMsg("handleLNTDeviceDescriptionResponse: UPnPSOAPURL is NULL"); + else LogInfo("handleLNTDeviceDescriptionResponse: SOAP URL [%s]", m->UPnPSOAPURL); } mDNSlocal void handleLNTGetExternalAddressResponse(tcpLNTInfo *tcpInfo) @@ -325,26 +514,40 @@ mDNSlocal void handleLNTGetExternalAddressResponse(tcpLNTInfo *tcpInfo) mDNS *m = tcpInfo->m; mDNSu16 err = NATErr_None; mDNSv4Addr ExtAddr; - char *ptr = (char *)tcpInfo->Reply; - char *end = (char *)tcpInfo->Reply + tcpInfo->nread; - char *addrend; + mDNSu8 *ptr = (mDNSu8*)tcpInfo->Reply; + mDNSu8 *end = (mDNSu8*)tcpInfo->Reply + tcpInfo->nread; + mDNSu8 *addrend; static char tagname[20] = "NewExternalIPAddress"; // Array NOT including a terminating nul -// LogOperation("handleLNTGetExternalAddressResponse: %s", ptr); +// LogInfo("handleLNTGetExternalAddressResponse: %s", ptr); - while (ptr < end && strncasecmp(ptr, tagname, sizeof(tagname))) ptr++; + mDNSs16 http_result = ParseHTTPResponseCode(&ptr, end); // Note: modifies ptr + if (http_result == HTTPCode_404) LNT_ClearState(m); + if (http_result != HTTPCode_200) + { + mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.AddressRequest", "noop", "HTTP Result", "HTTP code: %d", http_result); + return; + } + + + while (ptr < end && strncasecmp((char*)ptr, tagname, sizeof(tagname))) ptr++; ptr += sizeof(tagname); // Skip over "NewExternalIPAddress" while (ptr < end && *ptr != '>') ptr++; ptr += 1; // Skip over ">" // Find the end of the address and terminate the string so inet_pton() can convert it addrend = ptr; - while (addrend < end && (mdnsIsDigit(*addrend) || *addrend == '.')) addrend++; + while (addrend < end && (mDNSIsDigit(*addrend) || *addrend == '.')) addrend++; if (addrend >= end) return; *addrend = 0; - if (inet_pton(AF_INET, ptr, &ExtAddr) <= 0) - { LogMsg("handleLNTGetExternalAddressResponse: Router returned bad address %s", ptr); err = NATErr_NetFail; } - if (!err) LogOperation("handleLNTGetExternalAddressResponse: External IP address is %.4a", &ExtAddr); + if (inet_pton(AF_INET, (char*)ptr, &ExtAddr) <= 0) + { + mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.AddressRequest", "noop", "inet_pton", ""); + LogMsg("handleLNTGetExternalAddressResponse: Router returned bad address %s", ptr); + err = NATErr_NetFail; + ExtAddr = zerov4Addr; + } + if (!err) LogInfo("handleLNTGetExternalAddressResponse: External IP address is %.4a", &ExtAddr); natTraversalHandleAddressReply(m, err, ExtAddr); } @@ -353,56 +556,53 @@ mDNSlocal void handleLNTPortMappingResponse(tcpLNTInfo *tcpInfo) { mDNS *m = tcpInfo->m; mDNSIPPort extport = zeroIPPort; - char *ptr = (char *)tcpInfo->Reply; - char *end = (char *)tcpInfo->Reply + tcpInfo->nread; + mDNSu8 *ptr = (mDNSu8*)tcpInfo->Reply; + mDNSu8 *end = (mDNSu8*)tcpInfo->Reply + tcpInfo->nread; NATTraversalInfo *natInfo; + mDNSs16 http_result; 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; } + if (!natInfo) { LogInfo("handleLNTPortMappingResponse: can't find matching tcpInfo in NATTraversals!"); return; } - // 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) + http_result = ParseHTTPResponseCode(&ptr, end); // Note: modifies ptr + if (http_result == HTTPCode_200) + { + LogInfo("handleLNTPortMappingResponse: got a valid response, sending reply to natTraversalHandlePortMapReply(internal %d external %d retries %d)", + mDNSVal16(natInfo->IntPort), RequestedPortNum(natInfo), tcpInfo->retries); + + // Make sure to compute extport *before* we zero tcpInfo->retries + extport = mDNSOpaque16fromIntVal(RequestedPortNum(natInfo)); + tcpInfo->retries = 0; + natTraversalHandlePortMapReply(m, natInfo, m->UPnPInterfaceID, mStatus_NoError, extport, NATMAP_DEFAULT_LEASE); + } + else if (http_result == HTTPCode_500) { - if (*ptr == ' ') + while (ptr && ptr != end) { - 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) + if (((*ptr == 'c' || *ptr == 'C') && end - ptr >= 8 && strncasecmp((char*)ptr, "Conflict", 8) == 0) || (*ptr == '>' && end - ptr >= 15 && strncasecmp((char*)ptr, ">718retries < 100) + { + tcpInfo->retries++; SendPortMapRequest(tcpInfo->m, natInfo); + mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", "noop", "Conflict", "Retry %d", tcpInfo->retries); + } + else { - 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++; + LogMsg("handleLNTPortMappingResponse too many conflict retries %d %d", mDNSVal16(natInfo->IntPort), mDNSVal16(natInfo->RequestedPort)); + mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", "noop", "Conflict - too many retries", "Retries: %d", tcpInfo->retries); + natTraversalHandlePortMapReply(m, natInfo, m->UPnPInterfaceID, NATErr_Res, zeroIPPort, 0); } - break; // out of HTTP status search + return; } + ptr++; } - 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); - - // 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); + else if (http_result == HTTPCode_Bad) LogMsg("handleLNTPortMappingResponse got data that was not a valid HTTP response"); + else if (http_result == HTTPCode_Other) LogMsg("handleLNTPortMappingResponse got unexpected response code"); + else if (http_result == HTTPCode_404) LNT_ClearState(m); + if (http_result != HTTPCode_200 && http_result != HTTPCode_500) + mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", "noop", "HTTP Result", "HTTP code: %d", http_result); } mDNSlocal void DisposeInfoFromUnmapList(mDNS *m, tcpLNTInfo *tcpInfo) @@ -420,32 +620,32 @@ mDNSlocal void tcpConnectionCallback(TCPSocket *sock, void *context, mDNSBool Co long n = 0; long nsent = 0; - if (tcpInfo == mDNSNULL) { LogOperation("tcpConnectionCallback: no tcpInfo context"); status = mStatus_Invalid; goto exit; } + if (tcpInfo == mDNSNULL) { LogInfo("tcpConnectionCallback: no tcpInfo context"); status = mStatus_Invalid; goto exit; } // The handlers below expect to be called with the lock held mDNS_Lock(tcpInfo->m); - if (err) { LogOperation("tcpConnectionCallback: received error"); goto exit; } + if (err) { LogInfo("tcpConnectionCallback: received error"); goto exit; } if (ConnectionEstablished) // connection is established - send the message { - LogOperation("tcpConnectionCallback: connection established, sending message"); + LogInfo("tcpConnectionCallback: connection established, sending message"); nsent = mDNSPlatformWriteTCP(sock, (char *)tcpInfo->Request, tcpInfo->requestLen); if (nsent != (long)tcpInfo->requestLen) { LogMsg("tcpConnectionCallback: error writing"); status = mStatus_UnknownErr; goto exit; } } else { n = mDNSPlatformReadTCP(sock, (char *)tcpInfo->Reply + tcpInfo->nread, tcpInfo->replyLen - tcpInfo->nread, &closed); - LogOperation("tcpConnectionCallback: mDNSPlatformReadTCP read %d bytes", n); + LogInfo("tcpConnectionCallback: mDNSPlatformReadTCP read %d bytes", n); - 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; } + if (n < 0) { LogInfo("tcpConnectionCallback - read returned %d", n); status = mStatus_ConnFailed; goto exit; } + else if (closed) { LogInfo("tcpConnectionCallback: socket closed by remote end %d", tcpInfo->nread); status = mStatus_ConnFailed; goto exit; } tcpInfo->nread += n; - LogOperation("tcpConnectionCallback tcpInfo->nread %d", tcpInfo->nread); + LogInfo("tcpConnectionCallback tcpInfo->nread %d", tcpInfo->nread); if (tcpInfo->nread > LNT_MAXBUFSIZE) { - LogOperation("result truncated..."); + LogInfo("result truncated..."); tcpInfo->nread = LNT_MAXBUFSIZE; } @@ -461,6 +661,26 @@ mDNSlocal void tcpConnectionCallback(TCPSocket *sock, void *context, mDNSBool Co exit: if (err || status) { + mDNS *m = tcpInfo->m; + switch (tcpInfo->op) + { + case LNTDiscoveryOp: if (m->UPnPSOAPAddressString == mDNSNULL) + mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "failure", "SOAP Address", ""); + if (m->UPnPSOAPURL == mDNSNULL) + mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "failure", "SOAP path", ""); + if (m->UPnPSOAPAddressString && m->UPnPSOAPURL) + mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "success", "success", ""); + break; + case LNTExternalAddrOp: mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.AddressRequest", mDNSIPv4AddressIsZero(m->ExternalAddress) ? "failure" : "success", mDNSIPv4AddressIsZero(m->ExternalAddress) ? "failure" : "success", ""); + break; + case LNTPortMapOp: if (tcpInfo->parentNATInfo) + mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", (tcpInfo->parentNATInfo->Result) ? "failure" : "success", + (tcpInfo->parentNATInfo->Result) ? "failure" : "success", "Result: %d", tcpInfo->parentNATInfo->Result); + break; + case LNTPortMapDeleteOp: break; + default: break; + } + mDNSPlatformTCPCloseConnection(tcpInfo->sock); tcpInfo->sock = mDNSNULL; if (tcpInfo->Request) { mDNSPlatformMemFree(tcpInfo->Request); tcpInfo->Request = mDNSNULL; } @@ -486,12 +706,12 @@ mDNSlocal mStatus MakeTCPConnection(mDNS *const m, tcpLNTInfo *info, const mDNSA 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); } + else if ((info->Reply = (mDNSs8 *) mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogInfo("can't allocate reply buffer"); return (mStatus_NoMemoryErr); } - if (info->sock) { LogOperation("MakeTCPConnection: closing previous open connection"); mDNSPlatformTCPCloseConnection(info->sock); info->sock = mDNSNULL; } + if (info->sock) { LogInfo("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)); + LogInfo("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; @@ -505,7 +725,7 @@ mDNSlocal mStatus MakeTCPConnection(mDNS *const m, tcpLNTInfo *info, const mDNSA else { // Don't need to log this in customer builds -- it happens quite often during sleep, wake, configuration changes, etc. - LogOperation("LNT MakeTCPConnection: connection failed"); + LogInfo("LNT MakeTCPConnection: connection failed"); mDNSPlatformTCPCloseConnection(info->sock); // Dispose the socket we created with mDNSPlatformTCPSocket() above info->sock = mDNSNULL; mDNSPlatformMemFree(info->Reply); @@ -564,8 +784,8 @@ mDNSlocal mStatus SendSOAPMsgControlAction(mDNS *m, tcpLNTInfo *info, char *Acti char *body = (char *)&m->omsg; // Typically requires 1110-1122 bytes; m->omsg is 8952 bytes, which is plenty 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; } + if (mDNSIPPortIsZero(m->UPnPSOAPPort) || m->UPnPSOAPURL == mDNSNULL || m->UPnPSOAPAddressString == mDNSNULL) // if no SOAP URL or address exists get out here + { LogInfo("SendSOAPMsgControlAction: no SOAP port, URL or address string"); return mStatus_Invalid; } // Create body bodyLen = mDNS_snprintf (body, sizeof(m->omsg), body1, Action, m->UPnPWANPPPConnection ? "PPP" : "IP"); @@ -619,7 +839,7 @@ mDNSlocal mStatus SendPortMapRequest(mDNS *m, NATTraversalInfo *n) } else { - natTraversalHandlePortMapReply(m, n, m->UPnPInterfaceID, NATErr_Refused, zeroIPPort, 0); + natTraversalHandlePortMapReply(m, n, m->UPnPInterfaceID, NATErr_Res, zeroIPPort, 0); return mStatus_NoError; } } @@ -659,13 +879,13 @@ mDNSlocal mStatus SendPortMapRequest(mDNS *m, NATTraversalInfo *n) propArgs[7].type = "ui4"; propArgs[7].value = "0"; - LogOperation("SendPortMapRequest: internal %u external %u", mDNSVal16(n->IntPort), ReqPortNum); + LogInfo("SendPortMapRequest: internal %u external %u", mDNSVal16(n->IntPort), ReqPortNum); return SendSOAPMsgControlAction(m, &n->tcpInfo, "AddPortMapping", 8, propArgs, LNTPortMapOp); } mDNSexport mStatus LNT_MapPort(mDNS *m, NATTraversalInfo *n) { - LogOperation("LNT_MapPort"); + LogInfo("LNT_MapPort"); if (n->tcpInfo.sock) return(mStatus_NoError); // If we already have a connection up don't make another request for the same thing n->tcpInfo.parentNATInfo = n; n->tcpInfo.retries = 0; @@ -681,7 +901,7 @@ mDNSexport mStatus LNT_UnmapPort(mDNS *m, NATTraversalInfo *n) 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; + if (mDNSIPPortIsZero(m->UPnPSOAPPort) || !m->UPnPSOAPURL || !m->UPnPSOAPAddressString) return mStatus_NoError; mDNS_snprintf(externalPort, sizeof(externalPort), "%u", mDNSVal16(mDNSIPPortIsZero(n->RequestedPort) ? n->IntPort : n->RequestedPort)); @@ -699,14 +919,14 @@ mDNSexport mStatus LNT_UnmapPort(mDNS *m, NATTraversalInfo *n) 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) LogInfo("LNT_UnmapPort: closing previous open connection"); if (n->tcpInfo.sock ) { mDNSPlatformTCPCloseConnection(n->tcpInfo.sock); n->tcpInfo.sock = mDNSNULL; } if (n->tcpInfo.Request) { mDNSPlatformMemFree(n->tcpInfo.Request); n->tcpInfo.Request = mDNSNULL; } if (n->tcpInfo.Reply ) { mDNSPlatformMemFree(n->tcpInfo.Reply); n->tcpInfo.Reply = mDNSNULL; } // make a copy of the tcpInfo that we can clean up later (the one passed in will be destroyed by the client as soon as this returns) if ((info = mDNSPlatformMemAllocate(sizeof(tcpLNTInfo))) == mDNSNULL) - { LogOperation("LNT_UnmapPort: can't allocate tcpInfo"); return(mStatus_NoMemoryErr); } + { LogInfo("LNT_UnmapPort: can't allocate tcpInfo"); return(mStatus_NoMemoryErr); } *info = n->tcpInfo; while (*infoPtr) infoPtr = &(*infoPtr)->next; // find the end of the list @@ -735,13 +955,15 @@ mDNSlocal mStatus GetDeviceDescription(mDNS *m, tcpLNTInfo *info) "Connection: close\r\n" "\r\n"; - if (m->UPnPRouterURL == mDNSNULL || m->UPnPRouterAddressString == mDNSNULL) { LogOperation("GetDeviceDescription: no router URL or address string!"); return (mStatus_Invalid); } + if (!mDNSIPPortIsZero(m->UPnPSOAPPort)) return mStatus_NoError; // already have the info we need + + if (m->UPnPRouterURL == mDNSNULL || m->UPnPRouterAddressString == mDNSNULL) { LogInfo("GetDeviceDescription: no router URL or address string!"); return (mStatus_Invalid); } // build message if (info->Request != mDNSNULL) mDNSPlatformMemZero(info->Request, LNT_MAXBUFSIZE); // reuse previously allocated buffer - else if ((info->Request = (mDNSs8 *) mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogOperation("can't allocate send buffer for discovery"); return (mStatus_NoMemoryErr); } + else if ((info->Request = (mDNSs8 *) mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogInfo("can't allocate send buffer for discovery"); return (mStatus_NoMemoryErr); } info->requestLen = mDNS_snprintf((char *)info->Request, LNT_MAXBUFSIZE, szSSDPMsgDescribeDeviceFMT, m->UPnPRouterURL, m->UPnPRouterAddressString); - LogOperation("Describe Device: [%s]", info->Request); + LogInfo("Describe Device: [%s]", info->Request); return MakeTCPConnection(m, info, &m->Router, m->UPnPRouterPort, LNTDiscoveryOp); } @@ -752,6 +974,9 @@ mDNSexport void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID Interface { char *ptr = (char *)data; char *end = (char *)data + len; + char *stop = ptr; + + if (!mDNSIPPortIsZero(m->UPnPRouterPort)) return; // already have the info we need // The formatting of the HTTP header is not always the same when it comes to the placement of // the service and location strings, so we just look for each of them from the beginning for every response @@ -777,77 +1002,66 @@ mDNSexport void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID Interface ptr = (char *)data; while (ptr && ptr != end) { - if (*ptr == 'L' && (strncasecmp(ptr, "Location", 8) == 0)) break; // find the first 'L'; is this Location? if not, keep looking + if (*ptr == 'L' && (strncasecmp(ptr, "Location:", 9) == 0)) break; // find the first 'L'; is this Location? if not, keep looking ptr++; } - if (ptr == mDNSNULL || ptr == end) return; // not a message we care about + if (ptr == mDNSNULL || ptr == end) + { + mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Location", ""); + return; // not a message we care about + } + ptr += 9; //Skip over 'Location:' + while (*ptr == ' ' && ptr < end) ptr++; // skip over spaces + if (ptr >= end) return; - // find "http://", starting from where we left off - while (ptr && ptr != end) + // find the end of the line + for (stop = ptr; stop != end; stop++) { if (*stop == '\r') { end = stop; break; } } + + // fill in default port + m->UPnPRouterPort = mDNSOpaque16fromIntVal(80); + + // free string pointers and set to NULL + if (m->UPnPRouterAddressString != mDNSNULL) { - if (*ptr == 'h' && (strncasecmp(ptr, "http://", 7) == 0)) // find the first 'h'; is this a URL? if not, keep looking - { - 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 + mDNSPlatformMemFree(m->UPnPRouterAddressString); + m->UPnPRouterAddressString = mDNSNULL; + } + if (m->UPnPRouterURL != mDNSNULL) + { + mDNSPlatformMemFree(m->UPnPRouterURL); + m->UPnPRouterURL = mDNSNULL; + } - // 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 + // the Router URL should look something like "/dyndev/uuid:0013-108c-4b3f0000f3dc" + if (ParseHttpUrl(ptr, end, &m->UPnPRouterAddressString, &m->UPnPRouterPort, &m->UPnPRouterURL) != mStatus_NoError) + { + mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Parse URL", ""); + return; } - // find port and router URL, starting after the "http://" if it was there - while (ptr && ptr != end) + m->UPnPInterfaceID = InterfaceID; + + if (m->UPnPRouterAddressString == mDNSNULL) { - 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 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 + mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Router address", ""); + LogMsg("LNT_ConfigureRouterInfo: UPnPRouterAddressString is NULL"); } + else LogInfo("LNT_ConfigureRouterInfo: Router address string [%s]", m->UPnPRouterAddressString); + + if (m->UPnPRouterURL == mDNSNULL) + { + mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "failure", "Router path", ""); + LogMsg("LNT_ConfigureRouterInfo: UPnPRouterURL is NULL"); + } + else LogInfo("LNT_ConfigureRouterInfo: Router URL [%s]", m->UPnPRouterURL); + + LogInfo("LNT_ConfigureRouterInfo: Router port %d", mDNSVal16(m->UPnPRouterPort)); + LogInfo("LNT_ConfigureRouterInfo: Router interface %d", m->UPnPInterfaceID); - if (ptr == mDNSNULL || ptr == end) return; // not a valid message - LogOperation("Router port %d, URL set to [%s]...", mDNSVal16(m->UPnPRouterPort), m->UPnPRouterURL); - // Don't need the SSDP socket anymore - if (m->SSDPSocket) { LogOperation("LNT_ConfigureRouterInfo destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; } + if (m->SSDPSocket) { debugf("LNT_ConfigureRouterInfo destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; } + mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.ssdp", "success", "success", ""); // now send message to get the device description GetDeviceDescription(m, &m->tcpDeviceInfo); } @@ -864,6 +1078,13 @@ mDNSexport void LNT_SendDiscoveryMsg(mDNS *m) mDNSu8* buf = (mDNSu8*)&m->omsg; //m->omsg is 8952 bytes, which is plenty unsigned int bufLen; + + if (!mDNSIPPortIsZero(m->UPnPRouterPort)) + { + if (m->SSDPSocket) { debugf("LNT_SendDiscoveryMsg destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; } + if (mDNSIPPortIsZero(m->UPnPSOAPPort) && !m->tcpDeviceInfo.sock) GetDeviceDescription(m, &m->tcpDeviceInfo); + return; + } // Always query for WANIPConnection in the first SSDP packet if (m->retryIntervalGetAddr <= NATMAP_INIT_RETRY) m->SSDPWANPPPConnection = mDNSfalse; @@ -871,11 +1092,11 @@ mDNSexport void LNT_SendDiscoveryMsg(mDNS *m) // Create message bufLen = mDNS_snprintf((char*)buf, sizeof(m->omsg), msg, m->SSDPWANPPPConnection ? "PPP" : "IP"); - LogOperation("LNT_SendDiscoveryMsg Router %.4a Current External Address %.4a", &m->Router.ip.v4, &m->ExternalAddress); + debugf("LNT_SendDiscoveryMsg Router %.4a Current External Address %.4a", &m->Router.ip.v4, &m->ExternalAddress); - if (!mDNSIPv4AddressIsZero(m->Router.ip.v4) && mDNSIPv4AddressIsZero(m->ExternalAddress)) + if (!mDNSIPv4AddressIsZero(m->Router.ip.v4)) { - if (!m->SSDPSocket) { m->SSDPSocket = mDNSPlatformUDPSocket(m, zeroIPPort); LogOperation("LNT_SendDiscoveryMsg created SSDPSocket %p", &m->SSDPSocket); } + if (!m->SSDPSocket) { m->SSDPSocket = mDNSPlatformUDPSocket(m, zeroIPPort); debugf("LNT_SendDiscoveryMsg created SSDPSocket %p", &m->SSDPSocket); } mDNSPlatformSendUDP(m, buf, buf + bufLen, 0, m->SSDPSocket, &m->Router, SSDPPort); mDNSPlatformSendUDP(m, buf, buf + bufLen, 0, m->SSDPSocket, &multicastDest, SSDPPort); } @@ -883,4 +1104,11 @@ mDNSexport void LNT_SendDiscoveryMsg(mDNS *m) m->SSDPWANPPPConnection = !m->SSDPWANPPPConnection; } +mDNSexport void LNT_ClearState(mDNS *const m) + { + if (m->tcpAddrInfo.sock) { mDNSPlatformTCPCloseConnection(m->tcpAddrInfo.sock); m->tcpAddrInfo.sock = mDNSNULL; } + if (m->tcpDeviceInfo.sock) { mDNSPlatformTCPCloseConnection(m->tcpDeviceInfo.sock); m->tcpDeviceInfo.sock = mDNSNULL; } + m->UPnPSOAPPort = m->UPnPRouterPort = zeroIPPort; // Reset UPnP ports + } + #endif /* _LEGACY_NAT_TRAVERSAL_ */ diff --git a/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c b/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c index a42d9a5..af22edf 100644 --- a/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c +++ b/mDNSMacOSX/PreferencePane/ConfigurationAuthority.c @@ -44,6 +44,9 @@ Change History (most recent first): $Log: ConfigurationAuthority.c,v $ +Revision 1.3 2008/06/26 17:34:18 mkrochma + Pref pane destroying shared "system.preferences" authorization right + Revision 1.2 2005/08/07 22:48:05 mkrochma Bonjour Pref Pane returns -927 when "system.preferences" is not shared @@ -170,7 +173,7 @@ OSStatus AttemptAcquireAuthority( Boolean allowUI) OSStatus ReleaseAuthority(void) /* Discard authority to perform operations */ { - (void) AuthorizationFree( gAuthRef, kAuthorizationFlagDestroyRights); + (void) AuthorizationFree( gAuthRef, kAuthorizationFlagDefaults); gAuthRef = 0; return AuthorizationCreate( (AuthorizationRights*) NULL, (AuthorizationEnvironment*) NULL, (AuthorizationFlags) 0, &gAuthRef); diff --git a/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m b/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m index 412da6d..1c481dc 100644 --- a/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m +++ b/mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m @@ -43,6 +43,24 @@ Change History (most recent first): $Log: DNSServiceDiscoveryPref.m,v $ +Revision 1.16 2008/09/15 23:52:30 cheshire + mDNSResponder-177 fails to compile on Linux with .desc pseudo-op +Made __crashreporter_info__ symbol conditional, so we only use it for OS X build + +Revision 1.15 2008/08/18 17:57:04 mcguire + build error + +Revision 1.14 2008/07/18 17:39:14 cheshire +If NSInteger is not defined (indicated by lack of definition for NSINTEGER_DEFINED) +then #define "NSInteger" to be "int" like it used to be + +Revision 1.13 2008/07/01 01:40:01 mcguire + 64-bit fixes + +Revision 1.12 2008/05/08 00:46:38 cheshire + GetNextLabel insufficiently defensive +User shared copy of GetNextLabel in ClientCommon.c instead of having a local copy here + Revision 1.11 2007/11/30 23:42:09 cheshire Fixed compile warning: declaration of 'index' shadows a global declaration @@ -84,9 +102,15 @@ Add Preference Pane to facilitate testing of DDNS & wide-area features #import "PrivilegedOperations.h" #import +#include "../../Clients/ClientCommon.h" + +#ifndef NSINTEGER_DEFINED +#define NSInteger int +#endif + @implementation DNSServiceDiscoveryPref -static int +static NSComparisonResult MyArrayCompareFunction(id val1, id val2, void *context) { (void)context; // Unused @@ -94,7 +118,7 @@ MyArrayCompareFunction(id val1, id val2, void *context) } -static int +static NSComparisonResult MyDomainArrayCompareFunction(id val1, id val2, void *context) { (void)context; // Unused @@ -104,34 +128,6 @@ MyDomainArrayCompareFunction(id val1, id val2, void *context) } -static const char * -GetNextLabel(const char *cstr, char label[64]) -{ - char *ptr = label; - while (*cstr && *cstr != '.') // While we have characters in the label... - { - char c = *cstr++; - if (c == '\\') - { - c = *cstr++; - if (isdigit(cstr[-1]) && isdigit(cstr[0]) && isdigit(cstr[1])) - { - int v0 = cstr[-1] - '0'; // then interpret as three-digit decimal - int v1 = cstr[ 0] - '0'; - int v2 = cstr[ 1] - '0'; - int val = v0 * 100 + v1 * 10 + v2; - if (val <= 255) { c = (char)val; cstr += 2; } // If valid three-digit decimal value, use it - } - } - *ptr++ = c; - if (ptr >= label+64) return(NULL); - } - if (*cstr) cstr++; // Skip over the trailing dot (if present) - *ptr++ = 0; - return(cstr); -} - - static void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context) { (void)store; // Unused @@ -459,7 +455,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) -- (int)numberOfRowsInTableView:(NSTableView *)tableView; +- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView; { (void)tableView; // Unused int numberOfRows = 0; @@ -480,7 +476,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) } -- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row; +- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row; { (void)tableView; // Unused NSDictionary *browseDomainDict; @@ -594,12 +590,10 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) [self startDomainBrowsing]; [self watchForPreferenceChanges]; - [tabView setDelegate:self]; - InitConfigAuthority(); err = EnsureToolInstalled(); if (err == noErr) toolInstalled = YES; - else fprintf(stderr, "EnsureToolInstalled returned %ld\n", err); + else { long int tmp = err; fprintf(stderr, "EnsureToolInstalled returned %ld\n", tmp); } } @@ -1195,7 +1189,7 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) } -- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(int)row; +- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row; { (void)row; // Unused (void)tableView; // Unused @@ -1250,6 +1244,8 @@ MyDNSServiceAddServiceToRunLoop(MyDNSServiceState * query) // The "@(#) " pattern is a special prefix the "what" command looks for const char VersionString_SCCS[] = "@(#) Bonjour Preference Pane " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")"; +#if _BUILDING_XCODE_PROJECT_ // If the process crashes, then this string will be magically included in the automatically-generated crash log const char *__crashreporter_info__ = VersionString_SCCS + 5; asm(".desc ___crashreporter_info__, 0x10"); +#endif diff --git a/mDNSMacOSX/PreferencePane/PrivilegedOperations.c b/mDNSMacOSX/PreferencePane/PrivilegedOperations.c index 01f09c5..5be5792 100644 --- a/mDNSMacOSX/PreferencePane/PrivilegedOperations.c +++ b/mDNSMacOSX/PreferencePane/PrivilegedOperations.c @@ -43,6 +43,9 @@ Change History (most recent first): $Log: PrivilegedOperations.c,v $ +Revision 1.9 2008/06/26 17:34:18 mkrochma + Pref pane destroying shared "system.preferences" authorization right + Revision 1.8 2007/11/30 23:42:33 cheshire Fixed compile warning: declaration of 'status' shadows a previous local @@ -159,7 +162,7 @@ OSStatus EnsureToolInstalled(void) err = -1; } } - (void) AuthorizationFree(authRef, kAuthorizationFlagDestroyRights); + (void) AuthorizationFree(authRef, kAuthorizationFlagDefaults); } } diff --git a/mDNSMacOSX/PreferencePane/ddnswriteconfig.m b/mDNSMacOSX/PreferencePane/ddnswriteconfig.m index f415180..4417418 100644 --- a/mDNSMacOSX/PreferencePane/ddnswriteconfig.m +++ b/mDNSMacOSX/PreferencePane/ddnswriteconfig.m @@ -45,6 +45,16 @@ Change History (most recent first): $Log: ddnswriteconfig.m,v $ +Revision 1.13 2008/11/04 20:08:44 cheshire +Use constant kDNSServiceMaxDomainName instead of literal value "1005" + +Revision 1.12 2008/09/15 23:52:30 cheshire + mDNSResponder-177 fails to compile on Linux with .desc pseudo-op +Made __crashreporter_info__ symbol conditional, so we only use it for OS X build + +Revision 1.11 2008/06/26 17:34:18 mkrochma + Pref pane destroying shared "system.preferences" authorization right + Revision 1.10 2007/11/30 23:43:04 cheshire Fixed compile warning: declaration of 'access' shadows a global declaration @@ -93,6 +103,7 @@ Add Preference Pane to facilitate testing of DDNS & wide-area features #import #import #import +#import #import #import #import @@ -202,7 +213,7 @@ SetAuthInfo( int fd) require( len == kAuthorizationExternalFormLength, ReadParamsFailed); if (gAuthRef != 0) { - (void) AuthorizationFree(gAuthRef, kAuthorizationFlagDestroyRights); + (void) AuthorizationFree(gAuthRef, kAuthorizationFlagDefaults); gAuthRef = 0; } @@ -361,9 +372,9 @@ SetKeychainEntry(int fd) int result = 0; u_int32_t tag, len; char *p; - char keyname[1005]; - char domain[1005]; - char secret[1005]; + char keyname[kDNSServiceMaxDomainName]; + char domain[kDNSServiceMaxDomainName]; + char secret[kDNSServiceMaxDomainName]; AuthorizationItem kcAuth = { EDIT_SYS_KEYCHAIN_RIGHT, 0, NULL, 0 }; AuthorizationRights authSet = { 1, &kcAuth }; @@ -386,9 +397,9 @@ SetKeychainEntry(int fd) secretString = (CFStringRef)CFDictionaryGetValue(secretDictionary, SC_DYNDNS_SECRET_KEY); assert(secretString != NULL); - CFStringGetCString(keyNameString, keyname, 1005, kCFStringEncodingUTF8); - CFStringGetCString(domainString, domain, 1005, kCFStringEncodingUTF8); - CFStringGetCString(secretString, secret, 1005, kCFStringEncodingUTF8); + CFStringGetCString(keyNameString, keyname, kDNSServiceMaxDomainName, kCFStringEncodingUTF8); + CFStringGetCString(domainString, domain, kDNSServiceMaxDomainName, kCFStringEncodingUTF8); + CFStringGetCString(secretString, secret, kDNSServiceMaxDomainName, kCFStringEncodingUTF8); result = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem); if (result == noErr) { @@ -470,6 +481,8 @@ int main( int argc, char **argv) // The "@(#) " pattern is a special prefix the "what" command looks for const char VersionString_SCCS[] = "@(#) ddnswriteconfig " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")"; +#if _BUILDING_XCODE_PROJECT_ // If the process crashes, then this string will be magically included in the automatically-generated crash log const char *__crashreporter_info__ = VersionString_SCCS + 5; asm(".desc ___crashreporter_info__, 0x10"); +#endif diff --git a/mDNSMacOSX/SamplemDNSClient.c b/mDNSMacOSX/SamplemDNSClient.c index 6497498..76ec65a 100644 --- a/mDNSMacOSX/SamplemDNSClient.c +++ b/mDNSMacOSX/SamplemDNSClient.c @@ -30,6 +30,13 @@ Change History (most recent first): $Log: SamplemDNSClient.c,v $ +Revision 1.56 2008/10/22 02:59:58 mkrochma + Fix errors compiling mDNS tool caused by BIND8 removal + +Revision 1.55 2008/09/15 23:52:30 cheshire + mDNSResponder-177 fails to compile on Linux with .desc pseudo-op +Made __crashreporter_info__ symbol conditional, so we only use it for OS X build + Revision 1.54 2007/11/30 23:39:55 cheshire Fixed compile warning: declaration of 'client' shadows a global declaration @@ -60,7 +67,6 @@ Revision 1.47 2006/01/10 02:29:22 cheshire */ #include -#define BIND_8_COMPAT #include #include #include @@ -256,7 +262,7 @@ static void myCFRunLoopTimerCallBack(CFRunLoopTimerRef timer, void *info) switch (addtest) { case 0: printf("Adding Test HINFO record\n"); - record = DNSServiceRegistrationAddRecord(client, T_HINFO, sizeof(myhinfo9), &myhinfo9[0], 120); + record = DNSServiceRegistrationAddRecord(client, ns_t_hinfo, sizeof(myhinfo9), &myhinfo9[0], 120); addtest = 1; break; case 1: printf("Updating Test HINFO record\n"); @@ -285,7 +291,7 @@ static void myCFRunLoopTimerCallBack(CFRunLoopTimerRef timer, void *info) case 'N': { printf("Adding big NULL record\n"); - DNSServiceRegistrationAddRecord(client, T_NULL, sizeof(bigNULL), &bigNULL[0], 120); + DNSServiceRegistrationAddRecord(client, ns_t_null, sizeof(bigNULL), &bigNULL[0], 120); CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode); } break; @@ -411,7 +417,7 @@ int main(int argc, char **argv) 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); + record = DNSServiceRegistrationAddRecord(client, ns_t_txt, sizeof(TXT2)-1, TXT2, 120); break; } @@ -466,6 +472,8 @@ Fail: // The "@(#) " pattern is a special prefix the "what" command looks for const char VersionString_SCCS[] = "@(#) mDNS " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")"; +#if _BUILDING_XCODE_PROJECT_ // If the process crashes, then this string will be magically included in the automatically-generated crash log const char *__crashreporter_info__ = VersionString_SCCS + 5; asm(".desc ___crashreporter_info__, 0x10"); +#endif diff --git a/mDNSMacOSX/daemon.c b/mDNSMacOSX/daemon.c index 25b2e43..50abe96 100644 --- a/mDNSMacOSX/daemon.c +++ b/mDNSMacOSX/daemon.c @@ -30,6 +30,240 @@ Change History (most recent first): $Log: daemon.c,v $ +Revision 1.434 2009/06/27 00:55:27 cheshire +Added code for displaying the size of various structures like CacheRecord and CacheGroup + +Revision 1.433 2009/06/25 23:36:57 cheshire +To facilitate testing, added command-line switch "-OfferSleepProxyService" +to re-enable the previously-supported mode of operation where we offer +sleep proxy service on desktop Macs that are set to never sleep. + +Revision 1.432 2009/05/13 17:25:33 mkrochma + Should not schedule maintenance wake when machine has no advertised services +Sleep proxy client should only look for services being advertised via Multicast + +Revision 1.431 2009/05/12 23:21:18 cheshire + Should not schedule maintenance wake when machine has no advertised services +Use mDNSCoreHaveAdvertisedServices routine to determine whether we should schedule a maintenance wake + +Revision 1.430 2009/05/01 19:17:36 cheshire + Sleep Proxy: Reduce the frequency of maintenance wakes: ODD, fans, power + +Revision 1.429 2009/04/30 20:07:50 mcguire + Support multiple UDSs from launchd + +Revision 1.428 2009/04/22 19:43:37 cheshire +To facilitate debugging, added -DebugLogging and -UnicastPacketLogging switches +as launch-time alternatives to sending SIGUSR1 and SIGUSR2 signals later + +Revision 1.427 2009/04/22 01:19:57 jessic2 + Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32 + +Revision 1.426 2009/04/20 19:25:26 cheshire +For readability, changed "nomulticastadvertisements" to "NoMulticastAdvertisements" + +Revision 1.425 2009/04/20 19:17:19 cheshire +Added a comment explaining why we don't need our CatchABRT handler on 10.5 and later + +Revision 1.424 2009/04/17 19:10:27 mcguire + May still ping-pong with kernel when a framework calls abort() + +Revision 1.423 2009/04/16 16:03:08 mcguire + abort() causes high CPU usage instead of crash & restart + +Revision 1.422 2009/04/11 01:43:28 jessic2 + Daemon: Should be able to turn on LogOperation dynamically + +Revision 1.421 2009/04/11 00:20:06 jessic2 + Daemon: Should be able to turn on LogOperation dynamically + +Revision 1.420 2009/03/20 23:53:03 jessic2 + SIGHUP should restart all in-progress queries + +Revision 1.419 2009/03/20 21:30:04 cheshire + Crash passing invalid parameters to DNSServiceBrowserCreate() +Do not append a new question to the browser list until *after* we verify that mDNS_StartBrowse() succeeded + +Revision 1.418 2009/03/17 21:32:15 cheshire +Improved "DHCPWakeTime: SCDynamicStoreCopyDHCPInfo failed" error message + +Revision 1.417 2009/03/17 01:25:39 cheshire + Sleep Proxy: Retransmit and retry Sleep Proxy Server requests +In SIGINFO output, show three best Sleep Proxies + +Revision 1.416 2009/02/21 01:47:36 cheshire + Race condition when sleep initiated and then immediately canceled + +Revision 1.415 2009/02/21 01:45:33 cheshire +Move declaration of "mDNSs32 interval" + +Revision 1.414 2009/02/14 00:05:32 cheshire +Left-justify interface names + +Revision 1.413 2009/02/13 18:16:05 cheshire +Fixed some compile warnings + +Revision 1.412 2009/02/13 06:34:41 cheshire +Converted LogOperation messages to LogInfo or LogSPS + +Revision 1.411 2009/02/12 20:57:26 cheshire +Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch + +Revision 1.410 2009/02/11 02:32:18 cheshire +m->p->SystemWakeForNetworkAccessEnabled renamed to m->SystemWakeOnLANEnabled + +Revision 1.409 2009/02/09 21:16:14 cheshire +Improved debugging messages + +Revision 1.408 2009/02/07 06:08:44 cheshire +Commented out testing code + +Revision 1.407 2009/02/07 02:57:31 cheshire + Sleep Proxy: Need to adopt IOPMConnection + +Revision 1.406 2009/02/06 03:06:49 mcguire + Adopt vproc_transaction API in mDNSResponder + +Revision 1.405 2009/02/04 23:00:28 cheshire +Move logic for deciding when to next wake up into a subroutine called AllowSleepNow + +Revision 1.404 2009/02/02 22:18:32 cheshire +If we wake up and find no wireless network, don't just give up and go back to sleep and never try again + +Revision 1.403 2009/01/15 21:58:18 cheshire +Stop using ifa_name field of NetworkInterfaceInfoOSX structure, because it will be going away + +Revision 1.402 2009/01/07 23:08:18 cheshire +Updated debugging messages and comments + +Revision 1.401 2008/12/17 05:05:26 cheshire +Fixed alignment of NAT mapping syslog messages + +Revision 1.400 2008/12/10 19:30:57 cheshire +Use symbolic name OSXVers_10_3_Panther in version check instead of literal integer "7" + +Revision 1.399 2008/12/10 02:13:04 cheshire +Fix alignment of SIGINFO output for longer interface names like "bridge0" + +Revision 1.398 2008/12/04 21:08:51 mcguire + mDNS: Provide mechanism to disable Multicast advertisements + +Revision 1.397 2008/12/04 02:18:50 cheshire +Improved sleep/wake debugging messages + +Revision 1.396 2008/11/26 23:37:44 cheshire +Use SCDynamicStoreCopyDHCPInfo to compute desired wakeup time for our next DHCP lease renewal + +Revision 1.395 2008/11/14 21:56:31 cheshire +Moved debugging routine ShowTaskSchedulingError() from daemon.c into DNSCommon.c + +Revision 1.394 2008/11/14 02:20:03 cheshire +Include m->NextScheduledSPS in task scheduling calculations + +Revision 1.393 2008/11/14 01:22:38 cheshire +Include SPS-registered records when computing the next required wakeup time + +Revision 1.392 2008/11/11 01:55:16 cheshire +Improved comments; minium requested sleep is 60 seconds + +Revision 1.391 2008/11/04 02:29:55 cheshire +Clear interface list before sleeping + +Revision 1.390 2008/11/02 21:22:05 cheshire +Changed mallocL size parameter back to "unsigned int" + +Revision 1.389 2008/11/02 21:14:58 cheshire +Fixes to make mallocL/freeL debugging checks work on 64-bit + +Revision 1.388 2008/10/31 23:05:30 cheshire +Move logic to decide when to at as Sleep Proxy Server from daemon.c to mDNSMacOSX.c + +Revision 1.387 2008/10/30 01:08:18 cheshire +After waking for network maintenance operations go back to sleep again + +Revision 1.386 2008/10/29 22:03:39 cheshire +Compute correct required wakeup time for NAT traversals and uDNS-registered records + +Revision 1.385 2008/10/28 20:40:13 cheshire +Now that the BPF code in mDNSMacOSX.c makes its own CFSocketCreateWithNative directly, the +udsSupportAddFDToEventLoop/udsSupportRemoveFDFromEventLoop routines can go back to using kqueue + +Revision 1.384 2008/10/27 22:22:59 cheshire +Extra sanity checking in udsSupportAddFDToEventLoop/udsSupportRemoveFDFromEventLoop + +Revision 1.383 2008/10/27 07:24:53 cheshire +Need a "usleep(1000)" (workaround for ) to avoid crashes + +Revision 1.382 2008/10/24 01:51:48 cheshire +Before going to sleep, request a future wakeup to renew NAT-PMP mappings, SPS registrations, etc. + +Revision 1.381 2008/10/23 22:25:58 cheshire +Renamed field "id" to more descriptive "updateid" + +Revision 1.380 2008/10/23 02:25:08 cheshire +Added locking in InternetSharingChanged() + +Revision 1.379 2008/10/22 23:23:59 cheshire +Moved definition of OSXVers from daemon.c into mDNSMacOSX.c + +Revision 1.378 2008/10/22 19:55:35 cheshire +Miscellaneous fixes; renamed FindFirstAnswerInCache to FindSPSInCache + +Revision 1.377 2008/10/22 17:17:22 cheshire +Need to open and close BPF fds when turning Sleep Proxy Server on and off + +Revision 1.376 2008/10/22 01:42:39 cheshire +Before allowing sleep, delay until NetWakeResolve queries have completed + +Revision 1.375 2008/10/20 22:31:31 cheshire +Instead of requesting a single BPF descriptor via mDNSRequestBPF(), call mDNSMacOSXNetworkChanged() +to signal that UDS is now available to handle BPF requests, and let it work out what it needs + +Revision 1.374 2008/10/16 22:40:48 cheshire +Removed "usleep(100000);" from CFSCallBack() + +Revision 1.373 2008/10/16 20:49:30 cheshire +When kevent/kqueue fails, fall back to using old CFSocket RunLoopSource instead + +Revision 1.372 2008/10/15 00:03:21 cheshire +When finally going to sleep, update m->SleepState from SleepState_Transferring to SleepState_Sleeping + +Revision 1.371 2008/10/14 19:09:53 cheshire +When going to sleep, delay sleep until we've got our acknowledgment from the SPS + +Revision 1.370 2008/10/09 22:32:27 cheshire +Include MAC address in interface listing in SIGINFO output + +Revision 1.369 2008/10/09 19:32:39 cheshire +Updated SIGINFO output to indicate whether we've found a sleep proxy server on a given interface +Hollow sun with rays "☼" indicates we're still looking; solid sun with rays "☀" indicates we found one + +Revision 1.368 2008/10/03 21:23:17 mkrochma +Fix crash by not passing NULL to CFGetTypeID + +Revision 1.367 2008/10/03 18:25:17 cheshire +Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);" + +Revision 1.366 2008/10/03 00:34:55 cheshire + Mac with Internet Sharing should also offer Sleep Proxy service +Start and stop Sleep Proxy service when user starts and stops Internet Sharing + +Revision 1.365 2008/10/02 22:23:13 cheshire +Additional debugging message giving explanation if shutdown is delayed + +Revision 1.364 2008/10/01 21:23:40 cheshire +In SIGINFO interface listing, indicate whether NetWake is set + +Revision 1.363 2008/09/27 01:29:15 cheshire +Call mDNSRequestBPF() to request the helper to send us the BPF fd + +Revision 1.362 2008/09/26 19:47:42 cheshire +Fixed locking error: lock is supposed to be held when calling mDNS_PurgeCacheResourceRecord + +Revision 1.361 2008/09/15 23:52:30 cheshire + mDNSResponder-177 fails to compile on Linux with .desc pseudo-op +Made __crashreporter_info__ symbol conditional, so we only use it for OS X build + Revision 1.360 2008/03/13 20:55:16 mcguire fix deprecated warnings/errors Additional cleanup: use a conditional macro instead of lots of #if @@ -102,7 +336,7 @@ Revision 1.340 2007/09/07 22:44:03 mcguire Move CFUserNotification code to mDNSResponderHelper Revision 1.339 2007/09/06 19:08:29 cheshire -LogAllOperations check needs to be "#if LogAllOperations || MDNS_DEBUGMSGS" +LogClientOperations check needs to be "#if LogClientOperations || MDNS_DEBUGMSGS" Revision 1.338 2007/09/05 23:34:27 mcguire Revert logging change @@ -378,6 +612,7 @@ Revision 1.261 2006/01/06 01:22:28 cheshire #include #include #include +#include #if TARGET_OS_EMBEDDED #include @@ -396,9 +631,12 @@ Revision 1.261 2006/01/06 01:22:28 cheshire #include #include "helper.h" +#include "safe_vproc.h" //************************************************************************************************************* -// Globals +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - Globals +#endif static mDNS_PlatformSupport PlatformStorage; @@ -415,7 +653,8 @@ 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; +static dnssd_sock_t *launchd_fds = mDNSNULL; +static mDNSu32 launchd_fds_count = 0; // mDNS Mach Message Timeout, in milliseconds. // We need this to be short enough that we don't deadlock the mDNSResponder if a client @@ -427,13 +666,13 @@ static dnssd_sock_t launchd_fd = dnssd_InvalidSocket; 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; +static mDNSBool advertise = mDNS_Init_AdvertiseLocalAddresses; // By default, advertise addresses (& other records) via multicast //************************************************************************************************************* -// Active client list structures +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - +#pragma mark - Active client list structures +#endif typedef struct DNSServiceDomainEnumeration_struct DNSServiceDomainEnumeration; struct DNSServiceDomainEnumeration_struct @@ -469,7 +708,7 @@ struct DNSServiceBrowser_struct DNSServiceBrowserResult *results; mDNSs32 lastsuccess; mDNSBool DefaultDomain; // was the browse started on an explicit domain? - domainname type; // registration type + domainname type; // registration type }; typedef struct DNSServiceResolver_struct DNSServiceResolver; @@ -509,7 +748,7 @@ typedef struct DNSServiceRegistration size_t rdsize; int NumSubTypes; char regtype[MAX_ESCAPED_DOMAIN_NAME]; // for use in AllocateSubtypes - domainlabel name; // used only if autoname is false + domainlabel name; // used only if autoname is false domainname type; mDNSIPPort port; unsigned char txtinfo[1024]; @@ -534,7 +773,10 @@ typedef struct KQSocketEventSource static KQSocketEventSource *gEventSources; //************************************************************************************************************* -// General Utility Functions +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - +#pragma mark - General Utility Functions +#endif #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING @@ -636,8 +878,8 @@ mDNSlocal void validatelists(mDNS *const m) // Check platform-layer lists NetworkInterfaceInfoOSX *i; for (i = m->p->InterfaceList; i; i = i->next) - 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); + if (i->next == (NetworkInterfaceInfoOSX *)~0 || !i->m || i->m == (mDNS *)~0) + LogMemCorruption("m->p->InterfaceList: %p is garbage (%p)", i, i->ifinfo.ifname); ClientTunnel *t; for (t = m->TunnelClients; t; t=t->next) @@ -645,14 +887,12 @@ mDNSlocal void validatelists(mDNS *const m) LogMemCorruption("m->TunnelClients: %p is garbage (%d)", t, t->dstname.c[0]); } -void *mallocL(char *msg, unsigned int size) +mDNSexport void *mallocL(char *msg, unsigned int size) { - unsigned long *mem = malloc(size+8); + // Allocate space for two words of sanity checking data before the requested block + mDNSu32 *mem = malloc(sizeof(mDNSu32) * 2 + size); if (!mem) - { - LogMsg("malloc( %s : %d ) failed", msg, size); - return(NULL); - } + { LogMsg("malloc( %s : %d ) failed", msg, size); return(NULL); } else { if (size > 24000) LogMsg("malloc( %s : %lu ) = %p suspiciously large", msg, size, &mem[2]); @@ -666,18 +906,18 @@ void *mallocL(char *msg, unsigned int size) } } -void freeL(char *msg, void *x) +mDNSexport 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; } + mDNSu32 *mem = ((mDNSu32 *)x) - 2; + if (mem[0] != 0xDEAD1234) { LogMsg("free( %s @ %p ) !!!! NOT ALLOCATED !!!!", msg, &mem[2]); return; } if (mem[1] > 24000) LogMsg("free( %s : %ld @ %p) suspiciously large", msg, mem[1], &mem[2]); else if (MACOSX_MDNS_MALLOC_DEBUGGING >= 2) LogMsg("free( %s : %ld @ %p)", msg, mem[1], &mem[2]); - //mDNSPlatformMemZero(mem, mem[1]+8); - memset(mem, 0xFF, mem[1]+8); + //mDNSPlatformMemZero(mem, sizeof(mDNSu32) * 2 + mem[1]); + memset(mem, 0xFF, sizeof(mDNSu32) * 2 + mem[1]); validatelists(&mDNSStorage); free(mem); } @@ -685,6 +925,12 @@ void freeL(char *msg, void *x) #endif +//************************************************************************************************************* +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - +#pragma mark - Mach client request handlers +#endif + //************************************************************************************************************* // Client Death Detection @@ -784,7 +1030,7 @@ mDNSlocal void AbortClient(mach_port_t ClientMachPort, void *m) while (si) { ServiceInstance *instance = si; - si = si->next; + si = si->next; instance->renameonmemfree = mDNSfalse; if (m && m != x) LogMsg("%5d: DNSServiceRegistration(%##s, %u) STOP; WARNING m %p != x %p", ClientMachPort, instance->srs.RR_SRV.resrec.name->c, SRS_PORT(&instance->srs), m, x); else LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort, instance->srs.RR_SRV.resrec.name->c, SRS_PORT(&instance->srs)); @@ -959,7 +1205,7 @@ mDNSexport kern_return_t provide_DNSServiceDomainEnumerationCreate_rpc(mach_port return(mStatus_NoError); fail: - LogMsg("%5d: DNSServiceDomainEnumeration(%d) failed: %s (%ld)", client, regDom, errormsg, err); + LogMsg("%5d: DNSServiceDomainEnumeration(%d) failed: %s (%d)", client, regDom, errormsg, err); return(err); } @@ -1016,10 +1262,15 @@ mDNSlocal mStatus AddDomainToBrowser(DNSServiceBrowser *browser, const domainnam if (!question) { LogMsg("Error: malloc"); return mStatus_NoMemoryErr; } AssignDomainName(&question->domain, d); question->next = browser->qlist; - browser->qlist = question; LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", browser->ClientMachPort, browser->type.c, d->c); err = mDNS_StartBrowse(&mDNSStorage, &question->q, &browser->type, d, mDNSInterface_Any, mDNSfalse, FoundInstance, browser); - if (err) LogMsg("Error: AddDomainToBrowser: mDNS_StartBrowse %d", err); + if (!err) + browser->qlist = question; + else + { + LogMsg("Error: AddDomainToBrowser: mDNS_StartBrowse %d", err); + freeL("DNSServiceBrowserQuestion", question); + } return err; } @@ -1126,7 +1377,7 @@ mDNSexport kern_return_t provide_DNSServiceBrowserCreate_rpc(mach_port_t unuseds badparam: err = mStatus_BadParamErr; fail: - LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", client, regtype, domain, errormsg, err); + LogMsg("%5d: DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%d)", client, regtype, domain, errormsg, err); return(err); } @@ -1257,7 +1508,7 @@ mDNSexport kern_return_t provide_DNSServiceResolverResolve_rpc(mach_port_t unuse badparam: err = mStatus_BadParamErr; fail: - LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", client, name, regtype, domain, errormsg, err); + LogMsg("%5d: DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%d)", client, name, regtype, domain, errormsg, err); return(err); } @@ -1293,7 +1544,7 @@ mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus r { // On conflict for an autoname service, rename and reregister *all* autoname services IncrementLabelSuffix(&m->nicelabel, mDNStrue); - m->MainCallback(m, mStatus_ConfigChanged); + mDNS_ConfigChanged(m); } else if (si->autoname) { @@ -1339,7 +1590,7 @@ mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus r } else if (result != mStatus_NATTraversal) - LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %ld", si->ClientMachPort, srs->RR_SRV.resrec.name->c, SRS_PORT(srs), result); + LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %d", si->ClientMachPort, srs->RR_SRV.resrec.name->c, SRS_PORT(srs), result); } mDNSlocal mStatus AddServiceInstance(DNSServiceRegistration *x, const domainname *domain) @@ -1531,7 +1782,7 @@ badtxt: badparam: err = mStatus_BadParamErr; fail: - LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%ld)", + LogMsg("%5d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", %d) failed: %s (%d)", client, name, regtype, domain, mDNSVal16(port), errormsg, err); return(err); } @@ -1542,13 +1793,13 @@ mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result) 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); + LogInfo("Local Hostname changed from \"%#s.local\" to \"%#s.local\"", m->p->userhostlabel.c, m->hostlabel.c); // One second pause in case we get a Computer Name update too -- don't want to alert the user twice RecordUpdatedNiceLabel(m, mDNSPlatformOneSecond); } else if (result == mStatus_NameConflict) { - LogOperation("Local Hostname conflict for \"%#s.local\"", m->hostlabel.c); + LogInfo("Local Hostname conflict for \"%#s.local\"", m->hostlabel.c); if (!m->p->HostNameConflict) m->p->HostNameConflict = NonZeroTime(m->timenow); else if (m->timenow - m->p->HostNameConflict > 60 * mDNSPlatformOneSecond) { @@ -1560,7 +1811,7 @@ mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result) { // 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); + //LogInfo("GrowCache %d * %d = %d", sizeof(CacheEntity), RR_CACHE_SIZE, sizeof(CacheEntity) * RR_CACHE_SIZE); if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE); } else if (result == mStatus_ConfigChanged) @@ -1647,7 +1898,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 ? x->name.c : (mDNSu8*)"\x8""«NULL»", type, data_len, errormsg, err); + LogMsg("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) failed: %s (%d)", client, x ? x->name.c : (mDNSu8*)"\x8""«NULL»", type, data_len, errormsg, err); return mStatus_UnknownErr; } @@ -1698,7 +1949,7 @@ mDNSlocal mStatus UpdateRecord(ServiceRecordSet *srs, mach_port_t client, AuthRe return(mStatus_NoError); fail: - LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %d) failed: %s (%ld)", client, name->c, data_len, errormsg, err); + LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %d) failed: %s (%d)", client, name->c, data_len, errormsg, err); return(err); } @@ -1743,7 +1994,7 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationUpdateRecord_rpc(mach_por return mStatus_NoError; fail: - LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%ld)", client, name->c, reference, data_len, errormsg, err); + LogMsg("%5d: DNSServiceRegistrationUpdateRecord(%##s, %X, %d) failed: %s (%d)", client, name->c, reference, data_len, errormsg, err); return(err); } @@ -1792,12 +2043,15 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationRemoveRecord_rpc(mach_por return mStatus_NoError; fail: - LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%X) failed: %s (%ld)", client, reference, errormsg, err); + LogMsg("%5d: DNSServiceRegistrationRemoveRecord(%X) failed: %s (%d)", client, reference, errormsg, err); return(err); } //************************************************************************************************************* -// Support Code +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - +#pragma mark - Startup, shutdown, and supporting code +#endif mDNSlocal void DNSserverCallback(CFMachPortRef port, void *msg, CFIndex size, void *info) { @@ -1955,7 +2209,7 @@ mDNSlocal kern_return_t destroyBootstrapService() mDNSlocal void ExitCallback(int sig) { (void)sig; // Unused - LogMsgIdent(mDNSResponderVersionString, "stopping"); + LogMsg("%s stopping", mDNSResponderVersionString); debugf("ExitCallback"); if (!mDNS_DebugMode && !started_via_launchdaemon) @@ -1971,7 +2225,7 @@ mDNSlocal void ExitCallback(int sig) while (DNSServiceRegistrationList) AbortClient(DNSServiceRegistrationList ->ClientMachPort, DNSServiceRegistrationList); - if (udsserver_exit(launchd_fd) < 0) LogMsg("ExitCallback: udsserver_exit failed"); + if (udsserver_exit() < 0) LogMsg("ExitCallback: udsserver_exit failed"); debugf("ExitCallback: mDNS_StartExit"); mDNS_StartExit(&mDNSStorage); @@ -1980,8 +2234,7 @@ mDNSlocal void ExitCallback(int sig) // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit mDNSlocal void HandleSIG(int sig) { - debugf(" "); - debugf("HandleSIG %d", sig); + // WARNING: can't call syslog or fprintf from signal handler mach_msg_header_t header; header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0); header.msgh_remote_port = signal_port; @@ -1989,17 +2242,19 @@ mDNSlocal void HandleSIG(int sig) header.msgh_size = sizeof(header); header.msgh_id = sig; if (mach_msg_send(&header) != MACH_MSG_SUCCESS) - { - LogMsg("HandleSIG %d: mach_msg_send failed", sig); if (sig == SIGTERM || sig == SIGINT) exit(-1); - } } mDNSlocal void CatchABRT(int sig) { - LogMsg("Received SIGABRT %d", sig); - sleep(1); // Pause to make sure syslog gets the message - while(1) *(long*)0 = 0; // Generate a CrashReporter stack trace so we can find out what library called abort(); + // WARNING: can't call syslog or fprintf from signal handler + // We want a CrashReporter stack trace so we can find out what library called abort() + // So that we will crash, unblock all signals (that abort() may have blocked) + sigset_t mask; + sigfillset(&mask); + sigprocmask(SIG_UNBLOCK, &mask, NULL); + (void)sig; + while(1) *(long*)0 = 0; } mDNSlocal void INFOCallback(void) @@ -2012,7 +2267,7 @@ mDNSlocal void INFOCallback(void) NetworkInterfaceInfoOSX *i; DNSServer *s; - LogMsgIdent(mDNSResponderVersionString, "---- BEGIN STATE LOG ----"); + LogMsg("---- BEGIN STATE LOG ----"); udsserver_info(&mDNSStorage); @@ -2056,21 +2311,32 @@ mDNSlocal void INFOCallback(void) { for (i = mDNSStorage.p->InterfaceList; i; i = i->next) { + // Allow six characters for interface name, for names like "vmnet8" 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, + LogMsgNoIdent("%p %s %-6s(%lu) %.6a %.6a %#-14a dormant for %d seconds", + i->ifinfo.InterfaceID, + i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifinfo.ifname, i->scope_id, &i->ifinfo.MAC, &i->BSSID, &i->ifinfo.ip, utc - i->LastSeen); else - 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, + { + const CacheRecord *sps[3]; + FindSPSInCache(&mDNSStorage, &i->ifinfo.NetWakeBrowse, sps); + LogMsgNoIdent("%p %s %-6s(%lu) %.6a %.6a %s %s %-15.4a %s %s %s %s %#a", + i->ifinfo.InterfaceID, + i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifinfo.ifname, i->scope_id, &i->ifinfo.MAC, &i->BSSID, i->ifinfo.InterfaceActive ? "Active" : " ", i->ifinfo.IPv4Available ? "v4" : " ", i->ifinfo.IPv4Available ? (mDNSv4Addr*)&i->ifa_v4addr : &zerov4Addr, i->ifinfo.IPv6Available ? "v6" : " ", - i->ifinfo.InterfaceID, - i->ifinfo.Advertise ? "Adv" : " ", - i->ifinfo.McastTxRx ? "TxRx" : " ", + i->ifinfo.Advertise ? "⊙" : " ", + i->ifinfo.McastTxRx ? "⇆" : " ", + !(i->ifinfo.InterfaceActive && i->ifinfo.NetWake) ? " " : !sps[0] ? "☼" : "☀", &i->ifinfo.ip); + + if (sps[0]) LogMsgNoIdent(" %13d %#s", SPSMetric(sps[0]->resrec.rdata->u.name.c), sps[0]->resrec.rdata->u.name.c); + if (sps[1]) LogMsgNoIdent(" %13d %#s", SPSMetric(sps[1]->resrec.rdata->u.name.c), sps[1]->resrec.rdata->u.name.c); + if (sps[2]) LogMsgNoIdent(" %13d %#s", SPSMetric(sps[2]->resrec.rdata->u.name.c), sps[2]->resrec.rdata->u.name.c); + } } } @@ -2082,7 +2348,7 @@ mDNSlocal void INFOCallback(void) { 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->domain.c, ifx ? ifx->ifinfo.ifname : "", ifx ? " " : "", &s->addr, mDNSVal16(s->port), s->teststate == DNSServer_Untested ? "(Untested)" : s->teststate == DNSServer_Passed ? "" : s->teststate == DNSServer_Failed ? "(Failed)" : @@ -2091,9 +2357,9 @@ mDNSlocal void INFOCallback(void) } mDNSs32 now = mDNS_TimeNow(&mDNSStorage); - LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now); + LogMsgNoIdent("Timenow 0x%08lX (%d)", (mDNSu32)now, now); - LogMsgIdent(mDNSResponderVersionString, "---- END STATE LOG ----"); + LogMsg("---- END STATE LOG ----"); } mDNSlocal void SignalCallback(CFMachPortRef port, void *msg, CFIndex size, void *info) @@ -2113,22 +2379,22 @@ mDNSlocal void SignalCallback(CFMachPortRef port, void *msg, CFIndex size, void CacheGroup *cg; CacheRecord *rr; LogMsg("SIGHUP: Purge cache"); + mDNS_Lock(m); FORALL_CACHERECORDS(slot, cg, rr) mDNS_PurgeCacheResourceRecord(m, rr); + // Restart unicast and multicast queries + mDNSCoreRestartQueries(m); + mDNS_Unlock(m); } break; case SIGINT: case SIGTERM: ExitCallback(msg_header->msgh_id); break; case SIGINFO: INFOCallback(); break; - case SIGUSR1: // mDNSCoreMachineSleep(m, !m->SleepState); break; - LogMsg("SIGUSR1: Simulate Network Configuration Change Event"); - mDNSMacOSXNetworkChanged(m); - - // Simulate KeychainChanged - mDNS_Lock(m); - SetDomainSecrets(m); - mDNS_Unlock(m); - + case SIGUSR1: mDNS_LoggingEnabled = mDNS_LoggingEnabled ? 0 : 1; + LogMsg("SIGUSR1: Logging %s", mDNS_LoggingEnabled ? "Enabled" : "Disabled"); + WatchDogReportingThreshold = mDNS_LoggingEnabled ? 50 : 250; + break; + case SIGUSR2: mDNS_PacketLoggingEnabled = mDNS_PacketLoggingEnabled ? 0 : 1; + LogMsg("SIGUSR2: Packet Logging %s", mDNS_PacketLoggingEnabled ? "Enabled" : "Disabled"); break; - case SIGUSR2: SigLogLevel(); break; default: LogMsg("SignalCallback: Unknown signal %d", msg_header->msgh_id); break; } KQueueUnlock(m, "Unix Signal"); @@ -2149,7 +2415,7 @@ mDNSlocal kern_return_t mDNSDaemonInitialize(void) { s_port = CFMachPortCreate(NULL, DNSserverCallback, NULL, NULL); m_port = CFMachPortGetPort(s_port); - char *MachServerName = OSXVers < 7 ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder"; + char *MachServerName = OSXVers < OSXVers_10_3_Panther ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder"; kern_return_t status = bootstrap_register(bootstrap_port, MachServerName, m_port); if (status) @@ -2170,18 +2436,17 @@ mDNSlocal kern_return_t mDNSDaemonInitialize(void) err = mDNS_Init(&mDNSStorage, &PlatformStorage, rrcachestorage, RR_CACHE_SIZE, - mDNS_Init_AdvertiseLocalAddresses, + advertise, mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext); - if (err) { LogMsg("Daemon start: mDNS_Init failed %ld", err); return(err); } + if (err) { LogMsg("Daemon start: mDNS_Init failed %d", err); return(err); } client_death_port = CFMachPortGetPort(d_port); signal_port = CFMachPortGetPort(i_port); - CFRunLoop = CFRunLoopGetCurrent(); - CFRunLoopAddSource(CFRunLoop, d_rls, kCFRunLoopDefaultMode); - CFRunLoopAddSource(CFRunLoop, s_rls, kCFRunLoopDefaultMode); - CFRunLoopAddSource(CFRunLoop, i_rls, kCFRunLoopDefaultMode); + CFRunLoopAddSource(PlatformStorage.CFRunLoop, d_rls, kCFRunLoopDefaultMode); + CFRunLoopAddSource(PlatformStorage.CFRunLoop, s_rls, kCFRunLoopDefaultMode); + CFRunLoopAddSource(PlatformStorage.CFRunLoop, i_rls, kCFRunLoopDefaultMode); CFRelease(d_rls); CFRelease(s_rls); CFRelease(i_rls); @@ -2201,6 +2466,8 @@ mDNSlocal mDNSs32 mDNSDaemonIdle(mDNS *const m) // we then systematically lose our own looped-back packets. if (m->p->NetworkChanged && now - m->p->NetworkChanged >= 0) mDNSMacOSXNetworkChanged(m); + if (m->p->RequestReSleep && now - m->p->RequestReSleep >= 0) { m->p->RequestReSleep = 0; mDNSPowerRequest(0, 0); } + // KeyChain frequently fails to notify clients of change events. To work around this // we set a timer and periodically poll to detect if any changes have occurred. // Without this Back To My Mac just does't work for a large number of users. @@ -2226,12 +2493,16 @@ mDNSlocal mDNSs32 mDNSDaemonIdle(mDNS *const m) if (nextevent - m->p->KeyChainBugTimer > 0) nextevent = m->p->KeyChainBugTimer; + if (m->p->RequestReSleep) + if (nextevent - m->p->RequestReSleep > 0) + nextevent = m->p->RequestReSleep; + // 3. Deliver any waiting browse messages to clients DNSServiceBrowser *b = DNSServiceBrowserList; while (b) { - // NOTE: Need to advance b to the next element BEFORE we call DeliverInstance(), because in the + // Note: Need to advance b to the next element BEFORE we call DeliverInstance(), because in the // event that the client Mach queue overflows, DeliverInstance() will call AbortBlockedClient() // and that will cause the DNSServiceBrowser object's memory to be freed before it returns DNSServiceBrowser *x = b; @@ -2308,61 +2579,202 @@ mDNSlocal mDNSs32 mDNSDaemonIdle(mDNS *const m) return(nextevent); } -mDNSlocal void ShowTaskSchedulingError(mDNS *const m) +// Right now we consider *ALL* of our DHCP leases +// It might make sense to be a bit more selective and only consider the leases on interfaces +// (a) that are capable and enabled for wake-on-LAN, and +// (b) where we have found (and successfully registered with) a Sleep Proxy +// If we can't be woken for traffic on a given interface, then why keep waking to renew its lease? +mDNSlocal mDNSu32 DHCPWakeTime(void) { - mDNS_Lock(m); - - LogMsg("Task Scheduling Error: Continuously busy for more than a second"); - - // NOTE: To accurately diagnose *why* we're busy, the debugging code here 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)); - if (m->NewLocalOnlyQuestions) - LogMsg("Task Scheduling Error: NewLocalOnlyQuestions %##s (%s)", - m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype)); - if (m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords)) - LogMsg("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m, m->NewLocalRecords)); - 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->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); - if (m->timenow - m->NextScheduledQuery >= 0) - LogMsg("Task Scheduling Error: m->NextScheduledQuery %d", m->timenow - m->NextScheduledQuery); - if (m->timenow - m->NextScheduledProbe >= 0) - 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); + mDNSu32 e = 24 * 3600; // Maximum maintenance wake interval is 24 hours + const CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); + if (!now) LogMsg("DHCPWakeTime: CFAbsoluteTimeGetCurrent failed"); + else + { + const SCPreferencesRef prefs = SCPreferencesCreate(NULL, CFSTR("mDNSResponder:DHCPWakeTime"), NULL); + if (!prefs) LogMsg("DHCPWakeTime: SCPreferencesCreate failed"); + else + { + const SCNetworkSetRef currentset = SCNetworkSetCopyCurrent(prefs); + if (!currentset) LogMsg("DHCPWakeTime: SCNetworkSetCopyCurrent failed"); + else + { + const CFArrayRef services = SCNetworkSetCopyServices(currentset); + if (!services) LogMsg("DHCPWakeTime: SCNetworkSetCopyServices failed"); + else + { + int i; + for (i = 0; i < CFArrayGetCount(services); i++) + { + const SCNetworkServiceRef service = CFArrayGetValueAtIndex(services, i); + if (!service) LogMsg("DHCPWakeTime: CFArrayGetValueAtIndex %d failed", i); + else + { + const CFStringRef serviceid = SCNetworkServiceGetServiceID(service); + if (!serviceid) LogMsg("DHCPWakeTime: SCNetworkServiceGetServiceID %d failed", i); + else + { + // Note: It's normal for this call to return NULL, for interfaces not using DHCP + const CFDictionaryRef dhcp = SCDynamicStoreCopyDHCPInfo(NULL, serviceid); + if (dhcp) + { + const CFDateRef start = DHCPInfoGetLeaseStartTime(dhcp); + const CFDataRef lease = DHCPInfoGetOptionData(dhcp, 51); // Option 51 = IP Address Lease Time + if (!start || !lease || CFDataGetLength(lease) < 4) + LogMsg("DHCPWakeTime: SCDynamicStoreCopyDHCPInfo index %d failed " + "CFDateRef start %p CFDataRef lease %p CFDataGetLength(lease) %d", + i, start, lease, lease ? CFDataGetLength(lease) : 0); + else + { + const UInt8 *d = CFDataGetBytePtr(lease); + if (!d) LogMsg("DHCPWakeTime: CFDataGetBytePtr %d failed", i); + else + { + const mDNSu32 elapsed = now - CFDateGetAbsoluteTime(start); + const mDNSu32 lifetime = (mDNSs32) ((mDNSs32)d[0] << 24 | (mDNSs32)d[1] << 16 | (mDNSs32)d[2] << 8 | d[3]); + const mDNSu32 remaining = lifetime - elapsed; + const mDNSu32 wake = remaining > 60 ? remaining - remaining/10 : 54; // Wake at 90% of the lease time + LogSPS("DHCP Address Lease Elapsed %6u Lifetime %6u Remaining %6u Wake %6u", elapsed, lifetime, remaining, wake); + if (e > wake) e = wake; + } + } + CFRelease(dhcp); + } + } + } + } + CFRelease(services); + } + CFRelease(currentset); + } + CFRelease(prefs); + } + } + return(e); } -mDNSlocal mDNSBool ReadyForSleep(mDNS *m) +// We deliberately schedule our wakeup for halfway between when we'd *like* it and when we *need* it. +// For example, if our DHCP lease expires in two hours, we'll typically renew it at the halfway point, after one hour. +// If we scheduled our wakeup for the one-hour renewal time, that might be just seconds from now, and sleeping +// for a few seconds and then waking again is silly and annoying. +// If we scheduled our wakeup for the two-hour expiry time, and we were slow to wake, we might lose our lease. +// Scheduling our wakeup for halfway in between -- 90 minutes -- avoids short wakeups while still +// allowing us an adequate safety margin to renew our lease before we lose it. + +mDNSlocal mDNSBool AllowSleepNow(mDNS *const m, mDNSs32 now) { - (void)m; + mDNSBool ready = mDNSCoreReadyForSleep(m); + if (m->SleepState && !ready && now - m->SleepLimit < 0) return(mDNSfalse); - // 1. Scan list of private LLQs, and make sure they've all completed their handshake with the server - DNSQuestion *q; - for (q = m->Questions; q; q = q->next) - if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->ReqLease == 0 && q->tcp) return(mDNSfalse); + m->p->WakeAtUTC = 0; + int result = kIOReturnSuccess; + CFDictionaryRef opts = NULL; - // 2. Scan list of registered records - AuthRecord *rr; - for (rr = m->ResourceRecords; rr; rr = rr->next) - if (rr->state == regState_Refresh && rr->tcp) return(mDNSfalse); + // If the sleep request was cancelled, and we're no longer planning to sleep, don't need to + // do the stuff below, but we *DO* still need to acknowledge the sleep message we received. + if (!m->SleepState) + LogMsg("AllowSleepNow: Sleep request was canceled with %d ticks remaining", m->SleepLimit - now); + else + { + if (!m->SystemWakeOnLANEnabled || !mDNSCoreHaveAdvertisedMulticastServices(m)) + LogSPS("AllowSleepNow: Not scheduling wakeup: SystemWakeOnLAN %s enabled; %s advertised services", + m->SystemWakeOnLANEnabled ? "is" : "not", + mDNSCoreHaveAdvertisedMulticastServices(m) ? "have" : "no"); + else + { + mDNSs32 dhcp = DHCPWakeTime(); + LogSPS("ComputeWakeTime: DHCP Wake %d", dhcp); + mDNSs32 interval = mDNSCoreIntervalToNextWake(m, now) / mDNSPlatformOneSecond; + if (interval > dhcp) interval = dhcp; + + // If we're not ready to sleep (failed to register with Sleep Proxy, maybe because of + // transient network problem) then schedule a wakeup in one hour to try again. Otherwise, + // a single SPS failure could result in a remote machine falling permanently asleep, requiring + // someone to go to the machine in person to wake it up again, which would be unacceptable. + if (!ready && interval > 3600) interval = 3600; + + //interval = 48; // For testing + +#ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements + if (m->p->IOPMConnection) // If lightweight-wake capability is available, use that + { + const CFDateRef WakeDate = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent() + interval); + if (!WakeDate) LogMsg("ScheduleNextWake: CFDateCreate failed"); + else + { + const mDNSs32 reqs = kIOPMSystemPowerStateCapabilityNetwork; + const CFNumberRef Requirements = CFNumberCreate(NULL, kCFNumberSInt32Type, &reqs); + if (!Requirements) LogMsg("ScheduleNextWake: CFNumberCreate failed"); + else + { + const void *OptionKeys[2] = { CFSTR("WakeDate"), CFSTR("Requirements") }; + const void *OptionVals[2] = { WakeDate, Requirements }; + opts = CFDictionaryCreate(NULL, (void*)OptionKeys, (void*)OptionVals, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (!opts) LogMsg("ScheduleNextWake: CFDictionaryCreate failed"); + CFRelease(Requirements); + } + CFRelease(WakeDate); + } + LogSPS("AllowSleepNow: Will request lightweight wakeup in %d seconds", interval); + } + else // else schedule the wakeup using the old API instead to +#endif + { + // If we wake within +/- 30 seconds of our requested time we'll assume the system woke for us, + // so we should put it back to sleep. To avoid frustrating the user, we always request at least + // 60 seconds sleep, so if they immediately re-wake the system within seconds of it going to sleep, + // we then shouldn't hit our 30-second window, and we won't attempt to re-sleep the machine. + if (interval < 60) interval = 60; + + result = mDNSPowerRequest(1, interval); + + if (result == kIOReturnNotReady) + { + LogMsg("Requested wakeup in %d seconds unsuccessful; retrying with longer intervals", interval); + // IOPMSchedulePowerEvent fails with kIOReturnNotReady (-536870184/0xe00002d8) if the + // requested wake time is "too soon", but there's no API to find out what constitutes + // "too soon" on any given OS/hardware combination, so if we get kIOReturnNotReady + // we just have to iterate with successively longer intervals until it doesn't fail. + // Additionally, if our power request is deemed "too soon" for the machine to get to + // sleep and wake back up again, we attempt to cancel the sleep request, since the + // implication is that the system won't manage to be awake again at the time we need it. + do + { + interval += (interval < 20) ? 1 : ((interval+3) / 4); + result = mDNSPowerRequest(1, interval); + } + while (result == kIOReturnNotReady); + } + + if (result) LogMsg("AllowSleepNow: Requested wakeup in %d seconds unsuccessful: %d %X", interval, result, result); + else LogSPS("AllowSleepNow: Requested wakeup in %d seconds", interval); + m->p->WakeAtUTC = mDNSPlatformUTC() + interval; + } + } + + // Clear our interface list to empty state, ready to go to sleep + // As a side effect of doing this, we'll also cancel any outstanding SPS Resolve calls that didn't complete + m->SleepState = SleepState_Sleeping; + mDNSMacOSXNetworkChanged(m); + } + + LogSPS("AllowSleepNow: %s(%lX) %s at %ld (%d ticks remaining)", +#ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements + (m->p->IOPMConnection) ? "IOPMConnectionAcknowledgeEventWithOptions" : +#endif + (result == kIOReturnSuccess) ? "IOAllowPowerChange" : "IOCancelPowerChange", + m->p->SleepCookie, ready ? "ready for sleep" : "giving up", now, m->SleepLimit - now); - // 2. Scan list of registered services - ServiceRecordSet *srs; - for (srs = m->ServiceRegistrations; srs; srs = srs->uDNS_next) - if (srs->state == regState_NoTarget && srs->tcp) return(mDNSfalse); + m->SleepLimit = 0; // Don't clear m->SleepLimit until after we've logged it above +#ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements + if (m->p->IOPMConnection) IOPMConnectionAcknowledgeEventWithOptions(m->p->IOPMConnection, m->p->SleepCookie, opts); + else +#endif + if (result == kIOReturnSuccess) IOAllowPowerChange (m->p->PowerConnection, m->p->SleepCookie); + else IOCancelPowerChange(m->p->PowerConnection, m->p->SleepCookie); + + if (opts) CFRelease(opts); return(mDNStrue); } @@ -2387,7 +2799,7 @@ mDNSlocal void * KQueueLoop(void *m_param) #endif pthread_mutex_lock(&PlatformStorage.BigMutex); - LogOperation("Starting time value 0x%08lX (%ld)", (mDNSu32)mDNSStorage.timenow_last, mDNSStorage.timenow_last); + LogInfo("Starting time value 0x%08lX (%ld)", (mDNSu32)mDNSStorage.timenow_last, mDNSStorage.timenow_last); // This is the main work loop: // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time @@ -2405,15 +2817,24 @@ mDNSlocal void * KQueueLoop(void *m_param) mDNSs32 nextTimerEvent = udsserver_idle(mDNSDaemonIdle(m)); mDNSs32 end = mDNSPlatformRawTime(); if (end - start >= WatchDogReportingThreshold) - LogOperation("WARNING: Idle task took %dms to complete", end - start); + LogInfo("WARNING: Idle task took %dms to complete", end - start); mDNSs32 now = mDNS_TimeNow(m); if (m->ShutdownTime) { + if (mDNSStorage.ResourceRecords) + { + LogInfo("Cannot exit yet; Resource Record still exists: %s", ARDisplayString(m, mDNSStorage.ResourceRecords)); + if (mDNS_LoggingEnabled) usleep(10000); // Sleep 10ms so that we don't flood syslog with too many messages + } + if (mDNSStorage.ServiceRegistrations) + LogInfo("Cannot exit yet; ServiceRegistrations still exists: %s", ARDisplayString(m, &mDNSStorage.ServiceRegistrations->RR_SRV)); if (mDNS_ExitNow(m, now)) { - LogOperation("mDNS_FinalExit"); + if (!mDNSStorage.ResourceRecords && !mDNSStorage.ServiceRegistrations) + safe_vproc_transaction_end(); + LogInfo("mDNS_FinalExit"); mDNS_FinalExit(&mDNSStorage); usleep(1000); // Little 1ms pause before exiting, so we don't lose our final syslog messages exit(0); @@ -2422,20 +2843,10 @@ mDNSlocal void * KQueueLoop(void *m_param) nextTimerEvent = m->ShutdownTime; } - if (m->p->SleepLimit) - { - mDNSBool ready = ReadyForSleep(m); - if (ready || now - m->p->SleepLimit >= 0) - { - LogOperation("IOAllowPowerChange(%lX) %s at %ld (%d ticks remaining)", m->p->SleepCookie, - ready ? "ready for sleep" : "giving up", now, m->p->SleepLimit - now); - m->p->SleepLimit = 0; - IOAllowPowerChange(m->p->PowerConnection, m->p->SleepCookie); - } - else - if (nextTimerEvent - m->p->SleepLimit >= 0) - nextTimerEvent = m->p->SleepLimit; - } + if (m->SleepLimit) + if (!AllowSleepNow(m, now)) + if (nextTimerEvent - m->SleepLimit >= 0) + nextTimerEvent = m->SleepLimit; // Convert absolute wakeup time to a relative time from now mDNSs32 ticks = nextTimerEvent - now; @@ -2504,13 +2915,11 @@ mDNSlocal void * KQueueLoop(void *m_param) { const KQueueEntry *const kqentry = new_events[i].udata; mDNSs32 stime = 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 etime = mDNSPlatformRawTime(); if (etime - stime >= WatchDogReportingThreshold) - LogOperation("WARNING: %s took %dms to complete", KQtask, etime - stime); + LogInfo("WARNING: %s took %dms to complete", KQtask, etime - stime); } } } @@ -2530,7 +2939,7 @@ mDNSlocal void LaunchdCheckin(void) 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 LogInfo("Launchd provided no launchdata; will open Mach port and Unix Domain Socket explicitly...", err); } else { @@ -2542,12 +2951,30 @@ mDNSlocal void LaunchdCheckin(void) 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"); + launchd_fds_count = launch_data_array_get_count(skt); + if (launchd_fds_count == 0) LogMsg("launch_data_array_get_count(skt) returned 0"); else { - launchd_fd = launch_data_get_fd(s); - LogOperation("Launchd Unix Domain Socket: %d", launchd_fd); + launchd_fds = mallocL("LaunchdCheckin", sizeof(dnssd_sock_t) * launchd_fds_count); + if (!launchd_fds) LogMsg("LaunchdCheckin: malloc failed"); + else + { + size_t i; + for(i = 0; i < launchd_fds_count; i++) + { + launch_data_t s = launch_data_array_get_index(skt, i); + if (!s) + { + launchd_fds[i] = dnssd_InvalidSocket; + LogMsg("launch_data_array_get_index(skt, %d) returned NULL", i); + } + else + { + launchd_fds[i] = launch_data_get_fd(s); + LogInfo("Launchd Unix Domain Socket [%d]: %d", i, launchd_fds[i]); + } + } + } // In some early versions of 10.4.x, the permissions on the UDS were not set correctly, so we fix them here chmod(MDNS_UDS_SERVERPATH, S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP | S_IROTH|S_IWOTH); } @@ -2559,11 +2986,11 @@ mDNSlocal void LaunchdCheckin(void) 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"); + if (!p) LogInfo("launch_data_dict_lookup(ports, \"com.apple.mDNSResponder\") returned NULL"); else { m_port = launch_data_get_fd(p); - LogOperation("Launchd Mach Port: %d", m_port); + LogInfo("Launchd Mach Port: %d", m_port); if (m_port == ~0U) m_port = MACH_PORT_NULL; } } @@ -2597,7 +3024,7 @@ mDNSlocal void DropPrivileges(void) *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"); + else LogInfo("DropPrivileges: Created subdirectory and symlink"); } } @@ -2615,25 +3042,54 @@ mDNSexport int main(int argc, char **argv) kern_return_t status; pthread_t KQueueThread; - LogMsgIdent(mDNSResponderVersionString, "starting"); + LogMsg("%s starting", mDNSResponderVersionString); + +#if 0 + LogMsg("CacheRecord %d", sizeof(CacheRecord)); + LogMsg("CacheGroup %d", sizeof(CacheGroup)); + LogMsg("ResourceRecord %d", sizeof(ResourceRecord)); + LogMsg("RData_small %d", sizeof(RData_small)); + + LogMsg("sizeof(CacheEntity) %d", sizeof(CacheEntity)); + LogMsg("RR_CACHE_SIZE %d", RR_CACHE_SIZE); + LogMsg("block usage %d", sizeof(CacheEntity) * RR_CACHE_SIZE); + LogMsg("block wastage %d", 16*1024 - sizeof(CacheEntity) * RR_CACHE_SIZE); +#endif + + safe_vproc_transaction_begin(); if (0 == geteuid()) DropPrivileges(); for (i=1; ifd != fd) p = &(*p)->next; + if (*p) { LogMsg("udsSupportAddFDToEventLoop: ERROR fd %d already has EventLoop source entry", fd); return mStatus_AlreadyRegistered; } + KQSocketEventSource *newSource = (KQSocketEventSource*) mallocL("KQSocketEventSource", sizeof *newSource); if (!newSource) return mStatus_NoMemoryErr; - mDNSPlatformMemZero(newSource, sizeof(*newSource)); - newSource->fd = fd; + newSource->next = mDNSNULL; + newSource->fd = fd; newSource->kqs.KQcallback = callback; newSource->kqs.KQcontext = context; newSource->kqs.KQtask = "UDS client"; if (KQueueSet(fd, EV_ADD, EVFILT_READ, &newSource->kqs) == 0) { - KQSocketEventSource **p = &gEventSources; - while (*p) p = &(*p)->next; *p = newSource; return mStatus_NoError; } - else - { - close(fd); - free(newSource); - return mStatus_NoMemoryErr; - } + + LogMsg("KQueueSet failed for fd %d errno %d (%s)", fd, errno, strerror(errno)); + freeL("KQSocketEventSource", newSource); + return mStatus_BadParamErr; } -mStatus udsSupportRemoveFDFromEventLoop(int fd) // Note: This also CLOSES the file descriptor +mDNSexport mStatus udsSupportRemoveFDFromEventLoop(int fd) // Note: This also CLOSES the file descriptor { KQSocketEventSource **p = &gEventSources; while (*p && (*p)->fd != fd) p = &(*p)->next; - if (*p) + if (*p) { KQSocketEventSource *s = *p; *p = (*p)->next; @@ -2755,12 +3213,15 @@ mStatus udsSupportRemoveFDFromEventLoop(int fd) // Note: This also CLOSES the f freeL("KQSocketEventSource", s); return mStatus_NoError; } + LogMsg("udsSupportRemoveFDFromEventLoop: ERROR fd %d not found in EventLoop source list", fd); return mStatus_NoSuchNameErr; } +#if _BUILDING_XCODE_PROJECT_ // If mDNSResponder crashes, then this string will be magically included in the automatically-generated crash log const char *__crashreporter_info__ = mDNSResponderVersionString; asm(".desc ___crashreporter_info__, 0x10"); +#endif // For convenience when using the "strings" command, this is the last thing in the file // The "@(#) " pattern is a special prefix the "what" command looks for diff --git a/mDNSMacOSX/helper-main.c b/mDNSMacOSX/helper-main.c index af019b3..3bf71f2 100644 --- a/mDNSMacOSX/helper-main.c +++ b/mDNSMacOSX/helper-main.c @@ -17,6 +17,48 @@ Change History (most recent first): $Log: helper-main.c,v $ +Revision 1.28 2009/04/11 00:20:08 jessic2 + Daemon: Should be able to turn on LogOperation dynamically + +Revision 1.27 2009/03/09 19:00:26 mcguire + temporarily don't use getpwnam + +Revision 1.26 2009/03/05 23:08:12 cheshire + mDNSResponderHelper deadlocked — Can't use syslog from within a signal handler + +Revision 1.25 2009/02/06 03:06:49 mcguire + Adopt vproc_transaction API in mDNSResponder + +Revision 1.24 2009/01/28 17:20:46 mcguire +changed incorrect notice level log to debug + +Revision 1.23 2009/01/28 03:17:19 mcguire + helper: Adopt vproc_transaction API + +Revision 1.22 2008/12/19 01:56:47 mcguire + crashes in mDNSResponderHelper + +Revision 1.21 2008/09/15 23:52:30 cheshire + mDNSResponder-177 fails to compile on Linux with .desc pseudo-op +Made __crashreporter_info__ symbol conditional, so we only use it for OS X build + +Revision 1.20 2008/08/13 23:11:35 mcguire + handle SIGTERM in mDNSResponderHelper + +Revision 1.19 2008/08/13 23:04:06 mcguire + handle SIGTERM in mDNSResponderHelper +Preparation: rename message function, as it will no longer be called only on idle exit + +Revision 1.18 2008/08/13 22:56:32 mcguire + handle SIGTERM in mDNSResponderHelper +Preparation: store mach port in global variable so we can write to it from a signal handler + +Revision 1.17 2008/07/24 01:04:04 mcguire + helper spawned every 10s + +Revision 1.16 2008/07/01 01:40:01 mcguire + 64-bit fixes + Revision 1.15 2008/03/13 20:55:16 mcguire fix deprecated warnings/errors Additional cleanup: use a conditional macro instead of lots of #if @@ -89,6 +131,7 @@ Revision 1.1 2007/08/08 22:34:58 mcguire #include "helper-server.h" #include "helpermsg.h" #include "helpermsgServer.h" +#include "safe_vproc.h" #if TARGET_OS_EMBEDDED #include @@ -109,17 +152,29 @@ union max_msg_size union __ReplyUnion__proxy_helper_subsystem rep; }; +#ifdef VPROC_HAS_TRANSACTIONS +typedef struct __transaction_s + { + struct __transaction_s* next; + vproc_transaction_t vt; + } transaction_t; + +static transaction_t* transactions = NULL; +#endif + 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 maxidle = 15; unsigned long actualidle = 3600; CFRunLoopRef gRunLoop = NULL; CFRunLoopTimerRef gTimer = NULL; +mach_port_t gPort = MACH_PORT_NULL; + static void helplogv(int level, const char *fmt, va_list ap) { if (NULL == logclient) { vfprintf(stderr, fmt, ap); fflush(stderr); } @@ -133,6 +188,24 @@ void helplog(int level, const char *fmt, ...) helplogv(level, fmt, ap); va_end(ap); } + +// for safe_vproc +void LogMsgWithLevel(mDNSLogLevel_t logLevel, const char *fmt, ...) + { + (void)logLevel; + va_list ap; + va_start(ap, fmt); + // safe_vproc only calls LogMsg, so assume logLevel maps to ASL_LEVEL_ERR + helplog(ASL_LEVEL_ERR, fmt, ap); + va_end(ap); + } + +static void handle_sigterm(int sig) + { + // debug("entry sig=%d", sig); Can't use syslog from within a signal handler + assert(sig == SIGTERM); + (void)proxy_mDNSExit(gPort); + } static void initialize_logging(void) { @@ -144,7 +217,10 @@ static void initialize_logging(void) static void initialize_id(void) { static char login[] = "_mdnsresponder"; - struct passwd *pwd = getpwnam(login); + struct passwd hardcode; + struct passwd *pwd = &hardcode; // getpwnam(login); + hardcode.pw_uid = 65; + hardcode.pw_gid = 65; if (!pwd) { helplog(ASL_LEVEL_ERR, "Could not find account name `%s'. I will only help root.", login); return; } mDNSResponderUID = pwd->pw_uid; @@ -153,10 +229,10 @@ static void initialize_id(void) static void diediedie(CFRunLoopTimerRef timer, void *context) { - debug("entry"); + debug("entry %p %p %d", timer, context, maxidle); assert(gTimer == timer); if (maxidle) - (void)proxy_mDNSIdleExit((mach_port_t)context); + (void)proxy_mDNSExit(gPort); } void pause_idle_timer(void) @@ -199,15 +275,16 @@ static void *idletimer(void *context) return NULL; } -static void initialize_timer(mach_port_t port) +static int initialize_timer() { - CFRunLoopTimerContext cxt = {0, (void *)port, NULL, NULL, NULL}; - gTimer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + actualidle, actualidle, 0, 0, diediedie, &cxt); + gTimer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + actualidle, actualidle, 0, 0, diediedie, NULL); int err = 0; - debug("entry port=%p", port); - if (0 != (err = pthread_create(&idletimer_thread, NULL, idletimer, (void *)port))) + debug("entry"); + if (0 != (err = pthread_create(&idletimer_thread, NULL, idletimer, NULL))) helplog(ASL_LEVEL_ERR, "Could not start idletimer thread: %s", strerror(err)); + + return err; } static mach_port_t checkin(char *service_name) @@ -272,9 +349,9 @@ 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; + mach_msg_header_t hdr; while ((ch = getopt(ac, av, "dt:")) != -1) switch (ch) @@ -303,20 +380,44 @@ int main(int ac, char *av[]) // Explicitly ensure that our Keychain operations utilize the system domain. SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem); #endif - port = checkin(kmDNSHelperServiceName); - if (!port) + gPort = checkin(kmDNSHelperServiceName); + if (!gPort) { helplog(ASL_LEVEL_ERR, "Launchd provided no launchdata; will open Mach port explicitly"); - port = register_service(kmDNSHelperServiceName); + gPort = 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); } + signal(SIGTERM, handle_sigterm); + + if (initialize_timer()) exit(EXIT_FAILURE); + for (n=0; n<100000; n++) if (!gRunLoop) usleep(100); + if (!gRunLoop) + { + helplog(ASL_LEVEL_ERR, "gRunLoop not set after waiting"); + exit(EXIT_FAILURE); + } + + for(;;) + { + hdr.msgh_bits = 0; + hdr.msgh_local_port = gPort; + hdr.msgh_remote_port = MACH_PORT_NULL; + hdr.msgh_size = sizeof(hdr); + hdr.msgh_id = 0; + kr = mach_msg(&hdr, MACH_RCV_LARGE | MACH_RCV_MSG, 0, hdr.msgh_size, gPort, 0, 0); + if (MACH_RCV_TOO_LARGE != kr) helplog(ASL_LEVEL_ERR, "kr: %d: %s", kr, mach_error_string(kr)); + + safe_vproc_transaction_begin(); + + kr = mach_msg_server_once(helper_server, MAX_MSG_SIZE, gPort, + MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)); + if (KERN_SUCCESS != kr) + { helplog(ASL_LEVEL_ERR, "mach_msg_server: %s\n", mach_error_string(kr)); exit(EXIT_FAILURE); } + + safe_vproc_transaction_end(); + } exit(EXIT_SUCCESS); } @@ -330,6 +431,8 @@ int main(int ac, char *av[]) // The "@(#) " pattern is a special prefix the "what" command looks for const char VersionString_SCCS[] = "@(#) mDNSResponderHelper " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")"; +#if _BUILDING_XCODE_PROJECT_ // If the process crashes, then this string will be magically included in the automatically-generated crash log const char *__crashreporter_info__ = VersionString_SCCS + 5; asm(".desc ___crashreporter_info__, 0x10"); +#endif diff --git a/mDNSMacOSX/helper-server.h b/mDNSMacOSX/helper-server.h index defebe1..1efaa41 100644 --- a/mDNSMacOSX/helper-server.h +++ b/mDNSMacOSX/helper-server.h @@ -17,6 +17,12 @@ Change History (most recent first): $Log: helper-server.h,v $ +Revision 1.5 2009/02/06 03:06:49 mcguire + Adopt vproc_transaction API in mDNSResponder + +Revision 1.4 2009/01/28 03:17:19 mcguire + helper: Adopt vproc_transaction API + Revision 1.3 2007/09/07 22:44:03 mcguire Move CFUserNotification code to mDNSResponderHelper diff --git a/mDNSMacOSX/helper-stubs.c b/mDNSMacOSX/helper-stubs.c index e2084e0..09b262c 100644 --- a/mDNSMacOSX/helper-stubs.c +++ b/mDNSMacOSX/helper-stubs.c @@ -16,6 +16,50 @@ Change History (most recent first): $Log: helper-stubs.c,v $ +Revision 1.19 2009/04/20 20:40:14 cheshire + uDNS: Running location cycling caused configd and mDNSResponder to deadlock +Changed mDNSPreferencesSetName (and similar) routines from MIG "routine" to MIG "simpleroutine" +so we don't deadlock waiting for a result that we're just going to ignore anyway + +Revision 1.18 2009/03/20 22:12:27 mcguire + Support CFUserNotificationDisplayNotice in mDNSResponderHelper +Make the call to the helper a simpleroutine: don't wait for an unused return value + +Revision 1.17 2009/03/20 20:52:22 cheshire + Support CFUserNotificationDisplayNotice in mDNSResponderHelper + +Revision 1.16 2009/03/14 01:42:56 mcguire + BTMM: Fix issues with multiple .Mac accounts on the same machine + +Revision 1.15 2009/01/22 02:14:27 cheshire + Sleep Proxy: Set correct target MAC address, instead of all zeroes + +Revision 1.14 2009/01/14 01:38:42 mcguire + Write out DynamicStore per-interface SleepProxyServer info + +Revision 1.13 2009/01/14 01:28:17 mcguire +removed unused variable + +Revision 1.12 2008/11/11 00:46:37 cheshire +Don't just show ""; show the actual numeric error code too, so we can see what the unknown error was + +Revision 1.11 2008/11/04 23:54:09 cheshire +Added routine mDNSSetARP(), used to replace an SPS client's entry in our ARP cache with +a dummy one, so that IP traffic to the SPS client initiated by the SPS machine can be +captured by our BPF filters, and used as a trigger to wake the sleeping machine. + +Revision 1.10 2008/10/29 21:25:35 cheshire +Don't report kIOReturnNotReady errors + +Revision 1.9 2008/10/24 01:42:36 cheshire +Added mDNSPowerRequest helper routine to request a scheduled wakeup some time in the future + +Revision 1.8 2008/10/20 22:01:28 cheshire +Made new Mach simpleroutine "mDNSRequestBPF" + +Revision 1.7 2008/09/27 00:58:32 cheshire +Added mDNSRequestBPF definition + Revision 1.6 2007/12/10 23:23:48 cheshire Removed unnecessary log message ("mDNSKeychainGetSecrets failed 0 00000000" because mDNSKeychainGetSecrets was failing to return a valid array) @@ -39,6 +83,7 @@ Revision 1.1 2007/08/08 22:34:58 mcguire #include #include #include +#include #include #include "mDNSDebug.h" #include "helper.h" @@ -52,46 +97,44 @@ static const char *errorstring[] = }; #undef ERROR -static mach_port_t -getHelperPort(int retry) +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)) + 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 *mDNSHelperError(int err) { - const char *p = ""; + static 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) +// We don't bother reporting kIOReturnNotReady because that error code occurs in "normal" operation +// and doesn't indicate anything unexpected that needs to be investigated + +#define MACHRETRYLOOP_BEGIN(kr, retry, err, fin) \ + for (;;) \ + { +#define MACHRETRYLOOP_END(kr, retry, err, fin) \ + if (KERN_SUCCESS == (kr)) break; \ + else if (MACH_SEND_INVALID_DEST == (kr) && 0 == (retry)++) continue; \ + else \ + { \ + (err) = kmDNSHelperCommunicationFailed; \ + LogMsg("%s: Mach communication failed: %s", __func__, mach_error_string(kr)); \ + goto fin; \ + } \ + } \ + if (0 != (err) && kIOReturnNotReady != (err)) \ + { LogMsg("%s: %d 0x%X (%s)", __func__, (err), (err), mDNSHelperError(err)); goto fin; } + +void mDNSPreferencesSetName(int key, domainlabel *old, domainlabel *new) { kern_return_t kr = KERN_FAILURE; int retry = 0; @@ -102,15 +145,14 @@ mDNSPreferencesSetName(int key, domainlabel* old, domainlabel* new) if (new) ConvertDomainLabelToCString_unescaped(new, newname); MACHRETRYLOOP_BEGIN(kr, retry, err, fin); - kr = proxy_mDNSPreferencesSetName(getHelperPort(retry), key, oldname, newname, &err); + kr = proxy_mDNSPreferencesSetName(getHelperPort(retry), key, oldname, newname); MACHRETRYLOOP_END(kr, retry, err, fin); fin: - return err; + (void)err; } -int -mDNSDynamicStoreSetConfig(int key, CFPropertyListRef value) +void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropertyListRef value) { CFWriteStreamRef stream = NULL; CFDataRef bytes = NULL; @@ -118,24 +160,20 @@ mDNSDynamicStoreSetConfig(int key, CFPropertyListRef value) int retry = 0; int err = 0; - if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(NULL, - NULL))) + if (NULL == (stream = CFWriteStreamCreateWithAllocatedBuffers(NULL, NULL))) { err = kmDNSHelperCreationFailed; - LogMsg("%s: CFWriteStreamCreateWithAllocatedBuffers failed", - __func__); + LogMsg("%s: CFWriteStreamCreateWithAllocatedBuffers failed", __func__); goto fin; } CFWriteStreamOpen(stream); - if (0 == CFPropertyListWriteToStream(value, stream, - kCFPropertyListBinaryFormat_v1_0, NULL)) + if (0 == CFPropertyListWriteToStream(value, stream, kCFPropertyListBinaryFormat_v1_0, NULL)) { err = kmDNSHelperPListWriteFailed; LogMsg("%s: CFPropertyListWriteToStream failed", __func__); goto fin; } - if (NULL == (bytes = CFWriteStreamCopyProperty(stream, - kCFStreamPropertyDataWritten))) + if (NULL == (bytes = CFWriteStreamCopyProperty(stream, kCFStreamPropertyDataWritten))) { err = kmDNSHelperCreationFailed; LogMsg("%s: CFWriteStreamCopyProperty failed", __func__); @@ -145,24 +183,60 @@ mDNSDynamicStoreSetConfig(int key, CFPropertyListRef value) CFRelease(stream); stream = NULL; MACHRETRYLOOP_BEGIN(kr, retry, err, fin); - kr = proxy_mDNSDynamicStoreSetConfig(getHelperPort(retry), key, - (vm_offset_t)CFDataGetBytePtr(bytes), - CFDataGetLength(bytes), &err); + kr = proxy_mDNSDynamicStoreSetConfig(getHelperPort(retry), key, subkey ? subkey : "", (vm_offset_t)CFDataGetBytePtr(bytes), CFDataGetLength(bytes)); MACHRETRYLOOP_END(kr, retry, err, fin); fin: - if (NULL != stream) - { - CFWriteStreamClose(stream); - CFRelease(stream); - } - if (NULL != bytes) - CFRelease(bytes); + if (NULL != stream) { CFWriteStreamClose(stream); CFRelease(stream); } + if (NULL != bytes) CFRelease(bytes); + (void)err; + } + +void mDNSRequestBPF(void) + { + kern_return_t kr = KERN_FAILURE; + int retry = 0, err = 0; + MACHRETRYLOOP_BEGIN(kr, retry, err, fin); + kr = proxy_mDNSRequestBPF(getHelperPort(retry)); + MACHRETRYLOOP_END(kr, retry, err, fin); +fin: + (void)err; + } + +int mDNSPowerRequest(int key, int interval) + { + kern_return_t kr = KERN_FAILURE; + int retry = 0, err = 0; + MACHRETRYLOOP_BEGIN(kr, retry, err, fin); + kr = proxy_mDNSPowerRequest(getHelperPort(retry), key, interval, &err); + MACHRETRYLOOP_END(kr, retry, err, fin); +fin: + return err; + } + +int mDNSSetARP(int ifindex, const v4addr_t ip, const ethaddr_t eth) + { + kern_return_t kr = KERN_FAILURE; + int retry = 0, err = 0; + MACHRETRYLOOP_BEGIN(kr, retry, err, fin); + kr = proxy_mDNSSetARP(getHelperPort(retry), ifindex, (uint8_t*)ip, (uint8_t*)eth, &err); + MACHRETRYLOOP_END(kr, retry, err, fin); +fin: return err; } -int -mDNSKeychainGetSecrets(CFArrayRef *result) +void mDNSNotify(const char *title, const char *msg) // Both strings are UTF-8 text + { + kern_return_t kr = KERN_FAILURE; + int retry = 0, err = 0; + MACHRETRYLOOP_BEGIN(kr, retry, err, fin); + kr = proxy_mDNSNotify(getHelperPort(retry), title, msg); + MACHRETRYLOOP_END(kr, retry, err, fin); +fin: + (void)err; + } + +int mDNSKeychainGetSecrets(CFArrayRef *result) { CFPropertyListRef plist = NULL; CFDataRef bytes = NULL; @@ -170,23 +244,19 @@ mDNSKeychainGetSecrets(CFArrayRef *result) unsigned int numsecrets = 0; void *secrets = NULL; mach_msg_type_number_t secretsCnt = 0; - int retry = 0; - int err = 0; + int retry = 0, err = 0; MACHRETRYLOOP_BEGIN(kr, retry, err, fin); - kr = proxy_mDNSKeychainGetSecrets(getHelperPort(retry), - &numsecrets, (vm_offset_t *)&secrets, &secretsCnt, &err); + kr = proxy_mDNSKeychainGetSecrets(getHelperPort(retry), &numsecrets, (vm_offset_t *)&secrets, &secretsCnt, &err); MACHRETRYLOOP_END(kr, retry, err, fin); - if (NULL == (bytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, - secrets, secretsCnt, kCFAllocatorNull))) + 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))) + if (NULL == (plist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, bytes, kCFPropertyListImmutable, NULL))) { err = kmDNSHelperInvalidPList; LogMsg("%s: CFPropertyListCreateFromXMLData failed", __func__); @@ -203,65 +273,56 @@ mDNSKeychainGetSecrets(CFArrayRef *result) *result = (CFArrayRef)plist; fin: - if (NULL != bytes) - CFRelease(bytes); - if (NULL != secrets) - vm_deallocate(mach_task_self(), (vm_offset_t)secrets, - secretsCnt); + 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) +void mDNSAutoTunnelInterfaceUpDown(int updown, v6addr_t address) { kern_return_t kr = KERN_SUCCESS; - int retry = 0; - int err = 0; - + int retry = 0, err = 0; MACHRETRYLOOP_BEGIN(kr, retry, err, fin); - kr = proxy_mDNSAutoTunnelInterfaceUpDown(getHelperPort(retry), - updown, address, &err); + kr = proxy_mDNSAutoTunnelInterfaceUpDown(getHelperPort(retry), updown, address); MACHRETRYLOOP_END(kr, retry, err, fin); - fin: - return err; + (void)err; } -int -mDNSConfigureServer(int updown, const char *keydata) +void mDNSConfigureServer(int updown, const domainname *const fqdn) { kern_return_t kr = KERN_SUCCESS; - int retry = 0; - int err = 0; - + int retry = 0, err = 0; + char fqdnStr[MAX_ESCAPED_DOMAIN_NAME] = { 0 }; + if (fqdn && ConvertDomainNameToCString(fqdn, fqdnStr)) + { + // remove the trailing dot, as that is not used in the keychain entry racoon will lookup + mDNSu32 fqdnEnd = mDNSPlatformStrLen(fqdnStr); + if (fqdnEnd) fqdnStr[fqdnEnd - 1] = 0; + } MACHRETRYLOOP_BEGIN(kr, retry, err, fin); - kr = proxy_mDNSConfigureServer(getHelperPort(retry), updown, keydata, &err); + kr = proxy_mDNSConfigureServer(getHelperPort(retry), updown, fqdnStr); MACHRETRYLOOP_END(kr, retry, err, fin); - fin: - return err; + (void)err; } -int -mDNSAutoTunnelSetKeys(int replacedelete, v6addr_t local_inner, +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) + v4addr_t remote_outer, short remote_port, const domainname *const fqdn) { kern_return_t kr = KERN_SUCCESS; - const char *p = NULL; - int retry = 0; - int err = 0; - - if (kmDNSAutoTunnelSetKeysReplace == replacedelete) - p = keydata; - else - p = ""; + int retry = 0, err = 0; + char fqdnStr[MAX_ESCAPED_DOMAIN_NAME] = { 0 }; + if (fqdn && ConvertDomainNameToCString(fqdn, fqdnStr)) + { + // remove the trailing dot, as that is not used in the keychain entry racoon will lookup + mDNSu32 fqdnEnd = mDNSPlatformStrLen(fqdnStr); + if (fqdnEnd) fqdnStr[fqdnEnd - 1] = 0; + } 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); + kr = proxy_mDNSAutoTunnelSetKeys(getHelperPort(retry), replacedelete, local_inner, local_outer, local_port, remote_inner, remote_outer, remote_port, fqdnStr, &err); MACHRETRYLOOP_END(kr, retry, err, fin); - fin: return err; } diff --git a/mDNSMacOSX/helper.c b/mDNSMacOSX/helper.c index d3ad6b1..720d18d 100644 --- a/mDNSMacOSX/helper.c +++ b/mDNSMacOSX/helper.c @@ -17,6 +17,145 @@ Change History (most recent first): $Log: helper.c,v $ +Revision 1.66 2009/04/20 20:40:14 cheshire + uDNS: Running location cycling caused configd and mDNSResponder to deadlock +Changed mDNSPreferencesSetName (and similar) routines from MIG "routine" to MIG "simpleroutine" +so we don't deadlock waiting for a result that we're just going to ignore anyway + +Revision 1.65 2009/03/20 22:12:28 mcguire + Support CFUserNotificationDisplayNotice in mDNSResponderHelper +Make the call to the helper a simpleroutine: don't wait for an unused return value + +Revision 1.64 2009/03/20 21:52:39 cheshire + Support CFUserNotificationDisplayNotice in mDNSResponderHelper +Need to CFRelease strings in do_mDNSNotify + +Revision 1.63 2009/03/20 21:21:15 cheshire + Support CFUserNotificationDisplayNotice in mDNSResponderHelper +Need to set error code correctly in do_mDNSNotify + +Revision 1.62 2009/03/20 20:52:22 cheshire + Support CFUserNotificationDisplayNotice in mDNSResponderHelper + +Revision 1.61 2009/03/14 01:42:56 mcguire + BTMM: Fix issues with multiple .Mac accounts on the same machine + +Revision 1.60 2009/02/18 02:09:10 cheshire + Sleep Proxy: PF_ROUTE command to set ARP entry returns errno 17 (EEXIST) +Also need to set rtmsg.hdr.rtm_index + +Revision 1.59 2009/02/17 23:33:45 cheshire + Sleep Proxy: PF_ROUTE command to set ARP entry returns errno 17 (EEXIST) + +Revision 1.58 2009/02/04 22:23:04 cheshire +Simplified do_mDNSPowerRequest -- +code was checking for CFAbsoluteTimeGetCurrent() returning NULL, which makes no sense + +Revision 1.57 2009/01/22 02:14:27 cheshire + Sleep Proxy: Set correct target MAC address, instead of all zeroes + +Revision 1.56 2009/01/20 21:03:22 cheshire +Improved debugging messages + +Revision 1.55 2009/01/20 02:37:26 mcguire +revert previous erroneous commit + +Revision 1.54 2009/01/20 02:35:15 mcguire +mDNSMacOSX/mDNSMacOSX.c + +Revision 1.53 2009/01/14 01:38:42 mcguire + Write out DynamicStore per-interface SleepProxyServer info + +Revision 1.52 2009/01/13 05:31:34 mkrochma + Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy + +Revision 1.51 2009/01/12 22:26:12 mkrochma +Change DynamicStore location from BonjourSleepProxy/DiscoveredServers to SleepProxyServers + +Revision 1.50 2008/12/15 18:40:41 mcguire + Socket leak in helper's doTunnelPolicy + +Revision 1.49 2008/12/12 00:37:42 mcguire + BTMM outbound fails if /var/run/racoon doesn't exist + +Revision 1.48 2008/12/05 02:35:24 mcguire + Write to the DynamicStore when a Sleep Proxy server is available on the network + +Revision 1.47 2008/11/21 02:28:55 mcguire + send racoon a SIGUSR1 instead of SIGHUP + +Revision 1.46 2008/11/11 02:09:42 cheshire +Removed some unnecessary log messages + +Revision 1.45 2008/11/06 23:35:38 cheshire +Refinements to the do_mDNSSetARP() routine + +Revision 1.44 2008/11/05 18:41:14 cheshire +Log errors from read() call in do_mDNSSetARP() + +Revision 1.43 2008/11/04 23:54:09 cheshire +Added routine mDNSSetARP(), used to replace an SPS client's entry in our ARP cache with +a dummy one, so that IP traffic to the SPS client initiated by the SPS machine can be +captured by our BPF filters, and used as a trigger to wake the sleeping machine. + +Revision 1.42 2008/10/31 23:35:31 cheshire +When scheduling new power event make sure all old events are deleted; +mDNSPowerRequest(-1,-1); just clears old events without scheduling a new one + +Revision 1.41 2008/10/31 18:41:55 cheshire +Do update_idle_timer() before returning from do_mDNSRequestBPF() + +Revision 1.40 2008/10/30 01:05:27 cheshire +mDNSPowerRequest(0, 0) means "sleep now" + +Revision 1.39 2008/10/29 21:26:50 cheshire +Only log IOPMSchedulePowerEvent calls when there's an error + +Revision 1.38 2008/10/24 01:42:36 cheshire +Added mDNSPowerRequest helper routine to request a scheduled wakeup some time in the future + +Revision 1.37 2008/10/24 00:17:22 mcguire +Add compatibility for older racoon behavior + +Revision 1.36 2008/10/22 17:22:31 cheshire +Remove SO_NOSIGPIPE bug workaround + +Revision 1.35 2008/10/20 22:01:28 cheshire +Made new Mach simpleroutine "mDNSRequestBPF" + +Revision 1.34 2008/10/02 23:50:07 mcguire + shutdown time issues +improve log messages when SCDynamicStoreCreate() fails + +Revision 1.33 2008/09/30 01:00:45 cheshire +Added workaround to avoid SO_NOSIGPIPE bug + +Revision 1.32 2008/09/27 01:11:46 cheshire +Added handler to respond to kmDNSSendBPF message + +Revision 1.31 2008/09/08 17:42:40 mcguire + change location of racoon files +cleanup, handle stat failure cases, reduce log messages + +Revision 1.30 2008/09/05 21:51:26 mcguire + BTMM: Need to launch racoon by opening VPN control socket + +Revision 1.29 2008/09/05 18:26:53 mcguire + BTMM: Need to launch racoon by opening VPN control socket + +Revision 1.28 2008/09/04 22:49:28 mcguire + change location of racoon files + +Revision 1.27 2008/08/28 23:11:12 mcguire + handle SIGTERM in mDNSResponderHelper + +Revision 1.26 2008/08/19 00:35:02 mcguire + handle SIGTERM in mDNSResponderHelper + +Revision 1.25 2008/08/13 23:04:06 mcguire + handle SIGTERM in mDNSResponderHelper +Preparation: rename message function, as it will no longer be called only on idle exit + Revision 1.24 2008/01/30 19:01:51 mcguire Crash in mDNSResponderHelper @@ -97,7 +236,10 @@ Revision 1.1 2007/08/08 22:34:58 mcguire #include #include #include +#include +#include #include +#include #include #include #include @@ -113,10 +255,13 @@ Revision 1.1 2007/08/08 22:34:58 mcguire #include #include #include +#include #include #include #include #include +#include + #include "mDNSEmbeddedAPI.h" #include "dns_sd.h" #include "dnssd_ipc.h" @@ -126,11 +271,19 @@ Revision 1.1 2007/08/08 22:34:58 mcguire #include "helper-server.h" #include "ipsec_options.h" +#ifndef RTF_IFSCOPE +#define RTF_IFSCOPE 0x1000000 +#endif + #if TARGET_OS_EMBEDDED #define NO_CFUSERNOTIFICATION 1 #define NO_SECURITYFRAMEWORK 1 #endif +// Embed the client stub code here, so we can access private functions like ConnectToServer, create_hdr, deliver_request +#include "../mDNSShared/dnssd_ipc.c" +#include "../mDNSShared/dnssd_clientstub.c" + typedef struct sadb_x_policy *ipsec_policy_t; uid_t mDNSResponderUID; @@ -166,93 +319,235 @@ authorized(audit_token_t *token) return ok; } -#ifndef MDNS_NO_IPSEC -static void -closefds(int from) +kern_return_t +do_mDNSExit(__unused mach_port_t port, audit_token_t token) { - int fd = 0; - struct dirent entry, *entryp = NULL; - DIR *dirp = opendir("/dev/fd"); + debug("entry"); + if (!authorized(&token)) + goto fin; + helplog(ASL_LEVEL_INFO, "exit"); + exit(0); - if (dirp == NULL) +fin: + debug("fin"); + return KERN_SUCCESS; + } + +kern_return_t do_mDNSRequestBPF(__unused mach_port_t port, audit_token_t token) + { + if (!authorized(&token)) return KERN_SUCCESS; + DNSServiceRef ref; + DNSServiceErrorType err = ConnectToServer(&ref, 0, send_bpf, NULL, NULL, NULL); + if (err) { helplog(ASL_LEVEL_ERR, "do_mDNSRequestBPF: ConnectToServer %d", err); return err; } + + char *ptr; + size_t len = sizeof(DNSServiceFlags); + ipc_msg_hdr *hdr = create_hdr(send_bpf, &len, &ptr, 0, ref); + if (!hdr) { DNSServiceRefDeallocate(ref); return kDNSServiceErr_NoMemory; } + put_flags(0, &ptr); + deliver_request(hdr, ref); // Will free hdr for us + DNSServiceRefDeallocate(ref); + update_idle_timer(); + return KERN_SUCCESS; + } + +kern_return_t do_mDNSPowerRequest(__unused mach_port_t port, int key, int interval, int *err, audit_token_t token) + { + *err = -1; + if (!authorized(&token)) { *err = kmDNSHelperNotAuthorized; goto fin; } + + CFArrayRef events = IOPMCopyScheduledPowerEvents(); + if (events) { - /* fall back to the erroneous getdtablesize method */ - for (fd = from; fd < getdtablesize(); ++fd) - close(fd); - return; + int i; + CFIndex count = CFArrayGetCount(events); + for (i=0; id_name); - if (fd >= from && fd != dirfd(dirp)) - close(fd); + IOReturn r = IOPMSleepSystem(IOPMFindPowerManagement(MACH_PORT_NULL)); + if (r) { usleep(100000); helplog(ASL_LEVEL_ERR, "IOPMSleepSystem %d", r); } + *err = r; } - closedir(dirp); + else if (key > 0) + { + CFDateRef w = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent() + interval); + if (w) + { + IOReturn r = IOPMSchedulePowerEvent(w, CFSTR("mDNSResponderHelper"), key ? CFSTR(kIOPMAutoWake) : CFSTR(kIOPMAutoSleep)); + if (r) { usleep(100000); helplog(ASL_LEVEL_ERR, "IOPMSchedulePowerEvent(%d) %d %x", interval, r, r); } + *err = r; + CFRelease(w); + } + } +fin: + update_idle_timer(); + return KERN_SUCCESS; } -#endif -kern_return_t -do_mDNSIdleExit(__unused mach_port_t port, audit_token_t token) +kern_return_t do_mDNSSetARP(__unused mach_port_t port, int ifindex, v4addr_t v4, ethaddr_t eth, int *err, audit_token_t token) { - debug("entry"); - if (!authorized(&token)) - goto fin; - helplog(ASL_LEVEL_INFO, "Idle exit"); - exit(0); + //helplog(ASL_LEVEL_ERR, "do_mDNSSetARP %d %d.%d.%d.%d %02X:%02X:%02X:%02X:%02X:%02X", + // ifindex, v4[0], v4[1], v4[2], v4[3], eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]); + + *err = -1; + if (!authorized(&token)) { *err = kmDNSHelperNotAuthorized; goto fin; } + + static int s = -1, seq = 0; + if (s < 0) + { + s = socket(PF_ROUTE, SOCK_RAW, 0); + if (s < 0) helplog(ASL_LEVEL_ERR, "do_mDNSSetARP: socket(PF_ROUTE, SOCK_RAW, 0) failed %d (%s)", errno, strerror(errno)); + } + + if (s >= 0) + { + struct timeval tv; + gettimeofday(&tv, 0); + + struct { struct rt_msghdr hdr; struct sockaddr_inarp dst; struct sockaddr_dl sdl; } rtmsg; + memset(&rtmsg, 0, sizeof(rtmsg)); + + rtmsg.hdr.rtm_msglen = sizeof(rtmsg); + rtmsg.hdr.rtm_version = RTM_VERSION; + rtmsg.hdr.rtm_type = RTM_ADD; + rtmsg.hdr.rtm_index = ifindex; + rtmsg.hdr.rtm_flags = RTF_HOST | RTF_STATIC | RTF_IFSCOPE; + rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY; + rtmsg.hdr.rtm_pid = 0; + rtmsg.hdr.rtm_seq = seq++; + rtmsg.hdr.rtm_errno = 0; + rtmsg.hdr.rtm_use = 0; + rtmsg.hdr.rtm_inits = RTV_EXPIRE; + rtmsg.hdr.rtm_rmx.rmx_expire = tv.tv_sec + 30; + + rtmsg.dst.sin_len = sizeof(struct sockaddr_inarp); + rtmsg.dst.sin_family = AF_INET; + rtmsg.dst.sin_port = 0; + rtmsg.dst.sin_addr.s_addr = *(in_addr_t*)v4; + rtmsg.dst.sin_srcaddr.s_addr = 0; + rtmsg.dst.sin_tos = 0; + rtmsg.dst.sin_other = 0; + + rtmsg.sdl.sdl_len = sizeof(struct sockaddr_dl); + rtmsg.sdl.sdl_family = AF_LINK; + rtmsg.sdl.sdl_index = ifindex; + rtmsg.sdl.sdl_type = IFT_ETHER; + rtmsg.sdl.sdl_nlen = 0; + rtmsg.sdl.sdl_alen = ETHER_ADDR_LEN; + rtmsg.sdl.sdl_slen = 0; + + // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h) + memcpy(rtmsg.sdl.sdl_data, eth, sizeof(ethaddr_t)); + + int len = write(s, (char *)&rtmsg, sizeof(rtmsg)); + if (len < 0) + helplog(ASL_LEVEL_ERR, "do_mDNSSetARP: write(%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s)", + sizeof(rtmsg), ifindex, v4[0], v4[1], v4[2], v4[3], rtmsg.hdr.rtm_seq, len, errno, strerror(errno)); + len = read(s, (char *)&rtmsg, sizeof(rtmsg)); + if (len < 0) + helplog(ASL_LEVEL_ERR, "do_mDNSSetARP: read (%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s)", + sizeof(rtmsg), ifindex, v4[0], v4[1], v4[2], v4[3], rtmsg.hdr.rtm_seq, len, errno, strerror(errno)); + + *err = 0; + } fin: - debug("fin"); + update_idle_timer(); + return KERN_SUCCESS; + } + +kern_return_t do_mDNSNotify(__unused mach_port_t port, const char *title, const char *msg, audit_token_t token) + { + if (!authorized(&token)) return KERN_SUCCESS; + +#ifndef NO_CFUSERNOTIFICATION + static const char footer[] = "(Note: This message only appears on machines with 17.x.x.x IP addresses — i.e. at Apple — not on customer machines.)"; + CFStringRef alertHeader = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8); + CFStringRef alertBody = CFStringCreateWithCString(NULL, msg, kCFStringEncodingUTF8); + CFStringRef alertFooter = CFStringCreateWithCString(NULL, footer, kCFStringEncodingUTF8); + CFStringRef alertMessage = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@\r\r%@"), alertBody, alertFooter); + CFRelease(alertBody); + CFRelease(alertFooter); + int err = CFUserNotificationDisplayNotice(0.0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, alertHeader, alertMessage, NULL); + if (err) helplog(ASL_LEVEL_ERR, "CFUserNotificationDisplayNotice returned %d", err); + CFRelease(alertHeader); + CFRelease(alertMessage); +#endif /* NO_CFUSERNOTIFICATION */ + + update_idle_timer(); 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, + const char* subkey, vm_offset_t value, mach_msg_type_number_t valueCnt, audit_token_t token) { CFStringRef sckey = NULL; + Boolean release_sckey = FALSE; CFDataRef bytes = NULL; CFPropertyListRef plist = NULL; SCDynamicStoreRef store = NULL; debug("entry"); - *err = 0; - if (!authorized(&token)) - { - *err = kmDNSHelperNotAuthorized; - goto fin; - } + if (!authorized(&token)) 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; + { + case kmDNSMulticastConfig: + sckey = CFSTR("State:/Network/" kDNSServiceCompMulticastDNS); + break; + case kmDNSDynamicConfig: + sckey = CFSTR("State:/Network/DynamicDNS"); + break; + case kmDNSPrivateConfig: + sckey = CFSTR("State:/Network/" kDNSServiceCompPrivateDNS); + break; + case kmDNSBackToMyMacConfig: + sckey = CFSTR("State:/Network/BackToMyMac"); + break; + case kmDNSSleepProxyServersState: + { + CFMutableStringRef tmp = CFStringCreateMutable(kCFAllocatorDefault, 0); + CFStringAppend(tmp, CFSTR("State:/Network/Interface/")); + CFStringAppendCString(tmp, subkey, kCFStringEncodingUTF8); + CFStringAppend(tmp, CFSTR("/SleepProxyServers")); + sckey = CFStringCreateCopy(kCFAllocatorDefault, tmp); + release_sckey = TRUE; + CFRelease(tmp); + break; + } + default: + debug("unrecognized key %d", key); + 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); @@ -260,23 +555,21 @@ do_mDNSDynamicStoreSetConfig(__unused mach_port_t port, int key, if (NULL == (store = SCDynamicStoreCreate(NULL, CFSTR(kmDNSHelperServiceName), NULL, NULL))) { - debug("SCDynamicStoreCreate failed"); - *err = kmDNSHelperDynamicStoreFailed; + debug("SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); 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); + if (release_sckey && sckey) + CFRelease(sckey); vm_deallocate(mach_task_self(), value, valueCnt); update_idle_timer(); return KERN_SUCCESS; @@ -475,7 +768,7 @@ static void update_notification(void) } kern_return_t -do_mDNSPreferencesSetName(__unused mach_port_t port, int key, const char* old, const char* new, int *err, audit_token_t token) +do_mDNSPreferencesSetName(__unused mach_port_t port, int key, const char* old, const char* new, audit_token_t token) { SCPreferencesRef session = NULL; Boolean ok = FALSE; @@ -486,12 +779,8 @@ do_mDNSPreferencesSetName(__unused mach_port_t port, int key, const char* old, c 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; - } + if (!authorized(&token)) goto fin; + switch ((enum mDNSPreferencesSetNameKey)key) { case kmDNSComputerName: @@ -504,7 +793,6 @@ do_mDNSPreferencesSetName(__unused mach_port_t port, int key, const char* old, c break; default: debug("unrecognized key: %d", key); - *err = kmDNSHelperInvalidNameKey; goto fin; } @@ -556,13 +844,11 @@ do_mDNSPreferencesSetName(__unused mach_port_t port, int key, const char* old, c 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; @@ -594,15 +880,11 @@ do_mDNSPreferencesSetName(__unused mach_port_t port, int key, const char* old, c !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) @@ -925,7 +1207,7 @@ aliasTunnelAddress(v6addr_t address) err = kmDNSHelperDatagramSocketCreationFailed; goto fin; } - bzero(&ifra_in6, sizeof(ifra_in6)); + memset(&ifra_in6, 0, sizeof(ifra_in6)); strlcpy(ifra_in6.ifra_name, kTunnelAddressInterface, sizeof(ifra_in6.ifra_name)); ifra_in6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; @@ -975,7 +1257,7 @@ unaliasTunnelAddress(v6addr_t address) err = kmDNSHelperDatagramSocketCreationFailed; goto fin; } - bzero(&ifr, sizeof(ifr)); + memset(&ifr, 0, 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); @@ -1005,27 +1287,22 @@ fin: int do_mDNSAutoTunnelInterfaceUpDown(__unused mach_port_t port, int updown, - v6addr_t address, int *err, audit_token_t token) + v6addr_t address, audit_token_t token) { #ifndef MDNS_NO_IPSEC debug("entry"); - *err = 0; - if (!authorized(&token)) - { - *err = kmDNSHelperNotAuthorized; - goto fin; - } + if (!authorized(&token)) goto fin; + switch ((enum mDNSUpDown)updown) - { - case kmDNSUp: - *err = aliasTunnelAddress(address); - break; - case kmDNSDown: - *err = unaliasTunnelAddress(address); - break; - default: - *err = kmDNSHelperInvalidInterfaceState; - goto fin; + { + case kmDNSUp: + aliasTunnelAddress(address); + break; + case kmDNSDown: + unaliasTunnelAddress(address); + break; + default: + goto fin; } debug("succeeded"); @@ -1039,15 +1316,85 @@ fin: } #ifndef MDNS_NO_IPSEC -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 g_racoon_config_dir[] = "/var/run/racoon/"; +static const char g_racoon_config_dir_old[] = "/etc/racoon/remote/"; + +CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void); +CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey; + +// Major version 6 is 10.2.x (Jaguar) +// Major version 7 is 10.3.x (Panther) +// Major version 8 is 10.4.x (Tiger) +// Major version 9 is 10.5.x (Leopard) +// Major version 10 is 10.6.x (SnowLeopard) +static int MacOSXSystemBuildNumber(char* letter_out, int* minor_out) + { + int major = 0, minor = 0; + char letter = 0, buildver[256]=""; + CFDictionaryRef vers = _CFCopySystemVersionDictionary(); + if (vers) + { + CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey); + if (cfbuildver) CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8); + sscanf(buildver, "%d%c%d", &major, &letter, &minor); + CFRelease(vers); + } + else + helplog(ASL_LEVEL_NOTICE, "_CFCopySystemVersionDictionary failed"); + + if (!major) { major=10; letter = 'A'; minor = 190; helplog(ASL_LEVEL_NOTICE, "Note: No Major Build Version number found; assuming 10A190"); } + if (letter_out) *letter_out = letter; + if (minor_out) *minor_out = minor; + return(major); + } + +static int g_oldRacoon = -1; +static int g_racoonSignal = SIGUSR1; + +static void DetermineRacoonVersion() + { + if (g_oldRacoon == -1) + { + char letter = 0; + int minor = 0; + g_oldRacoon = (MacOSXSystemBuildNumber(&letter, &minor) < 10); + if (g_oldRacoon || (letter == 'A' && minor < 218)) g_racoonSignal = SIGHUP; + debug("%s, signal=%d", g_oldRacoon?"old":"new", g_racoonSignal); + } + } + +static int UseOldRacoon() + { + DetermineRacoonVersion(); + return g_oldRacoon; + } + +static int RacoonSignal() + { + DetermineRacoonVersion(); + return g_racoonSignal; + } + +static const char* GetRacoonConfigDir() + { + return UseOldRacoon() ? g_racoon_config_dir_old : g_racoon_config_dir; + } + +static const char* GetOldRacoonConfigDir() + { + return UseOldRacoon() ? NULL : g_racoon_config_dir_old; + } + +static const char racoon_config_file[] = "anonymous.conf"; +static const char racoon_config_file_orig[] = "anonymous.conf.orig"; static const char configHeader[] = "# BackToMyMac\n"; -static int IsFamiliarRacoonConfiguration() +static int IsFamiliarRacoonConfiguration(const char* racoon_config_path) { int fd = open(racoon_config_path, O_RDONLY); - debug("entry"); + debug("entry %s", racoon_config_path); if (0 > fd) { helplog(ASL_LEVEL_NOTICE, "open \"%s\" failed: %s", racoon_config_path, strerror(errno)); @@ -1064,25 +1411,134 @@ static int IsFamiliarRacoonConfiguration() } static void -revertAnonymousRacoonConfiguration() +revertAnonymousRacoonConfiguration(const char* dir) { - debug("entry"); - if (!IsFamiliarRacoonConfiguration()) + if (!dir) return; + + debug("entry %s", dir); + + char racoon_config_path[64]; + strlcpy(racoon_config_path, dir, sizeof(racoon_config_path)); + strlcat(racoon_config_path, racoon_config_file, sizeof(racoon_config_path)); + + struct stat s; + int ret = stat(racoon_config_path, &s); + debug("stat(%s): %d errno=%d", racoon_config_path, ret, errno); + if (ret == 0) { - helplog(ASL_LEVEL_NOTICE, "\"%s\" does not look familiar, leaving in place", racoon_config_path); + if (IsFamiliarRacoonConfiguration(racoon_config_path)) + { + helplog(ASL_LEVEL_INFO, "\"%s\" looks familiar, unlinking", racoon_config_path); + unlink(racoon_config_path); + } + else + { + helplog(ASL_LEVEL_NOTICE, "\"%s\" does not look familiar, leaving in place", racoon_config_path); + return; + } + } + else if (errno != ENOENT) + { + helplog(ASL_LEVEL_NOTICE, "stat failed for \"%s\", leaving in place: %s", racoon_config_path, strerror(errno)); return; } - if (0 > rename(racoon_config_path_orig, racoon_config_path)) + char racoon_config_path_orig[64]; + strlcpy(racoon_config_path_orig, dir, sizeof(racoon_config_path_orig)); + strlcat(racoon_config_path_orig, racoon_config_file_orig, sizeof(racoon_config_path_orig)); + + ret = stat(racoon_config_path_orig, &s); + debug("stat(%s): %d errno=%d", racoon_config_path_orig, ret, errno); + if (ret == 0) { - 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); + if (0 > rename(racoon_config_path_orig, racoon_config_path)) + helplog(ASL_LEVEL_NOTICE, "rename \"%s\" \"%s\" failed: %s", racoon_config_path_orig, racoon_config_path, strerror(errno)); + else + debug("reverted \"%s\" to \"%s\"", racoon_config_path_orig, racoon_config_path); + } + else if (errno != ENOENT) + { + helplog(ASL_LEVEL_NOTICE, "stat failed for \"%s\", leaving in place: %s", racoon_config_path_orig, strerror(errno)); + return; + } + } + +static void +moveAsideAnonymousRacoonConfiguration(const char* dir) + { + if (!dir) return; + + debug("entry %s", dir); + + char racoon_config_path[64]; + strlcpy(racoon_config_path, dir, sizeof(racoon_config_path)); + strlcat(racoon_config_path, racoon_config_file, sizeof(racoon_config_path)); + + struct stat s; + int ret = stat(racoon_config_path, &s); + if (ret == 0) + { + if (IsFamiliarRacoonConfiguration(racoon_config_path)) + { + helplog(ASL_LEVEL_INFO, "\"%s\" looks familiar, unlinking", racoon_config_path); + unlink(racoon_config_path); + } + else + { + char racoon_config_path_orig[64]; + strlcpy(racoon_config_path_orig, dir, sizeof(racoon_config_path_orig)); + strlcat(racoon_config_path_orig, racoon_config_file_orig, sizeof(racoon_config_path_orig)); + if (0 > rename(racoon_config_path, racoon_config_path_orig)) // If we didn't write it, move it to the side so it can be reverted later + helplog(ASL_LEVEL_NOTICE, "rename \"%s\" to \"%s\" failed: %s", racoon_config_path, racoon_config_path_orig, strerror(errno)); + else + debug("successfully renamed \"%s\" to \"%s\"", racoon_config_path, racoon_config_path_orig); + } + } + else if (errno != ENOENT) + { + helplog(ASL_LEVEL_NOTICE, "stat failed for \"%s\", leaving in place: %s", racoon_config_path, strerror(errno)); + return; } } static int -createAnonymousRacoonConfiguration(const char *keydata) +ensureExistenceOfRacoonConfigDir(const char* const racoon_config_dir) + { + struct stat s; + int ret = stat(racoon_config_dir, &s); + if (ret != 0) + { + if (errno != ENOENT) + { + helplog(ASL_LEVEL_ERR, "stat of \"%s\" failed (%d): %s", + racoon_config_dir, ret, strerror(errno)); + return -1; + } + else + { + ret = mkdir(racoon_config_dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); + if (ret != 0) + { + helplog(ASL_LEVEL_ERR, "mkdir \"%s\" failed: %s", + racoon_config_dir, strerror(errno)); + return -1; + } + else + helplog(ASL_LEVEL_INFO, "created directory \"%s\"", racoon_config_dir); + } + } + else if (!(s.st_mode & S_IFDIR)) + { + helplog(ASL_LEVEL_ERR, "\"%s\" is not a directory!", + racoon_config_dir); + return -1; + } + + return 0; + } + +static int +createAnonymousRacoonConfiguration(const char *fqdn) { static const char config1[] = "remote anonymous {\n" @@ -1091,7 +1547,7 @@ createAnonymousRacoonConfiguration(const char *keydata) " situation identity_only;\n" " verify_identifier off;\n" " generate_policy on;\n" - " shared_secret use \""; + " shared_secret keychain_by_id \"dns:"; static const char config2[] = "\";\n" " nonce_size 16;\n" @@ -1115,11 +1571,21 @@ createAnonymousRacoonConfiguration(const char *keydata) " 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); - + char tmp_config_path[64]; + char racoon_config_path[64]; + const char* const racoon_config_dir = GetRacoonConfigDir(); + const char* const racoon_config_dir_old = GetOldRacoonConfigDir(); + int fd = -1; + debug("entry"); + + if (0 > ensureExistenceOfRacoonConfigDir(racoon_config_dir)) + return -1; + + strlcpy(tmp_config_path, racoon_config_dir, sizeof(tmp_config_path)); + strlcat(tmp_config_path, "tmp.XXXXXX", sizeof(tmp_config_path)); + + fd = mkstemp(tmp_config_path); if (0 > fd) { @@ -1129,23 +1595,23 @@ createAnonymousRacoonConfiguration(const char *keydata) } write(fd, configHeader, sizeof(configHeader)-1); write(fd, config1, sizeof(config1)-1); - write(fd, keydata, strlen(keydata)); + write(fd, fqdn, strlen(fqdn)); 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); + strlcpy(racoon_config_path, racoon_config_dir, sizeof(racoon_config_path)); + strlcat(racoon_config_path, racoon_config_file, sizeof(racoon_config_path)); + + moveAsideAnonymousRacoonConfiguration(racoon_config_dir_old); + moveAsideAnonymousRacoonConfiguration(racoon_config_dir); if (0 > rename(tmp_config_path, racoon_config_path)) { unlink(tmp_config_path); helplog(ASL_LEVEL_ERR, "rename \"%s\" \"%s\" failed: %s", tmp_config_path, racoon_config_path, strerror(errno)); - revertAnonymousRacoonConfiguration(); + revertAnonymousRacoonConfiguration(racoon_config_dir_old); + revertAnonymousRacoonConfiguration(racoon_config_dir); return -1; } @@ -1190,17 +1656,40 @@ notifyRacoon(void) debug("refusing to kill PID %lu", m); return kmDNSHelperRacoonNotificationFailed; } - if (0 != kill(m, SIGHUP)) + if (0 != kill(m, RacoonSignal())) { debug("Could not signal racoon (%lu): %s", m, strerror(errno)); return kmDNSHelperRacoonNotificationFailed; } - debug("Sent SIGHUP to racoon (%lu)", m); + debug("Sent racoon (%lu) signal %d", m, RacoonSignal()); return 0; } +static void +closefds(int from) + { + int fd = 0; + struct dirent entry, *entryp = NULL; + DIR *dirp = opendir("/dev/fd"); + + if (dirp == NULL) + { + /* fall back to the erroneous getdtablesize method */ + for (fd = from; fd < getdtablesize(); ++fd) + close(fd); + return; + } + while (0 == readdir_r(dirp, &entry, &entryp) && NULL != entryp) + { + fd = atoi(entryp->d_name); + if (fd >= from && fd != dirfd(dirp)) + close(fd); + } + closedir(dirp); + } + static int -startRacoon(void) +startRacoonOld(void) { debug("entry"); char * const racoon_args[] = { "/usr/sbin/racoon", "-e", NULL }; @@ -1256,53 +1745,147 @@ startRacoon(void) return 0; } +// constant and structure for the racoon control socket +#define VPNCTL_CMD_PING 0x0004 +typedef struct vpnctl_hdr_struct + { + u_int16_t msg_type; + u_int16_t flags; + u_int32_t cookie; + u_int32_t reserved; + u_int16_t result; + u_int16_t len; + } vpnctl_hdr; + +static int +startRacoon(void) + { + debug("entry"); + int fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (0 > fd) + { + helplog(ASL_LEVEL_ERR, "Could not create endpoint for racoon control socket: %d %s", + errno, strerror(errno)); + return kmDNSHelperRacoonStartFailed; + } + + struct sockaddr_un saddr; + memset(&saddr, 0, sizeof(saddr)); + saddr.sun_family = AF_UNIX; + saddr.sun_len = sizeof(saddr); + static const char racoon_control_sock_path[] = "/var/run/vpncontrol.sock"; + strcpy(saddr.sun_path, racoon_control_sock_path); + int result = connect(fd, (struct sockaddr*) &saddr, saddr.sun_len); + if (0 > result) + { + helplog(ASL_LEVEL_ERR, "Could not connect racoon control socket %s: %d %s", + racoon_control_sock_path, errno, strerror(errno)); + return kmDNSHelperRacoonStartFailed; + } + + u_int32_t btmm_cookie = 0x4d4d5442; + vpnctl_hdr h = { VPNCTL_CMD_PING, 0, btmm_cookie, 0, 0, 0 }; + size_t bytes = 0; + ssize_t ret = 0; + + while (bytes < sizeof(vpnctl_hdr)) + { + ret = write(fd, ((unsigned char*)&h)+bytes, sizeof(vpnctl_hdr) - bytes); + if (ret == -1) + { + helplog(ASL_LEVEL_ERR, "Could not write to racoon control socket: %d %s", + errno, strerror(errno)); + return kmDNSHelperRacoonStartFailed; + } + bytes += ret; + } + + int nfds = fd + 1; + fd_set fds; + int counter = 0; + struct timeval tv; + bytes = 0; + h.cookie = 0; + + while (counter < 100) + { + FD_ZERO(&fds); + FD_SET(fd, &fds); + tv = (struct timeval){ 0, 10000 }; // 10 milliseconds * 100 iterations = 1 second max wait time + + result = select(nfds, &fds, (fd_set*)NULL, (fd_set*)NULL, &tv); + if (result > 0) + { + if (FD_ISSET(fd, &fds)) + { + ret = read(fd, ((unsigned char*)&h)+bytes, sizeof(vpnctl_hdr) - bytes); + + if (ret == -1) + { + helplog(ASL_LEVEL_ERR, "Could not read from racoon control socket: %d %s", + strerror(errno)); + break; + } + bytes += ret; + if (bytes >= sizeof(vpnctl_hdr)) break; + } + else + { + debug("select returned but fd_isset not on expected fd\n"); + } + } + else if (result < 0) + { + debug("select returned %d errno %d %s\n", result, errno, strerror(errno)); + if (errno != EINTR) break; + } + } + + close(fd); + + if (bytes < sizeof(vpnctl_hdr) || h.cookie != btmm_cookie) return kmDNSHelperRacoonStartFailed; + + debug("racoon started"); + return 0; + } + static int kickRacoon(void) { if ( 0 == notifyRacoon() ) return 0; - return startRacoon(); + return UseOldRacoon() ? startRacoonOld() : startRacoon(); } #endif /* ndef MDNS_NO_IPSEC */ int -do_mDNSConfigureServer(__unused mach_port_t port, int updown, const char *keydata, int *err, audit_token_t token) +do_mDNSConfigureServer(__unused mach_port_t port, int updown, const char *fqdn, audit_token_t token) { #ifndef MDNS_NO_IPSEC debug("entry"); - *err = 0; - - if (!authorized(&token)) - { - *err = kmDNSHelperNotAuthorized; - goto fin; - } + if (!authorized(&token)) goto fin; switch ((enum mDNSUpDown)updown) { case kmDNSUp: - if (0 != createAnonymousRacoonConfiguration(keydata)) - { - *err = kmDNSHelperRacoonConfigCreationFailed; - goto fin; - } + if (0 != createAnonymousRacoonConfiguration(fqdn)) goto fin; break; case kmDNSDown: - revertAnonymousRacoonConfiguration(); + revertAnonymousRacoonConfiguration(GetOldRacoonConfigDir()); + revertAnonymousRacoonConfiguration(GetRacoonConfigDir()); break; default: - *err = kmDNSHelperInvalidServerState; goto fin; } - if (0 != (*err = kickRacoon())) + if (0 != kickRacoon()) goto fin; debug("succeeded"); fin: #else - (void)port; (void)updown; (void)keydata; (void)token; + (void)port; (void)updown; (void)fqdn; (void)token; *err = kmDNSHelperIPsecDisabled; #endif update_idle_timer(); @@ -1649,8 +2232,8 @@ doTunnelPolicy(mDNSTunnelPolicyWhich which, debug("succeeded"); fin: - if (0 >= s) - close(s); + if (s >= 0) + pfkey_close(s); if (NULL != policy) free(policy); return err; @@ -1662,7 +2245,7 @@ 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) + const char *fqdn, int *err, audit_token_t token) { #ifndef MDNS_NO_IPSEC static const char config[] = @@ -1673,7 +2256,8 @@ do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete, " situation identity_only;\n" " verify_identifier off;\n" " generate_policy on;\n" - " shared_secret use \"%s\";\n" + " my_identifier user_fqdn \"dns:%s\";\n" + " shared_secret keychain \"dns:%s\";\n" " nonce_size 16;\n" " lifetime time 5 min;\n" " initial_contact on;\n" @@ -1738,7 +2322,7 @@ do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete, lo, loc_port, ro, rmt_port); if ((int)sizeof(path) <= snprintf(path, sizeof(path), - "/etc/racoon/remote/%s.%u.conf", ro, + "%s%s.%u.conf", GetRacoonConfigDir(), ro, rmt_port)) { *err = kmDNSHelperResultTooLarge; @@ -1746,6 +2330,11 @@ do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete, } if (kmDNSAutoTunnelSetKeysReplace == replacedelete) { + if (0 > ensureExistenceOfRacoonConfigDir(GetRacoonConfigDir())) + { + *err = kmDNSHelperRacoonConfigCreationFailed; + goto fin; + } if ((int)sizeof(tmp_path) <= snprintf(tmp_path, sizeof(tmp_path), "%s.XXXXXX", path)) { @@ -1754,7 +2343,7 @@ do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete, } if (0 > (fd = mkstemp(tmp_path))) { - helplog(ASL_LEVEL_ERR, "mktemp \"%s\" failed: %s", + helplog(ASL_LEVEL_ERR, "mkstemp \"%s\" failed: %s", tmp_path, strerror(errno)); *err = kmDNSHelperRacoonConfigCreationFailed; goto fin; @@ -1767,7 +2356,7 @@ do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete, goto fin; } fd = -1; - fprintf(fp, config, configHeader, ro, rmt_port, keydata, ri, li, li, ri); + fprintf(fp, config, configHeader, ro, rmt_port, fqdn, fqdn, ri, li, li, ri); fclose(fp); fp = NULL; if (0 > rename(tmp_path, path)) diff --git a/mDNSMacOSX/helper.h b/mDNSMacOSX/helper.h index 00d5289..ac974a5 100644 --- a/mDNSMacOSX/helper.h +++ b/mDNSMacOSX/helper.h @@ -17,6 +17,47 @@ Change History (most recent first): $Log: helper.h,v $ +Revision 1.18 2009/04/20 20:40:14 cheshire + uDNS: Running location cycling caused configd and mDNSResponder to deadlock +Changed mDNSPreferencesSetName (and similar) routines from MIG "routine" to MIG "simpleroutine" +so we don't deadlock waiting for a result that we're just going to ignore anyway + +Revision 1.17 2009/03/20 22:12:28 mcguire + Support CFUserNotificationDisplayNotice in mDNSResponderHelper +Make the call to the helper a simpleroutine: don't wait for an unused return value + +Revision 1.16 2009/03/20 20:52:22 cheshire + Support CFUserNotificationDisplayNotice in mDNSResponderHelper + +Revision 1.15 2009/03/14 01:42:56 mcguire + BTMM: Fix issues with multiple .Mac accounts on the same machine + +Revision 1.14 2009/01/22 02:14:27 cheshire + Sleep Proxy: Set correct target MAC address, instead of all zeroes + +Revision 1.13 2009/01/14 01:38:43 mcguire + Write out DynamicStore per-interface SleepProxyServer info + +Revision 1.12 2009/01/12 22:26:13 mkrochma +Change DynamicStore location from BonjourSleepProxy/DiscoveredServers to SleepProxyServers + +Revision 1.11 2008/12/05 02:35:24 mcguire + Write to the DynamicStore when a Sleep Proxy server is available on the network + +Revision 1.10 2008/11/04 23:54:09 cheshire +Added routine mDNSSetARP(), used to replace an SPS client's entry in our ARP cache with +a dummy one, so that IP traffic to the SPS client initiated by the SPS machine can be +captured by our BPF filters, and used as a trigger to wake the sleeping machine. + +Revision 1.9 2008/10/24 01:42:36 cheshire +Added mDNSPowerRequest helper routine to request a scheduled wakeup some time in the future + +Revision 1.8 2008/10/20 22:01:28 cheshire +Made new Mach simpleroutine "mDNSRequestBPF" + +Revision 1.7 2008/09/27 00:58:11 cheshire +Added mDNSRequestBPF declaration + 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 @@ -44,7 +85,8 @@ enum mDNSDynamicStoreSetConfigKey kmDNSMulticastConfig = 1, kmDNSDynamicConfig, kmDNSPrivateConfig, - kmDNSBackToMyMacConfig + kmDNSBackToMyMacConfig, + kmDNSSleepProxyServersState }; enum mDNSPreferencesSetNameKey @@ -78,13 +120,18 @@ enum mDNSHelperErrors #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); + +extern void mDNSRequestBPF(void); +extern int mDNSPowerRequest(int key, int interval); +extern int mDNSSetARP(int ifindex, const v4addr_t ip, const ethaddr_t eth); +extern void mDNSNotify(const char *title, const char *msg); // Both strings are UTF-8 text +extern void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropertyListRef value); +extern void mDNSPreferencesSetName(int key, domainlabel *old, domainlabel *new); +extern int mDNSKeychainGetSecrets(CFArrayRef *secrets); +extern void mDNSAutoTunnelInterfaceUpDown(int updown, v6addr_t addr); +extern void mDNSConfigureServer(int updown, const domainname *const fqdn); +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 domainname *const fqdn); #endif /* H_HELPER_H */ diff --git a/mDNSMacOSX/helpermsg-types.h b/mDNSMacOSX/helpermsg-types.h index 1321692..07539d2 100644 --- a/mDNSMacOSX/helpermsg-types.h +++ b/mDNSMacOSX/helpermsg-types.h @@ -17,6 +17,9 @@ Change History (most recent first): $Log: helpermsg-types.h,v $ +Revision 1.3 2009/01/22 02:14:27 cheshire + Sleep Proxy: Set correct target MAC address, instead of all zeroes + Revision 1.2 2007/08/23 21:52:19 cheshire Added License header @@ -28,8 +31,9 @@ Revision 1.1 2007/08/08 22:34:58 mcguire #define H_HELPERMSG_TYPES_H #include -typedef uint8_t v6addr_t[16]; -typedef uint8_t v4addr_t[4]; +typedef uint8_t v4addr_t [ 4]; +typedef uint8_t ethaddr_t[ 6]; +typedef uint8_t v6addr_t [16]; typedef const char *string_t; #endif /* H_HELPERMSG_TYPES_H */ diff --git a/mDNSMacOSX/helpermsg.defs b/mDNSMacOSX/helpermsg.defs index 03ae2da..0c2d172 100644 --- a/mDNSMacOSX/helpermsg.defs +++ b/mDNSMacOSX/helpermsg.defs @@ -17,6 +17,45 @@ Change History (most recent first): $Log: helpermsg.defs,v $ +Revision 1.17 2009/04/20 20:40:14 cheshire + uDNS: Running location cycling caused configd and mDNSResponder to deadlock +Changed mDNSPreferencesSetName (and similar) routines from MIG "routine" to MIG "simpleroutine" +so we don't deadlock waiting for a result that we're just going to ignore anyway + +Revision 1.16 2009/03/20 22:12:28 mcguire + Support CFUserNotificationDisplayNotice in mDNSResponderHelper +Make the call to the helper a simpleroutine: don't wait for an unused return value + +Revision 1.15 2009/03/20 20:52:22 cheshire + Support CFUserNotificationDisplayNotice in mDNSResponderHelper + +Revision 1.14 2009/03/14 01:42:56 mcguire + BTMM: Fix issues with multiple .Mac accounts on the same machine + +Revision 1.13 2009/01/22 02:14:26 cheshire + Sleep Proxy: Set correct target MAC address, instead of all zeroes + +Revision 1.12 2009/01/14 01:38:43 mcguire + Write out DynamicStore per-interface SleepProxyServer info + +Revision 1.11 2008/11/04 23:54:09 cheshire +Added routine mDNSSetARP(), used to replace an SPS client's entry in our ARP cache with +a dummy one, so that IP traffic to the SPS client initiated by the SPS machine can be +captured by our BPF filters, and used as a trigger to wake the sleeping machine. + +Revision 1.10 2008/10/24 01:42:36 cheshire +Added mDNSPowerRequest helper routine to request a scheduled wakeup some time in the future + +Revision 1.9 2008/10/20 22:01:28 cheshire +Made new Mach simpleroutine "mDNSRequestBPF" + +Revision 1.8 2008/09/26 21:18:13 cheshire +Tidy up code layout + +Revision 1.7 2008/08/13 23:04:06 mcguire + handle SIGTERM in mDNSResponderHelper +Preparation: rename message function, as it will no longer be called only on idle exit + Revision 1.6 2007/09/07 22:44:03 mcguire Move CFUserNotification code to mDNSResponderHelper @@ -41,63 +80,77 @@ Revision 1.1 2007/08/08 22:34:58 mcguire import "helpermsg-types.h"; -type v6addr_t = array [16] of uint8_t; -type v4addr_t = array [4] of uint8_t; +type v4addr_t = array [ 4] of uint8_t; +type ethaddr_t = array [ 6] of uint8_t; +type v6addr_t = array [16] of uint8_t; type string_t = c_string[*:1024]; 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); +simpleroutine mDNSExit( port : mach_port_t; + ServerAuditToken token : audit_token_t); + +simpleroutine mDNSRequestBPF( port : mach_port_t; + ServerAuditToken token : audit_token_t); + +routine mDNSPowerRequest( port : mach_port_t; + key : int; + interval : int; + out err : int; + ServerAuditToken token : audit_token_t); + +routine mDNSSetARP( port : mach_port_t; + ifindex : int; + ip : v4addr_t; + eth : ethaddr_t; + out err : int; + ServerAuditToken token : audit_token_t); + +simpleroutine mDNSNotify( port : mach_port_t; + title : string_t; + msg : string_t; + ServerAuditToken token : audit_token_t); + +simpleroutine mDNSDynamicStoreSetConfig( + port : mach_port_t; + key : int; + subkey : string_t; + value : pointer_t; + ServerAuditToken token : audit_token_t); + +simpleroutine mDNSPreferencesSetName( port : mach_port_t; + key : int; + old : string_t; + new : string_t; + ServerAuditToken token : audit_token_t); + +routine mDNSKeychainGetSecrets( port : mach_port_t; + out numsecrets : unsigned; + out secrets : pointer_t; + out err : int; + ServerAuditToken token : audit_token_t); + +simpleroutine mDNSAutoTunnelInterfaceUpDown( + port : mach_port_t; + updown : int; + address : v6addr_t; + ServerAuditToken token : audit_token_t); + +simpleroutine mDNSConfigureServer( port : mach_port_t; + updown : int; + fqdn : string_t; + 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; + fqdn : string_t; + out err : int; + ServerAuditToken token : audit_token_t); diff --git a/mDNSMacOSX/mDNSMacOSX.c b/mDNSMacOSX/mDNSMacOSX.c index cc13980..7f66dd4 100644 --- a/mDNSMacOSX/mDNSMacOSX.c +++ b/mDNSMacOSX/mDNSMacOSX.c @@ -17,13 +17,481 @@ Change History (most recent first): $Log: mDNSMacOSX.c,v $ -Revision 1.536.2.2 2008/07/30 01:08:17 mcguire - Should use randomized source ports and transaction IDs to avoid DNS cache poisoning -merge r1.540 from +Revision 1.687 2009/06/30 21:16:09 cheshire + Plugging and unplugging the power cable shouldn't cause a network change event +Additional fix: Only start and stop NetWake browses for active interfaces that are currently registered with mDNSCore -Revision 1.536.2.1 2008/07/29 20:48:10 mcguire - Should use randomized source ports and transaction IDs to avoid DNS cache poisoning -merge r1.539 from +Revision 1.686 2009/06/25 23:36:56 cheshire +To facilitate testing, added command-line switch "-OfferSleepProxyService" +to re-enable the previously-supported mode of operation where we offer +sleep proxy service on desktop Macs that are set to never sleep. + +Revision 1.685 2009/06/25 23:15:12 cheshire +Don't try to use private header file "IOPowerSourcesPrivate.h" +(it prevents external developers from being able to compile the code) + +Revision 1.684 2009/06/24 22:14:22 cheshire + Plugging and unplugging the power cable shouldn't cause a network change event + +Revision 1.683 2009/06/08 22:31:03 cheshire +Fixed typo in comment: Portability > 35 means nominal weight < 3kg + +Revision 1.682 2009/05/19 23:30:31 cheshire +Suppressed some unnecessary debugging messages; added AppleTV to list of recognized hardware + +Revision 1.681 2009/05/12 23:23:15 cheshire +Removed unnecessary "mDNSPlatformTCPConnect - connect failed ... Error 50 (Network is down)" debugging message + +Revision 1.680 2009/05/05 01:32:50 jessic2 + regservice_callback: instance->request is NULL 0 -- Clean up spurious logs resulting from fixing this bug. + +Revision 1.679 2009/05/01 23:48:46 jessic2 + regservice_callback: instance->request is NULL 0 + +Revision 1.678 2009/04/24 23:32:28 cheshire +To facilitate testing, put back code to be a sleep proxy when set to never sleep, compiled out by compile-time switch + +Revision 1.677 2009/04/24 20:50:16 mcguire + 4 second delay in DNS response + +Revision 1.676 2009/04/24 02:17:58 mcguire + uDNS: Not always respecting preference order of DNS servers + +Revision 1.675 2009/04/23 18:51:28 mcguire + uDNS: PPP doesn't automatically reconnect on wake from sleep (no name resolver) + +Revision 1.674 2009/04/23 00:58:01 jessic2 + uDNS: DNS stops working after configd crashes + +Revision 1.673 2009/04/22 01:19:57 jessic2 + Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32 + +Revision 1.672 2009/04/21 16:34:47 mcguire + null deref in mDNSPlatformSetDNSConfig + +Revision 1.671 2009/04/15 01:14:07 mcguire + 4 second delay in DNS response + +Revision 1.670 2009/04/15 01:10:39 jessic2 + BTMM: Add support for setting kDNSServiceErr_NoSuchRecord in DynamicStore + +Revision 1.669 2009/04/11 02:02:34 mcguire + crash in doSSLHandshake + +Revision 1.668 2009/04/11 00:20:08 jessic2 + Daemon: Should be able to turn on LogOperation dynamically + +Revision 1.667 2009/04/09 20:01:00 cheshire + IOPMCopyActivePMPreferences not available on Apple TV +At Rory's suggestion, removed unnecessary "Could not get Wake On LAN value" log message + +Revision 1.666 2009/04/07 21:57:53 cheshire + IOPMCopyActivePMPreferences not available on Apple TV +Put previous code back + +Revision 1.665 2009/04/03 21:48:44 mcguire +Back out checkin 1.664 ( MessageTracer: prepend domain to make signature field unique) + +Revision 1.663 2009/04/02 22:21:16 mcguire + Adopt IOPM APIs + +Revision 1.662 2009/04/02 01:08:15 mcguire + Don't be a sleep proxy when set to sleep never + +Revision 1.661 2009/04/01 17:50:14 mcguire +cleanup mDNSRandom + +Revision 1.660 2009/04/01 01:13:10 mcguire + Sleep Proxy: Detect lid closed + +Revision 1.659 2009/03/30 21:11:07 jessic2 + Need to do some polish work on MessageTracer logging + +Revision 1.658 2009/03/30 20:07:28 mcguire + BTMM: SSLHandshake threads are leaking Mach ports + +Revision 1.657 2009/03/27 17:27:13 cheshire + Need to support querying IPv6 DNS servers + +Revision 1.656 2009/03/26 05:02:48 mcguire +fix build error in dnsextd + +Revision 1.655 2009/03/26 03:59:00 jessic2 +Changes for + +Revision 1.654 2009/03/20 20:53:26 cheshire +Added test code for testing with MacBook Air, using a USB dongle that doesn't actually support Wake-On-LAN + +Revision 1.653 2009/03/20 20:52:22 cheshire + Support CFUserNotificationDisplayNotice in mDNSResponderHelper + +Revision 1.652 2009/03/19 23:44:47 mcguire + Properly handle EADDRINUSE + +Revision 1.651 2009/03/17 19:15:24 mcguire + SSLHandshake deadlock issues + +Revision 1.650 2009/03/17 01:24:22 cheshire +Updated to new Sleep Proxy metric ranges: 100000-999999; 1000000 means "do not use" + +Revision 1.649 2009/03/15 01:30:29 mcguire +fix log message + +Revision 1.648 2009/03/15 01:16:08 mcguire + SSLHandshake deadlock issues + +Revision 1.647 2009/03/14 01:42:56 mcguire + BTMM: Fix issues with multiple .Mac accounts on the same machine + +Revision 1.646 2009/03/13 01:36:24 mcguire + Reachability fixes on DNS config change + +Revision 1.645 2009/03/10 23:48:33 cheshire + Task scheduling failure when Sleep Proxy Server is active + +Revision 1.644 2009/03/10 04:17:09 cheshire +Check for NULL answer in UpdateSPSStatus() + +Revision 1.643 2009/03/10 01:15:55 cheshire +Sleep Proxies with invalid names (score 10000) need to be ignored + +Revision 1.642 2009/03/08 04:46:51 mkrochma +Change Keychain LogMsg to LogInfo + +Revision 1.641 2009/03/05 23:53:34 cheshire +Removed spurious "SnowLeopardPowerChanged: wake ERROR" syslog message + +Revision 1.640 2009/03/05 21:57:13 cheshire +Don't close BPF fd until we have no more records we're proxying for on that interface + +Revision 1.639 2009/03/04 01:45:01 cheshire +HW_MODEL information should be LogSPS, not LogMsg + +Revision 1.638 2009/03/03 22:51:54 cheshire + Sleep Proxy: Waking on same network but different interface will cause conflicts + +Revision 1.637 2009/02/26 22:58:47 cheshire + Crash in mDNSResponder at mDNSResponder • CloseBPF + 75 +Fixed race condition between the kqueue thread and the CFRunLoop thread. + +Revision 1.636 2009/02/21 01:38:39 cheshire +Added comment: mDNSCoreMachineSleep(m, false); // Will set m->SleepState = SleepState_Awake; + +Revision 1.635 2009/02/17 23:29:03 cheshire +Throttle logging to a slower rate when running on SnowLeopard + +Revision 1.634 2009/02/14 00:29:17 mcguire +fixed typo + +Revision 1.633 2009/02/14 00:07:11 cheshire +Need to set up m->SystemWakeOnLANEnabled before calling UpdateInterfaceList(m, utc); + +Revision 1.632 2009/02/13 19:40:07 cheshire +Improved alignment of LogSPS messages + +Revision 1.631 2009/02/13 18:16:05 cheshire +Fixed some compile warnings + +Revision 1.630 2009/02/13 06:32:43 cheshire +Converted LogOperation messages to LogInfo or LogSPS + +Revision 1.629 2009/02/12 20:57:26 cheshire +Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch + +Revision 1.628 2009/02/11 02:34:45 cheshire +m->p->SystemWakeForNetworkAccessEnabled renamed to m->SystemWakeOnLANEnabled + +Revision 1.627 2009/02/10 00:19:17 cheshire + Sleep Proxy: Adopt SIOCGIFWAKEFLAGS ioctl to determine interface WOMP-ability + +Revision 1.626 2009/02/10 00:15:38 cheshire + Sleep Proxy: "Unknown DNS packet type 8849" logs + +Revision 1.625 2009/02/09 21:24:25 cheshire +Set correct bit in ifr.ifr_wake_flags (was coincidentally working because IF_WAKE_ON_MAGIC_PACKET happens to have the value 1) + +Revision 1.624 2009/02/09 21:11:43 cheshire +Need to acknowledge kIOPMSystemPowerStateCapabilityCPU message + +Revision 1.623 2009/02/09 06:20:42 cheshire +Upon receiving system power change notification, make sure our m->p->SystemWakeForNetworkAccessEnabled value +correctly reflects the current system setting + +Revision 1.622 2009/02/07 02:57:32 cheshire + Sleep Proxy: Need to adopt IOPMConnection + +Revision 1.621 2009/02/06 03:18:12 mcguire + BTMM: State not cleaned up on SIGTERM w/o reboot + +Revision 1.620 2009/02/02 22:14:11 cheshire +Instead of repeatedly checking the Dynamic Store, use m->p->SystemWakeForNetworkAccessEnabled variable + +Revision 1.619 2009/01/24 02:11:58 cheshire +Handle case where config->resolver[0]->nameserver[0] is NULL + +Revision 1.618 2009/01/24 01:55:51 cheshire +Handle case where config->resolver[0]->domain is NULL + +Revision 1.617 2009/01/24 01:48:42 cheshire + Implement logic to determine when to send dot-local lookups via Unicast + +Revision 1.616 2009/01/24 00:28:43 cheshire +Updated comments + +Revision 1.615 2009/01/22 02:14:26 cheshire + Sleep Proxy: Set correct target MAC address, instead of all zeroes + +Revision 1.614 2009/01/21 03:43:57 mcguire + BTMM: Add support for setting kDNSServiceErr_NATPortMappingDisabled in DynamicStore + +Revision 1.613 2009/01/20 02:38:41 mcguire +fix previous checkin comment + +Revision 1.612 2009/01/20 02:35:15 mcguire + don't update BTMM & SleepProxyServers status at shutdown time + +Revision 1.611 2009/01/17 04:15:40 cheshire +Updated "did sleep(5)" debugging message + +Revision 1.610 2009/01/16 20:37:30 cheshire +Fixed incorrect value of EOPNOTSUPP + +Revision 1.609 2009/01/16 03:08:13 cheshire +Use kernel event notifications to track KEV_DL_WAKEFLAGS_CHANGED +(indicates when SIOCGIFWAKEFLAGS changes for an interface, e.g. when AirPort +switches from a base-station that's WakeOnLAN-capable to one that isn't) + +Revision 1.608 2009/01/16 01:27:03 cheshire +Initial work to adopt SIOCGIFWAKEFLAGS ioctl to determine whether an interface is WakeOnLAN-capable + +Revision 1.607 2009/01/15 22:24:01 cheshire +Get rid of unnecessary ifa_name field in NetworkInterfaceInfoOSX (it just duplicates the content of ifinfo.ifname) +This also eliminates an unnecessary malloc, memory copy, and free + +Revision 1.606 2009/01/15 00:22:49 mcguire + NAT-PMP: mDNSResponder needs to listen on 224.0.0.1:5350/UDP with REUSEPORT + +Revision 1.605 2009/01/14 01:38:43 mcguire + Write out DynamicStore per-interface SleepProxyServer info + +Revision 1.604 2009/01/13 05:31:34 mkrochma + Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy + +Revision 1.603 2009/01/12 22:26:13 mkrochma +Change DynamicStore location from BonjourSleepProxy/DiscoveredServers to SleepProxyServers + +Revision 1.602 2008/12/19 20:23:34 mcguire + Lots of duplicate log messages about failure to bind to NAT-PMP Announcement port + +Revision 1.601 2008/12/15 19:51:56 mcguire + Retry UDP socket creation only when randomizing ports + +Revision 1.600 2008/12/12 21:30:14 cheshire +Additional defensive coding -- make sure InterfaceID is found in our list before using it + +Revision 1.599 2008/12/12 04:36:26 cheshire +Make sure we don't overflow our BPF filter buffer +Only add addresses for records where the InterfaceID matches + +Revision 1.598 2008/12/12 00:57:51 cheshire +Updated BPF filter generation to explicitly match addresses we're proxying for, +rather than just matching any unknown IP address + +Revision 1.597 2008/12/10 20:37:05 cheshire +Don't mark interfaces like PPP as being WakeonLAN-capable + +Revision 1.596 2008/12/10 19:34:30 cheshire +Use symbolic OS version names instead of literal integers + +Revision 1.595 2008/12/10 02:25:31 cheshire +Minor fixes to use of LogClientOperations symbol + +Revision 1.594 2008/12/10 02:11:45 cheshire +ARMv5 compiler doesn't like uncommented stuff after #endif + +Revision 1.593 2008/12/09 23:08:55 mcguire + should use IP_BOUND_IF +additional cleanup + +Revision 1.592 2008/12/09 19:58:44 mcguire + should use IP_BOUND_IF + +Revision 1.591 2008/12/09 15:39:05 cheshire +Workaround for bug on Leopard and earlier where Ethernet drivers report wrong link state immediately after wake from sleep + +Revision 1.590 2008/12/09 05:21:54 cheshire +Should key sleep/wake handling off kIOMessageSystemWillPowerOn message -- the kIOMessageSystemHasPoweredOn +message is delayed by some seemingly-random amount in the range 0-15 seconds. + +Revision 1.589 2008/12/05 02:35:25 mcguire + Write to the DynamicStore when a Sleep Proxy server is available on the network + +Revision 1.588 2008/12/04 21:08:52 mcguire + mDNS: Provide mechanism to disable Multicast advertisements + +Revision 1.587 2008/12/04 02:17:47 cheshire +Additional sleep/wake debugging messages + +Revision 1.586 2008/11/26 20:34:55 cheshire +Changed some "LogOperation" debugging messages to "debugf" + +Revision 1.585 2008/11/25 20:53:35 cheshire +Updated portability metrics; added Xserve and PowerBook to list + +Revision 1.584 2008/11/25 05:07:16 cheshire + Advertise Sleep Proxy metrics in service name + +Revision 1.583 2008/11/20 01:42:31 cheshire +For consistency with other parts of the code, changed code to only check +that the first 4 bytes of MAC address are zero, not the whole 6 bytes. + +Revision 1.582 2008/11/14 22:59:09 cheshire +When on a network with more than one subnet overlayed on a single physical link, don't make local ARP +entries for hosts that are on our physical link but not on our logical subnet -- it confuses the kernel + +Revision 1.581 2008/11/14 21:01:26 cheshire +Log a warning if we fail to get a MAC address for an interface + +Revision 1.580 2008/11/14 02:16:15 cheshire +Clean up NetworkChanged handling + +Revision 1.579 2008/11/12 23:15:37 cheshire +Updated log messages + +Revision 1.578 2008/11/06 23:41:57 cheshire +Refinement: Only need to create local ARP entry when sending ARP packet to broadcast address or to ourselves + +Revision 1.577 2008/11/06 01:15:47 mcguire +Fix compile error that occurs when LogOperation is disabled + +Revision 1.576 2008/11/05 21:55:21 cheshire +Fixed mistake in BPF filter generation + +Revision 1.575 2008/11/04 23:54:09 cheshire +Added routine mDNSSetARP(), used to replace an SPS client's entry in our ARP cache with +a dummy one, so that IP traffic to the SPS client initiated by the SPS machine can be +captured by our BPF filters, and used as a trigger to wake the sleeping machine. + +Revision 1.574 2008/11/04 00:27:58 cheshire +Corrected some timing anomalies in sleep/wake causing spurious name self-conflicts + +Revision 1.573 2008/11/03 01:12:42 mkrochma +Fix compile error that occurs when LogOperation is disabled + +Revision 1.572 2008/10/31 23:36:13 cheshire +One wakeup clear any previous power requests + +Revision 1.571 2008/10/31 23:05:30 cheshire +Move logic to decide when to at as Sleep Proxy Server from daemon.c to mDNSMacOSX.c + +Revision 1.570 2008/10/30 01:08:19 cheshire +After waking for network maintenance operations go back to sleep again + +Revision 1.569 2008/10/29 21:39:43 cheshire +Updated syslog messages; close BPF socket on read error + +Revision 1.568 2008/10/28 20:37:28 cheshire +Changed code to create its own CFSocketCreateWithNative directly, instead of +relying on udsSupportAddFDToEventLoop/udsSupportRemoveFDFromEventLoop + +Revision 1.567 2008/10/27 22:31:37 cheshire +Can't just close BPF_fd using "close(i->BPF_fd);" -- need to call +"udsSupportRemoveFDFromEventLoop(i->BPF_fd);" to remove it from our event source list + +Revision 1.566 2008/10/23 22:33:23 cheshire +Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu + +Revision 1.565 2008/10/22 23:23:55 cheshire +Moved definition of OSXVers from daemon.c into mDNSMacOSX.c + +Revision 1.564 2008/10/22 22:08:46 cheshire +Take IP header length into account when determining how many bytes to return from BPF filter + +Revision 1.563 2008/10/22 20:59:28 cheshire +BPF filter needs to capture a few more bytes so that we can examine TCP header fields + +Revision 1.562 2008/10/22 19:48:29 cheshire +Improved syslog messages + +Revision 1.561 2008/10/22 17:18:57 cheshire +Need to open and close BPF fds when turning Sleep Proxy Server on and off + +Revision 1.560 2008/10/22 01:09:36 cheshire +Fixed build warning when not using LogClientOperations + +Revision 1.559 2008/10/21 01:05:30 cheshire +Added code to receive raw packets using Berkeley Packet Filter (BPF) + +Revision 1.558 2008/10/16 22:42:06 cheshire +Removed debugging messages + +Revision 1.557 2008/10/09 22:33:14 cheshire +Fill in ifinfo.MAC field when fetching interface list + +Revision 1.556 2008/10/09 21:15:23 cheshire +In mDNSPlatformUDPSocket(), need to create an IPv6 socket as well as IPv4 + +Revision 1.555 2008/10/09 19:05:57 cheshire +No longer want to inhibit all networking when going to sleep + +Revision 1.554 2008/10/08 18:36:51 mkrochma + Supress Couldn't read user-specified Computer Name logs + +Revision 1.553 2008/10/04 00:47:12 cheshire +If NetWake setting changes for an interface, treat it as a whole new interface (like BSSID changing) + +Revision 1.552 2008/10/03 23:32:15 cheshire +Added definition of mDNSPlatformSendRawPacket + +Revision 1.551 2008/10/03 18:25:16 cheshire +Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);" + +Revision 1.550 2008/10/03 00:51:58 cheshire +Removed spurious "else" case that got left in by mistake + +Revision 1.549 2008/10/03 00:50:13 cheshire +Minor code rearrangement; don't set up interface list until *after* we've started watching for network changes + +Revision 1.548 2008/10/03 00:26:25 cheshire +Export DictionaryIsEnabled() so it's callable from other files + +Revision 1.547 2008/10/02 23:50:07 mcguire + shutdown time issues +improve log messages when SCDynamicStoreCreate() fails + +Revision 1.546 2008/10/02 22:26:21 cheshire +Moved declaration of BPF_fd from uds_daemon.c to mDNSMacOSX.c, where it really belongs + +Revision 1.545 2008/10/01 22:01:40 cheshire +On Allan Nathanson's advice, add "State:/IOKit/PowerManagement/CurrentSettings" +to keys array instead of patterns array, for efficiency + +Revision 1.544 2008/10/01 21:35:35 cheshire +Monitor "State:/IOKit/PowerManagement/CurrentSettings" to track state of "Wake for network access" setting + +Revision 1.543 2008/09/26 23:05:56 mkrochma +Improve log messages by using good old UTF-8 + +Revision 1.542 2008/09/26 19:49:51 cheshire +Improved "failed to send packet" debugging message + +Revision 1.541 2008/09/25 21:02:05 cheshire + Stop using separate m->ServiceRegistrations list +In TunnelServers(), need to check main m->ResourceRecords list to see +if we have a non-zero number of advertised AutoTunnel services + +Revision 1.540 2008/07/30 00:55:56 mcguire + Should use randomized source ports and transaction IDs to avoid DNS cache poisoning +Additional fixes so that we know when a socket has been closed while in a loop reading from it + +Revision 1.539 2008/07/24 20:23:04 cheshire + Should use randomized source ports and transaction IDs to avoid DNS cache poisoning + +Revision 1.538 2008/06/02 05:39:39 mkrochma + Don't set TOS bits anymore + +Revision 1.537 2008/05/01 18:30:54 mkrochma + Make mDNSResponder and mDNSResponderHelper shutdown at regular time Revision 1.536 2008/03/25 01:27:30 mcguire Status sometimes wrong when link goes down @@ -773,18 +1241,20 @@ Add (commented out) trigger value for testing "mach_absolute_time went backwards #define USE_V6_ONLY_WHEN_NO_ROUTABLE_V4 0 -#include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above +#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 "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform +#include "dns_sd.h" // For mDNSInterface_LocalOnly etc. #include "PlatformCommon.h" #include #include // For va_list support +#include // For arc4random #include #include // For IFT_ETHER #include +#include // For BIOCSETIF etc. #include #include #include @@ -831,11 +1301,19 @@ Add (commented out) trigger value for testing "mach_absolute_time went backwards #include #include + +#if USE_IOPMCOPYACTIVEPMPREFERENCES +#include +#include +#endif + #include #include #include #include "helper.h" +#include + #define kInterfaceSpecificOption "interface=" // *************************************************************************** @@ -845,21 +1323,41 @@ Add (commented out) trigger value for testing "mach_absolute_time went backwards #pragma mark - Globals #endif +// By default we don't offer sleep proxy service +// If OfferSleepProxyService is set non-zero (typically via command-line switch), +// then we'll offer sleep proxy service on desktop Macs that are set to never sleep. +// We currently do not offer sleep proxy service on laptops, or on machines that are set to go to sleep. +mDNSexport int OfferSleepProxyService = 0; + +mDNSexport int OSXVers; mDNSexport int KQueueFD; #ifndef NO_SECURITYFRAMEWORK static CFArrayRef ServerCerts; #endif /* NO_SECURITYFRAMEWORK */ -#define DYNDNS_KEYCHAIN_SERVICE "DynDNS Shared Secret" +static CFStringRef NetworkChangedKey_IPv4; +static CFStringRef NetworkChangedKey_IPv6; +static CFStringRef NetworkChangedKey_Hostnames; +static CFStringRef NetworkChangedKey_Computername; +static CFStringRef NetworkChangedKey_DNS; +static CFStringRef NetworkChangedKey_DynamicDNS = CFSTR("Setup:/Network/DynamicDNS"); +static CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac"); + +static char HINFO_HWstring_buffer[32]; +static char *HINFO_HWstring = "Device"; +static int HINFO_HWstring_prefixlen = 6; + +mDNSexport int WatchDogReportingThreshold = 250; -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"); +#if APPLE_OSX_mDNSResponder +static mDNSu8 SPMetricPortability = 99; +static mDNSu8 SPMetricMarginalPower = 99; +static mDNSu8 SPMetricTotalPower = 99; +mDNSexport domainname ActiveDirectoryPrimaryDomain; +mDNSexport int ActiveDirectoryPrimaryDomainLabelCount; +mDNSexport mDNSAddr ActiveDirectoryPrimaryDomainServer; +#endif // APPLE_OSX_mDNSResponder // *************************************************************************** // Functions @@ -875,7 +1373,7 @@ CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac"); // 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)) +#define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT)) mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both strings are UTF-8 text { @@ -905,12 +1403,7 @@ mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both s notifyCount++; #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); + mDNSNotify(title, msg); #endif /* NO_CFUSERNOTIFICATION */ } @@ -934,7 +1427,7 @@ mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, const { NetworkInterfaceInfoOSX *i; for (i = m->p->InterfaceList; i; i = i->next) - if (i->Exists && !strcmp(i->ifa_name, ifname) && + if (i->Exists && !strcmp(i->ifinfo.ifname, ifname) && ((type == AF_UNSPEC ) || (type == AF_INET && i->ifinfo.ip.type == mDNSAddrType_IPv4) || (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i); @@ -962,7 +1455,7 @@ mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const if (i->ifinfo.InterfaceID && i->scope_id == ifindex) 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", ifindex); + LogInfo("InterfaceID for interface index %d not found; Updating interface list", ifindex); mDNSMacOSXNetworkChanged(m); for (i = m->p->InterfaceList; i; i = i->next) if (i->ifinfo.InterfaceID && i->scope_id == ifindex) return(i->ifinfo.InterfaceID); @@ -981,7 +1474,7 @@ mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNS 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); + LogInfo("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); @@ -989,6 +1482,41 @@ mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNS return(0); } +#if APPLE_OSX_mDNSResponder +mDNSexport void mDNSASLLog(uuid_t *uuid, const char *subdomain, const char *result, const char *signature, const char *fmt, ...) + { + if (OSXVers < OSXVers_10_6_SnowLeopard) return; + + static char buffer[512]; + aslmsg asl_msg = asl_new(ASL_TYPE_MSG); + + if (!asl_msg) { LogMsg("mDNSASLLog: asl_new failed"); return; } + if (uuid) + { + char uuidStr[36]; + uuid_unparse(*uuid, uuidStr); + asl_set (asl_msg, "com.apple.message.uuid", uuidStr); + } + + static char domainBase[] = "com.apple.mDNSResponder.%s"; + mDNS_snprintf (buffer, sizeof(buffer), domainBase, subdomain); + asl_set (asl_msg, "com.apple.message.domain", buffer); + + if (result) asl_set(asl_msg, "com.apple.message.result", result); + if (signature) asl_set(asl_msg, "com.apple.message.signature", signature); + + va_list ptr; + va_start(ptr,fmt); + mDNS_vsnprintf(buffer, sizeof(buffer), fmt, ptr); + va_end(ptr); + + int old_filter = asl_set_filter(NULL,ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG)); + asl_log(NULL, asl_msg, ASL_LEVEL_DEBUG, "%s", buffer); + asl_set_filter(NULL, old_filter); + asl_free(asl_msg); + } +#endif + #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - #pragma mark - UDP & TCP send & receive @@ -1010,8 +1538,8 @@ mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr) return result; } -// NOTE: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket" -// NOTE: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface" +// Note: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket" +// Note: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface" // OR send via our primary v4 unicast socket // UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end, @@ -1021,7 +1549,7 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms // 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. NetworkInterfaceInfoOSX *info = (NetworkInterfaceInfoOSX *)InterfaceID; - char *ifa_name = info ? info->ifa_name : "unicast"; + char *ifa_name = info ? info->ifinfo.ifname : "unicast"; struct sockaddr_storage to; int s = -1, err; mStatus result = mStatus_NoError; @@ -1033,23 +1561,24 @@ 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 = m->p->permanentsockets.sktv4; - - if (src) { s = src->ss.sktv4; debugf("mDNSPlatformSendUDP using port %d %d %d", mDNSVal16(src->ss.port), m->p->permanentsockets.sktv4, s); } + s = (src ? src->ss : 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); + #ifdef IP_BOUND_IF + if (info->scope_id == 0) + LogInfo("IP_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info, ifa_name); + else + setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id)); #else { static int displayed = 0; if (displayed < 1000) { displayed++; - LogOperation("IP_FORCE_OUT_IFP Socket option not defined -- cannot specify interface for unicast packets"); + LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets"); } } #endif @@ -1057,7 +1586,8 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms 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)); + if (err < 0 && !m->p->NetworkChanged) + LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno)); } } } @@ -1070,11 +1600,11 @@ 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 = m->p->permanentsockets.sktv6; + s = (src ? src->ss : m->p->permanentsockets).sktv6; if (info && mDNSAddrIsDNSMulticast(dst)) // Specify outgoing interface { err = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &info->scope_id, sizeof(info->scope_id)); - if (err < 0) LogMsg("setsockopt - IPV6_MULTICAST_IF error %ld errno %d (%s)", err, errno, strerror(errno)); + if (err < 0) LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err, errno, strerror(errno)); } } else @@ -1086,15 +1616,6 @@ 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 (!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); @@ -1122,15 +1643,22 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms 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)); + if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN) + LogInfo("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu", + s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow)); + else + LogMsg("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu", + s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow)); } result = mStatus_UnknownErr; } -#ifdef IP_FORCE_OUT_IFP +#ifdef IP_BOUND_IF if (dst->type == mDNSAddrType_IPv4 && info && !mDNSAddrIsDNSMulticast(dst)) - setsockopt(s, IPPROTO_IP, IP_FORCE_OUT_IFP, "", 1); + { + static const mDNSu32 ifindex = 0; + setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex)); + } #endif return(result); @@ -1248,7 +1776,7 @@ mDNSlocal void myKQSocketCallBack(int s1, short filter, void *context) senderAddr.type = mDNSAddrType_IPv4; senderAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr; senderPort.NotAnInteger = s->sin_port; - //LogOperation("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname); + //LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname); } else if (from.ss_family == AF_INET6) { @@ -1256,7 +1784,7 @@ mDNSlocal void myKQSocketCallBack(int s1, short filter, void *context) 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); + //LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname); } else { @@ -1264,7 +1792,7 @@ mDNSlocal void myKQSocketCallBack(int s1, short filter, void *context) return; } - // NOTE: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet + // 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; @@ -1277,7 +1805,7 @@ mDNSlocal void myKQSocketCallBack(int s1, short filter, void *context) 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); +// &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname); // mDNSCoreReceive may close the socket we're reading from. We must break out of our // loop when that happens, or we may try to read from an invalid FD. We do this by @@ -1335,6 +1863,14 @@ mDNSlocal void myKQSocketCallBack(int s1, short filter, void *context) // TCP socket support +typedef enum + { + handshake_required, + handshake_in_progress, + handshake_completed, + handshake_to_be_closed + } handshakeStatus; + struct TCPSocket_struct { TCPSocketFlags flags; // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags @@ -1343,13 +1879,24 @@ struct TCPSocket_struct KQueueEntry kqEntry; #ifndef NO_SECURITYFRAMEWORK SSLContextRef tlsContext; + pthread_t handshake_thread; #endif /* NO_SECURITYFRAMEWORK */ void *context; mDNSBool setup; - mDNSBool handshakecomplete; mDNSBool connected; + handshakeStatus handshake; + mDNS *m; // So we can call KQueueLock from the SSLHandshake thread + mStatus err; }; +mDNSlocal void doTcpSocketCallback(TCPSocket *sock) + { + mDNSBool c = !sock->connected; + sock->connected = mDNStrue; + sock->callback(sock, sock->context, c, sock->err); + // Note: the callback may call CloseConnection here, which frees the context structure! + } + #ifndef NO_SECURITYFRAMEWORK mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength) @@ -1361,7 +1908,7 @@ mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, s 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)); + LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket *)connection)->fd, errno, strerror(errno)); return(errSSLClosedAbort); } @@ -1374,7 +1921,7 @@ mDNSlocal OSStatus tlsReadSock(SSLConnectionRef connection, void *data, size_t * 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)); + LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno, strerror(errno)); return(errSSLClosedAbort); } @@ -1392,6 +1939,73 @@ mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, mDNSBool server) return(err); } +mDNSlocal void *doSSLHandshake(void *ctx) + { + // Warning: Touching sock without the kqueue lock! + // We're protected because sock->handshake == handshake_in_progress + TCPSocket *sock = (TCPSocket*)ctx; + mDNS * const m = sock->m; // Get m now, as we may free sock if marked to be closed while we're waiting on SSLHandshake + mStatus err = SSLHandshake(sock->tlsContext); + + KQueueLock(m); + LogInfo("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock + + if (sock->handshake == handshake_to_be_closed) + { + LogInfo("SSLHandshake completed after close"); + mDNSPlatformTCPCloseConnection(sock); + } + else + { + if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry); + else LogMsg("doSSLHandshake: sock->fd is -1"); + + if (err == errSSLWouldBlock) + sock->handshake = handshake_required; + else + { + if (err) + { + LogMsg("SSLHandshake failed: %d", err); + SSLDisposeContext(sock->tlsContext); + sock->tlsContext = NULL; + } + + sock->err = err; + sock->handshake = handshake_completed; + + LogInfo("doSSLHandshake: %p calling doTcpSocketCallback", sock); + doTcpSocketCallback(sock); + } + } + + LogInfo("SSLHandshake %p: dropping lock", sock); + KQueueUnlock(m, "doSSLHandshake"); + return NULL; + } + +mDNSlocal mStatus spawnSSLHandshake(TCPSocket* sock) + { + LogInfo("spawnSSLHandshake %p: entry", sock); + if (sock->handshake != handshake_required) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock->handshake); + sock->handshake = handshake_in_progress; + KQueueSet(sock->fd, EV_DELETE, EVFILT_READ, &sock->kqEntry); + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + mStatus err = pthread_create(&sock->handshake_thread, &attr, doSSLHandshake, sock); + pthread_attr_destroy(&attr); + if (err) + { + LogMsg("Could not start SSLHandshake thread: (%d) %s", err, strerror(err)); + sock->handshake = handshake_completed; + sock->err = err; + KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry); + } + LogInfo("spawnSSLHandshake %p: done", sock); + return err; + } + mDNSlocal mDNSBool IsTunnelModeDomain(const domainname *d) { static const domainname *mmc = (const domainname*) "\x7" "members" "\x3" "mac" "\x3" "com"; @@ -1407,7 +2021,7 @@ mDNSlocal mDNSBool IsTunnelModeDomain(const domainname *d) mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context) { TCPSocket *sock = context; - mStatus err = mStatus_NoError; + sock->err = mStatus_NoError; //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter); //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter); @@ -1418,24 +2032,20 @@ mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context) { #ifndef NO_SECURITYFRAMEWORK if (!sock->setup) { sock->setup = mDNStrue; tlsSetupSock(sock, mDNSfalse); } - if (!sock->handshakecomplete) + + if (sock->handshake == handshake_required) { if (spawnSSLHandshake(sock) == 0) return; } + else if (sock->handshake == handshake_in_progress || sock->handshake == handshake_to_be_closed) return; + else if (sock->handshake != handshake_completed) { - //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; } + if (!sock->err) sock->err = mStatus_UnknownErr; + LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock->handshake); } #else - err = mStatus_UnsupportedErr; + sock->err = mStatus_UnsupportedErr; #endif /* NO_SECURITYFRAMEWORK */ } - - mDNSBool c = !sock->connected; - sock->connected = mDNStrue; - sock->callback(sock, sock->context, c, err); - // NOTE: the callback may call CloseConnection here, which frees the context structure! + + doTcpSocketCallback(sock); } mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef) @@ -1456,13 +2066,13 @@ 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); + LogInfo("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime); pthread_mutex_unlock(&m->p->BigMutex); char wake = 1; if (send(m->p->WakeKQueueLoopFD, &wake, sizeof(wake), 0) == -1) - LogMsg("ERROR: KQueueWake: send failed with error code: %d - %s", errno, strerror(errno)); + LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno, strerror(errno)); } mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port) @@ -1481,8 +2091,10 @@ mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, sock->flags = flags; sock->context = mDNSNULL; sock->setup = mDNSfalse; - sock->handshakecomplete = mDNSfalse; sock->connected = mDNSfalse; + sock->handshake = handshake_required; + sock->m = m; + sock->err = mStatus_NoError; if (sock->fd == -1) { @@ -1493,7 +2105,7 @@ mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, // Bind it struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); + mDNSPlatformMemZero(&addr, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = port->NotAnInteger; @@ -1505,7 +2117,7 @@ mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, 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)); + mDNSPlatformMemZero(&addr, sizeof(addr)); socklen_t len = sizeof(addr); if (getsockname(sock->fd, (struct sockaddr*) &addr, &len) < 0) { LogMsg("getsockname - %s", strerror(errno)); goto error; } @@ -1528,8 +2140,9 @@ mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, sock->callback = callback; sock->context = context; sock->setup = mDNSfalse; - sock->handshakecomplete = mDNSfalse; sock->connected = mDNSfalse; + sock->handshake = handshake_required; + sock->err = mStatus_NoError; (void) InterfaceID; //!!!KRS use this if non-zero!!! @@ -1545,13 +2158,6 @@ mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, 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)) - { - 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"; @@ -1583,7 +2189,10 @@ mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, 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)); + if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN) + LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock->fd, errno, strerror(errno)); + else + LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock->fd, errno, strerror(errno)); close(sock->fd); return mStatus_ConnFailed; } @@ -1601,7 +2210,7 @@ mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd) TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket)); if (!sock) return(mDNSNULL); - memset(sock, 0, sizeof(*sock)); + mDNSPlatformMemZero(sock, sizeof(*sock)); sock->fd = fd; sock->flags = flags; @@ -1630,10 +2239,18 @@ exit: mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock) { if (sock) - { + { #ifndef NO_SECURITYFRAMEWORK if (sock->tlsContext) { + if (sock->handshake == handshake_in_progress) // SSLHandshake thread using this sock (esp. tlsContext) + { + LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress"); + sock->handshake = handshake_to_be_closed; + } + if (sock->handshake == handshake_to_be_closed) + return; + SSLClose(sock->tlsContext); SSLDisposeContext(sock->tlsContext); sock->tlsContext = NULL; @@ -1658,15 +2275,9 @@ mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long bu if (sock->flags & kTCPSocketFlags_UseTLS) { #ifndef NO_SECURITYFRAMEWORK - if (!sock->handshakecomplete) - { - //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; } - } + if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; } + else if (sock->handshake == handshake_in_progress) return 0; + else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock->handshake); //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0)); mStatus err = SSLRead(sock->tlsContext, buf, buflen, (size_t*)&nread); @@ -1693,7 +2304,7 @@ mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long bu } // 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 if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno, strerror(errno)); nread = -1; } else // errno is EAGAIN (EWOULDBLOCK) -- no data available { nread = 0; @@ -1712,6 +2323,10 @@ mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned { #ifndef NO_SECURITYFRAMEWORK size_t processed; + if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; } + if (sock->handshake == handshake_in_progress) return 0; + else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock->handshake); + mStatus err = SSLWrite(sock->tlsContext, msg, len, &processed); if (!err) nsent = (int) processed; @@ -1743,7 +2358,6 @@ mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock) // If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport) { - const int ip_tosbits = IPTOS_LOWDELAY | IPTOS_THROUGHPUT; int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6; KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6; const int on = 1; @@ -1757,7 +2371,7 @@ mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa 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 (mDNSSameIPPort(port, MulticastDNSPort)) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)); + if (mDNSSameIPPort(port, MulticastDNSPort) || mDNSSameIPPort(port, NATPMPAnnouncementPort)) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)); if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; } if (sa_family == AF_INET) @@ -1782,21 +2396,20 @@ mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa 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 - err = setsockopt(skt, IPPROTO_IP, IP_TOS, &ip_tosbits, sizeof(ip_tosbits)); - if (err < 0) { errstr = "setsockopt - IP_TOS"; goto fail; } - // And start listening for packets struct sockaddr_in listening_sockaddr; listening_sockaddr.sin_family = AF_INET; listening_sockaddr.sin_port = port.NotAnInteger; // Pass in opaque ID without any byte swapping - listening_sockaddr.sin_addr.s_addr = 0; // Want to receive multicasts AND unicasts on this socket + listening_sockaddr.sin_addr.s_addr = mDNSSameIPPort(port, NATPMPAnnouncementPort) ? AllSystemsMcast.NotAnInteger : 0; err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr)); if (err) { errstr = "bind"; goto fail; } if (outport) outport->NotAnInteger = listening_sockaddr.sin_port; } else if (sa_family == AF_INET6) { + // NAT-PMP Announcements make no sense on IPv6, so bail early w/o error + if (mDNSSameIPPort(port, NATPMPAnnouncementPort)) { if (outport) *outport = zeroIPPort; return mStatus_NoError; } + // We want to receive destination addresses and receive interface identifiers err = setsockopt(skt, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)); if (err < 0) { errstr = "setsockopt - IPV6_PKTINFO"; goto fail; } @@ -1818,14 +2431,6 @@ mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa 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 - int tclass = IPTOS_LOWDELAY | IPTOS_THROUGHPUT; // This may not be right (since tclass is not implemented on OS X, I can't test it) - 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; } @@ -1857,15 +2462,19 @@ mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa fail: // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port)) - LogMsg("%s skt %d port %d error %ld errno %d (%s)", errstr, skt, mDNSVal16(port), err, errno, strerror(errno)); + LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr, skt, mDNSVal16(port), err, errno, strerror(errno)); - // If we got a "bind" failure 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."); + // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port + if (!strcmp(errstr, "bind") && errno == EADDRINUSE) + { + err = EADDRINUSE; + if (mDNSSameIPPort(port, MulticastDNSPort)) + NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed", + "Congratulations, you've reproduced an elusive bug.\r" + "Please contact the current assignee of .\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); @@ -1873,31 +2482,40 @@ mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport) { - int i; mStatus err; mDNSIPPort port = requestedport; + mDNSBool randomizePort = mDNSIPPortIsZero(requestedport); + int i = 10000; // Try at most 10000 times to get a unique random port UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket)); if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); } - memset(p, 0, sizeof(UDPSocket)); + mDNSPlatformMemZero(p, sizeof(UDPSocket)); p->ss.port = zeroIPPort; p->ss.m = m; p->ss.sktv4 = -1; p->ss.sktv6 = -1; - for (i=0; i<10000; i++) // Try at most 10000 times to get a unique random port + do { // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here - if (mDNSIPPortIsZero(requestedport)) port = mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF)); + if (randomizePort) port = mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF)); err = SetupSocket(&p->ss, port, AF_INET, &p->ss.port); - if (!err) break; - } + if (!err) + { + err = SetupSocket(&p->ss, port, AF_INET6, &p->ss.port); + if (err) { close(p->ss.sktv4); p->ss.sktv4 = -1; } + } + i--; + } while (err == EADDRINUSE && randomizePort && i); + if (err) { // In customer builds we don't want to log failures with port 5351, because this is a known issue // of failing to bind to this port when Internet Sharing has already bound to it - if (mDNSSameIPPort(requestedport, NATPMPPort)) - LogOperation("mDNSPlatformUDPSocket: SetupSocket %d failed error %ld errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno)); - else LogMsg ("mDNSPlatformUDPSocket: SetupSocket %d failed error %ld errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno)); + // We also don't want to log about port 5350, due to a known bug when some other + // process is bound to it. + if (mDNSSameIPPort(requestedport, NATPMPPort) || mDNSSameIPPort(requestedport, NATPMPAnnouncementPort)) + LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno)); + else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno)); freeL("UDPSocket", p); return(mDNSNULL); } @@ -1927,20 +2545,328 @@ mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock) #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - -#pragma mark - Key Management +#pragma mark - BPF Raw packet sending/receiving #endif -#ifndef NO_SECURITYFRAMEWORK -mDNSlocal CFArrayRef GetCertChain(SecIdentityRef identity) +#if APPLE_OSX_mDNSResponder + +mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID) { - 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); + if (!InterfaceID) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; } + NetworkInterfaceInfoOSX *info = (NetworkInterfaceInfoOSX *)InterfaceID; + if (info->BPF_fd < 0) + LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info->ifinfo.ifname, info->BPF_fd); else { - SecPolicySearchRef searchRef; + //LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname); + if (write(info->BPF_fd, msg, end - (mDNSu8 *)msg) < 0) + LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info->BPF_fd, errno, strerror(errno)); + } + } + +mDNSexport void mDNSPlatformSetLocalARP(const mDNSv4Addr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID) + { + if (!InterfaceID) { LogMsg("mDNSPlatformSetLocalARP: No InterfaceID specified"); return; } + NetworkInterfaceInfoOSX *info = (NetworkInterfaceInfoOSX *)InterfaceID; + // Manually inject an entry into our local ARP cache. + // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.) + mDNSBool makearp = mDNSv4AddressIsLinkLocal(tpa); + if (!makearp) + { + NetworkInterfaceInfoOSX *i; + for (i = info->m->p->InterfaceList; i; i = i->next) + if (i->Exists && i->ifinfo.InterfaceID == InterfaceID && i->ifinfo.ip.type == mDNSAddrType_IPv4) + if (((i->ifinfo.ip.ip.v4.NotAnInteger ^ tpa->NotAnInteger) & i->ifinfo.mask.ip.v4.NotAnInteger) == 0) + makearp = mDNStrue; + } + if (!makearp) + LogInfo("Don't need ARP entry for %s %.4a %.6a", info->ifinfo.ifname, tpa, tha); + else + { + int result = mDNSSetARP(info->scope_id, tpa->b, tha->b); + if (result) LogMsg("Set local ARP entry for %s %.4a %.6a failed: %d", info->ifinfo.ifname, tpa, tha, result); + else debugf ("Set local ARP entry for %s %.4a %.6a", info->ifinfo.ifname, tpa, tha); + } + } + +mDNSlocal void CloseBPF(NetworkInterfaceInfoOSX *const i) + { + LogSPS("%s closing BPF fd %d", i->ifinfo.ifname, i->BPF_fd); + + // Note: MUST NOT close() the underlying native BSD sockets. + // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because + // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them. + CFRunLoopRemoveSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode); + CFRelease(i->BPF_rls); + CFSocketInvalidate(i->BPF_cfs); + CFRelease(i->BPF_cfs); + i->BPF_fd = -1; + } + +mDNSlocal void bpf_callback(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context) + { + (void)cfs; + (void)CallBackType; + (void)address; + (void)data; + + NetworkInterfaceInfoOSX *const info = (NetworkInterfaceInfoOSX *)context; + KQueueLock(info->m); + + // Now we've got the lock, make sure the kqueue thread didn't close the fd out from under us (will not be a problem once the OS X + // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition). + if (info->BPF_fd < 0) goto exit; + + ssize_t n = read(info->BPF_fd, &info->m->imsg, info->BPF_len); + const mDNSu8 *ptr = (const mDNSu8 *)&info->m->imsg; + const mDNSu8 *end = (const mDNSu8 *)&info->m->imsg + n; + debugf("%3d: bpf_callback got %d bytes on %s", info->BPF_fd, n, info->ifinfo.ifname); + + if (n<0) + { + LogMsg("Closing %s BPF fd %d due to error %d (%s)", info->ifinfo.ifname, info->BPF_fd, errno, strerror(errno)); + CloseBPF(info); + goto exit; + } + + while (ptr < end) + { + const struct bpf_hdr *bh = (const struct bpf_hdr *)ptr; + debugf("%3d: bpf_callback bh_caplen %4d bh_datalen %4d remaining %4d", info->BPF_fd, bh->bh_caplen, bh->bh_datalen, end - (ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen))); + mDNSCoreReceiveRawPacket(info->m, ptr + bh->bh_hdrlen, ptr + bh->bh_hdrlen + bh->bh_caplen, info->ifinfo.InterfaceID); + ptr += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen); + } +exit: + KQueueUnlock(info->m, "bpf_callback"); + } + +#define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from) + +mDNSlocal int CountProxyTargets(mDNS *const m, NetworkInterfaceInfoOSX *x, int *p4, int *p6) + { + int numv4 = 0, numv6 = 0; + AuthRecord *rr; + + for (rr = m->ResourceRecords; rr; rr=rr->next) + if (rr->resrec.InterfaceID == (mDNSInterfaceID)x && rr->AddressProxy.type == mDNSAddrType_IPv4) + { + if (p4) LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s IP%2d %.4a", x->BPF_fd, x->ifinfo.ifname, numv4, &rr->AddressProxy.ip.v4); + numv4++; + } + + for (rr = m->ResourceRecords; rr; rr=rr->next) + if (rr->resrec.InterfaceID == (mDNSInterfaceID)x && rr->AddressProxy.type == mDNSAddrType_IPv6) + { + if (p6) LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s IP%2d %.16a", x->BPF_fd, x->ifinfo.ifname, numv6, &rr->AddressProxy.ip.v6); + numv6++; + } + + if (p4) *p4 = numv4; + if (p6) *p6 = numv6; + return(numv4 + numv6); + } + +mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID) + { + NetworkInterfaceInfoOSX *x; + for (x = m->p->InterfaceList; x; x = x->next) if (x == (NetworkInterfaceInfoOSX *)InterfaceID) break; + if (!x) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID); return; } + + #define MAX_BPF_ADDRS 250 + int numv4 = 0, numv6 = 0; + + if (CountProxyTargets(m, x, &numv4, &numv6) > MAX_BPF_ADDRS) + { + LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4, numv6); + if (numv4 > MAX_BPF_ADDRS) numv4 = MAX_BPF_ADDRS; + numv6 = MAX_BPF_ADDRS - numv4; + } + + LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC %.6a %d v4 %d v6", x->BPF_fd, x->ifinfo.ifname, &x->ifinfo.MAC, numv4, numv6); + + // Caution: This is a static structure, so we need to be careful that any modifications we make to it + // are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times + static struct bpf_insn filter[17 + MAX_BPF_ADDRS] = + { + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), // 0 Read Ethertype (bytes 12,13) + + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0806, 0, 1), // 1 If Ethertype == ARP goto next, else 3 + BPF_STMT(BPF_RET + BPF_K, 42), // 2 Return 42-byte ARP + + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0800, 4, 0), // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next + + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x86DD, 0, 9), // 4 If Ethertype == IPv6 goto next, else exit + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), // 5 Read Protocol and Hop Limit (bytes 20,21) + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x3AFF, 0, 9), // 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check + BPF_STMT(BPF_RET + BPF_K, 78), // 7 Return 78-byte ND + + // Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for + BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 30), // 8 Read IPv4 Dst (bytes 30,31,32,33) + }; + + struct bpf_insn *pc = &filter[9]; + struct bpf_insn *chk6 = pc + numv4 + 1; // numv4 address checks, plus a "return 0" + struct bpf_insn *fail = chk6 + 1 + numv6; // Get v6 Dst LSW, plus numv6 address checks + struct bpf_insn *ret4 = fail + 1; + struct bpf_insn *ret6 = ret4 + 4; + + static const struct bpf_insn rf = BPF_STMT(BPF_RET + BPF_K, 0); // No match: Return nothing + + static const struct bpf_insn g6 = BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 50); // Read IPv6 Dst LSW (bytes 50,51,52,53) + + static const struct bpf_insn r4a = BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14); // Get IP Header length (normally 20) + static const struct bpf_insn r4b = BPF_STMT(BPF_LD + BPF_IMM, 34); // A = 34 (14-byte Ethernet plus 20-byte TCP) + static const struct bpf_insn r4c = BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0); // A += IP Header length + static const struct bpf_insn r4d = BPF_STMT(BPF_RET + BPF_A, 0); // Success: Return Ethernet + IP + TCP + + static const struct bpf_insn r6a = BPF_STMT(BPF_RET + BPF_K, 94); // Success: Return Eth + IPv6 + TCP + 20 bytes spare + + BPF_SetOffset(&filter[4], jf, fail); // If Ethertype not ARP, IPv4, or IPv6, fail + BPF_SetOffset(&filter[6], jf, chk6); // If IPv6 but not ICMPv6, go to IPv6 address list check + + // BPF Byte-Order Note + // The BPF API designers apparently thought that programmers would not be smart enough to use htons + // and htonl correctly to convert numeric values to network byte order on little-endian machines, + // so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings + // that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc. + // As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API + // will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange + // that on little-endian machines we deliberately put addresses in memory with the bytes backwards, + // so that when the BPF API goes through and swaps them all, they end up back as they should be. + // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't* + // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly. + + AuthRecord *rr; + for (rr = m->ResourceRecords; rr; rr=rr->next) + if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4) + { + mDNSv4Addr a = rr->AddressProxy.ip.v4; + pc->code = BPF_JMP + BPF_JEQ + BPF_K; + BPF_SetOffset(pc, jt, ret4); + pc->jf = 0; + pc->k = (bpf_u_int32)a.b[0] << 24 | (bpf_u_int32)a.b[1] << 16 | (bpf_u_int32)a.b[2] << 8 | (bpf_u_int32)a.b[3]; + pc++; + } + *pc++ = rf; + + if (pc != chk6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc, chk6); + *pc++ = g6; // chk6 points here + + for (rr = m->ResourceRecords; rr; rr=rr->next) + if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6) + { + mDNSv6Addr a = rr->AddressProxy.ip.v6; + pc->code = BPF_JMP + BPF_JEQ + BPF_K; + BPF_SetOffset(pc, jt, ret6); + pc->jf = 0; + pc->k = (bpf_u_int32)a.b[12] << 24 | (bpf_u_int32)a.b[13] << 16 | (bpf_u_int32)a.b[14] << 8 | (bpf_u_int32)a.b[15]; + pc++; + } + + if (pc != fail) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc, fail); + *pc++ = rf; // fail points here + + if (pc != ret4) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc, ret4); + *pc++ = r4a; // ret4 points here + *pc++ = r4b; + *pc++ = r4c; + *pc++ = r4d; + + if (pc != ret6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc, ret6); + *pc++ = r6a; // ret6 points here + + struct bpf_program prog = { pc - filter, filter }; + +#if 0 + // For debugging BPF filter program + unsigned int q; + for (q=0; qtimenow == 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0"); + // Schedule check to see if we can close this BPF_fd now + if (!m->p->NetworkChanged) m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2); + // prog.bf_len = 0; This seems to panic the kernel + } + + if (ioctl(x->BPF_fd, BIOCSETF, &prog) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETF(%d) failed %d (%s)", prog.bf_len, errno, strerror(errno)); + else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETF(%d) successful", prog.bf_len); + } + +mDNSexport void mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd) + { + mDNS_Lock(m); + + NetworkInterfaceInfoOSX *i; + for (i = m->p->InterfaceList; i; i = i->next) if (i->BPF_fd == -2) break; + if (!i) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd); close(fd); } + else + { + LogSPS("%s using BPF fd %d", i->ifinfo.ifname, fd); + + struct bpf_version v; + if (ioctl(fd, BIOCVERSION, &v) < 0) + LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); + else if (BPF_MAJOR_VERSION != v.bv_major || BPF_MINOR_VERSION != v.bv_minor) + LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d", + fd, i->ifinfo.ifname, BPF_MAJOR_VERSION, BPF_MINOR_VERSION, v.bv_major, v.bv_minor); + + if (ioctl(fd, BIOCGBLEN, &i->BPF_len) < 0) + LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); + + if (i->BPF_len > sizeof(m->imsg)) + { + i->BPF_len = sizeof(m->imsg); + if (ioctl(fd, BIOCSBLEN, &i->BPF_len) < 0) + LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); + else LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", i->BPF_len); + } + + static const u_int opt_immediate = 1; + if (ioctl(fd, BIOCIMMEDIATE, &opt_immediate) < 0) + LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); + + struct ifreq ifr; + mDNSPlatformMemZero(&ifr, sizeof(ifr)); + strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name)); + if (ioctl(fd, BIOCSETIF, &ifr) < 0) + { LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); i->BPF_fd = -3; } + else + { + CFSocketContext myCFSocketContext = { 0, i, NULL, NULL, NULL }; + i->BPF_fd = fd; + i->BPF_cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, bpf_callback, &myCFSocketContext); + i->BPF_rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, i->BPF_cfs, 0); + CFRunLoopAddSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode); + mDNSPlatformUpdateProxyList(m, (mDNSInterfaceID)i); + } + } + + mDNS_Unlock(m); + } + +#endif // APPLE_OSX_mDNSResponder + +#if COMPILER_LIKES_PRAGMA_MARK +#pragma mark - +#pragma mark - Key Management +#endif + +#ifndef NO_SECURITYFRAMEWORK +mDNSlocal CFArrayRef GetCertChain(SecIdentityRef identity) + { + CFMutableArrayRef certChain = NULL; + if (!identity) { LogMsg("getCertChain: identity is NULL"); return(NULL); } + SecCertificateRef cert; + OSStatus err = SecIdentityCopyCertificate(identity, &cert); + if (err || !cert) LogMsg("getCertChain: SecIdentityCopyCertificate() returned %d", (int) err); + else + { + SecPolicySearchRef searchRef; err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef); if (err || !searchRef) LogMsg("getCertChain: SecPolicySearchCreate() returned %d", (int) err); else @@ -2058,12 +2984,13 @@ mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel) } } -mDNSlocal mDNSBool DDNSSettingEnabled(CFDictionaryRef dict) +mDNSexport mDNSBool DictionaryIsEnabled(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; } + if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val)) + { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse; } return val ? mDNStrue : mDNSfalse; } @@ -2101,7 +3028,9 @@ mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name) { mDNSEthAddr eth = zeroEthAddr; SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetBSSID"), NULL, NULL); - if (store) + if (!store) + LogMsg("GetBSSID: SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); + else { CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name); if (entityname) @@ -2121,6 +3050,73 @@ mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name) return(eth); } +mDNSlocal int GetMAC(mDNSEthAddr *eth, u_short ifindex) + { + struct ifaddrs *ifa; + for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next) + if (ifa->ifa_addr->sa_family == AF_LINK) + { + const struct sockaddr_dl *const sdl = (const struct sockaddr_dl *)ifa->ifa_addr; + if (sdl->sdl_index == ifindex) + { mDNSPlatformMemCopy(eth->b, sdl->sdl_data + sdl->sdl_nlen, 6); return 0; } + } + *eth = zeroEthAddr; + return -1; + } + +#ifndef SIOCGIFWAKEFLAGS +#define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */ +#endif + +#ifndef IF_WAKE_ON_MAGIC_PACKET +#define IF_WAKE_ON_MAGIC_PACKET 0x01 +#endif + +#ifndef ifr_wake_flags +#define ifr_wake_flags ifr_ifru.ifru_intval +#endif + +mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i) + { + if (!MulticastInterface(i) ) return(mDNSfalse); // We only use Sleep Proxy Service on multicast-capable interfaces + if (i->ifa_flags & IFF_LOOPBACK) return(mDNSfalse); // except loopback + + int s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { LogMsg("NetWakeInterface %s socket failed %s errno %d (%s)", i->ifinfo.ifname, errno, strerror(errno)); return(mDNSfalse); } + + struct ifreq ifr; + strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name)); + if (ioctl(s, SIOCGIFWAKEFLAGS, &ifr) < 0) + { + // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be + // 102 when compiling kernel code, and 45 when compiling user-level code. Since this + // error code is being returned from the kernel, we need to use the kernel version. + #define KERNEL_EOPNOTSUPP 102 + if (errno != KERNEL_EOPNOTSUPP) // "Operation not supported on socket", the expected result on Leopard and earlier + LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i->ifinfo.ifname, errno, strerror(errno)); + // If on Leopard or earlier, we get EOPNOTSUPP, so in that case + // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on. + ifr.ifr_wake_flags = (errno == KERNEL_EOPNOTSUPP && !(i)->BSSID.l[0] && i->m->SystemWakeOnLANEnabled) ? IF_WAKE_ON_MAGIC_PACKET : 0; + } +#if ASSUME_SNOWLEOPARD_INCORRECTLY_REPORTS_AIRPORT_INCAPABLE_OF_WAKE_ON_LAN + else + { + // Call succeeded. + // However, on SnowLeopard, it currently indicates incorrectly that AirPort is incapable of Wake-on-LAN. + // Therefore, for AirPort interfaces, we just track the system-wide Wake-on-LAN setting. + if ((i)->BSSID.l[0]) ifr.ifr_wake_flags = i->m->SystemWakeOnLANEnabled ? IF_WAKE_ON_MAGIC_PACKET : 0; + } +#endif + + close(s); + + // ifr.ifr_wake_flags = IF_WAKE_ON_MAGIC_PACKET; // For testing with MacBook Air, using a USB dongle that doesn't actually support Wake-On-LAN + + LogSPS("%-6s %#-14a %s WOMP", i->ifinfo.ifname, &i->ifinfo.ip, (ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) ? "supports" : "no"); + + return((ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) != 0); + } + // 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 @@ -2136,12 +3132,34 @@ mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifad NetworkInterfaceInfoOSX **p; for (p = &m->p->InterfaceList; *p; p = &(*p)->next) - if (scope_id == (*p)->scope_id && mDNSSameAddress(&ip, &(*p)->ifinfo.ip) && mDNSSameEthAddress(&bssid, &(*p)->BSSID)) + if (scope_id == (*p)->scope_id && + mDNSSameAddress(&ip, &(*p)->ifinfo.ip) && + mDNSSameEthAddress(&bssid, &(*p)->BSSID)) { debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p", 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; + + // If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected) + // we may need to start or stop or sleep proxy browse operation + const mDNSBool NetWake = NetWakeInterface(*p); + if ((*p)->ifinfo.NetWake != NetWake) + { + (*p)->ifinfo.NetWake = NetWake; + // If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly. + // If this interface is not already registered (i.e. it's a dormant interface we had in our list + // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet. + // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary. + if ((*p)->ifinfo.InterfaceID) + { + mDNS_Lock(m); + if (NetWake) mDNS_ActivateNetWake_internal (m, &(*p)->ifinfo); + else mDNS_DeactivateNetWake_internal(m, &(*p)->ifinfo); + mDNS_Unlock(m); + } + } + return(*p); } @@ -2149,28 +3167,35 @@ mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifad debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i); if (!i) return(mDNSNULL); mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX)); - i->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); // 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; 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; + // We can be configured to disable multicast advertisement, but we want to to support + // local-only services, which need a loopback address record. + i->ifinfo.Advertise = m->DivertMulticastAdvertisements ? ((ifa->ifa_flags & IFF_LOOPBACK) ? mDNStrue : mDNSfalse) : m->AdvertiseLocalAddresses; i->ifinfo.McastTxRx = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList i->next = mDNSNULL; + i->m = m; i->Exists = mDNStrue; - i->AppearanceTime = utc; // Brand new interface; AppearanceTime is now - i->LastSeen = utc; i->Flashing = mDNSfalse; i->Occulting = mDNSfalse; + i->AppearanceTime = utc; // Brand new interface; AppearanceTime is now + i->LastSeen = utc; + i->ifa_flags = ifa->ifa_flags; i->scope_id = scope_id; i->BSSID = bssid; i->sa_family = ifa->ifa_addr->sa_family; - i->ifa_flags = ifa->ifa_flags; + i->BPF_fd = -1; + i->BPF_len = 0; + + // Do this AFTER i->BSSID has been set up + i->ifinfo.NetWake = NetWakeInterface(i); + GetMAC(&i->ifinfo.MAC, scope_id); + if (i->ifinfo.NetWake && !i->ifinfo.MAC.l[0]) + LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i->ifinfo.MAC, scope_id, i->ifinfo.ifname, &ip); *p = i; return(i); @@ -2197,19 +3222,19 @@ mDNSlocal NetworkInterfaceInfoOSX *FindRoutableIPv4(mDNS *const m, mDNSu32 scope #define kRacoonPort 4500 -static mDNSBool AnonymousRacoonConfig = mDNSfalse; +static DomainAuthInfo* AnonymousRacoonConfig = mDNSNULL; #ifndef NO_SECURITYFRAMEWORK static CFMutableDictionaryRef domainStatusDict = NULL; // MUST be called with lock held -mDNSlocal void RemoveAutoTunnelDomainStatus(const DomainAuthInfo *const info) +mDNSlocal void RemoveAutoTunnelDomainStatus(const mDNS *const m, const DomainAuthInfo *const info) { char buffer[1024]; CFStringRef domain; - LogOperation("RemoveAutoTunnelDomainStatus: %##s", info->domain.c); + LogInfo("RemoveAutoTunnelDomainStatus: %##s", info->domain.c); if (!domainStatusDict) { LogMsg("RemoveAutoTunnelDomainStatus: No domainStatusDict"); return; } @@ -2220,13 +3245,28 @@ mDNSlocal void RemoveAutoTunnelDomainStatus(const DomainAuthInfo *const info) if (CFDictionaryContainsKey(domainStatusDict, domain)) { CFDictionaryRemoveValue(domainStatusDict, domain); - mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, domainStatusDict); + if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict); } CFRelease(domain); } #endif // ndef NO_SECURITYFRAMEWORK +mDNSlocal mStatus CheckQuestionForStatus(const DNSQuestion *const q) + { + if (q->LongLived) + { + if (q->nta || (q->servAddr.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsOnes(q->servAddr.ip.v4))) + return mStatus_NoSuchRecord; + else if (q->state == LLQ_Poll) + return mStatus_PollingMode; + else if (q->state != LLQ_Established && !q->DuplicateOf) + return mStatus_TransientErr; + } + + return mStatus_NoError; +} + // MUST be called with lock held mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAuthInfo *const info) { @@ -2326,17 +3366,36 @@ mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAut } } } + if (tun || llq) + { + mDNSu32 code = m->LastNATMapResultCode; + + num = CFNumberCreate(NULL, kCFNumberSInt32Type, &code); + if (!num) + LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode"); + else + { + CFDictionarySetValue(dict, CFSTR("LastNATMapResultCode"), num); + CFRelease(num); + } + } if (!llq && !tun) { status = mStatus_NotInitializedErr; mDNS_snprintf(buffer, sizeof(buffer), "Neither LLQ nor AutoTunnel NAT port mapping is currently active"); - } + } else if ((llq && llq->Result == mStatus_DoubleNAT) || (tun && tun->Result == mStatus_DoubleNAT)) { status = mStatus_DoubleNAT; mDNS_snprintf(buffer, sizeof(buffer), "Double NAT: Router is reporting an external address"); } + else if ((llq && llq->Result == mStatus_NATPortMappingDisabled) || (tun && tun->Result == mStatus_NATPortMappingDisabled) || + (m->LastNATMapResultCode == NATErr_Refused && ((llq && !llq->Result && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && !tun->Result && mDNSIPPortIsZero(tun->ExternalPort))))) + { + status = mStatus_NATPortMappingDisabled; + mDNS_snprintf(buffer, sizeof(buffer), "NAT-PMP is disabled on the router"); + } else if ((llq && llq->Result) || (tun && tun->Result)) { status = mStatus_NATTraversal; @@ -2359,23 +3418,20 @@ mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAut } else { - DNSQuestion* q; + DNSQuestion* q, *worst_q = mDNSNULL; for (q = m->Questions; q; q=q->next) - if (q->LongLived && q->AuthInfo == info && q->state == LLQ_Poll) + if (q->AuthInfo == info) { - status = mStatus_PollingMode; - mDNS_snprintf(buffer, sizeof(buffer), "Query polling %##s", q->qname.c); - break; + mStatus newStatus = CheckQuestionForStatus(q); + if (newStatus == mStatus_NoSuchRecord) { status = newStatus; worst_q = q; break; } + else if (newStatus == mStatus_PollingMode) { status = newStatus; worst_q = q; } + else if (newStatus == mStatus_TransientErr && status == mStatus_NoError) { status = newStatus; worst_q = q; } } - if (status == mStatus_NoError) - for (q = m->Questions; q; q=q->next) - if (q->LongLived && q->AuthInfo == info && q->state != LLQ_Established && !q->DuplicateOf) - { - status = mStatus_TransientErr; - mDNS_snprintf(buffer, sizeof(buffer), "Query not yet established %##s", q->qname.c); - break; - } - if (status == mStatus_NoError) mDNS_snprintf(buffer, sizeof(buffer), "Success"); + + if (status == mStatus_NoError) mDNS_snprintf(buffer, sizeof(buffer), "Success"); + else if (status == mStatus_NoSuchRecord) mDNS_snprintf(buffer, sizeof(buffer), "GetZoneData %s: %##s", worst_q->nta ? "not yet complete" : "failed", worst_q->qname.c); + else if (status == mStatus_PollingMode) mDNS_snprintf(buffer, sizeof(buffer), "Query polling %##s", worst_q->qname.c); + else if (status == mStatus_TransientErr) mDNS_snprintf(buffer, sizeof(buffer), "Query not yet established %##s", worst_q->qname.c); } num = CFNumberCreate(NULL, kCFNumberSInt32Type, &status); @@ -2400,13 +3456,19 @@ mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAut !CFEqual(dict, (CFMutableDictionaryRef)CFDictionaryGetValue(domainStatusDict, domain))) { CFDictionarySetValue(domainStatusDict, domain, dict); - mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, domainStatusDict); + if (!m->ShutdownTime) + { + static char statusBuf[16]; + mDNS_snprintf(statusBuf, sizeof(statusBuf), "%d", (int)status); + mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.domainstatus", status ? "failure" : "success", statusBuf, ""); + mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict); + } } CFRelease(domain); CFRelease(dict); - LogOperation("UpdateAutoTunnelDomainStatus: %s", buffer); + debugf("UpdateAutoTunnelDomainStatus: %s", buffer); #endif // def NO_SECURITYFRAMEWORK } @@ -2432,6 +3494,15 @@ mDNSlocal mDNSBool TunnelServers(mDNS *const m) DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, p->RR_SRV.resrec.name); if (AuthInfo && AuthInfo->AutoTunnel && !AuthInfo->deltime) return(mDNStrue); } + + AuthRecord *r; + for (r = m->ResourceRecords; r; r = r->next) + if (r->resrec.rrtype == kDNSType_SRV) + { + DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, r->resrec.name); + if (AuthInfo && AuthInfo->AutoTunnel && !AuthInfo->deltime) return(mDNStrue); + } + return(mDNSfalse); } @@ -2450,7 +3521,7 @@ mDNSlocal void RegisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info) if (info->AutoTunnelNAT.clientContext && !info->AutoTunnelNAT.Result && !mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort) && AutoTunnelUnregistered(info)) { mStatus err; - LogOperation("RegisterAutoTunnelRecords %##s (%#s)", info->domain.c, m->hostlabel.c); + LogInfo("RegisterAutoTunnelRecords %##s (%#s)", info->domain.c, m->hostlabel.c); // 1. Set up our address record for the internal tunnel address // (User-visible user-friendly host name, used as target in AutoTunnel SRV records) @@ -2460,7 +3531,7 @@ mDNSlocal void RegisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info) info->AutoTunnelHostRecord.resrec.rdata->u.ipv6 = m->AutoTunnelHostAddr; 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); + if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelHostRecord %##s", err, info->AutoTunnelHostRecord.namestorage.c); // 2. Set up device info record ConstructServiceName(&info->AutoTunnelDeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &info->domain); @@ -2496,7 +3567,7 @@ mDNSlocal void RegisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info) err = mDNS_Register(m, &info->AutoTunnelService); if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c); - LogOperation("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]", + LogInfo("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); } @@ -2504,7 +3575,7 @@ mDNSlocal void RegisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info) mDNSlocal void DeregisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info) { - LogOperation("DeregisterAutoTunnelRecords %##s", info->domain.c); + LogInfo("DeregisterAutoTunnelRecords %##s", info->domain.c); if (info->AutoTunnelService.resrec.RecordType > kDNSRecordTypeDeregistering) { mStatus err = mDNS_Deregister(m, &info->AutoTunnelService); @@ -2545,7 +3616,7 @@ mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mSt DomainAuthInfo *info = (DomainAuthInfo *)rr->RecordContext; if (result == mStatus_MemFree) { - LogOperation("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr)); + LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr)); // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister if (rr == &info->AutoTunnelHostRecord) { @@ -2556,28 +3627,35 @@ mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mSt } } +// Determine whether we need racoon to accept incoming connections +mDNSlocal void UpdateConfigureServer(mDNS *m) + { + DomainAuthInfo *info; + + for (info = m->AuthInfoList; info; info = info->next) + if (info->AutoTunnel && !info->deltime && !mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort)) + break; + + if (info != AnonymousRacoonConfig) + { + AnonymousRacoonConfig = info; + // Create or revert configuration file, and start (or SIGHUP) Racoon + (void)mDNSConfigureServer(AnonymousRacoonConfig ? kmDNSUp : kmDNSDown, AnonymousRacoonConfig ? &AnonymousRacoonConfig->domain : mDNSNULL); + } + } + mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n) { DomainAuthInfo *info = (DomainAuthInfo *)n->clientContext; - LogOperation("AutoTunnelNATCallback Result %d %.4a Internal %d External %d %#s.%##s", + LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d %#s.%##s", n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort), m->hostlabel.c, info->domain.c); m->NextSRVUpdate = NonZeroTime(m->timenow); DeregisterAutoTunnelRecords(m,info); RegisterAutoTunnelRecords(m,info); + + UpdateConfigureServer(m); - // 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 : ""); - } - UpdateAutoTunnelDomainStatus(m, (DomainAuthInfo *)n->clientContext); } @@ -2585,7 +3663,7 @@ mDNSlocal void AbortDeregistration(mDNS *const m, AuthRecord *rr) { if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) { - LogOperation("Aborting deregistration of %s", ARDisplayString(m, rr)); + LogInfo("Aborting deregistration of %s", ARDisplayString(m, rr)); CompleteDeregistration(m, rr); } else if (rr->resrec.RecordType != kDNSRecordTypeUnregistered) @@ -2597,13 +3675,13 @@ mDNSlocal void AbortDeregistration(mDNS *const m, AuthRecord *rr) // Must be called with the lock held mDNSexport void SetupLocalAutoTunnelInterface_internal(mDNS *const m) { - LogOperation("SetupLocalAutoTunnelInterface"); + LogInfo("SetupLocalAutoTunnelInterface"); // 1. Configure the local IPv6 address if (!m->AutoTunnelHostAddrActive) { m->AutoTunnelHostAddrActive = mDNStrue; - LogOperation("Setting up AutoTunnel address %.16a", &m->AutoTunnelHostAddr); + LogInfo("Setting up AutoTunnel address %.16a", &m->AutoTunnelHostAddr); (void)mDNSAutoTunnelInterfaceUpDown(kmDNSUp, m->AutoTunnelHostAddr.b); } @@ -2641,7 +3719,7 @@ mDNSexport void SetupLocalAutoTunnelInterface_internal(mDNS *const m) 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)); + 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), SkipLeadingLabels(&tun->dstname, 1))); } // If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine @@ -2654,14 +3732,14 @@ mDNSlocal void ReissueBlockedQuestionWithType(mDNS *const m, domainname *d, mDNS { if (q->NoAnswer == NoAnswer_Suspended && q->qtype == qtype && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d)) { - LogOperation("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); + LogInfo("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); mDNSQuestionCallback *tmp = q->QuestionCallback; q->QuestionCallback = AutoTunnelCallback; // Set QuestionCallback to suppress another call back to AddNewClientTunnel mDNS_StopQuery(m, q); mDNS_StartQuery(m, q); q->QuestionCallback = tmp; // Restore QuestionCallback back to the real value if (!success) q->NoAnswer = NoAnswer_Fail; - // When we call mDNS_StopQuery, it's possible for other subbordinate questions like the GetZoneData query to be cancelled too. + // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too. // In general we have to assume that the question list might have changed in arbitrary ways. // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is // already in use. The safest solution is just to go back to the start of the list and start again. @@ -2691,21 +3769,24 @@ mDNSlocal void UnlinkAndReissueBlockedQuestions(mDNS *const m, ClientTunnel *tun while (*p != tun && *p) p = &(*p)->next; if (*p) *p = tun->next; ReissueBlockedQuestions(m, &tun->dstname, success); - LogOperation("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun); + LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun); 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); + LogInfo("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 (%s)", question->qname.c, DNSTypeName(question->qtype)); + LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); + static char msgbuf[16]; + mDNS_snprintf(msgbuf, sizeof(msgbuf), "%s lookup", DNSTypeName(question->qtype)); + mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.config", "failure", msgbuf, ""); UnlinkAndReissueBlockedQuestions(m, tun, mDNSfalse); return; } @@ -2714,13 +3795,13 @@ mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const R { if (mDNSSameIPv6Address(answer->rdata->u.ipv6, m->AutoTunnelHostAddr)) { - LogOperation("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6); + LogInfo("AutoTunnelCallback: suppressing 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); + LogInfo("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; @@ -2728,7 +3809,7 @@ mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const R } else if (question->qtype == kDNSType_SRV) { - LogOperation("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c); + LogInfo("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; @@ -2737,7 +3818,7 @@ mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const R else if (question->qtype == kDNSType_A) { ClientTunnel *old = mDNSNULL; - LogOperation("AutoTunnelCallback: SRV target addr %.4a", &answer->rdata->u.ipv4); + LogInfo("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; @@ -2755,7 +3836,7 @@ mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const R 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); + LogInfo("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); @@ -2765,21 +3846,24 @@ mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const R !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); + LogInfo("Deleting existing AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner); AutoTunnelSetKeys(old, mDNSfalse); } else needSetKeys = mDNSfalse; - LogOperation("AutoTunnelCallback: Disposing ClientTunnel %p", tun); + LogInfo("AutoTunnelCallback: Disposing ClientTunnel %p", tun); freeL("ClientTunnel", old); } } - if (needSetKeys) LogOperation("New AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner); + if (needSetKeys) LogInfo("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; + static char msgbuf[32]; + mDNS_snprintf(msgbuf, sizeof(msgbuf), "Tunnel setup - %d", result); + mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.config", result ? "failure" : "success", msgbuf, ""); // Kick off any questions that were held pending this tunnel setup ReissueBlockedQuestions(m, &tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse); } @@ -2799,7 +3883,6 @@ mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q) 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; // We intentionally build list in reverse order @@ -2815,7 +3898,7 @@ mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q) p->q.QuestionCallback = AutoTunnelCallback; p->q.QuestionContext = p; - LogOperation("AddNewClientTunnel start tun %p %##s (%s)%s", p, &q->qname.c, DNSTypeName(q->qtype), q->LongLived ? " LongLived" : ""); + LogInfo("AddNewClientTunnel start tun %p %##s (%s)%s", p, &q->qname.c, DNSTypeName(q->qtype), q->LongLived ? " LongLived" : ""); mDNS_StartQuery_internal(m, &p->q); } @@ -2826,32 +3909,6 @@ mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q) #pragma mark - Power State & Configuration Change Management #endif -mDNSlocal void GenerateDefaultName(const mDNSEthAddr PrimaryMAC, char *buffer, mDNSu32 length) -{ - char hwName[32]; - size_t hwNameLen = sizeof(hwName); - - hwName[0] = 0; - if (sysctlbyname("hw.model", &hwName, &hwNameLen, NULL, 0) == 0) - { - // hw.model contains a number like iMac6,1. We want the "iMac" part. - hwName[sizeof(hwName) - 1] = 0; - char *ptr; - for (ptr = hwName; *ptr != 0; ptr++) - { - if (*ptr >= '0' && *ptr <= '9') *ptr = 0; - if (*ptr == ',') break; - } - // Prototype model names do not contain commas, do not use prototype names - if (*ptr != ',') hwName[0] = 0; - } - - if (hwName[0] == 0) strlcpy(hwName, "Device", sizeof(hwName)); - - mDNS_snprintf(buffer, length, "%s-%02X%02X%02X%02X%02X%02X", hwName, - PrimaryMAC.b[0], PrimaryMAC.b[1], PrimaryMAC.b[2], PrimaryMAC.b[3], PrimaryMAC.b[4], PrimaryMAC.b[5]); -} - mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc) { mDNSBool foundav4 = mDNSfalse; @@ -2859,13 +3916,12 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc) struct ifaddrs *ifa = myGetIfAddrs(1); struct ifaddrs *v4Loopback = NULL; struct ifaddrs *v6Loopback = NULL; - mDNSEthAddr PrimaryMAC = zeroEthAddr; char defaultname[64]; #ifndef NO_IPV6 int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0); if (InfoSocket < 3 && errno != EAFNOSUPPORT) LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno)); #endif - if (m->SleepState) ifa = NULL; + if (m->SleepState == SleepState_Sleeping) ifa = NULL; while (ifa) { @@ -2896,8 +3952,8 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc) if (ifa->ifa_addr->sa_family == AF_LINK) { struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr; - if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(PrimaryMAC) && mDNSSameEthAddress(&PrimaryMAC, &zeroEthAddr)) - mDNSPlatformMemCopy(PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6); + if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == sizeof(m->PrimaryMAC) && mDNSSameEthAddress(&m->PrimaryMAC, &zeroEthAddr)) + mDNSPlatformMemCopy(m->PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6); } if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr) @@ -2950,7 +4006,7 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc) else { NetworkInterfaceInfoOSX *i = AddInterfaceToList(m, ifa, utc); - if (i && MulticastInterface(i)) + if (i && MulticastInterface(i) && i->ifinfo.Advertise) { if (ifa->ifa_addr->sa_family == AF_INET) foundav4 = mDNStrue; else foundav6 = mDNStrue; @@ -2962,7 +4018,7 @@ 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 and advertising if (!foundav4 && v4Loopback) AddInterfaceToList(m, v4Loopback, utc); if (!foundav6 && v6Loopback) AddInterfaceToList(m, v6Loopback, utc); @@ -2987,7 +4043,7 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc) #endif // If we haven't set up AutoTunnelHostAddr yet, do it now - if (!mDNSSameEthAddress(&PrimaryMAC, &zeroEthAddr) && m->AutoTunnelHostAddr.b[0] == 0) + if (!mDNSSameEthAddress(&m->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); @@ -2997,21 +4053,22 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc) 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[0x8] = m->PrimaryMAC.b[0] ^ 0x02; // See RFC 3513, Appendix A for explanation + m->AutoTunnelHostAddr.b[0x9] = m->PrimaryMAC.b[1]; + m->AutoTunnelHostAddr.b[0xA] = m->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->AutoTunnelHostAddr.b[0xD] = m->PrimaryMAC.b[3]; + m->AutoTunnelHostAddr.b[0xE] = m->PrimaryMAC.b[4]; + m->AutoTunnelHostAddr.b[0xF] = m->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); + LogInfo("m->AutoTunnelLabel %#s", m->AutoTunnelLabel.c); } - GenerateDefaultName(PrimaryMAC, defaultname, sizeof(defaultname)); + mDNS_snprintf(defaultname, sizeof(defaultname), "%.*s-%02X%02X%02X%02X%02X%02X", HINFO_HWstring_prefixlen, HINFO_HWstring, + m->PrimaryMAC.b[0], m->PrimaryMAC.b[1], m->PrimaryMAC.b[2], m->PrimaryMAC.b[3], m->PrimaryMAC.b[4], m->PrimaryMAC.b[5]); // Set up the nice label domainlabel nicelabel; @@ -3019,7 +4076,7 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc) GetUserSpecifiedFriendlyComputerName(&nicelabel); if (nicelabel.c[0] == 0) { - LogMsg("Couldn't read user-specified Computer Name; using default “%s” instead", defaultname); + debugf("Couldn’t read user-specified Computer Name; using default “%s” instead", defaultname); MakeDomainLabelFromLiteralString(&nicelabel, defaultname); } @@ -3029,7 +4086,7 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc) GetUserSpecifiedLocalHostName(&hostlabel); if (hostlabel.c[0] == 0) { - LogMsg("Couldn't read user-specified local hostname; using default “%s.local” instead", defaultname); + debugf("Couldn’t read user-specified Local Hostname; using default “%s.local” instead", defaultname); MakeDomainLabelFromLiteralString(&hostlabel, defaultname); } @@ -3042,7 +4099,7 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc) else { if (m->p->usernicelabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot - LogMsg("User updated Computer Name from %#s to %#s", m->p->usernicelabel.c, nicelabel.c); + LogMsg("User updated Computer Name from “%#s” to “%#s”", m->p->usernicelabel.c, nicelabel.c); m->p->usernicelabel = m->nicelabel = nicelabel; namechange = mDNStrue; } @@ -3052,7 +4109,7 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc) else { if (m->p->userhostlabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot - LogMsg("User updated Local Hostname from %#s to %#s", m->p->userhostlabel.c, hostlabel.c); + LogMsg("User updated Local Hostname from “%#s” to “%#s”", m->p->userhostlabel.c, hostlabel.c); m->p->userhostlabel = m->hostlabel = hostlabel; mDNS_SetFQDN(m); namechange = mDNStrue; @@ -3066,12 +4123,11 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc) if (info->AutoTunnelNAT.clientContext && !mDNSIPv4AddressIsOnes(info->AutoTunnelNAT.ExternalAddress)) AutoTunnelNATCallback(m, &info->AutoTunnelNAT); } -#endif +#endif // APPLE_OSX_mDNSResponder 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) @@ -3087,7 +4143,6 @@ 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) @@ -3098,8 +4153,8 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc) if (i->Exists) { NetworkInterfaceInfo *const n = &i->ifinfo; - NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, AAAA_OVER_V4 ? AF_UNSPEC : i->sa_family); - if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifa_name); + NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AAAA_OVER_V4 ? AF_UNSPEC : i->sa_family); + if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifinfo.ifname); if (n->InterfaceID && n->InterfaceID != (mDNSInterfaceID)primary) // Sanity check { @@ -3109,7 +4164,7 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc) if (!n->InterfaceID) { - // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface, + // 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. // If n->InterfaceID is NOT set, then we haven't registered it and we should not try to deregister it n->InterfaceID = (mDNSInterfaceID)primary; @@ -3120,21 +4175,21 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc) 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), + if (!mDNSAddressIsLinkLocal(&n->ip)) count++; + LogInfo("SetupActiveInterfaces: Registered %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s", + i->ifinfo.ifname, i->scope_id, &i->BSSID, primary, &n->ip, CountMaskBits(&n->mask), i->Flashing ? " (Flashing)" : "", i->Occulting ? " (Occulting)" : "", n->InterfaceActive ? " (Primary)" : ""); if (!n->McastTxRx) - debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i->ifa_name, i->scope_id, &i->BSSID, primary, &n->ip); + debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i->ifinfo.ifname, i->scope_id, &i->BSSID, primary, &n->ip); else { if (i->sa_family == AF_INET) { struct ip_mreq imr; - primary->ifa_v4addr.s_addr = i->ifinfo.ip.ip.v4.NotAnInteger; + primary->ifa_v4addr.s_addr = n->ip.ip.v4.NotAnInteger; imr.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger; imr.imr_interface = primary->ifa_v4addr; @@ -3148,19 +4203,19 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc) // because by the time we get the configuration change notification, the interface is already gone, // so attempts to unsubscribe fail with EADDRNOTAVAIL (errno 49 "Can't assign requested address"). // IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces - if (SearchForInterfaceByName(m, i->ifa_name, AF_INET) == i) + if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET) == i) { - LogOperation("SetupActiveInterfaces: %5s(%lu) Doing precautionary IP_DROP_MEMBERSHIP for %.4a on %.4a", i->ifa_name, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface); + LogInfo("SetupActiveInterfaces: %5s(%lu) Doing precautionary IP_DROP_MEMBERSHIP for %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface); mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_DROP_MEMBERSHIP, &imr, sizeof(imr)); - if (err < 0 && (errno != EADDRNOTAVAIL || LogAllOperations)) - LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %ld errno %d (%s)", err, errno, strerror(errno)); + if (err < 0 && (errno != EADDRNOTAVAIL)) + LogMsg("setsockopt - IP_DROP_MEMBERSHIP error %d errno %d (%s)", err, errno, strerror(errno)); } - LogOperation("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i->ifa_name, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface); + LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv4 mcast group %.4a on %.4a", i->ifinfo.ifname, i->scope_id, &imr.imr_multiaddr, &imr.imr_interface); mStatus err = setsockopt(m->p->permanentsockets.sktv4, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(imr)); // Joining same group twice can give "Address already in use" error -- no need to report that - if (err < 0 && (errno != EADDRINUSE || LogAllOperations)) - LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %ld errno %d (%s) group %.4a on %.4a", err, errno, strerror(errno), &imr.imr_multiaddr, &imr.imr_interface); + if (err < 0 && (errno != EADDRINUSE)) + LogMsg("setsockopt - IP_ADD_MEMBERSHIP error %d errno %d (%s) group %.4a on %.4a", err, errno, strerror(errno), &imr.imr_multiaddr, &imr.imr_interface); } #ifndef NO_IPV6 if (i->sa_family == AF_INET6) @@ -3169,24 +4224,25 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc) i6mr.ipv6mr_interface = primary->scope_id; i6mr.ipv6mr_multiaddr = *(struct in6_addr*)&AllDNSLinkGroup_v6.ip.v6; - if (SearchForInterfaceByName(m, i->ifa_name, AF_INET6) == i) + if (SearchForInterfaceByName(m, i->ifinfo.ifname, AF_INET6) == i) { - LogOperation("SetupActiveInterfaces: %5s(%lu) Doing precautionary IPV6_LEAVE_GROUP for %.16a on %u", i->ifa_name, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface); + LogInfo("SetupActiveInterfaces: %5s(%lu) Doing precautionary IPV6_LEAVE_GROUP for %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface); mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr)); - if (err < 0 && (errno != EADDRNOTAVAIL || LogAllOperations)) - LogMsg("setsockopt - IPV6_LEAVE_GROUP error %ld errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface); + if (err < 0 && (errno != EADDRNOTAVAIL)) + LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface); } - LogOperation("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i->ifa_name, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface); + LogInfo("SetupActiveInterfaces: %5s(%lu) joining IPv6 mcast group %.16a on %u", i->ifinfo.ifname, i->scope_id, &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface); mStatus err = setsockopt(m->p->permanentsockets.sktv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr)); // Joining same group twice can give "Address already in use" error -- no need to report that - if (err < 0 && (errno != EADDRINUSE || LogAllOperations)) - LogMsg("setsockopt - IPV6_JOIN_GROUP error %ld errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface); + if (err < 0 && (errno != EADDRINUSE)) + LogMsg("setsockopt - IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface); } #endif } } } + return count; } @@ -3213,13 +4269,13 @@ mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc) for (i = m->p->InterfaceList; i; i = i->next) { // If this interface is no longer active, or its InterfaceID is changing, deregister it - NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifa_name, AAAA_OVER_V4 ? AF_UNSPEC : i->sa_family); + NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(m, i->ifinfo.ifname, AAAA_OVER_V4 ? AF_UNSPEC : i->sa_family); if (i->ifinfo.InterfaceID) if (i->Exists == 0 || i->Exists == 2 || i->ifinfo.InterfaceID != (mDNSInterfaceID)primary) { 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, + LogInfo("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s%s", + i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), i->Flashing ? " (Flashing)" : "", i->Occulting ? " (Occulting)" : "", @@ -3227,7 +4283,7 @@ mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc) mDNS_DeregisterInterface(m, &i->ifinfo, i->Flashing && i->Occulting); if (!mDNSAddressIsLinkLocal(&i->ifinfo.ip)) count++; i->ifinfo.InterfaceID = mDNSNULL; - // NOTE: If i->ifinfo.InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface, + // Note: If i->ifinfo.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. // If i->ifinfo.InterfaceID is NOT set, then it's not registered and we should not call mDNS_DeregisterInterface() on it. @@ -3247,14 +4303,16 @@ mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc) { if (i->LastSeen == utc) i->LastSeen = utc - 1; mDNSBool delete = (NumCacheRecordsForInterfaceID(m, (mDNSInterfaceID)i) == 0) && (utc - i->LastSeen >= 60); - LogOperation("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p %#a/%d Age %d%s", delete ? "Deleting" : "Holding", - i->ifa_name, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, + LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p %#a/%d Age %d%s", delete ? "Deleting" : "Holding", + i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen, i->ifinfo.InterfaceActive ? " (Primary)" : ""); +#if APPLE_OSX_mDNSResponder + if (i->BPF_fd >= 0) CloseBPF(i); +#endif // APPLE_OSX_mDNSResponder if (delete) { *p = i->next; - if (i->ifa_name) freeL("NetworkInterfaceInfoOSX name", i->ifa_name); freeL("NetworkInterfaceInfoOSX", i); continue; // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop } @@ -3278,6 +4336,14 @@ mDNSlocal void AppendDNameListElem(DNameListElem ***List, mDNSu32 uid, domainnam } } +mDNSlocal int compare_dns_configs(const void *aa, const void *bb) + { + dns_resolver_t *a = *(dns_resolver_t**)aa; + dns_resolver_t *b = *(dns_resolver_t**)bb; + + return (a->search_order < b->search_order) ? -1 : (a->search_order == b->search_order) ? 0 : 1; + } + mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains) { int i; @@ -3289,18 +4355,28 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN 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" : ""); + LogInfo("mDNSPlatformSetDNSConfig:%s%s%s%s%s", + setservers ? " setservers" : "", + setsearch ? " setsearch" : "", + fqdn ? " fqdn" : "", + RegDomains ? " RegDomains" : "", + BrowseDomains ? " BrowseDomains" : ""); // 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); + struct ifaddrs *ifa = mDNSNULL; + struct sockaddr_in saddr; + mDNSPlatformMemZero(&saddr, sizeof(saddr)); + saddr.sin_len = sizeof(saddr); + saddr.sin_family = AF_INET; + saddr.sin_port = 0; + saddr.sin_addr.s_addr = *(in_addr_t *)&m->Router.ip.v4; + + // Don't add any reverse-IP search domains if doing the WAB bootstrap queries would cause dial-on-demand connection initiation + if (!AddrRequiresPPPConnection((struct sockaddr *)&saddr)) ifa = myGetIfAddrs(1); + while (ifa) { mDNSAddr a, n; @@ -3336,101 +4412,119 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN // 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"); + if (OSXVers > OSXVers_10_3_Panther && (mDNSu32)mDNSPlatformRawTime() > (mDNSu32)(mDNSPlatformOneSecond * 180)) + LogMsg("mDNSPlatformSetDNSConfig: Error: dns_configuration_copy returned NULL"); } else { - LogOperation("mDNSPlatformSetDNSConfig: config->n_resolver = %d", config->n_resolver); + LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d", config->n_resolver); + if (setsearch && config->n_resolver) + { + // 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]); + } + +#if APPLE_OSX_mDNSResponder + // Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up + // by someone using Microsoft Active Directory using "local" as a private internal top-level domain + if (config->n_resolver && config->resolver[0]->domain && config->resolver[0]->n_nameserver && config->resolver[0]->nameserver[0]) + MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, config->resolver[0]->domain); + else ActiveDirectoryPrimaryDomain.c[0] = 0; + //MakeDomainNameFromDNSNameString(&ActiveDirectoryPrimaryDomain, "test.local"); + ActiveDirectoryPrimaryDomainLabelCount = CountLabels(&ActiveDirectoryPrimaryDomain); + if (config->n_resolver && config->resolver[0]->n_nameserver && SameDomainName(SkipLeadingLabels(&ActiveDirectoryPrimaryDomain, ActiveDirectoryPrimaryDomainLabelCount - 1), &localdomain)) + SetupAddr(&ActiveDirectoryPrimaryDomainServer, config->resolver[0]->nameserver[0]); + else + { + AssignDomainName(&ActiveDirectoryPrimaryDomain, (const domainname *)""); + ActiveDirectoryPrimaryDomainLabelCount = 0; + ActiveDirectoryPrimaryDomainServer = zeroAddr; + } +#endif + if (setservers) { + // For the "default" resolver ("resolver #1") the "domain" value is bogus and we need to ignore it. + // e.g. the default resolver's "domain" value might say "apple.com", which indicates that this resolver + // is only for names that fall under "apple.com", but that's not correct. Actually the default resolver is + // for all names not covered by a more specific resolver (i.e. its domain should be ".", the root domain). + if (config->n_resolver && config->resolver[0]->domain) + config->resolver[0]->domain[0] = 0; // don't stop pointing at the memory, just change the first byte + + qsort(config->resolver, config->n_resolver, sizeof(dns_resolver_t*), compare_dns_configs); + for (i = 0; i < config->n_resolver; i++) { - int j, n; + int 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) + mDNSInterfaceID interface = mDNSInterface_Any; + int disabled = 0; + + // On Tiger, dnsinfo entries for mDNS domains have port 5353, the mDNS port. Ignore them. // 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 + // We also don't need to do any more work if there are no nameserver addresses + if (r->port == 5353 || r->n_nameserver == 0) continue; + + if (!r->domain || !*r->domain) d.c[0] = 0; + else if (!MakeDomainNameFromDNSNameString(&d, r->domain)) { LogMsg("mDNSPlatformSetDNSConfig: bad domain %s", r->domain); continue; } + + // DNS server option parsing + if (r->options != NULL) { - 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) + char *nextOption = r->options; + char *currentOption = NULL; + while ((currentOption = strsep(&nextOption, " ")) != NULL && currentOption[0] != 0) { - 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) + // 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 *ni; + 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; } + LogInfo("%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 (ni = m->p->InterfaceList; ni; ni = ni->next) + if (ni->ifinfo.InterfaceID && ni->scope_id == ifindex) break; + if (ni != NULL) interface = ni->ifinfo.InterfaceID; + if (interface == mDNSNULL) { disabled = 1; LogMsg("RegisterSplitDNS: interfaceSpecific - index %d (%s) not found", ifindex, ifname); continue; } + } } } - 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) + + for (n = 0; n < r->n_nameserver; n++) + if (r->nameserver[n]->sa_family == AF_INET || r->nameserver[n]->sa_family == AF_INET6) { - char *nextOption = r->options; - char *currentOption = NULL; - while ((currentOption = strsep(&nextOption, " ")) != NULL && currentOption[0] != 0) + mDNSAddr saddr; + // mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 192, 168, 1, 1 } } } }; // for testing + if (SetupAddr(&saddr, r->nameserver[n])) LogMsg("RegisterSplitDNS: bad IP address"); + else { - // The option may be in the form of interface=xxx where xxx is an interface name. - if (strncmp(currentOption, kInterfaceSpecificOption, sizeof(kInterfaceSpecificOption) - 1) == 0) + DNSServer *s = mDNS_AddDNSServer(m, &d, interface, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort); + if (s) { - NetworkInterfaceInfoOSX *ni; - 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 (ni = m->p->InterfaceList; ni; ni = ni->next) - if (ni->ifinfo.InterfaceID && ni->scope_id == ifindex) break; - if (ni != NULL) interface = ni->ifinfo.InterfaceID; - if (interface == mDNSNULL) { disabled = 1; LogMsg("RegisterSplitDNS: interfaceSpecific - index %d (%s) not found", ifindex, ifname); continue; } + if (disabled) s->teststate = DNSServer_Disabled; + LogInfo("Added dns server %#a:%d for domain %##s from slot %d,%d", &s->addr, mDNSVal16(s->port), d.c, i, n); } } } - 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, interface, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort); - if (s && disabled) s->teststate = DNSServer_Disabled; - } - } - } + } } - if (setsearch) - { - // 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; @@ -3439,7 +4533,9 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN #endif // MDNS_NO_DNSINFO SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformSetDNSConfig"), NULL, NULL); - if (store) + if (!store) + LogMsg("mDNSPlatformSetDNSConfig: SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); + else { CFDictionaryRef ddnsdict = SCDynamicStoreCopyValue(store, NetworkChangedKey_DynamicDNS); if (ddnsdict) @@ -3451,7 +4547,7 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN { // 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)) + if (fqdnDict && DictionaryIsEnabled(fqdnDict)) { CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain")); if (name) @@ -3471,7 +4567,7 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN if (regArray && CFArrayGetCount(regArray) > 0) { CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0); - if (regDict && DDNSSettingEnabled(regDict)) + if (regDict && DictionaryIsEnabled(regDict)) { CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain")); if (name) @@ -3497,7 +4593,7 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN for (i = 0; i < CFArrayGetCount(browseArray); i++) { CFDictionaryRef browseDict = CFArrayGetValueAtIndex(browseArray, i); - if (browseDict && DDNSSettingEnabled(browseDict)) + if (browseDict && DictionaryIsEnabled(browseDict)) { CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain")); if (name) @@ -3529,7 +4625,7 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN CFDictionaryGetKeysAndValues(btmm, key, val); for (i = 0; i < size; i++) { - LogOperation("BackToMyMac %d", i); + LogInfo("BackToMyMac %d", i); if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8)) LogMsg("Can't read BackToMyMac %d key %s", i, buf); else @@ -3539,7 +4635,7 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN 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); + LogInfo("BackToMyMac %d %d %##s", i, uid, d.c); AppendDNameListElem(&RegDomains, uid, &d); } } @@ -3558,15 +4654,20 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN CFArrayRef values = CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses); if (values) { + LogInfo("DNS Server Address values: %d", CFArrayGetCount(values)); for (i = 0; i < CFArrayGetCount(values); i++) { CFStringRef s = CFArrayGetValueAtIndex(values, i); mDNSAddr addr = { mDNSAddrType_IPv4, { { { 0 } } } }; if (s && CFStringGetCString(s, buf, 256, kCFStringEncodingUTF8) && inet_aton(buf, (struct in_addr *) &addr.ip.v4)) + { + LogInfo("Adding DNS server from dict: %s", buf); mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, &addr, UnicastDNSPort); + } } } + else LogInfo("No DNS Server Address values"); } if (setsearch) { @@ -3607,7 +4708,8 @@ mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, (void)m; // Unused SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL, NULL); - if (!store) LogMsg("mDNSPlatformGetPrimaryInterface: SCDynamicStoreCreate failed"); + if (!store) + LogMsg("mDNSPlatformGetPrimaryInterface: SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); else { CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_IPv4); @@ -3628,8 +4730,7 @@ mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, 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; + *(in_addr_t *)&r->ip.v4 = saddr.sin_addr.s_addr; } } @@ -3686,7 +4787,7 @@ mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status) { - LogOperation("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status, dname->c); + LogInfo("mDNSPlatformDynDNSHostNameStatusChanged %d %##s", status, dname->c); char uname[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL ConvertDomainNameToCString(dname, uname); @@ -3713,19 +4814,19 @@ mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const else { const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) }; - if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%ld) failed", status); + if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status); else { - const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, NULL, NULL) }; + const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) }; if (HostVals[0]) { - const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, NULL, NULL) }; + const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) }; if (StateVals[0]) { - CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, NULL, NULL); + CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (StateDict) { - mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, StateDict); + mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, mDNSNULL, StateDict); CFRelease(StateDict); } CFRelease(StateVals[0]); @@ -3747,7 +4848,7 @@ mDNSexport void SetDomainSecrets(mDNS *m) #else mDNSBool haveAutoTunnels = mDNSfalse; - LogOperation("SetDomainSecrets"); + LogInfo("SetDomainSecrets"); // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds. // In the case where the user simultaneously removes their DDNS host name and the key @@ -3764,11 +4865,11 @@ mDNSexport void SetDomainSecrets(mDNS *m) ClientTunnel *client; for (client = m->TunnelClients; client; client = client->next) { - LogOperation("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c); + LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c); client->MarkedForDeletion = mDNStrue; } } -#endif APPLE_OSX_mDNSResponder +#endif // APPLE_OSX_mDNSResponder // String Array used to write list of private domains to Dynamic Store CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); @@ -3836,27 +4937,16 @@ mDNSexport void SetDomainSecrets(mDNS *m) 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); + LogInfo("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(stringbuf, 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", stringbuf); - if (queryNotInProgress) AutoTunnelSetKeys(client, mDNStrue); - } } } - mDNSBool keyChanged = FoundInList && FoundInList->AutoTunnel ? strncmp(stringbuf, FoundInList->b64keydata, sizeof(FoundInList->b64keydata)) : mDNSfalse; - -#endif APPLE_OSX_mDNSResponder +#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, stringbuf); + //LogInfo("SetDomainSecrets: %##s %##s %s", &domain.c, &keyname.c, stringbuf); // If didn't find desired domain in the list, make a new entry ptr = FoundInList; @@ -3867,7 +4957,7 @@ mDNSexport void SetDomainSecrets(mDNS *m) if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; } } - LogOperation("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain); + LogInfo("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain); if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, stringbuf, IsTunnelModeDomain(&domain)) == mStatus_BadParamErr) { if (!FoundInList) mDNSPlatformMemFree(ptr); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately @@ -3875,14 +4965,8 @@ mDNSexport void SetDomainSecrets(mDNS *m) } #if APPLE_OSX_mDNSResponder - if (keyChanged && AnonymousRacoonConfig) - { - LogOperation("SetDomainSecrets: secret changed for %##s", &domain); - (void)mDNSConfigureServer(kmDNSUp, stringbuf); - } - if (ptr->AutoTunnel) UpdateAutoTunnelDomainStatus(m, ptr); -#endif APPLE_OSX_mDNSResponder +#endif // APPLE_OSX_mDNSResponder ConvertDomainNameToCString(&domain, stringbuf); CFStringRef cfs = CFStringCreateWithCString(NULL, stringbuf, kCFStringEncodingUTF8); @@ -3890,10 +4974,10 @@ mDNSexport void SetDomainSecrets(mDNS *m) } CFRelease(secrets); } - mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, sa); + mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, sa); CFRelease(sa); - #if APPLE_OSX_mDNSResponder +#if APPLE_OSX_mDNSResponder { // clean up ClientTunnels ClientTunnel **pp = &m->TunnelClients; @@ -3902,13 +4986,13 @@ mDNSexport void SetDomainSecrets(mDNS *m) if ((*pp)->MarkedForDeletion) { ClientTunnel *cur = *pp; - LogOperation("SetDomainSecrets: removing client %p %##s from list", cur, cur->dstname.c); + LogInfo("SetDomainSecrets: removing client %p %##s from list", cur, cur->dstname.c); if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q); AutoTunnelSetKeys(cur, mDNSfalse); *pp = cur->next; freeL("ClientTunnel", cur); } - else + else pp = &(*pp)->next; } @@ -3934,7 +5018,7 @@ mDNSexport void SetDomainSecrets(mDNS *m) } info->AutoTunnelNAT.clientContext = mDNSNULL; } - RemoveAutoTunnelDomainStatus(info); + RemoveAutoTunnelDomainStatus(m, info); } info = info->next; } @@ -3942,24 +5026,19 @@ mDNSexport void SetDomainSecrets(mDNS *m) if (!haveAutoTunnels && !m->TunnelClients && m->AutoTunnelHostAddrActive) { // remove interface if no autotunnel servers and no more client tunnels - LogOperation("SetDomainSecrets: Bringing tunnel interface DOWN"); + LogInfo("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, ""); + mDNSPlatformMemZero(m->AutoTunnelHostAddr.b, sizeof(m->AutoTunnelHostAddr.b)); } + UpdateConfigureServer(m); + if (m->AutoTunnelHostAddr.b[0]) if (TunnelClients(m) || TunnelServers(m)) SetupLocalAutoTunnelInterface_internal(m); } - #endif APPLE_OSX_mDNSResponder +#endif // APPLE_OSX_mDNSResponder #endif /* NO_SECURITYFRAMEWORK */ } @@ -3976,116 +5055,436 @@ mDNSlocal void SetLocalDomains(void) CFArrayAppendValue(sa, CFSTR("a.e.f.ip6.arpa")); CFArrayAppendValue(sa, CFSTR("b.e.f.ip6.arpa")); - mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, sa); + mDNSDynamicStoreSetConfig(kmDNSMulticastConfig, mDNSNULL, sa); CFRelease(sa); } +mDNSlocal void GetCurrentPMSetting(const CFStringRef name, mDNSs32 *val) + { +#if USE_IOPMCOPYACTIVEPMPREFERENCES + CFTypeRef blob = NULL; + CFStringRef str = NULL; + CFDictionaryRef odict = NULL; + CFDictionaryRef idict = NULL; + CFNumberRef number = NULL; + + blob = IOPSCopyPowerSourcesInfo(); + if (!blob) { LogMsg("GetCurrentPMSetting: IOPSCopyPowerSourcesInfo failed!"); goto end; } + + odict = IOPMCopyActivePMPreferences(); + if (!odict) { LogMsg("GetCurrentPMSetting: IOPMCopyActivePMPreferences failed!"); goto end; } + + str = IOPSGetProvidingPowerSourceType(blob); + if (!str) { LogMsg("GetCurrentPMSetting: IOPSGetProvidingPowerSourceType failed!"); goto end; } + + idict = CFDictionaryGetValue(odict, str); + if (!idict) + { + char buf[256]; + if (!CFStringGetCString(str, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0; + LogMsg("GetCurrentPMSetting: CFDictionaryGetValue (%s) failed!", buf); + goto end; + } + + number = CFDictionaryGetValue(idict, name); + if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val)) + *val = 0; +end: + if (blob) CFRelease(blob); + if (odict) CFRelease(odict); + +#else + + SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetCurrentPMSetting"), NULL, NULL); + if (!store) LogMsg("GetCurrentPMSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); + else + { + CFDictionaryRef dict = SCDynamicStoreCopyValue(store, CFSTR("State:/IOKit/PowerManagement/CurrentSettings")); + if (!dict) LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict"); + else + { + CFNumberRef number = CFDictionaryGetValue(dict, name); + if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val)) + *val = 0; + CFRelease(dict); + } + CFRelease(store); + } + +#endif + } + +#if APPLE_OSX_mDNSResponder + +static CFMutableDictionaryRef spsStatusDict = NULL; +static const CFStringRef kMetricRef = CFSTR("Metric"); + +mDNSlocal void SPSStatusPutNumber(CFMutableDictionaryRef dict, const mDNSu8* const ptr, CFStringRef key) + { + mDNSu8 tmp = (ptr[0] - '0') * 10 + ptr[1] - '0'; + CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt8Type, &tmp); + if (!num) + LogMsg("SPSStatusPutNumber: Could not create CFNumber"); + else + { + CFDictionarySetValue(dict, key, num); + CFRelease(num); + } + } + +mDNSlocal CFMutableDictionaryRef SPSCreateDict(const mDNSu8* const ptr) + { + CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (!dict) { LogMsg("SPSCreateDict: Could not create CFDictionary dict"); return dict; } + + char buffer[1024]; + buffer[mDNS_snprintf(buffer, sizeof(buffer), "%##s", ptr) - 1] = 0; + CFStringRef spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8); + if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname full"); CFRelease(dict); return NULL; } + CFDictionarySetValue(dict, CFSTR("FullName"), spsname); + CFRelease(spsname); + + if (ptr[0] >= 2) SPSStatusPutNumber(dict, ptr + 1, CFSTR("Type")); + if (ptr[0] >= 5) SPSStatusPutNumber(dict, ptr + 4, CFSTR("Portability")); + if (ptr[0] >= 8) SPSStatusPutNumber(dict, ptr + 7, CFSTR("MarginalPower")); + if (ptr[0] >= 11) SPSStatusPutNumber(dict, ptr +10, CFSTR("TotalPower")); + + mDNSu32 tmp = SPSMetric(ptr); + CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tmp); + if (!num) + LogMsg("SPSCreateDict: Could not create CFNumber"); + else + { + CFDictionarySetValue(dict, kMetricRef, num); + CFRelease(num); + } + + if (ptr[0] >= 12) + { + memcpy(buffer, ptr + 13, ptr[0] - 12); + buffer[ptr[0] - 12] = 0; + spsname = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8); + if (!spsname) { LogMsg("SPSCreateDict: Could not create CFString spsname"); CFRelease(dict); return NULL; } + else + { + CFDictionarySetValue(dict, CFSTR("PrettyName"), spsname); + CFRelease(spsname); + } + } + + return dict; + } + +mDNSlocal CFComparisonResult CompareSPSEntries(const void *val1, const void *val2, void *context) + { + (void)context; + return CFNumberCompare((CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val1, kMetricRef), + (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)val2, kMetricRef), + NULL); + } + +mDNSlocal void UpdateSPSStatus(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) + { + (void)m; + NetworkInterfaceInfo* info = (NetworkInterfaceInfo*)question->QuestionContext; + debugf("UpdateSPSStatus: %s %##s %s %s", info->ifname, question->qname.c, AddRecord ? "Add" : "Rmv", answer ? RRDisplayString(m, answer) : ""); + + if (answer && SPSMetric(answer->rdata->u.name.c) > 999999) return; // Ignore instances with invalid names + + if (!spsStatusDict) + { + spsStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (!spsStatusDict) { LogMsg("UpdateSPSStatus: Could not create CFDictionary spsStatusDict"); return; } + } + + CFStringRef ifname = CFStringCreateWithCString(NULL, info->ifname, kCFStringEncodingUTF8); + if (!ifname) { LogMsg("UpdateSPSStatus: Could not create CFString ifname"); return; } + + CFMutableArrayRef array = NULL; + + if (!CFDictionaryGetValueIfPresent(spsStatusDict, ifname, (const void**) &array)) + { + array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + if (!array) { LogMsg("UpdateSPSStatus: Could not create CFMutableArray"); CFRelease(ifname); return; } + CFDictionarySetValue(spsStatusDict, ifname, array); + CFRelease(array); // let go of our reference, now that the dict has one + } + else + if (!array) { LogMsg("UpdateSPSStatus: Could not get CFMutableArray for %s", info->ifname); CFRelease(ifname); return; } + + if (!answer) // special call that means the question has been stopped (because the interface is going away) + CFArrayRemoveAllValues(array); + else + { + CFMutableDictionaryRef dict = SPSCreateDict(answer->rdata->u.name.c); + if (!dict) { CFRelease(ifname); return; } + + if (AddRecord) + { + if (!CFArrayContainsValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict)) + { + int i=0; + for (i=0; iifname, answer->rdata->u.name.c); + } + else + { + CFIndex i = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), dict); + if (i != -1) CFArrayRemoveValueAtIndex(array, i); + else LogMsg("UpdateSPSStatus: %s array does not contain %##s", info->ifname, answer->rdata->u.name.c); + } + + CFRelease(dict); + } + + if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSSleepProxyServersState, info->ifname, array); + + CFRelease(ifname); + } + +mDNSlocal mDNSs32 GetSystemSleepTimerSetting(void) + { + mDNSs32 val = -1; + SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetSystemSleepTimerSetting"), NULL, NULL); + if (!store) + LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); + else + { + CFDictionaryRef dict = SCDynamicStoreCopyValue(store, CFSTR("State:/IOKit/PowerManagement/CurrentSettings")); + if (dict) + { + CFNumberRef number = CFDictionaryGetValue(dict, CFSTR("System Sleep Timer")); + if (number) CFNumberGetValue(number, kCFNumberSInt32Type, &val); + CFRelease(dict); + } + CFRelease(store); + } + return val; + } + +mDNSlocal void SetSPS(mDNS *const m) + { + SCPreferencesSynchronize(m->p->SCPrefs); + CFDictionaryRef dict = SCPreferencesGetValue(m->p->SCPrefs, CFSTR("NAT")); + mDNSBool natenabled = (dict && (CFGetTypeID(dict) == CFDictionaryGetTypeID()) && DictionaryIsEnabled(dict)); + mDNSu8 sps = natenabled ? 50 : (OfferSleepProxyService && GetSystemSleepTimerSetting() == 0) ? OfferSleepProxyService : 0; + + // For devices that are not running NAT, but are set to never sleep, we may choose to act + // as a Sleep Proxy, but only for non-portable Macs (Portability > 35 means nominal weight < 3kg) + if (sps > 50 && SPMetricPortability > 35) sps = 0; + + // If we decide to let laptops act as Sleep Proxy, we should do it only when running on AC power, not on battery + + // For devices that are unable to sleep at all to save power (e.g. the current Apple TV hardware) + // it makes sense for them to offer low-priority Sleep Proxy service on the network. + // We rate such a device as metric 70 ("Incidentally Available Hardware") + if (SPMetricMarginalPower == 10 && (!sps || sps > 70)) sps = 70; + + mDNSCoreBeSleepProxyServer(m, sps, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower); + } + +mDNSlocal void InternetSharingChanged(SCPreferencesRef prefs, SCPreferencesNotification notificationType, void *context) + { + (void)prefs; // Parameter not used + (void)notificationType; // Parameter not used + mDNS *const m = (mDNS *const)context; + KQueueLock(m); + mDNS_Lock(m); + + // Tell platform layer to open or close its BPF fds + if (!m->p->NetworkChanged || + m->p->NetworkChanged - NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2) < 0) + { + m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2); + LogInfo("InternetSharingChanged: Set NetworkChanged to %d (%d)", m->p->NetworkChanged - m->timenow, m->p->NetworkChanged); + } + + mDNS_Unlock(m); + KQueueUnlock(m, "InternetSharingChanged"); + } + +mDNSlocal mStatus WatchForInternetSharingChanges(mDNS *const m) + { + SCPreferencesRef SCPrefs = SCPreferencesCreate(NULL, CFSTR("mDNSResponder:WatchForInternetSharingChanges"), CFSTR("com.apple.nat.plist")); + if (!SCPrefs) { LogMsg("SCPreferencesCreate failed: %s", SCErrorString(SCError())); return(mStatus_NoMemoryErr); } + + SCPreferencesContext context = { 0, m, NULL, NULL, NULL }; + if (!SCPreferencesSetCallback(SCPrefs, InternetSharingChanged, &context)) + { LogMsg("SCPreferencesSetCallback failed: %s", SCErrorString(SCError())); CFRelease(SCPrefs); return(mStatus_NoMemoryErr); } + + if (!SCPreferencesScheduleWithRunLoop(SCPrefs, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) + { LogMsg("SCPreferencesScheduleWithRunLoop failed: %s", SCErrorString(SCError())); CFRelease(SCPrefs); return(mStatus_NoMemoryErr); } + + m->p->SCPrefs = SCPrefs; + return(mStatus_NoError); + } + +#endif // APPLE_OSX_mDNSResponder + +static io_service_t g_rootdomain = MACH_PORT_NULL; + +mDNSlocal mDNSBool SystemWakeForNetworkAccess(void) + { + mDNSs32 val = 0; + CFBooleanRef clamshellStop = NULL; + mDNSBool retnow = mDNSfalse; + + GetCurrentPMSetting(CFSTR("Wake On LAN"), &val); + LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", val); + if (!val) return mDNSfalse; + + if (!g_rootdomain) g_rootdomain = IORegistryEntryFromPath(MACH_PORT_NULL, kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain"); + if (!g_rootdomain) { LogMsg("SystemWakeForNetworkAccess: IORegistryEntryFromPath failed; assuming no clamshell so can WOMP"); return mDNStrue; } + + clamshellStop = (CFBooleanRef)IORegistryEntryCreateCFProperty(g_rootdomain, CFSTR(kAppleClamshellStateKey), kCFAllocatorDefault, 0); + if (!clamshellStop) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellStateKey does not exist; assuming no clamshell so can WOMP"); return mDNStrue; } + retnow = clamshellStop == kCFBooleanFalse; + CFRelease(clamshellStop); + if (retnow) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellStateKey is false; clamshell is open so can WOMP"); return mDNStrue; } + + clamshellStop = (CFBooleanRef)IORegistryEntryCreateCFProperty(g_rootdomain, CFSTR(kAppleClamshellCausesSleepKey), kCFAllocatorDefault, 0); + if (!clamshellStop) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellCausesSleepKey does not exist; assuming no clamshell so can WOMP"); return mDNStrue; } + retnow = clamshellStop == kCFBooleanFalse; + CFRelease(clamshellStop); + if (retnow) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellCausesSleepKey is false; clamshell is closed but can WOMP"); return mDNStrue; } + + LogSPS("SystemWakeForNetworkAccess: clamshell is closed and can't WOMP"); + return mDNSfalse; + } + mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m) { - LogOperation("*** Network Configuration Change *** (%d)%s", + LogInfo("*** Network Configuration Change *** (%d)%s", m->p->NetworkChanged ? mDNS_TimeNow(m) - m->p->NetworkChanged : 0, m->p->NetworkChanged ? "" : " (no scheduled configuration change)"); m->p->NetworkChanged = 0; // If we received a network change event and deferred processing, we're now dealing with it mDNSs32 utc = mDNSPlatformUTC(); + m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess(); MarkAllInterfacesInactive(m, utc); UpdateInterfaceList(m, utc); ClearInactiveInterfaces(m, utc); SetupActiveInterfaces(m, utc); - #if APPLE_OSX_mDNSResponder +#if APPLE_OSX_mDNSResponder + + if (m->AutoTunnelHostAddr.b[0]) { - 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) { - 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; + mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst); + if (!mDNSSameIPv6Address(p->loc_inner, m->AutoTunnelHostAddr) || + !mDNSSameIPv4Address(p->loc_outer, tmpSrc.ip.v4)) { - mDNSAddr tmpSrc = zeroAddr; - mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} }; - tmpDst.ip.v4 = p->rmt_outer; - mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst); - 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); - } + AutoTunnelSetKeys(p, mDNSfalse); + p->loc_inner = m->AutoTunnelHostAddr; + p->loc_outer = tmpSrc.ip.v4; + AutoTunnelSetKeys(p, mDNStrue); } + } + + SetSPS(m); + + NetworkInterfaceInfoOSX *i; + for (i = m->p->InterfaceList; i; i = i->next) + { + if (!m->SPSSocket) // Not being Sleep Proxy Server; close any open BPF fds + { + if (i->BPF_fd >= 0 && CountProxyTargets(m, i, mDNSNULL, mDNSNULL) == 0) CloseBPF(i); + } + else // else, we're Sleep Proxy Server; open BPF fds + { + if (i->Exists && i->ifinfo.InterfaceID == (mDNSInterfaceID)i && !(i->ifa_flags & IFF_LOOPBACK) && i->BPF_fd == -1) + { LogSPS("%s requesting BPF", i->ifinfo.ifname); i->BPF_fd = -2; mDNSRequestBPF(); } + } } - #endif APPLE_OSX_mDNSResponder + +#endif // APPLE_OSX_mDNSResponder uDNS_SetupDNSConfig(m); + mDNS_ConfigChanged(m); + } - if (m->MainCallback) - m->MainCallback(m, mStatus_ConfigChanged); +// Called with KQueueLock & mDNS lock +mDNSlocal void SetNetworkChanged(mDNS *const m, mDNSs32 delay) + { + if (!m->p->NetworkChanged || m->p->NetworkChanged - NonZeroTime(m->timenow + delay) < 0) + { + m->p->NetworkChanged = NonZeroTime(m->timenow + delay); + LogInfo("SetNetworkChanged: setting network changed to %d (%d)", delay, m->p->NetworkChanged); + } } + mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context) { (void)store; // Parameter not used - (void)changedKeys; // Parameter not used mDNS *const m = (mDNS *const)context; KQueueLock(m); mDNS_Lock(m); - mDNSs32 delay = mDNSPlatformOneSecond; // Start off assuming a one-second delay + mDNSs32 delay = mDNSPlatformOneSecond * 2; // Start off assuming a two-second delay int c = CFArrayGetCount(changedKeys); // Count changes CFRange range = { 0, c }; int c1 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Hostnames ) != 0); int c2 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0); int c3 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS ) != 0); - if (c && c - c1 - c2 - c3 == 0) delay = mDNSPlatformOneSecond/20; // If these were the only changes, shorten delay + int c4 = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DNS ) != 0); + if (c && c - c1 - c2 - c3 - c4 == 0) delay = mDNSPlatformOneSecond/10; // If these were the only changes, shorten delay -#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 we have a global DNS change, then disregard delay and reconfigure immediately - if (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DNS) != 0) m->p->NetworkChanged = NonZeroTime(m->timenow); + int i; + for (i=0; i1?"s":"", + c1 ? "(Local Hostname) " : "", + c2 ? "(Computer Name) " : "", + c3 ? "(DynamicDNS) " : "", + c4 ? "(DNS) " : "", + delay); + } + SetNetworkChanged(m, delay); + // KeyChain frequently fails to notify clients of change events. To work around this // we set a timer and periodically poll to detect if any changes have occurred. // Without this Back To My Mac just does't work for a large number of users. // See Not getting Keychain Changed events when enabling BTMM if (c3 || CFArrayContainsValue(changedKeys, range, NetworkChangedKey_BackToMyMac)) { - LogOperation("*** NetworkChanged *** starting KeyChainBugTimer"); + LogInfo("*** NetworkChanged *** starting KeyChainBugTimer"); m->p->KeyChainBugTimer = NonZeroTime(m->timenow + delay); m->p->KeyChainBugInterval = mDNSPlatformOneSecond; } - if (!m->SuppressSending || - m->SuppressSending - m->p->NetworkChanged < 0) - m->SuppressSending = m->p->NetworkChanged; - mDNS_Unlock(m); + + // If DNS settings changed, immediately force a reconfig (esp. cache flush) + if (c4) mDNSMacOSXNetworkChanged(m); + KQueueUnlock(m, "NetworkChanged"); } @@ -4109,6 +5508,7 @@ mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m) CFArrayAppendValue(keys, NetworkChangedKey_DNS); CFArrayAppendValue(keys, NetworkChangedKey_DynamicDNS); CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac); + CFArrayAppendValue(keys, CFSTR("State:/IOKit/PowerManagement/CurrentSettings")); // should remove as part of CFArrayAppendValue(patterns, pattern1); CFArrayAppendValue(patterns, pattern2); CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort")); @@ -4135,10 +5535,107 @@ mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m) return(err); } +#if 0 // +mDNSlocal void PMChanged(void *context) + { + mDNS *const m = (mDNS *const)context; + + KQueueLock(m); + mDNS_Lock(m); + + LogSPS("PMChanged"); + + SetNetworkChanged(m, mDNSPlatformOneSecond * 2); + + mDNS_Unlock(m); + KQueueUnlock(m, "PMChanged"); + } + +mDNSlocal mStatus WatchForPMChanges(mDNS *const m) + { + m->p->PMRLS = IOPMPrefsNotificationCreateRunLoopSource(PMChanged, m); + if (!m->p->PMRLS) { LogMsg("IOPMPrefsNotificationCreateRunLoopSource failed!"); return mStatus_UnknownErr; } + + CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->PMRLS, kCFRunLoopDefaultMode); + + return mStatus_NoError; + } +#endif + +#ifndef KEV_DL_WAKEFLAGS_CHANGED +#define KEV_DL_WAKEFLAGS_CHANGED 17 +#endif + +mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context) + { + mDNS *const m = (mDNS *const)context; + + mDNS_Lock(m); + + struct { struct kern_event_msg k; char extra[256]; } msg; + int bytes = recv(s1, &msg, sizeof(msg), 0); + if (bytes < 0) + LogMsg("SysEventCallBack: recv error %d errno %d (%s)", bytes, errno, strerror(errno)); + else + { + LogInfo("SysEventCallBack got %d bytes size %d %X %s %X %s %X %s id %d code %d %s", + bytes, msg.k.total_size, + msg.k.vendor_code , msg.k.vendor_code == KEV_VENDOR_APPLE ? "KEV_VENDOR_APPLE" : "?", + msg.k.kev_class , msg.k.kev_class == KEV_NETWORK_CLASS ? "KEV_NETWORK_CLASS" : "?", + msg.k.kev_subclass, msg.k.kev_subclass == KEV_DL_SUBCLASS ? "KEV_DL_SUBCLASS" : "?", + msg.k.id, msg.k.event_code, + msg.k.event_code == KEV_DL_SIFFLAGS ? "KEV_DL_SIFFLAGS" : + msg.k.event_code == KEV_DL_SIFMETRICS ? "KEV_DL_SIFMETRICS" : + msg.k.event_code == KEV_DL_SIFMTU ? "KEV_DL_SIFMTU" : + msg.k.event_code == KEV_DL_SIFPHYS ? "KEV_DL_SIFPHYS" : + msg.k.event_code == KEV_DL_SIFMEDIA ? "KEV_DL_SIFMEDIA" : + msg.k.event_code == KEV_DL_SIFGENERIC ? "KEV_DL_SIFGENERIC" : + msg.k.event_code == KEV_DL_ADDMULTI ? "KEV_DL_ADDMULTI" : + msg.k.event_code == KEV_DL_DELMULTI ? "KEV_DL_DELMULTI" : + msg.k.event_code == KEV_DL_IF_ATTACHED ? "KEV_DL_IF_ATTACHED" : + msg.k.event_code == KEV_DL_IF_DETACHING ? "KEV_DL_IF_DETACHING" : + msg.k.event_code == KEV_DL_IF_DETACHED ? "KEV_DL_IF_DETACHED" : + msg.k.event_code == KEV_DL_LINK_OFF ? "KEV_DL_LINK_OFF" : + msg.k.event_code == KEV_DL_LINK_ON ? "KEV_DL_LINK_ON" : + msg.k.event_code == KEV_DL_PROTO_ATTACHED ? "KEV_DL_PROTO_ATTACHED" : + msg.k.event_code == KEV_DL_PROTO_DETACHED ? "KEV_DL_PROTO_DETACHED" : + msg.k.event_code == KEV_DL_LINK_ADDRESS_CHANGED ? "KEV_DL_LINK_ADDRESS_CHANGED" : + msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED ? "KEV_DL_WAKEFLAGS_CHANGED" : "?"); + + if (msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED) SetNetworkChanged(m, mDNSPlatformOneSecond * 2); + } + + mDNS_Unlock(m); + } + +mDNSlocal mStatus WatchForSysEvents(mDNS *const m) + { + m->p->SysEventNotifier = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT); + if (m->p->SysEventNotifier < 0) + { LogMsg("WatchForNetworkChanges: socket failed %s errno %d (%s)", errno, strerror(errno)); return(mStatus_NoMemoryErr); } + + struct kev_request kev_req = { KEV_VENDOR_APPLE, KEV_NETWORK_CLASS, KEV_DL_SUBCLASS }; + int err = ioctl(m->p->SysEventNotifier, SIOCSKEVFILT, &kev_req); + if (err < 0) + { + LogMsg("WatchForNetworkChanges: SIOCSKEVFILT failed %s errno %d (%s)", errno, strerror(errno)); + close(m->p->SysEventNotifier); + m->p->SysEventNotifier = -1; + return(mStatus_UnknownErr); + } + + m->p->SysEventKQueue.KQcallback = SysEventCallBack; + m->p->SysEventKQueue.KQcontext = m; + m->p->SysEventKQueue.KQtask = "System Event Notifier"; + KQueueSet(m->p->SysEventNotifier, EV_ADD, EVFILT_READ, &m->p->SysEventKQueue); + + return(mStatus_NoError); + } + #ifndef NO_SECURITYFRAMEWORK mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void *context) { - LogOperation("*** Keychain Changed ***"); + LogInfo("*** Keychain Changed ***"); mDNS *const m = (mDNS *const)context; SecKeychainRef skc; OSStatus err = SecKeychainCopyDefault(&skc); @@ -4163,11 +5660,11 @@ mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCa } if (relevant) { - LogMsg("*** Keychain Changed *** KeychainEvent=%d %s", + LogInfo("*** Keychain Changed *** KeychainEvent=%d %s", keychainEvent, - keychainEvent == kSecAddEvent ? "kSecAddEvent" : - keychainEvent == kSecDeleteEvent ? "kSecDeleteEvent" : - keychainEvent == kSecUpdateEvent ? "kSecUpdateEvent" : ""); + keychainEvent == kSecAddEvent ? "kSecAddEvent" : + keychainEvent == kSecDeleteEvent ? "kSecDeleteEvent" : + keychainEvent == kSecUpdateEvent ? "kSecUpdateEvent" : ""); // We're running on the CFRunLoop (Mach port) thread, not the kqueue thread, so we need to grab the KQueueLock before proceeding KQueueLock(m); mDNS_Lock(m); @@ -4184,46 +5681,137 @@ mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCa #endif #ifndef NO_IOPOWER +mDNSlocal void PowerOn(mDNS *const m) + { + mDNSCoreMachineSleep(m, false); // Will set m->SleepState = SleepState_Awake; + if (m->p->WakeAtUTC) + { + long utc = mDNSPlatformUTC(); + mDNSPowerRequest(-1,-1); // Need to explicitly clear any previous power requests -- they're not cleared automatically on wake + if (m->p->WakeAtUTC - utc > 30) LogInfo("PowerChanged PowerOn %d seconds early, assuming not maintenance wake", m->p->WakeAtUTC - utc); + else if (utc - m->p->WakeAtUTC > 30) LogInfo("PowerChanged PowerOn %d seconds late, assuming not maintenance wake", utc - m->p->WakeAtUTC); + else + { + mDNSs32 i = 20; + //int result = mDNSPowerRequest(0, i); + //if (result == kIOReturnNotReady) do i += (i<20) ? 1 : ((i+3)/4); while (mDNSPowerRequest(0, i) == kIOReturnNotReady); + LogMsg("PowerChanged: Waking for network maintenance operations %d seconds early; re-sleeping in %d seconds", m->p->WakeAtUTC - utc, i); + m->p->RequestReSleep = mDNS_TimeNow(m) + i * mDNSPlatformOneSecond; + } + } + } + mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messageType, void *messageArgument) { mDNS *const m = (mDNS *const)refcon; KQueueLock(m); (void)service; // Parameter not used - LogOperation("PowerChanged %X %lX", messageType, messageArgument); + debugf("PowerChanged %X %lX", messageType, messageArgument); + + // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting + m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess(); + switch(messageType) { - case kIOMessageCanSystemPowerOff: debugf ("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240 - case kIOMessageSystemWillPowerOff: LogOperation("PowerChanged kIOMessageSystemWillPowerOff"); - mDNSCoreMachineSleep(m, true); mDNSMacOSXNetworkChanged(m); break; // E0000250 - case kIOMessageSystemWillNotPowerOff: debugf ("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260 - case kIOMessageCanSystemSleep: debugf ("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270 - case kIOMessageSystemWillSleep: LogOperation("PowerChanged kIOMessageSystemWillSleep"); - mDNSCoreMachineSleep(m, true); mDNSMacOSXNetworkChanged(m); break; // E0000280 - case kIOMessageSystemWillNotSleep: debugf ("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290 - case kIOMessageSystemHasPoweredOn: LogOperation("PowerChanged kIOMessageSystemHasPoweredOn"); + case kIOMessageCanSystemPowerOff: LogInfo("PowerChanged kIOMessageCanSystemPowerOff (no action)"); break; // E0000240 + case kIOMessageSystemWillPowerOff: LogInfo("PowerChanged kIOMessageSystemWillPowerOff"); // E0000250 + mDNSCoreMachineSleep(m, true); + if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m); + break; + case kIOMessageSystemWillNotPowerOff: LogInfo("PowerChanged kIOMessageSystemWillNotPowerOff (no action)"); break; // E0000260 + case kIOMessageCanSystemSleep: LogInfo("PowerChanged kIOMessageCanSystemSleep (no action)"); break; // E0000270 + case kIOMessageSystemWillSleep: LogInfo("PowerChanged kIOMessageSystemWillSleep"); // E0000280 + mDNSCoreMachineSleep(m, true); + break; + case kIOMessageSystemWillNotSleep: LogInfo("PowerChanged kIOMessageSystemWillNotSleep (no action)"); break; // E0000290 + case kIOMessageSystemHasPoweredOn: LogInfo("PowerChanged kIOMessageSystemHasPoweredOn"); // E0000300 // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now - if (m->SleepState) mDNSCoreMachineSleep(m, false); - // Just to be safe, also make sure our interface list is fully up to date, in case we - // haven't yet received the System Configuration Framework "network changed" event that - // we expect to receive some time shortly after the kIOMessageSystemWillPowerOn message - mDNSMacOSXNetworkChanged(m); break; // E0000300 - case kIOMessageSystemWillRestart: debugf ("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310 - case kIOMessageSystemWillPowerOn: LogOperation("PowerChanged kIOMessageSystemWillPowerOn"); + if (m->SleepState) + { + LogMsg("PowerChanged kIOMessageSystemHasPoweredOn: ERROR m->SleepState %d", m->SleepState); + PowerOn(m); + } + // Just to be safe, schedule a mDNSMacOSXNetworkChanged(), in case we never received + // the System Configuration Framework "network changed" event that we expect + // to receive some time shortly after the kIOMessageSystemWillPowerOn message + mDNS_Lock(m); + if (!m->p->NetworkChanged || + m->p->NetworkChanged - NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2) < 0) + m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2); + mDNS_Unlock(m); + + break; + case kIOMessageSystemWillRestart: LogInfo("PowerChanged kIOMessageSystemWillRestart (no action)"); break; // E0000310 + case kIOMessageSystemWillPowerOn: LogInfo("PowerChanged kIOMessageSystemWillPowerOn"); // E0000320 + + // On Leopard and earlier, on wake from sleep, instead of reporting link state down, Apple + // Ethernet drivers report "hardware incapable of detecting link state", which the kernel + // interprets as "should assume we have networking", which results in the first 4-5 seconds + // of packets vanishing into a black hole. To work around this, on wake from sleep, + // we block for five seconds to let Ethernet come up, and then resume normal operation. + if (OSXVers < OSXVers_10_6_SnowLeopard) + { + sleep(5); + LogMsg("Running on Mac OS X version 10.%d earlier than 10.6; " + "PowerChanged did sleep(5) to wait for Ethernet hardware", OSXVers - OSXVers_Base); + } + // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake - mDNSMacOSXNetworkChanged(m); mDNSCoreMachineSleep(m, false); break; // E0000320 - default: LogOperation("PowerChanged unknown message %X", messageType); break; + if (m->SleepState != SleepState_Sleeping) + { + LogMsg("kIOMessageSystemWillPowerOn: ERROR m->SleepState %d", m->SleepState); + m->SleepState = SleepState_Sleeping; + mDNSMacOSXNetworkChanged(m); + } + PowerOn(m); + break; + default: LogInfo("PowerChanged unknown message %X", messageType); break; } - if (!m->p->SleepLimit && messageType == kIOMessageSystemWillSleep) + if (messageType == kIOMessageSystemWillSleep) m->p->SleepCookie = (long)messageArgument; + else IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument); + + KQueueUnlock(m, "PowerChanged Sleep/Wake"); + } + +#ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements +mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection, IOPMConnectionMessageToken token, IOPMSystemPowerStateCapabilities eventDescriptor) + { + mDNS *const m = (mDNS *const)refcon; + KQueueLock(m); + LogSPS("SnowLeopardPowerChanged %X %X %X%s%s%s%s%s", + connection, token, eventDescriptor, + eventDescriptor & kIOPMSystemPowerStateCapabilityCPU ? " CPU" : "", + eventDescriptor & kIOPMSystemPowerStateCapabilityVideo ? " Video" : "", + eventDescriptor & kIOPMSystemPowerStateCapabilityAudio ? " Audio" : "", + eventDescriptor & kIOPMSystemPowerStateCapabilityNetwork ? " Network" : "", + eventDescriptor & kIOPMSystemPowerStateCapabilityDisk ? " Disk" : ""); + + // Make sure our m->SystemWakeOnLANEnabled value correctly reflects the current system setting + m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess(); + + if (eventDescriptor & kIOPMSystemPowerStateCapabilityCPU) { - m->p->SleepLimit = NonZeroTime(mDNS_TimeNow(m) + mDNSPlatformOneSecond * 5); - m->p->SleepCookie = (long)messageArgument; + // CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down. + if (m->SleepState == SleepState_Sleeping) PowerOn(m); + IOPMConnectionAcknowledgeEvent(connection, token); } else - IOAllowPowerChange(m->p->PowerConnection, (long)messageArgument); + { + // CPU sleeping. Should not get this repeatedly -- once we're told that the CPU is halting + // we should hear nothing more until we're told that the CPU has started executing again. + if (m->SleepState) LogMsg("SnowLeopardPowerChanged: Sleep Error %X m->SleepState %d", eventDescriptor, m->SleepState); + //sleep(5); + //mDNSMacOSXNetworkChanged(m); + mDNSCoreMachineSleep(m, true); + //if (m->SleepState == SleepState_Sleeping) mDNSMacOSXNetworkChanged(m); + m->p->SleepCookie = token; + } - KQueueUnlock(m, "Sleep/Wake"); + KQueueUnlock(m, "SnowLeopardPowerChanged Sleep/Wake"); } +#endif + #endif /* NO_IOPOWER */ #if COMPILER_LIKES_PRAGMA_MARK @@ -4236,9 +5824,11 @@ CF_EXPORT const CFStringRef _kCFSystemVersionProductNameKey; CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey; CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey; -// Major version 6 is 10.2.x (Jaguar) -// Major version 7 is 10.3.x (Panther) -// Major version 8 is 10.4.x (Tiger) +// Major version 6 is 10.2.x (Jaguar) +// Major version 7 is 10.3.x (Panther) +// Major version 8 is 10.4.x (Tiger) +// Major version 9 is 10.5.x (Leopard) +// Major version 10 is 10.6.x (SnowLeopard) mDNSexport int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring) { int major = 0, minor = 0; @@ -4251,8 +5841,8 @@ mDNSexport int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring) CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey); if (cfprodname) CFStringGetCString(cfprodname, prodname, sizeof(prodname), kCFStringEncodingUTF8); if (cfprodvers) CFStringGetCString(cfprodvers, prodvers, sizeof(prodvers), kCFStringEncodingUTF8); - if (cfbuildver) CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8); - sscanf(buildver, "%d%c%d", &major, &letter, &minor); + if (cfbuildver && CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8)) + sscanf(buildver, "%d%c%d", &major, &letter, &minor); CFRelease(vers); } if (!major) { major=8; LogMsg("Note: No Major Build Version number found; assuming 8"); } @@ -4297,6 +5887,10 @@ mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void) mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m) { mStatus err; + m->p->CFRunLoop = CFRunLoopGetCurrent(); + + char HINFO_SWstring[256] = ""; + OSXVers = mDNSMacOSXSystemBuildNumber(HINFO_SWstring); // 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. @@ -4312,16 +5906,16 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m) m->hostlabel.c[0] = 0; - char *HINFO_HWstring = "Macintosh"; - char HINFO_HWstring_buffer[256]; int get_model[2] = { CTL_HW, HW_MODEL }; size_t len_model = sizeof(HINFO_HWstring_buffer); - if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0) + // Names that contain no commas are prototype model names, so we ignore those + if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ',')) HINFO_HWstring = HINFO_HWstring_buffer; + HINFO_HWstring_prefixlen = strcspn(HINFO_HWstring, "0123456789"); - char HINFO_SWstring[256] = ""; - if (mDNSMacOSXSystemBuildNumber(HINFO_SWstring) < 7) m->KnownBugs |= mDNS_KnownBug_PhantomInterfaces; - if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue; + if (OSXVers < OSXVers_10_3_Panther ) m->KnownBugs |= mDNS_KnownBug_PhantomInterfaces; + if (OSXVers >= OSXVers_10_6_SnowLeopard ) m->KnownBugs |= mDNS_KnownBug_LossySyslog; + if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue; mDNSu32 hlen = mDNSPlatformStrLen(HINFO_HWstring); mDNSu32 slen = mDNSPlatformStrLen(HINFO_SWstring); @@ -4364,14 +5958,15 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m) m->p->usernicelabel.c[0] = 0; m->p->NotifyUser = 0; m->p->KeyChainBugTimer = 0; - m->p->SleepLimit = 0; + m->p->WakeAtUTC = 0; + m->p->RequestReSleep = 0; + +#if APPLE_OSX_mDNSResponder + uuid_generate(m->asl_uuid); +#endif 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); @@ -4383,6 +5978,19 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m) err = WatchForNetworkChanges(m); if (err) { LogMsg("mDNSPlatformInit_setup: WatchForNetworkChanges failed %d", err); return(err); } +#if 0 // + err = WatchForPMChanges(m); + if (err) { LogMsg("mDNSPlatformInit_setup: WatchForPMChanges failed %d", err); return(err); } +#endif + + err = WatchForSysEvents(m); + if (err) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err); return(err); } + + mDNSs32 utc = mDNSPlatformUTC(); + m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess(); + UpdateInterfaceList(m, utc); + SetupActiveInterfaces(m, utc); + // Explicitly ensure that our Keychain operations utilize the system domain. #ifndef NO_SECURITYFRAMEWORK SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem); @@ -4399,11 +6007,53 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m) #endif #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); + +#ifndef kIOPMAcknowledgmentOptionSystemCapabilityRequirements + LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support"); +#else + IOPMConnection c; + IOReturn iopmerr = IOPMConnectionCreate(CFSTR("mDNSResponder"), kIOPMSystemPowerStateCapabilityCPU, &c); + if (iopmerr) LogMsg("IOPMConnectionCreate failed %d", iopmerr); + else + { + iopmerr = IOPMConnectionSetNotification(c, m, SnowLeopardPowerChanged); + if (iopmerr) LogMsg("IOPMConnectionSetNotification failed %d", iopmerr); + else + { + iopmerr = IOPMConnectionScheduleWithRunLoop(c, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + if (iopmerr) LogMsg("IOPMConnectionScheduleWithRunLoop failed %d", iopmerr); + } + } + m->p->IOPMConnection = iopmerr ? mDNSNULL : c; + if (iopmerr) // If IOPMConnectionCreate unavailable or failed, proceed with old-style power notification code below +#endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements + { + m->p->PowerConnection = IORegisterForSystemPower(m, &m->p->PowerPortRef, PowerChanged, &m->p->PowerNotifier); + if (!m->p->PowerConnection) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); } + else CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode); + } #endif /* NO_IOPOWER */ +#if APPLE_OSX_mDNSResponder + // Note: We use SPMetricPortability > 35 to indicate a laptop of some kind + // SPMetricPortability <= 35 means nominally a non-portable machine (i.e. Mac mini or better) + // An Apple TV does not actually weigh 3kg, but we assign it a 'nominal' mass of 3kg to indicate that it's treated as being relatively less portable than a laptop + if (!strncasecmp(HINFO_HWstring, "Xserve", 6)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; } + else if (!strncasecmp(HINFO_HWstring, "RackMac", 7)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; } + else if (!strncasecmp(HINFO_HWstring, "MacPro", 6)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; } + else if (!strncasecmp(HINFO_HWstring, "PowerMac", 8)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 82 /* 160W */; SPMetricTotalPower = 83 /* 200W */; } + else if (!strncasecmp(HINFO_HWstring, "iMac", 4)) { SPMetricPortability = 30 /* 10kg */; SPMetricMarginalPower = 77 /* 50W */; SPMetricTotalPower = 78 /* 60W */; } + else if (!strncasecmp(HINFO_HWstring, "Macmini", 7)) { SPMetricPortability = 33 /* 5kg */; SPMetricMarginalPower = 73 /* 20W */; SPMetricTotalPower = 74 /* 25W */; } + else if (!strncasecmp(HINFO_HWstring, "AppleTV", 7)) { SPMetricPortability = 35 /* 3kg */; SPMetricMarginalPower = 10 /* 0W */; SPMetricTotalPower = 73 /* 20W */; } + else if (!strncasecmp(HINFO_HWstring, "MacBook", 7)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; } + else if (!strncasecmp(HINFO_HWstring, "PowerBook",9)) { SPMetricPortability = 37 /* 2kg */; SPMetricMarginalPower = 71 /* 13W */; SPMetricTotalPower = 72 /* 15W */; } + LogSPS("HW_MODEL: %.*s (%s) Portability %d Marginal Power %d Total Power %d", + HINFO_HWstring_prefixlen, HINFO_HWstring, HINFO_HWstring, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower); + + err = WatchForInternetSharingChanges(m); + if (err) { LogMsg("WatchForInternetSharingChanges failed %d", err); return(err); } +#endif // APPLE_OSX_mDNSResponder + return(mStatus_NoError); } @@ -4413,6 +6063,13 @@ mDNSexport mStatus mDNSPlatformInit(mDNS *const m) LogMsg("Note: Compiled without Apple-specific Split-DNS support"); #endif + // Adding interfaces will use this flag, so set it now. + m->DivertMulticastAdvertisements = !m->AdvertiseLocalAddresses; + +#if APPLE_OSX_mDNSResponder + m->SPSBrowseCallback = UpdateSPSStatus; +#endif + 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 @@ -4445,18 +6102,28 @@ mDNSexport void mDNSPlatformClose(mDNS *const m) m->p->Store = NULL; m->p->StoreRLS = NULL; } + + if (m->p->PMRLS) + { + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->PMRLS, kCFRunLoopDefaultMode); + CFRunLoopSourceInvalidate(m->p->PMRLS); + CFRelease(m->p->PMRLS); + m->p->PMRLS = NULL; + } + + if (m->p->SysEventNotifier >= 0) { close(m->p->SysEventNotifier); m->p->SysEventNotifier = -1; } mDNSs32 utc = mDNSPlatformUTC(); MarkAllInterfacesInactive(m, utc); ClearInactiveInterfaces(m, utc); CloseSocketSet(&m->p->permanentsockets); - #if APPLE_OSX_mDNSResponder +#if APPLE_OSX_mDNSResponder // clean up tunnels while (m->TunnelClients) { ClientTunnel *cur = m->TunnelClients; - LogOperation("mDNSPlatformClose: removing client tunnel %p %##s from list", cur, cur->dstname.c); + LogInfo("mDNSPlatformClose: removing client tunnel %p %##s from list", cur, cur->dstname.c); if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q); AutoTunnelSetKeys(cur, mDNSfalse); m->TunnelClients = cur->next; @@ -4465,18 +6132,18 @@ mDNSexport void mDNSPlatformClose(mDNS *const m) if (AnonymousRacoonConfig) { - AnonymousRacoonConfig = mDNSfalse; - LogOperation("mDNSPlatformClose: Deconfiguring autotunnel"); - (void)mDNSConfigureServer(kmDNSDown, ""); + AnonymousRacoonConfig = mDNSNULL; + LogInfo("mDNSPlatformClose: Deconfiguring autotunnel"); + (void)mDNSConfigureServer(kmDNSDown, mDNSNULL); } if (m->AutoTunnelHostAddrActive && m->AutoTunnelHostAddr.b[0]) { m->AutoTunnelHostAddrActive = mDNSfalse; - LogOperation("mDNSPlatformClose: Removing AutoTunnel address %.16a", &m->AutoTunnelHostAddr); + LogInfo("mDNSPlatformClose: Removing AutoTunnel address %.16a", &m->AutoTunnelHostAddr); (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown, m->AutoTunnelHostAddr.b); } - #endif // APPLE_OSX_mDNSResponder +#endif // APPLE_OSX_mDNSResponder } #if COMPILER_LIKES_PRAGMA_MARK @@ -4484,9 +6151,9 @@ mDNSexport void mDNSPlatformClose(mDNS *const m) #pragma mark - General Platform Support Layer functions #endif -mDNSexport mDNSu32 mDNSPlatformRandomSeed(void) +mDNSexport mDNSu32 mDNSPlatformRandomNumber(void) { - return(mach_absolute_time()); + return(arc4random()); } mDNSexport mDNSs32 mDNSPlatformOneSecond = 1000; @@ -4533,7 +6200,7 @@ mDNSexport mDNSs32 mDNSPlatformRawTime(void) last_mach_absolute_time = this_mach_absolute_time; // 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) + if (OSXVers >= OSXVers_10_4_Tiger) 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" @@ -4557,7 +6224,7 @@ mDNSexport void mDNSPlatformStrCopy( void *dst, const void *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); } +mDNSexport void mDNSPlatformMemZero( void *dst, mDNSu32 len) { memset(dst, 0, len); } #if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING) mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); } #endif diff --git a/mDNSMacOSX/mDNSMacOSX.h b/mDNSMacOSX/mDNSMacOSX.h index 17fd2b9..d2e0e73 100644 --- a/mDNSMacOSX/mDNSMacOSX.h +++ b/mDNSMacOSX/mDNSMacOSX.h @@ -17,6 +17,84 @@ Change History (most recent first): $Log: mDNSMacOSX.h,v $ +Revision 1.104 2009/06/25 23:36:56 cheshire +To facilitate testing, added command-line switch "-OfferSleepProxyService" +to re-enable the previously-supported mode of operation where we offer +sleep proxy service on desktop Macs that are set to never sleep. + +Revision 1.103 2009/04/11 00:20:13 jessic2 + Daemon: Should be able to turn on LogOperation dynamically + +Revision 1.102 2009/04/06 22:14:02 cheshire +Need to include IOKit/pwr_mgt/IOPM.h to build for AppleTV + +Revision 1.101 2009/04/02 22:21:17 mcguire + Adopt IOPM APIs + +Revision 1.100 2009/02/12 20:57:26 cheshire +Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch + +Revision 1.99 2009/02/11 02:31:05 cheshire +Move SystemWakeForNetworkAccessEnabled into mDNS structure so it's accessible to mDNSCore routines + +Revision 1.98 2009/02/07 02:52:19 cheshire + Sleep Proxy: Need to adopt IOPMConnection + +Revision 1.97 2009/02/02 22:13:01 cheshire +Added SystemWakeForNetworkAccessEnabled setting + +Revision 1.96 2009/01/17 04:13:57 cheshire +Added version symbols for Cheetah and Puma + +Revision 1.95 2009/01/16 02:32:55 cheshire +Added SysEventNotifier and SysEventKQueue in mDNS_PlatformSupport_struct + +Revision 1.94 2009/01/15 22:24:53 cheshire +Removed unused ifa_name field from NetworkInterfaceInfoOSX_struct + +Revision 1.93 2008/12/10 19:30:01 cheshire +Added symbolic names for the various OS X versions + +Revision 1.92 2008/10/31 23:49:38 mkrochma +Increased sizecheck limit + +Revision 1.91 2008/10/31 22:48:27 cheshire +Added SCPreferencesRef to mDNS_PlatformSupport_struct + +Revision 1.90 2008/10/30 01:04:35 cheshire +Added WakeAtUTC and SleepTime fields to mDNS_PlatformSupport_struct + +Revision 1.89 2008/10/29 18:38:33 mcguire +Increase sizecheck limits to account for CFRunLoop added to mDNS_PlatformSupport_struct in 64bit builds + +Revision 1.88 2008/10/28 20:33:56 cheshire +Added CFRunLoopRef in mDNS_PlatformSupport_struct, to hold reference to our main thread's CFRunLoop + +Revision 1.87 2008/10/28 18:32:09 cheshire +Added CFSocketRef and CFRunLoopSourceRef in NetworkInterfaceInfoOSX_struct + +Revision 1.86 2008/10/22 23:23:53 cheshire +Moved definition of OSXVers from daemon.c into mDNSMacOSX.c + +Revision 1.85 2008/10/21 00:12:00 cheshire +Added BPF-related fields in NetworkInterfaceInfoOSX_struct + +Revision 1.84 2008/10/14 20:20:44 cheshire +Increase sizecheck limits to account for DNSQuestions added to NetworkInterfaceInfo_struct + +Revision 1.83 2008/10/07 21:41:57 mcguire +Increase sizecheck limits to account for DNSQuestion added to NetworkInterfaceInfo_struct in 64bit builds + +Revision 1.82 2008/10/07 15:56:24 cheshire +Increase sizecheck limits to account for DNSQuestion added to NetworkInterfaceInfo_struct + +Revision 1.81 2008/10/03 00:26:25 cheshire +Export DictionaryIsEnabled() so it's callable from other files + +Revision 1.80 2008/10/02 22:47:01 cheshire + Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service +Added SCPreferencesRef so we can track whether Internet Sharing is on or off + Revision 1.79 2008/07/30 00:55:56 mcguire Should use randomized source ports and transaction IDs to avoid DNS cache poisoning Additional fixes so that we know when a socket has been closed while in a loop reading from it @@ -120,7 +198,9 @@ Revision 1.52 2006/01/05 21:41:49 cheshire #endif #include +#include #include +#include #include #include #include "mDNSEmbeddedAPI.h" // for domain name structure @@ -156,21 +236,25 @@ struct NetworkInterfaceInfoOSX_struct { NetworkInterfaceInfo ifinfo; // MUST be the first element in this structure NetworkInterfaceInfoOSX *next; - mDNSu32 Exists; // 1 = currently exists in getifaddrs list; 0 = doesn't + mDNS *m; + mDNSu8 Exists; // 1 = currently exists in getifaddrs list; 0 = doesn't // 2 = exists, but McastTxRx state changed + mDNSu8 Flashing; // Set if interface appeared for less than 60 seconds and then vanished + mDNSu8 Occulting; // Set if interface vanished for less than 60 seconds and then came back 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; + int BPF_fd; // -1 uninitialized; -2 requested BPF; -3 failed + u_int BPF_len; + CFSocketRef BPF_cfs; + CFRunLoopSourceRef BPF_rls; }; struct mDNS_PlatformSupport_struct @@ -189,19 +273,39 @@ struct mDNS_PlatformSupport_struct // See Not getting Keychain Changed events when enabling BTMM mDNSs32 KeyChainBugTimer; mDNSs32 KeyChainBugInterval; - + + CFRunLoopRef CFRunLoop; SCDynamicStoreRef Store; CFRunLoopSourceRef StoreRLS; + CFRunLoopSourceRef PMRLS; + int SysEventNotifier; + KQueueEntry SysEventKQueue; IONotificationPortRef PowerPortRef; io_connect_t PowerConnection; io_object_t PowerNotifier; - mDNSs32 SleepLimit; // Set when we get kIOMessageSystemWillSleep notification +#ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements + IOPMConnection IOPMConnection; +#endif + SCPreferencesRef SCPrefs; long SleepCookie; // Cookie we need to pass to IOAllowPowerChange() + long WakeAtUTC; + mDNSs32 RequestReSleep; pthread_mutex_t BigMutex; mDNSs32 BigMutexStartTime; int WakeKQueueLoopFD; }; +extern int OfferSleepProxyService; +extern int OSXVers; +#define OSXVers_Base 4 +#define OSXVers_10_0_Cheetah 4 +#define OSXVers_10_1_Puma 5 +#define OSXVers_10_2_Jaguar 6 +#define OSXVers_10_3_Panther 7 +#define OSXVers_10_4_Tiger 8 +#define OSXVers_10_5_Leopard 9 +#define OSXVers_10_6_SnowLeopard 10 + extern int KQueueFD; extern void NotifyOfElusiveBug(const char *title, const char *msg); // Both strings are UTF-8 text @@ -216,6 +320,8 @@ extern int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *con extern void KQueueLock(mDNS *const m); extern void KQueueUnlock(mDNS *const m, const char const *task); +extern mDNSBool DictionaryIsEnabled(CFDictionaryRef dict); + // 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 @@ -232,19 +338,15 @@ extern void KQueueUnlock(mDNS *const m, const char const *task); // 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 +extern int WatchDogReportingThreshold; struct CompileTimeAssertionChecks_mDNSMacOSX { // Check our structures are reasonable sizes. Including overly-large buffers, or embedding // other overly-large structures instead of having a pointer to them, can inadvertently // cause structure sizes (and therefore memory usage) to balloon unreasonably. - char sizecheck_NetworkInterfaceInfoOSX[(sizeof(NetworkInterfaceInfoOSX) <= 4456) ? 1 : -1]; - char sizecheck_mDNS_PlatformSupport [(sizeof(mDNS_PlatformSupport) <= 368) ? 1 : -1]; + char sizecheck_NetworkInterfaceInfoOSX[(sizeof(NetworkInterfaceInfoOSX) <= 7000) ? 1 : -1]; + char sizecheck_mDNS_PlatformSupport [(sizeof(mDNS_PlatformSupport) <= 476) ? 1 : -1]; }; #ifdef __cplusplus diff --git a/mDNSMacOSX/mDNSResponder.order b/mDNSMacOSX/mDNSResponder.order index a0cc39d..bb130ff 100644 --- a/mDNSMacOSX/mDNSResponder.order +++ b/mDNSMacOSX/mDNSResponder.order @@ -1,367 +1,317 @@ -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 +__start +_dyld_stub_binding_helper +__dyld_func_lookup +_main +_LogMsgWithLevel +_mDNS_vsnprintf +_mDNSPlatformWriteLogMsg +_safe_vproc_transaction_begin +_KQueueSet +_mDNSMacOSXSystemBuildNumber +_mDNSDaemonInitialize +_mDNS_Init +_mDNSPlatformTimeInit +_mDNSRandom +_mDNSPlatformRandomNumber +_mDNSPlatformRawTime +_mDNSPlatformInit +_mDNS_snprintf +_GetUserSpecifiedLocalHostName +_SetupSocket +_SystemWakeForNetworkAccess +_UpdateInterfaceList +_myGetIfAddrs +_AddInterfaceToList +_SetupAddr +_NetWakeInterface +_mDNS_SetFQDN +_AppendDomainLabel +_AppendLiteralLabelString +_mDNS_Lock_ +_mDNSPlatformLock +_SameDomainNameCS +_DomainNameLengthLimit +_mDNSPlatformMemCopy +_mDNS_Unlock_ +_mDNSPlatformUnlock +_SetupActiveInterfaces +_SearchForInterfaceByName +_mDNS_RegisterInterface +_AdvertiseInterface +_mDNS_SetupResourceRecord +_MakeDomainNameFromDNSNameString +_AppendDNSNameString +_mDNS_Register_internal +_InitializeLastAPTime +_SetNextAnnounceProbeTime +_GetRDLength +_ValidateRData +_DomainNameHashValue +_RDataHashValue +_SetTargetToHostName +_SameDomainName +_SetNewRData +_CompressedDomainNameLength +_AcknowledgeRecord +_mDNS_StartBrowse_internal +_ConstructServiceName +_AppendDomainName +_mDNS_StartQuery_internal +_IsLocalDomain +_CheckForSoonToExpireRecords +_GetAuthInfoForQuestion +_GetAuthInfoForName_internal +_FindDuplicateQuestion +_SetNextQueryTime +_SetDomainSecrets +_mDNSKeychainGetSecrets +_getHelperPort +_proxy_mDNSKeychainGetSecrets +_mDNS_SetSecretForDomain +_DNSDigest_ConstructHMACKeyfromBase64 +_mDNSPlatformMemZero +_UpdateAutoTunnelDomainStatus +_ConvertDomainLabelToCString_withescape +_mDNSASLLog +_mDNSDynamicStoreSetConfig +_proxy_mDNSDynamicStoreSetConfig +_ConvertDomainNameToCString_withescape +_UpdateConfigureServer +_TunnelServers +_mDNSCoreInitComplete +_mDNS_StatusCallback +_mDNSPlatformMemSame +_uDNS_SetupDNSConfig +_mDNSPlatformSetDNSConfig +_dns_configuration_copy +___dns_initialize +__dns_configuration_server_port +_shared_dns_infoGet +_CountLabels +_SkipLeadingLabels +_dns_configuration_free +_mDNSPlatformGetPrimaryInterface +_mDNS_SetPrimaryInterfaceInfo +_udsserver_init +_udsSupportAddFDToEventLoop +_mDNS_GetDomains +_mDNS_StartQuery +_RegisterLocalOnlyDomainEnumPTR +_mDNSPlatformMemAllocate +_mDNS_Register +_AddAutoBrowseDomain +_udsserver_automatic_browse_domain_changed +_machserver_automatic_browse_domain_changed +_udsserver_handle_configchange +_UpdateDeviceInfoRecord +_AppendDNameListElem +_SetPrefsBrowseDomains +_udsserver_default_reg_domain_changed +_machserver_automatic_registration_domain_changed +_mDNSMacOSXNetworkChanged +_mDNSSameAddress +_ClearInactiveInterfaces +_mDNSCoreBeSleepProxyServer +_mDNS_ConfigChanged +_mDNSPreferencesSetName +_proxy_mDNSPreferencesSetName +_SameRDataBody +_DeregisterLocalOnlyDomainEnumPTR +_mDNS_Deregister +_mDNS_Deregister_internal +_mDNSPlatformMemFree +_RmvAutoBrowseDomain +_KQueueLoop +_mDNS_TimeNow +_mDNS_Execute +_SendQueries +_GetFirstActiveInterface +_InitializeDNSMessage +_uDNS_Execute +_mDNSv4AddrIsRFC1918 +_udsserver_idle +_connect_callback +_NewRequest +_request_callback +_ConvertHeaderBytes +_handle_regservice_request +_get_uint32 +_mDNSPlatformInterfaceIDfromInterfaceIndex +_get_string +_mDNSPlatformStrCopy +_get_uint16 +_ChopSubTypes +_AuthorizedDomain +_register_service_instance +_AllocateSubTypes +_mDNS_RegisterService +_ServiceCallback +_GetServiceTarget +_SetupLocalAutoTunnelInterface_internal +_mDNSAutoTunnelInterfaceUpDown +_proxy_mDNSAutoTunnelInterfaceUpDown +_NetworkChanged +_KQueueLock +_AbortDeregistration +_mDNS_StartNATOperation_internal +_put_uint32 +_send_all +_uDNS_SendNATMsg +_KQueueUnlock +_KQWokenFlushBytes +_handle_queryrecord_request +_mDNS_NewMessageID +_GetServerForName +_ActivateUnicastQuery +_LastLabel +_SameDomainLabel +_uDNS_CheckCurrentQuestion +_CacheGroupForName +_MakeNegativeCacheRecord +_CreateNewCacheEntry +_GetCacheEntity +_ResourceRecordAnswersQuestion +_SetNextCacheCheckTime +_SameNameRecordAnswersQuestion +_CheckCacheExpiration +_CacheRecordDeferredAdd +_AnswerCurrentQuestionWithResourceRecord +_queryrecord_result_callback +_create_reply +_mDNSPlatformInterfaceIndexfromInterfaceID +_put_string +_put_uint16 +_abort_request +_queryrecord_termination_callback +_mDNS_StopQuery +_mDNS_StopQuery_internal +_putQuestion +_putDomainNameAsLabels +_FindCompressionPointer +_GetNextActiveInterfaceID +_PutResourceRecordTTLWithLimit +_putRData +_mDNSSendDNSMessage +_putHINFO +_mDNSPlatformSendUDP +_mDNSAddrIsDNSMulticast +_myKQSocketCallBack +_mDNSCoreReceive +_mDNSCoreReceiveQuery +_AddressIsLocalSubnet +_LocateOptRR +_LocateAdditionals +_LocateAuthorities +_LocateAnswers +_skipResourceRecord +_getQuestion +_getDomainName +_GetLargeResourceRecord +_PacketRRConflict +_AddAdditionalsToResponseList +_mDNS_HostNameCallback +_regservice_callback +_GenerateNTDResponse +_DeconstructServiceName +_CountPeerRegistrations +_RecordUpdatedNiceLabel +_ClearProxyRecords +_SendResponses +_uDNS_recvLLQResponse +_AnswerAllLocalQuestionsWithLocalAuthRecord +_handle_regrecord_request +_read_rr_from_ipc_msg +_get_rdata +_regrecord_callback +_StartGetZoneData +_GetZoneData_StartQuery +_SetRecordRetry +_GetZoneData_QuestionCallback +_RecordRegistrationGotZoneData +_SameResourceRecordSignature +_FindIdenticalRecordInCache +_mDNS_GrowCache +_ShouldSuppressKnownAnswer +_AutoTunnelNATCallback +_RegisterAutoTunnelRecords +_SysEventCallBack +_UpdateSRVRecords +_UpdateSRV +_mDNS_DeregisterInterface +_mDNS_PurgeCacheResourceRecord +_DeadvertiseInterface +_NumCacheRecordsForInterfaceID +_AddrRequiresPPPConnection +_mDNS_AddDNSServer +_PurgeOrReconfirmCacheRecord +_LNT_ClearState +_UpdateAutoTunnelDomainStatuses +_ReleaseCacheGroup +_mDNS_AddDynDNSHostName +_AdvertiseHostname +_mDNSConfigureServer +_mDNSPlatformStrLen +_proxy_mDNSConfigureServer +_CancelGetZoneData +_mDNSPlatformUDPSocket +_uDNS_ReceiveMsg +_GetLLQOptData +_ExpectingUnicastResponseForQuestion +_UpdateSPSStatus +_SPSStatusPutNumber +_mDNSPlatformUDPClose +_CloseSocketSet +_SendRecordRegistration +_putZone +_putUpdateLease +_MakeTCPConn +_mDNSPlatformTCPSocket +_mDNSPlatformTCPConnect +_putDeleteRRSet +_ServiceRegistrationGotZoneData +_SendServiceRegistration +_tcpKQSocketCallback +_tlsSetupSock +_doSSLHandshake +_tlsWriteSock +_tlsReadSock +_tcpCallback +_GetAuthInfoForName +_DNSDigest_SignMessage +_MD5_Update +_md5_block_data_order +_md5_block_host_order +_mDNSPlatformUTC +_MD5_Final +_mDNSPlatformWriteTCP +_mDNSPlatformReadTCP +_DisposeTCPConn +_mDNSPlatformTCPCloseConnection +_GetPktLease +_checkUpdateResult +_HostnameCallback +_AutoTunnelRecordCallback +_handle_getproperty_request +_AbortUnlinkAndFree +_udsSupportRemoveFDFromEventLoop +_handle_browse_request +_add_domain_to_browser +_mDNS_StartBrowse +_ReconfirmAntecedents +_FoundInstance +_connection_termination +_startLLQHandshake +_LLQNATCallback +_uDNS_RegisterSearchDomains +_mDNS_AddSearchDomain +_AnswerLocalQuestionWithLocalAuthRecord +_enum_result_callback +_LLQGotZoneData +_GetLLQEventPort +_mDNSPlatformSourceAddrForDest +_putLLQ +_SetLLQTimer +_sendLLQRefresh +_SendDelayedUnicastResponse +_mDNS_Reconfirm_internal diff --git a/mDNSMacOSX/mDNSResponder.sb b/mDNSMacOSX/mDNSResponder.sb index 8f8ab2c..b4a0922 100644 --- a/mDNSMacOSX/mDNSResponder.sb +++ b/mDNSMacOSX/mDNSResponder.sb @@ -26,9 +26,47 @@ ; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ; ; $Log: mDNSResponder.sb,v $ -; Revision 1.25.2.1 2008/07/29 20:48:34 mcguire -; Should use randomized source ports and transaction IDs to avoid DNS cache poisoning -; merge r1.27 from +; Revision 1.38 2009/04/16 16:03:08 mcguire +; abort() causes high CPU usage instead of crash & restart +; +; Revision 1.37 2009/04/02 22:21:17 mcguire +; Adopt IOPM APIs +; +; Revision 1.36 2009/03/02 01:32:20 mcguire +; Seatbelt: Add rule to allow raw sockets +; +; Revision 1.35 2009/02/07 02:51:10 cheshire +; Sleep Proxy: Need to adopt IOPMConnection +; Allow mDNSResponder to access IOPMConnection API +; +; Revision 1.34 2008/11/11 00:55:08 mcguire +; sandbox: need to allow Mach port com.apple.system.DirectoryService.membership_v1 +; +; Revision 1.33 2008/10/24 02:03:30 cheshire +; So we can watch for Internet Sharing changes, allow read access to +; /Library/Preferences/SystemConfiguration/com.apple.nat.plist +; +; Revision 1.32 2008/10/07 23:06:58 mcguire +; Seatbelt: Policy denied Mach service lookup: com.apple.system.logger +; +; Revision 1.31 2008/09/24 23:57:27 mcguire +; need read access to /private/var/db/crls/crlcache.db +; +; Revision 1.30 2008/09/11 22:01:51 mcguire +; re-add accidentally removed log comment +; +; Revision 1.29 2008/09/11 20:46:08 mcguire +; can't write to -Caches- +; +; Revision 1.28 2008/09/11 20:04:14 mcguire +; Instances of \. in regex exprs don't do what is intended +; +; Revision 1.27 2008/07/24 21:18:14 cheshire +; Should use randomized source ports and transaction IDs to avoid DNS cache poisoning +; Need to allow access to /dev/urandom +; +; Revision 1.26 2008/06/03 01:21:12 mcguire +; add /var/db/mds to sb profile ; ; Revision 1.25 2008/03/17 18:04:41 mcguire ; SC now reads preference file @@ -147,45 +185,58 @@ "com.apple.bsd.dirhelper" "com.apple.distributed_notifications.2" "com.apple.ocspd" + "com.apple.PowerManagement.control" "com.apple.mDNSResponderHelper" "com.apple.SecurityServer" "com.apple.SystemConfiguration.configd" "com.apple.system.DirectoryService.libinfo_v1" - "com.apple.system.notification_center")) + "com.apple.system.DirectoryService.membership_v1" + "com.apple.system.notification_center" + "com.apple.system.logger")) ; Rules to allow the operations mDNSResponder needs start here +(allow signal (target self)) (allow network*) ; Allow networking, including Unix Domain Sockets +(if (defined? 'system-socket) + (allow system-socket)) ; To create raw 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 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 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 "^/dev/urandom$")) -(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 "^/Library/Preferences/SystemConfiguration/preferences\.plist\$")) -(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/CoreServices/SystemVersion.*\$")) -(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 file-read-data (regex #"^/dev/urandom$")) +(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 #"^/Library/Preferences/SystemConfiguration/preferences\.plist$")) +(allow file-read-data (regex #"^/Library/Preferences/SystemConfiguration/com\.apple\.nat\.plist$")) +(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/CoreServices/SystemVersion.*$")) +(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 file-read-data (regex #"^/System/Library/SystemConfiguration/PowerManagement\.bundle(/|$)")) +(allow file-read-data (regex #"^/Library/Preferences/SystemConfiguration/com\.apple\.PowerManagement\.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\$")) +(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]+(/|\$)")) - +(allow file-read-data (regex #"^/private/var/tmp/mds/")) +(allow file-read* file-write* (regex #"^/private/var/tmp/mds/[0-9]+(/|$)")) +(allow file-read-data (regex #"^/private/var/db/mds/")) +(allow file-read* file-write* (regex #"^/private/var/db/mds/[0-9]+(/|$)")) +(allow file-read* file-write* (regex #"^/private/var/folders/[^/]+/[^/]+/-Caches-/mds(/|$)")) +; CRL Cache for SSL/TLS connections +(allow file-read-data (regex #"^/private/var/db/crls/crlcache\.db$")) diff --git a/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj b/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj index cb961b8..cb3660f 100644 --- a/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj +++ b/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj @@ -19,7 +19,6 @@ D284BF300ADD81630027CCDF /* PBXTargetDependency */, D284BF260ADD814F0027CCDF /* PBXTargetDependency */, D284BF2A0ADD81530027CCDF /* PBXTargetDependency */, - FFD41DDB0664169900F0C438 /* PBXTargetDependency */, ); name = "Build More"; productName = "Build All"; @@ -97,8 +96,13 @@ 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 */; }; + 4AE9B04B0F39448B0080B59D /* safe_vproc.c in Sources */ = {isa = PBXBuildFile; fileRef = 4AE9B0480F39448B0080B59D /* safe_vproc.c */; }; + 4AE9B04C0F39448B0080B59D /* safe_vproc.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AE9B0490F39448B0080B59D /* safe_vproc.h */; }; + 4AE9B0920F3A52A10080B59D /* safe_vproc.c in Sources */ = {isa = PBXBuildFile; fileRef = 4AE9B0480F39448B0080B59D /* safe_vproc.c */; }; + 4AE9B0930F3A52A20080B59D /* safe_vproc.c in Sources */ = {isa = PBXBuildFile; fileRef = 4AE9B0480F39448B0080B59D /* safe_vproc.c */; }; + 4AE9B0940F3A52AE0080B59D /* safe_vproc.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AE9B0490F39448B0080B59D /* safe_vproc.h */; }; + 4AE9B0950F3A52AE0080B59D /* safe_vproc.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AE9B0490F39448B0080B59D /* safe_vproc.h */; }; 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, ); }; }; @@ -188,21 +192,6 @@ 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 */; }; @@ -214,12 +203,15 @@ 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 */; }; + FFB437150EB165BD00E17C68 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; }; FFC22AA20B00F42A00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; }; FFC22AA30B00F42B00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; }; FFC22AA40B00F42C00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; }; FFC22AA50B00F43000BAB070 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; }; FFC22AA60B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; }; FFC22AA70B00F43100BAB070 /* DNSServiceDiscoveryReply.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC00022EAFBA00000109 /* DNSServiceDiscoveryReply.defs */; settings = {ATTRIBUTES = (Server, ); }; }; + FFF589B70E37F66800EF515C /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; }; + FFF589C10E37F67E00EF515C /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; }; FFFA38630AEEDB090065B80A /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; }; FFFA38650AEEDB130065B80A /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; }; FFFA38660AEEDB2B0065B80A /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; }; @@ -286,18 +278,11 @@ remoteGlobalIDString = 03067D640C83A3700022BE1F; remoteInfo = "Build Some"; }; - D284BDEA0ADD77F60027CCDF /* PBXContainerItemProxy */ = { + 4AE471690EAFF83800A6C5AD /* 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; + remoteGlobalIDString = 4AE471670EAFF81900A6C5AD; remoteInfo = dns_sd.jar; }; D284BF250ADD814F0027CCDF /* PBXContainerItemProxy */ = { @@ -474,6 +459,8 @@ 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; }; + 4AE9B0480F39448B0080B59D /* safe_vproc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = safe_vproc.c; sourceTree = ""; }; + 4AE9B0490F39448B0080B59D /* safe_vproc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = safe_vproc.h; sourceTree = ""; }; 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 = ""; }; @@ -541,6 +528,7 @@ FF2C5FB20A48B86E0066DA11 /* RegisterRecordListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = RegisterRecordListener.java; path = ../mDNSShared/Java/RegisterRecordListener.java; sourceTree = SOURCE_ROOT; }; FF354EB108516C63007C00E1 /* installtool */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; name = installtool; path = PreferencePane/installtool; sourceTree = SOURCE_ROOT; }; FF485D5105632E0000130380 /* mDNSResponder.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = mDNSResponder.8; path = ../mDNSShared/mDNSResponder.8; sourceTree = SOURCE_ROOT; }; + FF5852100DD27BD300862BDF /* ClientCommon.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = ClientCommon.c; path = ../Clients/ClientCommon.c; sourceTree = SOURCE_ROOT; }; FF85880B0BD599F40080D89F /* mDNSResponder.sb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mDNSResponder.sb; sourceTree = SOURCE_ROOT; }; FFA572390AF18F1C0055A0F1 /* 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; }; @@ -549,7 +537,6 @@ 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; }; @@ -569,6 +556,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + FFB437150EB165BD00E17C68 /* IOKit.framework in Frameworks */, 2E0406150C3197CB00F13B59 /* libbsm.dylib in Frameworks */, 2E04070A0C31EEEC00F13B59 /* CoreFoundation.framework in Frameworks */, 2E04070B0C31EEEC00F13B59 /* SystemConfiguration.framework in Frameworks */, @@ -656,13 +644,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - DB2CC4520662DD6800335AB3 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; FFA572360AF18F1C0055A0F1 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -704,6 +685,8 @@ 08FB7795FE84155DC02AAC07 /* mDNS Server Sources */ = { isa = PBXGroup; children = ( + 4AE9B0480F39448B0080B59D /* safe_vproc.c */, + 4AE9B0490F39448B0080B59D /* safe_vproc.h */, 4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */, 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */, 2E35528F0C3A95C100CA1CB7 /* helper-error.h */, @@ -770,7 +753,6 @@ isa = PBXGroup; children = ( D284C04D0ADD95D30027CCDF /* Info-PreferencePane.plist */, - FFD41DDA0664157900F0C438 /* dns_sd.jar */, D284BE730ADD80740027CCDF /* mDNSResponder */, D284BE950ADD80800027CCDF /* mDNSResponder.debug */, D284BEA30ADD808B0027CCDF /* mDNS */, @@ -803,6 +785,7 @@ children = ( 6575FC20022EB7AA00000109 /* SamplemDNSClient.c */, FF1C919F07021E3F001048AB /* dns-sd.c */, + FF5852100DD27BD300862BDF /* ClientCommon.c */, ); name = "Command-Line Clients"; sourceTree = ""; @@ -877,6 +860,7 @@ 2ECC11A80C4FEC3800CB1885 /* helpermsg-types.h in Headers */, 2E8165E80C5980E300485EB2 /* libpfkey.h in Headers */, 2E8165EA0C5980F700485EB2 /* ipsec_strerror.h in Headers */, + 4AE9B04C0F39448B0080B59D /* safe_vproc.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -890,6 +874,7 @@ 2EDC5E750C39EA640092701B /* helper-server.h in Headers */, 2E3552900C3A95C100CA1CB7 /* helper-error.h in Headers */, 2ECC11A60C4FEC3800CB1885 /* helpermsg-types.h in Headers */, + 4AE9B0950F3A52AE0080B59D /* safe_vproc.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -906,6 +891,7 @@ 2EDC5E740C39EA640092701B /* helper-server.h in Headers */, 2E3552910C3A95C100CA1CB7 /* helper-error.h in Headers */, 2ECC11A70C4FEC3800CB1885 /* helpermsg-types.h in Headers */, + 4AE9B0940F3A52AE0080B59D /* safe_vproc.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -976,36 +962,23 @@ }; /* 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" */; +/* Begin PBXLegacyTarget section */ + 4AE471670EAFF81900A6C5AD /* dns_sd.jar */ = { + isa = PBXLegacyTarget; + buildArgumentsString = "-f ${SRCROOT}/../mDNSPosix/Makefile OBJDIR=${CONFIGURATION_TEMP_DIR}/dns_sd.jar.build BUILDDIR=${BUILT_PRODUCTS_DIR} SHAREDDIR=${SRCROOT}/../mDNSShared os=x JavaForXcode_$(ACTION)"; + buildConfigurationList = 4AE471770EAFF84000A6C5AD /* Build configuration list for PBXLegacyTarget "dns_sd.jar" */; buildPhases = ( - DB2CC4500662DD6800335AB3 /* Sources */, - DB2CC4510662DD6800335AB3 /* JavaArchive */, - DB2CC4520662DD6800335AB3 /* Frameworks */, - DB2CC4550662DE1700335AB3 /* ShellScript */, - FFD41DDD06641B4200F0C438 /* ShellScript */, ); + buildToolPath = /usr/bin/make; + buildWorkingDirectory = ""; comments = "Multiplatform .jar file that implements Java interface to DNS-SD"; dependencies = ( ); name = dns_sd.jar; - productInstallPath = /System/Library/Java/Extensions; + passBuildSettingsInEnvironment = 1; productName = dns_sd.jar; - productReference = FFD41DDA0664157900F0C438 /* dns_sd.jar */; }; -/* End PBXLibraryTarget section */ +/* End PBXLegacyTarget section */ /* Begin PBXNativeTarget section */ 2E0405EF0C31955500F13B59 /* mDNSResponderHelper */ = { @@ -1122,7 +1095,7 @@ ); comments = "Platform-specific JNI library that bridges dns_sd.jar to ."; dependencies = ( - D284BEB30ADD809A0027CCDF /* PBXTargetDependency */, + 4AE4716A0EAFF83800A6C5AD /* PBXTargetDependency */, ); name = libjdns_sd.jnilib; productInstallPath = /usr/lib/java; @@ -1134,7 +1107,6 @@ isa = PBXNativeTarget; buildConfigurationList = D284BED60ADD80A20027CCDF /* Build configuration list for PBXNativeTarget "dnsextd" */; buildPhases = ( - 030BBF010CE13A2800472F0C /* ShellScript */, D284BEC20ADD80A20027CCDF /* Headers */, D284BEC40ADD80A20027CCDF /* Sources */, D284BECE0ADD80A20027CCDF /* Frameworks */, @@ -1267,7 +1239,7 @@ 2E0405EF0C31955500F13B59 /* mDNSResponderHelper */, D284BE970ADD808B0027CCDF /* mDNS tool */, D284BEA50ADD80920027CCDF /* dns-sd tool */, - DB2CC4530662DD6800335AB3 /* dns_sd.jar */, + 4AE471670EAFF81900A6C5AD /* dns_sd.jar */, D284BEB20ADD809A0027CCDF /* libjdns_sd.jnilib */, D284BEBF0ADD80A20027CCDF /* dnsextd */, D284BEDB0ADD80A70027CCDF /* ddnswriteconfig */, @@ -1298,7 +1270,6 @@ D284BEF90ADD80B00027CCDF /* InfoPlist.strings in Resources */, D284BEFB0ADD80B00027CCDF /* inprogress.tiff in Resources */, D284BEFC0ADD80B00027CCDF /* installtool in Resources */, - D284C04E0ADD95D30027CCDF /* Info-PreferencePane.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1377,20 +1348,6 @@ shellPath = /bin/sh; shellScript = "if [ -e \"${SDKROOT}/usr/lib/libipsec.dylib\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libipsec.a\"\nelse\necho \"#define MDNS_NO_IPSEC 1\" > ${CONFIGURATION_TEMP_DIR}/ipsec_options.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libipsec.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n"; }; - 030BBF010CE13A2800472F0C /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "rm -f \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\n"; - showEnvVarsInLog = 0; - }; D284BE510ADD80740027CCDF /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1398,7 +1355,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if [ -e \"${SDKROOT}/usr/local/include/dnsinfo.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/sandbox.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nfi\n"; + shellScript = "if [ -e \"${SDKROOT}/usr/local/include/dnsinfo.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/sandbox.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/vproc.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nelse\ntouch \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/Frameworks/IOKit.framework/PrivateHeaders/pwr_mgt/IOPMLibPrivate.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/IOKit\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt\"\ntouch \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt/IOPMLibPrivate.h\"\nfi\n"; }; D284BE6C0ADD80740027CCDF /* ShellScript */ = { isa = PBXShellScriptBuildPhase; @@ -1418,15 +1375,6 @@ shellPath = /bin/sh; shellScript = "if [ -e \"${SDKROOT}/usr/local/include/dnsinfo.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\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 \"${SDKROOT}/usr/include/sandbox.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nfi\n"; }; - 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; @@ -1449,15 +1397,6 @@ 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 */ @@ -1469,6 +1408,7 @@ 2E0405F60C31961100F13B59 /* helpermsg.defs in Sources */, 2E96A51D0C39BDAC0087C4D2 /* helper-main.c in Sources */, 2E8165E90C5980EE00485EB2 /* pfkey.c in Sources */, + 4AE9B04B0F39448B0080B59D /* safe_vproc.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1491,6 +1431,7 @@ D284BE630ADD80740027CCDF /* daemon.c in Sources */, 2E04061F0C3198B700F13B59 /* helpermsg.defs in Sources */, 2E96A5320C39C1A50087C4D2 /* helper-stubs.c in Sources */, + 4AE9B0930F3A52A20080B59D /* safe_vproc.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1513,6 +1454,7 @@ D284BE8B0ADD80800027CCDF /* daemon.c in Sources */, 2E0406200C3198B700F13B59 /* helpermsg.defs in Sources */, 2E96A5300C39C1A50087C4D2 /* helper-stubs.c in Sources */, + 4AE9B0920F3A52A10080B59D /* safe_vproc.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1529,6 +1471,7 @@ buildActionMask = 2147483647; files = ( D284BEA80ADD80920027CCDF /* dns-sd.c in Sources */, + FFF589B70E37F66800EF515C /* ClientCommon.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1555,7 +1498,6 @@ D284BECD0ADD80A20027CCDF /* PlatformCommon.c in Sources */, 2EAE955A0C31F4D30021F738 /* helpermsg.defs in Sources */, 2E35529E0C3A9E7600CA1CB7 /* helper-stubs.c in Sources */, - 4A8202650C56C4C900DDFD48 /* pfkey.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1574,27 +1516,7 @@ 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 */, + FFF589C10E37F67E00EF515C /* ClientCommon.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1665,10 +1587,10 @@ target = 03067D640C83A3700022BE1F /* Build Some */; targetProxy = 03067D850C849CC30022BE1F /* PBXContainerItemProxy */; }; - D284BEB30ADD809A0027CCDF /* PBXTargetDependency */ = { + 4AE4716A0EAFF83800A6C5AD /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = DB2CC4530662DD6800335AB3 /* dns_sd.jar */; - targetProxy = D284BEB40ADD809A0027CCDF /* PBXContainerItemProxy */; + target = 4AE471670EAFF81900A6C5AD /* dns_sd.jar */; + targetProxy = 4AE471690EAFF83800A6C5AD /* PBXContainerItemProxy */; }; D284BF260ADD814F0027CCDF /* PBXTargetDependency */ = { isa = PBXTargetDependency; @@ -1720,11 +1642,6 @@ 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 */ @@ -1767,7 +1684,7 @@ CONFIGURATION_TEMP_DIR = "$(PROJECT_TEMP_DIR)"; COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_WARN_CHECK_SWITCH_STATEMENTS = NO; HEADER_SEARCH_PATHS = "${CONFIGURATION_TEMP_DIR}"; INSTALL_PATH = /usr/sbin; @@ -1783,34 +1700,13 @@ }; name = Development; }; - D284BE1D0ADD78180027CCDF /* Development */ = { + 4AE471680EAFF81900A6C5AD /* Development */ = { isa = XCBuildConfiguration; buildSettings = { - CONFIGURATION_BUILD_DIR = "${BUILD_DIR}"; - CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build"; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; + COPY_PHASE_STRIP = NO; 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"; + GCC_OPTIMIZATION_LEVEL = 0; + PRODUCT_NAME = dns_sd.jar; }; name = Development; }; @@ -1820,7 +1716,7 @@ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}"; CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build"; GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; OTHER_CFLAGS = ""; OTHER_LDFLAGS = ""; @@ -1833,6 +1729,8 @@ D284BE2C0ADD78180027CCDF /* Development */ = { isa = XCBuildConfiguration; buildSettings = { + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)"; + DEAD_CODE_STRIPPING = YES; GCC_PREPROCESSOR_DEFINITIONS = ( "APPLE_OSX_mDNSResponder=1", "__MigTypeCheck=1", @@ -1842,8 +1740,12 @@ ); GCC_TREAT_WARNINGS_AS_ERRORS = YES; MVERS = "\"(Engineering Build)\""; - OTHER_CFLAGS = "-DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS"; + OTHER_CFLAGS = ( + "-DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS", + "-fwrapv", + ); PREBINDING = NO; + STRIP_STYLE = debugging; WARNING_CFLAGS = ( "-W", "-Wall", @@ -1863,7 +1765,7 @@ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build"; FRAMEWORK_SEARCH_PATHS = ""; GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; HEADER_SEARCH_PATHS = ( ../mDNSShared, @@ -1874,6 +1776,7 @@ INSTALL_PATH = /usr/sbin; LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\""; MACOSX_DEPLOYMENT_TARGET = 10.4; + ORDER_FILE = "${SRCROOT}/mDNSResponder.order"; OTHER_CFLAGS = ( "$(inherited)", "-no-cpp-precomp", @@ -1882,13 +1785,6 @@ OTHER_REZFLAGS = ""; PRODUCT_NAME = mDNSResponder; REZ_EXECUTABLE = YES; - SECTORDER_FLAGS = ( - "-sectorder", - __TEXT, - __text, - mDNSResponder.order, - ); - STRIPFLAGS = "-S"; }; name = Development; }; @@ -1928,7 +1824,6 @@ __text, mDNSResponder.order, ); - STRIPFLAGS = "-S"; }; name = Development; }; @@ -1938,7 +1833,7 @@ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}"; CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build"; GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; INSTALL_PATH = /usr/bin; MACOSX_DEPLOYMENT_TARGET = 10.4; @@ -1948,7 +1843,6 @@ PRODUCT_NAME = mDNS; REZ_EXECUTABLE = YES; SECTORDER_FLAGS = ""; - STRIPFLAGS = "-S"; }; name = Development; }; @@ -1958,7 +1852,7 @@ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}"; CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build"; GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; HEADER_SEARCH_PATHS = ../mDNSShared; INSTALL_PATH = /usr/bin; @@ -1969,7 +1863,6 @@ PRODUCT_NAME = "dns-sd"; REZ_EXECUTABLE = YES; SECTORDER_FLAGS = ""; - STRIPFLAGS = "-S"; }; name = Development; }; @@ -1982,14 +1875,14 @@ DYLIB_CURRENT_VERSION = 1; EXECUTABLE_EXTENSION = jnilib; GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_SYMBOLS_PRIVATE_EXTERN = NO; HEADER_SEARCH_PATHS = ( ../mDNSShared, "${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/A/Headers", "${SYSTEM_LIBRARY_DIR}/Frameworks/JavaVM.framework/Versions/1.3.1/Headers", - "${CONFIGURATION_TEMP_DIR}/dns_sd.jar.build", + "${PROJECT_DERIVED_FILE_DIR}", ); INSTALL_PATH = /usr/lib/java; LIBRARY_STYLE = DYNAMIC; @@ -2000,7 +1893,6 @@ PRODUCT_NAME = libjdns_sd; REZ_EXECUTABLE = YES; SECTORDER_FLAGS = ""; - STRIPFLAGS = "-S"; }; name = Development; }; @@ -2011,7 +1903,7 @@ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build"; FRAMEWORK_SEARCH_PATHS = ""; GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; HEADER_SEARCH_PATHS = ( "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers", @@ -2032,7 +1924,6 @@ PRODUCT_NAME = dnsextd; REZ_EXECUTABLE = YES; SECTORDER_FLAGS = ""; - STRIPFLAGS = "-S"; YACC = "/usr/bin/bison -y"; }; name = Development; @@ -2043,17 +1934,16 @@ CONFIGURATION_BUILD_DIR = "${BUILD_DIR}"; CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build"; GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; INSTALL_PATH = "/Library/Application Support/Bonjour"; - MACOSX_DEPLOYMENT_TARGET = 10.4; + MACOSX_DEPLOYMENT_TARGET = ""; OTHER_CFLAGS = ""; OTHER_LDFLAGS = ""; OTHER_REZFLAGS = ""; PRODUCT_NAME = ddnswriteconfig; REZ_EXECUTABLE = YES; SECTORDER_FLAGS = ""; - STRIPFLAGS = "-S"; }; name = Development; }; @@ -2064,18 +1954,17 @@ CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build"; EXPORTED_SYMBOLS_FILE = ""; GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; 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.4; + MACOSX_DEPLOYMENT_TARGET = ""; OTHER_CFLAGS = ""; OTHER_LDFLAGS = "-twolevel_namespace"; OTHER_REZFLAGS = ""; PRODUCT_NAME = Bonjour; SECTORDER_FLAGS = ""; - STRIPFLAGS = "-S"; WRAPPER_EXTENSION = prefPane; }; name = Development; @@ -2173,10 +2062,10 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Development; }; - D284BE1C0ADD78180027CCDF /* Build configuration list for PBXLibraryTarget "dns_sd.jar" */ = { + 4AE471770EAFF84000A6C5AD /* Build configuration list for PBXLegacyTarget "dns_sd.jar" */ = { isa = XCConfigurationList; buildConfigurations = ( - D284BE1D0ADD78180027CCDF /* Development */, + 4AE471680EAFF81900A6C5AD /* Development */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Development; diff --git a/mDNSMacOSX/safe_vproc.c b/mDNSMacOSX/safe_vproc.c new file mode 100644 index 0000000..eaf41c9 --- /dev/null +++ b/mDNSMacOSX/safe_vproc.c @@ -0,0 +1,92 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2009 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: safe_vproc.c,v $ +Revision 1.3 2009/02/14 00:09:53 cheshire +Only log "Compiled without vproc_transaction support" when running on a system +where we expect that to be available -- if running on a system that doesn't even +have vproc_transaction, then it doesn't matter that the code was compiled without it. + +Revision 1.2 2009/02/09 21:16:17 mcguire + Adopt vproc_transaction API in mDNSResponder +additional cleanup: don't alloc memory since we currently only expect to have one transaction + +Revision 1.1 2009/02/06 03:06:49 mcguire + Adopt vproc_transaction API in mDNSResponder + + */ + +#include +#include +#include +#include "safe_vproc.h" +#include "mDNSDebug.h" + +#ifdef VPROC_HAS_TRANSACTIONS + +static vproc_transaction_t transaction = NULL; + +void safe_vproc_transaction_begin(void) + { + if (vproc_transaction_begin) + { + if (transaction) { LogMsg("safe_vproc_transaction_begin: Already have a transaction"); } + else transaction = vproc_transaction_begin(NULL); + } + } + +void safe_vproc_transaction_end(void) + { + if (vproc_transaction_end) + { + if (transaction) { vproc_transaction_end(NULL, transaction); transaction = NULL; } + else LogMsg("safe_vproc_transaction_end: No current transaction"); + } + } + +#else + +#include +#include + +CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void); +CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey; +#define OSXVers_10_6_SnowLeopard 10 + +void safe_vproc_transaction_begin(void) + { + static int majorversion = 0; + if (!majorversion) + { + CFDictionaryRef vers = _CFCopySystemVersionDictionary(); + if (vers) + { + char buildver[256]; + CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey); + if (cfbuildver && CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8)) + sscanf(buildver, "%d", &majorversion); + CFRelease(vers); + } + if (!majorversion || majorversion >= OSXVers_10_6_SnowLeopard) + LogMsg("Compiled without vproc_transaction support"); + } + } + +void safe_vproc_transaction_end(void) { } + +#endif diff --git a/mDNSMacOSX/safe_vproc.h b/mDNSMacOSX/safe_vproc.h new file mode 100644 index 0000000..79932d1 --- /dev/null +++ b/mDNSMacOSX/safe_vproc.h @@ -0,0 +1,31 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2009 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: safe_vproc.h,v $ +Revision 1.1 2009/02/06 03:06:49 mcguire + Adopt vproc_transaction API in mDNSResponder + + */ + +#ifndef __SAFE_VPROC_H +#define __SAFE_VPROC_H + +extern void safe_vproc_transaction_begin(void); +extern void safe_vproc_transaction_end(void); + +#endif /* __SAFE_VPROC_H */ diff --git a/mDNSPosix/Client.c b/mDNSPosix/Client.c index 6efffc3..bd6137d 100755 --- a/mDNSPosix/Client.c +++ b/mDNSPosix/Client.c @@ -17,6 +17,9 @@ Change History (most recent first): $Log: Client.c,v $ +Revision 1.21 2008/11/04 19:46:01 cheshire +Updated comment about MAX_ESCAPED_DOMAIN_NAME size (should be 1009, not 1005) + 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 @@ -55,7 +58,7 @@ Typo: Wrote "domC" where it should have said "domainC" Revision 1.10 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. +Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1009) instead of 256-byte buffers. Revision 1.9 2003/08/14 02:19:55 cheshire Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord diff --git a/mDNSPosix/Identify.c b/mDNSPosix/Identify.c index ee88102..c2a033f 100644 --- a/mDNSPosix/Identify.c +++ b/mDNSPosix/Identify.c @@ -30,6 +30,12 @@ Change History (most recent first): $Log: Identify.c,v $ +Revision 1.44 2009/01/13 05:31:34 mkrochma + Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy + +Revision 1.43 2008/09/05 22:51:21 cheshire +Minor cleanup to bring code in sync with TOT, and make "_services" metaquery work again + 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 @@ -134,7 +140,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, QC_result AddRecord) +mDNSlocal void NameCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) { (void)m; // Unused (void)question; // Unused @@ -148,7 +154,7 @@ static void NameCallback(mDNS *const m, DNSQuestion *question, const ResourceRec } } -static void InfoCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) +mDNSlocal void InfoCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) { (void)m; // Unused (void)question; // Unused @@ -187,10 +193,10 @@ static void InfoCallback(mDNS *const m, DNSQuestion *question, const ResourceRec } // If we've got everything we're looking for, don't need to wait any more - if (NumHINFO && (NumAddr || NumAAAA)) StopNow = 1; + if (/*NumHINFO && */ (NumAddr || NumAAAA)) StopNow = 1; } -static void ServicesCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) +mDNSlocal void ServicesCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) { (void)m; // Unused (void)question; // Unused @@ -201,13 +207,11 @@ static void ServicesCallback(mDNS *const m, DNSQuestion *question, const Resourc if (answer->rrtype == kDNSType_PTR && mDNSSameAddress(&lastsrc, &target)) { NumAnswers++; - NumAddr++; mprintf("%##s %s %##s\n", answer->name->c, DNSTypeName(answer->rrtype), answer->rdata->u.name.c); - StopNow = 1; } } -mDNSexport void WaitForAnswer(mDNS *const m, int seconds) +mDNSlocal void WaitForAnswer(mDNS *const m, int seconds) { struct timeval end; gettimeofday(&end, NULL); @@ -224,7 +228,11 @@ mDNSexport void WaitForAnswer(mDNS *const m, int seconds) FD_ZERO(&readfds); gettimeofday(&now, NULL); if (remain.tv_usec < now.tv_usec) { remain.tv_usec += 1000000; remain.tv_sec--; } - if (remain.tv_sec < now.tv_sec) return; + if (remain.tv_sec < now.tv_sec) + { + if (!NumAnswers) printf("No response after %d seconds\n", seconds); + return; + } remain.tv_usec -= now.tv_usec; remain.tv_sec -= now.tv_sec; mDNSPosixGetFDSet(m, &nfds, &readfds, &remain); @@ -236,15 +244,16 @@ mDNSexport void WaitForAnswer(mDNS *const m, int seconds) mDNSlocal mStatus StartQuery(DNSQuestion *q, char *qname, mDNSu16 qtype, const mDNSAddr *target, mDNSQuestionCallback callback) { + lastsrc = zeroAddr; if (qname) MakeDomainNameFromDNSNameString(&q->qname, qname); + q->InterfaceID = mDNSInterface_Any; q->Target = target ? *target : zeroAddr; q->TargetPort = MulticastDNSPort; q->TargetQID = zeroID; - q->InterfaceID = mDNSInterface_Any; q->qtype = qtype; q->qclass = kDNSClass_IN; q->LongLived = mDNSfalse; - q->ExpectUnique = mDNStrue; + q->ExpectUnique = mDNSfalse; // Don't want to stop after the first response packet 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; @@ -269,7 +278,7 @@ mDNSlocal void DoOneQuery(DNSQuestion *q, char *qname, mDNSu16 qtype, const mDNS mDNSlocal int DoQuery(DNSQuestion *q, char *qname, mDNSu16 qtype, const mDNSAddr *target, mDNSQuestionCallback callback) { DoOneQuery(q, qname, qtype, target, callback); - if (StopNow == 0 && target && target->type) + if (StopNow == 0 && NumAnswers == 0 && target && target->type) { mprintf("%##s %s Trying multicast\n", q->qname.c, DNSTypeName(q->qtype)); DoOneQuery(q, qname, qtype, NULL, callback); @@ -350,7 +359,7 @@ mDNSexport int main(int argc, char **argv) } mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa."); target.type = mDNSAddrType_IPv6; - bcopy(&s6, &target.ip.v6, sizeof(target.ip.v6)); + mDNSPlatformMemCopy(&target.ip.v6, &s6, sizeof(target.ip.v6)); DoQuery(&q, buffer, kDNSType_PTR, &target, NameCallback); if (StopNow == 2) break; } @@ -364,25 +373,24 @@ mDNSexport int main(int argc, char **argv) if (hardware[0] || software[0]) { - DNSQuestion q1; printf("HINFO Hardware: %s\n", hardware); printf("HINFO Software: %s\n", software); - // We need to make sure the services query is targeted - if (target.type == 0) target = hostaddr; - StartQuery(&q1, "_services._dns-sd._udp.local.", kDNSQType_ANY, &target, ServicesCallback); - WaitForAnswer(&mDNSStorage, 4); - mDNS_StopQuery(&mDNSStorage, &q1); - if (StopNow == 2) break; } - else if (NumAnswers) + else if (NumAnswers) printf("%s has no HINFO record\n", hostname); + else printf("Incorrect dot-local hostname, address, or no mDNSResponder running on that machine\n"); + + if (NumAnswers) { - printf("Host has no HINFO record; Best guess is "); - if (id.b[1]) printf("mDNSResponder-%d\n", id.b[1]); - else if (NumAAAA) printf("very early Panther build (mDNSResponder-33 or earlier)\n"); - else printf("Jaguar version of mDNSResponder with no IPv6 support\n"); + // Because of the way we use lastsrc in ServicesCallback, we need to clear the cache to make sure we're getting fresh answers + mDNS *const m = &mDNSStorage; + mDNSu32 slot; + CacheGroup *cg; + CacheRecord *rr; + FORALL_CACHERECORDS(slot, cg, rr) mDNS_PurgeCacheResourceRecord(m, rr); + if (target.type == 0) target = hostaddr; // Make sure the services query is targeted + DoQuery(&q, "_services._dns-sd._udp.local.", kDNSType_PTR, &target, ServicesCallback); + if (StopNow == 2) break; } - else - printf("Incorrect dot-local hostname, address, or no mDNSResponder running on that machine\n"); } mDNS_Close(&mDNSStorage); diff --git a/mDNSPosix/Makefile b/mDNSPosix/Makefile index 0a4763f..82e78b0 100755 --- a/mDNSPosix/Makefile +++ b/mDNSPosix/Makefile @@ -31,6 +31,29 @@ # then try typing "gmake os=xxx" instead. # # $Log: Makefile,v $ +# Revision 1.83 2009/02/02 19:44:06 cheshire +# Use "-fwrapv" option to tell compiler that the code is written assuming that +# signed arithmetic is implemented using the twos-complement representation +# (this is pretty much universally true on today's processors). +# +# Without this option, gcc may decide that because the C language +# does not require processors to use twos-complement representation, that means +# gcc is free to do some "creative" optimizations that don't preserve the overflow +# behaviour of twos-complement arithmetic. See also "-fstrict-overflow": +# +# +# Revision 1.82 2009/01/12 22:48:00 cheshire +# Don't need to include "." in the "#include" search path +# +# Revision 1.81 2009/01/11 03:20:06 mkrochma +# Fixes from Igor Seleznev to get mdnsd working on Solaris +# +# Revision 1.80 2008/11/03 23:27:51 cheshire +# Defined __MAC_OS_X_VERSION_MIN_REQUIRED=__MAC_OS_X_VERSION_10_4 to stop build failures on Leopard +# +# Revision 1.79 2008/10/24 01:59:59 mcguire +# Build Failure: Need to stop using Jam +# # Revision 1.78 2007/10/22 20:16:49 cheshire # Got rid of jaguar and panther from list of target platforms; # changed "os=tiger" to "os=x" (which works with both Tiger and Leopard) @@ -290,7 +313,7 @@ LIBVERS = 1 COREDIR = ../mDNSCore -SHAREDDIR = ../mDNSShared +SHAREDDIR ?= ../mDNSShared JDK = /usr/jdk CC = @cc @@ -300,7 +323,7 @@ LD = ld -shared CP = cp RM = rm LN = ln -s -f -CFLAGS_COMMON = -I. -I$(COREDIR) -I$(SHAREDDIR) -I$(OBJDIR) -W -Wall -DPID_FILE=\"/var/run/mdnsd.pid\" -DMDNS_UDS_SERVERPATH=\"/var/run/mdnsd\" +CFLAGS_COMMON = -I$(COREDIR) -I$(SHAREDDIR) -I$(OBJDIR) -fwrapv -W -Wall -DPID_FILE=\"/var/run/mdnsd.pid\" -DMDNS_UDS_SERVERPATH=\"/var/run/mdnsd\" CFLAGS_PTHREAD = LINKOPTS = LINKOPTS_PTHREAD = -lpthread @@ -319,15 +342,16 @@ else # 1. We want to make small binaries, suitable for putting into hardware devices # 2. Some of the code analysis warnings only work when some form of optimization is enabled CFLAGS_DEBUG = -Os -DMDNS_DEBUGMSGS=0 -OBJDIR = objects/prod -BUILDDIR = build/prod +OBJDIR ?= objects/prod +BUILDDIR ?= build/prod STRIP = strip -S endif # Configure per-OS peculiarities ifeq ($(os),solaris) +CFLAGS_DEBUG = -O0 -DMDNS_DEBUGMSGS=0 CFLAGS_OS = -DNOT_HAVE_DAEMON -DNOT_HAVE_SA_LEN -DNOT_HAVE_SOCKLEN_T -DNOT_HAVE_IF_NAMETOINDEX \ - -DLOG_PERROR=0 -D_XPG4_2 -D__EXTENSIONS__ -DHAVE_BROKEN_RECVIF_NAME + -DLOG_PERROR=0 -D_XPG4_2 -D__EXTENSIONS__ -DHAVE_BROKEN_RECVIF_NAME -DTARGET_OS_SOLARIS CC = gcc LD = gcc -shared LINKOPTS = -lsocket -lnsl -lresolv @@ -375,7 +399,10 @@ LDCONFIG = ldconfig else ifeq ($(os),x) -CFLAGS_OS = -DHAVE_IPV6 -no-cpp-precomp -Werror -Wdeclaration-after-statement #-Wunreachable-code +# We have to define __MAC_OS_X_VERSION_MIN_REQUIRED=__MAC_OS_X_VERSION_10_4 or on Leopard +# we get build failures: ‘daemon’ is deprecated (declared at /usr/include/stdlib.h:283) +CFLAGS_OS = -DHAVE_IPV6 -no-cpp-precomp -Werror -Wdeclaration-after-statement \ + -D__MAC_OS_X_VERSION_MIN_REQUIRED=__MAC_OS_X_VERSION_10_4 #-Wunreachable-code CC = @gcc-4.0 LD = $(CC) -dynamiclib LINKOPTS = -lSystem @@ -450,10 +477,8 @@ install: setup InstalledDaemon InstalledStartup InstalledLib InstalledManPages I # 'setup' sets up the build directory structure the way we want setup: - @if test ! -d objects ; then mkdir objects ; fi - @if test ! -d build ; then mkdir build ; fi - @if test ! -d $(OBJDIR) ; then mkdir $(OBJDIR) ; fi - @if test ! -d $(BUILDDIR) ; then mkdir $(BUILDDIR) ; fi + @if test ! -d $(OBJDIR) ; then mkdir -p $(OBJDIR) ; fi + @if test ! -d $(BUILDDIR) ; then mkdir -p $(BUILDDIR) ; fi # clean removes targets and objects clean: @@ -593,6 +618,7 @@ $(NSSINSTPATH)/$(NSSLIBFILE): $(BUILDDIR)/$(NSSLIBFILE) ############################################################################# # The following targets build Java wrappers for the dns-sd.h API. +# Note that the JavaForXcode targets are used when building the project for OS X using Xcode JAVAC = $(JDK)/bin/javac JAVAH = $(JDK)/bin/javah @@ -600,6 +626,29 @@ JAVADOC = $(JDK)/bin/javadoc JAR = $(JDK)/bin/jar JAVACFLAGS = $(CFLAGS) $(JAVACFLAGS_OS) -I$(JDK)/include +JavaForXcode_: setup $(BUILDDIR)/dns_sd.jar $(PROJECT_DERIVED_FILE_DIR)/DNSSD.java.h + @echo $@ done + +$(PROJECT_DERIVED_FILE_DIR)/DNSSD.java.h: $(OBJDIR)/DNSSD.java.h + @if test ! -d $(PROJECT_DERIVED_FILE_DIR) ; then mkdir -p $(PROJECT_DERIVED_FILE_DIR) ; fi + $(CP) $< $@ + +JavaForXcode_clean: + @if test -d $(OBJDIR) ; then rm -r $(OBJDIR) ; fi + @if test -f $(PROJECT_DERIVED_FILE_DIR)/DNSSD.java.h ; then $(RM) $(PROJECT_DERIVED_FILE_DIR)/DNSSD.java.h ; fi + @if test -f $(BUILDDIR)/dns_sd.jar ; then $(RM) $(BUILDDIR)/dns_sd.jar ; fi + @echo $@ done + +JavaForXcode_installhdrs: + @echo $@ NOOP + +JavaForXcode_install: JavaForXcode_ $(DSTROOT)/$(SYSTEM_LIBRARY_DIR)/Java/Extensions/dns_sd.jar + @echo $@ done + +$(DSTROOT)/$(SYSTEM_LIBRARY_DIR)/Java/Extensions/dns_sd.jar: $(BUILDDIR)/dns_sd.jar + @if test ! -d $(DSTROOT)/$(SYSTEM_LIBRARY_DIR)/Java/Extensions ; then mkdir -p $(DSTROOT)/$(SYSTEM_LIBRARY_DIR)/Java/Extensions ; fi + $(CP) $< $@ + Java: setup $(BUILDDIR)/dns_sd.jar $(BUILDDIR)/libjdns_sd.$(LDSUFFIX) @echo "Java wrappers done" @@ -636,7 +685,9 @@ $(OBJDIR)/DNSSD.java.h: $(OBJDIR)/com/apple/dnssd/DNSSD.class com.apple.dnssd.AppleRegistration \ com.apple.dnssd.AppleQuery \ com.apple.dnssd.AppleDomainEnum \ - com.apple.dnssd.AppleService + com.apple.dnssd.AppleService \ + com.apple.dnssd.AppleDNSRecord \ + com.apple.dnssd.AppleRecordRegistrar ############################################################################# diff --git a/mDNSPosix/NetMonitor.c b/mDNSPosix/NetMonitor.c index 9f26ea0..f873ea3 100644 --- a/mDNSPosix/NetMonitor.c +++ b/mDNSPosix/NetMonitor.c @@ -30,6 +30,23 @@ Change History (most recent first): $Log: NetMonitor.c,v $ +Revision 1.94 2009/04/24 00:31:56 cheshire + Return negative answers when host knows authoritatively that no answer exists +Added code to display NSEC records + +Revision 1.93 2009/01/13 05:31:34 mkrochma + Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy + +Revision 1.92 2009/01/11 03:20:06 mkrochma + Fixes from Igor Seleznev to get mdnsd working on Solaris + +Revision 1.91 2008/11/13 22:08:07 cheshire +Show additional records in Query packets + +Revision 1.90 2008/09/05 22:20:26 cheshire + Should use randomized source ports and transaction IDs to avoid DNS cache poisoning +Add "UDPSocket *src" parameter in mDNSPlatformSendUDP call + Revision 1.89 2007/05/17 19:12:42 cheshire Tidy up code layout @@ -95,7 +112,7 @@ Use IFNAMSIZ (more portable) instead of IF_NAMESIZE #include // For printf() #include // For malloc() -#include // For bcopy() +#include // For strrchr(), strcmp() #include // For "struct tm" etc. #include // For SIGINT, SIGTERM #include // For gethostbyname() @@ -361,7 +378,7 @@ mDNSlocal void SendUnicastQuery(mDNS *const m, HostEntry *entry, domainname *nam InterfaceID = mDNSInterface_Any; // Send query from our unicast reply socket } - mDNSSendDNSMessage(&mDNSStorage, &query, qptr, InterfaceID, target, MulticastDNSPort, mDNSNULL, mDNSNULL); + mDNSSendDNSMessage(&mDNSStorage, &query, qptr, InterfaceID, mDNSNULL, target, MulticastDNSPort, mDNSNULL, mDNSNULL); } mDNSlocal void AnalyseHost(mDNS *const m, HostEntry *entry, const mDNSInterfaceID InterfaceID) @@ -583,6 +600,12 @@ mDNSlocal void DisplayResourceRecord(const mDNSAddr *const srcaddr, const char * } break; case kDNSType_AAAA: n += mprintf("%.16a", &rd->ipv6); break; case kDNSType_SRV: n += mprintf("%##s:%d", rd->srv.target.c, mDNSVal16(rd->srv.port)); break; + case kDNSType_NSEC: { + int i; + for (i=0; i<255; i++) + if (rd->nsec.bitmap[i>>3] & (128 >> (i&7))) + n += mprintf("%s ", DNSTypeName(i)); + } break; default: { mDNSu8 *s = rd->data; while (s < rdend && p < buffer+MaxWidth) @@ -693,6 +716,14 @@ mDNSlocal void DisplayQuery(mDNS *const m, const DNSMessage *const msg, const mD if (!ptr) { DisplayError(srcaddr, ep, end, "AUTHORITY"); return; } } + for (i=0; ih.numAdditionals; i++) + { + const mDNSu8 *ep = ptr; + ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &pkt); + if (!ptr) { DisplayError(srcaddr, ep, end, "ADDITIONAL"); return; } + DisplayResourceRecord(srcaddr, " ", &pkt.r.resrec); + } + if (entry) AnalyseHost(m, entry, InterfaceID); } @@ -943,7 +974,7 @@ mDNSexport int main(int argc, char **argv) else if (inet_pton(AF_INET6, argv[i], &s6) == 1) { a.type = mDNSAddrType_IPv6; - bcopy(&s6, &a.ip.v6, sizeof(a.ip.v6)); + mDNSPlatformMemCopy(&a.ip.v6, &s6, sizeof(a.ip.v6)); } else { diff --git a/mDNSPosix/PosixDaemon.c b/mDNSPosix/PosixDaemon.c index be0523f..4d19265 100644 --- a/mDNSPosix/PosixDaemon.c +++ b/mDNSPosix/PosixDaemon.c @@ -21,6 +21,25 @@ Change History (most recent first): $Log: PosixDaemon.c,v $ +Revision 1.49 2009/04/30 20:07:51 mcguire + Support multiple UDSs from launchd + +Revision 1.48 2009/04/11 01:43:28 jessic2 + Daemon: Should be able to turn on LogOperation dynamically + +Revision 1.47 2009/01/11 03:20:06 mkrochma + Fixes from Igor Seleznev to get mdnsd working on Solaris + +Revision 1.46 2008/11/03 23:09:15 cheshire +Don't need to include mDNSDebug.h as well as mDNSEmbeddedAPI.h + +Revision 1.45 2008/10/03 18:25:17 cheshire +Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);" + +Revision 1.44 2008/09/15 23:52:30 cheshire + mDNSResponder-177 fails to compile on Linux with .desc pseudo-op +Made __crashreporter_info__ symbol conditional, so we only use it for OS X build + Revision 1.43 2007/10/22 20:05:34 cheshire Use mDNSPlatformSourceAddrForDest instead of FindSourceAddrForIP @@ -79,8 +98,8 @@ Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsex #include #include "mDNSEmbeddedAPI.h" -#include "mDNSDebug.h" #include "mDNSPosix.h" +#include "mDNSUNP.h" // For daemon() #include "uds_daemon.h" #include "PlatformCommon.h" @@ -130,7 +149,7 @@ static void Reconfigure(mDNS *m) mDNSPlatformSourceAddrForDest(&DynDNSIP, &dummy); if (DynDNSHostname.c[0]) mDNS_AddDynDNSHostName(m, &DynDNSHostname, NULL, NULL); if (DynDNSIP.type) mDNS_SetPrimaryInterfaceInfo(m, &DynDNSIP, NULL, NULL); - m->MainCallback(m, mStatus_ConfigChanged); + mDNS_ConfigChanged(m); } // Do appropriate things at startup with command line arguments. Calls exit() if unhappy. @@ -156,9 +175,9 @@ mDNSlocal void ParseCmdLinArgs(int argc, char **argv) mDNSlocal void DumpStateLog(mDNS *const m) // Dump a little log of what we've been up to. { - LogMsgIdent(mDNSResponderVersionString, "---- BEGIN STATE LOG ----"); + LogMsg("---- BEGIN STATE LOG ----"); udsserver_info(m); - LogMsgIdent(mDNSResponderVersionString, "---- END STATE LOG ----"); + LogMsg("---- END STATE LOG ----"); } mDNSlocal mStatus MainLoop(mDNS *m) // Loop until we quit. @@ -209,13 +228,13 @@ int main(int argc, char **argv) ParseCmdLinArgs(argc, argv); - LogMsgIdent(mDNSResponderVersionString, "starting"); + LogMsg("%s starting", mDNSResponderVersionString); err = mDNS_Init(&mDNSStorage, &PlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext); if (mStatus_NoError == err) - err = udsserver_init(dnssd_InvalidSocket); + err = udsserver_init(mDNSNULL, 0); Reconfigure(&mDNSStorage); @@ -232,11 +251,11 @@ int main(int argc, char **argv) if (mStatus_NoError == err) err = MainLoop(&mDNSStorage); - LogMsgIdent(mDNSResponderVersionString, "stopping"); + LogMsg("%s stopping", mDNSResponderVersionString); mDNS_Close(&mDNSStorage); - if (udsserver_exit(dnssd_InvalidSocket) < 0) + if (udsserver_exit() < 0) LogMsg("ExitCallback: udsserver_exit failed"); #if MDNS_DEBUGMSGS > 0 @@ -269,9 +288,11 @@ mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay) // No-op, for now } +#if _BUILDING_XCODE_PROJECT_ // If the process crashes, then this string will be magically included in the automatically-generated crash log const char *__crashreporter_info__ = mDNSResponderVersionString_SCCS + 5; asm(".desc ___crashreporter_info__, 0x10"); +#endif // For convenience when using the "strings" command, this is the last thing in the file #if mDNSResponderVersion > 1 diff --git a/mDNSPosix/ProxyResponder.c b/mDNSPosix/ProxyResponder.c index 5ae6809..dd76ac7 100644 --- a/mDNSPosix/ProxyResponder.c +++ b/mDNSPosix/ProxyResponder.c @@ -17,6 +17,9 @@ Change History (most recent first): $Log: ProxyResponder.c,v $ +Revision 1.45 2008/11/04 19:46:01 cheshire +Updated comment about MAX_ESCAPED_DOMAIN_NAME size (should be 1009, not 1005) + Revision 1.44 2007/04/22 20:16:25 cheshire Fix compiler errors (const parameter declarations) @@ -84,7 +87,7 @@ Add support for mDNSResponder on Linux. Revision 1.24 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. +Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1009) instead of 256-byte buffers. Revision 1.23 2003/10/30 19:39:28 cheshire Fix warnings on certain compilers diff --git a/mDNSPosix/Responder.c b/mDNSPosix/Responder.c index 9a4d13a..67cc817 100755 --- a/mDNSPosix/Responder.c +++ b/mDNSPosix/Responder.c @@ -17,6 +17,15 @@ Change History (most recent first): $Log: Responder.c,v $ +Revision 1.36 2009/01/15 03:39:08 mkrochma +Fix warning about ignoring return value of daemon + +Revision 1.35 2009/01/13 05:31:34 mkrochma + Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy + +Revision 1.34 2009/01/11 03:20:06 mkrochma + Fixes from Igor Seleznev to get mdnsd working on Solaris + Revision 1.33 2007/04/16 20:49:39 cheshire Fix compile errors for mDNSPosix build @@ -126,6 +135,7 @@ First checkin #include "mDNSEmbeddedAPI.h"// Defines the interface to the client layer above #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform +#include "mDNSUNP.h" // For daemon() #include #include // For printf() @@ -404,7 +414,7 @@ static void ParseArguments(int argc, char **argv) while (optind < argc) { gServiceText[gServiceTextLen] = strlen(argv[optind]); - memcpy(gServiceText+gServiceTextLen+1, argv[optind], gServiceText[gServiceTextLen]); + mDNSPlatformMemCopy(gServiceText+gServiceTextLen+1, argv[optind], gServiceText[gServiceTextLen]); gServiceTextLen += 1 + gServiceText[gServiceTextLen]; optind++; } @@ -636,7 +646,7 @@ static mStatus RegisterServicesInFile(const char *filePath) unsigned int newlen = textLen + 1 + len; if (len == 0 || newlen >= sizeof(text)) break; text[textLen] = len; - memcpy(text + textLen + 1, rawText, len); + mDNSPlatformMemCopy(text + textLen + 1, rawText, len); textLen = newlen; } else @@ -726,11 +736,12 @@ int main(int argc, char **argv) // because printf has no format specified for pid_t. if (gDaemon) { + int result; if (gMDNSPlatformPosixVerboseLevel > 0) { fprintf(stderr, "%s: Starting in daemon mode\n", gProgramName); } - daemon(0,0); - { + result = daemon(0,0); + if (result == 0) { FILE *fp; int junk; @@ -740,6 +751,9 @@ int main(int argc, char **argv) junk = fclose(fp); assert(junk == 0); } + } else { + fprintf(stderr, "%s: Could not run as daemon - exiting\n", gProgramName); + exit(result); } } else { if (gMDNSPlatformPosixVerboseLevel > 0) { diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c index 403f160..70defbd 100755 --- a/mDNSPosix/mDNSPosix.c +++ b/mDNSPosix/mDNSPosix.c @@ -30,6 +30,22 @@ Change History (most recent first): $Log: mDNSPosix.c,v $ +Revision 1.108 2009/01/25 03:16:46 mkrochma +Added skeleton definition of mDNSPlatformSetLocalARP + +Revision 1.107 2009/01/07 08:25:03 mkrochma +Added skeleton definition of mDNSPlatformUpdateProxyList + +Revision 1.106 2008/10/22 17:19:57 cheshire +Don't need to define BPF_fd any more (it's now per-interface, not global) + +Revision 1.105 2008/10/03 23:34:08 cheshire +Added skeleton definition of mDNSPlatformSendRawPacket + +Revision 1.104 2008/09/05 22:16:48 cheshire + Should use randomized source ports and transaction IDs to avoid DNS cache poisoning +Add "UDPSocket *src" parameter in mDNSPlatformSendUDP + Revision 1.103 2007/10/02 19:31:17 cheshire In ParseDNSServers, should use strncasecmp for case-insensitive compare @@ -246,13 +262,15 @@ mDNSlocal void SockAddrTomDNSAddr(const struct sockaddr *const sa, mDNSAddr *ipA // mDNS core calls this routine when it needs to send a packet. mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end, - mDNSInterfaceID InterfaceID, const mDNSAddr *dst, mDNSIPPort dstPort) + mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, mDNSIPPort dstPort) { int err = 0; struct sockaddr_storage to; PosixNetworkInterface * thisIntf = (PosixNetworkInterface *)(InterfaceID); int sendingsocket = -1; + (void)src; // Will need to use this parameter once we implement mDNSPlatformUDPSocket/mDNSPlatformUDPClose + assert(m != NULL); assert(msg != NULL); assert(end != NULL); @@ -477,6 +495,26 @@ mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock) { (void)sock; // Unused } + +mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID) + { + (void)m; // Unused + (void)InterfaceID; // Unused + } + +mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID) + { + (void)msg; // Unused + (void)end; // Unused + (void)InterfaceID; // Unused + } + +mDNSexport void mDNSPlatformSetLocalARP(const mDNSv4Addr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID) + { + (void)tpa; // Unused + (void)tha; // Unused + (void)InterfaceID; // Unused + } mDNSexport mStatus mDNSPlatformTLSSetupCerts(void) { diff --git a/mDNSPosix/mDNSUNP.c b/mDNSPosix/mDNSUNP.c index 852883d..d32406e 100755 --- a/mDNSPosix/mDNSUNP.c +++ b/mDNSPosix/mDNSUNP.c @@ -17,6 +17,18 @@ Change History (most recent first): $Log: mDNSUNP.c,v $ +Revision 1.40 2009/01/13 05:31:34 mkrochma + Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy + +Revision 1.39 2009/01/11 03:20:06 mkrochma + Fixes from Igor Seleznev to get mdnsd working on Solaris + +Revision 1.38 2009/01/10 22:54:42 mkrochma + Fixes from Igor Seleznev to get mdnsd working on Linux + +Revision 1.37 2008/10/23 22:33:24 cheshire +Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu + Revision 1.36 2008/04/21 18:21:22 mkrochma Need to free ifi_netmask Submitted by Igor Seleznev @@ -145,6 +157,7 @@ First checkin #include #include #include +#include #include #include @@ -178,7 +191,7 @@ First checkin #if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX #include #include -// NOTE: netinet/in_var.h implicitly includes netinet6/in6_var.h for us +// Note: netinet/in_var.h implicitly includes netinet6/in6_var.h for us #endif #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX @@ -503,7 +516,7 @@ struct ifi_info *get_ifi_info(int family, int doaliases) struct in6_ifreq ifr6; if (sockf6 == -1) sockf6 = socket(AF_INET6, SOCK_DGRAM, 0); - bzero(&ifr6, sizeof(ifr6)); + memset(&ifr6, 0, sizeof(ifr6)); memcpy(&ifr6.ifr_name, &ifr->ifr_name, sizeof(ifr6.ifr_name )); memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr)); if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) goto gotError; @@ -673,6 +686,11 @@ struct in_pktinfo strncpy(pktp->ipi_ifname, sdl->sdl_data, nameLen); #endif pktp->ipi_ifindex = sdl->sdl_index; +#ifdef HAVE_BROKEN_RECVIF_NAME + if (sdl->sdl_index == 0) { + pktp->ipi_ifindex = *(uint_t*)sdl; + } +#endif assert(pktp->ipi_ifname[IFI_NAME - 1] == 0); // null terminated because of memset above continue; diff --git a/mDNSPosix/nss_mdns.c b/mDNSPosix/nss_mdns.c index ecbbc71..5af2f8e 100755 --- a/mDNSPosix/nss_mdns.c +++ b/mDNSPosix/nss_mdns.c @@ -335,7 +335,7 @@ enum #define DNS_LABEL_MAXLEN 63 // Maximum length of a single DNS label -#define DNS_NAME_MAXLEN 255 +#define DNS_NAME_MAXLEN 256 // Maximum length of a DNS name //---------- @@ -486,7 +486,7 @@ const int MDNS_VERBOSE = 0; // This enables verbose syslog messages // If zero, only "imporant" messages will appear in syslog -#define k_hostname_maxlen 255 +#define k_hostname_maxlen 256 // As per RFC1034 and RFC1035 #define k_aliases_max 15 #define k_addrs_max 15 @@ -1826,7 +1826,7 @@ init_config () temp_config = (config_t *) malloc (sizeof (config_t)); if (temp_config) { - // NOTE: This code will leak memory if initialisation fails + // Note: This code will leak memory if initialisation fails // repeatedly. This should only happen in the case of a memory // error, so I'm not sure if it's a meaningful problem. - AW *temp_config = k_empty_config; diff --git a/mDNSResponder.sln b/mDNSResponder.sln index 7a0f87c..1e0eca1 100755 --- a/mDNSResponder.sln +++ b/mDNSResponder.sln @@ -1,15 +1,10 @@ -Microsoft Visual Studio Solution File, Format Version 8.00 +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DLL", "mDNSWindows\DLL\dnssd.vcproj", "{AB581101-18F0-46F6-B56A-83A6B1EA657E}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mDNSResponder", "mDNSWindows\SystemService\Service.vcproj", "{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NSPTool", "mDNSWindows\NSPTool\NSPTool.vcproj", "{208B3A9F-1CA0-4D1D-9D6C-C61616F94705}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mdnsNSP", "mDNSWindows\mdnsNSP\mdnsNSP.vcproj", "{F4F15529-F0EB-402F-8662-73C5797EE557}" ProjectSection(ProjectDependencies) = postProject @@ -18,16 +13,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mdnsNSP", "mDNSWindows\mdns EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExplorerPlugin", "Clients\ExplorerPlugin\ExplorerPlugin.vcproj", "{BB8AC1B5-6587-4163-BDC6-788B157705CA}" ProjectSection(ProjectDependencies) = postProject - {AB581101-18F0-46F6-B56A-83A6B1EA657E} = {AB581101-18F0-46F6-B56A-83A6B1EA657E} + {3A2B6325-3053-4236-84BD-AA9BE2E323E5} = {3A2B6325-3053-4236-84BD-AA9BE2E323E5} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PrinterSetupWizard", "Clients\PrinterSetupWizard\PrinterSetupWizard.vcproj", "{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}" ProjectSection(ProjectDependencies) = postProject - {AB581101-18F0-46F6-B56A-83A6B1EA657E} = {AB581101-18F0-46F6-B56A-83A6B1EA657E} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DLL.NET", "mDNSWindows\DLL.NET\dnssd_NET.vcproj", "{9C6701E2-82B7-44B7-9B5E-3897D9153F79}" - ProjectSection(ProjectDependencies) = postProject + {3A2B6325-3053-4236-84BD-AA9BE2E323E5} = {3A2B6325-3053-4236-84BD-AA9BE2E323E5} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ControlPanel", "mDNSWindows\ControlPanel\ControlPanel.vcproj", "{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}" @@ -35,29 +26,27 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ControlPanel", "mDNSWindows {AB581101-18F0-46F6-B56A-83A6B1EA657E} = {AB581101-18F0-46F6-B56A-83A6B1EA657E} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PrinterSetupWizardLocRes", "Clients\PrinterSetupWizard\PrinterSetupWizardLocRes.vcproj", "{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PrinterSetupWizardLocRes", "Clients\PrinterSetupWizard\PrinterSetupWizardLocRes.vcproj", "{967F5375-0176-43D3-ADA3-22EE25551C37}" ProjectSection(ProjectDependencies) = postProject {AB581101-18F0-46F6-B56A-83A6B1EA657E} = {AB581101-18F0-46F6-B56A-83A6B1EA657E} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PrinterSetupWizardRes", "Clients\PrinterSetupWizard\PrinterSetupWizardRes.vcproj", "{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PrinterSetupWizardRes", "Clients\PrinterSetupWizard\PrinterSetupWizardRes.vcproj", "{CFCCB176-6CAA-472B-B0A2-90511C8E2E52}" ProjectSection(ProjectDependencies) = postProject {AB581101-18F0-46F6-B56A-83A6B1EA657E} = {AB581101-18F0-46F6-B56A-83A6B1EA657E} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExplorerPluginLocRes", "Clients\ExplorerPlugin\ExplorerPluginLocRes.vcproj", "{BB8AC1B5-6587-4163-BDC6-788B157705CA}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExplorerPluginLocRes", "Clients\ExplorerPlugin\ExplorerPluginLocRes.vcproj", "{1643427B-F226-4AD6-B413-97DA64D5C6B4}" ProjectSection(ProjectDependencies) = postProject {AB581101-18F0-46F6-B56A-83A6B1EA657E} = {AB581101-18F0-46F6-B56A-83A6B1EA657E} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExplorerPluginRes", "Clients\ExplorerPlugin\ExplorerPluginRes.vcproj", "{BB8AC1B5-6587-4163-BDC6-788B157705CA}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExplorerPluginRes", "Clients\ExplorerPlugin\ExplorerPluginRes.vcproj", "{871B1492-B4A4-4B57-9237-FA798484D7D7}" ProjectSection(ProjectDependencies) = postProject {AB581101-18F0-46F6-B56A-83A6B1EA657E} = {AB581101-18F0-46F6-B56A-83A6B1EA657E} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dns-sd", "Clients\DNS-SD.VisualStudio\dns-sd.vcproj", "{AA230639-E115-4A44-AA5A-44A61235BA50}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Java", "mDNSWindows\Java\Java.vcproj", "{9CE2568A-3170-41C6-9F20-A0188A9EC114}" ProjectSection(ProjectDependencies) = postProject @@ -70,84 +59,146 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JavaSamples", "Clients\Java EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ControlPanel (Vista)", "mDNSWindows\ControlPanel\ControlPanelExe.vcproj", "{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DLLStub", "mDNSWindows\DLLStub\DLLStub.vcproj", "{3A2B6325-3053-4236-84BD-AA9BE2E323E5}" ProjectSection(ProjectDependencies) = postProject + {AB581101-18F0-46F6-B56A-83A6B1EA657E} = {AB581101-18F0-46F6-B56A-83A6B1EA657E} EndProjectSection EndProject Global - GlobalSection(SolutionConfiguration) = preSolution - Debug = Debug - Release = Release - EndGlobalSection - GlobalSection(ProjectDependencies) = postSolution - EndGlobalSection - GlobalSection(ProjectConfiguration) = postSolution - {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug.ActiveCfg = Debug|Win32 - {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug.Build.0 = Debug|Win32 - {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release.ActiveCfg = Release|Win32 - {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release.Build.0 = Release|Win32 - {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug.ActiveCfg = Debug|Win32 - {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug.Build.0 = Debug|Win32 - {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release.ActiveCfg = Release|Win32 - {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release.Build.0 = Release|Win32 - {208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Debug.ActiveCfg = Debug|Win32 - {208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Debug.Build.0 = Debug|Win32 - {208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Release.ActiveCfg = Release|Win32 - {208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Release.Build.0 = Release|Win32 - {F4F15529-F0EB-402F-8662-73C5797EE557}.Debug.ActiveCfg = Debug|Win32 - {F4F15529-F0EB-402F-8662-73C5797EE557}.Debug.Build.0 = Debug|Win32 - {F4F15529-F0EB-402F-8662-73C5797EE557}.Release.ActiveCfg = Release|Win32 - {F4F15529-F0EB-402F-8662-73C5797EE557}.Release.Build.0 = Release|Win32 - {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Debug.ActiveCfg = Debug|Win32 - {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Debug.Build.0 = Debug|Win32 - {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Release.ActiveCfg = Release|Win32 - {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Release.Build.0 = Release|Win32 - {B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Debug.ActiveCfg = Debug|Win32 - {B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Debug.Build.0 = Debug|Win32 - {B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Release.ActiveCfg = Release|Win32 - {B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Release.Build.0 = Release|Win32 - {9C6701E2-82B7-44B7-9B5E-3897D9153F79}.Debug.ActiveCfg = Debug|Win32 - {9C6701E2-82B7-44B7-9B5E-3897D9153F79}.Debug.Build.0 = Debug|Win32 - {9C6701E2-82B7-44B7-9B5E-3897D9153F79}.Release.ActiveCfg = Release|Win32 - {9C6701E2-82B7-44B7-9B5E-3897D9153F79}.Release.Build.0 = Release|Win32 - {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug.ActiveCfg = Debug|Win32 - {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug.Build.0 = Debug|Win32 - {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release.ActiveCfg = Release|Win32 - {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release.Build.0 = Release|Win32 - {B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Debug.ActiveCfg = Debug|Win32 - {B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Debug.Build.0 = Debug|Win32 - {B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Release.ActiveCfg = Release|Win32 - {B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Release.Build.0 = Release|Win32 - {B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Debug.ActiveCfg = Debug|Win32 - {B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Debug.Build.0 = Debug|Win32 - {B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Release.ActiveCfg = Release|Win32 - {B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Release.Build.0 = Release|Win32 - {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Debug.ActiveCfg = Debug|Win32 - {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Debug.Build.0 = Debug|Win32 - {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Release.ActiveCfg = Release|Win32 - {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Release.Build.0 = Release|Win32 - {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Debug.ActiveCfg = Debug|Win32 - {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Debug.Build.0 = Debug|Win32 - {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Release.ActiveCfg = Release|Win32 - {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Release.Build.0 = Release|Win32 - {AA230639-E115-4A44-AA5A-44A61235BA50}.Debug.ActiveCfg = Debug|Win32 - {AA230639-E115-4A44-AA5A-44A61235BA50}.Debug.Build.0 = Debug|Win32 - {AA230639-E115-4A44-AA5A-44A61235BA50}.Release.ActiveCfg = Release|Win32 - {AA230639-E115-4A44-AA5A-44A61235BA50}.Release.Build.0 = Release|Win32 - {9CE2568A-3170-41C6-9F20-A0188A9EC114}.Debug.ActiveCfg = Debug|Win32 - {9CE2568A-3170-41C6-9F20-A0188A9EC114}.Debug.Build.0 = Debug|Win32 - {9CE2568A-3170-41C6-9F20-A0188A9EC114}.Release.ActiveCfg = Release|Win32 - {9CE2568A-3170-41C6-9F20-A0188A9EC114}.Release.Build.0 = Release|Win32 - {A987A0C1-344F-475C-869C-F082EB11EEBA}.Debug.ActiveCfg = Debug|Win32 - {A987A0C1-344F-475C-869C-F082EB11EEBA}.Debug.Build.0 = Debug|Win32 - {A987A0C1-344F-475C-869C-F082EB11EEBA}.Release.ActiveCfg = Release|Win32 - {A987A0C1-344F-475C-869C-F082EB11EEBA}.Release.Build.0 = Release|Win32 - {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug.ActiveCfg = Debug|Win32 - {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug.Build.0 = Debug|Win32 - {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release.ActiveCfg = Release|Win32 - {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release.Build.0 = Release|Win32 + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug|Win32.ActiveCfg = Debug|Win32 + {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug|Win32.Build.0 = Debug|Win32 + {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug|x64.ActiveCfg = Debug|x64 + {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug|x64.Build.0 = Debug|x64 + {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release|Win32.ActiveCfg = Release|Win32 + {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release|Win32.Build.0 = Release|Win32 + {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release|x64.ActiveCfg = Release|x64 + {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release|x64.Build.0 = Release|x64 + {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug|Win32.ActiveCfg = Debug|Win32 + {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug|Win32.Build.0 = Debug|Win32 + {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug|x64.ActiveCfg = Debug|x64 + {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug|x64.Build.0 = Debug|x64 + {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release|Win32.ActiveCfg = Release|Win32 + {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release|Win32.Build.0 = Release|Win32 + {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release|x64.ActiveCfg = Release|x64 + {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release|x64.Build.0 = Release|x64 + {208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Debug|Win32.ActiveCfg = Debug|Win32 + {208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Debug|Win32.Build.0 = Debug|Win32 + {208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Debug|x64.ActiveCfg = Debug|x64 + {208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Debug|x64.Build.0 = Debug|x64 + {208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Release|Win32.ActiveCfg = Release|Win32 + {208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Release|Win32.Build.0 = Release|Win32 + {208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Release|x64.ActiveCfg = Release|x64 + {208B3A9F-1CA0-4D1D-9D6C-C61616F94705}.Release|x64.Build.0 = Release|x64 + {F4F15529-F0EB-402F-8662-73C5797EE557}.Debug|Win32.ActiveCfg = Debug|Win32 + {F4F15529-F0EB-402F-8662-73C5797EE557}.Debug|Win32.Build.0 = Debug|Win32 + {F4F15529-F0EB-402F-8662-73C5797EE557}.Debug|x64.ActiveCfg = Debug|x64 + {F4F15529-F0EB-402F-8662-73C5797EE557}.Debug|x64.Build.0 = Debug|x64 + {F4F15529-F0EB-402F-8662-73C5797EE557}.Release|Win32.ActiveCfg = Release|Win32 + {F4F15529-F0EB-402F-8662-73C5797EE557}.Release|Win32.Build.0 = Release|Win32 + {F4F15529-F0EB-402F-8662-73C5797EE557}.Release|x64.ActiveCfg = Release|x64 + {F4F15529-F0EB-402F-8662-73C5797EE557}.Release|x64.Build.0 = Release|x64 + {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Debug|Win32.ActiveCfg = Debug|Win32 + {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Debug|Win32.Build.0 = Debug|Win32 + {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Debug|x64.ActiveCfg = Debug|x64 + {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Debug|x64.Build.0 = Debug|x64 + {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Release|Win32.ActiveCfg = Release|Win32 + {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Release|Win32.Build.0 = Release|Win32 + {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Release|x64.ActiveCfg = Release|x64 + {BB8AC1B5-6587-4163-BDC6-788B157705CA}.Release|x64.Build.0 = Release|x64 + {B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Debug|Win32.ActiveCfg = Debug|Win32 + {B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Debug|Win32.Build.0 = Debug|Win32 + {B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Debug|x64.ActiveCfg = Debug|x64 + {B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Debug|x64.Build.0 = Debug|x64 + {B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Release|Win32.ActiveCfg = Release|Win32 + {B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Release|Win32.Build.0 = Release|Win32 + {B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Release|x64.ActiveCfg = Release|x64 + {B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Release|x64.Build.0 = Release|x64 + {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|Win32.ActiveCfg = Debug|Win32 + {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|Win32.Build.0 = Debug|Win32 + {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|x64.ActiveCfg = Debug|x64 + {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|x64.Build.0 = Debug|x64 + {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|Win32.ActiveCfg = Release|Win32 + {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|Win32.Build.0 = Release|Win32 + {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|x64.ActiveCfg = Release|x64 + {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|x64.Build.0 = Release|x64 + {967F5375-0176-43D3-ADA3-22EE25551C37}.Debug|Win32.ActiveCfg = Debug|Win32 + {967F5375-0176-43D3-ADA3-22EE25551C37}.Debug|Win32.Build.0 = Debug|Win32 + {967F5375-0176-43D3-ADA3-22EE25551C37}.Debug|x64.ActiveCfg = Debug|x64 + {967F5375-0176-43D3-ADA3-22EE25551C37}.Debug|x64.Build.0 = Debug|x64 + {967F5375-0176-43D3-ADA3-22EE25551C37}.Release|Win32.ActiveCfg = Release|Win32 + {967F5375-0176-43D3-ADA3-22EE25551C37}.Release|Win32.Build.0 = Release|Win32 + {967F5375-0176-43D3-ADA3-22EE25551C37}.Release|x64.ActiveCfg = Release|x64 + {967F5375-0176-43D3-ADA3-22EE25551C37}.Release|x64.Build.0 = Release|x64 + {CFCCB176-6CAA-472B-B0A2-90511C8E2E52}.Debug|Win32.ActiveCfg = Debug|Win32 + {CFCCB176-6CAA-472B-B0A2-90511C8E2E52}.Debug|Win32.Build.0 = Debug|Win32 + {CFCCB176-6CAA-472B-B0A2-90511C8E2E52}.Debug|x64.ActiveCfg = Debug|x64 + {CFCCB176-6CAA-472B-B0A2-90511C8E2E52}.Debug|x64.Build.0 = Debug|x64 + {CFCCB176-6CAA-472B-B0A2-90511C8E2E52}.Release|Win32.ActiveCfg = Release|Win32 + {CFCCB176-6CAA-472B-B0A2-90511C8E2E52}.Release|Win32.Build.0 = Release|Win32 + {CFCCB176-6CAA-472B-B0A2-90511C8E2E52}.Release|x64.ActiveCfg = Release|x64 + {CFCCB176-6CAA-472B-B0A2-90511C8E2E52}.Release|x64.Build.0 = Release|x64 + {1643427B-F226-4AD6-B413-97DA64D5C6B4}.Debug|Win32.ActiveCfg = Debug|Win32 + {1643427B-F226-4AD6-B413-97DA64D5C6B4}.Debug|Win32.Build.0 = Debug|Win32 + {1643427B-F226-4AD6-B413-97DA64D5C6B4}.Debug|x64.ActiveCfg = Debug|x64 + {1643427B-F226-4AD6-B413-97DA64D5C6B4}.Debug|x64.Build.0 = Debug|x64 + {1643427B-F226-4AD6-B413-97DA64D5C6B4}.Release|Win32.ActiveCfg = Release|Win32 + {1643427B-F226-4AD6-B413-97DA64D5C6B4}.Release|Win32.Build.0 = Release|Win32 + {1643427B-F226-4AD6-B413-97DA64D5C6B4}.Release|x64.ActiveCfg = Release|x64 + {1643427B-F226-4AD6-B413-97DA64D5C6B4}.Release|x64.Build.0 = Release|x64 + {871B1492-B4A4-4B57-9237-FA798484D7D7}.Debug|Win32.ActiveCfg = Debug|Win32 + {871B1492-B4A4-4B57-9237-FA798484D7D7}.Debug|Win32.Build.0 = Debug|Win32 + {871B1492-B4A4-4B57-9237-FA798484D7D7}.Debug|x64.ActiveCfg = Debug|x64 + {871B1492-B4A4-4B57-9237-FA798484D7D7}.Debug|x64.Build.0 = Debug|x64 + {871B1492-B4A4-4B57-9237-FA798484D7D7}.Release|Win32.ActiveCfg = Release|Win32 + {871B1492-B4A4-4B57-9237-FA798484D7D7}.Release|Win32.Build.0 = Release|Win32 + {871B1492-B4A4-4B57-9237-FA798484D7D7}.Release|x64.ActiveCfg = Release|x64 + {871B1492-B4A4-4B57-9237-FA798484D7D7}.Release|x64.Build.0 = Release|x64 + {AA230639-E115-4A44-AA5A-44A61235BA50}.Debug|Win32.ActiveCfg = Debug|Win32 + {AA230639-E115-4A44-AA5A-44A61235BA50}.Debug|Win32.Build.0 = Debug|Win32 + {AA230639-E115-4A44-AA5A-44A61235BA50}.Debug|x64.ActiveCfg = Debug|x64 + {AA230639-E115-4A44-AA5A-44A61235BA50}.Debug|x64.Build.0 = Debug|x64 + {AA230639-E115-4A44-AA5A-44A61235BA50}.Release|Win32.ActiveCfg = Release|Win32 + {AA230639-E115-4A44-AA5A-44A61235BA50}.Release|Win32.Build.0 = Release|Win32 + {AA230639-E115-4A44-AA5A-44A61235BA50}.Release|x64.ActiveCfg = Release|x64 + {AA230639-E115-4A44-AA5A-44A61235BA50}.Release|x64.Build.0 = Release|x64 + {9CE2568A-3170-41C6-9F20-A0188A9EC114}.Debug|Win32.ActiveCfg = Debug|Win32 + {9CE2568A-3170-41C6-9F20-A0188A9EC114}.Debug|Win32.Build.0 = Debug|Win32 + {9CE2568A-3170-41C6-9F20-A0188A9EC114}.Debug|x64.ActiveCfg = Debug|x64 + {9CE2568A-3170-41C6-9F20-A0188A9EC114}.Release|Win32.ActiveCfg = Release|Win32 + {9CE2568A-3170-41C6-9F20-A0188A9EC114}.Release|Win32.Build.0 = Release|Win32 + {9CE2568A-3170-41C6-9F20-A0188A9EC114}.Release|x64.ActiveCfg = Release|x64 + {A987A0C1-344F-475C-869C-F082EB11EEBA}.Debug|Win32.ActiveCfg = Debug|Win32 + {A987A0C1-344F-475C-869C-F082EB11EEBA}.Debug|Win32.Build.0 = Debug|Win32 + {A987A0C1-344F-475C-869C-F082EB11EEBA}.Debug|x64.ActiveCfg = Debug|x64 + {A987A0C1-344F-475C-869C-F082EB11EEBA}.Release|Win32.ActiveCfg = Release|Win32 + {A987A0C1-344F-475C-869C-F082EB11EEBA}.Release|Win32.Build.0 = Release|Win32 + {A987A0C1-344F-475C-869C-F082EB11EEBA}.Release|x64.ActiveCfg = Release|x64 + {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug|Win32.ActiveCfg = Debug|Win32 + {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug|Win32.Build.0 = Debug|Win32 + {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug|x64.ActiveCfg = Debug|x64 + {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug|x64.Build.0 = Debug|x64 + {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release|Win32.ActiveCfg = Release|Win32 + {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release|Win32.Build.0 = Release|Win32 + {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release|x64.ActiveCfg = Release|x64 + {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release|x64.Build.0 = Release|x64 + {3A2B6325-3053-4236-84BD-AA9BE2E323E5}.Debug|Win32.ActiveCfg = Debug|Win32 + {3A2B6325-3053-4236-84BD-AA9BE2E323E5}.Debug|Win32.Build.0 = Debug|Win32 + {3A2B6325-3053-4236-84BD-AA9BE2E323E5}.Debug|x64.ActiveCfg = Debug|x64 + {3A2B6325-3053-4236-84BD-AA9BE2E323E5}.Debug|x64.Build.0 = Debug|x64 + {3A2B6325-3053-4236-84BD-AA9BE2E323E5}.Release|Win32.ActiveCfg = Release|Win32 + {3A2B6325-3053-4236-84BD-AA9BE2E323E5}.Release|Win32.Build.0 = Release|Win32 + {3A2B6325-3053-4236-84BD-AA9BE2E323E5}.Release|x64.ActiveCfg = Release|x64 + {3A2B6325-3053-4236-84BD-AA9BE2E323E5}.Release|x64.Build.0 = Release|x64 EndGlobalSection - GlobalSection(ExtensibilityAddIns) = postSolution + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection EndGlobal diff --git a/mDNSShared/CommonServices.h b/mDNSShared/CommonServices.h index 4623e37..e0ab8a4 100644 --- a/mDNSShared/CommonServices.h +++ b/mDNSShared/CommonServices.h @@ -17,6 +17,16 @@ Change History (most recent first): $Log: CommonServices.h,v $ +Revision 1.11 2009/03/30 19:51:29 herscher + Current Bonjour code does not compile on Windows + Move build train to Visual Studio 2005 + +Revision 1.10 2009/01/11 03:20:06 mkrochma + Fixes from Igor Seleznev to get mdnsd working on Solaris + +Revision 1.9 2009/01/10 22:03:43 mkrochma + dnsextd fails to build on Linux + Revision 1.8 2007/01/17 19:16:59 cheshire Only define ssize_t if it's not already defined @@ -92,6 +102,16 @@ Common Services and portability support for various platforms. #endif #endif +// Solaris + +#if( !defined( TARGET_OS_SOLARIS ) ) + #if( defined(solaris) || (defined(__SVR4) && defined(sun)) ) + #define TARGET_OS_SOLARIS 1 + #else + #define TARGET_OS_SOLARIS 0 + #endif +#endif + // Palm #if( !defined( TARGET_OS_PALM ) ) @@ -108,7 +128,7 @@ Common Services and portability support for various platforms. // No predefined macro for VxWorks so just assume VxWorks if nothing else is set. - #if( !macintosh && !__MACH__ && !defined( __linux__ ) && !defined( __PALMOS_TRAPS__ ) && !defined( __PALMOS_ARMLET__ ) && !defined( _WIN32 ) ) + #if( !macintosh && !__MACH__ && !defined( __linux__ ) && !defined ( __SVR4 ) && !defined ( __sun ) && !defined( __PALMOS_TRAPS__ ) && !defined( __PALMOS_ARMLET__ ) && !defined( _WIN32 ) ) #define TARGET_OS_VXWORKS 1 #else #define TARGET_OS_VXWORKS 0 @@ -148,6 +168,9 @@ Common Services and portability support for various platforms. //=========================================================================================================================== #if( !KERNEL ) + #if defined(WIN32) && !defined(_WSPIAPI_COUNTOF) + #define _WSPIAPI_COUNTOF(_Array) (sizeof(_Array) / sizeof(_Array[0])) + #endif #include #endif @@ -196,7 +219,26 @@ Common Services and portability support for various platforms. #elif( TARGET_OS_LINUX ) - // Linux (no special includes yet). + // Linux + + #include + #include + +#elif( TARGET_OS_SOLARIS ) + + // Solaris + + #include + + #include + #include + + #if ( defined( BYTE_ORDER ) && defined( LITTLE_ENDIAN ) && ( BYTE_ORDER == LITTLE_ENDIAN ) ) + #define TARGET_RT_LITTLE_ENDIAN 1 + #endif + #if ( defined( BYTE_ORDER ) && defined( BIG_ENDIAN ) && ( BYTE_ORDER == BIG_ENDIAN ) ) + #define TARGET_RT_BIG_ENDIAN 1 + #endif #elif( TARGET_OS_PALM ) diff --git a/mDNSShared/Java/DNSSD.java b/mDNSShared/Java/DNSSD.java index 9ecb7cb..e608869 100644 --- a/mDNSShared/Java/DNSSD.java +++ b/mDNSShared/Java/DNSSD.java @@ -17,6 +17,9 @@ Change History (most recent first): $Log: DNSSD.java,v $ +Revision 1.16 2008/11/04 20:06:20 cheshire + Change MAX_DOMAIN_NAME to 256 + Revision 1.15 2007/03/13 00:28:03 vazquez Java: Rename exported symbols in libjdns_sd.jnilib @@ -126,7 +129,7 @@ abstract public class DNSSD public static final int REGISTRATION_DOMAINS = ( 1 << 7 ); /** Maximum length, in bytes, of a domain name represented as an escaped C-String. */ - public static final int MAX_DOMAIN_NAME = 1005; + public static final int MAX_DOMAIN_NAME = 1009; /** Pass for ifIndex to specify all available interfaces. */ public static final int ALL_INTERFACES = 0; diff --git a/mDNSShared/PlatformCommon.c b/mDNSShared/PlatformCommon.c index 434c2f1..c3bf9cc 100644 --- a/mDNSShared/PlatformCommon.c +++ b/mDNSShared/PlatformCommon.c @@ -17,6 +17,18 @@ Change History (most recent first): $Log: PlatformCommon.c,v $ +Revision 1.21 2009/04/11 00:20:24 jessic2 + Daemon: Should be able to turn on LogOperation dynamically + +Revision 1.20 2008/10/09 22:26:05 cheshire +Save space by not showing high-resolution timestamp in LogMsgNoIdent() lines + +Revision 1.19 2008/07/14 17:43:36 mkrochma +Fix previous check in so connect still gets called + +Revision 1.18 2008/07/12 17:19:41 mkrochma + mDNSResponder PlatformCommon.c uses sin_len even on non-compliant platforms + Revision 1.17 2008/03/05 00:19:09 cheshire Conditionalize LogTimeStamps so it's specific to APPLE_OSX, for now @@ -97,19 +109,26 @@ mDNSexport void mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAdd { union { struct sockaddr s; struct sockaddr_in a4; struct sockaddr_in6 a6; } addr; socklen_t len = sizeof(addr); + socklen_t inner_len = 0; int sock = socket(AF_INET, SOCK_DGRAM, 0); src->type = mDNSAddrType_None; if (sock == -1) return; if (dst->type == mDNSAddrType_IPv4) { - addr.a4.sin_len = sizeof(addr.a4); + inner_len = sizeof(addr.a4); + #ifndef NOT_HAVE_SA_LEN + addr.a4.sin_len = inner_len; + #endif addr.a4.sin_family = AF_INET; addr.a4.sin_port = 1; // Not important, any port will do addr.a4.sin_addr.s_addr = dst->ip.v4.NotAnInteger; } else if (dst->type == mDNSAddrType_IPv6) { - addr.a6.sin6_len = sizeof(addr.a6); + inner_len = sizeof(addr.a6); + #ifndef NOT_HAVE_SA_LEN + addr.a6.sin6_len = inner_len; + #endif addr.a6.sin6_family = AF_INET6; addr.a6.sin6_flowinfo = 0; addr.a6.sin6_port = 1; // Not important, any port will do @@ -117,8 +136,8 @@ mDNSexport void mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAdd addr.a6.sin6_scope_id = 0; } else return; - - if ((connect(sock, &addr.s, addr.s.sa_len)) < 0) + + if ((connect(sock, &addr.s, inner_len)) < 0) { LogMsg("mDNSPlatformSourceAddrForDest: connect %#a failed errno %d (%s)", dst, errno, strerror(errno)); goto exit; } if ((getsockname(sock, &addr.s, &len)) < 0) @@ -202,7 +221,7 @@ mDNSexport void mDNSPlatformWriteDebugMsg(const char *msg) } #endif -mDNSexport void mDNSPlatformWriteLogMsg(const char *ident, const char *buffer, int logoptflags) +mDNSexport void mDNSPlatformWriteLogMsg(const char *ident, const char *buffer, mDNSLogLevel_t loglevel) { #if APPLE_OSX_mDNSResponder && LogTimeStamps extern mDNS mDNSStorage; @@ -214,7 +233,7 @@ mDNSexport void mDNSPlatformWriteLogMsg(const char *ident, const char *buffer, i if (mDNS_DebugMode) // In debug mode we write to stderr { #if APPLE_OSX_mDNSResponder && LogTimeStamps - if (mDNSPlatformClockDivisor) + if (ident && ident[0] && mDNSPlatformClockDivisor) fprintf(stderr,"%8d.%03d: %s\n", (int)(t/1000), ms, buffer); else #endif @@ -223,13 +242,28 @@ mDNSexport void mDNSPlatformWriteLogMsg(const char *ident, const char *buffer, i } else // else, in production mode, we write to syslog { - openlog(ident, LOG_CONS | logoptflags, LOG_DAEMON); + static int log_inited = 0; + + int syslog_level = LOG_ERR; + switch (loglevel) + { + case MDNS_LOG_MSG: syslog_level = LOG_ERR; break; + case MDNS_LOG_OPERATION: syslog_level = LOG_WARNING; break; + case MDNS_LOG_SPS: syslog_level = LOG_NOTICE; break; + case MDNS_LOG_INFO: syslog_level = LOG_INFO; break; + case MDNS_LOG_DEBUG: syslog_level = LOG_DEBUG; break; + default: + fprintf(stderr, "Unknown loglevel %d, assuming LOG_ERR\n", loglevel); + fflush(stderr); + } + + if (!log_inited) { openlog(ident, LOG_CONS, LOG_DAEMON); log_inited++; } + #if APPLE_OSX_mDNSResponder && LogTimeStamps - if (mDNSPlatformClockDivisor) - syslog(LOG_ERR, "%8d.%03d: %s", (int)(t/1000), ms, buffer); + if (ident && ident[0] && mDNSPlatformClockDivisor) + syslog(syslog_level, "%8d.%03d: %s", (int)(t/1000), ms, buffer); else #endif - syslog(LOG_ERR, "%s", buffer); - closelog(); + syslog(syslog_level, "%s", buffer); } } diff --git a/mDNSShared/dns_sd.h b/mDNSShared/dns_sd.h index 4dd99a7..3169a5a 100644 --- a/mDNSShared/dns_sd.h +++ b/mDNSShared/dns_sd.h @@ -70,14 +70,14 @@ * checking, so that C code building with earlier versions of the header file * can avoid compile errors trying to use functions that aren't even defined * in those earlier versions. Similar checks may also be performed at run-time: - * => weak linking -- to avoid link failures if run with an earler + * => weak linking -- to avoid link failures if run with an earlier * version of the library that's missing some desired symbol, or * => DNSServiceGetProperty(DaemonVersion) -- to verify whether the running daemon * ("system service" on Windows) meets some required minimum functionality level. */ #ifndef _DNS_SD_H -#define _DNS_SD_H 1760300 +#define _DNS_SD_H 2120100 #ifdef __cplusplus extern "C" { @@ -115,7 +115,6 @@ typedef INT32 int32_t; #elif defined(_WIN32) #include #define _UNUSED -#define bzero(a, b) memset(a, 0, b) #ifndef _MSL_STDINT_H typedef UINT8 uint8_t; typedef INT8 int8_t; @@ -242,11 +241,9 @@ enum * the CNAME referral, the intermediate CNAME result is also returned to the client. * When this flag is not set, NXDomain errors are not returned, and CNAME records * are followed silently without informing the client of the intermediate steps. + * (In earlier builds this flag was briefly calledkDNSServiceFlagsReturnCNAME) */ - /* Previous name for kDNSServiceFlagsReturnIntermediates flag (not used externally) */ - #define kDNSServiceFlagsReturnCNAME kDNSServiceFlagsReturnIntermediates - kDNSServiceFlagsNonBrowsable = 0x2000, /* A service registered with the NonBrowsable flag set can be resolved using * DNSServiceResolve(), but will not be discoverable using DNSServiceBrowse(). @@ -256,7 +253,7 @@ enum * an associated PTR record. */ - kDNSServiceFlagsShareConnection = 0x4000 + kDNSServiceFlagsShareConnection = 0x4000, /* For efficiency, clients that perform many concurrent operations may want to use a * single Unix Domain Socket connection with the background daemon, instead of having a * separate connection for each independent operation. To use this mode, clients first @@ -284,24 +281,38 @@ enum * 1. Collective kDNSServiceFlagsMoreComing flag * When callbacks are invoked using a shared DNSServiceRef, the * kDNSServiceFlagsMoreComing flag applies collectively to *all* active - * operations sharing the same DNSServiceRef. If the MoreComing flag is - * set it means that there are more results queued on this DNSServiceRef, + * operations sharing the same parent DNSServiceRef. If the MoreComing flag is + * set it means that there are more results queued on this parent DNSServiceRef, * but not necessarily more results for this particular callback function. * The implication of this for client programmers is that when a callback * is invoked with the MoreComing flag set, the code should update its * internal data structures with the new result, and set a variable indicating * that its UI needs to be updated. Then, later when a callback is eventually * invoked with the MoreComing flag not set, the code should update *all* - * stale UI elements related to that shared DNSServiceRef that need updating, - * not just the UI elements related to the particular callback that happened - * to be the last one to be invoked. + * stale UI elements related to that shared parent DNSServiceRef that need + * updating, not just the UI elements related to the particular callback + * that happened to be the last one to be invoked. + * + * 2. Canceling operations and kDNSServiceFlagsMoreComing + * Whenever you cancel any operation for which you had deferred UI updates + * waiting because of a kDNSServiceFlagsMoreComing flag, you should perform + * those deferred UI updates. This is because, after cancelling the operation, + * you can no longer wait for a callback *without* MoreComing set, to tell + * you do perform your deferred UI updates (the operation has been canceled, + * so there will be no more callbacks). An implication of the collective + * kDNSServiceFlagsMoreComing flag for shared connections is that this + * guideline applies more broadly -- any time you cancel an operation on + * a shared connection, you should perform all deferred UI updates for all + * operations sharing that connection. This is because the MoreComing flag + * might have been referring to events coming for the operation you canceled, + * which will now not be coming because the operation has been canceled. * - * 2. Only share DNSServiceRef's created with DNSServiceCreateConnection + * 3. Only share DNSServiceRef's created with DNSServiceCreateConnection * Calling DNSServiceCreateConnection(&ref) creates a special shareable DNSServiceRef. * DNSServiceRef's created by other calls like DNSServiceBrowse() or DNSServiceResolve() * cannot be shared by copying them and using kDNSServiceFlagsShareConnection. * - * 3. Don't Double-Deallocate + * 4. Don't Double-Deallocate * Calling DNSServiceRefDeallocate(ref) for a particular operation's DNSServiceRef terminates * just that operation. Calling DNSServiceRefDeallocate(ref) for the main shared DNSServiceRef * (the parent DNSServiceRef, originally created by DNSServiceCreateConnection(&ref)) @@ -311,7 +322,7 @@ enum * to do a DNSServiceRefDeallocate (or any other operation) on them will result in accesses * to freed memory, leading to crashes or other equally undesirable results. * - * 4. Thread Safety + * 5. Thread Safety * The dns_sd.h API does not presuppose any particular threading model, and consequently * does no locking of its own (which would require linking some specific threading library). * If client code calls API routines on the same DNSServiceRef concurrently @@ -319,6 +330,9 @@ enum * lock or take similar appropriate precautions to serialize those calls. */ + kDNSServiceFlagsSuppressUnusable = 0x8000 + /* Placeholder definition, for future use + */ }; /* Possible protocols for DNSServiceNATPortMappingCreate(). */ @@ -400,9 +414,19 @@ enum kDNSServiceType_SSHFP = 44, /* SSH Key Fingerprint */ kDNSServiceType_IPSECKEY = 45, /* IPSECKEY */ kDNSServiceType_RRSIG = 46, /* RRSIG */ - kDNSServiceType_NSEC = 47, /* NSEC */ + kDNSServiceType_NSEC = 47, /* Denial of Existence */ kDNSServiceType_DNSKEY = 48, /* DNSKEY */ - kDNSServiceType_DHCID = 49, /* DHCID */ + kDNSServiceType_DHCID = 49, /* DHCP Client Identifier */ + kDNSServiceType_NSEC3 = 50, /* Hashed Authenticated Denial of Existence */ + kDNSServiceType_NSEC3PARAM= 51, /* Hashed Authenticated Denial of Existence */ + + kDNSServiceType_HIP = 55, /* Host Identity Protocol */ + + kDNSServiceType_SPF = 99, /* Sender Policy Framework for E-Mail */ + kDNSServiceType_UINFO = 100, /* IANA-Reserved */ + kDNSServiceType_UID = 101, /* IANA-Reserved */ + kDNSServiceType_GID = 102, /* IANA-Reserved */ + kDNSServiceType_UNSPEC = 103, /* IANA-Reserved */ kDNSServiceType_TKEY = 249, /* Transaction key */ kDNSServiceType_TSIG = 250, /* Transaction signature. */ @@ -460,15 +484,15 @@ enum /* Maximum length, in bytes, of a domain name represented as an *escaped* C-String */ /* including the final trailing dot, and the C-String terminating NULL at the end. */ -#define kDNSServiceMaxDomainName 1005 +#define kDNSServiceMaxDomainName 1009 /* * Notes on DNS Name Escaping * -- or -- - * "Why is kDNSServiceMaxDomainName 1005, when the maximum legal domain name is 255 bytes?" + * "Why is kDNSServiceMaxDomainName 1009, when the maximum legal domain name is 256 bytes?" * - * All strings used in DNS-SD are UTF-8 strings. - * With few exceptions, most are also escaped using standard DNS escaping rules: + * All strings used in the DNS-SD APIs are UTF-8 strings. Apart from the exceptions noted below, + * the APIs expect the strings to be properly escaped, using the conventional DNS escaping rules: * * '\\' represents a single literal '\' in the name * '\.' represents a single literal '.' in the name @@ -493,7 +517,7 @@ enum * _service._udp, where the "service" part is 1-14 characters, which may be * letters, digits, or hyphens. The domain part of the three-part name may be * any legal domain, providing that the resulting servicename+regtype+domain - * name does not exceed 255 bytes. + * name does not exceed 256 bytes. * * For most software, these issues are transparent. When browsing, the discovered * servicenames should simply be displayed as-is. When resolving, the discovered @@ -979,7 +1003,9 @@ DNSServiceErrorType DNSSD_API DNSServiceRegister * * rdata: The raw rdata to be contained in the added resource record. * - * ttl: The time to live of the resource record, in seconds. Pass 0 to use a default value. + * ttl: The time to live of the resource record, in seconds. + * Most clients should pass 0 to indicate that the system should + * select a sensible default value. * * return value: Returns kDNSServiceErr_NoError on success, otherwise returns an * error code indicating the error that occurred (the RecordRef is not initialized). @@ -1019,6 +1045,8 @@ DNSServiceErrorType DNSSD_API DNSServiceAddRecord * rdata: The new rdata to be contained in the updated resource record. * * ttl: The time to live of the updated resource record, in seconds. + * Most clients should pass 0 to indicate that the system should + * select a sensible default value. * * return value: Returns kDNSServiceErr_NoError on success, otherwise returns an * error code indicating the error that occurred. @@ -1600,7 +1628,7 @@ DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef); * call, this ref may be passed to DNSServiceUpdateRecord() or DNSServiceRemoveRecord(). * (To deregister ALL records registered on a single connected DNSServiceRef * and deallocate each of their corresponding DNSServiceRecordRefs, call - * DNSServiceRefDealloocate()). + * DNSServiceRefDeallocate()). * * flags: Possible values are kDNSServiceFlagsShared or kDNSServiceFlagsUnique * (see flag type definitions for details). @@ -1620,7 +1648,9 @@ DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef); * * rdata: A pointer to the raw rdata, as it is to appear in the DNS record. * - * ttl: The time to live of the resource record, in seconds. Pass 0 to use a default value. + * ttl: The time to live of the resource record, in seconds. + * Most clients should pass 0 to indicate that the system should + * select a sensible default value. * * callBack: The function to be called when a result is found, or if the call * asynchronously fails (e.g. because of a name conflict.) @@ -1704,25 +1734,66 @@ DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord /* DNSServiceNATPortMappingCreate * - * Request a port mapping in the NAT gateway which maps a port on the local machine - * to a public port on the NAT. + * Request a port mapping in the NAT gateway, which maps a port on the local machine + * to an external port on the NAT. + * * The port mapping will be renewed indefinitely until the client process exits, or * explicitly terminates the port mapping request by calling DNSServiceRefDeallocate(). * The client callback will be invoked, informing the client of the NAT gateway's - * public IP address and the public port that has been allocated for this client. - * The client should then record this public IP address and port using whatever + * external IP address and the external port that has been allocated for this client. + * The client should then record this external IP address and port using whatever * directory service mechanism it is using to enable peers to connect to it. * (Clients advertising services using Wide-Area DNS-SD DO NOT need to use this API * -- when a client calls DNSServiceRegister() NAT mappings are automatically created - * and the public IP address and port for the service are recorded in the global DNS. + * and the external IP address and port for the service are recorded in the global DNS. * Only clients using some directory mechanism other than Wide-Area DNS-SD need to use * this API to explicitly map their own ports.) + * * It's possible that the client callback could be called multiple times, for example * if the NAT gateway's IP address changes, or if a configuration change results in a - * different public port being mapped for this client. Over the lifetime of any long-lived + * different external port being mapped for this client. Over the lifetime of any long-lived * port mapping, the client should be prepared to handle these notifications of changes * in the environment, and should update its recorded address and/or port as appropriate. * + * NOTE: There are two unusual aspects of how the DNSServiceNATPortMappingCreate API works, + * which were intentionally designed to help simplify client code: + * + * 1. It's not an error to request a NAT mapping when the machine is not behind a NAT gateway. + * In other NAT mapping APIs, if you request a NAT mapping and the machine is not behind a NAT + * gateway, then the API returns an error code -- it can't get you a NAT mapping if there's no + * NAT gateway. The DNSServiceNATPortMappingCreate API takes a different view. Working out + * whether or not you need a NAT mapping can be tricky and non-obvious, particularly on + * a machine with multiple active network interfaces. Rather than make every client recreate + * this logic for deciding whether a NAT mapping is required, the PortMapping API does that + * work for you. If the client calls the PortMapping API when the machine already has a + * routable public IP address, then instead of complaining about it and giving an error, + * the PortMapping API just invokes your callback, giving the machine's public address + * and your own port number. This means you don't need to write code to work out whether + * your client needs to call the PortMapping API -- just call it anyway, and if it wasn't + * necessary, no harm is done: + * + * - If the machine already has a routable public IP address, then your callback + * will just be invoked giving your own address and port. + * - If a NAT mapping is required and obtained, then your callback will be invoked + * giving you the external address and port. + * - If a NAT mapping is required but not obtained from the local NAT gateway, + * or the machine has no network connectivity, then your callback will be + * invoked giving zero address and port. + * + * 2. In other NAT mapping APIs, if a laptop computer is put to sleep and woken up on a new + * network, it's the client's job to notice this, and work out whether a NAT mapping + * is required on the new network, and make a new NAT mapping request if necessary. + * The DNSServiceNATPortMappingCreate API does this for you, automatically. + * The client just needs to make one call to the PortMapping API, and its callback will + * be invoked any time the mapping state changes. This property complements point (1) above. + * If the client didn't make a NAT mapping request just because it determined that one was + * not required at that particular moment in time, the client would then have to monitor + * for network state changes to determine if a NAT port mapping later became necessary. + * By unconditionally making a NAT mapping request, even when a NAT mapping not to be + * necessary, the PortMapping API will then begin monitoring network state changes on behalf of + * the client, and if a NAT mapping later becomes necessary, it will automatically create a NAT + * mapping and inform the client with a new callback giving the new address and port information. + * * DNSServiceNATPortMappingReply() parameters: * * sdRef: The DNSServiceRef initialized by DNSServiceNATPortMappingCreate(). @@ -1737,14 +1808,14 @@ DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord * For other failures, will indicate the failure that occurred, and the other * parameters are undefined. * - * publicAddress: Four byte IPv4 address in network byte order. + * externalAddress: Four byte IPv4 address in network byte order. * * protocol: Will be kDNSServiceProtocol_UDP or kDNSServiceProtocol_TCP or both. * - * privatePort: The port on the local machine that was mapped. + * internalPort: The port on the local machine that was mapped. * - * publicPort: The actual public port in the NAT gateway that was mapped. - * This is very likely to be different than the requested public port. + * externalPort: The actual external port in the NAT gateway that was mapped. + * This is likely to be different than the requested external port. * * ttl: The lifetime of the NAT port mapping created on the gateway. * This controls how quickly stale mappings will be garbage-collected @@ -1763,11 +1834,11 @@ typedef void (DNSSD_API *DNSServiceNATPortMappingReply) DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, - uint32_t publicAddress, /* four byte IPv4 address in network byte order */ + uint32_t externalAddress, /* four byte IPv4 address in network byte order */ DNSServiceProtocol protocol, - uint16_t privatePort, - uint16_t publicPort, /* may be different than the requested port */ - uint32_t ttl, /* may be different than the requested ttl */ + uint16_t internalPort, + uint16_t externalPort, /* may be different than the requested port */ + uint32_t ttl, /* may be different than the requested ttl */ void *context ); @@ -1786,14 +1857,14 @@ typedef void (DNSSD_API *DNSServiceNATPortMappingReply) * * protocol: To request a port mapping, pass in kDNSServiceProtocol_UDP, or kDNSServiceProtocol_TCP, * or (kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP) to map both. - * The local listening port number must also be specified in the privatePort parameter. - * To just discover the NAT gateway's public IP address, pass zero for protocol, - * privatePort, publicPort and ttl. + * The local listening port number must also be specified in the internalPort parameter. + * To just discover the NAT gateway's external IP address, pass zero for protocol, + * internalPort, externalPort and ttl. * - * privatePort: The port number in network byte order on the local machine which is listening for packets. + * internalPort: The port number in network byte order on the local machine which is listening for packets. * - * publicPort: The requested public port in network byte order in the NAT gateway that you would - * like to map to the private port. Pass 0 if you don't care which public port is chosen for you. + * externalPort: The requested external port in network byte order in the NAT gateway that you would + * like to map to the internal port. Pass 0 if you don't care which external port is chosen for you. * * ttl: The requested renewal period of the NAT port mapping, in seconds. * If the client machine crashes, suffers a power failure, is disconnected from @@ -1817,8 +1888,8 @@ typedef void (DNSSD_API *DNSServiceNATPortMappingReply) * the error that occurred. * * If you don't actually want a port mapped, and are just calling the API - * because you want to find out the NAT's public IP address (e.g. for UI - * display) then pass zero for protocol, privatePort, publicPort and ttl. + * because you want to find out the NAT's external IP address (e.g. for UI + * display) then pass zero for protocol, internalPort, externalPort and ttl. */ DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate @@ -1826,12 +1897,12 @@ DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate DNSServiceRef *sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, - DNSServiceProtocol protocol, /* TCP and/or UDP */ - uint16_t privatePort, /* network byte order */ - uint16_t publicPort, /* network byte order */ - uint32_t ttl, /* time to live in seconds */ + DNSServiceProtocol protocol, /* TCP and/or UDP */ + uint16_t internalPort, /* network byte order */ + uint16_t externalPort, /* network byte order */ + uint32_t ttl, /* time to live in seconds */ DNSServiceNATPortMappingReply callBack, - void *context /* may be NULL */ + void *context /* may be NULL */ ); @@ -1850,7 +1921,7 @@ DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate * Parameters: * * fullName: A pointer to a buffer that where the resulting full domain name is to be written. - * The buffer must be kDNSServiceMaxDomainName (1005) bytes in length to + * The buffer must be kDNSServiceMaxDomainName (1009) bytes in length to * accommodate the longest legal domain name without buffer overrun. * * service: The service name - any dots or backslashes must NOT be escaped. @@ -1863,11 +1934,11 @@ DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate * domain: The domain name, e.g. "apple.com.". Literal dots or backslashes, * if any, must be escaped, e.g. "1st\. Floor.apple.com." * - * return value: Returns 0 on success, -1 on error. + * return value: Returns kDNSServiceErr_NoError (0) on success, kDNSServiceErr_BadParam on error. * */ -int DNSSD_API DNSServiceConstructFullName +DNSServiceErrorType DNSSD_API DNSServiceConstructFullName ( char *fullName, const char *service, /* may be NULL */ @@ -1988,7 +2059,7 @@ void DNSSD_API TXTRecordDeallocate * * key: A null-terminated string which only contains printable ASCII * values (0x20-0x7E), excluding '=' (0x3D). Keys should be - * 8 characters or less (not counting the terminating null). + * 9 characters or fewer (not counting the terminating null). * * valueSize: The size of the value. * @@ -2087,13 +2158,13 @@ const void * DNSSD_API TXTRecordGetBytesPtr * val1ptr = TXTRecordGetValuePtr(txtLen, txtRecord, "key1", &len1); * val2ptr = TXTRecordGetValuePtr(txtLen, txtRecord, "key2", &len2); * ... - * bcopy(val1ptr, myval1, len1); - * bcopy(val2ptr, myval2, len2); + * memcpy(myval1, val1ptr, len1); + * memcpy(myval2, val2ptr, len2); * ... * return; * * If you wish to retain the values after return from the DNSServiceResolve() - * callback, then you need to copy the data to your own storage using bcopy() + * callback, then you need to copy the data to your own storage using memcpy() * or similar, as shown in the example above. * * If for some reason you need to parse a TXT record you built yourself @@ -2203,7 +2274,7 @@ uint16_t DNSSD_API TXTRecordGetCount * key: A string buffer used to store the key name. * On return, the buffer contains a null-terminated C string * giving the key name. DNS-SD TXT keys are usually - * 8 characters or less. To hold the maximum possible + * 9 characters or fewer. To hold the maximum possible * key name, the buffer should be 256 bytes long. * * valueLen: On output, will be set to the size of the "value" data. diff --git a/mDNSShared/dnsextd.c b/mDNSShared/dnsextd.c index 807ced9..d272f0f 100644 --- a/mDNSShared/dnsextd.c +++ b/mDNSShared/dnsextd.c @@ -17,6 +17,36 @@ Change History (most recent first): $Log: dnsextd.c,v $ +Revision 1.97 2009/01/13 05:31:34 mkrochma + Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy + +Revision 1.96 2009/01/13 00:45:41 cheshire +Uncommented "#ifdef NOT_HAVE_DAEMON" check + +Revision 1.95 2009/01/12 22:47:13 cheshire +Only include "mDNSUNP.h" when building on a system that requires the "daemon()" definition (currently only Solaris) + +Revision 1.94 2009/01/11 03:20:06 mkrochma + Fixes from Igor Seleznev to get mdnsd working on Solaris + +Revision 1.93 2008/12/17 05:06:53 cheshire +Increased maximum DNS Update lifetime from 20 minutes to 2 hours -- now that we have Sleep Proxy, +having clients wake every fifteen minutes to renew their record registrations is no longer reasonable. + +Revision 1.92 2008/11/13 19:09:36 cheshire +Updated rdataOPT code + +Revision 1.91 2008/11/04 23:06:51 cheshire +Split RDataBody union definition into RDataBody and RDataBody2, and removed +SOA from the normal RDataBody union definition, saving 270 bytes per AuthRecord + +Revision 1.90 2008/10/03 18:18:57 cheshire +Define dummy "mDNS_ConfigChanged(mDNS *const m)" routine to avoid link errors + +Revision 1.89 2008/09/15 23:52:30 cheshire + mDNSResponder-177 fails to compile on Linux with .desc pseudo-op +Made __crashreporter_info__ symbol conditional, so we only use it for OS X build + Revision 1.88 2008/03/06 21:26:11 cheshire Moved duplicated STRINGIFY macro from individual C files to DNSCommon.h @@ -191,6 +221,11 @@ Revision 1.42 2006/07/05 22:48:19 cheshire #include #include +// Solaris doesn't have daemon(), so we define it here +#ifdef NOT_HAVE_DAEMON +#include "../mDNSPosix/mDNSUNP.h" // For daemon() +#endif // NOT_HAVE_DAEMON + // Compatibility workaround #ifndef AF_LOCAL #define AF_LOCAL AF_UNIX @@ -591,7 +626,7 @@ RecvPacket pkt = malloc(allocsize); require_action_quiet( pkt, exit, err = mStatus_NoMemoryErr; LogErr( "RecvPacket", "malloc" ) ); - bzero( pkt, sizeof( *pkt ) ); + mDNSPlatformMemZero( pkt, sizeof( *pkt ) ); } pkt->len = msglen; @@ -600,7 +635,7 @@ RecvPacket if ( getpeername( fd, ( struct sockaddr* ) &pkt->src, &srclen ) || ( srclen != sizeof( pkt->src ) ) ) { LogErr("RecvPacket", "getpeername"); - bzero(&pkt->src, sizeof(pkt->src)); + mDNSPlatformMemZero(&pkt->src, sizeof(pkt->src)); } nread = my_recv(sock, &pkt->msg, msglen, closed ); @@ -703,7 +738,7 @@ mDNSlocal mDNSBool IsLLQRequest(PktMsg *pkt) if (!ptr) { Log("Unable to read additional record"); goto end; } } - if ( lcr.r.resrec.rrtype == kDNSType_OPT && lcr.r.resrec.rdlength >= LLQ_OPT_RDLEN && lcr.r.resrec.rdata->u.opt.opt == kDNSOpt_LLQ ) + if ( lcr.r.resrec.rrtype == kDNSType_OPT && lcr.r.resrec.rdlength >= DNSOpt_LLQData_Space && lcr.r.resrec.rdata->u.opt[0].opt == kDNSOpt_LLQ ) { result = mDNStrue; } @@ -926,7 +961,7 @@ mDNSlocal CacheRecord *CopyCacheRecord(const CacheRecord *orig, domainname *name cr = malloc(size); if (!cr) { LogErr("CopyCacheRecord", "malloc"); return NULL; } memcpy(cr, orig, size); - cr->resrec.rdata = (RData*)&cr->rdatastorage; + cr->resrec.rdata = (RData*)&cr->smallrdatastorage; cr->resrec.name = name; return cr; @@ -947,7 +982,7 @@ mDNSlocal void RehashTable(DaemonInfo *d) 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 *)); + mDNSPlatformMemZero(new, newnbuckets * sizeof(RRTableElem *)); for (i = 0; i < d->nbuckets; i++) { @@ -1008,7 +1043,7 @@ mDNSlocal mDNSu8 *putRRSetDeletion(DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit, 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 + mDNSPlatformMemZero(ptr+4, sizeof(rr->rroriginalttl) + sizeof(rr->rdlength)); // zero ttl/rdata msg->h.mDNS_numUpdates++; return ptr + 10; } @@ -1208,7 +1243,7 @@ mDNSlocal int ProcessArgs(int argc, char *argv[], DaemonInfo *d) // setup our sockaddr - bzero( &d->addr, sizeof( d->addr ) ); + mDNSPlatformMemZero( &d->addr, sizeof( d->addr ) ); d->addr.sin_addr.s_addr = zerov4Addr.NotAnInteger; d->addr.sin_port = UnicastDNSPort.NotAnInteger; d->addr.sin_family = AF_INET; @@ -1218,7 +1253,7 @@ mDNSlocal int ProcessArgs(int argc, char *argv[], DaemonInfo *d) // setup nameserver's sockaddr - bzero(&d->ns_addr, sizeof(d->ns_addr)); + mDNSPlatformMemZero(&d->ns_addr, sizeof(d->ns_addr)); d->ns_addr.sin_family = AF_INET; inet_pton( AF_INET, LOOPBACK, &d->ns_addr.sin_addr ); d->ns_addr.sin_port = NSIPCPort.NotAnInteger; @@ -1281,7 +1316,7 @@ mDNSlocal int InitLeaseTable(DaemonInfo *d) 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); + mDNSPlatformMemZero(d->table, sizeof(RRTableElem *) * LEASETABLE_INIT_NBUCKETS); return 0; } @@ -1328,7 +1363,7 @@ SetupSockets // set up sockets on which we receive llq requests - bzero(&self->llq_addr, sizeof(self->llq_addr)); + mDNSPlatformMemZero(&self->llq_addr, sizeof(self->llq_addr)); self->llq_addr.sin_family = AF_INET; self->llq_addr.sin_addr.s_addr = zerov4Addr.NotAnInteger; self->llq_addr.sin_port = ( self->llq_port.NotAnInteger ) ? self->llq_port.NotAnInteger : DNSEXTPort.NotAnInteger; @@ -1370,7 +1405,7 @@ SetupSockets self->llq_tcpsd = socket( AF_INET, SOCK_STREAM, 0 ); require_action( dnssd_SocketValid(self->tlssd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) ); - bzero(&daddr, sizeof(daddr)); + mDNSPlatformMemZero(&daddr, sizeof(daddr)); daddr.sin_family = AF_INET; daddr.sin_addr.s_addr = zerov4Addr.NotAnInteger; daddr.sin_port = ( self->private_port.NotAnInteger ) ? self->private_port.NotAnInteger : PrivateDNSPort.NotAnInteger; @@ -1580,7 +1615,7 @@ mDNSlocal void UpdateLeaseTable(PktMsg *pkt, DaemonInfo *d, mDNSs32 lease) 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; + tmp->rr.resrec.rdata = (RData *)&tmp->rr.smallrdatastorage; AssignDomainName(&tmp->name, rr->name); tmp->rr.resrec.name = &tmp->name; tmp->expire = tv.tv_sec + (unsigned)lease; @@ -1661,15 +1696,15 @@ HandleRequest static const mDNSOpaque16 UpdateRefused = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, kDNSFlag1_RC_Refused } }; Log("Rejecting Update Request with %d additions but no lease", adds); reply = malloc(sizeof(*reply)); - bzero(&reply->src, sizeof(reply->src)); + mDNSPlatformMemZero(&reply->src, sizeof(reply->src)); reply->len = sizeof(DNSMessageHeader); reply->zone = NULL; reply->isZonePublic = 0; InitializeDNSMessage(&reply->msg.h, request->msg.h.id, UpdateRefused); return(reply); } - if (lease > 1200) // Don't allow lease greater than 20 minutes - lease = 1200; + if (lease > 7200) // Don't allow lease greater than two hours; typically 90-minute renewal period + lease = 7200; } // Send msg to server, read reply @@ -1772,18 +1807,17 @@ exit: // Set fields of an LLQ OPT Resource Record mDNSlocal void FormatLLQOpt(AuthRecord *opt, int opcode, const mDNSOpaque64 *const id, mDNSs32 lease) { - bzero(opt, sizeof(*opt)); + mDNSPlatformMemZero(opt, sizeof(*opt)); mDNS_SetupResourceRecord(opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL); opt->resrec.rrclass = NormalMaxDNSMessageData; - 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; - opt->resrec.rdata->u.opt.OptData.llq.id = *id; - opt->resrec.rdata->u.opt.OptData.llq.llqlease = lease; + opt->resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record + opt->resrec.rdestimate = sizeof(rdataOPT); + opt->resrec.rdata->u.opt[0].opt = kDNSOpt_LLQ; + opt->resrec.rdata->u.opt[0].u.llq.vers = kLLQ_Vers; + opt->resrec.rdata->u.opt[0].u.llq.llqOp = opcode; + opt->resrec.rdata->u.opt[0].u.llq.err = LLQErr_NoError; + opt->resrec.rdata->u.opt[0].u.llq.id = *id; + opt->resrec.rdata->u.opt[0].u.llq.llqlease = lease; } // Calculate effective remaining lease of an LLQ @@ -2481,14 +2515,14 @@ mDNSlocal int RecvLLQ( DaemonInfo *d, PktMsg *pkt, TCPSocket *sock ) // validate OPT if (opt.r.resrec.rrtype != kDNSType_OPT) { Log("Malformatted LLQ from %s: last Additional not an OPT RR", addr); goto end; } - if (opt.r.resrec.rdlength < pkt->msg.h.numQuestions * LLQ_OPT_RDLEN) { Log("Malformatted LLQ from %s: OPT RR to small (%d bytes for %d questions)", addr, opt.r.resrec.rdlength, pkt->msg.h.numQuestions); } + if (opt.r.resrec.rdlength < pkt->msg.h.numQuestions * DNSOpt_LLQData_Space) { Log("Malformatted LLQ from %s: OPT RR to small (%d bytes for %d questions)", addr, opt.r.resrec.rdlength, pkt->msg.h.numQuestions); } // dispatch each question for (i = 0; i < pkt->msg.h.numQuestions; i++) { qptr = getQuestion(&pkt->msg, qptr, end, 0, &q); if (!qptr) { Log("Malformatted LLQ from %s: cannot read question %d", addr, i); goto end; } - llq = (LLQOptData *)&opt.r.resrec.rdata->u.opt.OptData.llq + i; // point into OptData at index i + llq = (LLQOptData *)&opt.r.resrec.rdata->u.opt[0].u.llq + i; // point into OptData at index i if (llq->vers != kLLQ_Vers) { Log("LLQ from %s contains bad version %d (expected %d)", addr, llq->vers, kLLQ_Vers); goto end; } e = LookupLLQ(d, pkt->src, &q.qname, q.qtype, &llq->id); @@ -2702,7 +2736,7 @@ RecvUDPMessage context = malloc( sizeof( UDPContext ) ); require_action( context, exit, err = mStatus_NoMemoryErr ; LogErr( "RecvUDPMessage", "malloc" ) ); - bzero( context, sizeof( *context ) ); + mDNSPlatformMemZero( context, sizeof( *context ) ); context->d = self; context->sd = sd; @@ -2940,7 +2974,7 @@ AcceptTCPConnection context = ( TCPContext* ) malloc( sizeof( TCPContext ) ); require_action( context, exit, err = mStatus_NoMemoryErr; LogErr( "AcceptTCPConnection", "malloc" ) ); - bzero( context, sizeof( sizeof( TCPContext ) ) ); + mDNSPlatformMemZero( context, sizeof( sizeof( TCPContext ) ) ); context->d = self; newSock = accept( sd, ( struct sockaddr* ) &context->cliaddr, &clilen ); require_action( newSock != -1, exit, err = mStatus_UnknownErr; LogErr( "AcceptTCPConnection", "accept" ) ); @@ -3158,7 +3192,7 @@ int main(int argc, char *argv[]) d = malloc(sizeof(*d)); if (!d) { LogErr("main", "malloc"); exit(1); } - bzero(d, sizeof(DaemonInfo)); + mDNSPlatformMemZero(d, sizeof(DaemonInfo)); // Setup the public SRV record names @@ -3224,6 +3258,7 @@ int main(int argc, char *argv[]) // It's an error for these routines to actually be called, so perhaps we should log any call // to them. void mDNSCoreInitComplete( mDNS * const m, mStatus result) { ( void ) m; ( void ) result; } +void mDNS_ConfigChanged(mDNS *const m) { ( void ) m; } void mDNSCoreMachineSleep(mDNS * const m, mDNSBool wake) { ( void ) m; ( void ) wake; } void mDNSCoreReceive(mDNS *const m, void *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport, @@ -3262,6 +3297,8 @@ mDNS mDNSStorage; // The "@(#) " pattern is a special prefix the "what" command looks for const char mDNSResponderVersionString_SCCS[] = "@(#) dnsextd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")"; +#if _BUILDING_XCODE_PROJECT_ // If the process crashes, then this string will be magically included in the automatically-generated crash log const char *__crashreporter_info__ = mDNSResponderVersionString_SCCS + 5; asm(".desc ___crashreporter_info__, 0x10"); +#endif diff --git a/mDNSShared/dnsextd_lexer.l b/mDNSShared/dnsextd_lexer.l index be64cbd..352828f 100644 --- a/mDNSShared/dnsextd_lexer.l +++ b/mDNSShared/dnsextd_lexer.l @@ -17,6 +17,12 @@ Change History (most recent first): $Log: dnsextd_lexer.l,v $ +Revision 1.6 2008/07/18 17:40:46 cheshire +Removed redundant definition of "YY_NO_UNPUT" (not needed now that we use "%option nounput" instead) + +Revision 1.5 2008/06/24 18:32:26 mcguire + flex producing .c files that result in warnings + Revision 1.4 2007/05/25 20:01:43 cheshire /usr/bin/flex failures prevent mDNSResponder from building Only define "int yylineno" on flex 2.5.4 and earlier @@ -47,8 +53,6 @@ extern YYSTYPE yylval; int yylineno = 1; #endif -#define YY_NO_UNPUT - int yylex(void); static char* @@ -69,6 +73,7 @@ StripQuotes %} +%option nounput %% options return OPTIONS; diff --git a/mDNSShared/dnsextd_parser.y b/mDNSShared/dnsextd_parser.y index 8332df5..943be29 100644 --- a/mDNSShared/dnsextd_parser.y +++ b/mDNSShared/dnsextd_parser.y @@ -17,6 +17,9 @@ Change History (most recent first): $Log: dnsextd_parser.y,v $ +Revision 1.9 2009/01/11 03:20:06 mkrochma + Fixes from Igor Seleznev to get mdnsd working on Solaris + Revision 1.8 2007/03/21 19:47:50 cheshire Leak: On error path in ParseConfig @@ -49,8 +52,8 @@ Revision 1.1 2006/07/06 00:09:05 cheshire #include #include #include -#include -#include +#include "mDNSEmbeddedAPI.h" +#include "DebugServices.h" #include "dnsextd.h" void yyerror( const char* error ); diff --git a/mDNSShared/dnssd_clientlib.c b/mDNSShared/dnssd_clientlib.c index 01ffaff..d5d46c8 100644 --- a/mDNSShared/dnssd_clientlib.c +++ b/mDNSShared/dnssd_clientlib.c @@ -28,6 +28,16 @@ Change History (most recent first): $Log: dnssd_clientlib.c,v $ +Revision 1.21 2009/04/01 21:10:11 herscher + Current Bonjour code does not compile on Windows. Use _stricmp and _strnicmp. + +Revision 1.20 2008/11/26 20:57:37 cheshire +For consistency with other similar macros, renamed mdnsIsDigit/mdnsIsLetter/mdnsValidHostChar +to mDNSIsDigit/mDNSIsLetter/mDNSValidHostChar + +Revision 1.19 2008/11/04 21:15:18 cheshire + Potential buffer overflows in DNSServiceConstructFullName + Revision 1.18 2007/11/30 23:06:10 cheshire Fixed compile warning: declaration of 'index' shadows a global declaration @@ -101,6 +111,8 @@ like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code #if defined(_WIN32) // disable warning "conversion from to uint16_t" #pragma warning(disable:4244) +#define strncasecmp _strnicmp +#define strcasecmp _stricmp #endif /********************************************************************************************* @@ -109,7 +121,10 @@ like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code * *********************************************************************************************/ -#define mdnsIsDigit(X) ((X) >= '0' && (X) <= '9') +#define mDNSIsDigit(X) ((X) >= '0' && (X) <= '9') + +// DomainEndsInDot returns 1 if name ends with a dot, 0 otherwise +// (DNSServiceConstructFullName depends this returning 1 for true, rather than any non-zero value meaning true) static int DomainEndsInDot(const char *dom) { @@ -117,7 +132,7 @@ static int DomainEndsInDot(const char *dom) { if (dom[0] == '\\') // advance past escaped byte sequence { - if (mdnsIsDigit(dom[1]) && mdnsIsDigit(dom[2]) && mdnsIsDigit(dom[3])) + if (mDNSIsDigit(dom[1]) && mDNSIsDigit(dom[2]) && mDNSIsDigit(dom[3])) dom += 4; // If "\ddd" then skip four else dom += 2; // else if "\x" then skip two } @@ -153,52 +168,66 @@ static uint8_t *InternalTXTRecordSearch * *********************************************************************************************/ -int DNSSD_API DNSServiceConstructFullName +// Note: Need to make sure we don't write more than kDNSServiceMaxDomainName (1009) bytes to fullName +// In earlier builds this constant was defined to be 1005, so to avoid buffer overruns on clients +// compiled with that constant we'll actually limit the output to 1005 bytes. + +DNSServiceErrorType DNSSD_API DNSServiceConstructFullName ( - char *fullName, - const char *service, /* may be NULL */ - const char *regtype, - const char *domain + char *const fullName, + const char *const service, // May be NULL + const char *const regtype, + const char *const domain ) { - unsigned long len; - unsigned char c; - char *fn = fullName; - const char *s = service; - const char *r = regtype; - const char *d = domain; + const size_t len = !regtype ? 0 : strlen(regtype) - DomainEndsInDot(regtype); + char *fn = fullName; + char *const lim = fullName + 1005; + const char *s = service; + const char *r = regtype; + const char *d = domain; + + // regtype must be at least "x._udp" or "x._tcp" + if (len < 6 || !domain || !domain[0]) return kDNSServiceErr_BadParam; + if (strncasecmp((regtype + len - 4), "_tcp", 4) && strncasecmp((regtype + len - 4), "_udp", 4)) return kDNSServiceErr_BadParam; if (service && *service) { while (*s) { - c = (unsigned char)*s++; - if (c == '.' || (c == '\\')) *fn++ = '\\'; // escape dot and backslash literals - else if (c <= ' ') // escape non-printable characters + unsigned char c = *s++; // Needs to be unsigned, or values like 0xFF will be interpreted as < 32 + if (c <= ' ') // Escape non-printable characters { + if (fn+4 >= lim) goto fail; *fn++ = '\\'; - *fn++ = (char) ('0' + (c / 100)); - *fn++ = (char) ('0' + (c / 10) % 10); - c = (unsigned char)('0' + (c % 10)); + *fn++ = '0' + (c / 100); + *fn++ = '0' + (c / 10) % 10; + c = '0' + (c ) % 10; } + else if (c == '.' || (c == '\\')) // Escape dot and backslash literals + { + if (fn+2 >= lim) goto fail; + *fn++ = '\\'; + } + else + if (fn+1 >= lim) goto fail; *fn++ = (char)c; } *fn++ = '.'; } - if (!regtype) return -1; - len = (unsigned long) strlen(regtype); - if (DomainEndsInDot(regtype)) len--; - if (len < 6) return -1; // regtype must be at least "x._udp" or "x._tcp" - if (strncasecmp((regtype + len - 4), "_tcp", 4) && strncasecmp((regtype + len - 4), "_udp", 4)) return -1; - while (*r) *fn++ = *r++; - if (!DomainEndsInDot(regtype)) *fn++ = '.'; - - if (!domain || !domain[0]) return -1; - while (*d) *fn++ = *d++; - if (!DomainEndsInDot(domain)) *fn++ = '.'; + while (*r) if (fn+1 >= lim) goto fail; else *fn++ = *r++; + if (!DomainEndsInDot(regtype)) { if (fn+1 >= lim) goto fail; else *fn++ = '.'; } + + while (*d) if (fn+1 >= lim) goto fail; else *fn++ = *d++; + if (!DomainEndsInDot(domain)) { if (fn+1 >= lim) goto fail; else *fn++ = '.'; } + + *fn = '\0'; + return kDNSServiceErr_NoError; + +fail: *fn = '\0'; - return 0; + return kDNSServiceErr_BadParam; } /********************************************************************************************* diff --git a/mDNSShared/dnssd_clientstub.c b/mDNSShared/dnssd_clientstub.c index 3aac7ed..8326019 100644 --- a/mDNSShared/dnssd_clientstub.c +++ b/mDNSShared/dnssd_clientstub.c @@ -28,6 +28,107 @@ Change History (most recent first): $Log: dnssd_clientstub.c,v $ +Revision 1.134 2009/06/19 23:13:24 cheshire + Library: crash at handle_resolve_response + 183 +Added check for NULL after calling get_string + +Revision 1.133 2009/05/27 22:19:12 cheshire +Remove questionable uses of errno + +Revision 1.132 2009/05/26 21:31:07 herscher +Fix compile errors on Windows + +Revision 1.131 2009/05/26 04:48:19 herscher + ExplorerPlugin does not work in B4W 2.0 + +Revision 1.130 2009/05/02 01:29:48 mcguire + spin calling DNSServiceProcessResult if errno was set to EWOULDBLOCK by an unrelated call + +Revision 1.129 2009/05/01 19:18:50 cheshire + Using duplicate DNSServiceRefs when sharing a connection should return an error + +Revision 1.128 2009/04/01 21:09:35 herscher + Current Bonjour code does not compile on Windows. + +Revision 1.127 2009/03/03 21:38:19 cheshire +Improved "deliver_request ERROR" message + +Revision 1.126 2009/02/12 21:02:22 cheshire +Commented out BPF "Sending fd" debugging message + +Revision 1.125 2009/02/12 20:28:32 cheshire +Added some missing "const" declarations + +Revision 1.124 2009/02/10 01:44:39 cheshire + DNSServiceUpdateRecord fails with kDNSServiceErr_BadReference for otherwise valid reference + +Revision 1.123 2009/01/19 00:49:21 mkrochma +Type cast size_t values to unsigned long + +Revision 1.122 2009/01/18 03:51:37 mkrochma +Fix warning in deliver_request on Linux + +Revision 1.121 2009/01/16 23:34:37 cheshire + Uninitialized error code variable in error handling path in deliver_request + +Revision 1.120 2009/01/13 05:31:35 mkrochma + Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy + +Revision 1.119 2009/01/11 03:45:08 mkrochma +Stop type casting num_written and num_read to int + +Revision 1.118 2009/01/11 03:20:06 mkrochma + Fixes from Igor Seleznev to get mdnsd working on Solaris + +Revision 1.117 2009/01/10 22:03:43 mkrochma + dnsextd fails to build on Linux + +Revision 1.116 2009/01/05 16:55:24 cheshire + Stuck in "Examining available disks" +ConnectionResponse handler was accidentally matching the parent DNSServiceRef before +finding the appropriate subordinate DNSServiceRef for the operation in question. + +Revision 1.115 2008/12/18 00:19:11 mcguire + Stuck in "Examining available disks" + +Revision 1.114 2008/12/10 02:11:43 cheshire +ARMv5 compiler doesn't like uncommented stuff after #endif + +Revision 1.113 2008/12/04 03:23:05 cheshire +Preincrement UID counter before we use it -- it helps with debugging if we know the all-zeroes ID should never appear + +Revision 1.112 2008/11/25 22:56:54 cheshire + Make library code more defensive when client calls DNSServiceProcessResult with bad DNSServiceRef repeatedly + +Revision 1.111 2008/10/28 17:58:44 cheshire +If client code keeps calling DNSServiceProcessResult repeatedly after an error, rate-limit the +"DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function" log messages + +Revision 1.110 2008/10/23 23:38:58 cheshire +For Windows compatibility, instead of "strerror(errno)" use "dnssd_strerror(dnssd_errno)" + +Revision 1.109 2008/10/23 23:06:17 cheshire +Removed () from dnssd_errno macro definition -- it's not a function and doesn't need any arguments + +Revision 1.108 2008/10/23 22:33:24 cheshire +Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu + +Revision 1.107 2008/10/20 21:50:11 cheshire +Improved /dev/bpf error message + +Revision 1.106 2008/10/20 15:37:18 cheshire +Log error message if opening /dev/bpf fails + +Revision 1.105 2008/09/27 01:26:34 cheshire +Added handler to pass back BPF fd when requested + +Revision 1.104 2008/09/23 01:36:00 cheshire +Updated code to use internalPort/externalPort terminology, instead of the old privatePort/publicPort +terms (which could be misleading, because the word "private" suggests security). + +Revision 1.103 2008/07/24 18:51:13 cheshire +Removed spurious spaces + Revision 1.102 2008/02/25 19:16:19 cheshire Problems with DNSServiceGetAddrInfo API Was returning a bogus result (NULL pointer) when following a CNAME referral @@ -215,9 +316,13 @@ Minor textual tidying #if defined(_WIN32) + #define _SSIZE_T + #include + #include #include #include #include + #include #define sockaddr_mdns sockaddr_in #define AF_MDNS AF_INET @@ -233,9 +338,22 @@ Minor textual tidying #define sleep(X) Sleep((X) * 1000) static int g_initWinsock = 0; - + #define LOG_WARNING kDebugLevelWarning + static void syslog( int priority, const char * message, ...) + { + va_list args; + int len; + char * buffer; + DWORD err = WSAGetLastError(); + va_start( args, message ); + len = _vscprintf( message, args ) + 1; + buffer = malloc( len * sizeof(char) ); + if ( buffer ) { vsprintf( buffer, message, args ); OutputDebugString( buffer ); free( buffer ); } + WSASetLastError( err ); + } #else + #include // For O_RDWR etc. #include #include #include @@ -268,7 +386,7 @@ typedef struct _DNSServiceRef_t DNSServiceOp; typedef struct _DNSRecordRef_t DNSRecord; // client stub callback to process message from server and deliver results to client application -typedef void (*ProcessReplyFn)(DNSServiceOp *sdr, CallbackHeader *cbh, char *msg, char *end); +typedef void (*ProcessReplyFn)(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *msg, const char *const end); #define ValidatorBits 0x12345678 #define DNSServiceRefValid(X) (dnssd_SocketValid((X)->sockfd) && (((X)->sockfd ^ (X)->validator) == ValidatorBits)) @@ -306,7 +424,7 @@ struct _DNSRecordRef_t static int write_all(dnssd_sock_t sd, char *buf, int len) { // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead. - //if (send(sd, buf, len, MSG_WAITALL) != len) return -1; + //if (send(sd, buf, len, MSG_WAITALL) != len) return -1; while (len) { ssize_t num_written = send(sd, buf, len, 0); @@ -314,9 +432,9 @@ static int write_all(dnssd_sock_t sd, char *buf, int len) { // Should never happen. If it does, it indicates some OS bug, // or that the mDNSResponder daemon crashed (which should never happen). - syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %d/%d %d %s", sd, num_written, len, - (num_written < 0) ? errno : 0, - (num_written < 0) ? strerror(errno) : ""); + syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%d %d %s", sd, num_written, len, + (num_written < 0) ? dnssd_errno : 0, + (num_written < 0) ? dnssd_strerror(dnssd_errno) : ""); return -1; } buf += num_written; @@ -325,7 +443,9 @@ static int write_all(dnssd_sock_t sd, char *buf, int len) return 0; } -// Read len bytes. Return 0 on success, -1 on error +enum { read_all_success = 0, read_all_fail = -1, read_all_wouldblock = -2 }; + +// Read len bytes. Return 0 on success, read_all_fail on error, or read_all_wouldblock for static int read_all(dnssd_sock_t sd, char *buf, int len) { // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead. @@ -338,15 +458,15 @@ static int read_all(dnssd_sock_t sd, char *buf, int len) { // Should never happen. If it does, it indicates some OS bug, // or that the mDNSResponder daemon crashed (which should never happen). - syslog(LOG_WARNING, "dnssd_clientstub read_all(%d) failed %d/%d %d %s", sd, num_read, len, - (num_read < 0) ? errno : 0, - (num_read < 0) ? strerror(errno) : ""); - return -1; + syslog(LOG_WARNING, "dnssd_clientstub read_all(%d) failed %ld/%d %d %s", sd, num_read, len, + (num_read < 0) ? dnssd_errno : 0, + (num_read < 0) ? dnssd_strerror(dnssd_errno) : ""); + return (num_read < 0 && dnssd_errno == dnssd_EWOULDBLOCK) ? read_all_wouldblock : read_all_fail; } buf += num_read; len -= num_read; } - return 0; + return read_all_success; } // Returns 1 if more bytes remain to be read on socket descriptor sd, 0 otherwise @@ -385,7 +505,7 @@ static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int #elif defined(USE_NAMED_ERROR_RETURN_SOCKET) struct timeval time; if (gettimeofday(&time, NULL) < 0) - { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: gettimeofday failed %d %s", errno, strerror(errno)); return NULL; } + { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: gettimeofday failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); return NULL; } sprintf(ctrl_path, "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX, (int)getpid(), (unsigned long)(time.tv_sec & 0xFFF), (unsigned long)(time.tv_usec)); *len += strlen(ctrl_path) + 1; @@ -401,7 +521,7 @@ static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int msg = malloc(*len); if (!msg) { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: malloc failed"); return NULL; } - bzero(msg, *len); + memset(msg, 0, *len); hdr = (ipc_msg_hdr *)msg; hdr->version = VERSION; hdr->datalen = datalen; @@ -464,7 +584,7 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; } - if (!DNSServiceRefValid(*ref)) + if (!DNSServiceRefValid(*ref) || (*ref)->op != connection_request || (*ref)->primary) { syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with invalid DNSServiceRef %p %08X %08X", (*ref), (*ref)->sockfd, (*ref)->validator); @@ -505,11 +625,12 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f DNSServiceOp **p = &(*ref)->next; // Append ourselves to end of primary's list while (*p) p = &(*p)->next; *p = sdr; + // Preincrement counter before we use it -- it helps with debugging if we know the all-zeroes ID should never appear + if (++(*ref)->uid.u32[0] == 0) ++(*ref)->uid.u32[1]; // In parent DNSServiceOp increment UID counter sdr->primary = *ref; // Set our primary pointer sdr->sockfd = (*ref)->sockfd; // Inherit primary's socket sdr->validator = (*ref)->validator; sdr->uid = (*ref)->uid; - if (++(*ref)->uid.u32[0] == 0) ++(*ref)->uid.u32[1]; // In parent DNSServiceOp increment UID counter //printf("ConnectToServer sharing socket %d\n", sdr->sockfd); } else @@ -522,14 +643,14 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f sdr->validator = sdr->sockfd ^ ValidatorBits; if (!dnssd_SocketValid(sdr->sockfd)) { - syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: socket failed %d %s", errno, strerror(errno)); + syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: socket failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); FreeDNSServiceOp(sdr); return kDNSServiceErr_NoMemory; } #ifdef SO_NOSIGPIPE // Some environments (e.g. OS X) support turning off SIGPIPE for a socket if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0) - syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_NOSIGPIPE failed %d %s", errno, strerror(errno)); + syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_NOSIGPIPE failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); #endif #if defined(USE_TCP_LOOPBACK) saddr.sin_family = AF_INET; @@ -559,6 +680,9 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f return kDNSServiceErr_NoError; } +#define deliver_request_bailout(MSG) \ + do { syslog(LOG_WARNING, "dnssd_clientstub deliver_request: %s failed %d (%s)", (MSG), dnssd_errno, dnssd_strerror(dnssd_errno)); goto cleanup; } while(0) + static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr) { uint32_t datalen = hdr->datalen; // We take a copy here because we're going to convert hdr->datalen to network byte order @@ -566,7 +690,7 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr) char *const data = (char *)hdr + sizeof(ipc_msg_hdr); #endif dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket; - DNSServiceErrorType err; + DNSServiceErrorType err = kDNSServiceErr_Unknown; // Default for the "goto cleanup" cases int MakeSeparateReturnSocket = 0; // Note: need to check hdr->op, not sdr->op. @@ -593,14 +717,14 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr) dnssd_sockaddr_t caddr; dnssd_socklen_t len = (dnssd_socklen_t) sizeof(caddr); listenfd = socket(AF_DNSSD, SOCK_STREAM, 0); - if (!dnssd_SocketValid(listenfd)) goto cleanup; + if (!dnssd_SocketValid(listenfd)) deliver_request_bailout("TCP socket"); caddr.sin_family = AF_INET; caddr.sin_port = 0; caddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR); - if (bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr)) < 0) goto cleanup; - if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) goto cleanup; - listen(listenfd, 1); + if (bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr)) < 0) deliver_request_bailout("TCP bind"); + if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) deliver_request_bailout("TCP getsockname"); + if (listen(listenfd, 1) < 0) deliver_request_bailout("TCP listen"); port.s = caddr.sin_port; data[0] = port.b[0]; // don't switch the byte order, as the data[1] = port.b[1]; // daemon expects it in network byte order @@ -611,7 +735,7 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr) int bindresult; dnssd_sockaddr_t caddr; listenfd = socket(AF_DNSSD, SOCK_STREAM, 0); - if (!dnssd_SocketValid(listenfd)) goto cleanup; + if (!dnssd_SocketValid(listenfd)) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET socket"); caddr.sun_family = AF_LOCAL; // According to Stevens (section 3.2), there is no portable way to @@ -623,16 +747,13 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr) mask = umask(0); bindresult = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr)); umask(mask); - if (bindresult < 0) goto cleanup; - listen(listenfd, 1); + if (bindresult < 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET bind"); + if (listen(listenfd, 1) < 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET listen"); } #else { dnssd_sock_t sp[2]; - //if (pipe(sp) < 0) - // syslog(LOG_WARNING, "dnssd_clientstub ERROR: pipe() failed errno %d (%s)", errno, strerror(errno)); - if (socketpair(AF_DNSSD, SOCK_STREAM, 0, sp) < 0) - syslog(LOG_WARNING, "dnssd_clientstub ERROR: socketpair() failed errno %d (%s)", errno, strerror(errno)); + if (socketpair(AF_DNSSD, SOCK_STREAM, 0, sp) < 0) deliver_request_bailout("socketpair"); else { errsd = sp[0]; // We'll read our four-byte error code from sp[0] @@ -649,27 +770,33 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr) // any associated data does not work reliably -- e.g. one particular issue we ran // into is that if the receiving program is in a kqueue loop waiting to be notified // of the received message, it doesn't get woken up when the control message arrives. - if (MakeSeparateReturnSocket) datalen--; + if (MakeSeparateReturnSocket || sdr->op == send_bpf) datalen--; // Okay to use sdr->op when checking for op == send_bpf #endif // At this point, our listening socket is set up and waiting, if necessary, for the daemon to connect back to ConvertHeaderBytes(hdr); - //syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %ld bytes", datalen + sizeof(ipc_msg_hdr)); + //syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %lu bytes", (unsigned long)(datalen + sizeof(ipc_msg_hdr))); //if (MakeSeparateReturnSocket) syslog(LOG_WARNING, "dnssd_clientstub deliver_request name is %s", data); #if TEST_SENDING_ONE_BYTE_AT_A_TIME unsigned int i; for (i=0; isockfd, ((char *)hdr)+i, 1) < 0) goto cleanup; + syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %d", i); + if (write_all(sdr->sockfd, ((char *)hdr)+i, 1) < 0) + { syslog(LOG_WARNING, "write_all (byte %u) failed", i); goto cleanup; } usleep(10000); } #else - if (write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr)) < 0) goto cleanup; + if (write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr)) < 0) + { + syslog(LOG_WARNING, "dnssd_clientstub deliver_request ERROR: write_all(%d, %lu bytes) failed", + sdr->sockfd, (unsigned long)(datalen + sizeof(ipc_msg_hdr))); + goto cleanup; + } #endif if (!MakeSeparateReturnSocket) errsd = sdr->sockfd; - else + if (MakeSeparateReturnSocket || sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf { #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET) // At this point we may block in accept for a few milliseconds waiting for the daemon to connect back to us, @@ -677,7 +804,7 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr) dnssd_sockaddr_t daddr; dnssd_socklen_t len = sizeof(daddr); errsd = accept(listenfd, (struct sockaddr *)&daddr, &len); - if (!dnssd_SocketValid(errsd)) goto cleanup; + if (!dnssd_SocketValid(errsd)) deliver_request_bailout("accept"); #else #if APPLE_OSX_mDNSResponder @@ -696,6 +823,22 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr) struct msghdr msg; struct cmsghdr *cmsg; char cbuf[CMSG_SPACE(sizeof(dnssd_sock_t))]; + + if (sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf + { + int i; + char p[12]; // Room for "/dev/bpf999" with terminating null + for (i=0; i<100; i++) + { + snprintf(p, sizeof(p), "/dev/bpf%d", i); + listenfd = open(p, O_RDWR, 0); + //if (dnssd_SocketValid(listenfd)) syslog(LOG_WARNING, "Sending fd %d for %s", listenfd, p); + if (!dnssd_SocketValid(listenfd) && dnssd_errno != EBUSY) + syslog(LOG_WARNING, "Error opening %s %d (%s)", p, dnssd_errno, dnssd_strerror(dnssd_errno)); + if (dnssd_SocketValid(listenfd) || dnssd_errno != EBUSY) break; + } + } + msg.msg_name = 0; msg.msg_namelen = 0; msg.msg_iov = &vec; @@ -719,19 +862,19 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr) sizeof(struct cmsghdr) + sizeof(dnssd_sock_t), CMSG_LEN(sizeof(dnssd_sock_t)), (long)CMSG_SPACE(sizeof(dnssd_sock_t)), (long)((char*)CMSG_DATA(cmsg) + 4 - cbuf)); -#endif DEBUG_64BIT_SCM_RIGHTS +#endif // DEBUG_64BIT_SCM_RIGHTS if (sendmsg(sdr->sockfd, &msg, 0) < 0) { - syslog(LOG_WARNING, "dnssd_clientstub ERROR: sendmsg failed read sd=%d write sd=%d errno %d (%s)", - errsd, listenfd, errno, strerror(errno)); + syslog(LOG_WARNING, "dnssd_clientstub deliver_request ERROR: sendmsg failed read sd=%d write sd=%d errno %d (%s)", + errsd, listenfd, dnssd_errno, dnssd_strerror(dnssd_errno)); err = kDNSServiceErr_Incompatible; goto cleanup; } #if DEBUG_64BIT_SCM_RIGHTS syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d okay", errsd, listenfd); -#endif DEBUG_64BIT_SCM_RIGHTS +#endif // DEBUG_64BIT_SCM_RIGHTS #endif // Close our end of the socketpair *before* blocking in read_all to get the four-byte error code. @@ -743,7 +886,9 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr) // At this point we may block in read_all for a few milliseconds waiting for the daemon to send us the error code, // but that's okay -- the daemon is a trusted service and we know if won't take more than a few milliseconds to respond. - if (read_all(errsd, (char*)&err, (int)sizeof(err)) < 0) + if (sdr->op == send_bpf) // Okay to use sdr->op when checking for op == send_bpf + err = kDNSServiceErr_NoError; + else if (read_all(errsd, (char*)&err, (int)sizeof(err)) < 0) err = kDNSServiceErr_ServiceNotRunning; // On failure read_all will have written a message to syslog for us else err = ntohl(err); @@ -758,10 +903,11 @@ cleanup: #if defined(USE_NAMED_ERROR_RETURN_SOCKET) // syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removing UDS: %s", data); if (unlink(data) != 0) - syslog(LOG_WARNING, "dnssd_clientstub WARNING: unlink(\"%s\") failed errno %d (%s)", data, errno, strerror(errno)); + syslog(LOG_WARNING, "dnssd_clientstub WARNING: unlink(\"%s\") failed errno %d (%s)", data, dnssd_errno, dnssd_strerror(dnssd_errno)); // else syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removed UDS: %s", data); #endif } + free(hdr); return err; } @@ -808,7 +954,9 @@ DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef) if (!sdRef->ProcessReply) { - syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function"); + static int num_logs = 0; + if (num_logs < 10) syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function"); + if (num_logs < 1000) num_logs++; else sleep(1); return kDNSServiceErr_BadReference; } @@ -820,22 +968,21 @@ DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef) // return NoError on EWOULDBLOCK. This will handle the case // where a non-blocking socket is told there is data, but it was a false positive. // On error, read_all will write a message to syslog for us, so don't need to duplicate that here - if (read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr)) < 0) + // Note: If we want to properly support using non-blocking sockets in the future + int result = read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr)); + if (result == read_all_fail) { - if (dnssd_errno() != dnssd_EWOULDBLOCK) - { - sdRef->ProcessReply = NULL; - return kDNSServiceErr_ServiceNotRunning; - } - else + sdRef->ProcessReply = NULL; + return kDNSServiceErr_ServiceNotRunning; + } + else if (result == read_all_wouldblock) + { + if (morebytes && sdRef->logcounter < 100) { - if (morebytes && sdRef->logcounter < 100) - { - sdRef->logcounter++; - syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult error: select indicated data was waiting but read_all returned EWOULDBLOCK"); - } - return kDNSServiceErr_NoError; + sdRef->logcounter++; + syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult error: select indicated data was waiting but read_all returned EWOULDBLOCK"); } + return kDNSServiceErr_NoError; } ConvertHeaderBytes(&cbh.ipc_hdr); @@ -856,7 +1003,7 @@ DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef) } else { - char *ptr = data; + const char *ptr = data; cbh.cb_flags = get_flags (&ptr, data + cbh.ipc_hdr.datalen); cbh.cb_interface = get_uint32 (&ptr, data + cbh.ipc_hdr.datalen); cbh.cb_err = get_error_code(&ptr, data + cbh.ipc_hdr.datalen); @@ -960,7 +1107,7 @@ DNSServiceErrorType DNSSD_API DNSServiceGetProperty(const char *property, void * return kDNSServiceErr_NoError; } -static void handle_resolve_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end) +static void handle_resolve_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *end) { char fullname[kDNSServiceMaxDomainName]; char target[kDNSServiceMaxDomainName]; @@ -970,7 +1117,7 @@ static void handle_resolve_response(DNSServiceOp *sdr, CallbackHeader *cbh, char get_string(&data, end, fullname, kDNSServiceMaxDomainName); get_string(&data, end, target, kDNSServiceMaxDomainName); - if (data + 2 > end) data = NULL; + if (!data || data + 2 > end) data = NULL; else { port.b[0] = *data++; @@ -1027,12 +1174,12 @@ DNSServiceErrorType DNSSD_API DNSServiceResolve return err; } -static void handle_query_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end) +static void handle_query_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) { uint32_t ttl; char name[kDNSServiceMaxDomainName]; uint16_t rrtype, rrclass, rdlen; - char *rdata; + const char *rdata; get_string(&data, end, name, kDNSServiceMaxDomainName); rrtype = get_uint16(&data, end); @@ -1086,11 +1233,11 @@ DNSServiceErrorType DNSSD_API DNSServiceQueryRecord return err; } -static void handle_addrinfo_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end) +static void handle_addrinfo_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) { char hostname[kDNSServiceMaxDomainName]; uint16_t rrtype, rrclass, rdlen; - char *rdata; + const char *rdata; uint32_t ttl; get_string(&data, end, hostname, kDNSServiceMaxDomainName); @@ -1112,7 +1259,7 @@ static void handle_addrinfo_response(DNSServiceOp *sdr, CallbackHeader *cbh, cha const struct sockaddr *const sa = (rrtype == kDNSServiceType_A) ? (struct sockaddr*)&sa4 : (struct sockaddr*)&sa6; if (rrtype == kDNSServiceType_A) { - bzero(&sa4, sizeof(sa4)); + memset(&sa4, 0, sizeof(sa4)); #ifndef NOT_HAVE_SA_LEN sa4.sin_len = sizeof(struct sockaddr_in); #endif @@ -1122,7 +1269,7 @@ static void handle_addrinfo_response(DNSServiceOp *sdr, CallbackHeader *cbh, cha } else { - bzero(&sa6, sizeof(sa6)); + memset(&sa6, 0, sizeof(sa6)); #ifndef NOT_HAVE_SA_LEN sa6.sin6_len = sizeof(struct sockaddr_in6); #endif @@ -1181,7 +1328,7 @@ DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo return err; } -static void handle_browse_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end) +static void handle_browse_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) { char replyName[256], replyType[kDNSServiceMaxDomainName], replyDomain[kDNSServiceMaxDomainName]; get_string(&data, end, replyName, 256); @@ -1247,7 +1394,7 @@ DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags return err; } -static void handle_regservice_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end) +static void handle_regservice_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) { char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName]; get_string(&data, end, name, 256); @@ -1318,7 +1465,7 @@ DNSServiceErrorType DNSSD_API DNSServiceRegister return err; } -static void handle_enumeration_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end) +static void handle_enumeration_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) { char domain[kDNSServiceMaxDomainName]; get_string(&data, end, domain, kDNSServiceMaxDomainName); @@ -1362,7 +1509,7 @@ DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains return err; } -static void ConnectionResponse(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end) +static void ConnectionResponse(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *const data, const char *const end) { DNSRecordRef rref = cbh->ipc_hdr.client_context.context; (void)data; // Unused @@ -1371,13 +1518,15 @@ static void ConnectionResponse(DNSServiceOp *sdr, CallbackHeader *cbh, char *dat if (cbh->ipc_hdr.op != reg_record_reply_op) { // When using kDNSServiceFlagsShareConnection, need to search the list of associated DNSServiceOps - // to find the one this response is intended for, and then call through to its ProcessReply handler - while (sdr && (sdr->uid.u32[0] != cbh->ipc_hdr.client_context.u32[0] || sdr->uid.u32[1] != cbh->ipc_hdr.client_context.u32[1])) - sdr = sdr->next; - // NOTE: We may sometimes not find a matching DNSServiceOp, in the case where the client has + // to find the one this response is intended for, and then call through to its ProcessReply handler. + // We start with our first subordinate DNSServiceRef -- don't want to accidentally match the parent DNSServiceRef. + DNSServiceOp *op = sdr->next; + while (op && (op->uid.u32[0] != cbh->ipc_hdr.client_context.u32[0] || op->uid.u32[1] != cbh->ipc_hdr.client_context.u32[1])) + op = op->next; + // Note: We may sometimes not find a matching DNSServiceOp, in the case where the client has // cancelled the subordinate DNSServiceOp, but there are still messages in the pipeline from the daemon - if (sdr && sdr->ProcessReply) sdr->ProcessReply(sdr, cbh, data, end); - // WARNING: Don't touch sdr after this -- client may have called DNSServiceRefDeallocate + if (op && op->ProcessReply) op->ProcessReply(op, cbh, data, end); + // WARNING: Don't touch op or sdr after this -- client may have called DNSServiceRefDeallocate return; } @@ -1385,7 +1534,7 @@ static void ConnectionResponse(DNSServiceOp *sdr, CallbackHeader *cbh, char *dat rref->AppCallback(rref->sdr, rref, cbh->cb_flags, cbh->cb_err, rref->AppContext); else { - syslog(LOG_WARNING, "dnssd_clientstub handle_regrecord_response: sdr->op != connection_request"); + syslog(LOG_WARNING, "dnssd_clientstub ConnectionResponse: sdr->op != connection_request"); rref->AppCallback(rref->sdr, rref, 0, kDNSServiceErr_Unknown, rref->AppContext); } // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function @@ -1531,7 +1680,6 @@ DNSServiceErrorType DNSSD_API DNSServiceAddRecord rref->record_index = sdRef->max_index++; rref->sdr = sdRef; *RecordRef = rref; - hdr->client_context.context = rref; hdr->reg_index = rref->record_index; return deliver_request(hdr, sdRef); // Will free hdr for us @@ -1649,31 +1797,31 @@ DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord return err; } -static void handle_port_mapping_response(DNSServiceOp *sdr, CallbackHeader *cbh, char *data, char *end) +static void handle_port_mapping_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end) { union { uint32_t l; u_char b[4]; } addr; uint8_t protocol = 0; - union { uint16_t s; u_char b[2]; } privatePort; - union { uint16_t s; u_char b[2]; } publicPort; + union { uint16_t s; u_char b[2]; } internalPort; + union { uint16_t s; u_char b[2]; } externalPort; uint32_t ttl = 0; - if (data + 13 > end) data = NULL; + if (!data || data + 13 > end) data = NULL; else { - addr .b[0] = *data++; - addr .b[1] = *data++; - addr .b[2] = *data++; - addr .b[3] = *data++; - protocol = *data++; - privatePort.b[0] = *data++; - privatePort.b[1] = *data++; - publicPort .b[0] = *data++; - publicPort .b[1] = *data++; - ttl = get_uint32(&data, end); + addr .b[0] = *data++; + addr .b[1] = *data++; + addr .b[2] = *data++; + addr .b[3] = *data++; + protocol = *data++; + internalPort.b[0] = *data++; + internalPort.b[1] = *data++; + externalPort.b[0] = *data++; + externalPort.b[1] = *data++; + ttl = get_uint32(&data, end); } if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_port_mapping_response: error reading result from daemon"); - else ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, addr.l, protocol, privatePort.s, publicPort.s, ttl, sdr->AppContext); + else ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, addr.l, protocol, internalPort.s, externalPort.s, ttl, sdr->AppContext); // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function } @@ -1683,8 +1831,8 @@ DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate DNSServiceFlags flags, uint32_t interfaceIndex, uint32_t protocol, /* TCP and/or UDP */ - uint16_t privatePortInNetworkByteOrder, - uint16_t publicPortInNetworkByteOrder, + uint16_t internalPortInNetworkByteOrder, + uint16_t externalPortInNetworkByteOrder, uint32_t ttl, /* time to live in seconds */ DNSServiceNATPortMappingReply callBack, void *context /* may be NULL */ @@ -1693,8 +1841,8 @@ DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate char *ptr; size_t len; ipc_msg_hdr *hdr; - union { uint16_t s; u_char b[2]; } privatePort = { privatePortInNetworkByteOrder }; - union { uint16_t s; u_char b[2]; } publicPort = { publicPortInNetworkByteOrder }; + union { uint16_t s; u_char b[2]; } internalPort = { internalPortInNetworkByteOrder }; + union { uint16_t s; u_char b[2]; } externalPort = { externalPortInNetworkByteOrder }; DNSServiceErrorType err = ConnectToServer(sdRef, flags, port_mapping_request, handle_port_mapping_response, callBack, context); if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL @@ -1702,8 +1850,8 @@ DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate len = sizeof(flags); len += sizeof(interfaceIndex); len += sizeof(protocol); - len += sizeof(privatePort); - len += sizeof(publicPort); + len += sizeof(internalPort); + len += sizeof(externalPort); len += sizeof(ttl); hdr = create_hdr(port_mapping_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef); @@ -1712,10 +1860,10 @@ DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate put_flags(flags, &ptr); put_uint32(interfaceIndex, &ptr); put_uint32(protocol, &ptr); - *ptr++ = privatePort.b[0]; - *ptr++ = privatePort.b[1]; - *ptr++ = publicPort .b[0]; - *ptr++ = publicPort .b[1]; + *ptr++ = internalPort.b[0]; + *ptr++ = internalPort.b[1]; + *ptr++ = externalPort.b[0]; + *ptr++ = externalPort.b[1]; put_uint32(ttl, &ptr); err = deliver_request(hdr, *sdRef); // Will free hdr for us diff --git a/mDNSShared/dnssd_ipc.c b/mDNSShared/dnssd_ipc.c index 2e16747..f929ec0 100644 --- a/mDNSShared/dnssd_ipc.c +++ b/mDNSShared/dnssd_ipc.c @@ -28,6 +28,15 @@ Change History (most recent first): $Log: dnssd_ipc.c,v $ +Revision 1.23 2009/04/01 21:10:34 herscher + Current Bonjour code does not compile on Windows + +Revision 1.22 2009/02/12 20:28:31 cheshire +Added some missing "const" declarations + +Revision 1.21 2008/10/23 23:21:31 cheshire +Moved definition of dnssd_strerror() to be with the definition of dnssd_errno, in dnssd_ipc.h + Revision 1.20 2007/07/23 22:12:53 cheshire Make mDNSResponder more defensive against malicious local clients @@ -75,6 +84,32 @@ Update to APSL 2.0 #include "dnssd_ipc.h" +#if defined(_WIN32) + +char *win32_strerror(int inErrorCode) + { + static char buffer[1024]; + DWORD n; + memset(buffer, 0, sizeof(buffer)); + n = FormatMessageA( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + (DWORD) inErrorCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + buffer, + sizeof(buffer), + NULL); + if (n > 0) + { + // Remove any trailing CR's or LF's since some messages have them. + while ((n > 0) && isspace(((unsigned char *) buffer)[n - 1])) + buffer[--n] = '\0'; + } + return buffer; + } + +#endif + void put_uint32(const uint32_t l, char **ptr) { (*ptr)[0] = (char)((l >> 24) & 0xFF); @@ -84,7 +119,7 @@ void put_uint32(const uint32_t l, char **ptr) *ptr += sizeof(uint32_t); } -uint32_t get_uint32(char **ptr, char *end) +uint32_t get_uint32(const char **ptr, const char *end) { if (!*ptr || *ptr + sizeof(uint32_t) > end) { @@ -106,7 +141,7 @@ void put_uint16(uint16_t s, char **ptr) *ptr += sizeof(uint16_t); } -uint16_t get_uint16(char **ptr, char *end) +uint16_t get_uint16(const char **ptr, const char *end) { if (!*ptr || *ptr + sizeof(uint16_t) > end) { @@ -129,7 +164,7 @@ int put_string(const char *str, char **ptr) return 0; } -int get_string(char **ptr, char *end, char *buffer, int buflen) +int get_string(const char **ptr, const char *const end, char *buffer, int buflen) { if (!*ptr) { @@ -157,7 +192,7 @@ void put_rdata(const int rdlen, const unsigned char *rdata, char **ptr) *ptr += rdlen; } -char *get_rdata(char **ptr, char *end, int rdlen) +const char *get_rdata(const char **ptr, const char *end, int rdlen) { if (!*ptr || *ptr + rdlen > end) { @@ -166,7 +201,7 @@ char *get_rdata(char **ptr, char *end, int rdlen) } else { - char *rd = *ptr; + const char *rd = *ptr; *ptr += rdlen; return rd; } diff --git a/mDNSShared/dnssd_ipc.h b/mDNSShared/dnssd_ipc.h index 4cd2f20..92976f7 100644 --- a/mDNSShared/dnssd_ipc.h +++ b/mDNSShared/dnssd_ipc.h @@ -28,6 +28,24 @@ Change History (most recent first): $Log: dnssd_ipc.h,v $ +Revision 1.46 2009/05/27 22:20:44 cheshire +Removed unused dnssd_errno_assign() (we have no business writing to errno -- we should only read it) + +Revision 1.45 2009/05/26 21:31:07 herscher +Fix compile errors on Windows + +Revision 1.44 2009/02/12 20:28:31 cheshire +Added some missing "const" declarations + +Revision 1.43 2008/10/23 23:21:31 cheshire +Moved definition of dnssd_strerror() to be with the definition of dnssd_errno, in dnssd_ipc.h + +Revision 1.42 2008/10/23 23:06:17 cheshire +Removed () from dnssd_errno macro definition -- it's not a function and doesn't need any arguments + +Revision 1.41 2008/09/27 01:04:09 cheshire +Added "send_bpf" to list of request_op_t operation codes + Revision 1.40 2007/09/07 20:56:03 cheshire Renamed uint32_t field in client_context_t from "ptr64" to more accurate name "u32" @@ -157,7 +175,8 @@ Update to APSL 2.0 # define dnssd_sock_t SOCKET # define dnssd_socklen_t int # define dnssd_close(sock) closesocket(sock) -# define dnssd_errno() WSAGetLastError() +# define dnssd_errno WSAGetLastError() +# define dnssd_strerror(X) win32_strerror(X) # define ssize_t int # define getpid _getpid #else @@ -178,7 +197,8 @@ Update to APSL 2.0 # define dnssd_sock_t int # define dnssd_socklen_t unsigned int # define dnssd_close(sock) close(sock) -# define dnssd_errno() errno +# define dnssd_errno errno +# define dnssd_strerror(X) strerror(X) #endif #if defined(USE_TCP_LOOPBACK) @@ -241,6 +261,7 @@ typedef enum getproperty_request, // New in B4W 1.0.4 port_mapping_request, // New in Leopard and B4W 2.0 addrinfo_request, + send_bpf, // New in SL cancel_request = 63 } request_op_t; @@ -289,10 +310,10 @@ typedef packedstruct // it is advanced to point to the next field, or the end of the message void put_uint32(const uint32_t l, char **ptr); -uint32_t get_uint32(char **ptr, char *end); +uint32_t get_uint32(const char **ptr, const char *end); void put_uint16(uint16_t s, char **ptr); -uint16_t get_uint16(char **ptr, char *end); +uint16_t get_uint16(const char **ptr, const char *end); #define put_flags put_uint32 #define get_flags get_uint32 @@ -301,10 +322,10 @@ uint16_t get_uint16(char **ptr, char *end); #define get_error_code get_uint32 int put_string(const char *str, char **ptr); -int get_string(char **ptr, char *end, char *buffer, int buflen); +int get_string(const char **ptr, const char *const end, char *buffer, int buflen); void put_rdata(const int rdlen, const unsigned char *rdata, char **ptr); -char *get_rdata(char **ptr, char *end, int rdlen); // return value is rdata pointed to by *ptr - +const char *get_rdata(const char **ptr, const char *end, int rdlen); // return value is rdata pointed to by *ptr - // rdata is not copied from buffer. void ConvertHeaderBytes(ipc_msg_hdr *hdr); diff --git a/mDNSShared/mDNSDebug.c b/mDNSShared/mDNSDebug.c index 4d0adbc..60154d1 100644 --- a/mDNSShared/mDNSDebug.c +++ b/mDNSShared/mDNSDebug.c @@ -23,6 +23,15 @@ Change History (most recent first): $Log: mDNSDebug.c,v $ +Revision 1.16 2009/04/11 01:43:28 jessic2 + Daemon: Should be able to turn on LogOperation dynamically + +Revision 1.15 2009/04/11 00:20:26 jessic2 + Daemon: Should be able to turn on LogOperation dynamically + +Revision 1.14 2008/11/26 00:01:08 cheshire +Get rid of "Unknown" tag in SIGINFO output on Leopard + Revision 1.13 2007/12/01 00:40:30 cheshire Fixes from Bob Bradley for building on EFI @@ -82,7 +91,8 @@ Changes necessary to support mDNSResponder on Linux. #include "mDNSEmbeddedAPI.h" -mDNSexport LogLevel_t mDNS_LogLevel = MDNS_LOG_INITIAL_LEVEL; +mDNSexport int mDNS_LoggingEnabled = 0; +mDNSexport int mDNS_PacketLoggingEnabled = 0; #if MDNS_DEBUGMSGS mDNSexport int mDNS_DebugMode = mDNStrue; @@ -92,18 +102,6 @@ mDNSexport int mDNS_DebugMode = mDNSfalse; // Note, this uses mDNS_vsnprintf instead of standard "vsnprintf", because mDNS_vsnprintf knows // how to print special data types like IP addresses and length-prefixed domain names -#if MDNS_DEBUGMSGS -mDNSexport void debugf_(const char *format, ...) - { - char buffer[512]; - va_list ptr; - va_start(ptr,format); - buffer[mDNS_vsnprintf(buffer, sizeof(buffer), format, ptr)] = 0; - va_end(ptr); - mDNSPlatformWriteDebugMsg(buffer); - } -#endif - #if MDNS_DEBUGMSGS > 1 mDNSexport void verbosedebugf_(const char *format, ...) { @@ -117,55 +115,34 @@ mDNSexport void verbosedebugf_(const char *format, ...) #endif // Log message with default "mDNSResponder" ident string at the start -mDNSexport void LogMsg(const char *format, ...) +mDNSlocal void LogMsgWithLevelv(mDNSLogLevel_t logLevel, const char *format, va_list ptr) { char buffer[512]; - va_list ptr; - va_start(ptr,format); buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0; - va_end(ptr); - mDNSPlatformWriteLogMsg(ProgramName, buffer, 0); + mDNSPlatformWriteLogMsg(ProgramName, buffer, logLevel); } -// Log message with specified ident string at the start -mDNSexport void LogMsgIdent(const char *ident, 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); - mDNSPlatformWriteLogMsg(ident, buffer, ident && *ident ? LOG_PID : 0); +#define LOG_HELPER_BODY(L) \ + { \ + va_list ptr; \ + va_start(ptr,format); \ + LogMsgWithLevelv(L, format, ptr); \ + va_end(ptr); \ } -// Log message with no ident string at the start -mDNSexport void LogMsgNoIdent(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); - mDNSPlatformWriteLogMsg("", buffer, 0); - } +// see mDNSDebug.h +#if !MDNS_HAS_VA_ARG_MACROS +void debug_noop(const char *format, ...) { (void) format; } +void LogMsg_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_MSG) +void LogOperation_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_OPERATION) +void LogSPS_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_SPS) +void LogInfo_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_INFO) +#endif -mDNSlocal const char *CStringForLogLevel(LogLevel_t level) - { - switch (level) - { - case MDNS_LOG_NONE: return "MDNS_LOG_NONE"; -// case MDNS_LOG_ERROR: return "MDNS_LOG_ERROR"; -// case MDNS_LOG_WARN: return "MDNS_LOG_WARN"; -// case MDNS_LOG_INFO: return "MDNS_LOG_INFO"; -// case MDNS_LOG_DEBUG: return "MDNS_LOG_DEBUG"; - case MDNS_LOG_VERBOSE_DEBUG: return "MDNS_LOG_VERBOSE_DEBUG"; - default: return "MDNS_LOG_UNKNOWN"; - } - } +#if MDNS_DEBUGMSGS +void debugf_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_DEBUG) +#endif -mDNSexport void SigLogLevel(void) - { - if (mDNS_LogLevel < MDNS_LOG_VERBOSE_DEBUG) mDNS_LogLevel++; - else mDNS_LogLevel = MDNS_LOG_NONE; - LogMsg("Log Level Changed to %s", CStringForLogLevel(mDNS_LogLevel)); - } +// Log message with default "mDNSResponder" ident string at the start +mDNSexport void LogMsgWithLevel(mDNSLogLevel_t logLevel, const char *format, ...) + LOG_HELPER_BODY(logLevel) diff --git a/mDNSShared/mDNSResponder.8 b/mDNSShared/mDNSResponder.8 index a94f24c..e383eb6 100644 --- a/mDNSShared/mDNSResponder.8 +++ b/mDNSShared/mDNSResponder.8 @@ -15,6 +15,12 @@ .\" limitations under the License. .\" .\" $Log: mDNSResponder.8,v $ +.\" Revision 1.10 2009/04/20 16:12:13 mcguire +.\" manpage: roff errors +.\" +.\" Revision 1.9 2009/04/11 00:20:27 jessic2 +.\" Daemon: Should be able to turn on LogOperation dynamically +.\" .\" Revision 1.8 2006/10/06 17:31:33 mkrochma .\" Typo in man page for mDNSResponder(8) .\" @@ -47,7 +53,7 @@ .\" .Sh NAME .Nm mDNSResponder -.Nd Multicast DNS daemon \" Name Description for whatis database +.Nd Multicast and Unicast DNS daemon \" Name Description for whatis database .\" .Sh SYNOPSIS .Nm @@ -57,31 +63,56 @@ (also known as .Nm mdnsd on some systems) -is a daemon invoked at boot time to implement Multicast DNS -and DNS Service Discovery. +is a daemon invoked at boot time to implement Multicast DNS and DNS Service Discovery. On +Mac OS X 10.6 (Snow Leopard), +.Nm +is also the system-wide Unicast DNS Resolver. .Pp .Nm -listens UDP port 5353 for Multicast DNS Query packets. +listens on UDP port 5353 for Multicast DNS Query packets. When it receives a query for which it knows an answer, .Nm issues the appropriate Multicast DNS Reply packet. .Pp .Nm -also performs Multicast DNS Queries on behalf of client processes, -and maintains a cache of the replies. +also performs Unicast and Multicast DNS Queries on behalf of client processes, and +maintains a cache of the replies. .Pp .Nm has no user-specifiable command-line argument, and users should not run .Nm manually. .Pp -To examine -.Nm Ns 's internal state, for debugging and diagnostic purposes, -send it a SIGINFO signal, and it will then dump a snapshot summary -of its internal state to -.Pa /var/log/system.log Ns , e.g. +.Ss LOGGING +There are several methods with which to examine +.Nm Ns 's internal state for debugging and diagnostic purposes. The syslog(1) +logging levels map as follows: +.Pp +.Dl Error - Error messages +.Dl Warning - Client-initiated operations +.Dl Notice - Sleep proxy operations +.Dl Info - Informational messages +.Pp +By default, only log level Error is logged. +.Pp +A SIGUSR1 signal toggles additional logging, with Warning and Notice +enabled by default: +.Pp +.Dl % sudo killall -USR1 mDNSResponder +.Pp +Once this logging is enabled, users can additionally use syslog(1) +to change the log filter for the process. For example, to enable log levels Emergency - Debug: +.Pp +.Dl % sudo syslog -c mDNSResponder -d +.Pp +A SIGUSR2 signal toggles packet logging: +.Pp +.Dl % sudo killall -USR2 mDNSResponder +.Pp +A SIGINFO signal will dump a snapshot summary of the internal state to +.Pa /var/log/system.log Ns : .Pp -.Dl sudo killall -INFO mDNSResponder +.Dl % sudo killall -INFO mDNSResponder .Sh FILES .Pa /usr/sbin/mDNSResponder \" Pathname .\" diff --git a/mDNSShared/uds_daemon.c b/mDNSShared/uds_daemon.c index a01eb08..dfae86e 100644 --- a/mDNSShared/uds_daemon.c +++ b/mDNSShared/uds_daemon.c @@ -17,6 +17,236 @@ Change History (most recent first): $Log: uds_daemon.c,v $ +Revision 1.461 2009/06/19 23:15:07 cheshire + Library: crash at handle_resolve_response + 183 +Made resolve_result_callback code more defensive and improved LogOperation messages + +Revision 1.460 2009/05/26 21:31:07 herscher +Fix compile errors on Windows + +Revision 1.459 2009/04/30 20:07:51 mcguire + Support multiple UDSs from launchd + +Revision 1.458 2009/04/25 00:59:06 mcguire +Change a few stray LogInfo to LogOperation + +Revision 1.457 2009/04/22 01:19:57 jessic2 + Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32 + +Revision 1.456 2009/04/21 01:56:34 jessic2 + BTMM: Back out change for preventing other local users from sending packets to your BTMM machines + +Revision 1.455 2009/04/20 19:19:57 cheshire + BTMM: If multiple local users are logged in to same BTMM account, all but one fail +Don't need "empty info->u.browser.browsers list" debugging message, now that we expect this to be +a case that can legitimately happen. + +Revision 1.454 2009/04/18 20:56:43 jessic2 + BTMM: If multiple local users are logged in to same BTMM account, all but one fail + +Revision 1.453 2009/04/11 00:20:29 jessic2 + Daemon: Should be able to turn on LogOperation dynamically + +Revision 1.452 2009/04/07 01:17:42 jessic2 + BTMM: Multiple accounts lets me see others' remote services & send packets to others' remote hosts + +Revision 1.451 2009/04/02 22:34:26 jessic2 + Race condition: If fd has already been closed, SO_NOSIGPIPE returns errno 22 (Invalid argument) + +Revision 1.450 2009/04/01 21:11:28 herscher + Current Bonjour code does not compile on Windows. Workaround use of recvmsg. + +Revision 1.449 2009/03/17 19:44:25 cheshire + Don't let negative unicast answers block Multicast DNS responses + +Revision 1.448 2009/03/17 04:53:40 cheshire + Don't let negative unicast answers block Multicast DNS responses + +Revision 1.447 2009/03/17 04:41:32 cheshire +Moved LogOperation message to after check for "if (answer->RecordType == kDNSRecordTypePacketNegative)" + +Revision 1.446 2009/03/04 01:47:35 cheshire +Include m->ProxyRecords in SIGINFO output + +Revision 1.445 2009/03/03 23:04:44 cheshire +For clarity, renamed "MAC" field to "HMAC" (Host MAC, as opposed to Interface MAC) + +Revision 1.444 2009/03/03 22:51:55 cheshire + Sleep Proxy: Waking on same network but different interface will cause conflicts + +Revision 1.443 2009/02/27 02:28:41 cheshire +Need to declare "const AuthRecord *ar;" + +Revision 1.442 2009/02/27 00:58:17 cheshire +Improved detail of SIGINFO logging for m->DuplicateRecords + +Revision 1.441 2009/02/24 22:18:59 cheshire +Include interface name for interface-specific AuthRecords + +Revision 1.440 2009/02/21 01:38:08 cheshire +Added report of m->SleepState value in SIGINFO output + +Revision 1.439 2009/02/18 23:38:44 cheshire + Could not write data to client 13 - aborting connection +Eliminated unnecessary "request_state *request" field from the reply_state structure. + +Revision 1.438 2009/02/18 23:23:14 cheshire +Cleaned up debugging log messages + +Revision 1.437 2009/02/17 23:29:05 cheshire +Throttle logging to a slower rate when running on SnowLeopard + +Revision 1.436 2009/02/13 06:28:02 cheshire +Converted LogOperation messages to LogInfo + +Revision 1.435 2009/02/12 20:57:26 cheshire +Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch + +Revision 1.434 2009/02/12 20:28:31 cheshire +Added some missing "const" declarations + +Revision 1.433 2009/02/10 01:44:39 cheshire + DNSServiceUpdateRecord fails with kDNSServiceErr_BadReference for otherwise valid reference + +Revision 1.432 2009/02/10 01:38:56 cheshire +Move regservice_termination_callback() earlier in file in preparation for subsequent work + +Revision 1.431 2009/02/07 01:48:55 cheshire +In SIGINFO output include sequence number for proxied records + +Revision 1.430 2009/01/31 21:58:05 cheshire + Implement logic to determine when to send dot-local lookups via Unicast +Only want to do unicast dot-local lookups for address queries and conventional (RFC 2782) SRV queries + +Revision 1.429 2009/01/31 00:45:26 cheshire + Implement logic to determine when to send dot-local lookups via Unicast +Further refinements + +Revision 1.428 2009/01/30 19:52:31 cheshire +Eliminated unnecessary duplicated "dnssd_sock_t sd" fields in service_instance and reply_state structures + +Revision 1.427 2009/01/24 01:48:43 cheshire + Implement logic to determine when to send dot-local lookups via Unicast + +Revision 1.426 2009/01/16 21:07:08 cheshire +In SIGINFO "Duplicate Records" list, show expiry time for Sleep Proxy records + +Revision 1.425 2009/01/16 20:53:16 cheshire +Include information about Sleep Proxy records in SIGINFO output + +Revision 1.424 2009/01/12 22:43:50 cheshire +Fixed "unused variable" warning when SO_NOSIGPIPE is not defined + +Revision 1.423 2009/01/10 22:54:42 mkrochma + Fixes from Igor Seleznev to get mdnsd working on Linux + +Revision 1.422 2009/01/10 01:52:48 cheshire +Include DuplicateRecords and LocalOnlyQuestions in SIGINFO output + +Revision 1.421 2008/12/17 05:05:26 cheshire +Fixed alignment of NAT mapping syslog messages + +Revision 1.420 2008/12/12 00:52:05 cheshire +mDNSPlatformSetBPF is now called mDNSPlatformReceiveBPF_fd + +Revision 1.419 2008/12/10 02:11:44 cheshire +ARMv5 compiler doesn't like uncommented stuff after #endif + +Revision 1.418 2008/12/09 05:12:53 cheshire +Updated debugging messages + +Revision 1.417 2008/12/04 03:38:12 cheshire +Miscellaneous defensive coding changes and improvements to debugging log messages + +Revision 1.416 2008/12/02 22:02:12 cheshire + Adding domains after TXT record updates registers stale TXT record data + +Revision 1.415 2008/11/26 20:35:59 cheshire +Changed some "LogOperation" debugging messages to "debugf" + +Revision 1.414 2008/11/26 00:02:25 cheshire +Improved SIGINFO output to list AutoBrowseDomains and AutoRegistrationDomains + +Revision 1.413 2008/11/25 04:48:58 cheshire +Added logging to show whether Sleep Proxy Service is active + +Revision 1.412 2008/11/24 23:05:43 cheshire +Additional checking in uds_validatelists() + +Revision 1.411 2008/11/05 21:41:39 cheshire +Updated LogOperation message + +Revision 1.410 2008/11/04 20:06:20 cheshire + Change MAX_DOMAIN_NAME to 256 + +Revision 1.409 2008/10/31 23:44:22 cheshire +Fixed compile error in Posix build + +Revision 1.408 2008/10/29 21:32:33 cheshire +Align "DNSServiceEnumerateDomains ... RESULT" log messages + +Revision 1.407 2008/10/27 07:34:36 cheshire +Additional sanity checks for debugging + +Revision 1.406 2008/10/23 23:55:56 cheshire +Fixed some missing "const" declarations + +Revision 1.405 2008/10/23 23:21:31 cheshire +Moved definition of dnssd_strerror() to be with the definition of dnssd_errno, in dnssd_ipc.h + +Revision 1.404 2008/10/23 23:06:17 cheshire +Removed () from dnssd_errno macro definition -- it's not a function and doesn't need any arguments + +Revision 1.403 2008/10/23 22:33:25 cheshire +Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu + +Revision 1.402 2008/10/22 19:47:59 cheshire +Instead of SameRData(), use equivalent IdenticalSameNameRecord() macro + +Revision 1.401 2008/10/22 17:20:40 cheshire +Don't give up if setsockopt SO_NOSIGPIPE fails + +Revision 1.400 2008/10/21 01:06:57 cheshire +Pass BPF fd to mDNSMacOSX.c using mDNSPlatformSetBPF() instead of just writing it into a shared global variable + +Revision 1.399 2008/10/20 22:06:42 cheshire +Updated debugging log messages + +Revision 1.398 2008/10/03 18:25:17 cheshire +Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);" + +Revision 1.397 2008/10/02 22:26:21 cheshire +Moved declaration of BPF_fd from uds_daemon.c to mDNSMacOSX.c, where it really belongs + +Revision 1.396 2008/09/30 01:04:55 cheshire +Made BPF code a bit more defensive, to ignore subsequent BPF fds if we get passed more than one + +Revision 1.395 2008/09/27 01:28:43 cheshire +Added code to receive and store BPF fd when passed via a send_bpf message + +Revision 1.394 2008/09/23 04:12:40 cheshire + Remove "local" from the end of _services._dns-sd._udp PTR records +Added a special-case to massage these new records for Bonjour Browser's benefit + +Revision 1.393 2008/09/23 03:01:58 cheshire +Added operation logging of domain enumeration results + +Revision 1.392 2008/09/18 22:30:06 cheshire + device-info record not removed when last service deregisters + +Revision 1.391 2008/09/18 22:05:44 cheshire +Fixed "DNSServiceRegister ... ADDED" message to have escaping consistent with +the other DNSServiceRegister operation messages + +Revision 1.390 2008/09/16 21:06:56 cheshire +Improved syslog output to show if q->LongLived flag is set for multicast questions + +Revision 1.389 2008/07/25 22:34:11 mcguire +fix sizecheck issues for 64bit + +Revision 1.388 2008/07/01 01:40:02 mcguire + 64-bit fixes + Revision 1.387 2008/02/26 21:24:13 cheshire Fixed spelling mistake in comment @@ -51,7 +281,7 @@ Revision 1.377 2007/10/30 23:48:20 cheshire Improved SIGINFO listing of question state Revision 1.376 2007/10/30 20:43:54 cheshire -Fixed compiler warning when LogAllOperations is turned off +Fixed compiler warning when LogClientOperations is turned off Revision 1.375 2007/10/26 22:51:38 cheshire Improved SIGINFO output to show timers for AuthRecords and ServiceRegistrations @@ -656,29 +886,7 @@ Revision 1.189 2006/01/06 00:56:31 cheshire #if defined(_WIN32) #include -#define dnssd_strerror(X) win32_strerror(X) #define usleep(X) Sleep(((X)+999)/1000) -mDNSlocal char *win32_strerror(int inErrorCode) - { - static char buffer[1024]; - DWORD n; - memset(buffer, 0, sizeof(buffer)); - n = FormatMessageA( - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - (DWORD) inErrorCode, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - buffer, - sizeof(buffer), - NULL); - if (n > 0) - { - // Remove any trailing CR's or LF's since some messages have them. - while ((n > 0) && isspace(((unsigned char *) buffer)[n - 1])) - buffer[--n] = '\0'; - } - return buffer; - } #else #include #include @@ -686,11 +894,11 @@ mDNSlocal char *win32_strerror(int inErrorCode) #include #include #include -#define dnssd_strerror(X) strerror(X) #endif #include #include + #include "mDNSEmbeddedAPI.h" #include "DNSCommon.h" #include "uDNS.h" @@ -732,7 +940,7 @@ typedef struct registered_record_entry struct registered_record_entry *next; mDNSu32 key; AuthRecord *rr; // Pointer to variable-sized AuthRecord - client_context_t client_context; + client_context_t regrec_client_context; request_state *request; } registered_record_entry; @@ -743,7 +951,6 @@ typedef struct service_instance { struct service_instance *next; request_state *request; - dnssd_sock_t sd; AuthRecord *subtypes; mDNSBool renameonmemfree; // Set on config change when we deregister original name mDNSBool clientnotified; // Has client been notified of successful registration yet? @@ -763,22 +970,22 @@ typedef struct browser_t struct request_state { request_state *next; - request_state *primary; // If this operation is on a shared socket, pointer to - // primary request_state for the original DNSServiceConnect() operation + request_state *primary; // If this operation is on a shared socket, pointer to primary + // request_state for the original DNSServiceConnect() operation dnssd_sock_t sd; dnssd_sock_t errsd; mDNSu32 uid; - // NOTE: On a shared connection these fields in the primary structure, including hdr, are re-used + // Note: On a shared connection these fields in the primary structure, including hdr, are re-used // for each new request. This is because, until we've read the ipc_msg_hdr to find out what the // operation is, we don't know if we're going to need to allocate a new request_state or not. transfer_state ts; - mDNSu32 hdr_bytes; // bytes of header already read - ipc_msg_hdr hdr; - mDNSu32 data_bytes; // bytes of message data already read - char *msgbuf; // pointer to data storage to pass to free() - char *msgptr; // pointer to data to be read from (may be modified) - char *msgend; // pointer to byte after last byte of message + mDNSu32 hdr_bytes; // bytes of header already read + ipc_msg_hdr hdr; + mDNSu32 data_bytes; // bytes of message data already read + char *msgbuf; // pointer to data storage to pass to free() + const char *msgptr; // pointer to data to be read from (may be modified) + char *msgend; // pointer to byte after last byte of message // reply, termination, error, and client context info int no_reply; // don't send asynchronous replies to client @@ -829,12 +1036,16 @@ struct request_state } pm; struct { +#if 0 + DNSServiceFlags flags; +#endif DNSQuestion q_all; DNSQuestion q_default; } enumeration; struct { DNSQuestion q; + DNSQuestion q2; } queryrecord; struct { @@ -844,7 +1055,6 @@ struct request_state const ResourceRecord *srv; mDNSs32 ReportTime; } resolve; - ; } u; }; @@ -858,16 +1068,11 @@ typedef struct typedef struct reply_state { - dnssd_sock_t sd; - transfer_state ts; + struct reply_state *next; // If there are multiple unsent replies + mDNSu32 totallen; mDNSu32 nwriten; - mDNSu32 len; - request_state *request; // the request that this answers - struct reply_state *next; // if there are multiple unsent replies - char *msgbuf; // pointer to malloc'd buffer - ipc_msg_hdr *mhdr; // pointer into message buffer - allows fields to be changed after message is formatted - reply_hdr *rhdr; - char *sdata; // pointer to start of call-specific data + ipc_msg_hdr mhdr[1]; + reply_hdr rhdr[1]; } reply_state; // *************************************************************************** @@ -906,7 +1111,7 @@ mDNSexport DNameListElem *AutoRegistrationDomains; // Domains where we automatic mDNSlocal void FatalError(char *errmsg) { - LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno())); + LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno)); *(long*)0 = 0; // On OS X abort() doesn't generate a crash log, but writing to zero does abort(); // On platforms where writing to zero doesn't generate an exception, abort instead } @@ -922,15 +1127,21 @@ mDNSlocal mDNSu32 dnssd_htonl(mDNSu32 l) // hack to search-replace perror's to LogMsg's mDNSlocal void my_perror(char *errmsg) { - LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno())); + LogMsg("%s: %d (%s)", errmsg, dnssd_errno, dnssd_strerror(dnssd_errno)); } mDNSlocal void abort_request(request_state *req) { + if (req->terminate == (req_termination_fn)~0) + { LogMsg("abort_request: ERROR: Attempt to abort operation %p with req->terminate %p", req, req->terminate); return; } + // First stop whatever mDNSCore operation we were doing if (req->terminate) req->terminate(req); - // Now, if this request_state is not subbordinate to some other primary, close file descriptor and discard replies + if (!dnssd_SocketValid(req->sd)) + { LogMsg("abort_request: ERROR: Attempt to abort operation %p with invalid fd %d", req, req->sd); return; } + + // Now, if this request_state is not subordinate to some other primary, close file descriptor and discard replies if (!req->primary) { if (req->errsd != req->sd) LogOperation("%3d: Removing FD and closing errsd %d", req->sd, req->errsd); @@ -942,19 +1153,20 @@ mDNSlocal void abort_request(request_state *req) { reply_state *ptr = req->replies; req->replies = req->replies->next; - if (ptr->msgbuf) freeL("reply_state msgbuf (abort)", ptr->msgbuf); freeL("reply_state (abort)", ptr); } } -// Set req->sd to something invalid, so that udsserver_idle knows to unlink and free this structure + // Set req->sd to something invalid, so that udsserver_idle knows to unlink and free this structure #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING // Don't use dnssd_InvalidSocket (-1) because that's the sentinel value MACOSX_MDNS_MALLOC_DEBUGGING uses // for detecting when the memory for an object is inadvertently freed while the object is still on some list - req->sd = -2; + req->sd = req->errsd = -2; #else - req->sd = dnssd_InvalidSocket; + req->sd = req->errsd = dnssd_InvalidSocket; #endif + // We also set req->terminate to a bogus value so we know if abort_request() gets called again for this request + req->terminate = (req_termination_fn)~0; } mDNSlocal void AbortUnlinkAndFree(request_state *req) @@ -963,38 +1175,33 @@ mDNSlocal void AbortUnlinkAndFree(request_state *req) abort_request(req); while (*p && *p != req) p=&(*p)->next; if (*p) { *p = req->next; freeL("request_state/AbortUnlinkAndFree", req); } + else LogMsg("AbortUnlinkAndFree: ERROR: Attempt to abort operation %p not in list", req); } mDNSlocal reply_state *create_reply(const reply_op_t op, const size_t datalen, request_state *const request) { reply_state *reply; - int totallen = (int) (datalen + sizeof(ipc_msg_hdr)); if ((unsigned)datalen < sizeof(reply_hdr)) { - LogMsg("ERROR: create_reply - data length less than lenght of required fields"); + LogMsg("ERROR: create_reply - data length less than length of required fields"); return NULL; } - reply = mallocL("reply_state", sizeof(reply_state)); + reply = mallocL("reply_state", sizeof(reply_state) + datalen - sizeof(reply_hdr)); if (!reply) FatalError("ERROR: malloc"); - mDNSPlatformMemZero(reply, sizeof(reply_state)); - reply->ts = t_morecoming; - reply->sd = request->sd; - reply->request = request; - reply->len = totallen; - reply->msgbuf = mallocL("reply_state msgbuf", totallen); - if (!reply->msgbuf) FatalError("ERROR: malloc"); - mDNSPlatformMemZero(reply->msgbuf, totallen); - reply->mhdr = (ipc_msg_hdr *)reply->msgbuf; - reply->rhdr = (reply_hdr *)(reply->msgbuf + sizeof(ipc_msg_hdr)); - reply->sdata = reply->msgbuf + sizeof(ipc_msg_hdr) + sizeof(reply_hdr); - reply->mhdr->version = VERSION; - reply->mhdr->datalen = datalen; - reply->mhdr->ipc_flags = 0; - reply->mhdr->op = op; + + reply->next = mDNSNULL; + reply->totallen = datalen + sizeof(ipc_msg_hdr); + reply->nwriten = 0; + + reply->mhdr->version = VERSION; + reply->mhdr->datalen = datalen; + reply->mhdr->ipc_flags = 0; + reply->mhdr->op = op; reply->mhdr->client_context = request->hdr.client_context; - reply->mhdr->reg_index = 0; + reply->mhdr->reg_index = 0; + return reply; } @@ -1047,7 +1254,7 @@ mDNSlocal mStatus GenerateNTDResponse(const domainname *const servicename, const (*rep)->rhdr->error = dnssd_htonl(err); // Build reply body - data = (*rep)->sdata; + data = (char *)&(*rep)->rhdr[1]; put_string(namestr, &data); put_string(typestr, &data); put_string(domstr, &data); @@ -1056,6 +1263,46 @@ mDNSlocal mStatus GenerateNTDResponse(const domainname *const servicename, const } } +// Special support to enable the DNSServiceBrowse call made by Bonjour Browser +// Remove after Bonjour Browser is updated to use DNSServiceQueryRecord instead of DNSServiceBrowse +mDNSlocal void GenerateBonjourBrowserResponse(const domainname *const servicename, const mDNSInterfaceID id, + request_state *const request, reply_state **const rep, reply_op_t op, DNSServiceFlags flags, mStatus err) + { + char namestr[MAX_DOMAIN_LABEL+1]; + char typestr[MAX_ESCAPED_DOMAIN_NAME]; + static const char domstr[] = "."; + int len; + char *data; + + *rep = NULL; + + // 1. Put first label in namestr + ConvertDomainLabelToCString_unescaped((const domainlabel *)servicename, namestr); + + // 2. Put second label and "local" into typestr + mDNS_snprintf(typestr, sizeof(typestr), "%#s.local.", SecondLabel(servicename)); + + // Calculate reply data length + len = sizeof(DNSServiceFlags); + len += sizeof(mDNSu32); // if index + len += sizeof(DNSServiceErrorType); + len += (int) (strlen(namestr) + 1); + len += (int) (strlen(typestr) + 1); + len += (int) (strlen(domstr) + 1); + + // Build reply header + *rep = create_reply(op, len, request); + (*rep)->rhdr->flags = dnssd_htonl(flags); + (*rep)->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(&mDNSStorage, id)); + (*rep)->rhdr->error = dnssd_htonl(err); + + // Build reply body + data = (char *)&(*rep)->rhdr[1]; + put_string(namestr, &data); + put_string(typestr, &data); + put_string(domstr, &data); + } + // Returns a resource record (allocated w/ malloc) containing the data found in an IPC message // Data must be in the following format: flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional) ttl // (ttl only extracted/set if ttl argument is non-zero). Returns NULL for a bad-parameter error @@ -1064,11 +1311,11 @@ mDNSlocal AuthRecord *read_rr_from_ipc_msg(request_state *request, int GetTTL, i DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend); mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend); char name[256]; - int str_err = get_string(&request->msgptr, request->msgend, name, sizeof(name)); - mDNSu16 type = get_uint16(&request->msgptr, request->msgend); - mDNSu16 class = get_uint16(&request->msgptr, request->msgend); - mDNSu16 rdlen = get_uint16(&request->msgptr, request->msgend); - char *rdata = get_rdata(&request->msgptr, request->msgend, rdlen); + int str_err = get_string(&request->msgptr, request->msgend, name, sizeof(name)); + mDNSu16 type = get_uint16(&request->msgptr, request->msgend); + mDNSu16 class = get_uint16(&request->msgptr, request->msgend); + mDNSu16 rdlen = get_uint16(&request->msgptr, request->msgend); + const char *rdata = get_rdata (&request->msgptr, request->msgend, rdlen); mDNSu32 ttl = GetTTL ? get_uint32(&request->msgptr, request->msgend) : 0; int storage_size = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody); AuthRecord *rr; @@ -1127,10 +1374,39 @@ mDNSlocal void send_all(dnssd_sock_t s, const char *ptr, int len) // (four bytes for a typical error code return, 12 bytes for DNSServiceGetProperty(DaemonVersion)). // If it does fail, we don't attempt to handle this failure, but we do log it so we know something is wrong. if (n < len) - LogMsg("ERROR: send_all(%d) wrote %d of %d errno %d %s", - s, n, len, dnssd_errno(), dnssd_strerror(dnssd_errno())); + LogMsg("ERROR: send_all(%d) wrote %d of %d errno %d (%s)", + s, n, len, dnssd_errno, dnssd_strerror(dnssd_errno)); } +#if 0 +mDNSlocal mDNSBool AuthorizedDomain(const request_state * const request, const domainname * const d, const DNameListElem * const doms) +{ + const DNameListElem *delem = mDNSNULL; + int bestDelta = -1; // the delta of the best match, lower is better + int dLabels = 0; + mDNSBool allow = mDNSfalse; + + if (SystemUID(request->uid)) return mDNStrue; + + dLabels = CountLabels(d); + for (delem = doms; delem; delem = delem->next) + { + if (delem->uid) + { + int delemLabels = CountLabels(&delem->name); + int delta = dLabels - delemLabels; + if ((bestDelta == -1 || delta <= bestDelta) && SameDomainName(&delem->name, SkipLeadingLabels(d, delta))) + { + bestDelta = delta; + allow = (allow || (delem->uid == request->uid)); + } + } + } + + return bestDelta == -1 ? mDNStrue : allow; +} +#endif + // *************************************************************************** #if COMPILER_LIKES_PRAGMA_MARK #pragma mark - @@ -1140,11 +1416,11 @@ mDNSlocal void send_all(dnssd_sock_t s, const char *ptr, int len) mDNSexport void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result) { ExtraResourceRecord *extra = (ExtraResourceRecord *)rr->RecordContext; - (void)m; //unused + (void)m; // Unused if (result != mStatus_MemFree) { LogMsg("Error: FreeExtraRR invoked with unexpected error %d", result); return; } - LogOperation(" FreeExtraRR %s", RRDisplayString(m, &rr->resrec)); + LogInfo(" FreeExtraRR %s", RRDisplayString(m, &rr->resrec)); if (rr->resrec.rdata != &rr->rdatastorage) freeL("Extra RData", rr->resrec.rdata); @@ -1192,11 +1468,11 @@ mDNSexport int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs ServiceRecordSet *s; for (rr = m->ResourceRecords; rr; rr=rr->next) - if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !SameRData(&rr->resrec, r)) + if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !IdenticalSameNameRecord(&rr->resrec, r)) count++; for (s = m->ServiceRegistrations; s; s = s->uDNS_next) - if (s->state != regState_Unregistered && SameDomainName(s->RR_SRV.resrec.name, r->name) && !SameRData(&s->RR_SRV.resrec, r)) + if (s->state != regState_Unregistered && SameDomainName(s->RR_SRV.resrec.name, r->name) && !IdenticalSameNameRecord(&s->RR_SRV.resrec, r)) count++; verbosedebugf("%d peer registrations for %##s", count, r->name->c); @@ -1220,25 +1496,24 @@ mDNSlocal void SendServiceRemovalNotification(ServiceRecordSet *const srs) reply_state *rep; service_instance *instance = srs->ServiceContext; if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, 0, mStatus_NoError) != mStatus_NoError) - LogMsg("%3d: SendServiceRemovalNotification: %##s is not valid DNS-SD SRV name", instance->sd, srs->RR_SRV.resrec.name->c); + LogMsg("%3d: SendServiceRemovalNotification: %##s is not valid DNS-SD SRV name", instance->request->sd, srs->RR_SRV.resrec.name->c); else { append_reply(instance->request, rep); instance->clientnotified = mDNSfalse; } } // service registration callback performs three duties - frees memory for deregistered services, -// handles name conflicts, and delivers completed registration information to the client (via -// process_service_registraion()) +// handles name conflicts, and delivers completed registration information to the client mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result) { mStatus err; mDNSBool SuppressError = mDNSfalse; service_instance *instance = srs->ServiceContext; reply_state *rep; -#if LogAllOperations || MDNS_DEBUGMSGS - char *fmt = (result == mStatus_NoError) ? "%3d: DNSServiceRegister(%##s, %u) REGISTERED" : - (result == mStatus_MemFree) ? "%3d: DNSServiceRegister(%##s, %u) DEREGISTERED" : - (result == mStatus_NameConflict) ? "%3d: DNSServiceRegister(%##s, %u) NAME CONFLICT" : - "%3d: DNSServiceRegister(%##s, %u) %s %d"; -#endif + char *fmt = ""; + if (mDNS_LoggingEnabled) + fmt = (result == mStatus_NoError) ? "%3d: DNSServiceRegister(%##s, %u) REGISTERED" : + (result == mStatus_MemFree) ? "%3d: DNSServiceRegister(%##s, %u) DEREGISTERED" : + (result == mStatus_NameConflict) ? "%3d: DNSServiceRegister(%##s, %u) NAME CONFLICT" : + "%3d: DNSServiceRegister(%##s, %u) %s %d"; (void)m; // Unused if (!srs) { LogMsg("regservice_callback: srs is NULL %d", result); return; } if (!instance) { LogMsg("regservice_callback: srs->ServiceContext is NULL %d", result); return; } @@ -1249,7 +1524,8 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m !instance->default_local) SuppressError = mDNStrue; - LogOperation(fmt, instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port), SuppressError ? "suppressed error" : "CALLBACK", result); + LogOperation(fmt, instance->request ? instance->request->sd : -99, + srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port), SuppressError ? "suppressed error" : "CALLBACK", result); if (!instance->request && result != mStatus_MemFree) { LogMsg("regservice_callback: instance->request is NULL %d", result); return; } @@ -1266,7 +1542,7 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m } if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError) - LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", instance->sd, srs->RR_SRV.resrec.name->c); + LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", instance->request->sd, srs->RR_SRV.resrec.name->c); else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; } if (instance->request->u.servicereg.autoname && CountPeerRegistrations(m, srs) == 0) @@ -1278,7 +1554,7 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m { instance->renameonmemfree = 0; err = mDNS_RenameAndReregisterService(m, srs, &instance->request->u.servicereg.name); - if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %ld", err); + if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %d", err); // error should never happen - safest to log and continue } else @@ -1292,7 +1568,7 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m { // On conflict for an autoname service, rename and reregister *all* autoname services IncrementLabelSuffix(&m->nicelabel, mDNStrue); - m->MainCallback(m, mStatus_ConfigChanged); // will call back into udsserver_handle_configchange() + mDNS_ConfigChanged(m); // Will call back into udsserver_handle_configchange() } else // On conflict for a non-autoname service, rename and reregister just that one service { @@ -1305,7 +1581,7 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m if (!SuppressError) { if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError) - LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", instance->sd, srs->RR_SRV.resrec.name->c); + LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", instance->request->sd, srs->RR_SRV.resrec.name->c); else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; } } unlink_and_free_service_instance(instance); @@ -1316,7 +1592,7 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m if (!SuppressError) { if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, instance->request, &rep, reg_service_reply_op, kDNSServiceFlagsAdd, result) != mStatus_NoError) - LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", instance->sd, srs->RR_SRV.resrec.name->c); + LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", instance->request->sd, srs->RR_SRV.resrec.name->c); else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; } } } @@ -1341,7 +1617,7 @@ mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord *rr, mStatus result) request_state *request = re->request; int len = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + sizeof(DNSServiceErrorType); reply_state *reply = create_reply(reg_record_reply_op, len, request); - reply->mhdr->client_context = re->client_context; + reply->mhdr->client_context = re->regrec_client_context; reply->rhdr->flags = dnssd_htonl(0); reply->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, rr->resrec.InterfaceID)); reply->rhdr->error = dnssd_htonl(result); @@ -1370,6 +1646,8 @@ mDNSlocal void connection_termination(request_state *request) { // Since we're already doing a list traversal, we unlink the request directly instead of using AbortUnlinkAndFree() request_state *tmp = *req; + if (tmp->primary == tmp) LogMsg("connection_termination ERROR (*req)->primary == *req for %p %d", tmp, tmp->sd); + if (tmp->replies) LogMsg("connection_termination ERROR How can subordinate req %p %d have replies queued?", tmp, tmp->sd); abort_request(tmp); *req = tmp->next; freeL("request_state/connection_termination", tmp); @@ -1391,7 +1669,7 @@ mDNSlocal void connection_termination(request_state *request) mDNSlocal void handle_cancel_request(request_state *request) { request_state **req = &all_requests; - LogOperation("%3d: Cancel %X%08X", request->sd, request->hdr.client_context.u32[1], request->hdr.client_context.u32[0]); + LogOperation("%3d: Cancel %08X %08X", request->sd, request->hdr.client_context.u32[1], request->hdr.client_context.u32[0]); while (*req) { if ((*req)->primary == request && @@ -1421,12 +1699,15 @@ mDNSlocal mStatus handle_regrecord_request(request_state *request) re->key = request->hdr.reg_index; re->rr = rr; re->request = request; - re->client_context = request->hdr.client_context; + re->regrec_client_context = request->hdr.client_context; rr->RecordContext = re; rr->RecordCallback = regrecord_callback; re->next = request->u.reg_recs; request->u.reg_recs = re; +#if 0 + if (!AuthorizedDomain(request, rr->resrec.name, AutoRegistrationDomains)) return (mStatus_NoError); +#endif if (rr->resrec.rroriginalttl == 0) rr->resrec.rroriginalttl = DefaultTTLforRRType(rr->resrec.rrtype); @@ -1436,7 +1717,49 @@ mDNSlocal mStatus handle_regrecord_request(request_state *request) return(err); } -mDNSlocal mStatus add_record_to_service(request_state *request, service_instance *instance, mDNSu16 rrtype, mDNSu16 rdlen, char *rdata, mDNSu32 ttl) +mDNSlocal void UpdateDeviceInfoRecord(mDNS *const m); + +mDNSlocal void regservice_termination_callback(request_state *request) + { + if (!request) { LogMsg("regservice_termination_callback context is NULL"); return; } + while (request->u.servicereg.instances) + { + service_instance *p = request->u.servicereg.instances; + request->u.servicereg.instances = request->u.servicereg.instances->next; + // only safe to free memory if registration is not valid, i.e. deregister fails (which invalidates p) + LogOperation("%3d: DNSServiceRegister(%##s, %u) STOP", + request->sd, p->srs.RR_SRV.resrec.name->c, mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port)); + + // Clear backpointer *before* calling mDNS_DeregisterService/unlink_and_free_service_instance + // We don't need unlink_and_free_service_instance to cut its element from the list, because we're already advancing + // request->u.servicereg.instances as we work our way through the list, implicitly cutting one element at a time + // We can't clear p->request *after* the calling mDNS_DeregisterService/unlink_and_free_service_instance + // because by then we might have already freed p + p->request = NULL; + if (mDNS_DeregisterService(&mDNSStorage, &p->srs)) unlink_and_free_service_instance(p); + // Don't touch service_instance *p after this -- it's likely to have been freed already + } + if (request->u.servicereg.txtdata) + { freeL("service_info txtdata", request->u.servicereg.txtdata); request->u.servicereg.txtdata = NULL; } + if (request->u.servicereg.autoname) + { + // Clear autoname before calling UpdateDeviceInfoRecord() so it doesn't mistakenly include this in its count of active autoname registrations + request->u.servicereg.autoname = mDNSfalse; + UpdateDeviceInfoRecord(&mDNSStorage); + } + } + +mDNSlocal request_state *LocateSubordinateRequest(request_state *request) + { + request_state *req; + for (req = all_requests; req; req = req->next) + if (req->primary == request && + req->hdr.client_context.u32[0] == request->hdr.client_context.u32[0] && + req->hdr.client_context.u32[1] == request->hdr.client_context.u32[1]) return(req); + return(request); + } + +mDNSlocal mStatus add_record_to_service(request_state *request, service_instance *instance, mDNSu16 rrtype, mDNSu16 rdlen, const char *rdata, mDNSu32 ttl) { ServiceRecordSet *srs = &instance->srs; mStatus result; @@ -1461,16 +1784,22 @@ mDNSlocal mStatus handle_add_request(request_state *request) { service_instance *i; mStatus result = mStatus_UnknownErr; - DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend); - mDNSu16 rrtype = get_uint16(&request->msgptr, request->msgend); - mDNSu16 rdlen = get_uint16(&request->msgptr, request->msgend); - char *rdata = get_rdata(&request->msgptr, request->msgend, rdlen); - mDNSu32 ttl = get_uint32(&request->msgptr, request->msgend); + DNSServiceFlags flags = get_flags (&request->msgptr, request->msgend); + mDNSu16 rrtype = get_uint16(&request->msgptr, request->msgend); + mDNSu16 rdlen = get_uint16(&request->msgptr, request->msgend); + const char *rdata = get_rdata (&request->msgptr, request->msgend, rdlen); + mDNSu32 ttl = get_uint32(&request->msgptr, request->msgend); if (!ttl) ttl = DefaultTTLforRRType(rrtype); (void)flags; // Unused if (!request->msgptr) { LogMsg("%3d: DNSServiceAddRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); } + // If this is a shared connection, check if the operation actually applies to a subordinate request_state object + if (request->terminate == connection_termination) request = LocateSubordinateRequest(request); + + if (request->terminate != regservice_termination_callback) + { LogMsg("%3d: DNSServiceAddRecord(not a registered service ref)", request->sd); return(mStatus_BadParamErr); } + LogOperation("%3d: DNSServiceAddRecord(%##s, %s, %d)", request->sd, (request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL, DNSTypeName(rrtype), rdlen); @@ -1490,7 +1819,7 @@ mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd if (oldrd != &rr->rdatastorage) freeL("RData/update_callback", oldrd); } -mDNSlocal mStatus update_record(AuthRecord *rr, mDNSu16 rdlen, char *rdata, mDNSu32 ttl) +mDNSlocal mStatus update_record(AuthRecord *rr, mDNSu16 rdlen, const char *rdata, mDNSu32 ttl) { int rdsize; RData *newrd; @@ -1509,32 +1838,36 @@ mDNSlocal mStatus update_record(AuthRecord *rr, mDNSu16 rdlen, char *rdata, mDNS if (rr->resrec.rrtype == kDNSType_TXT && rdlen == 0) { rdlen = 1; newrd->u.txt.c[0] = 0; } result = mDNS_Update(&mDNSStorage, rr, ttl, rdlen, newrd, update_callback); - if (result) { LogMsg("ERROR: mDNS_Update - %ld", result); freeL("RData/update_record", newrd); } + if (result) { LogMsg("ERROR: mDNS_Update - %d", result); freeL("RData/update_record", newrd); } return result; } mDNSlocal mStatus handle_update_request(request_state *request) { + const ipc_msg_hdr *const hdr = &request->hdr; mStatus result = mStatus_BadReferenceErr; service_instance *i; AuthRecord *rr = NULL; // get the message data - DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend); // flags unused - mDNSu16 rdlen = get_uint16(&request->msgptr, request->msgend); - char *rdata = get_rdata(&request->msgptr, request->msgend, rdlen); - mDNSu32 ttl = get_uint32(&request->msgptr, request->msgend); + DNSServiceFlags flags = get_flags (&request->msgptr, request->msgend); // flags unused + mDNSu16 rdlen = get_uint16(&request->msgptr, request->msgend); + const char *rdata = get_rdata (&request->msgptr, request->msgend, rdlen); + mDNSu32 ttl = get_uint32(&request->msgptr, request->msgend); (void)flags; // Unused if (!request->msgptr) { LogMsg("%3d: DNSServiceUpdateRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); } + // If this is a shared connection, check if the operation actually applies to a subordinate request_state object + if (request->terminate == connection_termination) request = LocateSubordinateRequest(request); + if (request->terminate == connection_termination) { // update an individually registered record registered_record_entry *reptr; for (reptr = request->u.reg_recs; reptr; reptr = reptr->next) { - if (reptr->key == request->hdr.reg_index) + if (reptr->key == hdr->reg_index) { result = update_record(reptr->rr, rdlen, rdata, ttl); goto end; @@ -1544,15 +1877,33 @@ mDNSlocal mStatus handle_update_request(request_state *request) goto end; } + if (request->terminate != regservice_termination_callback) + { LogMsg("%3d: DNSServiceUpdateRecord(not a registered service ref)", request->sd); return(mStatus_BadParamErr); } + + // update the saved off TXT data for the service + if (hdr->reg_index == TXT_RECORD_INDEX) + { + if (request->u.servicereg.txtdata) + { freeL("service_info txtdata", request->u.servicereg.txtdata); request->u.servicereg.txtdata = NULL; } + if (rdlen > 0) + { + request->u.servicereg.txtdata = mallocL("service_info txtdata", rdlen); + if (!request->u.servicereg.txtdata) FatalError("ERROR: handle_update_request - malloc"); + mDNSPlatformMemCopy(request->u.servicereg.txtdata, rdata, rdlen); + } + else + request->u.servicereg.txtdata = NULL; + } + // update a record from a service record set for (i = request->u.servicereg.instances; i; i = i->next) { - if (request->hdr.reg_index == TXT_RECORD_INDEX) rr = &i->srs.RR_TXT; + if (hdr->reg_index == TXT_RECORD_INDEX) rr = &i->srs.RR_TXT; else { ExtraResourceRecord *e; for (e = i->srs.Extras; e; e = e->next) - if (e->ClientID == request->hdr.reg_index) { rr = &e->r; break; } + if (e->ClientID == hdr->reg_index) { rr = &e->r; break; } } if (!rr) { result = mStatus_BadReferenceErr; goto end; } @@ -1562,9 +1913,10 @@ mDNSlocal mStatus handle_update_request(request_state *request) } end: - LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)", request->sd, - (request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL, - rr ? DNSTypeName(rr->resrec.rrtype) : ""); + if (request->terminate == regservice_termination_callback) + LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)", request->sd, + (request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL, + rr ? DNSTypeName(rr->resrec.rrtype) : ""); return(result); } @@ -1585,7 +1937,7 @@ mDNSlocal mStatus remove_record(request_state *request) err = mDNS_Deregister(&mDNSStorage, e->rr); if (err) { - LogMsg("ERROR: remove_record, mDNS_Deregister: %ld", err); + LogMsg("ERROR: remove_record, mDNS_Deregister: %d", err); freeL("registered_record_entry AuthRecord remove_record", e->rr); } freeL("registered_record_entry remove_record", e); @@ -1615,8 +1967,13 @@ mDNSlocal mStatus handle_removerecord_request(request_state *request) if (!request->msgptr) { LogMsg("%3d: DNSServiceRemoveRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); } + // If this is a shared connection, check if the operation actually applies to a subordinate request_state object + if (request->terminate == connection_termination) request = LocateSubordinateRequest(request); + if (request->terminate == connection_termination) err = remove_record(request); // remove individually registered record + else if (request->terminate != regservice_termination_callback) + { LogMsg("%3d: DNSServiceRemoveRecord(not a registered service ref)", request->sd); return(mStatus_BadParamErr); } else { service_instance *i; @@ -1715,7 +2072,11 @@ mDNSlocal mStatus register_service_instance(request_state *request, const domain for (ptr = &request->u.servicereg.instances; *ptr; ptr = &(*ptr)->next) { if (SameDomainName(&(*ptr)->domain, domain)) - { LogMsg("register_service_instance: domain %##s already registered", domain->c); return mStatus_AlreadyRegistered; } + { + LogMsg("register_service_instance: domain %##s already registered for %#s.%##s", + domain->c, &request->u.servicereg.name, &request->u.servicereg.type); + return mStatus_AlreadyRegistered; + } } // Special-case hack: We don't advertise SMB service in AutoTunnel domains, because AutoTunnel @@ -1734,7 +2095,6 @@ mDNSlocal mStatus register_service_instance(request_state *request, const domain instance->next = mDNSNULL; instance->request = request; - instance->sd = request->sd; instance->subtypes = AllocateSubTypes(request->u.servicereg.num_subtypes, request->u.servicereg.type_as_string); instance->renameonmemfree = 0; instance->clientnotified = mDNSfalse; @@ -1744,9 +2104,6 @@ mDNSlocal mStatus register_service_instance(request_state *request, const domain if (request->u.servicereg.num_subtypes && !instance->subtypes) { unlink_and_free_service_instance(instance); instance = NULL; FatalError("ERROR: malloc"); } - LogOperation("%3d: DNSServiceRegister(%#s.%##s%##s, %u) ADDING", - instance->sd, &request->u.servicereg.name, &request->u.servicereg.type, domain->c, mDNSVal16(request->u.servicereg.port)); - result = mDNS_RegisterService(&mDNSStorage, &instance->srs, &request->u.servicereg.name, &request->u.servicereg.type, domain, request->u.servicereg.host.c[0] ? &request->u.servicereg.host : NULL, @@ -1755,7 +2112,12 @@ mDNSlocal mStatus register_service_instance(request_state *request, const domain instance->subtypes, request->u.servicereg.num_subtypes, request->u.servicereg.InterfaceID, regservice_callback, instance); - if (!result) *ptr = instance; // Append this to the end of our request->u.servicereg.instances list + if (!result) + { + *ptr = instance; // Append this to the end of our request->u.servicereg.instances list + LogOperation("%3d: DNSServiceRegister(%##s, %u) ADDED", + instance->request->sd, instance->srs.RR_SRV.resrec.name->c, mDNSVal16(request->u.servicereg.port)); + } else { LogMsg("register_service_instance %#s.%##s%##s error %d", @@ -1766,33 +2128,6 @@ mDNSlocal mStatus register_service_instance(request_state *request, const domain return result; } -mDNSlocal void UpdateDeviceInfoRecord(mDNS *const m); - -mDNSlocal void regservice_termination_callback(request_state *request) - { - if (!request) { LogMsg("regservice_termination_callback context is NULL"); return; } - while (request->u.servicereg.instances) - { - service_instance *p = request->u.servicereg.instances; - request->u.servicereg.instances = request->u.servicereg.instances->next; - // only safe to free memory if registration is not valid, i.e. deregister fails (which invalidates p) - LogOperation("%3d: DNSServiceRegister(%##s, %u) STOP", - request->sd, p->srs.RR_SRV.resrec.name->c, mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port)); - - // Clear backpointer *before* calling mDNS_DeregisterService/unlink_and_free_service_instance - // We don't need unlink_and_free_service_instance to cut its element from the list, because we're already advancing - // request->u.servicereg.instances as we work our way through the list, implicitly cutting one element at a time - // We can't clear p->request *after* the calling mDNS_DeregisterService/unlink_and_free_service_instance - // because by then we might have already freed p - p->request = NULL; - if (mDNS_DeregisterService(&mDNSStorage, &p->srs)) unlink_and_free_service_instance(p); - // Don't touch service_instance *p after this -- it's likely to have been freed already - } - if (request->u.servicereg.txtdata) - { freeL("service_info txtdata", request->u.servicereg.txtdata); request->u.servicereg.txtdata = NULL; } - if (request->u.servicereg.autoname) UpdateDeviceInfoRecord(&mDNSStorage); - } - mDNSlocal void udsserver_default_reg_domain_changed(const DNameListElem *const d, const mDNSBool add) { request_state *request; @@ -1963,24 +2298,32 @@ mDNSlocal mStatus handle_regservice_request(request_state *request) LogOperation("%3d: DNSServiceRegister(\"%s\", \"%s\", \"%s\", \"%s\", %u) START", request->sd, name, request->u.servicereg.type_as_string, domain, host, mDNSVal16(request->u.servicereg.port)); + + // We need to unconditionally set request->terminate, because even if we didn't successfully + // start any registrations right now, subsequent configuration changes may cause successful + // registrations to be added, and we'll need to cancel them before freeing this memory. + // We also need to set request->terminate first, before adding additional service instances, + // because the uds_validatelists uses the request->terminate function pointer to determine + // what kind of request this is, and therefore what kind of list validation is required. + request->terminate = regservice_termination_callback; + err = register_service_instance(request, &d); - // Set request->terminate first, before adding additional service instances, because the - // uds_validatelists uses the request->terminate function pointer to determine what kind - // of request this is, and therefore what kind of list validation is required. +#if 0 + err = AuthorizedDomain(request, &d, AutoRegistrationDomains) ? register_service_instance(request, &d) : mStatus_NoError; +#endif if (!err) { - request->terminate = regservice_termination_callback; if (request->u.servicereg.autoname) UpdateDeviceInfoRecord(&mDNSStorage); - } - if (!err && !*domain) - { - DNameListElem *ptr; - // note that we don't report errors for non-local, non-explicit domains - for (ptr = AutoRegistrationDomains; ptr; ptr = ptr->next) - if (!ptr->uid || SystemUID(request->uid) || request->uid == ptr->uid) - register_service_instance(request, &ptr->name); + if (!*domain) + { + DNameListElem *ptr; + // Note that we don't report errors for non-local, non-explicit domains + for (ptr = AutoRegistrationDomains; ptr; ptr = ptr->next) + if (!ptr->uid || SystemUID(request->uid) || request->uid == ptr->uid) + register_service_instance(request, &ptr->name); + } } return(err); @@ -2004,11 +2347,21 @@ mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const Resourc if (GenerateNTDResponse(&answer->rdata->u.name, answer->InterfaceID, req, &rep, browse_reply_op, flags, mStatus_NoError) != mStatus_NoError) { + if (SameDomainName(&req->u.browser.regtype, (const domainname*)"\x09_services\x07_dns-sd\x04_udp")) + { + // Special support to enable the DNSServiceBrowse call made by Bonjour Browser + // Remove after Bonjour Browser is updated to use DNSServiceQueryRecord instead of DNSServiceBrowse + GenerateBonjourBrowserResponse(&answer->rdata->u.name, answer->InterfaceID, req, &rep, browse_reply_op, flags, mStatus_NoError); + goto bonjourbrowserhack; + } + LogMsg("%3d: FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer", req->sd, answer->name->c, answer->rdata->u.name.c); return; } +bonjourbrowserhack: + LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %d: %s", req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv", mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID), RRDisplayString(m, answer)); @@ -2041,8 +2394,9 @@ mDNSlocal mStatus add_domain_to_browser(request_state *info, const domainname *d { b->next = info->u.browser.browsers; info->u.browser.browsers = b; + LogOperation("%3d: DNSServiceBrowse(%##s) START", info->sd, b->q.qname.c); } - return err; + return err; } mDNSlocal void browse_termination_callback(request_state *info) @@ -2124,7 +2478,7 @@ mDNSlocal void RegisterLocalOnlyDomainEnumPTR(mDNS *m, const domainname *d, int mStatus err; ARListElem *ptr = mDNSPlatformMemAllocate(sizeof(*ptr)); - LogOperation("Incrementing %s refcount for %##s", + debugf("Incrementing %s refcount for %##s", (type == mDNS_DomainTypeBrowse ) ? "browse domain " : (type == mDNS_DomainTypeRegistration ) ? "registration dom" : (type == mDNS_DomainTypeBrowseAutomatic) ? "automatic browse" : "?", d->c); @@ -2151,7 +2505,7 @@ mDNSlocal void DeregisterLocalOnlyDomainEnumPTR(mDNS *m, const domainname *d, in ARListElem **ptr = &LocalDomainEnumRecords; domainname lhs; // left-hand side of PTR, for comparison - LogOperation("Decrementing %s refcount for %##s", + debugf("Decrementing %s refcount for %##s", (type == mDNS_DomainTypeBrowse ) ? "browse domain " : (type == mDNS_DomainTypeRegistration ) ? "registration dom" : (type == mDNS_DomainTypeBrowseAutomatic) ? "automatic browse" : "?", d->c); @@ -2251,8 +2605,8 @@ mDNSexport void udsserver_handle_configchange(mDNS *const m) { request_state *req; service_instance *ptr; - DNameListElem *RegDomains; - DNameListElem *BrowseDomains; + DNameListElem *RegDomains = NULL; + DNameListElem *BrowseDomains = NULL; DNameListElem *p; UpdateDeviceInfoRecord(m); @@ -2381,12 +2735,20 @@ mDNSlocal mStatus handle_browse_request(request_state *request) request->u.browser.browsers = NULL; LogOperation("%3d: DNSServiceBrowse(\"%##s\", \"%s\") START", request->sd, request->u.browser.regtype.c, domain); + + // We need to unconditionally set request->terminate, because even if we didn't successfully + // start any browses right now, subsequent configuration changes may cause successful + // browses to be added, and we'll need to cancel them before freeing this memory. + request->terminate = browse_termination_callback; + if (domain[0]) { if (!MakeDomainNameFromDNSNameString(&d, domain)) return(mStatus_BadParamErr); err = add_domain_to_browser(request, &d); +#if 0 + err = AuthorizedDomain(request, &d, AutoBrowseDomains) ? add_domain_to_browser(request, &d) : mStatus_NoError; +#endif } - else { DNameListElem *sdom; @@ -2402,8 +2764,6 @@ mDNSlocal mStatus handle_browse_request(request_state *request) } } - if (!err) request->terminate = browse_termination_callback; - return(err); } @@ -2422,17 +2782,12 @@ mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, con request_state *req = question->QuestionContext; (void)m; // Unused - LogOperation("%3d: DNSServiceResolve(%##s, %s) %s %s", - req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer)); - - // This code used to do this trick of just keeping a copy of the pointer to - // the answer record in the cache, but the unicast query code doesn't currently - // put its answer records in the cache, so for now we can't do this. + LogOperation("%3d: DNSServiceResolve(%##s) %s %s", req->sd, question->qname.c, AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer)); if (!AddRecord) { - if (answer->rrtype == kDNSType_SRV && req->u.resolve.srv == answer) req->u.resolve.srv = mDNSNULL; - if (answer->rrtype == kDNSType_TXT && req->u.resolve.txt == answer) req->u.resolve.txt = mDNSNULL; + if (req->u.resolve.srv == answer) req->u.resolve.srv = mDNSNULL; + if (req->u.resolve.txt == answer) req->u.resolve.txt = mDNSNULL; return; } @@ -2459,16 +2814,17 @@ mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, con rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID)); rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError); - data = rep->sdata; + data = (char *)&rep->rhdr[1]; // write reply data to message put_string(fullname, &data); put_string(target, &data); - *data++ = req->u.resolve.srv->rdata->u.srv.port.b[0]; - *data++ = req->u.resolve.srv->rdata->u.srv.port.b[1]; + *data++ = req->u.resolve.srv->rdata->u.srv.port.b[0]; + *data++ = req->u.resolve.srv->rdata->u.srv.port.b[1]; put_uint16(req->u.resolve.txt->rdlength, &data); - put_rdata(req->u.resolve.txt->rdlength, req->u.resolve.txt->rdata->u.data, &data); + put_rdata (req->u.resolve.txt->rdlength, req->u.resolve.txt->rdata->u.data, &data); + LogOperation("%3d: DNSServiceResolve(%s) RESULT %s:%d", req->sd, fullname, target, mDNSVal16(req->u.resolve.srv->rdata->u.srv.port)); append_reply(req, rep); } @@ -2528,8 +2884,13 @@ mDNSlocal mStatus handle_resolve_request(request_state *request) request->u.resolve.qtxt.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0; request->u.resolve.qtxt.QuestionCallback = resolve_result_callback; request->u.resolve.qtxt.QuestionContext = request; + request->u.resolve.ReportTime = NonZeroTime(mDNS_TimeNow(&mDNSStorage) + 130 * mDNSPlatformOneSecond); +#if 0 + if (!AuthorizedDomain(request, &fqdn, AutoBrowseDomains)) return(mStatus_NoError); +#endif + // ask the questions LogOperation("%3d: DNSServiceResolve(%##s) START", request->sd, request->u.resolve.qsrv.qname.c); err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qsrv); @@ -2537,10 +2898,9 @@ mDNSlocal mStatus handle_resolve_request(request_state *request) { err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qtxt); if (err) mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv); + else request->terminate = resolve_termination_callback; } - if (!err) request->terminate = resolve_termination_callback; - return(err); } @@ -2565,18 +2925,43 @@ mDNSlocal void queryrecord_result_callback(mDNS *const m, DNSQuestion *question, DNSServiceErrorType error = kDNSServiceErr_NoError; (void)m; // Unused - LogOperation("%3d: %s(%##s, %s) %s %s", req->sd, - req->hdr.op == query_request ? "DNSServiceQueryRecord" : "DNSServiceGetAddrInfo", - question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer)); +#if APPLE_OSX_mDNSResponder + if (question == &req->u.queryrecord.q2) + { + mDNS_StopQuery(&mDNSStorage, question); + // If we got a non-negative answer for our "local SOA" test query, start an additional parallel unicast query + if (answer->RecordType == kDNSRecordTypePacketNegative || + (question->qtype == req->u.queryrecord.q.qtype && SameDomainName(&question->qname, &req->u.queryrecord.q.qname))) + question->QuestionCallback = mDNSNULL; + else + { + *question = req->u.queryrecord.q; + question->InterfaceID = mDNSInterface_Unicast; + question->ExpectUnique = mDNStrue; + mStatus err = mDNS_StartQuery(&mDNSStorage, question); + if (!err) LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) unicast", req->sd, question->qname.c, DNSTypeName(question->qtype)); + else LogMsg("%3d: ERROR: queryrecord_result_callback %##s %s mDNS_StartQuery: %d", req->sd, question->qname.c, DNSTypeName(question->qtype), (int)err); + } + return; + } +#endif // APPLE_OSX_mDNSResponder if (answer->RecordType == kDNSRecordTypePacketNegative) { + // When we're doing parallel unicast and multicast queries for dot-local names (for supporting Microsoft + // Active Directory sites) we need to ignore negative unicast answers. Otherwise we'll generate negative + // answers for just about every single multicast name we ever look up, since the Microsoft Active Directory + // server is going to assert that pretty much every single multicast name doesn't exist. + if (!answer->InterfaceID && IsLocalDomain(answer->name)) return; error = kDNSServiceErr_NoSuchRecord; - ConvertDomainNameToCString(&question->qname, name); AddRecord = mDNStrue; } - else - ConvertDomainNameToCString(answer->name, name); + + ConvertDomainNameToCString(answer->name, name); + + LogOperation("%3d: %s(%##s, %s) %s %s", req->sd, + req->hdr.op == query_request ? "DNSServiceQueryRecord" : "DNSServiceGetAddrInfo", + question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer)); len = sizeof(DNSServiceFlags); // calculate reply data length len += sizeof(mDNSu32); // interface index @@ -2592,29 +2977,19 @@ mDNSlocal void queryrecord_result_callback(mDNS *const m, DNSQuestion *question, rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID)); rep->rhdr->error = dnssd_htonl(error); - data = rep->sdata; - - put_string(name, &data); + data = (char *)&rep->rhdr[1]; - if (answer->RecordType == kDNSRecordTypePacketNegative) - { - put_uint16(question->qtype, &data); - put_uint16(question->qclass, &data); - put_uint16(0, &data); - put_rdata(0, mDNSNULL, &data); - put_uint32(0, &data); - } - else - { - put_uint16(answer->rrtype, &data); - put_uint16(answer->rrclass, &data); - put_uint16(answer->rdlength, &data); - //put_rdata(answer->rdlength, answer->rdata->u.data, &data); + put_string(name, &data); + put_uint16(answer->rrtype, &data); + put_uint16(answer->rrclass, &data); + put_uint16(answer->rdlength, &data); + // We need to use putRData here instead of the crude put_rdata function, because the crude put_rdata + // function just does a blind memory copy without regard to structures that may have holes in them. + if (answer->rdlength) if (!putRData(mDNSNULL, (mDNSu8 *)data, (mDNSu8 *)rep->rhdr + len, answer)) LogMsg("queryrecord_result_callback putRData failed %d", (mDNSu8 *)rep->rhdr + len - (mDNSu8 *)data); - data += answer->rdlength; - put_uint32(AddRecord ? answer->rroriginalttl : 0, &data); - } + data += answer->rdlength; + put_uint32(AddRecord ? answer->rroriginalttl : 0, &data); append_reply(req, rep); } @@ -2624,10 +2999,12 @@ mDNSlocal void queryrecord_termination_callback(request_state *request) LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP", request->sd, request->u.queryrecord.q.qname.c, DNSTypeName(request->u.queryrecord.q.qtype)); mDNS_StopQuery(&mDNSStorage, &request->u.queryrecord.q); // no need to error check + if (request->u.queryrecord.q2.QuestionCallback) mDNS_StopQuery(&mDNSStorage, &request->u.queryrecord.q2); } mDNSlocal mStatus handle_queryrecord_request(request_state *request) { + DNSQuestion *const q = &request->u.queryrecord.q; char name[256]; mDNSu16 rrtype, rrclass; mStatus err; @@ -2644,26 +3021,63 @@ mDNSlocal mStatus handle_queryrecord_request(request_state *request) if (!request->msgptr) { LogMsg("%3d: DNSServiceQueryRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); } - mDNSPlatformMemZero(&request->u.queryrecord.q, sizeof(&request->u.queryrecord.q)); + mDNSPlatformMemZero(&request->u.queryrecord, sizeof(request->u.queryrecord)); - request->u.queryrecord.q.InterfaceID = InterfaceID; - request->u.queryrecord.q.Target = zeroAddr; - if (!MakeDomainNameFromDNSNameString(&request->u.queryrecord.q.qname, name)) return(mStatus_BadParamErr); - request->u.queryrecord.q.qtype = rrtype; - request->u.queryrecord.q.qclass = rrclass; - request->u.queryrecord.q.LongLived = (flags & kDNSServiceFlagsLongLivedQuery ) != 0; - request->u.queryrecord.q.ExpectUnique = mDNSfalse; - request->u.queryrecord.q.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0; - request->u.queryrecord.q.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0; - request->u.queryrecord.q.QuestionCallback = queryrecord_result_callback; - request->u.queryrecord.q.QuestionContext = request; + q->InterfaceID = InterfaceID; + q->Target = zeroAddr; + if (!MakeDomainNameFromDNSNameString(&q->qname, name)) return(mStatus_BadParamErr); +#if 0 + if (!AuthorizedDomain(request, &q->qname, AutoBrowseDomains)) return (mStatus_NoError); +#endif + q->qtype = rrtype; + q->qclass = rrclass; + q->LongLived = (flags & kDNSServiceFlagsLongLivedQuery ) != 0; + q->ExpectUnique = mDNSfalse; + q->ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0; + q->ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0; + q->QuestionCallback = queryrecord_result_callback; + q->QuestionContext = request; + + LogOperation("%3d: DNSServiceQueryRecord(%##s, %s, %X) START", request->sd, q->qname.c, DNSTypeName(q->qtype), flags); + err = mDNS_StartQuery(&mDNSStorage, q); + if (err) LogMsg("%3d: ERROR: DNSServiceQueryRecord %##s %s mDNS_StartQuery: %d", request->sd, q->qname.c, DNSTypeName(q->qtype), (int)err); + else request->terminate = queryrecord_termination_callback; - LogOperation("%3d: DNSServiceQueryRecord(%##s, %s, %X) START", - request->sd, request->u.queryrecord.q.qname.c, DNSTypeName(request->u.queryrecord.q.qtype), flags); - err = mDNS_StartQuery(&mDNSStorage, &request->u.queryrecord.q); - if (err) LogMsg("ERROR: mDNS_StartQuery: %d", (int)err); +#if APPLE_OSX_mDNSResponder + // Workaround for networks using Microsoft Active Directory using "local" as a private internal top-level domain + extern domainname ActiveDirectoryPrimaryDomain; + #define VALID_MSAD_SRV_TRANSPORT(T) (SameDomainLabel((T)->c, (const mDNSu8 *)"\x4_tcp") || SameDomainLabel((T)->c, (const mDNSu8 *)"\x4_udp")) + #define VALID_MSAD_SRV(Q) ((Q)->qtype == kDNSType_SRV && VALID_MSAD_SRV_TRANSPORT(SecondLabel(&(Q)->qname))) - if (!err) request->terminate = queryrecord_termination_callback; + if (!q->ForceMCast && SameDomainLabel(LastLabel(&q->qname), (const mDNSu8 *)&localdomain)) + if (q->qtype == kDNSType_A || q->qtype == kDNSType_AAAA || VALID_MSAD_SRV(q)) + { + int labels = CountLabels(&q->qname); + DNSQuestion *const q2 = &request->u.queryrecord.q2; + *q2 = *q; + q2->InterfaceID = mDNSInterface_Unicast; + q2->ExpectUnique = mDNStrue; + + // For names of the form ".bar.local." we always do a second unicast query in parallel. + // For names of the form ".local." it's less clear whether we should do a unicast query. + // If the name being queried is exactly the same as the name in the DHCP "domain" option (e.g. the DHCP + // "domain" is my-small-company.local, and the user types "my-small-company.local" into their web browser) + // then that's a hint that it's worth doing a unicast query. Otherwise, we first check to see if the + // site's DNS server claims there's an SOA record for "local", and if so, that's also a hint that queries + // for names in the "local" domain will be safely answered privately before they hit the root name servers. + if (labels == 2 && !SameDomainName(&q->qname, &ActiveDirectoryPrimaryDomain)) + { + AssignDomainName(&q2->qname, &localdomain); + q2->qtype = kDNSType_SOA; + q2->LongLived = mDNSfalse; + q2->ForceMCast = mDNSfalse; + q2->ReturnIntermed = mDNStrue; + } + err = mDNS_StartQuery(&mDNSStorage, q2); + if (!err) LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) unicast", request->sd, q2->qname.c, DNSTypeName(q2->qtype)); + else LogMsg("%3d: ERROR: DNSServiceQueryRecord %##s %s mDNS_StartQuery: %d", request->sd, q2->qname.c, DNSTypeName(q2->qtype), (int)err); + } +#endif // APPLE_OSX_mDNSResponder return(err); } @@ -2688,9 +3102,9 @@ mDNSlocal reply_state *format_enumeration_reply(request_state *request, reply = create_reply(enumeration_reply_op, len, request); reply->rhdr->flags = dnssd_htonl(flags); - reply->rhdr->ifi = dnssd_htonl(ifi); + reply->rhdr->ifi = dnssd_htonl(ifi); reply->rhdr->error = dnssd_htonl(err); - data = reply->sdata; + data = (char *)&reply->rhdr[1]; put_string(domain, &data); return reply; } @@ -2711,7 +3125,11 @@ mDNSlocal void enum_result_callback(mDNS *const m, (void)m; // Unused if (answer->rrtype != kDNSType_PTR) return; - + +#if 0 + if (!AuthorizedDomain(request, &answer->rdata->u.name, request->u.enumeration.flags ? AutoRegistrationDomains : AutoBrowseDomains)) return; +#endif + // We only return add/remove events for the browse and registration lists // For the default browse and registration answers, we only give an "ADD" event if (question == &request->u.enumeration.q_default && !AddRecord) return; @@ -2728,6 +3146,9 @@ mDNSlocal void enum_result_callback(mDNS *const m, // network, so we just pass kDNSServiceInterfaceIndexAny reply = format_enumeration_reply(request, domain, flags, kDNSServiceInterfaceIndexAny, kDNSServiceErr_NoError); if (!reply) { LogMsg("ERROR: enum_result_callback, format_enumeration_reply"); return; } + + LogOperation("%3d: DNSServiceEnumerateDomains(%#2s) RESULT %s: %s", request->sd, question->qname.c, AddRecord ? "Add" : "Rmv", domain); + append_reply(request, reply); } @@ -2748,6 +3169,11 @@ mDNSlocal mStatus handle_enum_request(request_state *request) // allocate context structures uDNS_RegisterSearchDomains(&mDNSStorage); +#if 0 + // mark which kind of enumeration we're doing so we can (de)authorize certain domains + request->u.enumeration.flags = reg; +#endif + // enumeration requires multiple questions, so we must link all the context pointers so that // necessary context can be reached from the callbacks request->u.enumeration.q_all .QuestionContext = request; @@ -2765,8 +3191,8 @@ mDNSlocal mStatus handle_enum_request(request_state *request) { err = mDNS_GetDomains(&mDNSStorage, &request->u.enumeration.q_default, t_default, NULL, InterfaceID, enum_result_callback, request); if (err) mDNS_StopGetDomains(&mDNSStorage, &request->u.enumeration.q_all); + else request->terminate = enum_termination_callback; } - if (!err) request->terminate = enum_termination_callback; return(err); } @@ -2874,7 +3300,7 @@ mDNSlocal void port_mapping_create_request_callback(mDNS *m, NATTraversalInfo *n rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, n->InterfaceID)); rep->rhdr->error = dnssd_htonl(n->Result); - data = rep->sdata; + data = (char *)&rep->rhdr[1]; *data++ = request->u.pm.NATinfo.ExternalAddress.b[0]; *data++ = request->u.pm.NATinfo.ExternalAddress.b[1]; @@ -2939,7 +3365,8 @@ mDNSlocal mStatus handle_port_mapping_request(request_state *request) LogOperation("%3d: DNSServiceNATPortMappingCreate(%X, %u, %u, %d) START", request->sd, protocol, mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease); err = mDNS_StartNATOperation(&mDNSStorage, &request->u.pm.NATinfo); - if (!err) request->terminate = port_mapping_termination_callback; + if (err) LogMsg("ERROR: mDNS_StartNATOperation: %d", (int)err); + else request->terminate = port_mapping_termination_callback; return(err); } @@ -2973,12 +3400,14 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request) DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend); mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend); + + mDNSPlatformMemZero(&request->u.addrinfo, sizeof(request->u.addrinfo)); request->u.addrinfo.interface_id = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex); + request->u.addrinfo.flags = flags; + request->u.addrinfo.protocol = get_uint32(&request->msgptr, request->msgend); + if (interfaceIndex && !request->u.addrinfo.interface_id) return(mStatus_BadParamErr); - request->u.addrinfo.flags = flags; - request->u.addrinfo.protocol = get_uint32(&request->msgptr, request->msgend); - if (request->u.addrinfo.protocol > (kDNSServiceProtocol_IPv4|kDNSServiceProtocol_IPv6)) - return(mStatus_BadParamErr); + if (request->u.addrinfo.protocol > (kDNSServiceProtocol_IPv4|kDNSServiceProtocol_IPv6)) return(mStatus_BadParamErr); if (get_string(&request->msgptr, request->msgend, hostname, 256) < 0) return(mStatus_BadParamErr); @@ -2987,6 +3416,10 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request) if (!MakeDomainNameFromDNSNameString(&d, hostname)) { LogMsg("ERROR: handle_addrinfo_request: bad hostname: %s", hostname); return(mStatus_BadParamErr); } +#if 0 + if (!AuthorizedDomain(request, &d, AutoBrowseDomains)) return (mStatus_NoError); +#endif + if (!request->u.addrinfo.protocol) { NetworkInterfaceInfo *i; @@ -3049,6 +3482,8 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request) { LogMsg("ERROR: mDNS_StartQuery: %d", (int)err); request->u.addrinfo.q6.QuestionContext = mDNSNULL; + if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv4) // If we started a query for IPv4, + addrinfo_termination_callback(request); // we need to cancel it } } @@ -3114,7 +3549,7 @@ mDNSlocal void read_msg(request_state *req) { LogMsg("%3d: ERROR: client version 0x%08X daemon version 0x%08X", req->sd, req->hdr.version, VERSION); req->ts = t_error; return; } // Largest conceivable single request is a DNSServiceRegisterRecord() or DNSServiceAddRecord() - // with 64kB of rdata. Adding 1005 byte for a maximal domain name, plus a safety margin + // with 64kB of rdata. Adding 1009 byte for a maximal domain name, plus a safety margin // for other overhead, this means any message above 70kB is definitely bogus. if (req->hdr.datalen > 70000) { LogMsg("%3d: ERROR: read_msg - hdr.datalen %lu (%X) > 70000", req->sd, req->hdr.datalen, req->hdr.datalen); req->ts = t_error; return; } @@ -3134,6 +3569,7 @@ mDNSlocal void read_msg(request_state *req) { mDNSu32 nleft = req->hdr.datalen - req->data_bytes; int nread; +#if !defined(_WIN32) struct iovec vec = { req->msgbuf + req->data_bytes, nleft }; // Tell recvmsg where we want the bytes put struct msghdr msg; struct cmsghdr *cmsg; @@ -3146,25 +3582,41 @@ mDNSlocal void read_msg(request_state *req) msg.msg_controllen = sizeof(cbuf); msg.msg_flags = 0; nread = recvmsg(req->sd, &msg, 0); +#else + nread = recv(req->sd, (char *)req->msgbuf + req->data_bytes, nleft, 0); +#endif if (nread == 0) { req->ts = t_terminated; return; } if (nread < 0) goto rerror; req->data_bytes += nread; if (req->data_bytes > req->hdr.datalen) { LogMsg("%3d: ERROR: read_msg - read too many data bytes", req->sd); req->ts = t_error; return; } +#if !defined(_WIN32) cmsg = CMSG_FIRSTHDR(&msg); #if DEBUG_64BIT_SCM_RIGHTS LogMsg("%3d: Expecting %d %d %d %d", req->sd, sizeof(cbuf), sizeof(cbuf), SOL_SOCKET, SCM_RIGHTS); LogMsg("%3d: Got %d %d %d %d", req->sd, msg.msg_controllen, cmsg->cmsg_len, cmsg->cmsg_level, cmsg->cmsg_type); -#endif DEBUG_64BIT_SCM_RIGHTS +#endif // DEBUG_64BIT_SCM_RIGHTS if (msg.msg_controllen == sizeof(cbuf) && cmsg->cmsg_len == sizeof(cbuf) && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { - req->errsd = *(dnssd_sock_t *)CMSG_DATA(cmsg); +#if APPLE_OSX_mDNSResponder + // Strictly speaking BPF_fd belongs solely in the platform support layer, but because + // of privilege separation on Mac OS X we need to get BPF_fd from mDNSResponderHelper, + // and it's convenient to repurpose the existing fd-passing code here for that task + if (req->hdr.op == send_bpf) + { + dnssd_sock_t x = *(dnssd_sock_t *)CMSG_DATA(cmsg); + LogOperation("%3d: Got BPF %d", req->sd, x); + mDNSPlatformReceiveBPF_fd(&mDNSStorage, x); + } + else +#endif // APPLE_OSX_mDNSResponder + req->errsd = *(dnssd_sock_t *)CMSG_DATA(cmsg); #if DEBUG_64BIT_SCM_RIGHTS LogMsg("%3d: read req->errsd %d", req->sd, req->errsd); -#endif DEBUG_64BIT_SCM_RIGHTS +#endif // DEBUG_64BIT_SCM_RIGHTS if (req->data_bytes < req->hdr.datalen) { LogMsg("%3d: Client sent error socket %d via SCM_RIGHTS with req->data_bytes %d < req->hdr.datalen %d", @@ -3173,6 +3625,7 @@ mDNSlocal void read_msg(request_state *req) return; } } +#endif } // If our header and data are both complete, see if we need to make our separate error return socket @@ -3183,6 +3636,7 @@ mDNSlocal void read_msg(request_state *req) dnssd_sockaddr_t cliaddr; #if defined(USE_TCP_LOOPBACK) mDNSOpaque16 port; + int opt = 1; port.b[0] = req->msgptr[0]; port.b[1] = req->msgptr[1]; req->msgptr += 2; @@ -3213,10 +3667,10 @@ mDNSlocal void read_msg(request_state *req) { #if !defined(USE_TCP_LOOPBACK) struct stat sb; - LogMsg("%3d: read_msg: Couldn't connect to error return path socket “%s” errno %d %s", - req->sd, cliaddr.sun_path, dnssd_errno(), dnssd_strerror(dnssd_errno())); + LogMsg("%3d: read_msg: Couldn't connect to error return path socket “%s” errno %d (%s)", + req->sd, cliaddr.sun_path, dnssd_errno, dnssd_strerror(dnssd_errno)); if (stat(cliaddr.sun_path, &sb) < 0) - LogMsg("%3d: read_msg: stat failed “%s” errno %d %s", req->sd, cliaddr.sun_path, dnssd_errno(), dnssd_strerror(dnssd_errno())); + LogMsg("%3d: read_msg: stat failed “%s” errno %d (%s)", req->sd, cliaddr.sun_path, dnssd_errno, dnssd_strerror(dnssd_errno)); else LogMsg("%3d: read_msg: file “%s” mode %o (octal) uid %d gid %d", req->sd, cliaddr.sun_path, sb.st_mode, sb.st_uid, sb.st_gid); #endif @@ -3225,15 +3679,15 @@ mDNSlocal void read_msg(request_state *req) } got_errfd: - LogOperation("%3d: Using separate error socket %d", req->sd, req->errsd); + LogOperation("%3d: Error socket %d created %08X %08X", req->sd, req->errsd, req->hdr.client_context.u32[1], req->hdr.client_context.u32[0]); #if defined(_WIN32) if (ioctlsocket(req->errsd, FIONBIO, &opt) != 0) #else if (fcntl(req->errsd, F_SETFL, fcntl(req->errsd, F_GETFL, 0) | O_NONBLOCK) != 0) #endif { - LogMsg("%3d: ERROR: could not set control socket to non-blocking mode errno %d %s", - req->sd, dnssd_errno(), dnssd_strerror(dnssd_errno())); + LogMsg("%3d: ERROR: could not set control socket to non-blocking mode errno %d (%s)", + req->sd, dnssd_errno, dnssd_strerror(dnssd_errno)); req->ts = t_error; return; } @@ -3245,8 +3699,8 @@ got_errfd: return; rerror: - if (dnssd_errno() == dnssd_EWOULDBLOCK || dnssd_errno() == dnssd_EINTR) return; - LogMsg("%3d: ERROR: read_msg errno %d %s", req->sd, dnssd_errno(), dnssd_strerror(dnssd_errno())); + if (dnssd_errno == dnssd_EWOULDBLOCK || dnssd_errno == dnssd_EINTR) return; + LogMsg("%3d: ERROR: read_msg errno %d (%s)", req->sd, dnssd_errno, dnssd_strerror(dnssd_errno)); req->ts = t_error; } @@ -3270,6 +3724,7 @@ mDNSlocal void request_callback(int fd, short filter, void *info) read_msg(req); if (req->ts == t_morecoming) return; if (req->ts == t_terminated || req->ts == t_error) { AbortUnlinkAndFree(req); return; } + if (req->ts != t_complete) { LogMsg("req->ts %d != t_complete", req->ts); AbortUnlinkAndFree(req); return; } if (req->hdr.version != VERSION) { @@ -3295,6 +3750,7 @@ mDNSlocal void request_callback(int fd, short filter, void *info) case getproperty_request: min_size = 2; break; case port_mapping_request: min_size += sizeof(mDNSu32) + 4 /* udp/tcp */ + 4 /* int/ext port */ + 4 /* ttl */; break; case addrinfo_request: min_size += sizeof(mDNSu32) + 4 /* v4/v6 */ + 1 /* hostname */; break; + case send_bpf: // Same as cancel_request below case cancel_request: min_size = 0; break; default: LogMsg("ERROR: validate_message - unsupported req type: %d", req->hdr.op); min_size = -1; break; } @@ -3332,27 +3788,26 @@ mDNSlocal void request_callback(int fd, short filter, void *info) else switch(req->hdr.op) { // These are all operations that have their own first-class request_state object - case connection_request: - LogOperation("%3d: DNSServiceCreateConnection START", req->sd); - req->terminate = connection_termination; - break; - case resolve_request: err = handle_resolve_request (req); break; - case query_request: err = handle_queryrecord_request (req); break; - case browse_request: err = handle_browse_request (req); break; - case reg_service_request: err = handle_regservice_request (req); break; - case enumeration_request: err = handle_enum_request (req); break; - case reconfirm_record_request: err = handle_reconfirm_request (req); break; - case setdomain_request: err = handle_setdomain_request (req); break; - case getproperty_request: handle_getproperty_request (req); break; - case port_mapping_request: err = handle_port_mapping_request(req); break; - case addrinfo_request: err = handle_addrinfo_request (req); break; + case connection_request: LogOperation("%3d: DNSServiceCreateConnection START", req->sd); + req->terminate = connection_termination; break; + case resolve_request: err = handle_resolve_request (req); break; + case query_request: err = handle_queryrecord_request (req); break; + case browse_request: err = handle_browse_request (req); break; + case reg_service_request: err = handle_regservice_request (req); break; + case enumeration_request: err = handle_enum_request (req); break; + case reconfirm_record_request: err = handle_reconfirm_request (req); break; + case setdomain_request: err = handle_setdomain_request (req); break; + case getproperty_request: handle_getproperty_request (req); break; + case port_mapping_request: err = handle_port_mapping_request(req); break; + case addrinfo_request: err = handle_addrinfo_request (req); break; + case send_bpf: /* Do nothing for send_bpf */ break; // These are all operations that work with an existing request_state object - case reg_record_request: err = handle_regrecord_request (req); break; - case add_record_request: err = handle_add_request (req); break; - case update_record_request: err = handle_update_request (req); break; - case remove_record_request: err = handle_removerecord_request(req); break; - case cancel_request: handle_cancel_request (req); break; + case reg_record_request: err = handle_regrecord_request (req); break; + case add_record_request: err = handle_add_request (req); break; + case update_record_request: err = handle_update_request (req); break; + case remove_record_request: err = handle_removerecord_request(req); break; + case cancel_request: handle_cancel_request (req); break; default: LogMsg("%3d: ERROR: Unsupported UDS req: %d", req->sd, req->hdr.op); } @@ -3361,16 +3816,17 @@ mDNSlocal void request_callback(int fd, short filter, void *info) // There's no return data for a cancel request (DNSServiceRefDeallocate returns no result) // For a DNSServiceGetProperty call, the handler already generated the response, so no need to do it again here - if (req->hdr.op != cancel_request && req->hdr.op != getproperty_request) + if (req->hdr.op != cancel_request && req->hdr.op != getproperty_request && req->hdr.op != send_bpf) { - err = dnssd_htonl(err); - send_all(req->errsd, (const char *)&err, sizeof(err)); + const mStatus err_netorder = dnssd_htonl(err); + send_all(req->errsd, (const char *)&err_netorder, sizeof(err_netorder)); if (req->errsd != req->sd) { - LogOperation("%3d: Closing error socket %d", req->sd, req->errsd); + LogOperation("%3d: Error socket %d closed %08X %08X (%d)", + req->sd, req->errsd, req->hdr.client_context.u32[1], req->hdr.client_context.u32[0], err); dnssd_close(req->errsd); req->errsd = req->sd; - // Also need to reset the parent's errsd, if this is a subbordinate operation + // Also need to reset the parent's errsd, if this is a subordinate operation if (req->primary) req->primary->errsd = req->primary->sd; } } @@ -3389,27 +3845,24 @@ mDNSlocal void connect_callback(int fd, short filter, void *info) { dnssd_sockaddr_t cliaddr; dnssd_socklen_t len = (dnssd_socklen_t) sizeof(cliaddr); - dnssd_sock_t sd = accept(listenfd, (struct sockaddr*) &cliaddr, &len); + dnssd_sock_t sd = accept(fd, (struct sockaddr*) &cliaddr, &len); +#if defined(SO_NOSIGPIPE) || defined(_WIN32) const unsigned long optval = 1; +#endif - (void)fd; // Unused (void)filter; // Unused (void)info; // Unused if (!dnssd_SocketValid(sd)) { - if (dnssd_errno() != dnssd_EWOULDBLOCK) my_perror("ERROR: accept"); + if (dnssd_errno != dnssd_EWOULDBLOCK) my_perror("ERROR: accept"); return; } #ifdef SO_NOSIGPIPE // Some environments (e.g. OS X) support turning off SIGPIPE for a socket if (setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0) - { - my_perror("ERROR: setsockopt - SO_NOSIGPIPE - aborting client"); - dnssd_close(sd); - return; - } + LogMsg("%3d: WARNING: setsockopt - SO_NOSIGPIPE %d (%s)", sd, dnssd_errno, dnssd_strerror(dnssd_errno)); #endif #if defined(_WIN32) @@ -3429,26 +3882,66 @@ mDNSlocal void connect_callback(int fd, short filter, void *info) request->sd = sd; request->errsd = sd; #if APPLE_OSX_mDNSResponder - struct xucred x; - socklen_t xucredlen = sizeof(x); - if (getsockopt(sd, 0, LOCAL_PEERCRED, &x, &xucredlen) >= 0 && x.cr_version == XUCRED_VERSION) request->uid = x.cr_uid; - else my_perror("ERROR: getsockopt, LOCAL_PEERCRED"); - debugf("LOCAL_PEERCRED %d %u %u %d", xucredlen, x.cr_version, x.cr_uid, x.cr_ngroups); -#endif APPLE_OSX_mDNSResponder + struct xucred x; + socklen_t xucredlen = sizeof(x); + if (getsockopt(sd, 0, LOCAL_PEERCRED, &x, &xucredlen) >= 0 && x.cr_version == XUCRED_VERSION) request->uid = x.cr_uid; + else my_perror("ERROR: getsockopt, LOCAL_PEERCRED"); + debugf("LOCAL_PEERCRED %d %u %u %d", xucredlen, x.cr_version, x.cr_uid, x.cr_ngroups); +#endif // APPLE_OSX_mDNSResponder LogOperation("%3d: Adding FD for uid %u", request->sd, request->uid); udsSupportAddFDToEventLoop(sd, request_callback, request); } } -mDNSexport int udsserver_init(dnssd_sock_t skt) +mDNSlocal mDNSBool uds_socket_setup(dnssd_sock_t skt) + { +#if defined(SO_NP_EXTENSIONS) + struct so_np_extensions sonpx; + socklen_t optlen = sizeof(struct so_np_extensions); + sonpx.npx_flags = SONPX_SETOPTSHUT; + sonpx.npx_mask = SONPX_SETOPTSHUT; + if (setsockopt(skt, SOL_SOCKET, SO_NP_EXTENSIONS, &sonpx, optlen) < 0) + my_perror("WARNING: could not set sockopt - SO_NP_EXTENSIONS"); +#endif +#if defined(_WIN32) + // SEH: do we even need to do this on windows? + // This socket will be given to WSAEventSelect which will automatically set it to non-blocking + u_long opt = 1; + if (ioctlsocket(skt, FIONBIO, &opt) != 0) +#else + if (fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK) != 0) +#endif + { + my_perror("ERROR: could not set listen socket to non-blocking mode"); + return mDNSfalse; + } + + if (listen(skt, LISTENQ) != 0) + { + my_perror("ERROR: could not listen on listen socket"); + return mDNSfalse; + } + + if (mStatus_NoError != udsSupportAddFDToEventLoop(skt, connect_callback, (void *) NULL)) + { + my_perror("ERROR: could not add listen socket to event loop"); + return mDNSfalse; + } + else LogOperation("%3d: Listening for incoming Unix Domain Socket client requests", skt); + + return mDNStrue; + } + +mDNSexport int udsserver_init(dnssd_sock_t skts[], mDNSu32 count) { dnssd_sockaddr_t laddr; int ret; + mDNSu32 i = 0; #if defined(_WIN32) u_long opt = 1; #endif - LogOperation("udsserver_init"); + LogInfo("udsserver_init"); // If a particular platform wants to opt out of having a PID file, define PID_FILE to be "" if (PID_FILE[0]) @@ -3461,8 +3954,12 @@ mDNSexport int udsserver_init(dnssd_sock_t skt) } } - if (dnssd_SocketValid(skt)) - listenfd = skt; + if (skts) + { + for (i = 0; i < count; i++) + if (dnssd_SocketValid(skts[i]) && !uds_socket_setup(skts[i])) + goto error; + } else { listenfd = socket(AF_DNSSD, SOCK_STREAM, 0); @@ -3489,7 +3986,7 @@ mDNSexport int udsserver_init(dnssd_sock_t skt) #else { mode_t mask = umask(0); - unlink(MDNS_UDS_SERVERPATH); //OK if this fails + unlink(MDNS_UDS_SERVERPATH); // OK if this fails laddr.sun_family = AF_LOCAL; #ifndef NOT_HAVE_SA_LEN // According to Stevens (section 3.2), there is no portable way to @@ -3506,33 +4003,10 @@ mDNSexport int udsserver_init(dnssd_sock_t skt) } } #endif + + if (!uds_socket_setup(listenfd)) goto error; } -#if defined(_WIN32) - // SEH: do we even need to do this on windows? - // This socket will be given to WSAEventSelect which will automatically set it to non-blocking - if (ioctlsocket(listenfd, FIONBIO, &opt) != 0) -#else - if (fcntl(listenfd, F_SETFL, fcntl(listenfd, F_GETFL, 0) | O_NONBLOCK) != 0) -#endif - { - my_perror("ERROR: could not set listen socket to non-blocking mode"); - goto error; - } - - if (listen(listenfd, LISTENQ) != 0) - { - my_perror("ERROR: could not listen on listen socket"); - goto error; - } - - if (mStatus_NoError != udsSupportAddFDToEventLoop(listenfd, connect_callback, (void *) NULL)) - { - my_perror("ERROR: could not add listen socket to event loop"); - goto error; - } - else LogOperation("%3d: Listening for incoming Unix Domain Socket client requests", listenfd); - #if !defined(PLATFORM_NO_RLIMIT) { // Set maximum number of open file descriptors @@ -3576,11 +4050,11 @@ error: return -1; } -mDNSexport int udsserver_exit(dnssd_sock_t skt) +mDNSexport int udsserver_exit(void) { // If the launching environment created no listening socket, // that means we created it ourselves, so we should clean it up on exit - if (!dnssd_SocketValid(skt)) + if (dnssd_SocketValid(listenfd)) { dnssd_close(listenfd); #if !defined(USE_TCP_LOOPBACK) @@ -3612,7 +4086,8 @@ mDNSlocal void LogClientInfo(mDNS *const m, request_state *req) { service_instance *ptr; for (ptr = req->u.servicereg.instances; ptr; ptr = ptr->next) - LogMsgNoIdent("%3d: DNSServiceRegister %##s %u", req->sd, ptr->srs.RR_SRV.resrec.name->c, SRS_PORT(&ptr->srs)); + LogMsgNoIdent("%3d: DNSServiceRegister %##s %u/%u", + req->sd, ptr->srs.RR_SRV.resrec.name->c, mDNSVal16(req->u.servicereg.port), SRS_PORT(&ptr->srs)); } else if (req->terminate == browse_termination_callback) { @@ -3646,18 +4121,62 @@ mDNSlocal void LogClientInfo(mDNS *const m, request_state *req) LogMsgNoIdent("%3d: Unrecognized operation %p", req->sd, req->terminate); } -mDNSexport void udsserver_info(mDNS *const m) +mDNSlocal void LogAuthRecords(mDNS *const m, const mDNSs32 now, AuthRecord *ResourceRecords, int *proxy) { - mDNSs32 now = mDNS_TimeNow(m); - mDNSu32 CacheUsed = 0, CacheActive = 0; - mDNSu32 slot; - CacheGroup *cg; - CacheRecord *cr; + if (!ResourceRecords) LogMsgNoIdent(""); + else + { + const AuthRecord *ar; + mDNSEthAddr owner = zeroEthAddr; + LogMsgNoIdent(" Int Next Expire State"); + for (ar = ResourceRecords; ar; ar=ar->next) + { + NetworkInterfaceInfo *info = (NetworkInterfaceInfo *)ar->resrec.InterfaceID; + if (ar->WakeUp.HMAC.l[0]) (*proxy)++; + if (!mDNSSameEthAddress(&owner, &ar->WakeUp.HMAC)) + { + owner = ar->WakeUp.HMAC; + if (ar->WakeUp.password.l[0]) + LogMsgNoIdent("Proxying for H-MAC %.6a I-MAC %.6a Password %.6a seq %d", &ar->WakeUp.HMAC, &ar->WakeUp.IMAC, &ar->WakeUp.password, ar->WakeUp.seq); + else if (!mDNSSameEthAddress(&ar->WakeUp.HMAC, &ar->WakeUp.IMAC)) + LogMsgNoIdent("Proxying for H-MAC %.6a I-MAC %.6a seq %d", &ar->WakeUp.HMAC, &ar->WakeUp.IMAC, ar->WakeUp.seq); + else + LogMsgNoIdent("Proxying for %.6a seq %d", &ar->WakeUp.HMAC, ar->WakeUp.seq); + } + if (AuthRecord_uDNS(ar)) + LogMsgNoIdent("%7d %7d %7d %7d %s", + ar->ThisAPInterval / mDNSPlatformOneSecond, + (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond, + ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0, + ar->state, ARDisplayString(m, ar)); + else if (ar->resrec.InterfaceID != mDNSInterface_LocalOnly) + LogMsgNoIdent("%7d %7d %7d %7s %s", + ar->ThisAPInterval / mDNSPlatformOneSecond, + ar->AnnounceCount ? (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond : 0, + ar->TimeExpire ? (ar->TimeExpire - now) / mDNSPlatformOneSecond : 0, + info ? info->ifname : "ALL", + ARDisplayString(m, ar)); + else + LogMsgNoIdent(" LO %s", ARDisplayString(m, ar)); + usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000); + } + } + } - LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now); +mDNSexport void udsserver_info(mDNS *const m) + { + const mDNSs32 now = mDNS_TimeNow(m); + mDNSu32 CacheUsed = 0, CacheActive = 0, slot; + int ProxyA = 0, ProxyD = 0; + const CacheGroup *cg; + const CacheRecord *cr; + const DNSQuestion *q; + const DNameListElem *d; + + LogMsgNoIdent("Timenow 0x%08lX (%d)", (mDNSu32)now, now); LogMsgNoIdent("------------ Cache -------------"); - LogMsgNoIdent("Slt Q TTL if U Type rdlen"); + LogMsgNoIdent("Slt Q TTL if U Type rdlen"); for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) for (cg = m->rrcache_hash[slot]; cg; cg=cg->next) { @@ -3668,7 +4187,7 @@ mDNSexport void udsserver_info(mDNS *const m) NetworkInterfaceInfo *info = (NetworkInterfaceInfo *)cr->resrec.InterfaceID; CacheUsed++; if (cr->CRActiveQuestion) CacheActive++; - LogMsgNoIdent("%3d %s%8ld %-6s%s %-6s%s", + LogMsgNoIdent("%3d %s%8ld %-7s%s %-6s%s", slot, cr->CRActiveQuestion ? "*" : " ", remain, @@ -3677,7 +4196,7 @@ mDNSexport void udsserver_info(mDNS *const m) (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? " " : "+", DNSTypeName(cr->resrec.rrtype), CRDisplayString(m, cr)); - usleep(1000); // Limit rate a little so we don't flood syslog too fast + usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000); } } @@ -3688,26 +4207,10 @@ mDNSexport void udsserver_info(mDNS *const m) LogMsgNoIdent("Cache currently contains %lu entities; %lu referenced by active questions", CacheUsed, CacheActive); LogMsgNoIdent("--------- Auth Records ---------"); - if (!m->ResourceRecords) LogMsgNoIdent(""); - else - { - AuthRecord *ar; - LogMsgNoIdent(" Int Next Expire State"); - for (ar = m->ResourceRecords; ar; ar=ar->next) - if (AuthRecord_uDNS(ar)) - LogMsgNoIdent("%7d %7d %7d %7d %s", - ar->ThisAPInterval / mDNSPlatformOneSecond, - (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond, - ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0, - ar->state, ARDisplayString(m, ar)); - else if (ar->resrec.InterfaceID != mDNSInterface_LocalOnly) - LogMsgNoIdent("%7d %7d M %s", - ar->ThisAPInterval / mDNSPlatformOneSecond, - ar->AnnounceCount ? (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond : 0, - ARDisplayString(m, ar)); - else - LogMsgNoIdent(" LO %s", ARDisplayString(m, ar)); - } + LogAuthRecords(m, now, m->ResourceRecords, &ProxyA); + + LogMsgNoIdent("------ Duplicate Records -------"); + LogAuthRecords(m, now, m->DuplicateRecords, &ProxyD); LogMsgNoIdent("----- ServiceRegistrations -----"); if (!m->ServiceRegistrations) LogMsgNoIdent(""); @@ -3727,10 +4230,9 @@ mDNSexport void udsserver_info(mDNS *const m) if (!m->Questions) LogMsgNoIdent(""); else { - DNSQuestion *q; CacheUsed = 0; CacheActive = 0; - LogMsgNoIdent(" Int Next if T NumAns Type Name"); + LogMsgNoIdent(" Int Next if T NumAns Type Name"); for (q = m->Questions; q; q=q->next) { mDNSs32 i = q->ThisQInterval / mDNSPlatformOneSecond; @@ -3738,18 +4240,24 @@ mDNSexport void udsserver_info(mDNS *const m) NetworkInterfaceInfo *info = (NetworkInterfaceInfo *)q->InterfaceID; CacheUsed++; if (q->ThisQInterval) CacheActive++; - LogMsgNoIdent("%6d%6d %-6s%s%s %5d %-6s%##s%s", + LogMsgNoIdent("%6d%6d %-7s%s%s %5d %-6s%##s%s", i, n, info ? info->ifname : mDNSOpaque16IsZero(q->TargetQID) ? "" : "-U-", - mDNSOpaque16IsZero(q->TargetQID) ? " " : q->LongLived ? "L" : "O", // mDNS, long-lived, or one-shot query? + mDNSOpaque16IsZero(q->TargetQID) ? (q->LongLived ? "l" : " ") : (q->LongLived ? "L" : "O"), q->AuthInfo ? "P" : " ", q->CurrentAnswers, DNSTypeName(q->qtype), q->qname.c, q->DuplicateOf ? " (dup)" : ""); - usleep(1000); // Limit rate a little so we don't flood syslog too fast + usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000); } LogMsgNoIdent("%lu question%s; %lu active", CacheUsed, CacheUsed > 1 ? "s" : "", CacheActive); } + LogMsgNoIdent("----- Local-Only Questions -----"); + if (!m->LocalOnlyQuestions) LogMsgNoIdent(""); + else for (q = m->LocalOnlyQuestions; q; q=q->next) + LogMsgNoIdent(" %5d %-6s%##s%s", + q->CurrentAnswers, DNSTypeName(q->qtype), q->qname.c, q->DuplicateOf ? " (dup)" : ""); + LogMsgNoIdent("---- Active Client Requests ----"); if (!all_requests) LogMsgNoIdent(""); else @@ -3757,6 +4265,7 @@ mDNSexport void udsserver_info(mDNS *const m) request_state *req; for (req = all_requests; req; req=req->next) LogClientInfo(m, req); + usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000); } LogMsgNoIdent("-------- NAT Traversals --------"); @@ -3767,16 +4276,17 @@ mDNSexport void udsserver_info(mDNS *const m) for (nat = m->NATTraversals; nat; nat=nat->next) { if (nat->Protocol) - LogMsgNoIdent("%p %s Int %5d Ext %5d Err %d Retry %d Interval %d Expire %d", + LogMsgNoIdent("%p %s Int %5d Ext %5d Err %d Retry %5d Interval %5d Expire %5d", nat, nat->Protocol == NATOp_MapTCP ? "TCP" : "UDP", mDNSVal16(nat->IntPort), mDNSVal16(nat->ExternalPort), nat->Result, nat->retryPortMap ? (nat->retryPortMap - now) / mDNSPlatformOneSecond : 0, nat->retryInterval / mDNSPlatformOneSecond, nat->ExpiryTime ? (nat->ExpiryTime - now) / mDNSPlatformOneSecond : 0); else - LogMsgNoIdent("%p Address Request Retry %d Interval %d", nat, + LogMsgNoIdent("%p Address Request Retry %5d Interval %5d", nat, (m->retryGetAddr - now) / mDNSPlatformOneSecond, m->retryIntervalGetAddr / mDNSPlatformOneSecond); + usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000); } } @@ -3790,7 +4300,7 @@ mDNSexport void udsserver_info(mDNS *const m) } #if APPLE_OSX_mDNSResponder - LogMsgNoIdent("--------- TunnelClients ---------"); + LogMsgNoIdent("--------- TunnelClients --------"); if (!m->TunnelClients) LogMsgNoIdent(""); else { @@ -3799,18 +4309,56 @@ mDNSexport void udsserver_info(mDNS *const m) LogMsgNoIdent("%##s local %.16a %.4a remote %.16a %.4a %5d interval %d", c->dstname.c, &c->loc_inner, &c->loc_outer, &c->rmt_inner, &c->rmt_outer, mDNSVal16(c->rmt_outer_port), c->q.ThisQInterval); } - #endif + #endif // APPLE_OSX_mDNSResponder + + LogMsgNoIdent("---------- Misc State ----------"); + + LogMsgNoIdent("PrimaryMAC: %.6a", &m->PrimaryMAC); + + LogMsgNoIdent("m->SleepState %d (%s) seq %d", + m->SleepState, + m->SleepState == SleepState_Awake ? "Awake" : + m->SleepState == SleepState_Transferring ? "Transferring" : + m->SleepState == SleepState_Sleeping ? "Sleeping" : "?", + m->SleepSeqNum); + + if (!m->SPSSocket) LogMsgNoIdent("Not offering Sleep Proxy Service"); + else LogMsgNoIdent("Offering Sleep Proxy Service: %#s", m->SPSRecords.RR_SRV.resrec.name->c); + + if (m->ProxyRecords == ProxyA + ProxyD) LogMsgNoIdent("ProxyRecords: %d + %d = %d", ProxyA, ProxyD, ProxyA + ProxyD); + else LogMsgNoIdent("ProxyRecords: MISMATCH %d + %d = %d ≠ %d", ProxyA, ProxyD, ProxyA + ProxyD, m->ProxyRecords); + + LogMsgNoIdent("------ Auto Browse Domains -----"); + if (!AutoBrowseDomains) LogMsgNoIdent(""); + else for (d=AutoBrowseDomains; d; d=d->next) LogMsgNoIdent("%##s", d->name.c); + + LogMsgNoIdent("--- Auto Registration Domains --"); + if (!AutoRegistrationDomains) LogMsgNoIdent(""); + else for (d=AutoRegistrationDomains; d; d=d->next) LogMsgNoIdent("%##s", d->name.c); } #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING mDNSexport void uds_validatelists(void) { - request_state *req; + const request_state *req, *p; for (req = all_requests; req; req=req->next) { if (req->next == (request_state *)~0 || (req->sd < 0 && req->sd != -2)) LogMemCorruption("UDS request list: %p is garbage (%d)", req, req->sd); + if (req->primary == req) + LogMemCorruption("UDS request list: req->primary should not point to self %p/%d", req, req->sd); + + if (req->primary && req->replies) + LogMemCorruption("UDS request list: Subordinate request %p/%d/%p should not have replies (%p)", + req, req->sd, req->primary && req->replies); + + p = req->primary; + if ((long)p & 3) + LogMemCorruption("UDS request list: req %p primary %p is misaligned (%d)", req, p, req->sd); + else if (p && (p->next == (request_state *)~0 || (p->sd < 0 && p->sd != -2))) + LogMemCorruption("UDS request list: req %p primary %p is garbage (%d)", req, p, p->sd); + reply_state *rep; for (rep = req->replies; rep; rep=rep->next) if (rep->next == (reply_state *)~0) @@ -3818,24 +4366,24 @@ mDNSexport void uds_validatelists(void) if (req->terminate == connection_termination) { - registered_record_entry *p; - for (p = req->u.reg_recs; p; p=p->next) - if (p->next == (registered_record_entry *)~0) - LogMemCorruption("UDS req->u.reg_recs: %p is garbage", p); + registered_record_entry *r; + for (r = req->u.reg_recs; r; r=r->next) + if (r->next == (registered_record_entry *)~0) + LogMemCorruption("UDS req->u.reg_recs: %p is garbage", r); } else if (req->terminate == regservice_termination_callback) { - service_instance *p; - for (p = req->u.servicereg.instances; p; p=p->next) - if (p->next == (service_instance *)~0) - LogMemCorruption("UDS req->u.servicereg.instances: %p is garbage", p); + service_instance *s; + for (s = req->u.servicereg.instances; s; s=s->next) + if (s->next == (service_instance *)~0) + LogMemCorruption("UDS req->u.servicereg.instances: %p is garbage", s); } else if (req->terminate == browse_termination_callback) { - browser_t *p; - for (p = req->u.browser.browsers; p; p=p->next) - if (p->next == (browser_t *)~0) - LogMemCorruption("UDS req->u.browser.browsers: %p is garbage", p); + browser_t *b; + for (b = req->u.browser.browsers; b; b=b->next) + if (b->next == (browser_t *)~0) + LogMemCorruption("UDS req->u.browser.browsers: %p is garbage", b); } } @@ -3857,38 +4405,37 @@ mDNSexport void uds_validatelists(void) if (d->next == (DNameListElem *)~0 || d->name.c[0] > 63) LogMemCorruption("AutoRegistrationDomains: %p is garbage (%d)", d, d->name.c[0]); } -#endif +#endif // APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING -mDNSlocal int send_msg(reply_state *rep) +mDNSlocal int send_msg(request_state *const req) { + reply_state *const rep = req->replies; // Send the first waiting reply ssize_t nwriten; - if (!rep->msgbuf) { LogMsg("ERROR: send_msg called with NULL message buffer"); return(rep->ts = t_error); } - if (rep->request->no_reply) { freeL("reply_state msgbuf (no_reply)", rep->msgbuf); return(rep->ts = t_complete); } + if (req->no_reply) return(t_complete); ConvertHeaderBytes(rep->mhdr); - nwriten = send(rep->sd, rep->msgbuf + rep->nwriten, rep->len - rep->nwriten, 0); + nwriten = send(req->sd, (char *)&rep->mhdr + rep->nwriten, rep->totallen - rep->nwriten, 0); ConvertHeaderBytes(rep->mhdr); if (nwriten < 0) { - if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK) nwriten = 0; + if (dnssd_errno == dnssd_EINTR || dnssd_errno == dnssd_EWOULDBLOCK) nwriten = 0; else { #if !defined(PLATFORM_NO_EPIPE) - if (dnssd_errno() == EPIPE) - return(rep->request->ts = rep->ts = t_terminated); + if (dnssd_errno == EPIPE) + return(req->ts = t_terminated); else #endif { - LogMsg("send_msg ERROR: failed to write %d bytes to fd %d errno %d %s", - rep->len - rep->nwriten, rep->sd, dnssd_errno(), dnssd_strerror(dnssd_errno())); - return(rep->ts = t_error); + LogMsg("send_msg ERROR: failed to write %d of %d bytes to fd %d errno %d (%s)", + rep->totallen - rep->nwriten, rep->totallen, req->sd, dnssd_errno, dnssd_strerror(dnssd_errno)); + return(t_error); } } } rep->nwriten += nwriten; - if (rep->nwriten == rep->len) { freeL("reply_state msgbuf (t_complete)", rep->msgbuf); rep->ts = t_complete; } - return rep->ts; + return (rep->nwriten == rep->totallen) ? t_complete : t_morecoming; } mDNSexport mDNSs32 udsserver_idle(mDNSs32 nextevent) @@ -3898,53 +4445,60 @@ mDNSexport mDNSs32 udsserver_idle(mDNSs32 nextevent) while (*req) { - if ((*req)->terminate == resolve_termination_callback) - if ((*req)->u.resolve.ReportTime && now - (*req)->u.resolve.ReportTime >= 0) + request_state *const r = *req; + + if (r->terminate == resolve_termination_callback) + if (r->u.resolve.ReportTime && now - r->u.resolve.ReportTime >= 0) { - (*req)->u.resolve.ReportTime = 0; + r->u.resolve.ReportTime = 0; LogMsgNoIdent("Client application bug: DNSServiceResolve(%##s) active for over two minutes. " - "This places considerable burden on the network.", (*req)->u.resolve.qsrv.qname.c); + "This places considerable burden on the network.", r->u.resolve.qsrv.qname.c); } - while ((*req)->replies) // Send queued replies + // Note: Only primary req's have reply lists, not subordinate req's. + while (r->replies) // Send queued replies { transfer_state result; - if ((*req)->replies->next) (*req)->replies->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsMoreComing); - result = send_msg((*req)->replies); // Returns t_morecoming if buffer full because client is not reading + if (r->replies->next) r->replies->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsMoreComing); + result = send_msg(r); // Returns t_morecoming if buffer full because client is not reading if (result == t_complete) { - reply_state *fptr = (*req)->replies; - (*req)->replies = (*req)->replies->next; + reply_state *fptr = r->replies; + r->replies = r->replies->next; freeL("reply_state/udsserver_idle", fptr); - (*req)->time_blocked = 0; // reset failure counter after successful send + r->time_blocked = 0; // reset failure counter after successful send continue; } - else if (result == t_terminated || result == t_error) abort_request(*req); + else if (result == t_terminated || result == t_error) + { + LogMsg("%3d: Could not write data to client because of error - aborting connection", r->sd); + LogClientInfo(&mDNSStorage, r); + abort_request(r); + } break; } - if ((*req)->replies) // If we failed to send everything, check our time_blocked timer + if (r->replies) // If we failed to send everything, check our time_blocked timer { - if (!(*req)->time_blocked) (*req)->time_blocked = NonZeroTime(now); - if (now - (*req)->time_blocked >= 60 * mDNSPlatformOneSecond) + if (!r->time_blocked) r->time_blocked = NonZeroTime(now); + if (now - r->time_blocked >= 60 * mDNSPlatformOneSecond) { - LogMsg("Could not write data to client %d after %ld seconds - aborting connection", - (*req)->sd, (now - (*req)->time_blocked) / mDNSPlatformOneSecond); - LogClientInfo(&mDNSStorage, *req); - abort_request(*req); + LogMsg("%3d: Could not write data to client after %ld seconds - aborting connection", r->sd, + (now - r->time_blocked) / mDNSPlatformOneSecond); + LogClientInfo(&mDNSStorage, r); + abort_request(r); } else if (nextevent - now > mDNSPlatformOneSecond) nextevent = now + mDNSPlatformOneSecond; } - if (!dnssd_SocketValid((*req)->sd)) // If this request is finished, unlink it from the list and free the memory + if (!dnssd_SocketValid(r->sd)) // If this request is finished, unlink it from the list and free the memory { // Since we're already doing a list traversal, we unlink the request directly instead of using AbortUnlinkAndFree() - request_state *tmp = *req; - *req = tmp->next; - freeL("request_state/udsserver_idle", tmp); + *req = r->next; + freeL("request_state/udsserver_idle", r); } else - req = &(*req)->next; + req = &r->next; } return nextevent; } @@ -3954,10 +4508,10 @@ struct CompileTimeAssertionChecks_uds_daemon // 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_request_state [(sizeof(request_state) <= 1800) ? 1 : -1]; - char sizecheck_registered_record_entry[(sizeof(registered_record_entry) <= 30) ? 1 : -1]; - char sizecheck_service_instance [(sizeof(service_instance) <= 6000) ? 1 : -1]; - char sizecheck_browser_t [(sizeof(browser_t) <= 1000) ? 1 : -1]; - char sizecheck_reply_hdr [(sizeof(reply_hdr) <= 20) ? 1 : -1]; - char sizecheck_reply_state [(sizeof(reply_state) <= 40) ? 1 : -1]; + char sizecheck_request_state [(sizeof(request_state) <= 1760) ? 1 : -1]; + char sizecheck_registered_record_entry[(sizeof(registered_record_entry) <= 40) ? 1 : -1]; + char sizecheck_service_instance [(sizeof(service_instance) <= 6552) ? 1 : -1]; + char sizecheck_browser_t [(sizeof(browser_t) <= 992) ? 1 : -1]; + char sizecheck_reply_hdr [(sizeof(reply_hdr) <= 12) ? 1 : -1]; + char sizecheck_reply_state [(sizeof(reply_state) <= 64) ? 1 : -1]; }; diff --git a/mDNSShared/uds_daemon.h b/mDNSShared/uds_daemon.h index 0d102e4..b6d966e 100644 --- a/mDNSShared/uds_daemon.h +++ b/mDNSShared/uds_daemon.h @@ -23,6 +23,15 @@ Change History (most recent first): $Log: uds_daemon.h,v $ +Revision 1.27 2009/04/30 20:07:51 mcguire + Support multiple UDSs from launchd + +Revision 1.26 2008/10/02 22:26:21 cheshire +Moved declaration of BPF_fd from uds_daemon.c to mDNSMacOSX.c, where it really belongs + +Revision 1.25 2008/09/27 01:08:25 cheshire +Added external declaration of "dnssd_sock_t BPF_fd" + Revision 1.24 2007/09/19 20:25:17 cheshire Deleted outdated comment @@ -109,11 +118,11 @@ Changes necessary to support mDNSResponder on Linux. #define SRS_PORT(S) mDNSVal16((S)->RR_SRV.resrec.rdata->u.srv.port) -extern int udsserver_init(dnssd_sock_t skt); +extern int udsserver_init(dnssd_sock_t skts[], mDNSu32 count); extern mDNSs32 udsserver_idle(mDNSs32 nextevent); extern void udsserver_info(mDNS *const m); // print out info about current state extern void udsserver_handle_configchange(mDNS *const m); -extern int udsserver_exit(dnssd_sock_t skt); // should be called prior to app exit +extern int udsserver_exit(void); // should be called prior to app exit /* Routines that uds_daemon expects to link against: */ diff --git a/mDNSVxWorks/mDNSVxWorks.c b/mDNSVxWorks/mDNSVxWorks.c index 6a72d23..97a597b 100644 --- a/mDNSVxWorks/mDNSVxWorks.c +++ b/mDNSVxWorks/mDNSVxWorks.c @@ -17,6 +17,12 @@ Change History (most recent first): $Log: mDNSVxWorks.c,v $ +Revision 1.35 2009/01/13 05:31:35 mkrochma + Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy + +Revision 1.34 2008/10/03 18:25:18 cheshire +Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);" + Revision 1.33 2007/03/22 18:31:48 cheshire Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy @@ -251,7 +257,7 @@ mStatus mDNSPlatformInit( mDNS * const inMDNS ) // Do minimal initialization to get the task started and so we can cleanup safely if an error occurs. - memset( &gMDNSPlatformSupport, 0, sizeof( gMDNSPlatformSupport ) ); + mDNSPlatformMemZero( &gMDNSPlatformSupport, sizeof( gMDNSPlatformSupport ) ); if( !inMDNS->p ) inMDNS->p = &gMDNSPlatformSupport; inMDNS->p->unicastSS.info = NULL; inMDNS->p->unicastSS.sockV4 = kInvalidSocketRef; @@ -896,7 +902,7 @@ mDNSlocal mStatus UpdateInterfaceList( mDNS *const inMDNS, mDNSs32 inUTC ) struct in6_ifreq ifr6; sa6 = (struct sockaddr_in6 *) ifa->ifa_addr; - memset( &ifr6, 0, sizeof( ifr6 ) ); + mDNSPlatformMemZero( &ifr6, sizeof( ifr6 ) ); strcpy( ifr6.ifr_name, ifa->ifa_name ); ifr6.ifr_addr = *sa6; if( ioctl( infoSock, SIOCGIFAFLAG_IN6, (int) &ifr6 ) != -1 ) @@ -1374,7 +1380,7 @@ mDNSlocal mStatus SetupSocket( mDNS *const inMDNS, const mDNSAddr *inAddr, mDNSB // Start listening for packets. - memset( &sa4, 0, sizeof( sa4 ) ); + mDNSPlatformMemZero( &sa4, sizeof( sa4 ) ); sa4.sin_len = sizeof( sa4 ); sa4.sin_family = AF_INET; sa4.sin_port = port.NotAnInteger; @@ -1431,7 +1437,7 @@ mDNSlocal mStatus SetupSocket( mDNS *const inMDNS, const mDNSAddr *inAddr, mDNSB // Start listening for packets. - memset( &sa6, 0, sizeof( sa6 ) ); + mDNSPlatformMemZero( &sa6, sizeof( sa6 ) ); sa6.sin6_len = sizeof( sa6 ); sa6.sin6_family = AF_INET6; sa6.sin6_port = port.NotAnInteger; @@ -1592,7 +1598,7 @@ mDNSlocal mStatus ProcessCommand( mDNS * const inMDNS ) SetupActiveInterfaces( inMDNS, utc ); mDNSPlatformUnlock( inMDNS ); - if( inMDNS->MainCallback ) inMDNS->MainCallback( inMDNS, mStatus_ConfigChanged ); + mDNS_ConfigChanged(inMDNS); break; case kMDNSPipeCommandCodeQuit: // Quit: just set a flag so the task exits cleanly. diff --git a/mDNSVxWorks/mDNSVxWorksIPv4Only.c b/mDNSVxWorks/mDNSVxWorksIPv4Only.c index 19020a9..a4a30a3 100644 --- a/mDNSVxWorks/mDNSVxWorksIPv4Only.c +++ b/mDNSVxWorks/mDNSVxWorksIPv4Only.c @@ -21,6 +21,15 @@ Change History (most recent first): $Log: mDNSVxWorksIPv4Only.c,v $ +Revision 1.34 2009/01/13 05:31:35 mkrochma + Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy + +Revision 1.33 2008/11/04 19:51:13 cheshire +Updated comment about MAX_ESCAPED_DOMAIN_NAME size (should be 1009, not 1005) + +Revision 1.32 2008/10/03 18:25:18 cheshire +Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);" + Revision 1.31 2007/03/22 18:31:49 cheshire Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy @@ -94,7 +103,7 @@ Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again Revision 1.10 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. +Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1009) instead of 256-byte buffers. Revision 1.9 2003/11/14 20:59:09 cheshire Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h. @@ -410,7 +419,7 @@ mStatus mDNSPlatformInit( mDNS * const inMDNS ) // Initialize variables. - memset( &gMDNSPlatformSupport, 0, sizeof( gMDNSPlatformSupport ) ); + mDNSPlatformMemZero( &gMDNSPlatformSupport, sizeof( gMDNSPlatformSupport ) ); inMDNS->p = &gMDNSPlatformSupport; inMDNS->p->commandPipe = ERROR; inMDNS->p->task = ERROR; @@ -549,7 +558,7 @@ mStatus item = (MDNSInterfaceItem *) inInterfaceID; check( item->sendingSocketRef != kInvalidSocketRef ); - memset( &addr, 0, sizeof( addr ) ); + mDNSPlatformMemZero( &addr, sizeof( addr ) ); addr.sin_family = AF_INET; addr.sin_port = inDstPort.NotAnInteger; addr.sin_addr.s_addr = inDstIP->ip.v4.NotAnInteger; @@ -1237,7 +1246,7 @@ mDNSlocal mStatus // Bind to the multicast DNS address and port 5353. - memset( &addr, 0, sizeof( addr ) ); + mDNSPlatformMemZero( &addr, sizeof( addr ) ); addr.sin_family = AF_INET; addr.sin_port = inPort.NotAnInteger; addr.sin_addr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger; @@ -1252,7 +1261,7 @@ mDNSlocal mStatus // Bind to the interface address and multicast DNS port. ip.NotAnInteger = ipv4->sin_addr.s_addr; - memset( &addr, 0, sizeof( addr ) ); + mDNSPlatformMemZero( &addr, sizeof( addr ) ); addr.sin_family = AF_INET; addr.sin_port = MulticastDNSPort.NotAnInteger; addr.sin_addr.s_addr = ip.NotAnInteger; @@ -1447,14 +1456,11 @@ mDNSlocal void ProcessCommandReconfigure( mDNS *inMDNS ) // Inform clients of the change. - if( inMDNS->MainCallback ) - { - inMDNS->MainCallback( inMDNS, mStatus_ConfigChanged ); - } + mDNS_ConfigChanged(m); // Force mDNS to update. - mDNSCoreMachineSleep( inMDNS, mDNSfalse ); + mDNSCoreMachineSleep( inMDNS, mDNSfalse ); // What is this for? Mac OS X does not do this // Bump the config ID so the main processing loop detects the configuration change. diff --git a/mDNSWindows/ControlPanel/ConfigPropertySheet.cpp b/mDNSWindows/ControlPanel/ConfigPropertySheet.cpp index bcf0f7a..ea2d9b7 100755 --- a/mDNSWindows/ControlPanel/ConfigPropertySheet.cpp +++ b/mDNSWindows/ControlPanel/ConfigPropertySheet.cpp @@ -17,6 +17,13 @@ Change History (most recent first): $Log: ConfigPropertySheet.cpp,v $ +Revision 1.7 2009/07/01 19:20:37 herscher + UI changes for configuring sleep proxy settings. + +Revision 1.6 2009/03/30 19:57:45 herscher + Current Bonjour code does not compile on Windows + Move build train to Visual Studio 2005 + Revision 1.5 2006/08/14 23:25:28 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -57,6 +64,7 @@ CConfigPropertySheet::CConfigPropertySheet() AddPage(&m_firstPage); AddPage(&m_secondPage); AddPage(&m_thirdPage); + AddPage(&m_fourthPage ); InitializeCriticalSection( &m_lock ); } @@ -125,7 +133,7 @@ CConfigPropertySheet::OnCommand(WPARAM wParam, LPARAM lParam) // CConfigPropertySheet::OnDataReady //--------------------------------------------------------------------------------------------------------------------------- -LONG +LRESULT CConfigPropertySheet::OnDataReady(WPARAM inWParam, LPARAM inLParam) { if (WSAGETSELECTERROR(inLParam) && !(HIWORD(inLParam))) @@ -154,7 +162,7 @@ CConfigPropertySheet::OnDataReady(WPARAM inWParam, LPARAM inLParam) // CConfigPropertySheet::OnRegistryChanged //--------------------------------------------------------------------------------------------------------------------------- -afx_msg LONG +afx_msg LRESULT CConfigPropertySheet::OnRegistryChanged( WPARAM inWParam, LPARAM inLParam ) { DEBUG_UNUSED( inWParam ); diff --git a/mDNSWindows/ControlPanel/ConfigPropertySheet.h b/mDNSWindows/ControlPanel/ConfigPropertySheet.h index b92fc1f..00dd137 100755 --- a/mDNSWindows/ControlPanel/ConfigPropertySheet.h +++ b/mDNSWindows/ControlPanel/ConfigPropertySheet.h @@ -17,6 +17,13 @@ Change History (most recent first): $Log: ConfigPropertySheet.h,v $ +Revision 1.7 2009/07/01 19:20:37 herscher + UI changes for configuring sleep proxy settings. + +Revision 1.6 2009/03/30 19:58:47 herscher + Current Bonjour code does not compile on Windows + Move build train to Visual Studio 2005 + Revision 1.5 2006/08/14 23:25:28 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -33,6 +40,7 @@ Revision 1.4 2005/03/03 19:55:21 shersche #include "FirstPage.h" #include "SecondPage.h" #include "ThirdPage.h" +#include "FourthPage.h" #include #include @@ -60,6 +68,7 @@ protected: CFirstPage m_firstPage; CSecondPage m_secondPage; CThirdPage m_thirdPage; + CFourthPage m_fourthPage; //{{AFX_VIRTUAL(CConfigPropertySheet) //}}AFX_VIRTUAL @@ -72,11 +81,8 @@ protected: afx_msg BOOL OnInitDialog(); afx_msg BOOL OnCommand( WPARAM wParam, LPARAM lParam ); - - afx_msg LONG OnDataReady( WPARAM inWParam, LPARAM inLParam ); - - afx_msg LONG OnRegistryChanged( WPARAM inWParam, LPARAM inLParam ); - + afx_msg LRESULT OnDataReady( WPARAM inWParam, LPARAM inLParam ); + afx_msg LRESULT OnRegistryChanged( WPARAM inWParam, LPARAM inLParam ); void OnEndDialog(); private: diff --git a/mDNSWindows/ControlPanel/ControlPanel.cpp b/mDNSWindows/ControlPanel/ControlPanel.cpp index 9348d53..fb85d9a 100755 --- a/mDNSWindows/ControlPanel/ControlPanel.cpp +++ b/mDNSWindows/ControlPanel/ControlPanel.cpp @@ -17,6 +17,10 @@ Change History (most recent first): $Log: ControlPanel.cpp,v $ +Revision 1.5 2009/03/30 20:00:19 herscher + Current Bonjour code does not compile on Windows + Move build train to Visual Studio 2005 + Revision 1.4 2007/04/27 20:42:11 herscher mDNS: Bonjour Control Panel for Windows doesn't work on Vista @@ -304,7 +308,7 @@ CCPApp::OnExit() //--------------------------------------------------------------------------------------------------------------------------- LRESULT -CCPApp::OnCplMsg(HWND hWndCPl, UINT uMsg, LONG lParam1, LONG lParam2) +CCPApp::OnCplMsg(HWND hWndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2) { LRESULT lResult = 1; diff --git a/mDNSWindows/ControlPanel/ControlPanel.rc b/mDNSWindows/ControlPanel/ControlPanel.rc index 72bae45..035b0d1 100644 --- a/mDNSWindows/ControlPanel/ControlPanel.rc +++ b/mDNSWindows/ControlPanel/ControlPanel.rc @@ -136,6 +136,16 @@ BEGIN PUSHBUTTON "Remove",IDC_REMOVE_BROWSE_DOMAIN,205,100,50,14 END +IDR_APPLET_PAGE4 DIALOGEX 0, 0, 262, 140 +STYLE DS_SETFONT | WS_CHILD | WS_CAPTION +CAPTION "Power Management" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + CONTROL "Allow Bonjour to wake this machine on network access.",IDC_POWER_MANAGEMENT, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,19,199,8 + LTEXT "Warning: Allowing Bonjour to bring the computer out of standby may cause this computer to periodically wakeup to refresh its network state.",IDC_STATIC,13,41,227,20 +END + IDR_ADD_BROWSE_DOMAIN DIALOGEX 0, 0, 230, 95 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU diff --git a/mDNSWindows/ControlPanel/ControlPanel.vcproj b/mDNSWindows/ControlPanel/ControlPanel.vcproj index 5fcd30d..ffdb6ff 100755 --- a/mDNSWindows/ControlPanel/ControlPanel.vcproj +++ b/mDNSWindows/ControlPanel/ControlPanel.vcproj @@ -1,149 +1,417 @@ + ProjectGUID="{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}" + Keyword="MFCProj" + > + Name="Win32" + /> + + + + ATLMinimizesCRunTimeLibraryUsage="false" + > + + + + + + SuppressStartupBanner="true" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + DisableSpecificWarnings="4311;4312" + /> + + + Name="VCPreLinkEventTool" + /> + ImportLibrary=".\$(OutDir)\Bonjour.lib" + TargetMachine="1" + /> + + + + + + + + + + + + + + - + HeaderFileName="" + /> + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared" + PreprocessorDefinitions="WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1" + RuntimeLibrary="1" + UsePrecompiledHeader="0" + PrecompiledHeaderThrough="" + PrecompiledHeaderFile="" + AssemblerListingLocation="$(IntDir)\" + ObjectFile="$(IntDir)\" + ProgramDataBaseFileName="$(IntDir)\vc80.pdb" + WarningLevel="4" + SuppressStartupBanner="true" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + DisableSpecificWarnings="4311;4312" + /> + Name="VCManagedResourceCompilerTool" + /> + Culture="1033" + AdditionalIncludeDirectories="../" + /> + + + + Name="VCManifestTool" + AdditionalManifestFiles="res\ControlPanel64.manifest" + /> + Name="VCXDCMakeTool" + /> + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + + + ATLMinimizesCRunTimeLibraryUsage="false" + > + + + + + + SuppressStartupBanner="true" + DisableSpecificWarnings="4702" + /> + Name="VCManagedResourceCompilerTool" + /> + + + ImportLibrary=".\$(OutDir)\Bonjour.lib" + TargetMachine="1" + /> + + + + + + + + + + + + + + + HeaderFileName="" + /> - + Name="VCCLCompilerTool" + Optimization="2" + InlineFunctionExpansion="1" + AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1" + StringPooling="true" + RuntimeLibrary="0" + EnableFunctionLevelLinking="true" + UsePrecompiledHeader="0" + AssemblerListingLocation="$(IntDir)\" + ObjectFile="$(IntDir)\" + ProgramDataBaseFileName="$(IntDir)\vc80.pdb" + WarningLevel="4" + SuppressStartupBanner="true" + DisableSpecificWarnings="4702" + /> + Name="VCManagedResourceCompilerTool" + /> + Culture="1033" + AdditionalIncludeDirectories="../" + /> + + + Name="VCALinkTool" + /> + Name="VCManifestTool" + AdditionalManifestFiles="res\ControlPanel64.manifest" + /> + Name="VCXDCMakeTool" + /> + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + + + @@ -151,197 +419,384 @@ + Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" + > + RelativePath="ConfigDialog.cpp" + > + + + + Name="Debug|x64" + > + PreprocessorDefinitions="" + /> + + + + Name="Release|x64" + > + PreprocessorDefinitions="" + /> + RelativePath="ConfigPropertySheet.cpp" + > + + + + Name="Debug|x64" + > + PreprocessorDefinitions="" + /> + Name="Release|Win32" + > + PreprocessorDefinitions="" + /> + + + + RelativePath="ControlPanel.cpp" + > + Name="Debug|Win32" + > + PreprocessorDefinitions="" + /> + Name="Debug|x64" + > + + + + PreprocessorDefinitions="" + /> + + + + RelativePath="ControlPanel.def" + > + RelativePath="FirstPage.cpp" + > + Name="Debug|Win32" + > + PreprocessorDefinitions="" + /> + Name="Debug|x64" + > + + + + + + + PreprocessorDefinitions="" + /> + RelativePath=".\FourthPage.cpp" + > + + + Name="Debug|Win32" + > + PreprocessorDefinitions="" + /> + + + + + + + Name="Release|x64" + > + PreprocessorDefinitions="" + /> + RelativePath="SharedSecret.cpp" + > + RelativePath="stdafx.cpp" + > + + + + Name="Debug|x64" + > + UsePrecompiledHeader="0" + /> + Name="Release|Win32" + > + UsePrecompiledHeader="0" + /> + + + + RelativePath="ThirdPage.cpp" + > + Filter="h;hpp;hxx;hm;inl" + > + RelativePath="ConfigDialog.h" + > + RelativePath="ConfigPropertySheet.h" + > + RelativePath="ControlPanel.h" + > + RelativePath="FirstPage.h" + > + RelativePath=".\FourthPage.h" + > + RelativePath="Resource.h" + > + RelativePath="SecondPage.h" + > + RelativePath="SharedSecret.h" + > + RelativePath="stdafx.h" + > + RelativePath="ThirdPage.h" + > + Filter="ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" + > + RelativePath="res\configurator.ico" + > + RelativePath="res\controlpanel.ico" + > + RelativePath=".\res\ControlPanel.rc2" + > + RelativePath=".\ControlPanelDll.rc" + > + RelativePath="res\failure.ico" + > + RelativePath="res\success.ico" + > + > + + + + + + + RelativePath="..\..\mDNSShared\dns_sd.h" + > + RelativePath="..\Secret.c" + > + RelativePath="..\Secret.h" + > + RelativePath="..\WinServices.cpp" + > + RelativePath="..\WinServices.h" + > + diff --git a/mDNSWindows/ControlPanel/ControlPanelDll.rc b/mDNSWindows/ControlPanel/ControlPanelDll.rc index bcf8cb1..5d1f495 100644 --- a/mDNSWindows/ControlPanel/ControlPanelDll.rc +++ b/mDNSWindows/ControlPanel/ControlPanelDll.rc @@ -62,15 +62,6 @@ BEGIN END -///////////////////////////////////////////////////////////////////////////// -// -// RT_MANIFEST -// - -2 RT_MANIFEST "res\\ControlPanel.dll.manifest" - - - #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // diff --git a/mDNSWindows/ControlPanel/ControlPanelExe.rc b/mDNSWindows/ControlPanel/ControlPanelExe.rc index 995997c..4ea5f95 100644 --- a/mDNSWindows/ControlPanel/ControlPanelExe.rc +++ b/mDNSWindows/ControlPanel/ControlPanelExe.rc @@ -62,15 +62,6 @@ BEGIN END -///////////////////////////////////////////////////////////////////////////// -// -// RT_MANIFEST -// - -1 RT_MANIFEST "res\\ControlPanel.exe.manifest" - - - #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // diff --git a/mDNSWindows/ControlPanel/ControlPanelExe.vcproj b/mDNSWindows/ControlPanel/ControlPanelExe.vcproj index dee51a8..c97f430 100755 --- a/mDNSWindows/ControlPanel/ControlPanelExe.vcproj +++ b/mDNSWindows/ControlPanel/ControlPanelExe.vcproj @@ -1,147 +1,415 @@ + Keyword="MFCProj" + > + Name="Win32" + /> + + + + ATLMinimizesCRunTimeLibraryUsage="false" + > + + + + + + DisableSpecificWarnings="4311;4312" + /> + + + Name="VCPreLinkEventTool" + /> + TargetMachine="1" + /> + + + + + + + + + + + + + + - + MkTypLibCompatible="false" + TargetEnvironment="3" + /> + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared" + PreprocessorDefinitions="WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;WINVER=0x0501;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1" + StringPooling="true" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="1" + UsePrecompiledHeader="0" + PrecompiledHeaderThrough="" + PrecompiledHeaderFile="" + AssemblerListingLocation="$(IntDir)\" + ObjectFile="$(IntDir)\" + ProgramDataBaseFileName="$(IntDir)\vc80.pdb" + WarningLevel="4" + SuppressStartupBanner="true" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + CallingConvention="0" + DisableSpecificWarnings="4311;4312" + /> + Name="VCManagedResourceCompilerTool" + /> + AdditionalIncludeDirectories="../" + /> + + + + + + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + Name="VCWebDeploymentTool" + /> + Name="VCPostBuildEventTool" + /> + CharacterSet="2" + > + + + + + + SuppressStartupBanner="true" + DisableSpecificWarnings="4702" + /> + + Name="VCResourceCompilerTool" + PreprocessorDefinitions="NDEBUG" + Culture="1033" + AdditionalIncludeDirectories="../" + /> + + TargetMachine="1" + /> + + + + + + + + + + + + + + - + MkTypLibCompatible="false" + TargetEnvironment="3" + /> + Name="VCCLCompilerTool" + Optimization="2" + InlineFunctionExpansion="1" + AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0501;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1" + StringPooling="true" + MinimalRebuild="false" + RuntimeLibrary="0" + EnableFunctionLevelLinking="true" + TreatWChar_tAsBuiltInType="true" + UsePrecompiledHeader="0" + AssemblerListingLocation="$(IntDir)\" + ObjectFile="$(IntDir)\" + ProgramDataBaseFileName="$(IntDir)\vc80.pdb" + WarningLevel="4" + SuppressStartupBanner="true" + DisableSpecificWarnings="4702" + /> + Name="VCManagedResourceCompilerTool" + /> + AdditionalIncludeDirectories="../" + /> + + Name="VCLinkerTool" + AdditionalOptions="/NXCOMPAT /DYNAMICBASE" + AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib" + OutputFile="$(OutDir)/ControlPanel.exe" + LinkIncremental="1" + SuppressStartupBanner="true" + ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb" + SubSystem="2" + OptimizeReferences="0" + EnableCOMDATFolding="0" + EntryPointSymbol="wWinMainCRTStartup" + TargetMachine="17" + /> + Name="VCALinkTool" + /> + Name="VCManifestTool" + AdditionalManifestFiles="res\ControlPanel64.manifest" + /> + Name="VCXDCMakeTool" + /> + Name="VCBscMakeTool" + /> + + + + @@ -149,177 +417,337 @@ + Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" + > + RelativePath="ConfigDialog.cpp" + > + + + + Name="Debug|x64" + > + PreprocessorDefinitions="" + /> + Name="Release|Win32" + > + PreprocessorDefinitions="" + /> + + + + RelativePath="ConfigPropertySheet.cpp" + > + Name="Debug|Win32" + > + PreprocessorDefinitions="" + /> + Name="Debug|x64" + > + + + + PreprocessorDefinitions="" + /> + + + + RelativePath=".\ControlPanelExe.cpp" + > + RelativePath="FirstPage.cpp" + > + + + + Name="Debug|x64" + > + PreprocessorDefinitions="" + /> + Name="Release|Win32" + > + PreprocessorDefinitions="" + /> + + + + + + RelativePath="SecondPage.cpp" + > + Name="Debug|Win32" + > + PreprocessorDefinitions="" + /> + Name="Debug|x64" + > + + + + PreprocessorDefinitions="" + /> + + + + RelativePath="SharedSecret.cpp" + > + RelativePath="stdafx.cpp" + > + Name="Debug|Win32" + > + UsePrecompiledHeader="0" + /> + Name="Debug|x64" + > + + + + UsePrecompiledHeader="0" + /> + + + + RelativePath="ThirdPage.cpp" + > + Filter="h;hpp;hxx;hm;inl" + > + RelativePath="ConfigDialog.h" + > + RelativePath="ConfigPropertySheet.h" + > + RelativePath=".\ControlPanelExe.h" + > + RelativePath="FirstPage.h" + > + RelativePath=".\FourthPage.h" + > + RelativePath="Resource.h" + > + RelativePath="SecondPage.h" + > + RelativePath="SharedSecret.h" + > + RelativePath="stdafx.h" + > + RelativePath="ThirdPage.h" + > + Filter="ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" + > + RelativePath="res\configurator.ico" + > + RelativePath="res\controlpanel.ico" + > + RelativePath=".\res\ControlPanel.rc2" + > + RelativePath=".\ControlPanelExe.rc" + > + RelativePath="res\failure.ico" + > + RelativePath="res\success.ico" + > + > + + + + + + + RelativePath="..\..\mDNSShared\dns_sd.h" + > + RelativePath="..\Secret.c" + > + RelativePath="..\Secret.h" + > + RelativePath="..\WinServices.cpp" + > + RelativePath="..\WinServices.h" + > diff --git a/mDNSWindows/ControlPanel/FirstPage.cpp b/mDNSWindows/ControlPanel/FirstPage.cpp index 5d6c90a..3fc3180 100755 --- a/mDNSWindows/ControlPanel/FirstPage.cpp +++ b/mDNSWindows/ControlPanel/FirstPage.cpp @@ -17,6 +17,9 @@ Change History (most recent first): $Log: FirstPage.cpp,v $ +Revision 1.7 2009/06/22 23:25:10 herscher + ControlPanel doesn't display key and password in dialog box. Refactor Lsa calls into Secret.h and Secret.c, which is used by both the ControlPanel and mDNSResponder system service. + Revision 1.6 2006/08/14 23:25:28 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -132,7 +135,7 @@ void CFirstPage::OnBnClickedSharedSecret() CSharedSecret dlg; - dlg.m_key = name; + dlg.Load( name ); if ( dlg.DoModal() == IDOK ) { diff --git a/mDNSWindows/ControlPanel/FourthPage.cpp b/mDNSWindows/ControlPanel/FourthPage.cpp new file mode 100755 index 0000000..c1f9849 --- /dev/null +++ b/mDNSWindows/ControlPanel/FourthPage.cpp @@ -0,0 +1,191 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + Change History (most recent first): + +$Log: FourthPage.cpp,v $ +Revision 1.1 2009/07/01 19:20:37 herscher + UI changes for configuring sleep proxy settings. + + + +*/ + +#include "FourthPage.h" +#include "resource.h" + +#include "ConfigPropertySheet.h" +#include "SharedSecret.h" + +#include + +#define MAX_KEY_LENGTH 255 + + +IMPLEMENT_DYNCREATE(CFourthPage, CPropertyPage) + + +//--------------------------------------------------------------------------------------------------------------------------- +// CFourthPage::CFourthPage +//--------------------------------------------------------------------------------------------------------------------------- + +CFourthPage::CFourthPage() +: + CPropertyPage(CFourthPage::IDD) +{ + //{{AFX_DATA_INIT(CFourthPage) + //}}AFX_DATA_INIT +} + + +//--------------------------------------------------------------------------------------------------------------------------- +// CFourthPage::~CFourthPage +//--------------------------------------------------------------------------------------------------------------------------- + +CFourthPage::~CFourthPage() +{ +} + + +//--------------------------------------------------------------------------------------------------------------------------- +// CFourthPage::DoDataExchange +//--------------------------------------------------------------------------------------------------------------------------- + +void CFourthPage::DoDataExchange(CDataExchange* pDX) +{ + CPropertyPage::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CFourthPage) + //}}AFX_DATA_MAP + DDX_Control(pDX, IDC_POWER_MANAGEMENT, m_checkBox); +} + +BEGIN_MESSAGE_MAP(CFourthPage, CPropertyPage) + //{{AFX_MSG_MAP(CFourthPage) + //}}AFX_MSG_MAP + ON_BN_CLICKED(IDC_POWER_MANAGEMENT, &CFourthPage::OnBnClickedPowerManagement) +END_MESSAGE_MAP() + + +//--------------------------------------------------------------------------------------------------------------------------- +// CFourthPage::SetModified +//--------------------------------------------------------------------------------------------------------------------------- + +void CFourthPage::SetModified( BOOL bChanged ) +{ + m_modified = bChanged; + + CPropertyPage::SetModified( bChanged ); +} + + +//--------------------------------------------------------------------------------------------------------------------------- +// CFourthPage::OnSetActive +//--------------------------------------------------------------------------------------------------------------------------- + +BOOL +CFourthPage::OnSetActive() +{ + CConfigPropertySheet * psheet; + HKEY key = NULL; + DWORD dwSize; + DWORD enabled; + DWORD err; + BOOL b = CPropertyPage::OnSetActive(); + + psheet = reinterpret_cast(GetParent()); + require_quiet( psheet, exit ); + + m_checkBox.SetCheck( 0 ); + + // Now populate the browse domain box + + err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", &key ); + require_noerr( err, exit ); + + dwSize = sizeof( DWORD ); + err = RegQueryValueEx( key, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize ); + require_noerr( err, exit ); + + m_checkBox.SetCheck( enabled ); + +exit: + + if ( key ) + { + RegCloseKey( key ); + } + + return b; +} + + +//--------------------------------------------------------------------------------------------------------------------------- +// CFourthPage::OnOK +//--------------------------------------------------------------------------------------------------------------------------- + +void +CFourthPage::OnOK() +{ + if ( m_modified ) + { + Commit(); + } +} + + + +//--------------------------------------------------------------------------------------------------------------------------- +// CFourthPage::Commit +//--------------------------------------------------------------------------------------------------------------------------- + +void +CFourthPage::Commit() +{ + HKEY key = NULL; + DWORD enabled; + DWORD err; + + err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", &key ); + require_noerr( err, exit ); + + enabled = m_checkBox.GetCheck(); + err = RegSetValueEx( key, L"Enabled", NULL, REG_DWORD, (LPBYTE) &enabled, sizeof( enabled ) ); + require_noerr( err, exit ); + +exit: + + if ( key ) + { + RegCloseKey( key ); + } +} + + +//--------------------------------------------------------------------------------------------------------------------------- +// CFourthPage::OnBnClickedRemoveBrowseDomain +//--------------------------------------------------------------------------------------------------------------------------- + + +void CFourthPage::OnBnClickedPowerManagement() +{ + char buf[ 256 ]; + + sprintf( buf, "check box: %d", m_checkBox.GetCheck() ); + OutputDebugStringA( buf ); + // TODO: Add your control notification handler code here + + SetModified( TRUE ); +} diff --git a/mDNSWindows/ControlPanel/FourthPage.h b/mDNSWindows/ControlPanel/FourthPage.h new file mode 100755 index 0000000..9ec8a29 --- /dev/null +++ b/mDNSWindows/ControlPanel/FourthPage.h @@ -0,0 +1,93 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + Change History (most recent first): + +$Log: FourthPage.h,v $ +Revision 1.1 2009/07/01 19:20:37 herscher + UI changes for configuring sleep proxy settings. + + +*/ + +#pragma once + +#include "stdafx.h" +#include "resource.h" + +#include +#include +#include "afxcmn.h" + +#include "afxwin.h" + + + + + +//--------------------------------------------------------------------------------------------------------------------------- +// CFourthPage +//--------------------------------------------------------------------------------------------------------------------------- + +class CFourthPage : public CPropertyPage +{ +public: + CFourthPage(); + ~CFourthPage(); + +protected: + + //{{AFX_DATA(CFourthPage) + enum { IDD = IDR_APPLET_PAGE4 }; + //}}AFX_DATA + + //{{AFX_VIRTUAL(CFourthPage) + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + + DECLARE_DYNCREATE(CFourthPage) + + //{{AFX_MSG(CFourthPage) + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +private: + + typedef std::list StringList; + + afx_msg BOOL + OnSetActive(); + + afx_msg void + OnOK(); + + void + SetModified( BOOL bChanged = TRUE ); + + void + Commit(); + + BOOL m_modified; + +public: +private: + + CButton m_checkBox; + +public: + + afx_msg void OnBnClickedPowerManagement(); +}; diff --git a/mDNSWindows/ControlPanel/SharedSecret.cpp b/mDNSWindows/ControlPanel/SharedSecret.cpp index 8633fd7..b74366e 100644 --- a/mDNSWindows/ControlPanel/SharedSecret.cpp +++ b/mDNSWindows/ControlPanel/SharedSecret.cpp @@ -17,6 +17,9 @@ Change History (most recent first): $Log: SharedSecret.cpp,v $ +Revision 1.7 2009/06/22 23:25:11 herscher + ControlPanel doesn't display key and password in dialog box. Refactor Lsa calls into Secret.h and Secret.c, which is used by both the ControlPanel and mDNSResponder system service. + Revision 1.6 2007/06/12 20:06:06 herscher ControlPanel was inadvertently adding a trailing dot to all key names. @@ -39,22 +42,14 @@ Revision 1.2 2005/03/03 19:55:22 shersche // SharedSecret.cpp : implementation file // + +#include #include "stdafx.h" #include "SharedSecret.h" +#include #include -#include - -//--------------------------------------------------------------------------------------------------------------------------- -// Private declarations -//--------------------------------------------------------------------------------------------------------------------------- -static BOOL -InitLsaString - ( - PLSA_UNICODE_STRING pLsaString, - LPCWSTR pwszString - ); // SharedSecret dialog @@ -98,129 +93,46 @@ BEGIN_MESSAGE_MAP(CSharedSecret, CDialog) END_MESSAGE_MAP() - //--------------------------------------------------------------------------------------------------------------------------- -// CSharedSecret::Commit +// CSharedSecret::Load //--------------------------------------------------------------------------------------------------------------------------- void -CSharedSecret::Commit( CString zone ) +CSharedSecret::Load( CString zone ) { - LSA_OBJECT_ATTRIBUTES attrs; - LSA_HANDLE handle = NULL; - NTSTATUS res; - LSA_UNICODE_STRING lucZoneName; - LSA_UNICODE_STRING lucKeyName; - LSA_UNICODE_STRING lucSecretName; - BOOL ok; - OSStatus err; - - // If there isn't a trailing dot, add one because the mDNSResponder - // presents names with the trailing dot. - - if ( zone.ReverseFind( '.' ) != ( zone.GetLength() - 1 ) ) - { - zone += '.'; - } + char zoneUTF8[ 256 ]; + char outDomain[ 256 ]; + char outKey[ 256 ]; + char outSecret[ 256 ]; - if ( m_key.ReverseFind( '.' ) != ( m_key.GetLength() - 1 ) ) + StringObjectToUTF8String( zone, zoneUTF8, sizeof( zoneUTF8 ) ); + + if ( LsaGetSecret( zoneUTF8, outDomain, sizeof( outDomain ) / sizeof( TCHAR ), outKey, sizeof( outKey ) / sizeof( TCHAR ), outSecret, sizeof( outSecret ) / sizeof( TCHAR ) ) ) { - m_key += '.'; + m_key = outKey; + m_secret = outSecret; } - - // - // - // Prepend "$" to the key name, so that there will - // be no conflict between the zone name and the key - // name - - m_key.Insert( 0, L"$" ); - - // attrs are reserved, so initialize to zeroes. - - ZeroMemory( &attrs, sizeof( attrs ) ); - - // Get a handle to the Policy object on the local system - - res = LsaOpenPolicy( NULL, &attrs, POLICY_ALL_ACCESS, &handle ); - err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr ); - require_noerr( err, exit ); - - // Intializing PLSA_UNICODE_STRING structures - - ok = InitLsaString( &lucZoneName, zone ); - err = translate_errno( ok, errno_compat(), kUnknownErr ); - require_noerr( err, exit ); - - ok = InitLsaString( &lucKeyName, m_key ); - err = translate_errno( ok, errno_compat(), kUnknownErr ); - require_noerr( err, exit ); - - ok = InitLsaString( &lucSecretName, m_secret ); - err = translate_errno( ok, errno_compat(), kUnknownErr ); - require_noerr( err, exit ); - - // Store the private data. - - res = LsaStorePrivateData( handle, &lucZoneName, &lucKeyName ); - err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr ); - require_noerr( err, exit ); - - res = LsaStorePrivateData( handle, &lucKeyName, &lucSecretName ); - err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr ); - require_noerr( err, exit ); - -exit: - - if ( handle ) + else { - LsaClose( handle ); - handle = NULL; + m_key = zone; } - - return; } //--------------------------------------------------------------------------------------------------------------------------- -// InitLsaString +// CSharedSecret::Commit //--------------------------------------------------------------------------------------------------------------------------- -static BOOL -InitLsaString - ( - PLSA_UNICODE_STRING pLsaString, - LPCWSTR pwszString - ) +void +CSharedSecret::Commit( CString zone ) { - size_t dwLen = 0; - BOOL ret = FALSE; - - if ( pLsaString == NULL ) - { - goto exit; - } - - if ( pwszString != NULL ) - { - dwLen = wcslen(pwszString); - - // String is too large - if (dwLen > 0x7ffe) - { - goto exit; - } - } - - // Store the string. - - pLsaString->Buffer = (WCHAR *) pwszString; - pLsaString->Length = (USHORT) dwLen * sizeof(WCHAR); - pLsaString->MaximumLength = (USHORT)(dwLen+1) * sizeof(WCHAR); - - ret = TRUE; + char zoneUTF8[ 256 ]; + char keyUTF8[ 256 ]; + char secretUTF8[ 256 ]; -exit: + StringObjectToUTF8String( zone, zoneUTF8, sizeof( zoneUTF8 ) ); + StringObjectToUTF8String( m_key, keyUTF8, sizeof( keyUTF8 ) ); + StringObjectToUTF8String( m_secret, secretUTF8, sizeof( secretUTF8 ) ); - return ret; + LsaSetSecret( zoneUTF8, keyUTF8, secretUTF8 ); } diff --git a/mDNSWindows/ControlPanel/SharedSecret.h b/mDNSWindows/ControlPanel/SharedSecret.h index f5f6435..73aef5b 100644 --- a/mDNSWindows/ControlPanel/SharedSecret.h +++ b/mDNSWindows/ControlPanel/SharedSecret.h @@ -17,6 +17,9 @@ Change History (most recent first): $Log: SharedSecret.h,v $ +Revision 1.5 2009/06/22 23:25:11 herscher + ControlPanel doesn't display key and password in dialog box. Refactor Lsa calls into Secret.h and Secret.c, which is used by both the ControlPanel and mDNSResponder system service. + Revision 1.4 2006/08/14 23:25:28 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -50,6 +53,9 @@ public: // Dialog Data enum { IDD = IDR_SECRET }; + void + Load( CString zone ); + void Commit( CString zone ); diff --git a/mDNSWindows/ControlPanel/res/ControlPanel.manifest b/mDNSWindows/ControlPanel/res/ControlPanel.manifest new file mode 100644 index 0000000..4879215 --- /dev/null +++ b/mDNSWindows/ControlPanel/res/ControlPanel.manifest @@ -0,0 +1,17 @@ + + + + Control Panel applet for configuring Wide-Area Bonjour. + + + + + + + + + + + + + diff --git a/mDNSWindows/ControlPanel/res/ControlPanel64.manifest b/mDNSWindows/ControlPanel/res/ControlPanel64.manifest new file mode 100644 index 0000000..a47a4e2 --- /dev/null +++ b/mDNSWindows/ControlPanel/res/ControlPanel64.manifest @@ -0,0 +1,17 @@ + + + + Control Panel applet for configuring Wide-Area Bonjour. + + + + + + + + + + + + + diff --git a/mDNSWindows/ControlPanel/resource.h b/mDNSWindows/ControlPanel/resource.h index 3a0fec7..e82d604 100644 --- a/mDNSWindows/ControlPanel/resource.h +++ b/mDNSWindows/ControlPanel/resource.h @@ -8,6 +8,7 @@ #define IDR_APPLET_PAGE2 132 #define IDR_SECRET 133 #define IDR_APPLET_PAGE3 134 +#define IDR_APPLET_PAGE4 135 #define IDI_FAILURE 140 #define IDI_SUCCESS 141 #define IDD_ADD_BROWSE_DOMAIN 142 @@ -30,6 +31,7 @@ #define IDC_BUTTON2 1012 #define IDC_REMOVE_BROWSE_DOMAIN 1012 #define IDC_ADD_BROWSE_DOMAIN 1013 +#define IDC_POWER_MANAGEMENT 1014 // Next default values for new objects // @@ -37,7 +39,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 143 #define _APS_NEXT_COMMAND_VALUE 32771 -#define _APS_NEXT_CONTROL_VALUE 1014 +#define _APS_NEXT_CONTROL_VALUE 1015 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/mDNSWindows/DLL.NET/AssemblyInfo.cpp b/mDNSWindows/DLL.NET/AssemblyInfo.cpp index 4a71579..d99c8ab 100755 --- a/mDNSWindows/DLL.NET/AssemblyInfo.cpp +++ b/mDNSWindows/DLL.NET/AssemblyInfo.cpp @@ -17,6 +17,10 @@ Change History (most recent first): $Log: AssemblyInfo.cpp,v $ +Revision 1.6 2009/03/30 20:16:27 herscher + Current Bonjour code does not compile on Windows + Move build train to Visual Studio 2005 + Revision 1.5 2006/08/14 23:25:43 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -38,8 +42,11 @@ Initial revision #include "stdafx.h" #include "WinVersRes.h" +using namespace System; using namespace System::Reflection; using namespace System::Runtime::CompilerServices; +using namespace System::Runtime::InteropServices; +using namespace System::Security::Permissions; // // General Information about an assembly is controlled through the following @@ -49,9 +56,9 @@ using namespace System::Runtime::CompilerServices; [assembly:AssemblyTitleAttribute("dnssd.NET")]; [assembly:AssemblyDescriptionAttribute(".NET wrapper for DNS-SD services")]; [assembly:AssemblyConfigurationAttribute("")]; -[assembly:AssemblyCompanyAttribute("Apple Computer, Inc.")]; +[assembly:AssemblyCompanyAttribute("Apple Inc.")]; [assembly:AssemblyProductAttribute("")]; -[assembly:AssemblyCopyrightAttribute("Apple Computer, Inc.")]; +[assembly:AssemblyCopyrightAttribute("Apple Inc.")]; [assembly:AssemblyTrademarkAttribute("")]; [assembly:AssemblyCultureAttribute("")]; @@ -95,3 +102,7 @@ using namespace System::Runtime::CompilerServices; [assembly:AssemblyDelaySignAttribute(false)]; [assembly:AssemblyKeyFileAttribute("dnssd_NET.snk")]; [assembly:AssemblyKeyNameAttribute("")]; + +[assembly:ComVisible(false)]; +[assembly:CLSCompliantAttribute(true)]; +[assembly:SecurityPermission(SecurityAction::RequestMinimum, UnmanagedCode = true)]; diff --git a/mDNSWindows/DLL.NET/Stdafx.h b/mDNSWindows/DLL.NET/Stdafx.h index 7fbc319..ff4647d 100755 --- a/mDNSWindows/DLL.NET/Stdafx.h +++ b/mDNSWindows/DLL.NET/Stdafx.h @@ -17,6 +17,10 @@ Change History (most recent first): $Log: Stdafx.h,v $ +Revision 1.6 2009/03/30 20:17:57 herscher + Current Bonjour code does not compile on Windows + Move build train to Visual Studio 2005 + Revision 1.5 2006/08/14 23:25:43 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -47,3 +51,6 @@ Initial revision #using #using +struct _DNSServiceRef_t {}; +struct _DNSRecordRef_t {}; + diff --git a/mDNSWindows/DLL.NET/dnssd_NET.cpp b/mDNSWindows/DLL.NET/dnssd_NET.cpp index f5ba486..b30699e 100755 --- a/mDNSWindows/DLL.NET/dnssd_NET.cpp +++ b/mDNSWindows/DLL.NET/dnssd_NET.cpp @@ -17,6 +17,10 @@ Change History (most recent first): $Log: dnssd_NET.cpp,v $ +Revision 1.11 2009/03/30 20:19:05 herscher + Current Bonjour code does not compile on Windows + Move build train to Visual Studio 2005 + Revision 1.10 2006/08/14 23:25:43 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -120,7 +124,7 @@ ServiceRef::StartThread() m_impl->SetupEvents(); - m_thread = new Thread(new ThreadStart(this, ProcessingThread)); + m_thread = new Thread(new ThreadStart(this, &Apple::DNSSD::ServiceRef::ProcessingThread)); m_thread->Name = S"DNSService Thread"; m_thread->IsBackground = true; diff --git a/mDNSWindows/DLL.NET/dnssd_NET.vcproj b/mDNSWindows/DLL.NET/dnssd_NET.vcproj index d857d4c..98cc63b 100755 --- a/mDNSWindows/DLL.NET/dnssd_NET.vcproj +++ b/mDNSWindows/DLL.NET/dnssd_NET.vcproj @@ -1,167 +1,444 @@ + ProjectGUID="{2A2FFA97-AF60-494F-9384-BBAA283AA3F2}" + RootNamespace="DLL2NET" + Keyword="ManagedCProj" + > + Name="Win32" + /> + + + + CharacterSet="1" + ManagedExtensions="4" + > + + + + + + /> + + Name="VCResourceCompilerTool" + AdditionalIncludeDirectories="../" + /> + + GenerateDebugInformation="true" + AssemblyDebug="1" + TargetMachine="1" + /> + + + + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + + + + + + CommandLine="sn -k dnssd_NET.snk" + /> + + + + + + Name="VCManagedResourceCompilerTool" + /> + AdditionalIncludeDirectories="../" + /> + + + + + Name="VCXDCMakeTool" + /> + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + Name="VCWebDeploymentTool" + /> + + CharacterSet="1" + ManagedExtensions="4" + WholeProgramOptimization="1" + > + + + + + + DebugInformationFormat="3" + /> + + + Name="VCPreLinkEventTool" + /> + GenerateDebugInformation="true" + TargetMachine="1" + /> + Name="VCALinkTool" + /> + Name="VCManifestTool" + EmbedManifest="false" + /> + + + + + + + + + CommandLine="sn -k dnssd_NET.snk" + /> + + Name="VCXMLDataGeneratorTool" + /> + + + + + AdditionalIncludeDirectories="../" + /> + Name="VCPreLinkEventTool" + /> + Name="VCLinkerTool" + AdditionalDependencies="../DLL/$(OutDir)/dnssd.lib ws2_32.lib" + OutputFile="$(OutDir)\dnssd.NET.dll" + LinkIncremental="1" + GenerateDebugInformation="true" + TargetMachine="17" + /> + + + Name="VCXDCMakeTool" + /> + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + + + + + + + Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + RelativePath=".\AssemblyInfo.cpp" + > + RelativePath=".\dnssd_NET.cpp" + > + RelativePath=".\Stdafx.cpp" + > + + + + + + + + + + + + - - + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + RelativePath=".\dnssd_NET.h" + > + RelativePath=".\resource.h" + > + RelativePath=".\Stdafx.h" + > + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" + > + RelativePath=".\dnssd_NET.ico" + > + RelativePath=".\dnssd_NET.rc" + > + RelativePath=".\ReadMe.txt" + > diff --git a/mDNSWindows/DLL/dnssd.def b/mDNSWindows/DLL/dnssd.def index 91b3f54..008ad97 100644 --- a/mDNSWindows/DLL/dnssd.def +++ b/mDNSWindows/DLL/dnssd.def @@ -17,6 +17,9 @@ ; Change History (most recent first): ; ; $Log: dnssd.def,v $ +; Revision 1.5 2009/03/30 20:14:27 herscher +; Current Bonjour code does not compile on Windows +; ; Revision 1.4 2006/09/27 00:46:18 herscher ; API: Need DNSServiceGetAddrInfo() ; @@ -58,6 +61,7 @@ EXPORTS DNSServiceReconfirmRecord DNSServiceNATPortMappingCreate DNSServiceGetAddrInfo + DNSServiceGetProperty TXTRecordCreate TXTRecordDeallocate TXTRecordSetValue diff --git a/mDNSWindows/DLL/dnssd.vcproj b/mDNSWindows/DLL/dnssd.vcproj index eab0f41..22a6e3d 100644 --- a/mDNSWindows/DLL/dnssd.vcproj +++ b/mDNSWindows/DLL/dnssd.vcproj @@ -1,131 +1,388 @@ + RootNamespace="DLL" + Keyword="Win32Proj" + > + Name="Win32" + /> + + + + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" + CharacterSet="2" + > + + + + + + DisableSpecificWarnings="4127;4204" + /> + + + Name="VCPreLinkEventTool" + /> + ImportLibrary="$(OutDir)\dnssd.lib" + TargetMachine="1" + /> + + + Name="VCXDCMakeTool" + /> + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + + + + + + + + + + + + AdditionalIncludeDirectories="../" + /> + + + + + + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + Name="VCWebDeploymentTool" + /> + Name="VCPostBuildEventTool" + /> + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" + CharacterSet="2" + > + + + + + + DisableSpecificWarnings="4127;4204" + /> + + Name="VCResourceCompilerTool" + AdditionalIncludeDirectories="../" + /> + + ImportLibrary="$(OutDir)\dnssd.lib" + TargetMachine="1" + /> + + + + + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + Name="VCWebDeploymentTool" + /> + Name="VCPostBuildEventTool" + CommandLine="if not "%RC_XBS%" == "YES" goto END if not exist "$(DSTROOT)\WINDOWS\system32\$(PlatformName)" mkdir "$(DSTROOT)\WINDOWS\system32\$(PlatformName)" if not exist "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)" if not exist "$(DSTROOT)\Program Files\Bonjour SDK\include" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\include" xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\WINDOWS\system32\$(PlatformName)" xcopy /I/Y "$(OutDir)\dnssd.lib" "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)" xcopy /I/Y "$(ProjectDir)..\..\mDNSShared\dns_sd.h" "$(DSTROOT)\Program Files\Bonjour SDK\include" :END " + /> + + + + + + + + + + AdditionalIncludeDirectories="../" + /> + Name="VCPreLinkEventTool" + /> + Name="VCLinkerTool" + AdditionalOptions="/NXCOMPAT /DYNAMICBASE" + AdditionalDependencies="ws2_32.lib iphlpapi.lib" + OutputFile="$(OutDir)/dnssd.dll" + LinkIncremental="1" + ModuleDefinitionFile="dnssd.def" + GenerateDebugInformation="true" + ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb" + SubSystem="2" + OptimizeReferences="2" + EnableCOMDATFolding="2" + BaseAddress="0x16000000" + ImportLibrary="$(OutDir)\dnssd.lib" + TargetMachine="17" + /> + + + Name="VCXDCMakeTool" + /> + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + + + @@ -134,61 +391,75 @@ + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + RelativePath="..\..\mDNSShared\DebugServices.c" + > + RelativePath=".\dllmain.c" + > + RelativePath=".\dnssd.def" + > + RelativePath="..\..\mDNSShared\dnssd_clientlib.c" + > + RelativePath="..\..\mDNSShared\dnssd_clientstub.c" + > + RelativePath="..\..\mDNSShared\dnssd_ipc.c" + > + RelativePath="..\..\mDNSShared\GenLinkedList.c" + > - - + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + RelativePath="..\..\mDNSShared\CommonServices.h" + > + RelativePath="..\..\mDNSShared\DebugServices.h" + > + RelativePath="..\..\mDNSShared\dns_sd.h" + > + RelativePath="..\..\mDNSShared\dnssd_ipc.h" + > + RelativePath="..\..\mDNSShared\GenLinkedList.h" + > + RelativePath=".\resource.h" + > + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" + > + RelativePath=".\dll.rc" + > diff --git a/mDNSWindows/DLLStub/DLLStub.cpp b/mDNSWindows/DLLStub/DLLStub.cpp new file mode 100755 index 0000000..c39a747 --- /dev/null +++ b/mDNSWindows/DLLStub/DLLStub.cpp @@ -0,0 +1,693 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2009, Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "DLLStub.h" + +static int g_defaultErrorCode = kDNSServiceErr_Unknown; +static DLLStub g_glueLayer; + + +// ------------------------------------------ +// DLLStub implementation +// ------------------------------------------ +DLLStub * DLLStub::m_instance; + +DLLStub::DLLStub() +: + m_library( LoadLibrary( TEXT( "dnssd.dll" ) ) ) +{ + m_instance = this; +} + + +DLLStub::~DLLStub() +{ + if ( m_library != NULL ) + { + FreeLibrary( m_library ); + m_library = NULL; + } + + m_instance = NULL; +} + + +bool +DLLStub::GetProcAddress( FARPROC * func, LPCSTR lpProcName ) +{ + if ( m_instance && m_instance->m_library ) + { + // Only call ::GetProcAddress if *func is NULL. This allows + // the calling code to cache the funcptr value, and we get + // some performance benefit. + + if ( *func == NULL ) + { + *func = ::GetProcAddress( m_instance->m_library, lpProcName ); + } + } + else + { + *func = NULL; + } + + return ( *func != NULL ); +} + + +int DNSSD_API +DNSServiceRefSockFD(DNSServiceRef sdRef) +{ + typedef int (DNSSD_API * Func)(DNSServiceRef sdRef); + static Func func = NULL; + int ret = -1; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( sdRef ); + } + + return ret; +} + + +DNSServiceErrorType DNSSD_API +DNSServiceProcessResult(DNSServiceRef sdRef) +{ + typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef sdRef); + static Func func = NULL; + DNSServiceErrorType ret = g_defaultErrorCode; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( sdRef ); + } + + return ret; +} + + +void DNSSD_API +DNSServiceRefDeallocate(DNSServiceRef sdRef) +{ + typedef void (DNSSD_API * Func)(DNSServiceRef sdRef); + static Func func = NULL; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + func( sdRef ); + } +} + + +DNSServiceErrorType DNSSD_API +DNSServiceEnumerateDomains + ( + DNSServiceRef *sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceDomainEnumReply callBack, + void *context + ) +{ + typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef*, DNSServiceFlags, uint32_t, DNSServiceDomainEnumReply, void* ); + static Func func = NULL; + DNSServiceErrorType ret = g_defaultErrorCode; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( sdRef, flags, interfaceIndex, callBack, context ); + } + + return ret; +} + + +DNSServiceErrorType DNSSD_API +DNSServiceRegister + ( + DNSServiceRef *sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + const char *name, + const char *regtype, + const char *domain, + const char *host, + uint16_t port, + uint16_t txtLen, + const void *txtRecord, + DNSServiceRegisterReply callBack, + void *context + ) +{ + typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef*, DNSServiceFlags, uint32_t, const char*, const char*, const char*, const char*, uint16_t, uint16_t, const void*, DNSServiceRegisterReply, void* ); + static Func func = NULL; + DNSServiceErrorType ret = g_defaultErrorCode; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( sdRef, flags, interfaceIndex, name, regtype, domain, host, port, txtLen, txtRecord, callBack, context ); + } + + return ret; +} + + +DNSServiceErrorType DNSSD_API +DNSServiceAddRecord + ( + DNSServiceRef sdRef, + DNSRecordRef *RecordRef, + DNSServiceFlags flags, + uint16_t rrtype, + uint16_t rdlen, + const void *rdata, + uint32_t ttl + ) +{ + typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef, DNSRecordRef*, DNSServiceFlags, uint16_t, uint16_t, const void*, uint32_t ); + static Func func = NULL; + DNSServiceErrorType ret = g_defaultErrorCode; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( sdRef, RecordRef, flags, rrtype, rdlen, rdata, ttl ); + } + + return ret; +} + + +DNSServiceErrorType DNSSD_API +DNSServiceUpdateRecord + ( + DNSServiceRef sdRef, + DNSRecordRef RecordRef, /* may be NULL */ + DNSServiceFlags flags, + uint16_t rdlen, + const void *rdata, + uint32_t ttl + ) +{ + typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef, DNSRecordRef, DNSServiceFlags, uint16_t, const void*, uint32_t ); + static Func func = NULL; + DNSServiceErrorType ret = g_defaultErrorCode; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( sdRef, RecordRef, flags, rdlen, rdata, ttl ); + } + + return ret; +} + + +DNSServiceErrorType DNSSD_API +DNSServiceRemoveRecord + ( + DNSServiceRef sdRef, + DNSRecordRef RecordRef, + DNSServiceFlags flags + ) +{ + typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef, DNSRecordRef, DNSServiceFlags ); + static Func func = NULL; + DNSServiceErrorType ret = g_defaultErrorCode; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( sdRef, RecordRef, flags ); + } + + return ret; +} + + +DNSServiceErrorType DNSSD_API +DNSServiceBrowse + ( + DNSServiceRef *sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + const char *regtype, + const char *domain, /* may be NULL */ + DNSServiceBrowseReply callBack, + void *context /* may be NULL */ + ) +{ + typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef*, DNSServiceFlags, uint32_t, const char*, const char*, DNSServiceBrowseReply, void* ); + static Func func = NULL; + DNSServiceErrorType ret = g_defaultErrorCode; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( sdRef, flags, interfaceIndex, regtype, domain, callBack, context ); + } + + return ret; +} + + +DNSServiceErrorType DNSSD_API +DNSServiceResolve + ( + DNSServiceRef *sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + const char *name, + const char *regtype, + const char *domain, + DNSServiceResolveReply callBack, + void *context /* may be NULL */ + ) +{ + typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef*, DNSServiceFlags, uint32_t, const char*, const char*, const char*, DNSServiceResolveReply, void* ); + static Func func = NULL; + DNSServiceErrorType ret = g_defaultErrorCode; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( sdRef, flags, interfaceIndex, name, regtype, domain, callBack, context ); + } + + return ret; +} + + +DNSServiceErrorType DNSSD_API +DNSServiceConstructFullName + ( + char *fullName, + const char *service, /* may be NULL */ + const char *regtype, + const char *domain + ) +{ + typedef DNSServiceErrorType (DNSSD_API * Func)( char*, const char*, const char*, const char* ); + static Func func = NULL; + DNSServiceErrorType ret = g_defaultErrorCode; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( fullName, service, regtype, domain ); + } + + return ret; +} + + +DNSServiceErrorType DNSSD_API +DNSServiceCreateConnection(DNSServiceRef *sdRef) +{ + typedef DNSServiceErrorType (DNSSD_API * Func)( DNSServiceRef* ); + static Func func = NULL; + DNSServiceErrorType ret = g_defaultErrorCode; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( sdRef ); + } + + return ret; +} + + +DNSServiceErrorType DNSSD_API +DNSServiceRegisterRecord + ( + DNSServiceRef sdRef, + DNSRecordRef *RecordRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + const char *fullname, + uint16_t rrtype, + uint16_t rrclass, + uint16_t rdlen, + const void *rdata, + uint32_t ttl, + DNSServiceRegisterRecordReply callBack, + void *context /* may be NULL */ + ) +{ + typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef, DNSRecordRef*, DNSServiceFlags, uint32_t, const char*, uint16_t, uint16_t, uint16_t, const void*, uint16_t, DNSServiceRegisterRecordReply, void* ); + static Func func = NULL; + DNSServiceErrorType ret = g_defaultErrorCode; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( sdRef, RecordRef, flags, interfaceIndex, fullname, rrtype, rrclass, rdlen, rdata, ttl, callBack, context ); + } + + return ret; +} + + +DNSServiceErrorType DNSSD_API +DNSServiceQueryRecord + ( + DNSServiceRef *sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + const char *fullname, + uint16_t rrtype, + uint16_t rrclass, + DNSServiceQueryRecordReply callBack, + void *context /* may be NULL */ + ) +{ + typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef*, DNSServiceFlags, uint32_t, const char*, uint16_t, uint16_t, DNSServiceQueryRecordReply, void* ); + static Func func = NULL; + DNSServiceErrorType ret = g_defaultErrorCode; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( sdRef, flags, interfaceIndex, fullname, rrtype, rrclass, callBack, context ); + } + + return ret; +} + + +DNSServiceErrorType DNSSD_API +DNSServiceReconfirmRecord + ( + DNSServiceFlags flags, + uint32_t interfaceIndex, + const char *fullname, + uint16_t rrtype, + uint16_t rrclass, + uint16_t rdlen, + const void *rdata + ) +{ + typedef DNSServiceErrorType (DNSSD_API * Func)( DNSServiceFlags, uint32_t, const char*, uint16_t, uint16_t, uint16_t, const void* ); + static Func func = NULL; + DNSServiceErrorType ret = g_defaultErrorCode; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( flags, interfaceIndex, fullname, rrtype, rrclass, rdlen, rdata ); + } + + return ret; +} + + +DNSServiceErrorType DNSSD_API +DNSServiceNATPortMappingCreate + ( + DNSServiceRef *sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceProtocol protocol, /* TCP and/or UDP */ + uint16_t internalPort, /* network byte order */ + uint16_t externalPort, /* network byte order */ + uint32_t ttl, /* time to live in seconds */ + DNSServiceNATPortMappingReply callBack, + void *context /* may be NULL */ + ) +{ + typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef*, DNSServiceFlags, uint32_t, DNSServiceProtocol, uint16_t, uint16_t, uint16_t, DNSServiceNATPortMappingReply, void* ); + static Func func = NULL; + DNSServiceErrorType ret = g_defaultErrorCode; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( sdRef, flags, interfaceIndex, protocol, internalPort, externalPort, ttl, callBack, context ); + } + + return ret; +} + + +DNSServiceErrorType DNSSD_API +DNSServiceGetAddrInfo + ( + DNSServiceRef *sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceProtocol protocol, + const char *hostname, + DNSServiceGetAddrInfoReply callBack, + void *context /* may be NULL */ + ) +{ + typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef*, DNSServiceFlags, uint32_t, DNSServiceProtocol, const char*, DNSServiceGetAddrInfoReply, void* ); + static Func func = NULL; + DNSServiceErrorType ret = g_defaultErrorCode; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( sdRef, flags, interfaceIndex, protocol, hostname, callBack, context ); + } + + return ret; +} + + +DNSServiceErrorType DNSSD_API +DNSServiceGetProperty + ( + const char *property, /* Requested property (i.e. kDNSServiceProperty_DaemonVersion) */ + void *result, /* Pointer to place to store result */ + uint32_t *size /* size of result location */ + ) +{ + typedef DNSServiceErrorType (DNSSD_API * Func)( const char*, void*, uint32_t* ); + static Func func = NULL; + DNSServiceErrorType ret = g_defaultErrorCode; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( property, result, size ); + } + + return ret; +} + + +void DNSSD_API +TXTRecordCreate + ( + TXTRecordRef *txtRecord, + uint16_t bufferLen, + void *buffer + ) +{ + typedef void (DNSSD_API * Func)( TXTRecordRef*, uint16_t, void* ); + static Func func = NULL; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + func( txtRecord, bufferLen, buffer ); + } +} + + +void DNSSD_API +TXTRecordDeallocate + ( + TXTRecordRef *txtRecord + ) +{ + typedef void (DNSSD_API * Func)( TXTRecordRef* ); + static Func func = NULL; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + func( txtRecord ); + } +} + + +DNSServiceErrorType DNSSD_API +TXTRecordSetValue + ( + TXTRecordRef *txtRecord, + const char *key, + uint8_t valueSize, /* may be zero */ + const void *value /* may be NULL */ + ) +{ + typedef DNSServiceErrorType (DNSSD_API * Func)( TXTRecordRef*, const char*, uint8_t, const void* ); + static Func func = NULL; + DNSServiceErrorType ret = g_defaultErrorCode; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( txtRecord, key, valueSize, value ); + } + + return ret; +} + + +DNSServiceErrorType DNSSD_API +TXTRecordRemoveValue + ( + TXTRecordRef *txtRecord, + const char *key + ) +{ + typedef DNSServiceErrorType (DNSSD_API * Func)( TXTRecordRef*, const char* ); + static Func func = NULL; + DNSServiceErrorType ret = g_defaultErrorCode; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( txtRecord, key ); + } + + return ret; +} + + +int DNSSD_API +TXTRecordContainsKey + ( + uint16_t txtLen, + const void *txtRecord, + const char *key + ) +{ + typedef int (DNSSD_API * Func)( uint16_t, const void*, const char* ); + static Func func = NULL; + int ret = 0; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( txtLen, txtRecord, key ); + } + + return ret; +} + + +uint16_t DNSSD_API +TXTRecordGetCount + ( + uint16_t txtLen, + const void *txtRecord + ) +{ + typedef uint16_t (DNSSD_API * Func)( uint16_t, const void* ); + static Func func = NULL; + uint16_t ret = 0; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( txtLen, txtRecord ); + } + + return ret; +} + + +uint16_t DNSSD_API +TXTRecordGetLength + ( + const TXTRecordRef *txtRecord + ) +{ + typedef uint16_t (DNSSD_API * Func)( const TXTRecordRef* ); + static Func func = NULL; + uint16_t ret = 0; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( txtRecord ); + } + + return ret; +} + + +const void * DNSSD_API +TXTRecordGetBytesPtr + ( + const TXTRecordRef *txtRecord + ) +{ + typedef const void* (DNSSD_API * Func)( const TXTRecordRef* ); + static Func func = NULL; + const void* ret = NULL; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( txtRecord ); + } + + return ret; +} + + +const void * DNSSD_API +TXTRecordGetValuePtr + ( + uint16_t txtLen, + const void *txtRecord, + const char *key, + uint8_t *valueLen + ) +{ + typedef const void* (DNSSD_API * Func)( uint16_t, const void*, const char*, uint8_t* ); + static Func func = NULL; + const void* ret = NULL; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( txtLen, txtRecord, key, valueLen ); + } + + return ret; +} + + +DNSServiceErrorType DNSSD_API +TXTRecordGetItemAtIndex + ( + uint16_t txtLen, + const void *txtRecord, + uint16_t itemIndex, + uint16_t keyBufLen, + char *key, + uint8_t *valueLen, + const void **value + ) +{ + typedef DNSServiceErrorType (DNSSD_API * Func)( uint16_t, const void*, uint16_t, uint16_t, char*, uint8_t*, const void** ); + static Func func = NULL; + DNSServiceErrorType ret = g_defaultErrorCode; + + if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) ) + { + ret = func( txtLen, txtRecord, itemIndex, keyBufLen, key, valueLen, value ); + } + + return ret; +} \ No newline at end of file diff --git a/mDNSWindows/DLLStub/DLLStub.h b/mDNSWindows/DLLStub/DLLStub.h new file mode 100755 index 0000000..44f57d1 --- /dev/null +++ b/mDNSWindows/DLLStub/DLLStub.h @@ -0,0 +1,52 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2009, Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _DLLStub_h +#define _DLLStub_h + +#include +#include + +class DLLStub +{ +public: + + DLLStub(); + ~DLLStub(); + + static bool + GetProcAddress( FARPROC * func, LPCSTR lpProcName ); + +private: + + static DLLStub * m_instance; + HMODULE m_library; +}; + + +#endif \ No newline at end of file diff --git a/mDNSWindows/DLLStub/DLLStub.vcproj b/mDNSWindows/DLLStub/DLLStub.vcproj new file mode 100755 index 0000000..b693b27 --- /dev/null +++ b/mDNSWindows/DLLStub/DLLStub.vcproj @@ -0,0 +1,318 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mDNSWindows/DLLX/DLLX.cpp b/mDNSWindows/DLLX/DLLX.cpp new file mode 100755 index 0000000..7cc6c63 --- /dev/null +++ b/mDNSWindows/DLLX/DLLX.cpp @@ -0,0 +1,120 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2009 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. + + Change History (most recent first): + +$Log: DLLX.cpp,v $ +Revision 1.1 2009/05/26 04:43:54 herscher + COM component that can be used with any .NET language and VB. + + +*/ + + +#include "stdafx.h" +#include "resource.h" +#include "DLLX.h" +#include "dlldatax.h" +#include + + +class CDLLComponentModule : public CAtlDllModuleT< CDLLComponentModule > +{ +public : + DECLARE_LIBID(LIBID_Bonjour) + DECLARE_REGISTRY_APPID_RESOURCEID(IDR_DLLX, "{56608F9C-223B-4CB6-813D-85EDCCADFB4B}") +}; + +CDLLComponentModule _AtlModule; + + +#ifdef _MANAGED +#pragma managed(push, off) +#endif + +// DLL Entry Point +extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +{ + debug_initialize( kDebugOutputTypeWindowsDebugger ); + debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelVerbose ); + +#ifdef _MERGE_PROXYSTUB + if (!PrxDllMain(hInstance, dwReason, lpReserved)) + return FALSE; +#endif + hInstance; + return _AtlModule.DllMain(dwReason, lpReserved); +} + +#ifdef _MANAGED +#pragma managed(pop) +#endif + + + + +// Used to determine whether the DLL can be unloaded by OLE +STDAPI DllCanUnloadNow(void) +{ +#ifdef _MERGE_PROXYSTUB + HRESULT hr = PrxDllCanUnloadNow(); + if (hr != S_OK) + return hr; +#endif + return _AtlModule.DllCanUnloadNow(); +} + + +// Returns a class factory to create an object of the requested type +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) +{ +#ifdef _MERGE_PROXYSTUB + if (PrxDllGetClassObject(rclsid, riid, ppv) == S_OK) + return S_OK; +#endif + return _AtlModule.DllGetClassObject(rclsid, riid, ppv); +} + + +// DllRegisterServer - Adds entries to the system registry +STDAPI DllRegisterServer(void) +{ + // registers object, typelib and all interfaces in typelib + HRESULT hr = _AtlModule.DllRegisterServer(); +#ifdef _MERGE_PROXYSTUB + if (FAILED(hr)) + return hr; + hr = PrxDllRegisterServer(); +#endif + return hr; +} + + +// DllUnregisterServer - Removes entries from the system registry +STDAPI DllUnregisterServer(void) +{ + HRESULT hr = _AtlModule.DllUnregisterServer(); +#ifdef _MERGE_PROXYSTUB + if (FAILED(hr)) + return hr; + hr = PrxDllRegisterServer(); + if (FAILED(hr)) + return hr; + hr = PrxDllUnregisterServer(); +#endif + return hr; +} + diff --git a/mDNSWindows/DLLX/DLLX.def b/mDNSWindows/DLLX/DLLX.def new file mode 100755 index 0000000..3029b69 --- /dev/null +++ b/mDNSWindows/DLLX/DLLX.def @@ -0,0 +1,33 @@ +; -*- Mode: C; tab-width: 4 -*- +; +; Copyright (c) 2009 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. +; +; Change History (most recent first): +; +; $Log: DLLX.def,v $ +; Revision 1.1 2009/05/26 04:43:54 herscher +; COM component that can be used with any .NET language and VB. +; +; +; + + +LIBRARY "dnssdX.DLL" + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/mDNSWindows/DLLX/DLLX.idl b/mDNSWindows/DLLX/DLLX.idl new file mode 100755 index 0000000..05725e8 --- /dev/null +++ b/mDNSWindows/DLLX/DLLX.idl @@ -0,0 +1,309 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2009 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. + + Change History (most recent first): + +$Log: DLLX.idl,v $ +Revision 1.1 2009/05/26 04:43:54 herscher + COM component that can be used with any .NET language and VB. + + +*/ + +// This file will be processed by the MIDL tool to +// produce the type library (DLLComponent.tlb) and marshalling code. + +typedef [ uuid(4085DD59-D0E1-4efe-B6EE-DDBF7631B9C0) ] +enum DNSSDFlags +{ + kDNSSDFlagsMoreComing = 0x0001, + kDNSSDFlagsDefault = 0x0004, + kDNSSDFlagsNoAutoRename = 0x0008, + kDNSSDFlagsShared = 0x0010, + kDNSSDFlagsUnique = 0x0020, + kDNSSDFlagsBrowseDomains = 0x0040, + kDNSSDFlagsRegistrationDomains = 0x0080, + kDNSSDFlagsLongLivedQuery = 0x0100, + kDNSSDFlagsAllowRemoteQuery = 0x0200, + kDNSSDFlagsForceMulticast = 0x0400, + kDNSSDFlagsForce = 0x0800, + kDNSSDFlagsReturnIntermediates = 0x1000, + kDNSSDFlagsNonBrowsable = 0x2000 +} DNSSDFlags; + + +typedef [ uuid(30CDF335-CA52-4b17-AFF2-E83C64C450D4) ] +enum DNSSDAddressFamily +{ + kDNSSDAddressFamily_IPv4 = 0x1, + kDNSSDAddressFamily_IPv6 = 0x2 +} DNSSDAddressFamily; + + +typedef [ uuid(98FB4702-7374-4b16-A8DB-AD35BFB8364D) ] +enum DNSSDProtocol +{ + kDNSSDProtocol_UDP = 0x10, + kDNSSDProtocol_TCP = 0x20 +} DNSSDProtocol; + + +typedef [ uuid(72BF3EC3-19BC-47e5-8D95-3B73FF37D893) ] +enum DNSSDRRClass +{ + kDNSSDClass_IN = 1 +} DNSSDRRClass; + + +typedef [ uuid(08E362DF-5468-4c9a-AC66-FD4747B917BD) ] +enum DNSSDRRType +{ + kDNSSDType_A = 1, + kDNSSDType_NS = 2, + kDNSSDType_MD = 3, + kDNSSDType_MF = 4, + kDNSSDType_CNAME = 5, + kDNSSDType_SOA = 6, + kDNSSDType_MB = 7, + kDNSSDType_MG = 8, + kDNSSDType_MR = 9, + kDNSSDType_NULL = 10, + kDNSSDType_WKS = 11, + kDNSSDType_PTR = 12, + kDNSSDType_HINFO = 13, + kDNSSDType_MINFO = 14, + kDNSSDType_MX = 15, + kDNSSDType_TXT = 16, + kDNSSDType_RP = 17, + kDNSSDType_AFSDB = 18, + kDNSSDType_X25 = 19, + kDNSSDType_ISDN = 20, + kDNSSDType_RT = 21, + kDNSSDType_NSAP = 22, + kDNSSDType_NSAP_PTR = 23, + kDNSSDType_SIG = 24, + kDNSSDType_KEY = 25, + kDNSSDType_PX = 26, + kDNSSDType_GPOS = 27, + kDNSSDType_AAAA = 28, + kDNSSDType_LOC = 29, + kDNSSDType_NXT = 30, + kDNSSDType_EID = 31, + kDNSSDType_NIMLOC = 32, + kDNSSDType_SRV = 33, + kDNSSDType_ATMA = 34, + kDNSSDType_NAPTR = 35, + kDNSSDType_KX = 36, + kDNSSDType_CERT = 37, + kDNSSDType_A6 = 38, + kDNSSDType_DNAME = 39, + kDNSSDType_SINK = 40, + kDNSSDType_OPT = 41, + kDNSSDType_APL = 42, + kDNSSDType_DS = 43, + kDNSSDType_SSHFP = 44, + kDNSSDType_IPSECKEY = 45, + kDNSSDType_RRSIG = 46, + kDNSSDType_NSEC = 47, + kDNSSDType_DNSKEY = 48, + kDNSSDType_DHCID = 49, + kDNSSDType_NSEC3 = 50, + kDNSSDType_NSEC3PARAM= 51, + kDNSSDType_HIP = 55, + kDNSSDType_SPF = 99, + kDNSSDType_UINFO = 100, + kDNSSDType_UID = 101, + kDNSSDType_GID = 102, + kDNSSDType_UNSPEC = 103, + kDNSSDType_TKEY = 249, + kDNSSDType_TSIG = 250, + kDNSSDType_IXFR = 251, + kDNSSDType_AXFR = 252, + kDNSSDType_MAILB = 253, + kDNSSDType_MAILA = 254, + kDNSSDType_ANY = 255 +} DNSSDRRType; + + +typedef [ uuid(3B0059E7-5297-4301-9AAB-1522F31EC8A7) ] +enum DNSSDError +{ + kDNSSDError_NoError = 0, + kDNSSDError_Unknown = -65537, + kDNSSDError_NoSuchName = -65538, + kDNSSDError_NoMemory = -65539, + kDNSSDError_BadParam = -65540, + kDNSSDError_BadReference = -65541, + kDNSSDError_BadState = -65542, + kDNSSDError_BadFlags = -65543, + kDNSSDError_Unsupported = -65544, + kDNSSDError_NotInitialized = -65545, + kDNSSDError_AlreadyRegistered = -65547, + kDNSSDError_NameConflict = -65548, + kDNSSDError_Invalid = -65549, + kDNSSDError_Firewall = -65550, + kDNSSDError_Incompatible = -65551, + kDNSSDError_BadInterfaceIndex = -65552, + kDNSSDError_Refused = -65553, + kDNSSDError_NoSuchRecord = -65554, + kDNSSDError_NoAuth = -65555, + kDNSSDError_NoSuchKey = -65556, + kDNSSDError_NATTraversal = -65557, + kDNSSDError_DoubleNAT = -65558, + kDNSSDError_BadTime = -65559, + kDNSSDError_BadSig = -65560, + kDNSSDError_BadKey = -65561, + kDNSSDError_Transient = -65562, + kDNSSDError_ServiceNotRunning = -65563, /* Background daemon not running */ + kDNSSDError_NATPortMappingUnsupported = -65564, /* NAT doesn't support NAT-PMP or UPnP */ + kDNSSDError_NATPortMappingDisabled = -65565, /* NAT supports NAT-PMP or UPnP but it's disabled by the administrator */ + kDNSSDError_NoRouter = -65566, /* No router currently configured (probably no network connectivity) */ + kDNSSDError_PollingMode = -65567 +} DNSSDError; + +import "oaidl.idl"; +import "ocidl.idl"; + + +[ + object, + uuid(8FA0889C-5973-4FC9-970B-EC15C925D0CE), + dual, + nonextensible, + helpstring("ITXTRecord Interface"), + pointer_default(unique) +] +interface ITXTRecord : IDispatch{ + [id(1), helpstring("method SetValue")] HRESULT SetValue([in] BSTR key, [in] VARIANT value); + [id(2), helpstring("method RemoveValue")] HRESULT RemoveValue([in] BSTR key); + [id(3), helpstring("method ContainsKey")] HRESULT ContainsKey([in] BSTR key, [out,retval] VARIANT_BOOL* retval); + [id(4), helpstring("method GetValueForKey")] HRESULT GetValueForKey([in] BSTR key, [out,retval] VARIANT* value); + [id(5), helpstring("method GetCount")] HRESULT GetCount([out,retval] ULONG* count); + [id(6), helpstring("method GetKeyAtIndex")] HRESULT GetKeyAtIndex([in] ULONG index, [out,retval] BSTR* retval); + [id(7), helpstring("method GetValueAtIndex")] HRESULT GetValueAtIndex([in] ULONG index, [out,retval] VARIANT* retval); +}; +[ + object, + uuid(9CE603A0-3365-4DA0-86D1-3F780ECBA110), + dual, + nonextensible, + helpstring("IDNSSDRecord Interface"), + pointer_default(unique) +] +interface IDNSSDRecord : IDispatch{ + [id(1), helpstring("method Update")] HRESULT Update([in] DNSSDFlags flags, [in] VARIANT rdata, [in] ULONG ttl); + [id(2), helpstring("method Remove")] HRESULT Remove([in] DNSSDFlags flags); +}; +[ + object, + uuid(7FD72324-63E1-45AD-B337-4D525BD98DAD), + dual, + nonextensible, + helpstring("IDNSSDEventManager Interface"), + pointer_default(unique) +] +interface IDNSSDEventManager : IDispatch{ +}; +[ + object, + uuid(29DE265F-8402-474F-833A-D4653B23458F), + dual, + nonextensible, + helpstring("IDNSSDService Interface"), + pointer_default(unique) +] +interface IDNSSDService : IDispatch{ + [id(1), helpstring("method EnumerateDomains")] HRESULT EnumerateDomains([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service); + [id(2), helpstring("method Browse"), local] HRESULT Browse([in] DNSSDFlags flags, [in] ULONG interfaceIndex, [in] BSTR regtype, [in] BSTR domain, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** sdref); + [id(3), helpstring("method Resolve")] HRESULT Resolve([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR serviceName, [in] BSTR regType, [in] BSTR domain, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service); + [id(4), helpstring("method Register")] HRESULT Register([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR name, [in] BSTR regType, [in] BSTR domain, [in] BSTR host, [in] USHORT port, [in] ITXTRecord* record, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service); + [id(5), helpstring("method QueryRecord")] HRESULT QueryRecord([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR fullname, [in] DNSSDRRType rrtype, [in] DNSSDRRClass rrclass, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service); + [id(6), helpstring("method RegisterRecord")] HRESULT RegisterRecord([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR fullname, [in] DNSSDRRType rrtype, [in] DNSSDRRClass rrclass, [in] VARIANT rdata, [in] ULONG ttl, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDRecord** record); + [id(7), helpstring("method AddRecord")] HRESULT AddRecord([in] DNSSDFlags flags, [in] DNSSDRRType rrtype, [in] VARIANT rdata, [in] ULONG ttl, [out,retval] IDNSSDRecord** record); + [id(8), helpstring("method ReconfirmRecord")] HRESULT ReconfirmRecord([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR fullname, [in] DNSSDRRType rrtype, [in] DNSSDRRClass rrclass, [in] VARIANT rdata); + [id(9), helpstring("method GetProperty")] HRESULT GetProperty([in] BSTR prop, [in,out] VARIANT * value ); + [id(10), helpstring("method GetAddrInfo")] HRESULT GetAddrInfo([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] DNSSDAddressFamily addressFamily, [in] BSTR hostname, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service); + [id(11), helpstring("method NATPortMappingCreate")] HRESULT NATPortMappingCreate([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] DNSSDAddressFamily addressFamily, [in] DNSSDProtocol protocol, [in] USHORT internalPort, [in] USHORT externalPort, [in] ULONG ttl, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service); + [id(12), helpstring("method Stop"), local] HRESULT Stop(void); +}; +[ + uuid(18FBED6D-F2B7-4EC8-A4A4-46282E635308), + version(1.0), + helpstring("Apple Bonjour Library 1.0") +] +library Bonjour +{ + importlib("stdole2.tlb"); + [ + uuid(21AE8D7F-D5FE-45cf-B632-CFA2C2C6B498), + helpstring("_IDNSSDEvents Interface") + ] + dispinterface _IDNSSDEvents + { + properties: + methods: + [id(1), helpstring("method DomainFound")] void DomainFound([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR domain); + [id(2), helpstring("method DomainLost")] void DomainLost([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR domain); + [id(3), helpstring("method ServiceFound")] void ServiceFound([in] IDNSSDService* browser, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR serviceName, [in] BSTR regType, [in] BSTR domain); + [id(4), helpstring("method ServiceLost")] void ServiceLost([in] IDNSSDService* browser, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR serviceName, [in] BSTR regType, [in] BSTR domain); + [id(5), helpstring("method ServiceResolved")] void ServiceResolved([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR fullName, [in] BSTR hostName, [in] USHORT port, [in] ITXTRecord* record); + [id(6), helpstring("method ServiceRegistered")] void ServiceRegistered([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] BSTR name, [in] BSTR regType, [in] BSTR domain); + [id(7), helpstring("method QueryRecordAnswered")] void QueryRecordAnswered([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR fullName, [in] DNSSDRRType rrtype, [in] DNSSDRRClass rrclass, [in] VARIANT rdata, [in] ULONG ttl); + [id(8), helpstring("method RecordRegistered")] void RecordRegistered([in] IDNSSDRecord* record, [in] DNSSDFlags flags); + [id(9), helpstring("method AddressFound")] void AddressFound([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR hostname, [in] DNSSDAddressFamily addressFamily, [in] BSTR address, [in] ULONG ttl); + [id(10), helpstring("method MappingCreated")] void MappingCreated([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] ULONG externalAddress, [in] DNSSDAddressFamily addressFamily, [in] DNSSDProtocol protocol, [in] USHORT internalPort, [in] USHORT externalPort, [in] ULONG ttl); + [id(11), helpstring("method OperationFailed")] void OperationFailed([in] IDNSSDService* service, [in] DNSSDError error); + }; + [ + uuid(24CD4DE9-FF84-4701-9DC1-9B69E0D1090A), + helpstring("DNSSDService Class") + ] + coclass DNSSDService + { + [default] interface IDNSSDService; + }; + [ + uuid(AFEE063C-05BA-4248-A26E-168477F49734), + helpstring("TXTRecord Class") + ] + coclass TXTRecord + { + [default] interface ITXTRecord; + }; + [ + uuid(5E93C5A9-7516-4259-A67B-41A656F6E01C), + helpstring("DNSSDRecord Class") + ] + coclass DNSSDRecord + { + [default] interface IDNSSDRecord; + }; + [ + uuid(BEEB932A-8D4A-4619-AEFE-A836F988B221), + helpstring("DNSSDEventManager Class") + ] + coclass DNSSDEventManager + { + [default] interface IDNSSDEventManager; + [default, source] dispinterface _IDNSSDEvents; + }; + enum DNSSDFlags; + enum DNSSDAddressFamily; + enum DNSSDProtocol; + enum DNSSDRRClass; + enum DNSSDRRType; + enum DNSSDError; +}; diff --git a/mDNSWindows/DLLX/DLLX.rc b/mDNSWindows/DLLX/DLLX.rc new file mode 100755 index 0000000..4299b5a --- /dev/null +++ b/mDNSWindows/DLLX/DLLX.rc @@ -0,0 +1,126 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" +#include "WinVersRes.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "#include ""WinVersRes.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "1 TYPELIB ""BonjourLib.tlb""\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION MASTER_PROD_VERS + PRODUCTVERSION MASTER_PROD_VERS + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", MASTER_COMPANY_NAME + VALUE "FileDescription", "Bonjour COM Component Library" + VALUE "FileVersion", MASTER_PROD_VERS_STR + VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT + VALUE "InternalName", "dnssdX.dll" + VALUE "OriginalFilename", "dnssdX.dll" + VALUE "ProductName", MASTER_PROD_NAME + VALUE "ProductVersion", MASTER_PROD_VERS_STR + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// REGISTRY +// + +IDR_DLLX REGISTRY "DLLX.rgs" +IDR_DNSSDSERVICE REGISTRY "DNSSDService.rgs" +IDR_TXTRECORD REGISTRY "TXTRecord.rgs" +IDR_DNSSDRECORD REGISTRY "DNSSDRecord.rgs" +IDR_DNSSDEVENTMANAGER REGISTRY "DNSSDEventManager.rgs" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_PROJNAME "BonjourLib" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +1 TYPELIB "dnssdX.tlb" + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/mDNSWindows/DLLX/DLLX.rgs b/mDNSWindows/DLLX/DLLX.rgs new file mode 100755 index 0000000..c55ee8d --- /dev/null +++ b/mDNSWindows/DLLX/DLLX.rgs @@ -0,0 +1,11 @@ +HKCR +{ + NoRemove AppID + { + '%APPID%' = s 'Bonjour' + 'Bonjour.DLL' + { + val AppID = s '%APPID%' + } + } +} diff --git a/mDNSWindows/DLLX/DLLX.vcproj b/mDNSWindows/DLLX/DLLX.vcproj new file mode 100755 index 0000000..04fe58b --- /dev/null +++ b/mDNSWindows/DLLX/DLLX.vcproj @@ -0,0 +1,623 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mDNSWindows/DLLX/DNSSD.cpp b/mDNSWindows/DLLX/DNSSD.cpp new file mode 100755 index 0000000..84a8206 --- /dev/null +++ b/mDNSWindows/DLLX/DNSSD.cpp @@ -0,0 +1,892 @@ +// DNSSD.cpp : Implementation of CDNSSD + +#include "stdafx.h" +#include "DNSSD.h" +#include "DNSSDService.h" +#include "TXTRecord.h" +#include +#include +#include +#include "StringServices.h" + + +// CDNSSD + +STDMETHODIMP CDNSSD::Browse(DNSSDFlags flags, ULONG ifIndex, BSTR regtype, BSTR domain, IBrowseListener* listener, IDNSSDService** browser ) +{ + CComObject * object = NULL; + std::string regtypeUTF8; + std::string domainUTF8; + DNSServiceRef sref = NULL; + DNSServiceErrorType err = 0; + HRESULT hr = 0; + BOOL ok; + + // Initialize + *browser = NULL; + + // Convert BSTR params to utf8 + ok = BSTRToUTF8( regtype, regtypeUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + ok = BSTRToUTF8( domain, domainUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + + try + { + object = new CComObject(); + } + catch ( ... ) + { + object = NULL; + } + + require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory ); + hr = object->FinalConstruct(); + require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown ); + object->AddRef(); + + err = DNSServiceBrowse( &sref, flags, ifIndex, regtypeUTF8.c_str(), domainUTF8.c_str(), ( DNSServiceBrowseReply ) &BrowseReply, object ); + require_noerr( err, exit ); + + object->SetServiceRef( sref ); + object->SetListener( listener ); + + err = object->Run(); + require_noerr( err, exit ); + + *browser = object; + +exit: + + if ( err && object ) + { + object->Release(); + } + + return err; +} + + +STDMETHODIMP CDNSSD::Resolve(DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain, IResolveListener* listener, IDNSSDService** service) +{ + CComObject * object = NULL; + std::string serviceNameUTF8; + std::string regTypeUTF8; + std::string domainUTF8; + DNSServiceRef sref = NULL; + DNSServiceErrorType err = 0; + HRESULT hr = 0; + BOOL ok; + + // Initialize + *service = NULL; + + // Convert BSTR params to utf8 + ok = BSTRToUTF8( serviceName, serviceNameUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + ok = BSTRToUTF8( regType, regTypeUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + ok = BSTRToUTF8( domain, domainUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + + try + { + object = new CComObject(); + } + catch ( ... ) + { + object = NULL; + } + + require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory ); + hr = object->FinalConstruct(); + require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown ); + object->AddRef(); + + err = DNSServiceResolve( &sref, flags, ifIndex, serviceNameUTF8.c_str(), regTypeUTF8.c_str(), domainUTF8.c_str(), ( DNSServiceResolveReply ) &ResolveReply, object ); + require_noerr( err, exit ); + + object->SetServiceRef( sref ); + object->SetListener( listener ); + + err = object->Run(); + require_noerr( err, exit ); + + *service = object; + +exit: + + if ( err && object ) + { + object->Release(); + } + + return err; +} + + +STDMETHODIMP CDNSSD::EnumerateDomains(DNSSDFlags flags, ULONG ifIndex, IDomainListener *listener, IDNSSDService **service) +{ + CComObject * object = NULL; + DNSServiceRef sref = NULL; + DNSServiceErrorType err = 0; + HRESULT hr = 0; + + // Initialize + *service = NULL; + + try + { + object = new CComObject(); + } + catch ( ... ) + { + object = NULL; + } + + require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory ); + hr = object->FinalConstruct(); + require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown ); + object->AddRef(); + + err = DNSServiceEnumerateDomains( &sref, flags, ifIndex, ( DNSServiceDomainEnumReply ) &DomainEnumReply, object ); + require_noerr( err, exit ); + + object->SetServiceRef( sref ); + object->SetListener( listener ); + + err = object->Run(); + require_noerr( err, exit ); + + *service = object; + +exit: + + if ( err && object ) + { + object->Release(); + } + + return err; +} + + +STDMETHODIMP CDNSSD::Register(DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain, BSTR host, USHORT port, ITXTRecord *record, IRegisterListener *listener, IDNSSDService **service) +{ + CComObject * object = NULL; + std::string serviceNameUTF8; + std::string regTypeUTF8; + std::string domainUTF8; + std::string hostUTF8; + const void * txtRecord = NULL; + uint16_t txtLen = 0; + DNSServiceRef sref = NULL; + DNSServiceErrorType err = 0; + HRESULT hr = 0; + BOOL ok; + + // Initialize + *service = NULL; + + // Convert BSTR params to utf8 + ok = BSTRToUTF8( serviceName, serviceNameUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + ok = BSTRToUTF8( regType, regTypeUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + ok = BSTRToUTF8( domain, domainUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + ok = BSTRToUTF8( host, hostUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + + try + { + object = new CComObject(); + } + catch ( ... ) + { + object = NULL; + } + + require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory ); + hr = object->FinalConstruct(); + require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown ); + object->AddRef(); + + if ( record ) + { + CComObject< CTXTRecord > * realTXTRecord; + + realTXTRecord = ( CComObject< CTXTRecord >* ) record; + + txtRecord = realTXTRecord->GetBytes(); + txtLen = realTXTRecord->GetLen(); + } + + err = DNSServiceRegister( &sref, flags, ifIndex, serviceNameUTF8.c_str(), regTypeUTF8.c_str(), domainUTF8.c_str(), hostUTF8.c_str(), port, txtLen, txtRecord, ( DNSServiceRegisterReply ) &RegisterReply, object ); + require_noerr( err, exit ); + + object->SetServiceRef( sref ); + object->SetListener( listener ); + + err = object->Run(); + require_noerr( err, exit ); + + *service = object; + +exit: + + if ( err && object ) + { + object->Release(); + } + + return err; +} + + +STDMETHODIMP CDNSSD::QueryRecord(DNSSDFlags flags, ULONG ifIndex, BSTR fullname, DNSSDRRType rrtype, DNSSDRRClass rrclass, IQueryRecordListener *listener, IDNSSDService **service) +{ + CComObject * object = NULL; + DNSServiceRef sref = NULL; + std::string fullNameUTF8; + DNSServiceErrorType err = 0; + HRESULT hr = 0; + BOOL ok; + + // Initialize + *service = NULL; + + // Convert BSTR params to utf8 + ok = BSTRToUTF8( fullname, fullNameUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + + try + { + object = new CComObject(); + } + catch ( ... ) + { + object = NULL; + } + + require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory ); + hr = object->FinalConstruct(); + require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown ); + object->AddRef(); + + err = DNSServiceQueryRecord( &sref, flags, ifIndex, fullNameUTF8.c_str(), ( uint16_t ) rrtype, ( uint16_t ) rrclass, ( DNSServiceQueryRecordReply ) &QueryRecordReply, object ); + require_noerr( err, exit ); + + object->SetServiceRef( sref ); + object->SetListener( listener ); + + err = object->Run(); + require_noerr( err, exit ); + + *service = object; + +exit: + + if ( err && object ) + { + object->Release(); + } + + return err; +} + + +STDMETHODIMP CDNSSD::GetAddrInfo(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, BSTR hostName, IGetAddrInfoListener *listener, IDNSSDService **service) +{ + CComObject * object = NULL; + DNSServiceRef sref = NULL; + std::string hostNameUTF8; + DNSServiceErrorType err = 0; + HRESULT hr = 0; + BOOL ok; + + // Initialize + *service = NULL; + + // Convert BSTR params to utf8 + ok = BSTRToUTF8( hostName, hostNameUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + + try + { + object = new CComObject(); + } + catch ( ... ) + { + object = NULL; + } + + require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory ); + hr = object->FinalConstruct(); + require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown ); + object->AddRef(); + + err = DNSServiceGetAddrInfo( &sref, flags, ifIndex, addressFamily, hostNameUTF8.c_str(), ( DNSServiceGetAddrInfoReply ) &GetAddrInfoReply, object ); + require_noerr( err, exit ); + + object->SetServiceRef( sref ); + object->SetListener( listener ); + + err = object->Run(); + require_noerr( err, exit ); + + *service = object; + +exit: + + if ( err && object ) + { + object->Release(); + } + + return err; +} + + +STDMETHODIMP CDNSSD::CreateConnection(IDNSSDService **service) +{ + CComObject * object = NULL; + DNSServiceRef sref = NULL; + DNSServiceErrorType err = 0; + HRESULT hr = 0; + + // Initialize + *service = NULL; + + try + { + object = new CComObject(); + } + catch ( ... ) + { + object = NULL; + } + + require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory ); + hr = object->FinalConstruct(); + require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown ); + object->AddRef(); + + err = DNSServiceCreateConnection( &sref ); + require_noerr( err, exit ); + + object->SetServiceRef( sref ); + + *service = object; + +exit: + + if ( err && object ) + { + object->Release(); + } + + return err; +} + + +STDMETHODIMP CDNSSD::NATPortMappingCreate(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, DNSSDProtocol protocol, USHORT internalPort, USHORT externalPort, ULONG ttl, INATPortMappingListener *listener, IDNSSDService **service) +{ + CComObject * object = NULL; + DNSServiceRef sref = NULL; + DNSServiceProtocol prot = 0; + DNSServiceErrorType err = 0; + HRESULT hr = 0; + + // Initialize + *service = NULL; + + try + { + object = new CComObject(); + } + catch ( ... ) + { + object = NULL; + } + + require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory ); + hr = object->FinalConstruct(); + require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown ); + object->AddRef(); + + prot = ( addressFamily | protocol ); + + err = DNSServiceNATPortMappingCreate( &sref, flags, ifIndex, prot, internalPort, externalPort, ttl, ( DNSServiceNATPortMappingReply ) &NATPortMappingReply, object ); + require_noerr( err, exit ); + + object->SetServiceRef( sref ); + object->SetListener( listener ); + + err = object->Run(); + require_noerr( err, exit ); + + *service = object; + +exit: + + if ( err && object ) + { + object->Release(); + } + + return err; +} + + +STDMETHODIMP CDNSSD::GetProperty(BSTR prop, VARIANT * value ) +{ + std::string propUTF8; + std::vector< BYTE > byteArray; + SAFEARRAY * psa = NULL; + BYTE * pData = NULL; + uint32_t elems = 0; + DNSServiceErrorType err = 0; + BOOL ok = TRUE; + + // Convert BSTR params to utf8 + ok = BSTRToUTF8( prop, propUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + + // Setup the byte array + require_action( V_VT( value ) == ( VT_ARRAY|VT_UI1 ), exit, err = kDNSServiceErr_Unknown ); + psa = V_ARRAY( value ); + require_action( psa, exit, err = kDNSServiceErr_Unknown ); + require_action( SafeArrayGetDim( psa ) == 1, exit, err = kDNSServiceErr_Unknown ); + byteArray.reserve( psa->rgsabound[0].cElements ); + byteArray.assign( byteArray.capacity(), 0 ); + elems = ( uint32_t ) byteArray.capacity(); + + // Call the function and package the return value in the Variant + err = DNSServiceGetProperty( propUTF8.c_str(), &byteArray[ 0 ], &elems ); + require_noerr( err, exit ); + ok = ByteArrayToVariant( &byteArray[ 0 ], elems, value ); + require_action( ok, exit, err = kDNSSDError_Unknown ); + +exit: + + if ( psa ) + { + SafeArrayUnaccessData( psa ); + psa = NULL; + } + + return err; +} + + +void DNSSD_API +CDNSSD::DomainEnumReply + ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t ifIndex, + DNSServiceErrorType errorCode, + const char *replyDomainUTF8, + void *context + ) +{ + CComObject * service; + int err; + + service = ( CComObject< CDNSSDService>* ) context; + require_action( service, exit, err = kDNSServiceErr_Unknown ); + + if ( !service->Stopped() ) + { + IDomainListener * listener; + + listener = ( IDomainListener* ) service->GetListener(); + require_action( listener, exit, err = kDNSServiceErr_Unknown ); + + if ( !errorCode ) + { + CComBSTR replyDomain; + + UTF8ToBSTR( replyDomainUTF8, replyDomain ); + + if ( flags & kDNSServiceFlagsAdd ) + { + listener->DomainFound( service, ( DNSSDFlags ) flags, ifIndex, replyDomain ); + } + else + { + listener->DomainLost( service, ( DNSSDFlags ) flags, ifIndex, replyDomain ); + } + } + else + { + listener->EnumDomainsFailed( service, ( DNSSDError ) errorCode ); + } + } + +exit: + + return; +} + + +void DNSSD_API +CDNSSD::BrowseReply + ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t ifIndex, + DNSServiceErrorType errorCode, + const char *serviceNameUTF8, + const char *regTypeUTF8, + const char *replyDomainUTF8, + void *context + ) +{ + CComObject * service; + int err; + + service = ( CComObject< CDNSSDService>* ) context; + require_action( service, exit, err = kDNSServiceErr_Unknown ); + + if ( !service->Stopped() ) + { + IBrowseListener * listener; + + listener = ( IBrowseListener* ) service->GetListener(); + require_action( listener, exit, err = kDNSServiceErr_Unknown ); + + if ( !errorCode ) + { + CComBSTR serviceName; + CComBSTR regType; + CComBSTR replyDomain; + + UTF8ToBSTR( serviceNameUTF8, serviceName ); + UTF8ToBSTR( regTypeUTF8, regType ); + UTF8ToBSTR( replyDomainUTF8, replyDomain ); + + if ( flags & kDNSServiceFlagsAdd ) + { + listener->ServiceFound( service, ( DNSSDFlags ) flags, ifIndex, serviceName, regType, replyDomain ); + } + else + { + listener->ServiceLost( service, ( DNSSDFlags ) flags, ifIndex, serviceName, regType, replyDomain ); + } + } + else + { + listener->BrowseFailed( service, ( DNSSDError ) errorCode ); + } + } + +exit: + + return; +} + + +void DNSSD_API +CDNSSD::ResolveReply + ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t ifIndex, + DNSServiceErrorType errorCode, + const char *fullNameUTF8, + const char *hostNameUTF8, + uint16_t port, + uint16_t txtLen, + const unsigned char *txtRecord, + void *context + ) +{ + CComObject * service; + int err; + + service = ( CComObject< CDNSSDService>* ) context; + require_action( service, exit, err = kDNSServiceErr_Unknown ); + + if ( !service->Stopped() ) + { + IResolveListener * listener; + + listener = ( IResolveListener* ) service->GetListener(); + require_action( listener, exit, err = kDNSServiceErr_Unknown ); + + if ( !errorCode ) + { + CComBSTR fullName; + CComBSTR hostName; + CComBSTR regType; + CComBSTR replyDomain; + CComObject< CTXTRecord >* record; + BOOL ok; + + ok = UTF8ToBSTR( fullNameUTF8, fullName ); + require_action( ok, exit, err = kDNSServiceErr_Unknown ); + ok = UTF8ToBSTR( hostNameUTF8, hostName ); + require_action( ok, exit, err = kDNSServiceErr_Unknown ); + + try + { + record = new CComObject(); + } + catch ( ... ) + { + record = NULL; + } + + require_action( record, exit, err = kDNSServiceErr_NoMemory ); + record->AddRef(); + + char buf[ 64 ]; + sprintf( buf, "txtLen = %d", txtLen ); + OutputDebugStringA( buf ); + + if ( txtLen > 0 ) + { + record->SetBytes( txtRecord, txtLen ); + } + + listener->ServiceResolved( service, ( DNSSDFlags ) flags, ifIndex, fullName, hostName, port, record ); + } + else + { + listener->ResolveFailed( service, ( DNSSDError ) errorCode ); + } + } + +exit: + + return; +} + + +void DNSSD_API +CDNSSD::RegisterReply + ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + DNSServiceErrorType errorCode, + const char *serviceNameUTF8, + const char *regTypeUTF8, + const char *domainUTF8, + void *context + ) +{ + CComObject * service; + int err; + + service = ( CComObject< CDNSSDService>* ) context; + require_action( service, exit, err = kDNSServiceErr_Unknown ); + + if ( !service->Stopped() ) + { + IRegisterListener * listener; + + listener = ( IRegisterListener* ) service->GetListener(); + require_action( listener, exit, err = kDNSServiceErr_Unknown ); + + if ( !errorCode ) + { + CComBSTR serviceName; + CComBSTR regType; + CComBSTR domain; + BOOL ok; + + ok = UTF8ToBSTR( serviceNameUTF8, serviceName ); + require_action( ok, exit, err = kDNSServiceErr_Unknown ); + ok = UTF8ToBSTR( regTypeUTF8, regType ); + require_action( ok, exit, err = kDNSServiceErr_Unknown ); + ok = UTF8ToBSTR( domainUTF8, domain ); + require_action( ok, exit, err = kDNSServiceErr_Unknown ); + + listener->ServiceRegistered( service, ( DNSSDFlags ) flags, serviceName, regType, domain ); + } + else + { + listener->ServiceRegisterFailed( service, ( DNSSDError ) errorCode ); + } + } + +exit: + + return; +} + + +void DNSSD_API +CDNSSD::QueryRecordReply + ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t ifIndex, + DNSServiceErrorType errorCode, + const char *fullNameUTF8, + uint16_t rrtype, + uint16_t rrclass, + uint16_t rdlen, + const void *rdata, + uint32_t ttl, + void *context + ) +{ + CComObject * service; + int err; + + service = ( CComObject< CDNSSDService>* ) context; + require_action( service, exit, err = kDNSServiceErr_Unknown ); + + if ( !service->Stopped() ) + { + IQueryRecordListener * listener; + + listener = ( IQueryRecordListener* ) service->GetListener(); + require_action( listener, exit, err = kDNSServiceErr_Unknown ); + + if ( !errorCode ) + { + CComBSTR fullName; + VARIANT var; + BOOL ok; + + ok = UTF8ToBSTR( fullNameUTF8, fullName ); + require_action( ok, exit, err = kDNSServiceErr_Unknown ); + ok = ByteArrayToVariant( rdata, rdlen, &var ); + require_action( ok, exit, err = kDNSServiceErr_Unknown ); + + listener->QueryRecordAnswered( service, ( DNSSDFlags ) flags, ifIndex, fullName, ( DNSSDRRType ) rrtype, ( DNSSDRRClass ) rrclass, var, ttl ); + } + else + { + listener->QueryRecordFailed( service, ( DNSSDError ) errorCode ); + } + } + +exit: + + return; +} + + +void DNSSD_API +CDNSSD::GetAddrInfoReply + ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t ifIndex, + DNSServiceErrorType errorCode, + const char *hostNameUTF8, + const struct sockaddr *rawAddress, + uint32_t ttl, + void *context + ) +{ + CComObject * service; + int err; + + service = ( CComObject< CDNSSDService>* ) context; + require_action( service, exit, err = kDNSServiceErr_Unknown ); + + if ( !service->Stopped() ) + { + IGetAddrInfoListener * listener; + + listener = ( IGetAddrInfoListener* ) service->GetListener(); + require_action( listener, exit, err = kDNSServiceErr_Unknown ); + + if ( !errorCode ) + { + CComBSTR hostName; + DWORD sockaddrLen; + DNSSDAddressFamily addressFamily; + char addressUTF8[INET6_ADDRSTRLEN]; + DWORD addressLen = sizeof( addressUTF8 ); + CComBSTR address; + BOOL ok; + + ok = UTF8ToBSTR( hostNameUTF8, hostName ); + require_action( ok, exit, err = kDNSServiceErr_Unknown ); + + switch ( rawAddress->sa_family ) + { + case AF_INET: + { + addressFamily = kDNSSDAddressFamily_IPv4; + sockaddrLen = sizeof( sockaddr_in ); + } + break; + + case AF_INET6: + { + addressFamily = kDNSSDAddressFamily_IPv6; + sockaddrLen = sizeof( sockaddr_in6 ); + } + break; + } + + err = WSAAddressToStringA( ( LPSOCKADDR ) rawAddress, sockaddrLen, NULL, addressUTF8, &addressLen ); + require_noerr( err, exit ); + ok = UTF8ToBSTR( addressUTF8, address ); + require_action( ok, exit, err = kDNSServiceErr_Unknown ); + + listener->GetAddrInfoReply( service, ( DNSSDFlags ) flags, ifIndex, hostName, addressFamily, address, ttl ); + } + else + { + listener->GetAddrInfoFailed( service, ( DNSSDError ) errorCode ); + } + } + +exit: + + return; +} + + +void DNSSD_API +CDNSSD::NATPortMappingReply + ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t ifIndex, + DNSServiceErrorType errorCode, + uint32_t externalAddress, /* four byte IPv4 address in network byte order */ + DNSServiceProtocol protocol, + uint16_t internalPort, + uint16_t externalPort, /* may be different than the requested port */ + uint32_t ttl, /* may be different than the requested ttl */ + void *context + ) +{ + CComObject * service; + int err; + + service = ( CComObject< CDNSSDService>* ) context; + require_action( service, exit, err = kDNSServiceErr_Unknown ); + + if ( !service->Stopped() ) + { + INATPortMappingListener * listener; + + listener = ( INATPortMappingListener* ) service->GetListener(); + require_action( listener, exit, err = kDNSServiceErr_Unknown ); + + if ( !errorCode ) + { + listener->MappingCreated( service, ( DNSSDFlags ) flags, ifIndex, externalAddress, ( DNSSDAddressFamily ) ( protocol & 0x8 ), ( DNSSDProtocol ) ( protocol & 0x80 ), internalPort, externalPort, ttl ); + } + else + { + listener->MappingFailed( service, ( DNSSDError ) errorCode ); + } + } + +exit: + + return; +} + diff --git a/mDNSWindows/DLLX/DNSSDEventManager.cpp b/mDNSWindows/DLLX/DNSSDEventManager.cpp new file mode 100755 index 0000000..af3248c --- /dev/null +++ b/mDNSWindows/DLLX/DNSSDEventManager.cpp @@ -0,0 +1,31 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2009 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. + + Change History (most recent first): + +$Log: DNSSDEventManager.cpp,v $ +Revision 1.1 2009/05/26 04:43:54 herscher + COM component that can be used with any .NET language and VB. + + +*/ + +#include "stdafx.h" +#include "DNSSDEventManager.h" + + +// CDNSSDEventManager + diff --git a/mDNSWindows/DLLX/DNSSDEventManager.h b/mDNSWindows/DLLX/DNSSDEventManager.h new file mode 100755 index 0000000..3e43b2e --- /dev/null +++ b/mDNSWindows/DLLX/DNSSDEventManager.h @@ -0,0 +1,82 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2009 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. + + Change History (most recent first): + +$Log: DNSSDEventManager.h,v $ +Revision 1.1 2009/05/26 04:43:54 herscher + COM component that can be used with any .NET language and VB. + + +*/ + +#pragma once +#include "resource.h" // main symbols + +#include "DLLX.h" +#include "_IDNSSDEvents_CP.H" + + +#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) +#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms." +#endif + + + +// CDNSSDEventManager + +class ATL_NO_VTABLE CDNSSDEventManager : + public CComObjectRootEx, + public CComCoClass, + public IConnectionPointContainerImpl, + public CProxy_IDNSSDEvents, + public IDispatchImpl +{ +public: + CDNSSDEventManager() + { + } + +DECLARE_REGISTRY_RESOURCEID(IDR_DNSSDEVENTMANAGER) + + +BEGIN_COM_MAP(CDNSSDEventManager) + COM_INTERFACE_ENTRY(IDNSSDEventManager) + COM_INTERFACE_ENTRY(IDispatch) + COM_INTERFACE_ENTRY(IConnectionPointContainer) +END_COM_MAP() + +BEGIN_CONNECTION_POINT_MAP(CDNSSDEventManager) + CONNECTION_POINT_ENTRY(__uuidof(_IDNSSDEvents)) +END_CONNECTION_POINT_MAP() + + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + HRESULT FinalConstruct() + { + return S_OK; + } + + void FinalRelease() + { + } + +public: + +}; + +OBJECT_ENTRY_AUTO(__uuidof(DNSSDEventManager), CDNSSDEventManager) diff --git a/mDNSWindows/DLLX/DNSSDEventManager.rgs b/mDNSWindows/DLLX/DNSSDEventManager.rgs new file mode 100755 index 0000000..9103512 --- /dev/null +++ b/mDNSWindows/DLLX/DNSSDEventManager.rgs @@ -0,0 +1,27 @@ +HKCR +{ + Bonjour.DNSSDEventManager.1 = s 'DNSSDEventManager Class' + { + CLSID = s '{BEEB932A-8D4A-4619-AEFE-A836F988B221}' + } + Bonjour.DNSSDEventManager = s 'DNSSDEventManager Class' + { + CLSID = s '{BEEB932A-8D4A-4619-AEFE-A836F988B221}' + CurVer = s 'Bonjour.DNSSDEventManager.1' + } + NoRemove CLSID + { + ForceRemove {BEEB932A-8D4A-4619-AEFE-A836F988B221} = s 'DNSSDEventManager Class' + { + ProgID = s 'Bonjour.DNSSDEventManager.1' + VersionIndependentProgID = s 'Bonjour.DNSSDEventManager' + ForceRemove 'Programmable' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + val AppID = s '%APPID%' + 'TypeLib' = s '{18FBED6D-F2B7-4EC8-A4A4-46282E635308}' + } + } +} diff --git a/mDNSWindows/DLLX/DNSSDRecord.cpp b/mDNSWindows/DLLX/DNSSDRecord.cpp new file mode 100755 index 0000000..37955af --- /dev/null +++ b/mDNSWindows/DLLX/DNSSDRecord.cpp @@ -0,0 +1,66 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2009 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. + + Change History (most recent first): + +$Log: DNSSDRecord.cpp,v $ +Revision 1.1 2009/05/26 04:43:54 herscher + COM component that can be used with any .NET language and VB. + + +*/ + +#include "stdafx.h" +#include "DNSSDRecord.h" +#include "StringServices.h" +#include + + +// CDNSSDRecord + +STDMETHODIMP CDNSSDRecord::Update(DNSSDFlags flags, VARIANT rdata, ULONG ttl) +{ + std::vector< BYTE > byteArray; + const void * byteArrayPtr = NULL; + DNSServiceErrorType err = 0; + HRESULT hr = 0; + BOOL ok; + + // Convert the VARIANT + ok = VariantToByteArray( &rdata, byteArray ); + require_action( ok, exit, err = kDNSServiceErr_Unknown ); + + err = DNSServiceUpdateRecord( m_serviceObject->GetSubordRef(), m_rref, flags, ( uint16_t ) byteArray.size(), byteArray.size() > 0 ? &byteArray[ 0 ] : NULL, ttl ); + require_noerr( err, exit ); + +exit: + + return err; +} + + +STDMETHODIMP CDNSSDRecord::Remove(DNSSDFlags flags) +{ + DNSServiceErrorType err = 0; + + err = DNSServiceRemoveRecord( m_serviceObject->GetSubordRef(), m_rref, flags ); + require_noerr( err, exit ); + +exit: + + return err; +} + diff --git a/mDNSWindows/DLLX/DNSSDRecord.h b/mDNSWindows/DLLX/DNSSDRecord.h new file mode 100755 index 0000000..fcf5c74 --- /dev/null +++ b/mDNSWindows/DLLX/DNSSDRecord.h @@ -0,0 +1,108 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2009 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. + + Change History (most recent first): + +$Log: DNSSDRecord.h,v $ +Revision 1.1 2009/05/26 04:43:54 herscher + COM component that can be used with any .NET language and VB. + + +*/ + +#pragma once +#include "resource.h" // main symbols + +#include "DLLX.h" +#include "DNSSDService.h" +#include + + +#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) +#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms." +#endif + + + +// CDNSSDRecord + +class ATL_NO_VTABLE CDNSSDRecord : + public CComObjectRootEx, + public CComCoClass, + public IDispatchImpl +{ +public: + CDNSSDRecord() + { + } + +DECLARE_REGISTRY_RESOURCEID(IDR_DNSSDRECORD) + + +BEGIN_COM_MAP(CDNSSDRecord) + COM_INTERFACE_ENTRY(IDNSSDRecord) + COM_INTERFACE_ENTRY(IDispatch) +END_COM_MAP() + + + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + HRESULT FinalConstruct() + { + return S_OK; + } + + void FinalRelease() + { + } + + inline CDNSSDService* + GetServiceObject() + { + return m_serviceObject; + } + + inline void + SetServiceObject( CDNSSDService * serviceObject ) + { + m_serviceObject = serviceObject; + } + + inline DNSRecordRef + GetRecordRef() + { + return m_rref; + } + + inline void + SetRecordRef( DNSRecordRef rref ) + { + m_rref = rref; + } + +public: + + STDMETHOD(Update)(DNSSDFlags flags, VARIANT rdata, ULONG ttl); + STDMETHOD(Remove)(DNSSDFlags flags); + +private: + + CDNSSDService * m_serviceObject; + DNSRecordRef m_rref; +}; + +OBJECT_ENTRY_AUTO(__uuidof(DNSSDRecord), CDNSSDRecord) diff --git a/mDNSWindows/DLLX/DNSSDRecord.rgs b/mDNSWindows/DLLX/DNSSDRecord.rgs new file mode 100755 index 0000000..ee0a5a2 --- /dev/null +++ b/mDNSWindows/DLLX/DNSSDRecord.rgs @@ -0,0 +1,27 @@ +HKCR +{ + Bonjour.DNSSDRecord.1 = s 'DNSSDRecord Class' + { + CLSID = s '{5E93C5A9-7516-4259-A67B-41A656F6E01C}' + } + Bonjour.DNSSDRecord = s 'DNSSDRecord Class' + { + CLSID = s '{5E93C5A9-7516-4259-A67B-41A656F6E01C}' + CurVer = s 'Bonjour.DNSSDRecord.1' + } + NoRemove CLSID + { + ForceRemove {5E93C5A9-7516-4259-A67B-41A656F6E01C} = s 'DNSSDRecord Class' + { + ProgID = s 'Bonjour.DNSSDRecord.1' + VersionIndependentProgID = s 'Bonjour.DNSSDRecord' + ForceRemove 'Programmable' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + val AppID = s '%APPID%' + 'TypeLib' = s '{18FBED6D-F2B7-4EC8-A4A4-46282E635308}' + } + } +} diff --git a/mDNSWindows/DLLX/DNSSDService.cpp b/mDNSWindows/DLLX/DNSSDService.cpp new file mode 100755 index 0000000..219c610 --- /dev/null +++ b/mDNSWindows/DLLX/DNSSDService.cpp @@ -0,0 +1,1106 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2009 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. + + Change History (most recent first): + +$Log: DNSSDService.cpp,v $ +Revision 1.1 2009/05/26 04:43:54 herscher + COM component that can be used with any .NET language and VB. + + +*/ + +#pragma warning(disable:4995) + +#include "stdafx.h" +#include +#include "DNSSDService.h" +#include "DNSSDEventManager.h" +#include "DNSSDRecord.h" +#include "TXTRecord.h" +#include "StringServices.h" +#include + + +#define WM_SOCKET (WM_APP + 100) + + +// CDNSSDService + +BOOL CDNSSDService::m_registeredWindowClass = FALSE; +HWND CDNSSDService::m_hiddenWindow = NULL; +CDNSSDService::SocketMap CDNSSDService::m_socketMap; + + +HRESULT CDNSSDService::FinalConstruct() +{ + DNSServiceErrorType err = 0; + HRESULT hr = S_OK; + + m_isPrimary = TRUE; + err = DNSServiceCreateConnection( &m_primary ); + require_action( !err, exit, hr = E_FAIL ); + + if ( !m_hiddenWindow ) + { + TCHAR windowClassName[ 256 ]; + + StringCchPrintf( windowClassName, sizeof( windowClassName ) / sizeof( TCHAR ), TEXT( "Bonjour Hidden Window %d" ), GetProcessId( NULL ) ); + + if ( !m_registeredWindowClass ) + { + WNDCLASS wc; + ATOM atom; + + wc.style = 0; + wc.lpfnWndProc = WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = NULL; + wc.hIcon = NULL; + wc.hCursor = NULL; + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = windowClassName; + + atom = RegisterClass(&wc); + require_action( atom != NULL, exit, hr = E_FAIL ); + + m_registeredWindowClass = TRUE; + } + + m_hiddenWindow = CreateWindow( windowClassName, windowClassName, WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL, GetModuleHandle( NULL ), NULL ); + require_action( m_hiddenWindow != NULL, exit, hr = E_FAIL ); + } + + err = WSAAsyncSelect( DNSServiceRefSockFD( m_primary ), m_hiddenWindow, WM_SOCKET, FD_READ ); + require_action( !err, exit, hr = E_FAIL ); + + m_socketMap[ DNSServiceRefSockFD( m_primary ) ] = this; + +exit: + + return hr; +} + + +void CDNSSDService::FinalRelease() +{ + dlog( kDebugLevelTrace, "FinalRelease()\n" ); + Stop(); +} + + +STDMETHODIMP CDNSSDService::EnumerateDomains(DNSSDFlags flags, ULONG ifIndex, IDNSSDEventManager *eventManager, IDNSSDService **service) +{ + CComObject * object = NULL; + DNSServiceRef subord = NULL; + DNSServiceErrorType err = 0; + HRESULT hr = 0; + + check( m_primary ); + + // Initialize + *service = NULL; + + try + { + object = new CComObject(); + } + catch ( ... ) + { + object = NULL; + } + + require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory ); + object->AddRef(); + + subord = m_primary; + err = DNSServiceEnumerateDomains( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, ( DNSServiceDomainEnumReply ) &DomainEnumReply, object ); + require_noerr( err, exit ); + + object->SetPrimaryRef( m_primary ); + object->SetSubordRef( subord ); + object->SetEventManager( eventManager ); + + *service = object; + +exit: + + if ( err && object ) + { + object->Release(); + } + + return err; +} + + +STDMETHODIMP CDNSSDService::Browse(DNSSDFlags flags, ULONG ifIndex, BSTR regtype, BSTR domain, IDNSSDEventManager* eventManager, IDNSSDService** service ) +{ + CComObject * object = NULL; + std::string regtypeUTF8; + std::string domainUTF8; + DNSServiceRef subord = NULL; + DNSServiceErrorType err = 0; + HRESULT hr = 0; + BOOL ok; + + check( m_primary ); + + // Initialize + *service = NULL; + + // Convert BSTR params to utf8 + ok = BSTRToUTF8( regtype, regtypeUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + ok = BSTRToUTF8( domain, domainUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + + try + { + object = new CComObject(); + } + catch ( ... ) + { + object = NULL; + } + + require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory ); + object->AddRef(); + + subord = m_primary; + err = DNSServiceBrowse( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, regtypeUTF8.c_str(), ( domainUTF8.size() > 0 ) ? domainUTF8.c_str() : NULL, ( DNSServiceBrowseReply ) &BrowseReply, object ); + require_noerr( err, exit ); + + object->SetPrimaryRef( m_primary ); + object->SetSubordRef( subord ); + object->SetEventManager( eventManager ); + + *service = object; + +exit: + + if ( err && object ) + { + object->Release(); + } + + return err; +} + + +STDMETHODIMP CDNSSDService::Resolve(DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain, IDNSSDEventManager* eventManager, IDNSSDService** service) +{ + CComObject * object = NULL; + std::string serviceNameUTF8; + std::string regTypeUTF8; + std::string domainUTF8; + DNSServiceRef subord = NULL; + DNSServiceErrorType err = 0; + HRESULT hr = 0; + BOOL ok; + + check( m_primary ); + + // Initialize + *service = NULL; + + // Convert BSTR params to utf8 + ok = BSTRToUTF8( serviceName, serviceNameUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + ok = BSTRToUTF8( regType, regTypeUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + ok = BSTRToUTF8( domain, domainUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + + try + { + object = new CComObject(); + } + catch ( ... ) + { + object = NULL; + } + + require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory ); + object->AddRef(); + + subord = m_primary; + err = DNSServiceResolve( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, serviceNameUTF8.c_str(), regTypeUTF8.c_str(), domainUTF8.c_str(), ( DNSServiceResolveReply ) &ResolveReply, object ); + require_noerr( err, exit ); + + object->SetPrimaryRef( m_primary ); + object->SetSubordRef( subord ); + object->SetEventManager( eventManager ); + + *service = object; + +exit: + + if ( err && object ) + { + object->Release(); + } + + return err; +} + + +STDMETHODIMP CDNSSDService::Register(DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain, BSTR host, USHORT port, ITXTRecord *record, IDNSSDEventManager *eventManager, IDNSSDService **service) +{ + CComObject * object = NULL; + std::string serviceNameUTF8; + std::string regTypeUTF8; + std::string domainUTF8; + std::string hostUTF8; + const void * txtRecord = NULL; + uint16_t txtLen = 0; + DNSServiceRef subord = NULL; + DNSServiceErrorType err = 0; + HRESULT hr = 0; + BOOL ok; + + check( m_primary ); + + // Initialize + *service = NULL; + + // Convert BSTR params to utf8 + ok = BSTRToUTF8( serviceName, serviceNameUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + ok = BSTRToUTF8( regType, regTypeUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + ok = BSTRToUTF8( domain, domainUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + ok = BSTRToUTF8( host, hostUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + + try + { + object = new CComObject(); + } + catch ( ... ) + { + object = NULL; + } + + require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory ); + object->AddRef(); + + if ( record ) + { + CComObject< CTXTRecord > * realTXTRecord; + + realTXTRecord = ( CComObject< CTXTRecord >* ) record; + + txtRecord = realTXTRecord->GetBytes(); + txtLen = realTXTRecord->GetLen(); + } + + subord = m_primary; + err = DNSServiceRegister( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, serviceNameUTF8.c_str(), regTypeUTF8.c_str(), ( domainUTF8.size() > 0 ) ? domainUTF8.c_str() : NULL, hostUTF8.c_str(), htons( port ), txtLen, txtRecord, ( DNSServiceRegisterReply ) &RegisterReply, object ); + require_noerr( err, exit ); + + object->SetPrimaryRef( m_primary ); + object->SetSubordRef( subord ); + object->SetEventManager( eventManager ); + + *service = object; + +exit: + + if ( err && object ) + { + object->Release(); + } + + return err; +} + + +STDMETHODIMP CDNSSDService::QueryRecord(DNSSDFlags flags, ULONG ifIndex, BSTR fullname, DNSSDRRType rrtype, DNSSDRRClass rrclass, IDNSSDEventManager *eventManager, IDNSSDService **service) +{ + CComObject * object = NULL; + DNSServiceRef subord = NULL; + std::string fullNameUTF8; + DNSServiceErrorType err = 0; + HRESULT hr = 0; + BOOL ok; + + check( m_primary ); + + // Initialize + *service = NULL; + + // Convert BSTR params to utf8 + ok = BSTRToUTF8( fullname, fullNameUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + + try + { + object = new CComObject(); + } + catch ( ... ) + { + object = NULL; + } + + require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory ); + object->AddRef(); + + subord = m_primary; + err = DNSServiceQueryRecord( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, fullNameUTF8.c_str(), ( uint16_t ) rrtype, ( uint16_t ) rrclass, ( DNSServiceQueryRecordReply ) &QueryRecordReply, object ); + require_noerr( err, exit ); + + object->SetPrimaryRef( m_primary ); + object->SetSubordRef( subord ); + object->SetEventManager( eventManager ); + + *service = object; + +exit: + + if ( err && object ) + { + object->Release(); + } + + return err; +} + + +STDMETHODIMP CDNSSDService::RegisterRecord(DNSSDFlags flags, ULONG ifIndex, BSTR fullName, DNSSDRRType rrtype, DNSSDRRClass rrclass, VARIANT rdata, ULONG ttl, IDNSSDEventManager* eventManager, IDNSSDRecord** record) +{ + CComObject * object = NULL; + DNSRecordRef rref = NULL; + std::string fullNameUTF8; + std::vector< BYTE > byteArray; + const void * byteArrayPtr = NULL; + DNSServiceErrorType err = 0; + HRESULT hr = 0; + BOOL ok; + + check( m_primary ); + + // Initialize + *object = NULL; + + // Convert BSTR params to utf8 + ok = BSTRToUTF8( fullName, fullNameUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + + // Convert the VARIANT + ok = VariantToByteArray( &rdata, byteArray ); + require_action( ok, exit, err = kDNSServiceErr_Unknown ); + + try + { + object = new CComObject(); + } + catch ( ... ) + { + object = NULL; + } + + require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory ); + object->AddRef(); + + err = DNSServiceRegisterRecord( m_primary, &rref, flags, ifIndex, fullNameUTF8.c_str(), rrtype, rrclass, ( uint16_t ) byteArray.size(), byteArray.size() > 0 ? &byteArray[ 0 ] : NULL, ttl, &RegisterRecordReply, object ); + require_noerr( err, exit ); + + object->SetServiceObject( this ); + object->SetRecordRef( rref ); + this->SetEventManager( eventManager ); + + *record = object; + +exit: + + if ( err && object ) + { + object->Release(); + } + + return err; +} + + +STDMETHODIMP CDNSSDService::AddRecord(DNSSDFlags flags, DNSSDRRType rrtype, VARIANT rdata, ULONG ttl, IDNSSDRecord ** record) +{ + CComObject * object = NULL; + DNSRecordRef rref = NULL; + std::vector< BYTE > byteArray; + const void * byteArrayPtr = NULL; + DNSServiceErrorType err = 0; + HRESULT hr = 0; + BOOL ok; + + check( m_primary ); + + // Initialize + *object = NULL; + + // Convert the VARIANT + ok = VariantToByteArray( &rdata, byteArray ); + require_action( ok, exit, err = kDNSServiceErr_Unknown ); + + try + { + object = new CComObject(); + } + catch ( ... ) + { + object = NULL; + } + + require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory ); + object->AddRef(); + + err = DNSServiceAddRecord( m_primary, &rref, flags, rrtype, ( uint16_t ) byteArray.size(), byteArray.size() > 0 ? &byteArray[ 0 ] : NULL, ttl ); + require_noerr( err, exit ); + + object->SetServiceObject( this ); + object->SetRecordRef( rref ); + + *record = object; + +exit: + + if ( err && object ) + { + object->Release(); + } + + return err; +} + +STDMETHODIMP CDNSSDService::ReconfirmRecord(DNSSDFlags flags, ULONG ifIndex, BSTR fullName, DNSSDRRType rrtype, DNSSDRRClass rrclass, VARIANT rdata) +{ + std::string fullNameUTF8; + std::vector< BYTE > byteArray; + const void * byteArrayPtr = NULL; + DNSServiceErrorType err = 0; + HRESULT hr = 0; + BOOL ok; + + // Convert BSTR params to utf8 + ok = BSTRToUTF8( fullName, fullNameUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + + // Convert the VARIANT + ok = VariantToByteArray( &rdata, byteArray ); + require_action( ok, exit, err = kDNSServiceErr_Unknown ); + + err = DNSServiceReconfirmRecord( flags, ifIndex, fullNameUTF8.c_str(), rrtype, rrclass, ( uint16_t ) byteArray.size(), byteArray.size() > 0 ? &byteArray[ 0 ] : NULL ); + require_noerr( err, exit ); + +exit: + + return err; +} + + +STDMETHODIMP CDNSSDService::GetProperty(BSTR prop, VARIANT * value ) +{ + std::string propUTF8; + std::vector< BYTE > byteArray; + SAFEARRAY * psa = NULL; + BYTE * pData = NULL; + uint32_t elems = 0; + DNSServiceErrorType err = 0; + BOOL ok = TRUE; + + // Convert BSTR params to utf8 + ok = BSTRToUTF8( prop, propUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + + // Setup the byte array + require_action( V_VT( value ) == ( VT_ARRAY|VT_UI1 ), exit, err = kDNSServiceErr_Unknown ); + psa = V_ARRAY( value ); + require_action( psa, exit, err = kDNSServiceErr_Unknown ); + require_action( SafeArrayGetDim( psa ) == 1, exit, err = kDNSServiceErr_Unknown ); + byteArray.reserve( psa->rgsabound[0].cElements ); + byteArray.assign( byteArray.capacity(), 0 ); + elems = ( uint32_t ) byteArray.capacity(); + + // Call the function and package the return value in the Variant + err = DNSServiceGetProperty( propUTF8.c_str(), &byteArray[ 0 ], &elems ); + require_noerr( err, exit ); + ok = ByteArrayToVariant( &byteArray[ 0 ], elems, value ); + require_action( ok, exit, err = kDNSSDError_Unknown ); + +exit: + + if ( psa ) + { + SafeArrayUnaccessData( psa ); + psa = NULL; + } + + return err; +} + +STDMETHODIMP CDNSSDService::GetAddrInfo(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, BSTR hostName, IDNSSDEventManager *eventManager, IDNSSDService **service) +{ + CComObject * object = NULL; + DNSServiceRef subord = NULL; + std::string hostNameUTF8; + DNSServiceErrorType err = 0; + HRESULT hr = 0; + BOOL ok; + + check( m_primary ); + + // Initialize + *service = NULL; + + // Convert BSTR params to utf8 + ok = BSTRToUTF8( hostName, hostNameUTF8 ); + require_action( ok, exit, err = kDNSServiceErr_BadParam ); + + try + { + object = new CComObject(); + } + catch ( ... ) + { + object = NULL; + } + + require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory ); + object->AddRef(); + + subord = m_primary; + err = DNSServiceGetAddrInfo( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, addressFamily, hostNameUTF8.c_str(), ( DNSServiceGetAddrInfoReply ) &GetAddrInfoReply, object ); + require_noerr( err, exit ); + + object->SetPrimaryRef( m_primary ); + object->SetSubordRef( subord ); + object->SetEventManager( eventManager ); + + *service = object; + +exit: + + if ( err && object ) + { + object->Release(); + } + + return err; +} + + +STDMETHODIMP CDNSSDService::NATPortMappingCreate(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, DNSSDProtocol protocol, USHORT internalPort, USHORT externalPort, ULONG ttl, IDNSSDEventManager *eventManager, IDNSSDService **service) +{ + CComObject * object = NULL; + DNSServiceRef subord = NULL; + DNSServiceProtocol prot = 0; + DNSServiceErrorType err = 0; + HRESULT hr = 0; + + check( m_primary ); + + // Initialize + *service = NULL; + + try + { + object = new CComObject(); + } + catch ( ... ) + { + object = NULL; + } + + require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory ); + object->AddRef(); + + prot = ( addressFamily | protocol ); + + subord = m_primary; + err = DNSServiceNATPortMappingCreate( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, prot, htons( internalPort ), htons( externalPort ), ttl, ( DNSServiceNATPortMappingReply ) &NATPortMappingReply, object ); + require_noerr( err, exit ); + + object->SetPrimaryRef( m_primary ); + object->SetSubordRef( subord ); + object->SetEventManager( eventManager ); + + *service = object; + +exit: + + if ( err && object ) + { + object->Release(); + } + + return err; +} + + +STDMETHODIMP CDNSSDService::Stop(void) +{ + if ( !m_stopped ) + { + m_stopped = TRUE; + + dlog( kDebugLevelTrace, "Stop()\n" ); + + if ( m_isPrimary && m_primary ) + { + SocketMap::iterator it; + + if ( m_hiddenWindow ) + { + WSAAsyncSelect( DNSServiceRefSockFD( m_primary ), m_hiddenWindow, 0, 0 ); + } + + it = m_socketMap.find( DNSServiceRefSockFD( m_primary ) ); + + if ( it != m_socketMap.end() ) + { + m_socketMap.erase( it ); + } + + DNSServiceRefDeallocate( m_primary ); + m_primary = NULL; + } + else if ( m_subord ) + { + DNSServiceRefDeallocate( m_subord ); + m_subord = NULL; + } + + if ( m_eventManager != NULL ) + { + m_eventManager->Release(); + m_eventManager = NULL; + } + } + + return S_OK; +} + + +void DNSSD_API +CDNSSDService::DomainEnumReply + ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t ifIndex, + DNSServiceErrorType errorCode, + const char *replyDomainUTF8, + void *context + ) +{ + CComObject * service = NULL; + CDNSSDEventManager * eventManager = NULL; + int err = 0; + + service = ( CComObject< CDNSSDService>* ) context; + require_action( service, exit, err = kDNSServiceErr_Unknown ); + + if ( service->ShouldHandleReply( errorCode, eventManager ) ) + { + CComBSTR replyDomain; + BOOL ok; + + ok = UTF8ToBSTR( replyDomainUTF8, replyDomain ); + require_action( ok, exit, err = kDNSServiceErr_Unknown ); + + if ( flags & kDNSServiceFlagsAdd ) + { + eventManager->Fire_DomainFound( service, ( DNSSDFlags ) flags, ifIndex, replyDomain ); + } + else + { + eventManager->Fire_DomainLost( service, ( DNSSDFlags ) flags, ifIndex, replyDomain ); + } + } + +exit: + + return; +} + + +void DNSSD_API +CDNSSDService::BrowseReply + ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t ifIndex, + DNSServiceErrorType errorCode, + const char *serviceNameUTF8, + const char *regTypeUTF8, + const char *replyDomainUTF8, + void *context + ) +{ + CComObject * service = NULL; + CDNSSDEventManager * eventManager = NULL; + int err = 0; + + service = ( CComObject< CDNSSDService>* ) context; + require_action( service, exit, err = kDNSServiceErr_Unknown ); + + if ( service->ShouldHandleReply( errorCode, eventManager ) ) + { + CComBSTR serviceName; + CComBSTR regType; + CComBSTR replyDomain; + + UTF8ToBSTR( serviceNameUTF8, serviceName ); + UTF8ToBSTR( regTypeUTF8, regType ); + UTF8ToBSTR( replyDomainUTF8, replyDomain ); + + if ( flags & kDNSServiceFlagsAdd ) + { + eventManager->Fire_ServiceFound( service, ( DNSSDFlags ) flags, ifIndex, serviceName, regType, replyDomain ); + } + else + { + eventManager->Fire_ServiceLost( service, ( DNSSDFlags ) flags, ifIndex, serviceName, regType, replyDomain ); + } + } + +exit: + + return; +} + + +void DNSSD_API +CDNSSDService::ResolveReply + ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t ifIndex, + DNSServiceErrorType errorCode, + const char *fullNameUTF8, + const char *hostNameUTF8, + uint16_t port, + uint16_t txtLen, + const unsigned char *txtRecord, + void *context + ) +{ + CComObject * service = NULL; + CDNSSDEventManager * eventManager = NULL; + int err = 0; + + service = ( CComObject< CDNSSDService>* ) context; + require_action( service, exit, err = kDNSServiceErr_Unknown ); + + if ( service->ShouldHandleReply( errorCode, eventManager ) ) + { + CComBSTR fullName; + CComBSTR hostName; + CComBSTR regType; + CComBSTR replyDomain; + CComObject< CTXTRecord >* record; + BOOL ok; + + ok = UTF8ToBSTR( fullNameUTF8, fullName ); + require_action( ok, exit, err = kDNSServiceErr_Unknown ); + ok = UTF8ToBSTR( hostNameUTF8, hostName ); + require_action( ok, exit, err = kDNSServiceErr_Unknown ); + + try + { + record = new CComObject(); + } + catch ( ... ) + { + record = NULL; + } + + require_action( record, exit, err = kDNSServiceErr_NoMemory ); + record->AddRef(); + + if ( txtLen > 0 ) + { + record->SetBytes( txtRecord, txtLen ); + } + + eventManager->Fire_ServiceResolved( service, ( DNSSDFlags ) flags, ifIndex, fullName, hostName, ntohs( port ), record ); + } + +exit: + + return; +} + + +void DNSSD_API +CDNSSDService::RegisterReply + ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + DNSServiceErrorType errorCode, + const char *serviceNameUTF8, + const char *regTypeUTF8, + const char *domainUTF8, + void *context + ) +{ + CComObject * service = NULL; + CDNSSDEventManager * eventManager = NULL; + int err = 0; + + service = ( CComObject< CDNSSDService>* ) context; + require_action( service, exit, err = kDNSServiceErr_Unknown ); + + if ( service->ShouldHandleReply( errorCode, eventManager ) ) + { + CComBSTR serviceName; + CComBSTR regType; + CComBSTR domain; + BOOL ok; + + ok = UTF8ToBSTR( serviceNameUTF8, serviceName ); + require_action( ok, exit, err = kDNSServiceErr_Unknown ); + ok = UTF8ToBSTR( regTypeUTF8, regType ); + require_action( ok, exit, err = kDNSServiceErr_Unknown ); + ok = UTF8ToBSTR( domainUTF8, domain ); + require_action( ok, exit, err = kDNSServiceErr_Unknown ); + + eventManager->Fire_ServiceRegistered( service, ( DNSSDFlags ) flags, serviceName, regType, domain ); + } + +exit: + + return; +} + + +void DNSSD_API +CDNSSDService::QueryRecordReply + ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t ifIndex, + DNSServiceErrorType errorCode, + const char *fullNameUTF8, + uint16_t rrtype, + uint16_t rrclass, + uint16_t rdlen, + const void *rdata, + uint32_t ttl, + void *context + ) +{ + CComObject * service = NULL; + CDNSSDEventManager * eventManager = NULL; + int err = 0; + + service = ( CComObject< CDNSSDService>* ) context; + require_action( service, exit, err = kDNSServiceErr_Unknown ); + + if ( service->ShouldHandleReply( errorCode, eventManager ) ) + { + CComBSTR fullName; + VARIANT var; + BOOL ok; + + ok = UTF8ToBSTR( fullNameUTF8, fullName ); + require_action( ok, exit, err = kDNSServiceErr_Unknown ); + ok = ByteArrayToVariant( rdata, rdlen, &var ); + require_action( ok, exit, err = kDNSServiceErr_Unknown ); + + eventManager->Fire_QueryRecordAnswered( service, ( DNSSDFlags ) flags, ifIndex, fullName, ( DNSSDRRType ) rrtype, ( DNSSDRRClass ) rrclass, var, ttl ); + } + +exit: + + return; +} + + +void DNSSD_API +CDNSSDService::GetAddrInfoReply + ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t ifIndex, + DNSServiceErrorType errorCode, + const char *hostNameUTF8, + const struct sockaddr *rawAddress, + uint32_t ttl, + void *context + ) +{ + CComObject * service = NULL; + CDNSSDEventManager * eventManager = NULL; + int err = 0; + + service = ( CComObject< CDNSSDService>* ) context; + require_action( service, exit, err = kDNSServiceErr_Unknown ); + + if ( service->ShouldHandleReply( errorCode, eventManager ) ) + { + CComBSTR hostName; + DWORD sockaddrLen; + DNSSDAddressFamily addressFamily; + char addressUTF8[INET6_ADDRSTRLEN]; + DWORD addressLen = sizeof( addressUTF8 ); + CComBSTR address; + BOOL ok; + + ok = UTF8ToBSTR( hostNameUTF8, hostName ); + require_action( ok, exit, err = kDNSServiceErr_Unknown ); + + switch ( rawAddress->sa_family ) + { + case AF_INET: + { + addressFamily = kDNSSDAddressFamily_IPv4; + sockaddrLen = sizeof( sockaddr_in ); + } + break; + + case AF_INET6: + { + addressFamily = kDNSSDAddressFamily_IPv6; + sockaddrLen = sizeof( sockaddr_in6 ); + } + break; + } + + err = WSAAddressToStringA( ( LPSOCKADDR ) rawAddress, sockaddrLen, NULL, addressUTF8, &addressLen ); + require_noerr( err, exit ); + ok = UTF8ToBSTR( addressUTF8, address ); + require_action( ok, exit, err = kDNSServiceErr_Unknown ); + + eventManager->Fire_AddressFound( service, ( DNSSDFlags ) flags, ifIndex, hostName, addressFamily, address, ttl ); + } + +exit: + + return; +} + + +void DNSSD_API +CDNSSDService::NATPortMappingReply + ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t ifIndex, + DNSServiceErrorType errorCode, + uint32_t externalAddress, /* four byte IPv4 address in network byte order */ + DNSServiceProtocol protocol, + uint16_t internalPort, + uint16_t externalPort, /* may be different than the requested port */ + uint32_t ttl, /* may be different than the requested ttl */ + void *context + ) +{ + CComObject * service = NULL; + CDNSSDEventManager * eventManager = NULL; + int err = 0; + + service = ( CComObject< CDNSSDService>* ) context; + require_action( service, exit, err = kDNSServiceErr_Unknown ); + + if ( service->ShouldHandleReply( errorCode, eventManager ) ) + { + eventManager->Fire_MappingCreated( service, ( DNSSDFlags ) flags, ifIndex, externalAddress, ( DNSSDAddressFamily ) ( protocol & 0x8 ), ( DNSSDProtocol ) ( protocol & 0x80 ), ntohs( internalPort ), ntohs( externalPort ), ttl ); + } + +exit: + + return; +} + + +void DNSSD_API +CDNSSDService::RegisterRecordReply + ( + DNSServiceRef sdRef, + DNSRecordRef RecordRef, + DNSServiceFlags flags, + DNSServiceErrorType errorCode, + void *context + ) +{ + CComObject * record = NULL; + CDNSSDService * service = NULL; + CDNSSDEventManager * eventManager = NULL; + int err = 0; + + record = ( CComObject< CDNSSDRecord >* ) context; + require_action( record, exit, err = kDNSServiceErr_Unknown ); + service = record->GetServiceObject(); + require_action( service, exit, err = kDNSServiceErr_Unknown ); + + if ( service->ShouldHandleReply( errorCode, eventManager ) ) + { + eventManager->Fire_RecordRegistered( record, ( DNSSDFlags ) flags ); + } + +exit: + + return; +} + + +BOOL +CDNSSDService::ShouldHandleReply( DNSServiceErrorType errorCode, CDNSSDEventManager *& eventManager ) +{ + BOOL ok = FALSE; + + if ( !this->Stopped() ) + { + eventManager = this->GetEventManager(); + require_action( eventManager, exit, ok = FALSE ); + + if ( !errorCode ) + { + ok = TRUE; + } + else + { + eventManager->Fire_OperationFailed( this, ( DNSSDError ) errorCode ); + } + } + +exit: + + return ok; +} + + +LRESULT CALLBACK +CDNSSDService::WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + if ( msg == WM_SOCKET ) + { + SocketMap::iterator it; + + it = m_socketMap.find( ( SOCKET ) wParam ); + check( it != m_socketMap.end() ); + + if ( it != m_socketMap.end() ) + { + DNSServiceProcessResult( it->second->m_primary ); + } + } + + return DefWindowProc(hWnd, msg, wParam, lParam);; +} diff --git a/mDNSWindows/DLLX/DNSSDService.h b/mDNSWindows/DLLX/DNSSDService.h new file mode 100755 index 0000000..1618a00 --- /dev/null +++ b/mDNSWindows/DLLX/DNSSDService.h @@ -0,0 +1,273 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2009 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. + + Change History (most recent first): + +$Log: DNSSDService.h,v $ +Revision 1.1 2009/05/26 04:43:54 herscher + COM component that can be used with any .NET language and VB. + + +*/ + +#pragma once +#include "resource.h" // main symbols + +#include "DLLX.h" +#include "DNSSDEventManager.h" +#include +#include +#include +#include + + +#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) +#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms." +#endif + + + +// CDNSSDService + +class ATL_NO_VTABLE CDNSSDService : + public CComObjectRootEx, + public CComCoClass, + public IDispatchImpl +{ +public: + + typedef CComObjectRootEx Super; + + CDNSSDService() + : + m_isPrimary( FALSE ), + m_eventManager( NULL ), + m_stopped( FALSE ), + m_primary( NULL ), + m_subord( NULL ) + { + } + +DECLARE_REGISTRY_RESOURCEID(IDR_DNSSDSERVICE) + + +BEGIN_COM_MAP(CDNSSDService) + COM_INTERFACE_ENTRY(IDNSSDService) + COM_INTERFACE_ENTRY(IDispatch) +END_COM_MAP() + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + HRESULT + FinalConstruct(); + + void + FinalRelease(); + +public: + + inline DNSServiceRef + GetPrimaryRef() + { + return m_primary; + } + + inline void + SetPrimaryRef( DNSServiceRef primary ) + { + m_primary = primary; + } + + inline DNSServiceRef + GetSubordRef() + { + return m_subord; + } + + inline void + SetSubordRef( DNSServiceRef subord ) + { + m_subord = subord; + } + + inline CDNSSDEventManager* + GetEventManager() + { + return m_eventManager; + } + + inline void + SetEventManager( IDNSSDEventManager * eventManager ) + { + if ( m_eventManager ) + { + m_eventManager->Release(); + m_eventManager = NULL; + } + + if ( eventManager ) + { + m_eventManager = dynamic_cast< CDNSSDEventManager* >( eventManager ); + check( m_eventManager ); + m_eventManager->AddRef(); + } + } + + inline BOOL + Stopped() + { + return m_stopped; + } + +private: + + static void DNSSD_API + DomainEnumReply + ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t ifIndex, + DNSServiceErrorType errorCode, + const char *replyDomain, + void *context + ); + + static void DNSSD_API + BrowseReply + ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceErrorType errorCode, + const char *serviceName, + const char *regtype, + const char *replyDomain, + void *context + ); + + static void DNSSD_API + ResolveReply + ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceErrorType errorCode, + const char *fullname, + const char *hosttarget, + uint16_t port, + uint16_t txtLen, + const unsigned char *txtRecord, + void *context + ); + + static void DNSSD_API + RegisterReply + ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + DNSServiceErrorType errorCode, + const char *name, + const char *regtype, + const char *domain, + void *context + ); + + static void DNSSD_API + QueryRecordReply + ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceErrorType errorCode, + const char *fullname, + uint16_t rrtype, + uint16_t rrclass, + uint16_t rdlen, + const void *rdata, + uint32_t ttl, + void *context + ); + + static void DNSSD_API + GetAddrInfoReply + ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceErrorType errorCode, + const char *hostname, + const struct sockaddr *address, + uint32_t ttl, + void *context + ); + + static void DNSSD_API + NATPortMappingReply + ( + DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceErrorType errorCode, + uint32_t externalAddress, /* four byte IPv4 address in network byte order */ + DNSServiceProtocol protocol, + uint16_t internalPort, + uint16_t externalPort, /* may be different than the requested port */ + uint32_t ttl, /* may be different than the requested ttl */ + void *context + ); + + static void DNSSD_API + RegisterRecordReply + ( + DNSServiceRef sdRef, + DNSRecordRef RecordRef, + DNSServiceFlags flags, + DNSServiceErrorType errorCode, + void *context + ); + + inline BOOL + ShouldHandleReply( DNSServiceErrorType errorCode, CDNSSDEventManager *& eventManager ); + + static LRESULT CALLBACK + WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ); + + typedef std::map< SOCKET, CDNSSDService* > SocketMap; + + static BOOL m_registeredWindowClass; + static HWND m_hiddenWindow; + static SocketMap m_socketMap; + CDNSSDEventManager * m_eventManager; + BOOL m_stopped; + BOOL m_isPrimary; + DNSServiceRef m_primary; + DNSServiceRef m_subord; +public: + STDMETHOD(EnumerateDomains)(DNSSDFlags flags, ULONG ifIndex, IDNSSDEventManager *eventManager, IDNSSDService **service); + STDMETHOD(Browse)(DNSSDFlags flags, ULONG interfaceIndex, BSTR regtype, BSTR domain, IDNSSDEventManager* eventManager, IDNSSDService** sdref); + STDMETHOD(Resolve)(DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain, IDNSSDEventManager* eventManager, IDNSSDService** service); + STDMETHOD(Register)(DNSSDFlags flags, ULONG ifIndex, BSTR name, BSTR regType, BSTR domain, BSTR host, USHORT port, ITXTRecord *record, IDNSSDEventManager *eventManager, IDNSSDService **service); + STDMETHOD(QueryRecord)(DNSSDFlags flags, ULONG ifIndex, BSTR fullname, DNSSDRRType rrtype, DNSSDRRClass rrclass, IDNSSDEventManager *eventManager, IDNSSDService **service); + STDMETHOD(RegisterRecord)(DNSSDFlags flags, ULONG ifIndex, BSTR fullname, DNSSDRRType rrtype, DNSSDRRClass rrclass, VARIANT rdata, ULONG ttl, IDNSSDEventManager* eventManager, IDNSSDRecord** record); + STDMETHOD(AddRecord)(DNSSDFlags flags, DNSSDRRType rrtype, VARIANT rdata, ULONG ttl, IDNSSDRecord ** record); + STDMETHOD(ReconfirmRecord)(DNSSDFlags flags, ULONG ifIndex, BSTR fullname, DNSSDRRType rrtype, DNSSDRRClass rrclass, VARIANT rdata); + STDMETHOD(GetProperty)(BSTR prop, VARIANT * value); + STDMETHOD(GetAddrInfo)(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, BSTR hostname, IDNSSDEventManager *eventManager, IDNSSDService **service); + STDMETHOD(NATPortMappingCreate)(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, DNSSDProtocol protocol, USHORT internalPort, USHORT externalPort, ULONG ttl, IDNSSDEventManager *eventManager, IDNSSDService **service); + STDMETHOD(Stop)(void); +}; + +OBJECT_ENTRY_AUTO(__uuidof(DNSSDService), CDNSSDService) diff --git a/mDNSWindows/DLLX/DNSSDService.rgs b/mDNSWindows/DLLX/DNSSDService.rgs new file mode 100755 index 0000000..8a84297 --- /dev/null +++ b/mDNSWindows/DLLX/DNSSDService.rgs @@ -0,0 +1,27 @@ +HKCR +{ + Bonjour.DNSSDService.1 = s 'DNSSDService Class' + { + CLSID = s '{24CD4DE9-FF84-4701-9DC1-9B69E0D1090A}' + } + Bonjour.DNSSDService = s 'DNSSDService Class' + { + CLSID = s '{24CD4DE9-FF84-4701-9DC1-9B69E0D1090A}' + CurVer = s 'Bonjour.DNSSDService.1' + } + NoRemove CLSID + { + ForceRemove {24CD4DE9-FF84-4701-9DC1-9B69E0D1090A} = s 'DNSSDService Class' + { + ProgID = s 'Bonjour.DNSSDService.1' + VersionIndependentProgID = s 'Bonjour.DNSSDService' + ForceRemove 'Programmable' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + val AppID = s '%APPID%' + 'TypeLib' = s '{18FBED6D-F2B7-4EC8-A4A4-46282E635308}' + } + } +} diff --git a/mDNSWindows/DLLX/StringServices.cpp b/mDNSWindows/DLLX/StringServices.cpp new file mode 100755 index 0000000..a9c1d8a --- /dev/null +++ b/mDNSWindows/DLLX/StringServices.cpp @@ -0,0 +1,196 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2009 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. + + Change History (most recent first): + +$Log: StringServices.cpp,v $ +Revision 1.2 2009/06/02 18:43:57 herscher + Allow component consumers to pass in null strings + +Revision 1.1 2009/05/26 04:43:54 herscher + COM component that can be used with any .NET language and VB. + + +*/ + +#include "StringServices.h" +#include + + +extern BOOL +BSTRToUTF8 + ( + BSTR inString, + std::string & outString + ) +{ + USES_CONVERSION; + + char * utf8String = NULL; + OSStatus err = kNoErr; + + outString = ""; + + if ( inString ) + { + TCHAR * utf16String = NULL; + size_t size = 0; + + utf16String = OLE2T( inString ); + require_action( utf16String != NULL, exit, err = kUnknownErr ); + + if ( wcslen( utf16String ) > 0 ) + { + size = (size_t) WideCharToMultiByte( CP_UTF8, 0, utf16String, ( int ) wcslen( utf16String ), NULL, 0, NULL, NULL ); + err = translate_errno( size != 0, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + + try + { + utf8String = new char[ size + 1 ]; + } + catch ( ... ) + { + utf8String = NULL; + } + + require_action( utf8String != NULL, exit, err = kNoMemoryErr ); + size = (size_t) WideCharToMultiByte( CP_UTF8, 0, utf16String, ( int ) wcslen( utf16String ), utf8String, (int) size, NULL, NULL); + err = translate_errno( size != 0, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + + // have to add the trailing 0 because WideCharToMultiByte doesn't do it, + // although it does return the correct size + + utf8String[size] = '\0'; + outString = utf8String; + } + } + +exit: + + if ( utf8String != NULL ) + { + delete [] utf8String; + } + + return ( !err ) ? TRUE : FALSE; +} + + +extern BOOL +UTF8ToBSTR + ( + const char * inString, + CComBSTR & outString + ) +{ + wchar_t * unicode = NULL; + OSStatus err = 0; + + if ( inString ) + { + int n; + + n = MultiByteToWideChar( CP_UTF8, 0, inString, -1, NULL, 0 ); + + if ( n > 0 ) + { + try + { + unicode = new wchar_t[ n ]; + } + catch ( ... ) + { + unicode = NULL; + } + + require_action( unicode, exit, err = ERROR_INSUFFICIENT_BUFFER ); + + n = MultiByteToWideChar( CP_UTF8, 0, inString, -1, unicode, n ); + } + + outString = unicode; + } + +exit: + + if ( unicode != NULL ) + { + delete [] unicode; + } + + return ( !err ) ? TRUE : FALSE; +} + + +BOOL +ByteArrayToVariant + ( + const void * inArray, + size_t inArrayLen, + VARIANT * outVariant + ) +{ + LPBYTE buf = NULL; + HRESULT hr = 0; + BOOL ok = TRUE; + + VariantClear( outVariant ); + outVariant->vt = VT_ARRAY|VT_UI1; + outVariant->parray = SafeArrayCreateVector( VT_UI1, 0, ( ULONG ) inArrayLen ); + require_action( outVariant->parray, exit, ok = FALSE ); + hr = SafeArrayAccessData( outVariant->parray, (LPVOID *)&buf ); + require_action( hr == S_OK, exit, ok = FALSE ); + memcpy( buf, inArray, inArrayLen ); + hr = SafeArrayUnaccessData( outVariant->parray ); + require_action( hr == S_OK, exit, ok = FALSE ); + +exit: + + return ok; +} + + +extern BOOL +VariantToByteArray + ( + VARIANT * inVariant, + std::vector< BYTE > & outArray + ) +{ + SAFEARRAY * psa = NULL; + BYTE * pData = NULL; + ULONG cElements = 0; + HRESULT hr; + BOOL ok = TRUE; + + require_action( V_VT( inVariant ) == ( VT_ARRAY|VT_UI1 ), exit, ok = FALSE ); + psa = V_ARRAY( inVariant ); + require_action( psa, exit, ok = FALSE ); + require_action( SafeArrayGetDim( psa ) == 1, exit, ok = FALSE ); + hr = SafeArrayAccessData( psa, ( LPVOID* )&pData ); + require_action( hr == S_OK, exit, ok = FALSE ); + cElements = psa->rgsabound[0].cElements; + outArray.reserve( cElements ); + outArray.assign( cElements, 0 ); + memcpy( &outArray[ 0 ], pData, cElements ); + SafeArrayUnaccessData( psa ); + +exit: + + return ok; +} \ No newline at end of file diff --git a/mDNSWindows/DLLX/StringServices.h b/mDNSWindows/DLLX/StringServices.h new file mode 100755 index 0000000..ff6d59b --- /dev/null +++ b/mDNSWindows/DLLX/StringServices.h @@ -0,0 +1,67 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2009 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. + + Change History (most recent first): + +$Log: StringServices.h,v $ +Revision 1.1 2009/05/26 04:43:54 herscher + COM component that can be used with any .NET language and VB. + + +*/ + +#ifndef _StringServices_h +#define _StringServices_h + +#include +#include +#include + + +extern BOOL +BSTRToUTF8 + ( + BSTR inString, + std::string & outString + ); + + +extern BOOL +UTF8ToBSTR + ( + const char * inString, + CComBSTR & outString + ); + + +extern BOOL +ByteArrayToVariant + ( + const void * inArray, + size_t inArrayLen, + VARIANT * outVariant + ); + + +extern BOOL +VariantToByteArray + ( + VARIANT * inVariant, + std::vector< BYTE > & outArray + ); + + +#endif \ No newline at end of file diff --git a/mDNSWindows/DLLX/TXTRecord.cpp b/mDNSWindows/DLLX/TXTRecord.cpp new file mode 100755 index 0000000..5921654 --- /dev/null +++ b/mDNSWindows/DLLX/TXTRecord.cpp @@ -0,0 +1,206 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2009 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. + + Change History (most recent first): + +$Log: TXTRecord.cpp,v $ +Revision 1.1 2009/05/26 04:43:54 herscher + COM component that can be used with any .NET language and VB. + + +*/ + +#include "stdafx.h" +#include "TXTRecord.h" +#include "StringServices.h" +#include + + +// CTXTRecord + + +STDMETHODIMP CTXTRecord::SetValue(BSTR key, VARIANT value) +{ + std::string keyUTF8; + ByteArray valueArray; + BOOL ok; + DNSServiceErrorType err; + HRESULT hr = S_OK; + + if ( !m_allocated ) + { + TXTRecordCreate( &m_tref, 0, NULL ); + m_allocated = TRUE; + } + + ok = BSTRToUTF8( key, keyUTF8 ); + require_action( ok, exit, hr = S_FALSE ); + + ok = VariantToByteArray( &value, valueArray ); + require_action( ok, exit, hr = S_FALSE ); + + err = TXTRecordSetValue( &m_tref, keyUTF8.c_str(), ( uint8_t ) valueArray.size(), &valueArray[ 0 ] ); + require_action( !err, exit, hr = S_FALSE ); + +exit: + + return hr; +} + +STDMETHODIMP CTXTRecord::RemoveValue(BSTR key) +{ + HRESULT hr = S_OK; + + if ( m_allocated ) + { + std::string keyUTF8; + BOOL ok; + DNSServiceErrorType err; + + ok = BSTRToUTF8( key, keyUTF8 ); + require_action( ok, exit, hr = S_FALSE ); + + err = TXTRecordRemoveValue( &m_tref, keyUTF8.c_str() ); + require_action( !err, exit, hr = S_FALSE ); + } + +exit: + + return hr; +} + +STDMETHODIMP CTXTRecord::ContainsKey(BSTR key, VARIANT_BOOL* retval) +{ + std::string keyUTF8; + int ret = 0; + HRESULT err = S_OK; + + if ( m_byteArray.size() > 0 ) + { + BOOL ok; + + ok = BSTRToUTF8( key, keyUTF8 ); + require_action( ok, exit, err = S_FALSE ); + + ret = TXTRecordContainsKey( ( uint16_t ) m_byteArray.size(), &m_byteArray[ 0 ], keyUTF8.c_str() ); + } + + *retval = ( ret ) ? VARIANT_TRUE : VARIANT_FALSE; + +exit: + + return err; +} + +STDMETHODIMP CTXTRecord::GetValueForKey(BSTR key, VARIANT* value) +{ + std::string keyUTF8; + const void * rawValue; + uint8_t rawValueLen; + BOOL ok = TRUE; + HRESULT hr = S_OK; + + VariantClear( value ); + + if ( m_byteArray.size() > 0 ) + { + ok = BSTRToUTF8( key, keyUTF8 ); + require_action( ok, exit, hr = S_FALSE ); + + rawValue = TXTRecordGetValuePtr( ( uint16_t ) m_byteArray.size(), &m_byteArray[ 0 ], keyUTF8.c_str(), &rawValueLen ); + + if ( rawValue ) + { + ok = ByteArrayToVariant( rawValue, rawValueLen, value ); + require_action( ok, exit, hr = S_FALSE ); + } + } + +exit: + + return hr; +} + +STDMETHODIMP CTXTRecord::GetCount(ULONG* count) +{ + *count = 0; + + if ( m_byteArray.size() > 0 ) + { + *count = TXTRecordGetCount( ( uint16_t ) m_byteArray.size(), &m_byteArray[ 0 ] ); + } + + return S_OK; +} + +STDMETHODIMP CTXTRecord::GetKeyAtIndex(ULONG index, BSTR* retval) +{ + char keyBuf[ 64 ]; + uint8_t rawValueLen; + const void * rawValue; + CComBSTR temp; + DNSServiceErrorType err; + BOOL ok; + HRESULT hr = S_OK; + + err = TXTRecordGetItemAtIndex( ( uint16_t ) m_byteArray.size(), &m_byteArray[ 0 ], ( uint16_t ) index, sizeof( keyBuf ), keyBuf, &rawValueLen, &rawValue ); + require_action( !err, exit, hr = S_FALSE ); + + ok = UTF8ToBSTR( keyBuf, temp ); + require_action( ok, exit, hr = S_FALSE ); + + *retval = temp; + +exit: + + return hr; +} + +STDMETHODIMP CTXTRecord::GetValueAtIndex(ULONG index, VARIANT* retval) +{ + char keyBuf[ 64 ]; + uint8_t rawValueLen; + const void * rawValue; + CComBSTR temp; + DNSServiceErrorType err; + BOOL ok; + HRESULT hr = S_OK; + + err = TXTRecordGetItemAtIndex( ( uint16_t ) m_byteArray.size(), &m_byteArray[ 0 ], ( uint16_t ) index, sizeof( keyBuf ), keyBuf, &rawValueLen, &rawValue ); + require_action( !err, exit, hr = S_FALSE ); + + ok = ByteArrayToVariant( rawValue, rawValueLen, retval ); + require_action( ok, exit, hr = S_FALSE ); + +exit: + + return hr; +} + + +void +CTXTRecord::SetBytes + ( + const unsigned char * bytes, + uint16_t len + ) +{ + check ( bytes != NULL ); + check( len ); + + m_byteArray.reserve( len ); + m_byteArray.assign( bytes, bytes + len ); +} diff --git a/mDNSWindows/DLLX/TXTRecord.h b/mDNSWindows/DLLX/TXTRecord.h new file mode 100755 index 0000000..f74f8a0 --- /dev/null +++ b/mDNSWindows/DLLX/TXTRecord.h @@ -0,0 +1,117 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2009 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. + + Change History (most recent first): + +$Log: TXTRecord.h,v $ +Revision 1.1 2009/05/26 04:43:54 herscher + COM component that can be used with any .NET language and VB. + + +*/ + +#pragma once +#include "resource.h" // main symbols +#include "DLLX.h" +#include +#include + + +#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) +#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms." +#endif + + + +// CTXTRecord + +class ATL_NO_VTABLE CTXTRecord : + public CComObjectRootEx, + public CComCoClass, + public IDispatchImpl +{ +public: + CTXTRecord() + : + m_allocated( FALSE ) + { + } + +DECLARE_REGISTRY_RESOURCEID(IDR_TXTRECORD) + + +BEGIN_COM_MAP(CTXTRecord) + COM_INTERFACE_ENTRY(ITXTRecord) + COM_INTERFACE_ENTRY(IDispatch) +END_COM_MAP() + + + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + HRESULT FinalConstruct() + { + return S_OK; + } + + void FinalRelease() + { + if ( m_allocated ) + { + TXTRecordDeallocate( &m_tref ); + } + } + +public: + + STDMETHOD(SetValue)(BSTR key, VARIANT value); + STDMETHOD(RemoveValue)(BSTR key); + STDMETHOD(ContainsKey)(BSTR key, VARIANT_BOOL* retval); + STDMETHOD(GetValueForKey)(BSTR key, VARIANT* value); + STDMETHOD(GetCount)(ULONG* count); + STDMETHOD(GetKeyAtIndex)(ULONG index, BSTR* retval); + STDMETHOD(GetValueAtIndex)(ULONG index, VARIANT* retval); + +private: + + typedef std::vector< BYTE > ByteArray; + ByteArray m_byteArray; + BOOL m_allocated; + TXTRecordRef m_tref; + +public: + + uint16_t + GetLen() + { + return TXTRecordGetLength( &m_tref ); + } + + const void* + GetBytes() + { + return TXTRecordGetBytesPtr( &m_tref ); + } + + void + SetBytes + ( + const unsigned char * bytes, + uint16_t len + ); +}; + +OBJECT_ENTRY_AUTO(__uuidof(TXTRecord), CTXTRecord) diff --git a/mDNSWindows/DLLX/TXTRecord.rgs b/mDNSWindows/DLLX/TXTRecord.rgs new file mode 100755 index 0000000..ce2fe1e --- /dev/null +++ b/mDNSWindows/DLLX/TXTRecord.rgs @@ -0,0 +1,27 @@ +HKCR +{ + Bonjour.TXTRecord.1 = s 'TXTRecord Class' + { + CLSID = s '{AFEE063C-05BA-4248-A26E-168477F49734}' + } + Bonjour.TXTRecord = s 'TXTRecord Class' + { + CLSID = s '{AFEE063C-05BA-4248-A26E-168477F49734}' + CurVer = s 'Bonjour.TXTRecord.1' + } + NoRemove CLSID + { + ForceRemove {AFEE063C-05BA-4248-A26E-168477F49734} = s 'TXTRecord Class' + { + ProgID = s 'Bonjour.TXTRecord.1' + VersionIndependentProgID = s 'Bonjour.TXTRecord' + ForceRemove 'Programmable' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + val AppID = s '%APPID%' + 'TypeLib' = s '{18FBED6D-F2B7-4EC8-A4A4-46282E635308}' + } + } +} diff --git a/mDNSWindows/DLLX/_IDNSSDEvents_CP.h b/mDNSWindows/DLLX/_IDNSSDEvents_CP.h new file mode 100755 index 0000000..5c48397 --- /dev/null +++ b/mDNSWindows/DLLX/_IDNSSDEvents_CP.h @@ -0,0 +1,358 @@ + +// Wizard-generated connection point proxy class +// WARNING: This file may be regenerated by the wizard + + +#pragma once + +template +class CProxy_IDNSSDEvents : + public IConnectionPointImpl +{ +public: + HRESULT Fire_DomainFound( IDNSSDService * service, DNSSDFlags flags, ULONG ifIndex, BSTR domain) + { + HRESULT hr = S_OK; + T * pThis = static_cast(this); + int cConnections = m_vec.GetSize(); + + for (int iConnection = 0; iConnection < cConnections; iConnection++) + { + pThis->Lock(); + CComPtr punkConnection = m_vec.GetAt(iConnection); + pThis->Unlock(); + + IDispatch * pConnection = static_cast(punkConnection.p); + + if (pConnection) + { + CComVariant avarParams[4]; + avarParams[3] = service; + avarParams[2] = flags; + avarParams[1] = ifIndex; + avarParams[1].vt = VT_UI4; + avarParams[0] = domain; + avarParams[0].vt = VT_BSTR; + DISPPARAMS params = { avarParams, NULL, 4, 0 }; + hr = pConnection->Invoke(1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, NULL, NULL, NULL); + } + } + return hr; + } + HRESULT Fire_DomainLost( IDNSSDService * service, DNSSDFlags flags, ULONG ifIndex, BSTR domain) + { + HRESULT hr = S_OK; + T * pThis = static_cast(this); + int cConnections = m_vec.GetSize(); + + for (int iConnection = 0; iConnection < cConnections; iConnection++) + { + pThis->Lock(); + CComPtr punkConnection = m_vec.GetAt(iConnection); + pThis->Unlock(); + + IDispatch * pConnection = static_cast(punkConnection.p); + + if (pConnection) + { + CComVariant avarParams[4]; + avarParams[3] = service; + avarParams[2] = flags; + avarParams[1] = ifIndex; + avarParams[1].vt = VT_UI4; + avarParams[0] = domain; + avarParams[0].vt = VT_BSTR; + DISPPARAMS params = { avarParams, NULL, 4, 0 }; + hr = pConnection->Invoke(2, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, NULL, NULL, NULL); + } + } + return hr; + } + HRESULT Fire_ServiceFound( IDNSSDService * browser, DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain) + { + HRESULT hr = S_OK; + T * pThis = static_cast(this); + int cConnections = m_vec.GetSize(); + + for (int iConnection = 0; iConnection < cConnections; iConnection++) + { + pThis->Lock(); + CComPtr punkConnection = m_vec.GetAt(iConnection); + pThis->Unlock(); + + IDispatch * pConnection = static_cast(punkConnection.p); + + if (pConnection) + { + CComVariant avarParams[6]; + avarParams[5] = browser; + avarParams[4] = flags; + avarParams[3] = ifIndex; + avarParams[3].vt = VT_UI4; + avarParams[2] = serviceName; + avarParams[2].vt = VT_BSTR; + avarParams[1] = regType; + avarParams[1].vt = VT_BSTR; + avarParams[0] = domain; + avarParams[0].vt = VT_BSTR; + DISPPARAMS params = { avarParams, NULL, 6, 0 }; + hr = pConnection->Invoke(3, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, NULL, NULL, NULL); + } + } + return hr; + } + HRESULT Fire_ServiceLost( IDNSSDService * browser, DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain) + { + HRESULT hr = S_OK; + T * pThis = static_cast(this); + int cConnections = m_vec.GetSize(); + + for (int iConnection = 0; iConnection < cConnections; iConnection++) + { + pThis->Lock(); + CComPtr punkConnection = m_vec.GetAt(iConnection); + pThis->Unlock(); + + IDispatch * pConnection = static_cast(punkConnection.p); + + if (pConnection) + { + CComVariant avarParams[6]; + avarParams[5] = browser; + avarParams[4] = flags; + avarParams[3] = ifIndex; + avarParams[3].vt = VT_UI4; + avarParams[2] = serviceName; + avarParams[2].vt = VT_BSTR; + avarParams[1] = regType; + avarParams[1].vt = VT_BSTR; + avarParams[0] = domain; + avarParams[0].vt = VT_BSTR; + DISPPARAMS params = { avarParams, NULL, 6, 0 }; + hr = pConnection->Invoke(4, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, NULL, NULL, NULL); + } + } + return hr; + } + HRESULT Fire_ServiceResolved( IDNSSDService * service, DNSSDFlags flags, ULONG ifIndex, BSTR fullName, BSTR hostName, USHORT port, ITXTRecord * record) + { + HRESULT hr = S_OK; + T * pThis = static_cast(this); + int cConnections = m_vec.GetSize(); + + for (int iConnection = 0; iConnection < cConnections; iConnection++) + { + pThis->Lock(); + CComPtr punkConnection = m_vec.GetAt(iConnection); + pThis->Unlock(); + + IDispatch * pConnection = static_cast(punkConnection.p); + + if (pConnection) + { + CComVariant avarParams[7]; + avarParams[6] = service; + avarParams[5] = flags; + avarParams[4] = ifIndex; + avarParams[4].vt = VT_UI4; + avarParams[3] = fullName; + avarParams[3].vt = VT_BSTR; + avarParams[2] = hostName; + avarParams[2].vt = VT_BSTR; + avarParams[1] = port; + avarParams[1].vt = VT_UI2; + avarParams[0] = record; + DISPPARAMS params = { avarParams, NULL, 7, 0 }; + hr = pConnection->Invoke(5, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, NULL, NULL, NULL); + } + } + return hr; + } + HRESULT Fire_ServiceRegistered( IDNSSDService * service, DNSSDFlags flags, BSTR name, BSTR regType, BSTR domain) + { + HRESULT hr = S_OK; + T * pThis = static_cast(this); + int cConnections = m_vec.GetSize(); + + for (int iConnection = 0; iConnection < cConnections; iConnection++) + { + pThis->Lock(); + CComPtr punkConnection = m_vec.GetAt(iConnection); + pThis->Unlock(); + + IDispatch * pConnection = static_cast(punkConnection.p); + + if (pConnection) + { + CComVariant avarParams[5]; + avarParams[4] = service; + avarParams[3] = flags; + avarParams[2] = name; + avarParams[2].vt = VT_BSTR; + avarParams[1] = regType; + avarParams[1].vt = VT_BSTR; + avarParams[0] = domain; + avarParams[0].vt = VT_BSTR; + DISPPARAMS params = { avarParams, NULL, 5, 0 }; + hr = pConnection->Invoke(6, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, NULL, NULL, NULL); + } + } + return hr; + } + HRESULT Fire_QueryRecordAnswered( IDNSSDService * service, DNSSDFlags flags, ULONG ifIndex, BSTR fullName, DNSSDRRType rrtype, DNSSDRRClass rrclass, VARIANT rdata, ULONG ttl) + { + HRESULT hr = S_OK; + T * pThis = static_cast(this); + int cConnections = m_vec.GetSize(); + + for (int iConnection = 0; iConnection < cConnections; iConnection++) + { + pThis->Lock(); + CComPtr punkConnection = m_vec.GetAt(iConnection); + pThis->Unlock(); + + IDispatch * pConnection = static_cast(punkConnection.p); + + if (pConnection) + { + CComVariant avarParams[8]; + avarParams[7] = service; + avarParams[6] = flags; + avarParams[5] = ifIndex; + avarParams[5].vt = VT_UI4; + avarParams[4] = fullName; + avarParams[4].vt = VT_BSTR; + avarParams[3] = rrtype; + avarParams[2] = rrclass; + avarParams[1] = rdata; + avarParams[0] = ttl; + avarParams[0].vt = VT_UI4; + DISPPARAMS params = { avarParams, NULL, 8, 0 }; + hr = pConnection->Invoke(7, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, NULL, NULL, NULL); + } + } + return hr; + } + HRESULT Fire_RecordRegistered( IDNSSDRecord * record, DNSSDFlags flags) + { + HRESULT hr = S_OK; + T * pThis = static_cast(this); + int cConnections = m_vec.GetSize(); + + for (int iConnection = 0; iConnection < cConnections; iConnection++) + { + pThis->Lock(); + CComPtr punkConnection = m_vec.GetAt(iConnection); + pThis->Unlock(); + + IDispatch * pConnection = static_cast(punkConnection.p); + + if (pConnection) + { + CComVariant avarParams[2]; + avarParams[1] = record; + avarParams[0] = flags; + DISPPARAMS params = { avarParams, NULL, 2, 0 }; + hr = pConnection->Invoke(8, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, NULL, NULL, NULL); + } + } + return hr; + } + HRESULT Fire_AddressFound( IDNSSDService * service, DNSSDFlags flags, ULONG ifIndex, BSTR hostname, DNSSDAddressFamily addressFamily, BSTR address, ULONG ttl) + { + HRESULT hr = S_OK; + T * pThis = static_cast(this); + int cConnections = m_vec.GetSize(); + + for (int iConnection = 0; iConnection < cConnections; iConnection++) + { + pThis->Lock(); + CComPtr punkConnection = m_vec.GetAt(iConnection); + pThis->Unlock(); + + IDispatch * pConnection = static_cast(punkConnection.p); + + if (pConnection) + { + CComVariant avarParams[7]; + avarParams[6] = service; + avarParams[5] = flags; + avarParams[4] = ifIndex; + avarParams[4].vt = VT_UI4; + avarParams[3] = hostname; + avarParams[3].vt = VT_BSTR; + avarParams[2] = addressFamily; + avarParams[1] = address; + avarParams[1].vt = VT_BSTR; + avarParams[0] = ttl; + avarParams[0].vt = VT_UI4; + DISPPARAMS params = { avarParams, NULL, 7, 0 }; + hr = pConnection->Invoke(9, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, NULL, NULL, NULL); + } + } + return hr; + } + HRESULT Fire_MappingCreated( IDNSSDService * service, DNSSDFlags flags, ULONG ifIndex, ULONG externalAddress, DNSSDAddressFamily addressFamily, DNSSDProtocol protocol, USHORT internalPort, USHORT externalPort, ULONG ttl) + { + HRESULT hr = S_OK; + T * pThis = static_cast(this); + int cConnections = m_vec.GetSize(); + + for (int iConnection = 0; iConnection < cConnections; iConnection++) + { + pThis->Lock(); + CComPtr punkConnection = m_vec.GetAt(iConnection); + pThis->Unlock(); + + IDispatch * pConnection = static_cast(punkConnection.p); + + if (pConnection) + { + CComVariant avarParams[9]; + avarParams[8] = service; + avarParams[7] = flags; + avarParams[6] = ifIndex; + avarParams[6].vt = VT_UI4; + avarParams[5] = externalAddress; + avarParams[5].vt = VT_UI4; + avarParams[4] = addressFamily; + avarParams[3] = protocol; + avarParams[2] = internalPort; + avarParams[2].vt = VT_UI2; + avarParams[1] = externalPort; + avarParams[1].vt = VT_UI2; + avarParams[0] = ttl; + avarParams[0].vt = VT_UI4; + DISPPARAMS params = { avarParams, NULL, 9, 0 }; + hr = pConnection->Invoke(10, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, NULL, NULL, NULL); + } + } + return hr; + } + HRESULT Fire_OperationFailed( IDNSSDService * service, DNSSDError error) + { + HRESULT hr = S_OK; + T * pThis = static_cast(this); + int cConnections = m_vec.GetSize(); + + for (int iConnection = 0; iConnection < cConnections; iConnection++) + { + pThis->Lock(); + CComPtr punkConnection = m_vec.GetAt(iConnection); + pThis->Unlock(); + + IDispatch * pConnection = static_cast(punkConnection.p); + + if (pConnection) + { + CComVariant avarParams[2]; + avarParams[1] = service; + avarParams[0] = error; + DISPPARAMS params = { avarParams, NULL, 2, 0 }; + hr = pConnection->Invoke(11, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, NULL, NULL, NULL); + } + } + return hr; + } +}; + diff --git a/mDNSWindows/DLLX/dlldatax.c b/mDNSWindows/DLLX/dlldatax.c new file mode 100755 index 0000000..d2508e8 --- /dev/null +++ b/mDNSWindows/DLLX/dlldatax.c @@ -0,0 +1,41 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + Change History (most recent first): + +$Log: dlldatax.c,v $ +Revision 1.1 2009/05/26 04:43:54 herscher + COM component that can be used with any .NET language and VB. + + +*/ + +#ifdef _MERGE_PROXYSTUB // merge proxy stub DLL + +#define REGISTER_PROXY_DLL //DllRegisterServer, etc. + +#define _WIN32_WINNT 0x0500 //for WinNT 4.0 or Win95 with DCOM +#define USE_STUBLESS_PROXY //defined only with MIDL switch /Oicf + +#pragma comment(lib, "rpcns4.lib") +#pragma comment(lib, "rpcrt4.lib") + +#define ENTRY_PREFIX Prx + +#include "dlldata.c" +#include "DLLX_p.c" + +#endif //_MERGE_PROXYSTUB diff --git a/mDNSWindows/DLLX/dlldatax.h b/mDNSWindows/DLLX/dlldatax.h new file mode 100755 index 0000000..093d8f1 --- /dev/null +++ b/mDNSWindows/DLLX/dlldatax.h @@ -0,0 +1,40 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + Change History (most recent first): + +$Log: dlldatax.h,v $ +Revision 1.1 2009/05/26 04:43:54 herscher + COM component that can be used with any .NET language and VB. + + +*/ + +#pragma once + +#ifdef _MERGE_PROXYSTUB + +extern "C" +{ +BOOL WINAPI PrxDllMain(HINSTANCE hInstance, DWORD dwReason, + LPVOID lpReserved); +STDAPI PrxDllCanUnloadNow(void); +STDAPI PrxDllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv); +STDAPI PrxDllRegisterServer(void); +STDAPI PrxDllUnregisterServer(void); +} + +#endif diff --git a/mDNSWindows/DLLX/resource.h b/mDNSWindows/DLLX/resource.h new file mode 100755 index 0000000..5613187 --- /dev/null +++ b/mDNSWindows/DLLX/resource.h @@ -0,0 +1,30 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by DLLX.rc +// +#define IDS_PROJNAME 100 +#define IDR_DLLX 101 +#define IDR_DNSSD 102 +#define IDR_DNSSDSERVICE 103 +#define IDR_BROWSELISTENER 104 +#define IDR_RESOLVELISTENER 105 +#define IDR_TXTRECORD 106 +#define IDR_ENUMERATEDOMAINSLISTENER 107 +#define IDR_REGISTERLISTENER 108 +#define IDR_QUERYRECORDLISTENER 109 +#define IDR_GETADDRINFOLISTENER 110 +#define IDR_DNSSDRECORD 111 +#define IDR_REGISTERRECORDLISTENER 112 +#define IDR_NATPORTMAPPINGLISTENER 113 +#define IDR_DNSSDEVENTMANAGER 114 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 201 +#define _APS_NEXT_COMMAND_VALUE 32768 +#define _APS_NEXT_CONTROL_VALUE 201 +#define _APS_NEXT_SYMED_VALUE 115 +#endif +#endif diff --git a/mDNSWindows/DLLX/stdafx.h b/mDNSWindows/DLLX/stdafx.h new file mode 100755 index 0000000..fdde090 --- /dev/null +++ b/mDNSWindows/DLLX/stdafx.h @@ -0,0 +1,60 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2009 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. + + Change History (most recent first): + +$Log: stdafx.h,v $ +Revision 1.1 2009/05/26 04:43:54 herscher + COM component that can be used with any .NET language and VB. + + +*/ + +#pragma once + +#ifndef STRICT +#define STRICT +#endif + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef WINVER // Allow use of features specific to Windows XP or later. +#define WINVER 0x0501 // Change this to the appropriate value to target other versions of Windows. +#endif + +#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. +#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. +#endif + +#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later. +#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. +#endif + +#ifndef _WIN32_IE // Allow use of features specific to IE 6.0 or later. +#define _WIN32_IE 0x0600 // Change this to the appropriate value to target other versions of IE. +#endif + +#define _ATL_APARTMENT_THREADED +#define _ATL_NO_AUTOMATIC_NAMESPACE + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit + + +#include "resource.h" +#include +#include + +using namespace ATL; \ No newline at end of file diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp b/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp index 641349d..4a49fdf 100644 --- a/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp +++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp @@ -17,6 +17,9 @@ Change History (most recent first): $Log: AboutDialog.cpp,v $ +Revision 1.4 2008/10/23 22:33:26 cheshire +Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu + Revision 1.3 2006/08/14 23:25:49 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -75,7 +78,7 @@ AboutDialog::AboutDialog(CWnd* pParent /*=NULL*/) : CDialog(AboutDialog::IDD, pParent) { //{{AFX_DATA_INIT(AboutDialog) - // NOTE: the ClassWizard will add member initialization here + // Note: the ClassWizard will add member initialization here //}}AFX_DATA_INIT } @@ -97,6 +100,6 @@ void AboutDialog::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(AboutDialog) - // NOTE: the ClassWizard will add DDX and DDV calls here + // Note: the ClassWizard will add DDX and DDV calls here //}}AFX_DATA_MAP } diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.h b/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.h index 98f4103..e4869ca 100644 --- a/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.h +++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.h @@ -17,6 +17,9 @@ Change History (most recent first): $Log: AboutDialog.h,v $ +Revision 1.4 2008/10/23 22:33:26 cheshire +Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu + Revision 1.3 2006/08/14 23:25:49 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -69,7 +72,7 @@ class AboutDialog : public CDialog //{{AFX_DATA(AboutDialog) enum { IDD = IDD_ABOUT_DIALOG }; - // NOTE: the ClassWizard will add data members here + // Note: the ClassWizard will add data members here //}}AFX_DATA // ClassWizard generated virtual function overrides diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp b/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp index f917ce8..486d46b 100644 --- a/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp +++ b/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp @@ -17,6 +17,9 @@ Change History (most recent first): $Log: ChooserDialog.cpp,v $ +Revision 1.5 2008/10/23 22:33:26 cheshire +Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu + Revision 1.4 2006/08/14 23:25:49 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -387,7 +390,7 @@ ChooserDialog::ChooserDialog( CWnd *inParent ) : CDialog( ChooserDialog::IDD, inParent) { //{{AFX_DATA_INIT(ChooserDialog) - // NOTE: the ClassWizard will add member initialization here + // Note: the ClassWizard will add member initialization here //}}AFX_DATA_INIT // Load menu accelerator table. diff --git a/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp index 01fa3a0..5472b47 100644 --- a/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp +++ b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp @@ -17,6 +17,9 @@ Change History (most recent first): $Log: BrowserDialog.cpp,v $ +Revision 1.4 2008/10/23 22:33:26 cheshire +Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu + Revision 1.3 2006/08/14 23:25:55 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -87,7 +90,7 @@ BrowserDialog::BrowserDialog( CWnd *inParent ) : CDialog( BrowserDialog::IDD, inParent ) { //{{AFX_DATA_INIT(BrowserDialog) - // NOTE: the ClassWizard will add member initialization here + // Note: the ClassWizard will add member initialization here //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32. diff --git a/mDNSWindows/Java/Java.vcproj b/mDNSWindows/Java/Java.vcproj index a846ec9..593175d 100755 --- a/mDNSWindows/Java/Java.vcproj +++ b/mDNSWindows/Java/Java.vcproj @@ -1,36 +1,105 @@ + Keyword="MakeFileProj" + > + Name="Win32" + /> + + + + ConfigurationType="0" + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" + > + CleanCommandLine="nmake /f makefile DEBUG=1 clean" + Output="" + PreprocessorDefinitions="" + IncludeSearchPath="" + ForcedIncludes="" + AssemblySearchPath="" + ForcedUsingAssemblies="" + CompileAsManaged="" + /> + ConfigurationType="0" + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" + > + + + + + + + CleanCommandLine="nmake /f makefile clean" + Output="" + PreprocessorDefinitions="" + IncludeSearchPath="" + ForcedIncludes="" + AssemblySearchPath="" + ForcedUsingAssemblies="" + CompileAsManaged="" + /> diff --git a/mDNSWindows/Java/makefile b/mDNSWindows/Java/makefile index 99a7987..768b51f 100644 --- a/mDNSWindows/Java/makefile +++ b/mDNSWindows/Java/makefile @@ -15,6 +15,11 @@ # limitations under the License. # # $Log: makefile,v $ +# Revision 1.10 2009/03/30 20:22:43 herscher +# Current Bonjour code does not compile on Windows +# Update LIBDIR to work with new build directory structure +# Create postbuild rules for new buildtrain +# # Revision 1.9 2006/08/14 23:26:04 cheshire # Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 # @@ -89,13 +94,13 @@ CFLAGS_DEBUG = -Zi -DMDNS_DEBUGMSGS=2 OBJDIR = objects\debug BUILDDIR = build\debug INSTALLDIR = root\"Program Files"\Bonjour -LIBDIR = ..\DLL\Debug +LIBDIR = ..\DLL\Win32\Debug !else CFLAGS_DEBUG = -Os -DMDNS_DEBUGMSGS=0 OBJDIR = objects\prod BUILDDIR = build\prod INSTALLDIR = root\"Program Files"\Bonjour -LIBDIR = ..\DLL\Release +LIBDIR = ..\DLL\Win32\Release !endif CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_DEBUG) @@ -113,7 +118,13 @@ setup: @if not exist $(BUILDDIR) mkdir $(BUILDDIR) postbuild: - @if not exist root mkdir root + @if not "%RC_XBS%"=="YES" GOTO CONT + @if not exist "$(DSTROOT)\WINDOWS\system32\Win32" mkdir "$(DSTROOT)\WINDOWS\system32\Win32" + @if not exist "$(DSTROOT)\Program Files\Bonjour\Win32" mkdir "$(DSTROOT)\Program Files\Bonjour\Win32" + @copy $(BUILDDIR)\jdns_sd.dll "$(DSTROOT)\WINDOWS\system32\Win32" + @copy $(BUILDDIR)\dns_sd.jar "$(DSTROOT)\Program Files\Bonjour\Win32" + @:CONT + @if not exist root mkdir root @if not exist root\"Program Files" mkdir root\"Program Files" @if not exist $(INSTALLDIR) mkdir $(INSTALLDIR) copy $(BUILDDIR)\dns_sd.jar $(INSTALLDIR) @@ -137,14 +148,14 @@ JARCONTENTS = $(OBJDIR)\com\apple\dnssd\DNSSDService.class \ $(OBJDIR)\com\apple\dnssd\DNSRecord.class \ $(OBJDIR)\com\apple\dnssd\TXTRecord.class \ $(OBJDIR)\com\apple\dnssd\DNSSDRegistration.class \ + $(OBJDIR)\com\apple\dnssd\DNSSDRecordRegistrar.class \ $(OBJDIR)\com\apple\dnssd\BaseListener.class \ $(OBJDIR)\com\apple\dnssd\BrowseListener.class \ $(OBJDIR)\com\apple\dnssd\ResolveListener.class \ $(OBJDIR)\com\apple\dnssd\RegisterListener.class \ + $(OBJDIR)\com\apple\dnssd\RegisterRecordListener.class \ $(OBJDIR)\com\apple\dnssd\QueryListener.class \ $(OBJDIR)\com\apple\dnssd\DomainListener.class \ - $(OBJDIR)\com\apple\dnssd\DNSSDRecordRegistrar.class \ - $(OBJDIR)\com\apple\dnssd\RegisterRecordListener.class \ $(OBJDIR)\com\apple\dnssd\DNSSD.class $(BUILDDIR)\dns_sd.jar: $(JARCONTENTS) diff --git a/mDNSWindows/NSPTool/NSPTool.vcproj b/mDNSWindows/NSPTool/NSPTool.vcproj index f42620a..bed3203 100644 --- a/mDNSWindows/NSPTool/NSPTool.vcproj +++ b/mDNSWindows/NSPTool/NSPTool.vcproj @@ -1,121 +1,361 @@ + Keyword="Win32Proj" + > + Name="Win32" + /> + + + + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" + CharacterSet="2" + > + + + + + + CallingConvention="0" + /> + + Name="VCResourceCompilerTool" + AdditionalIncludeDirectories="..\" + /> + + TargetMachine="1" + /> + + + + + + + + + + + Name="VCPreBuildEventTool" + /> + Name="VCCustomBuildTool" + /> + Name="VCXMLDataGeneratorTool" + /> + Name="VCWebServiceProxyGeneratorTool" + /> + + + + AdditionalIncludeDirectories="..\" + /> + + + + + + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + Name="VCWebDeploymentTool" + /> + Name="VCPostBuildEventTool" + /> + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" + CharacterSet="2" + > + + + + + + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + /> + Name="VCManagedResourceCompilerTool" + /> + + + TargetMachine="1" + /> + + + + + + + + + + + + Name="VCCustomBuildTool" + /> + Name="VCXMLDataGeneratorTool" + /> + Name="VCWebServiceProxyGeneratorTool" + /> + Name="VCMIDLTool" + TargetEnvironment="3" + /> + + + AdditionalIncludeDirectories="..\" + /> + + + + + + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + Name="VCWebDeploymentTool" + /> + Name="VCPostBuildEventTool" + /> @@ -124,34 +364,43 @@ + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + RelativePath="..\..\mDNSShared\DebugServices.c" + > + RelativePath=".\NSPTool.c" + > + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + RelativePath="..\..\mDNSShared\CommonServices.h" + > + RelativePath="..\..\mDNSShared\DebugServices.h" + > + RelativePath=".\resource.h" + > + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" + > + RelativePath=".\NSPTool.rc" + > diff --git a/mDNSWindows/RegNames.h b/mDNSWindows/RegNames.h index c86b7ec..47b910d 100644 --- a/mDNSWindows/RegNames.h +++ b/mDNSWindows/RegNames.h @@ -17,6 +17,9 @@ Change History (most recent first): $Log: RegNames.h,v $ +Revision 1.5 2009/03/30 21:47:35 herscher +Fix file corruption during previous checkin + Revision 1.3 2006/08/14 23:25:20 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -35,7 +38,10 @@ Consolidates all registry key names and can safely be included in any component #if defined(UNICODE) -# define kServiceParametersNode L"SOFTWARE\\Apple Computer, Inc.\\Bonjour" +# define kServiceParametersSoftware L"SOFTWARE" +# define kServiceParametersAppleComputer L"Apple Computer, Inc." +# define kServiceParametersBonjour L"Bonjour" +# define kServiceParametersNode L"SOFTWARE\\Apple Inc.\\Bonjour" # define kServiceName L"Bonjour Service" # define kServiceDynDNSBrowseDomains L"BrowseDomains" # define kServiceDynDNSHostNames L"HostNames" @@ -49,7 +55,10 @@ Consolidates all registry key names and can safely be included in any component # else -# define kServiceParametersNode "SOFTWARE\\Apple Computer, Inc.\\Bonjour" +# define kServiceParametersSoftware "SOFTWARE" +# define kServiceParametersAppleComputer "Apple Computer, Inc." +# define kServiceParametersBonjour "Bonjour" +# define kServiceParametersNode "SOFTWARE\\Apple Inc.\\Bonjour" # define kServiceName "Bonjour Service" # define kServiceDynDNSBrowseDomains "BrowseDomains" # define kServiceDynDNSHostNames "HostNames" diff --git a/mDNSWindows/Secret.c b/mDNSWindows/Secret.c new file mode 100644 index 0000000..4c12d15 --- /dev/null +++ b/mDNSWindows/Secret.c @@ -0,0 +1,348 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + Change History (most recent first): + +$Log: Secret.c,v $ +Revision 1.2 2009/06/25 21:11:52 herscher +Fix compilation error when building Control Panel. + +Revision 1.1 2009/06/22 23:25:04 herscher + ControlPanel doesn't display key and password in dialog box. Refactor Lsa calls into Secret.h and Secret.c, which is used by both the ControlPanel and mDNSResponder system service. + + +*/ + +#include "Secret.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "DebugServices.h" + + +mDNSlocal OSStatus MakeLsaStringFromUTF8String( PLSA_UNICODE_STRING output, const char * input ); +mDNSlocal OSStatus MakeUTF8StringFromLsaString( char * output, size_t len, PLSA_UNICODE_STRING input ); + + +BOOL +LsaGetSecret( const char * inDomain, char * outDomain, unsigned outDomainLength, char * outKey, unsigned outKeyLength, char * outSecret, unsigned outSecretLength ) +{ + PLSA_UNICODE_STRING domainLSA; + PLSA_UNICODE_STRING keyLSA; + PLSA_UNICODE_STRING secretLSA; + size_t i; + size_t dlen; + LSA_OBJECT_ATTRIBUTES attrs; + LSA_HANDLE handle = NULL; + NTSTATUS res; + OSStatus err; + + check( inDomain ); + check( outDomain ); + check( outKey ); + check( outSecret ); + + // Initialize + + domainLSA = NULL; + keyLSA = NULL; + secretLSA = NULL; + + // If there isn't a trailing dot, add one because the mDNSResponder + // presents names with the trailing dot. + + strcpy_s( outDomain, outDomainLength, inDomain ); + dlen = strlen( outDomain ); + + if ( outDomain[ dlen - 1 ] != '.' ) + { + outDomain[ dlen ] = '.'; + outDomain[ dlen + 1 ] = '\0'; + } + + // Canonicalize name by converting to lower case (keychain and some name servers are case sensitive) + + dlen = strlen( outDomain ); + for ( i = 0; i < dlen; i++ ) + { + outDomain[i] = (char) tolower( outDomain[i] ); // canonicalize -> lower case + } + + // attrs are reserved, so initialize to zeroes. + + ZeroMemory( &attrs, sizeof( attrs ) ); + + // Get a handle to the Policy object on the local system + + res = LsaOpenPolicy( NULL, &attrs, POLICY_GET_PRIVATE_INFORMATION, &handle ); + err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr ); + require_noerr( err, exit ); + + // Get the encrypted data + + domainLSA = ( PLSA_UNICODE_STRING ) malloc( sizeof( LSA_UNICODE_STRING ) ); + require_action( domainLSA != NULL, exit, err = mStatus_NoMemoryErr ); + err = MakeLsaStringFromUTF8String( domainLSA, outDomain ); + require_noerr( err, exit ); + + // Retrieve the key + + res = LsaRetrievePrivateData( handle, domainLSA, &keyLSA ); + err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr ); + require_noerr_quiet( err, exit ); + + // Lsa secrets use a flat naming space. Therefore, we will prepend "$" to the keyname to + // make sure it doesn't conflict with a zone name. + + // Strip off the "$" prefix. + + err = MakeUTF8StringFromLsaString( outKey, outKeyLength, keyLSA ); + require_noerr( err, exit ); + require_action( outKey[0] == '$', exit, err = kUnknownErr ); + memcpy( outKey, outKey + 1, strlen( outKey ) ); + + // Retrieve the secret + + res = LsaRetrievePrivateData( handle, keyLSA, &secretLSA ); + err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr ); + require_noerr_quiet( err, exit ); + + // Convert the secret to UTF8 string + + err = MakeUTF8StringFromLsaString( outSecret, outSecretLength, secretLSA ); + require_noerr( err, exit ); + +exit: + + if ( domainLSA != NULL ) + { + if ( domainLSA->Buffer != NULL ) + { + free( domainLSA->Buffer ); + } + + free( domainLSA ); + } + + if ( keyLSA != NULL ) + { + LsaFreeMemory( keyLSA ); + } + + if ( secretLSA != NULL ) + { + LsaFreeMemory( secretLSA ); + } + + if ( handle ) + { + LsaClose( handle ); + handle = NULL; + } + + return ( !err ) ? TRUE : FALSE; +} + + +mDNSBool +LsaSetSecret( const char * inDomain, const char * inKey, const char * inSecret ) +{ + size_t inDomainLength; + size_t inKeyLength; + char domain[ 1024 ]; + char key[ 1024 ]; + LSA_OBJECT_ATTRIBUTES attrs; + LSA_HANDLE handle = NULL; + NTSTATUS res; + LSA_UNICODE_STRING lucZoneName; + LSA_UNICODE_STRING lucKeyName; + LSA_UNICODE_STRING lucSecretName; + BOOL ok = TRUE; + OSStatus err; + + require_action( inDomain != NULL, exit, ok = FALSE ); + require_action( inKey != NULL, exit, ok = FALSE ); + require_action( inSecret != NULL, exit, ok = FALSE ); + + inDomainLength = strlen( inDomain ); + require_action( ( inDomainLength > 0 ) && ( inDomainLength < sizeof( domain ) ), exit, ok = FALSE ); + + inKeyLength = strlen( inKey ); + require_action( ( inKeyLength > 0 ) && ( inKeyLength < ( sizeof( key ) - 1 ) ), exit, ok = FALSE ); + + // If there isn't a trailing dot, add one because the mDNSResponder + // presents names with the trailing dot. + + ZeroMemory( domain, sizeof( domain ) ); + strcpy_s( domain, sizeof( domain ), inDomain ); + + if ( domain[ strlen( domain ) - 1 ] != '.' ) + { + domain[ strlen( domain ) - 1 ] = '.'; + } + + // + // + // Prepend "$" to the key name, so that there will + // be no conflict between the zone name and the key + // name + + ZeroMemory( key, sizeof( key ) ); + key[ 0 ] = '$'; + strcpy_s( key + 1, sizeof( key ) - 1, inKey ); + + if ( key[ strlen( key ) - 1 ] != '.' ) + { + key[ strlen( key ) - 1 ] = '.'; + } + + // attrs are reserved, so initialize to zeroes. + + ZeroMemory( &attrs, sizeof( attrs ) ); + + // Get a handle to the Policy object on the local system + + res = LsaOpenPolicy( NULL, &attrs, POLICY_ALL_ACCESS, &handle ); + err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr ); + require_noerr( err, exit ); + + // Intializing PLSA_UNICODE_STRING structures + + ok = MakeLsaStringFromUTF8String( &lucZoneName, domain ); + err = translate_errno( ok, errno_compat(), kUnknownErr ); + require_noerr( err, exit ); + + ok = MakeLsaStringFromUTF8String( &lucKeyName, key ); + err = translate_errno( ok, errno_compat(), kUnknownErr ); + require_noerr( err, exit ); + + ok = MakeLsaStringFromUTF8String( &lucSecretName, inSecret ); + err = translate_errno( ok, errno_compat(), kUnknownErr ); + require_noerr( err, exit ); + + // Store the private data. + + res = LsaStorePrivateData( handle, &lucZoneName, &lucKeyName ); + err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr ); + require_noerr( err, exit ); + + res = LsaStorePrivateData( handle, &lucKeyName, &lucSecretName ); + err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr ); + require_noerr( err, exit ); + +exit: + + if ( handle ) + { + LsaClose( handle ); + handle = NULL; + } + + return ok; +} + + +//=========================================================================================================================== +// MakeLsaStringFromUTF8String +//=========================================================================================================================== + +mDNSlocal OSStatus +MakeLsaStringFromUTF8String( PLSA_UNICODE_STRING output, const char * input ) +{ + int size; + OSStatus err; + + check( input ); + check( output ); + + output->Buffer = NULL; + + size = MultiByteToWideChar( CP_UTF8, 0, input, -1, NULL, 0 ); + err = translate_errno( size > 0, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + + output->Length = (USHORT)( size * sizeof( wchar_t ) ); + output->Buffer = (PWCHAR) malloc( output->Length ); + require_action( output->Buffer, exit, err = mStatus_NoMemoryErr ); + size = MultiByteToWideChar( CP_UTF8, 0, input, -1, output->Buffer, size ); + err = translate_errno( size > 0, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + + // We're going to subtrace one wchar_t from the size, because we didn't + // include it when we encoded the string + + output->MaximumLength = output->Length; + output->Length -= sizeof( wchar_t ); + +exit: + + if ( err && output->Buffer ) + { + free( output->Buffer ); + output->Buffer = NULL; + } + + return( err ); +} + + + +//=========================================================================================================================== +// MakeUTF8StringFromLsaString +//=========================================================================================================================== + +mDNSlocal OSStatus +MakeUTF8StringFromLsaString( char * output, size_t len, PLSA_UNICODE_STRING input ) +{ + size_t size; + OSStatus err = kNoErr; + + // The Length field of this structure holds the number of bytes, + // but WideCharToMultiByte expects the number of wchar_t's. So + // we divide by sizeof(wchar_t) to get the correct number. + + size = (size_t) WideCharToMultiByte(CP_UTF8, 0, input->Buffer, ( input->Length / sizeof( wchar_t ) ), NULL, 0, NULL, NULL); + err = translate_errno( size != 0, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + + // Ensure that we have enough space (Add one for trailing '\0') + + require_action( ( size + 1 ) <= len, exit, err = mStatus_NoMemoryErr ); + + // Convert the string + + size = (size_t) WideCharToMultiByte( CP_UTF8, 0, input->Buffer, ( input->Length / sizeof( wchar_t ) ), output, (int) size, NULL, NULL); + err = translate_errno( size != 0, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + + // have to add the trailing 0 because WideCharToMultiByte doesn't do it, + // although it does return the correct size + + output[size] = '\0'; + +exit: + + return err; +} + diff --git a/mDNSWindows/Secret.h b/mDNSWindows/Secret.h new file mode 100644 index 0000000..a117f09 --- /dev/null +++ b/mDNSWindows/Secret.h @@ -0,0 +1,53 @@ +/* -*- Mode: C; tab-width: 4 -*- + * + * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + Change History (most recent first): + +$Log: Secret.h,v $ +Revision 1.2 2009/06/25 21:11:52 herscher +Fix compilation error when building Control Panel. + +Revision 1.1 2009/06/22 23:25:04 herscher + ControlPanel doesn't display key and password in dialog box. Refactor Lsa calls into Secret.h and Secret.c, which is used by both the ControlPanel and mDNSResponder system service. + + +*/ + +#ifndef _Secret_h +#define _Secret_h + +#include "mDNSEmbeddedAPI.h" + + +#if defined(__cplusplus ) +extern "C" { +#endif + + +extern mDNSBool +LsaGetSecret( const char * inDomain, char * outDomain, unsigned outDomainLength, char * outKey, unsigned outKeyLength, char * outSecret, unsigned outSecretLength ); + + +extern mDNSBool +LsaSetSecret( const char * inDomain, const char * inKey, const char * inSecret ); + + +#if defined(__cplusplus) +} +#endif + + +#endif \ No newline at end of file diff --git a/mDNSWindows/SystemService/Firewall.cpp b/mDNSWindows/SystemService/Firewall.cpp index 79019da..4f1ad49 100755 --- a/mDNSWindows/SystemService/Firewall.cpp +++ b/mDNSWindows/SystemService/Firewall.cpp @@ -17,6 +17,14 @@ Change History (most recent first): $Log: Firewall.cpp,v $ +Revision 1.6 2009/04/24 04:55:26 herscher + Advertise SMB file sharing via Bonjour + +Revision 1.5 2009/03/30 20:39:29 herscher + Current Bonjour code does not compile on Windows + Put in extra defensive checks to prevent NULL pointer dereferencing crash + Move build train to Visual Studio 2005 + Revision 1.4 2006/08/14 23:26:07 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -39,10 +47,6 @@ Wrapper for Windows Firewall API code #endif -#if !defined(_WSPIAPI_COUNTOF) -# define _WSPIAPI_COUNTOF(_Array) (sizeof(_Array) / sizeof(_Array[0])) -#endif - #include "Firewall.h" #include #include @@ -71,12 +75,12 @@ mDNSFirewallInitialize(OUT INetFwProfile ** fwProfile) // call will fail on anything other than XP SP2 err = CoCreateInstance( __uuidof(NetFwMgr), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwMgr), (void**)&fwMgr ); - require(SUCCEEDED(err), exit); + require(SUCCEEDED(err) && ( fwMgr != NULL ), exit); // Use the reference to get the local firewall policy err = fwMgr->get_LocalPolicy(&fwPolicy); - require(SUCCEEDED(err), exit); + require(SUCCEEDED(err) && ( fwPolicy != NULL ), exit); // Use the reference to get the extant profile. Empirical evidence // suggests that there is the potential for a race condition when a system @@ -156,16 +160,16 @@ mDNSFirewallAppIsEnabled // Get the list of authorized applications err = fwProfile->get_AuthorizedApplications(&fwApps); - require(SUCCEEDED(err), exit); + require(SUCCEEDED(err) && ( fwApps != NULL ), exit); fwBstrProcessImageFileName = SysAllocString(fwProcessImageFileName); - require_action(SysStringLen(fwBstrProcessImageFileName) > 0, exit, err = kNoMemoryErr); + require_action( ( fwProcessImageFileName != NULL ) && ( SysStringLen(fwBstrProcessImageFileName) > 0 ), exit, err = kNoMemoryErr); // Look for us err = fwApps->Item(fwBstrProcessImageFileName, &fwApp); - if (SUCCEEDED(err)) + if (SUCCEEDED(err) && ( fwApp != NULL ) ) { // It's listed, but is it enabled? @@ -186,7 +190,10 @@ exit: // Deallocate the BSTR - SysFreeString(fwBstrProcessImageFileName); + if ( fwBstrProcessImageFileName != NULL ) + { + SysFreeString(fwBstrProcessImageFileName); + } // Release the COM objects @@ -234,15 +241,15 @@ mDNSFirewallAddApp // Get the list of authorized applications err = fwProfile->get_AuthorizedApplications(&fwApps); - require(SUCCEEDED(err), exit); + require(SUCCEEDED(err) && ( fwApps != NULL ), exit); // Create an instance of an authorized application. err = CoCreateInstance( __uuidof(NetFwAuthorizedApplication), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwAuthorizedApplication), (void**)&fwApp ); - require(SUCCEEDED(err), exit); + require(SUCCEEDED(err) && ( fwApp != NULL ), exit); fwBstrProcessImageFileName = SysAllocString(fwProcessImageFileName); - require_action(SysStringLen(fwBstrProcessImageFileName) > 0, exit, err = kNoMemoryErr); + require_action(( fwProcessImageFileName != NULL ) && ( SysStringLen(fwBstrProcessImageFileName) > 0 ), exit, err = kNoMemoryErr); // Set the executable file name @@ -250,7 +257,7 @@ mDNSFirewallAddApp require(SUCCEEDED(err), exit); fwBstrName = SysAllocString(fwName); - require_action(SysStringLen(fwBstrName) > 0, exit, err = kNoMemoryErr); + require_action( ( fwBstrName != NULL ) && ( SysStringLen(fwBstrName) > 0 ), exit, err = kNoMemoryErr); // Set the friendly name @@ -269,8 +276,15 @@ exit: // Deallocate the BSTR objects - SysFreeString(fwBstrName); - SysFreeString(fwBstrProcessImageFileName); + if ( fwBstrName != NULL ) + { + SysFreeString(fwBstrName); + } + + if ( fwBstrProcessImageFileName != NULL ) + { + SysFreeString(fwBstrProcessImageFileName); + } // Release the COM objects @@ -285,6 +299,57 @@ exit: } return err; +} + + +static OSStatus +mDNSFirewallIsFileAndPrintSharingEnabled + ( + IN INetFwProfile * fwProfile, + OUT BOOL * fwServiceEnabled + ) +{ + VARIANT_BOOL fwEnabled; + INetFwService* fwService = NULL; + INetFwServices* fwServices = NULL; + OSStatus err = S_OK; + + _ASSERT(fwProfile != NULL); + _ASSERT(fwServiceEnabled != NULL); + + *fwServiceEnabled = FALSE; + + // Retrieve the globally open ports collection. + err = fwProfile->get_Services(&fwServices); + require( SUCCEEDED( err ), exit ); + + // Attempt to retrieve the globally open port. + err = fwServices->Item(NET_FW_SERVICE_FILE_AND_PRINT, &fwService); + require( SUCCEEDED( err ), exit ); + + // Find out if the globally open port is enabled. + err = fwService->get_Enabled(&fwEnabled); + require( SUCCEEDED( err ), exit ); + if (fwEnabled != VARIANT_FALSE) + { + *fwServiceEnabled = TRUE; + } + +exit: + + // Release the globally open port. + if (fwService != NULL) + { + fwService->Release(); + } + + // Release the globally open ports collection. + if (fwServices != NULL) + { + fwServices->Release(); + } + + return err; } @@ -315,7 +380,7 @@ mDNSAddToFirewall // Connect to the firewall err = mDNSFirewallInitialize(&fwProfile); - require_noerr(err, exit); + require( SUCCEEDED( err ) && ( fwProfile != NULL ), exit); // Add us to the list of exempt programs @@ -326,7 +391,10 @@ exit: // Disconnect from the firewall - mDNSFirewallCleanup(fwProfile); + if ( fwProfile != NULL ) + { + mDNSFirewallCleanup(fwProfile); + } // De-initialize COM @@ -337,3 +405,52 @@ exit: return err; } + + +BOOL +mDNSIsFileAndPrintSharingEnabled() +{ + INetFwProfile * fwProfile = NULL; + HRESULT comInit = E_FAIL; + BOOL enabled = FALSE; + OSStatus err = kNoErr; + + // Initialize COM. + + comInit = CoInitializeEx( 0, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE ); + + // Ignore this case. RPC_E_CHANGED_MODE means that COM has already been + // initialized with a different mode. + + if (comInit != RPC_E_CHANGED_MODE) + { + err = comInit; + require(SUCCEEDED(err), exit); + } + + // Connect to the firewall + + err = mDNSFirewallInitialize(&fwProfile); + require( SUCCEEDED( err ) && ( fwProfile != NULL ), exit); + + err = mDNSFirewallIsFileAndPrintSharingEnabled( fwProfile, &enabled ); + require_noerr( err, exit ); + +exit: + + // Disconnect from the firewall + + if ( fwProfile != NULL ) + { + mDNSFirewallCleanup(fwProfile); + } + + // De-initialize COM + + if (SUCCEEDED(comInit)) + { + CoUninitialize(); + } + + return enabled; +} diff --git a/mDNSWindows/SystemService/Firewall.h b/mDNSWindows/SystemService/Firewall.h index e84a930..155ac9a 100755 --- a/mDNSWindows/SystemService/Firewall.h +++ b/mDNSWindows/SystemService/Firewall.h @@ -17,6 +17,9 @@ Change History (most recent first): $Log: Firewall.h,v $ +Revision 1.3 2009/04/24 04:55:26 herscher + Advertise SMB file sharing via Bonjour + Revision 1.2 2006/08/14 23:26:07 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -71,6 +74,10 @@ mDNSAddToFirewall ); +BOOL +mDNSIsFileAndPrintSharingEnabled(); + + diff --git a/mDNSWindows/SystemService/Service.c b/mDNSWindows/SystemService/Service.c index dfe06d1..8671e0b 100644 --- a/mDNSWindows/SystemService/Service.c +++ b/mDNSWindows/SystemService/Service.c @@ -17,6 +17,26 @@ Change History (most recent first): $Log: Service.c,v $ +Revision 1.46 2009/06/05 18:28:24 herscher + mDNSResponder should be able to identify VPN adapters generically + WIN7: Bonjour removes the default gateway entry and thereby breaks network connectivity + +Revision 1.45 2009/04/30 20:07:51 mcguire + Support multiple UDSs from launchd + +Revision 1.44 2009/03/30 20:41:36 herscher + Current Bonjour code does not compile on Windows + Bonjour for Windows incompatible w/Juniper Network Connect. Do a substring search for "Juniper" in the description field + of the network adapter. + Bonjour for Windows incompatible w/Cisco AnyConnect VPN Client + Bonjour for Windows incompatible w/Juniper Network Connect. Update the adapter name per info received from Juniper + Core: Default Gateway set to 0.0.0.0 on Vista causes ARP flood + Change the registry values from Apple Computer, Inc. to Apple Inc. + wchar/sizeof mismatch in CheckFirewall() + +Revision 1.43 2009/01/13 05:31:35 mkrochma + Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy + Revision 1.42 2007/02/14 01:58:19 cheshire Don't delete Unix Domain Socket on exit if we didn't create it on startup @@ -168,6 +188,8 @@ mDNSResponder Windows Service. Provides global Bonjour support with an IPC inter #include #include +#include +#include #include "CommonServices.h" @@ -188,10 +210,17 @@ mDNSResponder Windows Service. Provides global Bonjour support with an IPC inter #include #include #include + #include + #include #include + #include #include #endif +#ifndef HeapEnableTerminationOnCorruption +# define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS)1 +#endif + #if 0 #pragma mark == Constants == #endif @@ -205,6 +234,9 @@ mDNSResponder Windows Service. Provides global Bonjour support with an IPC inter #define kServiceDependencies TEXT("Tcpip\0\0") #define kDNSServiceCacheEntryCountDefault 512 #define kRetryFirewallPeriod 30 * 1000 +#define kDefValueSize MAX_PATH + 1 +#define kZeroIndex 0 +#define kDefaultRouteMetric 399 #define RR_CACHE_SIZE 500 static CacheEntity gRRCache[RR_CACHE_SIZE]; @@ -292,8 +324,12 @@ static void CoreCallback(mDNS * const inMDNS, mStatus result); static void HostDescriptionChanged(mDNS * const inMDNS); static OSStatus GetRouteDestination(DWORD * ifIndex, DWORD * address); static OSStatus SetLLRoute( mDNS * const inMDNS ); -static bool HaveRoute( PMIB_IPFORWARDROW rowExtant, unsigned long addr ); +static bool HaveRoute( PMIB_IPFORWARDROW rowExtant, unsigned long addr, unsigned long metric ); static bool IsValidAddress( const char * addr ); +static bool IsNortelVPN( IP_ADAPTER_INFO * pAdapter ); +static bool IsJuniperVPN( IP_ADAPTER_INFO * pAdapter ); +static bool IsCiscoVPN( IP_ADAPTER_INFO * pAdapter ); +static const char * strnistr( const char * string, const char * subString, size_t max ); #if defined(UNICODE) # define StrLen(X) wcslen(X) @@ -337,6 +373,12 @@ DEBUG_LOCAL HANDLE gStopEvent = NULL; DEBUG_LOCAL CRITICAL_SECTION gEventSourceLock; DEBUG_LOCAL GenLinkedList gEventSources; DEBUG_LOCAL BOOL gRetryFirewall = FALSE; +DEBUG_LOCAL DWORD gOSMajorVersion; +DEBUG_LOCAL DWORD gOSMinorVersion; + +typedef DWORD ( WINAPI * GetIpInterfaceEntryFunctionPtr )( PMIB_IPINTERFACE_ROW ); +mDNSlocal HMODULE gIPHelperLibraryInstance = NULL; +mDNSlocal GetIpInterfaceEntryFunctionPtr gGetIpInterfaceEntryFunctionPtr = NULL; #if 0 @@ -356,6 +398,8 @@ int __cdecl main( int argc, char *argv[] ) BOOL ok; BOOL start; int i; + + HeapSetInformation( NULL, HeapEnableTerminationOnCorruption, NULL, 0 ); debug_initialize( kDebugOutputTypeMetaConsole ); debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelVerbose ); @@ -798,7 +842,7 @@ static OSStatus CheckFirewall() // Get a full path to the executable - size = GetModuleFileNameW( NULL, fullPath, sizeof( fullPath ) ); + size = GetModuleFileNameW( NULL, fullPath, MAX_PATH ); err = translate_errno( size > 0, (OSStatus) GetLastError(), kPathErr ); require_noerr( err, exit ); @@ -1164,16 +1208,22 @@ static OSStatus ServiceRun( int argc, LPTSTR argv[] ) initialized = FALSE; - // Initialize the service-specific stuff and mark the service as running. + // Make the service as running before we call ServiceSpecificInitialize. We've + // had reports that some machines with McAfee firewall installed cause a problem with iTunes installation. + // We think that the firewall product is interferring with code in ServiceSpecificInitialize. So as a + // simple workaround, we'll mark us as running *before* we call ServiceSpecificInitialize. This will unblock + // any installers that are waiting for our state to change. + + gServiceStatus.dwCurrentState = SERVICE_RUNNING; + ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus ); + check_translated_errno( ok, GetLastError(), kParamErr ); + + // Initialize the service-specific stuff err = ServiceSpecificInitialize( argc, argv ); require_noerr( err, exit ); initialized = TRUE; - gServiceStatus.dwCurrentState = SERVICE_RUNNING; - ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus ); - check_translated_errno( ok, GetLastError(), kParamErr ); - err = CheckFirewall(); check_noerr( err ); @@ -1232,13 +1282,15 @@ static void ServiceStop( void ) static OSStatus ServiceSpecificInitialize( int argc, LPTSTR argv[] ) { - OSStatus err; + OSVERSIONINFO osInfo; + OSStatus err; + BOOL ok; DEBUG_UNUSED( argc ); DEBUG_UNUSED( argv ); - memset( &gMDNSRecord, 0, sizeof gMDNSRecord); - memset( &gPlatformStorage, 0, sizeof gPlatformStorage); + mDNSPlatformMemZero( &gMDNSRecord, sizeof gMDNSRecord); + mDNSPlatformMemZero( &gPlatformStorage, sizeof gPlatformStorage); gPlatformStorage.idleThreadCallback = udsIdle; gPlatformStorage.hostDescriptionChangedCallback = HostDescriptionChanged; @@ -1252,19 +1304,20 @@ static OSStatus ServiceSpecificInitialize( int argc, LPTSTR argv[] ) err = mDNS_Init( &gMDNSRecord, &gPlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, CoreCallback, mDNS_Init_NoInitCallbackContext); require_noerr( err, exit); - err = udsserver_init(dnssd_InvalidSocket); + err = udsserver_init(mDNSNULL, 0); require_noerr( err, exit); // - // Don't call SetLLRoute on loopback - // - // Otherwise, set a route to link local addresses (169.254.0.0) + // Get the version of Windows that we're running on // + osInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO ); + ok = GetVersionEx( &osInfo ); + err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + gOSMajorVersion = osInfo.dwMajorVersion; + gOSMinorVersion = osInfo.dwMinorVersion; - if ( gServiceManageLLRouting && !gPlatformStorage.registeredLoopback4 ) - { - SetLLRoute( &gMDNSRecord ); - } + SetLLRoute( &gMDNSRecord ); exit: if( err != kNoErr ) @@ -1346,7 +1399,7 @@ static void ServiceSpecificFinalize( int argc, LPTSTR argv[] ) // // give a chance for the udsserver code to clean up // - udsserver_exit(dnssd_InvalidSocket); + udsserver_exit(); // // and finally close down the mDNSCore @@ -1357,6 +1410,18 @@ static void ServiceSpecificFinalize( int argc, LPTSTR argv[] ) // clean up the event sources mutex...no one should be using it now // DeleteCriticalSection(&gEventSourceLock); + + // + // clean up loaded library + // + + if( gIPHelperLibraryInstance ) + { + gGetIpInterfaceEntryFunctionPtr = NULL; + + FreeLibrary( gIPHelperLibraryInstance ); + gIPHelperLibraryInstance = NULL; + } } @@ -1365,16 +1430,7 @@ CoreCallback(mDNS * const inMDNS, mStatus status) { if (status == mStatus_ConfigChanged) { - // - // Don't call SetLLRoute on loopback - // - // Otherwise, set a route to link local addresses (169.254.0.0) - // - - if ( gServiceManageLLRouting && !inMDNS->p->registeredLoopback4 ) - { - SetLLRoute( inMDNS ); - } + SetLLRoute( inMDNS ); } } @@ -1465,7 +1521,7 @@ udsSocketThread(LPVOID inParam) // if (result == WAIT_OBJECT_0) { - source->callback(source->context); + source->callback( (int) source->sock, 0, source->context); } // // close event @@ -1477,7 +1533,7 @@ udsSocketThread(LPVOID inParam) // so we'll go in here and it will clean up for us // shutdown(source->sock, 2); - source->callback(source->context); + source->callback( (int) source->sock, 0, source->context); break; } @@ -1525,7 +1581,7 @@ udsSupportAddFDToEventLoop( SocketRef fd, udsEventCallback callback, void *conte newSource = malloc(sizeof(Win32EventSource)); require_action( newSource, exit, err = mStatus_NoMemoryErr ); - memset(newSource, 0, sizeof(Win32EventSource)); + mDNSPlatformMemZero(newSource, sizeof(Win32EventSource)); newSource->flags = 0; newSource->sock = (SOCKET) fd; @@ -1783,7 +1839,7 @@ EventSourceUnlock() //=========================================================================================================================== static bool -HaveRoute( PMIB_IPFORWARDROW rowExtant, unsigned long addr ) +HaveRoute( PMIB_IPFORWARDROW rowExtant, unsigned long addr, unsigned long metric ) { PMIB_IPFORWARDTABLE pIpForwardTable = NULL; DWORD dwSize = 0; @@ -1815,7 +1871,7 @@ HaveRoute( PMIB_IPFORWARDROW rowExtant, unsigned long addr ) // for ( i = 0; i < pIpForwardTable->dwNumEntries; i++) { - if ( pIpForwardTable->table[i].dwForwardDest == addr ) + if ( ( pIpForwardTable->table[i].dwForwardDest == addr ) && ( !metric || ( pIpForwardTable->table[i].dwForwardMetric1 == metric ) ) ) { memcpy( rowExtant, &(pIpForwardTable->table[i]), sizeof(*rowExtant) ); found = true; @@ -1846,124 +1902,128 @@ IsValidAddress( const char * addr ) //=========================================================================================================================== -// SetLLRoute +// GetAdditionalMetric //=========================================================================================================================== -static OSStatus -SetLLRoute( mDNS * const inMDNS ) +static ULONG +GetAdditionalMetric( DWORD ifIndex ) { - DWORD ifIndex; - MIB_IPFORWARDROW rowExtant; - bool addRoute; - MIB_IPFORWARDROW row; - OSStatus err; + ULONG metric = 0; - ZeroMemory(&row, sizeof(row)); - - err = GetRouteDestination(&ifIndex, &row.dwForwardNextHop); - require_noerr( err, exit ); - row.dwForwardDest = inet_addr(kLLNetworkAddr); - row.dwForwardIfIndex = ifIndex; - row.dwForwardMask = inet_addr(kLLNetworkAddrMask); - row.dwForwardType = 3; - row.dwForwardProto = MIB_IPPROTO_NETMGMT; - row.dwForwardAge = 0; - row.dwForwardPolicy = 0; - row.dwForwardMetric1 = 30; - row.dwForwardMetric2 = (DWORD) - 1; - row.dwForwardMetric3 = (DWORD) - 1; - row.dwForwardMetric4 = (DWORD) - 1; - row.dwForwardMetric5 = (DWORD) - 1; - - addRoute = true; - - // - // check to make sure we don't already have a route - // - if ( HaveRoute( &rowExtant, inet_addr( kLLNetworkAddr ) ) ) + if( !gIPHelperLibraryInstance ) { - // - // set the age to 0 so that we can do a memcmp. - // - rowExtant.dwForwardAge = 0; + gIPHelperLibraryInstance = LoadLibrary( TEXT( "Iphlpapi" ) ); - // - // check to see if this route is the same as our route - // - if (memcmp(&row, &rowExtant, sizeof(row)) != 0) - { - // - // if it isn't then delete this entry - // - DeleteIpForwardEntry(&rowExtant); - } - else - { - // - // else it is, so we don't want to create another route - // - addRoute = false; + gGetIpInterfaceEntryFunctionPtr = + (GetIpInterfaceEntryFunctionPtr) GetProcAddress( gIPHelperLibraryInstance, "GetIpInterfaceEntry" ); + + if( !gGetIpInterfaceEntryFunctionPtr ) + { + BOOL ok; + + ok = FreeLibrary( gIPHelperLibraryInstance ); + check_translated_errno( ok, GetLastError(), kUnknownErr ); + gIPHelperLibraryInstance = NULL; } } - if (addRoute && row.dwForwardNextHop) + if ( gGetIpInterfaceEntryFunctionPtr ) { - err = CreateIpForwardEntry(&row); + MIB_IPINTERFACE_ROW row; + DWORD err; + ZeroMemory( &row, sizeof( MIB_IPINTERFACE_ROW ) ); + row.Family = AF_INET; + row.InterfaceIndex = ifIndex; + err = gGetIpInterfaceEntryFunctionPtr( &row ); require_noerr( err, exit ); + metric = row.Metric + 256; } +exit: + + return metric; +} + + +//=========================================================================================================================== +// SetLLRoute +//=========================================================================================================================== + +static OSStatus +SetLLRoute( mDNS * const inMDNS ) +{ + OSStatus err = kNoErr; + + DEBUG_UNUSED( inMDNS ); + // - // Now we want to see if we should install a default route for this interface. - // We want to do this if the following are true: - // - // 1. This interface has a link-local address - // 2. This is the only IPv4 interface + // Don't call SetLLRoute on loopback + // Default route on Windows 7 breaks network connectivity + // + // Don't mess w/ the routing table on Vista and later OSes, as + // they have a permanent route to link-local addresses. Otherwise, + // set a route to link local addresses (169.254.0.0) // - - if ( ( row.dwForwardNextHop & 0xFFFF ) == row.dwForwardDest ) + if ( ( gOSMajorVersion < 6 ) && gServiceManageLLRouting && !gPlatformStorage.registeredLoopback4 ) { - mDNSInterfaceData * ifd; - int numLinkLocalInterfaces = 0; - int numInterfaces = 0; - - for ( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next ) - { - if ( ifd->defaultAddr.type == mDNSAddrType_IPv4 ) - { - numInterfaces++; + DWORD ifIndex; + MIB_IPFORWARDROW rowExtant; + bool addRoute; + MIB_IPFORWARDROW row; - if ( ( ifd->interfaceInfo.ip.ip.v4.b[0] == 169 ) && ( ifd->interfaceInfo.ip.ip.v4.b[1] == 254 ) ) - { - numLinkLocalInterfaces++; - } - } - } + ZeroMemory(&row, sizeof(row)); - row.dwForwardDest = 0; + err = GetRouteDestination(&ifIndex, &row.dwForwardNextHop); + require_noerr( err, exit ); + row.dwForwardDest = inet_addr(kLLNetworkAddr); row.dwForwardIfIndex = ifIndex; - row.dwForwardMask = 0; + row.dwForwardMask = inet_addr(kLLNetworkAddrMask); row.dwForwardType = 3; row.dwForwardProto = MIB_IPPROTO_NETMGMT; row.dwForwardAge = 0; row.dwForwardPolicy = 0; - row.dwForwardMetric1 = 20; + row.dwForwardMetric1 = 20 + GetAdditionalMetric( ifIndex ); row.dwForwardMetric2 = (DWORD) - 1; row.dwForwardMetric3 = (DWORD) - 1; row.dwForwardMetric4 = (DWORD) - 1; row.dwForwardMetric5 = (DWORD) - 1; - - if ( numInterfaces == numLinkLocalInterfaces ) + + addRoute = true; + + // + // check to make sure we don't already have a route + // + if ( HaveRoute( &rowExtant, inet_addr( kLLNetworkAddr ), 0 ) ) { - if ( !HaveRoute( &row, 0 ) ) + // + // set the age to 0 so that we can do a memcmp. + // + rowExtant.dwForwardAge = 0; + + // + // check to see if this route is the same as our route + // + if (memcmp(&row, &rowExtant, sizeof(row)) != 0) { - err = CreateIpForwardEntry(&row); - require_noerr( err, exit ); + // + // if it isn't then delete this entry + // + DeleteIpForwardEntry(&rowExtant); + } + else + { + // + // else it is, so we don't want to create another route + // + addRoute = false; } } - else + + if (addRoute && row.dwForwardNextHop) { - DeleteIpForwardEntry( &row ); + err = CreateIpForwardEntry(&row); + check_noerr( err ); } } @@ -2019,25 +2079,19 @@ GetRouteDestination(DWORD * ifIndex, DWORD * address) err = kUnknownErr; // + // // - // Look for the Nortel VPN virtual interface. This interface - // is identified by it's unique MAC address: 44-45-53-54-42-00 + // Look for the Nortel VPN virtual interface, along with Juniper virtual interface. // - // If the interface is active (i.e., has a non-zero IP Address), + // If these interfaces are active (i.e., has a non-zero IP Address), // then we want to disable routing table modifications. while (pAdapter) { - if ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) && - (pAdapter->AddressLength == 6) && - (pAdapter->Address[0] == 0x44) && - (pAdapter->Address[1] == 0x45) && - (pAdapter->Address[2] == 0x53) && - (pAdapter->Address[3] == 0x54) && - (pAdapter->Address[4] == 0x42) && - (pAdapter->Address[5] == 0x00) && - (inet_addr( pAdapter->IpAddressList.IpAddress.String ) != 0)) + if ( ( IsNortelVPN( pAdapter ) || IsJuniperVPN( pAdapter ) || IsCiscoVPN( pAdapter ) ) && + ( inet_addr( pAdapter->IpAddressList.IpAddress.String ) != 0 ) ) { + dlog( kDebugLevelTrace, DEBUG_NAME "disabling routing table management due to VPN incompatibility" ); goto exit; } @@ -2089,3 +2143,89 @@ exit: return( err ); } + + +static bool +IsNortelVPN( IP_ADAPTER_INFO * pAdapter ) +{ + return ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) && + (pAdapter->AddressLength == 6) && + (pAdapter->Address[0] == 0x44) && + (pAdapter->Address[1] == 0x45) && + (pAdapter->Address[2] == 0x53) && + (pAdapter->Address[3] == 0x54) && + (pAdapter->Address[4] == 0x42) && + (pAdapter->Address[5] == 0x00)) ? true : false; +} + + +static bool +IsJuniperVPN( IP_ADAPTER_INFO * pAdapter ) +{ + return ( strnistr( pAdapter->Description, "Juniper", sizeof( pAdapter->Description ) ) != NULL ) ? true : false; +} + + +static bool +IsCiscoVPN( IP_ADAPTER_INFO * pAdapter ) +{ + return ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) && + (pAdapter->AddressLength == 6) && + (pAdapter->Address[0] == 0x00) && + (pAdapter->Address[1] == 0x05) && + (pAdapter->Address[2] == 0x9a) && + (pAdapter->Address[3] == 0x3c) && + (pAdapter->Address[4] == 0x7a) && + (pAdapter->Address[5] == 0x00)) ? true : false; +} + + +static const char * +strnistr( const char * string, const char * subString, size_t max ) +{ + size_t subStringLen; + size_t offset; + size_t maxOffset; + size_t stringLen; + const char * pPos; + + if ( ( string == NULL ) || ( subString == NULL ) ) + { + return string; + } + + stringLen = ( max > strlen( string ) ) ? strlen( string ) : max; + + if ( stringLen == 0 ) + { + return NULL; + } + + subStringLen = strlen( subString ); + + if ( subStringLen == 0 ) + { + return string; + } + + if ( subStringLen > stringLen ) + { + return NULL; + } + + maxOffset = stringLen - subStringLen; + pPos = string; + + for ( offset = 0; offset <= maxOffset; offset++ ) + { + if ( _strnicmp( pPos, subString, subStringLen ) == 0 ) + { + return pPos; + } + + pPos++; + } + + return NULL; +} + diff --git a/mDNSWindows/SystemService/Service.vcproj b/mDNSWindows/SystemService/Service.vcproj index e25dc6e..d16d017 100644 --- a/mDNSWindows/SystemService/Service.vcproj +++ b/mDNSWindows/SystemService/Service.vcproj @@ -1,121 +1,376 @@ + Keyword="Win32Proj" + > + Name="Win32" + /> + + + + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" + CharacterSet="2" + > + + + + + + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + CallingConvention="2" + DisableSpecificWarnings="4127" + ShowIncludes="false" + /> + + Name="VCResourceCompilerTool" + AdditionalIncludeDirectories="../" + /> + + TargetMachine="1" + /> + + + + + + + + + + + Name="VCPreBuildEventTool" + /> + Name="VCCustomBuildTool" + /> + Name="VCXMLDataGeneratorTool" + /> + Name="VCWebServiceProxyGeneratorTool" + /> + + + + AdditionalIncludeDirectories="../" + /> + + Name="VCLinkerTool" + AdditionalOptions="/NXCOMPAT /DYNAMICBASE" + AdditionalDependencies="ws2_32.lib iphlpapi.lib crypt32.lib netapi32.lib" + OutputFile="$(OutDir)/mDNSResponder.exe" + LinkIncremental="2" + IgnoreAllDefaultLibraries="false" + GenerateDebugInformation="true" + ProgramDatabaseFile="$(OutDir)/mDNSResponder.pdb" + SubSystem="1" + TargetMachine="17" + /> + Name="VCALinkTool" + /> + Name="VCManifestTool" + AdditionalManifestFiles="res\mDNSResponder64.manifest" + /> + Name="VCXDCMakeTool" + /> + Name="VCBscMakeTool" + /> + + + + + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" + CharacterSet="2" + > + + + + + + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + DisableSpecificWarnings="4127" + /> + + Name="VCResourceCompilerTool" + AdditionalIncludeDirectories="../" + /> + + TargetMachine="1" + /> + + + + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + Name="VCWebDeploymentTool" + /> + + + + + + + + + + + AdditionalIncludeDirectories="../" + /> + Name="VCPreLinkEventTool" + /> + Name="VCLinkerTool" + AdditionalOptions="/NXCOMPAT /DYNAMICBASE" + AdditionalDependencies="ws2_32.lib iphlpapi.lib netapi32.lib" + OutputFile="$(OutDir)/mDNSResponder.exe" + LinkIncremental="1" + GenerateDebugInformation="true" + ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="17" + /> + + + + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + + @@ -124,94 +379,127 @@ + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + + + RelativePath="..\..\mDNSCore\DNSCommon.c" + > + RelativePath="..\..\mDNSCore\DNSDigest.c" + > + RelativePath="..\..\mDNSShared\dnssd_ipc.c" + > + RelativePath="Firewall.cpp" + > + RelativePath="..\..\mDNSShared\GenLinkedList.c" + > + RelativePath="..\..\mDNSMacOSX\LegacyNATTraversal.c" + > + RelativePath="..\..\mDNSCore\mDNS.c" + > + RelativePath="..\..\mDNSShared\mDNSDebug.c" + > + RelativePath="..\mDNSWin32.c" + > + RelativePath="..\Secret.c" + > + RelativePath=".\Service.c" + > + RelativePath="..\..\mDNSCore\uDNS.c" + > + RelativePath="..\..\mDNSShared\uds_daemon.c" + > + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + RelativePath="..\..\mDNSShared\CommonServices.h" + > + RelativePath="..\..\mDNSShared\DebugServices.h" + > + RelativePath="..\..\mDNSCore\DNSCommon.h" + > + RelativePath="..\..\mDNSShared\dnssd_ipc.h" + > + RelativePath="..\..\mDNSShared\GenLinkedList.h" + > + RelativePath="..\..\mDNSCore\mDNSDebug.h" + > + RelativePath="..\..\mDNSCore\mDNSEmbeddedAPI.h" + > + RelativePath="..\mDNSWin32.h" + > + RelativePath=".\Resource.h" + > + RelativePath="..\Secret.h" + > + RelativePath="..\..\mDNSCore\uDNS.h" + > + RelativePath="..\..\mDNSShared\uds_daemon.h" + > + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" + > + RelativePath=".\Service.rc" + > diff --git a/mDNSWindows/SystemService/res/mDNSResponder.manifest b/mDNSWindows/SystemService/res/mDNSResponder.manifest new file mode 100644 index 0000000..7275854 --- /dev/null +++ b/mDNSWindows/SystemService/res/mDNSResponder.manifest @@ -0,0 +1,12 @@ + + + + Enables hardware devices and software services to automatically configure themselves and advertise their presence on the network. + + + + + + + + diff --git a/mDNSWindows/SystemService/res/mDNSResponder64.manifest b/mDNSWindows/SystemService/res/mDNSResponder64.manifest new file mode 100644 index 0000000..13b3998 --- /dev/null +++ b/mDNSWindows/SystemService/res/mDNSResponder64.manifest @@ -0,0 +1,12 @@ + + + + Enables hardware devices and software services to automatically configure themselves and advertise their presence on the network. + + + + + + + + diff --git a/mDNSWindows/WinServices.cpp b/mDNSWindows/WinServices.cpp index 654b07a..b3b5551 100644 --- a/mDNSWindows/WinServices.cpp +++ b/mDNSWindows/WinServices.cpp @@ -17,6 +17,9 @@ Change History (most recent first): $Log: WinServices.cpp,v $ +Revision 1.3 2009/06/22 23:25:04 herscher + ControlPanel doesn't display key and password in dialog box. Refactor Lsa calls into Secret.h and Secret.c, which is used by both the ControlPanel and mDNSResponder system service. + Revision 1.2 2006/08/14 23:25:20 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -27,6 +30,7 @@ First checked in */ #include "WinServices.h" +#include //=========================================================================================================================== @@ -75,3 +79,29 @@ exit: } return( err ); } + + +//=========================================================================================================================== +// UTF8StringToStringObject +//=========================================================================================================================== + +OSStatus +StringObjectToUTF8String( CString &inObject, char* outUTF8, size_t outUTF8Len ) +{ + OSStatus err = kNoErr; + + memset( outUTF8, 0, outUTF8Len ); + + if ( inObject.GetLength() > 0 ) + { + size_t size; + + size = (size_t) WideCharToMultiByte( CP_UTF8, 0, inObject.GetBuffer(), inObject.GetLength(), outUTF8, (int) outUTF8Len, NULL, NULL); + err = translate_errno( size != 0, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + } + +exit: + + return err; +} diff --git a/mDNSWindows/WinServices.h b/mDNSWindows/WinServices.h index 9d9db91..8909cd1 100644 --- a/mDNSWindows/WinServices.h +++ b/mDNSWindows/WinServices.h @@ -17,6 +17,9 @@ Change History (most recent first): $Log: WinServices.h,v $ +Revision 1.3 2009/06/22 23:25:05 herscher + ControlPanel doesn't display key and password in dialog box. Refactor Lsa calls into Secret.h and Secret.c, which is used by both the ControlPanel and mDNSResponder system service. + Revision 1.2 2006/08/14 23:25:21 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -41,4 +44,5 @@ First checked in #include "CommonServices.h" -OSStatus UTF8StringToStringObject( const char *inUTF8, CString &inObject ); +OSStatus UTF8StringToStringObject( const char *inUTF8, CString &outObject ); +OSStatus StringObjectToUTF8String( CString &inObject, char* outUTF8, size_t outUTF8Len ); diff --git a/mDNSWindows/WinVersRes.h b/mDNSWindows/WinVersRes.h index 8c436e0..b155515 100644 --- a/mDNSWindows/WinVersRes.h +++ b/mDNSWindows/WinVersRes.h @@ -17,6 +17,24 @@ Change History (most recent first): $Log: WinVersRes.h,v $ +Revision 1.61 2009/06/30 17:37:32 herscher +Bump to 2.0.0.5 + +Revision 1.60 2009/06/15 18:03:41 herscher +Bump to version 2.0.0.4 + +Revision 1.59 2009/05/27 20:14:35 herscher +Bump version to 2.0.0.3 + +Revision 1.58 2009/05/26 21:13:35 herscher +Bump to version 2.0.0.2 + +Revision 1.57 2009/04/28 20:12:15 herscher +Bump version to 2.0.0.1 + +Revision 1.56 2009/04/02 22:04:43 herscher +Bump to version 2.0.0.0 + Revision 1.55 2007/04/27 20:34:31 herscher mDNS: Company name needs to be changed to Apple Inc. @@ -193,12 +211,12 @@ First checked in. #define MASTER_COMPANY_NAME "Apple Inc." // Define the product version for mDNSResponder on Windows -#define MASTER_PROD_VERS 1,0,3,1 -#define MASTER_PROD_VERS_STR "1,0,3,1" -#define MASTER_PROD_VERS_STR2 "1.0.3.1" -#define MASTER_PROD_VERS_STR3 "Explorer Plugin 1.0.3.1" +#define MASTER_PROD_VERS 2,0,0,5 +#define MASTER_PROD_VERS_STR "2,0,0,5" +#define MASTER_PROD_VERS_STR2 "2.0.0.5" +#define MASTER_PROD_VERS_STR3 "Explorer Plugin 2.0.0.5" // Define the legal copyright -#define MASTER_LEGAL_COPYRIGHT "Copyright (C) 2003-2007 Apple Inc." +#define MASTER_LEGAL_COPYRIGHT "Copyright (C) 2003-2009 Apple Inc." #endif // WINRESVERS_H diff --git a/mDNSWindows/isocode.h b/mDNSWindows/isocode.h index 953ef20..0edb6ff 100755 --- a/mDNSWindows/isocode.h +++ b/mDNSWindows/isocode.h @@ -92,8 +92,8 @@ unsigned char ISOCODES[] = { 4, 6, 'd','a', 0 , 0 , 0 , 0 , 4, 11, 'f','i', 0 , 0 , 0 , 0 , 4, 18, 'k','o', 0 , 0 , 0 , 0 , -4, 20, 'n','o', 0 , 0 , 0 , 0 , -8, 20, 'n','o', 0 , 0 , 0 , 0 , +4, 20, 'n','b', 0 , 0 , 0 , 0 , +8, 20, 'n','b', 0 , 0 , 0 , 0 , 4, 22, 'p','t', 0 , 0 , 0 , 0 , 4, 29, 's','v', 0 , 0 , 0 , 0 , 8, 29, 's','v', 0 , 0 , 0 , 0 , diff --git a/mDNSWindows/mDNSWin32.c b/mDNSWindows/mDNSWin32.c index 1cb1f64..8f1283f 100755 --- a/mDNSWindows/mDNSWin32.c +++ b/mDNSWindows/mDNSWin32.c @@ -17,6 +17,50 @@ Change History (most recent first): $Log: mDNSWin32.c,v $ +Revision 1.142 2009/06/25 21:11:02 herscher + Platform layer doesn't correctly initialize the port field of TCP and UDP socket structures. + +Revision 1.141 2009/06/22 23:25:05 herscher + ControlPanel doesn't display key and password in dialog box. Refactor Lsa calls into Secret.h and Secret.c, which is used by both the ControlPanel and mDNSResponder system service. + +Revision 1.140 2009/04/24 04:55:26 herscher + Advertise SMB file sharing via Bonjour + +Revision 1.139 2009/04/01 20:06:31 herscher + Corrupt computer name string used + +Revision 1.138 2009/04/01 19:31:54 herscher +Remove extraneous printf + +Revision 1.137 2009/04/01 17:50:15 mcguire +cleanup mDNSRandom + +Revision 1.136 2009/03/30 20:53:10 herscher + Current Bonjour code does not compile on Windows + iTunes 8: Bonjour doesn't work after upgrading iTunes 8. + Reduce sleep from 3 seconds to 2 seconds + Bonjour Service sometimes only gets a IPv6 link-local address after a network changed event + Bonjour For Windows doesn't show IPv4 loopback intermittently when no network interfaces are active + Bonjour service does not publish ANY IPv6 address on Windows Vista + Bonjour 105A6: mDNSResponder is crashing on startup + B4Windows: uDNS: Should use randomized source ports and transaction IDs to avoid DNS cache poisoning + Remove Virtual PC check from mDNSResponder code + +Revision 1.135 2009/01/13 05:31:35 mkrochma + Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy + +Revision 1.134 2008/10/23 22:33:25 cheshire +Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu + +Revision 1.133 2008/10/22 17:19:57 cheshire +Don't need to define BPF_fd any more (it's now per-interface, not global) + +Revision 1.132 2008/10/03 23:34:08 cheshire +Added skeleton definition of mDNSPlatformSendRawPacket + +Revision 1.131 2008/10/03 18:25:18 cheshire +Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);" + Revision 1.130 2007/11/16 18:53:56 cheshire TCPSocketFlags needs to be first field of TCPSocket_struct @@ -114,8 +158,9 @@ Revision 1.106 2006/02/26 19:31:05 herscher #include "CommonServices.h" #include "DebugServices.h" -#include "VPCDetect.h" +#include "Firewall.h" #include "RegNames.h" +#include "Secret.h" #include #include @@ -123,10 +168,11 @@ Revision 1.106 2006/02/26 19:31:05 herscher #include #include #include + #include #endif #include "mDNSEmbeddedAPI.h" - +#include "DNSCommon.h" #include "mDNSWin32.h" #if 0 @@ -156,18 +202,19 @@ Revision 1.106 2006/02/26 19:31:05 herscher #define kWaitListComputerDescriptionEvent ( WAIT_OBJECT_0 + 3 ) #define kWaitListTCPIPEvent ( WAIT_OBJECT_0 + 4 ) #define kWaitListDynDNSEvent ( WAIT_OBJECT_0 + 5 ) -#define kWaitListFixedItemCount 6 + MDNS_WINDOWS_ENABLE_IPV4 + MDNS_WINDOWS_ENABLE_IPV6 +#define kWaitListFileShareEvent ( WAIT_OBJECT_0 + 6 ) +#define kWaitListFirewallEvent ( WAIT_OBJECT_0 + 7 ) +#define kWaitListFixedItemCount 8 + MDNS_WINDOWS_ENABLE_IPV4 + MDNS_WINDOWS_ENABLE_IPV6 #define kRegistryMaxKeyLength 255 +#define kRegistryMaxValueName 16383 #if( !TARGET_OS_WINDOWS_CE ) static GUID kWSARecvMsgGUID = WSAID_WSARECVMSG; #endif #define kIPv6IfIndexBase (10000000L) - -#define kRetryVPCRate (-100000000) -#define kRetryVPCMax (10) +#define SMBPortAsNumber 445 #if 0 @@ -191,20 +238,24 @@ mDNSlocal mStatus SetupSocket( mDNS * const inMDNS, const struct sockaddr *inA mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort ); mDNSlocal mStatus SetupNotifications( mDNS * const inMDNS ); mDNSlocal mStatus TearDownNotifications( mDNS * const inMDNS ); -mDNSlocal mStatus SetupRetryVPCCheck( mDNS * const inMDNS ); -mDNSlocal mStatus TearDownRetryVPCCheck( mDNS * const inMDNS ); mDNSlocal mStatus SetupThread( mDNS * const inMDNS ); mDNSlocal mStatus TearDownThread( const mDNS * const inMDNS ); mDNSlocal unsigned WINAPI ProcessingThread( LPVOID inParam ); mDNSlocal mStatus ProcessingThreadInitialize( mDNS * const inMDNS ); mDNSlocal mStatus ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount ); -mDNSlocal void ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *inIFD, SocketRef inSock ); +mDNSlocal void ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *inIFD, UDPSocket * inUDPSocket, SocketRef inSock ); mDNSlocal void ProcessingThreadInterfaceListChanged( mDNS *inMDNS ); mDNSlocal void ProcessingThreadComputerDescriptionChanged( mDNS * inMDNS ); mDNSlocal void ProcessingThreadTCPIPConfigChanged( mDNS * inMDNS ); mDNSlocal void ProcessingThreadDynDNSConfigChanged( mDNS * inMDNS ); -mDNSlocal void ProcessingThreadRetryVPCCheck( mDNS * inMDNS ); +mDNSlocal void ProcessingThreadFileShareChanged( mDNS * inMDNS ); +mDNSlocal void ProcessingThreadFirewallChanged( mDNS * inMDNS ); +mDNSlocal OSStatus GetWindowsVersionString( char *inBuffer, size_t inBufferSize ); + +mDNSlocal int getifaddrs( struct ifaddrs **outAddrs ); +mDNSlocal void freeifaddrs( struct ifaddrs *inAddrs ); + // Platform Accessors @@ -231,21 +282,24 @@ struct TCPSocket_struct TCPSocket * next; }; +struct UDPSocket_struct +{ + mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port + SocketRef sock; + HANDLE readEvent; + mDNSAddr dstAddr; + LPFN_WSARECVMSG recvMsgPtr; + struct UDPSocket_struct * next; +}; -mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID ); -mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo ); -// Utilities -typedef struct PolyString PolyString; -struct PolyString -{ - domainname m_dname; - char m_utf8[256]; - PLSA_UNICODE_STRING m_lsa; -}; +mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID ); +mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo ); + +// Utilities #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS ) mDNSlocal int getifaddrs_ipv6( struct ifaddrs **outAddrs ); @@ -269,10 +323,18 @@ mDNSlocal mStatus RegQueryString( HKEY key, LPCSTR param, LPSTR * string, DWOR mDNSlocal struct ifaddrs* myGetIfAddrs(int refresh); mDNSlocal OSStatus TCHARtoUTF8( const TCHAR *inString, char *inBuffer, size_t inBufferSize ); mDNSlocal OSStatus WindowsLatin1toUTF8( const char *inString, char *inBuffer, size_t inBufferSize ); -mDNSlocal OSStatus MakeLsaStringFromUTF8String( PLSA_UNICODE_STRING output, const char * input ); -mDNSlocal OSStatus MakeUTF8StringFromLsaString( char * output, size_t len, PLSA_UNICODE_STRING input ); mDNSlocal void FreeTCPSocket( TCPSocket *sock ); +mDNSlocal void FreeUDPSocket( UDPSocket * sock ); mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa); +mDNSlocal void GetDDNSFQDN( domainname *const fqdn ); +#ifdef UNICODE +mDNSlocal void GetDDNSDomains( DNameListElem ** domains, LPCWSTR lpSubKey ); +#else +mDNSlocal void GetDDNSDomains( DNameListElem ** domains, LPCSTR lpSubKey ); +#endif +mDNSlocal void SetDomainSecrets( mDNS * const m ); +mDNSlocal void SetDomainSecret( mDNS * const m, const domainname * inDomain ); +mDNSlocal void CheckFileShares( mDNS * const m ); #ifdef __cplusplus } @@ -290,6 +352,8 @@ mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport; mDNSs32 mDNSPlatformOneSecond = 0; mDNSlocal TCPSocket * gTCPConnectionList = NULL; mDNSlocal int gTCPConnections = 0; +mDNSlocal UDPSocket * gUDPSocketList = NULL; +mDNSlocal int gUDPSockets = 0; mDNSlocal BOOL gWaitListChanged = FALSE; #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS ) @@ -307,6 +371,35 @@ mDNSlocal BOOL gWaitListChanged = FALSE; #endif + +#ifndef HCRYPTPROV + typedef ULONG_PTR HCRYPTPROV; // WinCrypt.h, line 249 +#endif + + +#ifndef CRYPT_MACHINE_KEYSET +# define CRYPT_MACHINE_KEYSET 0x00000020 +#endif + +#ifndef CRYPT_NEWKEYSET +# define CRYPT_NEWKEYSET 0x00000008 +#endif + +#ifndef PROV_RSA_FULL +# define PROV_RSA_FULL 1 +#endif + +typedef BOOL (__stdcall *fnCryptGenRandom)( HCRYPTPROV, DWORD, BYTE* ); +typedef BOOL (__stdcall *fnCryptAcquireContext)( HCRYPTPROV*, LPCTSTR, LPCTSTR, DWORD, DWORD); +typedef BOOL (__stdcall *fnCryptReleaseContext)(HCRYPTPROV, DWORD); + +static fnCryptAcquireContext g_lpCryptAcquireContext = NULL; +static fnCryptReleaseContext g_lpCryptReleaseContext = NULL; +static fnCryptGenRandom g_lpCryptGenRandom = NULL; +static HINSTANCE g_hAAPI32 = NULL; +static HCRYPTPROV g_hProvider = ( ULONG_PTR ) NULL; + + #if 0 #pragma mark - #pragma mark == Platform Support == @@ -331,7 +424,7 @@ mDNSexport mStatus mDNSPlatformInit( mDNS * const inMDNS ) // Initialize variables. If the PlatformSupport pointer is not null then just assume that a non-Apple client is // calling mDNS_Init and wants to provide its own storage for the platform-specific data so do not overwrite it. - memset( &gMDNSPlatformSupport, 0, sizeof( gMDNSPlatformSupport ) ); + mDNSPlatformMemZero( &gMDNSPlatformSupport, sizeof( gMDNSPlatformSupport ) ); if( !inMDNS->p ) inMDNS->p = &gMDNSPlatformSupport; inMDNS->p->interfaceListChangedSocket = kInvalidSocketRef; mDNSPlatformOneSecond = 1000; // Use milliseconds as the quantum of time @@ -361,12 +454,6 @@ mDNSexport mStatus mDNSPlatformInit( mDNS * const inMDNS ) inMDNS->HISoftware.c[ 0 ] = (mDNSu8) mDNSPlatformStrLen( &inMDNS->HISoftware.c[ 1 ] ); dlog( kDebugLevelInfo, DEBUG_NAME "HISoftware: %#s\n", inMDNS->HISoftware.c ); #endif - - // Bookkeeping - - inMDNS->p->vpcCheckCount = 0; - inMDNS->p->vpcCheckEvent = NULL; - inMDNS->p->timersCount = 0; // Set up the IPv4 unicast socket @@ -462,10 +549,19 @@ mDNSexport mStatus mDNSPlatformInit( mDNS * const inMDNS ) err = SetupThread( inMDNS ); require_noerr( err, exit ); + + // Notify core of domain secret keys + + SetDomainSecrets( inMDNS ); // Success! - + mDNSCoreInitComplete( inMDNS, err ); + + // See if we need to advertise file sharing + + inMDNS->p->smbRegistered = mDNSfalse; + CheckFileShares( inMDNS ); exit: if( err ) @@ -495,9 +591,6 @@ mDNSexport void mDNSPlatformClose( mDNS * const inMDNS ) err = TearDownInterfaceList( inMDNS ); check_noerr( err ); check( !inMDNS->p->inactiveInterfaceList ); - - err = TearDownRetryVPCCheck( inMDNS ); - check_noerr( err ); err = TearDownSynchronizationObjects( inMDNS ); check_noerr( err ); @@ -544,93 +637,34 @@ mDNSexport void mDNSPlatformClose( mDNS * const inMDNS ) } #endif - WSACleanup(); - - dlog( kDebugLevelTrace, DEBUG_NAME "platform close done\n" ); -} - -//=========================================================================================================================== -// mDNSPlatformSendUDP -//=========================================================================================================================== - -mDNSexport mStatus - mDNSPlatformSendUDP( - const mDNS * const inMDNS, - const void * const inMsg, - const mDNSu8 * const inMsgEnd, - mDNSInterfaceID inInterfaceID, - const mDNSAddr * inDstIP, - mDNSIPPort inDstPort ) -{ - SOCKET sendingsocket = INVALID_SOCKET; - mStatus err = mStatus_NoError; - mDNSInterfaceData * ifd = (mDNSInterfaceData*) inInterfaceID; - struct sockaddr_storage addr; - int n; - - DEBUG_USE_ONLY( inMDNS ); - - n = (int)( inMsgEnd - ( (const mDNSu8 * const) inMsg ) ); - check( inMDNS ); - check( inMsg ); - check( inMsgEnd ); - check( inDstIP ); - - dlog( kDebugLevelChatty, DEBUG_NAME "platform send %d bytes to %#a:%u\n", n, inDstIP, ntohs( inDstPort.NotAnInteger ) ); - - if( inDstIP->type == mDNSAddrType_IPv4 ) - { - struct sockaddr_in * sa4; - - sa4 = (struct sockaddr_in *) &addr; - sa4->sin_family = AF_INET; - sa4->sin_port = inDstPort.NotAnInteger; - sa4->sin_addr.s_addr = inDstIP->ip.v4.NotAnInteger; - sendingsocket = ifd ? ifd->sock : inMDNS->p->unicastSock4; - } - else if( inDstIP->type == mDNSAddrType_IPv6 ) - { - struct sockaddr_in6 * sa6; - - sa6 = (struct sockaddr_in6 *) &addr; - sa6->sin6_family = AF_INET6; - sa6->sin6_port = inDstPort.NotAnInteger; - sa6->sin6_flowinfo = 0; - sa6->sin6_addr = *( (struct in6_addr *) &inDstIP->ip.v6 ); - sa6->sin6_scope_id = 0; // Windows requires the scope ID to be zero. IPV6_MULTICAST_IF specifies interface. - sendingsocket = ifd ? ifd->sock : inMDNS->p->unicastSock6; - } - else - { - dlog( kDebugLevelError, DEBUG_NAME "%s: dst is not an IPv4 or IPv6 address (type=%d)\n", __ROUTINE__, inDstIP->type ); - err = mStatus_BadParamErr; - goto exit; - } - - if (IsValidSocket(sendingsocket)) + if ( g_hAAPI32 ) { - n = sendto( sendingsocket, (char *) inMsg, n, 0, (struct sockaddr *) &addr, sizeof( addr ) ); - err = translate_errno( n > 0, errno_compat(), kWriteErr ); + // Release any resources - if ( err ) + if ( g_hProvider && g_lpCryptReleaseContext ) { - // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations - - if ( !mDNSAddressIsAllDNSLinkGroup( inDstIP ) && ( WSAGetLastError() == WSAEHOSTDOWN || WSAGetLastError() == WSAENETDOWN || WSAGetLastError() == WSAEHOSTUNREACH || WSAGetLastError() == WSAENETUNREACH ) ) - { - err = mStatus_TransientErr; - } - else - { - require_noerr( err, exit ); - } + ( g_lpCryptReleaseContext )( g_hProvider, 0 ); } + + // Free the AdvApi32.dll + + FreeLibrary( g_hAAPI32 ); + + // And reset all the data + + g_lpCryptAcquireContext = NULL; + g_lpCryptReleaseContext = NULL; + g_lpCryptGenRandom = NULL; + g_hProvider = ( ULONG_PTR ) NULL; + g_hAAPI32 = NULL; } + + WSACleanup(); -exit: - return( err ); + dlog( kDebugLevelTrace, DEBUG_NAME "platform close done\n" ); } + //=========================================================================================================================== // mDNSPlatformLock //=========================================================================================================================== @@ -758,12 +792,82 @@ mDNSexport void mDNSPlatformMemFree( void *inMem ) } //=========================================================================================================================== -// mDNSPlatformRandomSeed +// mDNSPlatformRandomNumber //=========================================================================================================================== -mDNSexport mDNSu32 mDNSPlatformRandomSeed(void) +mDNSexport mDNSu32 mDNSPlatformRandomNumber(void) { - return( GetTickCount() ); + mDNSu32 randomNumber = 0; + BOOL bResult; + OSStatus err = 0; + + if ( !g_hAAPI32 ) + { + g_hAAPI32 = LoadLibrary( TEXT("AdvAPI32.dll") ); + err = translate_errno( g_hAAPI32 != NULL, GetLastError(), mStatus_UnknownErr ); + require_noerr( err, exit ); + } + + // Function Pointer: CryptAcquireContext + + if ( !g_lpCryptAcquireContext ) + { + g_lpCryptAcquireContext = ( fnCryptAcquireContext ) +#ifdef UNICODE + ( GetProcAddress( g_hAAPI32, "CryptAcquireContextW" ) ); +#else + ( GetProcAddress( g_hAAPI32, "CryptAcquireContextA" ) ); +#endif + err = translate_errno( g_lpCryptAcquireContext != NULL, GetLastError(), mStatus_UnknownErr ); + require_noerr( err, exit ); + } + + // Function Pointer: CryptReleaseContext + + if ( !g_lpCryptReleaseContext ) + { + g_lpCryptReleaseContext = ( fnCryptReleaseContext ) + ( GetProcAddress( g_hAAPI32, "CryptReleaseContext" ) ); + err = translate_errno( g_lpCryptReleaseContext != NULL, GetLastError(), mStatus_UnknownErr ); + require_noerr( err, exit ); + } + + // Function Pointer: CryptGenRandom + + if ( !g_lpCryptGenRandom ) + { + g_lpCryptGenRandom = ( fnCryptGenRandom ) + ( GetProcAddress( g_hAAPI32, "CryptGenRandom" ) ); + err = translate_errno( g_lpCryptGenRandom != NULL, GetLastError(), mStatus_UnknownErr ); + require_noerr( err, exit ); + } + + // Setup + + if ( !g_hProvider ) + { + bResult = (*g_lpCryptAcquireContext)( &g_hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET ); + + if ( !bResult ) + { + bResult = ( *g_lpCryptAcquireContext)( &g_hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET ); + err = translate_errno( bResult, GetLastError(), mStatus_UnknownErr ); + require_noerr( err, exit ); + } + } + + bResult = (*g_lpCryptGenRandom)( g_hProvider, sizeof( randomNumber ), ( BYTE* ) &randomNumber ); + err = translate_errno( bResult, GetLastError(), mStatus_UnknownErr ); + require_noerr( err, exit ); + +exit: + + if ( err ) + { + randomNumber = rand(); + } + + return randomNumber; } //=========================================================================================================================== @@ -965,12 +1069,12 @@ mDNSPlatformTCPSocket sock = (TCPSocket *) malloc( sizeof( TCPSocket ) ); require_action( sock, exit, err = mStatus_NoMemoryErr ); - memset( sock, 0, sizeof( TCPSocket ) ); + mDNSPlatformMemZero( sock, sizeof( TCPSocket ) ); sock->fd = INVALID_SOCKET; sock->flags = flags; - bzero(&saddr, sizeof(saddr)); + mDNSPlatformMemZero(&saddr, sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = htonl( INADDR_ANY ); saddr.sin_port = port->NotAnInteger; @@ -981,6 +1085,12 @@ mDNSPlatformTCPSocket err = translate_errno( sock->fd != INVALID_SOCKET, WSAGetLastError(), mStatus_UnknownErr ); require_noerr( err, exit ); + // bind + + err = bind( sock->fd, ( struct sockaddr* ) &saddr, sizeof( saddr ) ); + err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr ); + require_noerr( err, exit ); + // Set it to be non-blocking err = ioctlsocket( sock->fd, FIONBIO, &on ); @@ -989,7 +1099,7 @@ mDNSPlatformTCPSocket // Get port number - memset( &saddr, 0, sizeof( saddr ) ); + mDNSPlatformMemZero( &saddr, sizeof( saddr ) ); len = sizeof( saddr ); err = getsockname( sock->fd, ( struct sockaddr* ) &saddr, &len ); @@ -1040,7 +1150,7 @@ mDNSPlatformTCPConnect sock->callback = inCallback; sock->context = inContext; - bzero(&saddr, sizeof(saddr)); + mDNSPlatformMemZero(&saddr, sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_port = inDstPort.NotAnInteger; memcpy(&saddr.sin_addr, &inDstIP->ip.v4.NotAnInteger, sizeof(saddr.sin_addr)); @@ -1088,7 +1198,7 @@ mDNSexport TCPSocket *mDNSPlatformTCPAccept( TCPSocketFlags flags, int fd ) sock = malloc( sizeof( TCPSocket ) ); require_action( sock, exit, err = mStatus_NoMemoryErr ); - memset( sock, 0, sizeof( *sock ) ); + mDNSPlatformMemZero( sock, sizeof( *sock ) ); sock->fd = fd; sock->flags = flags; @@ -1202,193 +1312,303 @@ mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock ) return ( int ) sock->fd; } + //=========================================================================================================================== // mDNSPlatformUDPSocket //=========================================================================================================================== -mDNSexport UDPSocket *mDNSPlatformUDPSocket - ( - mDNS * const m, - mDNSIPPort port - ) +mDNSexport UDPSocket* mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport) +{ + UDPSocket* sock = NULL; + mDNSIPPort port = requestedport; + mStatus err = mStatus_NoError; + unsigned i; + + // Setup connection data object + + sock = (struct UDPSocket_struct*) malloc( sizeof( struct UDPSocket_struct ) ); + require_action( sock, exit, err = mStatus_NoMemoryErr ); + memset( sock, 0, sizeof( struct UDPSocket_struct ) ); + + // Create the socket + + sock->recvMsgPtr = m->p->unicastSock4RecvMsgPtr; + sock->dstAddr = m->p->unicastSock4DestAddr; + sock->sock = INVALID_SOCKET; + + // Try at most 10000 times to get a unique random port + + for (i=0; i<10000; i++) { - DEBUG_UNUSED( m ); - DEBUG_UNUSED( port ); + struct sockaddr_in saddr; + + saddr.sin_family = AF_INET; + saddr.sin_addr.s_addr = 0; + + // The kernel doesn't do cryptographically strong random port + // allocation, so we do it ourselves here + + if (mDNSIPPortIsZero(requestedport)) + { + port = mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF)); + } + + saddr.sin_port = port.NotAnInteger; + + err = SetupSocket(m, ( struct sockaddr* ) &saddr, port, &sock->sock ); + if (!err) break; + } + + require_noerr( err, exit ); + + // Set the port + + sock->port = port; + + // Set it up with Windows Eventing + + sock->readEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); + err = translate_errno( sock->readEvent, GetLastError(), mStatus_UnknownErr ); + require_noerr( err, exit ); + err = WSAEventSelect( sock->sock, sock->readEvent, FD_READ ); + require_noerr( err, exit ); + + // Bookkeeping + + sock->next = gUDPSocketList; + gUDPSocketList = sock; + gUDPSockets++; + gWaitListChanged = TRUE; + +exit: - return NULL; + if ( err ) + { + if ( sock ) + { + FreeUDPSocket( sock ); + sock = NULL; + } } + + return sock; +} //=========================================================================================================================== // mDNSPlatformUDPClose //=========================================================================================================================== mDNSexport void mDNSPlatformUDPClose( UDPSocket *sock ) +{ + UDPSocket * current = gUDPSocketList; + UDPSocket * last = NULL; + + while ( current ) { - DEBUG_UNUSED( sock ); - } - + if ( current == sock ) + { + if ( last == NULL ) + { + gUDPSocketList = sock->next; + } + else + { + last->next = sock->next; + } -//=========================================================================================================================== -// mDNSPlatformTLSSetupCerts -//=========================================================================================================================== + FreeUDPSocket( sock ); -mDNSexport mStatus -mDNSPlatformTLSSetupCerts(void) -{ - return mStatus_UnsupportedErr; + gUDPSockets--; + gWaitListChanged = TRUE; + + break; + } + + last = current; + current = current->next; + } } + //=========================================================================================================================== -// mDNSPlatformTLSTearDownCerts +// mDNSPlatformSendUDP //=========================================================================================================================== -mDNSexport void -mDNSPlatformTLSTearDownCerts(void) +mDNSexport mStatus + mDNSPlatformSendUDP( + const mDNS * const inMDNS, + const void * const inMsg, + const mDNSu8 * const inMsgEnd, + mDNSInterfaceID inInterfaceID, + UDPSocket * inSrcSocket, + const mDNSAddr * inDstIP, + mDNSIPPort inDstPort ) { -} - -//=========================================================================================================================== -// mDNSPlatformSetDNSConfig -//=========================================================================================================================== + SOCKET sendingsocket = INVALID_SOCKET; + mStatus err = mStatus_NoError; + mDNSInterfaceData * ifd = (mDNSInterfaceData*) inInterfaceID; + struct sockaddr_storage addr; + int n; + + DEBUG_USE_ONLY( inMDNS ); + + n = (int)( inMsgEnd - ( (const mDNSu8 * const) inMsg ) ); + check( inMDNS ); + check( inMsg ); + check( inMsgEnd ); + check( inDstIP ); + + dlog( kDebugLevelChatty, DEBUG_NAME "platform send %d bytes to %#a:%u\n", n, inDstIP, ntohs( inDstPort.NotAnInteger ) ); + + if( inDstIP->type == mDNSAddrType_IPv4 ) + { + struct sockaddr_in * sa4; + + sa4 = (struct sockaddr_in *) &addr; + sa4->sin_family = AF_INET; + sa4->sin_port = inDstPort.NotAnInteger; + sa4->sin_addr.s_addr = inDstIP->ip.v4.NotAnInteger; + sendingsocket = ifd ? ifd->sock : inMDNS->p->unicastSock4; -mDNSlocal void SetDNSServers( mDNS *const m ); -mDNSlocal void SetSearchDomainList( void ); + if (inSrcSocket) { sendingsocket = inSrcSocket->sock; debugf("mDNSPlatformSendUDP using port %d, static port %d, sock %d", mDNSVal16(inSrcSocket->port), inMDNS->p->unicastSock4, sendingsocket); } + } + else if( inDstIP->type == mDNSAddrType_IPv6 ) + { + struct sockaddr_in6 * sa6; + + sa6 = (struct sockaddr_in6 *) &addr; + sa6->sin6_family = AF_INET6; + sa6->sin6_port = inDstPort.NotAnInteger; + sa6->sin6_flowinfo = 0; + sa6->sin6_addr = *( (struct in6_addr *) &inDstIP->ip.v6 ); + sa6->sin6_scope_id = 0; // Windows requires the scope ID to be zero. IPV6_MULTICAST_IF specifies interface. + sendingsocket = ifd ? ifd->sock : inMDNS->p->unicastSock6; + } + else + { + dlog( kDebugLevelError, DEBUG_NAME "%s: dst is not an IPv4 or IPv6 address (type=%d)\n", __ROUTINE__, inDstIP->type ); + err = mStatus_BadParamErr; + goto exit; + } + + if (IsValidSocket(sendingsocket)) + { + n = sendto( sendingsocket, (char *) inMsg, n, 0, (struct sockaddr *) &addr, sizeof( addr ) ); + err = translate_errno( n > 0, errno_compat(), kWriteErr ); -void -mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **browseDomains) -{ - LPSTR name = NULL; - char subKeyName[kRegistryMaxKeyLength + 1]; - DWORD cSubKeys = 0; - DWORD cbMaxSubKey; - DWORD cchMaxClass; - DWORD dwSize; - DWORD enabled; - HKEY key; - HKEY subKey = NULL; - domainname dname; - DWORD i; - OSStatus err; + if ( err ) + { + // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations - if (setservers) SetDNSServers(m); - if (setsearch) SetSearchDomainList(); + if ( !mDNSAddressIsAllDNSLinkGroup( inDstIP ) && ( WSAGetLastError() == WSAEHOSTDOWN || WSAGetLastError() == WSAENETDOWN || WSAGetLastError() == WSAEHOSTUNREACH || WSAGetLastError() == WSAENETUNREACH ) ) + { + err = mStatus_TransientErr; + } + else + { + require_noerr( err, exit ); + } + } + } + +exit: + return( err ); +} - // Initialize - fqdn->c[0] = '\0'; +mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID) + { + DEBUG_UNUSED( m ); + DEBUG_UNUSED( InterfaceID ); + } - *browseDomains = NULL; +//=========================================================================================================================== +// mDNSPlatformSendRawPacket +//=========================================================================================================================== - err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSHostNames, &key ); - require_noerr( err, exit ); - - err = RegQueryString( key, "", &name, &dwSize, &enabled ); - if ( !err && ( name[0] != '\0' ) && enabled ) +mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID) { - if ( !MakeDomainNameFromDNSNameString( fqdn, name ) || !fqdn->c[0] ) - { - dlog( kDebugLevelError, "bad DDNS host name in registry: %s", name[0] ? name : "(unknown)"); - } + DEBUG_UNUSED( msg ); + DEBUG_UNUSED( end ); + DEBUG_UNUSED( InterfaceID ); } - if ( key ) +mDNSexport void mDNSPlatformReceiveRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID) { - RegCloseKey( key ); - key = NULL; + DEBUG_UNUSED( msg ); + DEBUG_UNUSED( end ); + DEBUG_UNUSED( InterfaceID ); } - if ( name ) +mDNSexport void mDNSPlatformSetLocalARP( const mDNSv4Addr * const tpa, const mDNSEthAddr * const tha, mDNSInterfaceID InterfaceID ) { - free( name ); - name = NULL; + DEBUG_UNUSED( tpa ); + DEBUG_UNUSED( tha ); + DEBUG_UNUSED( InterfaceID ); } - err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSBrowseDomains, &key ); - require_noerr( err, exit ); - - // Get information about this node - - err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL ); - require_noerr( err, exit ); +mDNSexport void mDNSPlatformWriteDebugMsg(const char *msg) + { + fprintf( stderr, msg ); + } - for ( i = 0; i < cSubKeys; i++) +mDNSexport void mDNSPlatformWriteLogMsg( const char * ident, const char * msg, int flags ) { - DWORD enabled; + DEBUG_UNUSED( ident ); + DEBUG_UNUSED( msg ); + DEBUG_UNUSED( flags ); + } - dwSize = kRegistryMaxKeyLength; - - err = RegEnumKeyExA( key, i, subKeyName, &dwSize, NULL, NULL, NULL, NULL ); +mDNSexport void mDNSPlatformSourceAddrForDest( mDNSAddr * const src, const mDNSAddr * const dst ) + { + DEBUG_UNUSED( src ); + DEBUG_UNUSED( dst ); + } - if ( !err ) - { - err = RegOpenKeyExA( key, subKeyName, 0, KEY_READ, &subKey ); - require_noerr( err, exit ); +//=========================================================================================================================== +// mDNSPlatformTLSSetupCerts +//=========================================================================================================================== - dwSize = sizeof( DWORD ); - err = RegQueryValueExA( subKey, "Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize ); +mDNSexport mStatus +mDNSPlatformTLSSetupCerts(void) +{ + return mStatus_UnsupportedErr; +} - if ( !err && ( subKeyName[0] != '\0' ) && enabled ) - { - if ( !MakeDomainNameFromDNSNameString( &dname, subKeyName ) || !dname.c[0] ) - { - dlog( kDebugLevelError, "bad DDNS browse domain in registry: %s", subKeyName[0] ? subKeyName : "(unknown)"); - } - else - { - DNameListElem * browseDomain = (DNameListElem*) malloc( sizeof( DNameListElem ) ); - require_action( browseDomain, exit, err = mStatus_NoMemoryErr ); - - AssignDomainName(&browseDomain->name, &dname); - browseDomain->next = *browseDomains; +//=========================================================================================================================== +// mDNSPlatformTLSTearDownCerts +//=========================================================================================================================== - *browseDomains = browseDomain; - } - } +mDNSexport void +mDNSPlatformTLSTearDownCerts(void) +{ +} - RegCloseKey( subKey ); - subKey = NULL; - } - } +//=========================================================================================================================== +// mDNSPlatformSetDNSConfig +//=========================================================================================================================== - if ( key ) - { - RegCloseKey( key ); - key = NULL; - } +mDNSlocal void SetDNSServers( mDNS *const m ); +mDNSlocal void SetSearchDomainList( void ); - err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains, &key ); - require_noerr( err, exit ); +mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **regDomains, DNameListElem **browseDomains) +{ + if (setservers) SetDNSServers(m); + if (setsearch) SetSearchDomainList(); - err = RegQueryString( key, "", &name, &dwSize, &enabled ); - if ( !err && ( name[0] != '\0' ) && enabled ) - { - *RegDomains = (DNameListElem*) malloc( sizeof( DNameListElem ) ); - if (!*RegDomains) dlog( kDebugLevelError, "No memory"); - else - { - (*RegDomains)->next = mDNSNULL; - if ( !MakeDomainNameFromDNSNameString( &(*RegDomains)->name, name ) || (*RegDomains)->name.c[0] ) - { - dlog( kDebugLevelError, "bad DDNS registration domain in registry: %s", name[0] ? name : "(unknown)"); - } - } - } - -exit: - - if ( subKey ) + if ( fqdn ) { - RegCloseKey( subKey ); + GetDDNSFQDN( fqdn ); } - if ( key ) + if ( browseDomains ) { - RegCloseKey( key ); + GetDDNSDomains( browseDomains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSBrowseDomains ); } - if ( name ) + if ( regDomains ) { - free( name ); + GetDDNSDomains( regDomains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains ); } } @@ -1398,9 +1618,10 @@ exit: //=========================================================================================================================== mDNSexport void -mDNSPlatformDynDNSHostNameStatusChanged(domainname *const dname, mStatus status) +mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status) { char uname[MAX_ESCAPED_DOMAIN_NAME]; + BYTE bStatus; LPCTSTR name; HKEY key = NULL; mStatus err; @@ -1422,8 +1643,8 @@ mDNSPlatformDynDNSHostNameStatusChanged(domainname *const dname, mStatus status) err = RegCreateKey( HKEY_LOCAL_MACHINE, name, &key ); require_noerr( err, exit ); - status = ( status ) ? 0 : 1; - err = RegSetValueEx( key, kServiceDynDNSStatus, 0, REG_DWORD, (const LPBYTE) &status, sizeof(DWORD) ); + bStatus = ( status ) ? 0 : 1; + err = RegSetValueEx( key, kServiceDynDNSStatus, 0, REG_DWORD, (const LPBYTE) &bStatus, sizeof(DWORD) ); require_noerr( err, exit ); exit: @@ -1442,115 +1663,39 @@ exit: //=========================================================================================================================== // This routine needs to be called whenever the system secrets database changes. -// Right now I call it from ProcessingThreadDynDNSConfigChanged, which may or may not be sufficient. -// Also, it needs to call mDNS_SetSecretForDomain() for *every* configured DNS domain/secret pair -// in the database, not just inDomain (the inDomain parameter should be deleted). +// We call it from ProcessingThreadDynDNSConfigChanged and mDNSPlatformInit mDNSlocal void -SetDomainSecrets( mDNS * const m, const domainname * inDomain ) +SetDomainSecrets( mDNS * const m ) { - PolyString domain; - PolyString key; - PolyString secret; - size_t i; - size_t dlen; - LSA_OBJECT_ATTRIBUTES attrs; - LSA_HANDLE handle = NULL; - NTSTATUS res; - OSStatus err; - - // Initialize PolyStrings - - domain.m_lsa = NULL; - key.m_lsa = NULL; - secret.m_lsa = NULL; - - // canonicalize name by converting to lower case (keychain and some name servers are case sensitive) - - ConvertDomainNameToCString( inDomain, domain.m_utf8 ); - dlen = strlen( domain.m_utf8 ); - for ( i = 0; i < dlen; i++ ) - { - domain.m_utf8[i] = (char) tolower( domain.m_utf8[i] ); // canonicalize -> lower case - } - - MakeDomainNameFromDNSNameString( &domain.m_dname, domain.m_utf8 ); - - // attrs are reserved, so initialize to zeroes. - - ZeroMemory( &attrs, sizeof( attrs ) ); + DomainAuthInfo *ptr; + domainname fqdn; + DNameListElem * regDomains = NULL; - // Get a handle to the Policy object on the local system - - res = LsaOpenPolicy( NULL, &attrs, POLICY_GET_PRIVATE_INFORMATION, &handle ); - err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr ); - require_noerr( err, exit ); - - // Get the encrypted data - - domain.m_lsa = ( PLSA_UNICODE_STRING) malloc( sizeof( LSA_UNICODE_STRING ) ); - require_action( domain.m_lsa != NULL, exit, err = mStatus_NoMemoryErr ); - err = MakeLsaStringFromUTF8String( domain.m_lsa, domain.m_utf8 ); - require_noerr( err, exit ); - - // Retrieve the key - - res = LsaRetrievePrivateData( handle, domain.m_lsa, &key.m_lsa ); - err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr ); - require_noerr_quiet( err, exit ); - - // Lsa secrets use a flat naming space. Therefore, we will prepend "$" to the keyname to - // make sure it doesn't conflict with a zone name. - - // Convert the key to a domainname. Strip off the "$" prefix. - - err = MakeUTF8StringFromLsaString( key.m_utf8, sizeof( key.m_utf8 ), key.m_lsa ); - require_noerr( err, exit ); - require_action( key.m_utf8[0] == '$', exit, err = kUnknownErr ); - MakeDomainNameFromDNSNameString( &key.m_dname, key.m_utf8 + 1 ); - - // Retrieve the secret - - res = LsaRetrievePrivateData( handle, key.m_lsa, &secret.m_lsa ); - err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr ); - require_noerr_quiet( err, exit ); + // 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. - // Convert the secret to UTF8 string - - err = MakeUTF8StringFromLsaString( secret.m_utf8, sizeof( secret.m_utf8 ), secret.m_lsa ); - require_noerr( err, exit ); - - // And finally, tell the core about this secret - - debugf("Setting shared secret for zone %s with key %##s", domain.m_utf8, key.m_dname.c); - mDNS_SetSecretForDomain( m, &domain.m_dname, &key.m_dname, secret.m_utf8, mDNSfalse ); - -exit: - - if ( domain.m_lsa != NULL ) - { - if ( domain.m_lsa->Buffer != NULL ) - { - free( domain.m_lsa->Buffer ); - } + for (ptr = m->AuthInfoList; ptr; ptr = ptr->next) + ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10); - free( domain.m_lsa ); - } + GetDDNSFQDN( &fqdn ); - if ( key.m_lsa != NULL ) + if ( fqdn.c[ 0 ] ) { - LsaFreeMemory( key.m_lsa ); + SetDomainSecret( m, &fqdn ); } - if ( secret.m_lsa != NULL ) - { - LsaFreeMemory( secret.m_lsa ); - } + GetDDNSDomains( ®Domains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains ); - if ( handle ) + while ( regDomains ) { - LsaClose( handle ); - handle = NULL; + DNameListElem * current = regDomains; + SetDomainSecret( m, ¤t->name ); + regDomains = regDomains->next; + free( current ); } } @@ -1567,8 +1712,8 @@ SetSearchDomainList( void ) { char * searchList = NULL; DWORD searchListLen; - DNameListElem * head = NULL; - DNameListElem * current = NULL; + //DNameListElem * head = NULL; + //DNameListElem * current = NULL; char * tok; HKEY key; mStatus err; @@ -1638,7 +1783,7 @@ SetReverseMapSearchDomainList( void ) ifa = ifa->ifa_next; } -exit: + return; } @@ -1718,7 +1863,7 @@ SetDNSServers( mDNS *const m ) { mDNSAddr addr; err = StringToAddress( &addr, ipAddr->IpAddress.String ); - if ( !err ) mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, addr, UnicastDNSPort); + if ( !err ) mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, &addr, UnicastDNSPort); } exit: @@ -1742,7 +1887,6 @@ exit: mDNSlocal void SetDomainFromDHCP( void ) { - DNameListElem * head = NULL; int i = 0; IP_ADAPTER_INFO * pAdapterInfo; IP_ADAPTER_INFO * pAdapter; @@ -1750,7 +1894,6 @@ SetDomainFromDHCP( void ) DWORD index; HKEY key = NULL; LPSTR domain = NULL; - domainname dname; DWORD dwSize; mStatus err = mStatus_NoError; @@ -2041,14 +2184,12 @@ mDNSlocal mStatus TearDownSynchronizationObjects( mDNS * const inMDNS ) mDNSlocal mStatus SetupNiceName( mDNS * const inMDNS ) { mStatus err = 0; - char tempString[ 256 ]; char utf8[ 256 ]; check( inMDNS ); // Set up the nice name. - tempString[ 0 ] = '\0'; - utf8[0] = '\0'; + utf8[0] = '\0'; // First try and open the registry key that contains the computer description value if (inMDNS->p->descKey == NULL) @@ -2086,16 +2227,17 @@ mDNSlocal mStatus SetupNiceName( mDNS * const inMDNS ) // if we can't find it in the registry, then use the hostname of the machine if ( err || ( utf8[ 0 ] == '\0' ) ) { - DWORD tempStringLen = sizeof( tempString ); + TCHAR hostname[256]; + DWORD hostnameLen = sizeof( hostname ) / sizeof( TCHAR ); BOOL ok; - ok = GetComputerNameExA( ComputerNamePhysicalDnsHostname, tempString, &tempStringLen ); + ok = GetComputerNameExW( ComputerNamePhysicalDnsHostname, hostname, &hostnameLen ); err = translate_errno( ok, (mStatus) GetLastError(), kNameErr ); check_noerr( err ); if( !err ) { - err = WindowsLatin1toUTF8( tempString, utf8, sizeof( utf8 ) ); + err = TCHARtoUTF8( hostname, utf8, sizeof( utf8 ) ); } if ( err ) @@ -2121,7 +2263,6 @@ mDNSlocal mStatus SetupNiceName( mDNS * const inMDNS ) return( err ); } - //=========================================================================================================================== // SetupHostName //=========================================================================================================================== @@ -2554,17 +2695,9 @@ mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inI #if( !TARGET_OS_WINDOWS_CE ) { DWORD size; - - // If we are running inside VPC, then we won't use WSARecvMsg because it will give us bogus information due to - // a bug in VPC itself. - err = inMDNS->p->inVirtualPC; - - if ( !err ) - { - err = WSAIoctl( sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), + err = WSAIoctl( sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &ifd->wsaRecvMsgFunctionPtr, sizeof( ifd->wsaRecvMsgFunctionPtr ), &size, NULL, NULL ); - } if ( err ) { @@ -2599,7 +2732,7 @@ mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inI err = SockAddrToMDNSAddr( inIFA->ifa_netmask, &ifd->interfaceInfo.mask, NULL ); require_noerr( err, exit ); - ifd->interfaceInfo.Advertise = inMDNS->AdvertiseLocalAddresses; + ifd->interfaceInfo.Advertise = ( mDNSu8 ) inMDNS->AdvertiseLocalAddresses; err = mDNS_RegisterInterface( inMDNS, &ifd->interfaceInfo, mDNSfalse ); require_noerr( err, exit ); @@ -2715,7 +2848,7 @@ mDNSlocal mStatus SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAdd // Bind the socket to the desired port ipv4.NotAnInteger = ( (const struct sockaddr_in *) inAddr )->sin_addr.s_addr; - memset( &sa4, 0, sizeof( sa4 ) ); + mDNSPlatformMemZero( &sa4, sizeof( sa4 ) ); sa4.sin_family = AF_INET; sa4.sin_port = port.NotAnInteger; sa4.sin_addr.s_addr = ipv4.NotAnInteger; @@ -2774,7 +2907,7 @@ mDNSlocal mStatus SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAdd // Bind the socket to the desired port - memset( &sa6, 0, sizeof( sa6 ) ); + mDNSPlatformMemZero( &sa6, sizeof( sa6 ) ); sa6.sin6_family = AF_INET6; sa6.sin6_port = port.NotAnInteger; sa6.sin6_flowinfo = 0; @@ -2978,17 +3111,51 @@ mDNSlocal mStatus SetupNotifications( mDNS * const inMDNS ) err = RegNotifyChangeKeyValue(inMDNS->p->ddnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->ddnsChangedEvent, TRUE); require_noerr( err, exit ); -exit: - if( err ) - { - TearDownNotifications( inMDNS ); - } - return( err ); -} + // This will catch all changes to file sharing -//=========================================================================================================================== -// TearDownNotifications -//=========================================================================================================================== + inMDNS->p->fileShareEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); + err = translate_errno( inMDNS->p->fileShareEvent, (mStatus) GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + + err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\Shares"), &inMDNS->p->fileShareKey ); + require_noerr( err, exit ); + + err = RegNotifyChangeKeyValue(inMDNS->p->fileShareKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->fileShareEvent, TRUE); + require_noerr( err, exit ); + + // This will catch changes to the Windows firewall + + inMDNS->p->firewallEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); + err = translate_errno( inMDNS->p->firewallEvent, (mStatus) GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + + // Just to make sure that initialization doesn't fail on some old OS + // that doesn't have this key, we'll only add the notification if + // the key exists. + + err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\SharedAccess\\Parameters\\FirewallPolicy\\FirewallRules"), &inMDNS->p->firewallKey ); + + if ( !err ) + { + err = RegNotifyChangeKeyValue(inMDNS->p->firewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->firewallEvent, TRUE); + require_noerr( err, exit ); + } + else + { + err = mStatus_NoError; + } + +exit: + if( err ) + { + TearDownNotifications( inMDNS ); + } + return( err ); +} + +//=========================================================================================================================== +// TearDownNotifications +//=========================================================================================================================== mDNSlocal mStatus TearDownNotifications( mDNS * const inMDNS ) { @@ -3028,64 +3195,31 @@ mDNSlocal mStatus TearDownNotifications( mDNS * const inMDNS ) inMDNS->p->ddnsKey = NULL; } - return( mStatus_NoError ); -} - - -//=========================================================================================================================== -// SetupRetryVPCCheck -//=========================================================================================================================== - -mDNSlocal mStatus -SetupRetryVPCCheck( mDNS * const inMDNS ) -{ - LARGE_INTEGER liDueTime; - BOOL ok; - mStatus err; - - dlog( kDebugLevelTrace, DEBUG_NAME "setting up retry VirtualPC check\n" ); - - liDueTime.QuadPart = kRetryVPCRate; - - // Create a waitable timer. - - inMDNS->p->vpcCheckEvent = CreateWaitableTimer( NULL, TRUE, TEXT( "VPCCheckTimer" ) ); - err = translate_errno( inMDNS->p->vpcCheckEvent, (mStatus) GetLastError(), kUnknownErr ); - require_noerr( err, exit ); - - // Set a timer to wait for 10 seconds. - - ok = SetWaitableTimer( inMDNS->p->vpcCheckEvent, &liDueTime, 0, NULL, NULL, 0 ); - err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr ); - require_noerr( err, exit ); - - inMDNS->p->timersCount++; - -exit: - - return err; -} - - -//=========================================================================================================================== -// TearDownRetryVPCCheck -//=========================================================================================================================== + if ( inMDNS->p->fileShareEvent != NULL ) + { + CloseHandle( inMDNS->p->fileShareEvent ); + inMDNS->p->fileShareEvent = NULL; + } -mDNSlocal mStatus -TearDownRetryVPCCheck( mDNS * const inMDNS ) -{ - dlog( kDebugLevelTrace, DEBUG_NAME "tearing down retry VirtualPC check\n" ); + if ( inMDNS->p->fileShareKey != NULL ) + { + RegCloseKey( inMDNS->p->fileShareKey ); + inMDNS->p->fileShareKey = NULL; + } - if ( inMDNS->p->vpcCheckEvent ) + if ( inMDNS->p->firewallEvent != NULL ) { - CancelWaitableTimer( inMDNS->p->vpcCheckEvent ); - CloseHandle( inMDNS->p->vpcCheckEvent ); + CloseHandle( inMDNS->p->firewallEvent ); + inMDNS->p->firewallEvent = NULL; + } - inMDNS->p->vpcCheckEvent = NULL; - inMDNS->p->timersCount--; + if ( inMDNS->p->firewallKey != NULL ) + { + RegCloseKey( inMDNS->p->firewallKey ); + inMDNS->p->firewallKey = NULL; } - return ( mStatus_NoError ); + return( mStatus_NoError ); } @@ -3241,6 +3375,16 @@ mDNSlocal unsigned WINAPI ProcessingThread( LPVOID inParam ) } else if( result == kWaitListInterfaceListChangedEvent ) { + // It would be nice to come up with a more elegant solution to this, but it seems that + // GetAdaptersAddresses doesn't always stay in sync after network changed events. So as + // as a simple workaround, we'll pause for a couple of seconds before processing the change. + + // We arrived at 2 secs by trial and error. We could reproduce the problem after sleeping + // for 500 msec and 750 msec, but couldn't after sleeping for 1 sec. We added another + // second on top of that to account for machine load or some other exigency. + + Sleep( 2000 ); + // Interface list changed event. Break out of the inner loop to re-setup the wait list. ProcessingThreadInterfaceListChanged( m ); @@ -3277,6 +3421,21 @@ mDNSlocal unsigned WINAPI ProcessingThread( LPVOID inParam ) ProcessingThreadDynDNSConfigChanged( m ); break; } + else if ( result == kWaitListFileShareEvent ) + { + // + // File sharing changed + // + ProcessingThreadFileShareChanged( m ); + break; + } + else if ( result == kWaitListFirewallEvent ) + { + // + // Firewall configuration changed + // + ProcessingThreadFirewallChanged( m ); + } else { int waitItemIndex; @@ -3286,26 +3445,21 @@ mDNSlocal unsigned WINAPI ProcessingThread( LPVOID inParam ) waitItemIndex = (int)( ( (int) result ) - WAIT_OBJECT_0 ); dlog( kDebugLevelChatty, DEBUG_NAME "socket data available on socket index %d\n", waitItemIndex ); check( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) ); + if( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) ) { HANDLE signaledObject; int n = 0; mDNSInterfaceData * ifd; TCPSocket * tcd; + UDPSocket * sock; signaledObject = waitList[ waitItemIndex ]; - if ( m->p->vpcCheckEvent == signaledObject ) - { - ProcessingThreadRetryVPCCheck( m ); - ++n; - - break; - } #if ( MDNS_WINDOWS_ENABLE_IPV4 ) if ( m->p->unicastSock4ReadEvent == signaledObject ) { - ProcessingThreadProcessPacket( m, NULL, m->p->unicastSock4 ); + ProcessingThreadProcessPacket( m, NULL, NULL, m->p->unicastSock4 ); ++n; } #endif @@ -3313,7 +3467,7 @@ mDNSlocal unsigned WINAPI ProcessingThread( LPVOID inParam ) #if ( MDNS_WINDOWS_ENABLE_IPV6 ) if ( m->p->unicastSock6ReadEvent == signaledObject ) { - ProcessingThreadProcessPacket( m, NULL, m->p->unicastSock6 ); + ProcessingThreadProcessPacket( m, NULL, NULL, m->p->unicastSock6 ); ++n; } #endif @@ -3322,7 +3476,7 @@ mDNSlocal unsigned WINAPI ProcessingThread( LPVOID inParam ) { if( ifd->readPendingEvent == signaledObject ) { - ProcessingThreadProcessPacket( m, ifd, ifd->sock ); + ProcessingThreadProcessPacket( m, ifd, NULL, ifd->sock ); ++n; } } @@ -3347,6 +3501,18 @@ mDNSlocal unsigned WINAPI ProcessingThread( LPVOID inParam ) } } + for ( sock = gUDPSocketList; sock; sock = sock->next ) + { + if ( sock->readEvent == signaledObject ) + { + ProcessingThreadProcessPacket( m, NULL, sock, sock->sock ); + + ++n; + + break; + } + } + check( n > 0 ); } else @@ -3400,14 +3566,6 @@ mDNSlocal mStatus ProcessingThreadInitialize( mDNS * const inMDNS ) inMDNS->p->threadID = GetCurrentThreadId(); - err = IsVPCRunning( &inMDNS->p->inVirtualPC ); - - if ( err ) - { - TearDownRetryVPCCheck( inMDNS ); - SetupRetryVPCCheck( inMDNS ); - } - err = SetupInterfaceList( inMDNS ); require_noerr( err, exit ); @@ -3419,7 +3577,6 @@ exit: if( err ) { TearDownInterfaceList( inMDNS ); - TearDownRetryVPCCheck( inMDNS ); } inMDNS->p->initStatus = err; @@ -3440,6 +3597,7 @@ mDNSlocal mStatus ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **o HANDLE * waitItemPtr; mDNSInterfaceData * ifd; TCPSocket * tcd; + UDPSocket * sock; dlog( kDebugLevelTrace, DEBUG_NAME "thread setting up wait list\n" ); check( inMDNS ); @@ -3449,7 +3607,7 @@ mDNSlocal mStatus ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **o // Allocate an array to hold all the objects to wait on. - waitListCount = kWaitListFixedItemCount + inMDNS->p->timersCount + inMDNS->p->interfaceCount + gTCPConnections; + waitListCount = kWaitListFixedItemCount + inMDNS->p->interfaceCount + gTCPConnections + gUDPSockets; waitList = (HANDLE *) malloc( waitListCount * sizeof( *waitList ) ); require_action( waitList, exit, err = mStatus_NoMemoryErr ); waitItemPtr = waitList; @@ -3462,13 +3620,8 @@ mDNSlocal mStatus ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **o *waitItemPtr++ = inMDNS->p->descChangedEvent; *waitItemPtr++ = inMDNS->p->tcpipChangedEvent; *waitItemPtr++ = inMDNS->p->ddnsChangedEvent; - - // Add timers - - if ( inMDNS->p->vpcCheckEvent ) - { - *waitItemPtr++ = inMDNS->p->vpcCheckEvent; - } + *waitItemPtr++ = inMDNS->p->fileShareEvent; + *waitItemPtr++ = inMDNS->p->firewallEvent; // Append all the dynamic wait items to the list. #if ( MDNS_WINDOWS_ENABLE_IPV4 ) @@ -3489,6 +3642,11 @@ mDNSlocal mStatus ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **o *waitItemPtr++ = tcd->pendingEvent; } + for ( sock = gUDPSocketList; sock; sock = sock->next ) + { + *waitItemPtr++ = sock->readEvent; + } + check( (int)( waitItemPtr - waitList ) == waitListCount ); *outWaitList = waitList; @@ -3509,7 +3667,7 @@ exit: // ProcessingThreadProcessPacket //=========================================================================================================================== -mDNSlocal void ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *inIFD, SocketRef inSock ) +mDNSlocal void ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *inIFD, UDPSocket * inUDPSocket, SocketRef inSock ) { OSStatus err; const mDNSInterfaceID iid = inIFD ? inIFD->interfaceInfo.InterfaceID : NULL; @@ -3536,18 +3694,25 @@ mDNSlocal void ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *i dstPort = MulticastDNSPort; ttl = 255; } + else if ( inUDPSocket ) + { + recvMsgPtr = inUDPSocket->recvMsgPtr; + dstAddr = inUDPSocket->dstAddr; + dstPort = inUDPSocket->port; + ttl = 255; + } else if ( inSock == inMDNS->p->unicastSock4 ) { recvMsgPtr = inMDNS->p->unicastSock4RecvMsgPtr; dstAddr = inMDNS->p->unicastSock4DestAddr; - dstPort = zeroIPPort; + dstPort = inMDNS->UnicastPort4; ttl = 255; } else if ( inSock == inMDNS->p->unicastSock6 ) { recvMsgPtr = inMDNS->p->unicastSock6RecvMsgPtr; dstAddr = inMDNS->p->unicastSock6DestAddr; - dstPort = zeroIPPort; + dstPort = inMDNS->UnicastPort6; ttl = 255; } else @@ -3578,7 +3743,7 @@ mDNSlocal void ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *i msg.dwFlags = 0; err = recvMsgPtr( inSock, &msg, &size, NULL, NULL ); - err = translate_errno( err == 0, (OSStatus) GetLastError(), kUnknownErr ); + err = translate_errno( err == 0, (OSStatus) WSAGetLastError(), kUnknownErr ); require_noerr( err, exit ); n = (int) size; @@ -3682,14 +3847,11 @@ mDNSlocal void ProcessingThreadInterfaceListChanged( mDNS *inMDNS ) // Inform clients of the change. - if( inMDNS->MainCallback ) - { - inMDNS->MainCallback( inMDNS, mStatus_ConfigChanged ); - } + mDNS_ConfigChanged(inMDNS); // Force mDNS to update. - mDNSCoreMachineSleep( inMDNS, mDNSfalse ); + mDNSCoreMachineSleep( inMDNS, mDNSfalse ); // What is this for? Mac OS X does not do this } @@ -3781,39 +3943,46 @@ mDNSlocal void ProcessingThreadDynDNSConfigChanged( mDNS *inMDNS ) //=========================================================================================================================== -// ProcessingThreadRetryVPCCheck +// ProcessingThreadFileShareChanged //=========================================================================================================================== - -mDNSlocal void -ProcessingThreadRetryVPCCheck( mDNS * inMDNS ) +mDNSlocal void ProcessingThreadFileShareChanged( mDNS *inMDNS ) { - mStatus err = mStatus_NoError; - - dlog( kDebugLevelTrace, DEBUG_NAME "in ProcessingThreadRetryVPCCheck\n" ); + mStatus err; - TearDownRetryVPCCheck( inMDNS ); + dlog( kDebugLevelInfo, DEBUG_NAME "File shares has changed\n" ); + check( inMDNS ); + + CheckFileShares( inMDNS ); + + // and reset the event handler - if ( inMDNS->p->vpcCheckCount < kRetryVPCMax ) + if ((inMDNS->p->fileShareKey != NULL) && (inMDNS->p->fileShareEvent)) { - inMDNS->p->vpcCheckCount++; + err = RegNotifyChangeKeyValue(inMDNS->p->fileShareKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->fileShareEvent, TRUE); + check_noerr( err ); + } +} - err = IsVPCRunning( &inMDNS->p->inVirtualPC ); - require_noerr( err, exit ); + +//=========================================================================================================================== +// ProcessingThreadFileShareChanged +//=========================================================================================================================== +mDNSlocal void ProcessingThreadFirewallChanged( mDNS *inMDNS ) +{ + mStatus err; - if ( inMDNS->p->inVirtualPC ) - { - ProcessingThreadInterfaceListChanged( inMDNS ); - } - } + dlog( kDebugLevelInfo, DEBUG_NAME "Firewall has changed\n" ); + check( inMDNS ); -exit: + CheckFileShares( inMDNS ); - if ( err ) + // and reset the event handler + + if ((inMDNS->p->firewallKey != NULL) && (inMDNS->p->firewallEvent)) { - SetupRetryVPCCheck( inMDNS ); + err = RegNotifyChangeKeyValue(inMDNS->p->firewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->firewallEvent, TRUE); + check_noerr( err ); } - - return; } @@ -3856,8 +4025,9 @@ mDNSlocal int getifaddrs( struct ifaddrs **outAddrs ) // Use the new IPv6-capable routine if supported. Otherwise, fall back to the old and compatible IPv4-only code. // Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 fails - - if( !gGetAdaptersAddressesFunctionPtr || ( ( err = getifaddrs_ipv6( outAddrs ) ) != mStatus_NoError ) ) + // Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 returns no addrs + + if( !gGetAdaptersAddressesFunctionPtr || ( ( ( err = getifaddrs_ipv6( outAddrs ) ) != mStatus_NoError ) || ( ( outAddrs != NULL ) && ( *outAddrs == NULL ) ) ) ) { err = getifaddrs_ipv4( outAddrs ); require_noerr( err, exit ); @@ -3983,10 +4153,33 @@ mDNSlocal int getifaddrs_ipv6( struct ifaddrs **outAddrs ) int prefixIndex; IP_ADAPTER_PREFIX * prefix; ULONG prefixLength; + uint32_t ipv4Index; + struct sockaddr_in ipv4Netmask; family = addr->Address.lpSockaddr->sa_family; if( ( family != AF_INET ) && ( family != AF_INET6 ) ) continue; + // iTunes 8: Bonjour doesn't work after upgrading iTunes 8 + // Seems as if the problem here is a buggy implementation of some network interface + // driver. It is reporting that is has a link-local address when it is actually + // disconnected. This was causing a problem in AddressToIndexAndMask. + // The solution is to call AddressToIndexAndMask first, and if unable to lookup + // the address, to ignore that address. + + ipv4Index = 0; + memset( &ipv4Netmask, 0, sizeof( ipv4Netmask ) ); + + if ( family == AF_INET ) + { + err = AddressToIndexAndMask( addr->Address.lpSockaddr, &ipv4Index, ( struct sockaddr* ) &ipv4Netmask ); + + if ( err ) + { + err = 0; + continue; + } + } + ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) ); require_action( ifa, exit, err = WSAENOBUFS ); @@ -4050,7 +4243,7 @@ mDNSlocal int getifaddrs_ipv6( struct ifaddrs **outAddrs ) prefixLength = 0; for( prefixIndex = 0, prefix = firstPrefix; prefix; ++prefixIndex, prefix = prefix->Next ) { - if( prefixIndex == addrIndex ) + if( ( prefix->Address.lpSockaddr->sa_family == family ) && ( prefixIndex == addrIndex ) ) { check_string( prefix->Address.lpSockaddr->sa_family == family, "addr family != netmask family" ); prefixLength = prefix->PrefixLength; @@ -4063,25 +4256,10 @@ mDNSlocal int getifaddrs_ipv6( struct ifaddrs **outAddrs ) { struct sockaddr_in * sa4; - require_action( prefixLength <= 32, exit, err = ERROR_INVALID_DATA ); - sa4 = (struct sockaddr_in *) calloc( 1, sizeof( *sa4 ) ); require_action( sa4, exit, err = WSAENOBUFS ); - sa4->sin_family = AF_INET; - - if ( prefixLength != 0 ) - { - sa4->sin_addr.s_addr = htonl( 0xFFFFFFFFU << ( 32 - prefixLength ) ); - } - else - { - uint32_t index; - - dlog( kDebugLevelWarning, DEBUG_NAME "%s: IPv4 prefixLength is 0\n", __ROUTINE__ ); - err = AddressToIndexAndMask( ifa->ifa_addr, &index, (struct sockaddr*) sa4 ); - require_noerr( err, exit ); - } + sa4->sin_addr.s_addr = ipv4Netmask.sin_addr.s_addr; dlog( kDebugLevelInfo, DEBUG_NAME "%s: IPv4 mask = %s\n", __ROUTINE__, inet_ntoa( sa4->sin_addr ) ); ifa->ifa_netmask = (struct sockaddr *) sa4; @@ -4206,12 +4384,27 @@ mDNSlocal int getifaddrs_ipv4( struct ifaddrs **outAddrs ) for( i = 0; i < n; ++i ) { + uint32_t ifIndex; + struct sockaddr_in netmask; + ifInfo = &buffer[ i ]; if( ifInfo->iiAddress.Address.sa_family != AF_INET ) { continue; } + // iTunes 8: Bonjour doesn't work after upgrading iTunes 8 + // See comment in getifaddrs_ipv6 + + ifIndex = 0; + memset( &netmask, 0, sizeof( netmask ) ); + err = AddressToIndexAndMask( ( struct sockaddr* ) &ifInfo->iiAddress.AddressIn, &ifIndex, ( struct sockaddr* ) &netmask ); + + if ( err ) + { + continue; + } + ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) ); require_action( ifa, exit, err = WSAENOBUFS ); @@ -4240,14 +4433,14 @@ mDNSlocal int getifaddrs_ipv4( struct ifaddrs **outAddrs ) memcpy( ifa->ifa_addr, sa4, sizeof( *sa4 ) ); ifa->ifa_netmask = (struct sockaddr*) calloc(1, sizeof( *sa4 ) ); + require_action( ifa->ifa_netmask, exit, err = WSAENOBUFS ); // Service won't start on Win2K. The address // family field was not being initialized. ifa->ifa_netmask->sa_family = AF_INET; - require_action( ifa->ifa_netmask, exit, err = WSAENOBUFS ); - err = AddressToIndexAndMask( ifa->ifa_addr, &ifa->ifa_extra.index, ifa->ifa_netmask ); - require_noerr( err, exit ); + ( ( struct sockaddr_in* ) ifa->ifa_netmask )->sin_addr = netmask.sin_addr; + ifa->ifa_extra.index = ifIndex; } else { @@ -4315,7 +4508,7 @@ mDNSlocal int getifaddrs_ce( struct ifaddrs **outAddrs ) // Call WSAIoctl with SIO_ADDRESS_LIST_QUERY and pass a null buffer. This call will fail, but the size needed to // for the request will be filled in. Once we know the size, allocate a buffer to hold the entire list. // - // NOTE: Due to a bug in Windows CE, the size returned by WSAIoctl is not enough so double it as a workaround. + // Note: Due to a bug in Windows CE, the size returned by WSAIoctl is not enough so double it as a workaround. size = 0; WSAIoctl( sock, SIO_ADDRESS_LIST_QUERY, NULL, 0, NULL, 0, &size, NULL, NULL ); @@ -4333,7 +4526,7 @@ mDNSlocal int getifaddrs_ce( struct ifaddrs **outAddrs ) // Process the raw interface list and build a linked list of interfaces. // - // NOTE: Due to a bug in Windows CE, the iAddressCount field is always 0 so use 1 in that case. + // Note: Due to a bug in Windows CE, the iAddressCount field is always 0 so use 1 in that case. n = addressList->iAddressCount; if( n == 0 ) @@ -4551,6 +4744,7 @@ AddressToIndexAndMask( struct sockaddr * addr, uint32_t * ifIndex, struct sockad } require_noerr( err, exit ); + err = mStatus_UnknownErr; for ( i = 0; i < pIPAddrTable->dwNumEntries; i++ ) { @@ -4591,7 +4785,7 @@ mDNSlocal mDNSBool CanReceiveUnicast( void ) ok = IsValidSocket( sock ); if( ok ) { - memset( &addr, 0, sizeof( addr ) ); + mDNSPlatformMemZero( &addr, sizeof( addr ) ); addr.sin_family = AF_INET; addr.sin_port = MulticastDNSPort.NotAnInteger; addr.sin_addr.s_addr = htonl( INADDR_ANY ); @@ -4923,135 +5117,326 @@ exit: //=========================================================================================================================== -// ConvertUTF8ToLsaString +// FreeTCPConnectionData //=========================================================================================================================== -mDNSlocal OSStatus -MakeLsaStringFromUTF8String( PLSA_UNICODE_STRING output, const char * input ) +mDNSlocal void +FreeTCPSocket( TCPSocket *sock ) +{ + check( sock ); + + if ( sock->pendingEvent ) + { + CloseHandle( sock->pendingEvent ); + } + + if ( sock->fd != INVALID_SOCKET ) + { + closesocket( sock->fd ); + } + + free( sock ); +} + + +//=========================================================================================================================== +// FreeUDPSocket +//=========================================================================================================================== + +mDNSlocal void +FreeUDPSocket( UDPSocket * sock ) { - int size; + check( sock ); + + if ( sock->readEvent ) + { + CloseHandle( sock->readEvent ); + } + + if ( sock->sock != INVALID_SOCKET ) + { + closesocket( sock->sock ); + } + + free( sock ); +} + +//=========================================================================================================================== +// SetupAddr +//=========================================================================================================================== + +mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa) + { + if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); } + + if (sa->sa_family == AF_INET) + { + struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa; + ip->type = mDNSAddrType_IPv4; + ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr; + return(mStatus_NoError); + } + + if (sa->sa_family == AF_INET6) + { + struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa; + ip->type = mDNSAddrType_IPv6; + if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.u.Word[1] = 0; + ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr; + return(mStatus_NoError); + } + + LogMsg("SetupAddr invalid sa_family %d", sa->sa_family); + return(mStatus_Invalid); + } + + +mDNSlocal void GetDDNSFQDN( domainname *const fqdn ) +{ + LPSTR name = NULL; + DWORD dwSize; + DWORD enabled; + HKEY key = NULL; OSStatus err; - - check( input ); - check( output ); - output->Buffer = NULL; + check( fqdn ); - size = MultiByteToWideChar( CP_UTF8, 0, input, -1, NULL, 0 ); - err = translate_errno( size > 0, GetLastError(), kUnknownErr ); - require_noerr( err, exit ); + // Initialize + + fqdn->c[0] = '\0'; - output->Length = (USHORT)( size * sizeof( wchar_t ) ); - output->Buffer = (PWCHAR) malloc( output->Length ); - require_action( output->Buffer, exit, err = mStatus_NoMemoryErr ); - size = MultiByteToWideChar( CP_UTF8, 0, input, -1, output->Buffer, size ); - err = translate_errno( size > 0, GetLastError(), kUnknownErr ); + // Get info from Bonjour registry key + + err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSHostNames, &key ); require_noerr( err, exit ); - // We're going to subtrace one wchar_t from the size, because we didn't - // include it when we encoded the string + err = RegQueryString( key, "", &name, &dwSize, &enabled ); + if ( !err && ( name[0] != '\0' ) && enabled ) + { + if ( !MakeDomainNameFromDNSNameString( fqdn, name ) || !fqdn->c[0] ) + { + dlog( kDebugLevelError, "bad DDNS host name in registry: %s", name[0] ? name : "(unknown)"); + } + } - output->MaximumLength = output->Length; - output->Length -= sizeof( wchar_t ); - exit: - if ( err && output->Buffer ) + if ( key ) { - free( output->Buffer ); - output->Buffer = NULL; + RegCloseKey( key ); + key = NULL; } - return( err ); + if ( name ) + { + free( name ); + name = NULL; + } } -//=========================================================================================================================== -// ConvertLsaStringToUTF8 -//=========================================================================================================================== - -mDNSlocal OSStatus -MakeUTF8StringFromLsaString( char * output, size_t len, PLSA_UNICODE_STRING input ) +#ifdef UNICODE +mDNSlocal void GetDDNSDomains( DNameListElem ** domains, LPCWSTR lpSubKey ) +#else +mDNSlocal void GetDDNSConfig( DNameListElem ** domains, LPCSTR lpSubKey ) +#endif { - size_t size; - OSStatus err = kNoErr; + char subKeyName[kRegistryMaxKeyLength + 1]; + DWORD cSubKeys = 0; + DWORD cbMaxSubKey; + DWORD cchMaxClass; + DWORD dwSize; + HKEY key = NULL; + HKEY subKey = NULL; + domainname dname; + DWORD i; + OSStatus err; - // The Length field of this structure holds the number of bytes, - // but WideCharToMultiByte expects the number of wchar_t's. So - // we divide by sizeof(wchar_t) to get the correct number. + check( domains ); - size = (size_t) WideCharToMultiByte(CP_UTF8, 0, input->Buffer, ( input->Length / sizeof( wchar_t ) ), NULL, 0, NULL, NULL); - err = translate_errno( size != 0, GetLastError(), kUnknownErr ); - require_noerr( err, exit ); - - // Ensure that we have enough space (Add one for trailing '\0') + // Initialize - require_action( ( size + 1 ) <= len, exit, err = mStatus_NoMemoryErr ); + *domains = NULL; - // Convert the string + err = RegCreateKey( HKEY_LOCAL_MACHINE, lpSubKey, &key ); + require_noerr( err, exit ); - size = (size_t) WideCharToMultiByte( CP_UTF8, 0, input->Buffer, ( input->Length / sizeof( wchar_t ) ), output, (int) size, NULL, NULL); - err = translate_errno( size != 0, GetLastError(), kUnknownErr ); + // Get information about this node + + err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL ); require_noerr( err, exit ); - // have to add the trailing 0 because WideCharToMultiByte doesn't do it, - // although it does return the correct size + for ( i = 0; i < cSubKeys; i++) + { + DWORD enabled; - output[size] = '\0'; + dwSize = kRegistryMaxKeyLength; + + err = RegEnumKeyExA( key, i, subKeyName, &dwSize, NULL, NULL, NULL, NULL ); -exit: + if ( !err ) + { + err = RegOpenKeyExA( key, subKeyName, 0, KEY_READ, &subKey ); + require_noerr( err, exit ); - return err; -} + dwSize = sizeof( DWORD ); + err = RegQueryValueExA( subKey, "Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize ); + + if ( !err && ( subKeyName[0] != '\0' ) && enabled ) + { + if ( !MakeDomainNameFromDNSNameString( &dname, subKeyName ) || !dname.c[0] ) + { + dlog( kDebugLevelError, "bad DDNS domain in registry: %s", subKeyName[0] ? subKeyName : "(unknown)"); + } + else + { + DNameListElem * domain = (DNameListElem*) malloc( sizeof( DNameListElem ) ); + require_action( domain, exit, err = mStatus_NoMemoryErr ); + + AssignDomainName(&domain->name, &dname); + domain->next = *domains; + *domains = domain; + } + } -//=========================================================================================================================== -// FreeTCPConnectionData -//=========================================================================================================================== + RegCloseKey( subKey ); + subKey = NULL; + } + } -mDNSlocal void -FreeTCPSocket( TCPSocket *sock ) -{ - check( sock ); +exit: - if ( sock->pendingEvent ) + if ( subKey ) { - CloseHandle( sock->pendingEvent ); + RegCloseKey( subKey ); } - if ( sock->fd != INVALID_SOCKET ) + if ( key ) { - closesocket( sock->fd ); + RegCloseKey( key ); } - - free( sock ); } -//=========================================================================================================================== -// SetupAddr -//=========================================================================================================================== -mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa) +mDNSlocal void SetDomainSecret( mDNS * const m, const domainname * inDomain ) +{ + char domainUTF8[ 256 ]; + DomainAuthInfo *foundInList; + DomainAuthInfo *ptr; + char outDomain[ 256 ]; + char outKey[ 256 ]; + char outSecret[ 256 ]; + OSStatus err; + + ConvertDomainNameToCString( inDomain, domainUTF8 ); + + // If we're able to find a secret for this domain + + if ( LsaGetSecret( domainUTF8, outDomain, sizeof( outDomain ), outKey, sizeof( outKey ), outSecret, sizeof( outSecret ) ) ) { - if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); } + domainname domain; + domainname key; - if (sa->sa_family == AF_INET) + // Tell the core about this secret + + MakeDomainNameFromDNSNameString( &domain, outDomain ); + MakeDomainNameFromDNSNameString( &key, outKey ); + + for (foundInList = m->AuthInfoList; foundInList; foundInList = foundInList->next) + if (SameDomainName(&foundInList->domain, &domain ) ) break; + + ptr = foundInList; + + if (!ptr) { - struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa; - ip->type = mDNSAddrType_IPv4; - ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr; - return(mStatus_NoError); + ptr = (DomainAuthInfo*)malloc(sizeof(DomainAuthInfo)); + require_action( ptr, exit, err = mStatus_NoMemoryErr ); } - if (sa->sa_family == AF_INET6) + err = mDNS_SetSecretForDomain(m, ptr, &domain, &key, outSecret, mDNSfalse ); + require_action( err != mStatus_BadParamErr, exit, if (!foundInList ) mDNSPlatformMemFree( ptr ) ); + + debugf("Setting shared secret for zone %s with key %##s", outDomain, key.c); + } + +exit: + + return; +} + + +mDNSlocal void +CheckFileShares( mDNS * const m ) +{ + PSHARE_INFO_1 bufPtr = ( PSHARE_INFO_1 ) NULL; + DWORD entriesRead = 0; + DWORD totalEntries = 0; + DWORD resume = 0; + mDNSBool enabled = mDNSfalse; + NET_API_STATUS res; + mStatus err; + + check( m ); + + if ( mDNSIsFileAndPrintSharingEnabled() ) + { + dlog( kDebugLevelTrace, DEBUG_NAME "file and print sharing is enabled\n" ); + + res = NetShareEnum( NULL, 1, ( LPBYTE* )&bufPtr, MAX_PREFERRED_LENGTH, &entriesRead, &totalEntries, &resume ); + + if ( ( res == ERROR_SUCCESS ) || ( res == ERROR_MORE_DATA ) ) { - struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa; - ip->type = mDNSAddrType_IPv6; - if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.u.Word[1] = 0; - ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr; - return(mStatus_NoError); + PSHARE_INFO_1 p = bufPtr; + DWORD i; + + for( i = 0; i <= totalEntries; i++ ) + { + // We are only interested if the user is sharing anything other + // than the built-in "print$" source + + if ( ( p->shi1_type == STYPE_DISKTREE ) && ( wcscmp( p->shi1_netname, TEXT( "print$" ) ) != 0 ) ) + { + enabled = mDNStrue; + break; + } + + p++; + } + + NetApiBufferFree( bufPtr ); + bufPtr = NULL; } + } - LogMsg("SetupAddr invalid sa_family %d", sa->sa_family); - return(mStatus_Invalid); + if ( enabled && !m->p->smbRegistered ) + { + domainname type; + domainname domain; + mDNSIPPort port = { { SMBPortAsNumber >> 8, SMBPortAsNumber & 0xFF } }; + mDNSInterfaceID iid = mDNSPlatformInterfaceIDfromInterfaceIndex( m, 0 ); + + dlog( kDebugLevelTrace, DEBUG_NAME "registering smb type\n" ); + + MakeDomainNameFromDNSNameString(&type, "_smb._tcp" ); + MakeDomainNameFromDNSNameString(&domain, "local."); + + err = mDNS_RegisterService( m, &m->p->smbSRS, &m->nicelabel, &type, &domain, NULL, port, NULL, 0, NULL, 0, iid, /* callback */ NULL, /* context */ NULL); + require_noerr( err, exit ); + + m->p->smbRegistered = mDNStrue; + } + else if ( !enabled && m->p->smbRegistered ) + { + dlog( kDebugLevelTrace, DEBUG_NAME "deregistering smb type\n" ); + + err = mDNS_DeregisterService( m, &m->p->smbSRS ); + require_noerr( err, exit ); + + m->p->smbRegistered = mDNSfalse; } + +exit: + + return; +} diff --git a/mDNSWindows/mDNSWin32.h b/mDNSWindows/mDNSWin32.h index 04be2ce..c85f2fe 100755 --- a/mDNSWindows/mDNSWin32.h +++ b/mDNSWindows/mDNSWin32.h @@ -17,6 +17,14 @@ Change History (most recent first): $Log: mDNSWin32.h,v $ +Revision 1.28 2009/04/24 04:55:26 herscher + Advertise SMB file sharing via Bonjour + +Revision 1.27 2009/03/30 20:45:52 herscher + Current Bonjour code does not compile on Windows + B4Windows: uDNS: Should use randomized source ports and transaction IDs to avoid DNS cache poisoning +Remove VirtualPC workaround + Revision 1.26 2006/08/14 23:25:21 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -199,16 +207,18 @@ struct mDNS_PlatformSupport_struct HANDLE descChangedEvent; // Computer description changed event HANDLE tcpipChangedEvent; // TCP/IP config changed HANDLE ddnsChangedEvent; // DynDNS config changed + HANDLE fileShareEvent; // File Sharing changed + HANDLE firewallEvent; // Firewall changed HANDLE wakeupEvent; HANDLE initEvent; - HANDLE vpcCheckEvent; // Timer handle to check if we're running in Virtual PC - int vpcCheckCount; HKEY descKey; HKEY tcpipKey; HKEY ddnsKey; + HKEY fileShareKey; + HKEY firewallKey; + mDNSBool smbRegistered; + ServiceRecordSet smbSRS; mStatus initStatus; - mDNSBool inVirtualPC; - int timersCount; mDNSBool registeredLoopback4; SocketRef interfaceListChangedSocket; int interfaceCount; @@ -257,32 +267,6 @@ struct ifaddrs }; -//--------------------------------------------------------------------------------------------------------------------------- -/*! @function GetWindowsVersionString - - @abstract Stores Windows version information in the string passed in (inBuffer) -*/ - -OSStatus GetWindowsVersionString( char *inBuffer, size_t inBufferSize ); - - -//--------------------------------------------------------------------------------------------------------------------------- -/*! @function getifaddrs - - @abstract Builds a linked list of interfaces. Caller must free using freeifaddrs if successful. -*/ - -int getifaddrs( struct ifaddrs **outAddrs ); - -//--------------------------------------------------------------------------------------------------------------------------- -/*! @function freeifaddrs - - @abstract Frees a linked list of interfaces built with getifaddrs. -*/ - -void freeifaddrs( struct ifaddrs *inAddrs ); - - #ifdef __cplusplus } #endif diff --git a/mDNSWindows/mdnsNSP/mdnsNSP.c b/mDNSWindows/mdnsNSP/mdnsNSP.c index db0d802..8173b0d 100644 --- a/mDNSWindows/mdnsNSP/mdnsNSP.c +++ b/mDNSWindows/mdnsNSP/mdnsNSP.c @@ -17,6 +17,13 @@ Change History (most recent first): $Log: mdnsNSP.c,v $ +Revision 1.22 2009/03/30 20:34:51 herscher + Current Bonjour code does not compile on Windows + Eliminate use of GetNextLabel in mdnsNSP + +Revision 1.21 2008/07/16 01:25:10 cheshire + Eliminate use of GetNextLabel in mdnsNSP + Revision 1.20 2006/08/14 23:26:10 cheshire Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 @@ -96,6 +103,7 @@ mDNS NameSpace Provider (NSP). Hooks into the Windows name resolution system to #include #include +#include "ClientCommon.h" #include "CommonServices.h" #include "DebugServices.h" @@ -115,6 +123,8 @@ mDNS NameSpace Provider (NSP). Hooks into the Windows name resolution system to #define snprintf _snprintf #endif +#define MAX_LABELS 128 + #if 0 #pragma mark == Structures == #endif @@ -284,7 +294,6 @@ DEBUG_LOCAL OSStatus HostsFileOpen( HostsFile ** self, const char * fname ); DEBUG_LOCAL OSStatus HostsFileClose( HostsFile * self ); DEBUG_LOCAL void HostsFileInfoFree( HostsFileInfo * info ); DEBUG_LOCAL OSStatus HostsFileNext( HostsFile * self, HostsFileInfo ** hInfo ); -DEBUG_LOCAL const char * GetNextLabel( const char *cstr, char label[64] ); DEBUG_LOCAL DWORD GetScopeId( DWORD ifIndex ); #ifdef ENABLE_REVERSE_LOOKUP @@ -391,7 +400,7 @@ STDAPI DllRegisterServer( void ) WSCUnInstallNameSpace( &gNSPGUID ); - err = GetModuleFileNameW( gInstance, path, sizeof( path ) ); + err = GetModuleFileNameW( gInstance, path, MAX_PATH ); err = translate_errno( err != 0, errno_compat(), kUnknownErr ); require_noerr( err, exit ); @@ -654,7 +663,7 @@ DEBUG_LOCAL int WSPAPI char translated[ kDNSServiceMaxDomainName ]; int n; int labels = 0; - const char * label[128]; + const char * label[MAX_LABELS]; char text[64]; n = WideCharToMultiByte( CP_UTF8, 0, name, -1, translated, sizeof( translated ), NULL, NULL ); @@ -664,9 +673,12 @@ DEBUG_LOCAL int WSPAPI // Don't resolve multi-label name + // Eliminate use of GetNextLabel in mdnsNSP + // Add checks for GetNextLabel returning NULL, individual labels being greater than + // 64 bytes, and the number of labels being greater than MAX_LABELS replyDomain = translated; - while ( *replyDomain ) + while (replyDomain && *replyDomain && labels < MAX_LABELS) { label[labels++] = replyDomain; replyDomain = GetNextLabel(replyDomain, text); @@ -682,7 +694,7 @@ DEBUG_LOCAL int WSPAPI require_action( InHostsTable( translated ) == FALSE, exit, err = WSASERVICE_NOT_FOUND ); } - // The name ends in .local ( and isn't in the hosts table ), {8,9,A,B}.E.F.ip6.arpa, or .254.169.in-addr.arpa so start the resolve operation. Lazy initialize DNS-SD if needed. + // The name ends in .local ( and isn't in the hosts table ), .0.8.e.f.ip6.arpa, or .254.169.in-addr.arpa so start the resolve operation. Lazy initialize DNS-SD if needed. NSPLock(); @@ -2319,37 +2331,6 @@ exit: } -//=========================================================================================================================== -// GetNextLabel -//=========================================================================================================================== -DEBUG_LOCAL const char* -GetNextLabel(const char *cstr, char label[64]) -{ - char *ptr = label; - while (*cstr && *cstr != '.') // While we have characters in the label... - { - char c = *cstr++; - if (c == '\\') - { - c = *cstr++; - if (isdigit(cstr[-1]) && isdigit(cstr[0]) && isdigit(cstr[1])) - { - int v0 = cstr[-1] - '0'; // then interpret as three-digit decimal - int v1 = cstr[ 0] - '0'; - int v2 = cstr[ 1] - '0'; - int val = v0 * 100 + v1 * 10 + v2; - if (val <= 255) { c = (char)val; cstr += 2; } // If valid three-digit decimal value, use it - } - } - *ptr++ = c; - if (ptr >= label+64) return(NULL); - } - if (*cstr) cstr++; // Skip over the trailing dot (if present) - *ptr++ = 0; - return(cstr); -} - - #ifdef ENABLE_REVERSE_LOOKUP //=========================================================================================================================== // IsReverseLookup @@ -2361,6 +2342,7 @@ IsReverseLookup( LPCWSTR name, size_t size ) LPCWSTR p; OSStatus err = kNoErr; + // IPv6LL Reverse-mapping domains are {8,9,A,B}.E.F.ip6.arpa require_action_quiet( size > sizeof_string( ".0.8.e.f.ip6.arpa" ), exit, err = WSASERVICE_NOT_FOUND ); p = name + ( size - 1 ); diff --git a/mDNSWindows/mdnsNSP/mdnsNSP.vcproj b/mDNSWindows/mdnsNSP/mdnsNSP.vcproj index f10b4bc..1d6f563 100644 --- a/mDNSWindows/mdnsNSP/mdnsNSP.vcproj +++ b/mDNSWindows/mdnsNSP/mdnsNSP.vcproj @@ -1,134 +1,393 @@ + Keyword="Win32Proj" + > + Name="Win32" + /> + + + + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" + CharacterSet="2" + > + + + + + + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + CallingConvention="2" + /> + + + Name="VCPreLinkEventTool" + /> + TargetMachine="1" + /> + + + + + + + + + + + + + Name="VCXMLDataGeneratorTool" + /> + Name="VCWebServiceProxyGeneratorTool" + /> + Name="VCMIDLTool" + TargetEnvironment="3" + /> + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories=".;../;../../mDNSShared;../../Clients" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;NSP_EXPORTS;DEBUG;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1" + StringPooling="true" + MinimalRebuild="true" + ExceptionHandling="0" + BasicRuntimeChecks="3" + SmallerTypeCheck="true" + RuntimeLibrary="1" + BufferSecurityCheck="true" + UsePrecompiledHeader="0" + AssemblerListingLocation="$(IntDir)\" + WarningLevel="4" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + CallingConvention="2" + /> + + AdditionalIncludeDirectories="../" + /> + Name="VCPreLinkEventTool" + /> + Name="VCLinkerTool" + AdditionalOptions="/NXCOMPAT /DYNAMICBASE" + AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib iphlpapi.lib shlwapi.lib" + OutputFile="$(OutDir)/mdnsNSP.dll" + LinkIncremental="2" + ModuleDefinitionFile="mdnsNSP.def" + DelayLoadDLLs="dnssd.dll" + GenerateDebugInformation="true" + ProgramDatabaseFile="$(OutDir)/mdnsNSP.pdb" + SubSystem="2" + BaseAddress="0x64000000" + ImportLibrary="$(OutDir)/mdnsNSP.lib" + TargetMachine="17" + /> + + + Name="VCXDCMakeTool" + /> + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + + + + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" + CharacterSet="2" + > + + + + + + CallingConvention="2" + /> + + + Name="VCPreLinkEventTool" + /> + TargetMachine="1" + /> + Name="VCALinkTool" + /> + Name="VCManifestTool" + /> + Name="VCXDCMakeTool" + /> + Name="VCBscMakeTool" + /> + + + + + + + + + + + + + + AdditionalIncludeDirectories="../" + /> + + + + + Name="VCXDCMakeTool" + /> + Name="VCBscMakeTool" + /> + Name="VCFxCopTool" + /> + Name="VCAppVerifierTool" + /> + Name="VCWebDeploymentTool" + /> + @@ -137,40 +396,59 @@ + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + + + RelativePath="..\..\mDNSShared\DebugServices.c" + > + RelativePath=".\mdnsNSP.c" + > + RelativePath=".\mdnsNSP.def" + > + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + + + RelativePath="..\..\mDNSShared\CommonServices.h" + > + RelativePath="..\..\mDNSShared\DebugServices.h" + > + RelativePath="..\..\..\mDNSShared\dns_sd.h" + > + RelativePath=".\resource.h" + > + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" + > + RelativePath=".\mdnsNSP.rc" + > -- 2.47.2